How to set reset zoom button and title to exactly center of the high charts - charts

I am trying to set the reset zoom button and title to exactly the center of the high chart. Here the title is the selected time range of the chart portion. I need to set this as dynamically centered based on the screen resolution.
chart:{
zoomType:'x',
resetZoomButton:{
position:{
verticalAlign:'top'
},
relativeTo:'chart'
},
events:{
selection:function(event){
this.setTitle({{text:selectedChartPortion,useHtml:true}})
}
}
}
here text:selectedChartPortion is a span tag that has some style properties and the selected value.
Expected Chart outlook:
Can anyone help me to resolve it?

I think that this config should help you to achieve a wanted effect:
xAxis: {
events: {
afterSetExtremes() {
const chart = this.chart;
const resetZoomButton = chart.resetZoomButton;
const padding = 5;
if (resetZoomButton) {
chart.title.translate(-chart.title.getBBox().width / 2 - padding, 0)
resetZoomButton.translate(chart.plotWidth / 2 + resetZoomButton.getBBox().width / 2 + padding, 0)
} else {
chart.title.translate(chart.title.getBBox().width / 2 + chart.title.translateX, 0)
}
}
}
}
Demo: https://jsfiddle.net/BlackLabel/8yjd9orx/
API: https://api.highcharts.com/highcharts/chart.resetZoomButton.position.align
API: https://api.highcharts.com/highcharts/xAxis.events.afterSetExtremes

Related

Horizontal scrolling to identify hidden or dynamic element (with WDIO + Appium + JS)

I came across this interesting problem related to appium UI automation. In my app I have few UI elements that are loading dynamically after user horizontal scroll action. I tried to build my custom method to perform horizontal action on UI elements but no luck (attached screenshot for error). I see that the (x,y) position works pretty well with the vertically scrolling and would like to know if anyone has done horizontal scrolling to make hidden elements visible (dynamically loaded elements)? If you have any pointers on this please let me know. Thanks in advance.
Note: In the screenshot below you can see the last visible element is 16x20 but there is one more button “20x30” after that and I am trying to select that.
I tried with below options:
First:
browser.execute('mobile: scroll', {element: element, direction: 'left'});
Second:
screenAction.swipeLR(element,5);
The element i am passing in my custom method is last visible element i.e. 16x20:
{
console.log("Performing touch ops horizontally");
//element.touchMove(10,0);
//element.scrollIntoView();
const xLocation = element.getLocation('x')
console.log(xLocation); // outputs: 150
const yLocation = element.getLocation('y')
console.log(yLocation); // outputs: 20
const swipeStart = {
x:<Number>xLocation,
y: <Number>yLocation,
};
const swipeEnd = {
x: <Number>(xLocation+20),
y: <Number>yLocation,
};
// scroll up-to numberOfSwipes
let counter = 0;
while (counter < numberOfSwipes) {
console.log('Swipe process started');
this.swipe(swipeStart, swipeEnd);
counter += 1;
if (counter >= numberOfSwipes) {
break;
}
}
}````
[![enter image description here][1]][1]
[![enter image description here][2]][2]
[1]: https://i.stack.imgur.com/t893q.png
[2]: https://i.stack.imgur.com/YMh9Z.png

Highcharts create legend for waterwall and stack column chart

New to Highcharts, need to make a waterfall and stack column chart, as in attached image. I have completed the chart but unable to get the legend for the stack column.
https://jsfiddle.net/b9vLxoua/ Here is the chart code
Required chart with legend highlighted
Please help.
You can create a custom legend by using the SVERenderer tool on the render callback.
Demo: https://jsfiddle.net/BlackLabel/qhr6nsw9/
render() {
let chart = this,
colors = ['#003975', '#F9BD50', '#3FA27E']
chart.series[1].points.forEach((p,i) => {
if (p.category === 0) {
if (p.customRect) {
p.customRect.destroy();
}
p.customRect = chart.renderer.rect(chart.plotSizeX + chart.plotLeft + 10, 100 + i * 50, 20, 20, 5)
.attr({
fill: colors[i],
zIndex: 3
})
.add();
if (p.customText) {
p.customText.destroy();
}
p.customText = chart.renderer.label(p.t, chart.plotSizeX + chart.plotLeft + 40, 100 + i * 50).add()
}
})
}
API: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#label
API: https://api.highcharts.com/highcharts/chart.events.render

ChartJS: Custom tooltip always displaying

