Add d3-sankey Definitions (#16051)

* d3-sankey:
*  Initial incomplete draft of definitions (see TODOs) In particular issue with circular definitions given the source code approach to mutating nodes and links.
* Added tsconfig and tslint.

* Added initial draft of shape tests
* Subject to addressing SankeyNodes/SankeyLinks circularity in definitions
* Fixed return types of nodes() and links() to reflect source code rather than API Doc.

* Use intersection types to avoid circularity
* Using intersection types avoids running into the circularity issue with the generics driving SankeyNode an SankeyLink

* Refine SankeyLinkPathGenerator tests.

* Add interface tests for SankeyNode and SankeyLink

* Complete comments. Add one pathGen test.

* Fix lint errors.

* semicolon.

* Updated some comments.
* Some comments were updated to reflect the comments used in PR 23 to the d3-sankey repo

* Fix typo. Thx @gustavderdrache .

* Add Co-Maintainer
This commit is contained in:
Tom Wanzek 2017-05-01 19:46:04 -04:00 committed by Mohamed Hegazy
parent 48d4027255
commit 5ff63bda5e
4 changed files with 554 additions and 0 deletions

View File

@ -0,0 +1,258 @@
/**
* Typescript definition tests for d3/d3-sankey module
*
* Note: These tests are intended to test the definitions only
* in the sense of typing and call signature consistency. They
* are not intended as functional tests.
*/
import * as d3Sankey from 'd3-sankey';
import {select, Selection} from 'd3-selection';
// ---------------------------------------------------------------------------
// Preparatory Steps
// ---------------------------------------------------------------------------
// Create interfaces for the user-provided node/link attributes, which are NOT mandated or calculated by
// the Sankey layout generator. The latter are reflected in the SankeyNode and SankeyLink interfaces provided
// by the definitions file
interface SNodeExtra {
nodeId: number;
name: string;
}
interface SLinkExtra {
uom: string;
}
// For convenience
type SNode = d3Sankey.SankeyNode<SNodeExtra, SLinkExtra>;
type SLink = d3Sankey.SankeyLink<SNodeExtra, SLinkExtra>;
interface DAG {
nodes: SNode[];
links: SLink[];
}
const graph: DAG = {
nodes: [{
nodeId: 0,
name: "node0"
}, {
nodeId: 1,
name: "node1"
}, {
nodeId: 2,
name: "node2"
}, {
nodeId: 3,
name: "node3"
}, {
nodeId: 4,
name: "node4"
}],
links: [{
source: 0,
target: 2,
value: 2,
uom: 'Widget(s)'
}, {
source: 1,
target: 2,
value: 2,
uom: 'Widget(s)'
}, {
source: 1,
target: 3,
value: 2,
uom: 'Widget(s)'
}, {
source: 0,
target: 4,
value: 2,
uom: 'Widget(s)'
}, {
source: 2,
target: 3,
value: 2,
uom: 'Widget(s)'
}, {
source: 2,
target: 4,
value: 2,
uom: 'Widget(s)'
}, {
source: 3,
target: 4,
value: 4,
uom: 'Widget(s)'
}]
};
let sNodes: SNode[];
let sLinks: SLink[];
let num: number;
let numMaybe: number | undefined;
let str: string;
let size: [number, number];
const svgLinkPaths = select<SVGSVGElement, undefined>('svg').selectAll<SVGPathElement, SLink>('.linkPath'); // assume mock DOM
// ---------------------------------------------------------------------------
// Obtain SankeyLayout Generator
// ---------------------------------------------------------------------------
let slgDefault: d3Sankey.SankeyLayout<{}, {}> = d3Sankey.sankey();
let slgDAG: d3Sankey.SankeyLayout<SNodeExtra, SLinkExtra> = d3Sankey.sankey<SNodeExtra, SLinkExtra>();
// ---------------------------------------------------------------------------
// NodeWidth
// ---------------------------------------------------------------------------
// Set -----------------------------------------------------------------------
// test return type for chainability
slgDAG = slgDAG.nodeWidth(32);
// Get -----------------------------------------------------------------------
num = slgDAG.nodeWidth();
// ---------------------------------------------------------------------------
// NodePadding
// ---------------------------------------------------------------------------
// Set -----------------------------------------------------------------------
// test return type for chainability
slgDAG = slgDAG.nodePadding(8);
// Get -----------------------------------------------------------------------
num = slgDAG.nodePadding();
// ---------------------------------------------------------------------------
// Size
// ---------------------------------------------------------------------------
// Set -----------------------------------------------------------------------
// test return type for chainability
slgDAG = slgDAG.size([1200, 800]);
// Get -----------------------------------------------------------------------
size = slgDAG.size();
// ---------------------------------------------------------------------------
// Nodes
// ---------------------------------------------------------------------------
// Set -----------------------------------------------------------------------
// test return type for chainability
slgDAG = slgDAG.nodes(graph.nodes);
// Get -----------------------------------------------------------------------
sNodes = slgDAG.nodes();
// ---------------------------------------------------------------------------
// Links
// ---------------------------------------------------------------------------
// Set -----------------------------------------------------------------------
// test return type for chainability
slgDAG = slgDAG.links(graph.links);
// Get -----------------------------------------------------------------------
sLinks = slgDAG.links();
// ---------------------------------------------------------------------------
// Compute Layout
// ---------------------------------------------------------------------------
// test return type for chainability
slgDAG = slgDAG.layout(22);
// ---------------------------------------------------------------------------
// Relayout
// ---------------------------------------------------------------------------
// test return type for chainability
slgDAG = slgDAG.relayout();
// ---------------------------------------------------------------------------
// Obtain and Use Link SVG Path Generator
// ---------------------------------------------------------------------------
let pathGen: d3Sankey.SankeyLinkPathGenerator<SNodeExtra, SLinkExtra>;
pathGen = slgDAG.link();
// Adjust Link SVG Path Generator curvature ----------------------------------
// test return type
pathGen = pathGen.curvature(0.6);
num = pathGen.curvature();
// uses
let svgPathString: string = pathGen(slgDAG.links()[0]);
svgLinkPaths.attr('d', pathGen);
// ---------------------------------------------------------------------------
// Shape test Node/Link related interfaces and types
// ---------------------------------------------------------------------------
// Sankey Node --------------------------------------------------------------
let sNode = sNodes[0];
// User-specified extra properties:
num = sNode.nodeId;
str = sNode.name;
// Sankey Layout calculated (if layout has been run, otherwise undefined):
numMaybe = sNode.dx;
numMaybe = sNode.x;
numMaybe = sNode.dy;
numMaybe = sNode.y;
numMaybe = sNode.value;
let linksArrMaybe: SLink[] | undefined;
linksArrMaybe = sNode.sourceLinks;
linksArrMaybe = sNode.targetLinks;
// Sankey Link --------------------------------------------------------------
let sLink = sLinks[0];
// User-specified extra properties:
str = sLink.uom;
// Sankey Layout mandated link properties:
num = sLink.value;
// Node depending on initialization strategy and whether
// layout(...) was invoked, the source and target nodes may be numbers
// objects without the Sankey layout coordinates, or objects with calculated
// information
let numOrSankeyNode: number | SNode;
numOrSankeyNode = sLink.source;
numOrSankeyNode = sLink.target;
// Sankey Layout calculated (if layout has been run, otherwise undefined):
numMaybe = sLink.sy;
numMaybe = sLink.ty;
numMaybe = sLink.dy;

267
types/d3-sankey/index.d.ts vendored Normal file
View File

@ -0,0 +1,267 @@
// Type definitions for D3JS d3-sankey module 0.4
// Project: https://github.com/d3/d3-sankey/
// Definitions by: Tom Wanzek <https://github.com/tomwanzek>, Alex Ford <https://github.com/gustavderdrache>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Last module patch version validated against: 0.4.2
/**
* A helper interface as an extension reference for user-provided properties of
* nodes and links in the graph, which are not required or calculated by
* the Sankey Layout Generator
*/
export interface SankeyExtraProperties { [key: string]: any; }
/**
* Helper interface to define the properties of Sankey Nodes. Calculated properties may only be defined,
* once the layout(...) method of the Sankey layout generator has been invoked.
*
* The first generic N refers to user-defined properties contained in the node data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyNodeMinimal interface.
*
* The second generic L refers to user-defined properties contained in the link data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyLinkMinimal interface.
*/
export interface SankeyNodeMinimal<N extends SankeyExtraProperties, L extends SankeyExtraProperties> {
/**
* Array of links which have this node as their source.
* This property is calculated internally by the Sankey layout generator.
*/
sourceLinks?: Array<SankeyLink<N, L>>;
/**
* Array of links which have this node as their target.
* This property is calculated internally by the Sankey layout generator.
*/
targetLinks?: Array<SankeyLink<N, L>>;
/**
* Node value calculated by Sankey Layout Generator based on values of incoming and outgoing links
*/
value?: number;
/**
* Node horizontal position calculated by Sankey layout generator
*/
x?: number;
/**
* Node width calculated by Sankey layout generator
*/
dx?: number;
/**
* Node vertical position (depth) calculated by Sankey layout generator
*/
y?: number;
/**
* Node height (vertical extent based on node value) calculated by Sankey layout generator
*/
dy?: number;
}
/**
* Sankey Node type including both user-defined node data elements as well as those
* calculated once the layout(...) method of the Sankey layout generators has been invoked.
*
* The first generic N refers to user-defined properties contained in the node data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyNodeMinimal interface.
*
* The second generic L refers to user-defined properties contained in the link data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyLinkMinimal interface.
*/
export type SankeyNode<N extends SankeyExtraProperties, L extends SankeyExtraProperties> = N & SankeyNodeMinimal<N, L>;
/**
* Helper interface to define the properties of Sankey Links. Calculated properties may only be defined,
* once the layout(...) method of the Sankey layout generator has been invoked.
*
* The first generic N refers to user-defined properties contained in the node data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyNodeMinimal interface.
*
* The second generic L refers to user-defined properties contained in the link data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyLinkMinimal interface.
*/
export interface SankeyLinkMinimal<N extends SankeyExtraProperties, L extends SankeyExtraProperties> {
/**
* Source node of the link. For convenience, when initializing a Sankey layout, source may be the index of the source node in the nodes array
* passed into the Sankey layout generator. Once the layout(...) method is invoked, the numeric index will be replaced with the corresponding
* source node object.
*/
source: number | SankeyNode<N, L>;
/**
* Target node of the link. For convenience, when initializing a Sankey layout, target may be the index of the target node in the nodes array
* passed into the Sankey layout generator. Once the layout(...) method is invoked, the numeric index will be replaced with the corresponding
* target node object.
*/
target: number | SankeyNode<N, L>;
/**
* Value of the link
*/
value: number;
/**
* Link breadth calculated by Sankey layout generator based on the link value
*/
dy?: number;
/**
* Vertical starting position of the link (at source node) calculated by Sankey layout generator
*/
sy?: number;
/**
* Vertical end position of the link (at target node) calculated by Sankey layout generator
*/
ty?: number;
}
/**
* Sankey Link type including both user-defined link data elements, those required by the Sankey layout generator,
* as well as those calculated once the layout(...) method of the layout generator has been invoked.
*
* The first generic N refers to user-defined properties contained in the node data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyNodeMinimal interface.
*
* The second generic L refers to user-defined properties contained in the link data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyLinkMinimal interface.
*/
export type SankeyLink<N extends SankeyExtraProperties, L extends SankeyExtraProperties> = L & SankeyLinkMinimal<N, L>;
/**
* An svg path generator factory for the link paths in a calculated Sankey Layout.
*/
export interface SankeyLinkPathGenerator<N extends SankeyExtraProperties, L extends SankeyExtraProperties> {
/**
* Return svg path string for a given link.
*
* IMPORTANT: Only invoke for link data with Sankey Layout information previously calculated.
*
* @param link A Sankey diagram link, for which the layout has already been calculated.
*/
(link: SankeyLink<N, L>): string;
/**
* Returns the current curvature used to calculate svg paths for links.
* The default curvature is 0.5.
*/
curvature(): number;
/**
* Set the curvature used to calculate svg paths for links and return the updated link path generator.
*
* @param curvature Curvature to be used when calculating svg paths for links. The default curvature is 0.5.
*/
curvature(curvature: number): this;
}
/**
* A Sankey layout generator.
*
* The first generic N refers to user-defined properties contained in the node data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyNodeMinimal interface.
*
* The second generic L refers to user-defined properties contained in the link data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyLinkMinimal interface.
*/
export interface SankeyLayout<N extends SankeyExtraProperties, L extends SankeyExtraProperties> {
/**
* Return the current node width, which defaults to 24.
*/
nodeWidth(): number;
/**
* Set the node width to the specified number and return this Sankey layout generator.
*
* @param width Width of node in pixels, which defaults to 24.
*/
nodeWidth(width: number): this;
/**
* Return the current node padding, which defaults to 8.
*
* Node padding refers to the vertical space between nodes which occupy the same horizontal space.
*/
nodePadding(): number;
/**
* Set the node padding to the specified number and return this Sankey layout generator.
*
* Node padding refers to the vertical space between nodes which occupy the same horizontal space.
*
* @param padding Node padding in pixels, which defaults to 8.
*/
nodePadding(padding: number): this;
/**
* Return the current array of nodes, which defaults to [].
*/
nodes(): Array<SankeyNode<N, L>>;
/**
* Set the sankey generator's nodes to the specified array of objects and returns this sankey layout generator.
*
* @param nodes Array of nodes.
*/
nodes(nodes: Array<SankeyNode<N, L>>): this;
/**
* Return the current array of links, which defaults to [].
*/
links(): Array<SankeyLink<N, L>>;
/**
* Set the sankey generator's links to the specified array of objects and returns this sankey layout generator.
*
* @param links Array of links.
*/
links(links: Array<SankeyLink<N, L>>): this;
/**
* Runs the sankey layout algorithm updating the nodes and links with their respective layout information and returns this sankey generator.
*
* @param iterations Number of passes to be used in the iterative relaxation algorithm for node placement.
*/
layout(iterations: number): this;
/**
* Recalculate the depth of links and return this Sankey layout generator.
* This methods is primarily used when a node is moved vertically, e.g. using d3-drag.
*/
relayout(): this;
/**
* Return the current layout size in pixels. The size is a two element array of [width, height] which defaults to [1, 1].
*/
size(): [number, number];
/**
* Set the size of the layout and return this Sankey layout generator.
*
* @param size A two element array of [width, height] in pixels which defaults to [1, 1].
*/
size(size: [number, number]): this;
/**
* Return a Sankey link path generator for the links based on the calculated Sankey diagram layout.
* The link path generator can be invoked as a function being passed as its argument a link object
* with calculated layout information. It returns the computed <svg> path string for the link.
* By default the link path generator uses a curvature of 0.5.
*/
link(): SankeyLinkPathGenerator<N, L>;
}
/**
* Get a Sankey layout generator.
*
* Invoking sankey() without generics, means the node type and link type assume no user-defined attributes, i.e.
* only the attributes internally used by the Sankey layout generator.
*/
export function sankey(): SankeyLayout<{}, {}>;
/**
* Get a Sankey layout generator.
*
* The first generic N refers to user-defined properties contained in the node data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyNodeMinimal interface.
*
* The second generic L refers to user-defined properties contained in the link data passed into
* Sankey layout generator. These properties are IN EXCESS to the properties explicitly identified in the
* SankeyLinkMinimal interface.
*/
export function sankey<N extends SankeyExtraProperties, L extends SankeyExtraProperties>(): SankeyLayout<N, L>;

View File

@ -0,0 +1,23 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"d3-sankey-tests.ts"
]
}

View File

@ -0,0 +1,6 @@
{
"extends": "dtslint/dt.json",
"rules": {
"unified-signatures": false
}
}