D3.js svg.diagonal issue - javascript

I have this little issue : I'm not able to draw a curved line with json data.
Here's go my code
var diagonal = d3.svg.diagonal();
groupe.selectAll("path")
.data([data])
.enter()
.append("path")
.attr("d",diagonal
.source({x:250, y:500})
.target({x:400, y:300}))
.attr("fill", "none")
.attr("stroke", "#000")
.attr("stroke-width","2");
Here I put some data, but when i try with
.source({'x':function(d) {return d.x},'y':function(d) {return d.x})
I habve an error in the console and I'm not able to draw the lines
Do you know where is my error ?
My data looks like this
var data = [
{"x":250,"y":500,"width": 100, "height": 100, "nx":400, "ny":300, "class":"brief", "name": "Prise de Brief"},
{"x":400,"y":300,"width": 150, "height": 150, "nx":600, "ny":450, "class":"conception", "name": "Conception"},
{"x":600,"y":450,"width": 150, "height": 150, "nx":900, "ny":500, "xI":600,"yI":450,"wI": 50, "hI": 50, "xlink": "img/hexagone_plein.svg", "class":"crea", "name": "Création graphique", "id": "crea"},
{"x":900,"y":500,"width": 150, "height": 150, "nx":1150, "ny":350, "class":"dev", "name": "Développements techniques"},
{"x":1150,"y":350,"width": 100, "height": 100, "nx":1300, "ny":500, "class":"recette", "name": "Recette"},
{"x":1300,"y":500,"width": 100, "height": 100, "nx":1500, "ny":650, "class":"mel", "name": "Mise en ligne"},
{"x":1500,"y":650,"width": 100, "height": 100, "nx":1500, "ny":650, "class":"garantie", "name": "Garantie"}
];

I think you have the syntax wrong for source functions, as well as the data already being an array, maybe this will work?
var diagonal = d3.svg.diagonal();
groupe.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("d",diagonal
.source(function(d){ return {"x":d.x, "y":d.y};})
.target({x:400, y:300}))
.attr("fill", "none")
.attr("stroke", "#000")
.attr("stroke-width","2");

Related

Plotting nodes and links from JSON files with SVG

I'm new to D3 and I'm having trouble visualising my json file. I'm supposed to plot the locations (sites) as circles with their radius equal to the "amount". I'm extremely confused about how to work with the nodes and links. I have provided an example of the JSON code as well. Please help me understand where I am going wrong with the coding
<html>
<head>
<title>D3 Visualisation </title>
<h1> Trading Data </h1>
<style>
.svgCanvas {
border: solid 1px
}
</style>
</head>
<body>
<svg></svg>
<script src="https://d3js.org/d3.v4.min.js"></script> <script>
window.onload = function(){
var width = 800;
var height = 300;
var thisCanvas = d3.select("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "svgCanvas");
d3.json("data.json", function(d){
console.log(d);
var svgCanvas.selectAll("circle")
.data(d).enter()
.append("circle")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return d.amount; } )
.style("fill", “lightgreen”); })
})
}
</script>
</body>
</html>
The Json code example is as follows:
{
"nodes": [
{
"id": "site09",
"x": 317.5,
"y": 282.5
},
{
"id": "site01",
"x": 112,
"y": 47
},
{
"id": "site03",
"x": 69.5,
"y": 287
}
],
"links": [
{"node01": "site05", "node02": "site08", "amount": 10},
{"node01": "site05", "node02": "site02", "amount": 120},
{"node01": "site05", "node02": "site03", "amount": 50}
]
}
Here you can get the working solution. Just replace the data object with json.
https://playcode.io/324480?tabs=console&script.js&output

Creating line chart with d3 getting error

