control/drawControl/index.js

import MapboxControl from '@mapbox/mapbox-gl-draw';
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
// import distance from '@turf/distance';
// import circle from '@turf/circle';
// import {point} from '@turf/helpers';
import baseUtil from '../../util/baseUtil';

const turf = require('../../tools/turf');

/**
 *@地图绘制控件及绘制方法类
 *@author lc
 *@date 2018-04-09 16:14:16
 */
 class  DrawControl {
    constructor(map, callback) {

        this.callback = callback;                              //回调
        this._map = map;                                       //地图
        this.circleID = `unique-drawCircleID-${baseUtil.guid()}`;
        this.boxID = `unique-drawBoxID-${baseUtil.guid()}`;
        this.mode = MapboxControl.modes;
        this.defaultOptions = {

            modes: this.mode,
            touchEnabled: true,
            keybindings: true,
            displayControlsDefault: false,
            styles: [{
                'id': 'gl-draw-polygon-fill-inactive.cold',
                'type': 'fill',
                'filter': ['all', ['==', 'active', 'false'], ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']],
                'paint': {'fill-color': '#3bb2d0', 'fill-outline-color': '#3bb2d0', 'fill-opacity': 0.1},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-polygon-fill-active.cold',
                'type': 'fill',
                'filter': ['all', ['==', 'active', 'true'], ['==', '$type', 'Polygon']],
                'paint': {'fill-color': '#3bb2d0', 'fill-outline-color': '#3bb2d0', 'fill-opacity': 0.1},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-polygon-midpoint.cold',
                'type': 'circle',
                'filter': ['all', ['==', '$type', 'Point'], ['==', 'meta', 'midpoint']],
                'paint': {'circle-radius': 3, 'circle-color': '#3bb2d0'},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-polygon-stroke-inactive.cold',
                'type': 'line',
                'filter': ['all', ['==', 'active', 'false'], ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#3bb2d0', 'line-width': 2},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-polygon-stroke-active.cold',
                'type': 'line',
                'filter': ['all', ['==', 'active', 'true'], ['==', '$type', 'Polygon']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#3bb2d0', 'line-width': 2},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-line-inactive.cold',
                'type': 'line',
                'filter': ['all', ['==', 'active', 'false'], ['==', '$type', 'LineString'], ['!=', 'mode', 'static']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#3bb2d0', 'line-width': 2},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-line-active.cold',
                'type': 'line',
                'filter': ['all', ['==', '$type', 'LineString'], ['==', 'active', 'true']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#3bb2d0', 'line-width': 2},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-polygon-and-line-vertex-stroke-inactive.cold',
                'type': 'circle',
                'filter': ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point'], ['!=', 'mode', 'static']],
                'paint': {'circle-radius': 5, 'circle-color': '#ff431e'},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-polygon-and-line-vertex-inactive.cold',
                'type': 'circle',
                'filter': ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point'], ['!=', 'mode', 'static']],
                'paint': {'circle-radius': 3, 'circle-color': '#f2f2f2'},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-point-point-stroke-inactive.cold',
                'type': 'circle',
                'filter': ['all', ['==', 'active', 'false'], ['==', '$type', 'Point'], ['==', 'meta', 'feature'], ['!=', 'mode', 'static']],
                'paint': {'circle-radius': 5, 'circle-opacity': 1, 'circle-color': '#fff'},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-point-inactive.cold',
                'type': 'circle',
                'filter': ['all', ['==', 'active', 'false'], ['==', '$type', 'Point'], ['==', 'meta', 'feature'], ['!=', 'mode', 'static']],
                'paint': {'circle-radius': 3, 'circle-color': '#3bb2d0'},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-point-stroke-active.cold',
                'type': 'circle',
                'filter': ['all', ['==', '$type', 'Point'], ['==', 'active', 'true'], ['!=', 'meta', 'midpoint']],
                'paint': {'circle-radius': 7, 'circle-color': '#fff'},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-point-active.cold',
                'type': 'circle',
                'filter': ['all', ['==', '$type', 'Point'], ['!=', 'meta', 'midpoint'], ['==', 'active', 'true']],
                'paint': {'circle-radius': 5, 'circle-color': '#3bb2d0'},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-polygon-fill-static.cold',
                'type': 'fill',
                'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'Polygon']],
                'paint': {'fill-color': '#404040', 'fill-outline-color': '#404040', 'fill-opacity': 0.1},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-polygon-stroke-static.cold',
                'type': 'line',
                'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'Polygon']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#404040', 'line-width': 2},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-line-static.cold',
                'type': 'line',
                'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'LineString']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#404040', 'line-width': 2},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-point-static.cold',
                'type': 'circle',
                'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'Point']],
                'paint': {'circle-radius': 5, 'circle-color': '#404040'},
                'source': 'mapbox-gl-draw-cold'
            }, {
                'id': 'gl-draw-polygon-fill-inactive.hot',
                'type': 'fill',
                'filter': ['all', ['==', 'active', 'false'], ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']],
                'paint': {'fill-color': '#3bb2d0', 'fill-outline-color': '#3bb2d0', 'fill-opacity': 0.1},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-polygon-fill-active.hot',
                'type': 'fill',
                'filter': ['all', ['==', 'active', 'true'], ['==', '$type', 'Polygon']],
                'paint': {'fill-color': '#3bb2d0', 'fill-outline-color': '#3bb2d0', 'fill-opacity': 0.1},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-polygon-midpoint.hot',
                'type': 'circle',
                'filter': ['all', ['==', '$type', 'Point'], ['==', 'meta', 'midpoint']],
                'paint': {'circle-radius': 3, 'circle-color': '#3bb2d0'},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-polygon-stroke-inactive.hot',
                'type': 'line',
                'filter': ['all', ['==', 'active', 'false'], ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#3bb2d0', 'line-width': 2},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-polygon-stroke-active.hot',
                'type': 'line',
                'filter': ['all', ['==', 'active', 'true'], ['==', '$type', 'Polygon']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#3bb2d0', 'line-width': 2},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-line-inactive.hot',
                'type': 'line',
                'filter': ['all', ['==', 'active', 'false'], ['==', '$type', 'LineString'], ['!=', 'mode', 'static']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#3bb2d0', 'line-width': 2},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-line-active.hot',
                'type': 'line',
                'filter': ['all', ['==', '$type', 'LineString'], ['==', 'active', 'true']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#3bb2d0', 'line-width': 2},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-polygon-and-line-vertex-stroke-inactive.hot',
                'type': 'circle',
                'filter': ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point'], ['!=', 'mode', 'static']],
                'paint': {'circle-radius': 5, 'circle-color': '#fff'},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-polygon-and-line-vertex-inactive.hot',
                'type': 'circle',
                'filter': ['all', ['==', 'meta', 'vertex'], ['==', '$type', 'Point'], ['!=', 'mode', 'static']],
                'paint': {'circle-radius': 3, 'circle-color': '#3bb2d0'},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-point-point-stroke-inactive.hot',
                'type': 'circle',
                'filter': ['all', ['==', 'active', 'false'], ['==', '$type', 'Point'], ['==', 'meta', 'feature'], ['!=', 'mode', 'static']],
                'paint': {'circle-radius': 5, 'circle-opacity': 1, 'circle-color': '#fff'},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-point-inactive.hot',
                'type': 'circle',
                'filter': ['all', ['==', 'active', 'false'], ['==', '$type', 'Point'], ['==', 'meta', 'feature'], ['!=', 'mode', 'static']],
                'paint': {'circle-radius': 3, 'circle-color': '#3bb2d0'},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-point-stroke-active.hot',
                'type': 'circle',
                'filter': ['all', ['==', '$type', 'Point'], ['==', 'active', 'true'], ['!=', 'meta', 'midpoint']],
                'paint': {'circle-radius': 7, 'circle-color': '#fff'},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-point-active.hot',
                'type': 'circle',
                'filter': ['all', ['==', '$type', 'Point'], ['!=', 'meta', 'midpoint'], ['==', 'active', 'true']],
                'paint': {'circle-radius': 5, 'circle-color': '#3bb2d0'},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-polygon-fill-static.hot',
                'type': 'fill',
                'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'Polygon']],
                'paint': {'fill-color': '#404040', 'fill-outline-color': '#404040', 'fill-opacity': 0.1},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-polygon-stroke-static.hot',
                'type': 'line',
                'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'Polygon']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#404040', 'line-width': 2},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-line-static.hot',
                'type': 'line',
                'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'LineString']],
                'layout': {'line-cap': 'round', 'line-join': 'round'},
                'paint': {'line-color': '#404040', 'line-width': 2},
                'source': 'mapbox-gl-draw-hot'
            }, {
                'id': 'gl-draw-point-static.hot',
                'type': 'circle',
                'filter': ['all', ['==', 'mode', 'static'], ['==', '$type', 'Point']],
                'paint': {'circle-radius': 5, 'circle-color': '#404040'},
                'source': 'mapbox-gl-draw-hot'
            }]

        };//默认绘制控件选项
        this.Draw = new MapboxControl(this.defaultOptions);    //原生绘制控件对象
        this._map.addControl(this.Draw);

        const geometryCallback = e => {

            this.geometrys = {
                coordinates: e.features[0].geometry.coordinates  //返回绘制图形的几何信息
            };
            if (this.callback) {

                this.callback(this.geometrys);

            }

        };
        this._map.on('draw.create', e => {                        //对原生绘制控件添加绘制完毕的监听

            geometryCallback(e);

        });
        this._map.on('draw.update', e => {                        //对原生绘制控件添加绘制更新的监听

            geometryCallback(e);

        });

    }

    onAdd() {

        //控件模式
        this._map.removeControl(this.Draw);
        this.defaultOptions.controls = {
            'point': 'on',
            'line_string': 'on',
            'trash': 'on',
            'polygon': 'on'
        };
        this.Draw = new MapboxControl(this.defaultOptions);
        this._map.addControl(this.Draw);

        //获取原生控件容器
        this._container = document.getElementsByClassName('mapbox-gl-draw_ctrl-draw-btn mapbox-gl-draw_trash')[0].parentNode;

        //拓展原生控件容器
        let drawCircleButton = document.createElement('button');   //添加绘圆按钮
        drawCircleButton.className = 'mapbox-gl-draw-extent_circle';
        drawCircleButton.onclick = this.drawCircle.bind(this);     //绑定点击事件
        this._container.appendChild(drawCircleButton);

        let drawBoxButton = document.createElement('button');      //添加绘矩形按钮
        drawBoxButton.className = 'mapbox-gl-draw-extent_box';
        drawBoxButton.onclick = this.drawBox.bind(this);           //绑定点击事件
        this._container.appendChild(drawBoxButton);

        return this._container;

    }

    onRemove() {

        this._container.parentNode.removeChild(this._container);
        this._map = undefined;

    }

    /**
     *@绘制圆
     *@author lc
     *@date 2018-04-09 16:25:42
     */
    drawCircle() {

        this.drawSpecialGeometry('circle', this.callback);

    }

    /**
     *@绘制矩形
     *@author lc
     *@date 2018-04-09 16:25:52
     */
    drawBox() {

        this.drawSpecialGeometry('box', this.callback);

    }

    /**
     * 监听鼠标事件生成坐标点
     * @param type('circle','box')
     * @param callback
     */
    drawSpecialGeometry(type, callback) {

        this._map.getCanvas().style.cursor = 'crosshair';
        let drawActive = true;
        let mouseDown = down => {     //鼠标单击事件

            let startPoint = down.lngLat;

            let mouseMove = move => {    //鼠标移动

                mouseDown = () => {  //重新设置鼠标单击事件

                    this._map.off('mousemove', mouseMove); //取消鼠标移动事件
                    mouseMove = null;
                    this._map.getCanvas().style.cursor = '';

                    this._map.off('mousedown', mouseDown); //取消鼠标单击事件
                    mouseDown = null;
                    if (drawActive) {                     //结束绘制,执行回调

                        if (callback) {

                            callback(this.geometrys);

                        }
                        drawActive = false;

                    }

                };

                this._map.on('mousedown', mouseDown);

                let movePoint = move.lngLat;
                switch (type) {
                    case 'circle':
                        this.generateCircleGeometry(startPoint, movePoint);
                        break;
                    case 'box':
                        this.generateBoxGeometry(startPoint, movePoint);
                        break;
                }

            };

            this._map.off('mousedown', mouseDown);
            mouseDown = null;
            this._map.on('mousemove', mouseMove);

        };
        this._map.on('mousedown', mouseDown);

    }

    /**
     * 绘制圆
     * @param startPoint(起点)
     * @param movePoint(移动点)
     */
    generateCircleGeometry(startPoint, movePoint) {

        let from = turf.point([startPoint.lng, startPoint.lat]);
        let to = turf.point([movePoint.lng, movePoint.lat]);
        let options = {units: 'kilometers'};
        let circleOptions = {steps: 10, units: 'kilometers', properties: {foo: 'bar'}};
        let radius = turf.distance(from, to, circleOptions);
        radius = radius === 0 ? 0.00000001 : radius;
        let circleGeometry = turf.circle([startPoint.lng, startPoint.lat], radius, options);//根据中心点和半径获取圆的坐标串

        let coordinates = circleGeometry.geometry.coordinates;
        let feature = {
            id: this.circleID,
            type: 'Feature',
            properties: {},
            geometry: {
                type: 'Polygon', coordinates: coordinates
            }
        };

        this.Draw.add(feature);   //通过绘制控件直接添加圆

        this.geometrys = {        //保存圆的几何信息
            coordinates: coordinates,
            center: [startPoint.lng, startPoint.lat],
            radius: radius * 1000
        };


    }

    /**
     * 绘制矩形
     * @param startPoint(起点)
     * @param movePoint(移动点)
     */
    generateBoxGeometry(startPoint, movePoint) {

        let coordinates = [[[startPoint.lng, startPoint.lat],
            [startPoint.lng, movePoint.lat],
            [movePoint.lng, movePoint.lat],
            [movePoint.lng, startPoint.lat],
            [startPoint.lng, startPoint.lat]]];    //矩形的坐标串
        let feature = {
            id: this.boxID,
            type: 'Feature',
            properties: {},
            geometry: {
                type: 'Polygon', coordinates: coordinates
            }
        };
        this.Draw.add(feature);  //通过绘制控件直接添加矩形
        this.geometrys = {

            coordinates: coordinates
        };

    }

    /**
     * 开始绘制几何图形
     * @param type ('line':绘制线段,'polygon':绘制多边形,'point':绘制点,'circle':绘制圆,'box':绘制矩形框)
     * @param callback(绘制完毕后的回调,返回几何图形的信息)
     */

    drawGeometry(type) {

        // this.Draw = new MapboxControl(this.defaultOptions);
        // this.callback = callback;
        // this.Draw.deleteAll();
        switch (type) {
            case 'line':
                this.Draw.changeMode('draw_line_string');
                break;
            case 'polygon':
                this.Draw.changeMode('draw_polygon');
                break;
            case 'point':
                this.Draw.changeMode('draw_point');
                break;
            default:
                this.drawSpecialGeometry(type, this.callback);
                break;
        }

        return this.Draw;

    }

    getGeometrys() {

        return this.geometrys;

    }

    deleteAll() {

        this.Draw.deleteAll();

    }
}
export default DrawControl;