Im using ChartJS to create a graph on my website.
Im trying to create a custom tooltip. According to the documentation, this should be easy:
var myPieChart = new Chart(ctx, {
type: 'pie',
data: data,
options: {
tooltips: {
custom: function(tooltip) {
// tooltip will be false if tooltip is not visible or should be hidden
if (!tooltip) {
return;
}
}
}
}
});
My problem is that the tooptip is never false and because of this my custom tooltip is always displayed.
Please see this JSFiddle (line 42 is never executed)
Question: Is it a bug that tooltip is never false, or am I missing something?
The custom tooltip option is used for when you want to create/style your own tooltip using HTLM/CSS outside of the scope of the canvas (and not use the built in tooltips at all).
In order to do this, you must define a place outside of your canvas to contain your tooltip (e.g. a div) and then use that container within your tooltips.custom function.
Here is an example where I used a custom tooltip to display the hovered pie chart section percentage in the middle of the chart. In this example I'm generating my tooltip inside a div with id "chartjs-tooltip". Notice how I interact with this div in my tooltips.custom function to position and change the value.
Also, the correct way to check if the tooltip should be hidden is to check it's opacity. The tooltip object will always exist, but when it should not be visible, the opacity is set to 0.
Chart.defaults.global.tooltips.custom = function(tooltip) {
// Tooltip Element
var tooltipEl = document.getElementById('chartjs-tooltip');
// Hide if no tooltip
if (tooltip.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
// Set Text
if (tooltip.body) {
var total = 0;
// get the value of the datapoint
var value = this._data.datasets[tooltip.dataPoints[0].datasetIndex].data[tooltip.dataPoints[0].index].toLocaleString();
// calculate value of all datapoints
this._data.datasets[tooltip.dataPoints[0].datasetIndex].data.forEach(function(e) {
total += e;
});
// calculate percentage and set tooltip value
tooltipEl.innerHTML = '<h1>' + (value / total * 100) + '%</h1>';
}
// calculate position of tooltip
var centerX = (this._chartInstance.chartArea.left + this._chartInstance.chartArea.right) / 2;
var centerY = ((this._chartInstance.chartArea.top + this._chartInstance.chartArea.bottom) / 2);
// Display, position, and set styles for font
tooltipEl.style.opacity = 1;
tooltipEl.style.left = centerX + 'px';
tooltipEl.style.top = centerY + 'px';
tooltipEl.style.fontFamily = tooltip._fontFamily;
tooltipEl.style.fontSize = tooltip.fontSize;
tooltipEl.style.fontStyle = tooltip._fontStyle;
tooltipEl.style.padding = tooltip.yPadding + 'px ' + tooltip.xPadding + 'px';
};
Here is the full codepen example.
I hope that helps clear things up!

Display values outside of pie chart in chartjs

When I hover on pie chart, the values are displayed in tooltip. However, I want to display values outside of pie chart. I want to make chart like this image:
How to do this?
I was able to get something similar working using chart.js v2.3.0 using both the plugin API and extending chart types API. You should be able to take this as a starting point and tweak it to your needs.
Here is how it looks after being rendered.
Note, this requires digging deep into chart.js internals and could break if they change the way tooltips are positioned or rendered in the future. I also added a new configuration option called showAllTooltips to enable selectively using the plugin on certain charts. This should work for all chart types, but I am currently only using it for pie, doughnut, bar, and line charts so far.
With that said, here is a working solution for the image above.
Chart.plugins.register({
beforeRender: function (chart) {
if (chart.config.options.showAllTooltips) {
// create a namespace to persist plugin state (which unfortunately we have to do)
if (!chart.showAllTooltipsPlugin) {
chart.showAllTooltipsPlugin = {};
}
// turn off normal tooltips in case it was also enabled (which is the global default)
chart.options.tooltips.enabled = false;
// we can't use the chart tooltip because there is only one tooltip per chart which gets
// re-positioned via animation steps.....so let's create a place to hold our tooltips
chart.showAllTooltipsPlugin.tooltipsCollection = [];
// create a tooltip for each plot on the chart
chart.config.data.datasets.forEach(function (dataset, i) {
chart.getDatasetMeta(i).data.forEach(function (sector, j) {
// but only create one for pie and doughnut charts if the plot is large enough to even see
if (!_.contains(['doughnut', 'pie'], sector._chart.config.type) || sector._model.circumference > 0.1) {
var tooltip;
// create a new tooltip based upon configuration
if (chart.config.options.showAllTooltips.extendOut) {
// this tooltip reverses the location of the carets from the default
tooltip = new Chart.TooltipReversed({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart);
} else {
tooltip = new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart);
}
// might as well initialize this now...it would be a waste to do it once we are looping over our tooltips
tooltip.initialize();
// save the tooltips so they can be rendered later
chart.showAllTooltipsPlugin.tooltipsCollection.push(tooltip);
}
});
});
}
},
afterDraw: function (chart, easing) {
if (chart.config.options.showAllTooltips) {
// we want to wait until everything on the chart has been rendered before showing the
// tooltips for the first time...otherwise it looks weird
if (!chart.showAllTooltipsPlugin.initialRenderComplete) {
// still animating until easing === 1
if (easing !== 1) {
return;
}
// animation is complete, let's remember that fact
chart.showAllTooltipsPlugin.initialRenderComplete = true;
}
// at this point the chart has been fully rendered for the first time so start rendering tooltips
Chart.helpers.each(chart.showAllTooltipsPlugin.tooltipsCollection, function (tooltip) {
// create a namespace to persist plugin state within this tooltip (which unfortunately we have to do)
if (!tooltip.showAllTooltipsPlugin) {
tooltip.showAllTooltipsPlugin = {};
}
// re-enable this tooltip otherise it won't be drawn (remember we disabled all tooltips in beforeRender)
tooltip._options.enabled = true;
// perform standard tooltip setup (which determines it's alignment and x, y coordinates)
tooltip.update(); // determines alignment/position and stores in _view
tooltip.pivot(); // we don't actually need this since we are not animating tooltips, but let's be consistent
tooltip.transition(easing).draw(); // render and animate the tooltip
// disable this tooltip in case something else tries to do something with it later
tooltip._options.enabled = false;
});
}
},
});
// A 'reversed' tooltip places the caret on the opposite side from the current default.
// In order to do this we just need to change the 'alignment' logic
Chart.TooltipReversed = Chart.Tooltip.extend({
// Note: tooltipSize is the size of the box (not including the caret)
determineAlignment: function(tooltipSize) {
var me = this;
var model = me._model;
var chart = me._chart;
var chartArea = me._chartInstance.chartArea;
// set caret position to top or bottom if tooltip y position will extend outsite the chart top/bottom
if (model.y < tooltipSize.height) {
model.yAlign = 'top';
} else if (model.y > (chart.height - tooltipSize.height)) {
model.yAlign = 'bottom';
}
var leftAlign, rightAlign; // functions to determine left, right alignment
var overflowLeft, overflowRight; // functions to determine if left/right alignment causes tooltip to go outside chart
var yAlign; // function to get the y alignment if the tooltip goes outside of the left or right edges
var midX = (chartArea.left + chartArea.right) / 2;
var midY = (chartArea.top + chartArea.bottom) / 2;
if (model.yAlign === 'center') {
leftAlign = function(x) {
return x >= midX;
};
rightAlign = function(x) {
return x < midX;
};
} else {
leftAlign = function(x) {
return x <= (tooltipSize.width / 2);
};
rightAlign = function(x) {
return x >= (chart.width - (tooltipSize.width / 2));
};
}
overflowLeft = function(x) {
return x - tooltipSize.width < 0;
};
overflowRight = function(x) {
return x + tooltipSize.width > chart.width;
};
yAlign = function(y) {
return y <= midY ? 'bottom' : 'top';
};
if (leftAlign(model.x)) {
model.xAlign = 'left';
// Is tooltip too wide and goes over the right side of the chart.?
if (overflowLeft(model.x)) {
model.xAlign = 'center';
model.yAlign = yAlign(model.y);
}
} else if (rightAlign(model.x)) {
model.xAlign = 'right';
// Is tooltip too wide and goes outside left edge of canvas?
if (overflowRight(model.x)) {
model.xAlign = 'center';
model.yAlign = yAlign(model.y);
}
}
}
});

Highlight area programmatically - Chart.js

I'm using Chart.js (doughnut chart) and I would like to ask if is there any choice to highlight area programmatically? I mean - when I click on a button, then the specific area will be highlighted.
Thanks for your reply.
Just loop through the doughnut segments, match based on label and swap / restore the fill color.
function highlight(label) {
myDoughnutChart.segments.forEach(function (segment, i) {
if (segment.label == label) {
if (segment.fillColor == segment.highlightColor)
segment.restore(["fillColor"]);
else
segment.fillColor = segment.highlightColor;
myDoughnutChart.render();
}
})
}
Fiddle - http://jsfiddle.net/35of1Lzg/
I've disabled tooltips and the tooltip highlight by setting tooltipEvents = [], but if you want them back you can always remove it from the options, but then hover / mouseout and the button click will do the same thing.
To popup the tooltip too when highlighting use this
function highlight(label) {
myDoughnutChart.segments.forEach(function (segment) {
if (segment.label == label) {
if (segment.fillColor == segment.highlightColor)
segment.restore(["fillColor"]);
else
segment.fillColor = segment.highlightColor;
myDoughnutChart.render()
}
})
var activeSegements = [];
myDoughnutChart.segments.forEach(function (segment) {
if (segment.fillColor === segment.highlightColor) {
activeSegements.push(segment)
}
});
myDoughnutChart.showTooltip(activeSegements, true)
}
http://jsfiddle.net/jdr5381e/
FYI the fiddles are no longer working, you'll need to replace the links to the Chart.min.js
I used these to get them working: https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.1.1/Chart.js