vue3标注ailabel

<template>
  <div class="label_main">
    <div class="labek_operation">
      <div class="button-wrap">
        <el-button type="primary" class="label_btn" @click="restoration()">图像居中</el-button>
        <el-button type="primary" class="label_btn" @click="zoomIn()">图像放大</el-button>
        <el-button type="primary" class="label_btn" @click="zoomOut()">图像缩小</el-button>
        <el-button type="primary" class="label_btn" @click="setMode('PAN')">移动</el-button>
        <!-- <el-button type="primary" class="label_btn" @click="setMode('MARKER')" >注记</el-button> -->
        <el-button type="primary" class="label_btn" @click="setMode('POINT')"></el-button>
        <el-button type="primary" class="label_btn" @click="setMode('LINE')">线段</el-button>
        <!-- <el-button type="primary" class="label_btn" @click="setMode('POLYLINE')" >多段线</el-button> -->
        <el-button type="primary" class="label_btn" @click="setMode('CIRCLE')"></el-button>
        <el-button type="primary" class="label_btn" @click="setMode('RECT')">矩形</el-button>
        <el-button type="primary" class="label_btn" @click="setMode('POLYGON')">多边形</el-button>
        <!-- <el-button type="primary" class="label_btn" @click="Fill()" >填充</el-button> -->
        <!-- <el-button type="primary" class="label_btn" @click="Revoke()">撤销</el-button> -->
        <el-button type="primary" class="label_btn" @click="getFeatures()">获取标注数据</el-button>
        <!-- <el-button type="primary" class="label_btn" @click="setMode('DRAWMASK')" >涂抹</el-button> -->
        <!-- <el-button type="primary" class="label_btn" @click="setMode('CLEARMASK')" >擦除</el-button> -->
        <!-- <el-button type="primary" class="label_btn" @click="getRle()">获取rle数据</el-button>   -->
        <!-- <el-button type="primary" class="label_btn" @click="setGraph()" >手动设置坐标</el-button> -->
      </div>
    </div>
    <div class="main_map" ref="main_map">
    </div>
  </div>
</template>
 
<script>
import AILabel from "ailabel";
import { reactive, toRefs, onBeforeMount, onMounted, watch, onBeforeUnmount, ref } from 'vue'
// 导入toRaw函数
import { toRaw } from '@vue/reactivity';
import { ElMessageBox, ElMessage } from 'element-plus';

