Commit f7443192 authored by dagal's avatar dagal
Browse files

First approach to box-select

Turns out I won't need an index as checking which of the 11k stops are contained in a box is efficient enough
parent a704e020
import {Map} from 'leaflet';
import {Handler} from 'leaflet/src/core/Handler';
import * as Util from 'leaflet/src/core/Util';
import * as DomUtil from 'leaflet/src/dom/DomUtil';
import * as DomEvent from 'leaflet/src/dom/DomEvent';
import {LatLngBounds} from 'leaflet/src/geo/LatLngBounds';
import {Bounds} from 'leaflet/src/geometry/Bounds';
/*
* L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map
* (zoom to a selected bounding box), enabled by default.
*/
// @namespace Map
// @section Interaction Options
Map.mergeOptions({
// @option boxZoom: Boolean = true
// Whether the map can be zoomed to a rectangular area specified by
// dragging the mouse while pressing the shift key.
rectSelect: true
});
export var RectSelect = Handler.extend({
initialize: function (map) {
this._map = map;
this._container = map._container;
this._pane = map._panes.overlayPane;
this._resetStateTimeout = 0;
map.on('unload', this._destroy, this);
},
addHooks: function () {
DomEvent.on(this._container, 'mousedown', this._onMouseDown, this);
},
removeHooks: function () {
DomEvent.off(this._container, 'mousedown', this._onMouseDown, this);
},
moved: function () {
return this._moved;
},
_destroy: function () {
DomUtil.remove(this._pane);
delete this._pane;
},
_resetState: function () {
this._resetStateTimeout = 0;
this._moved = false;
},
_clearDeferredResetState: function () {
if (this._resetStateTimeout !== 0) {
clearTimeout(this._resetStateTimeout);
this._resetStateTimeout = 0;
}
},
_onMouseDown: function (e) {
if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
// Clear the deferred resetState if it hasn't executed yet, otherwise it
// will interrupt the interaction and orphan a box element in the container.
this._clearDeferredResetState();
this._resetState();
DomUtil.disableTextSelection();
DomUtil.disableImageDrag();
this._startPoint = this._map.mouseEventToContainerPoint(e);
DomEvent.on(document, {
contextmenu: DomEvent.stop,
mousemove: this._onMouseMove,
mouseup: this._onMouseUp,
keydown: this._onKeyDown
}, this);
},
_onMouseMove: function (e) {
if (!this._moved) {
this._moved = true;
this._box = DomUtil.create('div', 'leaflet-zoom-box', this._container);
DomUtil.addClass(this._container, 'leaflet-crosshair');
this._map.fire('boxzoomstart');
}
this._point = this._map.mouseEventToContainerPoint(e);
var bounds = new Bounds(this._point, this._startPoint),
size = bounds.getSize();
DomUtil.setPosition(this._box, bounds.min);
this._box.style.width = size.x + 'px';
this._box.style.height = size.y + 'px';
},
_finish: function () {
if (this._moved) {
DomUtil.remove(this._box);
DomUtil.removeClass(this._container, 'leaflet-crosshair');
}
DomUtil.enableTextSelection();
DomUtil.enableImageDrag();
DomEvent.off(document, {
contextmenu: DomEvent.stop,
mousemove: this._onMouseMove,
mouseup: this._onMouseUp,
keydown: this._onKeyDown
}, this);
},
_onMouseUp: function (e) {
if ((e.which !== 1) && (e.button !== 1)) { return; }
this._finish();
if (!this._moved) { return; }
// Postpone to next JS tick so internal click event handling
// still see it as "moved".
this._clearDeferredResetState();
this._resetStateTimeout = setTimeout(Util.bind(this._resetState, this), 0);
var bounds = new LatLngBounds(
this._map.containerPointToLatLng(this._startPoint),
this._map.containerPointToLatLng(this._point));
this._map
//.fitBounds(bounds)
.fire('boxzoomend', {boxZoomBounds: bounds});
},
_onKeyDown: function (e) {
if (e.keyCode === 27) {
this._finish();
}
}
});
// @section Handlers
// @property boxZoom: Handler
// Box (shift-drag with mouse) zoom handler.
Map.addInitHook('addHandler', 'rectSelect', RectSelect);
import "./index.css";
import L from "leaflet";
import LContextMenu from "leaflet-contextmenu";
import RectSelect from "./Map.RectSelect";
import Vue from "vue";
import Hello from "./components/Hello.vue";
import StopPopup from "./components/StopPopup.vue";
......@@ -110,10 +111,31 @@ let app = new Vue({
}
});
function applySelectedMarkerStyle(marker) {
marker.setStyle({color: "#f00"});
}
function applyDefaultMarkerStyle(marker) {
marker.setStyle({color: "#3388ff"});
}
function filterStops(bounds) {
Object.values(app.stopMarkers).forEach(marker => {
if (bounds.contains(marker._latlng)) {
applySelectedMarkerStyle(marker);
}
});
}
let map = L.map('map', {
preferCanvas: true,
contextmenu: true,
}).setView([40.42, -3.70], 13);
boxZoom: false,
}).setView([40.42, -3.70], 13)
.on("boxzoomend", function(e) {
console.log(e);
filterStops(e.boxZoomBounds);
});
let canvasRenderer = L.canvas({ padding: 0.2 });
/*
......@@ -131,12 +153,12 @@ L.tileLayer('https://{s}.tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey
let stopLayer = L.geoJSON(null, {
onEachFeature: function(feature, layer) {
layer.bindPopup(() => {
layer.setStyle({color: "#f00"});
applySelectedMarkerStyle(layer);
app.selectedStop = feature.properties;
return app.$refs.hiddenStopPopup.$el;
}, {
maxWidth: "auto"
}).on("popupclose", () => layer.setStyle({color: "#3388ff"}));
}).on("popupclose", () => applyDefaultMarkerStyle(layer));
},
pointToLayer: function(feature, coords) {
app.stopMarkers[feature.properties.id] = L.circleMarker(coords, {
......@@ -179,13 +201,13 @@ let lineLayer = L.geoJSON(null, {
map.on("contextmenu.show", (e) => {
if (e.sourceTarget && e.sourceTarget.setStyle) {
app.contextStop = e.sourceTarget.feature;
e.sourceTarget.setStyle({color: "#f00"})
applySelectedMarkerStyle(e.sourceTarget);
}
});
map.on("contextmenu.hide", (e) => {
if (app.contextStop) {
app.stopMarkers[app.contextStop.properties.id].setStyle({color: "#3388ff"});
applyDefaultMarkerStyle(app.stopMarkers[app.contextStop.properties.id]);
//app.contextStop = null;
}
});
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment