@influxdata/giraffe
Advanced tools
Comparing version 0.12.1 to 0.12.2
import { FunctionComponent } from 'react'; | ||
import { LineHoverDimension } from '../types'; | ||
import { PlotEnv } from '../utils/PlotEnv'; | ||
import { LineData } from '../utils/lineData'; | ||
interface Props { | ||
env: PlotEnv; | ||
layerIndex: number; | ||
lineData: LineData; | ||
import { Props as LineLayerProps } from './LineLayer'; | ||
import { LineHoverDimension, LineData } from '../types'; | ||
interface Props extends LineLayerProps { | ||
rowIndices: number[] | null; | ||
dimension: LineHoverDimension; | ||
simplifiedLineData: LineData; | ||
} | ||
export declare const LineHoverLayer: FunctionComponent<Props>; | ||
export {}; |
import { FunctionComponent } from 'react'; | ||
import { PlotEnv } from '../utils/PlotEnv'; | ||
interface Props { | ||
env: PlotEnv; | ||
layerIndex: number; | ||
hoverX: number; | ||
hoverY: number; | ||
import { LayerProps, LineLayerSpec, LineLayerConfig } from '../types'; | ||
export interface Props extends LayerProps { | ||
spec: LineLayerSpec; | ||
config: LineLayerConfig; | ||
} | ||
export declare const LineLayer: FunctionComponent<Props>; | ||
export {}; |
import { FunctionComponent } from 'react'; | ||
import { PlotEnv } from '../utils/PlotEnv'; | ||
interface Props { | ||
env: PlotEnv; | ||
layerIndex: number; | ||
hoverX: number; | ||
hoverY: number; | ||
import { ScatterLayerConfig, ScatterLayerSpec, LayerProps } from '../types'; | ||
interface Props extends LayerProps { | ||
spec: ScatterLayerSpec; | ||
config: ScatterLayerConfig; | ||
} | ||
export declare const ScatterHoverLayer: FunctionComponent<Props>; | ||
export {}; |
import { FunctionComponent } from 'react'; | ||
import { PlotEnv } from '../utils/PlotEnv'; | ||
interface Props { | ||
env: PlotEnv; | ||
layerIndex: number; | ||
hoverX: number; | ||
hoverY: number; | ||
import { ScatterLayerConfig, ScatterLayerSpec, LayerProps } from '../types'; | ||
interface Props extends LayerProps { | ||
spec: ScatterLayerSpec; | ||
config: ScatterLayerConfig; | ||
} | ||
export declare const ScatterLayer: FunctionComponent<Props>; | ||
export {}; |
import { FunctionComponent } from 'react'; | ||
import { TooltipData } from '../types'; | ||
import { PlotEnv } from '../utils/PlotEnv'; | ||
import { TooltipData, Config } from '../types'; | ||
interface Props { | ||
data: TooltipData; | ||
env: PlotEnv; | ||
config: Config; | ||
} | ||
export declare const Tooltip: FunctionComponent<Props>; | ||
export {}; |
@@ -1,2 +0,2 @@ | ||
import { Config, LayerConfig } from '../types'; | ||
import { Config, LayerConfig, SymbolType } from '../types'; | ||
export declare const TICK_PADDING_RIGHT = 8; | ||
@@ -22,1 +22,2 @@ export declare const TICK_PADDING_TOP = 8; | ||
}; | ||
export declare const ALL_SYMBOL_TYPES: SymbolType[]; |
@@ -1,2 +0,1 @@ | ||
import { SymbolType } from '../utils/getSymbolScale'; | ||
export declare type NumericColumnData = number[] | Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Float32Array | Float64Array; | ||
@@ -6,7 +5,7 @@ export declare type ColumnData = NumericColumnData | string[] | boolean[]; | ||
export interface GetColumn { | ||
(columnKey: string): ColumnData; | ||
(columnKey: string, type: 'number'): NumericColumnData; | ||
(columnKey: string, type: 'time'): NumericColumnData; | ||
(columnKey: string, type: 'string'): string[]; | ||
(columnKey: string, type: 'boolean'): boolean[]; | ||
(columnKey: string): ColumnData | null; | ||
(columnKey: string, type: 'number'): NumericColumnData | null; | ||
(columnKey: string, type: 'time'): NumericColumnData | null; | ||
(columnKey: string, type: 'string'): string[] | null; | ||
(columnKey: string, type: 'boolean'): boolean[] | null; | ||
} | ||
@@ -54,10 +53,2 @@ export interface Table { | ||
} | ||
export interface LineMappings { | ||
x: string; | ||
y: string; | ||
fill: string[]; | ||
} | ||
export interface LineScales { | ||
fill: Scale<string, string>; | ||
} | ||
export interface HeatmapLayerConfig { | ||
@@ -69,23 +60,22 @@ type: 'heatmap'; | ||
binSize?: number; | ||
strokeWidth?: number; | ||
strokePadding?: number; | ||
strokeOpacity?: number; | ||
fillOpacity?: number; | ||
} | ||
export interface HeatmapScales { | ||
fill: Scale<number, string>; | ||
export declare type HistogramPosition = 'overlaid' | 'stacked'; | ||
export interface HistogramLayerConfig { | ||
type: 'histogram'; | ||
x: string; | ||
fill?: string[]; | ||
colors?: string[]; | ||
position?: HistogramPosition; | ||
binCount?: number; | ||
strokeWidth?: number; | ||
strokePadding?: number; | ||
strokeOpacity?: number; | ||
fillOpacity?: number; | ||
} | ||
export interface HeatmapMappings { | ||
xMin: 'xMin'; | ||
xMax: 'xMax'; | ||
yMin: 'yMin'; | ||
yMax: 'yMax'; | ||
fill: 'count'; | ||
} | ||
export interface HistogramMappings { | ||
xMin: 'xMin'; | ||
xMax: 'xMax'; | ||
yMin: 'yMin'; | ||
yMax: 'yMax'; | ||
fill: string[]; | ||
} | ||
export interface HistogramScales { | ||
fill: Scale<string, string>; | ||
} | ||
export declare type RectLayerConfig = HistogramLayerConfig | HeatmapLayerConfig; | ||
export declare type SymbolType = 'circle' | 'triangle' | 'square' | 'plus' | 'tritip' | 'ex'; | ||
export interface ScatterLayerConfig { | ||
@@ -99,24 +89,3 @@ type: 'scatter'; | ||
} | ||
export interface ScatterMappings { | ||
x: string; | ||
y: string; | ||
fill: string[]; | ||
symbol: string[]; | ||
} | ||
export interface ScatterScales { | ||
fill: Scale<string, string>; | ||
symbol: Scale<string, SymbolType>; | ||
} | ||
export declare type Mappings = LineMappings | HistogramMappings | HeatmapMappings | ScatterMappings; | ||
export declare type Scales = LineScales | HistogramScales | HeatmapScales | ScatterScales; | ||
export declare type LayerConfig = LineLayerConfig | HistogramLayerConfig | HeatmapLayerConfig | ScatterLayerConfig; | ||
export declare type HistogramPosition = 'overlaid' | 'stacked'; | ||
export interface HistogramLayerConfig { | ||
type: 'histogram'; | ||
x: string; | ||
fill?: string[]; | ||
colors?: string[]; | ||
position?: HistogramPosition; | ||
binCount?: number; | ||
} | ||
export interface Config { | ||
@@ -157,1 +126,82 @@ table: Table; | ||
}; | ||
export interface ColumnGroupMap { | ||
columnKeys: string[]; | ||
mappings: Array<{ | ||
[columnKey: string]: any; | ||
}>; | ||
} | ||
export declare type LineData = { | ||
[groupID: number]: { | ||
xs: number[]; | ||
ys: number[]; | ||
fill: string; | ||
}; | ||
}; | ||
export interface LineLayerSpec { | ||
type: 'line'; | ||
inputTable: Table; | ||
table: Table; | ||
lineData: LineData; | ||
xDomain: number[]; | ||
yDomain: number[]; | ||
xColumnKey: string; | ||
yColumnKey: string; | ||
xColumnType: ColumnType; | ||
yColumnType: ColumnType; | ||
scales: { | ||
fill: Scale<number, string>; | ||
}; | ||
columnGroupMaps: { | ||
fill: ColumnGroupMap; | ||
}; | ||
} | ||
export interface ScatterLayerSpec { | ||
type: 'scatter'; | ||
inputTable: Table; | ||
table: Table; | ||
xDomain: number[]; | ||
yDomain: number[]; | ||
xColumnKey: string; | ||
yColumnKey: string; | ||
xColumnType: ColumnType; | ||
yColumnType: ColumnType; | ||
scales: { | ||
fill: Scale<number, string>; | ||
symbol: Scale<number, SymbolType>; | ||
}; | ||
columnGroupMaps: { | ||
fill: ColumnGroupMap; | ||
symbol: ColumnGroupMap; | ||
}; | ||
} | ||
export interface RectLayerSpec { | ||
type: 'rect'; | ||
inputTable: Table; | ||
table: Table; | ||
binDimension: 'xy' | 'x'; | ||
xDomain: number[]; | ||
yDomain: number[]; | ||
xColumnKey: string; | ||
yColumnKey: string; | ||
xColumnType: ColumnType; | ||
yColumnType: ColumnType; | ||
scales: { | ||
fill: Scale<number, string>; | ||
}; | ||
columnGroupMaps: { | ||
fill?: ColumnGroupMap; | ||
}; | ||
} | ||
export interface LayerProps { | ||
xScale: Scale<number, number>; | ||
yScale: Scale<number, number>; | ||
width: number; | ||
height: number; | ||
spec: LayerSpec; | ||
config: LayerConfig; | ||
plotConfig: SizedConfig; | ||
columnFormatter: (colKey: string) => (x: any) => string; | ||
hoverX: number | null; | ||
hoverY: number | null; | ||
} | ||
export declare type LayerSpec = LineLayerSpec | ScatterLayerSpec | RectLayerSpec; |
interface DrawLinePointOptions { | ||
canvas: HTMLCanvasElement; | ||
context: CanvasRenderingContext2D; | ||
width: number; | ||
@@ -15,3 +15,3 @@ height: number; | ||
} | ||
export declare const drawLineHoverData: ({ canvas, width, height, crosshairX, crosshairY, crosshairColor, points, radius, }: DrawLinePointOptions) => void; | ||
export declare const drawLineHoverData: ({ context, width, height, crosshairX, crosshairY, crosshairColor, points, radius, }: DrawLinePointOptions) => void; | ||
export {}; |
@@ -1,5 +0,4 @@ | ||
import { LineInterpolation } from '../types'; | ||
import { LineData } from './lineData'; | ||
import { LineInterpolation, LineData } from '../types'; | ||
interface DrawLinesOptions { | ||
canvas: HTMLCanvasElement; | ||
context: CanvasRenderingContext2D; | ||
interpolation: LineInterpolation; | ||
@@ -12,3 +11,3 @@ lineData: LineData; | ||
} | ||
export declare const drawLines: ({ canvas, lineData, interpolation, lineWidth, shadeBelow, shadeBelowOpacity, shadeAboveY, }: DrawLinesOptions) => void; | ||
export declare const drawLines: ({ context, lineData, interpolation, lineWidth, shadeBelow, shadeBelowOpacity, shadeAboveY, }: DrawLinesOptions) => void; | ||
export {}; |
@@ -1,18 +0,16 @@ | ||
import { Scale, NumericColumnData } from '../types'; | ||
import { Scale, NumericColumnData, SymbolType } from '../types'; | ||
interface DrawPointsOptions { | ||
canvas: HTMLCanvasElement; | ||
width: number; | ||
height: number; | ||
context: CanvasRenderingContext2D; | ||
xColData: NumericColumnData; | ||
yColData: NumericColumnData; | ||
fillColData: string[]; | ||
symbolColData: string[]; | ||
fillColData: NumericColumnData; | ||
symbolColData: NumericColumnData; | ||
yScale: Scale<number, number>; | ||
xScale: Scale<number, number>; | ||
fillScale: Scale<string, string>; | ||
symbolScale: Scale<string, string>; | ||
fillScale: Scale<number, string>; | ||
symbolScale: Scale<number, SymbolType>; | ||
pointSize: number; | ||
rowIndices?: number[]; | ||
} | ||
export declare const drawPoints: ({ canvas, width, height, xColData, yColData, fillColData, symbolColData, yScale, xScale, fillScale, symbolScale, pointSize, rowIndices, }: DrawPointsOptions) => void; | ||
export declare const drawPoints: ({ context, xColData, yColData, fillColData, symbolColData, yScale, xScale, fillScale, symbolScale, pointSize, rowIndices, }: DrawPointsOptions) => void; | ||
export {}; |
import { Table, Scale } from '../types'; | ||
export declare const getLineHoverPoints: (table: Table, hoverRowIndices: number[], xColKey: string, yColKey: string, xScale: Scale<number, number>, yScale: Scale<number, number>, fillScale: Scale<string, string>) => { | ||
export declare const getLineHoverPoints: (table: Table, hoverRowIndices: number[], xColKey: string, yColKey: string, xScale: Scale<number, number>, yScale: Scale<number, number>, fillScale: Scale<number, string>) => { | ||
x: number; | ||
@@ -4,0 +4,0 @@ y: number; |
@@ -1,10 +0,3 @@ | ||
import { Table, Scale } from '../types'; | ||
export declare type LineData = { | ||
[groupKey: string]: { | ||
xs: number[] | Float64Array; | ||
ys: number[] | Float64Array; | ||
fill: string; | ||
}; | ||
}; | ||
import { Table, Scale, LineData } from '../types'; | ||
export declare const collectLineData: (table: Table, xColKey: string, yColKey: string, fillScale: Scale<string, string>) => LineData; | ||
export declare const simplifyLineData: (lineData: LineData, xScale: any, yScale: any) => LineData; |
@@ -1,2 +0,2 @@ | ||
import { SizedConfig, Margins, Scale, Table } from '../types'; | ||
import { SizedConfig, Margins, Scale, LayerSpec } from '../types'; | ||
export declare class PlotEnv { | ||
@@ -19,6 +19,4 @@ private _config; | ||
readonly yTickFormatter: (tick: number) => string; | ||
getSpec(layerIndex: number): LayerSpec; | ||
getFormatterForColumn: (colKey: string) => (x: any) => string; | ||
getTable: (layerIndex: number) => Table; | ||
getScale: (layerIndex: number, aesthetic: string) => Scale<any, any>; | ||
getMapping: (layerIndex: number, aesthetic: string) => string; | ||
resetDomains: () => void; | ||
@@ -31,7 +29,4 @@ private readonly charMetrics; | ||
private getYDomain; | ||
private getColumnTypeForAesthetics; | ||
private getColumnKeysForAesthetics; | ||
private getDomainForAesthetics; | ||
private getColumnTypeByKey; | ||
private readonly rangePadding; | ||
} |
import { TooltipColumn, Scale, Table } from '../types'; | ||
export declare const getRangeLabel: (min: number, max: number, formatter: any) => string; | ||
export declare const getTooltipGroupColumns: (table: Table, rowIndices: number[], groupColKeys: string[], getValueFormatter: (colKey: string) => (x: any) => string, rowColors: string[]) => TooltipColumn[]; | ||
export declare const getPointsTooltipData: (hoveredRowIndices: number[], table: Table, xColKey: string, yColKey: string, groupColKey: string, getValueFormatter: (colKey: string) => (x: any) => string, fillColKeys: string[], fillScale: Scale<string, string>) => TooltipColumn[]; | ||
export declare const getPointsTooltipData: (hoveredRowIndices: number[], table: Table, xColKey: string, yColKey: string, groupColKey: string, getValueFormatter: (colKey: string) => (x: any) => string, fillColKeys: string[], fillScale: Scale<number, string>) => TooltipColumn[]; |
import { Scale, NumericColumnData } from '../types'; | ||
export declare const useHoverPointIndices: (mode: "x" | "y" | "xy", mouseX: number, mouseY: number, xColData: NumericColumnData, yColData: NumericColumnData, groupColData: string[], xScale: Scale<number, number>, yScale: Scale<number, number>, width: number, height: number) => number[]; | ||
export declare const useHoverPointIndices: (mode: "x" | "y" | "xy", mouseX: number, mouseY: number, xColData: NumericColumnData, yColData: NumericColumnData, groupColData: NumericColumnData, xScale: Scale<number, number>, yScale: Scale<number, number>, width: number, height: number) => number[]; |
{ | ||
"name": "@influxdata/giraffe", | ||
"version": "0.12.1", | ||
"version": "0.12.2", | ||
"main": "dist/index.js", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -6,3 +6,3 @@ This repository contains Giraffe, a React-based visualization library used to implement the [InfluxDB 2.0](https://github.com/influxdata/influxdb/) UI. | ||
## Features | ||
## 🦒 Features | ||
@@ -9,0 +9,0 @@ There exist plenty of terrific visualization libraries in the JavaScript ecosystem. |
@@ -12,3 +12,3 @@ import { | ||
import {Config, LayerConfig} from '../types' | ||
import {Config, LayerConfig, SymbolType} from '../types' | ||
import {NINETEEN_EIGHTY_FOUR as DEFAULT_COLOR_SCHEME} from './colorSchemes' | ||
@@ -70,2 +70,6 @@ | ||
binSize: 10, | ||
strokeWidth: 0, | ||
strokePadding: 0, | ||
strokeOpacity: 0, | ||
fillOpacity: 1, | ||
}, | ||
@@ -82,3 +86,16 @@ scatter: { | ||
binCount: null, | ||
strokeWidth: 1, | ||
strokePadding: 0.75, | ||
strokeOpacity: 1, | ||
fillOpacity: 0.75, | ||
}, | ||
} | ||
export const ALL_SYMBOL_TYPES: SymbolType[] = [ | ||
'circle', | ||
'plus', | ||
'triangle', | ||
'square', | ||
'tritip', | ||
'ex', | ||
] |
@@ -1,3 +0,1 @@ | ||
import {SymbolType} from '../utils/getSymbolScale' | ||
export type NumericColumnData = | ||
@@ -19,7 +17,7 @@ | number[] | ||
export interface GetColumn { | ||
(columnKey: string): ColumnData | ||
(columnKey: string, type: 'number'): NumericColumnData | ||
(columnKey: string, type: 'time'): NumericColumnData | ||
(columnKey: string, type: 'string'): string[] | ||
(columnKey: string, type: 'boolean'): boolean[] | ||
(columnKey: string): ColumnData | null | ||
(columnKey: string, type: 'number'): NumericColumnData | null | ||
(columnKey: string, type: 'time'): NumericColumnData | null | ||
(columnKey: string, type: 'string'): string[] | null | ||
(columnKey: string, type: 'boolean'): boolean[] | null | ||
} | ||
@@ -102,12 +100,2 @@ | ||
export interface LineMappings { | ||
x: string | ||
y: string | ||
fill: string[] | ||
} | ||
export interface LineScales { | ||
fill: Scale<string, string> | ||
} | ||
export interface HeatmapLayerConfig { | ||
@@ -119,27 +107,32 @@ type: 'heatmap' | ||
binSize?: number | ||
strokeWidth?: number | ||
strokePadding?: number | ||
strokeOpacity?: number | ||
fillOpacity?: number | ||
} | ||
export interface HeatmapScales { | ||
fill: Scale<number, string> | ||
} | ||
export type HistogramPosition = 'overlaid' | 'stacked' | ||
export interface HeatmapMappings { | ||
xMin: 'xMin' | ||
xMax: 'xMax' | ||
yMin: 'yMin' | ||
yMax: 'yMax' | ||
fill: 'count' | ||
export interface HistogramLayerConfig { | ||
type: 'histogram' | ||
x: string | ||
fill?: string[] | ||
colors?: string[] | ||
position?: HistogramPosition | ||
binCount?: number | ||
strokeWidth?: number | ||
strokePadding?: number | ||
strokeOpacity?: number | ||
fillOpacity?: number | ||
} | ||
export interface HistogramMappings { | ||
xMin: 'xMin' | ||
xMax: 'xMax' | ||
yMin: 'yMin' | ||
yMax: 'yMax' | ||
fill: string[] | ||
} | ||
export type RectLayerConfig = HistogramLayerConfig | HeatmapLayerConfig | ||
export interface HistogramScales { | ||
fill: Scale<string, string> | ||
} | ||
export type SymbolType = | ||
| 'circle' | ||
| 'triangle' | ||
| 'square' | ||
| 'plus' | ||
| 'tritip' | ||
| 'ex' | ||
@@ -155,26 +148,2 @@ export interface ScatterLayerConfig { | ||
export interface ScatterMappings { | ||
x: string | ||
y: string | ||
fill: string[] | ||
symbol: string[] | ||
} | ||
export interface ScatterScales { | ||
fill: Scale<string, string> | ||
symbol: Scale<string, SymbolType> | ||
} | ||
export type Mappings = | ||
| LineMappings | ||
| HistogramMappings | ||
| HeatmapMappings | ||
| ScatterMappings | ||
export type Scales = | ||
| LineScales | ||
| HistogramScales | ||
| HeatmapScales | ||
| ScatterScales | ||
export type LayerConfig = | ||
@@ -186,13 +155,2 @@ | LineLayerConfig | ||
export type HistogramPosition = 'overlaid' | 'stacked' | ||
export interface HistogramLayerConfig { | ||
type: 'histogram' | ||
x: string | ||
fill?: string[] | ||
colors?: string[] | ||
position?: HistogramPosition | ||
binCount?: number | ||
} | ||
export interface Config { | ||
@@ -249,1 +207,113 @@ table: Table | ||
export type SizedConfig = Config & {width: number; height: number} | ||
export interface ColumnGroupMap { | ||
// The column keys that specify the grouping | ||
columnKeys: string[] | ||
// A group ID `i` takes on the values specified by `mappings[i]` for the | ||
// column keys that specify the grouping | ||
mappings: Array<{[columnKey: string]: any}> | ||
} | ||
export type LineData = { | ||
[groupID: number]: { | ||
xs: number[] | ||
ys: number[] | ||
fill: string | ||
} | ||
} | ||
export interface LineLayerSpec { | ||
type: 'line' | ||
inputTable: Table | ||
table: Table // has `FILL` column added | ||
lineData: LineData | ||
xDomain: number[] | ||
yDomain: number[] | ||
xColumnKey: string | ||
yColumnKey: string | ||
xColumnType: ColumnType | ||
yColumnType: ColumnType | ||
scales: { | ||
fill: Scale<number, string> | ||
} | ||
columnGroupMaps: { | ||
fill: ColumnGroupMap | ||
} | ||
} | ||
export interface ScatterLayerSpec { | ||
type: 'scatter' | ||
inputTable: Table | ||
table: Table // has `FILL` and `SYMBOL` columns added | ||
xDomain: number[] | ||
yDomain: number[] | ||
xColumnKey: string | ||
yColumnKey: string | ||
xColumnType: ColumnType | ||
yColumnType: ColumnType | ||
scales: { | ||
fill: Scale<number, string> | ||
symbol: Scale<number, SymbolType> | ||
} | ||
columnGroupMaps: { | ||
fill: ColumnGroupMap | ||
symbol: ColumnGroupMap | ||
} | ||
} | ||
export interface RectLayerSpec { | ||
type: 'rect' | ||
inputTable: Table | ||
table: Table // has `X_MIN`, `X_MAX`, `Y_MIN`, `Y_MAX`, and `COUNT` columns, and maybe a `FILL` column | ||
binDimension: 'xy' | 'x' | ||
xDomain: number[] | ||
yDomain: number[] | ||
xColumnKey: string | ||
yColumnKey: string | ||
xColumnType: ColumnType | ||
yColumnType: ColumnType | ||
scales: {fill: Scale<number, string>} | ||
columnGroupMaps: {fill?: ColumnGroupMap} | ||
} | ||
export interface LayerProps { | ||
xScale: Scale<number, number> | ||
yScale: Scale<number, number> | ||
width: number | ||
height: number | ||
spec: LayerSpec | ||
config: LayerConfig | ||
plotConfig: SizedConfig | ||
columnFormatter: (colKey: string) => (x: any) => string | ||
hoverX: number | null | ||
hoverY: number | null | ||
} | ||
/* | ||
When a user supplies a config for a layer, we derive various data from it: | ||
- If the layer implies a certain statistical transform or aggregate, we | ||
compute it. For example: a histogram layer needs to place data into bins, | ||
and count the number of observations within each bin. | ||
- Some layers support _group aesthetics_. These are aesthetics which multiple | ||
columns in the input table may be mapped to at once. In this case, we | ||
synthesize a new column in the table that contains a numeric group ID for | ||
each unique combination of values from these columns. We also record the | ||
values for each column that a particular group ID maps to, so that we can | ||
display those values in a legend. | ||
- For any data-to-aesthetic mapping, we create a scale function. The | ||
exception to this is for the `x` and `y` aesthetics; since multiple layers | ||
should use the same scale for `x` and `y` aesthetics, we do not generate | ||
those scales in a layer transform. Instead we record the `xDomain` and | ||
`yDomain` of the (transformed) data for the layer, so that some other | ||
entity may compute these scales. | ||
- We record the `xColumnType` and `yColumnType` for the layer, so that we can | ||
format x and y values from the layer approriately. | ||
We call the collection of this derived data a "spec". | ||
*/ | ||
export type LayerSpec = LineLayerSpec | ScatterLayerSpec | RectLayerSpec |
interface DrawLinePointOptions { | ||
canvas: HTMLCanvasElement | ||
context: CanvasRenderingContext2D | ||
width: number | ||
@@ -13,3 +13,3 @@ height: number | ||
export const drawLineHoverData = ({ | ||
canvas, | ||
context, | ||
width, | ||
@@ -23,4 +23,2 @@ height, | ||
}: DrawLinePointOptions): void => { | ||
const context = canvas.getContext('2d') | ||
context.strokeStyle = crosshairColor | ||
@@ -27,0 +25,0 @@ |
import {line, curveLinear, area} from 'd3-shape' | ||
import {range} from 'd3-array' | ||
import {LineInterpolation} from '../types' | ||
import {LineData} from './lineData' | ||
import {LineInterpolation, LineData} from '../types' | ||
import {CURVES} from '../constants' | ||
@@ -10,3 +9,3 @@ import {isDefined} from '../utils/isDefined' | ||
interface DrawLinesOptions { | ||
canvas: HTMLCanvasElement | ||
context: CanvasRenderingContext2D | ||
interpolation: LineInterpolation | ||
@@ -21,3 +20,3 @@ lineData: LineData | ||
export const drawLines = ({ | ||
canvas, | ||
context, | ||
lineData, | ||
@@ -30,4 +29,2 @@ interpolation, | ||
}: DrawLinesOptions): void => { | ||
const context = canvas.getContext('2d') | ||
if (shadeBelow) { | ||
@@ -34,0 +31,0 @@ for (const {xs, ys, fill} of Object.values(lineData)) { |
@@ -1,3 +0,2 @@ | ||
import {Scale, NumericColumnData} from '../types' | ||
import {clearCanvas} from '../utils/clearCanvas' | ||
import {Scale, NumericColumnData, SymbolType} from '../types' | ||
import { | ||
@@ -13,13 +12,11 @@ drawCircle, | ||
interface DrawPointsOptions { | ||
canvas: HTMLCanvasElement | ||
width: number | ||
height: number | ||
context: CanvasRenderingContext2D | ||
xColData: NumericColumnData | ||
yColData: NumericColumnData | ||
fillColData: string[] | ||
symbolColData: string[] | ||
fillColData: NumericColumnData | ||
symbolColData: NumericColumnData | ||
yScale: Scale<number, number> | ||
xScale: Scale<number, number> | ||
fillScale: Scale<string, string> | ||
symbolScale: Scale<string, string> | ||
fillScale: Scale<number, string> | ||
symbolScale: Scale<number, SymbolType> | ||
pointSize: number | ||
@@ -30,5 +27,3 @@ rowIndices?: number[] | ||
export const drawPoints = ({ | ||
canvas, | ||
width, | ||
height, | ||
context, | ||
xColData, | ||
@@ -45,5 +40,2 @@ yColData, | ||
}: DrawPointsOptions): void => { | ||
clearCanvas(canvas, width, height) | ||
const context = canvas.getContext('2d') | ||
const n = rowIndices ? rowIndices.length : xColData.length | ||
@@ -50,0 +42,0 @@ |
@@ -12,7 +12,7 @@ import {Table, Scale} from '../types' | ||
yScale: Scale<number, number>, | ||
fillScale: Scale<string, string> | ||
fillScale: Scale<number, string> | ||
): Array<{x: number; y: number; fill: string}> => { | ||
const xColData = table.getColumn(xColKey, 'number') | ||
const yColData = table.getColumn(yColKey, 'number') | ||
const groupColData = table.getColumn(FILL, 'string') | ||
const groupColData = table.getColumn(FILL, 'number') | ||
@@ -19,0 +19,0 @@ return hoverRowIndices.map(i => ({ |
@@ -1,13 +0,5 @@ | ||
import {Table, Scale} from '../types' | ||
import {Table, Scale, LineData} from '../types' | ||
import {simplify} from '../utils/simplify' | ||
import {FILL} from '../constants/columnKeys' | ||
export type LineData = { | ||
[groupKey: string]: { | ||
xs: number[] | Float64Array | ||
ys: number[] | Float64Array | ||
fill: string | ||
} | ||
} | ||
export const collectLineData = ( | ||
@@ -14,0 +6,0 @@ table: Table, |
@@ -55,3 +55,3 @@ import {Table, ColumnType, ColumnData} from '../types' | ||
if (!column) { | ||
throw new Error('column not found') | ||
return null | ||
} | ||
@@ -66,3 +66,3 @@ | ||
if (!column) { | ||
throw new Error('column not found') | ||
return null | ||
} | ||
@@ -69,0 +69,0 @@ |
@@ -5,3 +5,3 @@ /* | ||
import {SizedConfig, LineLayerConfig} from '../types' | ||
import {SizedConfig, LineLayerConfig, RectLayerSpec} from '../types' | ||
import {PlotEnv} from './PlotEnv' | ||
@@ -11,3 +11,4 @@ import {newTable} from './newTable' | ||
import * as layerTransforms from '../layerTransforms' | ||
import * as lineTransformModule from '../transforms/line' | ||
import * as histogramTransformModule from '../transforms/histogram' | ||
@@ -20,4 +21,8 @@ describe('PlotEnv', () => { | ||
beforeEach(() => { | ||
histogramTransformSpy = jest.spyOn(layerTransforms, 'getHistogramTable') | ||
lineTransformSpy = jest.spyOn(layerTransforms, 'getLineTable') | ||
histogramTransformSpy = jest.spyOn( | ||
histogramTransformModule, | ||
'histogramTransform' | ||
) | ||
lineTransformSpy = jest.spyOn(lineTransformModule, 'lineTransform') | ||
}) | ||
@@ -82,3 +87,6 @@ | ||
const getFirstBinCount = () => | ||
plotEnv.getTable(0).getColumn(COUNT, 'number')[0] | ||
(plotEnv.getSpec(0) as RectLayerSpec).table.getColumn( | ||
COUNT, | ||
'number' | ||
)[0] | ||
@@ -113,3 +121,6 @@ expect(getFirstBinCount()).toEqual(1) | ||
const getFirstBinCount = () => | ||
plotEnv.getTable(0).getColumn(COUNT, 'number')[0] | ||
(plotEnv.getSpec(0) as RectLayerSpec).table.getColumn( | ||
COUNT, | ||
'number' | ||
)[0] | ||
@@ -128,3 +139,3 @@ expect(getFirstBinCount()).toEqual(1) | ||
test('does not run bin stat when histogram colors change', () => { | ||
test('does not run bin stat when histogram fillOpacity change', () => { | ||
const plotEnv = new PlotEnv() | ||
@@ -139,5 +150,3 @@ | ||
height: 500, | ||
layers: [ | ||
{type: 'histogram', x: 'a', binCount: 10, colors: ['red', 'blue']}, | ||
], | ||
layers: [{type: 'histogram', x: 'a', binCount: 10, fillOpacity: 1}], | ||
} | ||
@@ -149,3 +158,3 @@ | ||
plotEnv.getTable(0) | ||
plotEnv.getSpec(0) | ||
@@ -156,8 +165,6 @@ expect(histogramTransformSpy).toHaveBeenCalledTimes(1) | ||
...config, | ||
layers: [ | ||
{type: 'histogram', x: 'a', binCount: 10, colors: ['red', 'green']}, | ||
], | ||
layers: [{type: 'histogram', x: 'a', binCount: 10, fillOpacity: 0.5}], | ||
} | ||
plotEnv.getTable(0) | ||
plotEnv.getSpec(0) | ||
@@ -221,3 +228,3 @@ expect(histogramTransformSpy).toHaveBeenCalledTimes(1) | ||
plotEnv.getTable(0) | ||
plotEnv.getSpec(0) | ||
@@ -228,3 +235,3 @@ expect(lineTransformSpy).toHaveBeenCalledTimes(1) | ||
plotEnv.getTable(0) | ||
plotEnv.getSpec(0) | ||
@@ -231,0 +238,0 @@ expect(lineTransformSpy).toHaveBeenCalledTimes(1) |
@@ -1,24 +0,6 @@ | ||
import { | ||
SizedConfig, | ||
Margins, | ||
Scale, | ||
Table, | ||
ColumnType, | ||
LineLayerConfig, | ||
} from '../types' | ||
import { | ||
DEFAULT_RANGE_PADDING, | ||
LAYER_DEFAULTS, | ||
CONFIG_DEFAULTS, | ||
} from '../constants' | ||
import * as transforms from '../layerTransforms' | ||
import {getTicks} from './getTicks' | ||
import {getTimeFormatter} from '../utils/getTimeFormatter' | ||
import {assert} from './assert' | ||
import {getTextMetrics} from './getTextMetrics' | ||
import {getMargins} from './getMargins' | ||
import {extentOfExtents} from './extrema' | ||
import {flatMap} from './flatMap' | ||
import {identityMerge} from './identityMerge' | ||
@@ -28,3 +10,22 @@ import {MemoizedFunctionCache} from './MemoizedFunctionCache' | ||
import {getLinearScale} from './getLinearScale' | ||
import {lineTransform} from '../transforms/line' | ||
import {scatterTransform} from '../transforms/scatter' | ||
import {histogramTransform} from '../transforms/histogram' | ||
import {heatmapTransform} from '../transforms/heatmap' | ||
import { | ||
DEFAULT_RANGE_PADDING, | ||
LAYER_DEFAULTS, | ||
CONFIG_DEFAULTS, | ||
} from '../constants' | ||
import { | ||
SizedConfig, | ||
Margins, | ||
Scale, | ||
LineLayerConfig, | ||
LayerSpec, | ||
ColumnType, | ||
} from '../types' | ||
const X_DOMAIN_AESTHETICS = ['x', 'xMin', 'xMax'] | ||
@@ -96,3 +97,3 @@ const Y_DOMAIN_AESTHETICS = ['y', 'yMin', 'yMax'] | ||
'horizontal', | ||
this.getColumnTypeForAesthetics(['x', 'xMin', 'xMax']), | ||
this.getSpec(0).xColumnType, | ||
this.charMetrics | ||
@@ -109,3 +110,3 @@ ) | ||
'vertical', | ||
this.getColumnTypeForAesthetics(['y', 'yMin', 'yMax']), | ||
this.getSpec(0).yColumnType, | ||
this.charMetrics | ||
@@ -180,129 +181,101 @@ ) | ||
public get xTickFormatter(): (tick: number) => string { | ||
const colKeys = this.getColumnKeysForAesthetics(X_DOMAIN_AESTHETICS) | ||
const firstXMapping = this.getSpec(0).xColumnKey | ||
return this.getFormatterForColumn(colKeys[0]) | ||
return this.getFormatterForColumn(firstXMapping) | ||
} | ||
public get yTickFormatter(): (tick: number) => string { | ||
const colKeys = this.getColumnKeysForAesthetics(Y_DOMAIN_AESTHETICS) | ||
const firstYMapping = this.getSpec(0).yColumnKey | ||
return this.getFormatterForColumn(colKeys[0]) | ||
return this.getFormatterForColumn(firstYMapping) | ||
} | ||
public getFormatterForColumn = (colKey: string): ((x: any) => string) => { | ||
const preferredFormatter = this.config.valueFormatters[colKey] | ||
public getSpec(layerIndex: number): LayerSpec { | ||
const layerConfig = this.config.layers[layerIndex] | ||
const table = this.config.table | ||
if (preferredFormatter) { | ||
return preferredFormatter | ||
} | ||
const memoizedTransformKey = `${layerIndex}: ${layerConfig.type}` | ||
const colType = this.getColumnTypeByKey(colKey) | ||
switch (colType) { | ||
case 'number': | ||
return defaultNumberFormatter | ||
case 'time': | ||
return this.timeFormatter | ||
default: | ||
return DEFAULT_FORMATTER | ||
} | ||
} | ||
public getTable = (layerIndex: number): Table => { | ||
const table = this.config.table | ||
const layerConfig = this.config.layers[layerIndex] | ||
const transformKey = `${layerIndex} ${layerConfig.type} table` | ||
switch (layerConfig.type) { | ||
case 'line': { | ||
const {fill} = layerConfig | ||
const transform = this.fns.get(transformKey, transforms.getLineTable) | ||
const transform = this.fns.get(memoizedTransformKey, lineTransform) | ||
return transform(table, fill) | ||
return transform( | ||
table, | ||
layerConfig.x, | ||
layerConfig.y, | ||
layerConfig.fill, | ||
layerConfig.colors | ||
) | ||
} | ||
case 'scatter': { | ||
const {fill, symbol} = layerConfig | ||
const transform = this.fns.get(transformKey, transforms.getScatterTable) | ||
const transform = this.fns.get(memoizedTransformKey, scatterTransform) | ||
return transform(table, fill, symbol) | ||
return transform( | ||
table, | ||
layerConfig.x, | ||
layerConfig.y, | ||
layerConfig.fill, | ||
layerConfig.symbol, | ||
layerConfig.colors | ||
) | ||
} | ||
case 'histogram': { | ||
const {x, fill, binCount, position} = layerConfig | ||
const transform = this.fns.get(memoizedTransformKey, histogramTransform) | ||
const transform = this.fns.get( | ||
transformKey, | ||
transforms.getHistogramTable | ||
return transform( | ||
table, | ||
layerConfig.x, | ||
this.config.xDomain, | ||
layerConfig.colors, | ||
layerConfig.fill, | ||
layerConfig.binCount, | ||
layerConfig.position | ||
) | ||
} | ||
case 'heatmap': { | ||
const transform = this.fns.get(memoizedTransformKey, heatmapTransform) | ||
return transform( | ||
table, | ||
x, | ||
layerConfig.x, | ||
layerConfig.y, | ||
this.config.xDomain, | ||
fill, | ||
binCount, | ||
position | ||
this.config.yDomain, | ||
this.config.width, | ||
this.config.height, | ||
layerConfig.binSize, | ||
layerConfig.colors | ||
) | ||
} | ||
case 'heatmap': { | ||
const {x, y, binSize} = layerConfig | ||
const {width, height, xDomain, yDomain} = this.config | ||
const transform = this.fns.get(transformKey, transforms.getHeatmapTable) | ||
return transform(table, x, y, xDomain, yDomain, width, height, binSize) | ||
} | ||
default: { | ||
return this.config.table | ||
} | ||
default: | ||
const unknownConfig: never = layerConfig | ||
const unknownType = (unknownConfig as any).type | ||
throw new Error( | ||
`transform not implemented for layer of type "${unknownType}"` | ||
) | ||
} | ||
} | ||
public getScale = (layerIndex: number, aesthetic: string): Scale => { | ||
const {type: layerType, colors} = this.config.layers[layerIndex] | ||
const transformKey = `${layerIndex} ${layerType} scales` | ||
const table = this.getTable(layerIndex) | ||
public getFormatterForColumn = (colKey: string): ((x: any) => string) => { | ||
const preferredFormatter = this.config.valueFormatters[colKey] | ||
switch (layerType) { | ||
case 'line': { | ||
const getter = this.fns.get(transformKey, transforms.getLineScales) | ||
return getter(table, colors)[aesthetic] | ||
} | ||
case 'scatter': { | ||
const getter = this.fns.get(transformKey, transforms.getScatterScales) | ||
return getter(table, colors)[aesthetic] | ||
} | ||
case 'histogram': { | ||
const getter = this.fns.get(transformKey, transforms.getHistogramScales) | ||
return getter(table, colors)[aesthetic] | ||
} | ||
case 'heatmap': { | ||
const getter = this.fns.get(transformKey, transforms.getHeatmapScales) | ||
return getter(table, colors)[aesthetic] | ||
} | ||
default: { | ||
throw new Error(`${aesthetic} scale for layer ${layerIndex} not found`) | ||
} | ||
if (preferredFormatter) { | ||
return preferredFormatter | ||
} | ||
} | ||
public getMapping = ( | ||
layerIndex: number, | ||
aesthetic: string | ||
): string | null => { | ||
const layerConfig = this.config.layers[layerIndex] | ||
const colType = this.getColumnTypeByKey(colKey) | ||
switch (layerConfig.type) { | ||
case 'line': | ||
return transforms.getLineMappings(layerConfig)[aesthetic] | ||
case 'scatter': | ||
return transforms.getScatterMappings(layerConfig)[aesthetic] | ||
case 'heatmap': | ||
return transforms.getHeatmapMappings()[aesthetic] | ||
case 'histogram': | ||
return transforms.getHistogramMappings(layerConfig.fill)[aesthetic] | ||
switch (colType) { | ||
case 'number': | ||
return defaultNumberFormatter | ||
case 'time': | ||
return this.timeFormatter | ||
default: | ||
return null | ||
return DEFAULT_FORMATTER | ||
} | ||
@@ -358,95 +331,31 @@ } | ||
private getXDomain() { | ||
return this.getDomainForAesthetics(X_DOMAIN_AESTHETICS) || DEFAULT_X_DOMAIN | ||
return ( | ||
extentOfExtents( | ||
...this.config.layers.map((_, i) => this.getSpec(i).xDomain) | ||
) || DEFAULT_X_DOMAIN | ||
) | ||
} | ||
private getYDomain() { | ||
return this.getDomainForAesthetics(Y_DOMAIN_AESTHETICS) || DEFAULT_Y_DOMAIN | ||
} | ||
private getColumnTypeForAesthetics(aesthetics: string[]): ColumnType | null { | ||
const columnTypes: ColumnType[] = this.config.layers.reduce( | ||
(acc, _, layerIndex) => { | ||
const table = this.getTable(layerIndex) | ||
const colKeys = aesthetics | ||
.map(aes => this.getMapping(layerIndex, aes)) | ||
.filter(d => !!d) | ||
return [...acc, ...colKeys.map(k => table.getColumnType(k))] | ||
}, | ||
[] | ||
return ( | ||
extentOfExtents( | ||
...this.config.layers.map((_, i) => this.getSpec(i).yDomain) | ||
) || DEFAULT_Y_DOMAIN | ||
) | ||
if (!columnTypes.length) { | ||
return null | ||
} | ||
assert( | ||
columnTypes.every(t => t === columnTypes[0]), | ||
`found multiple column types for aesthetics "${aesthetics}"` | ||
) | ||
return columnTypes[0] | ||
} | ||
private getColumnKeysForAesthetics(aesthetics: string[]): string[] { | ||
return flatMap((layer, layerIndex) => { | ||
const columnKeysForLayer = aesthetics.reduce((acc, aes) => { | ||
if (layer[aes]) { | ||
return [...acc, layer[aes]] | ||
} | ||
private getColumnTypeByKey(columnKey): ColumnType { | ||
const suppliedColumnType = this.config.table.getColumnType(columnKey) | ||
const derivedMapping = this.getMapping(layerIndex, aes) | ||
if (derivedMapping) { | ||
return [...acc, derivedMapping] | ||
} | ||
return acc | ||
}, []) | ||
return columnKeysForLayer | ||
}, this.config.layers) | ||
} | ||
private getDomainForAesthetics(aesthetics: string[]): number[] { | ||
// Collect column data arrays for all columns in the plot currently mapped | ||
// to any of the passed `aesthetics` | ||
const colData: number[][] = this.config.layers.reduce( | ||
(acc, _, layerIndex) => { | ||
const table = this.getTable(layerIndex) | ||
const colKeys = aesthetics | ||
.map(aes => this.getMapping(layerIndex, aes)) | ||
.filter(d => !!d) | ||
return [...acc, ...colKeys.map(k => table.getColumn(k))] | ||
}, | ||
[] | ||
) | ||
const fnKey = `extentOfExtents ${aesthetics.join(', ')}` | ||
const fn = this.fns.get(fnKey, extentOfExtents) | ||
// Compute the domain of all of those columns (memoized, since doing so is | ||
// an expensive operation) | ||
const domain = fn(...colData) | ||
return domain | ||
} | ||
private getColumnTypeByKey(key: string): ColumnType { | ||
if (this.config.table.columnKeys.includes(key)) { | ||
return this.config.table.getColumnType(key) | ||
if (suppliedColumnType) { | ||
return suppliedColumnType | ||
} | ||
for (let i = 0; i < this.config.layers.length; i++) { | ||
const table = this.getTable(i) | ||
const derivedColumnType = this.config.layers | ||
.map((_, i) => this.getSpec(i).table) | ||
.filter(table => !!table) | ||
.map(table => table.getColumnType(columnKey)) | ||
.find(k => !!k) | ||
if (table.columnKeys.includes(key)) { | ||
return table.getColumnType(key) | ||
} | ||
} | ||
return null | ||
return derivedColumnType | ||
} | ||
@@ -499,4 +408,2 @@ | ||
// TODO: can be stale via binCount | ||
const xyMappingsChanged = [ | ||
@@ -515,3 +422,12 @@ ...X_DOMAIN_AESTHETICS, | ||
const binCountChanged = config.layers.some( | ||
(layer: any, layerIndex) => | ||
layer.binCount !== (prevConfig.layers[layerIndex] as any).binCount | ||
) | ||
if (binCountChanged) { | ||
return true | ||
} | ||
return false | ||
} |
@@ -19,3 +19,3 @@ import {TooltipData, TooltipColumn, Scale, Table} from '../types' | ||
export const getTooltipGroupColumns = ( | ||
const getTooltipGroupColumns = ( | ||
table: Table, | ||
@@ -48,7 +48,7 @@ rowIndices: number[], | ||
fillColKeys: string[], | ||
fillScale: Scale<string, string> | ||
fillScale: Scale<number, string> | ||
): TooltipData => { | ||
const xColData = table.getColumn(xColKey, 'number') | ||
const yColData = table.getColumn(yColKey, 'number') | ||
const groupColData = table.getColumn(groupColKey, 'string') | ||
const groupColData = table.getColumn(groupColKey, 'number') | ||
const colors = hoveredRowIndices.map(i => fillScale(groupColData[i])) | ||
@@ -55,0 +55,0 @@ const xFormatter = getValueFormatter(xColKey) |
@@ -14,3 +14,3 @@ import {range} from 'd3-array' | ||
yColData: NumericColumnData, | ||
groupColData: string[], | ||
groupColData: NumericColumnData, | ||
xScale: Scale<number, number>, | ||
@@ -341,3 +341,3 @@ yScale: Scale<number, number>, | ||
colData: NumericColumnData, | ||
groupColData: string[], | ||
groupColData: NumericColumnData, | ||
length: number | ||
@@ -400,3 +400,3 @@ ): number[] => { | ||
colData: NumericColumnData, | ||
groupColData: string[] | ||
groupColData: NumericColumnData | ||
): void => { | ||
@@ -403,0 +403,0 @@ for (const i of rowIndices) { |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
819806
147
10556