Closed curran closed 1 year ago
An iteration:
tagName
to be the last argument and defaults it to 'g'
, which is the most common use case.tagName
to name
for consistency with other methods such as selection.create
. // Manages a single element.
const one = (selection, className, name = 'g') =>
selection
.selectAll(name + '.' + className)
.data([null])
.join(name)
.attr('class', className);
Example snippet before:
svg
.selectAll('.y-axis')
.data([null])
.join('g')
.attr('class', 'y-axis')
.attr('transform', `translate(${margin.left}, 0)`)
.call(axisLeft(yScale));
After:
one(svg, 'y-axis')
.attr('transform', `translate(${margin.left}, 0)`)
.call(axisLeft(yScale));
It could even parse the tag name and class from a selector string:
const one = (selection, selector) => {
const [name, className] = selector.split('.');
return selection
.selectAll(name + '.' + className)
.data([null])
.join(name)
.attr('class', className);
}
I like this because when you read its invocation, the tag name is clear, and there is no "magic" (no default "g" value).
one(svg, 'g.y-axis')
.attr('transform', `translate(${margin.left}, 0)`)
.call(axisLeft(yScale));
Would be super useful right now.
I have this in some code currently:
svg.append("g").call(xAxis);
and I need to change it to this:
svg
.selectAll('.x-axis')
.data([null])
.join('g')
.attr('class', 'x-axis')
.call(xAxis)
but I wish I could change it to this instead:
one(svg, 'g.x-axis').call(xAxis);
Would be super nice!
Another use case - setting up the SVG container:
Before:
const svg = select('body')
.selectAll('.viz')
.data([null])
.join('svg')
.attr('class', 'viz')
.attr('width', width)
.attr('height', height);
After:
const svg = one(select('body'), 'svg.viz')
.attr('width', width)
.attr('height', height);
Closing as the change is not welcome https://github.com/d3/d3-selection/pull/300#issuecomment-1060000113
Actually, wait a minute - we can avoid a string-based DSL and still implement the module.
Based on this feedback from https://github.com/d3/d3-selection/pull/300#issuecomment-1060000113:
I don’t want to introduce (and design and maintain) a new string-based DSL.
the proposal can be modified back to its original form:
one(g, 'g', 'x-axis');
The class name argument could be optional. For example:
one(svg, 'g');
Example from https://github.com/d3/d3-selection/issues/301
maybe d3.single()
for the method name?
Latest implementation for reference:
const one = (selection, name, className) =>
selection
.selectAll(name + '.' + className)
.data([null])
.join(name)
.attr('class', className);
I find myself copying this into codebases often, so thought I'd post it here for easy reference.
An interesting alternative solution https://the-politico.github.io/nicar2019_reactive-d3/parts/idempotence/
see discussion on #300
Added to https://github.com/curran/d3-rosetta
Managing a single element is a common scenario. For example, a group element that contains an axis or legend. It might be a nice idea to consider introducing a utility that makes it simpler to manage a single element.
The most common pattern I find myself using is something like this:
Something similar can be seen in d3-axis for managing the domain path.
Wouldn't it be nicer to have a utility that does this:
?
Here's a strawman implementation: