Bar Chart outside bounds and mouseover event issue - javascript

Here is my dimple.js code, the bar chart that it produces is outside the bounds and touching Y-axis.
Mouseover event is not changing the color of the bars.
Below is the image
var myChart2 = new dimple.chart(svg,data);
myChart2.setBounds(750,50,550,250);
var x = myChart2.addTimeAxis( "x", "date", "%m/%d/%Y", "%d-%b");
x.floatingBarWidth = 21;
var y2= myChart2.addMeasureAxis("y","callperorder");
var y1= myChart2.addMeasureAxis("y","calls");
var bars = myChart2.addSeries("or", dimple.plot.bar,[x,y2]);
var lines= myChart2.addSeries("cl", dimple.plot.line,[x,y1]);
lines.lineMarkers= true;
myChart2.addLegend(750, 20, 300, 20, "right");
myChart2.assignColor("cl","rgb(99,39,29)");
myChart2.assignColor("or","rgb(99,89,219)");
myChart2.draw();
\\MOUSEOVER EVENT
bars.addEventHandler("mouseover", function( {d3.select(this).style("fill","green")});

You need to add the event handler before calling draw if you want to use the dimple method. Alternatively you could use the d3 method after draw.
bars.shapes.on("mouseover", function () {...});
NB. There's also a typo in your event declaration, it's missing the closing bracket after function (.
In order to avoid overlapping the edge of the chart you will need to manually set the x bounds:
x.overrideMin = d3.time.format("%m/%d/%Y").parse("12/31/2014");
x.overrideMax = d3.time.format("%m/%d/%Y").parse("01/11/2015");
Using whatever values you want of course;

Related

'Click anywhere' event in plotly

I am trying to implement a 'click anywhere' feature in plotly so that I can get the coordinates on user clicks anywhere on plotly charts. The current "official" plotly functionality only works when users click on a plotted data point, but I want to register clicks e.g. on the background white canvas.
Shiny click events for plots can do that, but surprisingly this doesn't seem to exist yet in plotly.
I made some research and found the following codepen implementation which comes close: https://codepen.io/tim-logan/pen/yLXgpyp
#JS
var d3 = Plotly.d3;
var gd = document.getElementById('graph');
Plotly.plot('graph', [{
y: [2, 1, 2]
}])
.then(attach);
function attach() {
var xaxis = gd._fullLayout.xaxis;
var yaxis = gd._fullLayout.yaxis;
var l = gd._fullLayout.margin.l;
var t = gd._fullLayout.margin.t;
gd.addEventListener('mousemove', function(evt) {
var xInDataCoord = xaxis.p2c(evt.x - l);
var yInDataCoord = yaxis.p2c(evt.y - t);
console.log(evt.x, l)
Plotly.relayout(gd, 'title', ['x: ' + xInDataCoord, 'y : ' + yInDataCoord].join('<br>'));
});
}
# HTML
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div style="padding-left: 100px; margin-left: 100px">
<div id="graph"></div>
</div>
</body>
However, as the creator of the codepen pointed out, the click coordinates are not precises as they don't take into account the padding / margin:
One issue with the example workaround is that it doesn't account for padding/margin in parent objects.
I've taken the example and added a parent div that has both padding and margin on the left side, this then skews the value of the x-axis value, and is clearly something that would need to be handled in such a solution as is suggested here.
According to the flot documentation this should be possible for plot objects by subtracting the plot offset from the coordinates:
https://github.com/flot/flot/blob/master/API.md#plot-methods
See e.g. the following excerpt:
Various things are stuffed inside an axis object, e.g. you could use getAxes().xaxis.ticks to find out what the ticks are for the xaxis. Two other useful attributes are p2c and c2p, functions for transforming from data point space to the canvas plot space and back. Both returns values that are offset with the plot offset.
or:
offset()
Returns the offset of the plotting area inside the grid relative to the document, useful for instance for calculating mouse positions (event.pageX/Y minus this offset is the pixel position inside the plot).
I tried to implement a workaround based on offset(), but since my js knownledge is not too good I couldn't get a working version of the code.
Would somebody be able to provide a workaround to fix the offset problem?
I managed to remove the offset by getting the parent box's dimensions. See following example which fixed the above codepen:
var d3 = Plotly.d3;
var gd = document.getElementById('graph');
Plotly.plot('graph', [{
y: [2, 1, 2]
}])
.then(attach);
function attach() {
gd.addEventListener('mousemove', function(evt) {
var bb = evt.target.getBoundingClientRect();
var x = gd._fullLayout.xaxis.p2d(evt.clientX - bb.left);
var y = gd._fullLayout.yaxis.p2d(evt.clientY - bb.top);
Plotly.relayout(gd, 'title', ['x: ' + x, 'y : ' + y].join('<br>'));
});
}
Fixed codepen here: https://codepen.io/flaviofusero/pen/BaZRgzO
Adapted from sleighsoft's implementation here: plotly click events from anywhere on the plot

Highcharts: Auto-scale rendered shape along with chart?

I've placed a box shape on the chart using chart.renderer.rect(). I want that box to get skinnier (the same way the chart does) when I resize the page horizontally.
I can see in the inspector that the width attribute of all the SVG chart elements is getting changed as I resize the page but not my rendered box shape. How are they doing this? Is there some property I have to add to my rendered box shape?
I also noticed the add() method takes a parent but I can't figure out how to get the SVGElement from the chart I'm adding it to and I'm not sure setting the parent would give me the auto-scaling I want anyway.
You can store reference to an element and edit it's attributes, for example based on axis values. Example:
chart: {
events: {
render: function() {
const chart = this;
const xAxis = chart.xAxis[0];
const yAxis = chart.yAxis[0];
const startX = xAxis.toPixels(1);
const startY = yAxis.toPixels(7);
const width = xAxis.toPixels(6) - startX;
const height = yAxis.toPixels(4) - startY;
if (!chart.customRect) {
chart.customRect = chart.renderer.rect().attr({
'stroke-width': 2,
stroke: 'red',
fill: 'yellow'
}).add();
}
chart.customRect.attr({
x: startX,
y: startY,
width,
height
});
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/p6743jam/
API Reference:
https://api.highcharts.com/class-reference/Highcharts.SVGElement#attr
https://api.highcharts.com/class-reference/Highcharts.Axis#toPixels

Place text in kendo donut chart

I am trying to create a semi circle donut chart to show some progress data. This I was able to complete. Further I needed to place text inside/ center of the donut chart which again I was able to do successfully. Now I have a new requirement where I need to show some text on the start and end positions of the graph(I need 0% and 100% to be shown on either axis). I tried several ways without any ado. Can you please help me with a possible solution.
Please find the dojo I created here:
http://dojo.telerik.com/Exike
This is roughly what I would like my end result to appear like:
Any suggestions for the same?
Thanks in advance.
You could add a couple of text boxes to your render function and use the bounding box to place them:
render: function (e) {
var draw = kendo.drawing;
var geom = kendo.geometry;
var chart = e.sender;
// The center and radius are populated by now.
// We can ask a circle geometry to calculate the bounding rectangle for us.
var circleGeometry = new geom.Circle(center, radius);
var bbox = circleGeometry.bbox();
// Render the text
var text = new draw.Text("33%", [0, 0], {
font: "18px Verdana,Arial,sans-serif"
});
// Align the text in the bounding box
draw.align([text], bbox, "center");
draw.vAlign([text], bbox, "center");
var text0 = new draw.Text("0%", [bbox.origin.x, bbox.origin.y + bbox.size.height / 2 ], {
font: "10px Verdana,Arial,sans-serif"
});
var text100 = new draw.Text("100%", [bbox.origin.x + bbox.size.width - 28, bbox.origin.y + bbox.size.height / 2 ], {
font: "10px Verdana,Arial,sans-serif"
});
// Draw it on the Chart drawing surface
e.sender.surface.draw(text);
e.sender.surface.draw(text0);
e.sender.surface.draw(text100);
}
Use DonutCenterTemplate for that:
<ng-template kendoChartDonutCenterTemplate>
<h3>99.5%</h3>
Accepted
</ng-template>

Flot event for range updates in response to panning/zooming

For Flot, is there an event that fires after the user has completed panning or zooming using the mouse scroll wheel (after the range.xaxis.to/from and range.yaxis.to/from have settled)? I am trying to use the line below to update the selection on an overview plot after the user has panned or zoomed in the main plot, but am finding that either the update to the overview plot happens after panning or zooming(not both).
$("#plot").bind("mouseup scroll",updateOverviewSelection);
Edit: http://jsfiddle.net/apandit/nu2rr58h/9/
In the jsfiddle, I am unable to pan in the main plot and the cursor does not seem to change back to normal. The user can click and drag in the overview plot to make a selection, which leads to zooming in the main plot. I would also like to be able to allow the user to pan and zoom in the main plot and have the selection box in the overview plot updated; I am attempting to do this by binding the updateOverviewSelection method to the plot div for the scroll and mouseup events. Is there an event in Flot that fires every time the x- and y-axis limits are updated?
The solution to this issue is below. The issue was that setting the overview plot's selection(overview.setSelection(ranges);) was triggering the zoom method because it was bound to the plotselected event in the overview plot. At the end of the zoom method, the main plot was plotted, which was again calling the overview.setSelection(ranges); line in the updateOverviewSelection method. To prevent this ping-pong between the two methods/events, I added an updatingOverviewSelection flag.
http://jsfiddle.net/apandit/nu2rr58h/12/
var datasets = [[
[0,0],[1,1],[2,2],[3,3],[4,4],[5,5],[6,6],[7,7],[8,8],[9,9]
],
[
[0,0],[-1,-1],[-2,-2],[-3,-3],[-4,-4],[-5,-5],[-6,-6],[-7,-7],[-8,-8],[-9,-9]
]];
var plot = $.plot("#plot",datasets,{
pan: {
interactive: true
},
zoom: {
interactive: true,
mode: "x"
}
});
var overview = $.plot("#overview",datasets,{
selection: {
mode: "xy"
}
});
var updatingOverviewSelection = false;
$("#plot").bind("plotpan plotzoom",updateOverviewSelection);
$("#overview").bind("plotselected", zoom);
function zoom(event,ranges) {
if(updatingOverviewSelection) {
updatingOverviewSelection = false;
}
else {
var options = plot.getOptions();
options.xaxes[0].min = ranges.xaxis.from;
options.xaxes[0].max = ranges.xaxis.to;
options.yaxes[0].min = ranges.yaxis.from;
options.yaxes[0].max = ranges.yaxis.to;
plot = $.plot("#plot",datasets,options);
}
};
// get the window x-axis and y-axis ranges for the main plot
// and set the selection in the overview plot to those ranges
function updateOverviewSelection(event) {
var options = plot.getOptions();
var ranges = {
xaxis: {
from: options.xaxes[0].min,
to: options.xaxes[0].max
},
yaxis: {
from: options.yaxes[0].min,
to: options.yaxes[0].max
}
};
updatingOverviewSelection = true;
overview.setSelection(ranges);
};

Highstock panning asynchronously loading data

Using Highstock is it possible to drag the chart and load the data asynchronously?
I've seen the async demo on the highcharts website http://jsfiddle.net/hcharge/5zPLV/
However this uses the navigator/scrollbar to move the chart along the series and loads the data when you stop sliding it along, Ideally I want to use the panning capability of highstock to move along instead of the navigator as it takes up too much space.
Playing around with the demo if I turn off the navigator and scrollbar and disable the zoomtype: x then as soon as you start dragging the chart it tries to fetch the data, making the chart unusable. Here is a fiddle of that http://jsfiddle.net/hcharge/6YSvk/
navigator: {enabled: false}, scrollbar: {enabled: false}
Ideally we'd need to know when the user starts dragging and when they stop then load the data.
Is this even possible to do? Thanks
I think this is possible, but it won't be easy.
As you wrote, you should start with detecting drag & drop. It's not possible using build-in options, but we can add our own event listeners. Take a look at this code:
new Highcharts.StockChart({
// here comes your chart options, but we can pass callback function as the second parameter
}, function (chart) {
var report = document.getElementById('report'), // just an element to display current extremes
xAxis = chart.xAxis[0],
startX;
function drag(e) {
e = chart.tracker.normalizeMouseEvent(e);
startX = e.chartX;
}
function drop(e) {
e = chart.tracker.normalizeMouseEvent(e);
var delta = e.chartX - startX,
extremes = xAxis.getExtremes(),
newMin = Math.round(extremes.min - delta),
newMax = Math.round(extremes.max - delta);
// display extremes retrieved by panning
report.innerHTML = "<b>From:</b> " + new Date(newMin) + " <b>to:</b> " + new Date(newMax);
}
// bind events
Highcharts.addEvent(chart.container, 'mousedown', drag);
Highcharts.addEvent(chart.container, 'mouseup', drop);
});
Simply we detect mouseDown & mouseUp events, then calculate the difference, translate difference to x data and finally, substract difference from extremes.
Here you can find the jsfiddle demo with code posted above: http://jsfiddle.net/dSEAA/1/
To make #slawekkolodziej's example work, you need to translate the delta into ms on the xAxis, then update the xAxis extremes like so:
window.chart = new Highcharts.StockChart({
// chart options go here
}, function(chart) {
var xAxis = chart.xAxis[0],
startX;
function drag(e) {
e = chart.pointer.normalize(e);
startX = e.chartX;
}
function drop(e) {
e = chart.pointer.normalize(e);
var delta = e.chartX - startX,
extremes = xAxis.getExtremes(),
deltaMs = (extremes.max - extremes.min) / chart.plotWidth * delta,
newMin = Math.round(extremes.min - deltaMs),
newMax = Math.round(extremes.max - deltaMs);
xAxis.setExtremes(newMin, newMax)
}
Highcharts.addEvent(chart.container, 'mousedown', drag);
Highcharts.addEvent(chart.container, 'mouseup', drop);
});
});
Here's a working example with async data loading: http://jsfiddle.net/xw7goLj4/5/

Categories