分享Canvas画横断面图的vue源码

效果图:

 

源码:

<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>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值