UNPKG

ol-ext-datatable

Version:
340 lines (314 loc) 11.4 kB
import ol from 'ol' import ol_interaction_Interaction from 'ol/interaction/interaction' import ol_Geolocation from 'ol/geolocation' import ol_style_Circle from 'ol/style/circle' import ol_style_Stroke from 'ol/style/stroke' import ol_geom_Point from 'ol/geom/point' import ol_geom_LineString from 'ol/geom/linestring' import ol_geom_Polygon from 'ol/geom/polygon' import ol_style_Style from 'ol/style/style' import ol_style_RegularShape from 'ol/style/regularshape' import ol_style_Fill from 'ol/style/fill' import ol_layer_Vector from 'ol/layer/vector' import ol_source_Vector from 'ol/source/vector' import ol_Feature from 'ol/feature' import ol_interaction_Pointer from 'ol/interaction/pointer' import ol_extent from 'ol/extent' /** Interaction to draw on the current geolocation * It combines a draw with a ol_Geolocation * @constructor * @extends {ol_interaction_Interaction} * @fires drawstart, drawend, drawing, tracking, follow * @param {olx.interaction.GeolocationDrawOption} options * @param { ol.Collection.<ol.Feature> | undefined } option.features Destination collection for the drawn features. * @param { ol.source.Vector | undefined } options.source Destination source for the drawn features. * @param {ol.geom.GeometryType} options.type Drawing type ('Point', 'LineString', 'Polygon'). Required. * @param {Number | undefined} options.minAccuracy minimum accuracy underneath a new point will be register (if no condition), default 20 * @param {function | undefined} options.condition a function that take a ol_Geolocation object and return a boolean to indicate whether location should be handled or not, default return true if accuraty < minAccuraty * @param {Object} options.attributes a list of attributes to register as Point properties: {accuracy:true,accuracyGeometry:true,heading:true,speed:true}, default none. * @param {Number} options.tolerance tolerance to add a new point (in projection unit), use ol.geom.LineString.simplify() method, default 5 * @param {Number} options.zoom zoom for tracking, default 16 * @param {boolean|auto|position|visible} options.followTrack true if you want the interaction to follow the track on the map, default true * @param { ol.style.Style | Array.<ol.style.Style> | ol.StyleFunction | undefined } options.style Style for sketch features. */ var ol_interaction_GeolocationDraw = function(options) { if (!options) options={}; var self = this; // Geolocation var geoloc = this.geolocation = new ol_Geolocation(/** @type {olx.GeolocationOptions} */ ({ projection: "EPSG:4326", trackingOptions: { maximumAge: 10000, enableHighAccuracy: true, timeout: 600000 } })); this.geolocation.on('change', this.draw_, this); // Current path this.path_ = []; this.lastPosition_ = false; // Default style var white = [255, 255, 255, 1]; var blue = [0, 153, 255, 1]; var width = 3; var circle = new ol_style_Circle( { radius: width * 2, fill: new ol_style_Fill({ color: blue }), stroke: new ol_style_Stroke({ color: white, width: width / 2 }) }); var style = [ new ol_style_Style( { stroke: new ol_style_Stroke({ color: white, width: width + 2 }) }), new ol_style_Style( { stroke: new ol_style_Stroke({ color: blue, width: width }), fill: new ol_style_Fill({ color: [255, 255, 255, 0.5] }) }) ]; var triangle = new ol_style_RegularShape( { radius: width * 3.5, points: 3, rotation: 0, fill: new ol_style_Fill({ color: blue }), stroke: new ol_style_Stroke({ color: white, width: width / 2 }) }); // stretch the symbol var c = triangle.getImage(); var ctx = c.getContext("2d"); var c2 = document.createElement('canvas'); c2.width = c2.height = c.width; c2.getContext("2d").drawImage(c, 0,0); ctx.clearRect(0,0,c.width,c.height); ctx.drawImage(c2, 0,0, c.width, c.height, width, 0, c.width-2*width, c.height); var defaultStyle = function(f) { if (f.get('heading')===undefined) { style[1].setImage(circle); } else { style[1].setImage(triangle); triangle.setRotation( f.get('heading') || 0); } return style; } // Style for the accuracy geometry this.locStyle = { error: new ol_style_Style({ fill: new ol_style_Fill({ color: [255, 0, 0, 0.2] }) }), warn: new ol_style_Style({ fill: new ol_style_Fill({ color: [255, 192, 0, 0.2] }) }), ok: new ol_style_Style({ fill: new ol_style_Fill({ color: [0, 255, 0, 0.2] }) }), }; // Create a new overlay layer for the sketch this.overlayLayer_ = new ol_layer_Vector( { source: new ol_source_Vector(), name:'GeolocationDraw overlay', style: options.style || defaultStyle }); this.sketch_ = [new ol_Feature(), new ol_Feature(), new ol_Feature()]; this.overlayLayer_.getSource().addFeatures(this.sketch_); this.features_ = options.features; this.source_ = options.source; this.condition_ = options.condition || function(loc) { return loc.getAccuracy() < this.get("minAccuracy") }; // Prevent interaction when tracking ol_interaction_Interaction.call(this, { handleEvent: function() { return (!this.get('followTrack') || this.get('followTrack')=='auto');// || !geoloc.getTracking()); } }); this.set("type", options.type||"LineString"); this.set("attributes", options.attributes||{}); this.set("minAccuracy", options.minAccuracy||20); this.set("tolerance", options.tolerance||5); this.set("zoom", options.zoom); this.setFollowTrack (options.followTrack===undefined ? true : options.followTrack); this.setActive(false); }; ol.inherits(ol_interaction_GeolocationDraw, 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_GeolocationDraw.prototype.setMap = function(map) { if (this.getMap()) this.getMap().removeLayer(this.overlayLayer_); ol_interaction_Pointer.prototype.setMap.call (this, map); this.overlayLayer_.setMap(map); if (map) this.geolocation.setProjection(map.getView().getProjection()); }; /** Activate or deactivate the interaction. * @param {boolean} active */ ol_interaction_GeolocationDraw.prototype.setActive = function(active) { ol_interaction_Interaction.prototype.setActive.call(this, active); this.overlayLayer_.setVisible(active); if (this.getMap()) { this.geolocation.setTracking(active); this.getMap().renderSync(); } this.pause(!active); if (active) { // Start drawing this.reset(); this.dispatchEvent({ type:'drawstart', feature: this.sketch_[1]}); } else { var f = this.sketch_[1].clone(); if (f.getGeometry()) { if (this.features_) this.features_.push(f); if (this.source_) this.source_.addFeature(f); this.dispatchEvent({ type:'drawend', feature: f}); } } }; /** Reset drawing */ ol_interaction_GeolocationDraw.prototype.reset = function() { this.sketch_[1].setGeometry(); this.path_ = []; this.lastPosition_ = false; }; /** Start tracking = setActive(true) */ ol_interaction_GeolocationDraw.prototype.start = function() { this.setActive(true); }; /** Stop tracking = setActive(false) */ ol_interaction_GeolocationDraw.prototype.stop = function() { this.setActive(false); }; /** Pause drawing * @param {boolean} b */ ol_interaction_GeolocationDraw.prototype.pause = function(b) { this.pause_ = b!==false; }; /** Enable following the track on the map * @param {boolean|auto|position|visible} follow, * false: don't follow, * true: follow (position+zoom), * 'position': follow only position, * 'auto': start following until user move the map, * 'visible': center when position gets out of the visible extent */ ol_interaction_GeolocationDraw.prototype.setFollowTrack = function(follow) { this.set('followTrack', follow); var map = this.getMap(); // Center if wanted if (follow !== false && !this.lastPosition_ && map) { var pos = this.path_[this.path_.length-1]; if (pos) { map.getView().animate({ center: pos, zoom: (follow!="position" ? this.get("zoom") : undefined) }) } } this.lastPosition_ = false; this.dispatchEvent({ type:'follow', following: follow!==false }); }; /** Add a new point to the current path * @private */ ol_interaction_GeolocationDraw.prototype.draw_ = function(active) { var map = this.getMap(); if (!map) return; // Current location var loc = this.geolocation; var accu = loc.getAccuracy(); var pos = loc.getPosition(); pos.push (Math.round((loc.getAltitude()||0)*100)/100); pos.push (Math.round((new Date()).getTime()/1000)); var p = loc.getAccuracyGeometry(); // Center on point // console.log(this.get('followTrack')) switch (this.get('followTrack')) { // Follow center + zoom case true: // modify zoom if (this.get('followTrack') == true) { map.getView().setZoom( this.get("zoom") || 16 ); if (!ol_extent.containsExtent(map.getView().calculateExtent(map.getSize()), p.getExtent())) { map.getView().fit(p.getExtent()); } } // Follow position case 'position': // modify center map.getView().setCenter( pos ); break; // Keep on following case 'auto': if (this.lastPosition_) { var center = map.getView().getCenter(); // console.log(center,this.lastPosition_) if (center[0]!=this.lastPosition_[0] || center[1]!=this.lastPosition_[1]) { //this.dispatchEvent({ type:'follow', following: false }); this.setFollowTrack (false); } else { map.getView().setCenter( pos ); this.lastPosition_ = pos; } } else { map.getView().setCenter( pos ); if (this.get("zoom")) map.getView().setZoom( this.get("zoom") ); this.lastPosition_ = pos; } break; // Force to stay on the map case 'visible': if (!ol_extent.containsCoordinate(map.getView().calculateExtent(map.getSize()), pos)) { map.getView().setCenter (pos); } break; // Don't follow default: break; } // Draw occuracy var f = this.sketch_[0]; f.setGeometry(p); if (accu < this.get("minAccuracy")/2) f.setStyle(this.locStyle.ok); else if (accu < this.get("minAccuracy")) f.setStyle(this.locStyle.warn); else f.setStyle(this.locStyle.error); var geo; if (!this.pause_ && this.condition_.call(this, loc)) { f = this.sketch_[1]; this.path_.push(pos); switch (this.get("type")) { case "Point": this.path_ = [pos]; f.setGeometry(new ol_geom_Point(pos, 'XYZM')); var attr = this.get('attributes'); if (attr.heading) f.set("heading",loc.getHeading()); if (attr.accuracy) f.set("accuracy",loc.getAccuracy()); if (attr.altitudeAccuracy) f.set("altitudeAccuracy",loc.getAltitudeAccuracy()); if (attr.speed) f.set("speed",loc.getSpeed()); break; case "LineString": if (this.path_.length>1) { geo = new ol_geom_LineString(this.path_, 'XYZM'); geo.simplify (this.get("tolerance")); f.setGeometry(geo); } else f.setGeometry(); break; case "Polygon": if (this.path_.length>2) { geo = new ol_geom_Polygon([this.path_], 'XYZM'); geo.simplify (this.get("tolerance")); f.setGeometry(geo); } else f.setGeometry(); break; } this.dispatchEvent({ type:'drawing', feature: this.sketch_[1], geolocation: loc }); } this.sketch_[2].setGeometry(new ol_geom_Point(pos)); this.sketch_[2].set("heading",loc.getHeading()); // Drawing this.dispatchEvent({ type:'tracking', feature: this.sketch_[1], geolocation: loc }); }; export default ol_interaction_GeolocationDraw