Animate an SVG replacement in d3.js? - javascript

I am using a set of sliders to generate an SVG image in d3. Whenever a slider changes, my corresponding SVG image should change.
To generate my SVG, I'm using the following code -
function build_svg(json_data) {
d3.select(".col-sm-6").select("svg").remove();
var svg = d3.select(".col-sm-6").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.attr("class", "bubble");
d3.json(json_data, function(error, data) {
// Some logic to populate variable "svg"
}
}
The function build_svg is called whenever I want to put a new set of JSON data.
Unfortunately, every time I move my slider, I see a flickering image and I don't observe a smooth transition between the SVG images. What would be the best way to build this animation?

Related

Centering Images in D3 After Transform

I'm trying to move an element in D3, in order to correspond to a circle underneath. Basically, when the user zooms on the page, the circles shrink (which allows them to remain visually appealing and separated).
I want to build a function that fires with the zoom event, that keeps the images centered within the circles. The circles are centered on their center points. However, as the images shrink, they appear to move to the left because their anchors are in the top-left corner.
I need a solution that might involve adding their sacrificed width and height to their relative "x" and "y" attributes. How would I implement a function like this? Or is there a better way?
The blockbuilder is here: http://blockbuilder.org/KingOfCramers/125cc79bce7dea48b21786b37302d258
Here is the relevant bit of code (the icon variable is the starting width of the image):
function zoom() {
var iconMove = icon/d3.event.transform.k;
g.attr("transform", d3.event.transform)
d3.selectAll(".storyImages")
.attr("width", `${iconMove}px`)
.attr("height", `${iconMove}px`)
.attr("x", // Keep this centered)
.attr("y", // Keep this centered)
d3.selectAll("circle")
.attr("r", function(){
return cirSize/d3.event.transform.k
})
}
Thanks for any help you can provide!
If you can position them to start, you can update them the same way on zoom, just with the new width/height of each item. You initially append each item with these attributes:
.attr("x", (d) => projection([d.lat,d.lon])[0] - icon/2)
.attr("y", (d) => projection([d.lon,d.lat])[1] - icon/2)
.attr("width", `${icon}px`)
.attr("height", `${icon}px`)
Which offsets the icon from the x,y values returned by the projection by half the icon's width and height - centering it on the projected point. Note: Your x value is set with d.lat, d.lon rather than d.lon, d.lat, also, your csv has lng, rather than lon as a header, so d.lng should be used).
To keep the icon centered on the point, just update the icon using the new icon width/height (which in your case is located in iconMove) and the new projected point:
.attr("x", (d) => projection([d.lng,d.lat])[0] - iconMove/2)
.attr("y", (d) => projection([d.lng,d.lat])[1] - iconMove/2)
.attr("width", iconMove)
.attr("height", iconMove);
Here's an updated block (I wasn't able to figure out how to save a new block builder block).

d3.js create same svg object with different data

I have a script, that works fine and create a chord diagram I need.
But now I want to create the same .svg file on another div but with different matrix.
Should I duplicate the same script for a new svg, or I can do in more efficient way?
You can find my code here.
Now my .Js script use drawChordWithMatrix(matrix_T1_T2) to show chord on div with id chart
What should I do to run drawChordWithMatrix(matrix_T2_T3) on id chart1
One way i can think is
1) Move the SVG creation into the drawChordWithMatrix
So you need to pass the id to which you need to attach the SVG.
something like this function drawChordWithMatrix(matrix, id), and you create your SVG in the function like this.
var svg = d3.select(id).append("svg")//selecting on basis of ID.
.attr("width", (width + margin.left + margin.right))
.attr("height", (height + margin.top + margin.bottom));
2) Next move all functions like fade, fadeOnChord , etc.. into the drawChordWithMatrix so that they all have the same scope.
working code here

Trying to analyse why this transition is not happening

I have the following adapted d3.js visual and I'm unable to work out why the transition does not fire. The ars should rotate around to different sizes when the radio button is clicked.
It seems that clicking the radio button is changing the titles of the arc (if I hover the cursor over each)
Is this section of code to blame?
// check if svg group already exists
var svg = d3.select("#sunGroup");
if (svg.empty()) {
var svg = d3.select("#sunBurst")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr({
'transform': "translate(" + width / 2 + "," + height * .52 + ")",
id: "sunGroup"
});
}
Here is the full (not) working example:
https://plnkr.co/edit/hpvREU?p=preview
This is the transition I'm trying to hold onto: plnkr.co/edit/NnQUAp?p=preview
What I trying to do is move the logic at line 128 (starting d3.selectAll("input").on("change", function change() {...) out of this function
An easy fix to your problem is to remove all children of the SVG whenever you switch data types:
d3.select("#sunBurst").selectAll('*').remove()
That way, you are binding the new data to new elements. You can also remove the svg.empty() and d3.select('#sunGroup') code. This simple fix lets you switch between pie charts, and is in the spirit of the code you currently have. Here's the users pie chart.
However, this may not be the best way to do what you're trying to achieve. As a reference, see Mike Bostock's General Update Pattern series (link is to first in the series) for how to update your SVG.

D3 V4 setting initial zoom level

I've just started using D3 V4 and I'm having trouble getting a pan and zoom function working. The problem is that I want the initial scale value to be something over than 1 so I set this using
zoom.scaleTo(svg, 2);
However as soon as I pan or zoom the scale resets back to 1.
Here's an example of this behavior on JSFiddle, what am I doing wrong?
JSFiddle
Here's the problem:
var svg = d3.select("body").append("svg")
.attr("width", 600)
.attr("height", 600)
.call(zoom)
.append("g");
You are assigning the group element instead of the svg element to the variable svg.
The zoom is correctly applied to the svg element, but then when you call zoom.scaleTo(svg, 2) you are zooming the group element, not the svg element.
This can be fixed by first creating and assigning the svg element to the svg variable and only then creating and assigning the group element.
var svg = d3.select("body").append("svg")
.attr("width", 600)
.attr("height", 600)
.call(zoom);
var mainContainer = svg.append("g");
Here's the fixed JSFiddle: https://jsfiddle.net/skgktrcu/2/

appending d3.js canvas to div

I'm attempting to add a legend to a graph, and I want to append it to my chart div. Right now I'm using the following code, which appends the legend to the "body". I would like to instead append it to my "chart" div, so that I can create a footer after my legend. Right now the HTML page is processed first, and then my d3 javascript file gets run and therefore the legend gets placed below my footer. Thank you in advance.
// Create the svg drawing canvas...
var canvas = d3.select("body")
.append("svg:svg")
.attr("width", 300)//canvasWidth)
.attr("height", 300);//canvasHeight);
The following works, like I pointed out in the comment.
var canvas = d3.select("#chart")
.append("svg:svg")
.attr("width", 300)//canvasWidth)
.attr("height", 300);//canvasHeight);
Cheers :)

Categories