In the following example I am using a lineFunction for plotting co-ordinates for the path. I hope to enter code correctly, still facing error. Can someone help?
SNIPPET:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>
<script>
$(document).ready(function(){
//our basic data
var customData = [
{"x": 100, "y": 100},
{"x": 200, "y": 50},
{"x": 300, "y": 150},
{"x": 400, "y": 20}
];
//the line function for path
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
//Main svg container
var mySVG = d3.select("svg");
//defining the lines
var path = mySVG.append("path");
//plotting lines
path
.attr("d", lineFunction(customData))
.attr("stroke",function() { return "hsl(" + Math.random() * 360 + ",100%,50%)"; })
.attr("stroke-width", 2)
.attr("fill", "none");
});
</script>
</head>
<body>
<svg width="500px" height="500px"></svg>
</body>
</html>
ERROR:
var lineFunction = d3.svg.line() //error here ...
Looks like versioning issue for me take look at this -
$(document).ready(function(){
//our basic data
var customData = [
{"x": 100, "y": 100},
{"x": 200, "y": 50},
{"x": 300, "y": 150},
{"x": 400, "y": 20}
];
//the line function for path
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
//Main svg container
var mySVG = d3.select("svg");
//defining the lines
var path = mySVG.append("path");
//plotting lines
path
.attr("d", lineFunction(customData))
.attr("stroke",function() { return "hsl(" + Math.random() * 360 + ",100%,50%)"; })
.attr("stroke-width", 2)
.attr("fill", "none");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="//d3js.org/d3.v3.min.js"></script></script>
<svg width="500px" height="500px"></svg>
As Chetan already mentioned, it's a version problem of your included D3 file. You are including D3 V4 but using the syntax of D3 V3.
Within V4 they removed d3.svg. So everything you have to do is to change d3.svg.line() to d3.line() and it should work.
Ref: d3.svg.line() error: Uncaught TypeError: Cannot read property 'line' of undefined
EDIT-1: try this code Snippet
var svg;
//The data for our line
var lineData = [ { "x": 1, "y": 5}, { "x": 20, "y": 20},
{ "x": 40, "y": 10}, { "x": 60, "y": 40},
{ "x": 80, "y": 5}, { "x": 100, "y": 60}];
//This is the accessor function we talked about above
var lineFunction = d3.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; });
//The SVG Container
var svgContainer = d3.select("body").append("svg:svg")
.attr("width", 200)
.attr("height", 200);
//The line SVG Path we draw
var lineGraph = svgContainer.append("path")
.attr("d", lineFunction(lineData))
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "none");

d3js force button to allow/disable drag actions

