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.
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.
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.
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.
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")