Most of the gauge charts are donuts shape, but I am looking to a fill bar dynamic graph similar to the one here.
I am not sure if there is any d3 example which can be dynamic referenced to a dynamic value such as the mouse position as I made in this JSfiddle example where a donut shape gauge is used with the code I found on http://bl.ocks.org/tomerd/1499279 example with some modifications:
var gauges = [];
var w = window.innerWidth;
var h = window.innerHeight;
function createGauge(name, label, min, max)
{
var config =
{
size: 120,
label: label,
min: undefined != min ? min : 0,
max: undefined != max ? max : 100,
minorTicks: 5
}
gauges[name] = new Gauge(name + "GaugeContainer", config);
gauges[name].render();
}
function createGauges()
{
createGauge("xMouse", "X - Mouse");
createGauge("yMouse", "Y - Mouse");
}
function initialize()
{
createGauges();
$( document ).on( "mousemove", function( event ) {
gauges["xMouse"].redraw(100*event.pageX/w);
gauges["yMouse"].redraw(100*event.pageY/h);
});
}
I know that there are other SVG such as the rectangle, but which is the best way to make a "filler bar" gauge?
Related
Is it possible to change the label position, like padding or margin in CSS?
I would like to have the labels above the x-Axes.
You can change the xAxes label positions with the following steps:
Add .getContext("2d") to the call that gets the ctx canvas object:
var ctx = document.getElementById("gescanntePackzettelChart").getContext("2d");
Hide the current xAxes ticks:
xAxes: [{
ticks: {
display: false
}
}
Add an animation to the options config, and use the canvas fillText() method to create new labels:
animation: {
duration: 1,
onComplete: function() {
var controller = this.chart.controller;
var chart = controller.chart;
var xAxis = controller.scales['x-axis-0'];
var numTicks = xAxis.ticks.length;
var xOffsetStart = xAxis.width / numTicks;
var halfBarWidth = (xAxis.width / (numTicks * 2));
xAxis.ticks.forEach(function(value, index) {
var xOffset = (xOffsetStart * index) + halfBarWidth;
var yOffset = chart.height - 20;
ctx.fillText(value, xOffset, yOffset);
});
}
}
For xOffset, to figure out the correct position, take the xAxis width and divide it by the number of tick labels. This will tell you how wide each bar is. Then, multiply that number by the current index to position the label in front of the correct bar. Finally, add add the width of half a bar to center the labels in the bar.
For the yOffset, start with the chart's height and subtract however much you want to move the labels up.
Working JSFiddle: https://jsfiddle.net/m5tnkr4n/124
Building on #Tot-Zam's response, it's possible to use the ChartJs scale object's methods to define the context pixel coordinates easier. You also don't need to define a ctx object - it is already accessible using the this.chart object.
animation: {
duration: 0,
onComplete: function() {
let chart = this.chart;
let controller = chart.controller;
let axis = controller.scales['x-axis-0'];
let yOffset = chart.height - 5;
axis.ticks.forEach(function(value, index) {
let xOffset = axis.getPixelForValue(value);
chart.ctx.fillText(value, xOffset, yOffset);
})
}
}
Working repl: https://repl.it/#lunarplasma/ChartJs-custom-axis-labels
I'm trying to make a C3 bar plot using the X with dates. I have the data formatted already in consecutive dates aggregated by days.
I've created a fiddle with what I thought will work: https://jsfiddle.net/8aL1stcs/
the plot as such is working fine, here is a version of the fiddle with the X axis commented out: https://jsfiddle.net/8aL1stcs/1/
var elementID = "#myPlot";
var myData = {};
//myData.x = 'x';
//myData.xFormat = "%Y-%m-%d";
myData.type = 'bar';
myX = ["2015-11-20", "2015-11-21", "2015-11-22","2015-11-23", "2015-11-24"];
myY = [1,2,3,4,5];
myX.splice(0,0,'x');
myY.splice(0,0,'New Reports');
myData.columns = [];
//myData.columns.push(myX);
myData.columns.push(myY);
var chart = c3.generate({
bindto: elementID,
data: myData,
size: {
height: 480,
width:400,
},
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
}
// or
//width: 100 // this makes bar width 100px
}
});
Basically I want to mimic this plot here:
For this, I think I need to use some automated way of handling the x-ticks. In other words: I don't want to set the ticks manually.
You missed this in your c3 generate json.
axis: {
x: {
type: 'timeseries',
tick: {
format: "%b-%d"//format in which you want the output
}
},
}
Working code here
Hope this helps!
Using dimple.js, I am rendering a scatter plot with the code below. This works fine, but when i hover the mouse over any point, the x and y values are shown twice, once as decimal and below that as percentage. How can i simply keep the percentage x,y values in the hover-popup? Also, is there a way to display additional items in the hover-popup?
Here is the fiddle demonstarting the issue: http://jsfiddle.net/dizzy0ny/ch2187dd/52/
var svg = dimple.newSvg("#chartContainer", 600,600);
var myChart = new dimple.chart(svg);
myChart.setBounds(90, 35, 480, 400)
xAxis = myChart.addMeasureAxis("x", "x");
yAxis = myChart.addMeasureAxis("y", "y");
xAxis.showGridlines = true;
xAxis.tickFormat = '.1%'
yAxis.tickFormat = '.1%'
s1 = myChart.addSeries(["x","y","group"], dimple.plot.bubble, [xAxis, yAxis]);
s1.data = data_scatter
s2 = myChart.addSeries(["y","group"], dimple.plot.line, [xAxis, yAxis]);
s2.data = data_ser1
myChart.addLegend(90, 480, 330, 20, "left");
myChart.draw();
As per the docs here: http://dimplejs.org/adhoc_viewer.html?id=adhoc_bar_custom_tooltips
You can change the default tooltip like so:
s1.getTooltipText = function (e) {
return [
"This is a custom tooltip!",
"X value: %" + (e.aggField[0]*100).toFixed(2),
"Y value: %" + (e.aggField[1]*100).toFixed(2),
"Group: " + e.aggField[2]
];
};
Check out your updated fiddle here: http://jsfiddle.net/ch2187dd/55/
Also, try not to forget those semi-colons! :)
I'm working with Nvd3 charts from the examples from their official website. Now I want a line chart to update periodically based on data sent from server but I couldn't found any useful Example for this on internet.
I have created a function which re-draws the chart when new data is arrived but i want to append every new point to the existing chart (like we can do in highcharts) but i'm stuck.
Here is the code I'm using for Updating the chart.
var data = [{
"key" : "Long",
"values" : getData()
}];
var chart;
function redraw() {
nv.addGraph(function() {
var chart = nv.models.lineChart().margin({
left : 100
})
//Adjust chart margins to give the x-axis some breathing room.
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
.transitionDuration(350) //how fast do you want the lines to transition?
.showLegend(true) //Show the legend, allowing users to turn on/off line series.
.showYAxis(true) //Show the y-axis
.showXAxis(true);
//Show the x-axis
chart.xAxis.tickFormat(function(d) {
return d3.time.format('%x')(new Date(d))
});
chart.yAxis.tickFormat(d3.format(',.1%'));
d3.select('#chart svg').datum(data)
//.transition().duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
}
function getData() {
var arr = [];
var theDate = new Date(2012, 01, 01, 0, 0, 0, 0);
for (var x = 0; x < 30; x++) {
arr.push({
x : new Date(theDate.getTime()),
y : Math.random() * 100
});
theDate.setDate(theDate.getDate() + 1);
}
return arr;
}
setInterval(function() {
var long = data[0].values;
var next = new Date(long[long.length - 1].x);
next.setDate(next.getDate() + 1)
long.shift();
long.push({
x : next.getTime(),
y : Math.random() * 100
});
redraw();
}, 1500);
I've recently dropped use of Graphael and and extensions package Ico. I think it's still a great library, it just needs better documentation and a proper API before it can be widely adopted.
I've converted the areas with charting to use Google Charts and can't seem to find a way to do one particular feature I used graphael for: drag support. One of my line charts needs to be editable, meaning that individual dots on the line can be dragged up and down to adjust value.
I've been trying to find an event or a way to attach an event in the API without much success. Has anyone managed to do something like that?
It's supposedly possible to do custom charts - would it be possible to do it this way?
EDIT: Seems like it's not really possible or is incredibly hard to hook into Google API or outputted SVG. It being in an iframe and no source code available just makes it less and less attractive option.
I've since started experimenting with Highcharts. I was able to do everything that Google engine does and can fiddle with chart after it's been rendered. Since source code is provided it makes it easier to figure certain things out. It also seems to work a bit faster than Google solution since it uses path when doing a Line Chart instead of individual SVG circle elements.
The issue I'm facing now has to do with the SVG Path element - there is no single point to set up drag on. So in order to use jQuery.draggable one has to inject a SVG Circle or another element at the same position as the SVG Path fragment tying to drag. So the following has to be resolved:
- how to place the created element to correct position?
- how to move element when chart is scaled (min or max value change on either axis)?
- how to convert new position back to a value, scaled for series data supplied?
Has anyone got enough in depth experience with Highcharts to fiddle with these? I'll try to provide JSfiddle example when possible.
Draggable points is not built-in into Highcharts but using the events and methods in the API it is possible to implement an editable line/column/scatter/area-chart (will only handle moving the point in y-direction so far). The following example uses mousemove, mousedown and mouseup events to handle interaction.
At mousedown the start y value is recorded if a point is focused. The y-axis.translate method is the key here, it will translate mouse position to the data domain.
At mousemove the focused point and tooltip is updated with the new value.
At mouseup the point is updated and a new event drop is fired that updates the text in a status message.
Full example on jsfiddle.
See also the feature request draggable points
This is now an available plugin on Highcharts:
http://www.highcharts.com/plugin-registry/single/3/Draggable%20Points
Realize this is a rather old question, yet its highly referenced in relation to Google Charts, so perhaps this will help someone.
Spent a while working on this exact same issue, and with the help of several answers from #WhiteHat finally managed to get this working.
Basically, you need to addEventListener to the container for the chart for "mousemove", "mouseup", and "mousedown" and then track whether you're currently selected on a point or dragging a point.
The rest mostly ends up being a lot of edge and distance and scaling calculations to try and figure out where the point actually is at in the chart.
The main parts that end up being really relevant are:
// Get layout object for the chart (mostly for bounding boxes)
var chartLayout = myLineChart.getChart().getChartLayoutInterface();
// Get the actual chart container (has all the chart properties as sub-variables)
var chartContainer = document.getElementById( myLineChart.getContainerId() );
// Find the outer (beyond title and axes labels) limits of chart
// Varies with screen scrolling
var chartBounds = chartContainer.getBoundingClientRect();
// Find the actual drawn region where your lines are (offset relative to chart)
var chartAreaBounds = chartLayout.getChartAreaBoundingBox();
Once you've actually figured out where the point is at with your mouse movement, then the location can be adjusted with:
var dataTable = myLineChart.getDataTable();
var spX = ( x - chartBounds.left - chartAreaBounds.left ) / chartAreaBounds.width * ( chartMaxX - chartMinX );
var spY = ( chartAreaBounds.height - ( y - chartBounds.top - chartAreaBounds.top ) ) / chartAreaBounds.height * ( chartMaxY - chartMinY );
dataTable.setValue( selectedPoint.row, 0, spX );
dataTable.setValue( selectedPoint.row, selectedPoint.column, spY );
A working example is included below that has two different line datasets with separate X values.
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback( initChart );
var myLineChart;
var selectedPoint = null;
var arrData = [
['Age', 'Weight', 'Weight2'],
[ 3, 3.5, null ],
[ 4, 5, null ],
[ 4, 5.5, null ],
[ 6.5, 7, null ],
[ 8, 12, null ],
[ 11, 14, null ],
[ 1, null, 3.551 ],
[ 2, null, 12.753 ],
[ 3, null, 5.058 ],
[ 4, null, 6.620 ],
[ 5, null, 12.371 ],
[ 6, null, 1.342 ],
[ 7, null, 5.202 ],
[ 8, null, 7.008 ]
];
var data;
var options = {
title: 'Age vs. Weight comparison',
hAxis: {title: 'Age', minValue: 0, maxValue: 15},
vAxis: {title: 'Weight', minValue: 0, maxValue: 15},
legend: 'none'
};
function initChart(){
data = google.visualization.arrayToDataTable( arrData );
myLineChart = new google.visualization.ChartWrapper({
chartType: 'LineChart',
containerId: 'exampleChart',
dataTable: data,
options: options
});
document.getElementById("exampleChart").addEventListener( "mousemove", mouseMoveScript );
document.getElementById("exampleChart").addEventListener( "mousedown", mouseDownScript );
document.getElementById("exampleChart").addEventListener( "mouseup", mouseUpScript );
drawChart();
}
function drawChart() {
myLineChart.draw();
}
function selectPoints( mx, my ) {
var chartLayout = myLineChart.getChart().getChartLayoutInterface();
var chartContainer = document.getElementById( myLineChart.getContainerId() );
var chartBounds = chartContainer.getBoundingClientRect();
if ( ( ( (chartBounds.left + window.pageXOffset) <= mx ) && ( (chartBounds.left + chartBounds.width + window.pageXOffset) >= mx ) ) &&
( ( (chartBounds.top + window.pageYOffset) <= my ) && ( (chartBounds.top + chartBounds.height + window.pageYOffset) >= my ) ) ){
var selection = [];
var dataTable = myLineChart.getDataTable();
for (var row = 0; row < dataTable.getNumberOfRows(); row++) {
for (var col = 1; col < dataTable.getNumberOfColumns(); col++) {
var point = chartLayout.getBoundingBox('point#' + (col - 1) + '#' + row);
if( point != null ){
if ((((chartBounds.left + point.left) >= (mx - point.width)) &&
((chartBounds.left + point.left + point.width) <= (mx + point.width))) &&
(((chartBounds.top + point.top) >= (my - point.height)) &&
((chartBounds.top + point.top + point.height) <= (my + point.height)))) {
selection.push({row: row, column: col});
}
}
}
}
if( selection.length > 0 ){
var item = selection[0];
selectedPoint = selection[0];
} else {
selectedPoint = null;
}
myLineChart.getChart().setSelection( selection );
}
}
function mouseMoveScript( e ){
var x = e.clientX;
var y = e.clientY;
var coor = "Coordinates: (" + x + "," + y + ")";
document.getElementById("output").innerHTML = coor;
if( selectedPoint != null ){
var chartContainer = document.getElementById( myLineChart.getContainerId() );
var chartBounds = chartContainer.getBoundingClientRect();
var chartLayout = myLineChart.getChart().getChartLayoutInterface()
var chartAreaBounds = chartLayout.getChartAreaBoundingBox();
var chartMinX = chartLayout.getHAxisValue( chartAreaBounds.left );
var chartMaxX = chartLayout.getHAxisValue( chartAreaBounds.left + chartAreaBounds.width );
var chartMinY = chartLayout.getVAxisValue( chartAreaBounds.top + chartAreaBounds.height );
var chartMaxY = chartLayout.getVAxisValue( chartAreaBounds.top );
var dataTable = myLineChart.getDataTable();
var spX = ( x - chartBounds.left - chartAreaBounds.left ) / chartAreaBounds.width * ( chartMaxX - chartMinX );
var spY = ( chartAreaBounds.height - ( y - chartBounds.top - chartAreaBounds.top ) ) / chartAreaBounds.height * ( chartMaxY - chartMinY );
dataTable.setValue( selectedPoint.row, 0, spX );
dataTable.setValue( selectedPoint.row, selectedPoint.column, spY );
drawChart();
}
}
function mouseDownScript( e ){
var mx = e.clientX;
var my = e.clientY;
if( e.target ){
targ = e.target;
selectPoints( mx, my );
} else if (e.srcElement) {
targ = e.srcElement;
}
var tname;
tname = targ.tagName;
}
function mouseUpScript( e ){
if( selectedPoint != null ){
selectedPoint = null;
}
}
html, body {
height: 100%;
margin: 0px 0px 0px 0px;
padding: 0px 0px 0px 0px;
}
#select_div {
border: 1px dashed #3366cc;
position: absolute;
z-index: 1000;
}
.exampleChart{
height: 100%;
}
.hidden {
display: none;
visibility: hidden;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="output"></div>
<div>
<div id="exampleChart" style="width: 900px; height: 500px;"></div>
</div>