一、网址以及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
增加填充功能和撤回功能