oxjs/source/UI/js/Map/MapRectangle.js

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;
};