333 lines
8.5 KiB
JavaScript
333 lines
8.5 KiB
JavaScript
'use strict';
|
|
|
|
|
|
class MapLibreRectangle {
|
|
constructor(options = {}) {
|
|
this.id = options.id || 'rectangle-' + Ox.uid();
|
|
this.bounds = options.bounds;
|
|
this.draggable = options.draggable || false;
|
|
this.onclick = options.onclick || null
|
|
}
|
|
|
|
_createRectangle() {
|
|
const coords = this._getPolygonCoordinates();
|
|
|
|
const rectangleGeoJSON = {
|
|
type: 'Feature',
|
|
geometry: {
|
|
type: 'Polygon',
|
|
coordinates: [coords]
|
|
},
|
|
properties: {
|
|
id: this.id
|
|
}
|
|
};
|
|
var sourceId = `${this.id}-rectangles`
|
|
this.source = this.map.getSource(sourceId)
|
|
if (!this.source) {
|
|
this.map.addSource(sourceId, {
|
|
type: 'geojson',
|
|
data: {
|
|
type: 'FeatureCollection',
|
|
features: []
|
|
}
|
|
});
|
|
this.source = this.map.getSource(sourceId)
|
|
|
|
// Add fill layer
|
|
var layerId = `${this.id}-fill`
|
|
if (!this.map.getLayer(layerId)) {
|
|
this.map.addLayer({
|
|
id: layerId,
|
|
type: 'fill',
|
|
source: sourceId,
|
|
paint: {
|
|
'fill-color': '#088',
|
|
'fill-opacity': 0.3
|
|
}
|
|
});
|
|
}
|
|
|
|
// Add outline layer
|
|
var layerId = `${this.id}-outline`
|
|
if (!this.map.getLayer(layerId)) {
|
|
this.map.addLayer({
|
|
id: layerId,
|
|
type: 'line',
|
|
source: sourceId,
|
|
paint: {
|
|
'line-color': '#000',
|
|
'line-width': 2
|
|
}
|
|
});
|
|
}
|
|
}
|
|
/*
|
|
this.source._data.features.push(rectangleGeoJSON)
|
|
this.source.setData(this.source._data)
|
|
*/
|
|
}
|
|
|
|
_getPolygonCoordinates() {
|
|
const sw = this.bounds._sw;
|
|
const ne = this.bounds._ne;
|
|
|
|
return [
|
|
[sw.lng, ne.lat], // NW
|
|
[ne.lng, ne.lat], // NE
|
|
[ne.lng, sw.lat], // SE
|
|
[sw.lng, sw.lat], // SW
|
|
[sw.lng, ne.lat] // Close polygon
|
|
];
|
|
}
|
|
|
|
setBounds(bounds) {
|
|
this.bounds = bounds;
|
|
const coords = this._getPolygonCoordinates();
|
|
const updatedData = {
|
|
type: 'Feature',
|
|
geometry: {
|
|
type: 'Polygon',
|
|
coordinates: [coords]
|
|
},
|
|
properties: {
|
|
id: this.id
|
|
}
|
|
};
|
|
var updated = false;
|
|
this.source._data.features.forEach(feature => {
|
|
if (feature.properties.id == this.id) {
|
|
feature.geometry = updatedData.geometry
|
|
updated = true
|
|
}
|
|
})
|
|
if (!updated) {
|
|
this.source._data.features.push(updatedData)
|
|
}
|
|
this.source.setData(this.source._data)
|
|
}
|
|
|
|
getBounds() {
|
|
return this.bounds;
|
|
}
|
|
|
|
_enableDragging() {
|
|
let isDragging = false;
|
|
let startPos;
|
|
|
|
this.map.on('mousedown', `${this.id}-fill`, (e) => {
|
|
e.preventDefault();
|
|
isDragging = true;
|
|
startPos = e.lngLat;
|
|
this.map.getCanvas().style.cursor = 'grabbing';
|
|
});
|
|
|
|
this.map.on('mousemove', (e) => {
|
|
if (!isDragging) return;
|
|
|
|
const dx = e.lngLat.lng - startPos.lng;
|
|
const dy = e.lngLat.lat - startPos.lat;
|
|
|
|
const sw = [this.bounds[0][0] + dx, this.bounds[0][1] + dy];
|
|
const ne = [this.bounds[1][0] + dx, this.bounds[1][1] + dy];
|
|
|
|
this.setBounds([sw, ne]);
|
|
startPos = e.lngLat;
|
|
});
|
|
|
|
this.map.on('mouseup', () => {
|
|
if (isDragging) {
|
|
isDragging = false;
|
|
this.map.getCanvas().style.cursor = '';
|
|
}
|
|
});
|
|
}
|
|
_enableClicking() {
|
|
this.map.on('click', `${this.id}-fill`, e => {
|
|
console.log('click', e)
|
|
if (this.onclick) {
|
|
e.preventDefault()
|
|
//e.stopPropagation()
|
|
this.onclick(e)
|
|
}
|
|
})
|
|
}
|
|
|
|
remove() {
|
|
this.source._data.features = this.source._data.features.filter(feature => {
|
|
return feature.properties.id != this.id
|
|
})
|
|
this.source.setData(this.source._data)
|
|
}
|
|
|
|
add() {
|
|
this.setBounds(this.bounds)
|
|
}
|
|
|
|
addTo(map) {
|
|
this.map = map;
|
|
this._createRectangle();
|
|
if (this.draggable) this._enableDragging();
|
|
this._enableClicking();
|
|
}
|
|
}
|
|
|
|
|
|
/*@
|
|
Ox.MapRectangle <f> MapRectangle Object
|
|
(options) -> <o> MapRectangle Object
|
|
options <o> Options object
|
|
map <o|null> map
|
|
place <o|null> place
|
|
@*/
|
|
|
|
Ox.MapRectangle = function(options) {
|
|
|
|
options = Ox.extend({
|
|
map: null,
|
|
place: null
|
|
}, options);
|
|
|
|
var that = this,
|
|
themeData = Ox.Theme.getThemeData();
|
|
|
|
Ox.forEach(options, function(val, key) {
|
|
that[key] = val;
|
|
});
|
|
|
|
/*@
|
|
rectangle <f> google.maps.Rectangle
|
|
@*/
|
|
/*
|
|
that.rectangle = new google.maps.Rectangle({
|
|
clickable: true,
|
|
bounds: that.place.bounds
|
|
});
|
|
*/
|
|
that.rectangle = new MapLibreRectangle({
|
|
bounds: that.place.bounds,
|
|
});
|
|
that.rectangle.addTo(that.map.map);
|
|
that.rectangle.onclick = click
|
|
|
|
/*@
|
|
markers <a> array of markers (only corners for rectangle resizing)
|
|
@*/
|
|
var cornerPositions = ['ne', 'nw', 'se', 'sw'];
|
|
that.markers = cornerPositions.map(function(position) {
|
|
return new Ox.MapRectangleMarker({
|
|
map: that.map,
|
|
place: that.place,
|
|
position: position
|
|
});
|
|
});
|
|
|
|
setOptions();
|
|
|
|
function click(e) {
|
|
console.log('RECTANGLE CLICK DEBUG:');
|
|
console.log('- map.editable:', that.map.options('editable'));
|
|
console.log('- place.editable:', that.place.editable);
|
|
console.log('- place.editing:', that.place.editing);
|
|
console.log('- place object:', that.place);
|
|
|
|
if (
|
|
that.map.options('editable')
|
|
&& that.place.editable
|
|
&& !that.place.editing
|
|
) {
|
|
console.log('- Calling place.edit()');
|
|
that.place.edit();
|
|
} else if (that.map.getKey() == 'meta') {
|
|
that.place.submit();
|
|
} else if (that.map.getKey() == 'shift') {
|
|
that.map.zoomToPlace();
|
|
} else {
|
|
that.map.panToPlace();
|
|
}
|
|
}
|
|
|
|
function setOptions() {
|
|
var color = '#' + Ox.toHex(themeData[
|
|
that.place.editing
|
|
? 'mapPlaceEditingBorder'
|
|
: 'mapPlaceSelectedBorder'
|
|
]);
|
|
/*
|
|
that.rectangle.setOptions({
|
|
bounds: that.place.bounds,
|
|
fillColor: color,
|
|
fillOpacity: that.place.editing ? 0.1 : 0,
|
|
strokeColor: color,
|
|
strokeOpacity: that.place.id[0] == '_' ? 0.5 : 1,
|
|
strokeWeight: 2
|
|
});
|
|
*/
|
|
/*
|
|
console.log("fixme", {
|
|
bounds: that.place.bounds,
|
|
fillColor: color,
|
|
fillOpacity: that.place.editing ? 0.1 : 0,
|
|
strokeColor: color,
|
|
strokeOpacity: that.place.id[0] == '_' ? 0.5 : 1,
|
|
strokeWeight: 2
|
|
});
|
|
*/
|
|
}
|
|
|
|
/*@
|
|
add <f> add
|
|
@*/
|
|
that.add = function() {
|
|
that.rectangle.add()
|
|
return that;
|
|
};
|
|
|
|
/*@
|
|
deselect <f> deselect
|
|
@*/
|
|
that.deselect = function() {
|
|
setOptions();
|
|
Ox.Log('Map', 'MARKERS', that.markers)
|
|
Ox.forEach(that.markers, function(marker) {
|
|
marker.remove();
|
|
});
|
|
return that;
|
|
};
|
|
|
|
/*@
|
|
remove <f> remove
|
|
@*/
|
|
that.remove = function() {
|
|
that.rectangle.remove();
|
|
return that;
|
|
}
|
|
|
|
/*@
|
|
select <f> select
|
|
@*/
|
|
that.select = function() {
|
|
setOptions();
|
|
Ox.forEach(that.markers, function(marker) {
|
|
marker.add();
|
|
});
|
|
return that;
|
|
};
|
|
|
|
/*@
|
|
update <f> udpate
|
|
@*/
|
|
that.update = function() {
|
|
Ox.Log('Map', 'UPDATE...')
|
|
setOptions();
|
|
// Update the visual rectangle bounds
|
|
that.rectangle.setBounds(that.place.bounds);
|
|
Ox.forEach(that.markers, function(marker) {
|
|
marker.update();
|
|
});
|
|
return that;
|
|
}
|
|
|
|
return that;
|
|
|
|
};
|