I want to set intervals of negative and positive axes differently like my data in positive have values around 4000000 and in negative I have -2, -5 , -10 ..etc such values and they all are dynamic .
What's the best way to do that except Tick positioner? or with tick positioner?
Using Highcharts in Angular
You can use two y-axes and assign series to the appropriate one based on values.
yAxis: [{
height: '50%',
min: 0
}, {
top: '50%',
height: '50%',
offset: 0,
max: 0
}],
series: [{
data: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
}, {
data: [0, -1, 0, -2, -2, -3, -2, -5, 0, -2],
yAxis: 1,
}]
Live demo: http://jsfiddle.net/BlackLabel/0zsnpgou/
API Reference: https://api.highcharts.com/highcharts/yAxis
I'm using combination chart with four different data arrays in series and each one them is expected to have negative values
this is my chart
the code here
export const getAirlinesChartOption = (data) => {
let val;
console.log('data',data)
let tpSegments = data.map((x) => x.tpSegments);
let amadeusSegments = data.map((x) => x.amadeusSegments);
let sabreSegments = data.map((x) => x.sabreSegments);
let lytpSegments = data.map((x) => x.lytpSegments);
console.log('tpSegments',tpSegments)
console.log('amadeusSegments',amadeusSegments)
console.log('sabreSegments',sabreSegments)
console.log('lytpSegments',lytpSegments)
const allValues =[]
tpSegments.map((x,index)=>{
allValues.push(tpSegments[index])
allValues.push(amadeusSegments[index])
allValues.push(sabreSegments[index])
allValues.push(lytpSegments[index])
})
console.log('allValues',allValues)
const neg = allValues.filter(function (v) {
return v < 0;
}),
pos = allValues.filter(function (v) {
return v > 0;
});
let positiveCount = pos.length;
let negativeCount = neg.length;
let posMax = Math.max(...pos)
let negMax = Math.max(...neg)
console.log('pos',pos)
console.log('neg',neg)
console.log('posMax',posMax)
console.log('negMax',negMax)
let sortedPosArray = pos.sort(function(a, b) {
return a - b;
});
let sortedNegArray = neg.sort(function(a, b) {
return a - b;
});
let tickArray = sortedNegArray.concat(sortedPosArray)
console.log('sortedPosArray',sortedPosArray)
console.log('sortedNegArray',sortedNegArray)
console.log('tickArray',tickArray)
console.log('positiveCount',positiveCount)
console.log('negativeCount',negativeCount)
let obj: Highcharts.Options = {
credits: {
enabled: false,
},
chart: {
type: "column",
height: 180,
reflow: false,
},
title: {
text: null,
},
legend: {
padding: 0,
itemMarginTop: -15,
itemMarginBottom: -15,
itemHoverStyle: {
color: "#83858e",
},
itemStyle: {
fontSize: "10px",
color: "#83858e",
fontWeight: "light",
},
},
xAxis: {
categories: data.map(x=>x.airline),
labels: {
style: {
color: "#b6bbc0",
fontSize: "10px",
},
},
},
yAxis: {
gridLineDashStyle: "Dash",
labels: {
formatter: function () {
if (this.value >= 1000 || this.value <= -1000) {
val = Highcharts.numberFormat(this.value / 1000, 0) + "K"
return val;
}
else {
val = this.value
return val;
}
},
style: {
color: "#b6bbc0",
fontSize: "10px",
},
},
title: {
text: "",
},
// tickInterval:1000,
// tickPositions: tickArray,
min: negMax<0 && negMax !== -Infinity ?negMax:0,
max: posMax>0 && posMax !== -Infinity?posMax:0,
tickPositioner: function () {
var positions = [],
tick = Math.floor(this.min),
increment = Math.ceil((Math.abs(this.max) - Math.abs(this.min)) / 10);
console.log('increment',increment)
if (this.max !== null && this.min !== null) {
console.log('min',this.min);
for (tick; tick - increment <= this.max; tick += increment) {
positions.push(tick);
}
}
return positions;
}
},
plotOptions: {
series: {
events: {
legendItemClick: function (e) {
e.preventDefault();
},
},
},
},
tooltip: {
pointFormatter: function(){ return '' +
'<span style="color:' + this.color + '">' + this.series.name + '</span>: <b>' + this.y.toLocaleString() +'</b>'
},
//headerFormat: '<span style="font-size:11px">{category}</span><br>',
},
series: [
{
name: "TP",
type: "column",
color: "#01DFA5",
data: data.map(x=>Number(x.tpSegments)),
pointWidth: 5,
groupPadding:0.28,
borderRadius: 5,
},
{
name: "1S",
type: "column",
color: "#5858FA",
data:data.map(x=>Number(x.sabreSegments)),
pointWidth: 5,
groupPadding:0.28,
borderRadius: 5,
},
{
name: "1A",
type: "column",
color: "#11cdef",
data: data.map(x=>Number(x.amadeusSegments)),
pointWidth: 5,
groupPadding:0.28,
borderRadius: 5,
},
{
type: "line",
name: "LYTP",
grouping: false,
color: "#000000",
data: data.map(x=>Number(x.lytpSegments)),
borderRadius: 5,
pointRange:1,
marker: {
symbol: "triangle",
},
},
],
};
return obj;
};
Related
I am trying to get the segments to start at 0 and go up (if positive) and down (if negative) and start at the 0 value of the tick.
This is what I have so far
And I aiming for this...
And here's my code so far
const data = {
datasets: [
{
data: [100, 19, 3, 50, -20, -100],
borderWidth: 1,
},
],
};
const options = {
datasets: {
polarArea: {
backgroundColor: function (context: {
dataIndex: number;
dataset: { data: { [x: string]: any } };
}) {
const index = context.dataIndex;
const value = context.dataset.data[index];
return value < 0 ? 'red' : 'green';
},
},
},
scales: {
r: {
ticks: {
color: 'red',
beginAtZero: true,
z: 1,
},
},
},
};
return <PolarArea data={data} options={options} />;
I have create a custom series type to display the labels in Y Axis. When the label is large, then text is overlapping the main grid. I need to clip that overlapping text and also need to provide a scrollbar to display the remaining text. See the below image for better understanding of my question.
options = {
.......
grid: {
height: 250
},
yAxis: {
axisTick: { show: false },
splitLine: { show: false },
axisLine: { show: false },
axisLabel: { show: false },
min: 0,
max: this.labelData.length + 1,
},
series: [{
type: 'custom', // This is for rendering the main content (Gantt Chart)
renderItem: this.renderGanttItemClosure(),
itemStyle: {
opacity: 0.8
},
encode: {
x: [1, 2],
y: 0,
},
data: this.data
},
{
type: 'custom', // This is for rendering the label
renderItem: this.renderAxisLabelItem,
itemStyle: {
opacity: 0.8
},
encode: {
x: -1,
y: 0,
},
data: this.labelData,
}]
};
function renderAxisLabelItem(params: any, api: any) {
var categoryLevel = api.value(0);
var start = api.coord([0, categoryLevel]);
var barHeight = api.size([0, 1])[1] * 0.6;
var y = start[1];
if (y < params.coordSys.y + 5) {
return;
}
// M0,0 L0,150 L200,75 Z - Right arrow
// M0,0 L75,200 L150,0 Z - Down arrow
const labelItem = {
type: 'group',
position: [
10,
y
],
children: [] as any[]
};
var isExpanded = api.value(3);
const labelExpandIndicator = {
type: 'path',
shape: {
d: isExpanded ? 'M0,0 L75,200 L150,0 Z' : 'M0,0 L0,150 L200,75 Z',
x: 0,
y: -5,
width: 10,
height: 10,
layout: 'cover'
},
style: {
fill: '#000'
}
};
var hasChildren = api.value(2);
if (hasChildren) {
labelItem.children.push(labelExpandIndicator);
}
const hierarchyLevel = api.value(4);
const labelText = {
type: 'text',
style: {
x: 20 + (hierarchyLevel * 20),
y: 7,
text: api.value(1),
textVerticalAlign: 'bottom',
textAlign: 'left',
textFill: '#000'
}
};
labelItem.children.push(labelText);
return labelItem;
}
Demo code
Below is the full demo code. Just copy paste the below code in eCharts Editor
labelData = [{
name: "Application A to B",
value: [
2, // Category Level. Higher is on top.
"Application A to Application B", // Label Name
true, // Is there children
true, // Is expanded
0 // Hierarchy level
]
}, {
name: "Application B to Cosmos",
value: [
1,
"Application B to Cosmos",
false,
false,
1
]
}];
data = [{
name: "Application A to B",
value: [
2,
100,
1000,
1000
],
itemStyle: {
normal: {
color: '#7b9ce1'
}
}
}, {
name: "Application B processing",
value: [
1,
200,
700,
500
],
itemStyle: {
normal: {
color: '#bd6d6c'
}
}
}];
option = {
title: {
text: 'Dependency',
left: 'center'
},
tooltip: {
confine: true,
formatter: function (params) {
return params.marker + params.name + ': ' + params.value[3] + ' ms';
}
},
dataZoom: [{
type: 'slider',
filterMode: 'weakFilter',
showDataShadow: false,
top: 360,
labelFormatter: ''
}, {
type: 'inside',
filterMode: 'weakFilter'
},
{
type: 'slider',
zoomLock: true,
width: 10,
right: 10,
top: 70,
bottom: 20,
start: 95,
end: 100,
handleSize: 0,
showDetail: false,
}],
grid: {
height: 250
},
xAxis: {
min: 100,
scale: true,
axisLabel: {
formatter: function (val) {
return val + ' ms';
}
}
},
yAxis: {
axisTick: { show: false },
splitLine: { show: false },
axisLine: { show: false },
axisLabel: { show: false },
min: 0,
max: labelData.length + 1,
},
series: [{
type: 'custom',
renderItem: renderGanttItem,
itemStyle: {
opacity: 0.8
},
encode: {
x: [1, 2],
y: 0,
},
data: this.data,
zlevel: 10
},
{
type: 'custom',
renderItem: renderAxisLabelItem,
itemStyle: {
opacity: 0.8
},
encode: {
x: -1,
y: 0,
},
data: this.labelData,
zlevel: 5
}]
};
merge = {};
mergeData = {};
function renderAxisLabelItem(params, api) {
var categoryLevel = api.value(0);
var start = api.coord([0, categoryLevel]);
var barHeight = api.size([0, 1])[1] * 0.6;
var y = start[1];
if (y < params.coordSys.y + 5) {
return;
}
// M0,0 L0,150 L200,75 Z - Right arrow
// M0,0 L75,200 L150,0 Z - Down arrow
const labelItem = {
type: 'group',
position: [
10,
y
],
children: []
};
var isExpanded = api.value(3);
const labelExpandIndicator = {
type: 'path',
shape: {
d: isExpanded ? 'M0,0 L75,200 L150,0 Z' : 'M0,0 L0,150 L200,75 Z',
x: 0,
y: -5,
width: 10,
height: 10,
layout: 'cover'
},
style: {
fill: '#000'
}
};
var hasChildren = api.value(2);
if (hasChildren) {
labelItem.children.push(labelExpandIndicator);
}
const hierarchyLevel = api.value(4);
const labelText = {
type: 'text',
style: {
x: 20 + (hierarchyLevel * 20),
y: 7,
text: api.value(1),
textVerticalAlign: 'bottom',
textAlign: 'left',
textFill: '#000'
}
};
labelItem.children.push(labelText);
return labelItem;
}
function renderGanttItem(params, api) {
var categoryIndex = api.value(0);
var start = api.coord([api.value(1), categoryIndex]);
var end = api.coord([api.value(2), categoryIndex]);
var coordSys = params.coordSys;
var barLength = end[0] - start[0];
// Get the heigth corresponds to length 1 on y axis.
var barHeight = api.size([0, 1])[1] * 0.6;
var x = start[0];
var y = start[1] - barHeight / 2;
var rectNormal = echarts.graphic.clipRectByRect({
x: x, y: y, width: barLength, height: barHeight
}, {
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
});
return {
type: 'group',
children: [{
type: 'rect',
shape: rectNormal,
style: api.style()
}]
};
}
I don't really have a question but just to share my knowledge here.
This is a knowledge sharing on how to auto scale font size in echarts.js based on the div size.
let myChart = echarts.init(document.getElementById('myChart'));
function autoFontSize() {
let width = document.getElementById('myChart').offsetWidth;
let newFontSize = Math.round(width / 11);
console.log(`Current width : ${width}, Updating Fontsize to ${newFontSize}`);
return newFontSize;
};
const fruits = [{
value: 100,
name: "Apple(s)"
},
{
value: 200,
name: "Banana(s)"
}
];
const sum = fruits.reduce(function(prev, current) {
return prev + current.value
}, 0);
let myChartOption = {
grid: {
left: 0,
top: 0,
right: 0,
bottom: 0
},
tooltip: {
trigger: 'item',
textStyle: {
fontSize: '15',
},
formatter: 'You have {c} {b}'
},
legend: {
orient: 'vertical',
x: 'right',
y: 'bottom',
padding: 0,
itemGap: 0,
textStyle: {
fontSize: '15',
},
formatter: function(name) {
var targetValue = 0;
fruits.forEach(function(c) {
if (c.name == name) {
targetValue = c.value;
}
});
return targetValue + ' ' + name;
}
},
series: [{
name: 'fruits',
type: 'pie',
center: ['50%', '40%'],
radius: ['50%', '60%'],
avoidLabelOverlap: false,
label: {
position: 'center',
textStyle: {
fontSize: autoFontSize(),
fontWeight: 'bold'
},
color: 'black',
formatter: '' + sum,
},
labelLine: {
normal: {
show: false
}
},
data: fruits,
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
};
myChart.setOption(myChartOption);
$(window).on('resize', function() {
if (myChart != null && myChart != undefined) {
myChart.resize({
width: 'auto',
height: 'auto'
});
myChart.setOption({
series: {
label: {
textStyle: {
fontSize: autoFontSize()
}
}
}
})
}
});
#myChart {
width: 100%;
min-height: 330px;
margin: 0 auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.6.0/echarts.min.js"></script>
<div id="myChart"></div>
Hi I'm looking to create a pie chart with highchart js that expands twolayers, and rotates to the center whenever I click a section.
So far I have a pie chart that expands one layer, and a click function that brings the arcs to the center (-90). I also have a click function that rotates the pie by degrees. My inner arc stays in the center and im having a hard time moving the arc to the same position of the out rings. The inner arc do not follow the click rotate aswell.
I would like to make a pie that rotates smoothly to center (-90) and expands with two extra layers. with the inner arch to follow the outer arch and be in the same starting point as the outer arch
Thank you in advance
here is what my code executes and looks like :
pie chart with what im currently running
Here is my script
$(function () {
var lastHighlight = -1;
var lastPos = [10,10,10];
$('#mouseMoveDiv').click(function () {
var theChart = $('#container').highcharts();
var currStartAngle = theChart.series[0].options.startAngle;
//console.log('currStartAngle: ' + currStartAngle);
var newStartAngle = currStartAngle + 5;
if (newStartAngle > 359) {
newStartAngle = 5;
}
//console.log(newStartAngle);
theChart.series[0].update({
startAngle: newStartAngle
});
var someData = theChart.series[0].data;
var N = someData.length;
var highLight = -1;
for (var i = 0; i < N; i++){
var startAngle = someData[i].angle + (((someData[i].percentage/100) * 6.28318)/2);
var dis = 1.5795 - startAngle;
if (lastPos[i] > 0 && dis < 0){
highLight = i;
lastPos[i] = dis;
break;
}
lastPos[i] = dis;
}
if (highLight != -1){
var someRows = $('#dataTable tr');
someRows.eq(lastHighlight).css('backgroundColor','white');
someRows.eq(highLight).css('backgroundColor','yellow');
lastHighlight = highLight;
}
});
$('#container').highcharts({
chart: {
type: 'pie',
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false
},
plotOptions: {
series: {
dataLabels: {
enabled: true,
format: '{point.name}',
center: ["50%", "50%"],
connectorWidth: 0,
startAngle: 90,
animation: false
}
}
},
exporting: {
enabled: false
},
tooltip: {
enabled: false
},
credits: {
enabled: false
},
title: {
text: null
},
series: [{
type: 'pie'
data: [
{ name: 'Planning', y: 33.3 },
{ name: 'Sprints', y: 33.3 },
{ name: 'Release', y: 33.3 }
],
size: '60%',
innerSize: '40%',
point: {
events: {
click: function () {
var chart = this.series.chart,
series = chart.series,
len = series.length,
index = this.x + 1,
i;
for (i = 1; i < len; i++) {
if (i === index) {
series[i].update({
size: '100%',
dataLabels: {
enabled: true
}
}, false);
} else {
series[i].update({
size: '0%',
dataLabels: {
enabled: false
}
}, false);
}
}
var points = this.series.points;
var startAngle = 0;
for (var i = 0; i < points.length; i++) {
var p = points[i];
if (p == this) {
break;
}
startAngle += (p.percentage / 100.0 * 360.0);
}
this.series.update({
startAngle: -startAngle + 90 - ((this.percentage / 100.0 * 360.0) / 2) // center at 180
})
chart.redraw();
}
}
},
dataLabels: {
distance: 90, //distance name
style: {
color: 'Black'
},
enabled: true
},
zIndex: 1
},
{
zIndex: 0,
type: 'pie',
size: '60%',
innerSize: '0%',
data: [{
y: 2,
color: 'rgba(250,0,0,1)',
name: 'Training'
},
{
y: 2,
color: 'rgba(250,0,0,1)',
name: 'Secure'
},
{
y: 8,
color: 'rgba(0,0,0,0)',
dataLabels: {
enabled: false
}
}],
dataLabels: {
distance: -30,
enabled: false,
style: {
color: 'black'
}
},
enableMouseTracking: false
},
{
zIndex: 0,
type: 'pie',
size: '0%',
data: [{
y: 3,
color: 'rgba(0,0,0,0)',
dataLabels: {
enabled: false
}
}, {
y: 1,
color: 'rgba(0,200,0,1)',
name: 'test'
}, {
y: 1,
color: 'rgba(0,200,0,1)',
name: 'test'
}, {
y: 1,
color: 'rgba(0,200,0,1)',
name: 'test'
}, {
y: 3,
color: 'rgba(0,0,0,0)',
dataLabels: {
enabled: false
}
}],
dataLabels: {
distance: -30,
enabled: false
style: {
color: 'black'
}
},
enableMouseTracking: false
},
{
zIndex: 0,
type: 'pie',
size: '0%',
data: [{
y: 6,
color: 'rgba(0,0,0,0)',
dataLabels: {
enabled: false
}
}, {
y: 1,
color: 'rgba(0,0,200,1)',
name: 'test'
}, {
y: 1,
color: 'rgba(0,0,200,1)',
name: 'test'
}, {
y: 1,
color: 'rgba(0,0,200,1)',
name: 'test'
}],
dataLabels: {
distance: -30,
enabled: false,
style: {
color: 'black'
}
},
enableMouseTracking: false
}]
});
});
I suggest to change logic a bit: use one series for each of the circles, and manage manually visibility of the slices instead. For example: http://jsfiddle.net/vkhvvs5d/3/
And to answer the second question, rotate animation is not supported when using series.update(), however it have an easy workaround: http://jsfiddle.net/8x54efu6/3
var chart = $("#container").highcharts(),
pie = chart.series[0];
pie.options.startAngle = new_angle;
pie.isDirty = pie.isDirtyData = true;
chart.redraw();
I am using Kendo chart with two valueAxes.
One valueAxis is all positive values
other can have negative
Range defined in chart is based on the values. I want both the valueAxis to have value "0" as axisCrossingValue.
I tried this with axisCrossingValue but it is not respecting this value for second valueAxis.
var data1 = [6000, 8000];
var data2 = [0.2, -0.3] ;
$scope.chartOptions = {
transitions: false,
legend: {
visible: false
},
chartArea:
{
margin: {
left: 20,
right: 20
},
background: "transparent"
},
seriesDefaults: {
type: "column"
},
series: [
{
type: "column",
stack: true,
name: "A",
color: "#efefef",
axis: "A",
highlight: {
visible: false
},
data: data1
}, {
type: "line",
name: "B",
color: "#008700",
axis: "B",
style: "smooth",
markers: {
visible: false,
border: {
width: 0
}
},
data: data2
}
],
valueAxes: [
{
name: "A",
labels: {
visible: true,
template: "#= kendo.format('{0:n}', value) #",
color: "#888"
},
axisCrossingValue: 0
}, {
name: "B",
labels: {
visible: true,
justified: true,
template: "#= value #",
color: "#888"
},
axisCrossingValue: 0
}
],
categoryAxis: {
labels: {
visible: false
},
categories: $scope.dates,
axisCrossingValues: [0, $scope.dates.length]
},
tooltip: {
}
};
It looks like the chart does not know how to automatically handle crossing at 0 on both axes. I think your best bet is to calculate/set the min and max values of the 2 axes such that 0 is in the same place on both axes:
valueAxis: [
{
name: "A",
axisCrossingValue: 0,
min: -9000,
max: 9000,
color: "#888",
majorGridLines: {
visible: false,
}
},
{
name: "B",
min: -0.5,
max: 0.5,
justified: true,
color: "#888",
majorGridLines: {
visible: false,
}
}
],
DEMO
To do this dynamically, I had to override the default max/min values for each axis with a rounded value calculated from my data sets.
$scope.getChartMaxMin(values, percentages) {
var minValue = 0;
var maxValue = 0;
var minPercent = 0;
var maxPercent = 0;
angular.forEach(values, function (val) {
if (val < minValue) {
minValue = val;
}
if (val > maxValue) {
maxValue = val;
}
})
angular.forEach(percentages, function (percent) {
percent = percent * 100;
if (percent < minPercent) {
minPercent = percent;
}
if (percent > maxPercent) {
maxPercent = percent;
}
})
minValue = intelliRound(Math.floor(minValue));
maxValue = intelliRound(Math.ceil(maxValue));
minPercent = intelliRound(Math.floor(minPercent));
maxPercent = intelliRound(Math.ceil(maxPercent));
var difference = maxValue / maxPercent;
minPercent = minValue / difference;
return {
minValue: minValue,
maxValue: maxValue,
minPercent: minPercent,
maxPercent: maxPercent
}
}
function intelliRound(num) {
var len = (num + '').length;
var result = 0;
if (num < 0) {
var fac = Math.pow(10, len - 2);
result = Math.floor(num / fac) * fac;
}
else {
var fac = Math.pow(10, len - 1);
result = Math.ceil(num / fac) * fac;
}
return result;
}
var values = [40000, 60000, -30000]
var percentages = [3.65,0.010,1.69]
var maxMin = $scope.getChartMaxMin(values, percentages);
$scope.chartOptions = {
series: [
{
type: "column",
stack: true,
name: "A",
color: "#efefef",
axis: "A",
highlight: {
visible: false
},
data: values
}, {
type: "line",
name: "B",
color: "#008700",
axis: "B",
style: "smooth",
markers: {
visible: false,
border: {
width: 0
}
},
data: percentages
}
],
valueAxes: [
{
name: "A",
labels: {
visible: true,
template: "#= kendo.format('{0:n}', value) #",
color: "#888"
min: maxMin[minValue],
max: maxMin[maxValue]
},
}, {
name: "B",
labels: {
visible: true,
justified: true,
template: "#= value #",
color: "#888"
},
min: maxMin[minPercent],
max: maxMin[maxPercent]
}
],
categoryAxis: {
labels: {
visible: false
},
categories: $scope.dates,
axisCrossingValues: [0, $scope.dates.length]
},
};