I am creating some mapping software with Mapbox GL JS. So far it has gotten a bit complex but everything is working how I intended except for moving features. The behavior is expected except in a few edge cases. It seems to happen when I am editing the point of a LineString with multiple points.
here is a link to a gif demonstrating my issue
MoveFeatures.js
var editing_feature = null;
var moving_features = false;
var get_manipulated_coordinate_index_buffer = 5;
var click_buffer = 5;
var get_attached_lines_buffer = 5;
var manipulated = null;
var manipulated_sources_buffer_array = [];
var get_attached_lines = (point_feature) => {
var point = window.MAP.mapbox.project(point_feature.geometry.coordinates);
var buffer = get_attached_lines_buffer;
var b = [window.MAP.mapbox.project([window.MAP.bounds.x, window.MAP.bounds.y]), window.MAP.mapbox.project([window.MAP.bounds.i, window.MAP.bounds.j])];
var features = [];
window.MAP.mapbox.queryRenderedFeatures([[point.x - buffer, point.y - buffer], [point.x + buffer, point.y + buffer]], {layers: ['lines']}).forEach((feature) => {
features[feature.id] = feature;
})
var at = window.MAP.mapbox.queryRenderedFeatures(b, {layers: ['lines']}).filter((feature) => {
return features[feature.id] !== undefined;
})
//console.log(at)
return at
}
var get_manipulated_coordinate_index = (attached_lines, point_feature) => { //gets the index of the coordinates that is being manipulated in a LineString
console.log(attached_lines)
var point = window.MAP.mapbox.project(point_feature.geometry.coordinates);
var buffer = get_manipulated_coordinate_index_buffer;
var indexes = [];
var pt1 = turf.polygon([[[point.x - buffer, point.y - buffer],[point.x + buffer, point.y - buffer],[point.x + buffer, point.y + buffer],[point.x - buffer, point.y + buffer],[point.x - buffer, point.y - buffer]]]);
attached_lines.forEach((feature, i) => {
feature.geometry.coordinates.forEach((coordinate, j) => {
var converted = window.MAP.mapbox.project(coordinate);
var pt = turf.point([converted.x, converted.y]);
if(turf.booleanPointInPolygon(pt, pt1)){
indexes.push({line_index:i, coordinate_index:j, source:window.MAP.mapbox.getSource(feature.source)})
}
})
})
return {indexes:indexes, lines:attached_lines};
}
export default {
actions:[
{
event_type:'click',
func: (e) => {
var buffer = click_buffer;
var feature = window.UTILS.get_clicked_point(e);
window.UTILS.toggle_point_highlight(feature);
if(!moving_features){
if(feature != null){
moving_features = true;
editing_feature = window.MAP.mapbox.getSource(feature.properties.s_uid + '_hovered')._data.features.filter((f) => { return f.id == feature.id })[0];
manipulated = get_manipulated_coordinate_index(get_attached_lines(editing_feature), editing_feature);
}
}else{
editing_feature = null;
manipulated = null;
manipulated_sources_buffer_array = [];
moving_features = false;
}
}
},
{
event_type:'mousemove',
func: (e) => {
if(moving_features){
manipulated.lines.forEach((feature, i) => {
var f = feature;
if(manipulated.indexes[i] !== undefined){
f.geometry.coordinates[manipulated.indexes[i].coordinate_index] = [e.lngLat.lng, e.lngLat.lat];
}
window.UTILS.update_feature(f);
})
editing_feature.geometry.coordinates = [e.lngLat.lng, e.lngLat.lat];
window.UTILS.update_feature(editing_feature);
}
}
},
{
event_type:'disable',
func: (e) => {
window.UTILS.toggle_point_highlight(editing_feature);
editing_feature = null;
manipulated = null;
manipulated_sources_buffer_array = [];
moving_features = false;
}
}
]
}
Utils.js
var debounced = [];
const UTILS = {
rgb_to_hex: (rgb) => {
rgb = rgb.split('(')[1].split(')')[0].split(',')
var r = parseInt(rgb[0]);
var g = parseInt(rgb[1]);
var b = parseInt(rgb[2]);
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
},
hex_to_rgb: (hex) => {
if(hex[0] == '#'){
hex = hex.slice(1);
}
return `rgb(${parseInt(hex.slice(1, 3), 16)}, ${parseInt(hex.slice(3, 5), 16)}, ${parseInt(hex.slice(5, 7), 16)})`;
},
get_clicked_point: (e) => {
var buffer = 5;
var symbol_hover_layers = window.MAP.loaded_images.map((image) => { return image + '_hovered' });
var feature = window.MAP.mapbox.queryRenderedFeatures([[e.point.x - buffer, e.point.y - buffer], [e.point.x + buffer, e.point.y + buffer]], {layers:[...window.MAP.loaded_images, ...symbol_hover_layers] })[0];
if(feature && feature.geometry.type == 'Point'){
return feature
}else{
return null;
}
},
get_render_area(){
var bounds = window.MAP.mapbox.getBounds();
var topLeft = bounds.getNorthWest();
var bottomRight = bounds.getSouthEast();
return {x: topLeft.lng, y: topLeft.lat, i: bottomRight.lng, j: bottomRight.lat}
},
get_render_area2(){
var render_area = window.UTILS.get_render_area();
var start = window.MAP.mapbox.project([render_area.x, render_area.y]);
var end = window.MAP.mapbox.project([render_area.i, render_area.j]);
return [start, end]
},
debounce(func, timeout){
if(window.debounce_timeout){
clearTimeout(window.debounce_timeout);
}
window.debounce_timeout = setTimeout(func, timeout)
},
delete_feature(feature){
var source = window.MAP.mapbox.getSource(feature.source);
source._data.features = source._data.features.filter((f) => {
return f.id !== feature.id;
});
source.setData(source._data);
},
update_feature(feature){
this.delete_feature(feature);
var source = window.MAP.mapbox.getSource(feature.source);
source._data.features.push(feature);
source.setData(source._data);
},
toggle_point_highlight(feature){
if(feature){
if(feature.properties.hover){
this.unhighlight_point(feature);
}else{
this.highlight_point(feature);
}
}
},
highlight_point(feature){
if(feature.geometry.type == 'Point'){
this.delete_feature(feature);
feature.properties.hover = true;
var s = window.MAP.mapbox.getSource(feature.source + '_hovered');
feature.source = feature.source + '_hovered';
s._data.features.push(feature);
s.setData(s._data);
}
},
unhighlight_point(feature){
if(feature.geometry.type == 'Point'){
this.delete_feature(feature);
feature.properties.hover = false;
var s = window.MAP.mapbox.getSource(feature.source.replace('_hovered', ''));
feature.source = feature.source.replace('_hovered', '');
s._data.features.push(feature);
s.setData(s._data);
}
}
}
export default UTILS;
Has anyone here implement feature manipulation in mapbox? What could I do differently to make this behave better? All i need to move is the points and the lines attached to them the rest of the lines should be maintained.