Skip to content

Commit

Permalink
Merge pull request #582 from OpenGeoscience/selection-based-zoom
Browse files Browse the repository at this point in the history
Fix selection rectangle and add selection-based zoom
  • Loading branch information
manthey authored Jun 14, 2016
2 parents 4b00f71 + db9a086 commit 8087452
Show file tree
Hide file tree
Showing 4 changed files with 313 additions and 55 deletions.
27 changes: 27 additions & 0 deletions src/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,33 @@ geo_event.brushend = 'geo_brushend';
//////////////////////////////////////////////////////////////////////////////
geo_event.brushstart = 'geo_brushstart';

//////////////////////////////////////////////////////////////////////////////
/**
* Triggered after a selection ends.
* The event object extends {@link geo.brushSelection}.
* @mixes geo.brushSelection
*/
//////////////////////////////////////////////////////////////////////////////
geo_event.select = 'geo_select';

//////////////////////////////////////////////////////////////////////////////
/**
* Triggered after a zoom selection ends.
* The event object extends {@link geo.brushSelection}.
* @mixes geo.brushSelection
*/
//////////////////////////////////////////////////////////////////////////////
geo_event.zoomselect = 'geo_zoomselect';

//////////////////////////////////////////////////////////////////////////////
/**
* Triggered after an unzoom selection ends.
* The event object extends {@link geo.brushSelection}.
* @mixes geo.brushSelection
*/
//////////////////////////////////////////////////////////////////////////////
geo_event.unzoomselect = 'geo_unzoomselect';

