Setting background-color for Forio Contour charts - d3.js

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

Related

display tip when mouse is anywhere over line chart

I have a composite line chart.
How can I display the respective values (date and value) when i hover on any place of the chart like below:
var composechart = dc.compositeChart("#test_composed");
composechart
.width(990)
.height(450)
.margins({ top: 50, right: 40, left: 50, bottom: 50 })
.x(d3.scaleTime().domain([new Date(2017, 0, 1), new Date(2019, 10, 30)]))
.rangeChart(xChart)
.elasticY(true)
.xUnits(d3.timeMonths)
.legend(dc.legend().x(80).y(20).itemHeight(13).gap(5))
.renderHorizontalGridLines(true)
.brushOn(false)
.compose([
dc.lineChart(composechart)
.dimension(salesgrafikDim)
.group(salesgrafikGroup,"Sales"),
dc.lineChart(composechart)
.dimension(satisgrafikDim)
.colors('red')
.group(quantitygrafikGroup,"Quantity")
])
xChart
.width(990)
.height(40)
.margins({top: 0, right: 50, bottom: 20, left: 50})
.dimension(salesgrafikDim)
.group(salesgrafikGroup)
.x(d3.scaleTime().domain([new Date(2017, 0, 1), new Date(2019, 10, 30)]))
.xUnits(d3.timeMonths);
xChart.yAxis().ticks(0);
Basically want to display a tooltip like in the screenshot below, where the mouse should not need to be over a dot for it to display.
I can do it with straight D3, with svg and append and so on. But i have dimension with other charts and dataTable, so I want to use this with dc.js.
It would be much more user friendly and easy to understand if you don't have to hover over the dots to see the tip.
My chart is below :
Since dc.js doesn't support this directly, you're going to end up dropping down into D3 in order to implement this.
First, we need to disable the existing titles:
.title(() => '')
and hover events:
composite.on('pretransition', chart => {
chart.children().forEach(
child => child.selectAll('circle.dot')
.on('mousemove', null)
.on('mouseout', null)
);
})
Then we can add a handler to put mouse handlers on the SVG itself
composite.on('postRender', chart => {
chart.svg().on('mousemove', () => { // 2
// find closest data point
const x = chart.x().invert(d3.mouse(chart.svg().node())[0] - chart.margins().left),
xs = chart.children()[0].group().all().map(kv => kv.key),
right = d3.bisectLeft(xs, x);
let closest = right;
if(right >= xs.length)
closest = right - 1;
else if(right > 0) {
// see if point to the left is closer
if(x - xs[right-1] < xs[right] - x)
closest = right - 1;
}
//console.log('closest', new Date(x), closest, xs[closest])
chart.children().forEach(child => { // 3
child.g().selectAll('circle.dot').each(function(d) {
if(d.x === xs[closest]) {
child._showDot(d3.select(this));
child.g().select('text.data-tip')
.attr('visibility', 'visible')
.attr('x', child.x()(d.x))
.attr('y', child.y()(d.y))
.text(tooltip_text(d.data))
} else
child._hideDot(d3.select(this));
});
})
})
chart.svg().on('mouseout', () => { // 4
chart.children().forEach(child => {
child.selectAll('circle.dot').each(function(d) {
child._hideDot(d3.select(this));
});
})
})
chart.children().forEach(child => child.g() // 1
.append('text')
.attr('class', 'data-tip')
.attr('fill', 'black')
.attr('alignment-baseline', 'top')
.attr('text-anchor', 'begin')
.attr('visibility', 'hidden')
)
});
I'm not going to get into the details, but this
adds a text element to each child chart, which will display the tip
listens for mousemove and finds the nearest point
shows the dots and text for the selected point in each child
hides all dots and text when the mouse leaves the chart
I ran out of time to think about this, so I didn't try to get the text positioned correctly or make it look nice.
linear scale
Linear scale fiddle.
time scale
Time scale fiddle.
As I mentioned in the comments, you're going to run into trouble with this design, if the lines get too close together. You can see this problem with the first point in this example.

Cannot hover over points that are behind path.area

As the title mention we are not able to hover over point thats are behind a path.area.
The situation is the following
If we hover the blue and the yellow line we are able to get the tooltip but if we hover over the red line we get the tooltip only from the first and the last point.
The code is the following:
let nix = crossfilter();
timeseriesFiltered.forEach(ts => {
ndx.add(ts.values.map(function(d) {
let temp = JSON.parse(JSON.stringify(objTemplate));
temp[ts.place] = d.value;
temp.date = new Date(d.timestamp);
return temp;
}));
});
let dimDate = ndx.dimension(dc.pluck('date'));
let lineChartGroups = [];
timeseriesFiltered.forEach((ts, index) => {
let group = dimDate.group().reduceSum(dc.pluck(ts.place));
let lineChart = dc.lineChart(composite)
.dimension(dimDate)
.renderDataPoints(true)
.renderArea(true)
.defined(d => {
return d.y != 0;
})
.colors(this.colors[index])
.group(group, this.setName(ts.place));
lineChartGroups.push(lineChart);
})
let chart = composite
.width(width)
.height(300)
.margins({top: 30, right: 60, bottom: 30, left: 60})
.x(d3.scaleTime().domain([new Date(minDate), new Date(maxDate)]))
.yAxisLabel(timeseriesFiltered[0].unit)
.elasticY(true)
.mouseZoomable(true)
.brushOn(false)
.clipPadding(10)
.legend(dc.legend().x(80).y(20).itemHeight(13).gap(5))
._rangeBandPadding(1)
.compose(lineChartGroups);
chart.render();
We have tried to raise all the circle dot by using the following statement:
d3.selectAll('circle.dot').raise();
But it didn't work. Any suggestion?
I'm not sure that it's a great idea to use renderArea in a composite chart; as you can see, the colors get muddied together into brown, and it's not really clear what it's supposed to convey.
I think renderArea works better with a stacked chart, where the area that is covered by each color means something.
That said, it's pretty easy to fix the problem you are seeing.
The reason why raising the dots doesn't work is because each child of the composite chart is in its own layer. So raising the dots only puts them at the top of that chart (where they already are).
Instead, you can disable mouse interactions for the filled areas:
path.area {
pointer-events: none;
}
Since the filled areas weren't interactive before, this shouldn't lose much, but you might want to be more conservative and restrict the rule to the particular chart with the selector #composite-chart path.area

set row chart labels outside the bar like a barchart in Dc.js?

How can I have the labels outside the bar in a row chart with dc.js?
I'd like a graph like this:
however, the labels are inside the actual bars... is there any settings i need to change to have it like this?
I finally got this working and here is the trick,
As mentioned by the Gordon it can be done on renderlet.
First I have gave the margin for my row chart ,
.margins({ top: 20, right: 20, bottom: 40, left: 110 })
Then took the label outside by giving x value in negative.
.labelOffsetX(-10)
This will perfectly move our label but its still need some style changes to look fine and that need to be done on renderlet,
.on('renderlet', function (chart) {
chart.selectAll("g.row text")
.style("text-anchor", "end")
.call(function (t) {
t.each(function (d) {
var self = d3.select(this);
var text = self.text();
if (text.length > 14) {
self.text('');
text = text.substring(0, 14) + '..';
self.text(text);
}
})
});
})
You can ignore .call() function as I place this just to make sure my label length does not cross certain limit.
Hope that work for you.!

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);

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

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.

Resources