Skip to content

Commit 5e7f31c

Browse files
authored
Merge pull request #1651 from freedomofpress/switch-react-animated-dataset
Use nested react-animated-dataset
2 parents 1721ff3 + 16b816c commit 5e7f31c

7 files changed

Lines changed: 341 additions & 287 deletions

File tree

client/charts/js/components/BarChart.jsx

Lines changed: 61 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default function BarChart({
4949
id = '',
5050
numberOfTicks = 4,
5151
description,
52-
openSearchPage,
52+
searchPageURL = () => {},
5353
// function prop received from ChartDownloader that binds the svg element to allow
5454
// it to be downloaded
5555
setSvgEl = () => {},
@@ -216,25 +216,30 @@ export default function BarChart({
216216
/>
217217
{dataset.map((d) => (
218218
<g key={d[x]}>
219-
<rect
220-
x={xScaleOverLayer(d[x])}
221-
y={yScale(d[y])}
222-
height={computeBarheight(d[y])}
223-
width={xScaleOverLayer.bandwidth()}
224-
style={{
225-
opacity: 0,
226-
cursor: 'pointer',
227-
}}
228-
onMouseEnter={() => setHoveredElement((tooltipXFormat || xFormat)(d[x]))}
229-
onMouseMove={updateTooltipPosition}
230-
onMouseLeave={() => setHoveredElement(null)}
231-
onMouseUp={() => openSearchPage(xFormat(d[x]))}
232-
shapeRendering="crispEdges"
219+
<a
220+
href={searchPageURL(xFormat(d[x]))}
221+
role="link"
222+
aria-label={`${xFormat(d[x])}: ${yFormat(d[y])} ${titleLabel}`}
233223
>
234-
<title>
235-
{xFormat(d[x])}: {yFormat(d[y])} {titleLabel}
236-
</title>
237-
</rect>
224+
<rect
225+
x={xScaleOverLayer(d[x])}
226+
y={yScale(d[y])}
227+
height={computeBarheight(d[y])}
228+
width={xScaleOverLayer.bandwidth()}
229+
style={{
230+
opacity: 0,
231+
cursor: 'pointer',
232+
}}
233+
onMouseEnter={() => setHoveredElement((tooltipXFormat || xFormat)(d[x]))}
234+
onMouseMove={updateTooltipPosition}
235+
onMouseLeave={() => setHoveredElement(null)}
236+
shapeRendering="crispEdges"
237+
>
238+
<title>
239+
{xFormat(d[x])}: {yFormat(d[y])} {titleLabel}
240+
</title>
241+
</rect>
242+
</a>
238243
</g>
239244
))}
240245
<AnimatedDataset
@@ -319,25 +324,45 @@ export default function BarChart({
319324
</g>
320325
<AnimatedDataset
321326
dataset={dataset}
322-
tag="rect"
327+
tag="a"
323328
attrs={{
324-
x: (d) => xScale(d[x]),
325-
y: (d) => yScale(d[y]),
326-
height: (d) => computeBarheight(d[y]),
327-
width: xScale.bandwidth(),
328-
fill: (d) =>
329-
sliderSelection === d[x] ? '#E07A5F' : sliderSelection === null ? '#E07A5F' : 'white',
330-
strokeWidth: borders.normal,
331-
stroke: (d) => (sliderSelection === d[x] ? '#E07A5F' : 'black'),
332-
cursor: 'pointer',
333-
shapeRendering: 'crispEdges',
334-
}}
335-
events={{
336-
onMouseUp: (mouseEvent, d) => openSearchPage(d[x]),
329+
href: d => searchPageURL(d[x]),
330+
role: "link",
331+
ariaLabel: d => `${xFormat(d[x])}: ${yFormat(d[y])} ${titleLabel}`,
337332
}}
338-
duration={250}
339333
keyFn={(d) => d.index}
340-
/>
334+
>
335+
<AnimatedDataset
336+
tag="rect"
337+
attrs={{
338+
x: (d) => xScale(d[x]),
339+
y: (d) => yScale(d[y]),
340+
height: (d) => computeBarheight(d[y]),
341+
width: xScale.bandwidth(),
342+
fill: (d) =>
343+
sliderSelection === d[x] ? '#E07A5F' : sliderSelection === null ? '#E07A5F' : 'white',
344+
strokeWidth: borders.normal,
345+
stroke: (d) => (sliderSelection === d[x] ? '#E07A5F' : 'black'),
346+
cursor: 'pointer',
347+
shapeRendering: 'crispEdges',
348+
}}
349+
duration={250}
350+
keyFn={(d) => d.index}
351+
/>
352+
<text
353+
x={width / 2}
354+
y={height - paddings.mobile / 2 - 7}
355+
textAnchor="middle"
356+
style={{
357+
fill: 'black',
358+
fontFamily: 'var(--font-base)',
359+
fontWeight: 500,
360+
fontSize: '14px',
361+
}}
362+
>
363+
{`${sliderSelection}: ${incidentsCount} ${titleLabel}`}
364+
</text>
365+
</AnimatedDataset>
341366
<Slider
342367
elements={dataset.map((d) => d[x])}
343368
xScale={xSlider}
@@ -346,20 +371,6 @@ export default function BarChart({
346371
sliderSelection={sliderSelection}
347372
idContainer={'barchart-svg'}
348373
/>
349-
350-
<text
351-
x={width / 2}
352-
y={height - paddings.mobile / 2 - 7}
353-
textAnchor="middle"
354-
style={{
355-
fill: 'black',
356-
fontFamily: 'var(--font-base)',
357-
fontWeight: 500,
358-
fontSize: '14px',
359-
}}
360-
>
361-
{`${sliderSelection}: ${incidentsCount} ${titleLabel}`}
362-
</text>
363374
</svg>
364375
)
365376
}
@@ -374,5 +385,5 @@ BarChart.propTypes = {
374385
width: PropTypes.number.isRequired,
375386
height: PropTypes.number.isRequired,
376387
numberOfTicks: PropTypes.number,
377-
openSearchPage: PropTypes.func,
388+
searchPageURL: PropTypes.func,
378389
}

client/charts/js/components/HomepageMainCharts.jsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import {
1010
filterDatasetByFiltersApplied,
1111
groupByMonthSorted,
1212
groupByState,
13-
goToFilterPage,
1413
countIncidentsOutsideUS,
1514
categoriesColors,
15+
getFilteredUrl,
1616
} from '../lib/utilities.js'
1717

1818
import '../../sass/HomepageMainCharts.sass'
@@ -87,9 +87,9 @@ function HomepageMainChartsWidth({
8787
minimumBarHeight={35}
8888
categoryColumn={'categories'}
8989
titleLabel={'incidents'}
90-
openSearchPage={(category) => {
91-
goToFilterPage(databasePath, { category }, currentDate, categories)
92-
}}
90+
searchPageURL={(category) =>
91+
getFilteredUrl(databasePath, { category }, currentDate, categories)
92+
}
9393
categoriesColors={categoriesColorMap}
9494
allCategories={Object.keys(categoriesColorMap)}
9595
/>
@@ -104,9 +104,9 @@ function HomepageMainChartsWidth({
104104
width={chartWidth}
105105
height={chartHeight}
106106
id={'homepage-usmap-chart-label'}
107-
openSearchPage={(state) => {
108-
goToFilterPage(databasePath, { ...filtersApplied, state }, currentDate, categories)
109-
}}
107+
searchPageURL={(state) =>
108+
getFilteredUrl(databasePath, { ...filtersApplied, state }, currentDate, categories)
109+
}
110110
addBottomBorder={true}
111111
/>
112112
</div>
@@ -121,9 +121,9 @@ function HomepageMainChartsWidth({
121121
width={chartWidth}
122122
height={chartHeight}
123123
isMobileView={width < 970}
124-
openSearchPage={(monthName) => {
125-
goToFilterPage(databasePath, { ...filtersApplied, monthName }, currentDate, categories)
126-
}}
124+
searchPageURL={(monthName) =>
125+
getFilteredUrl(databasePath, { ...filtersApplied, monthName }, currentDate, categories)
126+
}
127127
/>
128128
</div>
129129
</div>

client/charts/js/components/TreeMap.jsx

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export default function TreeMap({
132132
height,
133133
isHomePageDesktopView,
134134
minimumBarHeight,
135-
openSearchPage = () => {},
135+
searchPageURL,
136136
categoriesColors,
137137
allCategories,
138138
// function prop received from ChartDownloader that binds the svg element to allow
@@ -289,51 +289,60 @@ export default function TreeMap({
289289
/>
290290
<AnimatedDataset
291291
dataset={datasetStackedByCategory}
292-
tag="rect"
293-
init={{
294-
opacity: 0,
295-
[chartWidthDimension]: chartWidthPaddingBefore,
296-
[chartLengthDimension]: isMobile ? chartLength - chartLengthPaddingAfter : 0,
297-
[chartWidthTitle]: chartWidth - (chartWidthPaddingBefore + chartWidthPaddingAfter),
298-
[chartLengthTitle]: 0,
299-
}}
292+
tag="a"
300293
attrs={{
301-
opacity: 1,
302-
[chartWidthDimension]: chartWidthPaddingBefore,
303-
[chartLengthDimension]: (d) => chartLength - lengthScale(d.startingPoint),
304-
[chartWidthTitle]: chartWidth - (chartWidthPaddingBefore + chartWidthPaddingAfter),
305-
[chartLengthTitle]: (d) => computeBarHeight(d.startingPoint, d.endPoint),
306-
fill: (d) =>
307-
hoveredElement === d.category || hoveredElement === null
308-
? d.numberOfIncidents === 0
309-
? 'white'
310-
: findColor(d.category)
311-
: 'white',
312-
stroke: (d) => (hoveredElement === d.category ? findColor(d.category) : 'black'),
313-
strokeWidth: isHomePageDesktopView ? borderWidth.normal : borderWidth.mobile,
314-
cursor: 'pointer',
315-
pointerEvents: (d) => (d.numberOfIncidents === 0 ? 'none' : null),
316-
shapeRendering: 'crispEdges',
294+
href: d => searchPageURL(d.category),
295+
role: "link",
296+
ariaLabel: d => d.category,
317297
}}
318-
events={{
319-
// In a future, if we update our version of d3-selection the first
320-
// argument will be a MouseEvent, eliminating the need for d3event here
321-
onMouseMove: () => {
322-
updateTooltipPosition(d3event)
323-
},
324-
onMouseLeave: () => {
325-
setTooltipPosition({ x: 0, y: 0 })
326-
setHoveredElement(null)
327-
},
328-
// In a future, if we update our version of d3-selection this may
329-
// need to be updated to take arguments (MouseEvent, d) instead
330-
onMouseEnter: d => setHoveredElement(d.category),
331-
onMouseUp: d => openSearchPage(d.category),
332-
}}
333-
durationByAttr={{ fill: 0, stroke: 0 }}
334298
keyFn={(d) => d.category}
335-
duration={250}
336-
/>
299+
>
300+
<AnimatedDataset
301+
tag="rect"
302+
init={{
303+
opacity: 0,
304+
[chartWidthDimension]: chartWidthPaddingBefore,
305+
[chartLengthDimension]: isMobile ? chartLength - chartLengthPaddingAfter : 0,
306+
[chartWidthTitle]: chartWidth - (chartWidthPaddingBefore + chartWidthPaddingAfter),
307+
[chartLengthTitle]: 0,
308+
}}
309+
attrs={{
310+
opacity: 1,
311+
[chartWidthDimension]: chartWidthPaddingBefore,
312+
[chartLengthDimension]: (d) => chartLength - lengthScale(d.startingPoint),
313+
[chartWidthTitle]: chartWidth - (chartWidthPaddingBefore + chartWidthPaddingAfter),
314+
[chartLengthTitle]: (d) => computeBarHeight(d.startingPoint, d.endPoint),
315+
fill: (d) =>
316+
hoveredElement === d.category || hoveredElement === null
317+
? d.numberOfIncidents === 0
318+
? 'white'
319+
: findColor(d.category)
320+
: 'white',
321+
stroke: (d) => (hoveredElement === d.category ? findColor(d.category) : 'black'),
322+
strokeWidth: isHomePageDesktopView ? borderWidth.normal : borderWidth.mobile,
323+
cursor: 'pointer',
324+
pointerEvents: (d) => (d.numberOfIncidents === 0 ? 'none' : null),
325+
shapeRendering: 'crispEdges',
326+
}}
327+
events={{
328+
// In a future, if we update our version of d3-selection the first
329+
// argument will be a MouseEvent, eliminating the need for d3event here
330+
onMouseMove: () => {
331+
updateTooltipPosition(d3event)
332+
},
333+
onMouseLeave: () => {
334+
setTooltipPosition({ x: 0, y: 0 })
335+
setHoveredElement(null)
336+
},
337+
// In a future, if we update our version of d3-selection this may
338+
// need to be updated to take arguments (MouseEvent, d) instead
339+
onMouseEnter: d => setHoveredElement(d.category),
340+
}}
341+
durationByAttr={{ fill: 0, stroke: 0 }}
342+
keyFn={(d) => d.category}
343+
duration={250}
344+
/>
345+
</AnimatedDataset>
337346
<AnimatedDataset
338347
dataset={datasetStackedByCategory}
339348
tag="line"

0 commit comments

Comments
 (0)