//////////////////////////////////////////////////////////////////////////////
/**
* Triggered before a map navigation animation begins. Set
Expand Down
145 changes: 110 additions & 35 deletions src/mapInteractor.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var mapInteractor = function (args) {
m_queue,
$node,
m_selectionLayer = null,
m_selectionPlane = null,
m_selectionQuad,
m_paused = false,
m_clickMaybe = false,
m_callZoom = function () {};
Expand Down Expand Up @@ -68,19 +68,23 @@ var mapInteractor = function (args) {
zoomMoveButton: 'right',
zoomMoveModifiers: {},
rotateMoveButton: 'left',
rotateMoveModifiers: {'ctrl': true},
rotateMoveModifiers: {ctrl: true},
panWheelEnabled: false,
panWheelModifiers: {},
zoomWheelEnabled: true,
zoomWheelModifiers: {},
rotateWheelEnabled: true,
rotateWheelModifiers: {'ctrl': true},
rotateWheelModifiers: {ctrl: true},
wheelScaleX: 1,
wheelScaleY: 1,
zoomScale: 1,
rotateWheelScale: 6 * Math.PI / 180,
selectionButton: 'left',
selectionModifiers: {'shift': true},
selectionModifiers: {shift: true, ctrl: true},
zoomSelectionButton: 'left',
zoomSelectionModifiers: {shift: true},
unzoomSelectionButton: 'right',
unzoomSelectionModifiers: {shift: true},
momentum: {
enabled: true,
maxSpeed: 2.5,
Expand Down Expand Up @@ -202,7 +206,7 @@ var mapInteractor = function (args) {
// // a mousemove.
// click: {
// enabled: true | false,
// buttons: {'left': true, 'right': true, 'middle': true}
// buttons: {left: true, right: true, middle: true}
// duration: 0,
// cancelOnMove: true // cancels click if the mouse is moved before release
// }
Expand Down Expand Up @@ -406,7 +410,9 @@ var mapInteractor = function (args) {
if (m_options.panMoveButton === 'right' ||
m_options.zoomMoveButton === 'right' ||
m_options.rotateMoveButton === 'right' ||
m_options.selectionButton === 'right') {
m_options.selectionButton === 'right' ||
m_options.zoomSelectionButton === 'right' ||
m_options.unzoomSelectionButton === 'right') {
$node.on('contextmenu.geojs', function () { return false; });
}
return m_this;
Expand Down Expand Up @@ -561,27 +567,18 @@ var mapInteractor = function (args) {
};

// Get the gcs coordinates
gcs.upperLeft = map.displayToGcs(display.upperLeft);
gcs.lowerRight = map.displayToGcs(display.lowerRight);
gcs.upperRight = map.displayToGcs(display.upperRight);
gcs.lowerLeft = map.displayToGcs(display.lowerLeft);

m_selectionPlane.origin([
display.lowerLeft.x,
display.lowerLeft.y,
0
]);
m_selectionPlane.upperLeft([
display.upperLeft.x,
display.upperLeft.y,
0
]);
m_selectionPlane.lowerRight([
display.lowerRight.x,
display.lowerRight.y,
0
]);
m_selectionPlane.draw();
gcs.upperLeft = map.displayToGcs(display.upperLeft, null);
gcs.lowerRight = map.displayToGcs(display.lowerRight, null);
gcs.upperRight = map.displayToGcs(display.upperRight, null);
gcs.lowerLeft = map.displayToGcs(display.lowerLeft, null);

m_selectionQuad.data([{
ul: gcs.upperLeft,
ur: gcs.upperRight,
ll: gcs.lowerLeft,
lr: gcs.lowerRight
}]);
m_selectionQuad.draw();

return {
display: display,
Expand Down Expand Up @@ -653,6 +650,10 @@ var mapInteractor = function (args) {
action = 'rotate';
} else if (eventMatch(m_options.selectionButton, m_options.selectionModifiers)) {
action = 'select';
} else if (eventMatch(m_options.zoomSelectionButton, m_options.zoomSelectionModifiers)) {
action = 'zoomselect';
} else if (eventMatch(m_options.unzoomSelectionButton, m_options.unzoomSelectionModifiers)) {
action = 'unzoomselect';
}

// cancel transitions and momentum on click
Expand All @@ -677,7 +678,7 @@ var mapInteractor = function (args) {
delta: {x: 0, y: 0}
};

if (action === 'select') {
if (action === 'select' || action === 'zoomselect' || action === 'unzoomselect') {
// Make sure the old selection layer is gone.
if (m_selectionLayer) {
m_selectionLayer.clear();
Expand All @@ -686,10 +687,12 @@ var mapInteractor = function (args) {
}
// Create a feature layer and plane feature to show the selection bounds
m_selectionLayer = m_this.map().createLayer('feature', {renderer: 'd3'});
m_selectionPlane = m_selectionLayer.createFeature('plane');
m_selectionPlane.style({
screenCoordinates: true,
fillOpacity: function () { return 0.25; }

m_selectionQuad = m_selectionLayer.createFeature(
'quad', {gcs: m_this.map().gcs()});
m_selectionQuad.style({
opacity: 0.25,
color: {r: 0.3, g: 0.3, b: 0.3}
});
m_this.map().geoTrigger(geo_event.brushstart, m_this._getSelection());
}
Expand Down Expand Up @@ -798,7 +801,7 @@ var mapInteractor = function (args) {
cx = m_mouse.map.x - m_this.map().size().width / 2;
cy = m_mouse.map.y - m_this.map().size().height / 2;
m_this.map().rotation(m_state.origin.rotation + Math.atan2(cy, cx));
} else if (m_state.action === 'select') {
} else if (m_state.action === 'select' || m_state.action === 'zoomselect' || m_state.action === 'unzoomselect') {
// Get the bounds of the current selection
selectionObj = m_this._getSelection();
m_this.map().geoTrigger(geo_event.brush, selectionObj);
Expand Down Expand Up @@ -885,6 +888,71 @@ var mapInteractor = function (args) {
};
}

////////////////////////////////////////////////////////////////////////////
/**
* Based on the screen coodinates of a selection, zoom or unzoom and
* recenter.
*
* @private
* @param {string} action Either 'zoomselect' or 'unzoomselect'.
* @param {object} lowerLeft the x and y coordinates of the lower left corner
* of the zoom rectangle.
* @param {object} upperRight the x and y coordinates of the upper right
* corner of the zoom rectangle.
*/
////////////////////////////////////////////////////////////////////////////
this._zoomFromSelection = function (action, lowerLeft, upperRight) {
if (action !== 'zoomselect' && action !== 'unzoomselect') {
return;
}
if (lowerLeft.x === upperRight.x || lowerLeft.y === upperRight.y) {
return;
}
var zoom, center,
map = m_this.map(),
mapsize = map.size();
/* To arbitrarily handle rotation and projection, we center the map at the
* central coordinate of the selection and set the zoom level such that the
* four corners are just barely on the map. When unzooming (zooming out),
* we ensure that the previous view is centered in the selection but use
* the maximal size for the zoom factor. */
var scaling = {
x: Math.abs((upperRight.x - lowerLeft.x) / mapsize.width),
y: Math.abs((upperRight.y - lowerLeft.y) / mapsize.height)
};
if (action === 'zoomselect') {
center = map.displayToGcs({
x: (lowerLeft.x + upperRight.x) / 2,
y: (lowerLeft.y + upperRight.y) / 2
}, null);
zoom = map.zoom() - Math.log2(Math.max(scaling.x, scaling.y));
} else { /* unzoom */
/* To make the existing visible map entirely within the selection
* rectangle, this would be changed to Math.min instead of Math.max of
* the scaling factors. This felt wrong, though. */
zoom = map.zoom() + Math.log2(Math.max(scaling.x, scaling.y));
/* Record the current center. Later, this is panned to the center of the
* selection rectangle. */
center = map.center(undefined, null);
}
/* When discrete zoom is enable, always round down. We have to do this
* explicitly, as otherwise we may zoom too far and the selection will not
* be completely visible. */
if (map.discreteZoom()) {
zoom = Math.floor(zoom);
}
map.zoom(zoom);
if (action === 'zoomselect') {
map.center(center, null);
} else {
var newcenter = map.gcsToDisplay(center, null);
map.pan({
x: (lowerLeft.x + upperRight.x) / 2 - newcenter.x,
y: (lowerLeft.y + upperRight.y) / 2 - newcenter.y
});
}
};

