From a094893c46162042a2ca034ca3cfd470f3c7e628 Mon Sep 17 00:00:00 2001 From: denis Date: Mon, 4 Feb 2019 20:39:56 +0100 Subject: [PATCH] Update d3-selection to 1.4 (add join) Fix linting errors in d3-contour --- types/d3-contour/d3-contour-tests.ts | 8 +- types/d3-selection/d3-selection-tests.ts | 134 ++++++++++++++++++++++- types/d3-selection/index.d.ts | 42 ++++++- 3 files changed, 175 insertions(+), 9 deletions(-) diff --git a/types/d3-contour/d3-contour-tests.ts b/types/d3-contour/d3-contour-tests.ts index 2d23017040..2d18ebe957 100644 --- a/types/d3-contour/d3-contour-tests.ts +++ b/types/d3-contour/d3-contour-tests.ts @@ -25,10 +25,10 @@ import { randomNormal } from 'd3-random'; const n = 256; const m = 256; const values: number[] = new Array(n * m); -for (let j = 0.5, k = 0; j < m; ++j) { - for (let i = 0.5; i < n; i++) { +for (let j = 0.5, k = 0; j < m; j += 1) { + for (let i = 0.5; i < n; i += 1) { values[k] = goldsteinPrice(i / n * 4 - 2, 1 - j / m * 3); - k++; + k += 1; } } @@ -193,7 +193,7 @@ num = contDensCustom.bandwidth(); const indNorm: CustomDatum[] = []; const rX = randomNormal(); const rY = randomNormal(1, 2); -for (let i = 0; i < 1000; i++) { +for (let i = 0; i < 1000; i += 1) { indNorm.push({ x: rX(), y: rY() diff --git a/types/d3-selection/d3-selection-tests.ts b/types/d3-selection/d3-selection-tests.ts index 092e8bfa5a..57c30ef9aa 100644 --- a/types/d3-selection/d3-selection-tests.ts +++ b/types/d3-selection/d3-selection-tests.ts @@ -604,7 +604,7 @@ d3Selection.select('#svg-1') // irrelevant typing to get contextual typing in la .classed('has-transform-property', function(d) { console.log('Color of first data element array', d.length > 0 ? d[0].color : 'Data array empty'); // CircleDatumAlternative type // $ExpectError - return this.transform !== undefined; + return this!.transform !== undefined; }); // SCENARIO 3: Only inferred typing (To have datum-type in 'classed' method call, no need for DOM object access) @@ -649,6 +649,7 @@ const startCircleData: CircleDatumAlternative[] = [ color: 'slateblue' } ]; + const endCircleData: CircleDatumAlternative[] = [ { nodeId: 'n1', @@ -1169,3 +1170,134 @@ predefinedNamespaces['dummy'] = 'http://www.w3.org/2020/dummynamespace'; xWindow = d3Selection.window(xElement); xWindow = d3Selection.window(xDoc); xWindow = d3Selection.window(xWindow); + +// --------------------------------------------------------------------------------------- +// JOIN - Convenient alternative to explicit enter update and exit methods +// --------------------------------------------------------------------------------------- + +interface OldDatum { + oldData: number; +} + +interface Datum { + data: string; +} + +let selText: d3Selection.Selection; +let selTextAndCircle: d3Selection.Selection; + +const text = svgEl.selectAll('text').data([{data: 'a'}]); + +declare const r: () => boolean; + +// with only enter param + +selText = text.join('text'); +selText = text.join('custom'); +selText = text.join(enter => enter.append('text').text(d => d.data)); + +selText = text.join('circle'); // $ExpectError +selText = text.join('custom'); // $ExpectError +selText = text.join(enter => enter.append('circle')); // $ExpectError + +selTextAndCircle = text.join('circle'); +selTextAndCircle = text.join('custom'); +selTextAndCircle = text.join(enter => enter.append('circle').text(d => d.data)); + +// with all param + +selText = text.join( + 'text', + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => d.data).remove(), +); + +selText = text.join( + 'custom', + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => d.data).remove(), +); + +selText = text.join( + enter => enter.append('text').text(d => d.data), + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => d.data).remove(), +); + +selTextAndCircle = text.join( + 'circle', + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => d.data).remove(), +); + +selTextAndCircle = text.join( + 'custom', + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => d.data).remove(), +); + +selTextAndCircle = text.join( + enter => enter.append('circle').text(d => d.data), + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => d.data).remove(), +); + +// with all param and old datum + +selText = text.join<'text', OldDatum>( + 'text', + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => `Bye ${d.oldData}`).remove(), +); + +selText = text.join( + 'custom', + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => `Bye ${d.oldData}`).remove(), +); + +selText = text.join( + enter => enter.append('text').text(d => d.data), + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => d.oldData).remove(), +); + +selTextAndCircle = text.join<'circle', OldDatum>( + 'circle', + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => d.oldData).remove(), +); + +selTextAndCircle = text.join( + 'circle', + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => d.oldData).remove(), +); + +selTextAndCircle = text.join( + enter => enter.append('circle').text(d => d.data), + update => r ? undefined : update.text(d => d.data).attr('fill', 'gray'), + exit => exit.text(d => d.oldData).remove(), +); + +// Example from: https://github.com/d3/d3-selection/issues/194#issuecomment-427577484 +const groups = svgEl.selectAll('g') + .data([{r: 10, text: 'hi'}]) + .join( + (enter) => { + const g = enter.append('g').attr('class', 'tick'); + g.append('circle'); + g.append('text'); + return g; + }, + () => undefined, + (exit) => exit.remove() + ) + .attr('transform', (_, i) => `translate(0, ${i})`); + + groups.select('circle') + .attr('r', d => d.r); + + groups.select('text') + .text(d => d.text) + .attr('dy', '0.32em'); diff --git a/types/d3-selection/index.d.ts b/types/d3-selection/index.d.ts index c29f7aa952..eeda3d1486 100644 --- a/types/d3-selection/index.d.ts +++ b/types/d3-selection/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for D3JS d3-selection module 1.3 +// Type definitions for D3JS d3-selection module 1.4 // Project: https://github.com/d3/d3-selection/ // Definitions by: Tom Wanzek // Alex Ford @@ -7,7 +7,7 @@ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.3 -// Last module patch version validated against: 1.3.0 +// Last module patch version validated against: 1.4.0 // -------------------------------------------------------------------------- // Shared Type Definitions and Interfaces @@ -782,6 +782,40 @@ export interface Selection(data: ValueFn, key?: ValueFn): Selection; + /** + * Appends, removes and reorders elements as necessary to match the data that was previously bound by `selection.data`, returning the merged enter and update selection. + * This method is a convenient alternative to the more explicit `selection.enter`, `selection.exit`, `selection.append` and `selection.remove`. + * + * The "matching" logic is determined by the key function passed to `selection.data`. + */ + join( + enter: K, + update?: (elem: Selection) => Selection | undefined, + exit?: (elem: Selection) => void + ): Selection; + /** + * Appends, removes and reorders elements as necessary to match the data that was previously bound by `selection.data`, returning the merged enter and update selection. + * This method is a convenient alternative to the more explicit `selection.enter`, `selection.exit`, `selection.append` and `selection.remove`. + * + * The "matching" logic is determined by the key function passed to `selection.data`. + */ + join( + enter: string, + update?: (elem: Selection) => Selection | undefined, + exit?: (elem: Selection) => void + ): Selection; + /** + * Appends, removes and reorders elements as necessary to match the data that was previously bound by `selection.data`, returning the merged enter and update selection. + * This method is a convenient alternative to the more explicit `selection.enter`, `selection.exit`, `selection.append` and `selection.remove`. + * + * The "matching" logic is determined by the key function passed to `selection.data`. + */ + join( + enter: (elem: Selection) => Selection, + update?: (elem: Selection) => Selection | undefined, + exit?: (elem: Selection) => void + ): Selection; + /** * Return the enter selection: placeholder nodes for each datum that had no corresponding DOM element * in the selection. (The enter selection is empty for selections not returned by selection.data.) @@ -828,9 +862,9 @@ export interface Selection