UNPKG

kmap-ui

Version:

A components of zmap base on vue2.X

282 lines (261 loc) 9.6 kB
/* Copyright (c) 2016 Jean-Marc VIGLINO, released under the CeCILL-B license (French BSD license) (http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt). */ import ol_ext_inherits from '../util/ext' import ol_interaction_Interaction from 'ol/interaction/Interaction' import ol_style_Style from 'ol/style/Style' import ol_style_Stroke from 'ol/style/Stroke' import ol_source_Vector from 'ol/source/Vector' import ol_style_Fill from 'ol/style/Fill' import ol_style_Circle from 'ol/style/Circle' import ol_layer_Vector from 'ol/layer/Vector' import ol_geom_Point from 'ol/geom/Point' import ol_Feature from 'ol/Feature' import ol_geom_LineString from 'ol/geom/LineString' import {ol_coordinate_dist2d} from "../geom/GeomUtils"; import '../geom/LineStringSplitAt' /** Interaction split interaction for splitting feature geometry * @constructor * @extends {ol_interaction_Interaction} * @fires beforesplit, aftersplit, pointermove * @param {*} * @param {ol.source.Vector|Array<ol.source.Vector>} options.source a list of source to split (configured with useSpatialIndex set to true) * @param {ol.Collection.<ol.Feature>} options.features collection of feature to split * @param {integer} options.snapDistance distance (in px) to snap to an object, default 25px * @param {string|undefined} options.cursor cursor name to display when hovering an objet * @param {function|undefined} opttion.filter a filter that takes a feature and return true if it can be clipped, default always split. * @param ol_style_Style | Array<ol_style_Style> | false | undefined} options.featureStyle Style for the selected features, choose false if you don't want feature selection. By default the default edit style is used. * @param {ol_style_Style | Array<ol_style_Style> | undefined} options.sketchStyle Style for the sektch features. * @param {function|undefined} options.tolerance Distance between the calculated intersection and a vertex on the source geometry below which the existing vertex will be used for the split. Default is 1e-10. */ var ol_interaction_Split = function(options) { if (!options) options = {}; ol_interaction_Interaction.call(this, { handleEvent: function(e) { switch (e.type) { case "singleclick": return this.handleDownEvent(e); case "pointermove": return this.handleMoveEvent(e); default: return true; } //return true; } }); // Snap distance (in px) this.snapDistance_ = options.snapDistance || 25; // Split tolerance between the calculated intersection and the geometry this.tolerance_ = options.tolerance || 1e-10; // Cursor this.cursor_ = options.cursor; // List of source to split this.sources_ = options.sources ? (options.sources instanceof Array) ? options.sources:[options.sources] : []; if (options.features) { this.sources_.push (new ol_source_Vector({ features: options.features })); } // Get all features candidate this.filterSplit_ = options.filter || function(){ return true; }; // Default style var white = [255, 255, 255, 1]; var blue = [0, 153, 255, 1]; var width = 3; var fill = new ol_style_Fill({ color: 'rgba(255,255,255,0.4)' }); var stroke = new ol_style_Stroke({ color: '#3399CC', width: 1.25 }); var sketchStyle = [ new ol_style_Style({ image: new ol_style_Circle({ fill: fill, stroke: stroke, radius: 5 }), fill: fill, stroke: stroke }) ]; var featureStyle = [ new ol_style_Style({ stroke: new ol_style_Stroke({ color: white, width: width + 2 }) }), new ol_style_Style({ image: new ol_style_Circle({ radius: 2*width, fill: new ol_style_Fill({ color: blue }), stroke: new ol_style_Stroke({ color: white, width: width/2 }) }), stroke: new ol_style_Stroke({ color: blue, width: width }) }), ]; // Custom style if (options.sketchStyle) sketchStyle = options.sketchStyle instanceof Array ? options.sketchStyle : [options.sketchStyle]; if (options.featureStyle) featureStyle = options.featureStyle instanceof Array ? options.featureStyle : [options.featureStyle]; // Create a new overlay for the sketch this.overlayLayer_ = new ol_layer_Vector({ source: new ol_source_Vector({ useSpatialIndex: false }), name:'Split overlay', displayInLayerSwitcher: false, style: function(f) { if (f._sketch_) return sketchStyle; else return featureStyle; } }); }; ol_ext_inherits(ol_interaction_Split, ol_interaction_Interaction); /** * Remove the interaction from its current map, if any, and attach it to a new * map, if any. Pass `null` to just remove the interaction from the current map. * @param {ol.Map} map Map. * @api stable */ ol_interaction_Split.prototype.setMap = function(map) { if (this.getMap()) this.getMap().removeLayer(this.overlayLayer_); ol_interaction_Interaction.prototype.setMap.call (this, map); this.overlayLayer_.setMap(map); }; /** Get closest feature at pixel * @param {ol.Pixel} * @return {ol.feature} * @private */ ol_interaction_Split.prototype.getClosestFeature = function(e) { var source, f, c, g, d = this.snapDistance_+1; // Look for closest point in the sources this.sources_.forEach(function(si) { var fi = si.getClosestFeatureToCoordinate(e.coordinate); if (fi && fi.getGeometry().splitAt) { var ci = fi.getGeometry().getClosestPoint(e.coordinate); var gi = new ol_geom_LineString([e.coordinate,ci]); var di = gi.getLength() / e.frameState.viewState.resolution; if (di < d) { source = si; d = di; f = fi; g = gi; c = ci; } } }); // Snap ? if (d > this.snapDistance_) { return false; } else { // Snap to node var coord = this.getNearestCoord (c, f.getGeometry().getCoordinates()); var p = this.getMap().getPixelFromCoordinate(coord); if (ol_coordinate_dist2d(e.pixel, p) < this.snapDistance_) { c = coord; } // return { source:source, feature:f, coord: c, link: g }; } } /** Get nearest coordinate in a list * @param {ol.coordinate} pt the point to find nearest * @param {Array<ol.coordinate>} coords list of coordinates * @return {ol.coordinate} the nearest coordinate in the list */ ol_interaction_Split.prototype.getNearestCoord = function(pt, coords) { var d, dm=Number.MAX_VALUE, p0; for (var i=0; i < coords.length; i++) { d = ol_coordinate_dist2d (pt, coords[i]); if (d < dm) { dm = d; p0 = coords[i]; } } return p0; }; /** * @param {ol.MapBrowserEvent} evt Map browser event. * @return {boolean} `true` to start the drag sequence. */ ol_interaction_Split.prototype.handleDownEvent = function(evt) { // Something to split ? var current = this.getClosestFeature(evt); if (current) { var self = this; self.overlayLayer_.getSource().clear(); var split = current.feature.getGeometry().splitAt(current.coord, this.tolerance_); var i; if (split.length > 1) { var tosplit = []; for (i=0; i<split.length; i++) { var f = current.feature.clone(); f.setGeometry(split[i]); tosplit.push(f); } self.dispatchEvent({ type:'beforesplit', original: current.feature, features: tosplit }); current.source.dispatchEvent({ type:'beforesplit', original: current.feature, features: tosplit }); current.source.removeFeature(current.feature); for (i=0; i<tosplit.length; i++) { current.source.addFeature(tosplit[i]); } self.dispatchEvent({ type:'aftersplit', original: current.feature, features: tosplit }); current.source.dispatchEvent({ type:'aftersplit', original: current.feature, features: tosplit }); } } return false; }; /** * @param {ol.MapBrowserEvent} evt Event. */ ol_interaction_Split.prototype.handleMoveEvent = function(e) { var map = e.map; this.overlayLayer_.getSource().clear(); var current = this.getClosestFeature(e); if (current && this.filterSplit_(current.feature)) { var p, l; // Draw sketch this.overlayLayer_.getSource().addFeature(current.feature); p = new ol_Feature(new ol_geom_Point(current.coord)); p._sketch_ = true; this.overlayLayer_.getSource().addFeature(p); // l = new ol_Feature(current.link); l._sketch_ = true; this.overlayLayer_.getSource().addFeature(l); // move event this.dispatchEvent({ type: 'pointermove', coordinate: e.coordinate, frameState: e.frameState, originalEvent: e.originalEvent, map: e.map, pixel: e.pixel, feature: current.feature, linkGeometry: current.link }); } else { this.dispatchEvent(e); } var element = map.getTargetElement(); if (this.cursor_) { if (current) { if (element.style.cursor != this.cursor_) { this.previousCursor_ = element.style.cursor; element.style.cursor = this.cursor_; } } else if (this.previousCursor_ !== undefined) { element.style.cursor = this.previousCursor_; this.previousCursor_ = undefined; } } }; export default ol_interaction_Split