Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <template>
- <div>
- <div class="row">
- <div class="col-sm-12">
- <div class="content-header">Цветок</div>
- </div>
- </div>
- <section id="grid-option">
- <div class="row">
- <div class="col-12">
- <div class="card">
- <div class="card-body">
- <div class="card-block">
- <div class="col-md-12">
- <div class="card">
- <div class="card-body">
- <div class="card-block">
- <div class="card-text text-center">
- <div id="flowerElem" class="flower">
- <svg v-if="states.flowerEl"></svg>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
- <!--Modal-->
- <b-modal id="selectRefModal" @ok="addRefToFlower" ref="showSelectRefModal" title="Вставить в цветок"
- cancel-title="Отмена" ok-title="Вставить" :ok-disabled="!refSelected">
- <b-form-select v-model="refSelected" :options="refOptions" class="mb-3">
- <template slot="first">
- <option :value="null" disabled>{{ refOptions.length > 0 ? '-- Выберите человека для вставки --' : '-- Нет людей для вставки --' }}</option>
- </template>
- </b-form-select>
- </b-modal>
- </div>
- </template>
- <script>
- import * as d3 from 'd3'
- import _ from 'lodash'
- import {Flower} from '../classes/API'
- import Auth from "../classes/API/Auth"
- export default {
- name: 'Flower',
- data() {
- return {
- refOptions: [],
- refSelected: '',
- currentXY: {},
- states: {flowerEl: true},
- flowerData: []
- }
- },
- mounted() {
- this.init()
- },
- methods: {
- init(reload) {
- let self = this
- if (reload) {
- self.states.flowerEl = false
- setTimeout(function () {
- self.states.flowerEl = true
- return self.init()
- }, 500)
- }
- Flower.getFlowerView(this, {x: 0, y: 0}).then(response => {
- self.flowerData = response.data
- self.initFlower(self.flowerData)
- })
- },
- addRefToFlower() {
- Flower.flowerSetReferral(this, {
- userId: this.refSelected.id,
- x: this.currentXY.x,
- y: this.currentXY.y
- }).then(response => {
- if (response.status === 200) {
- this.init(true)
- } else {
- alert('Прозошла ошибка, попробуйте немного позже')
- }
- })
- },
- showSelectRefModal(elem) {
- this.currentXY = elem
- Flower.getFlowerToPlacement(this).then(response => {
- let refOption = []
- _.forEach(response.data, function (value) {
- refOption.push({value: value, text: value.name + ' (' + value.nickname + ')'})
- })
- this.refOptions = refOption
- this.refSelected = null
- this.$root.$emit('bv::show::modal', 'selectRefModal')
- })
- },
- initFlower(pages) {
- // index
- // Pan & Zooming
- let svg = d3.select("svg")
- .call(d3.zoom().on("zoom", function () {
- svg.attr("transform", d3.event.transform + "translate(100, 750), rotate(-90)")
- }).scaleExtent([1, 2]))
- svg = d3.select("svg")
- .append('g')
- .attr('id', 'svgMain')
- .attr("transform", "translate(100, 750) rotate(-90)")
- let tooltip = d3.select("body")
- .append("div")
- .attr("class", "tooltipFlower")
- .style("opacity", 0)
- let margin = {
- top: 10,
- right: 10,
- bottom: 10,
- left: 10
- }
- let height = 1000 - margin.left - margin.right
- let width = 1000 - margin.top - margin.bottom
- let self = this
- const
- w = 60,
- h = 45,
- radius = 55,
- radiusCos = radius * Math.cos(Math.PI / 6);
- let
- userCoordinates = {x: 0, y: 0},
- center = userCoordinates,
- parityCenter = Math.abs(center.x % 2),
- r = radius * 0.45,
- cos60 = Math.cos(Math.PI / 6),
- sin60 = Math.sin(Math.PI / 6),
- hexData = [
- {y: r, x: 0},
- {y: r * sin60, x: r * cos60},
- {y: -r * sin60, x: r * cos60},
- {y: -r, x: 0},
- {y: -r * sin60, x: -r * cos60},
- {y: r * sin60, x: -r * cos60},
- {y: r, x: 0}
- ];
- let hexGroup = svg.selectAll("g")
- .data(laps(calcCoordinates(fillMesh(mergePages(pages), center))))
- .enter()
- .append("g")
- .attr("transform", function (d) {
- return "translate(" + d._x + "," + d._y + "), rotate(90)";
- });
- let drawHexagon = d3.line()
- .x(function (d) {
- return d.x;
- })
- .y(function (d) {
- return d.y;
- });
- hexGroup
- .append('path')
- .attr("d", drawHexagon(hexData))
- .each(function (d) {
- switch (d.type) {
- case 'empty':
- d3.select(this)
- .style("stroke-dasharray", "4,2")
- .style("opacity", .3)
- .style("stroke", "lightblue")
- .style("stroke-width", "2")
- .style("stroke-linejoin", "round")
- .style("fill", "white");
- break;
- case 'append':
- d3.select(this)
- .style("stroke-dasharray", "4,2")
- .style("stroke", "#8fc5b7")
- .style("stroke-width", "2")
- .style("stroke-linejoin", "round")
- .style("fill", "white")
- .on('mouseover', function () {
- d3.select(this)
- .attr("cursor", "pointer")
- .transition()
- .ease(d3.easeElastic)
- .duration(1000)
- .attr("transform", function () {
- return "scale(1.2)";
- });
- })
- .on('mousemove', function () {
- })
- .on('mouseout', function () {
- tooltip.style('visibility', 'hidden');
- d3.select(this)
- .transition()
- .ease(d3.easeElastic)
- .duration(1000)
- .attr("transform", function () {
- return "scale(1)";
- });
- })
- .on('click', function (d) {
- self.showSelectRefModal(d)
- });
- break;
- case 'exist':
- d3.select(this)
- .style("stroke", function (d) {
- if (d.id === Auth.getUserRow('uid', true)) {
- return '#1f6e6a'
- }
- // color lap by current user qualification
- if (d.qLap === 1) {
- return '#c3786e'
- } else if (d.qLap === 2 || d.qLap === 3) {
- return '#e1a76c'
- } else if (d.qLap >= 4 && d.qLap <= 6) {
- return '#c38588'
- } else if (d.qLap >= 7 && d.qLap <= 10) {
- return '#7aaf77'
- } else if (d.qLap >= 11 && d.qLap <= 15) {
- return '#a773a0'
- } else if (d.qLap >= 16 && d.qLap <= 20) {
- return '#7172a1'
- } else if (d.qLap >= 21 && d.qLap <= 25) {
- return '#6a5692'
- } else if (d.qLap >= 26 && d.qLap <= 30) {
- return '#006961'
- } else {
- return '#84b9b5'
- }
- })
- .style("stroke-width", "2")
- .style("stroke-linejoin", "round")
- .attr("class", function (d) {
- return 'filled' + ' ' + d.qualification
- })
- .style("fill", function (d) {
- if (d.id === Auth.getUserRow('uid', true)) {
- return '#4ca398'
- }
- // fill lap by current user qualification
- if (d.qLap === 1) {
- return '#f5aeb1'
- } else if (d.qLap === 2 || d.qLap === 3) {
- return '#ffe4a2'
- } else if (d.qLap >= 4 && d.qLap <= 6) {
- return '#dcb495'
- } else if (d.qLap >= 7 && d.qLap <= 10) {
- return '#81af7e'
- } else if (d.qLap >= 11 && d.qLap <= 15) {
- return '#a7819d'
- } else if (d.qLap >= 16 && d.qLap <= 20) {
- return '#7c78a1'
- } else if (d.qLap >= 21 && d.qLap <= 25) {
- return '#746592'
- } else if (d.qLap >= 26 && d.qLap <= 30) {
- return '#1b6966'
- } else {
- return '#81d8cd'
- }
- })
- .style("opacity", function (d) {
- if (_.isUndefined(d.qLap) && d.id !== Auth.getUserRow('uid', true)) {
- return .7
- }
- })
- .on('mouseover', function () {
- tooltip.style('visibility', 'visible');
- d3.select(this)
- .attr("cursor", "pointer")
- .transition()
- .duration(200)
- .style("opacity", .8);
- })
- .on('mousemove', showTooltip)
- .on('mouseout', function () {
- tooltip.style('visibility', 'hidden');
- // opacity for elems
- d3.select(this)
- .transition()
- .duration(200)
- .style("opacity", function (d) {
- if (_.isUndefined(d.qLap) && d.id !== Auth.getUserRow('uid', true)) {
- return .7
- }
- return 1
- });
- });
- break;
- }
- });
- // Text on Hex
- hexGroup.append("text")
- .each(function (d) {
- switch (d.type) {
- case 'empty':
- break;
- case 'append':
- d3.select(this)
- .attr("text-anchor", "middle")
- .attr("y", 7)
- .attr("id", function (d, i) {
- return "append" + i;
- })
- .attr("font-size", "20px")
- .attr("font-family", "Arial")
- .attr("fill", "#8fc5b7")
- .attr("pointer-events", "none")
- .text("+");
- break;
- case 'exist':
- d3.select(this)
- .attr("text-anchor", "middle")
- .attr("y", 6)
- .attr("id", function (d, i) {
- return "exist" + i;
- })
- .attr("font-size", "18px")
- .attr("letter-spacing", "2px")
- .attr("font-family", "Arial")
- .attr("fill", "#FFF")
- .attr("pointer-events", "none")
- .text(function (d) {
- let initials = d.name.split(' ');
- let fName = initials[0][0] || '';
- if (initials[1]) {
- let lName = initials[1][0] || '';
- return (fName + lName).toUpperCase()
- }
- return fName.toUpperCase();
- });
- break;
- }
- });
- // Show tooltip
- function showTooltip(d) {
- let textBox = 'Имя: <b>' + d.name + '</b></b><br>'
- + 'Групповой объем: <b>' + self.$options.filters.round(d.teamVolume, 2) + ' (Б)</b><br>'
- + 'Личный объем: <b>' + self.$options.filters.round(d.personalVolume, 2) + ' (Б)</b><br>'
- + 'Квалификация: <b>' + d.qualification + '</b><br>';
- tooltip.style('visibility', 'visible');
- tooltip.transition()
- .style("opacity", .85);
- tooltip
- .html(textBox)
- .style("left", (d3.event.pageX + 5) + "px")
- .style("top", (d3.event.pageY - 36) + "px");
- }
- // draw
- function createEmptyMesh(centerPos, halfCountByWidth, halfCountByHeight) {
- let emptyMesh = [];
- for (let i = 0; i <= 2 * halfCountByHeight; i++) {
- for (let j = 0; j <= 2 * halfCountByWidth; j++) {
- emptyMesh.push({
- x: centerPos.x - halfCountByHeight + i,
- y: centerPos.y - halfCountByWidth + j,
- type: 'empty'
- });
- }
- }
- return emptyMesh;
- }
- function fillMesh(elems, centerPos) {
- function findAndReplace(_mesh, _elem) {
- let index = _.findIndex(_mesh, {x: _elem.x, y: _elem.y});
- if (index !== -1 && (_elem.type === 'exist' || (_elem.type === 'append' && _mesh[index].type === 'empty'))) {
- _mesh[index] = _elem;
- }
- }
- const halfCountByWidth = Math.round(width / 1.5 / radius * 3 / 2);
- const halfCountByHeight = Math.round(height / 1.5 / radiusCos * 3 / 2);
- let mesh = createEmptyMesh(centerPos, halfCountByWidth, halfCountByHeight);
- _.forEach(_.filter(
- elems,
- function (d) {
- return d.x <= centerPos.x + halfCountByWidth &&
- d.x >= centerPos.x - halfCountByWidth &&
- d.y <= centerPos.y + halfCountByHeight &&
- d.y >= centerPos.y - halfCountByHeight;
- }
- ), function (elem) {
- elem.type = 'exist';
- findAndReplace(mesh, elem);
- _.forEach(['left', 'right', 'left-up', 'right-up', 'left-down', 'right-down'], function (direction) {
- findAndReplace(mesh, stepPos({x: elem.x, y: elem.y, type: 'append'}, direction));
- });
- });
- return mesh;
- }
- function findLap(center, radius) {
- let lap = [{x: center.x, y: center.y - radius}]
- _.forEach(['right-up', 'right', 'right-down', 'left-down', 'left', 'left-up'], function (direction) {
- for (let i = 1; i <= radius; i++) {
- lap.push(stepPos(_.last(lap), direction))
- }
- })
- lap.pop()
- return lap
- }
- function laps(mesh) {
- let elemOnLaps = [],
- elemObj, centerUser = _.find(mesh, function (d) {
- return d.id === Auth.getUserRow('uid', true)
- })
- _.forEach(calcLapsByQualification(_.find(mesh, centerUser).qualification), function (lap) {
- _.map(findLap(centerUser, lap), function (obj) {
- elemObj = _.find(mesh, obj)
- elemObj.qLap = lap
- elemOnLaps.push(elemObj)
- })
- })
- return mesh
- }
- function calcLapsByQualification(q) {
- let lastLap, res = []
- switch (q) {
- case 'Q0':
- lastLap = 0
- break;
- case 'Q1':
- lastLap = 1
- break;
- case 'Q2':
- lastLap = 3
- break;
- case 'Q3':
- lastLap = 6
- break;
- case 'Q4':
- lastLap = 10
- break;
- case 'Q5':
- lastLap = 15
- break;
- case 'Q6':
- lastLap = 20
- break;
- case 'Q7':
- lastLap = 25
- break;
- case 'Q8':
- lastLap = 30
- break;
- }
- for (let i = 0; i <= lastLap; i++) {
- res.push(i)
- }
- return res
- }
- function calcCoordinates(mesh) {
- return _.flatten(_.values(_.mapValues(
- _.groupBy(
- mesh,
- 'x'
- ),
- function (rowElems, rowXCoordinate) {
- let x = (width / 2) - (center.x - rowXCoordinate) * radiusCos,
- res;
- if (Math.abs(rowXCoordinate % 2) === parityCenter) {
- res = _.map(rowElems, function (d) {
- d._x = x;
- d._y = (height / 2) - (center.y - d.y) * radius;
- return d;
- });
- } else if (parityCenter === 1) {
- res = _.map(rowElems, function (d) {
- d._x = x;
- d._y = (height / 2) - (center.y - d.y) * radius + radius / 2
- return d;
- });
- } else {
- res = _.map(rowElems, function (d) {
- d._x = x;
- d._y = (height / 2) - (center.y - d.y) * radius - radius / 2
- return d;
- });
- }
- return res;
- })));
- }
- // pos-support
- function pageWithPos(x, y) {
- return {x: w * (x / w), y: h * (y / h)};
- }
- function pagesForPos(x, y) {
- let xyPagePos = pageWithPos(x, y),
- res;
- if (x % w < w / 2. && y % h < h / 2.) {
- res = [{x: xyPagePos.x, y: xyPagePos.y},
- {x: xyPagePos.x - w, y: xyPagePos.y},
- {x: xyPagePos.x, y: xyPagePos.y - h},
- {x: xyPagePos.x - w, y: xyPagePos.y - h}];
- } else if (x % w > w / 2. && y % h < h / 2.) {
- res = [{x: xyPagePos.x, y: xyPagePos.y},
- {x: xyPagePos.x + w, y: xyPagePos.y},
- {x: xyPagePos.x, y: xyPagePos.y - h},
- {x: xyPagePos.x + w, y: xyPagePos.y - h}];
- } else {
- res = [{x: 0, y: 0}];
- }
- return res;
- }
- function pagesForPosWithout(x, y, needlessPages) {
- return _.filter(pagesForPos(x, y), function (page) {
- return _.isUndefined(_.find(needlessPages, function (needlessPage) {
- return needlessPage.x === page.x && needlessPage.y === page.y;
- }));
- });
- }
- function mergePages(pages) {
- return _.reduce(pages, function (acc, page) {
- return acc.concat(page.elems);
- }, []);
- }
- function updatePages(pages, newPages) {
- let notAffectedPages = _.filter(pages, function (page) {
- return _.isUndefined(_.find(newPages, function (newPage) {
- return newPage.x === page.x && newPage.y === page.y;
- }));
- });
- return notAffectedPages.concat(newPages);
- }
- function stepPos(elem, direction) {
- const parity = Math.abs(elem.x % 2);
- let res = {};
- switch (direction) {
- case 'left' :
- res = {
- x: elem.x,
- y: elem.y - 1
- };
- break;
- case 'right' :
- res = {
- x: elem.x,
- y: elem.y + 1
- };
- break;
- case 'left-up' :
- res = {
- x: elem.x + 1,
- y: (parity) ? elem.y - 1 : elem.y
- };
- break;
- case 'left-down' :
- res = {
- x: elem.x - 1,
- y: (parity) ? elem.y - 1 : elem.y
- };
- break;
- case 'right-up' :
- res = {
- x: elem.x + 1,
- y: (parity) ? elem.y : elem.y + 1
- };
- break;
- case 'right-down' :
- res = {
- x: elem.x - 1,
- y: (parity) ? elem.y : elem.y + 1
- };
- break;
- }
- if (elem.type) {
- res.type = elem.type;
- }
- return res;
- }
- }
- }
- }
- </script>
- <style scoped>
- .card .card-block {
- padding: 0;
- }
- .flower svg {
- width: 100%;
- height: 650px;
- }
- </style>
- <style>
- .tooltipFlower {
- text-align: center;
- position: absolute;
- font: 14px "Helvetica Neue", Helvetica, sans-serif;
- z-index: 99999999;
- border-radius: 8px;
- pointer-events: none;
- background-color: #ffffff;
- padding: 3px 12px;
- border: 1px solid #bbbbbb;
- box-shadow: 1px 1px 4px #bbbbbb;
- }
- </style>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement