Dynamically add an average line in highchart in angular - angularjs

How can I add a line showing average of any plotted graphs in highcharts' stochchart.
Image - average line
Any way to add this in angular?

You need to calculate the average value and add plot line. Example:
events: {
load: function() {
var yData = this.series[0].yData;
const sum = yData.reduce((a, b) => a + b);
this.yAxis[0].addPlotLine({
value: sum / yData.length,
color: 'red',
dashStyle: 'longdash'
});
}
}
Live demo: http://jsfiddle.net/BlackLabel/vt4muzr2/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Axis

Related

custom legend hide() does not remove data labels

I am building a project using React with a doughnut and bar chart. Working with Chart.js 3.xx.
I am trying to make my custom legend functional. I want to make data fractions disappear when the user clicks my legend items - like in the native legend, and optimally also remove the data and make the chart present it's updated data after removal.
I also use data labels to present percentage of the data on the fractions.
import ChartDataLabels from 'chartjs-plugin-datalabels';
I came across this topic: ChartJS - Show/hide data individually instead of entire dataset on bar/line charts
and used this suggested code there:
function chartOnClick(evt) {
let chart = evt.chart
const points = chart.getElementsAtEventForMode(evt, 'nearest', {}, true);
if (points.length) {
const firstPoint = points[0];
//var label = myChart.data.labels[firstPoint.index];
//var value = myChart.data.datasets[firstPoint.datasetIndex].data[firstPoint.index];
let datasetIndex = firstPoint.datasetIndex, index = firstPoint.index;
if (firstPoint.element.hidden != true) {
chart.hide(datasetIndex, index);
} else {
chart.show(datasetIndex, index);
}
}
}
options: { // chart options
onClick: chartOnClick
}
It almost works, but the hide() method doesn't remove the fraction's percentage data label when activated, whereas when clicking the native legend it does remove it entirely.
I tried looking in the plugin's docs but didn't manage to find how to remove a single label.
How can I achieve what I am looking for?
EDIT:
Options Object:
export const doughnutOptsObj = {
onClick: chartOnClick,
responsive: true,
maintainAspectRatio: false,
layout: { padding: { top: 16, bottom: 16 } },
hoverOffset: 32,
plugins: {
legend: {
display: true,
position: 'bottom',
},
datalabels: {
formatter: (value, dnct1) => {
let sum = 0;
let dataArr = dnct1.chart.data.datasets[0].data;
dataArr.map((data) => {
sum += Number(data);
});
let percentage = ((value * 100) / sum).toFixed() + '%';
return percentage;
},
color: ['#fbfcfd'],
font: { weight: 'bold' },
// display: false, <-- this works and makes all of the data labels disappear
},
},
};
It seems that the onClick function is working properly.
I have tried the attached code, leveraging on toggleDataVisibility API, and it's working as requested (codepen: https://codepen.io/stockinail/pen/abKNJqJ):
function chartOnClick(evt) {
let chart = evt.chart
const points = chart.getElementsAtEventForMode(evt, 'nearest', {}, true);
if (points.length) {
const firstPoint = points[0];
chart.toggleDataVisibility(firstPoint.index);
chart.update();
}
}

How to create and set a setMapTypeId using react-google-maps

I was looking for a way to create my own mars map in a website, using google maps.
I found this example in google map api
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 0, lng: 0},
zoom: 1,
streetViewControl: false,
mapTypeControlOptions: {
mapTypeIds: ['moon']
}
});
var moonMapType = new google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
var normalizedCoord = getNormalizedCoord(coord, zoom);
if (!normalizedCoord) {
return null;
}
var bound = Math.pow(2, zoom);
return '//mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw' +
'/' + zoom + '/' + normalizedCoord.x + '/' +
(bound - normalizedCoord.y - 1) + '.jpg';
},
tileSize: new google.maps.Size(256, 256),
maxZoom: 9,
minZoom: 0,
radius: 1738000,
name: 'Moon'
});
map.mapTypes.set('moon', moonMapType);
map.setMapTypeId('moon');
}
// Normalizes the coords that tiles repeat across the x axis (horizontally)
// like the standard Google map tiles.
function getNormalizedCoord(coord, zoom) {
var y = coord.y;
var x = coord.x;
// tile range in one direction range is dependent on zoom level
// 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc
var tileRange = 1 << zoom;
// don't repeat across y-axis (vertically)
if (y < 0 || y >= tileRange) {
return null;
}
// repeat across x-axis
if (x < 0 || x >= tileRange) {
x = (x % tileRange + tileRange) % tileRange;
}
return {x: x, y: y};
}
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map"></div>
<!-- Replace the value of the key parameter with your own API key. -->
<script
async
defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>
https://jsfiddle.net/dobleuber/319kgLh4/
It works perfect, but I would like to create the same thing with react using react-google-maps.
I looked out in the react-google-maps code but I only see getters no setters for the map props:
getMapTypeId, getStreetView, ect.
Is there any way to achieve this without modify the react-google-maps code?
Thanks in advance
use props mapTypeId="moon" in react-google-maps
I've found a better way to solve this that preserve the changes on re-render, leaving it here to anyone who comes here.
there is an onLoad function that exposes a map instance, we can use this to set mapTypeId instead of passing it as an option. In this way, if the user changes the map type later, it will preserve the changes on re-render.
<GoogleMap
onLoad={(map) => {
map.setMapTypeId('moon');
}}
/>

