d3-scale#scaleSequential JavaScript Examples
The following examples show how to use
d3-scale#scaleSequential.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: rampClosed.js From cs-wiki with GNU General Public License v3.0 | 5 votes |
export default function(range) {
var s = scaleSequential(interpolateRgbBasisClosed(colors(range))).clamp(true);
delete s.clamp;
return s;
}
Example #2
Source File: MapVisualizer.js From covid19india-react with MIT License | 4 votes |
function MapVisualizer({ mapCode, isDistrictView, mapViz, data, regionHighlighted, setRegionHighlighted, statistic, getMapStatistic, transformStatistic, noDistrictData, }) { const {t} = useTranslation(); const svgRef = useRef(null); const mapMeta = MAP_META[mapCode]; const history = useHistory(); const {data: geoData} = useSWR( mapMeta.geoDataFile, async (file) => { return await json(file); }, {suspense: false, revalidateOnFocus: false} ); const statisticTotal = useMemo(() => { return getMapStatistic(data[mapCode]); }, [data, mapCode, getMapStatistic]); const statisticConfig = STATISTIC_CONFIGS[statistic]; const strokeColor = useCallback( (alpha) => (statisticConfig?.color || '#343a40') + alpha, [statisticConfig] ); const features = useMemo(() => { if (!geoData) return null; const featuresWrap = !isDistrictView ? feature(geoData, geoData.objects.states).features : mapMeta.mapType === MAP_TYPES.COUNTRY && mapViz !== MAP_VIZS.CHOROPLETH ? [ ...feature(geoData, geoData.objects.states).features, ...feature(geoData, geoData.objects.districts).features, ] : feature(geoData, geoData.objects.districts).features; // Add id to each feature return featuresWrap.map((feature) => { const district = feature.properties.district; const state = feature.properties.st_nm; const obj = Object.assign({}, feature); obj.id = `${mapCode}-${state}${district ? '-' + district : ''}`; return obj; }); }, [geoData, mapCode, isDistrictView, mapViz, mapMeta]); const districtsSet = useMemo(() => { if (!geoData || !isDistrictView) return {}; return feature(geoData, geoData.objects.districts).features.reduce( (stateCodes, feature) => { const stateCode = STATE_CODES[feature.properties.st_nm]; if (!stateCodes[stateCode]) { stateCodes[stateCode] = new Set(); } stateCodes[stateCode].add(feature.properties.district); return stateCodes; }, {} ); }, [geoData, isDistrictView]); const statisticMax = useMemo(() => { const stateCodes = Object.keys(data).filter( (stateCode) => stateCode !== 'TT' && Object.keys(MAP_META).includes(stateCode) ); if (!isDistrictView) { return max(stateCodes, (stateCode) => transformStatistic(getMapStatistic(data[stateCode])) ); } else { const districtData = stateCodes.reduce((res, stateCode) => { const districts = Object.keys(data[stateCode]?.districts || []).filter( (districtName) => (districtsSet?.[stateCode] || new Set()).has(districtName) || (mapViz !== MAP_VIZS.CHOROPLETH && districtName === UNKNOWN_DISTRICT_KEY) ); res.push( ...districts.map((districtName) => transformStatistic( getMapStatistic(data[stateCode].districts[districtName]) ) ) ); return res; }, []); return max(districtData); } }, [ data, isDistrictView, getMapStatistic, mapViz, districtsSet, transformStatistic, ]); const mapScale = useMemo(() => { if (mapViz === MAP_VIZS.BUBBLE) { // No negative values return scaleSqrt([0, Math.max(1, statisticMax || 0)], [0, 40]) .clamp(true) .nice(3); } else if (mapViz === MAP_VIZS.SPIKE) { return scaleLinear([0, Math.max(1, statisticMax || 0)], [0, 80]) .clamp(true) .nice(3); } else if (STATISTIC_CONFIGS[statistic]?.mapConfig?.colorScale) { return STATISTIC_CONFIGS[statistic].mapConfig.colorScale; } else { // No negative values return scaleSequential( [0, Math.max(1, statisticMax || 0)], colorInterpolator(statistic) ).clamp(true); } }, [mapViz, statistic, statisticMax]); const fillColor = useCallback( (d) => { if (mapViz === MAP_VIZS.CHOROPLETH) { const stateCode = STATE_CODES[d.properties.st_nm]; const district = d.properties.district; const stateData = data[stateCode]; const districtData = stateData?.districts?.[district]; const n = transformStatistic( getMapStatistic(district ? districtData : stateData) ); const color = n ? mapScale(n) : '#ffffff00'; return color; } }, [mapViz, data, mapScale, getMapStatistic, transformStatistic] ); const populateTexts = useCallback( (regionSelection) => { regionSelection.select('title').text((d) => { if (mapViz !== MAP_VIZS.CHOROPLETH && !statisticConfig?.nonLinear) { const state = d.properties.st_nm; const stateCode = STATE_CODES[state]; const district = d.properties.district; const stateData = data[stateCode]; const districtData = stateData?.districts?.[district]; let n; if (district) n = getMapStatistic(districtData); else n = getMapStatistic(stateData); return `${formatNumber( 100 * (n / (statisticTotal || 0.001)), '%' )} from ${toTitleCase(district ? district : state)}`; } }); }, [mapViz, data, getMapStatistic, statisticTotal, statisticConfig] ); const onceTouchedRegion = useRef(null); // Reset on tapping outside map useEffect(() => { const svg = select(svgRef.current); svg.attr('pointer-events', 'auto').on('click', () => { onceTouchedRegion.current = null; setRegionHighlighted({ stateCode: mapCode, districtName: null, }); }); }, [mapCode, setRegionHighlighted]); const path = useMemo(() => { if (!geoData) return null; return geoPath(geoIdentity()); }, [geoData]); // Choropleth useEffect(() => { if (!geoData) return; const svg = select(svgRef.current); const T = transition().duration(D3_TRANSITION_DURATION); svg .select('.regions') .selectAll('path') .data(mapViz === MAP_VIZS.CHOROPLETH ? features : [], (d) => d.id) .join( (enter) => enter .append('path') .attr('d', path) .attr('stroke-width', 1.8) .attr('stroke-opacity', 0) .style('cursor', 'pointer') .on('mouseenter', (event, d) => { if (onceTouchedRegion.current) return; setRegionHighlighted({ stateCode: STATE_CODES[d.properties.st_nm], districtName: d.properties.district, }); }) .on('pointerdown', (event, d) => { if (onceTouchedRegion.current === d) onceTouchedRegion.current = null; else onceTouchedRegion.current = d; setRegionHighlighted({ stateCode: STATE_CODES[d.properties.st_nm], districtName: d.properties.district, }); }) .attr('fill', '#fff0') .attr('stroke', '#fff0'), (update) => update, (exit) => exit .transition(T) .attr('stroke', '#fff0') .attr('fill', '#fff0') .remove() ) .attr('pointer-events', 'all') .on('click', (event, d) => { event.stopPropagation(); const stateCode = STATE_CODES[d.properties.st_nm]; if ( onceTouchedRegion.current || mapMeta.mapType === MAP_TYPES.STATE || !data[stateCode]?.districts ) return; // Disable pointer events till the new map is rendered svg.attr('pointer-events', 'none'); svg.select('.regions').selectAll('path').attr('pointer-events', 'none'); // Switch map history.push( `/state/${stateCode}${window.innerWidth < 769 ? '#MapExplorer' : ''}` ); }) .call((sel) => { sel .transition(T) .attr('fill', fillColor) .attr('stroke', strokeColor.bind(this, '')); }); }, [ mapViz, data, features, fillColor, geoData, history, mapMeta.mapType, path, setRegionHighlighted, strokeColor, ]); const sortedFeatures = useMemo(() => { if (mapViz === MAP_VIZS.CHOROPLETH) { return []; } else { return (features || []) .map((feature) => { const stateCode = STATE_CODES[feature.properties.st_nm]; const districtName = feature.properties.district; const stateData = data[stateCode]; if (!isDistrictView) { feature.value = getMapStatistic(stateData); } else { const districtData = stateData?.districts?.[districtName]; if (districtName) feature.value = getMapStatistic(districtData); else feature.value = getMapStatistic( stateData?.districts?.[UNKNOWN_DISTRICT_KEY] ); } return feature; }) .filter((feature) => feature.value > 0) .sort((featureA, featureB) => featureB.value - featureB.value); } }, [mapViz, isDistrictView, getMapStatistic, features, data]); // Bubble useEffect(() => { const svg = select(svgRef.current); const T = transition().duration(D3_TRANSITION_DURATION); const regionSelection = svg .select('.circles') .selectAll('circle') .data( mapViz === MAP_VIZS.BUBBLE ? sortedFeatures : [], (feature) => feature.id ) .join( (enter) => enter .append('circle') .attr( 'transform', (feature) => `translate(${path.centroid(feature)})` ) .attr('fill-opacity', 0.25) .style('cursor', 'pointer') .attr('pointer-events', 'all') .call((enter) => { enter.append('title'); }), (update) => update, (exit) => exit.call((exit) => exit.transition(T).attr('r', 0).remove()) ) .on('mouseenter', (event, feature) => { if (onceTouchedRegion.current) return; setRegionHighlighted({ stateCode: STATE_CODES[feature.properties.st_nm], districtName: !isDistrictView ? null : feature.properties.district || UNKNOWN_DISTRICT_KEY, }); }) .on('pointerdown', (event, feature) => { if (onceTouchedRegion.current === feature) onceTouchedRegion.current = null; else onceTouchedRegion.current = feature; setRegionHighlighted({ stateCode: STATE_CODES[feature.properties.st_nm], districtName: !isDistrictView ? null : feature.properties.district || UNKNOWN_DISTRICT_KEY, }); }) .on('click', (event, feature) => { event.stopPropagation(); if (onceTouchedRegion.current || mapMeta.mapType === MAP_TYPES.STATE) return; history.push( `/state/${STATE_CODES[feature.properties.st_nm]}${ window.innerWidth < 769 ? '#MapExplorer' : '' }` ); }) .call((sel) => { sel .transition(T) .attr('fill', statisticConfig.color + '70') .attr('stroke', statisticConfig.color + '70') .attr('r', (feature) => mapScale(feature.value)); }); window.requestIdleCallback(() => { populateTexts(regionSelection); }); }, [ mapMeta.mapType, mapViz, isDistrictView, sortedFeatures, history, mapScale, path, setRegionHighlighted, populateTexts, statisticConfig, getMapStatistic, ]); // Spike (Note: bad unmodular code) useEffect(() => { const svg = select(svgRef.current); const T = transition().duration(D3_TRANSITION_DURATION); const regionSelection = svg .select('.spikes') .selectAll('path') .data( mapViz === MAP_VIZS.SPIKE ? sortedFeatures : [], (feature) => feature.id, (feature) => feature.id ) .join( (enter) => enter .append('path') .attr( 'transform', (feature) => `translate(${path.centroid(feature)})` ) .attr('opacity', 0) .attr('fill-opacity', 0.25) .style('cursor', 'pointer') .attr('pointer-events', 'all') .attr('d', spike(0)) .call((enter) => { enter.append('title'); }), (update) => update, (exit) => exit.call((exit) => exit.transition(T).attr('opacity', 0).attr('d', spike(0)).remove() ) ) .on('mouseenter', (event, feature) => { if (onceTouchedRegion.current) return; setRegionHighlighted({ stateCode: STATE_CODES[feature.properties.st_nm], districtName: !isDistrictView ? null : feature.properties.district || UNKNOWN_DISTRICT_KEY, }); }) .on('pointerdown', (event, feature) => { if (onceTouchedRegion.current === feature) onceTouchedRegion.current = null; else onceTouchedRegion.current = feature; setRegionHighlighted({ stateCode: STATE_CODES[feature.properties.st_nm], districtName: !isDistrictView ? null : feature.properties.district || UNKNOWN_DISTRICT_KEY, }); }) .on('click', (event, feature) => { event.stopPropagation(); if (onceTouchedRegion.current || mapMeta.mapType === MAP_TYPES.STATE) return; history.push( `/state/${STATE_CODES[feature.properties.st_nm]}${ window.innerWidth < 769 ? '#MapExplorer' : '' }` ); }) .call((sel) => { sel .transition(T) .attr('opacity', 1) .attr('fill', statisticConfig.color + '70') .attr('stroke', statisticConfig.color + '70') .attr('d', (feature) => spike(mapScale(feature.value))); }); window.requestIdleCallback(() => { populateTexts(regionSelection); }); }, [ mapMeta.mapType, mapViz, isDistrictView, sortedFeatures, history, mapScale, path, setRegionHighlighted, populateTexts, statisticConfig, getMapStatistic, ]); // Boundaries useEffect(() => { if (!geoData) return; const svg = select(svgRef.current); const T = transition().duration(D3_TRANSITION_DURATION); let meshStates = []; let meshDistricts = []; if (mapMeta.mapType === MAP_TYPES.COUNTRY) { meshStates = [mesh(geoData, geoData.objects.states)]; meshStates[0].id = `${mapCode}-states`; } if ( mapMeta.mapType === MAP_TYPES.STATE || (isDistrictView && mapViz === MAP_VIZS.CHOROPLETH) ) { // Add id to mesh meshDistricts = [mesh(geoData, geoData.objects.districts)]; meshDistricts[0].id = `${mapCode}-districts`; } svg .select('.state-borders') .attr('fill', 'none') .attr('stroke-width', 1.5) .selectAll('path') .data(meshStates, (d) => d.id) .join( (enter) => enter.append('path').attr('d', path).attr('stroke', '#fff0'), (update) => update, (exit) => exit.transition(T).attr('stroke', '#fff0').remove() ) .transition(T) .attr('stroke', strokeColor.bind(this, '40')); svg .select('.district-borders') .attr('fill', 'none') .attr('stroke-width', 1.5) .selectAll('path') .data(meshDistricts, (d) => d.id) .join( (enter) => enter .append('path') .attr('d', path) .attr('d', path) .attr('stroke', '#fff0'), (update) => update, (exit) => exit.transition(T).attr('stroke', '#fff0').remove() ) .transition(T) .attr('stroke', strokeColor.bind(this, '40')); }, [ geoData, mapMeta, mapCode, mapViz, isDistrictView, statistic, path, strokeColor, ]); // Highlight useEffect(() => { const stateCode = regionHighlighted.stateCode; const stateName = STATE_NAMES[stateCode]; const district = regionHighlighted.districtName; const svg = select(svgRef.current); if (mapViz === MAP_VIZS.BUBBLE) { svg .select('.circles') .selectAll('circle') .attr('fill-opacity', (d) => { const highlighted = stateName === d.properties.st_nm && ((!district && stateCode !== mapCode) || district === d.properties?.district || !isDistrictView || (district === UNKNOWN_DISTRICT_KEY && !d.properties.district)); return highlighted ? 1 : 0.25; }); } else if (mapViz === MAP_VIZS.SPIKE) { svg .select('.spikes') .selectAll('path') .attr('fill-opacity', (d) => { const highlighted = stateName === d.properties.st_nm && ((!district && stateCode !== mapCode) || district === d.properties?.district || !isDistrictView || (district === UNKNOWN_DISTRICT_KEY && !d.properties.district)); return highlighted ? 1 : 0.25; }); } else { svg .select('.regions') .selectAll('path') .each(function (d) { const highlighted = stateName === d.properties.st_nm && ((!district && stateCode !== mapCode) || district === d.properties?.district || !isDistrictView); if (highlighted) this.parentNode.appendChild(this); select(this).attr('stroke-opacity', highlighted ? 1 : 0); }); } }, [ geoData, data, mapCode, isDistrictView, mapViz, regionHighlighted.stateCode, regionHighlighted.districtName, statistic, ]); return ( <> <div className="svg-parent"> <svg id="chart" className={classnames({ zone: !!statisticConfig?.mapConfig?.colorScale, })} viewBox={`0 0 ${MAP_DIMENSIONS[0]} ${MAP_DIMENSIONS[1]}`} preserveAspectRatio="xMidYMid meet" ref={svgRef} > <g className="regions" /> <g className="state-borders" /> <g className="district-borders" /> <g className="circles" /> <g className="spikes" /> </svg> {noDistrictData && statisticConfig?.hasPrimary && ( <div className={classnames('disclaimer', `is-${statistic}`)}> <AlertIcon /> <span> {t('District-wise data not available in state bulletin')} </span> </div> )} </div> {mapScale && <MapLegend {...{data, statistic, mapViz, mapScale}} />} <svg style={{position: 'absolute', height: 0}}> <defs> <filter id="balance-color" colorInterpolationFilters="sRGB"> <feColorMatrix type="matrix" values="0.91372549 0 0 0 0.08627451 0 0.91372549 0 0 0.08627451 0 0 0.854901961 0 0.145098039 0 0 0 1 0" /> </filter> </defs> </svg> </> ); }