How to position the dataLabel for highcharts on the same side of the x-axis? - charts

I have a column chart with positive and negative values. Using the default dataLabels, keeps the label at the end of the column, which isn't ideal for negative values, as it goes below the x axis.
$(function () {
$('#container').highcharts({
chart: {
type: 'column',
height: 200,
borderColor: '#ddd'
},
title: {
text: ''
},
legend: {
padding: 0,
margin: 5
},
credits: {
enabled: true
},
tooltip: {
enabled: false
},
plotOptions: {
column: {
dataLabels: {
enabled: true,
crop: false,
overflow: 'none'
}
}
},
colors: ['#4572A7', '#AA4643', '#89A54E', '#80699B', '#3D96AE', '#DB843D', '#92A8CD', '#A47D7C', '#B5CA92'],
loading: {
labelStyle: {
top: '35%',
fontSize: "2em"
}
},
xAxis: {
categories: ["7/12", "7/13", "7/14", "7/15", "7/16"]
},
series: [{
"name": "Odometer",
"data": [{
"y": 94.98
}, {
"y": 182.96
}, {
"y": -160.97
}, {
"y": -18.00
}, {
"y": 117.97
}]
}]
});});
Example: http://jsfiddle.net/absessive/NKXRk/54/

Add plotOptions.column.stacking as normal like this and it will work.

You can change a little bit Highcharts.seriesTypes.column.prototype.alignDataLabel function, so it will not have functionality of aligning the dataLabel below your column if its value is smaller than 0.
Here you can find code that may help you:
H.seriesTypes.column.prototype.alignDataLabel = function(point, dataLabel, options, alignTo, isNew) {
var inverted = this.chart.inverted,
pick = H.pick,
Series = H.Series,
series = point.series,
merge = H.merge,
dlBox = point.dlBox || point.shapeArgs, // data label box for alignment
below = false,
inside = pick(options.inside, !!this.options.stacking), // draw it inside the box?
overshoot;
// Align to the column itself, or the top of it
if (dlBox) { // Area range uses this method but not alignTo
alignTo = merge(dlBox);
if (alignTo.y < 0) {
alignTo.height += alignTo.y;
alignTo.y = 0;
}
overshoot = alignTo.y + alignTo.height - series.yAxis.len;
if (overshoot > 0) {
alignTo.height -= overshoot;
}
if (inverted) {
alignTo = {
x: series.yAxis.len - alignTo.y - alignTo.height,
y: series.xAxis.len - alignTo.x - alignTo.width,
width: alignTo.height,
height: alignTo.width
};
}
// Compute the alignment box
if (!inside) {
if (inverted) {
alignTo.x += below ? 0 : alignTo.width;
alignTo.width = 0;
} else {
alignTo.y += below ? alignTo.height : 0;
alignTo.height = 0;
}
}
}
// When alignment is undefined (typically columns and bars), display the individual
// point below or above the point depending on the threshold
options.align = pick(
options.align, !inverted || inside ? 'center' : below ? 'right' : 'left'
);
options.verticalAlign = pick(
options.verticalAlign,
inverted || inside ? 'middle' : below ? 'top' : 'bottom'
);
// Call the parent method
Series.prototype.alignDataLabel.call(this, point, dataLabel, options, alignTo, isNew);
};
The only change I have made is that I have changed below parameter to false.
Here you can find an example how it can work:
http://jsfiddle.net/NKXRk/59/
Best regards,

Related

Is there any way to downplay toolbox custom feature button on another feature button