export default {
  name: "LabelTemplate",
  props: ['imgUrl', 'divId'],
  setup (props, context) {
    //动态添加视图
    const main_map = ref(null)
    const mountEle = document.createElement("div");
    mountEle.id = props.divId
    mountEle.style.overflow = 'hidden';
    mountEle.style.position = 'relative';
    mountEle.style.height = '450px';
    mountEle.style.width = '650px';
    mountEle.style.border = '1px dashed #ccc';

    const state = reactive({
      imgUrl: props.imgUrl,
      divId: props.divId,
      drawingStyle: {},
      mode: "",
      itemName: "",
      editId: "", //待填充图形id
      deleteIconId: "delete01",
      gMap: null, //AILabel实例
      gFirstFeatureLayer: null, //矢量图层实例(矩形,多边形等矢量)
      allFeatures: null, //所有features
      gFirstImageLayer: null, //图层
      nHeight: '',
      nWidth: '',
      centerObj: {},
      gFirstTextLayer: null, //文本
      gFirstMaskLayer : null, //涂抹层
    })

    onBeforeMount(() => {
    })
    onMounted(() => {
      main_map.value.appendChild(mountEle)
      //获取图片原宽高
      getImageWH()
      //初始化实例
      initMap()
      //添加事件
      addEvent();
      //图片层添加
      setGFirstImageLayer()
      //添加矢量图层
      setGFirstFeatureLayer()
      // 添加 text 文本图层,用于展示文本
      setGFirstTextLayer()
      //初始化涂抹层
      gFirstMaskLayer()
     

      // AILabel.Map设置绘制过程中十字丝关闭
      // gMap.disableDrawingCrosshair();

      // 禁用绘制时鼠标达到边界外自动平移
      // gMap.disablePanWhenDrawing();

      //禁用绘制时可鼠标滑轮缩放
      // gMap.disableZoomWhenDrawing()

      window.onresize = function () {
        state.gMap && state.gMap.resize();
      };
    })
    onBeforeUnmount(() => {
      state.gMap.destroy();
    })
    watch(() => state.mode, (newVal, oldVal) => {
      console.log('新的值mode:', newVal, '旧的mode:', oldVal,);
      state.gMap.setMode(newVal);
      setDrawingStyle(newVal);
    })
    watch(() => props.imgUrl, (newVal, oldVal) => {
      console.log('新的值imgUrl:', newVal, '旧的imgUrl:', oldVal,);
      state.imgUrl = newVal
      //获取图片原宽高
      getImageWH()
      //重新设置图片
      setGFirstImageLayer()
      //添加矢量图层
      setGFirstFeatureLayer()
      // 添加 text 文本图层,用于展示文本
      setGFirstTextLayer()
      //刷新map
      state.gMap.refresh();
    })
    // 初始化实例
    const initMap = () => {
      const gMap = new AILabel.Map(state.divId, {
        center: state.centerObj, // 为了让图片居中
        zoom: 500, //初始缩放级别
        mode: "PAN", // 绘制线段
        refreshDelayWhenZooming: true, // 缩放时是否允许刷新延时,性能更优
        zoomWhenDrawing: false, //绘制时可滑轮缩放
        panWhenDrawing: true, //绘制时可到边界外自动平移
        zoomWheelRatio: 5, // 控制滑轮缩放缩率[0, 10), 值越小,则缩放越快,反之越慢
        withHotKeys: true, // 关闭快捷键
      });
      state.gMap = gMap;
    }
    // 初始样式
    const setDrawingStyle = (mode) => {
      let drawingStyle = {};
      switch (mode) {
        //平移
        case "PAN": {
          break;
        }
        //注记
        case "MARKER": {
          // 忽略
          break;
        }
        //点
        case "POINT": {
          state.drawingStyle = { fillStyle: "#FF8C00" };
          state.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //圆
        case "CIRCLE": {
          state.drawingStyle = {
            fillStyle: "#87CEFF",
            fill: true, //是否填充 
            strokeStyle: "#87CEFF",
            globalAlpha: 0.3,
            lineWidth: 2,
          };
          state.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //线段
        case "LINE": {
          state.drawingStyle = {
            strokeStyle: "#BA55D3",
            lineJoin: "round",
            lineCap: "round",
            lineWidth: 10,
            arrow: false,
          };
          state.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //多线段
        case "POLYLINE": {
          state.drawingStyle = {
            strokeStyle: "#FF1493",
            lineJoin: "round",
            lineCap: "round",
            lineWidth: 10,
          };
          state.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //矩形
        case "RECT": {
          state.drawingStyle = {
            strokeStyle: "#0f0",
            lineWidth: 1,
            fillStyle: '#00f',
            fill: true, //是否填充 
            globalAlpha: 0.3,
            stroke: true,
          };
          state.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //多边形
        case "POLYGON": {
          state.drawingStyle = {
            strokeStyle: "#0099CC", //边框颜色
            fill: true, //是否填充
            fillStyle: "#FF6666", //填充色
            globalAlpha: 0.3,
            lineWidth: 3,
            stroke: true,
          };
          state.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //涂抹
        case "DRAWMASK": {
          state.drawingStyle = {
            strokeStyle: "rgba(255, 0, 0, .5)",
            fillStyle: "#00f",
            lineWidth: 50,
          };
          state.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //擦除
        case "CLEARMASK": {
          state.drawingStyle = { fillStyle: "#00f", lineWidth: 30 };
          state.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        default:
          break;
      }
    }
    //添加 text 文本图层,用于展示文本
    const setGFirstTextLayer = () => {
      const gFirstTextLayer = new AILabel.Layer.Text(
        'first-layer-text', // id
        { name: '第一个文本图层' }, // props
        { zIndex: 12, opacity: 1 } // style
      )
      state.gMap.addLayer(gFirstTextLayer)
      state.gFirstTextLayer = gFirstTextLayer
    }
    //添加 涂抹层
    const setGFirstMaskLayer = () => {
      const gFirstMaskLayer = new AILabel.Layer.Mask(
            'first-layer-mask', // id
            {name: '第一个涂抹图层'}, // props
            {zIndex: 11, opacity: .5} // style
        );
      state.gMap.addLayer(gFirstMaskLayer);
      state.gFirstMaskLayer = gFirstMaskLayer 
    }
    //添加矢量图层
    const setGFirstFeatureLayer = () => {
      // 添加矢量图层
      const gFirstFeatureLayer = new AILabel.Layer.Feature(
        "first-layer-feature", // id
        { name: "第一个矢量图层" }, // props
        { zIndex: 10 } // style
      );
      state.gFirstFeatureLayer = gFirstFeatureLayer;
      state.gMap.addLayer(gFirstFeatureLayer);
    }
    // 图片层添加
    const setGFirstImageLayer = () => {
      // 图片层添加
      const gFirstImageLayer = new AILabel.Layer.Image(
        "first-layer-image", // id
        {
          src: state.imgUrl,
          width: state.nWidth,
          height: state.nHeight,
          crossOrigin: false, // 如果跨域图片,需要设置为true
          position: {
            // 左上角相对中心点偏移量
            x: 0,
            y: 0,
          },
          // 网格
          grid: {
            // 3 * 3
            // columns: [{ color: "#9370DB" }, { color: "#FF6347" }],
            // rows: [{ color: "#9370DB" }, { color: "#FF6347" }],
          },
        }, // imageInfo
        { name: "第一个图片图层" }, // props
        { zIndex: 5 } // style
      );

      // 添加到gMap对象
      state.gMap.addLayer(gFirstImageLayer);
      state.gFirstImageLayer = gFirstImageLayer
    }

    //获取原图宽度高度
    const getImageWH = () => {
      let nWidth = 500
      let nHeight = 300
      let centerObj = { x: 250, y: 150 }
      // 创建对象
      var img = new Image()
      // 改变图片的src
      img.src = state.imgUrl
      //根据原图宽高展示全部内容
      if (img.width / nWidth == img.height / nHeight) {
        nWidth = 500
        nHeight = 300
        centerObj = { x: 250, y: 150 }
      } else if (img.width >= nWidth) {
        nWidth = (nWidth / img.width) * img.width
        nHeight = (nWidth / img.width) * img.height
        centerObj.y = nHeight / 2
      } else if (img.height >= nHeight) {
        nWidth = (nHeight / img.height) * img.width
        nHeight = (nHeight / img.height) * img.height
        centerObj.x = nWidth / 2
      } else if (img.height < nHeight || img.width < nWidth) {
        nHeight = 300
        nWidth = img.width * (300 / img.height)
        centerObj.x = nWidth / 2
        centerObj.y = nHeight / 2
      }
      state.centerObj = centerObj
      state.nWidth = nWidth
      state.nHeight = nHeight
      return { nWidth, nHeight, centerObj }
    }

    // 获取所有features
    const getFeatures = () => {
      state.allFeatures = state.gFirstFeatureLayer.getAllFeatures();
      console.log("--allFeatures--", toRaw(state.allFeatures));
      toRaw(state.allFeatures).forEach((e, i) => {
        console.log(`${i}条:`, e);
      })
    }

    // 添加图形
    const addFeature = (data, type, id) => {
      let drawingStyle = state.drawingStyle;
      let name = id
      id = `${id}${new Date().valueOf()}`
      console.log(data, '===', type);
      //线
      if (type === "LINE") {
        const scale = state.gMap.getScale();
        const width = drawingStyle.lineWidth / scale;
        const lineFeature = new AILabel.Feature.Line(
          id, // id
          { ...data, width }, // shape
          { name, textId: id }, // props
          drawingStyle // style
        );
        state.gFirstFeatureLayer.addFeature(lineFeature);
        // 多边形 添加 文本
        const textPosition = setText(data, type)
        addLayerText(id, name, textPosition)
      }
      //线段
      else if (type === "POLYLINE") {
        const scale = state.gMap.getScale();
        const width = drawingStyle.lineWidth / scale;
        const polylineFeature = new AILabel.Feature.Polyline(
          id, // id
          { points: data, width }, // shape
          { name, textId: id }, // props
          drawingStyle // style
        );
        state.gFirstFeatureLayer.addFeature(polylineFeature);
        // 多边形 添加 文本
        const textPosition = setText(data, type)
        addLayerText(id, name, textPosition)
      }
      //矩形
      else if (type === "RECT") {
        const rectFeature = new AILabel.Feature.Rect(
          id, // id
          data, // shape
          { name, textId: id }, // props
          drawingStyle // style
        );
        state.gFirstFeatureLayer.addFeature(rectFeature);
        // 多边形 添加 文本
        const textPosition = setText(data, type)
        addLayerText(id, name, textPosition)
      }
      //多边形
      else if (type === "POLYGON") {
        const polygonFeature = new AILabel.Feature.Polygon(
          id, // id
          { points: data }, // shape
          { name, textId: id }, // props
          drawingStyle // style
        );
        state.gFirstFeatureLayer.addFeature(polygonFeature);
        // 多边形 添加 文本
        const textPosition = setText(data, type)
        addLayerText(id, name, textPosition)
      }
      //点
      else if (type == "POINT") {
        const gFirstFeaturePoint = new AILabel.Feature.Point(
          id, // id
          { x: data.x, y: data.y, r: 5 }, // shape
          { name, textId: id }, // props
          { fillStyle: "#FF8C00", zIndex: 5, lineWidth: 2 } // style
        );
        state.gFirstFeatureLayer.addFeature(gFirstFeaturePoint);
        // 多边形 添加 文本
        const textPosition = setText(data, type)
        addLayerText(id, name, textPosition)
      }
      //注记
      else if (type == "MARKER") {
        const gFirstMarker = new AILabel.Marker(
          id, // id
          {
            src: "http://ailabel.com.cn/public/ailabel/demo/marker.png",
            position: {
              // marker坐标位置
              x: data.x,
              y: data.y,
            },
            offset: {
              x: -16,
              y: 32,
            },
          }, // markerInfo
          { name: "第一个marker注记", textId: id } // props
        );
        state.gFirstFeatureLayer.addFeature(gFirstMarker);
        // 多边形 添加 文本
        const textPosition = setText(data, type)
        addLayerText(id, name, textPosition)
      }
      //圆
      else if (type == "CIRCLE") {
        const gFirstFeatureCircle = new AILabel.Feature.Circle(
          id, // id
          { cx: data.cx, cy: data.cy, r: data.r }, // shape
          { name, textId: id }, // props
          {
            fillStyle: "#87CEFF",
            strokeStyle: "#3CB371",
            fill: true, //是否填充
            globalAlpha: 0.3,
            lineWidth: 2,
          } // style
        );
        state.gFirstFeatureLayer.addFeature(gFirstFeatureCircle);
        // 多边形 添加 文本
        const textPosition = setText(data, type)
        addLayerText(id, name, textPosition)
      }
      //涂抹
      else if (type == "DRAWMASK") {
        const drawMaskAction = new AILabel.Mask.Draw(
          `${+new Date().valueOf()}`, // id
          "铅笔",
          { points: data, width: 5 }, // shape
          { name: "港币", price: "1元", textId: id }, // props
          { strokeStyle: "#FF0000" } // style
        );
        state.gFirstFeatureLayer.addAction(drawMaskAction);
      }
      //擦除
      else if (type == "CLEARMASK") {
        const clearMaskAction = new AILabel.Mask.Clear(
          "first-action-clear", // id
          { points: data, width: 5 } // shape
        );
        state.gFirstMaskLayer.addAction(clearMaskAction);
      }
      getFeatures();
    }

    // 画完取名
    const getName = async (mode) => {
      console.log(mode);
      try {
        const { value } = await ElMessageBox.prompt("请输入填写名字", {
          confirmButtonText: "确定",
          showCancelButton: false,
          inputValidator: (v) => {
            if (v) {
              return true
            } else {
              return '请填写名字'
            }
          }
        });
        if (value) {
          state.itemName = value;
          return value;
        } else {
          return ''
        }
      } catch {
        return null;
      }
    }

    // 增加删除图标
    const addDeleteIcon = (feature, shape) => {
      // 添加delete-icon
      console.log(shape, "shape");
      let x = (shape?.x || shape?.cx || shape?.start?.x || shape?.points[0].x) + (shape?.width || shape?.r || 0)
      let y = (shape?.y || shape?.cy || shape?.start?.y || shape?.points[0].y) - 15
      const gFirstMarker = new AILabel.Marker(
        state.deleteIconId, // id
        {
          src: "https://s1.ax1x.com/2022/06/20/XvFRbT.png",
          position: { x, y }, // 矩形右上角 根据图形动态调整
          offset: {
            x: -20,
            y: -4,
          },
        }, // markerInfo
        { name: "delete" } // props
      );
      gFirstMarker.events.on("click", (marker) => {
        // 首先删除当前marker
        state.gMap.markerLayer.removeMarkerById(marker.id);
        // 删除对应text
        state.gFirstTextLayer.removeTextById(feature.props.textId);
        // 删除对应feature
        state.gFirstFeatureLayer.removeFeatureById(feature.id);
      });
      state.gMap.markerLayer.addMarker(gFirstMarker);
    }

    // 添加文本
    const addLayerText = (textId, textName, textPosition) => {
      // 添加一个文本
      const gFirstText = new AILabel.Text(
        textId, // id
        { text: textName, position: textPosition, offset: { x: 0, y: 0 } },
        { name: textName }, // props
        // 文本显示 style
        { fillStyle: '#F4A460', strokeStyle: '#D2691E', background: true, globalAlpha: 1, fontColor: 'red' }
      )
      state.gFirstTextLayer.addText(gFirstText)
    }

    // 删除 删除按钮
    const deIcon = () => {
      state.gMap.markerLayer.removeAllMarkers();
    }

    //设置文本坐标
    const setText = (data, type) => {
      let textPosition = {}
      switch (type) {
        case 'LINE':
          textPosition = { x: data?.start['x'], y: data?.start['y'] }
          break;
        case 'POLYLINE':
          textPosition = { x: data?.x, y: data?.y }
          break;
        case 'RECT':
          textPosition = { x: data['x'], y: data['y'] }
          break;
        case 'POLYGON':
          textPosition = { x: data[0]['x'], y: data[0]['y'] }
          break;
        case 'POINT':
          textPosition = { x: data.x, y: data.y }
          break;
        case 'MARKER':
          textPosition = { x: data.x, y: data.y }
          break;
        case 'CIRCLE':
          textPosition = { x: data.cx, y: data.cy - data.r }
          break;
        default:
          break;
      }
      return textPosition
    }

    // 增加事件
    const addEvent = () => {
      let gMap = state.gMap;
      gMap.events.on("drawDone", (type, data) => {
        console.log("--type, data--", type, data);
        if (type == "CLEARMASK" || type == "DRAWMASK") { //除了擦除 抹除外
          addFeature(data, type);
        } else {
          getName(type).then((id) => {
            if (id) {
              addFeature(data, type, id);
            }
          });
        }
      });
      gMap.events.on("boundsChanged", (data) => {
        console.log("--map boundsChanged--", data);
        return "";
      });
      // 双击编辑 在绘制模式下双击feature触发选中
      gMap.events.on("featureSelected", (feature) => {
        state.editId = feature.id;
        console.log("--map featureSelected--", feature, "双击编辑");
        //设置编辑feature
        gMap.setActiveFeature(feature);
        if (feature.type != "POINT") {
          // 增加删除按钮
          addDeleteIcon(feature, feature.shape);
        }
      });
      //右键 目前只针对"点"双击选中右键触发
      gMap.events.on("featureDeleted", (feature) => {
        if (feature.type == "POINT") {
          // 根据id删除对应feature
          state.gFirstFeatureLayer.removeFeatureById(feature.id);
          // 删除对应text
          state.gFirstTextLayer.removeTextById(feature.props.textId);
        }
      });
      // 单机空白取消编辑
      gMap.events.on("featureUnselected", () => {
        // 取消featureSelected
        state.editId = "";
        deIcon();
        gMap.setActiveFeature(null);
      });
      // 更新完
      gMap.events.on("featureUpdated", (feature, shape) => {
        console.log(feature, 'feature', shape);
        // 更新或者移动需要重新设置删除图标
        deIcon();
        feature.updateShape(shape);
        // 删除对应文本
        state.gFirstTextLayer.removeTextById(feature.props.textId);
        // 设置文本
        const textPosition = setText(shape, feature.type)
        addLayerText(feature.props.textId, feature.props.name, textPosition)
        if (feature.type != "POINT") {
          addDeleteIcon(feature, shape);
        }
        getFeatures()
      });

      // 删除
      gMap.events.on("FeatureDeleted", () => {
        console.log(2222222);
        // that.gFirstFeatureLayer.removeFeatureById(that.editId);
      });
    }
    // 获取坐标 需要自行添加
    const getPoints = (feature) => {
      switch (feature.type) {
        case "RECT":
          return feature.getPoints();
        case "LINE":
          return [feature.shape.start, feature.shape.end];
        case "POLYLINE":
          return feature.shape.points;
        case "POLYGON":
          return feature.shape.points;
        default:
          return [];
      }
    }
    //填充事件
    const Fill = () => {
      console.log("填充事件");
      if (!state.editId) {
        ElMessage({
          type: "info",
          message: "请选择填充标注",
        });
        return
      }
      let fill = state.gFirstFeatureLayer.getFeatureById(state.editId);
      console.log("--填充对象--", fill);
      fill.style.fillStyle = "#FFDAB9";
      fill.style.fill = true;
      //刷新map
      state.gMap.refresh();
    }
    //撤销
    const Revoke = () => {
      console.log("撤销");
      getFeatures();
      state.allFeatures.pop();
      //刷新map
      state.gMap.refresh();
      console.log(state.allFeatures, "--所有操作--");
    }
    const zoomIn = () => {
      state.gMap.zoomIn();
    }
    const zoomOut = () => {
      state.gMap.zoomOut();
    }
    const setMode = (mode) => {
      state.mode = mode;
    }
    //图片复位
    const restoration = () => {
      state.gMap.centerAndZoom({
        center: state.centerObj,
        zoom: 500
      })
    }

    //手动设置坐标
    function setGraph (data) {
      setDrawingStyle('POLYGON')
      addFeature([
        {
          "x": 163.125,
          "y": 63.125
        },
        {
          "x": 165.625,
          "y": 89.375
        },
        {
          "x": 226.25,
          "y": 106.875
        },
        {
          "x": 251.875,
          "y": 72.5
        },
        {
          "x": 268.75,
          "y": 37.5
        },
        {
          "x": 226.25,
          "y": 23.125
        }
      ], 'POLYGON');
    }
    function getRle () {
    }

    return {
      ...toRefs(state),
      initMap,
      getFeatures,
      setDrawingStyle,
      addFeature,
      getName,
      addDeleteIcon,
      addEvent,
      zoomIn,
      zoomOut,
      setMode,
      deIcon,
      getPoints,
      Fill,
      Revoke,
      setGraph,
      restoration,
      addLayerText,
      getRle,

      main_map
    }
  },
};
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss" scoped>
.label_main {
  display: flex;
  margin-left: 20px;
  flex-direction: column;
  height: 100%;
}

.button-wrap {
  display: flex;
  /* flex-direction: column; */
  position: relative;
  z-index: 99;

}

.label_btn {
  padding: 0 10px;
  border: 1px solid #ccc;
  border-right: 0;
  border-radius: 0;
}

.label_btn:first-child {
  border-radius: 4px 0 0 4px;
}

.label_btn:last-child {
  border: 1px solid #ccc;
  border-radius: 0 4px 4px 0;
}

#map {
  /* margin: 0 auto; */
  overflow: hidden;
  position: relative;
  height: 450px;
  width: 650px;
  border: 1px dashed #ccc;
  // margin-left: 36px;
}

.main_map {
  position: relative;
}

.zoom-icon-wrapper {
  position: absolute;
  /* left: -36px; */
  top: 0px;
  z-index: 1000;
}

.zoom-icon-plus {
  width: 30px;
  height: 30px;
  line-height: 20px;
  text-align: center;
  border: 3px solid #6495ed;
  font-size: 20px;
  border-top-left-radius: 6px;
  border-top-right-radius: 6px;
  color: #ff8c00;
  cursor: pointer;
}

.zoom-icon-plus:hover {
  border-color: #4169e1;
}

.zoom-icon-minus {
  margin-top: 6px;
  width: 30px;
  height: 30px;
  line-height: 20px;
  text-align: center;
  border: 3px solid #6495ed;
  font-size: 25px;
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
  color: #ff8c00;
  cursor: pointer;
}

.zoom-icon-minus:hover {
  border-color: #4169e1;
}

/* 删除图标 */
#delete01 {
  width: 10px;
  height: 10px;
}

.el-button+.el-button {
  margin-left: 0px;
}
</style>
使用
//引入
import { dLabelTemplate } from '@/components'
<dLabelTemplate :imgUrl="imgUrl" divId="map3" />

源代码(star点起来):https://github.com/dingyang9642/AILabel (已经关了)
这个是源代码地址:http://ailabel.com.cn/public/ailabel/demo/index.js
API文档:http://ailabel.com.cn/public/ailabel/api/index.html
Demo文档:http://ailabel.com.cn/public/ailabel/demo/index.html
Demo1文档:http://ailabel.com.cn/public/ailabel/demo/label/index.html
npm地址:https://www.npmjs.com/package/ailabel

老版API文档(小于v5.0.0):https://dingyang9642.github.io/AILabel/old_version_docs/#/

你可能感兴趣的:(vue,vue.js,前端,javascript)