Skip to content

Commit 8017f50

Browse files
committed
Extract some plotting functions
1 parent 2d27729 commit 8017f50

1 file changed

Lines changed: 85 additions & 56 deletions

File tree

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

Lines changed: 85 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,16 @@ const marginRight = 4
1717
const marginBottom = 32
1818
const marginLeft = 32
1919

20+
type RevenueMetric = {
21+
short: string
22+
value: number
23+
long: string
24+
currency: string
25+
}
26+
2027
type ResultItem = {
2128
dimensions: [string] // one item
22-
metrics: null | [number] | [{ value: number }] // one item
29+
metrics: null | [number] | [RevenueMetric] // one item
2330
}
2431
type MainGraphResponse = {
2532
results: Array<ResultItem | null>
@@ -168,59 +175,8 @@ export const MainGraph = ({
168175
.attr('class', tickLineClass)
169176
)
170177

171-
const addGradient = ({
172-
id,
173-
stopTop,
174-
stopBottom
175-
}: {
176-
id: string
177-
stopTop: { color: string; opacity: number }
178-
stopBottom: { color: string; opacity: number }
179-
}): string => {
180-
const grad = svg
181-
.append('defs')
182-
.append('linearGradient')
183-
.attr('id', id)
184-
.attr('x1', '0%')
185-
.attr('y1', '0%') // top
186-
.attr('x2', '0%')
187-
.attr('y2', `100%`) // bottom
188-
189-
grad
190-
.append('stop')
191-
.attr('offset', '0%')
192-
.attr('stop-color', stopTop.color)
193-
.attr('stop-opacity', stopTop.opacity)
194-
195-
grad
196-
.append('stop')
197-
.attr('offset', '100%')
198-
.attr('stop-color', stopBottom.color)
199-
.attr('stop-opacity', stopBottom.opacity)
200-
return id
201-
}
202-
203-
const paintUnderLine = (
204-
gradientId: string,
205-
isDefined: (d: GraphDatum) => boolean,
206-
y1Accessor: (d: GraphDatum, index: number) => number
207-
) => {
208-
const area = d3
209-
.area<GraphDatum>()
210-
.x((_d, index) => x(index))
211-
.defined(isDefined)
212-
.y0(height - marginBottom) // bottom edge
213-
.y1(y1Accessor) // top edge follows the data
214-
215-
// draw the filled area with the gradient
216-
svg
217-
.append('path')
218-
.datum(remappedData)
219-
.attr('fill', `url(#${gradientId})`)
220-
.attr('d', area)
221-
}
222-
223178
const drawLine = (
179+
svg: SelectedSVG,
224180
dataset: GraphDatum[],
225181
isDefined: (d: GraphDatum) => boolean,
226182
yAccessor: (d: GraphDatum, index: number) => number,
@@ -249,36 +205,50 @@ export const MainGraph = ({
249205
}
250206

251207
const mainGradientId = addGradient({
208+
svg,
252209
id: 'main',
253210
stopTop: primaryGradient.stopTop,
254211
stopBottom: primaryGradient.stopBottom
255212
})
256213
const comparisonGradientId = addGradient({
214+
svg,
257215
id: 'comparisonGradient',
258216
stopTop: secondaryGradient.stopTop,
259217
stopBottom: secondaryGradient.stopBottom
260218
})
261219

220+
const yBottomEdge = height - marginBottom
221+
262222
paintUnderLine(
223+
svg,
263224
mainGradientId,
264225
(d) => d.timeLabel !== null,
265-
(d) => y(d.value!)
226+
(_d, index) => x(index),
227+
yBottomEdge,
228+
(d) => y(d.value!),
229+
remappedData
266230
)
267231

268232
paintUnderLine(
233+
svg,
269234
comparisonGradientId,
270235
(d) => d.comparisonTimeLabel !== null,
271-
(d) => y(d.comparisonValue!)
236+
(_d, index) => x(index),
237+
yBottomEdge,
238+
(d) => y(d.comparisonValue!),
239+
remappedData
272240
)
273241

274242
drawLine(
243+
svg,
275244
remappedData,
276245
(d) => d.timeLabel !== null,
277246
(d) => y(d.value!),
278247
mainPathClass
279248
)
280249

281250
drawLine(
251+
svg,
282252
remappedData,
283253
(d) => d.comparisonTimeLabel !== null,
284254
(d) => y(d.comparisonValue!),
@@ -667,7 +637,6 @@ const tickClass = 'fill-gray-500 dark:fill-gray-400 text-xs'
667637
const mainDotClass = 'fill-indigo-500 dark:fill-indigo-400'
668638
const comparisonDotClass = 'fill-indigo-500/20 dark:fill-indigo-400/20'
669639

670-
// const pathClass = 'stroke-[#6366f1] stroke-2 z-1' // custom color like indigo-400
671640
const sharedPathClass = 'stroke-2'
672641
const mainPathClass = 'stroke-indigo-500 dark:stroke-indigo-400 z-2'
673642
const comparisonPathClass = 'stroke-indigo-500/20 dark:stroke-indigo-400/20 z-1'
@@ -687,3 +656,63 @@ const METRIC_LABELS = {
687656
scroll_depth: 'Scroll depth',
688657
time_on_page: 'Time on page'
689658
}
659+
660+
const addGradient = ({
661+
svg,
662+
id,
663+
stopTop,
664+
stopBottom
665+
}: {
666+
svg: SelectedSVG
667+
id: string
668+
stopTop: { color: string; opacity: number }
669+
stopBottom: { color: string; opacity: number }
670+
}): string => {
671+
const grad = svg
672+
.append('defs')
673+
.append('linearGradient')
674+
.attr('id', id)
675+
.attr('x1', '0%')
676+
.attr('y1', '0%') // top
677+
.attr('x2', '0%')
678+
.attr('y2', `100%`) // bottom
679+
680+
grad
681+
.append('stop')
682+
.attr('offset', '0%')
683+
.attr('stop-color', stopTop.color)
684+
.attr('stop-opacity', stopTop.opacity)
685+
686+
grad
687+
.append('stop')
688+
.attr('offset', '100%')
689+
.attr('stop-color', stopBottom.color)
690+
.attr('stop-opacity', stopBottom.opacity)
691+
return id
692+
}
693+
694+
const paintUnderLine = (
695+
svg: SelectedSVG,
696+
gradientId: string,
697+
isDefined: (d: GraphDatum) => boolean,
698+
xAccessor: (d: GraphDatum, index: number) => number,
699+
y0Accessor: number,
700+
y1Accessor: (d: GraphDatum, index: number) => number,
701+
datum: GraphDatum[]
702+
) => {
703+
const area = d3
704+
.area<GraphDatum>()
705+
.x(xAccessor)
706+
.defined(isDefined)
707+
.y0(y0Accessor) // bottom edge
708+
.y1(y1Accessor) // top edge follows the data
709+
710+
// draw the filled area with the gradient
711+
svg
712+
.append('path')
713+
.datum(datum)
714+
.attr('fill', `url(#${gradientId})`)
715+
.attr('d', area)
716+
}
717+
718+
type SelectedSVG = d3.Selection<SVGSVGElement, unknown, null, undefined>

0 commit comments

Comments
 (0)