Convert line to image in kinetic js v5.0.0

I have a line as shown below
Line attributes are
When I convert it to image using following code,
var nClone=$scope.currLine.clone(); // $scope.currLine has kinetic line info
$scope.currLine.remove(); // remove form layer as we have its clone
var pArr=nClone['attrs']['points'];
var i,wIs,hIs;
var xIs=0;
var yIs=0;
// to set width and height of image from line points
var arrLen=pArr.length;
for(i=0; i<arrLen;i){
if(i>=arrLen){
break;
}
wIs=Math.abs(pArr[i]-pArr[i+2]); // calculating difference
hIs=Math.abs(pArr[i+1]-pArr[i+3]);
i=i+4;
}
nClone.toImage({
x:xIs,
y:yIs,
width:wIs,
height:hIs,
callback: function(graphicImage){
console.log(graphicImage.src);
}
});
The image that I get is
I have tried a lot to set the line at 0,0 position any suggestion? Thanks
I am able to convert line to image:
var line = new Kinetic.Line({
points: $scope.points, // any 4 points 10 20 40 50
stroke: 'green',
strokeWidth: '2',
lineCap: 'round',
lineJoin: 'round'
});
var pArr=line['attrs']['points']; // calculate width and height
width=Math.abs(pArr[0]-pArr[2]);
height=Math.abs(pArr[1]-pArr[3]);
imgXis=pArr[0];
imgYis=pArr[1];
var shImage = line.toDataURL({
x:imgXis,
y:imgYis,
width:width,
height:height
});

angularjs-nvd3-directives line chart ticks doesn't work

I work with cmaurer nvd3 directives with angularjs and you can see it here
I want to change the x-axis ticks count to 3 (start, middle, end dates), but nvd3 ticks properties(xaxisticks, xaxistickvalues) don't work.
I even tried to use unix timestamp, but no success.
Have any thoughts?
<nvd3-line-chart
...
xAxisTickFormat="xAxisTickFormatFunction()"
yAxisTickFormat="yAxisTickFormatFunction()"
xaxistickvalues="xAxisTickValuesFunction()" // not work
xaxisticks="3" // not work
showXAxis="true"
showYAxis="true"
interactive="true"
...
forcey="[]"
>
<svg></svg>
</nvd3-line-chart>
Not a perfect solution, but was a quick change that removes duplication for the most part. Add a cache of the ticks as they are created, and since they are create in order, can eliminate sequential dupes.
controller: function($scope) {
var vm = this;
vm.xAxisTick = ""; // <- cache the x-axis ticks here...
vm.x2AxisTick = ""; // <- cache the x2-axis ticks here...
vm.options = {
chart: {
type: 'lineWithFocusChart',
xAxis: {
scale: d3.time.scale(),
tickFormat: function(d) {
var tick = moment.unix(d).format('h:mm a');
// compare tick versus the last one,
// return empty string if match
if (vm.xAxisTick === tick) {
return "";
}
// update our latest tick, and pass along to the chart
vm.xAxisTick = tick;
return tick;
},
rotateLabels: 30,
showMaxMin: false
},
x2Axis: {
scale: d3.time.scale(),
tickFormat: function(d) {
var tick = moment.unix(d).format('h:mm a');
// compare tick versus the last one,
// return empty string if match
if (vm.x2AxisTick === tick) {
return "";
}
// update our latest tick, and pass along to the chart
vm.x2AxisTick = tick;
return tick;
},
rotateLabels: 30,
showMaxMin: false
},
yAxis: {
axisLabel: 'Why',
axisLabelDistance: 30,
rotateYLabel: false
}
}
};
It seems all line charts in nvd3 have the ticks hardcoded, so any ticks setting gets ignored:
xAxis
.scale(x)
.ticks( availableWidth / 100 )
.tickSize(-availableHeight, 0);
See here: https://github.com/novus/nvd3/issues/70. Sadly it seems to get it working one needs to fork the library, or wait until version 2.0 is released, hopefully solving this among other bugs.

ExtJs Chart, How to get boundary dates from selection mask on 'Time' type axis

I have ExtJs 4 Area chart with Time serie. I'd like user to be able to horizontally select part of chart and then obtain higher density data from server adequately. Problem is I can't get boundary dates from selection. I've got:
var chart = Ext.create('Ext.chart.Chart', {
store: store,
enableMask: true,
mask: 'horizontal',
listeners: {
select: {
fn: function(me, selection) {
console.log(arguments); // selection = Object { height: 218, width: 117, x: 665, y: 123 }
}
},
...
But select listener provides only pixel data. Is there some way to get boundary axis data (e.g. { from: 2013-08-01, to: 2013-08-20 } or some way to unproject pixels to values? I'm desperade I would say it's such a basic thing but can't find solution anywhere. Thanks in advance.
Well.. it probably doesn't exists a method for this. After digging into source code I've utilized lines from chart.setZoom() method to create function for manual unprojecting of mask selection to X axis data:
var unprojectXAxis = function(chart, selection) {
zoomArea = {
x : selection.x - chart.el.getX(),
width : selection.width
};
xScale = chart.chartBBox.width,
zoomer = {
x : zoomArea.x / xScale,
width : zoomArea.width / xScale
}
ends = chart.axes.items[0].calcEnds();
from = (ends.to - ends.from) * zoomer.x + ends.from;
to = (ends.to - ends.from) * zoomer.width + from;
return { from: new Date(from), to: new Date(to) };
}

Resources