change the word cloud when the onchange functions is triggered - javascript

I want to change the word cloud when the onchange functions is triggered.
in my current scriupt bellow, when I change the selection from the drop down list the other image shows up on my chrome windows, I think this might have something to do with this like d3.select("body").append("svg")
How can I show one wordcloud at a time and not append to the current windows?
I tried d3.select("body") = "svg" instead but didn't work, I tried to remove empty clear the screen body element and then shows up the word cloud didn't work too.
Any hint will be highly appreciated!
Thanks!
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="js/d3.js"></script>
<script src="js/d3.layout.cloud.js"></script>
<script>
function displayResult()
{
//location.reload();
//var e = document.getElementsByTagName('svg');
//e.removeChild(document.body.svg);
var client_name=document.getElementById("client_name");
var client_nameSelected = client_name.options[client_name.selectedIndex].value;
//alert(client_nameSelected);
var fill = d3.scale.category20();
//var ClientName = {"Hello":0.10 , "world":0.20, "normally cool!":0.25, "you":0.15, "want":0.60, "more":0.45, "words":0.90 };
var data = { 'name1':{"Hello":0.10 , "world":0.20, "normally cool!":0.65, "you":0.15, "want":0.60, "more":0.85, "words":0.90 }, 'name2':{"Hello":0.10 , "world":0.20, "normally cool!":0.25, "you you":0.15, "Hug":0.99, "more feedback":0.45, "words":0.90 }};
var ClientName = data[client_nameSelected];
var keysdic = Object.keys(ClientName);
//document.write(keysdic);
d3.layout.cloud().size([600, 600])
.words( [].concat(keysdic)
.map(function(d) {
var wordsize = 10 + ClientName[d] * 40 ;
result = {text: d, size: wordsize };
return result;
}))
.padding(5)
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.fontSize(function(d) { return d.size; })
.on("end", draw)
.start();
function draw(words) {
d3.select("body").append("svg")
.attr("padding", 60)
.attr("width", 600)
.attr("height", 600)
.append("g")
.attr("transform", "translate(150,150)")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact")
.style("fill", function(d, i) { return fill(i); })
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
}
</script>
<body>
Client Name List :
<select name = 'client_name' id = "client_name" onchange="displayResult();" >
<option value='name1'>name1</option>
<option value='name2'>name2</option>
</select><br />
<body>

Related

How can I make dragged text element in the right position?

Currently I'm working on a small project. At this stage I have several word cloud SVGs with the help of d3.js word cloud.
Now I want to make the SVG's 'text' element draggable with JQuery UI so that user can drag the text element and then drop it on certain area (say a droppable div).
But after several attempts, it seems that JQuery-UI is not that compatible with SVG. I've compared several similar questions and tried on my own code, but none of them worked. The most up-voted answer of this question is very close to what I want. The text element is draggable, but when I click the element, it doesn't appear in the right position and it would appear elsewhere. And also the element cannot be dragged out of its SVG container.
Here's my JS code:
var fill = d3.scale.category20();
function draw(words) {
d3.select('#wordCloud').append("svg")
.attr("width", 600)
.attr("height", 600)
.append("g")
.attr("transform", "translate(300,300)")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact")
.style("fill", function(d, i) { return fill(i); })
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
wordCloudData.map((model) => {
let modelName = model.modelName;
let wordsArray = model.specArray;
var $title = $('<h4></h4>').text(modelName);
$('#wordCloud').append($title);
d3.layout.cloud().size([600, 600])
.words(wordsArray.map(function(d) {
return {text: d, size: 10 + Math.random() * 90};
}))
// .rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.fontSize(function(d) { return d.size * 0.6; })
.on("end", draw)
.start();
});
$(document).ready(function() {
let wordCloudCount = $('#wordCloud svg').length;
let svgArray = $('#wordCloud svg').clone();
let titleArray = $('#wordCloud h4').clone();
for (let i = 0; i < wordCloudCount; i++) {
let $wordCloudDiv = $('<div></div>').attr('class', 'wordCloud');
let $title = titleArray[i];
let $svg = svgArray[i];
$wordCloudDiv.append($title);
$wordCloudDiv.append($svg);
$('#wordCloudFinal').append($wordCloudDiv);
}
$('#wordCloud').hide();
$('text')
.draggable()
.bind('mousedown', function(event, ui){
$(event.target.parentElement).append( event.target );
})
.bind('drag', function(event, ui){
event.target.setAttribute('x', ui.position.left);
event.target.setAttribute('y', ui.position.top);
});
});
Here is my HTML code:
<div class="container">
<div id="wordCloud"></div>
<div id="wordCloudFinal"></div>
</div>

line break in d3 tag Cloud

I am using it to generate a heavy amount of words in my application and I grab data from a json file like below:
var a = [];
for (var i=0; i < a.length; i++){
a.push(a[i].word);
}
And this gives us an array.
a = ["gsad","sagsa","gsag","sagas","gsag","gsagas","yhff","gag"];
I have it display on the screen correctly but since the row is too long it got out from the border and I'd like to give it a link break instead of change the SVG size, How may i do this?
UPDATE:
The code below is how i insert my codes:
var PositiveArr = ["gsad","sagsa","gsag","sagas","gsag","gsagas","yhff","gag"]; //consider the NegativeArr,NeutralArr have the similar contents
var fill = d3.scale.category20();
d3.layout.cloud().size([600, 300])
.words([NegativeArr,NeutralArr,PositiveArr].map(function(d) {
return {text: d, size: 10 + Math.random() * 50};
}))
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.fontSize(function(d) { return d.size; })
.on("end", draw)
.start();
function draw(words) {
d3.select("#pre-theme").append("svg")
.attr("width", 600)
.attr("height", 300)
.append("g")
.attr("transform", "translate(300,150)")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact, Arial")
.style("fill", function(d, i) { return fill(i); })
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
SOLUTION:
I have found myself a solution, i just merge all my arrays into one using
var allResult = PersonsArr.concat(PlacesArr,PatternsArr,ProductsArr,CompaniesArr);
and insert the to the .map like
.words(entityResult.map(function(d) {
return {text: d, size: 10 + Math.random() * 50};
}))
SOLUTION: I have found myself a solution, i just merge all my arrays into one using
var allResult = PersonsArr.concat(PlacesArr,PatternsArr,ProductsArr,CompaniesArr);
and insert the to the .map like
.words(entityResult.map(function(d) {
return {text: d, size: 10 + Math.random() * 50};
}))

Getting Sankey diagram in D3 from csv file

I am attempting to create a Sankey diagram from a csv file. I am utilizing code provided by timelyportfolio, and also the code from the d3 site (and even the sample csv files). However, when I try to run the code in Chrome, I am getting a blank Html page, indicating that the code is crashing. I attempted to redirect the source codes to files on my desktop, but I am still running into the same issues. (I am working on a computer with Windows XP)
I have pasted the code below:
<!DOCTYPE html>
<meta charset="utf-8">
<title>SANKEY Experiment</title>
<style>
.node rect {
cursor: move;
fill-opacity: .9;
shape-rendering: crispEdges;
}
.node text {
pointer-events: none;
text-shadow: 0 1px 0 #fff;
}
.link {
fill: none;
stroke: #000;
stroke-opacity: .2;
}
.link:hover {
stroke-opacity: .5;
}
</style>
<body>
<p id="chart">
<script src="http://d3js.org/d3.v3.js"></script>
<script src="C:\Documents and Settings\jennifer.ducz\Desktop\sankey.js"></script>
<script>
var units = "Units";
var margin = {top: 10, right: 10, bottom: 10, left: 10},
width = 1400 - margin.left - margin.right,
height = 740 - margin.top - margin.bottom;
var formatNumber = d3.format(",.0f"), // zero decimal places
format = function(d) { return formatNumber(d) + " " + units; },
color = d3.scale.category20();
// append the svg canvas to the page
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Set the sankey diagram properties
var sankey = d3.sankey()
.nodeWidth(36)
.nodePadding(10)
.size([width, height]);
var path = sankey.link();
// load the data with d3.csv instead of d3.json
//for another much simpler example uncomment the below
d3.csv("C:\Documents and Settings\jennifer.ducz\Desktop\sankey.csv", function(error, data) {
//d3.csv("d3noob_energy.csv", function(error, data) {
//set up graph in same style as original example but empty
graph = {"nodes" : [], "links" : []};
data.forEach(function (d) {
graph.nodes.push({ "name": d.source });
graph.nodes.push({ "name": d.target });
graph.links.push({ "source": d.source, "target": d.target, "value": +d.value });
});
//thanks Mike Bostock https://groups.google.com/d/msg/d3-js/pl297cFtIQk/Eso4q_eBu1IJ
//this handy little function returns only the distinct / unique nodes
graph.nodes = d3.keys(d3.nest()
.key(function (d) { return d.name; })
.map(graph.nodes));
//it appears d3 with force layout wants a numeric source and target
//so loop through each link replacing the text with its index from node
graph.links.forEach(function (d, i) {
graph.links[i].source = graph.nodes.indexOf(graph.links[i].source);
graph.links[i].target = graph.nodes.indexOf(graph.links[i].target);
});
//now loop through each nodes to make nodes an array of objects rather than an array of strings
graph.nodes.forEach(function (d, i) {
graph.nodes[i] = { "name": d };
});
sankey
.nodes(graph.nodes)
.links(graph.links)
.layout(32);
// add in the links
var link = svg.append("g").selectAll(".link")
.data(graph.links)
.enter().append("path")
.attr("class", "link")
.attr("d", path)
.style("stroke-width", function(d) { return Math.max(1, d.dy); })
.sort(function(a, b) { return b.dy - a.dy; });
// add the link titles
link.append("title")
.text(function(d) {
return d.source.name + " → " +
d.target.name + "\n" + format(d.value); });
// add in the nodes
var node = svg.append("g").selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"; })
.call(d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", function() {
this.parentNode.appendChild(this); })
.on("drag", dragmove));
// add the rectangles for the nodes
node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) {
return d.color = color(d.name.replace(/ .*/, "")); })
.style("stroke", function(d) {
return d3.rgb(d.color).darker(2); })
.append("title")
.text(function(d) {
return d.name + "\n" + format(d.value); });
// add in the title for the nodes
node.append("text")
.attr("x", -6)
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "end")
.attr("transform", null)
.text(function(d) { return d.name; })
.filter(function(d) { return d.x < width / 2; })
.attr("x", 6 + sankey.nodeWidth())
.attr("text-anchor", "start");
// the function for moving the nodes
function dragmove(d) {
d3.select(this).attr("transform",
"translate(" + (
d.x = Math.max(0, Math.min(width - d.dx, d3.event.x))
) + "," + (
d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))
) + ")");
sankey.relayout();
link.attr("d", path);
}
});
</script>
</body>
</html>
If someone can tell me what I'm doing wrong, please let me know.
Edit: This is the sample data I'm using courtesy of timelyportfolio
source target value
Barry Elvis 2
Frodo Elvis 2
Frodo Sarah 2
Barry Alice 2
Elvis Sarah 2
Elvis Alice 2
Sarah Alice 4
I've never played with it; however,
1) run your developer tools/console to see exactly which line is crashing the app
2) the following link discusses problems/solutions in formatting the data
http://www.d3noob.org/2013/02/sankey-diagrams-description-of-d3js-code.html
if you are not using MAMP or any other kind of virtual server, Chrome won't load the csv or any other local files other than the html. Try using a local webserver and everything should be fine

