From a8c8260831a0f06c087b2386b8c85500dce33042 Mon Sep 17 00:00:00 2001 From: Vijayan Balasubramanian Date: Fri, 27 Jan 2023 20:45:57 -0800 Subject: [PATCH 1/4] Refactor add geoshape layers outside document layer Signed-off-by: Vijayan Balasubramanian --- public/model/documentLayerFunctions.ts | 155 +++++++------------------ public/model/map/operations.ts | 131 +++++++++++++++++++++ 2 files changed, 174 insertions(+), 112 deletions(-) create mode 100644 public/model/map/operations.ts diff --git a/public/model/documentLayerFunctions.ts b/public/model/documentLayerFunctions.ts index befcf5b5..31088a61 100644 --- a/public/model/documentLayerFunctions.ts +++ b/public/model/documentLayerFunctions.ts @@ -8,6 +8,7 @@ import { parse } from 'wellknown'; import { DocumentLayerSpecification } from './mapLayerType'; import { convertGeoPointToGeoJSON, isGeoJSON } from '../utils/geo_formater'; import { getMaplibreBeforeLayerId, layerExistInMbSource } from './layersFunctions'; +import { addCircleLayer, addLineLayer, addPolygonLayer } from './map/operations'; interface MaplibreRef { current: Maplibre | null; @@ -129,126 +130,56 @@ const addNewLayer = ( ) => { const maplibreInstance = maplibreRef.current; const mbLayerBeforeId = getMaplibreBeforeLayerId(layerConfig, maplibreRef, beforeLayerId); - const addLineLayer = ( - documentLayerConfig: DocumentLayerSpecification, - beforeId: string | undefined - ) => { - const lineLayerId = buildLayerSuffix(documentLayerConfig.id, 'line'); - maplibreInstance?.addLayer( - { - id: lineLayerId, - type: 'line', - source: documentLayerConfig.id, - filter: ['==', '$type', 'LineString'], - paint: { - 'line-color': documentLayerConfig.style?.fillColor, - 'line-opacity': documentLayerConfig.opacity / 100, - 'line-width': documentLayerConfig.style?.borderThickness, - }, - }, - beforeId - ); - maplibreInstance?.setLayoutProperty(lineLayerId, 'visibility', documentLayerConfig.visibility); - maplibreInstance?.setLayerZoomRange( - lineLayerId, - documentLayerConfig.zoomRange[0], - documentLayerConfig.zoomRange[1] - ); - }; - - const addCircleLayer = ( - documentLayerConfig: DocumentLayerSpecification, - beforeId: string | undefined - ) => { - const circleLayerId = buildLayerSuffix(documentLayerConfig.id, 'circle'); - maplibreInstance?.addLayer( - { - id: circleLayerId, - type: 'circle', - source: layerConfig.id, - filter: ['==', '$type', 'Point'], - paint: { - 'circle-radius': documentLayerConfig.style?.markerSize, - 'circle-color': documentLayerConfig.style?.fillColor, - 'circle-opacity': documentLayerConfig.opacity / 100, - 'circle-stroke-width': documentLayerConfig.style?.borderThickness, - 'circle-stroke-color': documentLayerConfig.style?.borderColor, - }, - }, - beforeId - ); - maplibreInstance?.setLayoutProperty( - circleLayerId, - 'visibility', - documentLayerConfig.visibility - ); - maplibreInstance?.setLayerZoomRange( - circleLayerId, - documentLayerConfig.zoomRange[0], - documentLayerConfig.zoomRange[1] - ); - }; - - const addFillLayer = ( - documentLayerConfig: DocumentLayerSpecification, - beforeId: string | undefined - ) => { - const fillLayerId = buildLayerSuffix(documentLayerConfig.id, 'fill'); - maplibreInstance?.addLayer( - { - id: fillLayerId, - type: 'fill', - source: layerConfig.id, - filter: ['==', '$type', 'Polygon'], - paint: { - 'fill-color': documentLayerConfig.style?.fillColor, - 'fill-opacity': documentLayerConfig.opacity / 100, - }, - }, - beforeId - ); - maplibreInstance?.setLayoutProperty(fillLayerId, 'visibility', documentLayerConfig.visibility); - maplibreInstance?.setLayerZoomRange( - fillLayerId, - documentLayerConfig.zoomRange[0], - documentLayerConfig.zoomRange[1] - ); - // Due to limitations on WebGL, fill can't render outlines with width wider than 1, - // so we have to create another style layer with type=line to apply width. - const outlineId = buildLayerSuffix(documentLayerConfig.id, 'fill-outline'); - maplibreInstance?.addLayer( - { - id: outlineId, - type: 'line', - source: layerConfig.id, - filter: ['==', '$type', 'Polygon'], - paint: { - 'line-color': layerConfig.style?.borderColor, - 'line-opacity': layerConfig.opacity / 100, - 'line-width': layerConfig.style?.borderThickness, - }, - }, - beforeId - ); - maplibreInstance?.setLayoutProperty(outlineId, 'visibility', layerConfig.visibility); - maplibreInstance?.setLayerZoomRange( - outlineId, - documentLayerConfig.zoomRange[0], - documentLayerConfig.zoomRange[1] - ); - }; - if (maplibreInstance) { const source = getLayerSource(data, layerConfig); maplibreInstance.addSource(layerConfig.id, { type: 'geojson', data: source, }); - addCircleLayer(layerConfig, mbLayerBeforeId); + addCircleLayer( + maplibreInstance, + { + fillColor: layerConfig.style?.fillColor, + maxZoom: layerConfig.zoomRange[1], + minZoom: layerConfig.zoomRange[0], + opacity: layerConfig.opacity, + outlineColor: layerConfig.style?.borderColor, + radius: layerConfig.style?.markerSize, + sourceId: layerConfig.id, + visibility: layerConfig.visibility, + width: layerConfig.style?.borderThickness, + }, + mbLayerBeforeId + ); const geoFieldType = getGeoFieldType(layerConfig); if (geoFieldType === 'geo_shape') { - addLineLayer(layerConfig, mbLayerBeforeId); - addFillLayer(layerConfig, mbLayerBeforeId); + addLineLayer( + maplibreInstance, + { + width: layerConfig.style?.borderThickness, + color: layerConfig.style?.fillColor, + maxZoom: layerConfig.zoomRange[1], + minZoom: layerConfig.zoomRange[0], + opacity: layerConfig.opacity, + sourceId: layerConfig.id, + visibility: layerConfig.visibility, + }, + mbLayerBeforeId + ); + addPolygonLayer( + maplibreInstance, + { + width: layerConfig.style?.borderThickness, + fillColor: layerConfig.style?.fillColor, + maxZoom: layerConfig.zoomRange[1], + minZoom: layerConfig.zoomRange[0], + opacity: layerConfig.opacity, + sourceId: layerConfig.id, + outlineColor: layerConfig.style?.borderColor, + visibility: layerConfig.visibility, + }, + mbLayerBeforeId + ); } } }; diff --git a/public/model/map/operations.ts b/public/model/map/operations.ts new file mode 100644 index 00000000..b64f44d9 --- /dev/null +++ b/public/model/map/operations.ts @@ -0,0 +1,131 @@ +import { Map as Maplibre } from 'maplibre-gl'; + +export type Visibility = 'visible' | 'none'; + +export interface LineLayerSpecification { + sourceId: string; + visibility: string; + color: string; + opacity: number; + width: number; + minZoom: number; + maxZoom: number; +} + +export const addLineLayer = ( + map: Maplibre, + specification: LineLayerSpecification, + beforeId?: string +): string => { + const lineLayerId = specification.sourceId + '-line'; + map.addLayer( + { + id: lineLayerId, + type: 'line', + source: specification.sourceId, + filter: ['==', '$type', 'LineString'], + paint: { + 'line-color': specification.color, + 'line-opacity': specification.opacity / 100, + 'line-width': specification.width, + }, + }, + beforeId + ); + map.setLayoutProperty(lineLayerId, 'visibility', specification.visibility); + map.setLayerZoomRange(lineLayerId, specification.minZoom, specification.maxZoom); + return lineLayerId; +}; + +export interface CircleLayerSpecification { + sourceId: string; + visibility: string; + fillColor: string; + outlineColor: string; + radius: number; + opacity: number; + width: number; + minZoom: number; + maxZoom: number; +} + +export const addCircleLayer = ( + map: Maplibre, + specification: CircleLayerSpecification, + beforeId?: string +): string => { + const circleLayerId = specification.sourceId + 'circle'; + map.addLayer( + { + id: circleLayerId, + type: 'circle', + source: specification.sourceId, + filter: ['==', '$type', 'Point'], + paint: { + 'circle-radius': specification.radius, + 'circle-color': specification.fillColor, + 'circle-opacity': specification.opacity / 100, + 'circle-stroke-width': specification.width, + 'circle-stroke-color': specification.outlineColor, + }, + }, + beforeId + ); + map.setLayoutProperty(circleLayerId, 'visibility', specification.visibility); + map?.setLayerZoomRange(circleLayerId, specification.minZoom, specification.maxZoom); + return circleLayerId; +}; + +export interface PolygonLayerSpecification { + sourceId: string; + visibility: string; + fillColor: string; + outlineColor: string; + opacity: number; + width: number; + minZoom: number; + maxZoom: number; +} + +export const addPolygonLayer = ( + map: Maplibre, + specification: PolygonLayerSpecification, + beforeId?: string +) => { + const fillLayerId = specification.sourceId + 'fill'; + map.addLayer( + { + id: fillLayerId, + type: 'fill', + source: specification.sourceId, + filter: ['==', '$type', 'Polygon'], + paint: { + 'fill-color': specification.fillColor, + 'fill-opacity': specification.opacity / 100, + }, + }, + beforeId + ); + map?.setLayoutProperty(fillLayerId, 'visibility', specification.visibility); + map?.setLayerZoomRange(fillLayerId, specification.minZoom, specification.maxZoom); + + // Due to limitations on WebGL, fill can't render outlines with width wider than 1, + // so we have to create another style layer with type=line to apply width. + const outlineId = specification.sourceId + 'fill-outline'; + map.addLayer( + { + id: outlineId, + type: 'line', + source: specification.sourceId, + filter: ['==', '$type', 'Polygon'], + paint: { + 'line-color': specification.outlineColor, + 'line-opacity': specification.opacity / 100, + 'line-width': specification.width, + }, + }, + beforeId + ); + map.setLayoutProperty(outlineId, 'visibility', specification.visibility); + map?.setLayerZoomRange(outlineId, specification.minZoom, specification.maxZoom); +}; From af208735d9fc3f13eb7169afef2159fe7dbe0db4 Mon Sep 17 00:00:00 2001 From: Vijayan Balasubramanian Date: Sat, 28 Jan 2023 15:51:01 -0800 Subject: [PATCH 2/4] Update layer opeartions Signed-off-by: Vijayan Balasubramanian --- public/model/documentLayerFunctions.ts | 235 +++++++++---------------- public/model/map/layer_operations.ts | 162 +++++++++++++++++ public/model/map/operations.ts | 131 -------------- 3 files changed, 241 insertions(+), 287 deletions(-) create mode 100644 public/model/map/layer_operations.ts delete mode 100644 public/model/map/operations.ts diff --git a/public/model/documentLayerFunctions.ts b/public/model/documentLayerFunctions.ts index 31088a61..0dfce730 100644 --- a/public/model/documentLayerFunctions.ts +++ b/public/model/documentLayerFunctions.ts @@ -8,7 +8,14 @@ import { parse } from 'wellknown'; import { DocumentLayerSpecification } from './mapLayerType'; import { convertGeoPointToGeoJSON, isGeoJSON } from '../utils/geo_formater'; import { getMaplibreBeforeLayerId, layerExistInMbSource } from './layersFunctions'; -import { addCircleLayer, addLineLayer, addPolygonLayer } from './map/operations'; +import { + addCircleLayer, + addLineLayer, + addPolygonLayer, + updateCircleLayer, + updateLineLayer, + updatePolygonLayer, +} from './map/layer_operations'; interface MaplibreRef { current: Maplibre | null; @@ -24,23 +31,6 @@ const openSearchGeoJSONMap = new Map([ ['geometrycollection', 'GeometryCollection'], ]); -const buildLayerSuffix = (layerId: string, mapLibreType: string) => { - if (mapLibreType.toLowerCase() === 'circle') { - return layerId; - } - if (mapLibreType.toLowerCase() === 'line') { - return layerId + '-line'; - } - if (mapLibreType.toLowerCase() === 'fill') { - return layerId + '-fill'; - } - if (mapLibreType.toLowerCase() === 'fill-outline') { - return layerId + '-outline'; - } - // if unknown type is found, use layerId as default - return layerId; -}; - const getFieldValue = (data: any, name: string) => { if (!name) { return null; @@ -129,156 +119,62 @@ const addNewLayer = ( beforeLayerId: string | undefined ) => { const maplibreInstance = maplibreRef.current; + if (!maplibreInstance) { + return; + } const mbLayerBeforeId = getMaplibreBeforeLayerId(layerConfig, maplibreRef, beforeLayerId); - if (maplibreInstance) { - const source = getLayerSource(data, layerConfig); - maplibreInstance.addSource(layerConfig.id, { - type: 'geojson', - data: source, - }); - addCircleLayer( + const source = getLayerSource(data, layerConfig); + maplibreInstance.addSource(layerConfig.id, { + type: 'geojson', + data: source, + }); + addCircleLayer( + maplibreInstance, + { + fillColor: layerConfig.style?.fillColor, + maxZoom: layerConfig.zoomRange[1], + minZoom: layerConfig.zoomRange[0], + opacity: layerConfig.opacity, + outlineColor: layerConfig.style?.borderColor, + radius: layerConfig.style?.markerSize, + sourceId: layerConfig.id, + visibility: layerConfig.visibility, + width: layerConfig.style?.borderThickness, + }, + mbLayerBeforeId + ); + const geoFieldType = getGeoFieldType(layerConfig); + if (geoFieldType === 'geo_shape') { + addLineLayer( maplibreInstance, { - fillColor: layerConfig.style?.fillColor, + width: layerConfig.style?.borderThickness, + color: layerConfig.style?.fillColor, maxZoom: layerConfig.zoomRange[1], minZoom: layerConfig.zoomRange[0], opacity: layerConfig.opacity, - outlineColor: layerConfig.style?.borderColor, - radius: layerConfig.style?.markerSize, sourceId: layerConfig.id, visibility: layerConfig.visibility, + }, + mbLayerBeforeId + ); + addPolygonLayer( + maplibreInstance, + { width: layerConfig.style?.borderThickness, + fillColor: layerConfig.style?.fillColor, + maxZoom: layerConfig.zoomRange[1], + minZoom: layerConfig.zoomRange[0], + opacity: layerConfig.opacity, + sourceId: layerConfig.id, + outlineColor: layerConfig.style?.borderColor, + visibility: layerConfig.visibility, }, mbLayerBeforeId ); - const geoFieldType = getGeoFieldType(layerConfig); - if (geoFieldType === 'geo_shape') { - addLineLayer( - maplibreInstance, - { - width: layerConfig.style?.borderThickness, - color: layerConfig.style?.fillColor, - maxZoom: layerConfig.zoomRange[1], - minZoom: layerConfig.zoomRange[0], - opacity: layerConfig.opacity, - sourceId: layerConfig.id, - visibility: layerConfig.visibility, - }, - mbLayerBeforeId - ); - addPolygonLayer( - maplibreInstance, - { - width: layerConfig.style?.borderThickness, - fillColor: layerConfig.style?.fillColor, - maxZoom: layerConfig.zoomRange[1], - minZoom: layerConfig.zoomRange[0], - opacity: layerConfig.opacity, - sourceId: layerConfig.id, - outlineColor: layerConfig.style?.borderColor, - visibility: layerConfig.visibility, - }, - mbLayerBeforeId - ); - } } }; -const updateCircleLayer = ( - maplibreInstance: Maplibre, - documentLayerConfig: DocumentLayerSpecification -) => { - const circleLayerId = buildLayerSuffix(documentLayerConfig.id, 'circle'); - const circleLayerStyle = documentLayerConfig.style; - maplibreInstance?.setLayerZoomRange( - circleLayerId, - documentLayerConfig.zoomRange[0], - documentLayerConfig.zoomRange[1] - ); - maplibreInstance?.setPaintProperty( - circleLayerId, - 'circle-opacity', - documentLayerConfig.opacity / 100 - ); - maplibreInstance?.setPaintProperty(circleLayerId, 'circle-color', circleLayerStyle?.fillColor); - maplibreInstance?.setPaintProperty( - circleLayerId, - 'circle-stroke-color', - circleLayerStyle?.borderColor - ); - maplibreInstance?.setPaintProperty( - circleLayerId, - 'circle-stroke-width', - circleLayerStyle?.borderThickness - ); - maplibreInstance?.setPaintProperty(circleLayerId, 'circle-radius', circleLayerStyle?.markerSize); -}; - -const updateLineLayer = ( - maplibreInstance: Maplibre, - documentLayerConfig: DocumentLayerSpecification -) => { - const lineLayerId = buildLayerSuffix(documentLayerConfig.id, 'line'); - maplibreInstance?.setLayerZoomRange( - lineLayerId, - documentLayerConfig.zoomRange[0], - documentLayerConfig.zoomRange[1] - ); - maplibreInstance?.setPaintProperty( - lineLayerId, - 'line-opacity', - documentLayerConfig.opacity / 100 - ); - maplibreInstance?.setPaintProperty( - lineLayerId, - 'line-color', - documentLayerConfig.style?.fillColor - ); - maplibreInstance?.setPaintProperty( - lineLayerId, - 'line-width', - documentLayerConfig.style?.borderThickness - ); -}; - -const updateFillLayer = ( - maplibreInstance: Maplibre, - documentLayerConfig: DocumentLayerSpecification -) => { - const fillLayerId = buildLayerSuffix(documentLayerConfig.id, 'fill'); - maplibreInstance?.setLayerZoomRange( - fillLayerId, - documentLayerConfig.zoomRange[0], - documentLayerConfig.zoomRange[1] - ); - maplibreInstance?.setPaintProperty( - fillLayerId, - 'fill-opacity', - documentLayerConfig.opacity / 100 - ); - maplibreInstance?.setPaintProperty( - fillLayerId, - 'fill-color', - documentLayerConfig.style?.fillColor - ); - maplibreInstance?.setPaintProperty( - fillLayerId, - 'fill-outline-color', - documentLayerConfig.style?.borderColor - ); - const outlineLayerId = buildLayerSuffix(documentLayerConfig.id, 'fill-outline'); - maplibreInstance?.setPaintProperty( - outlineLayerId, - 'line-color', - documentLayerConfig.style?.borderColor - ); - maplibreInstance?.setPaintProperty( - outlineLayerId, - 'line-width', - documentLayerConfig.style?.borderThickness - ); -}; - const updateLayerConfig = ( layerConfig: DocumentLayerSpecification, maplibreRef: MaplibreRef, @@ -291,11 +187,38 @@ const updateLayerConfig = ( // @ts-ignore dataSource.setData(getLayerSource(data, layerConfig)); } - updateCircleLayer(maplibreInstance, layerConfig); + updateCircleLayer(maplibreInstance, { + fillColor: layerConfig.style?.fillColor, + maxZoom: layerConfig.zoomRange[1], + minZoom: layerConfig.zoomRange[0], + opacity: layerConfig.opacity, + outlineColor: layerConfig.style?.borderColor, + radius: layerConfig.style?.markerSize, + sourceId: layerConfig.id, + visibility: layerConfig.visibility, + width: layerConfig.style?.borderThickness, + }); const geoFieldType = getGeoFieldType(layerConfig); if (geoFieldType === 'geo_shape') { - updateLineLayer(maplibreInstance, layerConfig); - updateFillLayer(maplibreInstance, layerConfig); + updateLineLayer(maplibreInstance, { + width: layerConfig.style?.borderThickness, + color: layerConfig.style?.fillColor, + maxZoom: layerConfig.zoomRange[1], + minZoom: layerConfig.zoomRange[0], + opacity: layerConfig.opacity, + sourceId: layerConfig.id, + visibility: layerConfig.visibility, + }); + updatePolygonLayer(maplibreInstance, { + width: layerConfig.style?.borderThickness, + fillColor: layerConfig.style?.fillColor, + maxZoom: layerConfig.zoomRange[1], + minZoom: layerConfig.zoomRange[0], + opacity: layerConfig.opacity, + sourceId: layerConfig.id, + outlineColor: layerConfig.style?.borderColor, + visibility: layerConfig.visibility, + }); } } }; diff --git a/public/model/map/layer_operations.ts b/public/model/map/layer_operations.ts new file mode 100644 index 00000000..b69d045a --- /dev/null +++ b/public/model/map/layer_operations.ts @@ -0,0 +1,162 @@ +import { Map as Maplibre } from 'maplibre-gl'; + +export interface LineLayerSpecification { + sourceId: string; + visibility: string; + color: string; + opacity: number; + width: number; + minZoom: number; + maxZoom: number; +} + +export const addLineLayer = ( + map: Maplibre, + specification: LineLayerSpecification, + beforeId?: string +): string => { + const lineLayerId = specification.sourceId + '-line'; + map.addLayer( + { + id: lineLayerId, + type: 'line', + source: specification.sourceId, + filter: ['==', '$type', 'LineString'], + }, + beforeId + ); + return updateLineLayer(map, specification, lineLayerId); +}; + +export const updateLineLayer = ( + map: Maplibre, + specification: LineLayerSpecification, + layerId?: string +): string => { + const lineLayerId = layerId ? layerId : specification.sourceId + '-line'; + map?.setPaintProperty(lineLayerId, 'line-opacity', specification.opacity / 100); + map?.setPaintProperty(lineLayerId, 'line-color', specification.color); + map?.setPaintProperty(lineLayerId, 'line-width', specification.width); + map.setLayoutProperty(lineLayerId, 'visibility', specification.visibility); + map.setLayerZoomRange(lineLayerId, specification.minZoom, specification.maxZoom); + return lineLayerId; +}; + +export interface CircleLayerSpecification { + sourceId: string; + visibility: string; + fillColor: string; + outlineColor: string; + radius: number; + opacity: number; + width: number; + minZoom: number; + maxZoom: number; +} + +export const addCircleLayer = ( + map: Maplibre, + specification: CircleLayerSpecification, + beforeId?: string +): string => { + const circleLayerId = specification.sourceId + '-circle'; + map.addLayer( + { + id: circleLayerId, + type: 'circle', + source: specification.sourceId, + filter: ['==', '$type', 'Point'], + }, + beforeId + ); + return updateCircleLayer(map, specification, circleLayerId); +}; + +export const updateCircleLayer = ( + map: Maplibre, + specification: CircleLayerSpecification, + layerId?: string +): string => { + const circleLayerId = layerId ? layerId : specification.sourceId + '-circle'; + map.setLayoutProperty(circleLayerId, 'visibility', specification.visibility); + map?.setLayerZoomRange(circleLayerId, specification.minZoom, specification.maxZoom); + map?.setPaintProperty(circleLayerId, 'circle-opacity', specification.opacity / 100); + map?.setPaintProperty(circleLayerId, 'circle-color', specification.fillColor); + map?.setPaintProperty(circleLayerId, 'circle-stroke-color', specification.outlineColor); + map?.setPaintProperty(circleLayerId, 'circle-stroke-width', specification.width); + map?.setPaintProperty(circleLayerId, 'circle-radius', specification.radius); + return circleLayerId; +}; + +export interface PolygonLayerSpecification { + sourceId: string; + visibility: string; + fillColor: string; + outlineColor: string; + opacity: number; + width: number; + minZoom: number; + maxZoom: number; +} + +export const addPolygonLayer = ( + map: Maplibre, + specification: PolygonLayerSpecification, + beforeId?: string +) => { + const fillLayerId = specification.sourceId + '-fill'; + map.addLayer( + { + id: fillLayerId, + type: 'fill', + source: specification.sourceId, + filter: ['==', '$type', 'Polygon'], + }, + beforeId + ); + updatePolygonFillLayer(map, specification, fillLayerId); + + // Due to limitations on WebGL, fill can't render outlines with width wider than 1, + // so we have to create another style layer with type=line to apply width. + const outlineId = specification.sourceId + '-fill-outline'; + map.addLayer( + { + id: outlineId, + type: 'line', + source: specification.sourceId, + filter: ['==', '$type', 'Polygon'], + }, + beforeId + ); + updatePolygonOutlineLayer(map, specification, outlineId); +}; + +export const updatePolygonLayer = (map: Maplibre, specification: PolygonLayerSpecification) => { + updatePolygonFillLayer(map, specification); + updatePolygonOutlineLayer(map, specification); +}; + +const updatePolygonFillLayer = ( + map: Maplibre, + specification: PolygonLayerSpecification, + layerId?: string +) => { + const fillLayerId = layerId ? layerId : specification.sourceId + '-fill'; + map?.setLayoutProperty(fillLayerId, 'visibility', specification.visibility); + map?.setLayerZoomRange(fillLayerId, specification.minZoom, specification.maxZoom); + map?.setPaintProperty(fillLayerId, 'fill-opacity', specification.opacity / 100); + map?.setPaintProperty(fillLayerId, 'fill-color', specification.fillColor); + return fillLayerId; +}; +const updatePolygonOutlineLayer = ( + map: Maplibre, + specification: PolygonLayerSpecification, + layerId?: string +) => { + const outlineLayerId = layerId ? layerId : specification.sourceId + '-fill-outline'; + map?.setPaintProperty(outlineLayerId, 'line-color', specification.outlineColor); + map?.setPaintProperty(outlineLayerId, 'line-width', specification.width); + map.setLayoutProperty(outlineLayerId, 'visibility', specification.visibility); + map?.setLayerZoomRange(outlineLayerId, specification.minZoom, specification.maxZoom); + return outlineLayerId; +}; diff --git a/public/model/map/operations.ts b/public/model/map/operations.ts deleted file mode 100644 index b64f44d9..00000000 --- a/public/model/map/operations.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { Map as Maplibre } from 'maplibre-gl'; - -export type Visibility = 'visible' | 'none'; - -export interface LineLayerSpecification { - sourceId: string; - visibility: string; - color: string; - opacity: number; - width: number; - minZoom: number; - maxZoom: number; -} - -export const addLineLayer = ( - map: Maplibre, - specification: LineLayerSpecification, - beforeId?: string -): string => { - const lineLayerId = specification.sourceId + '-line'; - map.addLayer( - { - id: lineLayerId, - type: 'line', - source: specification.sourceId, - filter: ['==', '$type', 'LineString'], - paint: { - 'line-color': specification.color, - 'line-opacity': specification.opacity / 100, - 'line-width': specification.width, - }, - }, - beforeId - ); - map.setLayoutProperty(lineLayerId, 'visibility', specification.visibility); - map.setLayerZoomRange(lineLayerId, specification.minZoom, specification.maxZoom); - return lineLayerId; -}; - -export interface CircleLayerSpecification { - sourceId: string; - visibility: string; - fillColor: string; - outlineColor: string; - radius: number; - opacity: number; - width: number; - minZoom: number; - maxZoom: number; -} - -export const addCircleLayer = ( - map: Maplibre, - specification: CircleLayerSpecification, - beforeId?: string -): string => { - const circleLayerId = specification.sourceId + 'circle'; - map.addLayer( - { - id: circleLayerId, - type: 'circle', - source: specification.sourceId, - filter: ['==', '$type', 'Point'], - paint: { - 'circle-radius': specification.radius, - 'circle-color': specification.fillColor, - 'circle-opacity': specification.opacity / 100, - 'circle-stroke-width': specification.width, - 'circle-stroke-color': specification.outlineColor, - }, - }, - beforeId - ); - map.setLayoutProperty(circleLayerId, 'visibility', specification.visibility); - map?.setLayerZoomRange(circleLayerId, specification.minZoom, specification.maxZoom); - return circleLayerId; -}; - -export interface PolygonLayerSpecification { - sourceId: string; - visibility: string; - fillColor: string; - outlineColor: string; - opacity: number; - width: number; - minZoom: number; - maxZoom: number; -} - -export const addPolygonLayer = ( - map: Maplibre, - specification: PolygonLayerSpecification, - beforeId?: string -) => { - const fillLayerId = specification.sourceId + 'fill'; - map.addLayer( - { - id: fillLayerId, - type: 'fill', - source: specification.sourceId, - filter: ['==', '$type', 'Polygon'], - paint: { - 'fill-color': specification.fillColor, - 'fill-opacity': specification.opacity / 100, - }, - }, - beforeId - ); - map?.setLayoutProperty(fillLayerId, 'visibility', specification.visibility); - map?.setLayerZoomRange(fillLayerId, specification.minZoom, specification.maxZoom); - - // Due to limitations on WebGL, fill can't render outlines with width wider than 1, - // so we have to create another style layer with type=line to apply width. - const outlineId = specification.sourceId + 'fill-outline'; - map.addLayer( - { - id: outlineId, - type: 'line', - source: specification.sourceId, - filter: ['==', '$type', 'Polygon'], - paint: { - 'line-color': specification.outlineColor, - 'line-opacity': specification.opacity / 100, - 'line-width': specification.width, - }, - }, - beforeId - ); - map.setLayoutProperty(outlineId, 'visibility', specification.visibility); - map?.setLayerZoomRange(outlineId, specification.minZoom, specification.maxZoom); -}; From 84b518caef698b14fffb154af97a79199557d7c3 Mon Sep 17 00:00:00 2001 From: Vijayan Balasubramanian Date: Sun, 29 Jan 2023 19:30:30 -0800 Subject: [PATCH 3/4] Add unit test Signed-off-by: Vijayan Balasubramanian --- public/model/map/__mocks__/layer.ts | 25 ++ public/model/map/__mocks__/map.ts | 54 +++++ public/model/map/layer_operations.test.ts | 275 ++++++++++++++++++++++ public/model/map/layer_operations.ts | 78 +++--- 4 files changed, 402 insertions(+), 30 deletions(-) create mode 100644 public/model/map/__mocks__/layer.ts create mode 100644 public/model/map/__mocks__/map.ts create mode 100644 public/model/map/layer_operations.test.ts diff --git a/public/model/map/__mocks__/layer.ts b/public/model/map/__mocks__/layer.ts new file mode 100644 index 00000000..1f307ff3 --- /dev/null +++ b/public/model/map/__mocks__/layer.ts @@ -0,0 +1,25 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export class MockLayer { + private layerProperties: Map = new Map(); + + constructor(id: string) { + this.layerProperties.set('id', id); + } + + public setProperty(name: string, value: any): this { + this.layerProperties.set(name, value); + return this; + } + + public getProperty(name: string): any { + return this.layerProperties.get(name); + } + + public hasProperty(name: string): boolean { + return this.layerProperties.has(name); + } +} diff --git a/public/model/map/__mocks__/map.ts b/public/model/map/__mocks__/map.ts new file mode 100644 index 00000000..cf89df85 --- /dev/null +++ b/public/model/map/__mocks__/map.ts @@ -0,0 +1,54 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { LayerSpecification } from 'maplibre-gl'; +import { MockLayer } from './layer'; + +export class MockMaplibreMap { + public _layers: MockLayer[]; + + constructor() { + this._layers = new Array(); + } + + getLayer(id: string): MockLayer[] { + return this._layers.filter((layer) => (layer.getProperty('id') as string).includes(id)); + } + + public setLayerZoomRange(layerId: string, minZoom: number, maxZoom: number) { + this.setProperty(layerId, 'minZoom', minZoom); + this.setProperty(layerId, 'maxZoom', maxZoom); + } + + public setLayoutProperty(layerId: string, property: string, value: any) { + this.setProperty(layerId, property, value); + } + + public setPaintProperty(layerId: string, property: string, value: any) { + this.setProperty(layerId, property, value); + } + + public setProperty(layerId: string, property: string, value: any) { + this.getLayer(layerId)?.forEach((layer) => { + layer.setProperty(property, value); + }); + } + + addLayer(layerSpec: LayerSpecification, beforeId?: string) { + const layer: MockLayer = new MockLayer(layerSpec.id); + Object.keys(layerSpec).forEach((key) => { + // @ts-ignore + layer.setProperty(key, layerSpec[key]); + }); + if (!beforeId) { + this._layers.push(layer); + return; + } + const beforeLayerIndex = this._layers.findIndex((l) => { + return l.getProperty('id') === beforeId; + }); + this._layers.splice(beforeLayerIndex, 0, layer); + } +} diff --git a/public/model/map/layer_operations.test.ts b/public/model/map/layer_operations.test.ts new file mode 100644 index 00000000..08553724 --- /dev/null +++ b/public/model/map/layer_operations.test.ts @@ -0,0 +1,275 @@ +import { + addCircleLayer, + addLineLayer, + addPolygonLayer, + updateCircleLayer, + updateLineLayer, + updatePolygonLayer, +} from './layer_operations'; +import { Map as Maplibre } from 'maplibre-gl'; +import { MockMaplibreMap } from './__mocks__/map'; + +describe('Circle layer', () => { + it('add new circle layer', () => { + const mockMap = new MockMaplibreMap(); + const sourceId: string = 'geojson-source'; + const expectedLayerId: string = sourceId + '-circle'; + expect(mockMap.getLayer(expectedLayerId).length).toBe(0); + expect( + addCircleLayer((mockMap as unknown) as Maplibre, { + maxZoom: 10, + minZoom: 2, + opacity: 60, + outlineColor: 'green', + radius: 10, + sourceId, + visibility: 'visible', + width: 2, + fillColor: 'red', + }) + ).toBe(expectedLayerId); + expect(mockMap.getLayer(sourceId).length).toBe(1); + + const addedLayer = mockMap.getLayer(sourceId)[0]; + + expect(addedLayer.getProperty('id')).toBe(expectedLayerId); + expect(addedLayer.getProperty('visibility')).toBe('visible'); + expect(addedLayer.getProperty('source')).toBe(sourceId); + expect(addedLayer.getProperty('type')).toBe('circle'); + expect(addedLayer.getProperty('filter')).toEqual(['==', '$type', 'Point']); + expect(addedLayer.getProperty('minZoom')).toBe(2); + expect(addedLayer.getProperty('maxZoom')).toBe(10); + expect(addedLayer.getProperty('circle-opacity')).toBe(0.6); + expect(addedLayer.getProperty('circle-color')).toBe('red'); + expect(addedLayer.getProperty('circle-stroke-color')).toBe('green'); + expect(addedLayer.getProperty('circle-stroke-width')).toBe(2); + expect(addedLayer.getProperty('circle-radius')).toBe(10); + }); + + it('update circle layer', () => { + const mockMap = new MockMaplibreMap(); + const sourceId: string = 'geojson-source'; + + // add layer first + const addedLayerId: string = addCircleLayer((mockMap as unknown) as Maplibre, { + maxZoom: 10, + minZoom: 2, + opacity: 60, + outlineColor: 'green', + radius: 10, + sourceId, + visibility: 'visible', + width: 2, + fillColor: 'red', + }); + expect( + updateCircleLayer((mockMap as unknown) as Maplibre, { + maxZoom: 12, + minZoom: 4, + opacity: 80, + outlineColor: 'yellow', + radius: 8, + sourceId, + visibility: 'none', + width: 7, + fillColor: 'blue', + }) + ).toBe(addedLayerId); + expect(mockMap.getLayer(addedLayerId).length).toBe(1); + + const updatedLayer = mockMap.getLayer(addedLayerId)[0]; + expect(updatedLayer.getProperty('id')).toBe(addedLayerId); + expect(updatedLayer.getProperty('visibility')).toBe('none'); + expect(updatedLayer.getProperty('source')).toBe(sourceId); + expect(updatedLayer.getProperty('type')).toBe('circle'); + expect(updatedLayer.getProperty('filter')).toEqual(['==', '$type', 'Point']); + expect(updatedLayer.getProperty('minZoom')).toBe(4); + expect(updatedLayer.getProperty('maxZoom')).toBe(12); + expect(updatedLayer.getProperty('circle-opacity')).toBe(0.8); + expect(updatedLayer.getProperty('circle-color')).toBe('blue'); + expect(updatedLayer.getProperty('circle-stroke-color')).toBe('yellow'); + expect(updatedLayer.getProperty('circle-stroke-width')).toBe(7); + expect(updatedLayer.getProperty('circle-radius')).toBe(8); + }); +}); + +describe('Line layer', () => { + it('add new Line layer', () => { + const mockMap = new MockMaplibreMap(); + const sourceId: string = 'geojson-source'; + const expectedLayerId: string = sourceId + '-line'; + expect(mockMap.getLayer(expectedLayerId).length).toBe(0); + expect( + addLineLayer((mockMap as unknown) as Maplibre, { + color: 'red', + maxZoom: 10, + minZoom: 2, + opacity: 60, + sourceId, + visibility: 'visible', + width: 2, + }) + ).toBe(expectedLayerId); + expect(mockMap.getLayer(sourceId).length).toBe(1); + const addedLayer = mockMap.getLayer(sourceId)[0]; + expect(addedLayer.getProperty('id')).toBe(expectedLayerId); + expect(addedLayer.getProperty('visibility')).toBe('visible'); + expect(addedLayer.getProperty('source')).toBe(sourceId); + expect(addedLayer.getProperty('type')).toBe('line'); + expect(addedLayer.getProperty('filter')).toEqual(['==', '$type', 'LineString']); + expect(addedLayer.getProperty('minZoom')).toBe(2); + expect(addedLayer.getProperty('maxZoom')).toBe(10); + expect(addedLayer.getProperty('line-opacity')).toBe(0.6); + expect(addedLayer.getProperty('line-color')).toBe('red'); + expect(addedLayer.getProperty('line-width')).toBe(2); + }); + + it('update line layer', () => { + const mockMap = new MockMaplibreMap(); + const sourceId: string = 'geojson-source'; + + // add layer first + const addedLineLayerId: string = addLineLayer((mockMap as unknown) as Maplibre, { + color: 'red', + maxZoom: 10, + minZoom: 2, + opacity: 60, + sourceId, + visibility: 'visible', + width: 2, + }); + expect( + updateLineLayer((mockMap as unknown) as Maplibre, { + color: 'blue', + maxZoom: 12, + minZoom: 4, + opacity: 80, + sourceId, + visibility: 'none', + width: 12, + }) + ).toBe(addedLineLayerId); + expect(mockMap.getLayer(addedLineLayerId).length).toBe(1); + + const updatedLayer = mockMap.getLayer(addedLineLayerId)[0]; + expect(updatedLayer.getProperty('id')).toBe(addedLineLayerId); + expect(updatedLayer.getProperty('visibility')).toBe('none'); + expect(updatedLayer.getProperty('source')).toBe(sourceId); + expect(updatedLayer.getProperty('type')).toBe('line'); + expect(updatedLayer.getProperty('filter')).toEqual(['==', '$type', 'LineString']); + expect(updatedLayer.getProperty('minZoom')).toBe(4); + expect(updatedLayer.getProperty('maxZoom')).toBe(12); + expect(updatedLayer.getProperty('line-opacity')).toBe(0.8); + expect(updatedLayer.getProperty('line-color')).toBe('blue'); + expect(updatedLayer.getProperty('line-width')).toBe(12); + }); +}); + +describe('Polygon layer', () => { + it('add new polygon layer', () => { + const mockMap = new MockMaplibreMap(); + const sourceId: string = 'geojson-source'; + const expectedFillLayerId = sourceId + '-fill'; + const expectedOutlineLayerId = expectedFillLayerId + '-outline'; + expect(mockMap.getLayer(expectedFillLayerId).length).toBe(0); + expect(mockMap.getLayer(expectedOutlineLayerId).length).toBe(0); + addPolygonLayer((mockMap as unknown) as Maplibre, { + maxZoom: 10, + minZoom: 2, + opacity: 60, + outlineColor: 'green', + sourceId, + visibility: 'visible', + width: 2, + fillColor: 'red', + }); + expect(mockMap.getLayer(sourceId).length).toBe(2); + + const fillLayer = mockMap + .getLayer(sourceId) + .filter((layer) => layer.getProperty('id').toString().endsWith('-fill'))[0]; + + expect(fillLayer.getProperty('id')).toBe(expectedFillLayerId); + expect(fillLayer.getProperty('visibility')).toBe('visible'); + expect(fillLayer.getProperty('source')).toBe(sourceId); + expect(fillLayer.getProperty('type')).toBe('fill'); + expect(fillLayer.getProperty('filter')).toEqual(['==', '$type', 'Polygon']); + expect(fillLayer.getProperty('minZoom')).toBe(2); + expect(fillLayer.getProperty('maxZoom')).toBe(10); + expect(fillLayer.getProperty('fill-opacity')).toBe(0.6); + expect(fillLayer.getProperty('fill-color')).toBe('red'); + const outlineLayer = mockMap + .getLayer(sourceId) + .filter((layer) => layer.getProperty('id').toString().endsWith('-fill-outline'))[0]; + expect(outlineLayer.getProperty('id')).toBe(expectedOutlineLayerId); + expect(outlineLayer.getProperty('visibility')).toBe('visible'); + expect(outlineLayer.getProperty('source')).toBe(sourceId); + expect(outlineLayer.getProperty('type')).toBe('line'); + expect(outlineLayer.getProperty('filter')).toEqual(['==', '$type', 'Polygon']); + expect(outlineLayer.getProperty('minZoom')).toBe(2); + expect(outlineLayer.getProperty('maxZoom')).toBe(10); + expect(outlineLayer.getProperty('line-opacity')).toBe(0.6); + expect(outlineLayer.getProperty('line-color')).toBe('green'); + expect(outlineLayer.getProperty('line-width')).toBe(2); + }); + + it('update polygon layer', () => { + const mockMap = new MockMaplibreMap(); + const sourceId: string = 'geojson-source'; + + const expectedFillLayerId = sourceId + '-fill'; + const expectedOutlineLayerId = expectedFillLayerId + '-outline'; + // add layer first + addPolygonLayer((mockMap as unknown) as Maplibre, { + maxZoom: 10, + minZoom: 2, + opacity: 60, + outlineColor: 'green', + sourceId, + visibility: 'visible', + width: 2, + fillColor: 'red', + }); + + expect(mockMap.getLayer(sourceId).length).toBe(2); + // update polygon for test + updatePolygonLayer((mockMap as unknown) as Maplibre, { + maxZoom: 12, + minZoom: 4, + opacity: 80, + outlineColor: 'yellow', + sourceId, + visibility: 'none', + width: 7, + fillColor: 'blue', + }); + + expect(mockMap.getLayer(sourceId).length).toBe(2); + const fillLayer = mockMap + .getLayer(sourceId) + .filter((layer) => layer.getProperty('id') === expectedFillLayerId)[0]; + + expect(fillLayer.getProperty('id')).toBe(expectedFillLayerId); + expect(fillLayer.getProperty('visibility')).toBe('none'); + expect(fillLayer.getProperty('source')).toBe(sourceId); + expect(fillLayer.getProperty('type')).toBe('fill'); + expect(fillLayer.getProperty('filter')).toEqual(['==', '$type', 'Polygon']); + expect(fillLayer.getProperty('minZoom')).toBe(4); + expect(fillLayer.getProperty('maxZoom')).toBe(12); + expect(fillLayer.getProperty('fill-opacity')).toBe(0.8); + expect(fillLayer.getProperty('fill-color')).toBe('blue'); + const outlineLayer = mockMap + .getLayer(sourceId) + .filter((layer) => layer.getProperty('id') === expectedOutlineLayerId)[0]; + expect(outlineLayer.getProperty('id')).toBe(expectedOutlineLayerId); + expect(outlineLayer.getProperty('visibility')).toBe('none'); + expect(outlineLayer.getProperty('source')).toBe(sourceId); + expect(outlineLayer.getProperty('type')).toBe('line'); + expect(outlineLayer.getProperty('filter')).toEqual(['==', '$type', 'Polygon']); + expect(outlineLayer.getProperty('minZoom')).toBe(4); + expect(outlineLayer.getProperty('maxZoom')).toBe(12); + expect(outlineLayer.getProperty('line-opacity')).toBe(0.8); + expect(outlineLayer.getProperty('line-color')).toBe('yellow'); + expect(outlineLayer.getProperty('line-width')).toBe(7); + }); +}); diff --git a/public/model/map/layer_operations.ts b/public/model/map/layer_operations.ts index b69d045a..948f06c1 100644 --- a/public/model/map/layer_operations.ts +++ b/public/model/map/layer_operations.ts @@ -1,3 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ import { Map as Maplibre } from 'maplibre-gl'; export interface LineLayerSpecification { @@ -34,9 +38,9 @@ export const updateLineLayer = ( layerId?: string ): string => { const lineLayerId = layerId ? layerId : specification.sourceId + '-line'; - map?.setPaintProperty(lineLayerId, 'line-opacity', specification.opacity / 100); - map?.setPaintProperty(lineLayerId, 'line-color', specification.color); - map?.setPaintProperty(lineLayerId, 'line-width', specification.width); + map.setPaintProperty(lineLayerId, 'line-opacity', specification.opacity / 100); + map.setPaintProperty(lineLayerId, 'line-color', specification.color); + map.setPaintProperty(lineLayerId, 'line-width', specification.width); map.setLayoutProperty(lineLayerId, 'visibility', specification.visibility); map.setLayerZoomRange(lineLayerId, specification.minZoom, specification.maxZoom); return lineLayerId; @@ -79,12 +83,13 @@ export const updateCircleLayer = ( ): string => { const circleLayerId = layerId ? layerId : specification.sourceId + '-circle'; map.setLayoutProperty(circleLayerId, 'visibility', specification.visibility); - map?.setLayerZoomRange(circleLayerId, specification.minZoom, specification.maxZoom); - map?.setPaintProperty(circleLayerId, 'circle-opacity', specification.opacity / 100); - map?.setPaintProperty(circleLayerId, 'circle-color', specification.fillColor); - map?.setPaintProperty(circleLayerId, 'circle-stroke-color', specification.outlineColor); - map?.setPaintProperty(circleLayerId, 'circle-stroke-width', specification.width); - map?.setPaintProperty(circleLayerId, 'circle-radius', specification.radius); + map.setLayerZoomRange(circleLayerId, specification.minZoom, specification.maxZoom); + map.setPaintProperty(circleLayerId, 'circle-opacity', specification.opacity / 100); + map.setPaintProperty(circleLayerId, 'circle-color', specification.fillColor); + map.setPaintProperty(circleLayerId, 'circle-stroke-color', specification.outlineColor); + map.setPaintProperty(circleLayerId, 'circle-stroke-width', specification.width); + map.setPaintProperty(circleLayerId, 'circle-stroke-opacity', specification.opacity / 100); + map.setPaintProperty(circleLayerId, 'circle-radius', specification.radius); return circleLayerId; }; @@ -118,7 +123,7 @@ export const addPolygonLayer = ( // Due to limitations on WebGL, fill can't render outlines with width wider than 1, // so we have to create another style layer with type=line to apply width. - const outlineId = specification.sourceId + '-fill-outline'; + const outlineId = fillLayerId + '-outline'; map.addLayer( { id: outlineId, @@ -128,35 +133,48 @@ export const addPolygonLayer = ( }, beforeId ); - updatePolygonOutlineLayer(map, specification, outlineId); + updateLineLayer( + map, + { + width: specification.width, + color: specification.outlineColor, + maxZoom: specification.maxZoom, + minZoom: specification.minZoom, + opacity: specification.opacity, + sourceId: specification.sourceId, + visibility: specification.visibility, + }, + outlineId + ); }; export const updatePolygonLayer = (map: Maplibre, specification: PolygonLayerSpecification) => { - updatePolygonFillLayer(map, specification); - updatePolygonOutlineLayer(map, specification); + const fillLayerId: string = updatePolygonFillLayer(map, specification); + const outlineLayerId: string = fillLayerId + '-outline'; + updateLineLayer( + map, + { + width: specification.width, + color: specification.outlineColor, + maxZoom: specification.maxZoom, + minZoom: specification.minZoom, + opacity: specification.opacity, + sourceId: specification.sourceId, + visibility: specification.visibility, + }, + outlineLayerId + ); }; const updatePolygonFillLayer = ( map: Maplibre, specification: PolygonLayerSpecification, layerId?: string -) => { +): string => { const fillLayerId = layerId ? layerId : specification.sourceId + '-fill'; - map?.setLayoutProperty(fillLayerId, 'visibility', specification.visibility); - map?.setLayerZoomRange(fillLayerId, specification.minZoom, specification.maxZoom); - map?.setPaintProperty(fillLayerId, 'fill-opacity', specification.opacity / 100); - map?.setPaintProperty(fillLayerId, 'fill-color', specification.fillColor); + map.setLayoutProperty(fillLayerId, 'visibility', specification.visibility); + map.setLayerZoomRange(fillLayerId, specification.minZoom, specification.maxZoom); + map.setPaintProperty(fillLayerId, 'fill-opacity', specification.opacity / 100); + map.setPaintProperty(fillLayerId, 'fill-color', specification.fillColor); return fillLayerId; }; -const updatePolygonOutlineLayer = ( - map: Maplibre, - specification: PolygonLayerSpecification, - layerId?: string -) => { - const outlineLayerId = layerId ? layerId : specification.sourceId + '-fill-outline'; - map?.setPaintProperty(outlineLayerId, 'line-color', specification.outlineColor); - map?.setPaintProperty(outlineLayerId, 'line-width', specification.width); - map.setLayoutProperty(outlineLayerId, 'visibility', specification.visibility); - map?.setLayerZoomRange(outlineLayerId, specification.minZoom, specification.maxZoom); - return outlineLayerId; -}; From a06e6ade893183f563cfb5b04b5731bc4fb3d114 Mon Sep 17 00:00:00 2001 From: Vijayan Balasubramanian Date: Mon, 30 Jan 2023 15:04:09 -0800 Subject: [PATCH 4/4] Add license Signed-off-by: Vijayan Balasubramanian --- public/model/map/layer_operations.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/model/map/layer_operations.test.ts b/public/model/map/layer_operations.test.ts index 08553724..779fdb4f 100644 --- a/public/model/map/layer_operations.test.ts +++ b/public/model/map/layer_operations.test.ts @@ -1,3 +1,7 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ import { addCircleLayer, addLineLayer,