@hackoregon/component-library
Version:
Official repo for Hack Oregon React component library
734 lines (645 loc) • 19.3 kB
JavaScript
/* eslint-disable import/no-extraneous-dependencies */
import React from "react";
import { storiesOf } from "@storybook/react";
import {
withKnobs,
text,
number,
select,
object,
optionsKnob as options
} from "@storybook/addon-knobs";
import { action } from "@storybook/addon-actions";
import { checkA11y } from "@storybook/addon-a11y";
import { at } from "lodash";
import { BaseMap, MultiLayerMap, DemoJSONLoader } from "../src";
import notes from "./multiLayerMap.notes";
const GROUP_IDS = {
DESIGN: "Design",
DATA: "Data"
};
const CIVIC_COLORS = {
"(none)": "",
civicBlue: "civicBlue",
civicGreen: "civicGreen",
civicPurple: "civicPurple",
civicPink: "civicPink",
civicYellow: "civicYellow",
thermal: "thermal",
planet: "planet",
space: "space",
earth: "earth",
ocean: "ocean",
purpleGreen: "purpleGreen",
purpleOrange: "purpleOrange"
};
const opacityOptions = {
range: true,
min: 0.1,
max: 1,
step: 0.05
};
const radiusScaleOptions = {
range: true,
min: 1,
max: 100,
step: 1
};
const iconSizeOptions = {
range: true,
min: 1,
max: 100,
step: 1
};
export default () =>
storiesOf("Component Lib|Maps/MultiLayer Map", module)
.addDecorator(withKnobs)
.addDecorator(checkA11y)
.add(
"Path Map",
() => {
const lineWidth = number("Line Width:", 25, {}, GROUP_IDS.DESIGN);
const opacity = number(
"Opacity:",
0.7,
opacityOptions,
GROUP_IDS.DESIGN
);
const PATH_MAP_SCALE_TYPE_COLOR_OPTIONS = {
none: "",
threshold: "threshold",
ordinal: "ordinal",
equal: "equal"
};
const lineColor = select(
"CIVIC Color:",
CIVIC_COLORS,
CIVIC_COLORS.civicGreen,
GROUP_IDS.DESIGN
);
const scaleTypeColor = options(
"Scale Type:",
PATH_MAP_SCALE_TYPE_COLOR_OPTIONS,
"",
{
display: "inline-radio"
},
GROUP_IDS.DESIGN
);
const fieldName = text("Field Name:", "shape_leng", GROUP_IDS.DESIGN);
const dataRange = object("Data Range:", [], GROUP_IDS.DESIGN);
const colorRange = object("Color Range:", [], GROUP_IDS.DESIGN);
const pathMapAPIURL =
"https://service.civicpdx.org/neighborhood-development/api/bike_greenways" +
"?format=json&limit=280";
const fetchURL = text("API URL:", pathMapAPIURL, GROUP_IDS.DATA);
const onLayerClick = info => action("Line Clicked:")(info);
return (
<DemoJSONLoader urls={[fetchURL]}>
{data => {
const featuresArrayPath = text(
"Features Array Path:",
"results.features",
GROUP_IDS.DATA
);
const featuresData = at(data, featuresArrayPath)[0];
const pathMapLayer = {
mapType: "PathMap",
id: "storybook-pathmap-00",
data: featuresData,
lineWidth,
opacity,
civicColor: lineColor,
scaleType: {
color: scaleTypeColor
},
fieldName: {
color: fieldName
},
dataRange,
colorRange,
onLayerClick
};
return (
<div style={{ height: "100vh" }}>
<BaseMap
initialZoom={12.8}
initialLongitude={-122.7150944}
initialLatitude={45.4761333}
updateViewport={false}
civicMapStyle="dark"
useContainerHeight
>
<MultiLayerMap mapLayers={[pathMapLayer]} />
</BaseMap>
</div>
);
}}
</DemoJSONLoader>
);
},
{
notes: notes.pathNotes
}
)
.add(
"ScatterPlot Map",
() => {
const circleRadius = number("radius:", 25, {}, GROUP_IDS.DESIGN);
const circleOpacity = number(
"opacity:",
0.7,
opacityOptions,
GROUP_IDS.DESIGN
);
const SCATTERPLOT_SCALE_TYPE_COLOR_OPTIONS = {
none: "",
ordinal: "ordinal"
};
const circleColor = select(
"CIVIC Color:",
CIVIC_COLORS,
CIVIC_COLORS.civicGreen,
GROUP_IDS.DESIGN
);
const scaleTypeColor = options(
"Scale Type (color):",
SCATTERPLOT_SCALE_TYPE_COLOR_OPTIONS,
"",
{
display: "inline-radio"
},
GROUP_IDS.DESIGN
);
const fieldNameColor = text(
"Field Name (color):",
"condition",
GROUP_IDS.DESIGN
);
const dataRange = object("Data Range:", [], GROUP_IDS.DESIGN);
const colorRange = object("Color Range:", [], GROUP_IDS.DESIGN);
const SCATTERPLOT_SCALE_TYPE_AREA_OPTIONS = {
none: "",
"circle area": "circle area"
};
const scaleTypeArea = options(
"Scale Type (area):",
SCATTERPLOT_SCALE_TYPE_AREA_OPTIONS,
"",
{
display: "inline-radio"
},
GROUP_IDS.DESIGN
);
const fieldNameArea = text(
"Field Name (area):",
"dbh",
GROUP_IDS.DESIGN
);
const circleRadiusScale = number(
"Radius Scale:",
20,
radiusScaleOptions,
GROUP_IDS.DESIGN
);
const scatterPlotAPIURL =
"https://service.civicpdx.org/neighborhood-development/api/trees" +
"?format=json&limit=1500&offset=2000";
const fetchAPIURL = text("API URL:", scatterPlotAPIURL, GROUP_IDS.DATA);
const onLayerClick = info => action("Circle Clicked:")(info);
return (
<DemoJSONLoader urls={[fetchAPIURL]}>
{data => {
const featuresArrayPath = text(
"Features Array Path:",
"results.features",
GROUP_IDS.DATA
);
const featuresData = at(data, featuresArrayPath)[0];
const scatterPlotMapLayer = {
mapType: "ScatterPlotMap",
id: "storybook-scatterplotmap-00",
data: featuresData,
radius: circleRadius,
opacity: circleOpacity,
civicColor: circleColor,
scaleType: {
area: scaleTypeArea,
color: scaleTypeColor
},
fieldName: {
area: fieldNameArea,
color: fieldNameColor
},
radiusScale: circleRadiusScale,
dataRange,
colorRange,
onLayerClick
};
return (
<div style={{ height: "100vh" }}>
<BaseMap
initialZoom={14}
initialLatitude={45.5298276}
initialLongitude={-122.698753}
updateViewport={false}
civicMapStyle="dark"
useContainerHeight
>
<MultiLayerMap mapLayers={[scatterPlotMapLayer]} />
</BaseMap>
</div>
);
}}
</DemoJSONLoader>
);
},
{
notes: notes.scatterPlotNotes
}
)
.add(
"Screen Grid Map",
() => {
const squareColor = select(
"CIVIC Colors:",
CIVIC_COLORS,
CIVIC_COLORS.thermal,
GROUP_IDS.DESIGN
);
const squareSize = number("Square Size:", 10, {}, GROUP_IDS.DESIGN);
const squareOpacity = number(
"Opacity:",
0.7,
opacityOptions,
GROUP_IDS.DESIGN
);
const screenGridMapAPIURL =
"https://service.civicpdx.org/neighborhood-development/api/retail_locations" +
"?format=json&limit=500";
const fetchAPIURL = text(
"API URL:",
screenGridMapAPIURL,
GROUP_IDS.DATA
);
return (
<DemoJSONLoader urls={[fetchAPIURL]}>
{data => {
const featuresArrayPath = text(
"Features Array Path:",
"results.features",
GROUP_IDS.DATA
);
const featuresData = at(data, featuresArrayPath)[0];
const screenGridMapLayer = {
mapType: "ScreenGridMap",
id: "storybook-screengridmap-00",
data: featuresData,
squareSize,
opacity: squareOpacity,
civicColor: squareColor
};
return (
<div style={{ height: "100vh" }}>
<BaseMap
initialZoom={10}
updateViewport={false}
civicMapStyle="dark"
useContainerHeight
>
<MultiLayerMap mapLayers={[screenGridMapLayer]} />
</BaseMap>
</div>
);
}}
</DemoJSONLoader>
);
},
{
notes: notes.screenGridNotes
}
)
.add(
"Icon Map",
() => {
const iconSize = number(
"Icon Size:",
10,
iconSizeOptions,
GROUP_IDS.DESIGN
);
const iconOpacity = number(
"Opacity:",
0.7,
opacityOptions,
GROUP_IDS.DESIGN
);
const iconAtlas = text(
"Icon Atlas:",
"https://i.imgur.com/xgTAROe.png",
GROUP_IDS.DESIGN
);
const iconMapping = object(
"Icon Mapping:",
{
School: {
x: 0,
y: 0,
width: 250,
height: 250,
mask: true
},
Hospital: {
x: 250,
y: 0,
width: 250,
height: 250,
mask: true
},
BEECN: {
x: 500,
y: 0,
width: 250,
height: 250,
mask: true
},
"Fire Station": {
x: 0,
y: 250,
width: 250,
height: 250,
mask: true
},
Pin: {
x: 250,
y: 250,
width: 250,
height: 250,
mask: true
},
COMMCTR: {
x: 500,
y: 250,
width: 250,
height: 250,
mask: true
}
},
GROUP_IDS.DESIGN
);
const ICON_SCALE_TYPE_COLOR_OPTIONS = {
ordinal: "ordinal"
};
const scaleType = options(
"Scale Type:",
ICON_SCALE_TYPE_COLOR_OPTIONS,
"ordinal",
{
display: "inline-radio"
},
GROUP_IDS.DESIGN
);
const fieldName = text("Field Name:", "type", GROUP_IDS.DESIGN);
const dataRange = object(
"Data Range:",
["BEECN", "COMMCTR", "Fire Station", "School", "Hospital"],
GROUP_IDS.DESIGN
);
const colorRange = object(
"Color Range:",
[
[0, 0, 0],
[114, 29, 124],
[220, 69, 86],
[255, 178, 38],
[30, 98, 189]
],
GROUP_IDS.DESIGN
);
const iconMapAPIURL =
"https://service.civicpdx.org/disaster-resilience/sandbox/slides/poi/";
const fetchAPIURL = text("API URL:", iconMapAPIURL, GROUP_IDS.DATA);
const onLayerClick = info => action("Icon Clicked:")(info);
return (
<DemoJSONLoader urls={[fetchAPIURL]}>
{data => {
const featuresArrayPath = text(
"Features Array Path:",
"slide_data.features",
GROUP_IDS.DATA
);
const featuresData = at(data, featuresArrayPath)[0];
const dataFilterNulls = featuresData
? featuresData.filter(d => d.geometry)
: [];
const iconMapLayer = {
mapType: "IconMap",
id: "storybook-icon-map",
data: dataFilterNulls,
iconSize,
opacity: iconOpacity,
iconAtlas,
iconMapping,
scaleType: {
color: scaleType
},
fieldName: {
color: fieldName
},
dataRange,
colorRange,
onLayerClick
};
return (
<div style={{ height: "100vh" }}>
<BaseMap
initialZoom={10}
updateViewport={false}
civicMapStyle="dark"
useContainerHeight
>
<MultiLayerMap mapLayers={[iconMapLayer]} />
</BaseMap>
</div>
);
}}
</DemoJSONLoader>
);
},
{
notes: notes.iconNotes
}
)
.add(
"Small Polygon Map",
() => {
const polygonOpacity = number(
"Opacity:",
0.7,
opacityOptions,
GROUP_IDS.DESIGN
);
const polygonColor = select(
"Civic Color:",
CIVIC_COLORS,
CIVIC_COLORS.civicGreen,
GROUP_IDS.DESIGN
);
const POLYGON_SCALE_TYPE_COLOR_OPTIONS = {
none: "",
threshold: "threshold",
ordinal: "ordinal"
};
const scaleTypeSelection = options(
"Scale Type:",
POLYGON_SCALE_TYPE_COLOR_OPTIONS,
"",
{
display: "inline-radio"
},
GROUP_IDS.DESIGN
);
const fieldName = text("Field Name:", "acres", GROUP_IDS.DESIGN);
const dataRange = object("Data Range:", [], GROUP_IDS.DESIGN);
const colorRange = object("Color Range:", [], GROUP_IDS.DESIGN);
const smallPolygonMapAPIURL =
"https://service.civicpdx.org/neighborhood-development/api/parks" +
"?format=json&limit=100";
const fetchAPIURL = text(
"API URL:",
smallPolygonMapAPIURL,
GROUP_IDS.DATA
);
const onLayerClick = info => action("Polygon Clicked:")(info);
return (
<DemoJSONLoader urls={[fetchAPIURL]}>
{data => {
const featuresArrayPath = text(
"Features Array Path:",
"results.features",
GROUP_IDS.DATA
);
const featuresData = at(data, featuresArrayPath)[0];
const smallPolygonMapLayer = {
mapType: "SmallPolygonMap",
id: "storybook-small-polygon-map",
data: featuresData,
opacity: polygonOpacity,
civicColor: polygonColor,
scaleType: {
color: scaleTypeSelection
},
fieldName: {
color: fieldName
},
dataRange,
colorRange,
onLayerClick
};
return (
<div style={{ height: "100vh" }}>
<BaseMap
initialZoom={10}
updateViewport={false}
civicMapStyle="dark"
useContainerHeight
>
<MultiLayerMap mapLayers={[smallPolygonMapLayer]} />
</BaseMap>
</div>
);
}}
</DemoJSONLoader>
);
},
{
notes: notes.smallPolygonNotes
}
)
.add(
"Choropleth Map",
() => {
const polygonOpacity = number(
"Opacity:",
0.7,
opacityOptions,
GROUP_IDS.DESIGN
);
const polygonColor = select(
"CIVIC Color:",
CIVIC_COLORS,
CIVIC_COLORS.thermal,
GROUP_IDS.DESIGN
);
const CHOROPLETH_SCALE_TYPE_COLOR_OPTIONS = {
equal: "equal",
threshold: "threshold",
ordinal: "ordinal"
};
const scaleTypeSelection = options(
"Scale Type:",
CHOROPLETH_SCALE_TYPE_COLOR_OPTIONS,
"equal",
{
display: "inline-radio"
},
GROUP_IDS.DESIGN
);
const choroplethMapAPIURL =
"https://service.civicpdx.org/disaster-resilience/api/DisasterNeighborhoodView/" +
"?format=json&limit=102";
const fetchURL = text("API URL:", choroplethMapAPIURL, GROUP_IDS.DATA);
const onLayerClick = info => action("Polygon Clicked:")(info);
return (
<DemoJSONLoader urls={[fetchURL]}>
{data => {
const fieldName = text(
"Field Name:",
"dayoccupants",
GROUP_IDS.DESIGN
);
const dataRange = object("Data Range:", [], GROUP_IDS.DESIGN);
const colorRange = object("Color Range:", [], GROUP_IDS.DESIGN);
const featuresArrayPath = text(
"Features Array Path:",
"results.features",
GROUP_IDS.DATA
);
const featuresData = at(data, featuresArrayPath)[0];
const choroplethMap = {
mapType: "ChoroplethMap",
id: "storybook-choropleth-map",
data: featuresData,
opacity: polygonOpacity,
civicColor: polygonColor,
scaleType: {
color: scaleTypeSelection
},
fieldName: {
color: fieldName
},
dataRange,
colorRange,
onLayerClick
};
return (
<div style={{ height: "100vh" }}>
<BaseMap
initialZoom={9.6}
initialLatitude={45.5401}
updateViewport={false}
civicMapStyle="dark"
useContainerHeight
>
<MultiLayerMap mapLayers={[choroplethMap]} />
</BaseMap>
</div>
);
}}
</DemoJSONLoader>
);
},
{
notes: notes.choroplethNotes
}
);