From 6d67d27bc75fd2a50b0f2324b79547967255bfcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Mon, 3 Jan 2022 12:06:13 +0100 Subject: [PATCH] selection.wrap --- README.md | 20 ++++++++++++++++++ src/selection/index.js | 2 ++ src/selection/wrap.js | 11 ++++++++++ test/selection/wrap-test.js | 42 +++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 src/selection/wrap.js create mode 100644 test/selection/wrap-test.js diff --git a/README.md b/README.md index b8513c6..4697957 100644 --- a/README.md +++ b/README.md @@ -412,6 +412,26 @@ selection.select(function() { }); ``` +# selection.wrap(type) · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/wrap.js) + +If the specified *type* is a string, creates a new element of this type (tag name) as a new parent for each selected element, and replaces that node in the document by its new parent. + +If the specified *type* is a function, it is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element (*nodes*[*i*]). This function should return an element to be used as the new parent. (The function typically creates a new element, but it may instead return an existing element.) For example, to wrap a paragraph around each SPAN element: + +```js +d3.selectAll("span").wrap("p"); +``` + +This is equivalent to: + +```js +d3.selectAll("span").wrap(() => document.createElement("p")); +``` + +In both cases, this method returns a new selection containing the new parent elements. Each new element inherits the data of the current element it wraps. + +The specified *name* may have a namespace prefix, such as `svg:text` to specify a `text` attribute in the SVG namespace. See [namespaces](#namespaces) for the map of supported namespaces; additional namespaces can be registered by adding to the map. If no namespace is specified, the namespace will be inherited from the selected element; or, if the name is one of the known prefixes, the corresponding namespace will be used (for example, `svg` implies `svg:svg`). To wrap svg elements in HTML A elements, pass an explicit namespace. + # selection.sort(compare) · [Source](https://github.com/d3/d3-selection/blob/master/src/selection/sort.js) Returns a new selection that contains a copy of each group in this selection sorted according to the *compare* function. After sorting, re-inserts elements to match the resulting order (per [*selection*.order](#selection_order)). diff --git a/src/selection/index.js b/src/selection/index.js index a593a21..5fb691c 100644 --- a/src/selection/index.js +++ b/src/selection/index.js @@ -32,6 +32,7 @@ import selection_datum from "./datum.js"; import selection_on from "./on.js"; import selection_dispatch from "./dispatch.js"; import selection_iterator from "./iterator.js"; +import selection_wrap from "./wrap.js"; export var root = [null]; @@ -84,6 +85,7 @@ Selection.prototype = selection.prototype = { datum: selection_datum, on: selection_on, dispatch: selection_dispatch, + wrap: selection_wrap, [Symbol.iterator]: selection_iterator }; diff --git a/src/selection/wrap.js b/src/selection/wrap.js new file mode 100644 index 0000000..5a9c087 --- /dev/null +++ b/src/selection/wrap.js @@ -0,0 +1,11 @@ +import creator from "../creator.js"; + +export default function(name) { + var create = typeof name === "function" ? name : creator(name); + return this.select(function() { + const wrap = create.apply(this, arguments); + if (this.parentNode) this.parentNode.insertBefore(wrap, this); + wrap.appendChild(this); + return wrap; + }); +} diff --git a/test/selection/wrap-test.js b/test/selection/wrap-test.js new file mode 100644 index 0000000..9f8d5a3 --- /dev/null +++ b/test/selection/wrap-test.js @@ -0,0 +1,42 @@ +import assert from "assert"; +import {create, selectAll} from "../../src/index.js"; +import {assertSelection} from "../asserts.js"; +import it from "../jsdom.js"; + +it("selection.wrap(name) wraps each of the selected elements in a new element of the specified name", "
", () => { + const one = document.querySelector("#one"); + const two = document.querySelector("#two"); + const selection = selectAll([one, two]).data([1, 2]).wrap("pre"); + const [three, four] = document.querySelectorAll("pre"); + assertSelection(selection, {groups: [[three, four]], parents: [null]}); +}); + +it("selection.wrap(name) wraps with the appropriate namespace", () => { + const htmllink = create("span").wrap("a"); + assert.strictEqual(htmllink.node().namespaceURI, "http://www.w3.org/1999/xhtml"); + const svglink = create("svg:text").wrap("a"); + assert.strictEqual(svglink.node().namespaceURI, "http://www.w3.org/2000/svg"); +}); + +it("selection.wrap(name) wraps unattached elements", () => { + const p = create("span").text("Hello").wrap("p"); + assert.strictEqual(p.node().nodeName, "P"); +}); + +it("selection.wrap(function) passes the creator function data, index and group", "
", () => { + const one = document.querySelector("#one"); + const two = document.querySelector("#two"); + const results = []; + + selectAll([one, two]) + .datum(function(d, i) { return "node-" + i; }) + .wrap(function(d, i, nodes) { + results.push([this, d, i, nodes]); + return document.createElement("p"); + }); + + assert.deepStrictEqual(results, [ + [one, "node-0", 0, [one, two]], + [two, "node-1", 1, [one, two]] + ]); +});