|
|
@ -3,99 +3,220 @@ |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import { getScaleByActualData } from "./utils" |
|
|
|
import { onceObserver } from "@screen/utils/resizeObserver"; |
|
|
|
import Vue from "vue"; |
|
|
|
import { Graph } from '@antv/x6' |
|
|
|
|
|
|
|
import { actualLocationList, canvasList } from "./data.js"; |
|
|
|
|
|
|
|
function setFont(size, bold = "normal", family = "微软雅黑") { |
|
|
|
return `${bold} ${size}px ${family}`; |
|
|
|
} |
|
|
|
let width, height; |
|
|
|
const actualDis = 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: getScaleByActualData(), |
|
|
|
list: canvasList, //计算真实距离与画布距离的比例 *节点真实距离作为canvasItem.distance的值 |
|
|
|
translateX: 0, |
|
|
|
translateY: 50, |
|
|
|
allInstance: 0 |
|
|
|
}; |
|
|
|
}, |
|
|
|
|
|
|
|
mounted() { |
|
|
|
onceObserver.call(this, this.$refs.ThumbnailRef, () => { |
|
|
|
this.$refs.ThumbnailRef.innerHTML = null; |
|
|
|
this.mapInit(); |
|
|
|
}) |
|
|
|
this.mapInit(); |
|
|
|
// onceObserver.call(this, this.$refs.ThumbnailRef, () => { |
|
|
|
// this.$refs.ThumbnailRef.innerHTML = null; |
|
|
|
// this.translateX = 0, |
|
|
|
// this.translateY = 50, |
|
|
|
// this.allInstance = 0 |
|
|
|
// this.mapInit(); |
|
|
|
// }); |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
async mapInit() { |
|
|
|
const content = this.$refs.ThumbnailRef; |
|
|
|
width = content.clientWidth; |
|
|
|
height = content.clientHeight; |
|
|
|
const baseData = { |
|
|
|
nodes: [ |
|
|
|
{ |
|
|
|
type: "text", |
|
|
|
label: "G2001济南绕城高速", |
|
|
|
x: 66, |
|
|
|
y: height / 2 - 21, |
|
|
|
attrs: { |
|
|
|
text: { |
|
|
|
fontSize: 12, |
|
|
|
fill: "#ffffff", |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
{ |
|
|
|
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; |
|
|
|
}, |
|
|
|
}); |
|
|
|
Vue.prototype.graphInstance = graph; |
|
|
|
baseData.nodes.forEach(node => { |
|
|
|
graph.addNode(node) |
|
|
|
}); |
|
|
|
|
|
|
|
const width = content.clientWidth; |
|
|
|
const height = content.clientHeight; |
|
|
|
const zoom = 3; |
|
|
|
const canvas = document.createElement("canvas"); |
|
|
|
canvas.style.width = width + "px"; |
|
|
|
canvas.style.height = height + "px"; |
|
|
|
const w = width * zoom; |
|
|
|
const h = height * zoom; |
|
|
|
canvas.width = w; |
|
|
|
canvas.height = h; |
|
|
|
content.appendChild(canvas); |
|
|
|
|
|
|
|
const ctx = canvas.getContext("2d"); |
|
|
|
Vue.prototype.canvasCtx = ctx; |
|
|
|
ctx.textAlign = "center"; |
|
|
|
ctx.textBaseline = "middle"; |
|
|
|
var imgbg = await this.loadImage(require("./images/bg.png")); |
|
|
|
ctx.drawImage(imgbg, 0, 0, w, h); |
|
|
|
ctx.font = setFont(12 * zoom); |
|
|
|
ctx.fillStyle = "#ffffff"; |
|
|
|
ctx.fillText("G2001济南绕城高速", 66 * zoom, h / 2 - 21 * zoom); |
|
|
|
ctx.fillText("G3021德上高速", w - 50 * zoom, h / 2 - 21 * zoom); |
|
|
|
|
|
|
|
ctx.font = setFont(12 * zoom, "italic 900", "Arial Black"); |
|
|
|
|
|
|
|
ctx.fillStyle = "#ddc85a"; |
|
|
|
ctx.fillText("项目起点", 270 * zoom, h / 2 - 50 * zoom); |
|
|
|
ctx.fillText("K55+378.7", 270 * zoom, h / 2 - 33 * zoom); |
|
|
|
ctx.fillText("项目终点", w - 210 * zoom, h / 2 - 50 * zoom); |
|
|
|
ctx.fillText("K208+153.4", w - 210 * zoom, h / 2 - 33 * zoom); |
|
|
|
|
|
|
|
ctx.font = setFont(12 * zoom); |
|
|
|
|
|
|
|
// 修改 位置 |
|
|
|
ctx.translate(-25 * zoom, 208 * zoom); |
|
|
|
|
|
|
|
this.drawCongestionAreas(ctx, 1404, 80, zoom) |
|
|
|
// this.drawCongestionAreas(ctx, 1365, 150, zoom) |
|
|
|
|
|
|
|
for (let i of this.list) { |
|
|
|
await this.drawTag(i, zoom, ctx); |
|
|
|
this.drawCongestionAreas(graph, 1404, 80); |
|
|
|
|
|
|
|
this.list.forEach(item => this.allInstance += item.distance); |
|
|
|
for (let index in this.list) { |
|
|
|
const info = this.list[index]; |
|
|
|
const ratio = ((width - width * 0.08 * 2) / actualDis); //减去俩侧空白区域 才是画布要计算的比例 |
|
|
|
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(zoom, text, ctx, isFoot = false) { |
|
|
|
ctx.setLineDash([4 * zoom, 4 * zoom]); |
|
|
|
ctx.strokeStyle = "#37B5D4"; |
|
|
|
ctx.lineWidth = 6; |
|
|
|
async drayLine(text, graph, isFoot = false) { |
|
|
|
const x = this.translateX + 141; |
|
|
|
if (isFoot) { |
|
|
|
ctx.translate(0, 12 * zoom); |
|
|
|
ctx.strokeRect(0, 0, 1, 161 * zoom); |
|
|
|
ctx.translate(0, -12 * zoom); |
|
|
|
graph.addNode({ |
|
|
|
...rect, x: x, y: 30, height: 161 |
|
|
|
}); |
|
|
|
} else { |
|
|
|
ctx.strokeRect(0, 0, 1, 135 * zoom); |
|
|
|
graph.addNode({ ...rect, x: x, y: 30, height: 135, zIndex: 1 }); |
|
|
|
} |
|
|
|
|
|
|
|
ctx.fillStyle = "#37B5D4"; |
|
|
|
ctx.translate(0, -16 * zoom); |
|
|
|
const textNode = { |
|
|
|
label: text, |
|
|
|
attrs: { |
|
|
|
label: { |
|
|
|
fontSize: 12, |
|
|
|
fill: "#37B5D4", |
|
|
|
fontWeight: 600 |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (isFoot) { |
|
|
|
ctx.fillText(text, 0, 54); |
|
|
|
ctx.translate(0, 226 * zoom); |
|
|
|
ctx.fillText(text, 0, -90); |
|
|
|
graph.addNode({ ...textNode, x: x, y: 22 }) |
|
|
|
// graph.fillText(text, 0, 54); |
|
|
|
// graph.translate(0, 226); |
|
|
|
graph.addNode({ ...textNode, x: x, y: 195 }); |
|
|
|
} else { |
|
|
|
ctx.fillText(text, 0, 18); |
|
|
|
graph.addNode({ ...textNode, x: x, y: 22 }); |
|
|
|
} |
|
|
|
}, |
|
|
|
async drawTag(info, zoom, ctx) { |
|
|
|
async drawTag(info, graph) { |
|
|
|
this.translateX += info.distance; |
|
|
|
let type = "3"; |
|
|
|
if (info.name.indexOf("枢纽") !== -1) { |
|
|
|
type = "0"; |
|
|
@ -105,40 +226,38 @@ export default { |
|
|
|
type = "1"; |
|
|
|
} |
|
|
|
if (type === "0") { |
|
|
|
ctx.translate(info.distance * zoom, -188 * zoom); |
|
|
|
ctx.font = setFont(12 * zoom, "600"); |
|
|
|
await this.drayLine(zoom, info.line, ctx, info.isFoot); |
|
|
|
if (info.isFoot) { |
|
|
|
ctx.translate(-10 * zoom, -180 * zoom); |
|
|
|
} else { |
|
|
|
ctx.translate(-10 * zoom, 35 * zoom); |
|
|
|
} |
|
|
|
await this.drayLine(info.line, graph, info.isFoot); |
|
|
|
if (info.name === "东平湖枢纽") { |
|
|
|
const r = -110; |
|
|
|
ctx.rotate((r * Math.PI) / 180); |
|
|
|
ctx.strokeRect(-15 * zoom, 0, 1, 90 * zoom); |
|
|
|
ctx.rotate((r * Math.PI) / -180); |
|
|
|
ctx.fillText("S33济徐高速", 124 * zoom, -27 * zoom); |
|
|
|
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 |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
} else { |
|
|
|
ctx.translate(info.distance * zoom, -169 * zoom); |
|
|
|
} |
|
|
|
let y = 42 - (info.name.length - 5) * 10; |
|
|
|
ctx.fillStyle = "#ffffff"; |
|
|
|
ctx.font = setFont(12 * zoom); |
|
|
|
var img = await this.loadImage(require(`./images/${info.icon || `tag${type}`}.png`)); |
|
|
|
ctx.drawImage(img, 0, 0, 21 * zoom, 117 * zoom); |
|
|
|
ctx.translate(11.1 * zoom, y * zoom); |
|
|
|
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++) { |
|
|
|
ctx.fillText(info.name[i], 0, i * 15 * zoom); |
|
|
|
const imageLabelNode = graph.addNode({ label: info.name[i], x: this.translateX, y: i * 15, attrs: { text: { fill: "#ffffff", fontSize: 12 } } }); |
|
|
|
imageLabelNode.translate(width * 0.0755, 50 + y); |
|
|
|
} |
|
|
|
|
|
|
|
ctx.translate(0, (169 - y) * zoom); |
|
|
|
ctx.font = setFont(10.5 * zoom); |
|
|
|
|
|
|
|
// 修改文字位置 |
|
|
|
ctx.fillText(info.code, 0, -132); |
|
|
|
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 * 0.0755, 0); |
|
|
|
|
|
|
|
}, |
|
|
|
loadImage(url) { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
@ -154,24 +273,30 @@ export default { |
|
|
|
}; |
|
|
|
}); |
|
|
|
}, |
|
|
|
drawCongestionAreas(ctx, x, y, zoom) { |
|
|
|
const { e: translateX, f: translateY } = ctx.getTransform(); |
|
|
|
x = translateX * -1 + x * zoom; |
|
|
|
y = translateY * -1 + y * zoom; |
|
|
|
|
|
|
|
const rectWidth = 180 * zoom; |
|
|
|
const rectHeight = 8 * zoom; |
|
|
|
|
|
|
|
const grad = ctx.createLinearGradient(x, 0, x + rectWidth, 0); |
|
|
|
grad.addColorStop(0, 'rgba(217,50,8,0)'); |
|
|
|
grad.addColorStop(0.27, '#D73208'); |
|
|
|
grad.addColorStop(0.42, '#D93208'); |
|
|
|
grad.addColorStop(0.81, '#F5FF83'); |
|
|
|
grad.addColorStop(1, 'rgba(215,50,8,0)'); |
|
|
|
drawCongestionAreas(graph, x, y) { |
|
|
|
// x = translateX * -1 + x; |
|
|
|
// y = translateY * -1 + y; |
|
|
|
|
|
|
|
ctx.fillStyle = grad; |
|
|
|
const rectWidth = 160; |
|
|
|
const rectHeight = 8; |
|
|
|
|
|
|
|
ctx.fillRect(x, y, rectWidth, rectHeight); |
|
|
|
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 |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
}, |
|
|
|
}; |
|
|
|