/** * This feature source helps the ShowDataLayer class: it introduces the necessary extra features and indicates with what renderConfig it should be rendered. */ import { Store } from "../../UIEventSource" import { GeoOperations } from "../../GeoOperations" import FeatureSource from "../FeatureSource" import PointRenderingConfig from "../../../Models/ThemeConfig/PointRenderingConfig" import LayerConfig from "../../../Models/ThemeConfig/LayerConfig" import LineRenderingConfig from "../../../Models/ThemeConfig/LineRenderingConfig" export default class RenderingMultiPlexerFeatureSource { public readonly features: Store< (any & { pointRenderingIndex: number | undefined lineRenderingIndex: number | undefined })[] > private readonly pointRenderings: { rendering: PointRenderingConfig; index: number }[] private readonly centroidRenderings: { rendering: PointRenderingConfig; index: number }[] private readonly projectedCentroidRenderings: { rendering: PointRenderingConfig index: number }[] private readonly startRenderings: { rendering: PointRenderingConfig; index: number }[] private readonly endRenderings: { rendering: PointRenderingConfig; index: number }[] private readonly hasCentroid: boolean private lineRenderObjects: LineRenderingConfig[] constructor(upstream: FeatureSource, layer: LayerConfig) { const pointRenderObjects: { rendering: PointRenderingConfig; index: number }[] = layer.mapRendering.map((r, i) => ({ rendering: r, index: i, })) this.pointRenderings = pointRenderObjects.filter((r) => r.rendering.location.has("point")) this.centroidRenderings = pointRenderObjects.filter((r) => r.rendering.location.has("centroid") ) this.projectedCentroidRenderings = pointRenderObjects.filter((r) => r.rendering.location.has("projected_centerpoint") ) this.startRenderings = pointRenderObjects.filter((r) => r.rendering.location.has("start")) this.endRenderings = pointRenderObjects.filter((r) => r.rendering.location.has("end")) this.hasCentroid = this.centroidRenderings.length > 0 || this.projectedCentroidRenderings.length > 0 this.lineRenderObjects = layer.lineRendering this.features = upstream.features.map((features) => { if (features === undefined) { return undefined } const withIndex: any[] = [] function addAsPoint(feat, rendering, coordinate) { const patched = { ...feat, pointRenderingIndex: rendering.index, } patched.geometry = { type: "Point", coordinates: coordinate, } withIndex.push(patched) } for (const f of features) { const feat = f.feature if (feat === undefined) { continue } this.inspectFeature(feat, addAsPoint, withIndex) } return withIndex }) } /** * For every source feature, adds the necessary rendering-features */ private inspectFeature( feat, addAsPoint: (feat, rendering, centerpoint: [number, number]) => void, withIndex: any[] ) { if (feat.geometry.type === "Point") { for (const rendering of this.pointRenderings) { withIndex.push({ ...feat, pointRenderingIndex: rendering.index, }) } } else if (feat.geometry.type === "MultiPolygon") { if (this.centroidRenderings.length > 0 || this.projectedCentroidRenderings.length > 0) { const centerpoints: [number, number][] = (<[number, number][][][]>( feat.geometry.coordinates )).map((rings) => GeoOperations.centerpointCoordinates({ type: "Feature", properties: {}, geometry: { type: "Polygon", coordinates: rings }, }) ) for (const centroidRendering of this.centroidRenderings) { for (const centerpoint of centerpoints) { addAsPoint(feat, centroidRendering, centerpoint) } } for (const centroidRendering of this.projectedCentroidRenderings) { for (const centerpoint of centerpoints) { addAsPoint(feat, centroidRendering, centerpoint) } } } // AT last, add it 'as is' to what we should render for (let i = 0; i < this.lineRenderObjects.length; i++) { withIndex.push({ ...feat, lineRenderingIndex: i, }) } } else { // This is a a line or polygon: add the centroids let centerpoint: [number, number] = undefined let projectedCenterPoint: [number, number] = undefined if (this.hasCentroid) { centerpoint = GeoOperations.centerpointCoordinates(feat) if (this.projectedCentroidRenderings.length > 0) { projectedCenterPoint = <[number, number]>( GeoOperations.nearestPoint(feat, centerpoint).geometry.coordinates ) } } for (const rendering of this.centroidRenderings) { addAsPoint(feat, rendering, centerpoint) } if (feat.geometry.type === "LineString") { for (const rendering of this.projectedCentroidRenderings) { addAsPoint(feat, rendering, projectedCenterPoint) } // Add start- and endpoints const coordinates = feat.geometry.coordinates for (const rendering of this.startRenderings) { addAsPoint(feat, rendering, coordinates[0]) } for (const rendering of this.endRenderings) { const coordinate = coordinates[coordinates.length - 1] addAsPoint(feat, rendering, coordinate) } } else { for (const rendering of this.projectedCentroidRenderings) { addAsPoint(feat, rendering, centerpoint) } } // AT last, add it 'as is' to what we should render for (let i = 0; i < this.lineRenderObjects.length; i++) { withIndex.push({ ...feat, lineRenderingIndex: i, }) } } } }