Two custom feature added in toolbox. I need functionality where in we can reset one feature on click of another.
like existing feature 'zoom' button and 'horizontally select' brush button. If we click the zoom button first and then click on brush button then zoom button automatically gets reset to default.
below is the reference code -
`function func(x) {
x /= 10;
return Math.random() * 22;
}
function generateData() {
let data = [];
for (let i = 0; i <= 10; i += 0.1) {
data.push([i, func(i)]);
}
return data;
}
var isPointSelect = false;
var rangeSelector = false;
option = {
animation: false,
toolbox: {
feature: {
dataZoom: {
yAxisIndex: false
},
myRangeSelector: {
show: true,
title: 'Range Selector',
icon: 'path://M432.45,595.444c0,2.177-4.661,6.82-11.305,6.82c-6.475,0-11.306-4.567-11.306-6.82s4.852-6.812,11.306-6.812C427.841,588.632,432.452,593.191,432.45,595.444L432.45,595.444z M421.155,589.876c-3.009,0-5.448,2.495-5.448,5.572s2.439,5.572,5.448,5.572c3.01,0,5.449-2.495,5.449-5.572C426.604,592.371,424.165,589.876,421.155,589.876L421.155,589.876z M421.146,591.891c-1.916,0-3.47,1.589-3.47,3.549c0,1.959,1.554,3.548,3.47,3.548s3.469-1.589,3.469-3.548C424.614,593.479,423.062,591.891,421.146,591.891L421.146,591.891zM421.146,591.891',
onclick: function (model, api, type) {
// debugger;
rangeSelector = !rangeSelector;
this.model.setIconStatus(type, rangeSelector ? 'emphasis' : 'normal');
}
},
myPointSelect: {
show: true,
title: 'Point Select',
icon: 'path://M432.45,595.444c0,2.177-4.689,6.82-11.305,6.82r-6.475,0-11.306-4.567-11.306-6.82s4.852-6.812,11.306-6.812C427.841,588.632,432.452,593.191,432.45,595.444L432.45,595.444z M421.155,589.876c-3.009,0-5.448,2.495-5.448,5.572s2.439,5.572,5.448,5.572c3.01,0,5.449-2.495,5.449-5.572C426.604,592.371,424.165,589.876,421.155,589.876L421.155,589.876z M621.146,591.294c-1.916,0-3.47,1.589-3.47,3.549c0,1.959,1.554,3.548,3.47,3.548s3.469-1.589,3.469-3.548C424.614,593.479,423.062,591.891,421.146,591.891L421.146,591.891zM421.146,591.891',
onclick: function (model, api, type) {
isPointSelect = !isPointSelect;
this.model.setIconStatus(type, isPointSelect ? 'emphasis' : 'normal');
}
},
brush: {
type: ['lineX', 'clear', 'keep']
}
}
},
brush: {
xAxisIndex: 'all',
brushLink: 'all',
brushStyle: {
color: 'white'
},
outOfBrush: {
colorAlpha: 0.1
}
},
graphic: {
elements: []
},
grid: {
top: 100,
left: 50,
right: 40,
bottom: 50
},
xAxis: {
minorTick: {
show: true
},
minorSplitLine: {
show: true
}
},
yAxis: {
minorTick: {
show: true
},
minorSplitLine: {
show: true
}
},
series: [
{
type: 'line',
showSymbol: false,
clip: true,
data: generateData(),
markArea: {
data: []
}
}
]
};`
Echart has similar functionality for zoom and brush feature.

Styling Turf buffer based on marker attribute

