forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			170 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /**
 | |
|  * 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,
 | |
|                 })
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |