mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Add react-table typings to Table (#21418)
* add typings * introduce tyings and refactor accordingly * extract setting celltype * update tests to reflect changes * removing unused things * renaming getCellType -> getCellDisplayType * fix width type error * remove caret * move cell back to utils, fix story * remove unused import * rename type
This commit is contained in:
parent
b6c75b10d1
commit
30eef76162
@ -30,6 +30,7 @@
|
||||
"@torkelo/react-select": "2.1.1",
|
||||
"@types/react-color": "2.17.0",
|
||||
"@types/react-select": "2.0.15",
|
||||
"@types/react-table": "7.0.2",
|
||||
"@types/slate": "0.47.1",
|
||||
"@types/slate-react": "0.22.5",
|
||||
"bizcharts": "^3.5.5",
|
||||
|
@ -0,0 +1,30 @@
|
||||
import React, { CSSProperties, FC } from 'react';
|
||||
import { TableCellProps } from './types';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { formattedValueToString } from '@grafana/data';
|
||||
|
||||
export const BackgroundColoredCell: FC<TableCellProps> = props => {
|
||||
const { cell, tableStyles, field } = props;
|
||||
|
||||
if (!field.display) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const themeFactor = tableStyles.theme.isDark ? 1 : -0.7;
|
||||
const displayValue = field.display(cell.value);
|
||||
|
||||
const bgColor2 = tinycolor(displayValue.color)
|
||||
.darken(10 * themeFactor)
|
||||
.spin(5)
|
||||
.toRgbString();
|
||||
|
||||
const styles: CSSProperties = {
|
||||
background: `linear-gradient(120deg, ${bgColor2}, ${displayValue.color})`,
|
||||
borderRadius: '0px',
|
||||
color: 'white',
|
||||
height: tableStyles.cellHeight,
|
||||
padding: tableStyles.cellPadding,
|
||||
};
|
||||
|
||||
return <div style={styles}>{formattedValueToString(displayValue)}</div>;
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
import React, { FC } from 'react';
|
||||
import { ReactTableCellProps, TableCellDisplayMode } from './types';
|
||||
import { BarGauge, BarGaugeDisplayMode } from '../BarGauge/BarGauge';
|
||||
import { ThresholdsConfig, ThresholdsMode, VizOrientation } from '@grafana/data';
|
||||
import { BarGauge, BarGaugeDisplayMode } from '../BarGauge/BarGauge';
|
||||
import { TableCellProps, TableCellDisplayMode } from './types';
|
||||
|
||||
const defaultScale: ThresholdsConfig = {
|
||||
mode: ThresholdsMode.Absolute,
|
||||
@ -17,9 +17,8 @@ const defaultScale: ThresholdsConfig = {
|
||||
],
|
||||
};
|
||||
|
||||
export const BarGaugeCell: FC<ReactTableCellProps> = props => {
|
||||
const { column, tableStyles, cell } = props;
|
||||
const { field } = column;
|
||||
export const BarGaugeCell: FC<TableCellProps> = props => {
|
||||
const { field, column, tableStyles, cell } = props;
|
||||
|
||||
if (!field.display) {
|
||||
return null;
|
||||
@ -40,10 +39,17 @@ export const BarGaugeCell: FC<ReactTableCellProps> = props => {
|
||||
barGaugeMode = BarGaugeDisplayMode.Lcd;
|
||||
}
|
||||
|
||||
let width;
|
||||
if (column.width) {
|
||||
width = (column.width as number) - tableStyles.cellPadding * 2;
|
||||
} else {
|
||||
width = tableStyles.cellPadding * 2;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={tableStyles.tableCell}>
|
||||
<BarGauge
|
||||
width={column.width - tableStyles.cellPadding * 2}
|
||||
width={width}
|
||||
height={tableStyles.cellHeightInner}
|
||||
field={config}
|
||||
value={displayValue}
|
||||
|
@ -1,41 +1,14 @@
|
||||
import React, { FC, CSSProperties } from 'react';
|
||||
import { ReactTableCellProps } from './types';
|
||||
import React, { FC } from 'react';
|
||||
import { TableCellProps } from './types';
|
||||
import { formattedValueToString } from '@grafana/data';
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
export const DefaultCell: FC<ReactTableCellProps> = props => {
|
||||
const { column, cell, tableStyles } = props;
|
||||
export const DefaultCell: FC<TableCellProps> = props => {
|
||||
const { field, cell, tableStyles } = props;
|
||||
|
||||
if (!column.field.display) {
|
||||
if (!field.display) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const displayValue = column.field.display(cell.value);
|
||||
const displayValue = field.display(cell.value);
|
||||
return <div className={tableStyles.tableCell}>{formattedValueToString(displayValue)}</div>;
|
||||
};
|
||||
|
||||
export const BackgroundColoredCell: FC<ReactTableCellProps> = props => {
|
||||
const { column, cell, tableStyles } = props;
|
||||
|
||||
if (!column.field.display) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const themeFactor = tableStyles.theme.isDark ? 1 : -0.7;
|
||||
const displayValue = column.field.display(cell.value);
|
||||
|
||||
const bgColor2 = tinycolor(displayValue.color)
|
||||
.darken(10 * themeFactor)
|
||||
.spin(5)
|
||||
.toRgbString();
|
||||
|
||||
const styles: CSSProperties = {
|
||||
background: `linear-gradient(120deg, ${bgColor2}, ${displayValue.color})`,
|
||||
borderRadius: '0px',
|
||||
color: 'white',
|
||||
height: tableStyles.cellHeight,
|
||||
padding: tableStyles.cellPadding,
|
||||
};
|
||||
|
||||
return <div style={styles}>{formattedValueToString(displayValue)}</div>;
|
||||
};
|
||||
|
@ -5,13 +5,15 @@ import { number } from '@storybook/addon-knobs';
|
||||
import { useTheme } from '../../themes';
|
||||
import mdx from './Table.mdx';
|
||||
import {
|
||||
applyFieldOverrides,
|
||||
ConfigOverrideRule,
|
||||
DataFrame,
|
||||
MutableDataFrame,
|
||||
FieldMatcherID,
|
||||
FieldType,
|
||||
GrafanaTheme,
|
||||
applyFieldOverrides,
|
||||
FieldMatcherID,
|
||||
ConfigOverrideRule,
|
||||
MutableDataFrame,
|
||||
ThresholdsConfig,
|
||||
ThresholdsMode,
|
||||
} from '@grafana/data';
|
||||
|
||||
export default {
|
||||
@ -56,7 +58,7 @@ function buildData(theme: GrafanaTheme, overrides: ConfigOverrideRule[]): DataFr
|
||||
config: {
|
||||
unit: 'percent',
|
||||
custom: {
|
||||
width: 50,
|
||||
width: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -118,7 +120,8 @@ export const BarGaugeCell = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const defaultThresholds = [
|
||||
const defaultThresholds: ThresholdsConfig = {
|
||||
steps: [
|
||||
{
|
||||
color: 'blue',
|
||||
value: -Infinity,
|
||||
@ -127,7 +130,9 @@ const defaultThresholds = [
|
||||
color: 'green',
|
||||
value: 20,
|
||||
},
|
||||
];
|
||||
],
|
||||
mode: ThresholdsMode.Absolute,
|
||||
};
|
||||
|
||||
export const ColoredCells = () => {
|
||||
const theme = useTheme();
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React, { useMemo, CSSProperties } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { DataFrame } from '@grafana/data';
|
||||
// @ts-ignore
|
||||
import { useSortBy, useTable, useBlockLayout } from 'react-table';
|
||||
import { useSortBy, useTable, useBlockLayout, Cell } from 'react-table';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
import { getTableStyles } from './styles';
|
||||
import { getColumns, getTableRows } from './utils';
|
||||
import { TableColumn } from './types';
|
||||
import { useTheme } from '../../themes';
|
||||
import { TableFilterActionCallback } from './types';
|
||||
import { getTableStyles } from './styles';
|
||||
import { TableCell } from './TableCell';
|
||||
|
||||
export interface Props {
|
||||
data: DataFrame;
|
||||
@ -15,17 +15,14 @@ export interface Props {
|
||||
onCellClick?: TableFilterActionCallback;
|
||||
}
|
||||
|
||||
type TableFilterActionCallback = (key: string, value: string) => void;
|
||||
|
||||
export const Table = ({ data, height, onCellClick, width }: Props) => {
|
||||
const theme = useTheme();
|
||||
const tableStyles = getTableStyles(theme);
|
||||
|
||||
const { getTableProps, headerGroups, rows, prepareRow } = useTable(
|
||||
{
|
||||
columns: useMemo(() => getColumns(data, width, theme), [data]),
|
||||
columns: useMemo(() => getColumns(data, width), [data]),
|
||||
data: useMemo(() => getTableRows(data), [data]),
|
||||
tableStyles,
|
||||
},
|
||||
useSortBy,
|
||||
useBlockLayout
|
||||
@ -37,7 +34,15 @@ export const Table = ({ data, height, onCellClick, width }: Props) => {
|
||||
prepareRow(row);
|
||||
return (
|
||||
<div {...row.getRowProps({ style })} className={tableStyles.row}>
|
||||
{row.cells.map((cell: RenderCellProps) => renderCell(cell, onCellClick))}
|
||||
{row.cells.map((cell: Cell, index: number) => (
|
||||
<TableCell
|
||||
key={index}
|
||||
field={data.fields[cell.column.index]}
|
||||
tableStyles={tableStyles}
|
||||
cell={cell}
|
||||
onCellClick={onCellClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
@ -60,34 +65,6 @@ export const Table = ({ data, height, onCellClick, width }: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
interface RenderCellProps {
|
||||
column: TableColumn;
|
||||
value: any;
|
||||
getCellProps: () => { style: CSSProperties };
|
||||
render: (component: string) => React.ReactNode;
|
||||
}
|
||||
|
||||
function renderCell(cell: RenderCellProps, onCellClick?: TableFilterActionCallback) {
|
||||
const filterable = cell.column.field.config.filterable;
|
||||
const cellProps = cell.getCellProps();
|
||||
let onClick: ((event: React.SyntheticEvent) => void) | undefined = undefined;
|
||||
|
||||
if (filterable && onCellClick) {
|
||||
cellProps.style.cursor = 'pointer';
|
||||
onClick = () => onCellClick(cell.column.Header, cell.value);
|
||||
}
|
||||
|
||||
if (cell.column.textAlign) {
|
||||
cellProps.style.textAlign = cell.column.textAlign;
|
||||
}
|
||||
|
||||
return (
|
||||
<div {...cellProps} onClick={onClick}>
|
||||
{cell.render('Cell')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function renderHeaderCell(column: any, className: string) {
|
||||
const headerProps = column.getHeaderProps(column.getSortByToggleProps());
|
||||
|
||||
|
37
packages/grafana-ui/src/components/Table/TableCell.tsx
Normal file
37
packages/grafana-ui/src/components/Table/TableCell.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import React, { FC } from 'react';
|
||||
import { Cell } from 'react-table';
|
||||
import { Field } from '@grafana/data';
|
||||
import { getTextAlign } from './utils';
|
||||
import { TableFilterActionCallback } from './types';
|
||||
import { TableStyles } from './styles';
|
||||
|
||||
interface Props {
|
||||
cell: Cell;
|
||||
field: Field;
|
||||
tableStyles: TableStyles;
|
||||
onCellClick?: TableFilterActionCallback;
|
||||
}
|
||||
|
||||
export const TableCell: FC<Props> = ({ cell, field, tableStyles, onCellClick }) => {
|
||||
const filterable = field.config.filterable;
|
||||
const cellProps = cell.getCellProps();
|
||||
|
||||
let onClick: ((event: React.SyntheticEvent) => void) | undefined = undefined;
|
||||
if (filterable && onCellClick) {
|
||||
if (cellProps.style) {
|
||||
cellProps.style.cursor = 'pointer';
|
||||
}
|
||||
|
||||
onClick = () => onCellClick(cell.column.Header as string, cell.value);
|
||||
}
|
||||
const fieldTextAlign = getTextAlign(field);
|
||||
if (fieldTextAlign && cellProps.style) {
|
||||
cellProps.style.textAlign = fieldTextAlign;
|
||||
}
|
||||
|
||||
return (
|
||||
<div {...cellProps} onClick={onClick}>
|
||||
{cell.render('Cell', { field, tableStyles })}
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,5 +1,4 @@
|
||||
import { TextAlignProperty } from 'csstype';
|
||||
import { ComponentType } from 'react';
|
||||
import { CellProps } from 'react-table';
|
||||
import { Field } from '@grafana/data';
|
||||
import { TableStyles } from './styles';
|
||||
|
||||
@ -19,27 +18,13 @@ export enum TableCellDisplayMode {
|
||||
|
||||
export type FieldTextAlignment = 'auto' | 'left' | 'right' | 'center';
|
||||
|
||||
export interface TableColumn {
|
||||
// React table props
|
||||
Header: string;
|
||||
accessor: string | Function;
|
||||
Cell: ComponentType<ReactTableCellProps>;
|
||||
// Grafana additions
|
||||
field: Field;
|
||||
width: number;
|
||||
textAlign: TextAlignProperty;
|
||||
}
|
||||
|
||||
export interface TableRow {
|
||||
[x: string]: any;
|
||||
}
|
||||
|
||||
export interface ReactTableCellProps {
|
||||
cell: ReactTableCell;
|
||||
column: TableColumn;
|
||||
tableStyles: TableStyles;
|
||||
}
|
||||
export type TableFilterActionCallback = (key: string, value: string) => void;
|
||||
|
||||
export interface ReactTableCell {
|
||||
value: any;
|
||||
export interface TableCellProps extends CellProps<any> {
|
||||
tableStyles: TableStyles;
|
||||
field: Field;
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { MutableDataFrame, GrafanaThemeType, FieldType } from '@grafana/data';
|
||||
import { getColumns } from './utils';
|
||||
import { getTheme } from '../../themes';
|
||||
import { MutableDataFrame, FieldType } from '@grafana/data';
|
||||
import { getColumns, getTextAlign } from './utils';
|
||||
|
||||
function getData() {
|
||||
const data = new MutableDataFrame({
|
||||
@ -34,33 +33,31 @@ function getData() {
|
||||
describe('Table utils', () => {
|
||||
describe('getColumns', () => {
|
||||
it('Should build columns from DataFrame', () => {
|
||||
const theme = getTheme(GrafanaThemeType.Dark);
|
||||
const columns = getColumns(getData(), 1000, theme);
|
||||
const columns = getColumns(getData(), 1000);
|
||||
|
||||
expect(columns[0].Header).toBe('Time');
|
||||
expect(columns[1].Header).toBe('Value');
|
||||
});
|
||||
|
||||
it('Should distribute width and use field config width', () => {
|
||||
const theme = getTheme(GrafanaThemeType.Dark);
|
||||
const columns = getColumns(getData(), 1000, theme);
|
||||
const columns = getColumns(getData(), 1000);
|
||||
|
||||
expect(columns[0].width).toBe(450);
|
||||
expect(columns[1].width).toBe(100);
|
||||
});
|
||||
|
||||
});
|
||||
describe('getTextAlign', () => {
|
||||
it('Should use textAlign from custom', () => {
|
||||
const theme = getTheme(GrafanaThemeType.Dark);
|
||||
const columns = getColumns(getData(), 1000, theme);
|
||||
const data = getData();
|
||||
const textAlign = getTextAlign(data.fields[2]);
|
||||
|
||||
expect(columns[2].textAlign).toBe('center');
|
||||
expect(textAlign).toBe('center');
|
||||
});
|
||||
|
||||
it('Should set textAlign to right for number values', () => {
|
||||
const theme = getTheme(GrafanaThemeType.Dark);
|
||||
const columns = getColumns(getData(), 1000, theme);
|
||||
|
||||
expect(columns[1].textAlign).toBe('right');
|
||||
const data = getData();
|
||||
const textAlign = getTextAlign(data.fields[1]);
|
||||
expect(textAlign).toBe('right');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { TextAlignProperty } from 'csstype';
|
||||
import { DataFrame, Field, GrafanaTheme, FieldType } from '@grafana/data';
|
||||
import { TableColumn, TableRow, TableFieldOptions, TableCellDisplayMode } from './types';
|
||||
import { DataFrame, Field, FieldType } from '@grafana/data';
|
||||
import { Column } from 'react-table';
|
||||
import { DefaultCell } from './DefaultCell';
|
||||
import { BarGaugeCell } from './BarGaugeCell';
|
||||
import { DefaultCell, BackgroundColoredCell } from './DefaultCell';
|
||||
import { BackgroundColoredCell } from './BackgroundColorCell';
|
||||
import { TableRow, TableFieldOptions, TableCellDisplayMode } from './types';
|
||||
|
||||
export function getTableRows(data: DataFrame): TableRow[] {
|
||||
const tableData = [];
|
||||
@ -19,7 +21,7 @@ export function getTableRows(data: DataFrame): TableRow[] {
|
||||
return tableData;
|
||||
}
|
||||
|
||||
function getTextAlign(field: Field): TextAlignProperty {
|
||||
export function getTextAlign(field: Field): TextAlignProperty {
|
||||
if (field.config.custom) {
|
||||
const custom = field.config.custom as TableFieldOptions;
|
||||
|
||||
@ -40,36 +42,21 @@ function getTextAlign(field: Field): TextAlignProperty {
|
||||
return 'left';
|
||||
}
|
||||
|
||||
export function getColumns(data: DataFrame, availableWidth: number, theme: GrafanaTheme): TableColumn[] {
|
||||
const cols: TableColumn[] = [];
|
||||
export function getColumns(data: DataFrame, availableWidth: number): Column[] {
|
||||
const columns: Column[] = [];
|
||||
let fieldCountWithoutWidth = data.fields.length;
|
||||
|
||||
for (const field of data.fields) {
|
||||
const fieldTableOptions = (field.config.custom || {}) as TableFieldOptions;
|
||||
|
||||
if (fieldTableOptions.width) {
|
||||
availableWidth -= fieldTableOptions.width;
|
||||
fieldCountWithoutWidth -= 1;
|
||||
}
|
||||
|
||||
let Cell = DefaultCell;
|
||||
let textAlign = getTextAlign(field);
|
||||
const Cell = getCellComponent(fieldTableOptions.displayMode);
|
||||
|
||||
switch (fieldTableOptions.displayMode) {
|
||||
case TableCellDisplayMode.ColorBackground:
|
||||
Cell = BackgroundColoredCell;
|
||||
break;
|
||||
case TableCellDisplayMode.LcdGauge:
|
||||
case TableCellDisplayMode.GradientGauge:
|
||||
Cell = BarGaugeCell;
|
||||
textAlign = 'center';
|
||||
break;
|
||||
}
|
||||
|
||||
cols.push({
|
||||
field,
|
||||
columns.push({
|
||||
Cell,
|
||||
textAlign,
|
||||
Header: field.name,
|
||||
accessor: field.name,
|
||||
width: fieldTableOptions.width,
|
||||
@ -78,11 +65,23 @@ export function getColumns(data: DataFrame, availableWidth: number, theme: Grafa
|
||||
|
||||
// divide up the rest of the space
|
||||
const sharedWidth = availableWidth / fieldCountWithoutWidth;
|
||||
for (const column of cols) {
|
||||
for (const column of columns) {
|
||||
if (!column.width) {
|
||||
column.width = sharedWidth;
|
||||
}
|
||||
}
|
||||
|
||||
return cols;
|
||||
return columns;
|
||||
}
|
||||
|
||||
function getCellComponent(displayMode: TableCellDisplayMode) {
|
||||
switch (displayMode) {
|
||||
case TableCellDisplayMode.ColorBackground:
|
||||
return BackgroundColoredCell;
|
||||
case TableCellDisplayMode.LcdGauge:
|
||||
case TableCellDisplayMode.GradientGauge:
|
||||
return BarGaugeCell;
|
||||
default:
|
||||
return DefaultCell;
|
||||
}
|
||||
}
|
||||
|
81
yarn.lock
81
yarn.lock
@ -3778,43 +3778,6 @@
|
||||
"@types/d3-interpolate" "*"
|
||||
"@types/d3-selection" "*"
|
||||
|
||||
"@types/d3@5.7.1":
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/d3/-/d3-5.7.1.tgz#99e6b3a558816264a674947822600d3aba8b84b0"
|
||||
integrity sha512-1TNamlKYTdpRzFjDIcgiRqpNqYz9VVvNOisVqCqvYsxXyysgbfTKxdOurrVcW+SxyURTPwAD68KV04BL5RKNcQ==
|
||||
dependencies:
|
||||
"@types/d3-array" "*"
|
||||
"@types/d3-axis" "*"
|
||||
"@types/d3-brush" "*"
|
||||
"@types/d3-chord" "*"
|
||||
"@types/d3-collection" "*"
|
||||
"@types/d3-color" "*"
|
||||
"@types/d3-contour" "*"
|
||||
"@types/d3-dispatch" "*"
|
||||
"@types/d3-drag" "*"
|
||||
"@types/d3-dsv" "*"
|
||||
"@types/d3-ease" "*"
|
||||
"@types/d3-fetch" "*"
|
||||
"@types/d3-force" "*"
|
||||
"@types/d3-format" "*"
|
||||
"@types/d3-geo" "*"
|
||||
"@types/d3-hierarchy" "*"
|
||||
"@types/d3-interpolate" "*"
|
||||
"@types/d3-path" "*"
|
||||
"@types/d3-polygon" "*"
|
||||
"@types/d3-quadtree" "*"
|
||||
"@types/d3-random" "*"
|
||||
"@types/d3-scale" "*"
|
||||
"@types/d3-scale-chromatic" "*"
|
||||
"@types/d3-selection" "*"
|
||||
"@types/d3-shape" "*"
|
||||
"@types/d3-time" "*"
|
||||
"@types/d3-time-format" "*"
|
||||
"@types/d3-timer" "*"
|
||||
"@types/d3-transition" "*"
|
||||
"@types/d3-voronoi" "*"
|
||||
"@types/d3-zoom" "*"
|
||||
|
||||
"@types/d3@5.7.2":
|
||||
version "5.7.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/d3/-/d3-5.7.2.tgz#52235eb71a1d3ca171d6dca52a58f5ccbe0254cc"
|
||||
@ -4290,6 +4253,13 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-table@7.0.2":
|
||||
version "7.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-table/-/react-table-7.0.2.tgz#184de5ad5a7c5aced08b49812002a4d2e8918cc0"
|
||||
integrity sha512-sxvjV0JCk/ijCzENejXth99cFMnmucATaC31gz1bMk8iQwUDE2VYaw2QQTcDrzBxzastBQGdcLpcFIN61RvgIA==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-test-renderer@*":
|
||||
version "16.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-16.9.1.tgz#9d432c46c515ebe50c45fa92c6fb5acdc22e39c4"
|
||||
@ -8245,43 +8215,6 @@ d3@5.15.0:
|
||||
d3-voronoi "1"
|
||||
d3-zoom "1"
|
||||
|
||||
d3@5.9.1:
|
||||
version "5.9.1"
|
||||
resolved "https://registry.yarnpkg.com/d3/-/d3-5.9.1.tgz#fde73fa9af7281d2ff0d2a32aa8f306e93a6d1cd"
|
||||
integrity sha512-JceuBn5VVWySPQc9EA0gfq0xQVgEQXGokHhe+359bmgGeUITLK2r2b9idMzquQne9DKxb7JDCE1gDRXe9OIF2Q==
|
||||
dependencies:
|
||||
d3-array "1"
|
||||
d3-axis "1"
|
||||
d3-brush "1"
|
||||
d3-chord "1"
|
||||
d3-collection "1"
|
||||
d3-color "1"
|
||||
d3-contour "1"
|
||||
d3-dispatch "1"
|
||||
d3-drag "1"
|
||||
d3-dsv "1"
|
||||
d3-ease "1"
|
||||
d3-fetch "1"
|
||||
d3-force "1"
|
||||
d3-format "1"
|
||||
d3-geo "1"
|
||||
d3-hierarchy "1"
|
||||
d3-interpolate "1"
|
||||
d3-path "1"
|
||||
d3-polygon "1"
|
||||
d3-quadtree "1"
|
||||
d3-random "1"
|
||||
d3-scale "2"
|
||||
d3-scale-chromatic "1"
|
||||
d3-selection "1"
|
||||
d3-shape "1"
|
||||
d3-time "1"
|
||||
d3-time-format "2"
|
||||
d3-timer "1"
|
||||
d3-transition "1"
|
||||
d3-voronoi "1"
|
||||
d3-zoom "1"
|
||||
|
||||
d@1, d@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
|
||||
|
Loading…
Reference in New Issue
Block a user