////////////////////////////////////////////////////////////////////////////
/**
* Handle event when a mouse button is unpressed on the document.
Expand Down Expand Up @@ -912,15 +980,19 @@ var mapInteractor = function (args) {
evt.preventDefault();
}

if (m_state.action === 'select') {
if (m_state.action === 'select' || m_state.action === 'zoomselect' || m_state.action === 'unzoomselect') {
m_this._getMousePosition(evt);
selectionObj = m_this._getSelection();

m_selectionLayer.clear();
m_this.map().deleteLayer(m_selectionLayer);
m_selectionLayer = null;
m_selectionPlane = null;
m_selectionQuad = null;

m_this.map().geoTrigger(geo_event.brushend, selectionObj);
m_this.map().geoTrigger(geo_event[m_state.action], selectionObj);
m_this._zoomFromSelection(m_state.action, selectionObj.display.lowerLeft,
selectionObj.display.upperRight);
}

// reset the interactor state
Expand Down Expand Up @@ -1419,6 +1491,9 @@ var mapInteractor = function (args) {
}
}
);
if (type.indexOf('.geojs') >= 0) {
$(document).trigger(evt);
}
$node.trigger(evt);
};
this._connectEvents();
Expand Down
11 changes: 0 additions & 11 deletions src/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,6 @@ var renderer = function (arg) {
}
};

////////////////////////////////////////////////////////////////////////////
/**
* Get base layer that belongs to this renderer
*/
////////////////////////////////////////////////////////////////////////////
this.baseLayer = function () {
if (m_this.map()) {
return m_this.map().baseLayer();
}
};

////////////////////////////////////////////////////////////////////////////
/**
* Get/Set if renderer has been initialized
Expand Down
Loading

0 comments on commit 8087452

Please sign in to comment.