可以动态修改颜色样式
标绘功能直接使用了mapbox-gl-draw,并进行了二次封装
首先可以自己预先自定义样式,从mapbox-gl-draw中拷出来theme.js,并根据自己需要进行修改
theme.js
/**
* 自定义绘制的默认样式
* 测量绘制样式为默认
* 标绘绘制样式根据属性渲染
*/
export default [
{
'id': 'gl-draw-polygon-fill-inactive',
'type': 'fill',
'filter': ['all',
['==', 'active', 'false'],
['==', '$type', 'Polygon'],
['!=', 'mode', 'static']
],
/*'paint': {
'fill-color':'#3bb2d0',
'fill-outline-color':'#3bb2d0',
'fill-opacity': 0.1
}*/
'paint': {
'fill-color': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_fill"],
'#3bb2d0'
],
'fill-outline-color': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_fill-outline-color"],
'#3bb2d0'
],
'fill-opacity': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_fill-opacity"],
0.1
]
}
},
{
'id': 'gl-draw-polygon-fill-active',
'type': 'fill',
'filter': ['all', ['==', 'active', 'true'], ['==', '$type', 'Polygon']],
'paint': {
'fill-color': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_fill"],
'#fbb03b'
],
'fill-outline-color':[
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_fill-outline-color"],
'#fbb03b'
],
'fill-opacity': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_fill-opacity"],
0.1
]
}
},
{
'id': 'gl-draw-polygon-midpoint',
'type': 'circle',
'filter': ['all',
['==', '$type', 'Point'],
['==', 'meta', 'midpoint']],
'paint': {
'circle-radius': 3,
'circle-color': '#fbb03b'
}
},
{
'id': 'gl-draw-polygon-stroke-inactive',
'type': 'line',
'filter': ['all',
['==', 'active', 'false'],
['==', '$type', 'Polygon'],
['!=', 'mode', 'static']
],
'layout': {
'line-cap': 'round',
'line-join': 'round'
},
'paint': {
'line-color':[
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_fill-outline-color"],
'#fbb03b'
],
'line-width': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_line-width"],
2
]
}
},
{
'id': 'gl-draw-polygon-stroke-active',
'type': 'line',
'filter': ['all', ['==', 'active', 'true'], ['==', '$type', 'Polygon']],
'layout': {
'line-cap': 'round',
'line-join': 'round'
},
'paint': {
'line-color': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_fill-outline-color"],
'#fbb03b'
],
'line-dasharray': [0.2, 2],
'line-width': 2
}
},
//线
{
'id': 'gl-draw-line-inactive',
'type': 'line',
'filter': ['all',
['==', 'active', 'false'],
['==', '$type', 'LineString'],
['!=', 'mode', 'static']
],
'layout': {
'line-cap': 'round',
'line-join': 'round'
},
/*'paint': {
'line-color': '#3bb2d0',
'line-width': 2
},*/
'paint': {
'line-color': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_line-color"],
'#3bb2d0'
],
'line-width': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_line-width"],
2
],
'line-opacity': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_line-opacity"],
1
]
}
},
{
'id': 'gl-draw-line-active',
'type': 'line',
'filter': ['all',
['==', '$type', 'LineString'],
['==', 'active', 'true']
],
'layout': {
'line-cap': 'round',
'line-join': 'round'
},
'paint': {
'line-color':[
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_line-color"],
'#fbb03b'
],
'line-dasharray': [0.2, 2],
'line-width': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_line-width"],
2
],
'line-opacity': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_line-opacity"],
1
]
}
/*'paint': {
'line-color': '#fbb03b',
'line-dasharray': [0.2, 2],
'line-width': 2
}*/
},
{
'id': 'gl-draw-polygon-and-line-vertex-stroke-inactive',
'type': 'circle',
'filter': ['all',
['==', 'meta', 'vertex'],
['==', '$type', 'Point'],
['!=', 'mode', 'static']
],
'paint': {
'circle-radius': 5,
'circle-color': '#fff'
}
},
{
'id': 'gl-draw-polygon-and-line-vertex-inactive',
'type': 'circle',
'filter': ['all',
['==', 'meta', 'vertex'],
['==', '$type', 'Point'],
['!=', 'mode', 'static']
],
'paint': {
'circle-radius': 3,
'circle-color': '#fbb03b'
}
},
{
'id': 'gl-draw-point-point-stroke-inactive',
'type': 'circle',
'filter': ['all',
['==', 'active', 'false'],
['==', '$type', 'Point'],
['==', 'meta', 'feature'],
['!=', 'mode', 'static']
],
'paint': {
'circle-radius': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['+',['get', "user_circle-radius"],2],
5
],
'circle-opacity': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_circle-opacity"],
1
],
'circle-color':[
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_circle-color"],
'#fff'
]
}
},
// 点
{
'id': 'gl-draw-point-inactive',
'type': 'circle',
'filter': ['all',
['==', 'active', 'false'],
['==', '$type', 'Point'],
['==', 'meta', 'feature'],
['!=', 'mode', 'static']
],
'paint':{
'circle-radius': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_circle-radius"],
3
],
'circle-color':[
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_circle-color"],
'#3bb2d0'
],
'circle-opacity': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_circle-opacity"],
1
]
}
/*'paint': {
'circle-radius': 3,
'circle-color': '#3bb2d0'
}*/
},
{
'id': 'gl-draw-point-stroke-active',
'type': 'circle',
'filter': ['all',
['==', '$type', 'Point'],
['==', 'active', 'true'],
['!=', 'meta', 'midpoint']
],
'paint': {
//'circle-radius': 7,
'circle-radius': [
"case",
['==', ['get', "user_isPlotFeature"], true], ["+", ['get', "user_circle-radius"], 5],
7
],
'circle-color':'#fff'
}
},
{
'id': 'gl-draw-point-active',
'type': 'circle',
'filter': ['all',
['==', '$type', 'Point'],
['!=', 'meta', 'midpoint'],
['==', 'active', 'true']],
'paint':{
'circle-radius': [
"case",
['==', ['get', "user_isPlotFeature"], true], ["+", ['get', "user_circle-radius"], 3],
5
],
'circle-color':[
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_circle-color"],
'#fbb03b'
],
'circle-opacity': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_circle-opacity"],
1
]
}
/*'paint': {
'circle-radius': 5,
'circle-color': '#fbb03b'
}*/
},
{
'id': 'gl-draw-polygon-fill-static',
'type': 'fill',
'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'Polygon']],
'paint': {
'fill-color': '#404040',
'fill-outline-color': '#404040',
'fill-opacity': 0.1
}
},
{
'id': 'gl-draw-polygon-stroke-static',
'type': 'line',
'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'Polygon']],
'layout': {
'line-cap': 'round',
'line-join': 'round'
},
'paint': {
'line-color': '#404040',
'line-width': 2
}
},
{
'id': 'gl-draw-line-static',
'type': 'line',
'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'LineString']],
'layout': {
'line-cap': 'round',
'line-join': 'round'
},
'paint': {
'line-color': '#404040',
'line-width': 2
}
},
{
'id': 'gl-draw-point-static',
'type': 'circle',
'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'Point']],
'paint': {
'circle-radius': 5,
'circle-color': '#404040',
'circle-opacity': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_circle-opacity"],
1
]
}
}
];
封装Draw类
Draw.js
/**
* @Author :TanShiJun [email protected]
* @Date :2022/5/16
* @Describe :绘制
* Last Modified by : TSJ
* Last Modified time :2022/5/23
**/
import MapboxDraw from "@mapbox/mapbox-gl-draw/index.js";
import * as MapboxDrawWaypoint from 'mapbox-gl-draw-waypoint';
import DrawRectangle from 'mapbox-gl-draw-rectangle-mode';
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
import {
CircleMode,
DragCircleMode,
DirectMode,
SimpleSelectMode
} from 'mapbox-gl-draw-circle';
import styles from './theme';
export default class Draw {
constructor(_map,_appConfig) {
this.map=_map
this.appConfig=_appConfig
let modes={
...MapboxDraw.modes,
draw_rectangle:DrawRectangle,
draw_circle : CircleMode,
drag_circle : DragCircleMode,
direct_select: DirectMode,
simple_select: SimpleSelectMode
}
// 测量绘制的要素,只允许拖动节点,不允许拖动整个要素
modes = MapboxDrawWaypoint.enable(modes,feature => feature.properties.isMeasureFeature);
this.mapboxDraw=new MapboxDraw({
displayControlsDefault: false,
modes,
userProperties: true,
styles,
/*controls: {
polygon: true,
trash: true
}*/
})
// 触发 setup onAdd事件
this.map.addControl(this.mapboxDraw);
this._init()
}
_init() {
this.map.on('draw.create', drawCreate);
this.map.on('draw.delete', drawDelete);
this.map.on('draw.update', drawUpdate);
this.callBack=undefined
let self=this
function drawCreate(evt){
//console.log('drawCreate',evt)
if(self.callBack){
self.callBack(evt)
}
}
function drawDelete(){}
function drawUpdate(){
}
}
startDraw(type,callback){
this.callBack=undefined
if(callback){
this.callBack=callback
}
switch (type) {
case 'draw_point':
this.mapboxDraw.changeMode('draw_point')
break
case 'draw_line_string':
this.mapboxDraw.changeMode('draw_line_string')
break
case 'draw_polygon':
this.mapboxDraw.changeMode('draw_polygon')
break
case 'draw_rectangle':
this.mapboxDraw.changeMode('draw_rectangle')
break
case 'draw_circle':
this.mapboxDraw.changeMode('draw_circle',{ initialRadiusInKm: 0.5 })
break
default :
console.error("未知的绘制类型")
/* case 'draw_polygon':
this.mapboxDraw.changeMode('draw_polygon')
break
case 'draw_polygon':
this.mapboxDraw.changeMode('draw_polygon')
break
case 'draw_polygon':
this.mapboxDraw.changeMode('draw_polygon')
break*/
}
}
static getInstance(_map,_appConfig) {
if (!this.instance) {
this.instance = new Draw(_map,_appConfig)
}
return this.instance
}
}
标绘管理类 可绘制点、线、面、矩形、圆、文字,包括样式的自定义
PlotManager.js
/**
* @Author :TanShiJun [email protected]
* @Date :2022/5/18
* @Describe :地图标绘
* Last Modified by : TSJ
* Last Modified time :2022/5/18
**/
import Draw from "../Draw";
export default class PlotManager {
constructor(map,appConfig) {
this.map=map
this.appConfig=appConfig
this.draw=Draw.getInstance(map,appConfig)
this.currentSelectFeature=null
this.map.on('draw.selectionchange',(data)=>{
if(data.features.length>0&&data.features[0].properties.isPlotFeature){
this.currentSelectFeature=data.features[0]
}
if(data.features.length===0){
this.currentSelectFeature=null
}
})
//绘制的默认样式
this.style={
lineStrokeColor: '#ff0000', // 线条的轮廓颜色
lineBorderStyle: '0', // 线条的样式,实线、虚线等
lineBorderWidth: 1, // 线条的宽度
lineOpacity: 48, // 线条的透明度
opacity:50,
shapeFillColor: '#00ff00', // 形状的填充颜色
shapeStrokeColor: '#ff0000', // 形状的轮廓颜色
shapeBorderWidth: 1, // 形状的边框线宽度
shareOpacity: 0.5, // 形状的透明度
fontContent: '', // 文字的内容
fontColor: '#ff0000', // 文字的颜色
fontSize: 18, // 文字的大小
}
this._initTextLayer()
}
_initTextLayer() {
//添加文字标记图层
this.plotTextlayerId='plot_text'
this.map.addLayer({
'id':this.plotTextlayerId,
'type': 'symbol',
'source':'mapbox-gl-draw-cold' ,
"layout": {
"text-field": "{user_text}",
'text-size': [
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_text-size"],
14
],
//"text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
"text-offset": [0, -0.6],
"text-anchor": "bottom"
},
'paint': {//绘制类属性
/*'text-color':"#fff",*/
'text-color':[
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_text-color"],
'#ff0000'
],
'text-halo-color':"#fff",
'text-halo-width':1,
'text-opacity':[
"case",
['==', ['get', "user_isPlotFeature"], true], ['get', "user_text-opacity"],
0
],
'text-translate': [0,0],//右、下 偏移量
}
})
this._bindLayerEvent(this.plotTextlayerId)
}
_bindLayerEvent(layerId){
let self=this
this.map.on('click', layerId, function (e) {
if(e.features[0]){
self.draw.mapboxDraw.changeMode('simple_select',{featureIds:[e.features[0].properties.id]})
}
});
this.map.on('mouseenter', layerId, function (e) {
self.map.getCanvas().style.cursor = 'pointer';
});
this.map.on('mouseleave',layerId, function (e) {
self.map.getCanvas().style.cursor = '';
});
}
//获取当前的选中绘制图形
getSelectedDraw() {
const ids=this.draw.mapboxDraw.getSelectedIds()
if(ids.length>0){
let feature=this.draw.mapboxDraw.get(ids[0])
if(feature&&feature.properties.isPlotFeature){
this.currentSelectFeature=feature
return feature
}
}else{
this.currentSelectFeature=null
}
return null
}
cancelDraw() {
this.currentSelectFeature=null
this.draw.mapboxDraw.changeMode('simple_select',{featureIds:[]})
}
deleteSelected() {
const ids=this.draw.mapboxDraw.getSelectedIds()
if(ids.length>0){
this.draw.mapboxDraw.delete(ids)
}
}
deleteAll() {
this.draw.mapboxDraw.deleteAll()
}
startDraw(geometryType,style,callback){
if(style){
this.style=style
}
let drawType=''
switch (geometryType) {
case 'POLYGON':// 绘制面
drawType='draw_polygon'
this.drawPolygon(drawType,geometryType,this.style,(data)=>{
if(callback){
callback(data)
}
})
break
case 'EXTENT':// 绘制矩形
drawType='draw_rectangle'
this.drawPolygon(drawType,geometryType,this.style,(data)=>{
if(callback){
callback(data)
}
})
break
case 'POLYLINE':
drawType='draw_line_string'
this.drawPolyline(drawType,geometryType,this.style,(data)=>{
if(callback){
callback(data)
}
})
break
case 'CIRCLE':
drawType='draw_circle'
this.drawPolygon(drawType,geometryType,this.style,(data)=>{
if(callback){
callback(data)
}
})
break
case 'POINT':
case 'FONT':
drawType='draw_point'
this.drawPoint(drawType,geometryType,this.style,(data)=>{
if(callback){
callback(data)
}
})
break
}
}
drawPolygon(drawType,geometryType,style,callback){
this.draw.startDraw(drawType,(data)=>{
if(data.features.length>0){
this.draw.mapboxDraw.setFeatureProperty(data.features[0].id,'isPlotFeature',true)
this.draw.mapboxDraw.setFeatureProperty(data.features[0].id,'plotType',geometryType)
//以下添加样式
this.updatePolygonStyle(data.features[0].id,style)
}
if(callback){
callback(data)
}
})
}
/**
* 更新样式属性
* @param feature 绘制的面要素id
* @param style 样式
*/
updatePolygonStyle(featureId,style) {
let feature=this.draw.mapboxDraw.get(featureId)
let layers=this.map.getStyle().layers;
this.draw.mapboxDraw.setFeatureProperty(featureId,'fill',style.shapeFillColor)
this.draw.mapboxDraw.setFeatureProperty(featureId,'fill-opacity',style.shareOpacity)
this.draw.mapboxDraw.setFeatureProperty(featureId,'fill-outline-color',style.shapeStrokeColor)
this.draw.mapboxDraw.setFeatureProperty(featureId,'line-width',style.shapeBorderWidth)
}
drawPolyline(drawType,geometryType,style,callback){
this.draw.startDraw(drawType,(data)=>{
if(data.features.length>0){
this.draw.mapboxDraw.setFeatureProperty(data.features[0].id,'isPlotFeature',true)
this.draw.mapboxDraw.setFeatureProperty(data.features[0].id,'plotType',geometryType)
//以下添加样式
this.updatePolylineStyle(data.features[0].id,style)
}
if(callback){
callback(data)
}
})
}
/**
* 更新样式属性
* @param feature 绘制的面要素id
* @param style 样式
*/
updatePolylineStyle(featureId,style) {
this.draw.mapboxDraw.setFeatureProperty(featureId,'line-opacity',style.lineOpacity)
this.draw.mapboxDraw.setFeatureProperty(featureId,'line-color',style.lineStrokeColor)
this.draw.mapboxDraw.setFeatureProperty(featureId,'line-width',style.lineBorderWidth)
}
drawPoint(drawType,geometryType,style,callback){
this.draw.startDraw(drawType,(data)=>{
if(data.features.length>0){
this.draw.mapboxDraw.setFeatureProperty(data.features[0].id,'isPlotFeature',true)
this.draw.mapboxDraw.setFeatureProperty(data.features[0].id,'plotType',geometryType)
//以下添加样式
if(geometryType==='POINT'){
this.updatePointStyle(data.features[0].id,style)
}
else if(geometryType==='FONT'){
// 文本定义默认点样式
this.draw.mapboxDraw.setFeatureProperty(data.features[0].id,'text','')
// 文本标记修改点样式
this.draw.mapboxDraw.setFeatureProperty(data.features[0].id,'circle-opacity',0.1)
this.draw.mapboxDraw.setFeatureProperty(data.features[0].id,'circle-radius',2)
this.draw.mapboxDraw.setFeatureProperty(data.features[0].id,'circle-color','#e8ff0c')
this.updateTextStyle(data.features[0].id,style)
}
}
if(callback){
callback(data)
}
})
}
updatePointStyle(featureId,style) {
let source=this.map.getSource('mapbox-gl-draw-cold')
console.log(source)
this.draw.mapboxDraw.setFeatureProperty(featureId,'circle-opacity',style.pointOpacity)
this.draw.mapboxDraw.setFeatureProperty(featureId,'circle-radius',style.pointRadius)
this.draw.mapboxDraw.setFeatureProperty(featureId,'circle-color',style.pointColor)
}
updateTextStyle(featureId,style){
this.draw.mapboxDraw.setFeatureProperty(featureId,'text-color',style.fontColor)
this.draw.mapboxDraw.setFeatureProperty(featureId,'text-size',style.fontSize)
this.draw.mapboxDraw.setFeatureProperty(featureId,'text-opacity',style.fontOpacity)
this.draw.mapboxDraw.setFeatureProperty(featureId,'text',style.fontContent)
}
static getInstance(map,appConfig) {
if(!this.instance){
this.instance=new PlotManager(map,appConfig)
}
return this.instance
}
}
vue组件调用
index.vue
<template>
<move-able-panel headName="标绘"
titleIcon="el-icon-edit"
:width="400"
:height="300"
:top="110"
:right="20"
:visible="visible"
@close="closePanel"
>
<div class="gis-plotting-box">
<!-- 图标类型 -->
<div class="gis-graphical-wrap">
<div v-for="(item, index) in graphicals"
:key="index"
class="gis-graphical-item"
@click="onChangeType(item)"
:title="item.name">
<div class="gis-graphical-block" :class="[item.selected ? 'selected' : '']">
<i :class="['iconfont', item.icon]"></i>
</div>
</div>
</div>
<!-- 图标属性 -->
<div class="gis-attribute-wrap">
<!-- 线条 -->
<el-form v-show="activeType === 'line'"
inline
size="mini"
label-width="68px">
<el-row>
<el-col :span="12">
<el-form-item label="轮廓颜色">
<el-color-picker v-model="lineStrokeColor" :predefine="predefineColors"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="线条样式">
<el-select v-model="lineBorderStyle" placeholder="请选择">
<el-option v-for="(item, index) in borderStyles"
:key="index"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="线条宽度">
<el-input-number v-model="lineBorderWidth" controls-position="right" :min="1"/>
</el-form-item>
</el-col>
<el-col :span="12">
<!--<div class="block">
<span class="demonstration">透明度</span>
<el-slider v-model="opacity"></el-slider>
</div>-->
<el-form-item label="透明度">
<el-input-number v-model="lineOpacity"
controls-position="right"
:min="0"
:max="1"
:step="0.1"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-button icon="el-icon-edit" type="primary" @click="startDraw">绘制</el-button>
<el-button icon="el-icon-close" type="info" @click="cancelDraw">取消</el-button>
<el-button icon="el-icon-check" type="success" @click="applySetting">确定</el-button>
<el-button icon="el-icon-delete" type="danger" @click="clearDraw">清除</el-button>
</el-row>
<!--<el-row>
<el-button type="text" size="mini" style="color: red">注:双击绘制的图形可选中,进行删除和添加属性</el-button>
</el-row>-->
</el-form>
<!-- 形状 -->
<el-form v-show="activeType === 'shape'"
inline
size="mini"
label-width="68px">
<el-row>
<el-col :span="12">
<el-form-item label="填充颜色">
<el-color-picker v-model="shapeFillColor" :predefine="predefineColors"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="透明度">
<el-input-number v-model="shareOpacity"
controls-position="right"
:min="0"
:max="1"
:step="0.1"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="轮廓颜色">
<el-color-picker v-model="shapeStrokeColor" :predefine="predefineColors"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="线条宽度">
<el-input-number v-model="shapeBorderWidth"
controls-position="right"
:min="1"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-button icon="el-icon-edit" type="primary" @click="startDraw">绘制</el-button>
<el-button icon="el-icon-close" type="info" @click="cancelDraw">取消</el-button>
<el-button icon="el-icon-check" type="success" @click="applySetting">确定</el-button>
<el-button icon="el-icon-delete" type="danger" @click="clearDraw">清除</el-button>
</el-row>
<!--<el-row>
<el-button type="text" size="mini" style="color: red">注:双击绘制的图形可选中,进行删除和添加属性</el-button>
</el-row>-->
</el-form>
<!-- 文字 -->
<el-form v-show="activeType === 'font'"
inline
size="mini"
label-width="68px">
<el-form-item label="文本内容" class="form-block">
<el-input v-model="fontContent"/>
</el-form-item>
<el-form-item label="文字颜色">
<el-color-picker v-model="fontColor" :predefine="predefineColors"/>
</el-form-item>
<el-form-item label="文字大小">
<el-input-number v-model="fontSize"
controls-position="right"
:min="12"
:max="100"
:step="1"/>
</el-form-item>
<el-form-item label="透明度">
<el-input-number v-model="fontOpacity"
controls-position="right"
:min="0"
:max="1"
:step="0.1"/>
</el-form-item>
<el-row>
<el-button icon="el-icon-edit" type="primary" @click="startDraw">绘制</el-button>
<el-button icon="el-icon-close" type="info" @click="cancelDraw">取消</el-button>
<el-button icon="el-icon-check" type="success" @click="applySetting">确定</el-button>
<el-button icon="el-icon-delete" type="danger" @click="clearDraw">清除</el-button>
</el-row>
<!--<el-row>
<el-button type="text" size="mini" style="color: red">注:双击绘制的图形可选中,进行删除和添加属性</el-button>
</el-row>-->
</el-form>
<!-- 点 -->
<el-form v-show="activeType === 'point'"
inline
size="mini"
label-width="68px">
<el-form-item label="点颜色">
<el-color-picker v-model="pointColor" :predefine="predefineColors"/>
</el-form-item>
<el-form-item label="点大小">
<el-input-number v-model="pointRadius"
controls-position="right"
:min="1"
:max="100"
:step="1"/>
</el-form-item>
<el-row>
<el-button icon="el-icon-edit" type="primary" @click="startDraw">绘制</el-button>
<el-button icon="el-icon-close" type="info" @click="cancelDraw">取消</el-button>
<el-button icon="el-icon-check" type="success" @click="applySetting">确定</el-button>
<el-button icon="el-icon-delete" type="danger" @click="clearDraw">清除</el-button>
</el-row>
<!--<el-row>
<el-button type="text" size="mini" style="color: red">注:双击绘制的图形可选中,进行删除和添加属性</el-button>
</el-row>-->
</el-form>
</div>
</div>
</move-able-panel>
</template>
<script>
import MoveAblePanel from '../../../components/MoveAblePanel'
import PlotWidget from "./PlotWidget";
export default {
name: 'Plot',
components: {
MoveAblePanel,
},
props: {
visible:{
type:Boolean,
default:true
}
},
computed: {
mapLoaded() {
return this.$store.getters['gis/getIsLoadedMap']
},
// 预定义颜色
predefineColors() {
return this.$store.getters['gis/getPredefineColors'];
},
styleConfig() {
return {
lineBorderStyle:this.lineBorderStyle,
lineStrokeColor:this.lineStrokeColor,
lineBorderWidth:this.lineBorderWidth,
lineOpacity:this.lineOpacity,
shapeFillColor:this.shapeFillColor,
shapeStrokeColor:this.shapeStrokeColor,
shapeBorderWidth:this.shapeBorderWidth,
shareOpacity:this.shareOpacity,
fontContent: this.fontContent,
fontColor:this.fontColor,
fontSize:this.fontSize,
fontOpacity:this.fontOpacity,
pointRadius:this.pointRadius,
pointColor:this.pointColor,
pointOpacity:this.pointOpacity,
drawType:this.currentGraphical?this.currentGraphical.drawType:'POLYLINE'
}
}
},
data: function () {
return {
isShow: this.visible, // 是否显示
activeId: '', // 当前选择的图形id
activeType: 'line', // 当前选择的图形类型
graphicals: [
{ id: 0, name: '折线', type: 'line', drawType:'POLYLINE',selected:true, icon: 'icon-icon-line-graph' },
{ id: 2, name: '圆形', type: 'shape',drawType:'CIRCLE',selected:false, icon: 'icon-yuanxing' },
/* { id: 3, name: '椭圆形', type: 'shape',drawType:'ELLIPSE',selected:false, icon: 'icon-tx-fill-tuoyuanxing' },*/
{ id: 4, name: '矩形', type: 'shape',drawType:'EXTENT',selected:false, icon: 'icon-juxing' },
{ id: 5, name: '多边形', type: 'shape',drawType:'POLYGON',selected:false, icon: 'icon-duobianxingchaxun' },
{ id: 3, name: '点', type: 'point',drawType:'POINT',selected:false, icon: 'icon-wired-weizhidian' },
{ id: 6, name: '文字', type: 'font',drawType:'FONT',selected:false, icon: 'icon-wenziyanse' }
], // 绘图类型
borderStyles: [
{ id: '0', name: '实线' },
{ id: '1', name: '虚线' }
], // 线条样式
lineStrokeColor: '#ff0000', // 线条的轮廓颜色
lineBorderStyle: '0', // 线条的样式,实线、虚线等
lineBorderWidth: 2, // 线条的宽度
lineOpacity: 1, // 线条的透明度
opacity:50,
shapeFillColor: '#00ff00', // 形状的填充颜色
shapeStrokeColor: '#ff0000', // 形状的轮廓颜色
shapeBorderWidth: 1, // 形状的边框线宽度
shareOpacity: 0.5, // 形状的透明度
fontContent: '', // 文字的内容
fontColor: '#ff0000', // 文字的颜色
fontSize: 18, // 文字的大小
fontOpacity:0.8,
pointRadius:3,// 点大小,半径
pointColor:'#00ff00',// 点颜色
pointOpacity:1,
currentSelectedGraphic:null
}
},
watch: {
styleConfig(newVal,oldValue) {
this.widget&&this.widget.updateDrawStyle(newVal)
// map.getSource('trace').setData(data);
}
},
mounted() {
},
methods: {
selectedPlottingGraphic(graphic) {
this.currentSelectedGraphic=graphic;
},
/**
* 显示Dialog
*/
onShow() {
this.$set(this, 'isShow', true);
},
//开始绘制
startDraw(){
if(!mapbox3D){
return this.$message.warning(`请先等待地图初始化完成...`)
}
if(!this.currentGraphical){
this.currentGraphical=this.graphicals[0]
}
this.widget=PlotWidget.getInstance(mapbox3D.map,appConfig)
let geometryType=this.currentGraphical.drawType;
this.widget.plottingDraw(geometryType,this.styleConfig,(data)=>{
})
},
//取消绘制
cancelDraw() {
this.widget.plotManager.cancelDraw()
},
//确定
applySetting() {
let drawFeature=this.widget.plotManager.getSelectedDraw()
if(!drawFeature){
return this.$message.warning(`请先选中绘制的要素`)
}else{
if(this.currentGraphical.drawType&&this.currentGraphical.drawType===drawFeature.properties.plotType){
this.widget.updateDrawStyle(this.styleConfig)
}else{
return this.$message.warning(`请切换到对应的样式修改面板`)
}
}
},
//清除
clearDraw() {
let drawFeature=this.widget.plotManager.getSelectedDraw()
if(!drawFeature){
return this.$message.warning(`请先选中绘制的要素`)
}else{
this.widget.plotManager.deleteSelected()
}
/*this.currentSelectedGraphic=null;
if(this.currentGraphical&&this.currentGraphical.drawType){
this.$ArcGIS.graphicsLayerManager.clearGraphicByType(this.currentGraphical.drawType);
}*/
},
/**
* 切换图标类型
* @param {Object} graphical 选择的图标对象
*/
onChangeType(graphical) {
this.$set(this, 'activeId', graphical.id);
this.$set(this, 'activeType', graphical.type);
for(let i=0;i<this.graphicals.length;i++){
this.graphicals[i].selected=false;
}
graphical.selected=true;
this.currentGraphical=graphical;
},
closePanel() {
this.$emit('close')
}
},
}
</script>
<style lang="scss">
.gis-plotting-box {
.el-form-item__label {
color: #ffffff;
}
padding: 10px;
.gis-graphical-wrap {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 25px;
overflow: hidden;
}
.gis-graphical-item {
flex: 1;
}
.gis-graphical-block {
margin: auto;
width: 24px;
height: 24px;
line-height: 24px;
color: #fff;
text-align: center;
background-color: #0b87e7;
border-radius: 3px;
transition: all .3s;
cursor: pointer;
&:hover {
background-color: #316892;
}
&.selected {
background-color: #316892;
}
}
.el-input__inner {
width: 100px;
}
.form-block {
width: 100%;
.el-input__inner {
width: 280px;
}
}
.el-form-item__label {
text-align: left;
}
.el-input-number {
width: 100px;
.el-input__inner {
width: 100px;
padding-right: 40px;
}
}
}
</style>
PlotWidget.js
/**
* @Author :TanShiJun [email protected]
* @Date :2022/5/19
* @Describe :
* Last Modified by : TSJ
* Last Modified time :2022/5/19
**/
import PlotManager from "../../../gis/core/PlotManager";
export default class PlotWidget {
constructor(map,appConfig) {
this.map=map
this.appConfig=appConfig
this.plotManager=PlotManager.getInstance(map,appConfig)
//挂在到全局
global.mapbox3D.plotManager=this.plotManager
}
plottingDraw(type,style,callback){
this.plotManager.startDraw(type,style,(data)=>{
if(callback){
callback(data)
}
})
}
// 更新绘制的样式
updateDrawStyle(style){
debugger
if(this.plotManager.currentSelectFeature&&this.plotManager.currentSelectFeature.properties.isPlotFeature){
const type=this.plotManager.currentSelectFeature.properties.plotType
switch (type) {
case 'POLYGON':
case 'EXTENT':
case 'CIRCLE':
this.plotManager.updatePolygonStyle(this.plotManager.currentSelectFeature.id,style)
break
case 'POLYLINE':
this.plotManager.updatePolylineStyle(this.plotManager.currentSelectFeature.id,style)
break
case 'POINT':
this.plotManager.updatePointStyle(this.plotManager.currentSelectFeature.id,style)
break
case 'FONT':
this.plotManager.updateTextStyle(this.plotManager.currentSelectFeature.id,style)
break
}
this.changeModeForRender(this.plotManager.currentSelectFeature.id,type)
}
}
// 添加模式切换能保证样式改变能重新渲染
changeModeForRender(featureId,type){
if(type!=='POINT'&&type!=='FONT'){
this.plotManager.draw.mapboxDraw.changeMode('simple_select')
this.plotManager.draw.mapboxDraw.changeMode('direct_select',{featureId:featureId})
}else{
this.plotManager.draw.mapboxDraw.changeMode('simple_select')
}
}
static getInstance(_map,_appConfig) {
if (!this.instance) {
this.instance = new PlotWidget(_map,_appConfig)
}
return this.instance
}
}
首先第一步初始化
this.mapboxDraw=new MapboxDraw({
displayControlsDefault: false,
modes,
userProperties: true,
styles,
/*controls: {
polygon: true,
trash: true
}*/
})
function MapboxDraw(options) {
setupDraw(options, this);
}
const setupDraw = function(options, api) {
options = setupOptions(options);
const ctx = {
options
};
api = setupAPI(ctx, api);
ctx.api = api;
const setup = runSetup(ctx);
api.onAdd = setup.onAdd;
api.onRemove = setup.onRemove;
api.types = Constants.types;
api.options = options;
return api;
};
setup中进一步初始化
import events from './events';
import Store from './store';
import ui from './ui';
import * as Constants from './constants';
import xtend from 'xtend';
export default function(ctx) {
let controlContainer = null;
let mapLoadedInterval = null;
const setup = {
onRemove() {
// Stop connect attempt in the event that control is removed before map is loaded
ctx.map.off('load', setup.connect);
clearInterval(mapLoadedInterval);
setup.removeLayers();
ctx.store.restoreMapConfig();
ctx.ui.removeButtons();
ctx.events.removeEventListeners();
ctx.ui.clearMapClasses();
ctx.map = null;
ctx.container = null;
ctx.store = null;
if (controlContainer && controlContainer.parentNode) controlContainer.parentNode.removeChild(controlContainer);
controlContainer = null;
return this;
},
connect() {
ctx.map.off('load', setup.connect);
clearInterval(mapLoadedInterval);
setup.addLayers();
ctx.store.storeMapConfig();
ctx.events.addEventListeners();
},
onAdd(map) {
if (process.env.NODE_ENV !== 'test') {
// Monkey patch to resolve breaking change to `fire` introduced by
// mapbox-gl-js. See mapbox/mapbox-gl-draw/issues/766.
const _fire = map.fire;
map.fire = function(type, event) {
// eslint-disable-next-line
let args = arguments;
if (_fire.length === 1 && arguments.length !== 1) {
args = [xtend({}, { type }, event)];
}
return _fire.apply(map, args);
};
}
ctx.map = map;
ctx.events = events(ctx);
ctx.ui = ui(ctx);
ctx.container = map.getContainer();
ctx.store = new Store(ctx);
controlContainer = ctx.ui.addButtons();
if (ctx.options.boxSelect) {
map.boxZoom.disable();
// Need to toggle dragPan on and off or else first
// dragPan disable attempt in simple_select doesn't work
map.dragPan.disable();
map.dragPan.enable();
}
if (map.loaded()) {
setup.connect();
} else {
map.on('load', setup.connect);
mapLoadedInterval = setInterval(() => { if (map.loaded()) setup.connect(); }, 16);
}
ctx.events.start();
return controlContainer;
},
addLayers() {
// drawn features style
ctx.map.addSource(Constants.sources.COLD, {
data: {
type: Constants.geojsonTypes.FEATURE_COLLECTION,
features: []
},
type: 'geojson'
});
// hot features style
ctx.map.addSource(Constants.sources.HOT, {
data: {
type: Constants.geojsonTypes.FEATURE_COLLECTION,
features: []
},
type: 'geojson'
});
ctx.options.styles.forEach((style) => {
ctx.map.addLayer(style);
});
ctx.store.setDirty(true);
ctx.store.render();
},
// Check for layers and sources before attempting to remove
// If user adds draw control and removes it before the map is loaded, layers and sources will be missing
removeLayers() {
ctx.options.styles.forEach((style) => {
if (ctx.map.getLayer(style.id)) {
ctx.map.removeLayer(style.id);
}
});
if (ctx.map.getSource(Constants.sources.COLD)) {
ctx.map.removeSource(Constants.sources.COLD);
}
if (ctx.map.getSource(Constants.sources.HOT)) {
ctx.map.removeSource(Constants.sources.HOT);
}
}
};
ctx.setup = setup;
return setup;
}
然后执行 setup中的回调函数,当时一直不知道在哪调用这个回调函数的,
直到看了下mapbox源码才发现
addControl(control: IControl, position?: ControlPosition): this {
if (position === undefined) {
if (control.getDefaultPosition) {
position = control.getDefaultPosition();
} else {
position = 'top-right';
}
}
if (!control || !control.onAdd) {
return this.fire(new ErrorEvent(new Error(
'Invalid argument to map.addControl(). Argument must be a control with onAdd and onRemove methods.')));
}
//在此处调用了onAdd方法,我们发现mapbox在添加Control中,必须得定义onAdd和onRemove回调函数
const controlElement = control.onAdd(this);
this._controls.push(control);
const positionContainer = this._controlPositions[position];
if (position.indexOf('bottom') !== -1) {
positionContainer.insertBefore(controlElement, positionContainer.firstChild);
} else {
positionContainer.appendChild(controlElement);
}
return this;
}
后面还封装了测量模块等有时间再写吧,欢迎大家留言讨论 QQ 1826356125
自己花了好几个月写了一个基于mapbox的gis框架,下载地址,能很方便大家学习,也很容易应用到gis展示的项目中,感兴趣加我QQ