So, I have a work-able d3 map but the only problem is the zoom is incredibly slow. This is a map of about 200 points on the globe where I'd like to be able to zoom in/pan and retreive info on each point. I think d3 looks so much better than leaflet, but for quick zooming/panning functionality, my first question is: is this better off in leaflet or can d3 handle slick zoom/pan even though it's not tile-based?
I've included a snippet of my code below: am I doing something wrong here? It works as is, but is there a way to make the zoom run more quickly? Thanks in advance! Everyone here has been so helpful.
function zoomed() {
console.log("zooming now!")
///called on zoom events
d3.selectAll(".centroid").attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
d3.selectAll(".gratLines").attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
d3.selectAll(".countries").attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
d3.selectAll(".gratBackground").attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
};
function setMap() {
var zoom = d3.behavior.zoom()
.translate([0, 0])
.scale(1)
.scaleExtent([1, 21])
.on("zoom", zoomed);
console.log("setting map")
var map = d3.select("body")
.append("svg")
.attr("width", mapWidth)
.attr("height", mapHeight)
.attr("class", "map")
var pageTitle = d3.select("body")
.append("text")
.attr("class", "pageTitle")
.html("UW Hospital Graduates:<br>Where Do They Go?");
var projection = d3.geo.naturalEarth()
.scale(410)
.translate([mapWidth / 2, mapHeight / 2])
.precision(.1);
var path = d3.geo.path()
.projection(projection);
var path = d3.geo.path()
.projection(projection)
.pointRadius(3);
//create graticule generator
var graticule = d3.geo.graticule();
//create graticule background (aka water)
var gratBackground = map.append("path")
.datum(graticule.outline)
.attr("class", "gratBackground")
.attr("d", path)
zoom.on('zoom', zoomed)
map.call(zoom);
var gratLines = map.selectAll(".gratLines")
.data(graticule.lines) //
.enter()
.append("path") //append one path for each element of the data (in this case, each graticule line)
.attr("class", "gratLines")
.attr("d", path) //this path is the variable path defined above. path generator
Related
I have fllowing questions.
I used force graph and add zoom for it.
But when mouse drag the blank area,the force graph keeps jumping.
like this
How to make the graph do not jump?Thanks.
(I feel very sorry for my English.Thank you again.)
This is my zoom code.
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
function zoomed() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
I added a g element to your base SVG to group everything together (also appended any other elements to the g element instead of the svg), then in the zoomed() method, performed transforms on that g element instead of on the svg element:
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(zoom);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")");
Zoom method:
function zoomed() {
g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
Also, when setting up node listeners, stop event propagation for the 'mousedown' event, like so:
var node = g.selectAll(".node")
.data(force.nodes())
.enter().append("g")
.attr("class", "node")
.on("mouseover", mouseover)
.on("mouseout", mouseout)
.on("click", click)
.on("dblclick", dblclick)
.on("mousedown", function(d) {
d3.event.stopPropagation();
})
.call(force.drag)
.on('click', connectedNodes);
Here's the working example.
I created a polar scatter plot using D3.js (based on this post) .
I would like to add the functionality to zoom and pan. I've seen examples for rectangular plots, but nothing for zooming/panning on circular plots.
I am just a beginner with using D3 so I'm a little lost. Can anyone help/offer suggestions?
I'm not entirely sure what your goal is, but I tried something below.
First you should add zoom behaviour. I used the r scale for both your x and y directions like:
var zoomBeh = d3.behavior.zoom()
.x(r)
.y(r)
.on("zoom", zoom);
And call the zoom behaviour into your svg:
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.call(zoomBeh);
Finally you should make a zoom function.
function zoom() {
var t = svg.transition().duration(750);
svg.selectAll(".point").transition(t)
.attr("transform", function(d) {
var coors = line([d]).slice(1).slice(0, -1);
return "translate(" + coors + ")"
})
}
Here is an updated fiddle. It's a little bit staggering, I'm not sure why yet.
Currently, i'm trying to implement a zoom function to my data visualization. Sometimes an error occurs "d3.min.js:1 Uncaught TypeError: t.apply is not a function" when i try to zoom or to move the svg element. It looks like an internal error within d3 library.
var height = $("#content").height();
var width = $("#content").width();
var svg = d3.select("#content").append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "svg_canvas")
.append("g")
.call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
.attr("transform", "translate(" + (width / 2.0) + "," + (height /2.0 )+ ")")
.append("g")
.attr("class", "interaction_group");
zoom_layer = svg;
//Overlay for zooming
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + (-width / 2.0) + "," + -(height/2.0 ) + ")");
The event handler "zoom" is really basic:
function zoom() {
zoom_layer.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
The implementation was realized with the latest D3.js V3 version.
Firstly, declare your zoom behavior:
var myZoomBehavior=d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom)
Then call it to the svg root:
var svg = d3.select("#content").append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "svg_canvas").call(myZoomBehavior)
Then create the zoomable g with the same variable name as in your zoom function:
var zoom_layer=svg.append("g")
I've created a hierarchical edge bundling graph with some data and after trying to implement zooming and dragging on the graph I've run into some issues.
Here is a similar working jsfiddle of what I have so far: https://jsfiddle.net/hnjvxd48/1/
and the relevant code:
var zoom = d3.behavior.zoom()
.scaleExtent([0,8])
.on("zoom", zoomhandler);
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
var svg = d3.select(".container").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")")
.call(zoom)
.call(drag);
function zoomhandler(){
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
You'll notice:
1) Dragging and zooming only occur on the outer edges and not the inner part of the graph.
2) Dragging the graph around causes flickering and centering of the graph to change and become cut off.
3) Zooming (done via mouse scroll wheel) also centers the graph incorrectly and places it in an unpredictable position, partly out of the view port.
4) Attempting to drag the graph after it has been zoomed out causes it to flicker and disappear.
What's causing these issues and how can I fix them? How can I give my graph (which is much bigger than the sample one I provided) an initially "zoomed out" state and perhaps trigger the zooming functionality using a button click event rather than the native scroll wheel implementation?
The big thing to notice here is that the drag functions are actually redundant. In this (http://bl.ocks.org/mbostock/6123708) d3 drag + zoom example, they're being used to move individual 'dots'. You want to move the whole graph at once, and this is handled by the 'translate' portion of the 'zoomhandler' function you've included.
Here's a working fiddle: https://jsfiddle.net/14f9f4k3/1/
And the key code that with changes noted in comments:
var zoom = d3.behavior.zoom()
.scaleExtent([0,8])
.on("zoom", zoomhandler);
//added another group as a child of the group having zoom called on it w/ id 'draggroup' to append nodes and links to
var svg = d3.select(".container").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")")
.call(zoom)
.append('g')
.attr('id','draggroup');
//added a rect behind the other elements to make an easy target for the pointer
d3.select('#draggroup')
.append('rect')
.attr("transform", "translate(" + -radius + "," + -radius + ")")
.attr('width',diameter)
.attr('height',diameter)
.attr('fill','#fff');
//no need for separate drag functions, translate and scale here do what you want
function zoomhandler(){
svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")");
}
//append the links and nodes to the group we created above instead of the base svg
var link = d3.select('#draggroup').append("g").selectAll(".link"),
node = d3.select('#draggroup').append("g").selectAll(".node");
So I've been given an assignment where I need to work with the US map, divided into states and further into counties. I already have the current code and need to extend on it.
I am not able to understand the following snippet from the code.
var colorRange = [ 'rgb(247,251,255)',
'rgb(222,235,247)',
'rgb(198,219,239)',
'rgb(158,202,225)',
'rgb(107,174,214)',
'rgb(66,146,198)',
'rgb(33,113,181)',
'rgb(8,81,156)',
'rgb(8,48,107)'];
var quantile = d3.scale.quantile()
.range(colorRange);
var path = d3.geo.path();
var svg = d3.select("#map")
.attr("width", width)
.attr("height", height)
.append('svg:g')
.call(d3.behavior.zoom().on("zoom", redraw))
.append('svg:g');
svg.attr("transform", "scale( " + .9 + ")");
function redraw() {
console.log("here", d3.event.translate, d3.event.scale);
svg.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
What exactly is happening in each line of this snippet?
Full Code taken from here
Thanks
the var colorRange is just a variable holding the colors to be applied to the various counties, the var quantile sets the scale for the color to be applied, the var path calls the path function and the var svg creates an svg. In this the command .call has a functionality .on("zoom", which calls the function redraw.
function redraw defines the function, which translates and scales the svg accordinglly to the zoom