As title suggests, i'm trying to style the Turf buffers around my marker layer based on attributes from that marker layer.
I know how to style a layer based on attributes of that SAME layer but am having trouble connecting the style to the buffers instead.
I have played with two methods, both of which are able to style my buffers but still don't connect to my marker's attribute information (for obvious reasons as you will see). Please ignore any strange formatting as the post rearranged things and I tried to fix them.
Attempt 1:
lyrHouses = {
type: "FeatureCollection",
features: [],
};
// parse local CSV file
Papa.parse("src/data1/Houses.csv", {
header: true,
download: true,
dynamicTyping: true,
skipEmptyLines: true,
complete: function (results) {
results.data.forEach((house) => {
feature = {
type: "Feature",
geometry: {
type: "Point",
coordinates: [house.Longitude, house.Latitude],
},
properties: {
Location: house.Location,
Type: house.Type,
},
};
mrkHouses = L.geoJSON(feature).addTo(mymap);
lyrHouses.features.push(feature);
houseBuffer = turf.buffer(mrkHouses.toGeoJSON(), 3, {
units: "kilometers",
});
lyrTest = L.geoJSON(houseBuffer, {
style: function (feature) {
switch (feature.properties.Type) {
case "Duplex":
return { color: "blue" };
case "Quadplex":
return { color: "yellow" };
}
return { color: "red" };
},
}).addTo(mymap);
});
},
});
Attempt 2:
function setBuffColor(d) {
return d = 'Duplex' ? "green" :
d = 'Quadplex' ? "red" :
d = 'Semidetached' ? "blue" :
'#FFED80';
}
function BuffStyle(feature) {
return {
color: setBuffColor(feature.properties.Type),
};
}
Why just not like this?
lyrTest = L.geoJSON(houseBuffer, { style: house.Type === 'Duplex' ? { color: "blue" } : (house.Type === 'Quadplex' ? { color: "yellow" } : { color: "red" }) });

how to add multiple reference lines in SAPUI5 vizframe?

My vizframe has multiple Measures. I want to have 1 reference line for each measure.
How can I add more than 1 reference line to the chart using setVizProperties?
current code which adding 1 reference line
var oChart = sap.ui.getCore().byId("mainPageView--idVizFrame");
oChart.setVizProperties({
plotArea: {
dataLabel: {
visible: true
},
referenceLine: {
line: {
valueAxis: [{
value: value1,
visible: show,
size: 1,
type: "dotted",
label: {
text: "Target:" + value1 + strrange,
visible: show
}
}]
}
}
}
});
the following code solves this issue
var RefLines2 = [];
var TargetValues = [40, 50, 60, 70];
for (var i = 0; i < TargetValues.length; i++) {
RefLines2.push({
value: TargetValues[i],
visible: show,
size: 1,
type: "dotted",
label: {
text: "Target:" + TargetValues[i] + strrange,
visible: show
}
}
);
}
oChart.setVizProperties({
plotArea: {
dataLabel: {
visible: true
},
referenceLine: {
line: {
valueAxis: RefLines2
}
}
}
});

Minimum value for x Axis doesn't work for horizontal bar chart | ChartJS

