Merge remote-tracking branch 'antv/master' into g6-react-node

This commit is contained in:
多牧 2021-02-02 13:24:36 +08:00
commit 4ea639dad2
71 changed files with 894 additions and 260 deletions

View File

@ -1,5 +1,27 @@
# ChangeLog
#### 4.1.7
- fix: polyline with negative endpoints;
- fix: polyline direction when linkCenter;
- fix: remove g6-core browser since it has no umd output;
- feat: custom texts for the time range and time point text in timeBar plugin;
- chore: types for strict mode;
#### 4.1.6
- fix: webworker problem after removing broswer in pc and g6;
#### 4.1.5
- fix: wrong style for modelRect after updating and state changing, closes: #2613;
- fix: drag-canvas with shouldBegin false, closes: #2571;
- fix: pack plugin with es module, closes: #2577;
- feat: dijkstra with multiple shortest paths, closes: #2297;
- fix: setMode while the delegates of brush-select and drag-node is on the canvas, closes: #2607;
- docs: update the english TimeBar docs, closes: #2597;
- fix: TimeBar time point switch text configurable, closes: #2597;
#### 4.1.4
- fix: drag-canvas with touch on mobile;

View File

@ -115,6 +115,16 @@ graph.render();
```bash
$ npm install
# lerna bootstrap for multiple packages
$ npm run bootstrap
# build the packages
$ npm run build:all
# if you wanna watch one of the packages, e.g. packages/core
$ cd ./packages/core
$ npm run watch
# run test case
$ npm test
@ -149,7 +159,7 @@ $ npm run demos
请让我们知道您要解决或贡献什么,所以在贡献之前请先提交 [issues](https://github.com/antvis/g6/issues) 描述 bug 或建议。
成为一个贡献者前请阅读 [代码贡献规范](https://github.com/antvis/g6/blob/master/CONTRIBUTING.zh-CN.md).
成为一个贡献者前请阅读 [代码贡献规范](https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.zh-CN.md).
## License

View File

@ -115,6 +115,16 @@ For more information of the usage, please refer to [Getting Started](https://ant
```bash
$ npm install
# lerna bootstrap for multiple packages
$ npm run bootstrap
# build the packages
$ npm run build:all
# if you wanna watch one of the packages, e.g. packages/core
$ cd ./packages/core
$ npm run watch
# run test case
$ npm test
@ -145,7 +155,7 @@ Users are welcome to join the **G6 Communication Group** or **G6 Communication G
Please let us know what you are you going to help. Do check out [issues](https://github.com/antvis/g6/issues) for bug reports or suggestions first.
To become a contributor, please follow our [contributing guide](https://github.com/antvis/g6/blob/master/CONTRIBUTING.md).
To become a contributor, please follow our [contributing guide](https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.md).
## License

View File

@ -64,10 +64,15 @@
"typescript": "^3.5.3"
},
"devDependencies": {
"@umijs/fabric": "^2.3.1",
"pre-commit": "^1.2.2",
"@types/react": "^16.9.35",
"@types/react-dom": "^16.9.8",
"@umijs/fabric": "^2.3.1",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-react": "^7.22.0",
"eslint-plugin-react-hooks": "^4.2.0",
"eslint-plugin-unicorn": "^27.0.0",
"pre-commit": "^1.2.2",
"react-scripts": "3.1.2"
},
"resolutions": {

View File

@ -115,8 +115,17 @@ graph.render();
```bash
$ npm install
# run bootstrap to link the packages
$ npm run bootstrap
# build all the packages
$ npm run build:all
# run test case
$ npm test
$ npm run test
# run lint
$ npm run lint
# run test case in watch mode
npm test -- --watch ./tests/unit/algorithm/find-path-spec
@ -149,7 +158,7 @@ $ npm run demos
请让我们知道您要解决或贡献什么,所以在贡献之前请先提交 [issues](https://github.com/antvis/g6/issues) 描述 bug 或建议。
成为一个贡献者前请阅读 [代码贡献规范](https://github.com/antvis/g6/blob/master/CONTRIBUTING.zh-CN.md).
成为一个贡献者前请阅读 [代码贡献规范](https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.zh-CN.md).
## License

View File

@ -115,8 +115,17 @@ For more information of the usage, please refer to [Getting Started](https://ant
```bash
$ npm install
# run bootstrap to link the packages
$ npm run bootstrap
# build all the packages
$ npm run build:all
# run test case
$ npm test
$ npm run test
# run lint
$ npm run lint
# run test case in watch mode
npm test -- --watch ./tests/unit/algorithm/find-path-spec
@ -145,7 +154,7 @@ Users are welcome to join the **G6 Communication Group** or **G6 Communication G
Please let us know what you are you going to help. Do check out [issues](https://github.com/antvis/g6/issues) for bug reports or suggestions first.
To become a contributor, please follow our [contributing guide](https://github.com/antvis/g6/blob/master/CONTRIBUTING.md).
To become a contributor, please follow our [contributing guide](https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.md).
## License

View File

@ -1,6 +1,6 @@
{
"name": "@antv/g6-core",
"version": "0.0.7",
"version": "0.0.9",
"description": "A Graph Visualization Framework in JavaScript",
"keywords": [
"antv",
@ -31,7 +31,6 @@
],
"main": "lib/index.js",
"module": "es/index.js",
"browser": "dist/g6-core.min.js",
"types": "lib/index.d.ts",
"scripts": {
"start": "father build --watch",
@ -59,7 +58,7 @@
]
},
"dependencies": {
"@antv/algorithm": "^0.0.6",
"@antv/algorithm": "^0.0.7",
"@antv/dom-util": "^2.0.1",
"@antv/event-emitter": "~0.1.0",
"@antv/g-base": "^0.5.1",

View File

@ -8,6 +8,7 @@ import { IPoint, Item, LabelStyle, ShapeStyle, ModelConfig, EdgeConfig } from '.
import Global from '../global';
import { ext } from '@antv/matrix-util';
import { deepMix, each, mix, isBoolean, isPlainObject, clone } from '@antv/util';
import { cloneBesidesImg } from '../util/graphic';
const transform = ext.transform;
@ -401,11 +402,11 @@ export const shapeBase: ShapeOptions = {
}
} else {
// 所有生效的 state 的样式
const enableStatesStyle = clone(item.getCurrentStatesStyle());
const enableStatesStyle = cloneBesidesImg(item.getCurrentStatesStyle());
const model = item.getModel();
// 原始样式
const originStyle = mix({}, model.style, clone(item.getOriginStyle()));
const originStyle = mix({}, model.style, cloneBesidesImg(item.getOriginStyle()));
const keyShapeName = shape.get('name');
@ -416,7 +417,7 @@ export const shapeBase: ShapeOptions = {
Object.keys(shapeAttrs).forEach((key) => {
if (key === 'img') return;
const attr = shapeAttrs[key];
if (typeof attr === 'object') {
if (attr && typeof attr === 'object') {
keyShapeStyles[key] = clone(attr);
} else {
keyShapeStyles[key] = attr;
@ -466,7 +467,6 @@ export const shapeBase: ShapeOptions = {
} else {
filtetDisableStatesStyle[keyShapeName] = keyShapeStyles;
}
for (const key in enableStatesStyle) {
if (keptAttrs[key]) continue;
const enableStyle = enableStatesStyle[key];

View File

@ -64,7 +64,7 @@ const colorSet = {
};
export default {
version: '0.0.7',
version: '0.0.9',
rootContainerClassName: 'root-container',
nodeContainerClassName: 'node-container',
edgeContainerClassName: 'edge-container',

View File

@ -120,6 +120,7 @@ export default class ModeController {
graph.emit('beforemodechange', { mode });
each(this.currentBehaves, behave => {
if (behave.delegate) behave.delegate.remove();
behave.unbind(graph);
});

View File

@ -360,7 +360,7 @@ export interface IAbstractGraph extends EventEmitter {
* @param {string} mode default
* @return {Graph} Graph
*/
updateBehavior: (behavior: string, newCfg: object, modes: string | string[]) => Graph;
updateBehavior: (behavior: string, newCfg: object, mode?: string) => Graph;
/**
*

View File

@ -363,5 +363,5 @@ export interface ICombo extends INode {
* @param node
* @return boolean true false
*/
removeNode: (node: string | INode) => boolean;
removeNode: (node: INode) => boolean;
}

View File

@ -1,7 +1,7 @@
import { IGroup } from '@antv/g-base';
import { ICombo, INode, IItemBaseConfig } from '../interface/item';
import Node from './node';
import { ComboConfig, IBBox, IShapeBase } from '../types';
import { ComboConfig, IBBox, IShapeBase, ModelConfig } from '../types';
import Global from '../global';
import { getBBox } from '../util/graphic';
import { isNumber } from '@antv/util';
@ -21,7 +21,7 @@ export default class Combo extends Node implements ICombo {
};
}
public getShapeCfg(model: ComboConfig): ComboConfig {
public getShapeCfg(model: ModelConfig): ModelConfig {
const styles = this.get('styles');
const bbox = this.get('bbox');
if (styles && bbox) {

View File

@ -217,13 +217,18 @@ export default class ItemBase implements IItemBase {
originStyles[name] =
shapeType !== 'image' ? clone(child.attr()) : self.getShapeStyleByName(name);
} else {
// !name || name === keyShape
const keyShapeStyle: ShapeStyle = self.getShapeStyleByName(); // 可优化,需要去除 child.attr 中其他 shape 名的对象
if (keyShapeStyle.path) delete keyShapeStyle.path;
if (keyShapeStyle.matrix) delete keyShapeStyle.matrix;
if (!keyShapeName) {
Object.assign(originStyles, keyShapeStyle);
} else {
originStyles[keyShapeName] = keyShapeStyle;
} else { // 若 keyShape 有 name 且 !name这个图形不是 keyShape给这个图形一个 name
if (!name) {
const shapeName = uniqueId('shape');
child.set('name', shapeName);
originStyles[shapeName] = shapeType !== 'image' ? clone(child.attr()) : self.getShapeStyleByName(name);
} else originStyles[keyShapeName] = keyShapeStyle
}
}
});

View File

@ -1,6 +1,6 @@
import { each, isNil, mix } from '@antv/util';
import { IEdge, INode } from '../interface/item';
import { IPoint, IShapeBase, NodeConfig } from '../types';
import { IPoint, IShapeBase, ModelConfig, NodeConfig } from '../types';
import { getBBox } from '../util/graphic';
import {
distance,
@ -237,7 +237,7 @@ export default class Node extends Item implements INode {
*
* @param cfg
*/
public isOnlyMove(cfg: NodeConfig): boolean {
public isOnlyMove(cfg: ModelConfig): boolean {
if (!cfg) {
return false;
}

View File

@ -13,7 +13,7 @@ import {
} from '../types';
import { applyMatrix } from './math';
import letterAspectRatio from './letterAspectRatio';
import { isString, clone, isNumber } from '@antv/util';
import { isString, clone, isNumber, isObject } from '@antv/util';
import { IAbstractGraph } from '../interface/graph';
const { PI, sin, cos } = Math;
@ -648,3 +648,22 @@ export const shouldRefreshEdge = (cfg) => {
isNumber(cfg.style.ry);
return refreshEdge;
};
export const cloneBesidesImg = (obj) => {
const clonedObj = {};
Object.keys(obj).forEach(key1 => {
const obj2 = obj[key1];
if (isObject(obj2)) {
const clonedObj2 = {};
Object.keys(obj2).forEach(key2 => {
const v = obj2[key2];
if(key2 === 'img' && !isString(v)) return;
clonedObj2[key2] = clone(v);
})
clonedObj[key1] = clonedObj2;
} else {
clonedObj[key1] = clone(obj2);
}
});
return clonedObj;
}

View File

@ -47,7 +47,7 @@ const isBetween = (value: number, min: number, max: number) => value >= min && v
* @return {Point}
*/
export const getLineIntersect = (p0: Point, p1: Point, p2: Point, p3: Point): Point | null => {
const tolerance = 0.001;
const tolerance = 0.0001;
const E: Point = {
x: p2.x - p0.x,
@ -63,12 +63,13 @@ export const getLineIntersect = (p0: Point, p1: Point, p2: Point, p3: Point): Po
};
const kross: number = D0.x * D1.y - D0.y * D1.x;
const sqrKross: number = kross * kross;
const invertKross: number = 1 / kross;
const sqrLen0: number = D0.x * D0.x + D0.y * D0.y;
const sqrLen1: number = D1.x * D1.x + D1.y * D1.y;
let point: Point | null = null;
if (sqrKross > tolerance * sqrLen0 * sqrLen1) {
const s = (E.x * D1.y - E.y * D1.x) / kross;
const t = (E.x * D0.y - E.y * D0.x) / kross;
const s = (E.x * D1.y - E.y * D1.x) * invertKross;
const t = (E.x * D0.y - E.y * D0.x) * invertKross;
if (isBetween(s, 0, 1) && isBetween(t, 0, 1)) {
point = {
x: p0.x + s * D0.x,

View File

@ -115,8 +115,17 @@ graph.render();
```bash
$ npm install
# run bootstrap to link the packages
$ npm run bootstrap
# build all the packages
$ npm run build:all
# run test case
$ npm test
$ npm run test
# run lint
$ npm run lint
# run test case in watch mode
npm test -- --watch ./tests/unit/algorithm/find-path-spec
@ -149,7 +158,7 @@ $ npm run demos
请让我们知道您要解决或贡献什么,所以在贡献之前请先提交 [issues](https://github.com/antvis/g6/issues) 描述 bug 或建议。
成为一个贡献者前请阅读 [代码贡献规范](https://github.com/antvis/g6/blob/master/CONTRIBUTING.zh-CN.md).
成为一个贡献者前请阅读 [代码贡献规范](https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.zh-CN.md).
## License

View File

@ -115,8 +115,17 @@ For more information of the usage, please refer to [Getting Started](https://ant
```bash
$ npm install
# run bootstrap to link the packages
$ npm run bootstrap
# build all the packages
$ npm run build:all
# run test case
$ npm test
$ npm run test
# run lint
$ npm run lint
# run test case in watch mode
npm test -- --watch ./tests/unit/algorithm/find-path-spec
@ -145,7 +154,7 @@ Users are welcome to join the **G6 Communication Group** or **G6 Communication G
Please let us know what you are you going to help. Do check out [issues](https://github.com/antvis/g6/issues) for bug reports or suggestions first.
To become a contributor, please follow our [contributing guide](https://github.com/antvis/g6/blob/master/CONTRIBUTING.md).
To become a contributor, please follow our [contributing guide](https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.md).
## License

View File

@ -1,6 +1,6 @@
{
"name": "@antv/g6-element",
"version": "0.0.6",
"version": "0.0.8",
"description": "A Graph Visualization Framework in JavaScript",
"keywords": [
"antv",
@ -61,7 +61,7 @@
},
"dependencies": {
"@antv/g-base": "^0.5.1",
"@antv/g6-core": "^0.0.7",
"@antv/g6-core": "^0.0.9",
"@antv/util": "~2.0.5"
},
"devDependencies": {

View File

@ -66,14 +66,13 @@ export const filterConnectPoints = (points: PolyPoint[]): PolyPoint[] => {
// pre-process: remove duplicated points
const result: any[] = [];
const pointsMap: any = {};
points.forEach((p) => {
const id = `${p.x}-${p.y}`;
p.id = id;
pointsMap[id] = p;
});
each(pointsMap, (p) => {
const pointsLength = points.length;
for (let i = 0; i < pointsLength; i++) {
const p = points[i];
p.id = `${p.x}|||${p.y}`;
pointsMap[p.id] = p;
result.push(p);
});
}
return result;
};
export const simplifyPolyline = (points: PolyPoint[]): PolyPoint[] => {
@ -102,13 +101,37 @@ export const getExpandedBBox = (bbox: any, offset: number): PBBox => {
width: bbox.width + 2 * offset,
};
};
export const isHorizontalPort = (port: PolyPoint, bbox: PBBox): boolean => {
export const isHorizontalPort = (port: PolyPoint, bbox: PBBox): boolean | number => {
const dx = Math.abs(port.x - bbox.centerX);
const dy = Math.abs(port.y - bbox.centerY);
if (dx === 0 && dy === 0) return 0;
return dx / bbox.width > dy / bbox.height;
};
export const getExpandedBBoxPoint = (bbox: any, point: PolyPoint): PolyPoint => {
export const getExpandedBBoxPoint = (
bbox: any,
point: PolyPoint,
anotherPoint: PolyPoint,
): PolyPoint => {
const isHorizontal = isHorizontalPort(point, bbox);
if (isHorizontal === 0) {
// 说明锚点是节点中心linkCenter: true。需要根据两个节点的相对关系决定方向
let x = bbox.centerX;
let y = bbox.centerY;
if (anotherPoint.y < point.y) {
// 另一端在左上/右上方时,总是从上方走
y = bbox.minY;
} else if (anotherPoint.x > point.x) {
// 另一端在右下方,往右边走
x = bbox.maxX;
} else if (anotherPoint.x < point.x) {
// 另一端在左下方,往左边走
x = bbox.minX;
} else if (anotherPoint.x === point.x) {
// 另一段在正下方,往下走
y = bbox.maxY;
}
return { x, y };
}
if (isHorizontal) {
return {
x: point.x > bbox.centerX ? bbox.maxX : bbox.minX,
@ -266,15 +289,21 @@ export const isSegmentsIntersected = (
p2: PolyPoint,
p3: PolyPoint,
): boolean => {
const s1X = p1.x - p0.x;
const s1Y = p1.y - p0.y;
const s2X = p3.x - p2.x;
const s2Y = p3.y - p2.y;
const v1x = p2.x - p0.x;
const v1y = p2.y - p0.y;
const v2x = p3.x - p0.x;
const v2y = p3.y - p0.y;
const v3x = p2.x - p1.x;
const v3y = p2.y - p1.y;
const v4x = p3.x - p1.x;
const v4y = p3.y - p1.y;
const s = (-s1Y * (p0.x - p2.x) + s1X * (p0.y - p2.y)) / (-s2X * s1Y + s1X * s2Y);
const t = (s2X * (p0.y - p2.y) - s2Y * (p0.x - p2.x)) / (-s2X * s1Y + s1X * s2Y);
const pd1 = v1x * v2y - v1y * v2x;
const pd2 = v3x * v4y - v3y * v4x;
const pd3 = v1x * v3y - v1y * v3x;
const pd4 = v2x * v4y - v2y * v4x;
return s >= 0 && s <= 1 && t >= 0 && t <= 1;
return pd1 * pd2 <= 0 && pd3 * pd4 <= 0;
};
export const isSegmentCrossingBBox = (p1: PolyPoint, p2: PolyPoint, bbox: PBBox): boolean => {
if (bbox.width === 0 && bbox.height === 0) {
@ -483,10 +512,9 @@ export const getPolylinePoints = (
// the expanded bounding boxes of source and target nodes are overlapping
return simplifyPolyline(getSimplePolyline(start, end));
}
const sPoint = getExpandedBBoxPoint(sxBBox, start);
const tPoint = getExpandedBBoxPoint(txBBox, end);
const sPoint = getExpandedBBoxPoint(sxBBox, start, end);
const tPoint = getExpandedBBoxPoint(txBBox, end, start);
const lineBBox = getBBoxFromPoints([sPoint, tPoint]);
const outerBBox = mergeBBox(sxBBox, txBBox);
const sMixBBox = mergeBBox(sxBBox, lineBBox);
const tMixBBox = mergeBBox(txBBox, lineBBox);
let connectPoints: any = [];

View File

@ -37,7 +37,7 @@ registerEdge(
routeCfg: {
obstacles: [], // 希望边绕过的障碍节点
maxAllowedDirectionChange: 90, // 允许的最大转角
maximumLoops: 1000,
maximumLoops: 500,
gridSize: 10, // 指定精度
},
stateStyles: {

View File

@ -97,8 +97,9 @@ export const octolinearCfg: RouterCfg = {
};
const pos2GridIx = (pos: number, gridSize: number) => {
const gridIx = Math.floor(pos / gridSize);
return gridIx < 0 ? 0 : gridIx;
const gridIx = Math.floor(Math.abs(pos / gridSize));
const sign = pos < 0 ? -1 : 1;
return gridIx < 0 ? 0 : sign * gridIx;
};
const getObstacleMap = (items: Item[], gridSize: number, offset: number) => {
@ -113,7 +114,7 @@ const getObstacleMap = (items: Item[], gridSize: number, offset: number) => {
y <= pos2GridIx(bbox.maxY, gridSize);
y += 1
) {
const gridKey = `${x}-${y}`;
const gridKey = `${x}|||${y}`;
map[gridKey] = true;
}
}
@ -158,7 +159,13 @@ const estimateCost = (from: PolyPoint, endPoints: PolyPoint[], distFunc) => {
};
// 计算考虑 offset 后的 BBox 上的连接点
const getBoxPoints = (point: PolyPoint, node: INode, cfg: RouterCfg): PolyPoint[] => {
const getBoxPoints = (
point: PolyPoint,
oriPoint: PolyPoint,
node: INode,
anotherPoint: PolyPoint,
cfg: RouterCfg,
): PolyPoint[] => {
const points = [];
// create-edge 生成边的过程中endNode 为 null
if (!node) {
@ -167,15 +174,16 @@ const getBoxPoints = (point: PolyPoint, node: INode, cfg: RouterCfg): PolyPoint[
const { directions, offset } = cfg;
const bbox = node.getBBox();
const expandBBox = getExpandedBBox(node.getBBox(), offset);
const isInside =
oriPoint.x > bbox.minX &&
oriPoint.x < bbox.maxX &&
oriPoint.y > bbox.minY &&
oriPoint.y < bbox.maxY;
const expandBBox = getExpandedBBox(bbox, offset);
for (const i in expandBBox) {
expandBBox[i] = pos2GridIx(expandBBox[i], cfg.gridSize);
}
const isInside =
point.x > pos2GridIx(bbox.minX, cfg.gridSize) &&
point.x < pos2GridIx(bbox.maxX, cfg.gridSize) &&
point.y > pos2GridIx(bbox.minY, cfg.gridSize) &&
point.y < pos2GridIx(bbox.maxY, cfg.gridSize);
if (isInside) {
// 如果 anchorPoint 在节点内部,允许第一段线穿过节点
@ -230,16 +238,16 @@ const getBoxPoints = (point: PolyPoint, node: INode, cfg: RouterCfg): PolyPoint[
boundLine[0],
boundLine[1],
) as PolyPoint;
if (insterctP && !isSegmentCrossingBBox(point, insterctP, node.getBBox())) {
insterctP.id = `${insterctP.x}-${insterctP.y}`;
if (insterctP && !isSegmentCrossingBBox(point, insterctP, bbox)) {
insterctP.id = `${insterctP.x}|||${insterctP.y}`;
points.push(insterctP);
}
}
}
} else {
// 如果 anchorPoint 在节点上,只有一个可选方向
const insterctP = getExpandedBBoxPoint(expandBBox, point);
insterctP.id = `${insterctP.x}-${insterctP.y}`;
const insterctP = getExpandedBBoxPoint(expandBBox, point, anotherPoint);
insterctP.id = `${insterctP.x}|||${insterctP.y}`;
points.push(insterctP);
}
@ -266,10 +274,10 @@ export const pathFinder = (
y: pos2GridIx(endPoint.y, cfg.gridSize),
};
startPoint.id = `${scaleStartPoint.x}-${scaleStartPoint.y}`;
endPoint.id = `${scaleEndPoint.x}-${scaleEndPoint.y}`;
const startPoints = getBoxPoints(scaleStartPoint, startNode, cfg);
const endPoints = getBoxPoints(scaleEndPoint, endNode, cfg);
startPoint.id = `${scaleStartPoint.x}|||${scaleStartPoint.y}`;
endPoint.id = `${scaleEndPoint.x}|||${scaleEndPoint.y}`;
const startPoints = getBoxPoints(scaleStartPoint, startPoint, startNode, scaleEndPoint, cfg);
const endPoints = getBoxPoints(scaleEndPoint, endPoint, endNode, scaleStartPoint, cfg);
startPoints.forEach((point) => {
delete map[point.id];
});
@ -311,8 +319,8 @@ export const pathFinder = (
} else {
const prevDirectionAngle = getDirectionAngle(
{
x: parseFloat(cameFrom[current.id].split('-')[0]),
y: parseFloat(cameFrom[current.id].split('-')[1]),
x: parseFloat(cameFrom[current.id].split('|||')[0]),
y: parseFloat(cameFrom[current.id].split('|||')[1]),
},
current,
);
@ -324,8 +332,8 @@ export const pathFinder = (
const getControlPoints = (currentId: string) => {
const controlPoints = [endPoint];
const lastPoint = {
x: parseFloat(currentId.split('-')[0]),
y: parseFloat(currentId.split('-')[1]),
x: parseFloat(currentId.split('|||')[0]),
y: parseFloat(currentId.split('|||')[1]),
id: currentId,
};
if (getDirectionChange(lastPoint, scaleEndPoint)) {
@ -336,14 +344,14 @@ export const pathFinder = (
}
while (cameFrom[currentId] && cameFrom[currentId] !== currentId) {
const point = {
x: parseFloat(currentId.split('-')[0]),
y: parseFloat(currentId.split('-')[1]),
x: parseFloat(currentId.split('|||')[0]),
y: parseFloat(currentId.split('|||')[1]),
id: currentId,
};
const preId = cameFrom[currentId];
const prePoint = {
x: parseFloat(preId.split('-')[0]),
y: parseFloat(preId.split('-')[1]),
x: parseFloat(preId.split('|||')[0]),
y: parseFloat(preId.split('|||')[1]),
id: preId,
};
const directionChange = getDirectionChange(prePoint, point);
@ -359,8 +367,8 @@ export const pathFinder = (
// 和startNode对齐
const firstPoint = {
x: parseFloat(currentId.split('-')[0]),
y: parseFloat(currentId.split('-')[1]),
x: parseFloat(currentId.split('|||')[0]),
y: parseFloat(currentId.split('|||')[1]),
id: currentId,
};
controlPoints[0].x = firstPoint.x === scaleStartPoint.x ? startPoint.x : controlPoints[0].x;
@ -399,7 +407,7 @@ export const pathFinder = (
const neighbor = {
x: current.x + direction.stepX,
y: current.y + direction.stepY,
id: `${current.x + direction.stepX}-${current.y + direction.stepY}`,
id: `${current.x + direction.stepX}|||${current.y + direction.stepY}`,
};
if (closedSet[neighbor.id]) continue;

View File

@ -302,6 +302,8 @@ registerNode(
y: 7,
text: cfg.label,
},
className: 'text-shape',
name: 'text-shape',
draggable: true,
});
}

View File

@ -115,8 +115,17 @@ graph.render();
```bash
$ npm install
# run bootstrap to link the packages
$ npm run bootstrap
# build all the packages
$ npm run build:all
# run test case
$ npm test
$ npm run test
# run lint
$ npm run lint
# run test case in watch mode
npm test -- --watch ./tests/unit/algorithm/find-path-spec
@ -149,7 +158,7 @@ $ npm run demos
请让我们知道您要解决或贡献什么,所以在贡献之前请先提交 [issues](https://github.com/antvis/g6/issues) 描述 bug 或建议。
成为一个贡献者前请阅读 [代码贡献规范](https://github.com/antvis/g6/blob/master/CONTRIBUTING.zh-CN.md).
成为一个贡献者前请阅读 [代码贡献规范](https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.zh-CN.md).
## License

View File

@ -115,8 +115,17 @@ For more information of the usage, please refer to [Getting Started](https://ant
```bash
$ npm install
# run bootstrap to link the packages
$ npm run bootstrap
# build all the packages
$ npm run build:all
# run test case
$ npm test
$ npm run test
# run lint
$ npm run lint
# run test case in watch mode
npm test -- --watch ./tests/unit/algorithm/find-path-spec
@ -145,7 +154,7 @@ Users are welcome to join the **G6 Communication Group** or **G6 Communication G
Please let us know what you are you going to help. Do check out [issues](https://github.com/antvis/g6/issues) for bug reports or suggestions first.
To become a contributor, please follow our [contributing guide](https://github.com/antvis/g6/blob/master/CONTRIBUTING.md).
To become a contributor, please follow our [contributing guide](https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.md).
## License

View File

@ -1,6 +1,6 @@
{
"name": "@antv/g6",
"version": "4.1.4",
"version": "4.1.7",
"description": "A Graph Visualization Framework in JavaScript",
"keywords": [
"antv",
@ -31,7 +31,7 @@
],
"main": "lib/index.js",
"module": "es/index.js",
"browser": "dist/g6.min.js",
"unpkg": "dist/g6.min.js",
"types": "lib/index.d.ts",
"scripts": {
"start": "father build --watch",
@ -66,7 +66,7 @@
]
},
"dependencies": {
"@antv/g6-pc": "^0.0.8"
"@antv/g6-pc": "^0.0.12"
},
"devDependencies": {
"@babel/core": "^7.7.7",

View File

@ -1,7 +1,7 @@
import G6 from '@antv/g6-pc';
G6.version = '4.1.4';
G6.version = '4.1.7';
export * from '@antv/g6-pc';
export default G6;
export const version = '4.1.4';
export const version = '4.1.7';

View File

@ -12,7 +12,8 @@
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"]
"lib": ["esnext", "dom"],
"skipLibCheck": true
},
"include": ["src"]
}

View File

@ -115,8 +115,17 @@ graph.render();
```bash
$ npm install
# run bootstrap to link the packages
$ npm run bootstrap
# build all the packages
$ npm run build:all
# run test case
$ npm test
$ npm run test
# run lint
$ npm run lint
# run test case in watch mode
npm test -- --watch ./tests/unit/algorithm/find-path-spec
@ -149,7 +158,7 @@ $ npm run demos
请让我们知道您要解决或贡献什么,所以在贡献之前请先提交 [issues](https://github.com/antvis/g6/issues) 描述 bug 或建议。
成为一个贡献者前请阅读 [代码贡献规范](https://github.com/antvis/g6/blob/master/CONTRIBUTING.zh-CN.md).
成为一个贡献者前请阅读 [代码贡献规范](https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.zh-CN.md).
## License

View File

@ -115,8 +115,17 @@ For more information of the usage, please refer to [Getting Started](https://ant
```bash
$ npm install
# run bootstrap to link the packages
$ npm run bootstrap
# build all the packages
$ npm run build:all
# run test case
$ npm test
$ npm run test
# run lint
$ npm run lint
# run test case in watch mode
npm test -- --watch ./tests/unit/algorithm/find-path-spec
@ -145,7 +154,7 @@ Users are welcome to join the **G6 Communication Group** or **G6 Communication G
Please let us know what you are you going to help. Do check out [issues](https://github.com/antvis/g6/issues) for bug reports or suggestions first.
To become a contributor, please follow our [contributing guide](https://github.com/antvis/g6/blob/master/CONTRIBUTING.md).
To become a contributor, please follow our [contributing guide](https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.md).
## License

View File

@ -1,6 +1,6 @@
{
"name": "@antv/g6-pc",
"version": "0.0.8",
"version": "0.0.12",
"description": "A Graph Visualization Framework in JavaScript",
"keywords": [
"antv",
@ -75,10 +75,10 @@
"@antv/g-math": "^0.1.1",
"@antv/g-svg": "^0.5.1",
"@antv/g-webgpu": "^0.5.1",
"@antv/g6-core": "^0.0.7",
"@antv/g6-plugin": "^0.0.6",
"@antv/g6-element": "^0.0.6",
"@antv/algorithm": "^0.0.6",
"@antv/g6-core": "^0.0.9",
"@antv/g6-plugin": "^0.0.8",
"@antv/g6-element": "^0.0.8",
"@antv/algorithm": "^0.0.7",
"@antv/hierarchy": "^0.6.2",
"@antv/layout": "^0.0.16",
"@antv/matrix-util": "^3.0.4",

View File

@ -190,6 +190,7 @@ export default {
name: 'brush-shape',
});
this.brush = brush;
this.delegate = brush;
return brush;
},
updateBrush(e: IG6GraphEvent) {

View File

@ -94,6 +94,10 @@ export default {
return;
}
if (!this.shouldBegin.call(this, e)) {
return;
}
if (self.keydown) return;
if (!(e.target && e.target.isCanvas && e.target.isCanvas())) return;

View File

@ -444,6 +444,7 @@ export default {
},
name: 'combo-delegate-shape',
});
this.delegate = this.delegateShape;
} else {
const clientX = evt.x - this.origin.x + this.originPoint.minX;
const clientY = evt.y - this.origin.y + this.originPoint.minY;

View File

@ -378,6 +378,7 @@ export default {
},
name: 'rect-delegate-shape',
});
this.delegate = this.delegateRect;
this.delegateRect.set('capture', false);
} else {
const clientX = e.x - this.origin.x + this.originPoint.minX;

View File

@ -216,6 +216,7 @@ export default {
name: 'lasso-shape',
});
this.lasso = lasso;
this.delegate = lasso;
this.points = [];
return lasso;
},

View File

@ -1 +1 @@
import '@antv/g6-element';
import '@antv/g6-element';

View File

@ -7,7 +7,7 @@ const textColor = 'rgb(0, 0, 0)';
const colorSet = getColorsWithSubjectColor(subjectColor, backColor);
export default {
version: '0.0.8',
version: '0.0.12',
rootContainerClassName: 'root-container',
nodeContainerClassName: 'node-container',
edgeContainerClassName: 'edge-container',

View File

@ -85,5 +85,5 @@ export default {
Algorithm,
Arrow,
Marker,
Shape,
Shape
};

View File

@ -11,9 +11,9 @@ export const mixColor = (backColor, frontColor, frontAlpha) => {
const bc = color(backColor);
const fc = color(frontColor);
return color([
(1 - frontAlpha) * bc.color[0] + frontAlpha * fc.color[0],
(1 - frontAlpha) * bc.color[1] + frontAlpha * fc.color[1],
(1 - frontAlpha) * bc.color[2] + frontAlpha * fc.color[2],
(1 - frontAlpha) * bc.red() + frontAlpha * fc.red(),
(1 - frontAlpha) * bc.green() + frontAlpha * fc.green(),
(1 - frontAlpha) * bc.blue() + frontAlpha * fc.blue(),
]).rgb();
};

View File

@ -0,0 +1,61 @@
import { Graph } from '../../../src';
import '../../../src';
const div = document.createElement('div');
div.id = 'edge-shape';
document.body.appendChild(div);
describe('polyline edge', () => {
it('polyline edge', () => {
const graph = new Graph({
container: div,
width: 500,
height: 500,
// linkCenter: true,
modes: {
default: ['drag-node', 'zoom-canvas', 'drag-canvas'],
},
defaultEdge: {
type: 'polyline',
},
defaultNode: {
type: 'rect',
size: [10, 10],
},
fitCenter: true,
});
const data = {
nodes: [
{
id: '1',
x: -100,
y: -300,
},
{
id: '2',
x: -200,
y: -200,
},
],
edges: [
{
source: '1',
target: '2',
},
],
};
graph.data(data);
graph.render();
const edge = graph.getEdges()[0];
const keyShape = edge.getKeyShape();
const path = keyShape.attr('path');
// expect(path[0][1]).toBe(100);
// expect(path[0][2]).toBe(300);
// expect(path[2][1]).toBe(100);
// expect(path[2][2]).toBe(200);
// expect(path[4][1]).toBe(200);
// expect(path[4][2]).toBe(200);
// graph.destroy();
});
});

View File

@ -0,0 +1,179 @@
import { Graph } from '../../../src';
const div = document.createElement('div');
div.id = 'hull-spec';
document.body.appendChild(div);
const data = {
nodes: [
{
id: '1',
label: '公司1',
group: 1,
},
{
id: '2',
label: '公司2',
group: 1,
},
{
id: '3',
label: '公司3',
group: 1,
},
{
id: '4',
label: '公司4',
group: 1,
},
{
id: '5',
label: '公司5',
group: 2,
},
{
id: '6',
label: '公司6',
group: 2,
},
{
id: '7',
label: '公司7',
group: 2,
},
{
id: '8',
label: '公司8',
group: 2,
},
{
id: '9',
label: '公司9',
group: 2,
},
],
edges: [
{
source: '1',
target: '1',
type: 'loop',
},
{
source: '2',
target: '2',
type: 'loop',
},
{
source: '1',
target: '2',
data: {
type: 'A',
amount: '100,000 元',
date: '2019-08-03',
},
},
{
source: '1',
target: '3',
data: {
type: 'B',
amount: '100,000 元',
date: '2019-08-03',
},
},
{
source: '2',
target: '5',
data: {
type: 'C',
amount: '100,000 元',
date: '2019-08-03',
},
},
{
source: '5',
target: '6',
data: {
type: 'B',
amount: '100,000 元',
date: '2019-08-03',
},
},
{
source: '3',
target: '4',
data: {
type: 'C',
amount: '100,000 元',
date: '2019-08-03',
},
},
{
source: '4',
target: '7',
data: {
type: 'B',
amount: '100,000 元',
date: '2019-08-03',
},
},
{
source: '1',
target: '8',
data: {
type: 'B',
amount: '100,000 元',
date: '2019-08-03',
},
},
{
source: '1',
target: '9',
data: {
type: 'C',
amount: '100,000 元',
date: '2019-08-03',
},
},
],
};
describe('graph setmode and clean the delegates', () => {
const graph = new Graph({
container: div,
width: 500,
height: 500,
modes: {
default: [{
type: 'drag-node',
enableDelegate: true
},
'zoom-canvas',
{
type: 'brush-select',
trigger: 'drag'
}],
custom: ['drag-canvas']
},
});
graph.data(data);
graph.render();
it('executing a behavior and set mode', () => {
const node = graph.getNodes()[0];
graph.emit('node:dragstart', { x: 100, y: 100, item: node });
graph.emit('node:drag', { x: 220, y: 220, item: node });
graph.setMode('custom');
const brushRect = graph.get('canvas').find(e => e.get('name') === 'brush-shape')
expect(!brushRect || brushRect.destroyed).toBe(true);
graph.setMode('default');
graph.emit('keydown', { canvasX: 20, canvasY: 20, key: 'shift' });
graph.emit('dragstart', { canvasX: 20, canvasY: 20 });
graph.emit('drag', { canvasX: 120, canvasY: 120 });
graph.setMode('custom');
const dragDelegate = graph.get('group').find(e => e.get('name') === 'rect-delegate-shape')
expect(!dragDelegate || dragDelegate.destroyed).toBe(true);
});
});

View File

@ -1,8 +1,7 @@
import { Graph } from '../../../src';
import G6, { Graph } from '../../../src';
import '../../../src/behavior';
import { GraphData, Item } from '@antv/g6-core';
import Core from '@antv/g6-core';
// import Plugin from '../../../src/plugins';
const { scale, translate } = Core.Util;
@ -71,7 +70,7 @@ describe('graph', () => {
width: 500,
height: 500,
modes: {
default: ['drag-node'],
default: ['drag-node', 'drag-canvas', 'zoom-canvas'],
},
});
const length = div.childNodes.length;

View File

@ -13,7 +13,8 @@
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"types": ["jest"]
"types": ["jest"],
"skipLibCheck": true
},
"include": ["src", "tests"],
"typedocOptions": {

View File

@ -13,8 +13,6 @@ coverage
# Dependency directories
node_modules
**/node_modules
**/lib
**/es
jspm_packages/
# Optional npm cache directory
@ -33,10 +31,6 @@ jspm_packages/
# IDE
.idea
# build
lib
build
# lock
package-lock.json

View File

@ -1,9 +1,9 @@
{
"name": "@antv/g6-plugin",
"version": "0.0.6",
"version": "0.0.8",
"description": "G6 Plugin",
"main": "lib/index.js",
"module": "es/index.ts",
"module": "es/index.js",
"scripts": {
"build": "npm run clean && father build",
"ci": "npm run build && npm run coverage",
@ -22,7 +22,7 @@
"@antv/g-base": "^0.5.1",
"@antv/g-canvas": "^0.5.2",
"@antv/g-svg": "^0.5.2",
"@antv/g6-core": "^0.0.7",
"@antv/g6-core": "^0.0.8",
"@antv/matrix-util": "^3.0.4",
"@antv/scale": "^0.3.4",
"@antv/util": "^2.0.9",
@ -57,6 +57,6 @@
"jquery": "^3.5.1",
"rimraf": "^3.0.2",
"ts-jest": "^26.4.4",
"@antv/g6": "^4.1.3"
"@antv/g6": "*"
}
}

View File

@ -59,6 +59,8 @@ export type ControllerCfg = Partial<{
readonly nextBtnStyle?: ShapeStyle;
readonly playBtnStyle?: ShapeStyle;
readonly fontFamily?: string;
readonly timePointControllerText?: string;
readonly timeRangeControllerText?: string;
}>;
export default class ControllerBtn {
@ -329,7 +331,7 @@ export default class ControllerBtn {
this.checkedText = this.toggleGroup.addShape('text', {
attrs: {
text: '单一时间',
text: this.controllerCfg?.timePointControllerText || '单一时间',
x: width - TOGGLE_MODEL_OFFSET + 20,
y: this.speedAxisY[1] + 15,
fill: '#ccc',
@ -365,11 +367,11 @@ export default class ControllerBtn {
const isChecked = evt.target.get('isChecked');
if (!isChecked) {
this.checkedIcon.show();
this.checkedText.attr('text', '时间范围');
this.checkedText.attr('text', this.controllerCfg?.timeRangeControllerText || '时间范围');
this.currentType = 'single';
} else {
this.checkedIcon.hide();
this.checkedText.attr('text', '单一时间');
this.checkedText.attr('text', this.controllerCfg?.timePointControllerText || '单一时间');
this.currentType = 'range';
}
evt.target.set('isChecked', !isChecked);

View File

@ -213,7 +213,7 @@ export default class TrendTimeBar {
this.ticks = ticks;
this.trendCfg = trendCfg;
this.controllerCfg = controllerCfg;
this.currentSpeed = controllerCfg.speed;
this.currentSpeed = controllerCfg.speed || 1;
// style
if (type === 'trend') {
this.backgroundStyle = { ...BACKGROUND_STYLE, ...backgroundStyle };
@ -467,6 +467,7 @@ export default class TrendTimeBar {
y: this.y + height + 25,
width,
height: 40,
...this.controllerCfg
});
// 根据 start end 更新 ui 的位置信息

View File

@ -109,7 +109,7 @@ describe('timeline play with timebar', () => {
// stroke: '#1890ff'
// }
// }
},
}
// loop: true
});
const graph = new G6.Graph({

View File

@ -32,7 +32,7 @@
"@antv/g-base": "^0.5.1",
"@types/yoga-layout": "^1.9.3",
"react": "^16.12.0",
"yoga-layout": "^1.9.3"
"yoga-layout-prebuilt": "^1.10.0"
},
"devDependencies": {
"@umijs/test": "^3.0.5",

View File

@ -1,6 +1,8 @@
---
title: 图配置 G6.Graph(cfg)
order: 0
redirect_from:
- /en/docs/api
---
Graph 是 G6 图表的载体,所有的 G6 节点实例操作以及事件,行为监听都在 Graph 实例上进行。Graph 的初始化通过 new 进行实例化,实例化时需要传入需要的参数。

View File

@ -339,123 +339,315 @@ const graph = new G6.Graph({
## TimeBar
**Important Note:** The latest Timebar document is to be updated, please refer to the components in the official website -> TimeBar DEMO.
There are three types of built-in TimeBar in G6:
The built-in TimeBar plugin has the following abilities:
- Time bar with a line chart as background;
- Simple time bar;
- Time bar with descrete ticks.
- Filtering the data of the graph by changing the time range;
- Demonstrating the trending of the data by an attribute on the TimeBar.
All the three types of timebar supports play, fast forward, and fast backward.
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*lfvIQJYbs7oAAAAAAAAAAAAAARQnAQ' width=700 alt='img'/>
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*DOo6QpfFfMUAAAAAAAAAAAAAARQnAQ' width='500' />
<br />Time bar with a line chart as background<br />
**Description:** It is a beta version of TimeBar, which will support complex time series graph and analysis in the future.
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*bzGBQKkewZMAAAAAAAAAAAAAARQnAQ' width='500' />
<br />Simple time bar<br />
### Configuration
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*kHRkQpnvBmwAAAAAAAAAAAAAARQnAQ' width='500' />
<br />Time bar with descrete ticks<br />
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| container | HTMLDivElement | null | The container of the TimeBar. A DOM container with className 'g6-component-timebar' will be used by default |
| width | number | 400 | The width of the TimeBar's container |
| height | number | 400 | The height of the TimeBar's container |
| timebar | TimeBarOption | {} | The style configurations for TimeBar |
| rangeChange | (graph: IGraph, min: number, max: number) => void | null | The callback function after changing the time range |
<br />Refer to the demos [HERE](https://g6.antv.vision/en/examples/tool/timebar#timebar)<br />
**TimeBarOption for timebar**
### Common Usage
```
interface HandleStyle {
width: number;
height: number;
style: ShapeStyle;
}
```
Same to other plugins of G6, the users can initiate the TimeBar and assign it to the graph as:
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| x | number | 0 | The begining x of the TimeBar |
| y | number | 0 | The begining y of the TimeBar |
| width | number | 400 | The width of the TimeBar |
| height | number | 400 | The height of the TimeBar |
| backgroundStyle | ShapeStyle | {} | The background style of the TimeBar |
| foregroundStyle | ShapeStyle | {} | The foreground style of the TimeBar, which indicates the selected area |
| handlerStyle | HandleStyle | null | The style of the slider handler |
| textStyle | ShapeStyle | null | The style of the texts |
| minLimit | number | 0 | The minimum position for the slider on the left, range from 0 to 1 |
| maxLimit | number | 1 | The maximum position for the slider on the right, range from 0 to 1 |
| start | number | 0 | The initial start position of the slider |
| end | number | 1 | The initial end position of the slider |
| minText | string | null | The text for the minimum value |
| maxText | string | null | The text for the maximum value |
| trend | TrendConfig | null | The configuration of the trend chart on the TimeBar |
```javascript
import G6 from '@antv/g6';
**TrendConfig for trend**
```
interface Data {
date: string;
value: number;
}
```
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| data | Data[] | [] | The data of the TimeBar |
| smooth | boolean | false | Whether use the smooth curve instead of polylines for the trend chart |
| isArea | boolean | false | Whether use the area chart instead of line chart |
| lineStyle | ShapeStyle | null | The style of the line for line chart, takes effect when `isArea` is `false` |
| areaStyle | ShapeStyle | null | The style of the area for area chart, takes effect when `isArea` is `true` |
### Usage
#### Default Usage
```
const timebar = new G6.TimeBar();
const graph = new G6.Graph({
//... Other configurations
plugins: [timebar], // Use timebar plugin
});
```
##### Style Configuration
It is free to configure the style for the TimeBar, and listen to the value changing to do some response.
```
const timebar = new G6.TimeBar({
width: 600,
timebar: {
width: 600,
backgroundStyle: {
fill: '#08979c',
opacity: 0.3
},
foregroundStyle: {
fill: '#40a9ff',
opacity: 0.4
},
trend: {
data: timeBarData,
isArea: false,
smooth: true,
lineStyle: {
stroke: '#9254de'
}
}
width: 500,
height: 150,
padding: 10,
type: 'trend',
trend: {
data: timeBarData,
},
rangeChange: (graph, min, max) => {
// Get the instance of the graph and the range of the timebar, you can control the rendering of the graph by yourself here
console.log(graph, min, max)
}
});
const graph = new G6.Graph({
//... Other configurations
plugins: [timebar], // Use timebar plugin
container: 'container',
width,
height,
plugins: [timebar],
});
```
<br />If you want to use the TimeBar with line chart, assign the `type` to be `trend` when instantiating the TimeBar, which results in:
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*lfvIQJYbs7oAAAAAAAAAAAAAARQnAQ' width='600' />
<br />Assigning the `type` to be `simple` results in:
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*g2zhQqP6ruYAAAAAAAAAAAAAARQnAQ' width='600' />
<br />And assigning the `type` to be `tick` results in a TimeBar with descrete ticks. Note that it is different from the above two types of TimeBar, \*\*The TimeBar with decrete ticks is configured with the `tick` object but not the `trend` object.
```javascript
const timebar = new G6.TimeBar({
width,
height: 150,
type: 'tick',
tick: {
data: timeBarData,
width,
height: 42,
tickLabelFormatter: (d) => {
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)}`;
},
},
});
```
<img src='https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*n6ECQ7Jn5pQAAAAAAAAAAAAAARQnAQ' width='600' />
### Definition of the Configurations
#### Definition of the Interfaces
The complete interfaces for the TimeBar is shown below:
```javascript
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' | 'tick';
// the configuration for the TimeBar with line chart and simple TimeBar, takes effect whtn the type is 'trend' or 'simple'
readonly trend?: TrendConfig;
// the configurations for the two sliders
readonly slider?: SliderOption;
// the configuration for the TimeBar with descrete ticks, takes effect whtn the type is 'tick'
readonly tick?: TimeBarSliceOption;
// the buttons for play, fast forward, and back forward
readonly controllerCfg?: ControllerCfg;
rangeChange?: (graph: IGraph, minValue: string, maxValue: string) => void;
valueChange?: (graph: IGraph, value: string) => void;
}
```
#### The Parameters of the Interfaces
| Name | Type | Default Value | Description |
| --- | --- | --- | --- |
| container | HTMLDivElement | null | The DOM container of the TimeBar. By default, the plugin will create a container DOM with 'g6-component-timebar' as className |
| x | number | 0 | The beginning x position of the TimeBar plugin |
| y | number | 0 | The beginning y position of the TimeBar plugin |
| width | number | | **Requred**, the width of the TimBar |
| height | number | | **Requred**, the height of the TimBar |
| padding | number/number[] | 10 | The padding of the container of the TimeBar |
| type | 'trend' / 'simple' / 'tick' | trend | The type of the TimeBar, 'trend' by default |
| trend | TrendConfig | null | The configuration for the TimeBar with line chart and simple TimeBar, takes effect whtn the type is 'trend' or 'simple' |
| slider | SliderOption | null | The configurations for the two sliders |
| tick | TimeBarSliceOption | null | The configuration for the TimeBar with descrete ticks, takes effect whtn the type is 'tick' |
| controllerCfg | ControllerCfg | null | The buttons for play, fast forward, and back forward |
| rangeChange | Function | null | The callback function after the time range is changed. When it is not assigned, the graph elements will be filtered after the time range is changed |
#### Interface for TrendConfig
> Does not support the configurations for the style of the tick labels.
```javascript
interface TrendConfig {
// The data
readonly data: {
date: string;
value: string;
}[];
// The position and size
readonly x?: number;
readonly y?: number;
readonly width?: number;
readonly height?: number;
// The styles
readonly smooth?: boolean;
readonly isArea?: boolean;
readonly lineStyle?: ShapeStyle;
readonly areaStyle?: ShapeStyle;
readonly interval?: Interval;
}
```
#### Parameters of the TrendConfig
| Name | Type | Default Value | Description |
| --- | --- | --- | --- | --- |
| x | number | 0 | The beginning x position of the trend line chart |
| y | number | 0 | The beginning y position of the trend line chart |
| width | number | The width of the TimeBar | The width of the trend line chart of the TimeBar, we suggest to use the default value. If you wanna custom it, please assign the `width` of the slider in the same time |
| height | number | 28 when type='trend'<br />8 when type='simple' | The height of the TimeBar | The width of the trend line chart of the TimeBar, we suggest to use the default value. If you wanna custom it, please assign the `height` of the slider in the same time |
| smooth | boolean | false | Whether to show a smooth line on the trend line chart |
| isArea | boolean | false | Whether to show a area chart instead |
| lineStyle | ShapeStyle | null | The configurations for the style of the line in the line chart |
| areaStyle | ShapeStyle | null | The configuration for the style of the area in the chart when `isArea` is `true` |
| interval | Interval | null | The configuration for the style of the bars in the chart. When it is assigned, a mixed trend chart will take place |
#### Interfaces of SliderOption
```javascript
export type SliderOption = Partial<{
readonly width?: number;
readonly height?: number;
readonly backgroundStyle?: ShapeStyle;
readonly foregroundStyle?: ShapeStyle;
// The style of the sliders
readonly handlerStyle?: {
width?: number;
height?: number;
style?: ShapeStyle;
};
readonly textStyle?: ShapeStyle;
// The start and end position for the sliders, which indicate the data range for the filtering. Ranges from 0 to 1
readonly start: number;
readonly end: number;
// The labels for the sliders
readonly minText: string;
readonly maxText: string;
}>;
```
#### Parameters for the SliderOption
| Name | Type | Default Value | Description |
| --- | --- | --- | --- |
| width | number | The width of the container of the TimeBar - 2 \* padding | The width of the background trend chart. We suggest to use the default value. If you wanna custom it, assign it the the `width` in the `trend` in the same time |
| height | number | 28 when type='trend'<br />8 when type='simple' | The height of the background trend chart. We suggest to use the default value. If you wanna custom it, assign it the the `height` in the `trend` in the same time |
| backgroundStyle | ShapeStyle | null | The configuration for the style of the background |
| foregroundStyle | ShapeStyle | null | The configuration for the style of the forground |
| handlerStyle | ShapeStyle | null | The configuration for the style of the two sliders |
| textStyle | ShapeStyle | null | The configuration for the style of the labels on the two sliders |
| start | number | 0.1 | The start position for the sliders, which indicate the start of the data range for the filtering. Ranges from 0 to `end` |
| end | number | 0.9 | The end position for the sliders, which indicate the end of the data range for the filtering. Ranges from `start` to 1 |
| minText | string | min | The label for the left slider |
| maxText | string | max | The label for the right slider |
#### TimeBarSliceOption
```javascript
export interface TimeBarSliceOption {
// 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 start?: number;
readonly end?: number;
// data
readonly data: {
date: string;
value: string;
}[];
// custom the formatter function for the tick labels
readonly tickLabelFormatter?: (d: any) => string | boolean;
// custom the formatter function for the tooltip
readonly tooltipFomatter?: (d: any) => string;
}
```
#### Parameters for the TimeBarSliceOption
| Name | Type | Default Value | Description |
| --- | --- | --- | --- |
| x | number | 0 | The beginning x position for the TimeBar |
| y | number | 0 | The beginning y position for the TimeBar |
| width | number | | **Requred**, the width of the TimeBar |
| height | number | | **Requred**, the height of the TimeBar |
| padding | number / number[] | 0 | The padding of the container of the TimeBar |
| selectedTickStyle | ShapeStyle | null | The style of the tick(s) which is(are) selected |
| unselectedTickStyle | ShapeStyle | null | The style of the tick(s) which is(are) unselected |
| tooltipBackgroundColor | ShapeStyle | null | The background style for the tooltip |
| start | number | 0.1 | The start position for the sliders, which indicate the start of the data range for the filtering. Ranges from 0 to `end` |
| end | number | 0.9 | The end position for the sliders, which indicate the end of the data range for the filtering. Ranges from `start` to 1 |
| data | any[] | [] | **Requred**, the data for the ticks |
| tickLabelFormatter | Function | null | The formatter function for customing the labels of the ticks |
| tooltipFomatter | Function | null | The formatter function for customing the tooltip |
#### Interface of the ControllerCfg
> Does not support for now
> Does not support the style configuration for controller buttons
> Does not support loop play
```javascript
type ControllerCfg = Partial<{
readonly x?: number;
readonly y?: number;
readonly width: number;
readonly height: number;
/** the play spped, means the playing time for 1 tick */
readonly speed?: number;
/** whether play in loop */
readonly loop?: boolean;
readonly hiddleToggle: boolean;
readonly fill?: string;
readonly stroke?: string;
/** style of the back forward button */
readonly preBtnStyle?: ShapeStyle;
/** style of the fast forward button */
readonly nextBtnStyle?: ShapeStyle;
/** style of the play button */
readonly playBtnStyle?: ShapeStyle;
/** the text for the right-botton switch controlling play with single time point or time range */
readonly timePointControllerText?: string;
readonly timeRangeControllerText?: string
}>
```
#### Parameters for ControllerCfg
| Name | Type | Default Value | Description |
| --- | --- | --- | --- |
| x | number | 0 | The beginning x position for the buttons group of the TimeBar |
| y | number | 0 | The beginning y position for the buttons group of the TimeBar |
| width | number | The width of the TimeBar | The width of the buttons group of the TimeBar |
| height | number | 40 | The width of the buttons group of the TimeBar |
| speed | number | 1 | The play speed |
| loop | boolean | false | _Does not support for now_, whether play in loop |
| hiddleToggle | boolean | true | Whther hide the switch of the time range type |
| fill | string | | The fillling color for the buttons group |
| stroke | string | | The stroke color for the buttons group |
| preBtnStyle | ShapeStyle | null | The style configuration for the backward button |
| nextBtnStyle | ShapeStyle | null | The style configuration for the forward button |
| playBtnStyle | ShapeStyle | null | The style configuration for the play button |
| timePointControllerText | string | "单一时间" | The text for the right-botton switch controlling play with single time point or time range |
| timeRangeControllerText | string | "时间范围" | The text for the right-botton switch controlling play with single time point or time range |
## ToolTip
ToolTip helps user to explore detail infomations on the node and edge. Do note that, This Tooltip Plugins will replace the tooltip in the built-in behavior after G6 4.0.
@ -486,7 +678,7 @@ const tooltip = new G6.Tooltip({
const outDiv = document.createElement('div');
outDiv.style.width = '180px';
outDiv.innerHTML = `
<h4>自定义tooltip</h4>
<h4>Custom Tooltip</h4>
<ul>
<li>Label: ${e.item.getModel().label || e.item.getModel().id}</li>
</ul>`

View File

@ -649,8 +649,8 @@ interface TimeBarConfig extends IPluginBaseConfig {
| container | HTMLDivElement | null | TimeBar 容器,如果不设置,则默认创建 className 为 g6-component-timebar 的 DOM 容器 |
| x | number | 0 | TimeBar 开始 x 坐标 |
| y | number | 0 | TimeBar 开始 y 坐标 |
| width | number | | 必选TimeBar 容器宽度 |
| height | number | | 必选TimeBar 高度 |
| width | number | | **必选**TimeBar 容器宽度 |
| height | number | | **必选**TimeBar 高度 |
| padding | number/number[] | 10 | TimeBar 距离容器的间距值 |
| type | 'trend' / 'simple' / 'tick' | trend | 默认的 TimeBar 类型,默认为趋势图样式 |
| trend | TrendConfig | null | Timebar 中趋势图的配置项,当 type 为 trend 或 simple 时,该字段必选 |
@ -808,9 +808,15 @@ type ControllerCfg = Partial<{
readonly hiddleToggle: boolean;
readonly fill?: string;
readonly stroke?: string;
/** 快退按钮样式 */
readonly preBtnStyle?: ShapeStyle;
/** 快进按钮样式 */
readonly nextBtnStyle?: ShapeStyle;
/** 播放按钮样式 */
readonly playBtnStyle?: ShapeStyle;
/** 右下角“单一时间”和“时间范围”文本 */
readonly timePointControllerText?: string;
readonly timeRangeControllerText?: string
}>
```
@ -830,3 +836,5 @@ type ControllerCfg = Partial<{
| preBtnStyle | ShapeStyle | null | 后退按钮样式配置项 |
| nextBtnStyle | ShapeStyle | null | 前进按钮样式配置项 |
| playBtnStyle | ShapeStyle | null | 播放按钮样式配置项 |
| timePointControllerText | string | "单一时间" | 右下角“单一时间”文本,默认为”单一时间“ |
| timePointControllerText | string | "时间范围" | 右下角“单一时间”文本,默认为”时间范围时间“ |

View File

@ -17,7 +17,7 @@ Implemented the redo function, refer to[here](https://github.com/antvis/G6/blob/
| --------- | ------- | -------- | ------------------------------------------------ | --------------------------------------------------- |
| action | string | false | operation typethe value of 'update' by default |
| data | unknown | false | Stacked data |
| stackType | 'redo' | 'undo' | false | push operation typethe value of 'redo' by default |
| stackType | 'redo' / 'undo' | false | push operation typethe value of 'undo' by default |
## getUndoStack()

View File

@ -17,7 +17,7 @@ order: 13
| --------- | ------- | -------- | ------------------------- | --------------------- |
| action | string | false | 操作类型,默认值为 update |
| data | unknown | false | 入栈的数据 |
| stackType | 'redo' | 'undo' | false | 入栈类型,默认为 redo |
| stackType | 'redo' / 'undo' | false | 入栈类型,默认为 undo |
## getUndoStack()

View File

@ -1,6 +1,6 @@
---
title: TreeGraph Functions
order: 5
order: 4
---
### data()

View File

@ -1,6 +1,6 @@
---
title: TreeGraph 实例方法
order: 5
order: 4
---
### data()

View File

@ -127,7 +127,7 @@ Users are welcome to join the **G6 Communication Group** or **G6 Communication G
Please let us know what you are you going to help. Do check out <a href='https://github.com/antvis/g6/issues' target='_blank'>issues</a> for bug reports or suggestions first.
To become a contributor, please follow our <a href='https://github.com/antvis/g6/blob/master/CONTRIBUTING.md' target='_blank'>Contributing Guide</a>.
To become a contributor, please follow our <a href='https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.md' target='_blank'>Contributing Guide</a>.
## License

View File

@ -128,7 +128,7 @@ graph.render();
请让我们知道您要解决或贡献什么,所以在贡献之前请先提交 <a href='https://github.com/antvis/g6/issues' target='_blank'>issues</a> 描述 bug 或建议。
成为一个贡献者前请阅读 <a href='https://github.com/antvis/g6/blob/master/CONTRIBUTING.zh-CN.md' target='_blank'>代码贡献规范</a>
成为一个贡献者前请阅读 <a href='https://github.com/antvis/G6/blob/master/packages/g6/CONTRIBUTING.zh-CN.md' target='_blank'>代码贡献规范</a>
## License

View File

@ -197,8 +197,8 @@ G6.registerNode(
const tooltip = new G6.Tooltip({
// offsetX and offsetY include the padding of the parent container
// offsetX 与 offsetY 需要加上父容器的 padding
offsetX: 140 + 10,
offsetY: 100 + 10,
offsetX: 10,
offsetY: 10,
// the types of items that allow the tooltip show up
// 允许出现 tooltip 的 item 类型
itemTypes: ['node'],

View File

@ -1,6 +1,6 @@
import G6 from '@antv/g6';
import AntVUtil from '@antv/util';
const Util = G6.Util;
let showNodes = [];
let showEdges = [];
let curShowNodes = [];
@ -308,7 +308,7 @@ G6.registerEdge(
drawShape(cfg, group) {
const self = this;
let shapeStyle = self.getShapeStyle(cfg);
shapeStyle = Util.mix(shapeStyle, {
shapeStyle = AntVUtil.mix(shapeStyle, {
opacity: 0,
strokeOpacity: 0,
});

View File

@ -538,8 +538,8 @@ const initGraph = (data) => {
const tooltip = new G6.Tooltip({
// offsetX and offsetY include the padding of the parent container
// offsetX 与 offsetY 需要加上父容器的 padding
offsetX: 140 + 10,
offsetY: 100 + 10,
offsetX: 20,
offsetY: 30,
// the types of items that allow the tooltip show up
// 允许出现 tooltip 的 item 类型
itemTypes: ['node'],

View File

@ -222,7 +222,8 @@ fetch('https://gw.alipayobjects.com/os/basement_prod/8c2353b0-99a9-4a93-a5e1-3e7
graph.get('container').style.background = '#000';
graph.get('container').style.backgroundImage =
'url("https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*G23iRqkiibIAAAAAAAAAAABkARQnAQ")';
graph.get('container').style.backgroundSize = 'auto 100%';
graph.get('container').style.backgroundSize = '500px 500px';
graph.get('container').style.backgroundRepeat = 'no-repeat';
function scaleNodesPoints(nodes, edges, graphSize) {
const size = graphSize[0] < graphSize[1] ? graphSize[0] : graphSize[1];

View File

@ -16,8 +16,8 @@ insertCss(`
const tooltip = new G6.Tooltip({
// offsetX and offsetY include the padding of the parent container
// offsetX 与 offsetY 需要加上父容器的 padding
offsetX: 140 + 10,
offsetY: 100 + 10,
offsetX: 30,
offsetY: 30,
// the types of items that allow the tooltip show up
// 允许出现 tooltip 的 item 类型
itemTypes: ['node', 'edge'],

View File

@ -16,8 +16,8 @@ insertCss(`
const tooltip = new G6.Tooltip({
// offsetX and offsetY include the padding of the parent container
// offsetX 与 offsetY 需要加上父容器的 padding
offsetX: 140 + 10,
offsetY: 100 + 10,
offsetX: 30,
offsetY: 30,
// the types of items that allow the tooltip show up
// 允许出现 tooltip 的 item 类型
itemTypes: ['node', 'edge'],

View File

@ -195,8 +195,10 @@ G6.registerNode(
});
image.animate(
(ratio) => {
const matrix = Util.mat3.create();
const toMatrix = Util.transform(matrix, [['r', ratio * Math.PI * 2]]);
const toMatrix = Util.transform(
[1, 0, 0, 0, 1, 0, 0, 0, 1],
[['r', ratio * Math.PI * 2]],
);
return {
matrix: toMatrix,
};

View File

@ -69,7 +69,7 @@ const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const toolbar = new G6.ToolBar({
position: { x: 130, y: 70 },
position: { x: 10, y: 10 },
});
const graph = new G6.Graph({

View File

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

View File

@ -233,7 +233,7 @@ module.exports = {
zh: '图布局 Graph Layout',
en: 'Graph Layout',
},
order: 1,
order: 2,
},
{
slug: 'api/graphFunc',
@ -241,7 +241,7 @@ module.exports = {
zh: 'Graph 实例方法',
en: 'Graph Functions',
},
order: 2,
order: 1,
},
{
slug: 'api/treeGraphLayout',
@ -249,10 +249,10 @@ module.exports = {
zh: '树图布局 TreeGraph Layout',
en: 'TreeGraph Layout',
},
order: 4,
order: 5,
},
{
slug: 'api/items',
slug: 'api/Items',
title: {
zh: '元素方法和配置',
en: 'Item Functions & Options',

View File

@ -1,7 +1,7 @@
{
"private": true,
"name": "@antv/g6-site",
"version": "4.1.3",
"version": "4.1.7",
"description": "G6 sites deployed on gh-pages",
"keywords": [
"antv",
@ -34,8 +34,8 @@
"dependencies": {
"@antv/chart-node-g6": "^0.0.3",
"@antv/util": "^2.0.9",
"@antv/g6": "^4.1.3",
"@antv/gatsby-theme-antv": "^1.0.5",
"@antv/g6": "^4.1.7",
"@antv/gatsby-theme-antv": "1.0.6",
"gatsby": "^2.24.40",
"gh-pages": "^2.1.1",
"typedoc": "^0.17.6",
@ -43,7 +43,8 @@
"@types/react": "^16.9.35",
"@types/react-dom": "^16.9.8",
"react-i18next": "^11.1.0",
"@ant-design/icons": "^4.0.6"
"@ant-design/icons": "^4.0.6",
"typescript": "^3.6.5"
},
"resolutions": {
"@types/react": "^16.9.35"