Related
I am implementing charts in our sites, Here using chartkick plugin. But some customization is not supported by chartkick, But we can use chartjs, highchart and google chart by using import options indirectly. chartkick is support the above charts in its configuration.
So we choose chartjs, Here we are customizing legend and tooltip. Found the options in chartjs but unable to implement in chartkick helper.
Need your help guys, here i am facing issue like unable to mention the customization options in rails tag. Because found customization options by using javascript, but i need to add this options inside rails tag<%= %>
These are things have used for implementation.
chart js version 2.9.4
added chartkick by added gem 'chartkick' to gemfile
added chartkick, require Chart.bundle
using chartjs inside chartkick by use adapter option to the chartkick helper
<%= area_chart data, library: {
legend: {
position: 'right',
labels: {
boxWidth: 15,
boxHeight: 15
}
}
}, id: 'consult-chart', adapter: 'chartjs' %>
Found the options for customizing legend and tooltip.
Added customization in legend is -> added few extra label to normal label
Added customization in tooltip is -> changed background color and added extra text.
The below one is the options for above customization by use of direct chart js implementaion.
<script>
var ctx = document.getElementById("myChart-total");
var myLegendContainer = document.getElementById("legends");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["0", "5", "10", "15", "20", "25"],
datasets: [
{
label: "Revenue",
lineTension: 0,
backgroundColor : "#e969e5",
borderColor : "#d93da9",
//backgroundColor: "#d93da9",
data: [0, 10, 23, 25, 60, 70]
}
]
},
options: {
layout: {
padding: {
bottom: 100
}
},
legend: {
position: 'right',
labels : {
generateLabels: function(chart){
var data = chart.data;
var legends = Array.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
return {
text: dataset.label,
fillStyle: (!Array.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
hidden: !chart.isDatasetVisible(i),
lineCap: dataset.borderCapStyle,
lineDash: dataset.borderDash,
lineDashOffset: dataset.borderDashOffset,
lineJoin: dataset.borderJoinStyle,
lineWidth: dataset.borderWidth,
strokeStyle: dataset.borderColor,
pointStyle: dataset.pointStyle,
// Below is extra data used for toggling the datasets
datasetIndex: i
};
}, this) : [];
var title_o = {
text: 'Past 6 months: $826.53',
strokeStyle: 'transparent',
fillStyle: 'transparent',
lineWidth: 0
};
var title_tw = {
text: 'Month-to-date: $67.91',
strokeStyle: 'transparent',
fillStyle: 'transparent',
lineWidth: 0
};
var title_th = {
text: 'Past 7 days: $26.53',
strokeStyle: 'transparent',
fillStyle: 'transparent',
lineWidth: 0
};
legends.push(title_o);
legends.push(title_tw);
legends.push(title_th);
return legends;
},
boxWidth: 15,
boxHeight: 20
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero:true
},
}],
xAxes: [{
gridLines: {
color: "rgba(0, 0, 0, 0)",
}
}]
},
tooltips: {
yAlign: 'bottom',
callbacks: {
title: function(tooltipItem, data) {
return "September "+data['labels'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
return "$"+data['datasets'][0]['data'][tooltipItem['index']];
},
},
backgroundColor: 'grey'
}
}
});
Here how can add the options for legend and tooltip
For legend customization, this option should be mention inside rails tag =>
legend: {
position: 'right',
labels : {
generateLabels: function(chart){
var data = chart.data;
var legends = Array.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
return {
text: dataset.label,
fillStyle: (!Array.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
hidden: !chart.isDatasetVisible(i),
lineCap: dataset.borderCapStyle,
lineDash: dataset.borderDash,
lineDashOffset: dataset.borderDashOffset,
lineJoin: dataset.borderJoinStyle,
lineWidth: dataset.borderWidth,
strokeStyle: dataset.borderColor,
pointStyle: dataset.pointStyle,
datasetIndex: i
};
}, this) : [];
var title_o = {
text: 'Past 6 months: $826.53',
strokeStyle: 'transparent',
fillStyle: 'transparent',
lineWidth: 0
};
legends.push(title_o);
return legends;
},
boxWidth: 15,
boxHeight: 20
}
},
For tooltip customization, this option should be mention inside rails tag =>
tooltips: {
yAlign: 'bottom',
callbacks: {
title: function(tooltipItem, data) {
return "September "+data['labels'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
return "$"+data['datasets'][0]['data'][tooltipItem['index']];
},
},
backgroundColor: 'grey'
}
==========================================-------------------=========================
But how i need to mention the above options in rails tag, because rails tag no supporting javascript function.
I added inside the quotes, but its not working, added like as below
<%= area_chart data, library: {
layout: {
padding: {
bottom: 1
}
},
legend: {
position: 'right',
labels: {
boxWidth: 15,
boxHeight: 15,
generateLabels: 'function(chart){
var data = chart.data;
var legends = Array.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
return {
text: dataset.label,
fillStyle: (!Array.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
hidden: !chart.isDatasetVisible(i),
lineCap: dataset.borderCapStyle,
lineDash: dataset.borderDash,
lineDashOffset: dataset.borderDashOffset,
lineJoin: dataset.borderJoinStyle,
lineWidth: dataset.borderWidth,
strokeStyle: dataset.borderColor,
pointStyle: dataset.pointStyle,
// Below is extra data used for toggling the datasets
datasetIndex: i
};
}, this) : [];
var title_o = {
text: "Past 6 months: $826.53",
strokeStyle: "transparent",
fillStyle: "transparent",
lineWidth: 0
};
legends.push(title_o);
return legends;
}',
}
},
tooltips: {
yAlign: 'bottom',
callbacks: "{
title: function(tooltipItem, data) {
return data['labels'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
return data['datasets'][0]['data'][tooltipItem['index']];
},
}",
backgroundColor: 'grey'
}
}, id: 'consult-chart', adapter: 'chartjs', width: "500px", height: "341px" %>
Please help me here, how to implement these customization options?
How to put shadow inside of bar chart like box-shadow inset(css) in hightcharts as image below.
Thank you. Have a good day~
enter image description here
You can use two overlap series, one with default shadow property and translate both of them by a few pixels in load event:
Highcharts.chart('container', {
chart: {
...,
events: {
load: function() {
this.series[0].points[0].graphic.attr({
translateX: -2
});
this.series[1].points[0].graphic.attr({
translateX: -2
});
}
}
},
...,
series: [{
...,
data: [100],
shadow: {
color: 'gray',
opacity: 0.8,
width: 2
}
}, {
data: [50]
}]
});
Live demo: http://jsfiddle.net/BlackLabel/b7hp0r6s/
API Reference: https://api.highcharts.com/highcharts/series.bar.shadow
Unfortunately, Highcharts doesn't have an inset shadow implemented in the core. However, it can be done by adding custom logic to Highcharts.SVGElement.prototype.shadow method. Check the code and demo posted below and let me know if something is unclear for you.
Additionally, to add a partial fill to columns with the inner shadow you have to make a custom column elements and insert them to the DOM between shadows and particular points.
Code:
function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
(function(H) {
H.SVGElement.prototype.shadow = function(shadowOptions, group, cutOff) {
var shadows = [],
i, shadow, element = this.element,
strokeWidth, shadowWidth, shadowElementOpacity,
// compensate for inverted plot area
transform,
elemBBox = element.getBBox(),
translateX,
translateY;
if (!shadowOptions) {
this.destroyShadows();
} else if (!this.shadows) {
shadowWidth = H.pick(shadowOptions.width, 3);
shadowElementOpacity = (shadowOptions.opacity || 0.15) /
shadowWidth;
transform = this.parentInverted ?
'(' + H.pick(shadowOptions.offsetY, 1) * -1 + ', ' +
H.pick(shadowOptions.offsetX, 1) * -1 + ')' :
'(' + H.pick(shadowOptions.offsetX, 1) + ', ' +
H.pick(shadowOptions.offsetY, 1) + ')';
if (!shadowOptions.inside) {
for (i = 1; i <= shadowWidth; i++) {
shadow = element.cloneNode(0);
strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
H.attr(shadow, {
stroke: (shadowOptions.color ||
'#000000'),
'stroke-opacity': shadowElementOpacity * i,
'stroke-width': strokeWidth,
transform: 'translate' + transform,
fill: 'none'
});
shadow.setAttribute('class', (shadow.getAttribute('class') || '') + ' highcharts-shadow');
if (cutOff) {
H.attr(shadow, 'height', Math.max(H.attr(shadow, 'height') - strokeWidth, 0));
shadow.cutHeight = strokeWidth;
}
if (group) {
group.element.appendChild(shadow);
} else if (element.parentNode) {
element.parentNode.insertBefore(shadow, element);
}
shadows.push(shadow);
}
} else {
for (i = shadowWidth; i >= 1; i--) {
shadow = element.cloneNode(0);
translateX = i / 2 - shadowOptions.offsetY;
translateY = i / 2 - shadowOptions.offsetX;
H.attr(shadow, {
stroke: (shadowOptions.color ||
'#000000'),
'stroke-opacity': shadowElementOpacity * (shadowWidth - i + 1),
'stroke-width': i,
transform: 'translate(' + translateX + ',' + translateY + ')',
fill: 'none'
});
H.css(shadow, {
width: elemBBox.width - i,
height: elemBBox.height - i,
});
shadow.setAttribute('class', (shadow.getAttribute('class') || '') + ' highcharts-shadow');
if (cutOff) {
H.attr(shadow, 'height', Math.max(H.attr(shadow, 'height') - strokeWidth, 0));
shadow.cutHeight = strokeWidth;
}
if (group) {
group.element.appendChild(shadow);
} else if (element.parentNode) {
insertAfter(shadow, element);
}
shadows.push(shadow);
}
}
this.shadows = shadows;
}
return this;
};
})(Highcharts)
Highcharts.chart('container', {
chart: {
type: 'column',
inverted: true,
events: {
render: function() {
var chart = this,
yAxis = chart.yAxis[0],
partialFillWidth,
elem,
bBox;
if (chart.customElements && chart.customElements.length) {
chart.customElements.forEach(custElem => {
custElem.parentNode.removeChild(custElem);
})
chart.customElements.length = 0;
} else {
chart.customElements = [];
}
chart.series[0].points.forEach(point => {
bBox = point.graphic.getBBox();
elem = point.graphic.element.cloneNode(0);
partialFillWidth = yAxis.toPixels(point.partialFill);
Highcharts.attr(elem, {
fill: point.partialFillColor,
transform: 'translate(0, ' + (bBox.height - (point.partialFill / point.y) * bBox.height) + ')'
});
Highcharts.css(elem, {
height: (point.partialFill / point.y) * bBox.height
});
insertAfter(elem, point.graphic.element);
chart.customElements.push(elem);
});
}
}
},
title: {
text: 'Efficiency Optimization by Branch'
},
xAxis: {
categories: [
'Seattle HQ',
'San Francisco',
'Tokyo'
]
},
yAxis: [{
min: 0,
title: {
text: 'Employees'
}
}, {
title: {
text: 'Profit (millions)'
},
opposite: true
}],
legend: {
shadow: false
},
tooltip: {
shared: true
},
plotOptions: {
column: {
grouping: false,
shadow: false,
borderWidth: 0,
pointPadding: 0,
groupPadding: 0
}
},
series: [{
color: '#efefef',
id: 'main',
data: [{
y: 120,
partialFill: 100,
partialFillColor: '#bbb'
}, {
y: 50,
partialFill: 10,
partialFillColor: '#bbb'
}, {
y: 70,
partialFill: 20,
partialFillColor: '#bbb'
}],
pointPadding: 0.4,
shadow: {
color: 'rgba(0, 0, 0, 0.5)',
opacity: 0.3,
width: 5,
offsetX: 0,
offsetY: 0,
inside: true
}
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container"></div>
Demo:
https://jsfiddle.net/BlackLabel/kvrjd48w/
API reference:
https://api.highcharts.com/highcharts/chart.events.render
https://api.highcharts.com/class-reference/Highcharts.SVGElement
https://api.highcharts.com/class-reference/Highcharts#.attr
I have a treemap made of
a big container
with an element
with an element
with an element which is itself made of
an element
an element
another big container
Highcharts.chart('container', {
series: [{
type: "treemap",
animation: false,
data: [
// first big category
{
id: 'B',
name: 'B'
},
{
name: 'Anne',
parent: 'B',
value: 4
}, {
name: 'Peter',
parent: 'B',
value: 1
},
// below is a member of forst big category, but with sub-categories
{
name: 'aaa container',
parent: 'B',
id: 'aaa'
}, {
name: 'Anneinaaa',
parent: 'aaa',
value: 1
}, {
name: 'Rickinaaa',
parent: 'aaa',
value: 3
},
// second big category
{
name: 'Susanne',
parent: 'Kiwi',
value: 2,
color: '#9EDE00'
}
]
}],
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/treemap.js"></script>
<div id="container"></div>
I would like to highlight the fact that there is a container for Rickinaaa and Anneinaaa, with a description.
Right now Rickinaaa and Anneinaaa are at the same level as Anne and Peter, despite the fact that it is their container (the one I do not know how to show) which should be at their level.
An example from ZingCharts which shows this multilayer presentation:
It is much easier to see the box-in-a-box structure.
Is there a way to achieve this in Highcharts? Specifically, how could I have a visible container labelled aaa container which would encompass the rectangles Rickinaaa and Anneinaaa
It can be done by using custom positioning algorithm for treemap. The process is described here: https://www.highcharts.com/docs/chart-and-series-types/treemap (ADD YOUR OWN ALGORITHM section).
I created simplified algorithm for demo purposes (some values are hardcoded):
// Custom positioning algorithm
function myFunction(parent, children) {
childrenAreas = [];
Highcharts.each(children, function(child) {
// Do some calculations
var newLeaf = null;
if (child.id === 'A') {
newLeaf = {
x: 0,
y: 0,
width: 50,
height: 50
};
} else if (child.id === 'B') {
newLeaf = {
x: 50,
y: 0,
width: 50,
height: 50
};
} else if (child.name === 'Rick') {
newLeaf = {
x: parent.x + 10,
y: parent.y + 10,
width: parent.width - 20,
height: (parent.height - 20) / 2
}
} else if (child.name === 'Peter') {
newLeaf = {
x: parent.x + 10,
y: parent.y + 30,
width: parent.width - 20,
height: (parent.height - 20) / 2
}
} else if (child.name === 'Anne') {
newLeaf = {
x: parent.x + 10,
y: 10,
width: parent.width - 20,
height: parent.height - 20
}
}
if (newLeaf) {
childrenAreas.push(newLeaf);
}
});
return childrenAreas;
};
Highcharts.seriesTypes.treemap.prototype.myCustomAlgorithm = myFunction;
By default Highcharts assigns color fill attribute only for the nodes of the Highest level - all other nodes have it set to none. It can be changed manually via CSS:
.highcharts-internal-node {
fill: #bada55
}
I also did a small change in the core code so that parent levels are drawn underneath the child ones:
(function(H) {
var grep = H.grep,
each = H.each,
seriesTypes = H.seriesTypes;
H.seriesTypes.treemap.prototype.drawPoints = function() {
var series = this,
points = grep(series.points, function(n) {
return n.node.visible;
});
each(points, function(point) {
var groupKey = 'level-group-' + point.node.levelDynamic;
if (!series[groupKey]) {
series[groupKey] = series.chart.renderer.g(groupKey)
.attr({
// CHANGED FROM: zIndex: 1000 - point.node.levelDynamic
zIndex: 1000 + point.node.levelDynamic // #todo Set the zIndex based upon the number of levels, instead of using 1000
})
.add(series.group);
}
point.group = series[groupKey];
});
// Call standard drawPoints
seriesTypes.column.prototype.drawPoints.call(this);
// If drillToNode is allowed, set a point cursor on clickables & add drillId to point
if (series.options.allowDrillToNode) {
each(points, function(point) {
if (point.graphic) {
point.drillId = series.options.interactByLeaf ? series.drillToByLeaf(point) : series.drillToByGroup(point);
}
});
}
}
})(Highcharts);
Live demo: https://jsfiddle.net/BlackLabel/wfed4jeo/
Code is as below
chart: {
type: "funnel",
marginBottom: 25,
backgroundColor: "transparent",
events: {
load: function() {
var chart = this;
Highcharts.each(chart.series[0].data, function(p, i) {
chart.options.labels.items.push({
html: "less confident" + i,
style: { left: 550, top: 50 }
});
p.dataLabel.attr({
x: (chart.plotWidth - chart.plotLeft) / 2,
"text-anchor": "middle"
});
});
}
}
},
I see that you're trying to add a label for every point. Highcharts has build in functionality for this called data labels: https://api.highcharts.com/highcharts/series.line.dataLabels
Another approach is to use SVGRenderer.label: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#label
How to implement $(this).stop(); in jqueryUI
graph.hover(function() {
wrap
$(this).stop();
.animate( { height: "hide" }, 2000, name )
},
function() {
wrap
$(this).stop();
.animate( { height: "show" }, 2000, name );
});
Like this :
graph.hover(function() {
$(this).stop().animate( { height: "hide" }, 2000, function(){//Callback})
},
function() {
$(this).stop().animate( { height: "show" }, 2000, function(){//Callback});
});