一、网址以及demo

官方文档AILabel与你一路同行

demo地址1: AILabel-标注篇demo地址2: AILabel示例一览

二、我的实例代码(vue环境下)

 

三、完整代码

首先  npm i ailabel

<template>
  <div class="main">
    <div class="operation">
      <div class="button-wrap">
        <el-button type="text" class="el-icon-thumb" @click="setMode('PAN')"
          >平移</el-button
        >
        <el-button
          type="text"
          class="el-icon-location-outline"
          @click="setMode('MARKER')"
          >注记</el-button
        >
        <el-button
          type="text"
          class="el-icon-more-outline"
          @click="setMode('POINT')"
          >点</el-button
        >
        <el-button type="text" class="el-icon-minus" @click="setMode('LINE')"
          >线段</el-button
        >
        <el-button
          type="text"
          class="el-icon-share"
          @click="setMode('POLYLINE')"
          >多段线</el-button
        >
        <el-button type="text" class="el-icon-orange" @click="setMode('CIRCLE')"
          >圆</el-button
        >
        <el-button
          type="text"
          class="el-icon-full-screen"
          @click="setMode('RECT')"
          >矩形</el-button
        >
        <el-button type="text" class="el-icon-house" @click="setMode('POLYGON')"
          >多边形</el-button
        >
        <el-button type="text" class="el-icon-magic-stick" @click="Fill()"
          >填充</el-button
        >
        <el-button type="text" class="el-icon-refresh-left" @click="Revoke()"
          >撤销</el-button
        >
        <el-button type="text" @click="getFeatures()">获取标注数据</el-button>

        <!-- <button class="btn btn-default" @click="setMode('DRAWMASK')">
          涂抹
        </button> -->
        <!-- <button class="btn btn-default" @click="setMode('CLEARMASK')">
          擦除
        </button> -->
        <!-- <button class="btn btn-default" @click="getRle()">获取rle数据</button> -->
      </div>
      <div class="zoom-icon-wrapper">
        <div class="zoom-icon-plus" @click="zoomIn">+</div>
        <div class="zoom-icon-minus" @click="zoomOut">-</div>
      </div>
    </div>

    <div id="map"></div>
  </div>
</template>
 
<script>
import AILabel from "ailabel";

