Adding tool-tip to an image rendered using Highcharts Renderer.image() api - image

I wanted to add a tool-tip to an image that is rendered using:
image (String source, Number x, Number y, Number width, Number height) api.
I couldn't figure out a way to do this, I am using org.moxieapps.gwt.highcharts API's to
create high charts in my GWT app.

Use chart.renderer.text and chart.renderer.rect to draw and position your own custom tooltip based on the position of the image.
This is a sample code snippet I used to display a tooltip for an image which is generated using chart.renderer.image -
marker = chart.renderer.image(src, x, y, imageSize, imageSize)
.on('click', function() {`enter code here`
})
.attr({
zIndex: 100
})
.on('mouseover', function() {
//Call back for image mouse hover
//Draw a text relative to Image X and Y
text = chart.renderer.text("Your tooltip Text",X, Y)
.add();
var box = text.getBBox();
//Now draw a box surrounding the tool tip text
textBG = chart.renderer.rect(box.x, box.y,box.width, box.height, 5)
.attr({
fill: '#FFFFEF',
stroke: 'gray',
'stroke-width': 1,
zIndex: 4
})
.add();
})
.on('mouseout', function() {
//Call back for mouse out on the image
//Destroy Both markers text and textBG on mouse out
//Make text and textBG as global functions for access accross functions
text.destroy();
textBG.destroy();
})
.add();
In this way you can create custom tooltip for images.
I used this link for syntax of adding tooltip text and its back ground to the chart.

Related

Disable resize of brush on range chart from focus charts (dc.js, d3.js) - Solved

