diff --git a/api/charts.api.md b/api/charts.api.md index 7e5eb22536..e28fb00276 100644 --- a/api/charts.api.md +++ b/api/charts.api.md @@ -8,9 +8,18 @@ import { $Values } from 'utility-types'; import { ComponentType } from 'react'; import React from 'react'; +// @public +export type Accessor = AccessorObjectKey | AccessorArrayIndex; + +// @public +export type AccessorArrayIndex = number; + // @public export type AccessorFn = UnaryAccessorFn; +// @public +export type AccessorObjectKey = string; + // @public export type AnnotationDomainType = $Values; @@ -149,8 +158,6 @@ export interface AxisSpec extends Spec { export interface AxisStyle { // (undocumented) axisLine: StrokeStyle & Visible; - // Warning: (ae-forgotten-export) The symbol "Visible" needs to be exported by the entry point index.d.ts - // // (undocumented) axisTitle: TextStyle & Visible; // (undocumented) @@ -486,6 +493,32 @@ export interface DataSeriesDatum { // @public (undocumented) export type Datum = any; +// Warning: (ae-missing-release-tag) "DebugState" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface DebugState { + // Warning: (ae-forgotten-export) The symbol "DebugStateArea" needs to be exported by the entry point index.d.ts + // + // (undocumented) + areas?: DebugStateArea[]; + // Warning: (ae-forgotten-export) The symbol "DebugStateAxes" needs to be exported by the entry point index.d.ts + // + // (undocumented) + axes?: DebugStateAxes; + // Warning: (ae-forgotten-export) The symbol "DebugStateBar" needs to be exported by the entry point index.d.ts + // + // (undocumented) + bars?: DebugStateBar[]; + // Warning: (ae-forgotten-export) The symbol "DebugStateLegend" needs to be exported by the entry point index.d.ts + // + // (undocumented) + legend?: DebugStateLegend; + // Warning: (ae-forgotten-export) The symbol "DebugStateLine" needs to be exported by the entry point index.d.ts + // + // (undocumented) + lines?: DebugStateLine[]; +} + // Warning: (ae-missing-release-tag) "DEFAULT_ANNOTATION_LINE_STYLE" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1218,7 +1251,6 @@ export interface SeriesAccessors { markSizeAccessor?: Accessor | AccessorFn; splitSeriesAccessors?: Accessor[]; stackAccessors?: Accessor[]; - // Warning: (ae-forgotten-export) The symbol "Accessor" needs to be exported by the entry point index.d.ts xAccessor: Accessor | AccessorFn; y0Accessors?: Accessor[]; yAccessors: Accessor[]; @@ -1330,9 +1362,10 @@ export interface SettingsSpec extends Spec { animateData: boolean; baseTheme?: Theme; brushAxis?: BrushAxis; - // (undocumented) debug: boolean; // @alpha + debugState?: boolean; + // @alpha externalPointerEvents: ExternalPointerEventsSettings; flatLegend?: boolean; hideDuplicateAxes: boolean; @@ -1340,7 +1373,6 @@ export interface SettingsSpec extends Spec { // (undocumented) legendColorPicker?: LegendColorPicker; legendMaxDepth?: number; - // (undocumented) legendPosition: Position; minBrushDelta?: number; // (undocumented) @@ -1614,6 +1646,14 @@ export const VerticalAlignment: Readonly<{ // @public export type VerticalAlignment = $Values; +// Warning: (ae-missing-release-tag) "Visible" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface Visible { + // (undocumented) + visible: boolean; +} + // Warning: (ae-missing-release-tag) "XYBrushArea" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-debug-options-basic-visually-looks-correct-1-snap.png b/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-debug-options-basic-visually-looks-correct-1-snap.png new file mode 100644 index 0000000000..31caf02a66 Binary files /dev/null and b/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-debug-options-basic-visually-looks-correct-1-snap.png differ diff --git a/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-debug-options-debug-state-visually-looks-correct-1-snap.png b/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-debug-options-debug-state-visually-looks-correct-1-snap.png new file mode 100644 index 0000000000..0cd6a8b91c Binary files /dev/null and b/integration/tests/__image_snapshots__/all-test-ts-baseline-visual-tests-for-all-stories-debug-options-debug-state-visually-looks-correct-1-snap.png differ diff --git a/src/chart_types/goal_chart/state/chart_state.tsx b/src/chart_types/goal_chart/state/chart_state.tsx index c5c2ee4a46..b67c08bf42 100644 --- a/src/chart_types/goal_chart/state/chart_state.tsx +++ b/src/chart_types/goal_chart/state/chart_state.tsx @@ -25,6 +25,7 @@ import { Tooltip } from '../../../components/tooltip'; import { InternalChartState, GlobalChartState, BackwardRef } from '../../../state/chart_state'; import { InitStatus } from '../../../state/selectors/get_internal_is_intialized'; import { LegendItemLabel } from '../../../state/selectors/get_legend_items_labels'; +import { DebugState } from '../../../state/types'; import { Dimensions } from '../../../utils/dimensions'; import { Goal } from '../renderer/canvas/connected_component'; import { getSpecOrNull } from './selectors/goal_spec'; @@ -130,4 +131,9 @@ export class GoalState implements InternalChartState { getBrushArea(): Dimensions | null { return null; } + + // TODO + getDebugState(): DebugState { + return {}; + } } diff --git a/src/chart_types/partition_chart/state/chart_state.tsx b/src/chart_types/partition_chart/state/chart_state.tsx index 328f4931c3..801488f4d4 100644 --- a/src/chart_types/partition_chart/state/chart_state.tsx +++ b/src/chart_types/partition_chart/state/chart_state.tsx @@ -23,6 +23,7 @@ import { ChartTypes } from '../..'; import { Tooltip } from '../../../components/tooltip'; import { InternalChartState, GlobalChartState, BackwardRef } from '../../../state/chart_state'; import { InitStatus } from '../../../state/selectors/get_internal_is_intialized'; +import { DebugState } from '../../../state/types'; import { Dimensions } from '../../../utils/dimensions'; import { Partition } from '../renderer/canvas/partition'; import { HighlighterFromHover } from '../renderer/dom/highlighter_hover'; @@ -132,4 +133,9 @@ export class PartitionState implements InternalChartState { getBrushArea(): Dimensions | null { return null; } + + // TODO + getDebugState(): DebugState { + return {}; + } } diff --git a/src/chart_types/xy_chart/rendering/rendering.ts b/src/chart_types/xy_chart/rendering/rendering.ts index cc9ffb8509..0b0a3eb4be 100644 --- a/src/chart_types/xy_chart/rendering/rendering.ts +++ b/src/chart_types/xy_chart/rendering/rendering.ts @@ -584,6 +584,7 @@ export function renderBubble( } /** @internal */ + export function renderArea( shift: number, dataSeries: DataSeries, diff --git a/src/chart_types/xy_chart/state/chart_state.tsx b/src/chart_types/xy_chart/state/chart_state.tsx index 18784d61fa..c25a665c1b 100644 --- a/src/chart_types/xy_chart/state/chart_state.tsx +++ b/src/chart_types/xy_chart/state/chart_state.tsx @@ -36,6 +36,7 @@ import { computeChartDimensionsSelector } from './selectors/compute_chart_dimens import { computeLegendSelector } from './selectors/compute_legend'; import { getBrushAreaSelector } from './selectors/get_brush_area'; import { getPointerCursorSelector } from './selectors/get_cursor_pointer'; +import { getDebugStateSelector } from './selectors/get_debug_state'; import { getHighlightedValuesSelector } from './selectors/get_highlighted_values'; import { getLegendItemsLabelsSelector } from './selectors/get_legend_items_labels'; import { getSeriesSpecsSelector } from './selectors/get_specs'; @@ -148,4 +149,8 @@ export class XYAxisChartState implements InternalChartState { this.onBrushEndCaller(globalState); this.onPointerMoveCaller(globalState); } + + getDebugState(globalState: GlobalChartState) { + return getDebugStateSelector(globalState); + } } diff --git a/src/chart_types/xy_chart/state/selectors/get_debug_state.ts b/src/chart_types/xy_chart/state/selectors/get_debug_state.ts new file mode 100644 index 0000000000..fac3519cad --- /dev/null +++ b/src/chart_types/xy_chart/state/selectors/get_debug_state.ts @@ -0,0 +1,254 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import createCachedSelector from 're-reselect'; + +import { LegendItem } from '../../../../commons/legend'; +import { AxisSpec } from '../../../../specs'; +import { getChartIdSelector } from '../../../../state/selectors/get_chart_id'; +import { + DebugState, + DebugStateValue, + DebugStateAxes, + DebugStateArea, + DebugStateLine, + DebugStateBar, + DebugStateLegend, +} from '../../../../state/types'; +import { AreaGeometry, BandedAccessorType, LineGeometry, BarGeometry } from '../../../../utils/geometry'; +import { FillStyle, Visible, StrokeStyle, Opacity } from '../../../../utils/themes/theme'; +import { isVerticalAxis } from '../../utils/axis_type_utils'; +import { computeAxisVisibleTicksSelector, AxisVisibleTicks } from './compute_axis_visible_ticks'; +import { computeLegendSelector } from './compute_legend'; +import { computeSeriesGeometriesSelector } from './compute_series_geometries'; +import { getAxisSpecsSelector } from './get_specs'; + +/** + * Returns a stringified version of the `debugState` + * @internal + */ +export const getDebugStateSelector = createCachedSelector( + [computeSeriesGeometriesSelector, computeLegendSelector, computeAxisVisibleTicksSelector, getAxisSpecsSelector], + ({ geometries }, legend, axes, axesSpecs): DebugState => { + const seriesNameMap = getSeriesNameMap(legend); + + return { + legend: getLegendState(legend), + axes: getAxes(axes, axesSpecs), + areas: geometries.areas.map(getAreaState(seriesNameMap)), + lines: geometries.lines.map(getLineState(seriesNameMap)), + bars: getBarsState(seriesNameMap, geometries.bars), + }; + }, +)(getChartIdSelector); + +const getAxes = (ticks: AxisVisibleTicks, axesSpecs: AxisSpec[]): DebugStateAxes | undefined => { + if (axesSpecs.length === 0) { + return; + } + + return axesSpecs.reduce( + (acc, { position, title, id }) => { + const axisTicks = ticks.axisVisibleTicks.get(id) ?? []; + const labels = axisTicks.map(({ label }) => label); + const values = axisTicks.map(({ value }) => value); + const grids = ticks.axisGridLinesPositions.get(id) ?? []; + const gridlines = grids.map(([x, y]) => ({ x, y })); + + if (isVerticalAxis(position)) { + acc.y.push({ + id, + title, + position, + // reverse for bottom/up coordinates + labels: labels.reverse(), + values: values.reverse(), + gridlines: gridlines.reverse(), + }); + } else { + acc.x.push({ + id, + title, + position, + labels, + values, + gridlines, + }); + } + + return acc; + }, + { + y: [], + x: [], + }, + ); +}; + +const getBarsState = (seriesNameMap: Map, barGeometries: BarGeometry[]): DebugStateBar[] => { + const buckets = new Map(); + + barGeometries.forEach( + ({ + color, + seriesIdentifier: { key }, + seriesStyle: { rect, rectBorder }, + value: { x, y, mark }, + displayValue, + }: BarGeometry) => { + const label = displayValue?.text; + const name = seriesNameMap.get(key) ?? ''; + const bucket: DebugStateBar = buckets.get(key) ?? { + key, + name, + color, + bars: [], + labels: [], + visible: hasVisibleStyle(rect) || hasVisibleStyle(rectBorder), + }; + + bucket.bars.push({ x, y, mark }); + + if (label) { + bucket.labels.push(label); + } + + buckets.set(key, bucket); + + return buckets; + }, + ); + + return [...buckets.values()]; +}; + +const getLineState = (seriesNameMap: Map) => ({ + line: path, + points, + color, + seriesIdentifier: { key }, + seriesLineStyle, + seriesPointStyle, +}: LineGeometry): DebugStateLine => { + const name = seriesNameMap.get(key) ?? ''; + + return { + path, + color, + key, + name, + visible: hasVisibleStyle(seriesLineStyle), + visiblePoints: hasVisibleStyle(seriesPointStyle), + points: points.map(({ value: { x, y, mark } }) => ({ x, y, mark })), + }; +}; + +const getAreaState = (seriesNameMap: Map) => ({ + area: path, + lines, + points, + color, + seriesIdentifier: { key }, + seriesAreaStyle, + seriesPointStyle, + seriesAreaLineStyle, +}: AreaGeometry): DebugStateArea => { + const [y1Path, y0Path] = lines; + const linePoints = points.reduce<{ + y0: DebugStateValue[]; + y1: DebugStateValue[]; + }>( + (acc, { value: { accessor, ...value } }) => { + if (accessor === BandedAccessorType.Y0) { + acc.y0.push(value); + } else { + acc.y1.push(value); + } + + return acc; + }, + { + y0: [], + y1: [], + }, + ); + const lineVisible = hasVisibleStyle(seriesAreaLineStyle); + const visiblePoints = hasVisibleStyle(seriesPointStyle); + const name = seriesNameMap.get(key) ?? ''; + + return { + path, + color, + key, + name, + visible: hasVisibleStyle(seriesAreaStyle), + lines: { + y0: y0Path + ? { + visible: lineVisible, + path: y0Path, + points: linePoints.y0, + visiblePoints, + } + : undefined, + y1: { + visible: lineVisible, + path: y1Path, + points: linePoints.y1, + visiblePoints, + }, + }, + }; +}; + +/** + * returns series key to name mapping + */ +function getSeriesNameMap(legendItems: LegendItem[]): Map { + return legendItems.reduce((acc, { label: name, seriesIdentifier: { key } }) => { + acc.set(key, name); + return acc; + }, new Map()); +} + +function getLegendState(legendItems: LegendItem[]): DebugStateLegend { + const items = legendItems + .filter(({ isSeriesHidden }) => !isSeriesHidden) + .map(({ label: name, color, seriesIdentifier: { key } }) => ({ + key, + name, + color, + })); + + return { items }; +} + +/** + * Returns true for styles if they are visible + * Serves as a catchall for multiple style types + */ +function hasVisibleStyle({ + visible = true, + fill = '#fff', + stroke = '#fff', + strokeWidth = 1, + opacity = 1, +}: Partial): boolean { + return Boolean(visible && opacity > 0 && strokeWidth > 0 && fill && stroke); +} diff --git a/src/chart_types/xy_chart/state/utils/spec.ts b/src/chart_types/xy_chart/state/utils/spec.ts index a0ef591fad..da23d7d0f5 100644 --- a/src/chart_types/xy_chart/state/utils/spec.ts +++ b/src/chart_types/xy_chart/state/utils/spec.ts @@ -28,8 +28,8 @@ export function getSpecsById(specs: T[], id: string): T | undefi /** @internal */ export function getAxesSpecForSpecId(axesSpecs: AxisSpec[], groupId: GroupId) { - let xAxis; - let yAxis; + let xAxis: AxisSpec | undefined; + let yAxis: AxisSpec | undefined; // eslint-disable-next-line no-restricted-syntax for (const axisSpec of axesSpecs) { if (axisSpec.groupId !== groupId) { @@ -41,6 +41,7 @@ export function getAxesSpecForSpecId(axesSpecs: AxisSpec[], groupId: GroupId) { xAxis = axisSpec; } } + return { xAxis, yAxis, diff --git a/src/components/chart_status.tsx b/src/components/chart_status.tsx index 81496eee06..e68d88573a 100644 --- a/src/components/chart_status.tsx +++ b/src/components/chart_status.tsx @@ -22,12 +22,15 @@ import { connect } from 'react-redux'; import { RenderChangeListener } from '../specs'; import { GlobalChartState } from '../state/chart_state'; +import { getDebugStateSelector } from '../state/selectors/get_debug_state'; import { getSettingsSpecSelector } from '../state/selectors/get_settings_specs'; +import { DebugState } from '../state/types'; interface ChartStatusStateProps { rendered: boolean; renderedCount: number; onRenderChange?: RenderChangeListener; + debugState: DebugState | null; } class ChartStatusComponent extends React.Component { componentDidMount() { @@ -48,16 +51,30 @@ class ChartStatusComponent extends React.Component { }; render() { - const { rendered, renderedCount } = this.props; - return
; + const { rendered, renderedCount, debugState } = this.props; + const debugStateString: string | null = debugState && JSON.stringify(debugState); + + return ( +
+ ); } } -const mapStateToProps = (state: GlobalChartState): ChartStatusStateProps => ({ - rendered: state.chartRendered, - renderedCount: state.chartRenderedCount, - onRenderChange: getSettingsSpecSelector(state).onRenderChange, -}); +const mapStateToProps = (state: GlobalChartState): ChartStatusStateProps => { + const settings = getSettingsSpecSelector(state); + + return { + rendered: state.chartRendered, + renderedCount: state.chartRenderedCount, + onRenderChange: settings.onRenderChange, + debugState: settings.debugState ? getDebugStateSelector(state) : null, + }; +}; /** @internal */ export const ChartStatus = connect(mapStateToProps)(ChartStatusComponent); diff --git a/src/index.ts b/src/index.ts index b6eb816f89..5ddc96bd6c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,6 +26,7 @@ export { SpecId, GroupId, AxisId, AnnotationId } from './utils/ids'; // Everything related to the specs types and react-components export * from './specs'; +export { DebugState } from './state/types'; export { CurveType } from './utils/curves'; export { SimplePadding } from './utils/dimensions'; export { timeFormatter, niceTimeFormatter, niceTimeFormatByDay } from './utils/data/formatters'; @@ -41,7 +42,14 @@ export { } from './chart_types/partition_chart/layout/types/config_types'; export { Layer as PartitionLayer } from './chart_types/partition_chart/specs/index'; export * from './chart_types/goal_chart/specs/index'; -export { AccessorFn, IndexedAccessorFn, UnaryAccessorFn } from './utils/accessor'; +export { + Accessor, + AccessorFn, + IndexedAccessorFn, + UnaryAccessorFn, + AccessorObjectKey, + AccessorArrayIndex, +} from './utils/accessor'; export { CustomTooltip, TooltipInfo } from './components/tooltip/types'; // scales diff --git a/src/specs/settings.tsx b/src/specs/settings.tsx index f61fb569cb..a1f8df78c2 100644 --- a/src/specs/settings.tsx +++ b/src/specs/settings.tsx @@ -290,7 +290,18 @@ export interface SettingsSpec extends Spec { * @alpha */ externalPointerEvents: ExternalPointerEventsSettings; + /** + * Show debug shadow elements on chart + */ debug: boolean; + /** + * Show debug render state on `ChartStatus` component + * @alpha + */ + debugState?: boolean; + /** + * Set legend position + */ legendPosition: Position; /** * Show an extra parameter on each legend item defined by the chart type diff --git a/src/state/chart_state.ts b/src/state/chart_state.ts index d46123181f..0d018fe656 100644 --- a/src/state/chart_state.ts +++ b/src/state/chart_state.ts @@ -42,6 +42,7 @@ import { interactionsReducer } from './reducers/interactions'; import { getInternalIsInitializedSelector, InitStatus } from './selectors/get_internal_is_intialized'; import { getLegendItemsSelector } from './selectors/get_legend_items'; import { LegendItemLabel } from './selectors/get_legend_items_labels'; +import { DebugState } from './types'; import { getInitialPointerState } from './utils'; export type BackwardRef = () => React.RefObject; @@ -140,6 +141,12 @@ export interface InternalChartState { * @param globalState */ getBrushArea(globalState: GlobalChartState): Dimensions | null; + + /** + * Get debug state of chart + * @param globalState + */ + getDebugState(globalState: GlobalChartState): DebugState; } /** @internal */ diff --git a/src/state/selectors/get_debug_state.ts b/src/state/selectors/get_debug_state.ts new file mode 100644 index 0000000000..f71421ea43 --- /dev/null +++ b/src/state/selectors/get_debug_state.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { GlobalChartState } from '../chart_state'; +import { DebugState } from '../types'; +import { getChartContainerDimensionsSelector } from './get_chart_container_dimensions'; + +/** @internal */ +export const getDebugStateSelector = (state: GlobalChartState): DebugState => { + if (state.internalChartState) { + const { height, width } = getChartContainerDimensionsSelector(state); + if (height * width > 0) { + return state.internalChartState.getDebugState(state); + } + } + return {}; +}; diff --git a/src/state/types.ts b/src/state/types.ts new file mode 100644 index 0000000000..2ee5b5d6a9 --- /dev/null +++ b/src/state/types.ts @@ -0,0 +1,92 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Position } from '../utils/commons'; +import { GeometryValue } from '../utils/geometry'; + +export interface DebugStateAxis { + id: string; + position: Position; + title?: string; + labels: string[]; + values: any[]; + gridlines: { + y: number; + x: number; + }[]; +} + +export interface DebugStateAxes { + x: DebugStateAxis[]; + y: DebugStateAxis[]; +} + +export interface DebugStateLegendItem { + key: string; + name: string; + color: string; +} + +export interface DebugStateLegend { + items: DebugStateLegendItem[]; +} + +interface DebugStateBase { + key: string; + name: string; + color: string; +} + +export type DebugStateValue = Pick; + +interface DebugStateLineConfig { + visible: boolean; + path: string; + points: DebugStateValue[]; + visiblePoints: boolean; +} + +export interface DebugStateLine extends DebugStateBase, DebugStateLineConfig {} + +export type DebugStateArea = Omit & { + path: string; + lines: { + y0?: DebugStateLineConfig; + y1: DebugStateLineConfig; + }; +}; + +export type DebugStateBar = DebugStateBase & { + visible: boolean; + bars: DebugStateValue[]; + labels: any[]; +}; + +/** + * Describes _visible_ chart state for use in functional tests + * + * TODO: add other chart types to debug state + */ +export interface DebugState { + legend?: DebugStateLegend; + axes?: DebugStateAxes; + areas?: DebugStateArea[]; + lines?: DebugStateLine[]; + bars?: DebugStateBar[]; +} diff --git a/src/utils/accessor.ts b/src/utils/accessor.ts index 1230d24abd..175c8ad9c8 100644 --- a/src/utils/accessor.ts +++ b/src/utils/accessor.ts @@ -45,8 +45,18 @@ export type AccessorFn = UnaryAccessorFn; * @public */ export type IndexedAccessorFn = UnaryAccessorFn | BinaryAccessorFn; -type AccessorObjectKey = string; -type AccessorArrayIndex = number; + +/** + * A key accessor string + * @public + */ +export type AccessorObjectKey = string; + +/** + * An index accessor number + * @public + */ +export type AccessorArrayIndex = number; /** * A datum accessor in form of object key accessor string/number diff --git a/src/utils/themes/theme.ts b/src/utils/themes/theme.ts index ad87e556bb..451d80b976 100644 --- a/src/utils/themes/theme.ts +++ b/src/utils/themes/theme.ts @@ -28,7 +28,7 @@ import { import { Margins, SimplePadding } from '../dimensions'; import { LIGHT_THEME } from './light_theme'; -interface Visible { +export interface Visible { visible: boolean; } diff --git a/stories/debug/1_basic.tsx b/stories/debug/1_basic.tsx new file mode 100644 index 0000000000..245644b343 --- /dev/null +++ b/stories/debug/1_basic.tsx @@ -0,0 +1,65 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { boolean } from '@storybook/addon-knobs'; +import React from 'react'; + +import { Chart, ScaleType, Settings, Position, Axis, BarSeries, AreaSeries, CurveType } from '../../src'; + +export const Example = () => { + const debug = boolean('debug', true); + + return ( + + + + Number(d).toFixed(2)} /> + + Number(d).toFixed(2)} /> + + + + ); +}; diff --git a/stories/debug/2_debug_state.tsx b/stories/debug/2_debug_state.tsx new file mode 100644 index 0000000000..6866fe5042 --- /dev/null +++ b/stories/debug/2_debug_state.tsx @@ -0,0 +1,108 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { action } from '@storybook/addon-actions'; +import { boolean, number } from '@storybook/addon-knobs'; +import React from 'react'; +import { debounce } from 'ts-debounce'; + +import { + Chart, + LineSeries, + ScaleType, + CurveType, + AreaSeries, + BarSeries, + Settings, + Axis, + Position, + SeriesNameFn, + DebugState, +} from '../../src'; +import { SeededDataGenerator } from '../../src/mocks/utils'; + +export const Example = () => { + const debug = boolean('debug', false); + const debugState = boolean('debugState', true); + const line = boolean('show line', true); + const area = boolean('show area', true); + const bar = boolean('show bar', true); + const groupCount = number('number of groups', 1, { min: 1 }); + const splitSeriesAccessors = groupCount > 1 ? ['g'] : undefined; + const naming: SeriesNameFn | undefined = + groupCount === 1 ? undefined : ({ specId, seriesKeys }) => `${specId} | ${seriesKeys[0]}`; + + const dg = new SeededDataGenerator(); + const lineData = dg.generateGroupedSeries(40, groupCount); + const areaData = dg.generateGroupedSeries(40, groupCount); + const barData = dg.generateGroupedSeries(40, groupCount); + + const dataStateAction = action('DataState'); + const logDebugstate = debounce(() => { + const statusEl = document.querySelector('.echChartStatus'); + + if (statusEl) { + const dataState = statusEl.dataset.echDebugState + ? (JSON.parse(statusEl.dataset.echDebugState) as DebugState) + : null; + dataStateAction(dataState); + } + }, 100); + + return ( + + + + Number(d).toFixed(2)} /> + + {line && ( + + )} + {area && ( + + )} + + {bar && ( + + )} + + ); +}; diff --git a/stories/debug/debug.stories.tsx b/stories/debug/debug.stories.tsx new file mode 100644 index 0000000000..837488be72 --- /dev/null +++ b/stories/debug/debug.stories.tsx @@ -0,0 +1,30 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { SB_SOURCE_PANEL } from '../utils/storybook'; + +export default { + title: 'Debug Options', + parameters: { + options: { selectedPanel: SB_SOURCE_PANEL }, + }, +}; + +export { Example as basic } from './1_basic'; +export { Example as debugState } from './2_debug_state';