Browse Source

feat x6重构底部canvas & 修复文字覆盖问题

wangqin
qingzhengli 9 months ago
parent
commit
45be9fd2a2
  1. 1
      ruoyi-ui/package.json
  2. 331
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/Thumbnail/index.vue
  3. 7
      ruoyi-ui/vue.config.js

1
ruoyi-ui/package.json

@ -38,6 +38,7 @@
}, },
"dependencies": { "dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1", "@amap/amap-jsapi-loader": "^1.0.1",
"@antv/x6": "^2.18.1",
"@jiaminghi/data-view": "^2.10.0", "@jiaminghi/data-view": "^2.10.0",
"@riophae/vue-treeselect": "0.4.0", "@riophae/vue-treeselect": "0.4.0",
"@vue/composition-api": "^1.7.1", "@vue/composition-api": "^1.7.1",

331
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/Thumbnail/index.vue

@ -3,99 +3,220 @@
</template> </template>
<script> <script>
import { getScaleByActualData } from "./utils"
import { onceObserver } from "@screen/utils/resizeObserver"; import { onceObserver } from "@screen/utils/resizeObserver";
import Vue from "vue"; import Vue from "vue";
import { Graph } from '@antv/x6'
import { actualLocationList, canvasList } from "./data.js";
function setFont(size, bold = "normal", family = "微软雅黑") { function setFont(size, bold = "normal", family = "微软雅黑") {
return `${bold} ${size}px ${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 { export default {
name: "Thumbnail", name: "Thumbnail",
data() { data() {
return { return {
list: getScaleByActualData(), list: canvasList, // *canvasItem.distance
translateX: 0,
translateY: 50,
allInstance: 0
}; };
}, },
mounted() { mounted() {
onceObserver.call(this, this.$refs.ThumbnailRef, () => { this.mapInit();
this.$refs.ThumbnailRef.innerHTML = null; // onceObserver.call(this, this.$refs.ThumbnailRef, () => {
this.mapInit(); // this.$refs.ThumbnailRef.innerHTML = null;
}) // this.translateX = 0,
// this.translateY = 50,
// this.allInstance = 0
// this.mapInit();
// });
}, },
methods: { methods: {
async mapInit() { async mapInit() {
const content = this.$refs.ThumbnailRef; 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; this.drawCongestionAreas(graph, 1404, 80);
const height = content.clientHeight;
const zoom = 3; this.list.forEach(item => this.allInstance += item.distance);
const canvas = document.createElement("canvas"); for (let index in this.list) {
canvas.style.width = width + "px"; const info = this.list[index];
canvas.style.height = height + "px"; const ratio = ((width - width * 0.08 * 2) / actualDis); //
const w = width * zoom; info.distance = actualLocationList[index].intervalDistance * ratio;
const h = height * zoom; await this.drawTag(info, graph);
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);
} }
//
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) { async drayLine(text, graph, isFoot = false) {
ctx.setLineDash([4 * zoom, 4 * zoom]); const x = this.translateX + 141;
ctx.strokeStyle = "#37B5D4";
ctx.lineWidth = 6;
if (isFoot) { if (isFoot) {
ctx.translate(0, 12 * zoom); graph.addNode({
ctx.strokeRect(0, 0, 1, 161 * zoom); ...rect, x: x, y: 30, height: 161
ctx.translate(0, -12 * zoom); });
} else { } else {
ctx.strokeRect(0, 0, 1, 135 * zoom); graph.addNode({ ...rect, x: x, y: 30, height: 135, zIndex: 1 });
} }
ctx.fillStyle = "#37B5D4"; const textNode = {
ctx.translate(0, -16 * zoom); label: text,
attrs: {
label: {
fontSize: 12,
fill: "#37B5D4",
fontWeight: 600
}
}
}
if (isFoot) { if (isFoot) {
ctx.fillText(text, 0, 54); graph.addNode({ ...textNode, x: x, y: 22 })
ctx.translate(0, 226 * zoom); // graph.fillText(text, 0, 54);
ctx.fillText(text, 0, -90); // graph.translate(0, 226);
graph.addNode({ ...textNode, x: x, y: 195 });
} else { } 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"; let type = "3";
if (info.name.indexOf("枢纽") !== -1) { if (info.name.indexOf("枢纽") !== -1) {
type = "0"; type = "0";
@ -105,40 +226,38 @@ export default {
type = "1"; type = "1";
} }
if (type === "0") { if (type === "0") {
ctx.translate(info.distance * zoom, -188 * zoom); await this.drayLine(info.line, graph, info.isFoot);
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);
}
if (info.name === "东平湖枢纽") { if (info.name === "东平湖枢纽") {
const r = -110; const r = -150;
ctx.rotate((r * Math.PI) / 180); const nodeLine = graph.addNode({ ...rect, shape: 'rect', x: 1205, y: 2, height: 85, zIndex: 1 });
ctx.strokeRect(-15 * zoom, 0, 1, 90 * zoom); nodeLine.rotate((r * Math.PI));
ctx.rotate((r * Math.PI) / -180);
ctx.fillText("S33济徐高速", 124 * zoom, -27 * zoom); 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; let y = 42 - (info.name.length - 5) * 10;
ctx.fillStyle = "#ffffff"; const imageNode = graph.addNode({
ctx.font = setFont(12 * zoom); shape: 'image', imageUrl: require(`./images/${info.icon || `tag${type}`}.png`), x: this.translateX, y: this.translateY, width: 21, height: 117
var img = await this.loadImage(require(`./images/${info.icon || `tag${type}`}.png`)); });
ctx.drawImage(img, 0, 0, 21 * zoom, 117 * zoom); imageNode.translate(width * 0.07, 0);
ctx.translate(11.1 * zoom, y * zoom);
for (var i = 0; i < info.name.length; i++) { 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) { loadImage(url) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -154,24 +273,30 @@ export default {
}; };
}); });
}, },
drawCongestionAreas(ctx, x, y, zoom) { drawCongestionAreas(graph, x, y) {
const { e: translateX, f: translateY } = ctx.getTransform(); // x = translateX * -1 + x;
x = translateX * -1 + x * zoom; // y = translateY * -1 + y;
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)');
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
}
}
});
} }
}, },
}; };

7
ruoyi-ui/vue.config.js

@ -26,6 +26,7 @@ module.exports = {
lintOnSave: process.env.NODE_ENV === "development", lintOnSave: process.env.NODE_ENV === "development",
// 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。 // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
productionSourceMap: false, productionSourceMap: false,
transpileDependencies: ["ml-matrix"], //默认情况下为[] babel-loader 忽略其中的所有文件 node_modules
// webpack-dev-server 相关配置 // webpack-dev-server 相关配置
devServer: { devServer: {
host: "0.0.0.0", host: "0.0.0.0",
@ -41,7 +42,7 @@ module.exports = {
// target: `http://192.168.0.194:8080`, // target: `http://192.168.0.194:8080`,
// target: `http://10.0.81.201:8080`, // target: `http://10.0.81.201:8080`,
// target: `http://10.168.73.36:8080`, // 周乐 // target: `http://10.168.73.36:8080`, // 周乐
// target: `http://10.168.77.209:8080`, // 刘朋 // target: `http://10.168.77.209:8087`, // 刘朋
// target: `http://10.168.66.196:8080`, //刘文阁 // target: `http://10.168.66.196:8080`, //刘文阁
// target: `http://10.168.56.206:8087`, //孟 // target: `http://10.168.56.206:8087`, //孟
// target: `http://10.168.78.135:8087`, //孟 // target: `http://10.168.78.135:8087`, //孟
@ -50,8 +51,8 @@ module.exports = {
// target: `http://10.0.81.204:8087`, //现场后台 刘文阁 // target: `http://10.0.81.204:8087`, //现场后台 刘文阁
// target: `http://10.168.69.255:8087`, //正晨后台 连现场物联 刘文阁 // target: `http://10.168.69.255:8087`, //正晨后台 连现场物联 刘文阁
// target: `http://10.168.78.135:8087`, //王钦 // target: `http://10.168.78.135:8087`, //王钦
target: `http://10.168.66.196:8087`, //正晨后台 连现场物联 刘文阁2 // target: `http://10.168.66.196:8087`, //正晨后台 连现场物联 刘文阁2
// target: `http://10.168.68.42:8087`, //王思祥 target: `http://10.168.68.42:8087`, //王思祥
changeOrigin: true, changeOrigin: true,
pathRewrite: { pathRewrite: {
["^" + process.env.VUE_APP_BASE_API]: "", ["^" + process.env.VUE_APP_BASE_API]: "",

Loading…
Cancel
Save