mirror of
https://github.com/zhigang1992/DefinitelyTyped.git
synced 2026-06-02 14:38:20 +08:00
Cytoscape: tested large amount of cases; heavily refactored general types; added some methods; added chaining possibility in some places
This commit is contained in:
@@ -1,6 +1,26 @@
|
||||
'use strict';
|
||||
import cytoscape = require('cytoscape');
|
||||
|
||||
// TODO: document all aliases as aliases, not as duplicates!
|
||||
|
||||
const assert = (tag: boolean) => { if (!tag) throw new Error(); };
|
||||
const aliases = (...obj: Array<{}>) => { if (obj.slice(1).some((alias) => alias !== obj[0])) throw new Error(); };
|
||||
const events = (obj: any) => {
|
||||
aliases(obj.on, obj.bind, obj.listen, obj.addListener);
|
||||
aliases(obj.promiseOn, obj.pon);
|
||||
aliases(obj.off, obj.unbind, obj.unlisten, obj.removeListener);
|
||||
aliases(obj.emit, obj.trigger);
|
||||
};
|
||||
|
||||
// definitions
|
||||
function oneOf<A, B, C, D, E>(a: A, b: B, c: C, d: D, e: E): A | B | C | D | E;
|
||||
function oneOf<A, B, C, D>(a: A, b: B, c: C, d: D): A | B | C | D;
|
||||
function oneOf<A, B, C>(a: A, b: B, c: C): A | B | C;
|
||||
function oneOf<A, B>(a: A, b: B): A | B;
|
||||
function oneOf<T>(...array: T[]): T {
|
||||
return array[0];
|
||||
}
|
||||
|
||||
import cytoscape = require('cytoscape');
|
||||
const parentCSS = {
|
||||
'padding-top': '10px',
|
||||
'padding-left': '10px',
|
||||
@@ -68,7 +88,7 @@ const cy = cytoscape({
|
||||
{ data: { id: 'eb', source: 'e', target: 'b' } }
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
// initial viewport state:
|
||||
zoom: 1,
|
||||
pan: { x: 0, y: 0 },
|
||||
@@ -96,7 +116,7 @@ const cy = cytoscape({
|
||||
motionBlurOpacity: 0.2,
|
||||
wheelSensitivity: 1,
|
||||
pixelRatio: 'auto',
|
||||
|
||||
|
||||
layout: {
|
||||
name: 'preset',
|
||||
padding: 5
|
||||
@@ -108,6 +128,42 @@ cy.on('zoom', (event) => {
|
||||
cy.nodes('$node > node').style('opacity', 0);
|
||||
}
|
||||
});
|
||||
cy.off('zoom');
|
||||
events(cy);
|
||||
|
||||
cy.add({ data: { id: 'g' }, position: {x: 200, y: 150} });
|
||||
cy.add([
|
||||
{ data: { id: 'h' }, position: {x: 250, y: 100} }
|
||||
]);
|
||||
const nodesBeforeDelete = cy.nodes();
|
||||
const edgesBeforeDelete = cy.edges();
|
||||
|
||||
const removed = cy.remove('#g #h');
|
||||
cy.add(removed);
|
||||
const diffNodes = nodesBeforeDelete.diff(cy.nodes());
|
||||
const diffEdges = edgesBeforeDelete.diff(cy.edges());
|
||||
assert(diffNodes.left.size() === 0 && diffNodes.right.size() === 0 && diffNodes.both.size() === cy.nodes().size());
|
||||
assert(nodesBeforeDelete.same(cy.nodes()));
|
||||
assert(edgesBeforeDelete.same(cy.edges()));
|
||||
|
||||
const gh = cy.collection().add(cy.$id('g')).union(cy.getElementById('h'));
|
||||
const gh2 = cy.$('#g #h');
|
||||
const gh3 = cy.nodes('#g #h');
|
||||
assert(gh2.same(gh));
|
||||
assert(gh3.same(gh));
|
||||
assert(gh.same(removed));
|
||||
|
||||
assert(cy.container() === null); // headless mode!
|
||||
|
||||
cy.center();
|
||||
cy.center(gh);
|
||||
aliases(cy.center, cy.centre);
|
||||
|
||||
cy.fit(cy.$('#a #b #h'));
|
||||
|
||||
const {x1, y1, x2, y2, w, h} = cy.extent();
|
||||
|
||||
aliases(cy.resize, cy.invalidateDimensions);
|
||||
|
||||
cy.animate({
|
||||
fit: {
|
||||
@@ -117,8 +173,323 @@ cy.animate({
|
||||
duration: 500
|
||||
});
|
||||
|
||||
const node = cy.nodes()[0];
|
||||
cy.animate({
|
||||
center: {eles: node},
|
||||
center: {eles: cy.nodes()[0]},
|
||||
duration: 500
|
||||
});
|
||||
|
||||
const anim = cy.animation({
|
||||
zoom: {
|
||||
level: 1,
|
||||
position: {x: 0, y: 0}
|
||||
},
|
||||
pan: {x: 100, y: 100},
|
||||
duration: 100,
|
||||
easing: 'ease'
|
||||
});
|
||||
cy.stop(true, true);
|
||||
anim.play();
|
||||
assert(anim.playing());
|
||||
anim.progress(anim.progress() + 50);
|
||||
anim.time(anim.time() - 50);
|
||||
anim.stop();
|
||||
|
||||
aliases(cy.layout, cy.createLayout, cy.makeLayout);
|
||||
|
||||
// Preconfigured data for layouts (as it could be passed)
|
||||
const boundingBox = oneOf({x1: 0, x2: 100, y1: 0, y2: 100}, {x1: 0, w: 100, y1: 0, h: 100});
|
||||
const positions = oneOf({a: {x: 100, y: 100}}, (node: cytoscape.NodeCollection): cytoscape.Position => ({x: 100, y: 100}));
|
||||
|
||||
// TODO: uncomment after we have the way to add layout options properties from extensions
|
||||
// const layouts = [
|
||||
// cy.layout({
|
||||
// name: 'null',
|
||||
// ready: () => {},
|
||||
// stop: () => {}
|
||||
// }),
|
||||
// cy.layout({
|
||||
// name: 'random',
|
||||
// fit: true,
|
||||
// padding: 30,
|
||||
// boundingBox,
|
||||
// animate: false,
|
||||
// animationDuration: 500,
|
||||
// animationEasing: 'ease-in',
|
||||
// animateFilter: (node, i) => true,
|
||||
// transform: (node, position) => position
|
||||
// }),
|
||||
// cy.layout({
|
||||
// name: 'preset',
|
||||
// positions,
|
||||
// zoom: 1,
|
||||
// pan: {x: 100, y: 100},
|
||||
// fit: false,
|
||||
// padding: 30,
|
||||
// animate: false,
|
||||
// animationDuration: 500,
|
||||
// animationEasing: 'ease-out',
|
||||
// animateFilter: (node, i) => true,
|
||||
// transform: (node, position) => position
|
||||
// }),
|
||||
// cy.layout({
|
||||
// name: 'grid',
|
||||
// fit: true,
|
||||
// padding: 30,
|
||||
// boundingBox,
|
||||
// avoidOverlap: true,
|
||||
// avoidOverlapPadding: 10,
|
||||
// nodeDimensionsIncludeLabels: false,
|
||||
// spacingFactor: oneOf(1, undefined),
|
||||
// condense: false,
|
||||
// rows: oneOf(10, undefined),
|
||||
// cols: oneOf(10, undefined),
|
||||
// position: (node) => ({ row: 1, col: 1 }),
|
||||
// sort: (a, b) => 1,
|
||||
// animate: false,
|
||||
// animationDuration: 500,
|
||||
// animationEasing: 'ease-in-out',
|
||||
// animateFilter: (node, i) => true,
|
||||
// transform: (node, position) => position
|
||||
// }),
|
||||
// cy.layout({
|
||||
// name: 'circle',
|
||||
// fit: true,
|
||||
// padding: 30,
|
||||
// boundingBox,
|
||||
// avoidOverlap: true,
|
||||
// nodeDimensionsIncludeLabels: false,
|
||||
// spacingFactor: oneOf(1, undefined),
|
||||
// radius: oneOf(1, undefined),
|
||||
// startAngle: 3 / 2 * Math.PI,
|
||||
// sweep: oneOf(6, undefined),
|
||||
// clockwise: true,
|
||||
// sort: (a, b) => 1,
|
||||
// animate: false,
|
||||
// animationDuration: 500,
|
||||
// animationEasing: 'ease-in-sine',
|
||||
// animateFilter: (node, i) => true,
|
||||
// transform: (node, position) => position
|
||||
// }),
|
||||
// cy.layout({
|
||||
// name: 'concentric',
|
||||
// fit: true,
|
||||
// padding: 30,
|
||||
// startAngle: 3 / 2 * Math.PI,
|
||||
// sweep: oneOf(6, undefined),
|
||||
// clockwise: true,
|
||||
// equidistant: false,
|
||||
// minNodeSpacing: 10,
|
||||
// boundingBox,
|
||||
// avoidOverlap: true,
|
||||
// nodeDimensionsIncludeLabels: false,
|
||||
// height: oneOf(500, undefined),
|
||||
// width: oneOf(500, undefined),
|
||||
// spacingFactor: oneOf(1, undefined),
|
||||
// concentric: (node) => 1,
|
||||
// levelWidth: (nodes) => 1,
|
||||
// animate: false,
|
||||
// animationDuration: 500,
|
||||
// animationEasing: 'ease-out-sine',
|
||||
// animateFilter: (node, i) => true,
|
||||
// transform: (node, position) => position
|
||||
// }),
|
||||
// cy.layout({
|
||||
// name: 'breadthfirst',
|
||||
// fit: true,
|
||||
// directed: false,
|
||||
// padding: 30,
|
||||
// circle: false,
|
||||
// spacingFactor: 1.75,
|
||||
// boundingBox,
|
||||
// avoidOverlap: true,
|
||||
// nodeDimensionsIncludeLabels: false,
|
||||
// maximalAdjustments: 0,
|
||||
// animate: false,
|
||||
// animationDuration: 500,
|
||||
// animationEasing: 'ease-in-out-sine',
|
||||
// animateFilter: (node, i) => true,
|
||||
// transform: (node, position) => position
|
||||
// }),
|
||||
// cy.layout({
|
||||
// name: 'cose',
|
||||
// ready: () => {},
|
||||
// stop: () => {},
|
||||
// animate: oneOf(true, false, 'end'),
|
||||
// animationEasing: oneOf('ease-in-quad', undefined),
|
||||
// animationDuration: oneOf(500, undefined),
|
||||
// animateFilter: function ( node, i ){ return true; },
|
||||
// animationThreshold: 250,
|
||||
// refresh: 20,
|
||||
// fit: true,
|
||||
// padding: 30,
|
||||
// boundingBox: undefined,
|
||||
// nodeDimensionsIncludeLabels: false,
|
||||
// randomize: false,
|
||||
// componentSpacing: 40,
|
||||
// nodeRepulsion: (node) => 2048,
|
||||
// nodeOverlap: 4,
|
||||
// idealEdgeLength: (edge) => 32,
|
||||
// edgeElasticity: (edge) => 32,
|
||||
// nestingFactor: 1.2,
|
||||
// gravity: 1,
|
||||
// numIter: 1000,
|
||||
// initialTemp: 1000,
|
||||
// coolingFactor: 0.99,
|
||||
// minTemp: 1.0,
|
||||
// weaver: false
|
||||
// })
|
||||
// ];
|
||||
// const lay = layouts[0];
|
||||
// aliases(lay.run, lay.start);
|
||||
// events(lay);
|
||||
// layouts.map(layout => {
|
||||
// layout.run();
|
||||
// layout.stop();
|
||||
// });
|
||||
|
||||
// TODO: cy.style
|
||||
|
||||
cy.png({
|
||||
output: oneOf('base64uri', 'base64', 'blob', undefined),
|
||||
bg: oneOf('#ffffff', undefined),
|
||||
full: true,
|
||||
scale: 2,
|
||||
maxWidth: 100,
|
||||
maxHeight: 100
|
||||
});
|
||||
aliases(cy.jpg, cy.jpeg);
|
||||
cy.jpg({
|
||||
output: oneOf('base64uri', 'base64', 'blob', undefined),
|
||||
bg: oneOf('#ffffff', undefined),
|
||||
full: true,
|
||||
scale: 2,
|
||||
maxWidth: 100,
|
||||
maxHeight: 100,
|
||||
quality: 0.5
|
||||
});
|
||||
cy.json(cy.json());
|
||||
|
||||
// Types possible to call methods
|
||||
const ele = oneOf(cy.nodes()[0], cy.edges()[0]);
|
||||
const eles = cy.elements();
|
||||
const node = cy.nodes()[0];
|
||||
const nodes = cy.nodes();
|
||||
const edge = cy.edges()[0];
|
||||
const edges = cy.edges();
|
||||
|
||||
assert(ele.cy() === cy);
|
||||
eles.remove();
|
||||
assert(eles.removed());
|
||||
assert(!eles.inside());
|
||||
eles.restore();
|
||||
|
||||
([ele, eles, node, nodes, edge, edges] as cytoscape.CollectionReturnValue[]).forEach((elem) => {
|
||||
aliases(elem.clone, elem.copy);
|
||||
events(elem);
|
||||
aliases(elem.data, elem.attr);
|
||||
aliases(elem.removeData, elem.removeAttr);
|
||||
});
|
||||
// TODO: tests for data flow
|
||||
|
||||
const loops = oneOf(true, false);
|
||||
node.degree(loops); node.indegree(loops); node.outdegree(loops);
|
||||
nodes.totalDegree(loops); nodes.minDegree(loops); nodes.maxDegree(loops);
|
||||
nodes.minIndegree(loops); nodes.maxIndegree(loops); nodes.minOutdegree(loops); nodes.maxOutdegree(loops);
|
||||
|
||||
// tslint:disable-next-line:ban-types
|
||||
const getsetPos = <T extends Function>(func: T): T => {
|
||||
func('x', func('x'));
|
||||
func(func());
|
||||
func({x: 100, y: 100});
|
||||
return func;
|
||||
};
|
||||
|
||||
aliases(node.modelPosition, node.point, node.position);
|
||||
getsetPos(node.position);
|
||||
|
||||
nodes.shift('x', 100);
|
||||
nodes.shift({x: -100, y: 0});
|
||||
|
||||
aliases(nodes.modelPositions, nodes.positions, nodes.points);
|
||||
nodes.positions((node, i) => Object.assign(node.position(), {x: node.position('x') + i}));
|
||||
|
||||
aliases(node.renderedPosition, node.renderedPoint);
|
||||
getsetPos(node.renderedPoint);
|
||||
|
||||
// TODO: tests for compound nodes (relativePosition, in particular)
|
||||
|
||||
const sizes: number[] = [
|
||||
ele.width(), ele.outerWidth(), ele.renderedWidth(), ele.renderedOuterWidth(),
|
||||
ele.height(), ele.outerHeight(), ele.renderedHeight(), ele.renderedOuterHeight()
|
||||
];
|
||||
|
||||
aliases(eles.boundingBox, eles.boundingbox);
|
||||
aliases(eles.renderedBoundingBox, eles.renderedBoundingbox);
|
||||
|
||||
const flags: boolean[] = [
|
||||
node.grabbed(), node.grabbable(), node.locked(), ele.active(),
|
||||
];
|
||||
|
||||
const edgePoints: cytoscape.Position[] = [
|
||||
...edge.controlPoints(), ...edge.segmentPoints(), edge.sourceEndpoint(), edge.targetEndpoint(), edge.midpoint()
|
||||
];
|
||||
|
||||
aliases(eles.layout, eles.createLayout, eles.makeLayout);
|
||||
const layout = eles.layout({name: 'random'}).run();
|
||||
|
||||
eles.select();
|
||||
assert(ele.selected()); // as we selected all, and this too
|
||||
aliases(eles.unselect, eles.deselect);
|
||||
eles.selectify();
|
||||
assert(ele.selectable());
|
||||
eles.unselectify();
|
||||
|
||||
eles.addClass('test');
|
||||
eles.toggleClass('test', oneOf(true, false, undefined));
|
||||
eles.removeClass('test');
|
||||
eles.classes(oneOf('test', undefined));
|
||||
eles.flashClass('test flash', oneOf(1000, undefined));
|
||||
assert(ele.hasClass('test'));
|
||||
|
||||
eles.style('background-color', 'green');
|
||||
Object.keys(eles.style()).map(key => eles.style(key));
|
||||
eles.style(eles.style());
|
||||
aliases(eles.style, eles.css);
|
||||
aliases(ele.renderedCss, ele.renderedStyle);
|
||||
|
||||
eles.anySame(nodes);
|
||||
aliases(eles.contains, eles.has);
|
||||
aliases(eles.allAreNeighbors, eles.allAreNeighbours);
|
||||
eles.is('#g');
|
||||
eles.allAre('#g');
|
||||
eles.some((el, i, els) => true);
|
||||
eles.every((el, i, els) => true);
|
||||
|
||||
aliases(eles.forEach, eles.each);
|
||||
const selected: cytoscape.SingularElementArgument[] = [eles.eq(0), eles.first(), eles.last()];
|
||||
const collSel = cy.collection(selected);
|
||||
const selectedNodes: cytoscape.NodeSingular[] = [nodes.eq(0), nodes.first(), nodes.last()];
|
||||
const collNodes = cy.collection(selectedNodes);
|
||||
const selectedEdges: cytoscape.EdgeSingular[] = [edges.eq(0), edges.first(), edges.last()];
|
||||
eles.slice(0, -1);
|
||||
eles.toArray();
|
||||
|
||||
aliases(eles.getElementById, eles.$id);
|
||||
aliases(eles.union, eles.add, eles.or, eles.u, eles['+'], eles['|']);
|
||||
aliases(eles.difference, eles.not, eles.subtract, eles.relativeComplement, eles['\\'], eles['!'], eles['-']);
|
||||
aliases(eles.absoluteComplement, eles.abscomp, eles.complement);
|
||||
aliases(eles.intersection, eles.intersect, eles.and, eles.n, eles['&'], eles['.']);
|
||||
aliases(eles.symmetricDifference, eles.symdiff, eles.xor, eles['^'], eles['(+)'], eles['(-)']);
|
||||
cy.collection([nodes[0]]).union(nodes[1]).union(eles.$id('g'));
|
||||
eles.difference(collNodes).abscomp().intersection(collSel).symdiff(collNodes);
|
||||
const diff = collSel.diff(collNodes);
|
||||
cy.collection().merge(diff.left).merge(diff.right).merge(diff.both).unmerge(collSel).filter((ele, i, eles) => true);
|
||||
|
||||
eles.sort((a, b) => 1).map((ele, i, eles) => [i, ele]);
|
||||
eles.reduce<any[]>((prev, ele, i, eles) => [...prev, [ele, i]], []).concat(['finish']);
|
||||
const min = eles.min((ele, i, eles) => ele.id.length + i); min.ele.scratch('min', min.value);
|
||||
const max = eles.max((ele, i, eles) => ele.id.length + i); max.ele.scratch('max', max.value);
|
||||
|
||||
// TODO: traversing (need to actively check the nodes/edeges distinction)
|
||||
// TODO: algorithms
|
||||
// TODO: compound nodes (there aren't any in current test case)
|
||||
|
||||
520
types/cytoscape/index.d.ts
vendored
520
types/cytoscape/index.d.ts
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user