ol-ext-datatable
Version:
Datatables version
418 lines (386 loc) • 13.2 kB
JavaScript
/* 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 from 'ol'
import ol_interaction_Interaction from 'ol/interaction/interaction'
import ol_style_Style from 'ol/style/style'
import ol_style_Circle from 'ol/style/circle'
import ol_style_Stroke from 'ol/style/stroke'
import ol_style_Fill from 'ol/style/fill'
import ol_Collection from 'ol/collection'
import ol_layer_Vector from 'ol/layer/vector'
import ol_source_Vector from 'ol/source/vector'
import ol_geom_Circle from 'ol/geom/circle'
import ol_geom_Polygon from 'ol/geom/polygon'
import ol_geom_LineString from 'ol/geom/linestring'
import ol_geom_Point from 'ol/geom/point'
import ol_Feature from 'ol/feature'
/** Interaction rotate
* @constructor
* @extends {ol_interaction_Interaction}
* @fires drawstart, drawing, drawend, drawcancel
* @param {olx.interaction.TransformOptions} options
* @param {Array<ol.Layer>} source Destination source for the drawn features
* @param {ol.Collection<ol.Feature>} features Destination collection for the drawn features
* @param {ol.style.Style | Array.<ol.style.Style> | ol.style.StyleFunction | undefined} style style for the sketch
* @param {integer} sides number of sides, default 0 = circle
* @param { ol.events.ConditionType | undefined } squareCondition A function that takes an ol.MapBrowserEvent and returns a boolean to draw square features.
* @param { ol.events.ConditionType | undefined } centerCondition A function that takes an ol.MapBrowserEvent and returns a boolean to draw centered features.
* @param { bool } canRotate Allow rotation when centered + square, default: true
* @param { number } clickTolerance click tolerance on touch devices, default: 6
* @param { number } maxCircleCoordinates Maximum number of point on a circle, default: 100
*/
var ol_interaction_DrawRegular = function(options)
{ if (!options) options={};
var self = this;
this.squaredClickTolerance_ = options.clickTolerance ? options.clickTolerance * options.clickTolerance : 36;
this.maxCircleCoordinates_ = options.maxCircleCoordinates || 100;
// Collection of feature to transform
this.features_ = options.features;
// List of layers to transform
this.source_ = options.source;
// Square condition
this.squareFn_ = options.squareCondition;
// Centered condition
this.centeredFn_ = options.centerCondition;
// Allow rotation when centered + square
this.canRotate_ = (options.canRotate !== false);
// Number of sides (default=0: circle)
this.setSides(options.sides);
// Style
var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
var defaultStyle = [
new ol_style_Style({
stroke: new ol_style_Stroke({ color: white, width: width + 2 })
}),
new ol_style_Style({
image: new ol_style_Circle({
radius: width * 2,
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 }),
fill: new ol_style_Fill({
color: [255, 255, 255, 0.5]
})
})
];
// Create a new overlay layer for the sketch
this.sketch_ = new ol_Collection();
this.overlayLayer_ = new ol_layer_Vector(
{ source: new ol_source_Vector({
features: this.sketch_,
useSpatialIndex: false
}),
name:'DrawRegular overlay',
displayInLayerSwitcher: false,
style: options.style || defaultStyle
});
ol_interaction_Interaction.call(this,
{
/*
handleDownEvent: this.handleDownEvent_,
handleMoveEvent: this.handleMoveEvent_,
handleUpEvent: this.handleUpEvent_,
*/
handleEvent: this.handleEvent_
});
};
ol.inherits(ol_interaction_DrawRegular, 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_DrawRegular.prototype.setMap = function(map)
{ if (this.getMap()) this.getMap().removeLayer(this.overlayLayer_);
ol_interaction_Interaction.prototype.setMap.call (this, map);
this.overlayLayer_.setMap(map);
};
/**
* Activate/deactivate the interaction
* @param {boolean}
* @api stable
*/
ol_interaction_DrawRegular.prototype.setActive = function(b)
{ this.reset();
ol_interaction_Interaction.prototype.setActive.call (this, b);
}
/**
* Reset the interaction
* @api stable
*/
ol_interaction_DrawRegular.prototype.reset = function()
{ this.overlayLayer_.getSource().clear();
this.started_ = false;
}
/**
* Set the number of sides.
* @param {int} number of sides.
* @api stable
*/
ol_interaction_DrawRegular.prototype.setSides = function (nb)
{ nb = parseInt(nb);
this.sides_ = nb>2 ? nb : 0;
}
/**
* Allow rotation when centered + square
* @param {bool}
* @api stable
*/
ol_interaction_DrawRegular.prototype.canRotate = function (b)
{ if (b===true || b===false) this.canRotate_ = b;
return this.canRotate_;
}
/**
* Get the number of sides.
* @return {int} number of sides.
* @api stable
*/
ol_interaction_DrawRegular.prototype.getSides = function ()
{ return this.sides_;
}
/** Default start angle array for each sides
*/
ol_interaction_DrawRegular.prototype.startAngle =
{ 'default':Math.PI/2,
3: -Math.PI/2,
4: Math.PI/4
};
/** Get geom of the current drawing
* @return {ol.geom.Polygon | ol.geom.Point}
*/
ol_interaction_DrawRegular.prototype.getGeom_ = function ()
{ this.overlayLayer_.getSource().clear();
if (!this.center_) return false;
var g;
if (this.coord_)
{ var center = this.center_;
var coord = this.coord_;
// Special case: circle
if (!this.sides_ && this.square_ && !this.centered_){
center = [(coord[0] + center[0])/2, (coord[1] + center[1])/2];
var d = [coord[0] - center[0], coord[1] - center[1]];
var r = Math.sqrt(d[0]*d[0]+d[1]*d[1]);
var circle = new ol_geom_Circle(center, r, 'XY');
// Optimize points on the circle
var centerPx = this.getMap().getPixelFromCoordinate(center);
var dmax = Math.max (100, Math.abs(centerPx[0]-this.coordPx_[0]), Math.abs(centerPx[1]-this.coordPx_[1]));
dmax = Math.min ( this.maxCircleCoordinates_, Math.round(dmax / 3 ));
return ol_geom_Polygon.fromCircle (circle, dmax, 0);
}
else {
var hasrotation = this.canRotate_ && this.centered_ && this.square_;
var d = [coord[0] - center[0], coord[1] - center[1]];
if (this.square_ && !hasrotation)
{ //var d = [coord[0] - center[0], coord[1] - center[1]];
var dm = Math.max (Math.abs(d[0]), Math.abs(d[1]));
coord[0] = center[0] + (d[0]>0 ? dm:-dm);
coord[1] = center[1] + (d[1]>0 ? dm:-dm);
}
var r = Math.sqrt(d[0]*d[0]+d[1]*d[1]);
if (r>0)
{ var circle = new ol_geom_Circle(center, r, 'XY');
var a;
if (hasrotation) a = Math.atan2(d[1], d[0]);
else a = this.startAngle[this.sides_] || this.startAngle['default'];
if (this.sides_) g = ol_geom_Polygon.fromCircle (circle, this.sides_, a);
else
{ // Optimize points on the circle
var centerPx = this.getMap().getPixelFromCoordinate(this.center_);
var dmax = Math.max (100, Math.abs(centerPx[0]-this.coordPx_[0]), Math.abs(centerPx[1]-this.coordPx_[1]));
dmax = Math.min ( this.maxCircleCoordinates_, Math.round(dmax / (this.centered_ ? 3:5) ));
g = ol_geom_Polygon.fromCircle (circle, dmax, 0);
}
if (hasrotation) return g;
// Scale polygon to fit extent
var ext = g.getExtent();
if (!this.centered_) center = this.center_;
else center = [ 2*this.center_[0]-this.coord_[0], 2*this.center_[1]-this.coord_[1] ];
var scx = (center[0] - coord[0]) / (ext[0] - ext[2]);
var scy = (center[1] - coord[1]) / (ext[1] - ext[3]);
if (this.square_)
{ var sc = Math.min(Math.abs(scx),Math.abs(scy));
scx = Math.sign(scx)*sc;
scy = Math.sign(scy)*sc;
}
var t = [ center[0] - ext[0]*scx, center[1] - ext[1]*scy ];
g.applyTransform(function(g1, g2, dim)
{ for (i=0; i<g1.length; i+=dim)
{ g2[i] = g1[i]*scx + t[0];
g2[i+1] = g1[i+1]*scy + t[1];
}
return g2;
});
return g;
}
}
}
// No geom => return a point
return new ol_geom_Point(this.center_);
};
/** Draw sketch
* @return {ol.Feature} The feature being drawn.
*/
ol_interaction_DrawRegular.prototype.drawSketch_ = function(evt)
{ this.overlayLayer_.getSource().clear();
if (evt)
{ this.square_ = this.squareFn_ ? this.squareFn_(evt) : evt.originalEvent.shiftKey;
this.centered_ = this.centeredFn_ ? this.centeredFn_(evt) : evt.originalEvent.metaKey || evt.originalEvent.ctrlKey;
var g = this.getGeom_();
if (g)
{ var f = this.feature_;
f.setGeometry (g);
this.overlayLayer_.getSource().addFeature(f);
if (this.coord_ && this.square_ && ((this.canRotate_ && this.centered_ && this.coord_) || (!this.sides_ && !this.centered_)))
{ this.overlayLayer_.getSource().addFeature(new ol_Feature(new ol_geom_LineString([this.center_,this.coord_])));
}
return f;
}
}
};
/** Draw sketch (Point)
*/
ol_interaction_DrawRegular.prototype.drawPoint_ = function(pt, noclear)
{ if (!noclear) this.overlayLayer_.getSource().clear();
this.overlayLayer_.getSource().addFeature(new ol_Feature(new ol_geom_Point(pt)));
};
/**
* @param {ol.MapBrowserEvent} evt Map browser event.
*/
ol_interaction_DrawRegular.prototype.handleEvent_ = function(evt)
{ switch (evt.type)
{ case "pointerdown": {
this.downPx_ = evt.pixel;
this.start_(evt);
}
break;
case "pointerup":
// Started and fisrt move
if (this.started_ && this.coord_)
{ var dx = this.downPx_[0] - evt.pixel[0];
var dy = this.downPx_[1] - evt.pixel[1];
if (dx*dx + dy*dy <= this.squaredClickTolerance_)
{ // The pointer has moved
if ( this.lastEvent == "pointermove" )
{ this.end_(evt);
}
// On touch device there is no move event : terminate = click on the same point
else
{ dx = this.upPx_[0] - evt.pixel[0];
dy = this.upPx_[1] - evt.pixel[1];
if ( dx*dx + dy*dy <= this.squaredClickTolerance_)
{ this.end_(evt);
}
else
{ this.handleMoveEvent_(evt);
this.drawPoint_(evt.coordinate,true);
}
}
}
}
this.upPx_ = evt.pixel;
break;
case "pointerdrag":
if (this.started_)
{ var centerPx = this.getMap().getPixelFromCoordinate(this.center_);
var dx = centerPx[0] - evt.pixel[0];
var dy = centerPx[1] - evt.pixel[1];
if (dx*dx + dy*dy <= this.squaredClickTolerance_)
{ this.reset();
}
}
break;
case "pointermove":
if (this.started_)
{ var dx = this.downPx_[0] - evt.pixel[0];
var dy = this.downPx_[1] - evt.pixel[1];
if (dx*dx + dy*dy > this.squaredClickTolerance_)
{ this.handleMoveEvent_(evt);
this.lastEvent = evt.type;
}
}
break;
default:
this.lastEvent = evt.type;
// Prevent zoom in on dblclick
if (this.started_ && evt.type==='dblclick')
{ //evt.stopPropagation();
return false;
}
break;
}
return true;
}
/** Stop drawing.
*/
ol_interaction_DrawRegular.prototype.finishDrawing = function()
{ if (this.started_ && this.coord_)
{ this.end_({ pixel: this.upPx_, coordinate: this.coord_});
}
};
/**
* @param {ol.MapBrowserEvent} evt Event.
*/
ol_interaction_DrawRegular.prototype.handleMoveEvent_ = function(evt)
{ if (this.started_)
{ this.coord_ = evt.coordinate;
this.coordPx_ = evt.pixel;
var f = this.drawSketch_(evt);
this.dispatchEvent({
type:'drawing',
feature: f,
pixel: evt.pixel,
startCoordinate: this.center_,
coordinate: evt.coordinate,
square: this.square_,
centered: this.centered_
});
}
else
{ this.drawPoint_(evt.coordinate);
}
};
/** Start an new draw
* @param {ol.MapBrowserEvent} evt Map browser event.
* @return {boolean} `false` to stop the drag sequence.
*/
ol_interaction_DrawRegular.prototype.start_ = function(evt)
{ if (!this.started_)
{ this.started_ = true;
this.center_ = evt.coordinate;
this.coord_ = null;
var f = this.feature_ = new ol_Feature();
this.drawSketch_(evt);
this.dispatchEvent({ type:'drawstart', feature: f, pixel: evt.pixel, coordinate: evt.coordinate });
}
else
{ this.coord_ = evt.coordinate;
}
};
/** End drawing
* @param {ol.MapBrowserEvent} evt Map browser event.
* @return {boolean} `false` to stop the drag sequence.
*/
ol_interaction_DrawRegular.prototype.end_ = function(evt)
{ this.coord_ = evt.coordinate;
this.started_ = false;
// Add new feature
if (this.coord_ && this.center_[0]!=this.coord_[0] && this.center_[1]!=this.coord_[1])
{ var f = this.feature_;
f.setGeometry(this.getGeom_());
if (this.source_) this.source_.addFeature(f);
else if (this.features_) this.features_.push(f);
this.dispatchEvent({ type:'drawend', feature: f, pixel: evt.pixel, coordinate: evt.coordinate, square: this.square_, centered: this.centered_ });
}
else
{ this.dispatchEvent({ type:'drawcancel', feature: null, pixel: evt.pixel, coordinate: evt.coordinate, square: this.square_, centered: this.centered_ });
}
this.center_ = this.coord_ = null;
this.drawSketch_();
};
export default ol_interaction_DrawRegular