Skip to content

Commit dc67243

Browse files
committed
Comparison works
1 parent e46439b commit dc67243

1 file changed

Lines changed: 88 additions & 35 deletions

File tree

assets/js/dashboard/stats/graph/main-graph.tsx

Lines changed: 88 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ type MainGraphResponse = {
2626
meta: {
2727
time_labels: string[]
2828
time_label_result_indices: (number | null)[]
29-
comparison_time_labels: string[]
30-
comparison_time_label_result_indices: (number | null)[]
29+
comparison_time_labels?: string[]
30+
comparison_time_label_result_indices?: (number | null)[]
3131
}
3232
query: {
3333
interval: string
@@ -47,7 +47,7 @@ type GraphDatum = {
4747

4848
type XPos = number
4949
type YPos = number
50-
type Point = [XPos, YPos[]]
50+
type Point = [XPos, { yMain: YPos | null; yComparison: YPos | null }]
5151

5252
type MainGraphData = MainGraphResponse & { period: DashboardPeriod }
5353

@@ -59,7 +59,7 @@ export const MainGraph = ({
5959
data: MainGraphData
6060
}) => {
6161
const { mode } = useTheme()
62-
const { primaryGradient } = paletteByTheme[mode]
62+
const { primaryGradient, secondaryGradient } = paletteByTheme[mode]
6363
const svgRef = useRef<SVGSVGElement | null>(null)
6464

6565
useEffect(() => {
@@ -101,12 +101,11 @@ export const MainGraph = ({
101101

102102
const points: Point[] = remappedData.map((d, index) => [
103103
x(index),
104-
[
105-
[d.timeLabel, d.value] as const,
106-
[d.comparisonTimeLabel, d.comparisonValue] as const
107-
]
108-
.filter(([label, _v]) => label !== null)
109-
.map(([_label, v]) => y(v!))
104+
{
105+
yMain: d.timeLabel !== null ? y(d.value!) : null,
106+
yComparison:
107+
d.comparisonTimeLabel !== null ? y(d.comparisonValue!) : null
108+
}
110109
])
111110

112111
// Create the SVG container.
@@ -173,8 +172,15 @@ export const MainGraph = ({
173172
.attr('class', tickLineClass)
174173
)
175174

176-
const addGradient = (): string => {
177-
const id = 'areaGradient'
175+
const addGradient = ({
176+
id,
177+
stopTop,
178+
stopBottom
179+
}: {
180+
id: string
181+
stopTop: [string, number]
182+
stopBottom: [string, number]
183+
}): string => {
178184
const grad = svg
179185
.append('defs')
180186
.append('linearGradient')
@@ -187,14 +193,14 @@ export const MainGraph = ({
187193
grad
188194
.append('stop')
189195
.attr('offset', '0%')
190-
.attr('stop-color', primaryGradient[0][0])
191-
.attr('stop-opacity', primaryGradient[0][1])
196+
.attr('stop-color', stopTop[0])
197+
.attr('stop-opacity', stopTop[1])
192198

193199
grad
194200
.append('stop')
195201
.attr('offset', '100%')
196-
.attr('stop-color', primaryGradient[1][0])
197-
.attr('stop-opacity', primaryGradient[1][1])
202+
.attr('stop-color', stopBottom[0])
203+
.attr('stop-opacity', stopBottom[1])
198204
return id
199205
}
200206

@@ -221,7 +227,8 @@ export const MainGraph = ({
221227
const drawLine = (
222228
dataset: GraphDatum[],
223229
isDefined: (d: GraphDatum) => boolean,
224-
yAccessor: (d: GraphDatum, index: number) => number
230+
yAccessor: (d: GraphDatum, index: number) => number,
231+
className?: string
225232
) => {
226233
const line = d3
227234
.line<GraphDatum>()
@@ -232,32 +239,58 @@ export const MainGraph = ({
232239
svg
233240
.append('path')
234241
.attr('fill', 'none')
235-
.attr('class', pathClass)
242+
.attr('class', classNames(sharedPathClass, className))
236243
.attr('stroke-linejoin', 'round')
237244
.attr('stroke-linecap', 'round')
238245
.datum(dataset)
239246
.attr('d', line)
240247
}
241248

242-
const drawDot = () => {
249+
const drawDot = (className: string) => {
243250
const dot = svg.append('g').attr('display', 'none')
244-
dot.append('circle').attr('r', 2.5).attr('class', dotClass)
251+
dot.append('circle').attr('r', 2.5).attr('class', className)
245252
return dot
246253
}
247254

248-
const gradientId = addGradient()
255+
const mainGradientId = addGradient({
256+
id: 'main',
257+
stopTop: primaryGradient[0],
258+
stopBottom: primaryGradient[1]
259+
})
260+
const comparisonGradientId = addGradient({
261+
id: 'comparisonGradient',
262+
stopTop: secondaryGradient[0],
263+
stopBottom: secondaryGradient[1]
264+
})
265+
266+
paintUnderLine(
267+
mainGradientId,
268+
(d) => d.timeLabel !== null,
269+
(d) => y(d.value!)
270+
)
271+
249272
paintUnderLine(
250-
gradientId,
251-
({ timeLabel }) => timeLabel !== null,
252-
({ value }) => y(value!)
273+
comparisonGradientId,
274+
(d) => d.comparisonTimeLabel !== null,
275+
(d) => y(d.comparisonValue!)
253276
)
277+
254278
drawLine(
255279
remappedData,
256280
(d) => d.timeLabel !== null,
257-
(d) => y(d.value!)
281+
(d) => y(d.value!),
282+
mainPathClass
258283
)
259-
260-
const dot = drawDot()
284+
285+
drawLine(
286+
remappedData,
287+
(d) => d.comparisonTimeLabel !== null,
288+
(d) => y(d.comparisonValue!),
289+
comparisonPathClass
290+
)
291+
292+
const dot = drawDot(mainDotClass)
293+
const comparisonDot = drawDot(comparisonDotClass)
261294

262295
svg
263296
.on('pointermove', (event) => {
@@ -266,12 +299,24 @@ export const MainGraph = ({
266299
.bisector((dataPoint: Point) => dataPoint[0])
267300
.center(points, xPointer)
268301
const [x, yValues] = points[closestIndexToPointer]
269-
dot
270-
.attr('transform', `translate(${x},${yValues[0]})`)
271-
.attr('display', null)
302+
if (yValues.yMain) {
303+
dot
304+
.attr('transform', `translate(${x},${yValues.yMain})`)
305+
.attr('display', null)
306+
} else {
307+
dot.attr('display', 'none')
308+
}
309+
if (yValues.yComparison) {
310+
comparisonDot
311+
.attr('transform', `translate(${x},${yValues.yComparison})`)
312+
.attr('display', null)
313+
} else {
314+
comparisonDot.attr('display', 'none')
315+
}
272316
})
273317
.on('pointerleave', () => {
274318
dot.attr('display', 'none')
319+
comparisonDot.attr('display', 'none')
275320
})
276321
.on('touchstart', (event) => event.preventDefault())
277322

@@ -391,9 +436,13 @@ const remapToGraphData = (
391436
// where to get the main result - the main graph is defined only
392437
data.meta.time_label_result_indices[index] ?? null,
393438
// comparison label
394-
data.meta.comparison_time_labels[index] ?? null,
439+
(data.meta.comparison_time_labels &&
440+
data.meta.comparison_time_labels[index]) ??
441+
null,
395442
// where to get the comparison result - the comparison graph is defined only where not null
396-
data.meta.comparison_time_label_result_indices[index] ?? null
443+
(data.meta.comparison_time_label_result_indices &&
444+
data.meta.comparison_time_label_result_indices[index]) ??
445+
null
397446
]
398447

399448
const mainResultDefined = typeof timeLabel === 'string'
@@ -493,7 +542,11 @@ const paletteByTheme = {
493542
const tickLineClass =
494543
'stroke-gray-150 dark:stroke-gray-800/75 group-first:stroke-gray-300 dark:group-first:stroke-gray-700'
495544
const tickClass = 'fill-gray-500 dark:fill-gray-400 text-xs'
496-
// const dotClass = 'fill-[#6366f1]' // custom color like indigo-400
497-
const dotClass = 'fill-indigo-400'
545+
546+
const mainDotClass = 'fill-indigo-500 dark:fill-indigo-400'
547+
const comparisonDotClass = 'fill-indigo-500/20 dark:fill-indigo-400/20'
548+
498549
// const pathClass = 'stroke-[#6366f1] stroke-2 z-1' // custom color like indigo-400
499-
const pathClass = 'stroke-indigo-500 dark:stroke-indigo-400 stroke-2 z-1'
550+
const sharedPathClass = 'stroke-2'
551+
const mainPathClass = 'stroke-indigo-500 dark:stroke-indigo-400 z-2'
552+
const comparisonPathClass = 'stroke-indigo-500/20 dark:stroke-indigo-400/20 z-1'

0 commit comments

Comments
 (0)