|
import React, { useState, useEffect } from "react"; |
|
import { fromJS, Map } from "immutable"; |
|
import MAP_STYLE from "./map-style-basic-v8.json"; |
|
|
|
const defaultMapStyle: Map<string, any> = fromJS(MAP_STYLE); |
|
const defaultLayers = defaultMapStyle.get("layers"); |
|
|
|
const categories: string[] = [ |
|
"labels", |
|
"roads", |
|
"buildings", |
|
"parks", |
|
"water", |
|
"background", |
|
]; |
|
|
|
|
|
const layerSelector: { [key: string]: RegExp } = { |
|
background: /background/, |
|
water: /water/, |
|
parks: /park/, |
|
buildings: /building/, |
|
roads: /bridge|road|tunnel/, |
|
labels: /label|place|poi/, |
|
}; |
|
|
|
|
|
const colorClass: { [key: string]: string } = { |
|
line: "line-color", |
|
fill: "fill-color", |
|
background: "background-color", |
|
symbol: "text-color", |
|
}; |
|
|
|
function getMapStyle({ visibility, color }: MapStyleOptions): Map<string, any> { |
|
const layers = defaultLayers |
|
.filter((layer: any) => { |
|
const id = layer.get("id"); |
|
return categories.every( |
|
(name) => visibility[name] || !layerSelector[name].test(id) |
|
); |
|
}) |
|
.map((layer: any) => { |
|
const id = layer.get("id"); |
|
const type = layer.get("type"); |
|
const category = categories.find((name) => layerSelector[name].test(id)); |
|
if (category && colorClass[type]) { |
|
return layer.setIn(["paint", colorClass[type]], color[category]); |
|
} |
|
return layer; |
|
}); |
|
|
|
return defaultMapStyle.set("layers", layers); |
|
} |
|
|
|
interface MapStyleOptions { |
|
visibility: { [key: string]: boolean }; |
|
color: { [key: string]: string }; |
|
} |
|
|
|
interface StyleControlsProps { |
|
onChange: (style: Map<string, any>) => void; |
|
} |
|
|
|
function StyleControls(props: StyleControlsProps) { |
|
const [visibility, setVisibility] = useState<any>({ |
|
water: true, |
|
parks: true, |
|
buildings: true, |
|
roads: true, |
|
labels: true, |
|
background: true, |
|
}); |
|
|
|
const [color, setColor] = useState<any>({ |
|
water: "#DBE2E6", |
|
parks: "#E6EAE9", |
|
buildings: "#c0c0c8", |
|
roads: "#ffffff", |
|
labels: "#78888a", |
|
background: "#EBF0F0", |
|
}); |
|
|
|
useEffect(() => { |
|
props.onChange(getMapStyle({ visibility, color })); |
|
}, [visibility, color]); |
|
|
|
const onColorChange = (name: string, value: string) => { |
|
setColor({ ...color, [name]: value }); |
|
}; |
|
|
|
const onVisibilityChange = (name: string, value: boolean) => { |
|
setVisibility({ ...visibility, [name]: value }); |
|
}; |
|
|
|
return ( |
|
<div className="control-panel"> |
|
<h3>Dynamic Styling</h3> |
|
<hr /> |
|
{categories.map((name) => ( |
|
<div |
|
key={name} |
|
className="input" |
|
style={{ |
|
display: "flex", |
|
flexDirection: "row", |
|
justifyContent: "space-between", |
|
alignItems: "center", |
|
}} |
|
> |
|
<label>{name}</label> |
|
<input |
|
type="checkbox" |
|
checked={visibility[name]} |
|
onChange={(evt) => onVisibilityChange(name, evt.target.checked)} |
|
/> |
|
<input |
|
type="color" |
|
value={color[name]} |
|
disabled={!visibility[name]} |
|
onChange={(evt) => onColorChange(name, evt.target.value)} |
|
/> |
|
</div> |
|
))} |
|
</div> |
|
); |
|
} |
|
|
|
export default React.memo(StyleControls); |
|
|