oxjs/source/UI/js/Map/MapPlace.js
Sanjay Bhangar a0b1e0eab4 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

223 lines
5.3 KiB
JavaScript

'use strict';
/*@
Ox.MapPlace <f> MapPlace Object
(options) -> <o> MapPlace Object
options <o> Options object
east <n|0>
editing <b|false>
geoname <s|''>
map <o|null>
markerColor <a|[255> 0> 0]>
markerSize <n|16>
name <s|''>
north <n|0>
selected <b|false>
south <n|0>
type <s|''>
visible <b|false>
west <n|0>
@*/
Ox.MapPlace = function(options) {
options = Ox.extend({
east: 0,
editable: true,
editing: false,
geoname: '',
map: null,
name: '',
north: 0,
selected: false,
south: 0,
type: '',
visible: false,
west: 0
}, options);
var that = this;
Ox.forEach(options, function(val, key) {
that[key] = val;
});
update();
function update(updateMarker) {
if (that.west > that.east) {
that.east += 360;
}
that.points = {
ne: new maplibregl.LngLat(that.east, that.north),
sw: new maplibregl.LngLat(that.west, that.south)
};
that.bounds = new maplibregl.LngLatBounds(that.points.sw, that.points.ne);
that.center = that.bounds.getCenter();
that.lat = that.center.lat;
that.lng = that.center.lng;
Ox.extend(that.points, {
e: new maplibregl.LngLat(that.east, that.lat),
s: new maplibregl.LngLat(that.lng, that.south),
se: new maplibregl.LngLat(that.east, that.south),
n: new maplibregl.LngLat(that.lng, that.north),
nw: new maplibregl.LngLat(that.west, that.north),
w: new maplibregl.LngLat(that.west, that.lat)
});
// fixme: use bounds.toSpan()
that.sizeNorthSouth = (that.north - that.south)
* Ox.EARTH_CIRCUMFERENCE / 360;
that.sizeEastWest = (that.east + (that.west > that.east ? 360 : 0) - that.west)
* Ox.getMetersPerDegree(that.lat);
that.area = Ox.getArea(
{lat: that.south, lng: that.west},
{lat: that.north, lng: that.east}
);
if (!that.marker) {
that.marker = new Ox.MapMarker({
map: that.map,
place: that
});
that.rectangle = new Ox.MapRectangle({
map: that.map,
place: that
});
} else if (updateMarker) {
console.log("fixme update marker")
//that.marker.update();
//that.rectangle.update();
}
}
function editable() {
return that.map.options('editable') && that.editable;
}
/*@
add <f> add
@*/
that.add = function() {
that.visible = true;
that.marker.add();
return that;
};
/*@
cancel <f> cancel
@*/
that.cancel = function() {
if (editable()) {
that.undo();
that.editing = false;
that.marker.update();
that.rectangle.deselect();
}
return that;
};
/*@
crossesDateline <f> crossesDateline
@*/
that.crossesDateline = function() {
return that.west > that.east;
}
/*@
deselect <f> dselect
@*/
that.deselect = function() {
that.editing && that.submit();
that.selected = false;
that.marker.update();
that.rectangle.remove();
return that;
};
/*@
edit <f> edit
@*/
that.edit = function() {
if (editable()) {
that.editing = true;
that.original = {
south: that.south,
west: that.west,
north: that.north,
east: that.east
};
that.marker.edit();
that.rectangle.select();
}
return that;
};
// fixme: make this an Ox.Element to get options handling for free?
that.options = function(options) {
options = Ox.makeObject(arguments);
Ox.forEach(options, function(value, key) {
that[key] = value;
});
update(true);
};
/*@
remove <f> remove
@*/
that.remove = function() {
that.editing && that.submit();
that.selected && that.deselect();
that.visible = false;
that.marker.remove();
return that;
};
/*@
select <f> select
@*/
that.select = function() {
that.selected = true;
!that.visible && that.add();
that.marker.update();
that.rectangle.add();
return that;
};
/*@
submit <f> submit
@*/
that.submit = function() {
if (editable()) {
that.editing = false;
that.marker.update();
that.rectangle.deselect();
}
return that;
};
/*@
update <f> update
@*/
that.update = function(updateMarker) {
update(updateMarker);
that.map.triggerEvent('changeplace', that);
return that;
};
/*@
undo <f> undo
@*/
that.undo = function() {
if (editable()) {
Ox.forEach(that.original, function(v, k) {
that[k] = v;
});
that.update();
that.marker.update();
that.rectangle.update();
}
return that;
};
return that;
};