From the d3.js bubbles example I have added the zoom + pan functions. Now I want to allow users to select a bubble on desktops and touch-screens. The dblclick and touchstart seem to be consistent for this.
I know d3 provides a way to cancel an event from .zoom but then it is disabled and doesn't do anything.
.call(d3.behavior.zoom().on("zoom", zoom)).on("dblclick", null);
Link: http://bl.ocks.org/4163494
What I have above sort of works but you will notice that a dblclick doesn't zoom at first but then it is revealed if you cause another zoom event. I am looking for the right way to do this.
To fix I left the
.on("zoom", redraw)
function where it was but moved the dblclick down to the circle, text, and tspan elements. From there they call a function that first stops propagation and then selects the circle.
http://jsfiddle.net/nnzS9/
Related
I have a simple plot with the zoom functionality along Y axis.
When I use wheel to change the zoom it works OK.
But when I use mouse to drag then at the beginning the chart jumps.
Here is the function I use on the zoom event:
I guess there should be added some test if the event is wheel or mouse and some more calculations in case of the mouse event.
function zoom(event: any) {
console.log(event);
let new_yScale = event.transform.rescaleY(yScale);
console.log(new_yScale);
console.log(new_yScale.domain());
console.log(new_yScale.range());
setMinY(new_yScale.domain()[0]);
setMaxY(new_yScale.domain()[1]);
}
I am using D3.js and React.
Code sandbox link:
Application demo:
In the attachment is the gif showing the strange behaviour.
I tried to console.log the event.transform result and noticed the event.transform values are different on wheel event and mouseevent. But I do not know how to recalculate the mouseevent result to be compatible with the wheel.
I solved it here:
https://p89vne.csb.app/
I found this tutorial very useful:
https://www.youtube.com/watch?v=dxUyI2wfYSI&list=PLDZ4p-ENjbiPo4WH7KdHjh_EMI7Ic8b2B&index=18
I think the initial example had flaw design ( with recreating the svg every tick) and that was the main problem.
I am using this example as a basis for zoom in my project but I would like to restrict the zoom to only the buttons and double clicking. Ideally, using the scroll wheel should just continue scrolling down the page and not zoom in on the svg when the mouse is over it. Any help is appreciated!
For D3 4.0, there're two ways to prevent d3 zoom from responding to wheel event.
A:
zoom.filter(function() { return !event.button && event.type !== 'wheel'; })
// the `!event.button` expression is from the default filter, according to
// doc for zoom.filter([filter])
B:
svg.on("wheel.zoom", null);
// according to doc for zoom(selection): Internally, the zoom behavior
// uses selection.on to bind the necessary event listeners for zooming.
// The listeners use the name .zoom
It's still possible to pan(translate) with mouse dragging.
You can achieve this by:
var svg = d3.select("body").select("svg")
.attr("width", width)
.attr("height", height)
.append("g")
//.call(zoom) //remove the zoom listener from the group.
.append("g");
Next attach doublclick listener on the circle and the rectangle for zooming.
d3.selectAll("rect").on('dblclick', zoomClick)
d3.selectAll("circle").on('dblclick', zoomClick)
working code here
I have a transparent drag layer on top of a shape layer. Works great to make interaction distinct so I can toggle what dragging does (between scrolling the view or editing the shape positions). However, unless I turn off drag mode (by hiding the intervening transparent Rect), none of the other mouseover events fire on the shape layer beneath it. I need to propogate the non-drag mouse events to the layer below it. There are A LOT of shapes with mouse over events.
Is there an easy way to propogate the mouse over events to the layer beneath it or do I need to write a custom handler to fire events for every shape?
I managed to solve this without having to propagate events between layers. I put a draggable surface behind the shapes on the shape layer only if a shape isn't clicked. Then to cover if a shape is clicked, on the shape dragstart event, if a layerdraggable flag is set, I do a stopDrag() on the shape and a startDrag() on the layer. This allowed me to toggle with a simple flag whether I want the whole layer dragging, or just the shape.
I had to clean up a little of the shape position on the dragend event, but alternatively you can do that with a dragbounds on the shape.
shape.on('dragstart', function () {
if (layerDraggable) {
shape.stopDrag();
shapeLayer.startDrag();
}
}
Please see my fiddle: http://jsfiddle.net/haiphong/BRjFE/
You can hold SHIFT and then drag and drop the rectangle to move it and the circle inside it around. You can hold SHIFT and zoom as well. This zoom/pan is done by d3.behavior.zoom(). Works well.
I want to zoom and pan the circle when NOT holding shift. So, I create another d3.behavior.zoom(). However, the circle can be zoomed but not panned. By debugging, I see that when I pan the circle, the handling code doesn't execute.
In sum, when binding a zoom to both the outer g element and the inner g element, the outer works well for zoom/pan; however, the inner only works for zoom. How to get it work for pan as well?
I found the solution for my answer. http://jsfiddle.net/haiphong/BRjFE/4/
When I pan the circle, its zoom event doesn't fire. However, its zoomstart event fires and it is fired before its parent's zoomstart. Somehow, when the parent's zoomstart fires, it eats the circle's event.
So, in the zoomstart of the circle, I force the event stop propagating when SHIFT isn't being hold. That makes the circle zoom fires.
I want to create sort of a 3D effect with the shapes I generated with KineticJS on my canvas.
When I drag them to the top, the need to become smaller, and when dragged to the bottom, they need to become bigger.
The closest I got to what I wanted is with the mousemove event you see here
$.each(bubbles, function(){
var bubble = this;
bubble = new Kinetic.Circle({x:this.x, y:this.y, radius:this.r, fill:'#000000', draggable:true});
bubble.on("mousemove",function(){
bubble.setRadius((bubble.getY()/5));
});
layer.add(bubble);
});
But this only changes the radius when ending dragging and click the shape again.
It would be very nice if I can make it possible to change them "realtime", when dragging.
Does anyone have any idea how to solve this?
Here's my JSFiddle http://jsfiddle.net/ZsADd/1/
Thank you!
I think what you want is bubble.on("dragmove"). Here is an example of it in action. For more info on drag events, look into the documentation which I found here.
To detect drag and drop events with KineticJS, we can use the on()
method to detect dragstart , dragmove, or dragend events. The on()
method requires an event type and a function to be executed when the
event occurs.