UNPKG

@deck.gl-community/layers

Version:

Add-on layers for deck.gl

506 lines (488 loc) 16.2 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; // dist/index.js var dist_exports = {}; __export(dist_exports, { PathMarkerLayer: () => PathMarkerLayer, PathOutlineLayer: () => PathOutlineLayer }); module.exports = __toCommonJS(dist_exports); // dist/path-outline-layer/path-outline-layer.js var import_layers = require("@deck.gl/layers"); var import_constants = require("@luma.gl/constants"); // dist/path-outline-layer/outline.js var INITIAL_STATE = { outlineEnabled: false, outlineRenderShadowmap: false, outlineShadowmap: null }; function getUniforms({ outlineEnabled, outlineRenderShadowmap, outlineShadowmap } = INITIAL_STATE) { const uniforms = {}; if (outlineEnabled !== void 0) { uniforms.outline_uEnabled = outlineEnabled; } if (outlineRenderShadowmap !== void 0) { uniforms.outline_uRenderOutlines = outlineRenderShadowmap; } if (outlineShadowmap !== void 0) { uniforms.outline_uShadowmap = outlineShadowmap; } return uniforms; } var vs = `#version 300 es in float instanceZLevel; out float outline_vzLevel; out vec4 outline_vPosition; // Set the z level for the outline shadowmap rendering void outline_setZLevel(float zLevel) { outline_vzLevel = zLevel; } // Store an adjusted position for texture2DProj void outline_setUV(vec4 position) { // mat4( // 0.5, 0.0, 0.0, 0.0, // 0.0, 0.5, 0.0, 0.0, // 0.0, 0.0, 0.5, 0.0, // 0.5, 0.5, 0.5, 1.0 // ) * position; outline_vPosition = vec4(position.xyz * 0.5 + position.w * 0.5, position.w); } `; var fs = `uniform bool outline_uEnabled; uniform bool outline_uRenderOutlines; uniform sampler2D outline_uShadowmap; in float outline_vzLevel; // in vec2 outline_vUV; in vec4 outline_vPosition; out vec4 fragColor; const float OUTLINE_Z_LEVEL_ERROR = 0.01; // Return a darker color in shadowmap vec4 outline_filterShadowColor(vec4 color) { return vec4(outline_vzLevel / 255., outline_vzLevel / 255., outline_vzLevel / 255., 1.); } // Return a darker color if in shadowmap vec4 outline_filterDarkenColor(vec4 color) { if (outline_uEnabled) { float maxZLevel; if (outline_vPosition.q > 0.0) { maxZLevel = texture2DProj(outline_uShadowmap, outline_vPosition).r * 255.; } else { discard; } if (maxZLevel < outline_vzLevel + OUTLINE_Z_LEVEL_ERROR) { vec4(color.rgb * 0.5, color.a); } else { discard; } } return color; } // if enabled and rendering outlines - Render depth to shadowmap // if enabled and rendering colors - Return a darker color if in shadowmap // if disabled, just return color vec4 outline_filterColor(vec4 color) { if (outline_uEnabled) { return outline_uRenderOutlines ? outline_filterShadowColor(color) : outline_filterDarkenColor(color); } return color; } `; var outline = { name: "outline", vs, fs, getUniforms }; // dist/path-outline-layer/path-outline-layer.js var UNIT = { common: 0, meters: 1, pixels: 2 }; function injectShaderCode({ source, code = "" }) { const INJECT_CODE = /}[^{}]*$/; return source.replace(INJECT_CODE, code.concat("\n}\n")); } var VS_CODE = ` outline_setUV(gl_Position); outline_setZLevel(instanceZLevel); `; var FS_CODE = ` fragColor = outline_filterColor(fragColor); `; var defaultProps = { getZLevel: () => 0 }; var PathOutlineLayer = class extends import_layers.PathLayer { state = void 0; // Override getShaders to inject the outline module getShaders() { const shaders = super.getShaders(); return Object.assign({}, shaders, { modules: shaders.modules.concat([outline]), vs: injectShaderCode({ source: shaders.vs, code: VS_CODE }), fs: injectShaderCode({ source: shaders.fs, code: FS_CODE }) }); } // @ts-expect-error PathLayer is missing LayerContext arg initializeState(context) { super.initializeState(); this.setState({ outlineFramebuffer: context.device.createFramebuffer({}), dummyTexture: context.device.createTexture({}) }); this.state.attributeManager.addInstanced({ instanceZLevel: { size: 1, type: 5121, accessor: "getZLevel" } }); } // Override draw to add render module draw({ moduleParameters = {}, parameters, uniforms, context }) { const { jointRounded, capRounded, billboard, miterLimit, widthUnits, widthScale, widthMinPixels, widthMaxPixels } = this.props; uniforms = Object.assign({}, uniforms, { jointType: Number(jointRounded), capType: Number(capRounded), billboard, widthUnits: UNIT[widthUnits], widthScale, miterLimit, widthMinPixels, widthMaxPixels }); const { outlineFramebuffer, dummyTexture } = this.state; this.state.model.updateModuleSettings({ outlineEnabled: true, outlineRenderShadowmap: true, outlineShadowmap: dummyTexture }); this.state.model.draw({ uniforms: Object.assign({}, uniforms, { jointType: 0, widthScale: this.props.widthScale * 1.3 }), parameters: { depthTest: false, // Biggest value needs to go into buffer blendEquation: 32776 }, framebuffer: outlineFramebuffer }); this.state.model.updateModuleSettings({ outlineEnabled: true, outlineRenderShadowmap: false, outlineShadowmap: outlineFramebuffer }); this.state.model.draw({ uniforms: Object.assign({}, uniforms, { jointType: Number(jointRounded), capType: Number(capRounded), widthScale: this.props.widthScale }), parameters: { depthTest: false } }); } }; __publicField(PathOutlineLayer, "layerName", "PathOutlineLayer"); __publicField(PathOutlineLayer, "defaultProps", defaultProps); // dist/path-marker-layer/path-marker-layer.js var import_core3 = require("@deck.gl/core"); var import_layers2 = require("@deck.gl/layers"); var import_mesh_layers = require("@deck.gl/mesh-layers"); // dist/path-marker-layer/arrow-2d-geometry.js var import_engine = require("@luma.gl/engine"); var Arrow2DGeometry = class extends import_engine.Geometry { constructor(opts = {}) { super(Object.assign({}, opts, { attributes: getArrowAttributes(opts), topology: "triangle-list" })); } }; function getArrowAttributes({ length = 1, headSize = 0.2, tailWidth = 0.05, tailStart = 0.05 }) { const texCoords = [ // HEAD 0.5, 1, 0, 0.5 - headSize / 2, 1 - headSize, 0, 0.5 + headSize / 2, 1 - headSize, 0, 0.5 - tailWidth / 2, tailStart, 0, 0.5 + tailWidth / 2, 1 - headSize, 0, 0.5 + tailWidth / 2, tailStart, 0, 0.5 - tailWidth / 2, tailStart, 0, 0.5 - tailWidth / 2, 1 - headSize, 0, 0.5 + tailWidth / 2, 1 - headSize, 0 ]; const normals = [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]; const positions = new Array(texCoords.length); for (let i = 0; i < texCoords.length / 3; i++) { const i3 = i * 3; positions[i3 + 0] = (texCoords[i3 + 0] - 0.5) * length; positions[i3 + 1] = (texCoords[i3 + 1] - 0.5) * length; positions[i3 + 2] = 0; } return { positions: { size: 3, value: new Float32Array(positions) }, normals: { size: 3, value: new Float32Array(normals) }, texCoords: { size: 2, value: new Float32Array(texCoords) } }; } // dist/path-marker-layer/create-path-markers.js var import_core = require("@math.gl/core"); function getLineLength(vPoints) { let lineLength = 0; for (let i = 0; i < vPoints.length - 1; i++) { lineLength += vPoints[i].distance(vPoints[i + 1]); } return lineLength; } var DEFAULT_COLOR = [0, 0, 0, 255]; var DEFAULT_DIRECTION = { forward: true, backward: false }; function createPathMarkers({ data, getPath = (x, context) => x.path, getDirection = (x) => x.direction, getColor = (x) => DEFAULT_COLOR, getMarkerPercentages = (x, info) => [0.5], projectFlat }) { const markers = []; for (const object of data) { const path = getPath(object, null); const direction = getDirection(object) || DEFAULT_DIRECTION; const color = getColor(object); const vPoints = path.map((p) => new import_core.Vector2(p)); const vPointsReverse = vPoints.slice(0).reverse(); const lineLength = getLineLength(vPoints); const percentages = getMarkerPercentages(object, { lineLength }); for (const percentage of percentages) { if (direction.forward) { const marker = createMarkerAlongPath({ path: vPoints, percentage, lineLength, color, object, projectFlat }); markers.push(marker); } if (direction.backward) { const marker = createMarkerAlongPath({ path: vPointsReverse, percentage, lineLength, color, object, projectFlat }); markers.push(marker); } } } return markers; } function createMarkerAlongPath({ path, percentage, lineLength, color, object, projectFlat }) { const distanceAlong = lineLength * percentage; let currentDistance = 0; let previousDistance = 0; let i = 0; for (i = 0; i < path.length - 1; i++) { currentDistance += path[i].distance(path[i + 1]); if (currentDistance > distanceAlong) { break; } previousDistance = currentDistance; } if (i === path.length - 1) { i -= 1; } const vDirection = path[i + 1].clone().subtract(path[i]).normalize(); const along = distanceAlong - previousDistance; const vCenter = vDirection.clone().multiply(new import_core.Vector2(along, along)).add(path[i]); const vDirection2 = new import_core.Vector2(projectFlat(path[i + 1])).subtract(projectFlat(path[i])); const angle = vDirection2.verticalAngle() * 180 / Math.PI; return { position: [vCenter.x, vCenter.y, 0], angle, color, object }; } // dist/path-marker-layer/polyline.js var import_core2 = require("@math.gl/core"); function getClosestPointOnLine({ p, p1, p2, clampToLine = true }) { const lineVector = new import_core2.Vector3(p2).subtract(p1); const pointVector = new import_core2.Vector3(p).subtract(p1); let dotProduct = lineVector.dot(pointVector); if (clampToLine) { dotProduct = (0, import_core2.clamp)(dotProduct, 0, 1); } return lineVector.lerp(p1, p2, dotProduct); } function getClosestPointOnPolyline({ p, points }) { p = new import_core2.Vector3(p); let pClosest = null; let distanceSquared = Infinity; let index = -1; for (let i = 0; i < points.length - 1; ++i) { const p1 = points[i]; const p2 = points[i + 1]; const pClosestOnLine = getClosestPointOnLine({ p, p1, p2 }); const distanceToLineSquared = p.distanceSquared(pClosestOnLine); if (distanceToLineSquared < distanceSquared) { distanceSquared = distanceToLineSquared; pClosest = pClosestOnLine; index = i; } } return { point: pClosest, index, p1: points[index], p2: points[index + 1], distanceSquared, distance: Math.sqrt(distanceSquared) }; } // dist/path-marker-layer/path-marker-layer.js var DISTANCE_FOR_MULTI_ARROWS = 0.1; var ARROW_HEAD_SIZE = 0.2; var ARROW_TAIL_WIDTH = 0.05; var DEFAULT_MARKER_LAYER = import_mesh_layers.SimpleMeshLayer; var DEFAULT_MARKER_LAYER_PROPS = { mesh: new Arrow2DGeometry({ headSize: ARROW_HEAD_SIZE, tailWidth: ARROW_TAIL_WIDTH }) }; var defaultProps2 = 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] }); var PathMarkerLayer = class extends import_core3.CompositeLayer { state = void 0; 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 === import_core3.COORDINATE_SYSTEM.METER_OFFSETS) { const [dx, dy] = viewport.metersToLngLatDelta(xyz); const [x, y] = coordinateOrigin; return viewport.projectFlat([x + dx, dy + y]); } else if (coordinateSystem === import_core3.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 import_layers2.ScatterplotLayer({ id: `${this.props.id}-highlight`, data: this.state.closestPoints, fp64: this.props.fp64 }) ]; } }; __publicField(PathMarkerLayer, "layerName", "PathMarkerLayer"); __publicField(PathMarkerLayer, "defaultProps", defaultProps2); //# sourceMappingURL=index.cjs.map