Please note - there is a solution for part of this problem by Gordon Woodhull in Disable brush on range chart before selecting a scale from the dropdown/on page load(dc.js,d3.js)
In addition,there is a partial solution at the end this question.
Furthermore there are two fiddles:
1) https://jsfiddle.net/dani2011/4dsjjdan/1/
2) https://jsfiddle.net/dani2011/uzg48yk7/1/ (with partial solution)
Need to disable resize of the brush on range chart (timeSlider) by dragging the line within the focus charts (bitChart,bitChart2). As Gordon Woodhull suggested (Disable brush resize (DC.js, D3.js) try to enable only pan without zoom.
Current behavior:
1)
Dragging the line on bitChart2 (focus chart) pans the brush until the borders of the timeChart. Once reaching the borders,the brush shrinks. The other focus chart (bitChart) resizes the brush of the range chart during drag of its line.
2)
When selecting a span for the brush from the dropdown only the .on('zoomed', function (chart, filter) { of bitChart2 is loaded and not the .on("zoomed"... of bitChart.
Print screens from the console:
a) Selecting scale from the dropdown
b) Dragging line on bitChart:
c) Dragging line on bitChart2:
3)
For both bitChart and bitChart2 the value of scale is 1 and the position
is 0,0:
.on('zoomed', function (chart, filter) {
//var zoom = d3.behavior.zoom()
// .translate([0, 0])
//.scale(1).scaleExtent([1, 1])
var zoom = d3.behavior.zoom()
var scale = zoom.scale(); var position = zoom.translate();
js file
The following implementations did not solve the issue:
**option 1**
bitChart.on('zoomed', function (chart, filter) {
d3.behavior.zoom().on("zoom", null);//doesn't stop zoom
//event needs svg element(tried different options),doesn't work
d3.behavior.zoom().scale(1).scaleExtent([1,1]).translate([0,0]).event(chart.select('g.stack_0')))
**option 2**
//Applied on timeslider,bitChart,bitChart2 to eliminate zoom and
//maintain pan
.zoomScale([1, 1])//dc.js
//And also
.on('zoomed', function (chart, filter) {
bitChart.zoomScale([1, 1]);
//Nothing pans with
chart.focus(chart.xOriginalDomain())
**option 3**
bitChart.on('zoomed', function (chart, filter) {
var svg = d3.select("body")
.append("svg")
.call(d3.behavior.zoom().on("zoom", function () {
svg.attr("transform", "translate(" + d3.event.translate + ")" +"
scale(" + 1 + ")")
}))
//.append("g")
**option 4**
.on('zoomed', function (chart, filter) {
var chartBody = chart.select('g.stack _0');
var path = chartBody.selectAll('path.line').data([extra_data]);
path.enter().append('path').attr({
class: 'line',
});
path.attr('transform', 'translate(0,50)');
**option 5**
bitChart.on('zoomed', function (chart, filter) {
var zoom = d3.behavior.zoom()
.scaleExtent([1, 1])
chart.select('g.stack _0').call(zoom);
zoom.scale(1);
zoom.event(chart.select('g.stack _0'));
**option 6**
bitChart.on('zoomed', function (chart, filter) {
svg.call(d3.behavior.zoom().scale(1));
**option 7**
var min_zoom = 1;
var max_zoom = 1;
var svg = d3.select("body").append("svg");
var zoom = d3.behavior.zoom().scaleExtent([min_zoom, max_zoom])
bitChart.on('zoomed', function (chart, filter) {
svg.call(zoom);
My fiddle:
https://jsfiddle.net/dani2011/4dsjjdan/1/ was forked from https://jsfiddle.net/gordonwoodhull/272xrsat/9/.
When selecting span from the dropdown and clicking on the range chart,The range chart (timeSlider) acts strange on the fiddle, but behaves as expected when run it in my environment. Please note in this fiddle that bitChart2 pans the brush as expected.The resize of the brush when reaching the edge happens in my enviroment. bitChart still resizes the brush.
A partial solution:
To enable multi focus charts on a single range chart as in https://github.com/dc-js/dc.js/blob/master/web/examples/multi-focus.html written by Gordon Woodhull.Used the focus chart which worked properly in my code (bitChart2) as the main reference chart:
bitChart2.focusCharts = function (chartlist) {
if (!arguments.length) {
return this._focusCharts;
}
this._focusCharts = chartlist; // only needed to support the getter above
this.on('filtered', function (range_chart) {
if (!range_chart.filter()) {
dc.events.trigger(function () {
chartlist.forEach(function(focus_chart) {
focus_chart.x().domain(focus_chart.xOriginalDomain());
});
});
} else chartlist.forEach(function(focus_chart) {
if (!rangesEqual(range_chart.filter(), focus_chart.filter())) {
dc.events.trigger(function () {
focus_chart.focus(range_chart.filter());
});
}
});
});
return this;
};
bitChart2.focusCharts([bitChart]);
My second fiddle:
https://jsfiddle.net/dani2011/uzg48yk7/1/ was forked from https://jsfiddle.net/gordonwoodhull/272xrsat/9/.
1) When clicking on the range chart in the fiddle it does not function properly, but works in my environment.
2) The brush does not resize at the edges of the range chart in the fiddle as it does in my environment
3) It does show in the fiddle that the whole range chart is selected when panning/clicking on the lines in the focus charts and when clicking in the range chart
4) It does show in the fiddle that after selecting the brush span from the dropdown, panning the lines in the focus charts moves the brush properly on the range chart.
5) It does show in the fiddle that dragging the brush on the range chart is possible again in no span is selected from the dropdown
Still needs to solve:
1) When reaching the ends of the range chart (timeSlider) the brush resizes
solved by updating versions to be the same as the version of the external resources in the fiddle https://jsfiddle.net/gordonwoodhull/272xrsat/9/. Thank you Gordon!
2) Before selecting a scale from the dropdown:
a) When panning /translating the line of the focus charts(bitChart,bitChart2) the brush resizes
b) It is possible again to drag the brush on the range chart
Any help would be appreciated !

Add graph in dc.js tooltip

I'm building a number of graphs using crossfilter and dc.js. Among others, there is a row chart and an histogram (a bar chart).
What I am trying to do is to create a tooltip on the row chart which will show the histogram.
Looking at this SO-question I saw an example using d3-tip. I have made an attempt in this jsfiddle. However, I cannot see how to embed a div in the tooltip.
Any suggestion? (If using plain d3 is better, I'm ok with that.)
Snippet of code is:
function draw_row(div_id){ ...; return row_chart; }
function draw_hist(div_id){ ...; return bar_chart; }
var rate_chart = draw_row('#rate').title(function(){return'';});
dc.renderAll();
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function () {
// What to put in here???
draw_hist('#distr').render();
return "<div id='distr'>Distribution<br></div>"
});
d3.selectAll("#rate g.row")
.call(tip)
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
Fun project!
Yes, as you noticed, you're not going to be able to render the chart while you're in the .html() callback - that only returns static HTML, and I don't think you can give it an element instead.
So we'll have to find a place to render after the HTML has already been generated. Luckily, d3-tip doesn't try to handle mouse events or anything like that - the code which displays the tip is right there in the code you've posted:
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
So we can wrap tip.show in a function of our own, and then render the chart into the tip once it's on the screen.
We have to watch out because mouseover will fire every time the mouse moves, and we probably don't want to replace the tip-chart until we hover over another bar. So we'll remember the id of the last bar we hovered:
var last_tip = null;
d3.selectAll("#rate g.row")
.call(tip)
.on('mouseover', function(d) {
if(d.key !== last_tip) {
tip.show(d);
draw_hist('#distr').render();
last_tip = d.key;
}
})
.on('mouseout', function(d) {
last_tip = null;
tip.hide(d);
});
Finally, d3-tip needs to know the size of the tip content in order to render in the right place. (If it accidentally renders on top of the element, this can cause horrible flickering when the mouse goes over the tip, registering mouseout on the element.)
So we'll just hard-code that, since we're hard-coding the chart size anyway. 20 extra pixels to fit the title:
.html(function (d) {
return "<div id='distr' style='min-width:300px; min-height: 320px'>Distribution<br></div>"
});
Looks pretty cool with the default translucent black style from d3-tip:
Here's the fork of your fiddle: https://jsfiddle.net/gordonwoodhull/hkx7j3r5/10/

Setting background-color for Forio Contour charts

I'm using the Forio Contour charting library - I can't figure out a way to set the background color for my charts (see jsfiddle). It always inherits the bg of the container div which is not what I want.
http://jsfiddle.net/Y4EVP/1/
$(function () {
var data = [22, 8, 5, 19, 11, 4, 5, 13, 20, 29, 25];
new Contour({
el: '.chart',
})
.cartesian()
.line(data)
.render();
});
Couldn't find any related properties on http://forio.com/contour/documentation.html - am I missing something?
You can do it in two ways:
You could set the background-color to the svg using css, which will set the background for the whole chart (including the axis and labels) if that's what you want
if you want to add a background color just to the plot area (ie, the axis and labels remain with the container's background), you could create an extension that is just a rect with the size of the plot area and then add that new extension to your chart in the correct order, something like:
Contour.export('background', function (color, layer, options) {
layer.enter().append('rect')
.attr('class', 'custom-background')
.attr('x', options.chart.plotLeft)
.attr('y', options.chart.plotTop)
.attr('width', options.chart.plotWidth)
.attr('height', options.chart.plotHeight)
});
now you have control of the background color with css:
.custom-background {
fill: #f00;
opacity: 0.5;
}
Hope this helps

How can i add an image in nvd3 piechart legend?

I want to add an image in nvd3 piechart legend instead of text.
I have this code but it changes only the text in the tooltip with the image. I want to change and the text in the legend with the same image.
var testdata = [
{
key: "<img src="+"./imgs/facebook.jpg"+">",
y: 1
},
{
key: ""<img src="+"./imgs/twitter.jpg"+">"",
y: 2
} ];
nv.addGraph(function() {
var chart = nv.models.pieChart()
.x(function(d) { return d.key})
.labelThreshold(.08)
.showLabels(true)
.color(d3.scale.category10().range())
.donut(true);
chart.pie.donutLabelsOutside(true).donut(true);
d3.select("#mypiechart")
.datum(testdata)
.transition().duration(1200)
.call(chart);
return chart;});
Any ideas?
This is not currently possible with nvd3.js. The tooltip works because the img element you have specified is being set into a div that isn't contained within the svg element. It doesn't work for the legend or chart labels because those are built using svg text elements. In order to show an image within the chart svg we'd need to use an svg image element.
We could build the svg image elements if we hack the nvd3.js code. Here's an outline of what you could do to get the legend working. You could then decide if you'd want to try something similar in the nv.models.pie code for the chart labels or if you'd just want to set chart.showLabels to false in your chart configuration.
Add a new key in your data to provide the image path:
var testdata = [
{
key: "<img src="+"./imgs/facebook.jpg"+">",
y: 1,
image_path: "./imgs/facebook.jpg"
},
{
key: "<img src="+"./imgs/twitter.jpg"+">",
y: 2,
image_path: "./imgs/twitter.jpg"
} ];
Update the nv.models.legend code to show the image:
seriesEnter.append('circle')
.style('stroke-width', 2)
.attr('class','nv-legend-symbol')
.attr('r', 5);
// Add an svg image into the legend
seriesEnter.append('image')
.attr('xlink:href', function(d) { return d.image_path} )
.attr('height',20)
.attr('width',20)
.attr('y', '-10')
.attr('x', '8');
Update the nv.models.legend code to not show the key:
// Don't add the key value into the legend text
//series.select('text').text(getKey);
Update the nv.models.legend code to consider the image width when determining the legend layout:
//seriesWidths.push(nodeTextLength + 28); // 28 is ~ the width of the circle plus some padding
//Include image width...
seriesWidths.push(nodeTextLength + 48);

nvd3.js how to properly redraw chart

I have chart type switcher (pieChart/lineChart), date selector and one svg element.
Changing the chart type or date triggers ajax request (different urls with different response data structure for pie/line) and then redraw my chart. Like this:
buildReport: function (data) {
var that = this;
// Format incoming data to chart's format
this.structure = this.formatters[this.type].call(this, data);
this.svgElem.empty(); // jQuery empty
nv.addGraph(function () {
var chart = nv.models[that.type](); // that.type - pieChart or lineChart
chart.options(that.options[that.type] || {});
d3.select(that.svgElem)
.datum(that.structure)
.transition()
.duration(500)
.call(chart);
return chart;
});
}
This function is called on chart type or date change (ajax request may cache for some conditions). Is it right to use svgElem.empty()? Or there is another way to destruct chart and draw another one?
And some additional questions:
1) How to draw legend in the center bottom of chart? Are there any options for this?
2) How to draw stacked area chart in "Expanded" state by default? I need to hide controls (showContols: false option) and draw expanded stackedArea chart
Thank you
To draw the chart with a style that is not the stacked you can use
chart.style("expand"); // for expanded
chart.style("stream"); // for stream

Resources