My goal is to allow or disable the drag action on the nodes of my graph. I have this input : <input id="drag" name="drag" type="button" value="switch drag" />. I found some hints here and on this question.
As I said in a comment below, it doesn't work if I create nodes and links from an external json file. Is my function d3.json("graph.json", function(error, graph) {...}); not correct ?
Here's my json file:
{
"nodes": [
{"x": 260, "y": 210, "fixed": true},
{"x": 300, "y": 210, "fixed": true},
{"x": 260, "y": 260, "fixed": true},
{"x": 300, "y": 260, "fixed": true}
],
"links": [
{"source": 0, "target": 1},
{"source": 0, "target": 2},
{"source": 2, "target": 3},
{"source": 3, "target": 1}
]
}
And here's my code :
var width = 960, height = 500;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var myLinks = svg.selectAll(".link");
var myNodes = svg.selectAll(".node");
var force = d3.layout.force()
.size([width, height])
.charge(-400)
.linkDistance(40)
.on("tick", tick);
// Allows the drag actions
var drag = force.drag();
// Read the json file and creates the links and the nodes
d3.json("graph.json", function(error, graph) {
if (error) alert(error);
force
.nodes(graph.nodes)
.links(graph.links)
.start();
myLinks = myLinks.data(graph.links)
.enter()
.append("line")
.attr("class", "link");
myNodes = myNodes.data(graph.nodes)
.enter()
.append("circle")
.attr("class", "node")
.attr("r", 6)
.call(drag);
});
// Add properties to myLinks and myNodes
function tick() {
myLinks.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
myNodes.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
var dragOnOff = d3.select("#drag");
dragOnOff.on("click", function() {
myNodes.on('mousedown.drag', null);
});
var dragOnOff = d3.select("#drag");
var dragCallback = myNodes.property('__onmousedown.drag')['_'];
var draggable = true;
dragOnOff.on("click", function () {
myNodes.on('mousedown.drag', draggable ? null : dragCallback);
this.value = 'switch drag to ' + draggable;
draggable = !draggable;
});
I wish someone could answer me and my post can help someone else !
Thanks in advance!
Use on "click" for buttons instead of on "input".
var dragOnOff = d3.select('#drag');
var draggable = true;
dragOnOff.on('click', function () {
myNodes.on('mousedown.drag', draggable ? null : dragCallback);
draggable = !draggable;
});
http://jsfiddle.net/77yndu1e/2/

Updating D3 data doesn't remove old data from faux-3d example

I am working on extending the example found here. I have a data source that will pull in data for different periods of time. The data is as expected and draws well individually. I added a timer to iterate through the result set. The following code is in the original example. There are three calls points, flyers, arcLines (only flyers is shown below)
svg.append("g").attr("class","flyers")
.selectAll("path").data(links)
.enter().append("path")
.attr("class","flyer")
.attr("d", function(d) { return swoosh(flying_arc(d)) })
I changed the code to this to allow updates and they kind of work. The lines/points/flyers are removed and only the data from the time interval are displayed.
var flyer_data = svg_flyers
.selectAll("path").data(links);
flyer_data
.exit().remove();
flyer_data
.enter().append("path")
.attr("class", "flyer")
.attr("d", function(d) {
return swoosh(flying_arc(d))
});
Now the data isn't displayed correctly when the points and lines are supposedly in focus. Only data that is right on the horizon is displayed before its clipped. There is another side effect of the above code. The bound data structure is changed correctly but the SVG gets more and more points/lines/arcs which are not displayed. This last observation is particular baffling with the ever growing SVG definitions. It slows down the browser after a few minutes.
I have created a gist with enough code to demonstrate the issue. The Gist can be found here.
Your link to gist isn't working.
However, depending on your situation you can select your object (in this case your path) by class or id. In the example I've provided you can give your path an id and refer to it.
var lineData = [ { "x": 1, "y": 5}, { "x": 20, "y": 20},
{ "x": 40, "y": 10}, { "x": 60, "y": 40},
{ "x": 80, "y": 5}, { "x": 100, "y": 60}];
var lineData2 = [ { "x": 5, "y": 1}, { "x": 20, "y": 20},
{ "x": 10, "y": 40}, { "x": 40, "y": 60},
{ "x": 5, "y": 80}, { "x": 60, "y": 100}];
var lineFunction = d3.svg.line()
.x(function(d) { return d.x; })
.y(function(d) { return d.y; })
.interpolate("linear");
d3.select("svg")
.append("path")
.attr("id", "MyUniqueId")
.attr("d", lineFunction(lineData));
d3.select("#MyUniqueId")
.transition()
.duration(5000)
.attr("d", lineFunction(lineData2));
See js fiddle:
http://jsfiddle.net/3M54q/3/

Accessing JSON values in D3

I'm trying to populate each group with a circle for "Forehand" / "Backhand" and "BH slice" but i'm having difficulties accessing these values. I have nested the elements in a way that the "Direction" is the Key so the related values will eventually influence the position and the size of each circle.
In a way it is similar to https://github.com/mbostock/d3/wiki/Selections#data the matrix example I guess but the data structure is different ?
JSbin of the current code here: http://jsbin.com/gahul/1
I have the following data:
var JSONdata = [
{
"Direction": "Crosscourt",
"Total": 118,
"Forehand": 75,
"Backhand": 41,
"BH slice": 2
}, {
"Direction": "Down_middle",
"Total": 50,
"Forehand": 34,
"Backhand": 9,
"BH slice": 7
}, {
"Direction": "Down_line",
"Total": 21,
"Forehand": 8,
"Backhand": 11,
"BH slice": 2
}, {
"Direction": "Inside_out",
"Total": 118,
"Forehand": 25,
"Backhand": 5,
"BH slice": 0
}, {
"Direction": "Inside_in",
"Total": 9,
"Forehand": 9,
"Backhand": 0,
"BH slice": 0
},
];
And the following d3 code:
var query1 = d3.nest()
.key(function(d){
return d.Direction;
})
.sortKeys(d3.ascending)
.entries(JSONdata)
var h = 420;
var w = 500;
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var group = svg.selectAll("g")
.data(query1)
.enter()
.append("g")
.attr("class", function(d){ return d.key })
var pop_directions = group.selectAll("circle")
.data(query1)
.enter()
.append("circle")
.attr("r", 30 )
.attr("cx", 100)
the values of your new object are in an array with one element, which you have to adress, for instance:
d.values[0].Forehand
gives you the forehand-value, while you can access your key-value by
d.key
see http://jsbin.com/hakamoga/1/edit for a simple example using the forehand-value as radius and title.

Categories