feat: add timebar examples

This commit is contained in:
baizn 2020-09-21 18:06:44 +08:00 committed by Moyee
parent 745cef2344
commit c944186cab
18 changed files with 474 additions and 1086 deletions

View File

@ -7,18 +7,26 @@
{
"filename": "timebar.js",
"title": {
"zh": "时间轴",
"en": "ToolBar"
"zh": "趋势时间轴",
"en": "TrendTimeBar"
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*eq2kQ4N-pNcAAAAAAAAAAABkARQnAQ"
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*lfvIQJYbs7oAAAAAAAAAAAAAARQnAQ"
},
{
"filename": "configTimebar.js",
"filename": "simple-timebar.js",
"title": {
"zh": "定义时间轴样式",
"en": "ToolBar"
"zh": "简易时间轴",
"en": "SimperTimeBar"
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*eq2kQ4N-pNcAAAAAAAAAAABkARQnAQ"
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*g2zhQqP6ruYAAAAAAAAAAAAAARQnAQ"
},
{
"filename": "slice-timebar.js",
"title": {
"zh": "刻度时间轴",
"en": "SliceTimeBar"
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*n6ECQ7Jn5pQAAAAAAAAAAAAAARQnAQ"
}
]
}

View File

@ -0,0 +1,114 @@
import G6 from '@antv/g6';
import insertCss from 'insert-css';
// 我们用 insert-css 演示引入自定义样式
// 推荐将样式添加到自己的样式文件中
// 若拷贝官方代码,别忘了 npm install insert-css
insertCss(`
.g6-component-timebar {
top: 450px;
left: 100px;
}
`);
const data = {
nodes: [],
edges: [],
};
for (let i = 0; i < 100; i++) {
const id = `node-${i}`;
data.nodes.push({
id,
date: `2020${i}`,
value: Math.round(Math.random() * 300),
});
data.edges.push({
source: `node-${Math.round(Math.random() * 90)}`,
target: `node-${Math.round(Math.random() * 90)}`,
});
}
const graphDiv = document.getElementById('container');
const width = document.getElementById('container').scrollWidth;
const height = document.getElementById('container').scrollHeight || 500;
const timeBarData = [];
const nodeSize = 20;
for (let i = 0; i < 100; i++) {
timeBarData.push({
date: `2020${i}`,
value: Math.round(Math.random() * 300),
});
}
const timebar = new G6.TimeBar({
x: 0,
y: 0,
width: 500,
height: 150,
padding: 10,
type: 'simple',
trend: {
data: timeBarData
}
});
// constrained the layout inside the area
const constrainBox = { x: 10, y: 10, width: 580, height: 450 };
const onTick = () => {
let minx = 99999999;
let maxx = -99999999;
let miny = 99999999;
let maxy = -99999999;
data.nodes.forEach((node) => {
if (minx > node.x) {
minx = node.x;
}
if (maxx < node.x) {
maxx = node.x;
}
if (miny > node.y) {
miny = node.y;
}
if (maxy < node.y) {
maxy = node.y;
}
});
const scalex = (constrainBox.width - nodeSize / 2) / (maxx - minx);
const scaley = (constrainBox.height - nodeSize / 2) / (maxy - miny);
data.nodes.forEach((node) => {
node.x = (node.x - minx) * scalex + constrainBox.x;
node.y = (node.y - miny) * scaley + constrainBox.y;
});
};
const graph = new G6.Graph({
container: 'container',
width,
height: height - 100,
linkCenter: true,
plugins: [timebar],
layout: {
type: 'force',
preventOverlap: true,
onTick,
},
defaultNode: {
size: nodeSize,
type: 'circle',
style: {
fill: '#DEE9FF',
stroke: '#5B8FF9',
},
},
modes: {
default: ['drag-node'],
},
});
graph.data(data);
graph.render();

View File

@ -5,9 +5,9 @@ import insertCss from 'insert-css';
// 推荐将样式添加到自己的样式文件中
// 若拷贝官方代码,别忘了 npm install insert-css
insertCss(`
#g6-component-timebar {
top: 540px;
left: 10px;
.g6-component-timebar {
top: 450px;
left: 100px;
}
`);
@ -44,49 +44,34 @@ for (let i = 0; i < 100; i++) {
const nodeSize = 20;
const timebar = new G6.TimeBar({
width: 600,
timebar: {
width: 580,
minLimit: 0,
maxLimit: 1,
start: 0,
end: 0.5,
backgroundStyle: {
fill: '#ddd',
opacity: 0.2,
lineWidth: 1,
stroke: '#aaa',
},
foregroundStyle: {
fill: '#f00',
opacity: 0.1,
},
trend: {
let count = 0;
const timebar = new G6.TimeBar({
x: 0,
y: 0,
width: 500,
height: 150,
padding: 10,
type: 'slice',
slice: {
data: timeBarData,
isArea: false,
smooth: true,
lineStyle: {
stroke: '#f00',
lineWidth: 2,
opacity: 0.5,
width: 500,
height: 42,
padding: 2,
tickLabelFormatter: d => {
count++;
const dateStr = `${d.date}`
if ((count - 1) % 10 === 0) {
return `${dateStr.substr(0, 4)}-${dateStr.substr(4, 2)}-${dateStr.substr(6, 2)}`;
}
return false;
},
tooltipFomatter: d => {
const dateStr = `${d}`
return `${dateStr.substr(0, 4)}-${dateStr.substr(4, 2)}-${dateStr.substr(6, 2)}`;
}
},
textStyle: {
fontWeight: 500,
fill: '#000',
fontSize: 14,
},
handlerStyle: {
width: 10,
height: 35,
},
},
rangeChange: (graph, min, max) => {
// 拿到 Graph 实例和 timebar 上范围,自己可以控制图上的渲染逻辑
console.log(graph, min, max);
},
});
});
// constrained the layout inside the area
const constrainBox = { x: 10, y: 10, width: 580, height: 450 };
@ -121,7 +106,7 @@ const onTick = () => {
const graph = new G6.Graph({
container: 'container',
width,
height: height - 50,
height: height - 100,
linkCenter: true,
plugins: [timebar],
layout: {

View File

@ -5,9 +5,9 @@ import insertCss from 'insert-css';
// 推荐将样式添加到自己的样式文件中
// 若拷贝官方代码,别忘了 npm install insert-css
insertCss(`
#g6-component-timebar {
top: 540px;
left: 10px;
.g6-component-timebar {
top: 450px;
left: 100px;
}
`);
@ -46,16 +46,14 @@ for (let i = 0; i < 100; i++) {
}
const timebar = new G6.TimeBar({
width: 600,
timebar: {
width: 550,
trend: {
data: timeBarData,
isArea: false,
smooth: true,
},
start: 0.4,
end: 0.5,
x: 0,
y: 0,
width: 500,
height: 150,
padding: 10,
type: 'trend',
trend: {
data: timeBarData
},
});
@ -93,7 +91,7 @@ const onTick = () => {
const graph = new G6.Graph({
container: 'container',
width,
height: height - 50,
height: height - 100,
linkCenter: true,
plugins: [timebar],
layout: {

View File

@ -7,4 +7,4 @@ G6 中内置的 TimeBar 组件。
## 使用指南
下面的代码演示展示了如何在图上使用 TimeBar。TimeBar 的样式可以参考 demo 2 进行配置
下面的代码演示展示了如何在图上使用 TimeBar。目前仅提供了三种类型的默认时间轴组件,更多配置的时间轴组件敬请期待

View File

@ -1,4 +1,4 @@
// window.g6 = require('./src/index.ts'); // import the source for debugging
window.g6 = require('./dist/g6.min.js'); // import the package for webworker
window.g6 = require('./src/index.ts'); // import the source for debugging
// window.g6 = require('./dist/g6.min.js'); // import the package for webworker
window.insertCss = require('insert-css');
window.Chart = require('@antv/chart-node-g6');

View File

@ -71,7 +71,6 @@
},
"dependencies": {
"@antv/color-util": "^2.0.5",
"@antv/component": "^0.6.1",
"@antv/dom-util": "^2.0.1",
"@antv/event-emitter": "~0.1.0",
"@antv/g-base": "^0.5.1",

View File

@ -1,4 +1,3 @@
import GCanvas from '@antv/g-canvas/lib/canvas';
import Base, { IPluginBaseConfig } from '../base';
import isString from '@antv/util/lib/is-string';
import createDOM from '@antv/dom-util/lib/create-dom';

View File

@ -0,0 +1,10 @@
export const TIMELINE_START = 'timelinestart';
export const TIMELINE_END = 'timelineend';
export const VALUE_CHANGE = 'valueChange';
export const TIMEBAR_CONFIG_CHANGE = 'timebarConfigChanged'
export const PLAY_PAUSE_BTN = 'playPauseBtn'
export const NEXT_STEP_BTN = 'nextStepBtn'
export const PRE_STEP_BTN = 'preStepBtn'

View File

@ -3,10 +3,6 @@ import { deepMix } from '@antv/util'
import Button from './timeButton';
import { ShapeStyle } from '../../types';
export const TIMELINE_START = 'timelinestart';
export const TIMELINE_CHANGE = 'timelinechange';
export const TIMELINE_END = 'timelineend';
const DEFAULT_RECT_FILL = '#ccc'
const DEFAULT_RECT_STROKE = 'green'
const DEFAULT_PLAYBTN_STYLE = {
@ -64,10 +60,6 @@ export type ControllerCfg = Partial<{
readonly playBtnStyle?: ShapeStyle;
}>
/**
*
* https://www.gapminder.org/tools/#$state$time$value=1870&delay:100;;&chart-type=bubbles
*/
export default class ControllerBtn {
/** 是否处于播放状态 */
private isPlay: boolean;
@ -372,6 +364,11 @@ export default class ControllerBtn {
}
public destroy() {
this.group.off('playPauseBtn:click')
this.speedGroup.off('speed-rect:click')
if (this.toggleGroup) {
this.toggleGroup.off('toggle-model:click')
this.toggleGroup.destroy()
}
this.speedGroup.destroy()
}
}

View File

@ -31,7 +31,7 @@ const DEFAULT_STYLE = {
opacity: 1,
cursor: 'ew-resize',
// 高亮的颜色
highLightFill: '#FFF',
highLightFill: '#0050b3',
};
const SIMPLE_DEFAULT_STYLE = {
@ -194,7 +194,9 @@ export default class Handler {
// 移动到对应的位置
this.updateXY();
this.bindEvents();
if (this.handleType === 'trend') {
this.bindEvents();
}
}
private bindEvents() {

View File

@ -1,79 +1,74 @@
import modifyCSS from '@antv/dom-util/lib/modify-css';
import createDOM from '@antv/dom-util/lib/create-dom';
import { IGroup } from '@antv/g-base';
import { Canvas } from '@antv/g-canvas';
import { Slider } from '@antv/component';
import { ShapeStyle, GraphData } from '../../types';
/**
* G
*/
import GCanvas from '@antv/g-canvas/lib/canvas';
import GSVGCanvas from '@antv/g-svg/lib/canvas';
import { IGroup, ICanvas } from '@antv/g-base';
import createDOM from '@antv/dom-util/lib/create-dom'
import modifyCSS from '@antv/dom-util/lib/modify-css'
import { isString } from '@antv/util'
import Base, { IPluginBaseConfig } from '../base';
import TrendTimeBar, { SliderOption, ControllerCfg } from './trendTimeBar'
import TimeBarSlice, { TimeBarSliceOption } from './timeBarSlice'
import { IGraph } from '../../interface/graph';
import { VALUE_CHANGE } from './constant'
import { GraphData, ShapeStyle } from '../../types';
import { Interval } from './trend';
interface Data {
date: string;
value: number;
}
// simple 版本默认高度
const DEFAULT_SIMPLE_HEIGHT = 8
interface Callback {
// trend 版本默认高度
const DEFAULT_TREND_HEIGHT = 26
export interface Callback {
originValue: number[];
value: number[];
target: IGroup;
}
interface TrendConfig {
readonly data: Data[];
// 数据
readonly data: {
date: string;
value: string;
}[];
// 位置大小
readonly x?: number;
readonly y?: number;
readonly width?: number;
readonly height?: number;
// 样式
readonly smooth?: boolean;
readonly isArea?: boolean;
readonly backgroundStyle?: ShapeStyle;
readonly lineStyle?: ShapeStyle;
readonly areaStyle?: ShapeStyle;
readonly interval?: Interval;
}
interface ExtendedTrendConfig {
readonly data: number[];
// 样式
readonly smooth?: boolean;
readonly isArea?: boolean;
readonly backgroundStyle?: ShapeStyle;
readonly lineStyle?: ShapeStyle;
readonly areaStyle?: ShapeStyle;
}
type TimeBarOption = Partial<{
// position size
readonly x: number;
readonly y: number;
readonly width: number;
readonly height: number;
readonly backgroundStyle: ShapeStyle;
readonly foregroundStyle: ShapeStyle;
// 滑块样式
readonly handlerStyle: {
width: number;
height: number;
style: ShapeStyle;
};
readonly textStyle: ShapeStyle;
// 允许滑动位置
readonly minLimit: number;
readonly maxLimit: number;
// 初始位置
readonly start: number;
readonly end: number;
// 滑块文本
readonly minText: string;
readonly maxText: string;
readonly trend: TrendConfig;
readonly trendCfg: ExtendedTrendConfig;
}>;
interface TimeBarConfig extends IPluginBaseConfig {
width?: number;
height?: number;
timebar: TimeBarOption;
rangeChange?: (graph: IGraph, min: number, max: number) => void;
// position size
readonly x?: number;
readonly y?: number;
readonly width?: number;
readonly height?: number;
readonly padding?: number;
readonly type?: 'trend' | 'simple' | 'slice';
// 趋势图配置项
readonly trend?: TrendConfig;
// 滑块、及前后背景的配置
readonly slider?: SliderOption;
// 刻度时间轴配置项
readonly slice?: TimeBarSliceOption;
// 控制按钮
readonly controllerCfg?: ControllerCfg;
rangeChange?: (graph: IGraph, minValue: string, maxValue: string) => void;
valueChange?: (graph: IGraph, value: string) => void;
}
export default class TimeBar extends Base {
@ -81,125 +76,162 @@ export default class TimeBar extends Base {
public getDefaultCfgs(): TimeBarConfig {
return {
width: 400,
height: 50,
rangeChange: null,
timebar: {
x: 10,
y: 10,
width: 380,
height: 26,
minLimit: 0,
maxLimit: 1,
container: null,
className: 'g6-component-timebar',
padding: 10,
type: 'trend',
trend: {
data: [],
isArea: false,
smooth: true
},
controllerCfg: {
speed: 2,
loop: false,
},
slider: {
start: 0.1,
end: 0.9,
minText: 'min',
maxText: 'max',
},
slice: {
start: 0.1,
end: 0.9,
data: []
}
};
}
public init() {
const timeBarConfig: TimeBarOption = this.get('timebar');
const { trend = {} as TrendConfig } = timeBarConfig;
const { data = [] } = trend;
if (!data || data.length === 0) {
console.warn('TimeBar 中没有传入数据');
return;
}
constructor(cfgs?: TimeBarConfig) {
super(cfgs)
}
/**
* TimeBar
*/
public initContainer() {
const graph: IGraph = this.get('graph');
const { width, height } = this._cfgs
const className: string = this.get('className') || 'g6-component-timebar';
const container: HTMLDivElement | null = this.get('container');
const graphContainer = this.get('graph').get('container');
let timebar;
let timeBarContainer;
if (!container) {
timebar = createDOM(`<div class='g6-component-timebar'></div>`);
modifyCSS(timebar, { position: 'absolute' });
timeBarContainer = createDOM(`<div class='${className}'></div>`);
modifyCSS(timeBarContainer, { position: 'absolute' });
} else {
timebar = container;
timeBarContainer = container;
}
graphContainer.appendChild(timebar);
graphContainer.appendChild(timeBarContainer);
this.set('timeBarContainer', timebar);
this.set('timeBarContainer', timeBarContainer);
this.initTimeBar(timebar);
let canvas;
const renderer = graph.get('renderer');
if (renderer === 'SVG') {
canvas = new GSVGCanvas({
container: timeBarContainer,
width,
height,
});
} else {
canvas = new GCanvas({
container: timeBarContainer,
width,
height,
});
}
this.set('canvas', canvas);
}
private initTimeBar(container: HTMLDivElement) {
const width = this.get('width');
const height = this.get('height');
const canvas = new Canvas({
container,
width,
height,
});
public init() {
this.initContainer()
const canvas: ICanvas = this.get('canvas')
const timeBarGroup = canvas.addGroup({
name: 'timebar-group'
})
const group = canvas.addGroup({
id: 'timebar-plugin',
});
this.set('timeBarGroup', timeBarGroup)
const timeBarConfig: TimeBarOption = this.get('timebar');
const { trend = {} as TrendConfig, ...option } = timeBarConfig;
const config = {
container: group,
minText: option.start,
maxText: option.end,
...option,
};
// 是否显示 TimeBar 根据是否传入了数据来确定
const { data = [], ...trendOption } = trend;
const trendData = data.map((d) => d.value);
config.trendCfg = {
...trendOption,
data: trendData,
};
const min = Math.round(data.length * option.start);
let max = Math.round(data.length * option.end);
max = max >= data.length ? data.length - 1 : max;
config.minText = data[min].date;
config.maxText = data[max].date;
this.set('trendData', data);
const slider = new Slider(config);
slider.init();
slider.render();
this.set('slider', slider);
this.bindEvent();
this.renderTrend()
this.initEvent()
}
/**
*
*/
private bindEvent() {
const slider = this.get('slider');
const { start, end } = this.get('timebar');
const graph: IGraph = this.get('graph');
graph.on('afterrender', (e) => {
this.filterData({ value: [start, end] });
});
private renderTrend() {
const { width, x, y, padding, type, trend, slider, controllerCfg } = this._cfgs
const { data, ...other } = trend
slider.on('valuechanged', (evt: Callback) => {
this.filterData(evt);
});
const realWidth = width - 2 * padding
const defaultHeight = type === 'trend' ? DEFAULT_TREND_HEIGHT : DEFAULT_SIMPLE_HEIGHT
const graph = this.get('graph')
const group = this.get('timeBarGroup')
const canvas = this.get('canvas')
let timebar = null
if (type === 'trend' || type === 'simple') {
timebar = new TrendTimeBar({
graph,
canvas,
group,
type,
x: x + padding,
y: type === 'trend' ? y + padding : y + padding + 15,
width: realWidth,
height: defaultHeight,
padding,
trendCfg: {
...other,
data: data.map(d => d.value)
},
...slider,
ticks: data.map(d => d.date),
handlerStyle: {
...slider.handlerStyle,
height: slider.height || defaultHeight
},
controllerCfg
})
} else if (type === 'slice') {
const { slice } = this._cfgs
// 刻度时间轴
timebar = new TimeBarSlice({
graph,
canvas,
group,
x: x + padding,
y: y + padding,
...slice
})
}
this.set('timebar', timebar)
}
private filterData(evt) {
const { value } = evt;
let trendData = null
const type = this._cfgs.type
if (type === 'trend' || type === 'simple') {
trendData = this._cfgs.trend.data
} else if (type === 'slice') {
trendData = this._cfgs.slice.data
}
if (!trendData || trendData.length === 0) {
console.warn('请配置 TimeBar 组件的数据')
return
}
const trendData: Data[] = this.get('trendData');
const rangeChange = this.get('rangeChange');
const graph: IGraph = this.get('graph');
const slider = this.get('slider');
const min = Math.round(trendData.length * value[0]);
let max = Math.round(trendData.length * value[1]);
max = max >= trendData.length ? trendData.length - 1 : max;
@ -207,8 +239,10 @@ export default class TimeBar extends Base {
const minText = trendData[min].date;
const maxText = trendData[max].date;
slider.set('minText', minText);
slider.set('maxText', maxText);
if (type !== 'slice') {
const timebar = this.get('timebar');
timebar.setText(minText, maxText)
}
if (rangeChange) {
rangeChange(graph, minText, maxText);
@ -242,26 +276,38 @@ export default class TimeBar extends Base {
}
}
public show() {
const slider = this.get('slider');
slider.show();
}
private initEvent() {
let start = 0
let end = 0
const type = this._cfgs.type
if (!type || type === 'trend' || type === 'simple') {
start = this._cfgs.slider.start
end = this._cfgs.slider.end
} else if (type === 'slice') {
start = this._cfgs.slice.start
end = this._cfgs.slice.end
}
public hide() {
const slider = this.get('slider');
slider.hide();
const graph: IGraph = this.get('graph');
graph.on('afterrender', () => {
this.filterData({ value: [start, end] });
});
// 时间轴的值发生改变的事件
graph.on(VALUE_CHANGE, (evt: Callback) => {
// 范围变化
this.filterData(evt);
});
}
public destroy() {
this.cacheGraphData = null;
const slider = this.get('slider');
if (slider) {
slider.off('valuechanged');
slider.destroy();
const timebar = this.get('timebar')
if (timebar && timebar.destory) {
timebar.destory()
}
super.destroy();
const timeBarContainer = this.get('timeBarContainer');
if (timeBarContainer) {
let container: HTMLDivElement | null = this.get('container');

View File

@ -1,301 +0,0 @@
/**
* G
*/
import GCanvas from '@antv/g-canvas/lib/canvas';
import GSVGCanvas from '@antv/g-svg/lib/canvas';
import { IGroup, ICanvas } from '@antv/g-base';
import createDOM from '@antv/dom-util/lib/create-dom'
import { isString } from '@antv/util'
import Base, { IPluginBaseConfig } from '../base';
import TrendTimeBar, { SliderOption, VALUE_CHANGE, ControllerCfg } from './trendTimeBar'
import TimeBarSlice, { TimeBarSliceOption } from './timeBarSlice'
import { IGraph } from '../../interface/graph';
import { GraphData, ShapeStyle } from '../../types';
import { Interval } from './trend';
// simple 版本默认高度
const DEFAULT_SIMPLE_HEIGHT = 8
// trend 版本默认高度
const DEFAULT_TREND_HEIGHT = 26
export interface Callback {
originValue: number[];
value: number[];
target: IGroup;
}
interface TrendConfig {
// 数据
readonly data: {
date: string;
value: string;
}[];
// 位置大小
readonly x?: number;
readonly y?: number;
readonly width?: number;
readonly height?: number;
// 样式
readonly smooth?: boolean;
readonly isArea?: boolean;
readonly backgroundStyle?: ShapeStyle;
readonly lineStyle?: ShapeStyle;
readonly areaStyle?: ShapeStyle;
readonly interval?: Interval;
}
interface TimeBarConfig extends IPluginBaseConfig {
// position size
readonly x?: number;
readonly y?: number;
readonly width?: number;
readonly height?: number;
readonly padding?: number;
readonly type?: 'trend' | 'simple' | 'slice';
// 趋势图配置项
readonly trend?: TrendConfig;
// 滑块、及前后背景的配置
readonly slider?: SliderOption;
// 刻度时间轴配置项
readonly slice?: TimeBarSliceOption;
// 控制按钮
readonly controllerCfg?: ControllerCfg;
rangeChange?: (graph: IGraph, minValue: string, maxValue: string) => void;
valueChange?: (graph: IGraph, value: string) => void;
}
export default class TimeBar extends Base {
private cacheGraphData: GraphData;
public getDefaultCfgs(): TimeBarConfig {
return {
container: null,
className: 'g6-component-timebar',
padding: 10,
type: 'trend',
trend: {
data: [],
isArea: false,
smooth: true
},
controllerCfg: {
speed: 2,
loop: false,
},
slider: {
start: 0.1,
end: 0.9,
minText: 'min',
maxText: 'max',
},
slice: {
start: 0.1,
end: 0.9,
data: []
}
};
}
constructor(cfgs?: TimeBarConfig) {
super(cfgs)
}
/**
* TimeBar
*/
public initContainer() {
const graph: IGraph = this.get('graph');
const { width, height } = this._cfgs
const className: string = this.get('className') || 'g6-component-timebar';
let parentNode: string | HTMLElement = this.get('container');
const container: HTMLElement = createDOM(
`<div class='${className}' style='position: absolute; width: ${width}px; height: ${height}px;'></div>`,
);
if (isString(parentNode)) {
parentNode = document.getElementById(parentNode) as HTMLElement;
}
if (parentNode) {
parentNode.appendChild(container);
} else {
graph.get('container').appendChild(container);
}
this.set('container', container);
let canvas;
const renderer = graph.get('renderer');
if (renderer === 'SVG') {
canvas = new GSVGCanvas({
container: container,
width,
height,
});
} else {
canvas = new GCanvas({
container: container,
width,
height,
});
}
this.set('canvas', canvas);
}
public init() {
this.initContainer()
const canvas: ICanvas = this.get('canvas')
const timeBarGroup = canvas.addGroup({
name: 'timebar-group'
})
this.set('timeBarGroup', timeBarGroup)
this.renderTrend()
this.initEvent()
}
private renderTrend() {
const { width, x, y, padding, type, trend, slider, controllerCfg } = this._cfgs
const { data, ...other } = trend
const realWidth = width - 2 * padding
const defaultHeight = type === 'trend' ? DEFAULT_TREND_HEIGHT : DEFAULT_SIMPLE_HEIGHT
const graph = this.get('graph')
const group = this.get('timeBarGroup')
const canvas = this.get('canvas')
let timebar = null
if (type === 'trend' || type === 'simple') {
timebar = new TrendTimeBar({
graph,
canvas,
group,
type,
x: x + padding,
y: type === 'trend' ? y + padding : y + padding + 15,
width: realWidth,
height: defaultHeight,
padding,
trendCfg: {
...other,
data: data.map(d => d.value)
},
...slider,
ticks: data.map(d => d.date),
handlerStyle: {
...slider.handlerStyle,
height: slider.height || defaultHeight
},
controllerCfg
})
} else if (type === 'slice') {
const { slice } = this._cfgs
// 刻度时间轴
timebar = new TimeBarSlice({
graph,
canvas,
group,
x: x + padding,
y: y + padding,
...slice
})
}
this.set('timebar', timebar)
}
private filterData(evt) {
const { value } = evt;
// TODO 不同类型的 TimeBar 取不同地方的data
let trendData = null
const type = this._cfgs.type
if (type === 'trend' || type === 'simple') {
trendData = this._cfgs.trend.data
} else if (type === 'slice') {
trendData = this._cfgs.slice.data
}
// const { data: trendData } = this._cfgs.trend
const rangeChange = this.get('rangeChange');
const graph: IGraph = this.get('graph');
const min = Math.round(trendData.length * value[0]);
let max = Math.round(trendData.length * value[1]);
max = max >= trendData.length ? trendData.length - 1 : max;
const minText = trendData[min].date;
const maxText = trendData[max].date;
if (type !== 'slice') {
const timebar = this.get('timebar');
timebar.setText(minText, maxText)
}
if (rangeChange) {
rangeChange(graph, minText, maxText);
} else {
// 自动过滤数据,并渲染 graph
const graphData = graph.save() as GraphData;
if (
!this.cacheGraphData ||
(this.cacheGraphData.nodes && this.cacheGraphData.nodes.length === 0)
) {
this.cacheGraphData = graphData;
}
// 过滤不在 min 和 max 范围内的节点
const filterData = this.cacheGraphData.nodes.filter(
(d: any) => d.date >= minText && d.date <= maxText,
);
const nodeIds = filterData.map((node) => node.id);
// 过滤 source 或 target 不在 min 和 max 范围内的边
const fileterEdges = this.cacheGraphData.edges.filter(
(edge) => nodeIds.includes(edge.source) && nodeIds.includes(edge.target),
);
graph.changeData({
nodes: filterData,
edges: fileterEdges,
});
}
}
private initEvent() {
let start = 0
let end = 0
const type = this._cfgs.type
if (!type || type === 'trend' || type === 'simple') {
start = this._cfgs.slider.start
end = this._cfgs.slider.end
} else if (type === 'slice') {
start = this._cfgs.slice.start
end = this._cfgs.slice.end
}
const graph: IGraph = this.get('graph');
graph.on('afterrender', () => {
this.filterData({ value: [start, end] });
});
// 时间轴的值发生改变的事件
graph.on(VALUE_CHANGE, (evt: Callback) => {
// 范围变化
this.filterData(evt);
});
}
public destroy() {
super.destroy();
const group = this.get('timeBarGroup')
group.off('playPauseBtn:click')
}
}

View File

@ -1,486 +0,0 @@
/**
* G
*/
import GCanvas from '@antv/g-canvas/lib/canvas';
import GSVGCanvas from '@antv/g-svg/lib/canvas';
import { ICanvas } from '@antv/g-base';
import createDOM from '@antv/dom-util/lib/create-dom'
import { isString } from '@antv/util'
import Base, { IPluginBaseConfig } from '../base';
import TimeBarTooltip from './timeBarTooltip';
import { SliderOption, ControllerCfg } from './trendTimeBar'
import { IGraph } from '../../interface/graph';
import { GraphData } from '../../types';
interface TrendConfig {
readonly slider?: SliderOption;
// 数据
readonly data: {
date: string;
value: string;
}[];
// 位置大小
readonly x?: number;
readonly y?: number;
readonly width?: number;
readonly height?: number;
// 样式
readonly smooth?: boolean;
readonly isArea?: boolean;
readonly backgroundStyle?: object;
readonly lineStyle?: object;
readonly areaStyle?: object;
}
interface TickStyle {
fill?: string,
stroke?: string,
lineWidth?: number,
opacity?: number,
fillOpacity?: number,
strokeOpacity?: number
}
interface TimeBarConfig extends IPluginBaseConfig {
// position size
readonly x?: number;
readonly y?: number;
readonly width?: number;
readonly height?: number;
readonly padding?: number;
// styles
readonly selectedTickStyle?: TickStyle;
readonly unselectedTickStyle?: TickStyle
readonly tooltipBackgroundColor?: string;
// 趋势图配置项
readonly trend?: TrendConfig;
// 滑块、及前后背景的配置
readonly slider?: SliderOption;
// 自定义标签格式化函数
readonly tickLabelFormatter?: (d: any) => string | boolean;
// 自定义 tooltip 内容格式化函数
readonly tooltipFomatter?: (d: any) => string;
// 控制按钮
readonly controllerCfg?: ControllerCfg;
// readonly opti
rangeChange?: (graph: IGraph, minValue: string, maxValue: string) => void;
valueChange?: (graph: IGraph, value: string) => void;
}
export default class TimeBarSlice extends Base {
private cacheGraphData: GraphData;
public getDefaultCfgs(): TimeBarConfig {
return {
container: null,
className: 'g6-component-timebar',
padding: 2,
trend: {
data: [],
isArea: false,
smooth: true
},
controllerCfg: {
speed: 2,
loop: false,
},
slider: {
minLimit: 0,
maxLimit: 1,
start: 0.1,
end: 0.9,
minText: 'min',
maxText: 'max',
},
selectedTickStyle: {
fill: '#5B8FF9'
},
unselectedTickStyle: {
fill: '#e6e8e9'
}
};
}
constructor(cfgs?: TimeBarConfig) {
super(cfgs)
}
/**
* TimeBar
*/
public initContainer() {
const graph: IGraph = this.get('graph');
const { width, height } = this._cfgs
const className: string = this.get('className') || 'g6-component-timebar';
let parentNode: string | HTMLElement = this.get('container');
const container: HTMLElement = createDOM(
`<div class='${className}' style='position: absolute; width: ${width}px; height: ${height}px;'></div>`,
);
if (isString(parentNode)) {
parentNode = document.getElementById(parentNode) as HTMLElement;
}
if (parentNode) {
parentNode.appendChild(container);
} else {
graph.get('container').appendChild(container);
}
this.set('container', container);
let canvas;
const renderer = graph.get('renderer');
if (renderer === 'SVG') {
canvas = new GSVGCanvas({
container: container,
width,
height,
});
} else {
canvas = new GCanvas({
container: container,
width,
height,
});
}
this.set('canvas', canvas);
}
public init() {
this.initContainer()
const canvas: ICanvas = this.get('canvas')
const timeBarGroup = canvas.addGroup({
name: 'timebar-group'
})
this.set('timeBarGroup', timeBarGroup)
this.renderSlices()
// this.renderTimeLine()
this.initEvent()
}
private renderSlices() {
const self = this;
const ratio = 0.6
const { width, height, x, y, padding, trend, slider, tickLabelFormatter } = self._cfgs
const { data, ...other } = trend
const { start, end } = slider;
// const realHeight = height - 2 * padding
const realWidth = width - 2 * padding
const fontSize = 10;
const labelLineHeight = 4;
const labelAreaHeight = 3 * padding + labelLineHeight + fontSize;
const ticksAreaHeight = height - labelAreaHeight - 2 * padding;
// styles
const selectedTickStyle = self.get('selectedTickStyle');
const unselectedTickStyle = self.get('unselectedTickStyle');
const gap = 2;
const ticksLength = data.length;
const tickWidth = (realWidth - gap * (ticksLength - 1)) / ticksLength;
self.set('tickWidth', tickWidth);
const group = self.get('timeBarGroup');
const tickRects = [];
const labels = [];
const startTickId = Math.round(ticksLength * start);
const endTickId = Math.round(ticksLength * end);
self.set('startTickRectId', startTickId);
self.set('endickRectId', endTickId);
data.forEach((d, i) => {
// draw the tick rects
const selected = i >= startTickId && i <= endTickId;
const tickStyle = selected ? selectedTickStyle : unselectedTickStyle
const rect = group.addShape('rect', {
attrs: {
x: padding + i * (tickWidth + gap),
y: padding,
width: tickWidth,
height: ticksAreaHeight,
...tickStyle
},
draggable: true,
name: `tick-rect-${i}`
});
// draw the pick tick rects
const pickRect = group.addShape('rect', {
attrs: {
x: padding + i * tickWidth + gap * (2 * i - 1) / 2,
y: padding,
width: (i === 0 || i === ticksLength - 1) ? (tickWidth + gap / 2) : (tickWidth + gap),
height: ticksAreaHeight,
fill: '#fff',
opacity: 0
},
draggable: true,
name: `pick-rect-${i}`
});
const rectBBox = rect.getBBox();
const centerX = (rectBBox.minX + rectBBox.maxX) / 2;
tickRects.push({
rect,
pickRect,
value: d.date,
x: centerX,
y: rectBBox.minY
});
let label = undefined;
if (tickLabelFormatter) {
label = tickLabelFormatter(d);
if (!isString(label) && label) { // return true
label = d.date;
}
} else if (i % Math.round(ticksLength / 10) === 0) {
label = d.date;
}
if (label) {
labels.push(label);
// draw tick lines
const lineStartY = rectBBox.maxY + padding * 2;
group.addShape('line', {
attrs: {
stroke: '#BFBFBF',
x1: centerX,
y1: lineStartY,
x2: centerX,
y2: lineStartY + labelLineHeight
}
});
const labelStartY = lineStartY + labelLineHeight + padding;
const text = group.addShape('text', {
attrs: {
fill: '#8c8c8c',
stroke: '#fff',
lineWidth: 1,
x: centerX,
y: labelStartY,
textAlign: 'center',
text: label,
textBaseline: 'top',
fontSize: 10
},
capture: false
});
const textBBox = text.getBBox();
if (textBBox.maxX > width) {
text.attr('textAlign', 'right');
} else if (textBBox.minX < 0) {
text.attr('textAlign', 'left');
}
// draw tick labels
}
});
self.set('tickRects', tickRects);
}
private filterData(evt) {
const { value } = evt;
const { data: trendData } = this._cfgs.trend
const rangeChange = this.get('rangeChange');
const graph: IGraph = this.get('graph');
const min = Math.round(trendData.length * value[0]);
let max = Math.round(trendData.length * value[1]);
max = max >= trendData.length ? trendData.length - 1 : max;
const minText = trendData[min].date;
const maxText = trendData[max].date;
if (rangeChange) {
rangeChange(graph, minText, maxText);
} else {
// 自动过滤数据,并渲染 graph
const graphData = graph.save() as GraphData;
if (
!this.cacheGraphData ||
(this.cacheGraphData.nodes && this.cacheGraphData.nodes.length === 0)
) {
this.cacheGraphData = graphData;
}
// 过滤掉不在 min 和 max 范围内的节点
const filterData = this.cacheGraphData.nodes.filter(
(d: any) => (d.date >= minText && d.date <= maxText),
);
const nodeIds = filterData.map((node) => node.id);
// 过滤 source 或 target 不在 min 和 max 范围内的边
const fileterEdges = this.cacheGraphData.edges.filter(
(edge) => nodeIds.includes(edge.source) && nodeIds.includes(edge.target),
);
graph.changeData({
nodes: filterData,
edges: fileterEdges,
});
}
}
private renderCurrentData(value: string) {
const valueChange = this.get('valueChange');
const graph: IGraph = this.get('graph');
if (valueChange) {
valueChange(graph, value);
} else {
// 自动过滤数据,并渲染 graph
const graphData = graph.save() as GraphData;
if (
!this.cacheGraphData ||
(this.cacheGraphData.nodes && this.cacheGraphData.nodes.length === 0)
) {
this.cacheGraphData = graphData;
}
// 过滤当前的节点
const filterData = this.cacheGraphData.nodes.filter(
(d: any) => d.date === value,
);
const nodeIds = filterData.map((node) => node.id);
// 过滤 source 或 target
const fileterEdges = this.cacheGraphData.edges.filter(
(edge) => nodeIds.includes(edge.source) && nodeIds.includes(edge.target),
);
graph.changeData({
nodes: filterData,
edges: fileterEdges,
});
}
}
private initEvent() {
const self = this;
const { start, end } = self._cfgs.slider;
const graph: IGraph = self.get('graph');
graph.on('afterrender', () => {
self.filterData({ value: [start, end] });
});
const group = self.get('timeBarGroup');
group.on('click', e => {
const tickRects = self.get('tickRects');
// cancel the selected ticks
const unselectedTickStyle = self.get('unselectedTickStyle');
tickRects.forEach(tickRect => {
tickRect.rect.attr(unselectedTickStyle);
})
const targetRect = e.target;
if (targetRect.get('type') !== 'rect') return;
const id = parseInt(targetRect.get('name').split('-')[2]);
const selectedTickStyle = self.get('selectedTickStyle');
tickRects[id].rect.attr(selectedTickStyle);
self.set('startTickRectId', id);
self.set('endTickRectId', id);
const ticksLength = tickRects.length;
const start = id / ticksLength;
this.filterData({ value: [start, start] });
});
group.on('dragstart', e => {
const tickRects = self.get('tickRects');
// cancel the selected ticks
const unselectedTickStyle = self.get('unselectedTickStyle');
tickRects.forEach(tickRect => {
tickRect.rect.attr(unselectedTickStyle);
})
const targetRect = e.target;
const id = parseInt(targetRect.get('name').split('-')[2]);
const selectedTickStyle = self.get('selectedTickStyle');
tickRects[id].rect.attr(selectedTickStyle);
self.set('startTickRectId', id);
const ticksLength = tickRects.length;
const start = id / ticksLength;
this.filterData({ value: [start, start] });
self.set('dragging', true);
});
group.on('dragover', e => {
if (!self.get('dragging')) return;
if (e.target.get('type') !== 'rect') return;
const id = parseInt(e.target.get('name').split('-')[2]);
const startTickRectId = self.get('startTickRectId');
const tickRects = self.get('tickRects');
const selectedTickStyle = self.get('selectedTickStyle');
const unselectedTickStyle = self.get('unselectedTickStyle');
for (let i = 0; i < tickRects.length; i++) {
const style = i >= startTickRectId && i <= id ? selectedTickStyle : unselectedTickStyle;
tickRects[i].rect.attr(style);
}
const ticksLength = tickRects.length;
self.set('endTickRectId', id);
const start = startTickRectId / ticksLength;
const end = id / ticksLength;
this.filterData({ value: [start, end] });
});
group.on('drop', e => {
if (!self.get('dragging')) return;
self.set('dragging', false);
if (e.target.get('type') !== 'rect') return;
const startTickRectId = self.get('startTickRectId');
const id = parseInt(e.target.get('name').split('-')[2]);
if (id < startTickRectId) return;
const selectedTickStyle = self.get('selectedTickStyle');
const tickRects = self.get('tickRects');
tickRects[id].rect.attr(selectedTickStyle);
self.set('endTickRectId', id);
const ticksLength = tickRects.length;
const start = startTickRectId / ticksLength;
const end = id / ticksLength;
this.filterData({ value: [start, end] });
});
// tooltip
const { tooltipBackgroundColor, tooltipFomatter } = self._cfgs;
const tooltip = new TimeBarTooltip({
container: self.get('container') as HTMLElement,
backgroundColor: tooltipBackgroundColor
});
const tickRects = self.get('tickRects');
const canvas = self.get('canvas');
tickRects.forEach(tickRect => {
const pickRect = tickRect.pickRect;
pickRect.on('mouseenter', e => {
const rect = e.target;
if (rect.get('type') !== 'rect') return;
const id = parseInt(rect.get('name').split('-')[2]);
const clientPoint = canvas.getClientByPoint(tickRects[id].x, tickRects[id].y)
tooltip.show({
x: tickRects[id].x,
y: tickRects[id].y,
clientX: clientPoint.x,
clientY: clientPoint.y,
text: tooltipFomatter ? tooltipFomatter(tickRects[id].value) : tickRects[id].value
})
});
pickRect.on('mouseleave', e => {
tooltip.hide();
})
})
}
public destroy() {
super.destroy();
const group = this.get('timeBarGroup')
group.off('playPauseBtn:click')
}
}

View File

@ -1,18 +1,13 @@
/**
* G
* G
*/
import GCanvas from '@antv/g-canvas/lib/canvas';
import GSVGCanvas from '@antv/g-svg/lib/canvas';
import { ICanvas, IGroup } from '@antv/g-base';
import createDOM from '@antv/dom-util/lib/create-dom'
import { isString } from '@antv/util'
import TimeBarTooltip from './timeBarTooltip';
import ControllerBtn from './controllerBtn'
import TrendTimeBar, { VALUE_CHANGE, TIMELINE_START, TIMELINE_CHANGE, TIMELINE_END } from './trendTimeBar'
import { VALUE_CHANGE, TIMELINE_START, TIMELINE_END, PLAY_PAUSE_BTN, NEXT_STEP_BTN, PRE_STEP_BTN, TIMEBAR_CONFIG_CHANGE } from './constant'
import { IGraph } from '../../interface/graph';
import { GraphData, ShapeStyle } from '../../types';
import { Callback } from './timeBar';
import { ShapeStyle } from '../../types';
const DEFAULT_SELECTEDTICK_STYLE = {
fill: '#5B8FF9'
@ -109,26 +104,6 @@ export default class TimeBarSlice {
private playHandler: number;
private frameCount: number = 0;
public getDefaultCfgs(): TimeBarSliceConfig {
return {
canvas: null,
graph: null,
group: null,
padding: 2,
data: [],
start: 0.1,
end: 0.9,
selectedTickStyle: {
fill: '#5B8FF9'
},
unselectedTickStyle: {
fill: '#e6e8e9'
},
x: 0,
y: 0
};
}
constructor(cfgs?: TimeBarSliceConfig) {
const {
graph,
@ -332,7 +307,6 @@ export default class TimeBarSlice {
const ticksLength = tickRects.length;
const start = id / ticksLength;
// this.filterData({ value: [start, start] });
this.graph.emit(VALUE_CHANGE, { value: [start, start] })
}
});
@ -352,7 +326,6 @@ export default class TimeBarSlice {
const ticksLength = tickRects.length;
const start = id / ticksLength;
// this.filterData({ value: [start, start] });
this.graph.emit(VALUE_CHANGE, { value: [start, start] })
this.dragging = true
@ -375,7 +348,6 @@ export default class TimeBarSlice {
const start = startTickRectId / ticksLength;
const end = id / ticksLength;
// this.filterData({ value: [start, end] });
this.graph.emit(VALUE_CHANGE, { value: [start, end] })
});
@ -397,17 +369,9 @@ export default class TimeBarSlice {
const ticksLength = tickRects.length;
const start = startTickRectId / ticksLength;
const end = id / ticksLength;
// this.filterData({ value: [start, end] });
this.graph.emit(VALUE_CHANGE, { value: [start, end] })
});
// 时间轴的值发生改变的事件
// this.graph.on(VALUE_CHANGE, (evt: Callback) => {
// // 范围变化
// this.filterData(evt);
// console.log(evt)
// });
// tooltip
const { tooltipBackgroundColor, tooltipFomatter, canvas } = this
const tooltip = new TimeBarTooltip({
@ -440,22 +404,22 @@ export default class TimeBarSlice {
const group = this.group;
// 播放区按钮控制
/** 播放/暂停事件 */
group.on('playPauseBtn:click', () => {
group.on(`${PLAY_PAUSE_BTN}:click`, () => {
this.isPlay = !this.isPlay;
this.changePlayStatus();
})
// 处理前进一步的事件
group.on('nextStepBtn:click', () => {
group.on(`${NEXT_STEP_BTN}:click`, () => {
this.updateStartEnd(1);
})
// 处理后退一步的事件
group.on('preStepBtn:click', () => {
group.on(`${PRE_STEP_BTN}:click`, () => {
this.updateStartEnd(-1);
})
group.on('timebarConfigChanged', ({ type, speed }) => {
group.on(TIMEBAR_CONFIG_CHANGE, ({ type, speed }) => {
this.currentSpeed = speed
})
}
@ -530,4 +494,30 @@ export default class TimeBarSlice {
const end = self.endTickRectId / ticksLength;
this.graph.emit(VALUE_CHANGE, { value: [start, end] })
}
public destory() {
this.graph.off(VALUE_CHANGE)
const group = this.sliceGroup
group.off('click')
group.off('dragstart')
group.off('dragover')
group.off('drop')
this.tickRects.forEach(tickRect => {
const pickRect = tickRect.pickRect;
pickRect.off('mouseenter')
pickRect.off('mouseleave')
})
this.tickRects.length = 0
group.off(`${PLAY_PAUSE_BTN}:click`)
group.off(`${NEXT_STEP_BTN}:click`)
group.off(`${PRE_STEP_BTN}:click`)
group.off(TIMEBAR_CONFIG_CHANGE)
this.sliceGroup.destroy()
}
}

View File

@ -5,6 +5,8 @@ import Handler from './handler';
import ControllerBtn from './controllerBtn'
import { IGraph } from '../../interface/graph';
import { ShapeStyle } from '../../types';
import { VALUE_CHANGE, TIMELINE_START, TIMEBAR_CONFIG_CHANGE,
PLAY_PAUSE_BTN, NEXT_STEP_BTN, PRE_STEP_BTN, TIMELINE_END } from './constant';
/**
*
@ -40,12 +42,6 @@ export const TEXT_STYLE = {
opacity: 0.45,
};
export const TIMELINE_START = 'timelinestart';
export const TIMELINE_CHANGE = 'timelinechange';
export const TIMELINE_END = 'timelineend';
export const VALUE_CHANGE = 'valueChange';
export type ControllerCfg = Partial<{
readonly x: number;
readonly y: number;
@ -491,27 +487,27 @@ export default class TrendTimeBar {
// 播放区按钮控制
/** 播放/暂停事件 */
this.group.on('playPauseBtn:click', () => {
this.group.on(`${PLAY_PAUSE_BTN}:click`, () => {
this.isPlay = !this.isPlay;
this.currentHandler = this.maxHandlerShape
this.changePlayStatus();
})
// 处理前进一步的事件
this.group.on('nextStepBtn:click', () => {
this.group.on(`${NEXT_STEP_BTN}:click`, () => {
this.currentHandler = this.maxHandlerShape
this.updateStartEnd(0.01);
this.updateUI()
})
// 处理后退一步的事件
this.group.on('preStepBtn:click', () => {
this.group.on(`${PRE_STEP_BTN}:click`, () => {
this.currentHandler = this.maxHandlerShape
this.updateStartEnd(-0.01);
this.updateUI()
})
this.group.on('timebarConfigChanged', ({ type, speed }) => {
this.group.on(TIMEBAR_CONFIG_CHANGE, ({ type, speed }) => {
this.currentSpeed = speed
this.currentMode = type
if (type === 'single') {
@ -798,4 +794,36 @@ export default class TrendTimeBar {
}
}
}
public destory() {
this.graph.off(VALUE_CHANGE)
const group = this.group
const minHandleShapeGroup = group.find(g => g.get('name') === 'minHandlerShape')
if (minHandleShapeGroup) {
minHandleShapeGroup.off('minHandlerShape-handler:mousedown')
minHandleShapeGroup.off('minHandlerShape-handler:touchstart');
minHandleShapeGroup.destroy()
}
const maxHandleShapeGroup = group.find(g => g.get('name') === 'maxHandlerShape')
// 2. 右滑块的滑动
if (maxHandleShapeGroup) {
maxHandleShapeGroup.off('maxHandlerShape-handler:mousedown');
maxHandleShapeGroup.off('maxHandlerShape-handler:touchstart');
maxHandleShapeGroup.destroy()
}
// 3. 前景选中区域
this.foregroundShape.off('mousedown');
this.foregroundShape.off('touchstart');
this.foregroundShape.destroy()
group.off(`${PLAY_PAUSE_BTN}:click`)
group.off(`${NEXT_STEP_BTN}:click`)
group.off(`${PRE_STEP_BTN}:click`)
group.off(TIMEBAR_CONFIG_CHANGE)
group.destroy()
}
}

View File

@ -1,7 +1,6 @@
import React, { useEffect } from 'react';
import G6, { Graph } from '../../../src';
import { IGraph } from '../../../src/interface/graph';
import TimeBar from '../../../src/plugins/timeBar/timeBar';
let graph: IGraph = null;
@ -50,7 +49,7 @@ const TimeBarS = () => {
console.log('timeBarData', timeBarData)
let count = 0;
const timebar = new TimeBar({
const timebar = new G6.TimeBar({
x: 0,
y: 0,
width: 500,

View File

@ -1,5 +1,5 @@
import G6 from '../../../src';
import TimeBar from '../../../src/plugins/timeBar/timeBar'
import TimeBar from '../../../src/plugins/timeBar'
const div = document.createElement('div');
div.id = 'timebar-plugin';
document.body.appendChild(div);