@hackoregon/component-library
Version:
Official repo for Hack Oregon React component library
293 lines (270 loc) • 8.9 kB
JavaScript
/* TODO: Fix linting errors */
/* eslint-disable */
import React from "react";
import { arrayOf, shape, func, node, number } from "prop-types";
import shortid from "shortid";
import DeckGL, {
IconLayer,
PathLayer,
PolygonLayer,
ScatterplotLayer,
ScreenGridLayer
} from "deck.gl";
import { scaleQuantize, scaleOrdinal, scaleThreshold, extent } from "d3";
const CivicSandboxMap = props => {
const {
viewport,
mapLayers,
children,
onClick,
onHoverSlide,
selectedFoundationDatum
} = props;
const getDefaultPosition = f => f.geometry.coordinates;
const getDefaultBoundaryPolygon = f => f.coordinates;
const highlighterYellow = [255, 255, 0, 200];
const createPathMap = slide => (
<PathLayer
key={shortid.generate()}
id={slide.data.id}
pickable={slide.data.pickable || true}
data={slide.data.data}
getColor={slide.data.getColor}
opacity={slide.data.opacity || 0.9}
getPath={slide.data.getPath || getDefaultPosition}
getWidth={slide.data.getWidth}
widthScale={slide.data.widthScale}
widthMinPixels={1}
rounded={slide.data.rounded || false}
autoHighlight={slide.data.autoHighlight || true}
highlightColor={slide.data.highlightColor || highlighterYellow}
onHover={onHoverSlide}
parameters={{ depthTest: false }}
/>
);
const createScatterPlotMap = slide => (
<ScatterplotLayer
key={shortid.generate()}
id={slide.data.id}
pickable={slide.data.pickable || true}
data={slide.data.data}
getPosition={slide.data.getPosition || getDefaultPosition}
opacity={slide.data.opacity || 0.9}
getFillColor={slide.data.getFillColor}
getLineColor={slide.data.getLineColor}
stroked={slide.data.stroked || false}
getLineWidth={slide.data.getLineWidth || 5}
lineWidthMinPixels={1}
getRadius={slide.data.getRadius}
radiusScale={slide.data.radiusScale || 1}
radiusMinPixels={1}
autoHighlight={slide.data.autoHighlight || true}
highlightColor={slide.data.highlightColor || highlighterYellow}
onHover={onHoverSlide}
parameters={{ depthTest: false }}
/>
);
const createIconMap = slide => (
<IconLayer
key={shortid.generate()}
id={slide.data.id}
pickable={slide.data.pickable || true}
data={slide.data.data}
opacity={slide.data.opacity}
iconAtlas={slide.data.iconAtlas}
iconMapping={slide.data.iconMapping}
sizeScale={slide.data.sizeScale(viewport.zoom)}
getPosition={slide.data.getPosition}
getIcon={slide.data.getIcon}
getSize={slide.data.getSize}
getColor={slide.data.getColor}
autoHighlight={slide.data.autoHighlight || false}
highlightColor={slide.data.highlightColor || [0, 0, 0, 0]}
onHover={onHoverSlide}
parameters={{ depthTest: false }}
/>
);
const createScreenGridMap = slide => (
<ScreenGridLayer
key={shortid.generate()}
id={slide.data.id}
pickable={slide.data.pickable || true}
data={slide.data.data}
getPosition={slide.data.getPosition || getDefaultPosition}
opacity={slide.data.opacity || 0.9}
colorRange={slide.data.colorRange}
cellSizePixels={slide.data.cellSizePixels}
autoHighlight={slide.data.autoHighlight || true}
highlightColor={slide.data.highlightColor || highlighterYellow}
updateTriggers={{ instanceColors: slide.data }}
gpuAggregation={false}
/>
);
const createBoundaryMap = slide => (
<PolygonLayer
key={shortid.generate()}
id={slide.data.id}
pickable={false}
data={slide.data.data}
opacity={slide.data.opacity}
getPolygon={slide.data.getPolygon || getDefaultBoundaryPolygon}
getLineColor={slide.data.getLineColor}
getLineWidth={slide.data.getLineWidth}
lineWidthMinPixels={1}
lineWidthScale={1}
lineJointRounded={slide.data.lineJointRounded || false}
stroked={true}
filled={false}
autoHighlight={false}
parameters={{ depthTest: false }}
/>
);
const createPolygonMap = slide => (
<PolygonLayer
key={shortid.generate()}
id={slide.data.id}
pickable={true}
data={slide.data.data}
opacity={slide.data.opacity || 0.9}
getPolygon={slide.data.getPolygon || getDefaultPosition}
getLineColor={slide.data.getLineColor}
getLineWidth={slide.data.getLineWidth}
lineWidthMinPixels={1}
lineWidthScale={1}
lineJointRounded={slide.data.lineJointRounded || false}
stroked={slide.data.stroked || true}
getFillColor={slide.data.getFillColor}
filled={slide.data.filled || true}
onHover={onHoverSlide}
autoHighlight={slide.data.autoHighlight || true}
highlightColor={slide.data.highlightColor || highlighterYellow}
parameters={{ depthTest: false }}
/>
);
const createEqualBins = (data, color, getPropValue) => {
const quantizeScale = scaleQuantize()
.domain(extent(data, getPropValue))
.range(color)
.nice();
return quantizeScale;
};
const createDiscreteBins = (categories, color) => {
const ordinalScale = scaleOrdinal()
.domain(categories)
.range(color)
.unknown([0, 0, 0, 0]);
return ordinalScale;
};
const createThresholdBins = (categories, color) => {
const thresholdScale = scaleThreshold()
.domain(categories)
.range(color);
return thresholdScale;
};
const createChoroplethMap = slide => {
const scaleType = slide.data.scaleType;
const colorScale =
scaleType === "ordinal"
? createDiscreteBins(slide.data.categories, slide.data.color)
: scaleType === "threshold"
? createThresholdBins(slide.data.categories, slide.data.color)
: createEqualBins(
slide.data.data,
slide.data.color,
slide.data.getPropValue
);
const getFillColor = f => {
const value =
slide.data.scaleType === "ordinal"
? f.properties[slide.data.propName]
: parseFloat(f.properties[slide.data.propName]);
return colorScale(value) ? colorScale(value) : [0, 0, 0, 55];
};
const getLineColor = f => {
const [selectedFeature] = selectedFoundationDatum;
const id = selectedFeature ? selectedFeature.id : null;
return f.id === id ? [255, 255, 0, 255] : [112, 122, 122, 155];
};
const getLineWidth = f => {
const [selectedFeature] = selectedFoundationDatum;
const id = selectedFeature ? selectedFeature.id : null;
return f.id === id ? 75 : 1;
};
return (
<PolygonLayer
key={shortid.generate()}
id={slide.data.id}
pickable={true}
data={slide.data.data}
opacity={slide.data.opacity || 0.9}
getPolygon={f => f.geometry.coordinates}
getLineColor={slide.data.getLineColor || getLineColor}
getLineWidth={slide.data.getLineWidth || getLineWidth}
lineWidthMinPixels={1}
stroked={true}
getFillColor={slide.data.getFillColor || getFillColor}
filled={true}
onClick={onClick || slide.data.onLayerClick}
autoHighlight={true}
highlightColor={slide.data.highlightColor || [255, 255, 0, 55]}
parameters={{ depthTest: false }}
updateTriggers={
slide.data.updateTriggers || {
getLineColor: selectedFoundationDatum,
getLineWidth: selectedFoundationDatum
}
}
/>
);
};
const renderMaps = mapLayers.map((layer, index) => {
const mapType = layer.data.mapType;
return mapType === "PathMap"
? createPathMap(layer, index)
: mapType === "ScatterPlotMap"
? createScatterPlotMap(layer, index)
: mapType === "IconMap"
? createIconMap(layer, index)
: mapType === "ScreenGridMap"
? createScreenGridMap(layer, index)
: mapType === "PolygonPlotMap"
? createPolygonMap(layer, index)
: mapType === "SmallPolygonMap"
? createPolygonMap(layer, index)
: mapType === "ChoroplethMap"
? createChoroplethMap(layer, index)
: mapType === "BoundaryMap"
? createBoundaryMap(layer, index)
: null;
});
return (
<div>
<DeckGL className="DeckGL" {...viewport} getCursor={() => "crosshair"}>
{renderMaps}
{children}
</DeckGL>
</div>
);
};
CivicSandboxMap.propTypes = {
viewport: shape({
latitude: number,
longitude: number,
height: number,
width: number,
zoom: number
}),
mapLayers: arrayOf(
shape({
data: shape({})
})
).isRequired,
onHoverSlide: func,
onClick: func,
children: node,
selectedFoundationDatum: arrayOf(shape({}))
};
CivicSandboxMap.defaultProps = {
selectedFoundationDatum: []
};
export default CivicSandboxMap;