@deck.gl-community/layers
Version:
Add-on layers for deck.gl
125 lines • 5.08 kB
JavaScript
// deck.gl-community
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { CompositeLayer, COORDINATE_SYSTEM } from '@deck.gl/core';
import { ScatterplotLayer } from '@deck.gl/layers';
import { SimpleMeshLayer } from '@deck.gl/mesh-layers';
import { PathOutlineLayer } from "../path-outline-layer/path-outline-layer.js";
import { Arrow2DGeometry } from "./arrow-2d-geometry.js";
import { createPathMarkers } from "./create-path-markers.js";
import { getClosestPointOnPolyline } from "./polyline.js";
const DISTANCE_FOR_MULTI_ARROWS = 0.1;
const ARROW_HEAD_SIZE = 0.2;
const ARROW_TAIL_WIDTH = 0.05;
// const ARROW_CENTER_ADJUST = -0.8;
const DEFAULT_MARKER_LAYER = SimpleMeshLayer;
const DEFAULT_MARKER_LAYER_PROPS = {
mesh: new Arrow2DGeometry({ headSize: ARROW_HEAD_SIZE, tailWidth: ARROW_TAIL_WIDTH })
};
const defaultProps = Object.assign({}, PathOutlineLayer.defaultProps, {
MarkerLayer: DEFAULT_MARKER_LAYER,
markerLayerProps: DEFAULT_MARKER_LAYER_PROPS,
sizeScale: 100,
fp64: false,
highlightIndex: -1,
highlightPoint: null,
getPath: (x) => x.path,
getColor: (x) => x.color,
getMarkerColor: (x) => [0, 0, 0, 255],
getDirection: (x) => x.direction,
getMarkerPercentages: (object, { lineLength }) => lineLength > DISTANCE_FOR_MULTI_ARROWS ? [0.25, 0.5, 0.75] : [0.5]
});
export class PathMarkerLayer extends CompositeLayer {
static layerName = 'PathMarkerLayer';
static defaultProps = defaultProps;
state = undefined;
initializeState() {
this.state = {
markers: [],
mesh: new Arrow2DGeometry({ headSize: ARROW_HEAD_SIZE, tailWidth: ARROW_TAIL_WIDTH }),
closestPoint: null,
closestPoints: []
};
}
projectFlat(xyz, viewport, coordinateSystem, coordinateOrigin) {
if (coordinateSystem === COORDINATE_SYSTEM.METER_OFFSETS) {
const [dx, dy] = viewport.metersToLngLatDelta(xyz);
const [x, y] = coordinateOrigin;
return viewport.projectFlat([x + dx, dy + y]);
}
else if (coordinateSystem === COORDINATE_SYSTEM.LNGLAT_OFFSETS) {
const [dx, dy] = xyz;
const [x, y] = coordinateOrigin;
return viewport.projectFlat([x + dx, dy + y]);
}
return viewport.projectFlat(xyz);
}
updateState({ props, oldProps, changeFlags }) {
if (changeFlags.dataChanged || changeFlags.updateTriggersChanged) {
const { data, getPath, getDirection, getMarkerColor, getMarkerPercentages, coordinateSystem, coordinateOrigin } = this.props;
const { viewport } = this.context;
const projectFlat = (o) => this.projectFlat(o, viewport, coordinateSystem, coordinateOrigin);
this.state.markers = createPathMarkers({
data,
getPath,
getDirection,
getColor: getMarkerColor,
getMarkerPercentages,
projectFlat
});
this._recalculateClosestPoint();
}
if (changeFlags.propsChanged) {
if (props.point !== oldProps.point) {
this._recalculateClosestPoint();
}
}
}
_recalculateClosestPoint() {
const { highlightPoint, highlightIndex } = this.props;
if (highlightPoint && highlightIndex >= 0) {
const object = this.props.data[highlightIndex];
const points = this.props.getPath(object, null);
const { point } = getClosestPointOnPolyline({ points, p: highlightPoint });
this.state.closestPoints = [{ position: point }];
}
else {
this.state.closestPoints = [];
}
}
getPickingInfo({ info }) {
return Object.assign(info, {
// override object with picked feature
object: (info.object && info.object.path) || info.object
});
}
renderLayers() {
return [
new PathOutlineLayer(this.props, this.getSubLayerProps({
id: 'paths',
// Note: data has to be passed explicitly like this to avoid being empty
data: this.props.data
})),
new this.props.MarkerLayer(this.getSubLayerProps(Object.assign({}, this.props.markerLayerProps, {
id: 'markers',
data: this.state.markers,
getOrientation: (x) => [0, -x.angle, 0],
getColor: (x) => x.color,
sizeScale: this.props.sizeScale,
fp64: this.props.fp64,
pickable: false,
parameters: {
blend: false,
depthTest: false
}
}))),
this.state.closestPoints &&
new ScatterplotLayer({
id: `${this.props.id}-highlight`,
data: this.state.closestPoints,
fp64: this.props.fp64
})
];
}
}
//# sourceMappingURL=path-marker-layer.js.map