Another one bites the dust

This commit is contained in:
HarelM
2023-12-23 14:58:33 +02:00
parent 5a62f4ab21
commit 90b692158a
2 changed files with 71 additions and 58 deletions
@@ -1,15 +1,15 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import MapLibreGl from 'maplibre-gl' import MapLibreGl, {LayerSpecification, Map, MapOptions, SourceSpecification, StyleSpecification} from 'maplibre-gl'
// @ts-ignore
import MapboxInspect from 'mapbox-gl-inspect' import MapboxInspect from 'mapbox-gl-inspect'
import MapMaplibreGlLayerPopup from './MapMaplibreGlLayerPopup' // @ts-ignore
import MapMaplibreGlFeaturePropertyPopup from './MapMaplibreGlFeaturePropertyPopup'
import tokens from '../config/tokens.json'
import colors from 'mapbox-gl-inspect/lib/colors' import colors from 'mapbox-gl-inspect/lib/colors'
import MapMaplibreGlLayerPopup from './MapMaplibreGlLayerPopup'
import MapMaplibreGlFeaturePropertyPopup, { InspectFeature } from './MapMaplibreGlFeaturePropertyPopup'
import Color from 'color' import Color from 'color'
import ZoomControl from '../libs/zoomcontrol' import ZoomControl from '../libs/zoomcontrol'
import { colorHighlightedLayer } from '../libs/highlight' import { HighlightedLayer, colorHighlightedLayer } from '../libs/highlight'
import 'maplibre-gl/dist/maplibre-gl.css' import 'maplibre-gl/dist/maplibre-gl.css'
import '../maplibregl.css' import '../maplibregl.css'
import '../libs/maplibre-rtl' import '../libs/maplibre-rtl'
@@ -17,26 +17,26 @@ import '../libs/maplibre-rtl'
const IS_SUPPORTED = MapLibreGl.supported(); const IS_SUPPORTED = MapLibreGl.supported();
function renderPopup(popup, mountNode) { function renderPopup(popup: JSX.Element, mountNode: ReactDOM.Container) {
ReactDOM.render(popup, mountNode); ReactDOM.render(popup, mountNode);
return mountNode; return mountNode;
} }
function buildInspectStyle(originalMapStyle, coloredLayers, highlightedLayer) { function buildInspectStyle(originalMapStyle: StyleSpecification, coloredLayers: HighlightedLayer[], highlightedLayer?: HighlightedLayer) {
const backgroundLayer = { const backgroundLayer = {
"id": "background", "id": "background",
"type": "background", "type": "background",
"paint": { "paint": {
"background-color": '#1c1f24', "background-color": '#1c1f24',
} }
} } as LayerSpecification
const layer = colorHighlightedLayer(highlightedLayer) const layer = colorHighlightedLayer(highlightedLayer)
if(layer) { if(layer) {
coloredLayers.push(layer) coloredLayers.push(layer)
} }
const sources = {} const sources: {[key:string]: SourceSpecification} = {}
Object.keys(originalMapStyle.sources).forEach(sourceId => { Object.keys(originalMapStyle.sources).forEach(sourceId => {
const source = originalMapStyle.sources[sourceId] const source = originalMapStyle.sources[sourceId]
if(source.type !== 'raster' && source.type !== 'raster-dem') { if(source.type !== 'raster' && source.type !== 'raster-dem') {
@@ -47,32 +47,43 @@ function buildInspectStyle(originalMapStyle, coloredLayers, highlightedLayer) {
const inspectStyle = { const inspectStyle = {
...originalMapStyle, ...originalMapStyle,
sources: sources, sources: sources,
layers: [backgroundLayer].concat(coloredLayers) layers: [backgroundLayer].concat(coloredLayers as LayerSpecification[])
} }
return inspectStyle return inspectStyle
} }
export default class MapMaplibreGl extends React.Component { type MapMaplibreGlProps = {
static propTypes = { onDataChange?(...args: unknown[]): unknown
onDataChange: PropTypes.func, onLayerSelect(...args: unknown[]): unknown
onLayerSelect: PropTypes.func.isRequired, mapStyle: StyleSpecification
mapStyle: PropTypes.object.isRequired, inspectModeEnabled: boolean
inspectModeEnabled: PropTypes.bool.isRequired, highlightedLayer?: HighlightedLayer
highlightedLayer: PropTypes.object, options?: MapOptions & {
options: PropTypes.object, showTileBoundaries?: boolean
replaceAccessTokens: PropTypes.func.isRequired, showCollisionBoxes?: boolean
onChange: PropTypes.func.isRequired, showOverdrawInspector?: boolean
} }
replaceAccessTokens(mapStyle: StyleSpecification): StyleSpecification
onChange(...args: unknown[]): unknown
};
type MapMaplibreGlState = {
map: Map | null
inspect: MapboxInspect | null
zoom?: number
};
export default class MapMaplibreGl extends React.Component<MapMaplibreGlProps, MapMaplibreGlState> {
static defaultProps = { static defaultProps = {
onMapLoaded: () => {}, onMapLoaded: () => {},
onDataChange: () => {}, onDataChange: () => {},
onLayerSelect: () => {}, onLayerSelect: () => {},
onChange: () => {}, onChange: () => {},
options: {}, options: {} as MapOptions,
} }
container: HTMLDivElement | null = null
constructor(props) { constructor(props: MapMaplibreGlProps) {
super(props) super(props)
this.state = { this.state = {
map: null, map: null,
@@ -80,7 +91,7 @@ export default class MapMaplibreGl extends React.Component {
} }
} }
updateMapFromProps(props) { updateMapFromProps(props: MapMaplibreGlProps) {
if(!IS_SUPPORTED) return; if(!IS_SUPPORTED) return;
if(!this.state.map) return if(!this.state.map) return
@@ -93,7 +104,7 @@ export default class MapMaplibreGl extends React.Component {
) )
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps: MapMaplibreGlProps, nextState: MapMaplibreGlState) {
let should = false; let should = false;
try { try {
should = JSON.stringify(this.props) !== JSON.stringify(nextProps) || JSON.stringify(this.state) !== JSON.stringify(nextState); should = JSON.stringify(this.props) !== JSON.stringify(nextProps) || JSON.stringify(this.state) !== JSON.stringify(nextState);
@@ -103,7 +114,7 @@ export default class MapMaplibreGl extends React.Component {
return should; return should;
} }
componentDidUpdate(prevProps, prevState, snapshot) { componentDidUpdate() {
if(!IS_SUPPORTED) return; if(!IS_SUPPORTED) return;
const map = this.state.map; const map = this.state.map;
@@ -128,9 +139,9 @@ export default class MapMaplibreGl extends React.Component {
} }
} }
map.showTileBoundaries = this.props.options.showTileBoundaries; map.showTileBoundaries = this.props.options?.showTileBoundaries!;
map.showCollisionBoxes = this.props.options.showCollisionBoxes; map.showCollisionBoxes = this.props.options?.showCollisionBoxes!;
map.showOverdrawInspector = this.props.options.showOverdrawInspector; map.showOverdrawInspector = this.props.options?.showOverdrawInspector!;
} }
} }
@@ -139,7 +150,7 @@ export default class MapMaplibreGl extends React.Component {
const mapOpts = { const mapOpts = {
...this.props.options, ...this.props.options,
container: this.container, container: this.container!,
style: this.props.mapStyle, style: this.props.mapStyle,
hash: true, hash: true,
maxZoom: 24 maxZoom: 24
@@ -154,9 +165,9 @@ export default class MapMaplibreGl extends React.Component {
} }
mapViewChange(); mapViewChange();
map.showTileBoundaries = mapOpts.showTileBoundaries; map.showTileBoundaries = mapOpts.showTileBoundaries!;
map.showCollisionBoxes = mapOpts.showCollisionBoxes; map.showCollisionBoxes = mapOpts.showCollisionBoxes!;
map.showOverdrawInspector = mapOpts.showOverdrawInspector; map.showOverdrawInspector = mapOpts.showOverdrawInspector!;
const zoomControl = new ZoomControl; const zoomControl = new ZoomControl;
map.addControl(zoomControl, 'top-right'); map.addControl(zoomControl, 'top-right');
@@ -175,11 +186,11 @@ export default class MapMaplibreGl extends React.Component {
showInspectMapPopupOnHover: true, showInspectMapPopupOnHover: true,
showInspectButton: false, showInspectButton: false,
blockHoverPopupOnClick: true, blockHoverPopupOnClick: true,
assignLayerColor: (layerId, alpha) => { assignLayerColor: (layerId: string, alpha: number) => {
return Color(colors.brightColor(layerId, alpha)).desaturate(0.5).string() return Color(colors.brightColor(layerId, alpha)).desaturate(0.5).string()
}, },
buildInspectStyle: (originalMapStyle, coloredLayers) => buildInspectStyle(originalMapStyle, coloredLayers, this.props.highlightedLayer), buildInspectStyle: (originalMapStyle: StyleSpecification, coloredLayers: HighlightedLayer[]) => buildInspectStyle(originalMapStyle, coloredLayers, this.props.highlightedLayer),
renderPopup: features => { renderPopup: (features: InspectFeature[]) => {
if(this.props.inspectModeEnabled) { if(this.props.inspectModeEnabled) {
return renderPopup(<MapMaplibreGlFeaturePropertyPopup features={features} />, tmpNode); return renderPopup(<MapMaplibreGlFeaturePropertyPopup features={features} />, tmpNode);
} else { } else {
@@ -199,7 +210,7 @@ export default class MapMaplibreGl extends React.Component {
map.on("data", e => { map.on("data", e => {
if(e.dataType !== 'tile') return if(e.dataType !== 'tile') return
this.props.onDataChange({ this.props.onDataChange!({
map: this.state.map map: this.state.map
}) })
}) })
@@ -208,7 +219,7 @@ export default class MapMaplibreGl extends React.Component {
console.log("ERROR", e); console.log("ERROR", e);
}) })
map.on("zoom", e => { map.on("zoom", _e => {
this.setState({ this.setState({
zoom: map.getZoom() zoom: map.getZoom()
}); });
@@ -218,7 +229,7 @@ export default class MapMaplibreGl extends React.Component {
map.on("zoomend", mapViewChange); map.on("zoomend", mapViewChange);
} }
onLayerSelectById = (id) => { onLayerSelectById = (id: string) => {
const index = this.props.mapStyle.layers.findIndex(layer => layer.id === id); const index = this.props.mapStyle.layers.findIndex(layer => layer.id === id);
this.props.onLayerSelect(index); this.props.onLayerSelect(index);
} }
+21 -19
View File
@@ -4,38 +4,40 @@ import stylegen from 'mapbox-gl-inspect/lib/stylegen'
import colors from 'mapbox-gl-inspect/lib/colors' import colors from 'mapbox-gl-inspect/lib/colors'
import {FilterSpecification,LayerSpecification } from '@maplibre/maplibre-gl-style-spec' import {FilterSpecification,LayerSpecification } from '@maplibre/maplibre-gl-style-spec'
export function colorHighlightedLayer(layer: LayerSpecification) { export type HighlightedLayer = LayerSpecification & {filter?: FilterSpecification};
if(!layer || layer.type === 'background' || layer.type === 'raster') return null
function changeLayer(l: LayerSpecification & {filter?: FilterSpecification}) { function changeLayer(l: HighlightedLayer, layer: LayerSpecification) {
if(l.type === 'circle') { if(l.type === 'circle') {
l.paint!['circle-radius'] = 3 l.paint!['circle-radius'] = 3
} else if(l.type === 'line') { } else if(l.type === 'line') {
l.paint!['line-width'] = 2 l.paint!['line-width'] = 2
}
if("filter" in layer) {
l.filter = layer.filter
} else {
delete l['filter']
}
l.id = l.id + '_highlight'
return l
} }
if("filter" in layer) {
l.filter = layer.filter
} else {
delete l['filter']
}
l.id = l.id + '_highlight'
return l
}
export function colorHighlightedLayer(layer?: LayerSpecification): HighlightedLayer | null {
if(!layer || layer.type === 'background' || layer.type === 'raster') return null
const sourceLayerId = layer['source-layer'] || '' const sourceLayerId = layer['source-layer'] || ''
const color = colors.brightColor(sourceLayerId, 1); const color = colors.brightColor(sourceLayerId, 1);
if(layer.type === "fill" || layer.type === 'fill-extrusion') { if(layer.type === "fill" || layer.type === 'fill-extrusion') {
return changeLayer(stylegen.polygonLayer(color, color, layer.source, layer['source-layer'])) return changeLayer(stylegen.polygonLayer(color, color, layer.source, layer['source-layer']), layer)
} }
if(layer.type === "symbol" || layer.type === 'circle') { if(layer.type === "symbol" || layer.type === 'circle') {
return changeLayer(stylegen.circleLayer(color, layer.source, layer['source-layer'])) return changeLayer(stylegen.circleLayer(color, layer.source, layer['source-layer']), layer)
} }
if(layer.type === 'line') { if(layer.type === 'line') {
return changeLayer(stylegen.lineLayer(color, layer.source, layer['source-layer'])) return changeLayer(stylegen.lineLayer(color, layer.source, layer['source-layer']), layer)
} }
return null return null