Comments (25)
selection.call(brush.move, null);
from d3-brush.
Sorry, but no, or at least not now. I am however considering creating an LLC to allow private licensing of my GPL’d code for a fee as a way to fund the ongoing development of D3. (I’m considering other funding models, too, but the added value of learning materials and examples seems like the most obvious way to offer a premium service on top of the free library.) It’s great that you are finding value from my software, but I can’t keep giving everything away forever.
from d3-brush.
I’ve updated this example to demonstrate brush snapping on end:
http://bl.ocks.org/mbostock/6232537
The main trick is to add this check to your end listener:
if (!d3.event.sourceEvent) return; // Only transition after input.
from d3-brush.
is there a reason brush.clear() was removed and replaced with this (which is not nearly as flexible as clear())
@sbromberger I assume you are asking what the underlying reason is, rather than implying I make random changes to the API without thought to the consequences.
The reason is that past versions of the brush didn’t cleanly specify where the brush state was stored. For the most part the state was stored on the brush object, but it was also necessary to store the brush state on selected elements to enable transitions (in element.chart). This led to bugs and confusion about the intended behavior. (Some of this is captured in d3/d3#1515.)
The D3 4.0 API clarifies that the brush state is always stored on the element. The brush is a rubber stamp (like d3-axis) that you apply to elements and re-apply to update. To access the brush’s selection you must use d3.event.selection within a brush event or d3.brushSelection, and to set the state you must use brush.move which takes a selection. (This design also eliminates the wart of brush.event in 3.x.)
You appear to argue that this:
selection.call(brush.move, null);
or equivalently this:
brush.move(selection, null);
is “way more complicated” and “not nearly as flexible” as this:
brush.clear();
But you don’t say why, so I don’t understand your criticism.
I argue that the new API is more flexible than the old one because it allows you to apply the brush event to multiple elements simultaneously, and is less complicated because the API doesn’t get confused about where the brush state is stored and whether multiple brushable elements share the same states. (In 3.x applying the brush to multiple elements was possible but buggy, as interaction would cause the other brushes to have detached states.) I suppose if you ignore the brokenness of the old API it might appear falsely simpler, but even then, it’s not particularly onerous to specify a selection whenever getting or setting the brush state.
If you meant that it’s complicated to call brush.move instead of a dedicated brush.clear method, I’d be willing to add a convenience method:
selection.call(brush.clear);
from d3-brush.
Thanks @mbostock !
Just to be 100% clear...
import {brush} from 'd3';
const myBrush = brush().on(...);
const brushArea = svg.append('g');
brushArea.call(myBrush);
// clear:
brushArea.call(myBrush.move, null);
// to move it programmatically
brushArea.call(myBrush.move, [[0,0], [1,1]]);
I was getting stuck trying to figure out how to use myBrush.move(brushArea, null)
because it seems if I execute that code in my end
handler, I end up with a start
event being fired with a mouseup
event as the current d3 event which is causing an execption.
Calling the brush.move
in a setTimeout( () => brush.move(area, null), 0);
causes a start
brush event with d3.event === undefined
from d3-brush.
Still can't get the myBrush.move(brushArea, null)
to work, I'm now getting a "call stack size exceeded" in d3.
from d3-brush.
❤️ thanks for all the help @mbostock
from d3-brush.
Sorry, let me clarify - yes - I was wondering why the change was made (not that you had erred in making it).
In my case, it changes my code from:
function brushend () {
var extent = brush.extent();
var xextent = extent.map(function (e) { return e[0]; });
if (brush.empty()) {
clicked += 1;
} else {
redrawChart(extent);
d3.select('.brush').call(brush.clear());
}
if (clicked >= 2) {
// zoom out code here
clicked = 0;
}
...
to
b.end = () => {
var extent = d3.event.selection;
if (!d3.event.sourceEvent) return;
if (extent === null) {
b.clicked += 1;
if (b.clicked >= 2) {
b.chart.zoomout();
b.clicked = 0;
}
return;
}
else {
var xextent = extent.map(e => e[0]);
b.chart.redraw(extent);
...
}
b.clear();
b.create();
}
clear () {
this.chart.brushArea.call(this.d3brush.move, null);
this.d3brush = null;
this.clicked = 0;
}
create () {
var d3brush = d3.brush()
.extent([[0,0], [this.chart.width, this.chart.height]])
.on('start', this.start)
.on('brush', this.move)
.on('end', this.end)
this.d3brush = d3brush;
return d3brush;
}
}
(The functionality I'm trying to achieve: brush to zoom in on a specific area of a chart; double-click to zoom out by a percentage.)
Which is significantly different and (at least to me) less intuitive.
Perhaps you have some suggestions as to how I might tighten up the new code?
from d3-brush.
Hard to tell from your code since those two snippets don’t seem comparable. But here’s my take on how to do it…
http://bl.ocks.org/mbostock/f48fcdb929a620ed97877e4678ab15e6
from d3-brush.
Thank you! Glad to hear you got it working. 🎉
from d3-brush.
hey @mbostock - would you mind releasing that block under a BSD or MIT license (instead of, or in addition to, GPL)? I've integrated parts of it into this non-GPL code and would rather avoid a clean-room reimplementation.
Thanks :)
from d3-brush.
@jwdomingo Your question seems a bit off-topic for this issue and it would probably be more appropriate to use Stack Overflow or the d3-js Google Group to ask for help. To answer your question, yes, there is no longer a brush.empty method because (as described in the release notes and D3’s CHANGES.md) the brush no longer stores the selection state internally: it is stored on the element(s) you apply the brush to, and is accessible either as d3.event.selection or d3.brushSelection, which takes an element. If the selection is null then there is no selection.
from d3-brush.
I’ve updated the documentation. (Though see also #15 for a bug if you clear the brush selection during an active brush gesture.)
from d3-brush.
In general any programmatic control of the brush goes through brush.move. The general pattern is to use brush first to set up the event listeners:
selection.call(brush);
And then any time you want to set the brush extent programmatically (or manually trigger the brush event listeners), call brush.move.
from d3-brush.
There are multiple things going on here. See #9 for the issue regarding mouseup and undefined events.
As for the stack overflow, it sounds like you’re trying to set the brush within a brush event handler, which then triggers more brush events because you’re moving the brush. You need to prevent an infinite loop by not moving the brush in response to you moving the brush. There are a variety of ways to do that—for instance you can check if the brush is already in the position you want it to be in before moving it, or you can set a temporary boolean to check whether the brush event is being caused by your call to brush.move.
from d3-brush.
@mbostock is there a reason brush.clear()
was removed and replaced with this (which is not nearly as flexible as clear()
)? I have a similar issue - I want to clear the brush within end but this just seems way more complicated.
from d3-brush.
Thanks, @mbostock - I'll see if I can adapt my code to yours. I appreciate the quick feedback.
from d3-brush.
Your code is fantastic, btw. Thank you. I got it working.
from d3-brush.
Just want to add my $0.02 here on this point - having the GPL license on all the core example blocks makes D3 contract work tricky, as it requires each technique to be - as @sbromberger said - "clean-room reimplemented". Even then, some usage patterns (a few lines of code here and there) necessarily end up being exactly the same code as the original GPL block, which gives me a sickening feeling that I'm violating some kind of copyright law or something when I deliver code to clients (e.g. Global Migration in 2015).
from d3-brush.
@curran - wow, that visualization is beautiful!! 👍 💯
from d3-brush.
Hello! brush.empty() is no longer a function?
from d3-brush.
Thank you @mbostock, I will migrate over to SO.
from d3-brush.
It might be good to update the documentation to reflect that you can call selection.call(brush.move, null)
https://github.com/d3/d3-brush/blob/master/README.md#brush_move
from d3-brush.
Hmm. I'm getting
Uncaught TypeError: Cannot read property '0' of null
when I try to .transition(t).call(brush.move, null)
but not when I just directly .call(brush.move, null)
. There's no active event from the user when this happens. Thoughts?
from d3-brush.
How can one remove a brush and all of its events?
// e.g. undo
selection.call(brush)
in essence I want a button to control whether or not the user can use a brush on the chart and whether or not the cross hairs, etc appear.
from d3-brush.
Related Issues (20)
- Brush event started does not initiate "points" variable HOT 1
- Apparent breaking change(s) in non-breaking release HOT 3
- Can't create new brush selection inside extent, only change exsisting one HOT 1
- a brush transition is not interrupted HOT 1
- multitouch HOT 2
- FF android HOT 2
- Allow mousemove event triggering or switching brush state HOT 2
- brush.move should accept an event HOT 1
- Using brush for fine-grained zooming HOT 3
- Brush Wrapping
- bbnk,
- Error multitouch emit undefined inside move function HOT 8
- Brushing uses wrong mouse coordinates if perspective transformations are applied HOT 3
- Is it possible to update d3-color ? HOT 2
- Conflict trying to .filter() with a false value if there is also a d3-zoom active
- incorrect position of the selected area in firefox HOT 2
- Allow to change default to CENTER mode HOT 2
- Errors when using `filter` on mobile HOT 2
- Customize the brush style HOT 2
- Brush handles disappear at zero width HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from d3-brush.