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

326 lines
8.1 KiB
JavaScript
Raw Normal View History

2011-11-05 17:46:53 +01:00
'use strict';
2025-08-05 18:50:06 +02:00
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)
2025-08-05 18:50:06 +02:00
if (!this.source) {
this.map.addSource(sourceId, {
2025-08-05 18:50:06 +02:00
type: 'geojson',
data: {
type: 'FeatureCollection',
features: []
}
});
this.source = this.map.getSource(sourceId)
2025-08-05 18:50:06 +02:00
// Add fill layer
var layerId = `${this.id}-fill`
if (!this.map.getLayer(layerId)) {
2025-08-05 18:50:06 +02:00
this.map.addLayer({
id: layerId,
2025-08-05 18:50:06 +02:00
type: 'fill',
source: sourceId,
2025-08-05 18:50:06 +02:00
paint: {
'fill-color': '#088',
'fill-opacity': 0.3
}
});
}
// Add outline layer
var layerId = `${this.id}-outline`
if (!this.map.getLayer(layerId)) {
2025-08-05 18:50:06 +02:00
this.map.addLayer({
id: layerId,
2025-08-05 18:50:06 +02:00
type: 'line',
source: sourceId,
2025-08-05 18:50:06 +02:00
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 => {
2025-08-06 21:50:00 +02:00
console.log('click', e)
2025-08-05 18:50:06 +02:00
if (this.onclick) {
2025-08-06 21:50:00 +02:00
e.preventDefault()
//e.stopPropagation()
2025-08-05 18:50:06 +02:00
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();
}
}
2011-05-16 12:49:48 +02:00
/*@
Ox.MapRectangle <f> MapRectangle Object
2012-05-31 12:32:54 +02:00
(options) -> <o> MapRectangle Object
2011-05-16 12:49:48 +02:00
options <o> Options object
map <o|null> map
place <o|null> place
@*/
2012-05-31 12:32:54 +02:00
Ox.MapRectangle = function(options) {
2011-04-23 00:03:10 +02:00
options = Ox.extend({
2012-05-28 18:21:00 +02:00
map: null,
place: null
}, options);
2011-04-23 00:03:10 +02:00
2012-12-28 18:00:02 +01:00
var that = this,
themeData = Ox.Theme.getThemeData();
2011-04-23 00:03:10 +02:00
Ox.forEach(options, function(val, key) {
that[key] = val;
});
2011-05-16 12:49:48 +02:00
/*@
rectangle <f> google.maps.Rectangle
@*/
2025-08-05 18:50:06 +02:00
/*
2011-04-23 00:03:10 +02:00
that.rectangle = new google.maps.Rectangle({
clickable: true,
2012-05-26 15:48:19 +00:00
bounds: that.place.bounds
2011-04-23 00:03:10 +02:00
});
2025-08-05 18:50:06 +02:00
*/
that.rectangle = new MapLibreRectangle({
bounds: that.place.bounds,
});
that.rectangle.addTo(that.map.map);
that.rectangle.onclick = click
2011-05-16 12:49:48 +02:00
/*@
Here's what we've accomplished to fix MapLibre GL rectangle editing: Core Issues Fixed: 1. MapLibre GL Event Compatibility: Fixed drag event handlers in MapMarker.js and MapRectangleMarker.js to use marker.getLngLat() instead of accessing e.lngLat properties that don't exist in MapLibre GL. 2. Rectangle Handle Visibility: Replaced Ox.MapMarkerImage() with proper DOM elements for corner handles since MapLibre GL expects DOM elements, not image objects. 3. Handle Positioning: Limited corner markers to only the 4 corners (ne, nw, se, sw) instead of all 8 positions (including edges). 4. Visual Rectangle Updates: Added that.rectangle.setBounds() call in MapRectangle update method so the visual rectangle updates when handles are dragged. 5. Click Event Conflicts: Fixed map click handler to detect rectangle clicks and avoid deselecting rectangles when clicked for editing. 6. Place Editable Property: Added editable: true as default in MapPlace constructor. Files Modified: - MapPlace.js: Added editable: true default - MapRectangle.js: - Limited markers to 4 corners only - Added rectangle bounds update in update() method - MapRectangleMarker.js: - Created proper DOM elements for handles - Fixed MapLibre GL drag event handling - Improved event cleanup - MapMarker.js: Fixed MapLibre GL drag event handling - MapMarkerImage.js: Fixed rectangle marker color (kept for backward compatibility) - Map.js: Added rectangle click detection to prevent conflicts Result: Rectangle editing now works completely: - Click rectangle → shows 4 corner handles - Drag handles → resizes rectangle in real-time - No console errors - Proper event handling
2025-08-09 14:15:54 +02:00
markers <a> array of markers (only corners for rectangle resizing)
2011-05-16 12:49:48 +02:00
@*/
Here's what we've accomplished to fix MapLibre GL rectangle editing: Core Issues Fixed: 1. MapLibre GL Event Compatibility: Fixed drag event handlers in MapMarker.js and MapRectangleMarker.js to use marker.getLngLat() instead of accessing e.lngLat properties that don't exist in MapLibre GL. 2. Rectangle Handle Visibility: Replaced Ox.MapMarkerImage() with proper DOM elements for corner handles since MapLibre GL expects DOM elements, not image objects. 3. Handle Positioning: Limited corner markers to only the 4 corners (ne, nw, se, sw) instead of all 8 positions (including edges). 4. Visual Rectangle Updates: Added that.rectangle.setBounds() call in MapRectangle update method so the visual rectangle updates when handles are dragged. 5. Click Event Conflicts: Fixed map click handler to detect rectangle clicks and avoid deselecting rectangles when clicked for editing. 6. Place Editable Property: Added editable: true as default in MapPlace constructor. Files Modified: - MapPlace.js: Added editable: true default - MapRectangle.js: - Limited markers to 4 corners only - Added rectangle bounds update in update() method - MapRectangleMarker.js: - Created proper DOM elements for handles - Fixed MapLibre GL drag event handling - Improved event cleanup - MapMarker.js: Fixed MapLibre GL drag event handling - MapMarkerImage.js: Fixed rectangle marker color (kept for backward compatibility) - Map.js: Added rectangle click detection to prevent conflicts Result: Rectangle editing now works completely: - Click rectangle → shows 4 corner handles - Drag handles → resizes rectangle in real-time - No console errors - Proper event handling
2025-08-09 14:15:54 +02:00
var cornerPositions = ['ne', 'nw', 'se', 'sw'];
that.markers = cornerPositions.map(function(position) {
2011-06-20 14:53:00 +02:00
return new Ox.MapRectangleMarker({
2011-04-23 00:03:10 +02:00
map: that.map,
place: that.place,
position: position
});
});
setOptions();
2025-08-05 18:50:06 +02:00
function click(e) {
2012-01-17 23:26:26 +05:30
if (
that.map.options('editable')
&& that.place.editable
&& !that.place.editing
) {
2011-04-23 00:03:10 +02:00
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() {
2012-12-28 18:00:02 +01:00
var color = '#' + Ox.toHex(themeData[
that.place.editing
? 'mapPlaceEditingBorder'
: 'mapPlaceSelectedBorder'
]);
2025-08-05 18:50:06 +02:00
/*
2011-04-23 00:03:10 +02:00
that.rectangle.setOptions({
bounds: that.place.bounds,
2011-04-23 00:03:10 +02:00
fillColor: color,
fillOpacity: that.place.editing ? 0.1 : 0,
strokeColor: color,
strokeOpacity: that.place.id[0] == '_' ? 0.5 : 1,
2011-04-23 00:03:10 +02:00
strokeWeight: 2
});
2025-08-05 18:50:06 +02:00
*/
/*
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
});
*/
2011-04-23 00:03:10 +02:00
}
2011-05-16 12:49:48 +02:00
/*@
add <f> add
@*/
2011-04-23 00:03:10 +02:00
that.add = function() {
2025-08-05 18:50:06 +02:00
that.rectangle.add()
2011-04-23 00:03:10 +02:00
return that;
};
2011-05-16 12:49:48 +02:00
/*@
deselect <f> deselect
@*/
2011-04-23 00:03:10 +02:00
that.deselect = function() {
setOptions();
2011-11-04 16:54:28 +01:00
Ox.Log('Map', 'MARKERS', that.markers)
2011-04-23 00:03:10 +02:00
Ox.forEach(that.markers, function(marker) {
marker.remove();
});
return that;
2011-04-23 00:03:10 +02:00
};
2011-05-16 12:49:48 +02:00
/*@
remove <f> remove
@*/
2011-04-23 00:03:10 +02:00
that.remove = function() {
2025-08-05 18:50:06 +02:00
that.rectangle.remove();
return that;
2011-04-23 00:03:10 +02:00
}
2011-05-16 12:49:48 +02:00
/*@
select <f> select
@*/
2011-04-23 00:03:10 +02:00
that.select = function() {
setOptions();
Ox.forEach(that.markers, function(marker) {
marker.add();
});
return that;
2011-04-23 00:03:10 +02:00
};
2011-05-16 12:49:48 +02:00
/*@
update <f> udpate
@*/
2011-04-23 00:03:10 +02:00
that.update = function() {
2011-11-04 16:54:28 +01:00
Ox.Log('Map', 'UPDATE...')
setOptions();
Here's what we've accomplished to fix MapLibre GL rectangle editing: Core Issues Fixed: 1. MapLibre GL Event Compatibility: Fixed drag event handlers in MapMarker.js and MapRectangleMarker.js to use marker.getLngLat() instead of accessing e.lngLat properties that don't exist in MapLibre GL. 2. Rectangle Handle Visibility: Replaced Ox.MapMarkerImage() with proper DOM elements for corner handles since MapLibre GL expects DOM elements, not image objects. 3. Handle Positioning: Limited corner markers to only the 4 corners (ne, nw, se, sw) instead of all 8 positions (including edges). 4. Visual Rectangle Updates: Added that.rectangle.setBounds() call in MapRectangle update method so the visual rectangle updates when handles are dragged. 5. Click Event Conflicts: Fixed map click handler to detect rectangle clicks and avoid deselecting rectangles when clicked for editing. 6. Place Editable Property: Added editable: true as default in MapPlace constructor. Files Modified: - MapPlace.js: Added editable: true default - MapRectangle.js: - Limited markers to 4 corners only - Added rectangle bounds update in update() method - MapRectangleMarker.js: - Created proper DOM elements for handles - Fixed MapLibre GL drag event handling - Improved event cleanup - MapMarker.js: Fixed MapLibre GL drag event handling - MapMarkerImage.js: Fixed rectangle marker color (kept for backward compatibility) - Map.js: Added rectangle click detection to prevent conflicts Result: Rectangle editing now works completely: - Click rectangle → shows 4 corner handles - Drag handles → resizes rectangle in real-time - No console errors - Proper event handling
2025-08-09 14:15:54 +02:00
// Update the visual rectangle bounds
that.rectangle.setBounds(that.place.bounds);
2011-04-23 00:03:10 +02:00
Ox.forEach(that.markers, function(marker) {
marker.update();
});
return that;
2011-04-23 00:03:10 +02:00
}
return that;
2011-11-03 16:42:41 +01:00
2011-04-23 00:03:10 +02:00
};