You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
529 lines
15 KiB
529 lines
15 KiB
<template>
|
|
<div class="bg" ref="ThumbnailRef"></div>
|
|
</template>
|
|
|
|
<script>
|
|
import { onceObserver } from "@screen/utils/resizeObserver";
|
|
import Vue from "vue";
|
|
import { Graph, Shape } from '@antv/x6'
|
|
import { debounce } from "lodash";
|
|
import { actualLocationList, canvasList } from "./data.js";
|
|
|
|
const faultBg = require(`@screen/images/mapBg/fault.svg`);
|
|
const normalBg = require(`@screen/images/mapBg/active.svg`);
|
|
|
|
const mouseenterDebounceFunc = debounce(({ node }) => {
|
|
if (["custom-html"].indexOf(node.shape) >= 0) {
|
|
node.setZIndex(100);
|
|
// console.log(node);
|
|
}
|
|
}, 0);
|
|
const mouseleaveDebounceFunc = debounce(({ node }) => {
|
|
if (["custom-html"].indexOf(node.shape) >= 0) {
|
|
node.setZIndex(1);
|
|
}
|
|
}, 0);
|
|
|
|
const clickDebounceFunc = debounce(({ node }) => {
|
|
if (["custom-html"].indexOf(node.shape) >= 0) {
|
|
const extData = node.getData()?.extData;
|
|
if (extData) {
|
|
this.setMapZoomAndCenter(18, [extData.longitude, extData.latitude])
|
|
}
|
|
}
|
|
}, 0);
|
|
|
|
|
|
function setFont(size, bold = "normal", family = "微软雅黑") {
|
|
return `${bold} ${size}px ${family}`;
|
|
}
|
|
let width, height;
|
|
const allActualDis = actualLocationList.reduce(
|
|
(count, item) => count + item.intervalDistance,
|
|
0
|
|
);
|
|
const rect = {
|
|
shape: "rect",
|
|
width: 0.1,
|
|
attrs: {
|
|
"body": {
|
|
stroke: "#37B5D4",
|
|
strokeWidth: 2,
|
|
strokeDasharray: '4, 7',
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
export default {
|
|
name: "Thumbnail",
|
|
data() {
|
|
return {
|
|
list: [], //计算真实距离与画布距离的比例 *节点真实距离作为canvasItem.distance的值
|
|
translateX: 0,
|
|
translateY: 50,
|
|
allInstance: 0,
|
|
width: window.innerWidth
|
|
};
|
|
},
|
|
props: {
|
|
map: {
|
|
type: String,
|
|
default: "B",
|
|
}
|
|
},
|
|
inject: ['setMapZoomAndCenter'],
|
|
mounted() {
|
|
this.mapInit();
|
|
// onceObserver.call(this, this.$refs.ThumbnailRef, () => {
|
|
// this.$refs.ThumbnailRef.innerHTML = null;
|
|
// this.translateX = 0,
|
|
// this.translateY = 50,
|
|
// this.allInstance = 0
|
|
// this.mapInit();
|
|
// });
|
|
window.addEventListener("resize", (x) => {
|
|
if(this.width !== window.innerWidth){
|
|
if (this.timeout) clearTimeout(this.timeout);
|
|
this.timeout = setTimeout(() => {
|
|
this.width = window.innerWidth
|
|
this.debug();
|
|
}, 200);
|
|
}
|
|
|
|
});
|
|
},
|
|
methods: {
|
|
|
|
getIcon({ config, extData }, type = '') {
|
|
const normal = require(`@screen/images/layer${type}${config.item.id.replace(
|
|
/^\.|[^/]+(?=.svg$)/g,
|
|
(str) => (str === "." ? "" : `${str}_active`)
|
|
)}`);
|
|
|
|
const fault = require(`@screen/images/layer${type}${config.item.id.replace(
|
|
/^\.|[^/]+(?=.svg$)/g,
|
|
(str) => (str === "." ? `` : `${str}_fault`)
|
|
)}`);
|
|
|
|
const currentState = this.getState({ config, extData });
|
|
|
|
const deviceIcon =
|
|
typeof config.iconCallback === "function" &&
|
|
config.iconCallback(currentState, extData, config.item);
|
|
|
|
return deviceIcon ? deviceIcon : currentState ? normal : fault;
|
|
},
|
|
|
|
getState(data) {
|
|
if (Array.isArray(data)) {
|
|
return data.every((item) => this.getStateSingle(item));
|
|
} else return this.getStateSingle(data);
|
|
},
|
|
|
|
getStateSingle({ config, extData }) {
|
|
return typeof config?.stateCallback === "function"
|
|
? config.stateCallback?.()
|
|
: extData.deviceState == 1;
|
|
},
|
|
debug() {
|
|
const nodes = _.cloneDeep(this._graph.getNodes()).filter(x => x.id.length < 11);
|
|
this._graph.dispose();
|
|
//
|
|
setTimeout(() => {
|
|
this.mapInit();
|
|
|
|
for (let n of nodes) {
|
|
|
|
const aryId = n.id.split('_')
|
|
const distance = (Number(aryId[0].replace(/\.\d+/, "").replace("+", ".").replace(/[Kk]/, "")) - 54.394) * window.canvasRatio + window.canvasWidth * window.offsetRatio; //K54+394 开始到K208+979计算的比例尺
|
|
if (n.data.nowBg) {
|
|
n.data.nowBg = this.getState(n.data.extNode) ? normalBg : faultBg;
|
|
}
|
|
if (n.data.src) {
|
|
n.data.src = `${this.getIcon(n.data.extNode)}`
|
|
}
|
|
|
|
const node = {
|
|
shape: "custom-html",
|
|
effect: ["data"],
|
|
data: n.data
|
|
};
|
|
this._graph.addNode({
|
|
x: distance,
|
|
y: 60,
|
|
width: 25,
|
|
height: 25,
|
|
...node,
|
|
zIndex: 1,
|
|
id: n.id,
|
|
});
|
|
}
|
|
|
|
}, 100);
|
|
},
|
|
async mapInit() {
|
|
this.list = _.cloneDeep(canvasList)
|
|
this.translateX = 0;
|
|
this.translateY = 50;
|
|
this.allInstance = 0;
|
|
const content = this.$refs.ThumbnailRef;
|
|
width = content.clientWidth;
|
|
height = content.clientHeight;
|
|
const baseData = {
|
|
nodes: [
|
|
{
|
|
type: "text",
|
|
label: "⇦ 济南方向",
|
|
x: 66,
|
|
y: height / 2 - 50,
|
|
attrs: {
|
|
text: {
|
|
fontSize: 12,
|
|
fill: "#7dd7fe",
|
|
}
|
|
}
|
|
},
|
|
{
|
|
type: "text",
|
|
label: "G2001济南绕城高速",
|
|
x: 66,
|
|
y: height / 2 - 21,
|
|
attrs: {
|
|
text: {
|
|
fontSize: 12,
|
|
fill: "#ffffff",
|
|
}
|
|
}
|
|
},
|
|
{
|
|
type: "text",
|
|
label: "菏泽方向 ⇨",
|
|
x: width - 50,
|
|
y: height - 50,
|
|
attrs: {
|
|
text: {
|
|
fontSize: 12,
|
|
fill: "#7dd7fe",
|
|
}
|
|
}
|
|
},
|
|
{
|
|
type: "text",
|
|
label: "G3021德上高速",
|
|
x: width - 50,
|
|
y: height / 2 - 21,
|
|
attrs: {
|
|
text: {
|
|
fontSize: 12,
|
|
fill: "#ffffff",
|
|
}
|
|
}
|
|
},
|
|
{
|
|
type: "text",
|
|
label: "项目起点",
|
|
x: 270,
|
|
y: height / 2 - 50,
|
|
attrs: {
|
|
text: {
|
|
fontSize: 12,
|
|
fontFamily: "Arial Black",
|
|
fontWeight: 900,
|
|
fontStyle: "italic",
|
|
fill: "#ddc85a",
|
|
}
|
|
}
|
|
},
|
|
{
|
|
type: "text",
|
|
label: "K55+378.7",
|
|
x: 270,
|
|
y: height / 2 - 33,
|
|
attrs: {
|
|
text: {
|
|
fontSize: 12,
|
|
fontFamily: "Arial Black",
|
|
fontWeight: 900,
|
|
fontStyle: "italic",
|
|
fill: "#ddc85a",
|
|
}
|
|
}
|
|
},
|
|
{
|
|
type: "text",
|
|
label: "项目终点",
|
|
x: width - 220,
|
|
y: height / 2 - 50,
|
|
attrs: {
|
|
text: {
|
|
fontSize: 12,
|
|
fontFamily: "Arial Black",
|
|
fontWeight: 900,
|
|
fontStyle: "italic",
|
|
fill: "#ddc85a",
|
|
}
|
|
}
|
|
},
|
|
{
|
|
type: "text",
|
|
label: "K208+153.4",
|
|
x: width - 220,
|
|
y: height / 2 - 33,
|
|
attrs: {
|
|
text: {
|
|
fontSize: 12,
|
|
fontFamily: "Arial Black",
|
|
fontWeight: 900,
|
|
fontStyle: "italic",
|
|
fill: "#ddc85a",
|
|
}
|
|
}
|
|
},
|
|
],
|
|
};
|
|
const graph = new Graph({
|
|
container: content,
|
|
width,
|
|
height,
|
|
|
|
background: {
|
|
image: require("./images/bg.png"),
|
|
size: "100% 100%"
|
|
},
|
|
interacting: function (cellView) {
|
|
if (true) return { nodeMovable: false }
|
|
// return true;
|
|
},
|
|
});
|
|
this._graph = graph;
|
|
graph.on('node:mouseenter', mouseenterDebounceFunc);
|
|
graph.on('node:mouseleave', mouseleaveDebounceFunc);
|
|
graph.on('node:click', debounce(({ node }) => {
|
|
if (["custom-html"].indexOf(node.shape) >= 0) {
|
|
const extData = node.getData()?.extData;
|
|
if (extData) {
|
|
this.setMapZoomAndCenter(18, [extData.longitude, extData.latitude])
|
|
}
|
|
|
|
}
|
|
}, 0));
|
|
|
|
Shape.HTML.register({
|
|
shape: 'custom-html',
|
|
width: 160,
|
|
height: 80,
|
|
html(node) {
|
|
const data = node.getData();
|
|
const { shape, nowBg, src, length } = data;
|
|
const { height, width } = node.prop().size;
|
|
const div = document.createElement('div')
|
|
|
|
let marginHeight = (data.extData.direction === '3'?height*-.3:height*2.2)
|
|
if(data.length && data.extNode.length > 1){
|
|
let d1 = data.extNode.filter(x=>x.extData.direction === '1')
|
|
let d3 = data.extNode.filter(x=>x.extData.direction === '3')
|
|
if(d1.length > 0 && d3.length > 0){
|
|
marginHeight = (height)
|
|
}
|
|
}
|
|
|
|
|
|
if (shape === "singleNode-html") {
|
|
div.innerHTML = `
|
|
<div style="
|
|
background-image: url(${nowBg});
|
|
background-size: 100% 100%;
|
|
background-repeat: no-repeat;
|
|
width: ${width * 1.2}px;
|
|
height: ${height * 1.2}px;
|
|
margin-top:${marginHeight}px;
|
|
display: flex;
|
|
justify-content: center;
|
|
">
|
|
<img style="
|
|
width: ${width * 0.8}px;
|
|
height: ${height * 0.8}px;
|
|
margin-top: ${height * 0.1}px;
|
|
" src='${src}'
|
|
>
|
|
</div>
|
|
`;
|
|
} else if (shape === "multiNode-html") {
|
|
div.innerHTML = `
|
|
<div style="
|
|
background-image: url(${nowBg});
|
|
background-size: 100% 100%;
|
|
background-repeat: no-repeat;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: ${width * 1.2}px;
|
|
height: ${height * 1.2}px;
|
|
margin-top:${marginHeight}px;
|
|
padding-bottom: ${height * 0.1}px;
|
|
">
|
|
${length}
|
|
</div>
|
|
`;
|
|
}
|
|
return div
|
|
},
|
|
})
|
|
|
|
window.graphInstance = graph;
|
|
|
|
// 底图文字
|
|
graph.addNodes(baseData.nodes);
|
|
|
|
// 拥堵路段区域
|
|
// this.drawCongestionAreas(graph, 1404, 80);
|
|
|
|
const ratio = ((width - width * 0.08 * 2) / allActualDis); //减去俩侧空白区域 才是画布要计算的比例
|
|
window.canvasRatio = ratio;
|
|
window.canvasWidth = width;
|
|
window.offsetRatio = 0.0755;
|
|
|
|
// 收费站/服务区标签
|
|
this.list.forEach(item => this.allInstance += item.distance);
|
|
for (let index in this.list) {
|
|
const info = this.list[index];
|
|
info.distance = actualLocationList[index].intervalDistance * ratio;
|
|
await this.drawTag(info, graph);
|
|
}
|
|
//文字覆盖问题修复
|
|
graph.getCellById("K79+010_底部文字").translate(-10, 0)
|
|
graph.getCellById("K83+885_底部文字").translate(-10, 0);
|
|
graph.getCellById("K86+499_底部文字").translate(10, 0);
|
|
|
|
graph.getCellById("K114+405_底部文字").translate(-10, 0);
|
|
graph.getCellById("K117+878_底部文字").translate(10, 0);
|
|
|
|
graph.getCellById("K159+156_底部文字").translate(8, 0);
|
|
|
|
graph.getCellById("K155+652_底部文字").translate(-10, 0);
|
|
graph.getCellById("K190+495_底部文字").translate(10, 0);
|
|
|
|
},
|
|
async drayLine(text, graph, isFoot = false) {
|
|
const x = this.translateX + 141;
|
|
if (isFoot) {
|
|
graph.addNode({
|
|
...rect, x: x, y: 30, height: 161
|
|
});
|
|
} else {
|
|
graph.addNode({ ...rect, x: x, y: 30, height: 135, zIndex: 1 });
|
|
}
|
|
|
|
const textNode = {
|
|
label: text,
|
|
attrs: {
|
|
label: {
|
|
fontSize: 12,
|
|
fill: "#37B5D4",
|
|
fontWeight: 600
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isFoot) {
|
|
graph.addNode({ ...textNode, x: x, y: 22 })
|
|
// graph.fillText(text, 0, 54);
|
|
// graph.translate(0, 226);
|
|
graph.addNode({ ...textNode, x: x, y: 195 });
|
|
} else {
|
|
graph.addNode({ ...textNode, x: x, y: 22 });
|
|
}
|
|
},
|
|
async drawTag(info, graph) {
|
|
this.translateX += info.distance;
|
|
let type = "3";
|
|
if (info.name.indexOf("枢纽") !== -1) {
|
|
type = "0";
|
|
} else if (info.name.indexOf("服务区") !== -1) {
|
|
type = "2";
|
|
} else if (info.name.indexOf("停车区") !== -1) {
|
|
type = "1";
|
|
}
|
|
if (type === "0") {
|
|
await this.drayLine(info.line, graph, info.isFoot);
|
|
if (info.name === "东平湖枢纽") {
|
|
const r = -150;
|
|
const nodeLine = graph.addNode({ ...rect, shape: 'rect', x: 1205, y: 2, height: 85, zIndex: 1 });
|
|
nodeLine.rotate((r * Math.PI));
|
|
|
|
graph.addNode({
|
|
label: "S33济徐高速", x: 1275, y: 22, attrs: {
|
|
label: {
|
|
fontSize: 12,
|
|
fill: "#37B5D4",
|
|
fontWeight: 600
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
let y = 42 - (info.name.length - 5) * 10;
|
|
const imageNode = graph.addNode({
|
|
shape: 'image', imageUrl: require(`./images/${info.icon || `tag${type}`}.png`), x: this.translateX, y: this.translateY, width: 21, height: 117
|
|
});
|
|
imageNode.translate(width * 0.07, 0);
|
|
|
|
for (var i = 0; i < info.name.length; i++) { //
|
|
const imageLabelNode = graph.addNode({ label: info.name[i], x: this.translateX, y: i * 15, attrs: { text: { fill: "#ffffff", fontSize: 12 } } });
|
|
imageLabelNode.translate(width * window.offsetRatio, 50 + y);
|
|
}
|
|
|
|
// 修改文字位置
|
|
const buttomLabelNode = graph.addNode({ label: info.code, x: this.translateX, y: 175, attrs: { text: { fill: "#ffffff", fontSize: 10.5 } }, id: info.code + "_底部文字" });
|
|
buttomLabelNode.translate(width * window.offsetRatio, 0);
|
|
|
|
},
|
|
loadImage(url) {
|
|
return new Promise((resolve, reject) => {
|
|
const img = new Image();
|
|
img.setAttribute("crossOrigin", "anonymous");
|
|
img.src = url;
|
|
img.onload = () => {
|
|
// 当图像加载完成后进行resolve
|
|
resolve(img);
|
|
};
|
|
img.onerror = () => {
|
|
reject(new Error("图像加载失败"));
|
|
};
|
|
});
|
|
},
|
|
drawCongestionAreas(graph, x, y) {
|
|
// x = translateX * -1 + x;
|
|
// y = translateY * -1 + y;
|
|
const rectWidth = 160;
|
|
const rectHeight = 8;
|
|
|
|
graph.addNode({
|
|
...rect, x: x - 50, y: y, width: rectWidth, height: rectHeight, attrs: {
|
|
body: {
|
|
fill: {
|
|
type: 'linearGradient',
|
|
stops: [
|
|
{ offset: '0%', color: 'rgba(217,50,8,0)' },
|
|
{ offset: '27%', color: '#D73208' },
|
|
{ offset: '42%', color: '#D93208' },
|
|
{ offset: '81%', color: '#F5FF83' },
|
|
{ offset: '100%', color: 'rgba(215,50,8,0)' },
|
|
],
|
|
},
|
|
strokeWidth: 0
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.bg {
|
|
height: 100%;
|
|
width: 100%;
|
|
}
|
|
</style>
|
|
|