export default {
  name: "HelloWorld",
  data() {
    return {
      imgUrl:
        "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F0186f0570f33d132f875a83991e34b.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1650076295&t=c0b8a135c2f9298d1d714703f5d30423",
      drawingStyle: {},
      mode: "",
      itemName: "",
      editId: "", //待填充图形id
      deleteIconId: "delete01",
      gMap: null, //AILabel实例
      gFirstFeatureLayer: null, //矢量图层实例(矩形,多边形等矢量)
      allFeatures: null, //所有features
    };
  },
  watch: {
    mode(mode) {
      this.gMap.setMode(mode);
      this.setDrawingStyle(mode);
    },
  },
  methods: {
    zoomIn() {
      this.gMap.zoomIn();
    },
    zoomOut() {
      this.gMap.zoomOut();
    },
    setMode(mode) {
      this.mode = mode;
    },
    // 获取所有features
    getFeatures() {
      this.allFeatures = this.gFirstFeatureLayer.getAllFeatures();
      console.log("--allFeatures--", this.allFeatures);
    },
    // 初始样式
    setDrawingStyle(mode) {
      let drawingStyle = {};
      switch (mode) {
        //平移
        case "PAN": {
          break;
        }
        //注记
        case "MARKER": {
          // 忽略
          break;
        }
        //点
        case "POINT": {
          this.drawingStyle = { fillStyle: "#FF8C00" };
          this.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //圆
        case "CIRCLE": {
          this.drawingStyle = {
            fillStyle: "#87CEFF",
            strokeStyle: "#87CEFF",
            lineWidth: 5,
          };
          this.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //线段
        case "LINE": {
          this.drawingStyle = {
            strokeStyle: "#BA55D3",
            lineJoin: "round",
            lineCap: "round",
            lineWidth: 10,
            arrow: false,
          };
          this.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //多线段
        case "POLYLINE": {
          this.drawingStyle = {
            strokeStyle: "#FF1493",
            lineJoin: "round",
            lineCap: "round",
            lineWidth: 10,
          };
          this.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //矩形
        case "RECT": {
          this.drawingStyle = { strokeStyle: "#0f0", lineWidth: 1 };
          this.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //多边形
        case "POLYGON": {
          this.drawingStyle = {
            strokeStyle: "#0099CC", //边框颜色
            fill: true, //是否填充
            fillStyle: "#FF6666", //填充色
            globalAlpha: 0.3,
            lineWidth: 3,
            fill: true,
            stroke: true,
          };
          this.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //涂抹
        case "DRAWMASK": {
          this.drawingStyle = {
            strokeStyle: "rgba(255, 0, 0, .5)",
            fillStyle: "#00f",
            lineWidth: 50,
          };
          this.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        //擦除
        case "CLEARMASK": {
          this.drawingStyle = { fillStyle: "#00f", lineWidth: 30 };
          this.gMap.setDrawingStyle(drawingStyle);
          break;
        }
        default:
          break;
      }
    },

    // 添加图形
    addFeature(data, type, id) {
      let that = this;
      let drawingStyle = this.drawingStyle;
      //线
      if (type === "LINE") {
        const scale = that.gMap.getScale();
        const width = drawingStyle.lineWidth / scale;
        const lineFeature = new AILabel.Feature.Line(
          id, // id
          { ...data, width }, // shape
          { name }, // props
          drawingStyle // style
        );
        that.gFirstFeatureLayer.addFeature(lineFeature);
      }
      //线段
      else if (type === "POLYLINE") {
        const scale = that.gMap.getScale();
        const width = drawingStyle.lineWidth / scale;
        const polylineFeature = new AILabel.Feature.Polyline(
          id, // id
          { points: data, width }, // shape
          { name }, // props
          drawingStyle // style
        );
        that.gFirstFeatureLayer.addFeature(polylineFeature);
      }
      //矩形
      else if (type === "RECT") {
        const rectFeature = new AILabel.Feature.Rect(
          id, // id
          data, // shape
          { name }, // props
          drawingStyle // style
        );
        that.gFirstFeatureLayer.addFeature(rectFeature);
      }
      //多边形
      else if (type === "POLYGON") {
        const polygonFeature = new AILabel.Feature.Polygon(
          id, // id
          { points: data }, // shape
          { name }, // props
          drawingStyle // style
        );
        that.gFirstFeatureLayer.addFeature(polygonFeature);
      }
      //点
      else if (type == "POINT") {
        const gFirstFeaturePoint = new AILabel.Feature.Point(
          id, // id
          { x: data.x, y: data.y, r: 5 }, // shape
          { name }, // props
          { fillStyle: "#FF8C00", zIndex: 5, lineWidth: 2 } // style
        );
        that.gFirstFeatureLayer.addFeature(gFirstFeaturePoint);
      }
      //注记
      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注记" } // props
        );
        that.gFirstFeatureLayer.addFeature(gFirstMarker);
      }
      //圆
      else if (type == "CIRCLE") {
        const gFirstFeatureCircle = new AILabel.Feature.Circle(
          id, // id
          { cx: data.cx, cy: data.cy, r: data.r }, // shape
          { name: "第一个矢量图层" }, // props
          {
            fillStyle: "#87CEFF",
            strokeStyle: "#3CB371",
            globalAlpha: 1,
            lineWidth: 5,
          } // style
        );
        that.gFirstFeatureLayer.addFeature(gFirstFeatureCircle);
      }
      //涂抹
      else if (type == "DRAWMASK") {
        const drawMaskAction = new AILabel.Mask.Draw(
          `${+new Date()}`, // id
          "铅笔",
          { points: data, width: 5 }, // shape
          { name: "港币", price: "1元" }, // props
          { strokeStyle: "#FF0000" } // style
        );
        that.gFirstFeatureLayer.addAction(drawMaskAction);
      }
      //擦除
      else if (type == "CLEARMASK") {
        const clearMaskAction = new AILabel.Mask.Clear(
          "first-action-clear", // id
          { points: data, width: 5 } // shape
        );
        that.gFirstMaskLayer.addAction(clearMaskAction);
      }
      this.getFeatures();
    },
    // 画完取名
    getName(mode) {
      return this.$prompt("请输入填写名字", {
        confirmButtonText: "确定",
        showCancelButton: false,
      })
        .then(({ value }) => {
          this.itemName = value;
          return value;
        })
        .catch(() => {
          return null;
        });
    },
    // 增加删除图标
    addDeleteIcon(feature, shape) {
      let gMap = this.gMap;
      let that = this;
      // 添加delete-icon
      // let points = that.getPoints(feature);
      console.log(shape, "shape");
      const gFirstMarker = new AILabel.Marker(
        that.deleteIconId, // id
        {
          src: "https://s1.aigei.com/src/img/png/45/45aabfc232a34e5b9bfaf75412973c08.png?|watermark/3/image/aHR0cHM6Ly9zMS5haWdlaS5jb20vd2F0ZXJtYXJrLzUwMC0xLnBuZz9lPTE3MzU0ODgwMDAmdG9rZW49UDdTMlhwemZ6MTF2QWtBU0xUa2ZITjdGdy1vT1pCZWNxZUpheHlwTDpjYWQ1NHVoRlhGUUViSGR3Vm02aXctVTJoWVE9/dissolve/40/gravity/NorthWest/dx/18/dy/21/ws/0.0/wst/0&e=1735488000&token=P7S2Xpzfz11vAkASLTkfHN7Fw-oOZBecqeJaxypL:C11LKqsRLbAqQo2uVPETYDya0QU=",
          position: { x: shape.x + shape.width, y: shape.y - 15 }, // 矩形右上角 根据图形动态调整
          offset: {
            x: -20,
            y: -4,
          },
        }, // markerInfo
        { name: "delete" } // props
      );
      gFirstMarker.events.on("click", (marker) => {
        // 首先删除当前marker
        gMap.markerLayer.removeMarkerById(marker.id);
        // 删除对应text
        // gFirstTextLayer.removeTextById(textId);
        // 删除对应feature
        that.gFirstFeatureLayer.removeFeatureById(feature.id);
      });
      gMap.markerLayer.addMarker(gFirstMarker);

      // that.gFirstFeatureLayer
    },
    // 删除 删除按钮
    deIcon() {
      this.gMap.markerLayer.removeAllMarkers();
    },
    // 增加事件
    addEvent() {
      let that = this;
      let gMap = this.gMap;
      gMap.events.on("drawDone", (type, data) => {
        console.log("--type, data--", type, data);
        // that.addFeature(data, type);
        if (type == "CLEARMASK" || type == "DRAWMASK") {
          that.addFeature(data, type);
        } else {
          that.getName(type).then((id) => {
            if (id) {
              that.addFeature(data, type, id);
            } else {
              this.$message({
                type: "info",
                message: "请填写名字",
              });
            }
          });
        }
      });
      gMap.events.on("boundsChanged", (data) => {
        console.log("--map boundsChanged--", data);
        return "";
      });
      // 双击编辑 在绘制模式下双击feature触发选中
      gMap.events.on("featureSelected", (feature) => {
        this.editId = feature.id;
        console.log("--map featureSelected--", feature, "双击编辑");
        //设置编辑feature
        gMap.setActiveFeature(feature);
        if (feature.type != "POINT") {
          // 增加删除按钮
          that.addDeleteIcon(feature, feature.shape);
        }
      });
      //右键 目前只针对点双击选中右键触发
      gMap.events.on("featureDeleted", (feature) => {
        if (feature.type == "POINT") {
          // 根据id删除对应feature
          that.gFirstFeatureLayer.removeFeatureById(feature.id);
        }
      });
      // 单机空白取消编辑
      gMap.events.on("featureUnselected", () => {
        // 取消featureSelected
        that.editId = "";
        that.deIcon();
        gMap.setActiveFeature(null);
      });
      // 更新完
      gMap.events.on("featureUpdated", (feature, shape) => {
        console.log(feature);
        // 更新或者移动需要重新设置删除图标
        that.deIcon();
        feature.updateShape(shape);
        if (feature.type != "POINT") {
          that.addDeleteIcon(feature, shape);
        }
      });

      // 删除
      gMap.events.on("FeatureDeleted", () => {
        console.log(2222222);
        // that.gFirstFeatureLayer.removeFeatureById(that.editId);
      });
    },
    // 获取坐标 需要自行添加
    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 [];
      }
    },
    //填充事件
    Fill() {
      console.log("填充事件");
      let fill = this.gFirstFeatureLayer.getFeatureById(this.editId);
      console.log("--填充对象--", fill);
      fill.style.fillStyle = "#FFDAB9";
      fill.style.fill = true;
      //刷新map
      this.gMap.refresh();
    },
    //撤销
    Revoke() {
      console.log("撤销");
      this.getFeatures();
      this.allFeatures.pop();
      //刷新map
      this.gMap.refresh();
      console.log(this.allFeatures, "--所有操作--");
    },
  },
  mounted() {
    let that = this;
    const gMap = new AILabel.Map("map", {
      center: { x: 250, y: 150 }, // 为了让图片居中
      zoom: 500,
      mode: "PAN", // 绘制线段
      refreshDelayWhenZooming: true, // 缩放时是否允许刷新延时,性能更优
      zoomWhenDrawing: true,
      panWhenDrawing: true,
      zoomWheelRatio: 5, // 控制滑轮缩放缩率[0, 10), 值越小,则缩放越快,反之越慢
      withHotKeys: true, // 关闭快捷键
    });
    that.gMap = gMap;
    this.addEvent();
    // 图片层添加
    const gFirstImageLayer = new AILabel.Layer.Image(
      "first-layer-image", // id
      {
        src: that.imgUrl,
        width: 500,
        height: 300,
        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对象
    gMap.addLayer(gFirstImageLayer);
    // 添加矢量图层
    const gFirstFeatureLayer = new AILabel.Layer.Feature(
      "first-layer-feature", // id
      { name: "第一个矢量图层" }, // props
      { zIndex: 10 } // style
    );
    this.gFirstFeatureLayer = gFirstFeatureLayer;
    gMap.addLayer(gFirstFeatureLayer);

    window.onresize = function () {
      this.gMap && this.gMap.resize();
    };
  },
  beforeDestroy() {
    this.gMap.destroy();
  },
};
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style>
.main {
  display: flex;
  flex-direction: row;
  margin: 50px;
  justify-content: center;
}

.button-wrap {
  display: flex;
  flex-direction: column;
  padding-bottom: 10px;
  position: relative;
  z-index: 99;
}

#map {
  /* margin: 0 auto; */
  overflow: hidden;
  position: relative;
  height: 600px;
  width: 800px;
  border: 1px dashed #ccc;
}

.zoom-icon-wrapper {
  position: absolute;
  /* left: 20px; */
  /* top: 20px; */
  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: 20px;
  height: 20px;
}
.el-button + .el-button {
  margin-left: 0px;
}
</style>

每个创建的图层都可以通过编辑进行删除操作

涂抹擦除 还有撤回功能(后续待更新)

2022/3/18

增加填充功能和撤回功能