Move interaction event handlers to class methods
This commit is contained in:
@@ -38,7 +38,7 @@ class DragRotateAndZoom extends PointerInteraction {
|
|||||||
|
|
||||||
const options = opt_options ? opt_options : {};
|
const options = opt_options ? opt_options : {};
|
||||||
|
|
||||||
super(options);
|
super(/** @type {import("./Pointer.js").Options} */ (options));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import MultiPolygon from '../geom/MultiPolygon.js';
|
|||||||
import {POINTER_TYPE} from '../pointer/MouseSource.js';
|
import {POINTER_TYPE} from '../pointer/MouseSource.js';
|
||||||
import Point from '../geom/Point.js';
|
import Point from '../geom/Point.js';
|
||||||
import Polygon, {fromCircle, makeRegular} from '../geom/Polygon.js';
|
import Polygon, {fromCircle, makeRegular} from '../geom/Polygon.js';
|
||||||
import PointerInteraction, {handleEvent as handlePointerEvent} from '../interaction/Pointer.js';
|
import PointerInteraction from '../interaction/Pointer.js';
|
||||||
import InteractionProperty from '../interaction/Property.js';
|
import InteractionProperty from '../interaction/Property.js';
|
||||||
import VectorLayer from '../layer/Vector.js';
|
import VectorLayer from '../layer/Vector.js';
|
||||||
import VectorSource from '../source/Vector.js';
|
import VectorSource from '../source/Vector.js';
|
||||||
@@ -186,12 +186,12 @@ class Draw extends PointerInteraction {
|
|||||||
*/
|
*/
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
|
||||||
super({
|
const pointerOptions = /** @type {import("./Pointer.js").Options} */ (options);
|
||||||
handleDownEvent: handleDownEvent,
|
if (!pointerOptions.stopDown) {
|
||||||
handleEvent: handleEvent,
|
pointerOptions.stopDown = FALSE;
|
||||||
handleUpEvent: handleUpEvent,
|
}
|
||||||
stopDown: FALSE
|
|
||||||
});
|
super(pointerOptions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@@ -472,6 +472,123 @@ class Draw extends PointerInteraction {
|
|||||||
return this.overlay_;
|
return this.overlay_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the {@link module:ol/MapBrowserEvent map browser event} and may actually draw or finish the drawing.
|
||||||
|
* @override
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
handleEvent(event) {
|
||||||
|
if (event.originalEvent.type === EventType.CONTEXTMENU) {
|
||||||
|
// Avoid context menu for long taps when drawing on mobile
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
this.freehand_ = this.mode_ !== Mode.POINT && this.freehandCondition_(event);
|
||||||
|
let move = event.type === MapBrowserEventType.POINTERMOVE;
|
||||||
|
let pass = true;
|
||||||
|
if (!this.freehand_ && this.lastDragTime_ && event.type === MapBrowserEventType.POINTERDRAG) {
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - this.lastDragTime_ >= this.dragVertexDelay_) {
|
||||||
|
this.downPx_ = event.pixel;
|
||||||
|
this.shouldHandle_ = !this.freehand_;
|
||||||
|
move = true;
|
||||||
|
} else {
|
||||||
|
this.lastDragTime_ = undefined;
|
||||||
|
}
|
||||||
|
if (this.shouldHandle_ && this.downTimeout_ !== undefined) {
|
||||||
|
clearTimeout(this.downTimeout_);
|
||||||
|
this.downTimeout_ = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.freehand_ &&
|
||||||
|
event.type === MapBrowserEventType.POINTERDRAG &&
|
||||||
|
this.sketchFeature_ !== null) {
|
||||||
|
this.addToDrawing_(event);
|
||||||
|
pass = false;
|
||||||
|
} else if (this.freehand_ &&
|
||||||
|
event.type === MapBrowserEventType.POINTERDOWN) {
|
||||||
|
pass = false;
|
||||||
|
} else if (move) {
|
||||||
|
pass = event.type === MapBrowserEventType.POINTERMOVE;
|
||||||
|
if (pass && this.freehand_) {
|
||||||
|
pass = this.handlePointerMove_(event);
|
||||||
|
} else if (/** @type {MapBrowserPointerEvent} */ (event).pointerEvent.pointerType == POINTER_TYPE ||
|
||||||
|
(event.type === MapBrowserEventType.POINTERDRAG && this.downTimeout_ === undefined)) {
|
||||||
|
this.handlePointerMove_(event);
|
||||||
|
}
|
||||||
|
} else if (event.type === MapBrowserEventType.DBLCLICK) {
|
||||||
|
pass = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.handleEvent(event) && pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDownEvent(event) {
|
||||||
|
this.shouldHandle_ = !this.freehand_;
|
||||||
|
|
||||||
|
if (this.freehand_) {
|
||||||
|
this.downPx_ = event.pixel;
|
||||||
|
if (!this.finishCoordinate_) {
|
||||||
|
this.startDrawing_(event);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (this.condition_(event)) {
|
||||||
|
this.lastDragTime_ = Date.now();
|
||||||
|
this.downTimeout_ = setTimeout(function() {
|
||||||
|
this.handlePointerMove_(new MapBrowserPointerEvent(
|
||||||
|
MapBrowserEventType.POINTERMOVE, event.map, event.pointerEvent, false, event.frameState));
|
||||||
|
}.bind(this), this.dragVertexDelay_);
|
||||||
|
this.downPx_ = event.pixel;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleUpEvent(event) {
|
||||||
|
let pass = true;
|
||||||
|
|
||||||
|
if (this.downTimeout_) {
|
||||||
|
clearTimeout(this.downTimeout_);
|
||||||
|
this.downTimeout_ = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handlePointerMove_(event);
|
||||||
|
|
||||||
|
const circleMode = this.mode_ === Mode.CIRCLE;
|
||||||
|
|
||||||
|
if (this.shouldHandle_) {
|
||||||
|
if (!this.finishCoordinate_) {
|
||||||
|
this.startDrawing_(event);
|
||||||
|
if (this.mode_ === Mode.POINT) {
|
||||||
|
this.finishDrawing();
|
||||||
|
}
|
||||||
|
} else if (this.freehand_ || circleMode) {
|
||||||
|
this.finishDrawing();
|
||||||
|
} else if (this.atFinish_(event)) {
|
||||||
|
if (this.finishCondition_(event)) {
|
||||||
|
this.finishDrawing();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.addToDrawing_(event);
|
||||||
|
}
|
||||||
|
pass = false;
|
||||||
|
} else if (this.freehand_) {
|
||||||
|
this.finishCoordinate_ = null;
|
||||||
|
this.abortDrawing_();
|
||||||
|
}
|
||||||
|
if (!pass && this.stopClick_) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle move events.
|
* Handle move events.
|
||||||
* @param {import("../MapBrowserEvent.js").default} event A move event.
|
* @param {import("../MapBrowserEvent.js").default} event A move event.
|
||||||
@@ -842,132 +959,6 @@ function getDefaultStyleFunction() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the {@link module:ol/MapBrowserEvent map browser event} and may actually
|
|
||||||
* draw or finish the drawing.
|
|
||||||
* @param {import("../MapBrowserEvent.js").default} event Map browser event.
|
|
||||||
* @return {boolean} `false` to stop event propagation.
|
|
||||||
* @this {Draw}
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
export function handleEvent(event) {
|
|
||||||
if (event.originalEvent.type === EventType.CONTEXTMENU) {
|
|
||||||
// Avoid context menu for long taps when drawing on mobile
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
this.freehand_ = this.mode_ !== Mode.POINT && this.freehandCondition_(event);
|
|
||||||
let move = event.type === MapBrowserEventType.POINTERMOVE;
|
|
||||||
let pass = true;
|
|
||||||
if (!this.freehand_ && this.lastDragTime_ && event.type === MapBrowserEventType.POINTERDRAG) {
|
|
||||||
const now = Date.now();
|
|
||||||
if (now - this.lastDragTime_ >= this.dragVertexDelay_) {
|
|
||||||
this.downPx_ = event.pixel;
|
|
||||||
this.shouldHandle_ = !this.freehand_;
|
|
||||||
move = true;
|
|
||||||
} else {
|
|
||||||
this.lastDragTime_ = undefined;
|
|
||||||
}
|
|
||||||
if (this.shouldHandle_ && this.downTimeout_ !== undefined) {
|
|
||||||
clearTimeout(this.downTimeout_);
|
|
||||||
this.downTimeout_ = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.freehand_ &&
|
|
||||||
event.type === MapBrowserEventType.POINTERDRAG &&
|
|
||||||
this.sketchFeature_ !== null) {
|
|
||||||
this.addToDrawing_(event);
|
|
||||||
pass = false;
|
|
||||||
} else if (this.freehand_ &&
|
|
||||||
event.type === MapBrowserEventType.POINTERDOWN) {
|
|
||||||
pass = false;
|
|
||||||
} else if (move) {
|
|
||||||
pass = event.type === MapBrowserEventType.POINTERMOVE;
|
|
||||||
if (pass && this.freehand_) {
|
|
||||||
pass = this.handlePointerMove_(event);
|
|
||||||
} else if (/** @type {MapBrowserPointerEvent} */ (event).pointerEvent.pointerType == POINTER_TYPE ||
|
|
||||||
(event.type === MapBrowserEventType.POINTERDRAG && this.downTimeout_ === undefined)) {
|
|
||||||
this.handlePointerMove_(event);
|
|
||||||
}
|
|
||||||
} else if (event.type === MapBrowserEventType.DBLCLICK) {
|
|
||||||
pass = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return handlePointerEvent.call(this, event) && pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {MapBrowserPointerEvent} event Event.
|
|
||||||
* @return {boolean} Start drag sequence?
|
|
||||||
* @this {Draw}
|
|
||||||
*/
|
|
||||||
function handleDownEvent(event) {
|
|
||||||
this.shouldHandle_ = !this.freehand_;
|
|
||||||
|
|
||||||
if (this.freehand_) {
|
|
||||||
this.downPx_ = event.pixel;
|
|
||||||
if (!this.finishCoordinate_) {
|
|
||||||
this.startDrawing_(event);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else if (this.condition_(event)) {
|
|
||||||
this.lastDragTime_ = Date.now();
|
|
||||||
this.downTimeout_ = setTimeout(function() {
|
|
||||||
this.handlePointerMove_(new MapBrowserPointerEvent(
|
|
||||||
MapBrowserEventType.POINTERMOVE, event.map, event.pointerEvent, false, event.frameState));
|
|
||||||
}.bind(this), this.dragVertexDelay_);
|
|
||||||
this.downPx_ = event.pixel;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {MapBrowserPointerEvent} event Event.
|
|
||||||
* @return {boolean} Stop drag sequence?
|
|
||||||
* @this {Draw}
|
|
||||||
*/
|
|
||||||
function handleUpEvent(event) {
|
|
||||||
let pass = true;
|
|
||||||
|
|
||||||
if (this.downTimeout_) {
|
|
||||||
clearTimeout(this.downTimeout_);
|
|
||||||
this.downTimeout_ = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.handlePointerMove_(event);
|
|
||||||
|
|
||||||
const circleMode = this.mode_ === Mode.CIRCLE;
|
|
||||||
|
|
||||||
if (this.shouldHandle_) {
|
|
||||||
if (!this.finishCoordinate_) {
|
|
||||||
this.startDrawing_(event);
|
|
||||||
if (this.mode_ === Mode.POINT) {
|
|
||||||
this.finishDrawing();
|
|
||||||
}
|
|
||||||
} else if (this.freehand_ || circleMode) {
|
|
||||||
this.finishDrawing();
|
|
||||||
} else if (this.atFinish_(event)) {
|
|
||||||
if (this.finishCondition_(event)) {
|
|
||||||
this.finishDrawing();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.addToDrawing_(event);
|
|
||||||
}
|
|
||||||
pass = false;
|
|
||||||
} else if (this.freehand_) {
|
|
||||||
this.finishCoordinate_ = null;
|
|
||||||
this.abortDrawing_();
|
|
||||||
}
|
|
||||||
if (!pass && this.stopClick_) {
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
return pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a `geometryFunction` for `type: 'Circle'` that will create a regular
|
* Create a `geometryFunction` for `type: 'Circle'` that will create a regular
|
||||||
* polygon with a user specified number of sides and start angle instead of an
|
* polygon with a user specified number of sides and start angle instead of an
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {boundingExtent, getArea} from '../extent.js';
|
|||||||
import GeometryType from '../geom/GeometryType.js';
|
import GeometryType from '../geom/GeometryType.js';
|
||||||
import Point from '../geom/Point.js';
|
import Point from '../geom/Point.js';
|
||||||
import {fromExtent as polygonFromExtent} from '../geom/Polygon.js';
|
import {fromExtent as polygonFromExtent} from '../geom/Polygon.js';
|
||||||
import PointerInteraction, {handleEvent as handlePointerEvent} from '../interaction/Pointer.js';
|
import PointerInteraction from '../interaction/Pointer.js';
|
||||||
import VectorLayer from '../layer/Vector.js';
|
import VectorLayer from '../layer/Vector.js';
|
||||||
import VectorSource from '../source/Vector.js';
|
import VectorSource from '../source/Vector.js';
|
||||||
import {createEditingStyle} from '../style/Style.js';
|
import {createEditingStyle} from '../style/Style.js';
|
||||||
@@ -85,15 +85,10 @@ class ExtentInteraction extends PointerInteraction {
|
|||||||
*/
|
*/
|
||||||
constructor(opt_options) {
|
constructor(opt_options) {
|
||||||
|
|
||||||
super({
|
|
||||||
handleDownEvent: handleDownEvent,
|
|
||||||
handleDragEvent: handleDragEvent,
|
|
||||||
handleEvent: handleEvent,
|
|
||||||
handleUpEvent: handleUpEvent
|
|
||||||
});
|
|
||||||
|
|
||||||
const options = opt_options || {};
|
const options = opt_options || {};
|
||||||
|
|
||||||
|
super(/** @type {import("./Pointer.js").Options} */ (options));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extent of the drawn box
|
* Extent of the drawn box
|
||||||
* @type {import("../extent.js").Extent}
|
* @type {import("../extent.js").Extent}
|
||||||
@@ -277,6 +272,105 @@ class ExtentInteraction extends PointerInteraction {
|
|||||||
return vertexFeature;
|
return vertexFeature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleEvent(mapBrowserEvent) {
|
||||||
|
if (!(mapBrowserEvent instanceof MapBrowserPointerEvent)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//display pointer (if not dragging)
|
||||||
|
if (mapBrowserEvent.type == MapBrowserEventType.POINTERMOVE && !this.handlingDownUpSequence) {
|
||||||
|
this.handlePointerMove_(mapBrowserEvent);
|
||||||
|
}
|
||||||
|
//call pointer to determine up/down/drag
|
||||||
|
super.handleEvent(mapBrowserEvent);
|
||||||
|
//return false to stop propagation
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDownEvent(mapBrowserEvent) {
|
||||||
|
const pixel = mapBrowserEvent.pixel;
|
||||||
|
const map = mapBrowserEvent.map;
|
||||||
|
|
||||||
|
const extent = this.getExtent();
|
||||||
|
let vertex = this.snapToVertex_(pixel, map);
|
||||||
|
|
||||||
|
//find the extent corner opposite the passed corner
|
||||||
|
const getOpposingPoint = function(point) {
|
||||||
|
let x_ = null;
|
||||||
|
let y_ = null;
|
||||||
|
if (point[0] == extent[0]) {
|
||||||
|
x_ = extent[2];
|
||||||
|
} else if (point[0] == extent[2]) {
|
||||||
|
x_ = extent[0];
|
||||||
|
}
|
||||||
|
if (point[1] == extent[1]) {
|
||||||
|
y_ = extent[3];
|
||||||
|
} else if (point[1] == extent[3]) {
|
||||||
|
y_ = extent[1];
|
||||||
|
}
|
||||||
|
if (x_ !== null && y_ !== null) {
|
||||||
|
return [x_, y_];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
if (vertex && extent) {
|
||||||
|
const x = (vertex[0] == extent[0] || vertex[0] == extent[2]) ? vertex[0] : null;
|
||||||
|
const y = (vertex[1] == extent[1] || vertex[1] == extent[3]) ? vertex[1] : null;
|
||||||
|
|
||||||
|
//snap to point
|
||||||
|
if (x !== null && y !== null) {
|
||||||
|
this.pointerHandler_ = getPointHandler(getOpposingPoint(vertex));
|
||||||
|
//snap to edge
|
||||||
|
} else if (x !== null) {
|
||||||
|
this.pointerHandler_ = getEdgeHandler(
|
||||||
|
getOpposingPoint([x, extent[1]]),
|
||||||
|
getOpposingPoint([x, extent[3]])
|
||||||
|
);
|
||||||
|
} else if (y !== null) {
|
||||||
|
this.pointerHandler_ = getEdgeHandler(
|
||||||
|
getOpposingPoint([extent[0], y]),
|
||||||
|
getOpposingPoint([extent[2], y])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//no snap - new bbox
|
||||||
|
} else {
|
||||||
|
vertex = map.getCoordinateFromPixel(pixel);
|
||||||
|
this.setExtent([vertex[0], vertex[1], vertex[0], vertex[1]]);
|
||||||
|
this.pointerHandler_ = getPointHandler(vertex);
|
||||||
|
}
|
||||||
|
return true; //event handled; start downup sequence
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDragEvent(mapBrowserEvent) {
|
||||||
|
if (this.pointerHandler_) {
|
||||||
|
const pixelCoordinate = mapBrowserEvent.coordinate;
|
||||||
|
this.setExtent(this.pointerHandler_(pixelCoordinate));
|
||||||
|
this.createOrUpdatePointerFeature_(pixelCoordinate);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleUpEvent(mapBrowserEvent) {
|
||||||
|
this.pointerHandler_ = null;
|
||||||
|
//If bbox is zero area, set to null;
|
||||||
|
const extent = this.getExtent();
|
||||||
|
if (!extent || getArea(extent) === 0) {
|
||||||
|
this.setExtent(null);
|
||||||
|
}
|
||||||
|
return false; //Stop handling downup sequence
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
@@ -310,113 +404,6 @@ class ExtentInteraction extends PointerInteraction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event.
|
|
||||||
* @return {boolean} Propagate event?
|
|
||||||
* @this {ExtentInteraction}
|
|
||||||
*/
|
|
||||||
function handleEvent(mapBrowserEvent) {
|
|
||||||
if (!(mapBrowserEvent instanceof MapBrowserPointerEvent)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
//display pointer (if not dragging)
|
|
||||||
if (mapBrowserEvent.type == MapBrowserEventType.POINTERMOVE && !this.handlingDownUpSequence) {
|
|
||||||
this.handlePointerMove_(mapBrowserEvent);
|
|
||||||
}
|
|
||||||
//call pointer to determine up/down/drag
|
|
||||||
handlePointerEvent.call(this, mapBrowserEvent);
|
|
||||||
//return false to stop propagation
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Event.
|
|
||||||
* @return {boolean} Event handled?
|
|
||||||
* @this {ExtentInteraction}
|
|
||||||
*/
|
|
||||||
function handleDownEvent(mapBrowserEvent) {
|
|
||||||
const pixel = mapBrowserEvent.pixel;
|
|
||||||
const map = mapBrowserEvent.map;
|
|
||||||
|
|
||||||
const extent = this.getExtent();
|
|
||||||
let vertex = this.snapToVertex_(pixel, map);
|
|
||||||
|
|
||||||
//find the extent corner opposite the passed corner
|
|
||||||
const getOpposingPoint = function(point) {
|
|
||||||
let x_ = null;
|
|
||||||
let y_ = null;
|
|
||||||
if (point[0] == extent[0]) {
|
|
||||||
x_ = extent[2];
|
|
||||||
} else if (point[0] == extent[2]) {
|
|
||||||
x_ = extent[0];
|
|
||||||
}
|
|
||||||
if (point[1] == extent[1]) {
|
|
||||||
y_ = extent[3];
|
|
||||||
} else if (point[1] == extent[3]) {
|
|
||||||
y_ = extent[1];
|
|
||||||
}
|
|
||||||
if (x_ !== null && y_ !== null) {
|
|
||||||
return [x_, y_];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
if (vertex && extent) {
|
|
||||||
const x = (vertex[0] == extent[0] || vertex[0] == extent[2]) ? vertex[0] : null;
|
|
||||||
const y = (vertex[1] == extent[1] || vertex[1] == extent[3]) ? vertex[1] : null;
|
|
||||||
|
|
||||||
//snap to point
|
|
||||||
if (x !== null && y !== null) {
|
|
||||||
this.pointerHandler_ = getPointHandler(getOpposingPoint(vertex));
|
|
||||||
//snap to edge
|
|
||||||
} else if (x !== null) {
|
|
||||||
this.pointerHandler_ = getEdgeHandler(
|
|
||||||
getOpposingPoint([x, extent[1]]),
|
|
||||||
getOpposingPoint([x, extent[3]])
|
|
||||||
);
|
|
||||||
} else if (y !== null) {
|
|
||||||
this.pointerHandler_ = getEdgeHandler(
|
|
||||||
getOpposingPoint([extent[0], y]),
|
|
||||||
getOpposingPoint([extent[2], y])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
//no snap - new bbox
|
|
||||||
} else {
|
|
||||||
vertex = map.getCoordinateFromPixel(pixel);
|
|
||||||
this.setExtent([vertex[0], vertex[1], vertex[0], vertex[1]]);
|
|
||||||
this.pointerHandler_ = getPointHandler(vertex);
|
|
||||||
}
|
|
||||||
return true; //event handled; start downup sequence
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Event.
|
|
||||||
* @return {boolean} Event handled?
|
|
||||||
* @this {ExtentInteraction}
|
|
||||||
*/
|
|
||||||
function handleDragEvent(mapBrowserEvent) {
|
|
||||||
if (this.pointerHandler_) {
|
|
||||||
const pixelCoordinate = mapBrowserEvent.coordinate;
|
|
||||||
this.setExtent(this.pointerHandler_(pixelCoordinate));
|
|
||||||
this.createOrUpdatePointerFeature_(pixelCoordinate);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Event.
|
|
||||||
* @return {boolean} Stop drag sequence?
|
|
||||||
* @this {ExtentInteraction}
|
|
||||||
*/
|
|
||||||
function handleUpEvent(mapBrowserEvent) {
|
|
||||||
this.pointerHandler_ = null;
|
|
||||||
//If bbox is zero area, set to null;
|
|
||||||
const extent = this.getExtent();
|
|
||||||
if (!extent || getArea(extent) === 0) {
|
|
||||||
this.setExtent(null);
|
|
||||||
}
|
|
||||||
return false; //Stop handling downup sequence
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default style for the drawn bbox
|
* Returns the default style for the drawn bbox
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ class Interaction extends BaseObject {
|
|||||||
constructor(options) {
|
constructor(options) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
if (options.handleEvent) {
|
||||||
|
this.handleEvent = options.handleEvent;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {import("../PluggableMap.js").default}
|
* @type {import("../PluggableMap.js").default}
|
||||||
@@ -45,12 +49,6 @@ class Interaction extends BaseObject {
|
|||||||
this.map_ = null;
|
this.map_ = null;
|
||||||
|
|
||||||
this.setActive(true);
|
this.setActive(true);
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {function(import("../MapBrowserEvent.js").default):boolean}
|
|
||||||
*/
|
|
||||||
this.handleEvent = options.handleEvent;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,6 +70,16 @@ class Interaction extends BaseObject {
|
|||||||
return this.map_;
|
return this.map_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the {@link module:ol/MapBrowserEvent map browser event}.
|
||||||
|
* @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
|
||||||
|
* @return {boolean} `false` to stop event propagation.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
handleEvent(mapBrowserEvent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate or deactivate the interaction.
|
* Activate or deactivate the interaction.
|
||||||
* @param {boolean} active Active.
|
* @param {boolean} active Active.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import {always, primaryAction, altKeyOnly, singleClick} from '../events/conditio
|
|||||||
import {boundingExtent, buffer, createOrUpdateFromCoordinate} from '../extent.js';
|
import {boundingExtent, buffer, createOrUpdateFromCoordinate} from '../extent.js';
|
||||||
import GeometryType from '../geom/GeometryType.js';
|
import GeometryType from '../geom/GeometryType.js';
|
||||||
import Point from '../geom/Point.js';
|
import Point from '../geom/Point.js';
|
||||||
import PointerInteraction, {handleEvent as handlePointerEvent} from '../interaction/Pointer.js';
|
import PointerInteraction from '../interaction/Pointer.js';
|
||||||
import VectorLayer from '../layer/Vector.js';
|
import VectorLayer from '../layer/Vector.js';
|
||||||
import VectorSource from '../source/Vector.js';
|
import VectorSource from '../source/Vector.js';
|
||||||
import VectorEventType from '../source/VectorEventType.js';
|
import VectorEventType from '../source/VectorEventType.js';
|
||||||
@@ -157,12 +157,7 @@ class Modify extends PointerInteraction {
|
|||||||
*/
|
*/
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
|
||||||
super({
|
super(/** @type {import("./Pointer.js").Options} */ (options));
|
||||||
handleDownEvent: handleDownEvent,
|
|
||||||
handleDragEvent: handleDragEvent,
|
|
||||||
handleEvent: handleEvent,
|
|
||||||
handleUpEvent: handleUpEvent
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -170,7 +165,6 @@ class Modify extends PointerInteraction {
|
|||||||
*/
|
*/
|
||||||
this.condition_ = options.condition ? options.condition : primaryAction;
|
this.condition_ = options.condition ? options.condition : primaryAction;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Browser event.
|
* @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Browser event.
|
||||||
@@ -667,6 +661,211 @@ class Modify extends PointerInteraction {
|
|||||||
return vertexFeature;
|
return vertexFeature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the {@link module:ol/MapBrowserEvent map browser event} and may modify the geometry.
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
handleEvent(mapBrowserEvent) {
|
||||||
|
if (!(mapBrowserEvent instanceof MapBrowserPointerEvent)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
this.lastPointerEvent_ = mapBrowserEvent;
|
||||||
|
|
||||||
|
let handled;
|
||||||
|
if (!mapBrowserEvent.map.getView().getInteracting() &&
|
||||||
|
mapBrowserEvent.type == MapBrowserEventType.POINTERMOVE &&
|
||||||
|
!this.handlingDownUpSequence) {
|
||||||
|
this.handlePointerMove_(mapBrowserEvent);
|
||||||
|
}
|
||||||
|
if (this.vertexFeature_ && this.deleteCondition_(mapBrowserEvent)) {
|
||||||
|
if (mapBrowserEvent.type != MapBrowserEventType.SINGLECLICK || !this.ignoreNextSingleClick_) {
|
||||||
|
handled = this.removePoint();
|
||||||
|
} else {
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapBrowserEvent.type == MapBrowserEventType.SINGLECLICK) {
|
||||||
|
this.ignoreNextSingleClick_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.handleEvent(mapBrowserEvent) && !handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDragEvent(evt) {
|
||||||
|
this.ignoreNextSingleClick_ = false;
|
||||||
|
this.willModifyFeatures_(evt);
|
||||||
|
|
||||||
|
const vertex = evt.coordinate;
|
||||||
|
for (let i = 0, ii = this.dragSegments_.length; i < ii; ++i) {
|
||||||
|
const dragSegment = this.dragSegments_[i];
|
||||||
|
const segmentData = dragSegment[0];
|
||||||
|
const depth = segmentData.depth;
|
||||||
|
const geometry = segmentData.geometry;
|
||||||
|
let coordinates;
|
||||||
|
const segment = segmentData.segment;
|
||||||
|
const index = dragSegment[1];
|
||||||
|
|
||||||
|
while (vertex.length < geometry.getStride()) {
|
||||||
|
vertex.push(segment[index][vertex.length]);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (geometry.getType()) {
|
||||||
|
case GeometryType.POINT:
|
||||||
|
coordinates = vertex;
|
||||||
|
segment[0] = segment[1] = vertex;
|
||||||
|
break;
|
||||||
|
case GeometryType.MULTI_POINT:
|
||||||
|
coordinates = geometry.getCoordinates();
|
||||||
|
coordinates[segmentData.index] = vertex;
|
||||||
|
segment[0] = segment[1] = vertex;
|
||||||
|
break;
|
||||||
|
case GeometryType.LINE_STRING:
|
||||||
|
coordinates = geometry.getCoordinates();
|
||||||
|
coordinates[segmentData.index + index] = vertex;
|
||||||
|
segment[index] = vertex;
|
||||||
|
break;
|
||||||
|
case GeometryType.MULTI_LINE_STRING:
|
||||||
|
coordinates = geometry.getCoordinates();
|
||||||
|
coordinates[depth[0]][segmentData.index + index] = vertex;
|
||||||
|
segment[index] = vertex;
|
||||||
|
break;
|
||||||
|
case GeometryType.POLYGON:
|
||||||
|
coordinates = geometry.getCoordinates();
|
||||||
|
coordinates[depth[0]][segmentData.index + index] = vertex;
|
||||||
|
segment[index] = vertex;
|
||||||
|
break;
|
||||||
|
case GeometryType.MULTI_POLYGON:
|
||||||
|
coordinates = geometry.getCoordinates();
|
||||||
|
coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex;
|
||||||
|
segment[index] = vertex;
|
||||||
|
break;
|
||||||
|
case GeometryType.CIRCLE:
|
||||||
|
segment[0] = segment[1] = vertex;
|
||||||
|
if (segmentData.index === CIRCLE_CENTER_INDEX) {
|
||||||
|
this.changingFeature_ = true;
|
||||||
|
geometry.setCenter(vertex);
|
||||||
|
this.changingFeature_ = false;
|
||||||
|
} else { // We're dragging the circle's circumference:
|
||||||
|
this.changingFeature_ = true;
|
||||||
|
geometry.setRadius(coordinateDistance(geometry.getCenter(), vertex));
|
||||||
|
this.changingFeature_ = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coordinates) {
|
||||||
|
this.setGeometryCoordinates_(geometry, coordinates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.createOrUpdateVertexFeature_(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDownEvent(evt) {
|
||||||
|
if (!this.condition_(evt)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.handlePointerAtPixel_(evt.pixel, evt.map);
|
||||||
|
const pixelCoordinate = evt.map.getCoordinateFromPixel(evt.pixel);
|
||||||
|
this.dragSegments_.length = 0;
|
||||||
|
this.modified_ = false;
|
||||||
|
const vertexFeature = this.vertexFeature_;
|
||||||
|
if (vertexFeature) {
|
||||||
|
const insertVertices = [];
|
||||||
|
const geometry = /** @type {Point} */ (vertexFeature.getGeometry());
|
||||||
|
const vertex = geometry.getCoordinates();
|
||||||
|
const vertexExtent = boundingExtent([vertex]);
|
||||||
|
const segmentDataMatches = this.rBush_.getInExtent(vertexExtent);
|
||||||
|
const componentSegments = {};
|
||||||
|
segmentDataMatches.sort(compareIndexes);
|
||||||
|
for (let i = 0, ii = segmentDataMatches.length; i < ii; ++i) {
|
||||||
|
const segmentDataMatch = segmentDataMatches[i];
|
||||||
|
const segment = segmentDataMatch.segment;
|
||||||
|
let uid = String(getUid(segmentDataMatch.feature));
|
||||||
|
const depth = segmentDataMatch.depth;
|
||||||
|
if (depth) {
|
||||||
|
uid += '-' + depth.join('-'); // separate feature components
|
||||||
|
}
|
||||||
|
if (!componentSegments[uid]) {
|
||||||
|
componentSegments[uid] = new Array(2);
|
||||||
|
}
|
||||||
|
if (segmentDataMatch.geometry.getType() === GeometryType.CIRCLE &&
|
||||||
|
segmentDataMatch.index === CIRCLE_CIRCUMFERENCE_INDEX) {
|
||||||
|
|
||||||
|
const closestVertex = closestOnSegmentData(pixelCoordinate, segmentDataMatch);
|
||||||
|
if (coordinatesEqual(closestVertex, vertex) && !componentSegments[uid][0]) {
|
||||||
|
this.dragSegments_.push([segmentDataMatch, 0]);
|
||||||
|
componentSegments[uid][0] = segmentDataMatch;
|
||||||
|
}
|
||||||
|
} else if (coordinatesEqual(segment[0], vertex) &&
|
||||||
|
!componentSegments[uid][0]) {
|
||||||
|
this.dragSegments_.push([segmentDataMatch, 0]);
|
||||||
|
componentSegments[uid][0] = segmentDataMatch;
|
||||||
|
} else if (coordinatesEqual(segment[1], vertex) &&
|
||||||
|
!componentSegments[uid][1]) {
|
||||||
|
|
||||||
|
// prevent dragging closed linestrings by the connecting node
|
||||||
|
if ((segmentDataMatch.geometry.getType() ===
|
||||||
|
GeometryType.LINE_STRING ||
|
||||||
|
segmentDataMatch.geometry.getType() ===
|
||||||
|
GeometryType.MULTI_LINE_STRING) &&
|
||||||
|
componentSegments[uid][0] &&
|
||||||
|
componentSegments[uid][0].index === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dragSegments_.push([segmentDataMatch, 1]);
|
||||||
|
componentSegments[uid][1] = segmentDataMatch;
|
||||||
|
} else if (this.insertVertexCondition_(evt) && getUid(segment) in this.vertexSegments_ &&
|
||||||
|
(!componentSegments[uid][0] && !componentSegments[uid][1])) {
|
||||||
|
insertVertices.push([segmentDataMatch, vertex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (insertVertices.length) {
|
||||||
|
this.willModifyFeatures_(evt);
|
||||||
|
}
|
||||||
|
for (let j = insertVertices.length - 1; j >= 0; --j) {
|
||||||
|
this.insertVertex_.apply(this, insertVertices[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !!this.vertexFeature_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleUpEvent(evt) {
|
||||||
|
for (let i = this.dragSegments_.length - 1; i >= 0; --i) {
|
||||||
|
const segmentData = this.dragSegments_[i][0];
|
||||||
|
const geometry = segmentData.geometry;
|
||||||
|
if (geometry.getType() === GeometryType.CIRCLE) {
|
||||||
|
// Update a circle object in the R* bush:
|
||||||
|
const coordinates = geometry.getCenter();
|
||||||
|
const centerSegmentData = segmentData.featureSegments[0];
|
||||||
|
const circumferenceSegmentData = segmentData.featureSegments[1];
|
||||||
|
centerSegmentData.segment[0] = centerSegmentData.segment[1] = coordinates;
|
||||||
|
circumferenceSegmentData.segment[0] = circumferenceSegmentData.segment[1] = coordinates;
|
||||||
|
this.rBush_.update(createOrUpdateFromCoordinate(coordinates), centerSegmentData);
|
||||||
|
this.rBush_.update(geometry.getExtent(), circumferenceSegmentData);
|
||||||
|
} else {
|
||||||
|
this.rBush_.update(boundingExtent(segmentData.segment), segmentData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.modified_) {
|
||||||
|
this.dispatchEvent(new ModifyEvent(ModifyEventType.MODIFYEND, this.features_, evt));
|
||||||
|
this.modified_ = false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../MapBrowserEvent.js").default} evt Event.
|
* @param {import("../MapBrowserEvent.js").default} evt Event.
|
||||||
* @private
|
* @private
|
||||||
@@ -985,223 +1184,6 @@ function compareIndexes(a, b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {MapBrowserPointerEvent} evt Event.
|
|
||||||
* @return {boolean} Start drag sequence?
|
|
||||||
* @this {Modify}
|
|
||||||
*/
|
|
||||||
function handleDownEvent(evt) {
|
|
||||||
if (!this.condition_(evt)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.handlePointerAtPixel_(evt.pixel, evt.map);
|
|
||||||
const pixelCoordinate = evt.map.getCoordinateFromPixel(evt.pixel);
|
|
||||||
this.dragSegments_.length = 0;
|
|
||||||
this.modified_ = false;
|
|
||||||
const vertexFeature = this.vertexFeature_;
|
|
||||||
if (vertexFeature) {
|
|
||||||
const insertVertices = [];
|
|
||||||
const geometry = /** @type {Point} */ (vertexFeature.getGeometry());
|
|
||||||
const vertex = geometry.getCoordinates();
|
|
||||||
const vertexExtent = boundingExtent([vertex]);
|
|
||||||
const segmentDataMatches = this.rBush_.getInExtent(vertexExtent);
|
|
||||||
const componentSegments = {};
|
|
||||||
segmentDataMatches.sort(compareIndexes);
|
|
||||||
for (let i = 0, ii = segmentDataMatches.length; i < ii; ++i) {
|
|
||||||
const segmentDataMatch = segmentDataMatches[i];
|
|
||||||
const segment = segmentDataMatch.segment;
|
|
||||||
let uid = String(getUid(segmentDataMatch.feature));
|
|
||||||
const depth = segmentDataMatch.depth;
|
|
||||||
if (depth) {
|
|
||||||
uid += '-' + depth.join('-'); // separate feature components
|
|
||||||
}
|
|
||||||
if (!componentSegments[uid]) {
|
|
||||||
componentSegments[uid] = new Array(2);
|
|
||||||
}
|
|
||||||
if (segmentDataMatch.geometry.getType() === GeometryType.CIRCLE &&
|
|
||||||
segmentDataMatch.index === CIRCLE_CIRCUMFERENCE_INDEX) {
|
|
||||||
|
|
||||||
const closestVertex = closestOnSegmentData(pixelCoordinate, segmentDataMatch);
|
|
||||||
if (coordinatesEqual(closestVertex, vertex) && !componentSegments[uid][0]) {
|
|
||||||
this.dragSegments_.push([segmentDataMatch, 0]);
|
|
||||||
componentSegments[uid][0] = segmentDataMatch;
|
|
||||||
}
|
|
||||||
} else if (coordinatesEqual(segment[0], vertex) &&
|
|
||||||
!componentSegments[uid][0]) {
|
|
||||||
this.dragSegments_.push([segmentDataMatch, 0]);
|
|
||||||
componentSegments[uid][0] = segmentDataMatch;
|
|
||||||
} else if (coordinatesEqual(segment[1], vertex) &&
|
|
||||||
!componentSegments[uid][1]) {
|
|
||||||
|
|
||||||
// prevent dragging closed linestrings by the connecting node
|
|
||||||
if ((segmentDataMatch.geometry.getType() ===
|
|
||||||
GeometryType.LINE_STRING ||
|
|
||||||
segmentDataMatch.geometry.getType() ===
|
|
||||||
GeometryType.MULTI_LINE_STRING) &&
|
|
||||||
componentSegments[uid][0] &&
|
|
||||||
componentSegments[uid][0].index === 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dragSegments_.push([segmentDataMatch, 1]);
|
|
||||||
componentSegments[uid][1] = segmentDataMatch;
|
|
||||||
} else if (this.insertVertexCondition_(evt) && getUid(segment) in this.vertexSegments_ &&
|
|
||||||
(!componentSegments[uid][0] && !componentSegments[uid][1])) {
|
|
||||||
insertVertices.push([segmentDataMatch, vertex]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (insertVertices.length) {
|
|
||||||
this.willModifyFeatures_(evt);
|
|
||||||
}
|
|
||||||
for (let j = insertVertices.length - 1; j >= 0; --j) {
|
|
||||||
this.insertVertex_.apply(this, insertVertices[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return !!this.vertexFeature_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {MapBrowserPointerEvent} evt Event.
|
|
||||||
* @this {Modify}
|
|
||||||
*/
|
|
||||||
function handleDragEvent(evt) {
|
|
||||||
this.ignoreNextSingleClick_ = false;
|
|
||||||
this.willModifyFeatures_(evt);
|
|
||||||
|
|
||||||
const vertex = evt.coordinate;
|
|
||||||
for (let i = 0, ii = this.dragSegments_.length; i < ii; ++i) {
|
|
||||||
const dragSegment = this.dragSegments_[i];
|
|
||||||
const segmentData = dragSegment[0];
|
|
||||||
const depth = segmentData.depth;
|
|
||||||
const geometry = segmentData.geometry;
|
|
||||||
let coordinates;
|
|
||||||
const segment = segmentData.segment;
|
|
||||||
const index = dragSegment[1];
|
|
||||||
|
|
||||||
while (vertex.length < geometry.getStride()) {
|
|
||||||
vertex.push(segment[index][vertex.length]);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (geometry.getType()) {
|
|
||||||
case GeometryType.POINT:
|
|
||||||
coordinates = vertex;
|
|
||||||
segment[0] = segment[1] = vertex;
|
|
||||||
break;
|
|
||||||
case GeometryType.MULTI_POINT:
|
|
||||||
coordinates = geometry.getCoordinates();
|
|
||||||
coordinates[segmentData.index] = vertex;
|
|
||||||
segment[0] = segment[1] = vertex;
|
|
||||||
break;
|
|
||||||
case GeometryType.LINE_STRING:
|
|
||||||
coordinates = geometry.getCoordinates();
|
|
||||||
coordinates[segmentData.index + index] = vertex;
|
|
||||||
segment[index] = vertex;
|
|
||||||
break;
|
|
||||||
case GeometryType.MULTI_LINE_STRING:
|
|
||||||
coordinates = geometry.getCoordinates();
|
|
||||||
coordinates[depth[0]][segmentData.index + index] = vertex;
|
|
||||||
segment[index] = vertex;
|
|
||||||
break;
|
|
||||||
case GeometryType.POLYGON:
|
|
||||||
coordinates = geometry.getCoordinates();
|
|
||||||
coordinates[depth[0]][segmentData.index + index] = vertex;
|
|
||||||
segment[index] = vertex;
|
|
||||||
break;
|
|
||||||
case GeometryType.MULTI_POLYGON:
|
|
||||||
coordinates = geometry.getCoordinates();
|
|
||||||
coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex;
|
|
||||||
segment[index] = vertex;
|
|
||||||
break;
|
|
||||||
case GeometryType.CIRCLE:
|
|
||||||
segment[0] = segment[1] = vertex;
|
|
||||||
if (segmentData.index === CIRCLE_CENTER_INDEX) {
|
|
||||||
this.changingFeature_ = true;
|
|
||||||
geometry.setCenter(vertex);
|
|
||||||
this.changingFeature_ = false;
|
|
||||||
} else { // We're dragging the circle's circumference:
|
|
||||||
this.changingFeature_ = true;
|
|
||||||
geometry.setRadius(coordinateDistance(geometry.getCenter(), vertex));
|
|
||||||
this.changingFeature_ = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coordinates) {
|
|
||||||
this.setGeometryCoordinates_(geometry, coordinates);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.createOrUpdateVertexFeature_(vertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {MapBrowserPointerEvent} evt Event.
|
|
||||||
* @return {boolean} Stop drag sequence?
|
|
||||||
* @this {Modify}
|
|
||||||
*/
|
|
||||||
function handleUpEvent(evt) {
|
|
||||||
for (let i = this.dragSegments_.length - 1; i >= 0; --i) {
|
|
||||||
const segmentData = this.dragSegments_[i][0];
|
|
||||||
const geometry = segmentData.geometry;
|
|
||||||
if (geometry.getType() === GeometryType.CIRCLE) {
|
|
||||||
// Update a circle object in the R* bush:
|
|
||||||
const coordinates = geometry.getCenter();
|
|
||||||
const centerSegmentData = segmentData.featureSegments[0];
|
|
||||||
const circumferenceSegmentData = segmentData.featureSegments[1];
|
|
||||||
centerSegmentData.segment[0] = centerSegmentData.segment[1] = coordinates;
|
|
||||||
circumferenceSegmentData.segment[0] = circumferenceSegmentData.segment[1] = coordinates;
|
|
||||||
this.rBush_.update(createOrUpdateFromCoordinate(coordinates), centerSegmentData);
|
|
||||||
this.rBush_.update(geometry.getExtent(), circumferenceSegmentData);
|
|
||||||
} else {
|
|
||||||
this.rBush_.update(boundingExtent(segmentData.segment), segmentData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.modified_) {
|
|
||||||
this.dispatchEvent(new ModifyEvent(ModifyEventType.MODIFYEND, this.features_, evt));
|
|
||||||
this.modified_ = false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the {@link module:ol/MapBrowserEvent map browser event} and may modify the
|
|
||||||
* geometry.
|
|
||||||
* @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
|
|
||||||
* @return {boolean} `false` to stop event propagation.
|
|
||||||
* @this {Modify}
|
|
||||||
*/
|
|
||||||
function handleEvent(mapBrowserEvent) {
|
|
||||||
if (!(mapBrowserEvent instanceof MapBrowserPointerEvent)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
this.lastPointerEvent_ = mapBrowserEvent;
|
|
||||||
|
|
||||||
let handled;
|
|
||||||
if (!mapBrowserEvent.map.getView().getInteracting() &&
|
|
||||||
mapBrowserEvent.type == MapBrowserEventType.POINTERMOVE &&
|
|
||||||
!this.handlingDownUpSequence) {
|
|
||||||
this.handlePointerMove_(mapBrowserEvent);
|
|
||||||
}
|
|
||||||
if (this.vertexFeature_ && this.deleteCondition_(mapBrowserEvent)) {
|
|
||||||
if (mapBrowserEvent.type != MapBrowserEventType.SINGLECLICK || !this.ignoreNextSingleClick_) {
|
|
||||||
handled = this.removePoint();
|
|
||||||
} else {
|
|
||||||
handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapBrowserEvent.type == MapBrowserEventType.SINGLECLICK) {
|
|
||||||
this.ignoreNextSingleClick_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return handlePointerEvent.call(this, mapBrowserEvent) && !handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the distance from a point to a line segment.
|
* Returns the distance from a point to a line segment.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -54,11 +54,9 @@ class MouseWheelZoom extends Interaction {
|
|||||||
*/
|
*/
|
||||||
constructor(opt_options) {
|
constructor(opt_options) {
|
||||||
|
|
||||||
super({
|
const options = opt_options ? opt_options : {};
|
||||||
handleEvent: handleEvent
|
|
||||||
});
|
|
||||||
|
|
||||||
const options = opt_options || {};
|
super(/** @type {import("./Interaction.js").InteractionOptions} */ (options));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -157,6 +155,127 @@ class MouseWheelZoom extends Interaction {
|
|||||||
view.setHint(ViewHint.INTERACTING, -1);
|
view.setHint(ViewHint.INTERACTING, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the {@link module:ol/MapBrowserEvent map browser event} (if it was a mousewheel-event) and eventually
|
||||||
|
* zooms the map.
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
handleEvent(mapBrowserEvent) {
|
||||||
|
if (!this.condition_(mapBrowserEvent)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const type = mapBrowserEvent.type;
|
||||||
|
if (type !== EventType.WHEEL && type !== EventType.MOUSEWHEEL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapBrowserEvent.preventDefault();
|
||||||
|
|
||||||
|
const map = mapBrowserEvent.map;
|
||||||
|
const wheelEvent = /** @type {WheelEvent} */ (mapBrowserEvent.originalEvent);
|
||||||
|
|
||||||
|
if (this.useAnchor_) {
|
||||||
|
this.lastAnchor_ = mapBrowserEvent.coordinate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delta normalisation inspired by
|
||||||
|
// https://github.com/mapbox/mapbox-gl-js/blob/001c7b9/js/ui/handler/scroll_zoom.js
|
||||||
|
let delta;
|
||||||
|
if (mapBrowserEvent.type == EventType.WHEEL) {
|
||||||
|
delta = wheelEvent.deltaY;
|
||||||
|
if (FIREFOX &&
|
||||||
|
wheelEvent.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
|
||||||
|
delta /= DEVICE_PIXEL_RATIO;
|
||||||
|
}
|
||||||
|
if (wheelEvent.deltaMode === WheelEvent.DOM_DELTA_LINE) {
|
||||||
|
delta *= 40;
|
||||||
|
}
|
||||||
|
} else if (mapBrowserEvent.type == EventType.MOUSEWHEEL) {
|
||||||
|
delta = -wheelEvent.wheelDeltaY;
|
||||||
|
if (SAFARI) {
|
||||||
|
delta /= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
if (this.startTime_ === undefined) {
|
||||||
|
this.startTime_ = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.mode_ || now - this.startTime_ > this.trackpadEventGap_) {
|
||||||
|
this.mode_ = Math.abs(delta) < 4 ?
|
||||||
|
Mode.TRACKPAD :
|
||||||
|
Mode.WHEEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mode_ === Mode.TRACKPAD) {
|
||||||
|
const view = map.getView();
|
||||||
|
if (this.trackpadTimeoutId_) {
|
||||||
|
clearTimeout(this.trackpadTimeoutId_);
|
||||||
|
} else {
|
||||||
|
view.setHint(ViewHint.INTERACTING, 1);
|
||||||
|
}
|
||||||
|
this.trackpadTimeoutId_ = setTimeout(this.decrementInteractingHint_.bind(this), this.trackpadEventGap_);
|
||||||
|
let resolution = view.getResolution() * Math.pow(2, delta / this.trackpadDeltaPerZoom_);
|
||||||
|
const minResolution = view.getMinResolution();
|
||||||
|
const maxResolution = view.getMaxResolution();
|
||||||
|
let rebound = 0;
|
||||||
|
if (resolution < minResolution) {
|
||||||
|
resolution = Math.max(resolution, minResolution / this.trackpadZoomBuffer_);
|
||||||
|
rebound = 1;
|
||||||
|
} else if (resolution > maxResolution) {
|
||||||
|
resolution = Math.min(resolution, maxResolution * this.trackpadZoomBuffer_);
|
||||||
|
rebound = -1;
|
||||||
|
}
|
||||||
|
if (this.lastAnchor_) {
|
||||||
|
const center = view.calculateCenterZoom(resolution, this.lastAnchor_);
|
||||||
|
view.setCenter(view.constrainCenter(center));
|
||||||
|
}
|
||||||
|
view.setResolution(resolution);
|
||||||
|
|
||||||
|
if (rebound === 0 && this.constrainResolution_) {
|
||||||
|
view.animate({
|
||||||
|
resolution: view.constrainResolution(resolution, delta > 0 ? -1 : 1),
|
||||||
|
easing: easeOut,
|
||||||
|
anchor: this.lastAnchor_,
|
||||||
|
duration: this.duration_
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rebound > 0) {
|
||||||
|
view.animate({
|
||||||
|
resolution: minResolution,
|
||||||
|
easing: easeOut,
|
||||||
|
anchor: this.lastAnchor_,
|
||||||
|
duration: 500
|
||||||
|
});
|
||||||
|
} else if (rebound < 0) {
|
||||||
|
view.animate({
|
||||||
|
resolution: maxResolution,
|
||||||
|
easing: easeOut,
|
||||||
|
anchor: this.lastAnchor_,
|
||||||
|
duration: 500
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.startTime_ = now;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.delta_ += delta;
|
||||||
|
|
||||||
|
const timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0);
|
||||||
|
|
||||||
|
clearTimeout(this.timeoutId_);
|
||||||
|
this.timeoutId_ = setTimeout(this.handleWheelZoom_.bind(this, map), timeLeft);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {import("../PluggableMap.js").default} map Map.
|
* @param {import("../PluggableMap.js").default} map Map.
|
||||||
@@ -190,129 +309,4 @@ class MouseWheelZoom extends Interaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the {@link module:ol/MapBrowserEvent map browser event} (if it was a
|
|
||||||
* mousewheel-event) and eventually zooms the map.
|
|
||||||
* @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
|
|
||||||
* @return {boolean} Allow event propagation.
|
|
||||||
* @this {MouseWheelZoom}
|
|
||||||
*/
|
|
||||||
function handleEvent(mapBrowserEvent) {
|
|
||||||
if (!this.condition_(mapBrowserEvent)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const type = mapBrowserEvent.type;
|
|
||||||
if (type !== EventType.WHEEL && type !== EventType.MOUSEWHEEL) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mapBrowserEvent.preventDefault();
|
|
||||||
|
|
||||||
const map = mapBrowserEvent.map;
|
|
||||||
const wheelEvent = /** @type {WheelEvent} */ (mapBrowserEvent.originalEvent);
|
|
||||||
|
|
||||||
if (this.useAnchor_) {
|
|
||||||
this.lastAnchor_ = mapBrowserEvent.coordinate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delta normalisation inspired by
|
|
||||||
// https://github.com/mapbox/mapbox-gl-js/blob/001c7b9/js/ui/handler/scroll_zoom.js
|
|
||||||
let delta;
|
|
||||||
if (mapBrowserEvent.type == EventType.WHEEL) {
|
|
||||||
delta = wheelEvent.deltaY;
|
|
||||||
if (FIREFOX &&
|
|
||||||
wheelEvent.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
|
|
||||||
delta /= DEVICE_PIXEL_RATIO;
|
|
||||||
}
|
|
||||||
if (wheelEvent.deltaMode === WheelEvent.DOM_DELTA_LINE) {
|
|
||||||
delta *= 40;
|
|
||||||
}
|
|
||||||
} else if (mapBrowserEvent.type == EventType.MOUSEWHEEL) {
|
|
||||||
delta = -wheelEvent.wheelDeltaY;
|
|
||||||
if (SAFARI) {
|
|
||||||
delta /= 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delta === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
|
|
||||||
if (this.startTime_ === undefined) {
|
|
||||||
this.startTime_ = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.mode_ || now - this.startTime_ > this.trackpadEventGap_) {
|
|
||||||
this.mode_ = Math.abs(delta) < 4 ?
|
|
||||||
Mode.TRACKPAD :
|
|
||||||
Mode.WHEEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.mode_ === Mode.TRACKPAD) {
|
|
||||||
const view = map.getView();
|
|
||||||
if (this.trackpadTimeoutId_) {
|
|
||||||
clearTimeout(this.trackpadTimeoutId_);
|
|
||||||
} else {
|
|
||||||
view.setHint(ViewHint.INTERACTING, 1);
|
|
||||||
}
|
|
||||||
this.trackpadTimeoutId_ = setTimeout(this.decrementInteractingHint_.bind(this), this.trackpadEventGap_);
|
|
||||||
let resolution = view.getResolution() * Math.pow(2, delta / this.trackpadDeltaPerZoom_);
|
|
||||||
const minResolution = view.getMinResolution();
|
|
||||||
const maxResolution = view.getMaxResolution();
|
|
||||||
let rebound = 0;
|
|
||||||
if (resolution < minResolution) {
|
|
||||||
resolution = Math.max(resolution, minResolution / this.trackpadZoomBuffer_);
|
|
||||||
rebound = 1;
|
|
||||||
} else if (resolution > maxResolution) {
|
|
||||||
resolution = Math.min(resolution, maxResolution * this.trackpadZoomBuffer_);
|
|
||||||
rebound = -1;
|
|
||||||
}
|
|
||||||
if (this.lastAnchor_) {
|
|
||||||
const center = view.calculateCenterZoom(resolution, this.lastAnchor_);
|
|
||||||
view.setCenter(view.constrainCenter(center));
|
|
||||||
}
|
|
||||||
view.setResolution(resolution);
|
|
||||||
|
|
||||||
if (rebound === 0 && this.constrainResolution_) {
|
|
||||||
view.animate({
|
|
||||||
resolution: view.constrainResolution(resolution, delta > 0 ? -1 : 1),
|
|
||||||
easing: easeOut,
|
|
||||||
anchor: this.lastAnchor_,
|
|
||||||
duration: this.duration_
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rebound > 0) {
|
|
||||||
view.animate({
|
|
||||||
resolution: minResolution,
|
|
||||||
easing: easeOut,
|
|
||||||
anchor: this.lastAnchor_,
|
|
||||||
duration: 500
|
|
||||||
});
|
|
||||||
} else if (rebound < 0) {
|
|
||||||
view.animate({
|
|
||||||
resolution: maxResolution,
|
|
||||||
easing: easeOut,
|
|
||||||
anchor: this.lastAnchor_,
|
|
||||||
duration: 500
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.startTime_ = now;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.delta_ += delta;
|
|
||||||
|
|
||||||
const timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0);
|
|
||||||
|
|
||||||
clearTimeout(this.timeoutId_);
|
|
||||||
this.timeoutId_ = setTimeout(this.handleWheelZoom_.bind(this, map), timeLeft);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default MouseWheelZoom;
|
export default MouseWheelZoom;
|
||||||
|
|||||||
@@ -28,14 +28,15 @@ class PinchRotate extends PointerInteraction {
|
|||||||
*/
|
*/
|
||||||
constructor(opt_options) {
|
constructor(opt_options) {
|
||||||
|
|
||||||
super({
|
const options = opt_options ? opt_options : {};
|
||||||
handleDownEvent: handleDownEvent,
|
|
||||||
handleDragEvent: handleDragEvent,
|
|
||||||
handleUpEvent: handleUpEvent,
|
|
||||||
stopDown: FALSE
|
|
||||||
});
|
|
||||||
|
|
||||||
const options = opt_options || {};
|
const pointerOptions = /** @type {import("./Pointer.js").Options} */ (options);
|
||||||
|
|
||||||
|
if (!pointerOptions.stopDown) {
|
||||||
|
pointerOptions.stopDown = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
super(pointerOptions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -75,98 +76,89 @@ class PinchRotate extends PointerInteraction {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDragEvent(mapBrowserEvent) {
|
||||||
|
let rotationDelta = 0.0;
|
||||||
|
|
||||||
|
const touch0 = this.targetPointers[0];
|
||||||
|
const touch1 = this.targetPointers[1];
|
||||||
|
|
||||||
/**
|
// angle between touches
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Event.
|
const angle = Math.atan2(
|
||||||
* @this {PinchRotate}
|
touch1.clientY - touch0.clientY,
|
||||||
*/
|
touch1.clientX - touch0.clientX);
|
||||||
function handleDragEvent(mapBrowserEvent) {
|
|
||||||
let rotationDelta = 0.0;
|
|
||||||
|
|
||||||
const touch0 = this.targetPointers[0];
|
if (this.lastAngle_ !== undefined) {
|
||||||
const touch1 = this.targetPointers[1];
|
const delta = angle - this.lastAngle_;
|
||||||
|
this.rotationDelta_ += delta;
|
||||||
// angle between touches
|
if (!this.rotating_ &&
|
||||||
const angle = Math.atan2(
|
Math.abs(this.rotationDelta_) > this.threshold_) {
|
||||||
touch1.clientY - touch0.clientY,
|
this.rotating_ = true;
|
||||||
touch1.clientX - touch0.clientX);
|
}
|
||||||
|
rotationDelta = delta;
|
||||||
if (this.lastAngle_ !== undefined) {
|
|
||||||
const delta = angle - this.lastAngle_;
|
|
||||||
this.rotationDelta_ += delta;
|
|
||||||
if (!this.rotating_ &&
|
|
||||||
Math.abs(this.rotationDelta_) > this.threshold_) {
|
|
||||||
this.rotating_ = true;
|
|
||||||
}
|
}
|
||||||
rotationDelta = delta;
|
this.lastAngle_ = angle;
|
||||||
}
|
|
||||||
this.lastAngle_ = angle;
|
|
||||||
|
|
||||||
const map = mapBrowserEvent.map;
|
|
||||||
const view = map.getView();
|
|
||||||
if (view.getConstraints().rotation === disable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rotate anchor point.
|
|
||||||
// FIXME: should be the intersection point between the lines:
|
|
||||||
// touch0,touch1 and previousTouch0,previousTouch1
|
|
||||||
const viewportPosition = map.getViewport().getBoundingClientRect();
|
|
||||||
const centroid = centroidFromPointers(this.targetPointers);
|
|
||||||
centroid[0] -= viewportPosition.left;
|
|
||||||
centroid[1] -= viewportPosition.top;
|
|
||||||
this.anchor_ = map.getCoordinateFromPixel(centroid);
|
|
||||||
|
|
||||||
// rotate
|
|
||||||
if (this.rotating_) {
|
|
||||||
const rotation = view.getRotation();
|
|
||||||
map.render();
|
|
||||||
rotateWithoutConstraints(view, rotation + rotationDelta, this.anchor_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Event.
|
|
||||||
* @return {boolean} Stop drag sequence?
|
|
||||||
* @this {PinchRotate}
|
|
||||||
*/
|
|
||||||
function handleUpEvent(mapBrowserEvent) {
|
|
||||||
if (this.targetPointers.length < 2) {
|
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
view.setHint(ViewHint.INTERACTING, -1);
|
if (view.getConstraints().rotation === disable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotate anchor point.
|
||||||
|
// FIXME: should be the intersection point between the lines:
|
||||||
|
// touch0,touch1 and previousTouch0,previousTouch1
|
||||||
|
const viewportPosition = map.getViewport().getBoundingClientRect();
|
||||||
|
const centroid = centroidFromPointers(this.targetPointers);
|
||||||
|
centroid[0] -= viewportPosition.left;
|
||||||
|
centroid[1] -= viewportPosition.top;
|
||||||
|
this.anchor_ = map.getCoordinateFromPixel(centroid);
|
||||||
|
|
||||||
|
// rotate
|
||||||
if (this.rotating_) {
|
if (this.rotating_) {
|
||||||
const rotation = view.getRotation();
|
const rotation = view.getRotation();
|
||||||
rotate(view, rotation, this.anchor_, this.duration_);
|
map.render();
|
||||||
|
rotateWithoutConstraints(view, rotation + rotationDelta, this.anchor_);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
/**
|
* @inheritDoc
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Event.
|
*/
|
||||||
* @return {boolean} Start drag sequence?
|
handleUpEvent(mapBrowserEvent) {
|
||||||
* @this {PinchRotate}
|
if (this.targetPointers.length < 2) {
|
||||||
*/
|
const map = mapBrowserEvent.map;
|
||||||
function handleDownEvent(mapBrowserEvent) {
|
const view = map.getView();
|
||||||
if (this.targetPointers.length >= 2) {
|
view.setHint(ViewHint.INTERACTING, -1);
|
||||||
const map = mapBrowserEvent.map;
|
if (this.rotating_) {
|
||||||
this.anchor_ = null;
|
const rotation = view.getRotation();
|
||||||
this.lastAngle_ = undefined;
|
rotate(view, rotation, this.anchor_, this.duration_);
|
||||||
this.rotating_ = false;
|
}
|
||||||
this.rotationDelta_ = 0.0;
|
return false;
|
||||||
if (!this.handlingDownUpSequence) {
|
} else {
|
||||||
map.getView().setHint(ViewHint.INTERACTING, 1);
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDownEvent(mapBrowserEvent) {
|
||||||
|
if (this.targetPointers.length >= 2) {
|
||||||
|
const map = mapBrowserEvent.map;
|
||||||
|
this.anchor_ = null;
|
||||||
|
this.lastAngle_ = undefined;
|
||||||
|
this.rotating_ = false;
|
||||||
|
this.rotationDelta_ = 0.0;
|
||||||
|
if (!this.handlingDownUpSequence) {
|
||||||
|
map.getView().setHint(ViewHint.INTERACTING, 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,15 +27,16 @@ class PinchZoom extends PointerInteraction {
|
|||||||
*/
|
*/
|
||||||
constructor(opt_options) {
|
constructor(opt_options) {
|
||||||
|
|
||||||
super({
|
|
||||||
handleDownEvent: handleDownEvent,
|
|
||||||
handleDragEvent: handleDragEvent,
|
|
||||||
handleUpEvent: handleUpEvent,
|
|
||||||
stopDown: FALSE
|
|
||||||
});
|
|
||||||
|
|
||||||
const options = opt_options ? opt_options : {};
|
const options = opt_options ? opt_options : {};
|
||||||
|
|
||||||
|
const pointerOptions = /** @type {import("./Pointer.js").Options} */ (options);
|
||||||
|
|
||||||
|
if (!pointerOptions.stopDown) {
|
||||||
|
pointerOptions.stopDown = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
super(pointerOptions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@@ -68,105 +69,96 @@ class PinchZoom extends PointerInteraction {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDragEvent(mapBrowserEvent) {
|
||||||
|
let scaleDelta = 1.0;
|
||||||
|
|
||||||
|
const touch0 = this.targetPointers[0];
|
||||||
|
const touch1 = this.targetPointers[1];
|
||||||
|
const dx = touch0.clientX - touch1.clientX;
|
||||||
|
const dy = touch0.clientY - touch1.clientY;
|
||||||
|
|
||||||
|
// distance between touches
|
||||||
|
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (this.lastDistance_ !== undefined) {
|
||||||
|
scaleDelta = this.lastDistance_ / distance;
|
||||||
|
}
|
||||||
|
this.lastDistance_ = distance;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Event.
|
|
||||||
* @this {PinchZoom}
|
|
||||||
*/
|
|
||||||
function handleDragEvent(mapBrowserEvent) {
|
|
||||||
let scaleDelta = 1.0;
|
|
||||||
|
|
||||||
const touch0 = this.targetPointers[0];
|
|
||||||
const touch1 = this.targetPointers[1];
|
|
||||||
const dx = touch0.clientX - touch1.clientX;
|
|
||||||
const dy = touch0.clientY - touch1.clientY;
|
|
||||||
|
|
||||||
// distance between touches
|
|
||||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
||||||
|
|
||||||
if (this.lastDistance_ !== undefined) {
|
|
||||||
scaleDelta = this.lastDistance_ / distance;
|
|
||||||
}
|
|
||||||
this.lastDistance_ = distance;
|
|
||||||
|
|
||||||
|
|
||||||
const map = mapBrowserEvent.map;
|
|
||||||
const view = map.getView();
|
|
||||||
const resolution = view.getResolution();
|
|
||||||
const maxResolution = view.getMaxResolution();
|
|
||||||
const minResolution = view.getMinResolution();
|
|
||||||
let newResolution = resolution * scaleDelta;
|
|
||||||
if (newResolution > maxResolution) {
|
|
||||||
scaleDelta = maxResolution / resolution;
|
|
||||||
newResolution = maxResolution;
|
|
||||||
} else if (newResolution < minResolution) {
|
|
||||||
scaleDelta = minResolution / resolution;
|
|
||||||
newResolution = minResolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scaleDelta != 1.0) {
|
|
||||||
this.lastScaleDelta_ = scaleDelta;
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale anchor point.
|
|
||||||
const viewportPosition = map.getViewport().getBoundingClientRect();
|
|
||||||
const centroid = centroidFromPointers(this.targetPointers);
|
|
||||||
centroid[0] -= viewportPosition.left;
|
|
||||||
centroid[1] -= viewportPosition.top;
|
|
||||||
this.anchor_ = map.getCoordinateFromPixel(centroid);
|
|
||||||
|
|
||||||
// scale, bypass the resolution constraint
|
|
||||||
map.render();
|
|
||||||
zoomWithoutConstraints(view, newResolution, this.anchor_);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Event.
|
|
||||||
* @return {boolean} Stop drag sequence?
|
|
||||||
* @this {PinchZoom}
|
|
||||||
*/
|
|
||||||
function handleUpEvent(mapBrowserEvent) {
|
|
||||||
if (this.targetPointers.length < 2) {
|
|
||||||
const map = mapBrowserEvent.map;
|
const map = mapBrowserEvent.map;
|
||||||
const view = map.getView();
|
const view = map.getView();
|
||||||
view.setHint(ViewHint.INTERACTING, -1);
|
|
||||||
const resolution = view.getResolution();
|
const resolution = view.getResolution();
|
||||||
if (this.constrainResolution_ ||
|
const maxResolution = view.getMaxResolution();
|
||||||
resolution < view.getMinResolution() ||
|
const minResolution = view.getMinResolution();
|
||||||
resolution > view.getMaxResolution()) {
|
let newResolution = resolution * scaleDelta;
|
||||||
// Zoom to final resolution, with an animation, and provide a
|
if (newResolution > maxResolution) {
|
||||||
// direction not to zoom out/in if user was pinching in/out.
|
scaleDelta = maxResolution / resolution;
|
||||||
// Direction is > 0 if pinching out, and < 0 if pinching in.
|
newResolution = maxResolution;
|
||||||
const direction = this.lastScaleDelta_ - 1;
|
} else if (newResolution < minResolution) {
|
||||||
zoom(view, resolution, this.anchor_, this.duration_, direction);
|
scaleDelta = minResolution / resolution;
|
||||||
|
newResolution = minResolution;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
} else {
|
if (scaleDelta != 1.0) {
|
||||||
return true;
|
this.lastScaleDelta_ = scaleDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale anchor point.
|
||||||
|
const viewportPosition = map.getViewport().getBoundingClientRect();
|
||||||
|
const centroid = centroidFromPointers(this.targetPointers);
|
||||||
|
centroid[0] -= viewportPosition.left;
|
||||||
|
centroid[1] -= viewportPosition.top;
|
||||||
|
this.anchor_ = map.getCoordinateFromPixel(centroid);
|
||||||
|
|
||||||
|
// scale, bypass the resolution constraint
|
||||||
|
map.render();
|
||||||
|
zoomWithoutConstraints(view, newResolution, this.anchor_);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
/**
|
* @inheritDoc
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} mapBrowserEvent Event.
|
*/
|
||||||
* @return {boolean} Start drag sequence?
|
handleUpEvent(mapBrowserEvent) {
|
||||||
* @this {PinchZoom}
|
if (this.targetPointers.length < 2) {
|
||||||
*/
|
const map = mapBrowserEvent.map;
|
||||||
function handleDownEvent(mapBrowserEvent) {
|
const view = map.getView();
|
||||||
if (this.targetPointers.length >= 2) {
|
view.setHint(ViewHint.INTERACTING, -1);
|
||||||
const map = mapBrowserEvent.map;
|
const resolution = view.getResolution();
|
||||||
this.anchor_ = null;
|
if (this.constrainResolution_ ||
|
||||||
this.lastDistance_ = undefined;
|
resolution < view.getMinResolution() ||
|
||||||
this.lastScaleDelta_ = 1;
|
resolution > view.getMaxResolution()) {
|
||||||
if (!this.handlingDownUpSequence) {
|
// Zoom to final resolution, with an animation, and provide a
|
||||||
map.getView().setHint(ViewHint.INTERACTING, 1);
|
// direction not to zoom out/in if user was pinching in/out.
|
||||||
|
// Direction is > 0 if pinching out, and < 0 if pinching in.
|
||||||
|
const direction = this.lastScaleDelta_ - 1;
|
||||||
|
zoom(view, resolution, this.anchor_, this.duration_, direction);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDownEvent(mapBrowserEvent) {
|
||||||
|
if (this.targetPointers.length >= 2) {
|
||||||
|
const map = mapBrowserEvent.map;
|
||||||
|
this.anchor_ = null;
|
||||||
|
this.lastDistance_ = undefined;
|
||||||
|
this.lastScaleDelta_ = 1;
|
||||||
|
if (!this.handlingDownUpSequence) {
|
||||||
|
map.getView().setHint(ViewHint.INTERACTING, 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,9 +52,7 @@ class PointerInteraction extends Interaction {
|
|||||||
|
|
||||||
const options = opt_options ? opt_options : {};
|
const options = opt_options ? opt_options : {};
|
||||||
|
|
||||||
super({
|
super(/** @type {import("./Interaction.js").InteractionOptions} */ (options));
|
||||||
handleEvent: options.handleEvent || handleEvent
|
|
||||||
});
|
|
||||||
|
|
||||||
if (options.handleDownEvent) {
|
if (options.handleDownEvent) {
|
||||||
this.handleDownEvent = options.handleDownEvent;
|
this.handleDownEvent = options.handleDownEvent;
|
||||||
@@ -72,20 +70,16 @@ class PointerInteraction extends Interaction {
|
|||||||
this.handleUpEvent = options.handleUpEvent;
|
this.handleUpEvent = options.handleUpEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.stopDown) {
|
||||||
|
this.stopDown = options.stopDown;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
this.handlingDownUpSequence = false;
|
this.handlingDownUpSequence = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is used to determine if "down" events should be propagated
|
|
||||||
* to other interactions or should be stopped.
|
|
||||||
* @type {function(boolean):boolean}
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
this.stopDown = options.stopDown ? options.stopDown : stopDown;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {!Object<string, import("../pointer/PointerEvent.js").default>}
|
* @type {!Object<string, import("../pointer/PointerEvent.js").default>}
|
||||||
* @private
|
* @private
|
||||||
@@ -117,6 +111,42 @@ class PointerInteraction extends Interaction {
|
|||||||
*/
|
*/
|
||||||
handleDragEvent(mapBrowserEvent) {}
|
handleDragEvent(mapBrowserEvent) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the {@link module:ol/MapBrowserEvent map browser event} and may call into
|
||||||
|
* other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are
|
||||||
|
* detected.
|
||||||
|
* @override
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
handleEvent(mapBrowserEvent) {
|
||||||
|
if (!(mapBrowserEvent instanceof MapBrowserPointerEvent)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let stopEvent = false;
|
||||||
|
this.updateTrackedPointers_(mapBrowserEvent);
|
||||||
|
if (this.handlingDownUpSequence) {
|
||||||
|
if (mapBrowserEvent.type == MapBrowserEventType.POINTERDRAG) {
|
||||||
|
this.handleDragEvent(mapBrowserEvent);
|
||||||
|
} else if (mapBrowserEvent.type == MapBrowserEventType.POINTERUP) {
|
||||||
|
const handledUp = this.handleUpEvent(mapBrowserEvent);
|
||||||
|
this.handlingDownUpSequence = handledUp && this.targetPointers.length > 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mapBrowserEvent.type == MapBrowserEventType.POINTERDOWN) {
|
||||||
|
const handled = this.handleDownEvent(mapBrowserEvent);
|
||||||
|
if (handled) {
|
||||||
|
mapBrowserEvent.preventDefault();
|
||||||
|
}
|
||||||
|
this.handlingDownUpSequence = handled;
|
||||||
|
stopEvent = this.stopDown(handled);
|
||||||
|
} else if (mapBrowserEvent.type == MapBrowserEventType.POINTERMOVE) {
|
||||||
|
this.handleMoveEvent(mapBrowserEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !stopEvent;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle pointer move events.
|
* Handle pointer move events.
|
||||||
* @param {MapBrowserPointerEvent} mapBrowserEvent Event.
|
* @param {MapBrowserPointerEvent} mapBrowserEvent Event.
|
||||||
@@ -134,6 +164,16 @@ class PointerInteraction extends Interaction {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used to determine if "down" events should be propagated
|
||||||
|
* to other interactions or should be stopped.
|
||||||
|
* @param {boolean} handled Was the event handled by the interaction?
|
||||||
|
* @return {boolean} Should the `down` event be stopped?
|
||||||
|
*/
|
||||||
|
stopDown(handled) {
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {MapBrowserPointerEvent} mapBrowserEvent Event.
|
* @param {MapBrowserPointerEvent} mapBrowserEvent Event.
|
||||||
* @private
|
* @private
|
||||||
@@ -188,51 +228,4 @@ function isPointerDraggingEvent(mapBrowserEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles the {@link module:ol/MapBrowserEvent map browser event} and may call into
|
|
||||||
* other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are
|
|
||||||
* detected.
|
|
||||||
* @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
|
|
||||||
* @return {boolean} `false` to stop event propagation.
|
|
||||||
* @this {PointerInteraction}
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
export function handleEvent(mapBrowserEvent) {
|
|
||||||
if (!(mapBrowserEvent instanceof MapBrowserPointerEvent)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let stopEvent = false;
|
|
||||||
this.updateTrackedPointers_(mapBrowserEvent);
|
|
||||||
if (this.handlingDownUpSequence) {
|
|
||||||
if (mapBrowserEvent.type == MapBrowserEventType.POINTERDRAG) {
|
|
||||||
this.handleDragEvent(mapBrowserEvent);
|
|
||||||
} else if (mapBrowserEvent.type == MapBrowserEventType.POINTERUP) {
|
|
||||||
const handledUp = this.handleUpEvent(mapBrowserEvent);
|
|
||||||
this.handlingDownUpSequence = handledUp && this.targetPointers.length > 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (mapBrowserEvent.type == MapBrowserEventType.POINTERDOWN) {
|
|
||||||
const handled = this.handleDownEvent(mapBrowserEvent);
|
|
||||||
if (handled) {
|
|
||||||
mapBrowserEvent.preventDefault();
|
|
||||||
}
|
|
||||||
this.handlingDownUpSequence = handled;
|
|
||||||
stopEvent = this.stopDown(handled);
|
|
||||||
} else if (mapBrowserEvent.type == MapBrowserEventType.POINTERMOVE) {
|
|
||||||
this.handleMoveEvent(mapBrowserEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return !stopEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default PointerInteraction;
|
export default PointerInteraction;
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {boolean} handled Was the event handled by the interaction?
|
|
||||||
* @return {boolean} Should the `down` event be stopped?
|
|
||||||
*/
|
|
||||||
function stopDown(handled) {
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {boundingExtent, createEmpty} from '../extent.js';
|
|||||||
import {TRUE, FALSE} from '../functions.js';
|
import {TRUE, FALSE} from '../functions.js';
|
||||||
import GeometryType from '../geom/GeometryType.js';
|
import GeometryType from '../geom/GeometryType.js';
|
||||||
import {fromCircle} from '../geom/Polygon.js';
|
import {fromCircle} from '../geom/Polygon.js';
|
||||||
import PointerInteraction, {handleEvent as handlePointerEvent} from '../interaction/Pointer.js';
|
import PointerInteraction from '../interaction/Pointer.js';
|
||||||
import {getValues} from '../obj.js';
|
import {getValues} from '../obj.js';
|
||||||
import {VectorSourceEvent} from '../source/Vector.js';
|
import {VectorSourceEvent} from '../source/Vector.js';
|
||||||
import VectorEventType from '../source/VectorEventType.js';
|
import VectorEventType from '../source/VectorEventType.js';
|
||||||
@@ -71,15 +71,20 @@ class Snap extends PointerInteraction {
|
|||||||
*/
|
*/
|
||||||
constructor(opt_options) {
|
constructor(opt_options) {
|
||||||
|
|
||||||
super({
|
|
||||||
handleEvent: handleEvent,
|
|
||||||
handleDownEvent: TRUE,
|
|
||||||
handleUpEvent: handleUpEvent,
|
|
||||||
stopDown: FALSE
|
|
||||||
});
|
|
||||||
|
|
||||||
const options = opt_options ? opt_options : {};
|
const options = opt_options ? opt_options : {};
|
||||||
|
|
||||||
|
const pointerOptions = /** @type {import("./Pointer.js").Options} */ (options);
|
||||||
|
|
||||||
|
if (!pointerOptions.handleDownEvent) {
|
||||||
|
pointerOptions.handleDownEvent = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pointerOptions.stopDown) {
|
||||||
|
pointerOptions.stopDown = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
super(pointerOptions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {import("../source/Vector.js").default}
|
* @type {import("../source/Vector.js").default}
|
||||||
* @private
|
* @private
|
||||||
@@ -239,6 +244,18 @@ class Snap extends PointerInteraction {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleEvent(evt) {
|
||||||
|
const result = this.snapTo(evt.pixel, evt.coordinate, evt.map);
|
||||||
|
if (result.snapped) {
|
||||||
|
evt.coordinate = result.vertex.slice(0, 2);
|
||||||
|
evt.pixel = result.vertexPixel;
|
||||||
|
}
|
||||||
|
return super.handleEvent(evt);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("../source/Vector.js").default|import("../Collection.js").CollectionEvent} evt Event.
|
* @param {import("../source/Vector.js").default|import("../Collection.js").CollectionEvent} evt Event.
|
||||||
* @private
|
* @private
|
||||||
@@ -283,6 +300,18 @@ class Snap extends PointerInteraction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleUpEvent(evt) {
|
||||||
|
const featuresToUpdate = getValues(this.pendingFeatures_);
|
||||||
|
if (featuresToUpdate.length) {
|
||||||
|
featuresToUpdate.forEach(this.updateFeature_.bind(this));
|
||||||
|
this.pendingFeatures_ = {};
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a feature from the collection of features that we may snap to.
|
* Remove a feature from the collection of features that we may snap to.
|
||||||
* @param {import("../Feature.js").default} feature Feature
|
* @param {import("../Feature.js").default} feature Feature
|
||||||
@@ -587,37 +616,6 @@ class Snap extends PointerInteraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle all pointer events events.
|
|
||||||
* @param {import("../MapBrowserEvent.js").default} evt A move event.
|
|
||||||
* @return {boolean} Pass the event to other interactions.
|
|
||||||
* @this {Snap}
|
|
||||||
*/
|
|
||||||
export function handleEvent(evt) {
|
|
||||||
const result = this.snapTo(evt.pixel, evt.coordinate, evt.map);
|
|
||||||
if (result.snapped) {
|
|
||||||
evt.coordinate = result.vertex.slice(0, 2);
|
|
||||||
evt.pixel = result.vertexPixel;
|
|
||||||
}
|
|
||||||
return handlePointerEvent.call(this, evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} evt Event.
|
|
||||||
* @return {boolean} Stop drag sequence?
|
|
||||||
* @this {Snap}
|
|
||||||
*/
|
|
||||||
function handleUpEvent(evt) {
|
|
||||||
const featuresToUpdate = getValues(this.pendingFeatures_);
|
|
||||||
if (featuresToUpdate.length) {
|
|
||||||
featuresToUpdate.forEach(this.updateFeature_.bind(this));
|
|
||||||
this.pendingFeatures_ = {};
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort segments by distance, helper function
|
* Sort segments by distance, helper function
|
||||||
* @param {SegmentData} a The first segment data.
|
* @param {SegmentData} a The first segment data.
|
||||||
|
|||||||
@@ -98,15 +98,10 @@ class Translate extends PointerInteraction {
|
|||||||
* @param {Options=} opt_options Options.
|
* @param {Options=} opt_options Options.
|
||||||
*/
|
*/
|
||||||
constructor(opt_options) {
|
constructor(opt_options) {
|
||||||
super({
|
|
||||||
handleDownEvent: handleDownEvent,
|
|
||||||
handleDragEvent: handleDragEvent,
|
|
||||||
handleMoveEvent: handleMoveEvent,
|
|
||||||
handleUpEvent: handleUpEvent
|
|
||||||
});
|
|
||||||
|
|
||||||
const options = opt_options ? opt_options : {};
|
const options = opt_options ? opt_options : {};
|
||||||
|
|
||||||
|
super(/** @type {import("./Pointer.js").Options} */ (options));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The last position we translated to.
|
* The last position we translated to.
|
||||||
* @type {import("../coordinate.js").Coordinate}
|
* @type {import("../coordinate.js").Coordinate}
|
||||||
@@ -160,6 +155,86 @@ class Translate extends PointerInteraction {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDownEvent(event) {
|
||||||
|
this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map);
|
||||||
|
if (!this.lastCoordinate_ && this.lastFeature_) {
|
||||||
|
this.lastCoordinate_ = event.coordinate;
|
||||||
|
this.handleMoveEvent(event);
|
||||||
|
|
||||||
|
const features = this.features_ || new Collection([this.lastFeature_]);
|
||||||
|
|
||||||
|
this.dispatchEvent(
|
||||||
|
new TranslateEvent(
|
||||||
|
TranslateEventType.TRANSLATESTART, features,
|
||||||
|
event.coordinate));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleUpEvent(event) {
|
||||||
|
if (this.lastCoordinate_) {
|
||||||
|
this.lastCoordinate_ = null;
|
||||||
|
this.handleMoveEvent(event);
|
||||||
|
|
||||||
|
const features = this.features_ || new Collection([this.lastFeature_]);
|
||||||
|
|
||||||
|
this.dispatchEvent(
|
||||||
|
new TranslateEvent(
|
||||||
|
TranslateEventType.TRANSLATEEND, features,
|
||||||
|
event.coordinate));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleDragEvent(event) {
|
||||||
|
if (this.lastCoordinate_) {
|
||||||
|
const newCoordinate = event.coordinate;
|
||||||
|
const deltaX = newCoordinate[0] - this.lastCoordinate_[0];
|
||||||
|
const deltaY = newCoordinate[1] - this.lastCoordinate_[1];
|
||||||
|
|
||||||
|
const features = this.features_ || new Collection([this.lastFeature_]);
|
||||||
|
|
||||||
|
features.forEach(function(feature) {
|
||||||
|
const geom = feature.getGeometry();
|
||||||
|
geom.translate(deltaX, deltaY);
|
||||||
|
feature.setGeometry(geom);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.lastCoordinate_ = newCoordinate;
|
||||||
|
this.dispatchEvent(
|
||||||
|
new TranslateEvent(
|
||||||
|
TranslateEventType.TRANSLATING, features,
|
||||||
|
newCoordinate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
handleMoveEvent(event) {
|
||||||
|
const elem = event.map.getViewport();
|
||||||
|
|
||||||
|
// Change the cursor to grab/grabbing if hovering any of the features managed
|
||||||
|
// by the interaction
|
||||||
|
if (this.featuresAtPixel_(event.pixel, event.map)) {
|
||||||
|
elem.classList.remove(this.lastCoordinate_ ? 'ol-grab' : 'ol-grabbing');
|
||||||
|
elem.classList.add(this.lastCoordinate_ ? 'ol-grabbing' : 'ol-grab');
|
||||||
|
} else {
|
||||||
|
elem.classList.remove('ol-grab', 'ol-grabbing');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests to see if the given coordinates intersects any of our selected
|
* Tests to see if the given coordinates intersects any of our selected
|
||||||
* features.
|
* features.
|
||||||
@@ -234,95 +309,4 @@ class Translate extends PointerInteraction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} event Event.
|
|
||||||
* @return {boolean} Start drag sequence?
|
|
||||||
* @this {Translate}
|
|
||||||
*/
|
|
||||||
function handleDownEvent(event) {
|
|
||||||
this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map);
|
|
||||||
if (!this.lastCoordinate_ && this.lastFeature_) {
|
|
||||||
this.lastCoordinate_ = event.coordinate;
|
|
||||||
handleMoveEvent.call(this, event);
|
|
||||||
|
|
||||||
const features = this.features_ || new Collection([this.lastFeature_]);
|
|
||||||
|
|
||||||
this.dispatchEvent(
|
|
||||||
new TranslateEvent(
|
|
||||||
TranslateEventType.TRANSLATESTART, features,
|
|
||||||
event.coordinate));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} event Event.
|
|
||||||
* @return {boolean} Stop drag sequence?
|
|
||||||
* @this {Translate}
|
|
||||||
*/
|
|
||||||
function handleUpEvent(event) {
|
|
||||||
if (this.lastCoordinate_) {
|
|
||||||
this.lastCoordinate_ = null;
|
|
||||||
handleMoveEvent.call(this, event);
|
|
||||||
|
|
||||||
const features = this.features_ || new Collection([this.lastFeature_]);
|
|
||||||
|
|
||||||
this.dispatchEvent(
|
|
||||||
new TranslateEvent(
|
|
||||||
TranslateEventType.TRANSLATEEND, features,
|
|
||||||
event.coordinate));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserPointerEvent.js").default} event Event.
|
|
||||||
* @this {Translate}
|
|
||||||
*/
|
|
||||||
function handleDragEvent(event) {
|
|
||||||
if (this.lastCoordinate_) {
|
|
||||||
const newCoordinate = event.coordinate;
|
|
||||||
const deltaX = newCoordinate[0] - this.lastCoordinate_[0];
|
|
||||||
const deltaY = newCoordinate[1] - this.lastCoordinate_[1];
|
|
||||||
|
|
||||||
const features = this.features_ || new Collection([this.lastFeature_]);
|
|
||||||
|
|
||||||
features.forEach(function(feature) {
|
|
||||||
const geom = feature.getGeometry();
|
|
||||||
geom.translate(deltaX, deltaY);
|
|
||||||
feature.setGeometry(geom);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.lastCoordinate_ = newCoordinate;
|
|
||||||
this.dispatchEvent(
|
|
||||||
new TranslateEvent(
|
|
||||||
TranslateEventType.TRANSLATING, features,
|
|
||||||
newCoordinate));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("../MapBrowserEvent.js").default} event Event.
|
|
||||||
* @this {Translate}
|
|
||||||
*/
|
|
||||||
function handleMoveEvent(event) {
|
|
||||||
const elem = event.map.getViewport();
|
|
||||||
|
|
||||||
// Change the cursor to grab/grabbing if hovering any of the features managed
|
|
||||||
// by the interaction
|
|
||||||
if (this.featuresAtPixel_(event.pixel, event.map)) {
|
|
||||||
elem.classList.remove(this.lastCoordinate_ ? 'ol-grab' : 'ol-grabbing');
|
|
||||||
elem.classList.add(this.lastCoordinate_ ? 'ol-grabbing' : 'ol-grab');
|
|
||||||
} else {
|
|
||||||
elem.classList.remove('ol-grab', 'ol-grabbing');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default Translate;
|
export default Translate;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import View from '../../../../src/ol/View.js';
|
|||||||
import Circle from '../../../../src/ol/geom/Circle.js';
|
import Circle from '../../../../src/ol/geom/Circle.js';
|
||||||
import Point from '../../../../src/ol/geom/Point.js';
|
import Point from '../../../../src/ol/geom/Point.js';
|
||||||
import LineString from '../../../../src/ol/geom/LineString.js';
|
import LineString from '../../../../src/ol/geom/LineString.js';
|
||||||
import Snap, {handleEvent} from '../../../../src/ol/interaction/Snap.js';
|
import Snap from '../../../../src/ol/interaction/Snap.js';
|
||||||
|
|
||||||
|
|
||||||
describe('ol.interaction.Snap', function() {
|
describe('ol.interaction.Snap', function() {
|
||||||
@@ -67,7 +67,7 @@ describe('ol.interaction.Snap', function() {
|
|||||||
coordinate: [0, 0],
|
coordinate: [0, 0],
|
||||||
map: map
|
map: map
|
||||||
};
|
};
|
||||||
handleEvent.call(snapInteraction, event);
|
snapInteraction.handleEvent(event);
|
||||||
// check that the coordinate is in XY and not XYZ
|
// check that the coordinate is in XY and not XYZ
|
||||||
expect(event.coordinate).to.eql([0, 0]);
|
expect(event.coordinate).to.eql([0, 0]);
|
||||||
});
|
});
|
||||||
@@ -86,7 +86,7 @@ describe('ol.interaction.Snap', function() {
|
|||||||
coordinate: [7, 4],
|
coordinate: [7, 4],
|
||||||
map: map
|
map: map
|
||||||
};
|
};
|
||||||
handleEvent.call(snapInteraction, event);
|
snapInteraction.handleEvent(event);
|
||||||
expect(event.coordinate).to.eql([7, 0]);
|
expect(event.coordinate).to.eql([7, 0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ describe('ol.interaction.Snap', function() {
|
|||||||
coordinate: [7, 4],
|
coordinate: [7, 4],
|
||||||
map: map
|
map: map
|
||||||
};
|
};
|
||||||
handleEvent.call(snapInteraction, event);
|
snapInteraction.handleEvent(event);
|
||||||
expect(event.coordinate).to.eql([10, 0]);
|
expect(event.coordinate).to.eql([10, 0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ describe('ol.interaction.Snap', function() {
|
|||||||
coordinate: [5, 5],
|
coordinate: [5, 5],
|
||||||
map: map
|
map: map
|
||||||
};
|
};
|
||||||
handleEvent.call(snapInteraction, event);
|
snapInteraction.handleEvent(event);
|
||||||
|
|
||||||
expect(event.coordinate[0]).to.roughlyEqual(Math.sin(Math.PI / 4) * 10, 1e-10);
|
expect(event.coordinate[0]).to.roughlyEqual(Math.sin(Math.PI / 4) * 10, 1e-10);
|
||||||
expect(event.coordinate[1]).to.roughlyEqual(Math.sin(Math.PI / 4) * 10, 1e-10);
|
expect(event.coordinate[1]).to.roughlyEqual(Math.sin(Math.PI / 4) * 10, 1e-10);
|
||||||
@@ -143,7 +143,7 @@ describe('ol.interaction.Snap', function() {
|
|||||||
coordinate: [7, 4],
|
coordinate: [7, 4],
|
||||||
map: map
|
map: map
|
||||||
};
|
};
|
||||||
handleEvent.call(snapInteraction, event);
|
snapInteraction.handleEvent(event);
|
||||||
expect(event.coordinate).to.eql([10, 0]);
|
expect(event.coordinate).to.eql([10, 0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ describe('ol.interaction.Snap', function() {
|
|||||||
coordinate: [7, 4],
|
coordinate: [7, 4],
|
||||||
map: map
|
map: map
|
||||||
};
|
};
|
||||||
handleEvent.call(snapInteraction, event);
|
snapInteraction.handleEvent(event);
|
||||||
expect(event.coordinate).to.eql([10, 0]);
|
expect(event.coordinate).to.eql([10, 0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ describe('ol.interaction.Snap', function() {
|
|||||||
coordinate: [7, 4],
|
coordinate: [7, 4],
|
||||||
map: map
|
map: map
|
||||||
};
|
};
|
||||||
handleEvent.call(snapInteraction, event);
|
snapInteraction.handleEvent(event);
|
||||||
expect(event.coordinate).to.eql([10, 0]);
|
expect(event.coordinate).to.eql([10, 0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user