TypeError: d3.layout.cloud is not a function

I am copying code from here. My code is essentially identical to the example code except I am running d3.layout.cloud.js on my server. When I run it I am getting a type error that d3.layout.cloud is not a function. What could be the reasons for this?
<!DOCTYPE html>
<meta charset="utf-8">
<script src="../lib/d3/d3.js"></script>
<script src="../d3.layout.cloud.js"></script>
<body>
<script>
var fill = d3.scale.category20();
d3.layout.cloud().size([300, 300])
.words([
"Hello", "world", "normally", "you", "want", "more", "words",
"than", "this"].map(function(d) {
return {text: d, size: 10 + Math.random() * 90};
}))
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.fontSize(function(d) { return d.size; })
.on("end", draw)
.start();
function draw(words) {
d3.select("body").append("svg")
.attr("width", 300)
.attr("height", 300)
.append("g")
.attr("transform", "translate(150,150)")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact")
.style("fill", function(d, i) { return fill(i); })
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
</script>
Are you sure you've put d3.cloud.layout.js in the correct folder on your server?
I edited your code to point to files that do exist:
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="https://gist.github.com/emeeks/3361332/raw/61cf57523fe8cf314333e5f60cc266351fec2017/d3.layout.cloud.js"></script>
And it seems to work:
http://jsfiddle.net/fHBsS/
To see if this is causing your problem, open the console in chrome (ctrl-shift-j) and see if there are any "Failed to load resource" errors.
This happened to me because I was loading the cloud layout JS before D3. D3 should be loaded first to fix.

Updating D3 circle pack layout

I'm trying to dynamically update a d3 circle pack layout with data I receive in json. Every second I call d3.json() to get the new json. Instead of updating the existing visualization, my implementation just creates a new one under the old one. I want to to dynamically update the existing layout instead...
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="d3.v2.js">
</script>
<script type="text/javascript" src="jquery-1.4.min.js"></script>
<link rel="stylesheet" href="style.css" type="text/css">
<link rel="stylesheet" href="syntax.css" type="text/css">
<link rel="stylesheet" href="pack.css" type="text/css">
</head>
<body>
<div id="chart"> </div>
<script type="text/javascript">
var width = 960,
height = 960,
format = d3.format(",d");
var pack = d3.layout.pack()
.size([width - 4, height -4])
.value(function(d) { return d.size; });
var vis = null;
var node = null;
vis = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "pack");
/* vis.append("g")
.attr("transform", "translate(2, 2)"); */
function update(json){
// Creating the circle packed core
var gNodes = vis.data([json]).selectAll("g.node")
.data(pack.nodes);
//remove old data
gNodes.exit().remove();
}
setInterval(function(){
d3.json("http://10.0.1.4:8080/cluster", function(json) {
update(json);
//update the visualization
vis
.selectAll("circle")
.data([json]).selectAll("g.node")
.data(pack.nodes)
.attr("class", function(d) { return d.children ? "node" : "leaf node"; })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.transition()
.duration(500)
.attr("r", function(d) { return d.children ? coreSize : d.r; });
var node = gNodes
.enter().append("g")
.attr("class", function(d) { return d.children ? "node" : "leaf node"; })
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.append("title")
.text(function(d) { return (d==null? "": d.name + (d.children ? "" : ": " + format(d.size))); });
node.append("circle")
.attr("r", function(d) { return (d==null? 0: d.r); });
node.filter(function(d) { return (d==null? "" : !d.children); }).append("text")
.attr("text-anchor", "middle")
.attr("dy", ".3em")
.text(function(d) { return (d==null?"":d.name.substring(0, d.r / 3)); });
});
}, 1000);
</script>
Take a look at my example here.
Basically, there is code for initial load, where all circles, tooltips, etc. are created and positioned in initial places. As well, the layout (pack) is created.
Than, on each button press, new data is loaded into pack, and the pack is recalculated. That crucial code is here:
if (dataSource == 0)
pack.value(function(d) { return d.size; });
if (dataSource == 1)
pack.value(function(d) { return 100; });
if (dataSource == 2)
pack.value(function(d) { return 1 +
Math.floor(Math.random()*501); });
var data1 = pack.nodes(data);
( I have three buttons, thats why 3 ifs)
After that, elements are tranistioned to new positions, and its attributes are changed as you determine.
Here are some pics with transition in action:
Start:
Transition:
End:

Categories