效果图:
源码:
<template>
<div class="qieMianTu">
<canvas id="canvas" width="900" height="800"></canvas>
<div style="border: 1px solid; width: 80px; padding: 5px" class="tuli">
<div :key="key" style="display: flex" v-for="(item, key) in chTypeColor">
<img width="28" :src="require('@/assets/images/' + item + '.png')" />
<span style="margin-left: 5px">{{ key }}</span>
</div>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
canvas: "",
ctx: "",
YkeyValue: {},
XkeyValue: {},
xLeft: 180, //x轴距离左边的距离
xPx: 800, //x轴的px长度
xLen: 0, //x轴数据的长度
xAxisLen: 0, //x轴的真正绘制长度
xSpacing: 0, //x轴刻度
xMinReal: 0, //x轴最小值
xOffset: 20, //x轴往右偏移量
yTop: 60, //y轴距离上方的值
yBottom: 20, //y轴距离下方的值
yPx: 500, //
yLen: 0, //y轴数据长度
yAxisLen: 0, //y轴的真正绘制长度
xSpacing: 0, //y轴刻度
yMinReal: 0, //y轴最小值
newData: [],
chTypeColor: [],
};
},
methods: {
//解析数据 确定x轴和y轴
parseData(data) {
let newData = [];
const compare = (property) => {
return (a, b) => {
var value1 = a[property];
var value2 = b[property];
return value1 - value2;
};
};
for (let key in data) {
if (data[key].length > 0) {
let obj = data[key];
obj.forEach((item) => {
newData.push({
xVal: item.point4528.x,
radius: item.radius,
floor: item.floor, //地面高程
height: item.height, //管线高程
dept: item.dept, //埋深
diam: item.diam, //管径
material: item.material, //材质
minLength: item.minLength, //道路边界线距离
category: key, //管类
});
});
}
}
newData.sort(compare("xVal"));
let minxVal = newData[0].xVal;
let maxxVal = newData[newData.length - 1].xVal;
newData.forEach((item) => {
item.xVal -= minxVal;
});
//确定X轴的最小值、最大值、刻度等
this.xLen = Math.ceil(maxxVal - minxVal) + 1;
console.log(this.xLen);
this.xAxisLen = this.xPx - this.xLeft;
this.xSpacing = (this.xAxisLen / this.xLen).toFixed(2);
console.log(this.xSpacing);
this.xMinReal = 0;
// console.log(newData);
//以上为x轴 数据
//确定Y轴的最小值、最大值、刻度等
newData.sort(compare("height"));
let minyVal = newData[0].height;
let maxyVal = newData[newData.length - 1].height;
//确定X轴的最小值、最大值、刻度等
this.yLen = Math.ceil(maxyVal - minyVal) + 1;
this.yAxisLen = this.yPx - this.yTop - this.yBottom;
this.ySpacing = (this.yAxisLen / this.yLen).toFixed(2);
this.yMinReal = minyVal < 0 ? -Math.ceil(Math.abs(minyVal)) : Math.floor(minyVal);
// console.log(newData, this.ySpacing);
this.newData = newData;
//以上为Y轴 数据
},
//画图 画y轴、X轴、网格、树木、地平线、中心线
drawCanvas() {
const _this = this;
_this.canvas = document.getElementById("canvas");
let ctx = _this.canvas.getContext("2d");
let PICWIDTH = _this.yTop,
VERTICAL_TICK_OFFSET = 15,
TICK_WIDTH = 6,
TICKS_LINEWIDTH = 0.5,
TICK_COLOR = "#4F4D98", //坐标轴颜色
AXIS_LINEWIDTH = 1,
AXIS_COLOR = "blue",
CIRCLE_WIDTH = 1,
CIRCLE_COLOR = "#9C5260",
LDRL_COLOR = "#808BA1",
TABLE_COLOR = "#000000";
// const dataTypeColor = {
// jsline: "#00FFFF", //给水
// wsline: "#4C2600", //污水
// ysline: "#997200", //雨水
// zyline: "#FF00FF", //中压
// dyline: "#FF00FF", //低压
// ldline: "#FF7F00", //照明
// };
const dataTypeColor = {
jsline: "#13227A", //给水
wsline: "#CCB6A1", //污水
ysline: "#5697FF", //雨水
zyline: "#D81E06", //中压
dyline: "#D4237A", //低压
ldline: "#ED7C30", //照明
};
const chTypeColor = {
给水: "jsline", //给水
污水: "wsline", //污水
雨水: "ysline", //雨水
中压: "zyline", //中压
低压: "dyline", //低压
照明: "ldline", //照明
};
this.chTypeColor = chTypeColor;
const textArr = [
{ key: "floor", name: "地面高程(米)" },
{ key: "height", name: "管线高程(米)" },
{ key: "dept", name: "埋深(米)" },
{ key: "diam", name: "管径(毫米)" },
{ key: "material", name: "管线材料" },
{ key: "minLength", name: "距道路边界线(米)" },
];
//绘制基本信息
drawInfo();
function drawInfo() {
// drawGrid();
drawVerticalMaxLine();
//绘制网格
function drawGrid(color = "lightgray", stepX = 10, stepY = 10) {
ctx.strokeStyle = color;
ctx.lineWidth = 0.5;
for (let i = stepX + 0.5; i < ctx.canvas.width; i += stepX) {
ctx.beginPath();
ctx.moveTo(i, 0);
ctx.lineTo(i, ctx.canvas.height);
ctx.stroke();
}
for (let i = stepY + 0.5; i < ctx.canvas.height; i += stepY) {
ctx.beginPath();
ctx.moveTo(0, i);
ctx.lineTo(ctx.canvas.width, i);
ctx.stroke();
}
}
//绘制地平线和树木
function drawVerticalMaxLine() {
ctx.strokeStyle = "#A1A3B2";
ctx.lineWidth = 1;
ctx.beginPath(_this.yTop);
ctx.moveTo(0, _this.yTop);
ctx.lineTo(_this.canvas.width, _this.yTop);
ctx.stroke();
ctx.fillStyle = "#6B6B91";
ctx.font = "9pt Calibri";
ctx.fillText("地平线", _this.canvas.width - 50, _this.yTop - 10);
ctx.stroke();
let newImg = new Image();
newImg.src = require("../assets/tree.png");
newImg.onload = () => {
ctx.drawImage(newImg, _this.canvas.width / 4, 0, PICWIDTH, PICWIDTH);
ctx.drawImage(
newImg,
(_this.canvas.width / 4) * 3 - PICWIDTH / 2,
0,
PICWIDTH,
PICWIDTH
);
};
}
}
//绘制y轴
drawAxis();
function drawAxis() {
ctx.save();
//绘制y轴
ctx.strokeStyle = AXIS_COLOR;
ctx.lineWidth = AXIS_LINEWIDTH;
ctx.beginPath();
ctx.moveTo(_this.xLeft, _this.yTop);
ctx.lineTo(_this.xLeft, _this.yPx - _this.yBottom);
ctx.stroke();
//绘制y轴刻度
ctx.lineWidth = TICKS_LINEWIDTH;
ctx.strokeStyle = TICK_COLOR;
//小刻度长度的临时变量
let j = _this.yLen;
for (let i = 0; i <= _this.yLen; i++) {
//画刻度尺
ctx.beginPath();
ctx.moveTo(_this.xLeft, _this.yPx - _this.yBottom - i * _this.ySpacing);
ctx.lineTo(
_this.xLeft + TICK_WIDTH,
_this.yPx - _this.yBottom - i * _this.ySpacing
);
ctx.stroke();
ctx.fillStyle = "red";
ctx.font = "16px Calibri";
ctx.fillText(
_this.yMinReal,
_this.xLeft - VERTICAL_TICK_OFFSET - 5,
_this.yPx - _this.yBottom - i * _this.ySpacing + 5
);
_this.YkeyValue[_this.yMinReal] =
_this.yPx - _this.yBottom - i * _this.ySpacing;
j--;
_this.yMinReal++;
ctx.stroke();
}
//画y轴的延长线
ctx.lineWidth = 1;
ctx.strokeStyle = TABLE_COLOR;
ctx.beginPath();
ctx.moveTo(_this.xLeft, _this.yPx - _this.yBottom);
ctx.lineTo(_this.xLeft, _this.canvas.height);
ctx.stroke();
ctx.restore();
//绘制x轴
// ctx.strokeStyle = AXIS_COLOR;
// ctx.lineWidth = AXIS_LINEWIDTH;
// ctx.beginPath();
// ctx.moveTo(_this.xLeft, _this.yPx - _this.yBottom);
// ctx.lineTo(_this.xPx, _this.yPx - _this.yBottom);
// ctx.stroke();
// ctx.lineWidth = TICKS_LINEWIDTH;
// ctx.strokeStyle = TICK_COLOR;
//小刻度长度的临时变量
for (let i = 0; i <= _this.xLen; i++) {
//画刻度尺和刻度
// ctx.beginPath();
// ctx.moveTo(_this.xLeft + i * _this.xSpacing, _this.yPx - _this.yBottom);
// ctx.lineTo(
// _this.xLeft + i * _this.xSpacing,
// _this.yPx - _this.yBottom - TICK_WIDTH
// );
// ctx.stroke();
// ctx.fillStyle = AXIS_COLOR;
// ctx.fillText(
// _this.xMinReal,
// _this.xLeft + i * _this.xSpacing,
// _this.yPx - _this.yBottom + VERTICAL_TICK_OFFSET
// );
// ctx.stroke();
_this.XkeyValue[_this.xMinReal] =
_this.xMinReal + i * _this.xSpacing + _this.xLeft;
j--;
_this.xMinReal++;
}
ctx.restore();
}
//绘制数据
drawData(_this.newData);
function drawData(data) {
function compute(value, spacing, keyValue, type = "Y") {
//判断y轴还是x轴
if (type == "Y") {
let key;
//判断正负 确定坐标轴的key值
if (value < 0) {
key = -Math.ceil(Math.abs(value));
} else {
key = Math.floor(value);
}
let a = ("" + value).split(".");
let b;
if (value < 0) {
if (a.length > 1) {
// console.log(a);
b = spacing * (1 - Number("0." + a[1]));
// console.log(1 - Number("0." + a[1]));
} else {
b = spacing * 0;
}
let c = keyValue[key];
let d = c - b;
return d;
} else {
if (a.length > 1) {
b = spacing * Number("0." + a[1]);
} else {
b = spacing * 0;
}
let c = keyValue[key];
let d = c - b;
return d;
}
} else {
// console.log(value, keyValue);
let key = Math.floor(value);
let a = ("" + value).split(".");
let b;
if (a.length > 1) {
b = spacing * Number("0." + a[1]);
} else {
b = spacing * 0;
}
let c = keyValue[key];
let d = c + b;
return d;
}
}
const RADIUS = 5;
ctx.strokeStyle = CIRCLE_COLOR;
ctx.lineWidth = CIRCLE_WIDTH;
//整体往右偏移量 20
//画圆
data.forEach((item) => {
let xAxisVal =
compute(item.xVal, _this.xSpacing, _this.XkeyValue, "X") + _this.xOffset,
yAxisVal = compute(item.height, _this.ySpacing, _this.YkeyValue, "Y");
//绘制道路边线
if (item.category == "LRDL") {
ctx.strokeStyle = LDRL_COLOR;
ctx.lineWidth = 1;
ctx.setLineDash([]);
ctx.beginPath();
ctx.moveTo(xAxisVal, _this.yPx);
ctx.lineTo(xAxisVal, _this.yTop);
ctx.stroke();
let newImg = new Image();
newImg.src = require("../assets/ludeng.png");
newImg.onload = () => {
ctx.drawImage(newImg, xAxisVal - 10, 0, 20, _this.yTop);
};
} else {
ctx.strokeStyle = dataTypeColor[item.category];
ctx.lineWidth = 1;
//画圆
// ctx.setLineDash([]);
// ctx.beginPath();
// ctx.arc(xAxisVal, yAxisVal, RADIUS, 0, 2 * Math.PI);
// ctx.stroke();
let linePng = new Image();
linePng.src = require(`@/assets/images/${item.category}.png`);
linePng.onload = () => {
ctx.drawImage(linePng, xAxisVal - 15, yAxisVal - 25, 28, 28);
};
//画圆的延伸虚线
ctx.setLineDash([5]);
ctx.beginPath();
ctx.moveTo(xAxisVal, _this.yPx);
// ctx.moveTo(xAxisVal, _this.yPx - _this.yBottom);
ctx.lineTo(xAxisVal, yAxisVal);
ctx.stroke();
//画圆的延伸实线
ctx.strokeStyle = "#000000";
ctx.setLineDash([]);
ctx.beginPath();
ctx.moveTo(xAxisVal, _this.yPx);
// ctx.moveTo(xAxisVal, _this.yPx - _this.yBottom);
ctx.lineTo(xAxisVal, _this.canvas.height);
ctx.stroke();
const dHeight = (_this.canvas.height - _this.yPx) / 6;
for (let i = 0; i < textArr.length; i++) {
ctx.save();
ctx.fillStyle = TABLE_COLOR;
ctx.translate(xAxisVal + 20, _this.yPx + dHeight * (i + 1));
ctx.rotate(-(Math.PI / 180) * 90);
ctx.font = "16px Calibri";
if (!Number(item[textArr[i].key])) {
ctx.font = "14px Calibri";
ctx.fillText(item[textArr[i].key], 0, 0);
} else {
ctx.fillText(
parseInt(item[textArr[i].key]) == parseFloat(item[textArr[i].key])
? item[textArr[i].key]
: item[textArr[i].key].toFixed(2),
10,
0
);
}
ctx.restore();
}
//填文字
}
});
}
//画表格
drawTable();
function drawTable() {
const dHeight = (_this.canvas.height - _this.yPx) / 6;
//画文字
//画线
for (let i = 0; i < 7; i++) {
let h = _this.yPx + dHeight * i;
ctx.strokeStyle = TABLE_COLOR;
ctx.lineWidth = 1;
ctx.setLineDash([]);
ctx.beginPath();
ctx.moveTo(0, h);
ctx.lineTo(_this.canvas.width, h);
ctx.stroke();
}
//画文字
for (let i = 0; i < 6; i++) {
let h = _this.yPx + dHeight * i;
ctx.fillStyle = TABLE_COLOR;
ctx.font = "20px Calibri";
ctx.fillText(textArr[i].name, 0, h + dHeight / 2);
}
//左侧
ctx.setLineDash([]);
ctx.beginPath();
ctx.moveTo(0, _this.yPx);
ctx.lineTo(0, _this.canvas.height);
ctx.stroke();
//右侧
ctx.setLineDash([]);
ctx.beginPath();
ctx.moveTo(_this.canvas.width, _this.yPx);
ctx.lineTo(_this.canvas.width, _this.canvas.height);
ctx.stroke();
}
},
},
created() {
// const url = `http://192.168.1.155:9111/admin/system/lineAnalysis/crossSection?x1=119.96998056486377&y1=31.811923664468853&x2=119.96993764951873&y2=31.811215561275713&srid=4490`;
const url = `http://192.168.1.155:9111/admin/system/lineAnalysis/crossSection?x1=119.95749219945752&y1=31.803581994276936&x2=119.95781674675438&y2=31.80355248997722&srid=4490`;
axios
.post(url)
.then((response) => {
let data = response.data.data;
this.parseData(data);
})
.catch((error) => {
console.log(error);
});
},
mounted() {
setTimeout(() => {
this.drawCanvas();
}, 1000);
},
};
</script>
<style lang="css">
.qieMianTu {
width: 100%;
height: 100%;
position: relative;
}
#canvas {
/* position: absolute;
transform: translate(0%, -50%);
left: 50%;
top: 50%; */
border: 1px solid #d3d3d3;
}
.tuli {
border: 1px solid;
width: 60px;
padding: 5px;
position: absolute;
top: 100px;
left: 10px;
}
</style>