D3 - How to call an array for a tooltip - javascript

I am trying to make it so that the name of each item shows up in the tooltip when you hover. I am sure there is a straightforward answer to this, but I am new to D3 so I am not sure what it is.
Example here: http://www.chloesilver.ca/favouritethings/object/
You can see that when you hover, some crazy code shows up so I obviously did it wrong.
In the D3 script, I did this:
$('svg circle').tipsy({
gravity: 'w',
html: true,
title: function() {
var o = colors.domain;
return o;
}
});
Where I am trying to call a specific domain label that was specified previously in the code. I was able to do this with a CSV, but the sticky bit here is that all the information is held within the script inside the HTML document.

Delete the code for the tooltips and after line 236: .call(force.drag) add the following:
.on("mouseover", function(d) {
$(this).tipsy({
gravity: 'w',
html: true,
title: function() {
return d.name;
}
})
});
You should now see the name of each item as a tooltip.

Related

angular directive d3 stuck when hidden on mobile

I have a simple directive that renders a d3 svg word cloud.
The directive should be visible only on desktop, so I remove it on mobile with bootstrap class: "xs-hidden"
the problem is the browser tab gets stuck as angular probably looks for the directive but cant find it.
I altered and added the render method of the directive scope,
the tab gets stuck when we call
layout.start();
only when the div is hidden with "hidden-xs"
** tab gets stuck means - it simply shows "loading" the page is loaded but the page is stuck, I cant refresh, I need to close the tab.
some code:
link: function(scope, element, attrs) {
//stuff....
scope.render(['word', 'word2']);
scope.render = function(words) {
if (!words || !words.length) return;
var maxSize = d3.max(words, function(d) { return d.count; });
var minSize = d3.min(words, function(d) { return d.count; });
var fontScale = d3.scale.linear()
.domain([minSize, maxSize])
.range([16, 40]);
var layout = d3.layout.cloud()
.size([svgWidth, 350])
.words(words.map(function(d) {
return {text: d.word, size: d.count};
}))
.padding(10)
.rotate(function() { return 0; })
.font("Arvo")
.fontSize(function(d) { return fontScale(d.size) })
.fontWeight(700)
.spiral('rectangular')
.on("end", draw);
//when this is called the tab get stuck and must be closed
layout.start();
function draw(words) {
//dont care
}
}
Have you checked if your element where word cloud needs to be rendered is present in DOM or not ?
The class you mentioned has:
.hidden-xs {
display: none !important;
}
So element may not be in DOM when you try to render the word cloud.

Selecting SVG with D3

I have the following function:
function myfunc(d) {
var svg = d3.select('.map-wrap svg');
console.log('svg is:');
console.log(svg);
// interesting stuff happens later ...
}
I call that function on a mouseover event. Here is code where myfunc is supposed to be called.
myChart.width(800)
.height(800)
.dimension(xDim)
.group(xDimGrp)
.projection(projection)
.colors(quantize)
.colorDomain(quantize.domain())
.colorCalculator(function (d) { return d ? getColorClass(myChart.colors()(d)) : '#ccc'; })
.overlayGeoJson(map.features, 'states', function (d) {
return d.properties.state;
}).on('mouseover', myfunc);
When I print out svg I expect to see this:
instead, I see the following:
I see 0: null instead of 0: svg, why is this happening? How can I select the SVG in a way that will give me what is shown in first picture?
.map-wrap is like so:
It was as Cyril said, after debugging better, I realised that it was indeed being called before the creation of the svg element.

How can I add a transition effect to a radius increase on a circle?

I have the following code that allows me to increase the size of a circle when it is clicked. I want to add a transition effect, but it isn't working:
D3.js
d3.selectAll(".bubble-node")
.on("click", function (d) {
$("#circle-" + d.id).transition().duration(1000).attr("r", r);
d.forceR = r; // forceR is a property on the data object
});
HTML/svg
<a class="bubble-node" id="bubble-id-3" style="fill: #62d5f4">
<circle id="circle-8" r="65"></circle>
</a>
What am I missing?
not sure exactly you're trying to do but i think the selector is wrong for d.id
try using this.id
$(".bubble-node")
.on("click", function (d) {
$("#circle-" + this.id).transition().duration(1000).attr("r", r);
d.forceR = r; // forceR is a property on the data object
});
but then the id would not match up when you concatenate "#circle-bubble-id-3" doesn't exist in the DOM. So you might want to change the id of the A element to "8" then it would concatenate to "#circle-8" effectively selecting your circle object.
Also if you're using jQuery I would stick with animate() unless transition() is a plugin you're using.

Making charts clickable

I am just learning and trying to code it at the same time, this is the code I have, If I take out the drill method and take out the .click(drill) then everything works so far, it draws some silly bar charts from the data I am sending to it
$( document ).ready(function() {
var dataset = gon.data;
d3.select("body").selectAll("div")
.data(dataset)
.enter()
.append("div")
.attr("class", "bar")
.click(drill)
.style("height", function(d) {
return d.brand_name + "px";
});
function drill (event) {
var target = event.currentTarget;
var data = $(target).data();
console.log(data);
}
});
But I am not able to add "click" event to those bar charts such that when I click on them I can know which chart I clicked on. The code above is result of my unsuccessful attempt to add "click" event to the charts I have drawn .... What is the correct way?
You can use .on("click", drill) if you want D3 to pass the object and data attached.
function drill(d, i) {
console.log(d); //data object
console.log(i); //array position
console.log(this); //DOM element
}
You can also use .attr("onclick", "drill()") syntax if you want to follow the standard HTML without the D3 wrapper.

How to invoke "click" event programmatically in d3?

I'm trying like that (also at https://gist.github.com/1703994):
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?1.27.2"></script>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.time.js?1.27.2"></script>
<script type="text/javascript" src="js-libs/jquery-1.7.js"></script>
<style>
<!--
#test {
width: 400px;
height: 500px;
}
-->
</style>
</head>
<body>
<script type="text/javascript">
$(function() {
var w = 600,
h = 350;
var vis = d3.select("#test").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");
var g = vis.selectAll("g")
.data([ { x:1 , y: 2} ])
.enter().append("svg:g");
g.append("svg:path")
.attr("fill", "red")
.attr("stroke", "red")
.attr("stroke-width", "10")
.attr("d", "M 100 350 l 150 -300")
g.select("path")
.on("click", function() { console.log("Hello"); });
// XXX: how to execute click programmaticaly?
})
</script>
<div id="test"></div>
</body>
</html>
But doesn't work
I think we may use https://github.com/mbostock/d3/wiki/Internals#wiki-dispatch_on
But how to do it?
not sure why, but there appears to be a discrepancy with the way jQuery and d3 handle events that causes a jQuery induced click event $("#some-d3-element").click() to not dispatch to the d3 element.
a workaround:
jQuery.fn.d3Click = function () {
this.each(function (i, e) {
var evt = new MouseEvent("click");
e.dispatchEvent(evt);
});
};
and then call it:
$("#some-d3-element").d3Click();
Simply call the .on method as a getter for the registered value (i.e. your handler function), then call the result of that:
g.select("path").on("click")();
It gets a little more complicated if your handler uses the bound data and/or event fields, or if you've got multiple event listeners bound (e.g "click.thing1" and "click.thing2"). In that case, you're probably best off just firing a fake event using the standard DOM methods:
var e = document.createEvent('UIEvents');
e.initUIEvent('click', true, true, /* ... */);
g.select("path").node().dispatchEvent(e);
With D3 v4 you will likely want this:
d3.select('#some-id').dispatch('click');
Ref.: https://github.com/d3/d3-selection#selection_dispatch
This works. I'm using pie charts, so I'm selecting all the "selected" pie slices, and for each of them, retrieving the attached "click" callback (that I have attached in another portion of code not included here, using d3's .on() method) and then invoking with the expected parameters in the correct context.
d3.selectAll("g.selected").each(function(d, i) {
var onClickFunc = d3.select(this).on("click");
onClickFunc.apply(this, [d, i]);
});
This answer might be somewhat unrelated - but hopefully useful to someone searching for how to invoke a click event of a SVG element - since jQuery $(mySvgElement).trigger("click") won't work.
This is how you would programmatically trigger/invoke/raise a click event for a SVG element:
var ev = document.createEvent("SVGEvents");
ev.initEvent("click",true,true);
var target = $("svg>g>path[fill='#0011cc']").get(0); // get the SVG element here
target.dispatchEvent(ev); // like $(target).trigger('click') - but working!
I came this thread looking for a d3 mousemove event for angular unit testing.
#natevw answer
g.select("path").on("click")();
helped a lot on mouseover event. But, applying that to mousemove was giving an e.source null error.
The work around was to set the d3 event programmatically.
d3.event = document.createEvent('MouseEvent');
d3.event.initMouseEvent("mousemove");
d3.select(elm[0]).select("rect").on("mousemove")();
Hope this helps.
You can go super manual by getting the mouse event and passing it the arguments that d3 would otherwise provide for you. This gives you a fairly clean way to do it while still using d3 constructs. For a single element use the following:
var path = g.select('path');
path.on('click').call(path.node(), path.datum());
For multiple elements, you can trigger each one in turn:
g.selectAll('path').each(function(d, i) {
d3.select(this).on('click').apply(this, arguments);
});
The latter can also be used for a single element if your selector is specific enough, or if you use .select() instead of .selectAll() to only return the first element.
#handler answer did not work for me entirely. It would click the svg element but additional simulated events would not register. This is what worked for me:
function eventFire(el, etype){
if (el.fireEvent) {
el.fireEvent('on' + etype);
} else {
var evObj = document.createEvent('Events');
evObj.initEvent(etype, true, false);
el.dispatchEvent(evObj);
}
}
Usage:
eventFire(document.getElementById(element_id), 'click');
This is how I do it.
g.selectAll("path").on("click", function(d, i){
my_function(d, i);
});
I've found the the callbacks work with anonymous functions. So for the code above, any path that is clicked will call my_function and pass in the current datum d and index i of the path that was clicked.
I find next workaround:
d3.selectAll("path").each(function(d, i) {
onClickFunc.apply(this, [d, i]);
});
Where d is data and i is index this data
Try g.select("path").trigger("click")

Categories

Resources