Good day, trying to figure out one last piece with a code rewrite that we've been working on. We have a bubble chart that animates, to essentially simulate a motion chart, since most of the motion chart libraries we relied on previously incorporated flash.
It seems like the mouseover space for the original render sticks around during animation, and causes the bubbles to "reset", I've noticed the tooltips also stick to the original location. Any ideas/suggestions?
I've copied up a mostly complete version here (the loading of additional variables isn't implemented):
https://nl.communityaccounts.ca/motionchart/motion_dev.asp
I'm working on a standalone jsfiddle as well, can put a link to that soon.
Highcharts uses plotX and plotY point's properties to position the tooltip in a default way. In your case, only properties: x, y, z and point's graphic are updated. You need to also update plotX and plotY:
dataObject.plotX = data.x + data.z;
dataObject.plotY = data.y + data.z;
Live demo: https://jsfiddle.net/BlackLabel/9drynwcz/
Related
To get labels on Chart.js Pie and Doughnut charts, there are plugins to do so, like: chartjs-plugin-labels but after doing so I noticed a big problem for my UI design:
The size of the actual chart shrinks so that the labels fit within the canvas. It makes sense that the labels need to be able to fit within the canvas they're rendered on, and thus the shrinking of the chart. But sometimes I may use labels, and other times not, and I need my pie charts to render the same size regardless.
Is there a solution in the settings of either Chart.js (the label plugin I'm using is compatible with < 3.0, I'm using 2.9) or chartjs-plugin-labels to maintain consistent chart size, regardless of whether labels are applied?
I tried applying an empty label to every chart, but the size of the chart actually shrinks based on the specific size of the labels being rendered, so aside from being a hacky solution, it doesn't consistently solve the uniformity problem.
For example maybe a way to make charts start off taking 50% of the canvas?
Yes, this is fairly simple actually. The chartjs-plugin-labels.js file contains several lines which force the chart to become smaller when the label settings set the position to either "border" or "outside". Download the script to your own server, comment out the lines below, and everything should work as expected. CodePen demo
Comment/remove these lines:
if (this.options.position === 'border') {
offset = (lines.length - 1) * this.options.fontSize / 2;
}
if (label.options.position === 'outside') {
someOutside = true;
var padding = label.options.fontSize * 1.5 + label.options.outsidePadding;
if (padding > maxPadding) {
maxPadding = padding;
}
}
Here is the updated JS file you can use: https://pastebin.com/raw/gSffqqKu
Just download it as chartjs-plugin-labels.js and use it in your project instead of the original plugin file.
I am using chart.js to try to create a timeline of events relative to current date.
The horizontal bar chart is close but would like to show only the tips of the bars eg as points which would pretty much be a horizontal line chart.
I have shown my horizontal bar chart along with a mock-up of what it would look like as horizontal line chart.
Is this possible with chart.js ?
You first need to know that every information that you can edit about the chart is stored in the variable containing your chart (called myChart usually, but my2Bar in your fiddle).
If you want to globally change the graph, you will need to edit attributes in myChart.config.options.
If you want to change a specific chart, you will need to edit attributes in myChart.config.data.
In this case, you need to change a specific chart (which is the horizontal bar).
If you happen to check the logs of your graph, and go very deep in the config, you will finally see that bars in your chart are drawn using attributes stored in myChart.config.data.datasets[0]._meta[0].data[n]._model (n being the nth rectangle drawn, top to bottom).
Some attributes you can find there :
base : The X position where the rectangle is starting to be drawn (0 in your xAxe for instance).
x : The rectangle is being drawn until this X position.
height : The height of the drawn rectangle.
and so on ...
To edit these values, you just need to loop in your different rectangles (the n in the above path).
But you just can't do it manually on the config of your variable. If you do this, it won't work since your chart is responsive (on resize, it will redraw the chart using the former options).
What you must use are Chart.js plugins.
Plugins let you handle all the events that are triggered while creating, updating, rendering your graph.
Then, in your beforeRender event (triggered after the initialisation, but before the drawing), you need to loop in your different rectangles to edit the values to affect how they will be drawn :
beforeRender: function(chart) {
for (var i = 0; i < chart.config.data.datasets[0]._meta[0].data.length; i++) {
// Change both `3` values to change the height & width of the point
chart.config.data.datasets[0]._meta[0].data[i]._model["base"] = chart.config.data.datasets[0]._meta[0].data[i]._model["x"] + 3;
chart.config.data.datasets[0]._meta[0].data[i]._model["height"] = 3;
}
}
Here is a jsFiddle with the final result.
Unfortunately, I wasn't able to make round dots, instead of squared ones.
Update :
I have also made another jsFiddle where all the dots are linked together which makes it look like it is a horizontal line chart (can be improved of course, but it is a good start).
This is in response to the following question, How to remove padding in c3.js?, where the answer that was provided solves this issue, but also raises another issue -- the buttons on the graph are cut off at the end --
How would I get there to be no padding and the buttons not to be cut off, for example, it should look like:
The dots are getting clipped off because of the clip-path set on the chart layer. You just have to remove it. You can use D3 for this, like so
d3.select(chart.element).select("." + c3.chart.internal.fn.CLASS.chart).attr("clip-path", null);
where chart is your C3 chart object
Fiddle - http://jsfiddle.net/zds67nh1/
However you most probably want the dots to appear above the axis layer. For that you need to detach and attach the chart layer (in SVG, the z-index is determined by the order - the last of the siblings come on top. So you have to basically move it to the end of the siblings list), like so
var chartLayer = d3.select(chart.element).select("." + c3.chart.internal.fn.CLASS.chart);
var chartLayerParentNode = chartLayer.node().parentNode;
var chartLayerNode = chartLayer.remove();
chartLayerParentNode.appendChild(chartLayerNode.node());
chartLayer.attr("clip-path", null);
Fidle - http://jsfiddle.net/7e1eL22f/
I'm trying to replicate this Focus+Context via Brushing example. I'm including the same layout, but with a scatterplot instead of a line/area plot.
I started working off this example I found which combines the area plot and a scatterplot. However, when I scrap the area plot, I lose the zoom/focus capability.
My last step (thus far unsuccessful) is to make the brush (small focus bar on the bottom) actually respond to the main panel (make it adjust/zoom in when smaller time periods are selected in the brush). The brush adjusts the axis as it should, but I just haven't been able to make the brush actually adjust/zoom the points on the main scatterplot. I'm not trying plot anything in the brush - there will be a lot of points, so keeping the brush with a grey background and no points is fine.
here's my fiddle: http://jsfiddle.net/fuqzp580/3/
Sidenote: I can't quite get the jsfiddle to work with the way I'm using d3.csv, so I coded up a slightly altered version with dummy data in lieu of using d3.csv. However, I included the d3.csv code (commented out), just in case that could be a cause for my problem.
I'm new to d3 so any pointers or ideas welcome!
Here's an updated fiddle with the dots zooming on the points in the main panel: http://jsfiddle.net/henbox/3uwg92f8/1/
You were very close, I just made 3 small changes:
Firstly, uncommented the code you already had in function brushed() for selecting the dots
Secondly, defined mydots globally (since you were only doing it inside initialize() and it needs to be used beyond this scope). Added this on line 55:
var mydots = focus.append("g");
And last (and most importantly), I changed the definition for xMap from
xMap = function(d) { return x2(d.time); }
to
xMap = function(d) { return x(d.time); }
When brushing, it's the x scale that gets updated, not the x2
I'm building in some custom functionality where users can click on data points in a line chart to add notes to that date. This is a bit misleading as the notes aren't actually attached to the metrics themselves but rather the date it lands on. In other words, if I have 6 series on one line chart that spans the dates 01/01/12 - 01/08/12, a single note on 01/05/12 will apply to all 6 series. So, as you can imagine clicking on a data point on one of the 6 series or the date 01/05/12 would mislead the user to believe that this note would be applied to that data point, not the entire date and any series that lands on that date.
So, to remedy this usability issue I've decided that the best visual cue would be something like this:
There would be a clickable icon at the top of each xAxis gridLine that would need to scale with the xAxis gridLine (like if a user selects an area to zoom in on).
Suggestions on best way to pull this off? I only need a suggestion for how best to add the icon to every line... I have all post-click functionality already built.
Building on Mark's suggestion using redraw event to position the images and using load event to create them. Adding them on load is necessary to make them available during export and you would not want to create new images on each redraw either.
These chart events are used:
events: {
load: drawImages,
redraw: alignImages
}
In the drawImages function I'm using the inverse translation for the xAxis to position the images on the chart:
x = chart.plotLeft + chart.xAxis[0].translate(i, false) - imageWidth / 2,
y = chart.plotTop - imageWidth / 2;
and then adding them and setting a click handler, zIndex, pointer cursor:
chart.renderer.image('http://highcharts.com/demo/gfx/sun.png', x, y, imageWidth, imageWidth)
.on('click', function() {
location.href = 'http://example.com'
})
.attr({
zIndex: 100
})
.css({
cursor: 'pointer'
})
.add();
In alignImages the attr function is used to set new x and y values for the images which are calculated the in the same way as in drawImages.
Full example on jsfiddle
Screenshot:
Couple of ideas. First, I would use the chart redraw event to know when the chart is being redrawn (say on a zoom). Then second, explicitly place your images at the axis locations of interest. To get those query directly out of the DOM.
Using jQuery:
$('.highcharts-axis') //return an array of the two axis.
They will have svg "text element" children with (x, y) positions.