I am using Chart.js (www.chartjs.org) to show the representation of the time spent on activities during the work. I have "Working"(green), "Smoking"(red), "At lunch"(orange), "At Toilette"(blue) and "At home"(grey) and I need to show all of them during a day for every worker. For that, I am using the horizontal bar stacked chart and it looks like this:
Before setting the minimum value - x Axis represents hours (0-24)
It bothers me that a lot of space is used for "At home", but I want to see only the time from 7 to 18. I tried to set ticks min to 7 but it doesn't work, and after that it looks like this:
After setting the minimum value to 7
You can see that the graph is messed up and I don't know why. How can I achieve that the x Axis begins from 7, and data is still represented correctly?
Here is my code:
var updateMainChart = function(data) {
$.ajax({
type: "GET",
url: "api/get_activitytracks.php?q=commands",
success: function(response) {
response = JSON.parse(response);
if (response.statusCode == 200) {
//get activity names
var activities = $.map(response.data, function(n, i) {
return n.title;
});
//get max number of activities
var names = [];
var max = 0;
Object.keys(data).forEach(function(key, index) {
names.push(key);
});
$.each(data, function(key, value) {
if (value.length > max) {
max = value.length;
}
});
//build datasets
var myDataSets = [];
var colors = [
'rgba(0, 255, 0, 0.6)',
'rgba(255, 0, 0, 0.6)',
'rgba(0, 0, 255, 0.6)',
'rgba(255, 127, 80, 0.6)',
'rgba(128, 128, 128, 0.8)'
];
for (var i = 0; i < max; i++) {
for (var j = 0; j < activities.length; j++) {
var obj = {};
obj["backgroundColor"] = Array.apply(null, Array(names.length))
.map(String.prototype.valueOf, colors[j]);
//obj[borderColor] = 'rgba(255,255,255,1)';
obj["borderWidth"] = 1;
obj["data"] = [];
obj["stack"] = "dummy";
$.each(data, function(key, value) {
if (undefined !== value[i]) {
if (value[i]["title"] === activities[j]) {
obj["data"].push(value[i]["duration"]);
} else {
obj["data"].push(0);
}
} else {
obj["data"].push(0);
}
});
myDataSets.push(obj);
}
}
$("#statsChart").show();
$("#mainChart").html("");
$("#mainChart").append('<canvas id="statsChart" height="70%"></canvas>');
var myBarChart = new Chart($("#statsChart"), {
type: 'horizontalBar',
data: {
labels: names,
datasets: myDataSets
},
options: {
scales: {
xAxes: [{
stacked: true,
ticks: {
min: 7
}
}],
yAxes: [{
stacked: true
}]
},
legend: {
display: false
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.yLabel;
}
}
}
}
});
}
}
});
};
Thanks.
I believe that this is a bug with the current Chart.js version.
As a workaround you could use a callback at the tick of you xAxes like this:
options: {
scales: {
xAxes: [{
stacked: true,
ticks: {
min: 0,
callback: function(value, index, values) {
return value + 7;
}
}
}],
...
For more details on callbacks have a look at the documentation.
options: {
scales: {
xAxes: [{
display: true,
ticks: {
suggestedMin: 7
}
}]
}
}
This will work for both Vertical and Horizontal
options:{
scales: {
xAxes: [{
ticks: {
suggestedMin: 0,
suggestedMax: 100
}
}],
yAxes: [{
ticks: {
suggestedMin: 0,
suggestedMax: 100
}
}],
},
}

Highcharts :Donut chart overlaps data labels

I'm working on a donut chart type, with the Highcharts library.
As you can see in the image below, some of the inner data labels are overlapped.
I've been playing with the parameter "distance" but doesn't fix this.
Find attached the code below,
// Create the chart
$(container).highcharts({
chart: {
type: 'pie'
},
credits: {
enabled: false
},
exporting: {
buttons: {
contextButton: {
symbol: 'url(/icon-turn-down.png)'
}
}
},
title: {
text: _title,
margin: 50
},
plotOptions: {
pie: {
shadow: false,
center: ['50%', '50%']
}
},
tooltip: {
formatter: function() {
var s = this.point.name.split('.');
if (s.length == 1) {
return this.y > 1? '<b>'+this.point.name+':</b> '+Highcharts.numberFormat(this.point.y) : null;
}
return this.y > 1? s[0]+'<br /><b>'+$.trim(s[1])+':</b> '+Highcharts.numberFormat(this.point.y) : null;
}
},
series: [{
name: '',
data: innerData,
size: '80%',
dataLabels: {
formatter: function() {
return this.y > 0 ? this.point.name : null;
},
color: 'white',
distance: -50
}
}, {
name: '',
data: outerData,
size: '100%',
innerSize: '80%',
dataLabels: {
formatter: function() {
var s = this.point.name.split('.');
if (s.length == 1) {
return this.y > 1 ? '<b>'+ this.point.name+':</b> '+ Highcharts.numberFormat(this.point.y) : null ;
}
s = this.point.name.substring(this.point.name.indexOf(".")+2);
return this.y > 1 ? '<b>'+ s+':</b> '+ Highcharts.numberFormat(this.point.y): null;
},
style: {
fontSize: "10px",
fontColor: "#000000"
}
}
}]
});
Finally, I found a solution, which is playing with the "startangle" attribute.
series: [{
name: '',
data: innerData,
startAngle:110,
size: '80%',
dataLabels: {
formatter: function() {
return this.y > 0 ? this.point.name : null;
},
color: 'white',
distance: -45
}, {
...
Distance parameter cannot be applied for each point, only general, so only what comes to my mind is iteared on each datalabel and use translate() function, or use formatter, apply CSS class and dhten use top/left parameter for each element. But will be helpful if you recreate your example as fiddle.