Я играю с созданием GridLayer на основе Konva для Leaflet (в основном абстракция вокруг элементов холста, чтобы попытаться эффективно отобразить десятки тысяч функций). У меня есть некоторый код, который, кажется, работает до некоторой степени (строки в моих примерах данных, похоже, совпадают с тем, что я ожидал), но я получаю странное поведение. В частности, функции будут заметно «телепортироваться» или полностью исчезать. Кроме того, нередко можно увидеть разрывы линий по краям плитки. Я подозреваю, что это означает, что я неправильно вычисляю местоположение пикселя внутри каждой плитки (хотя, безусловно, возможно, что-то еще не так). Я в основном идентифицирую местоположение пикселя плитки (x, y в renderStage()) и перевожу положение пикселя карты на это количество пикселей (pt.x и pt.y, сгенерированные путем проецирования широты/долготы). Это предназначено для создания массива [x1, y1, x2, y2, ...], который можно отобразить в отдельной плитке. Ожидается, что все будет в формате EPSG:4326.
Кто-нибудь знает, как правильно проецировать широту/долготу в пиксельные координаты в отдельных плитках GridLayer? Существует множество примеров того, как сделать это для всей карты, но, похоже, это не совсем понятно, как найти те же местоположения пикселей в тайлах, смещенных от верхнего левого угла карты.
import { GridLayer, withLeaflet } from "react-leaflet";
import { GridLayer as LeafletGridLayer } from "leaflet";
import { Stage, Line, FastLayer } from "konva";
import * as Util from 'leaflet/src/core/Util';
import _ from "lodash";
export const CollectionLayer = LeafletGridLayer.extend({
options: {
tileSize: 256
},
initialize: function(collection, props) {
Util.setOptions(this, props)
this.collection = collection;
this.stages = new Map();
this.shapes = {};
this.cached = {};
this.on('tileunload', (e) => {
const stage = this.stages[e.coords]
if (stage) {
this.stages.delete(e.coords)
stage.destroy()
}
})
},
renderStage: function(stage, coords, tileBounds) {
const x = coords.x * this._tileSize.x
const y = coords.y * this._tileSize.y
const z = coords.z;
const layer = stage.getLayers()[0]
if (!layer || !tileBounds) return;
_.each(this.collection.data, (entity, id) => {
if (entity.bounds && tileBounds.intersects(entity.bounds)) {
let shape = this.shapes[id]
if (!shape) {
shape = new Line()
shape.shadowForStrokeEnabled(false)
this.shapes[id] = shape
}
layer.add(shape);
const points = entity.position.reduce((pts, p) => {
const pt = this._map.project([p.value[1], p.value[0]], this._tileZoom)
pts.push(pt.x - x);
pts.push(pt.y - y);
return pts
}, [])
shape.points(points);
shape.stroke('red');
shape.strokeWidth(2);
this.shapes[id] = shape
}
})
layer.batchDraw()
},
createTile: function(coords) {
const tile = document.createElement("div");
const tileSize = this.getTileSize();
const stage = new Stage({
container: tile,
width: tileSize.x,
height: tileSize.y
});
const bounds = this._tileCoordsToBounds(coords);
const layer = new FastLayer();
stage.add(layer);
this.stages[coords] = stage
this.renderStage(stage, coords, bounds);
return tile;
}
});
class ReactCollectionLayer extends GridLayer {
createLeafletElement(props) {
console.log("PROPS", props);
return new CollectionLayer(props.collection.data, this.getOptions(props));
}
updateLeafletElement(fromProps, toProps) {
super.updateLeafletElement(fromProps, toProps);
if (this.leafletElement.collection !== toProps.collection) {
this.leafletElement.collection = toProps.collection
this.leafletElement.redraw();
}
}
}
export default withLeaflet(ReactCollectionLayer);