storybook/stories/small_multiples/3_grid_lines.story.tsx (166 lines of code) (raw):

/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ import { action } from '@storybook/addon-actions'; import { boolean, number, text } from '@storybook/addon-knobs'; import { startCase } from 'lodash'; import { DateTime } from 'luxon'; import React from 'react'; import type { AxisSpec, XYBrushEvent } from '@elastic/charts'; import { ScaleType, Position, Chart, Axis, LineSeries, GroupBy, SmallMultiples, Settings, niceTimeFormatByDay, timeFormatter, } from '@elastic/charts'; import { isVerticalAxis } from '@elastic/charts/src/chart_types/xy_chart/utils/axis_type_utils'; import { SeededDataGenerator } from '@elastic/charts/src/mocks/utils'; import type { ChartsStory } from '../../types'; import { useBaseTheme } from '../../use_base_theme'; const dg = new SeededDataGenerator(); const numOfDays = 90; const groupNames = new Array(16).fill(0).map((d, i) => String.fromCharCode(97 + i)); const data = dg.generateGroupedSeries(numOfDays, 16).map((d) => { return { y: d.y, x: DateTime.fromISO('2020-01-01T00:00:00Z').plus({ days: d.x }).toMillis(), g: d.g, h: groupNames.indexOf(d.g) % 4, v: Math.floor(groupNames.indexOf(d.g) / 4), }; }); const getAxisStyle = (position: Position): AxisSpec['style'] => ({ tickLabel: { padding: 5, }, axisPanelTitle: { visible: !boolean('Hide panel titles', false, position), }, axisTitle: { padding: 2, visible: !boolean('Hide title', false, position), }, tickLine: { visible: false, }, }); const tickTimeFormatter = timeFormatter(niceTimeFormatByDay(numOfDays)); const getAxisOptions = ( position: Position, ): Pick<AxisSpec, 'id' | 'title' | 'gridLine' | 'ticks' | 'domain' | 'tickFormat' | 'style' | 'hide' | 'position'> => { const isPrimary = position === Position.Left || position === Position.Bottom; const isVertical = isVerticalAxis(position); return { id: position, position, ticks: isVertical ? 2 : undefined, tickFormat: isVertical ? (d) => d.toFixed(2) : tickTimeFormatter, domain: isVertical ? { min: NaN, max: 10, } : undefined, hide: boolean('Hide', !isPrimary, position), gridLine: { visible: boolean('Show grid line', isPrimary, position), }, style: getAxisStyle(position), title: text( 'Title', isVertical ? `Metrics - ${startCase(position)}` : `Hosts - ${startCase(position)}`, position, ).trim(), }; }; export const Example: ChartsStory = (_, { title, description }) => { const debug = boolean('Debug', false); const showLegend = boolean('Show Legend', false); const onElementClick = action('onElementClick'); const metricPrefix = text('metric prefix', `Metric `).trim(); const hostPrefix = text('host prefix', `Host `).trim(); return ( <Chart title={title} description={description}> <Settings debug={debug} onElementClick={onElementClick} showLegend={showLegend} theme={{ lineSeriesStyle: { point: { visible: 'never', }, }, }} baseTheme={useBaseTheme()} onBrushEnd={(e) => { const { x } = e as XYBrushEvent; if (x) { action('brushEvent')(tickTimeFormatter(x[0] ?? 0), tickTimeFormatter(x[1] ?? 0)); } }} /> <Axis {...getAxisOptions(Position.Left)} /> <Axis {...getAxisOptions(Position.Bottom)} /> <Axis {...getAxisOptions(Position.Top)} /> <Axis {...getAxisOptions(Position.Right)} /> <GroupBy id="v_split" by={(_, { v }) => v} format={(v) => `${metricPrefix} ${v}`} sort="numDesc" /> <GroupBy id="h_split" by={(_, { h }) => h} format={(v) => `${hostPrefix} ${v}`} sort="numAsc" /> <SmallMultiples splitVertically="v_split" splitHorizontally="h_split" style={{ horizontalPanelPadding: { outer: number('Horizontal outer pad', 0, { range: true, min: 0, max: 0.5, step: 0.05, }), inner: number('Horizontal inner pad', 0.1, { range: true, min: 0, max: 0.5, step: 0.05, }), }, verticalPanelPadding: { outer: number('Vertical outer pad', 0, { range: true, min: 0, max: 0.5, step: 0.05, }), inner: number('Vertical inner pad', 0.3, { range: true, min: 0, max: 0.5, step: 0.05, }), }, }} /> <LineSeries id="line" name={({ splitAccessors }) => `Host ${splitAccessors.get('h')}`} xScaleType={ScaleType.Time} yScaleType={ScaleType.Linear} timeZone="UTC" xAccessor="x" yAccessors={['y']} splitSeriesAccessors={['h']} data={data} /> </Chart> ); }; Example.parameters = { markdown: `It is possible to add either a vertical and horizontal \`<GroupBy/>\` operations to create a grid of small multiples. The assignment of the series colors can be handled by defining an accessor in the \`color\` prop of the series that consider the \`smHorizontalAccessorValue\` or \`smVerticalAccessorValue\` values when returning the assigned color. `, };