Chart Js Line chart with fill on click with full information of its legend text - reactjs

I am using chart.js 2.9.3. I have used onClick handler in options as well as getElementAtEvent to achieve what I want but I get the items empty array and the event doesn't have the the information about the area that is clicked. Clicking on each point works fine, but clicking on Area of whole line doesn't give me much information.
Here is the code snippet of my chart.
var chart_canvas = document.getElementById("myChart");
var stackedLine = new Chart(chart_canvas, {
type: 'line',
data: {
labels: ["0.0", "0.2", "0.4", "0.6", "0.8", "1.0"],
fill: true,
datasets: [{
label: 'One',
pointRadius: 3,
data: [.5, .3, .2, .1, .4, .3],
borderWidth: 1
}, {
label: 'Two',
pointRadius: 3,
data: [.0, .1, .2, .4, .1, .4],
borderWidth: 1
}]
},
options: {
responsive: true,
onClick : (event, items) =>{
console.log("event",event);
},
}
});

Finally I tried to solve this using some DOM manipulation to get the information by clicking on area of each filled area of line chart.
Example is here:
https://codepen.io/amiablesyed/pen/RwKxaqE
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.4/dist/Chart.js"></script>
</head>
<body>
<div style="background-color: gainsboro">
Data:<span id="Data"></span>
</div>
<div style="width: 500px; height: 400px">
<canvas id="mainChart" width="700" height="400"> </canvas>
</div>
<script>
var ctx = document.getElementById("mainChart").getContext("2d");
var myChart = new Chart(ctx, {
type: "line",
data: {
labels: [
"Red",
"Blue",
"Yellow",
"Green",
"Purple",
"Orange",
"Pink",
"Black",
"Grey",
],
datasets: [
{
lineTension: 0,
label: "Data A",
data: [11, 12, 1, 3, 1, 1, 3, 5, 2],
backgroundColor: "#ffe8e8",
borderColor: ["#ffe8e8"],
borderWidth: 1,
},
{
lineTension: 0,
label: "Data B",
data: [12, 17, 3, 5, 2, 3, 6, 8, 4],
backgroundColor: "#e2ffcb",
borderColor: ["#e2ffcb"],
borderWidth: 1,
},
{
lineTension: 0,
label: "Data C",
data: [15, 23, 6, 9, 3, 8, 7, 10, 11],
backgroundColor: "#ffe689",
borderColor: ["#ffe689"],
borderWidth: 1,
},
],
},
});
document
.getElementById("mainChart")
.addEventListener("click", function (e) {
areaClick(e);
});
function areaClick(e) {
if (!myChart.scales["y-axis-0"]._gridLineItems) return;
var gridLineH = myChart.scales["y-axis-0"]._gridLineItems[0];
var lenH = myChart.scales["y-axis-0"]._gridLineItems.length;
var width = gridLineH.x2 - gridLineH.x1;
var yMax = myChart.scales["y-axis-0"].max;
var yMaxPixcel = myChart.scales["y-axis-0"].bottom - gridLineH.y1;
var gridLineV = myChart.scales["x-axis-0"]._gridLineItems[0];
var lenV = myChart.scales["x-axis-0"]._gridLineItems.length;
var height = gridLineV.y2 - gridLineV.y1;
var xMax = myChart.scales["x-axis-0"].maxIndex;
var scaleX = width / (lenV - 1);
var scaleY = height / (lenH - 1);
var yPixcel =
yMaxPixcel - (e.pageY - e.target.offsetTop - gridLineH.y1);
var yVal = yMax * (yPixcel / yMaxPixcel);
console.log(yVal);
var curXPixcel = e.pageX - e.target.offsetLeft - gridLineH.x1;
var xVal = Math.floor(curXPixcel / scaleX);
var xAxis = myChart.scales["x-axis-0"];
var label = "Others";
if (xVal < xAxis.maxIndex && xVal >= xAxis.minIndex) {
var x1x2Pixcels = getx1x2Pixcels(xVal, gridLineH.x1);
document.getElementById("Data").innerText = getDataLable(
xVal,
yVal,
x1x2Pixcels,
curXPixcel
);
}
}
function getx1x2Pixcels(xVal, offset) {
var x1x2 = {};
x1x2.x1 =
myChart.scales["x-axis-0"]._gridLineItems[xVal].x1 - offset + 0.5;
x1x2.x2 =
myChart.scales["x-axis-0"]._gridLineItems[xVal + 1].x1 - offset + 0.5;
return x1x2;
}
function getDataLable(xVal, yVal, x1x2Pixcels, curXPixcel) {
var datasetes = myChart.config.data.datasets;
var dataLable = "";
if (datasetes.length > 1) {
for (var i = datasetes.length; i > 0; i--) {
if (myChart.getDatasetMeta(i - 1).hidden) continue;
var dataA = datasetes[i - 1];
var dataALable = dataA.label;
var y1 = dataA.data[xVal];
var y2 = dataA.data[xVal + 1];
var isBelow = IsBelowTheLine(
curXPixcel,
yVal,
x1x2Pixcels.x1,
y1,
x1x2Pixcels.x2,
y2
);
if (isBelow) {
dataLable = isBelow ? dataALable : dataLable;
if (i == 1) {
var isBelowZeroLine = IsBelowTheLine(
curXPixcel,
yVal,
x1x2Pixcels.x1,
0,
x1x2Pixcels.x2,
0
);
dataLable = isBelowZeroLine ? "" : dataLable;
}
} else break;
}
}
return dataLable;
}
function IsBelowTheLine(x, y, x1, y1, x2, y2) {
var v1 = [x2 - x1, y2 - y1];
var v2 = [x2 - x, y2 - y];
var xp = v1[0] * v2[1] - v1[1] * v2[0];
return xp >= 0;
}
</script>
</body>
</html>

Related

Change background color of every second column in Chartjs? [duplicate]

In react-chartjs-2
In Line chart every grid should have different background colors.
Is this achievable with this library?
This is how LineChart should looks:
This is my Code/configuration:
const options = {
responsive: true,
scales: {
y: {
grid: {
backgroundColor: [
'rgba(36, 206, 0, 0.8)',
'rgba(255, 255, 0, .8)',
'rgba(255, 162, 0, 0.8)',
'rgba(36, 206, 0, 0.8)',
],
},
};
Thanks for reading.
You can use an inline plugin to achieve it:
var GradientBgPlugin = {
beforeDraw: function(chart, args, options) {
const ctx = chart.ctx;
const canvas = chart.canvas;
const chartArea = chart.chartArea;
// Chart background
var gradientBack = canvas.getContext("2d").createLinearGradient(0, 250, 0, 0);
gradientBack.addColorStop(0, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.16, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.17, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.25, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.26, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.5, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.51, "rgba(251,221,221,1)");
gradientBack.addColorStop(1, "rgba(251,221,221,1)");
ctx.fillStyle = gradientBack;
ctx.fillRect(chartArea.left, chartArea.bottom,
chartArea.right - chartArea.left, chartArea.top - chartArea.bottom);
}
};
Than just include it in your Chart options:
plugins: [GradientBgPlugin]
The result should be similar to this JSFiddle.
EDIT
For Reach Charts JS 2, you need small changes in setup. You define plugin this way:
const plugins = [{
beforeDraw: function(chart) {
const ctx = chart.ctx;
const canvas = chart.canvas;
const chartArea = chart.chartArea;
// Chart background
var gradientBack = canvas.getContext("2d").createLinearGradient(0, 250, 0, 0);
gradientBack.addColorStop(0, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.16, "rgba(213,235,248,1)");
gradientBack.addColorStop(0.17, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.25, "rgba(226,245,234,1)");
gradientBack.addColorStop(0.26, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.5, "rgba(252,244,219,1)");
gradientBack.addColorStop(0.51, "rgba(251,221,221,1)");
gradientBack.addColorStop(1, "rgba(251,221,221,1)");
ctx.fillStyle = gradientBack;
ctx.fillRect(chartArea.left, chartArea.bottom,
chartArea.right - chartArea.left, chartArea.top - chartArea.bottom);
}
}];
Than you plug it this way:
<Line data={data} plugins={plugins} />
You can see it working fine on CodeSandbox here.
You can write a custom inline plugin, that draws the colors on the chart Area. In the options section you can put an object with all the sections you want, from where to where and which color they need to be
Example:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [100, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
plugins: {
backgrounds: {
hbars: [{
from: 28,
to: 100,
color: "rgb(195, 230, 195)"
},
{
from: 20,
to: 28,
color: "rgb(230, 220, 195)"
},
{
from: 0,
to: 20,
color: "rgb(230, 195, 195)"
}
]
}
}
},
plugins: [{
id: 'backgrounds',
beforeDraw: (chart, args, options) => {
const {
ctx,
chartArea,
scales: {
y
}
} = chart;
options.hbars.forEach((hBar) => {
ctx.save();
ctx.fillStyle = hBar.color;
ctx.fillRect(chartArea.left, y.getPixelForValue(hBar.from), chartArea.right - chartArea.left, y.getPixelForValue(hBar.to) - y.getPixelForValue(hBar.from));
ctx.restore();
})
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.0/chart.js"></script>
</body>
Detailed explanation can be found here: https://medium.com/#omi10859/alternative-background-lines-in-chartjs-a626ce4d3bcb
We can use annotaion plugin with chartjs to create custom elements.
we can use annotation plugin to do this
import annotationPlugin from "chartjs-plugin-annotation";
import {Chart} from 'chart.js';
Chart.register(annotationPlugin);
this code will add a box to our chart
{
type: 'box', #type of draw
drawTime: 'beforeDraw', #this will decide background or foreground
yMin: 5, #value min on y axis
yMax: 10, #value max on y axis
borderColor: 'rgb(242, 244, 248, 0.9)', #border color of the box
borderWidth: 1, #boarder width for box
backgroundColor: '#F2F4F8', #colour of the box
}
# add option while rendering
const options = {
plugins: {annotation: {annotations: background_annotation}
}
this code render this

How to add labels to the bubbles in Bubble Graph of react-chartjs-2 package? [duplicate]

I'm creating a bubble chart using chartjs. I am able to create tooltips that describe each of the bubbles, but users of my chart may not be able to hover over it to see the tooltip. The BubbleData object format doesn't include a label element (I put one in anyway - no luck), I've tried the "labels" element for the Chart Data object (even though the docs say this is for Category labels - you never know!), and everything I can think of to put label on the bubble.
Is there a tooltip configuration that makes all the tooltips visible at all times? This would work for me as well.
Thanks;
Glenn
I was looking for the same thing and figured out how to do it.
add in the datasets the title:"dataTitle3" you want to show.
use the data labeling plugin.
simple code manipulation achieves what you want using
dataset.title
I have made a sample but I think you could find out how and represent the data you want if you play with: external link
new Chart(document.getElementById("bubble-chart"), {
type: 'bubble',
data: {
labels: "Africa",
datasets: [{
label: ["China"],
backgroundColor: "rgba(255,221,50,0.2)",
borderColor: "rgba(255,221,50,1)",
title: "dataTitle1", //adding the title you want to show
data: [{
x: 21269017,
y: 5.245,
r: 15
}]
}, {
label: ["Denmark"],
backgroundColor: "rgba(60,186,159,0.2)",
borderColor: "rgba(60,186,159,1)",
title: "dataTitle2",
data: [{
x: 258702,
y: 7.526,
r: 10
}]
}, {
label: ["Germany"],
backgroundColor: "rgba(0,0,0,0.2)",
borderColor: "#000",
title: "dataTitle3", //adding the title you want to show
data: [{
x: 3979083,
y: 6.994,
r: 15
}]
}, {
label: ["Japan"],
backgroundColor: "rgba(193,46,12,0.2)",
borderColor: "rgba(193,46,12,1)",
title: "dataTitle4", //adding the title you want to show
data: [{
x: 4931877,
y: 5.921,
r: 15
}]
}]
},
options: {
title: {
display: true,
text: 'Predicted world population (millions) in 2050'
},
scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: "Happiness"
}
}],
xAxes: [{
scaleLabel: {
display: true,
labelString: "GDP (PPP)"
}
}]
}
}
});
Chart.plugins.register({
afterDatasetsDraw: function(chart, easing) {
var ctx = chart.ctx;
chart.data.datasets.forEach(function(dataset, i) {
var meta = chart.getDatasetMeta(i);
if (meta.type == "bubble") { //exclude scatter
meta.data.forEach(function(element, index) {
// Draw the text in black, with the specified font
ctx.fillStyle = 'rgb(0, 0, 0)';
var fontSize = 13;
var fontStyle = 'normal';
var fontFamily = 'Helvetica Neue';
ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
// Just naively convert to string for now
var dataString = dataset.data[index].toString();
// Make sure alignment settings are correct
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
var padding = 15;
var position = element.tooltipPosition();
ctx.fillText(dataset.title, position.x, position.y - (fontSize / 2) - padding);
});
} //if
});
}
});
<canvas id="bubble-chart" width="800" height="800"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js" integrity="sha512-ElRFoEQdI5Ht6kZvyzXhYG9NqjtkmlkfYk0wr6wHxU9JEHakS7UJZNeml5ALk+8IKlU6jDgMabC3vkumRokgJA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
ChartJs has a plugin now for this.
https://github.com/chartjs/chartjs-plugin-datalabels
Just install it using nuget or bower and add the reference of it. It wil automatically set z as label
The sytax has changed with chart.js V3 in a few places so I thought I'd share my variation on the chosen answer.
Chart.register({
id: 'permanentLabel',
afterDatasetsDraw: function (chart, args, options) {
var ctx = chart.ctx
chart.data.datasets.forEach(function (dataset, i) {
var meta = chart.getDatasetMeta(i)
if (meta.type == 'bubble') {
meta.data.forEach(function (element, index) {
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
var position = element.tooltipPosition()
ctx.fillText(dataset.data[index].label.toString(), position.x, position.y - dataset.data[index].r - Chart.defaults.font.size)
})
}
})
},
})
I have an some extra code, to avoid overlapping of labels.
var labelPlugin = {
myTimeout: null,
getNewYPostion:function(item, alreadyUsed, fontSize){
for(let i of alreadyUsed){
if((item.y_from >= i.y_from && item.y_from <= i.y_to) || (item.y_to>= i.y_from && item.y_to <= i.y_to)){
if((item.x_from >= i.x_from && item.x_from <= i.x_to) || (item.x_to>= i.x_from && item.x_to <= i.x_to)){
item.y_from=i.y_to+(fontSize*0.1);
item.y_to=item.y_from+fontSize;
return this.getNewYPostion(item, alreadyUsed, fontSize);
}
}
}
return item;
},
afterDatasetsDraw: function (chart, args, options) {
var ctx = chart.ctx;
var that=this;
clearTimeout(this.myTimeout);
this.myTimeout = setTimeout(function () {
var alreadyUsed = [];
chart.data.datasets.forEach(function (dataset, i) {
var txt = dataset.label;
var txtSize = ctx.measureText(txt).width;
var meta = chart.getDatasetMeta(i);
if (meta.type === "bubble") { //exclude scatter
var fontSize = 10;
var fontStyle = 'normal';
var fontFamily = 'Helvetica Neue';
ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
ctx.fillStyle = 'rgb(0, 0, 0)';
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
var padding, position, x_from, x_to, y, y_from, y_to;
meta.data.forEach(function (element, index) {
padding = element.options.radius;
position = element.tooltipPosition();
x_from = position.x + padding + 5; // left
x_to = x_from + txtSize; // left
y = position.y; // top
y_from = y - (fontSize * 0.5);
y_to = y + (fontSize * 0.5);
var item={
'y_from': y_from,
'y_to': y_to,
'x_from': x_from,
'x_to': x_to,
};
item=that.getNewYPostion(item, alreadyUsed, fontSize);
alreadyUsed.push(item);
ctx.fillText(txt, item.x_from, item.y_from+(0.5*fontSize));
});
}
});
}, 500);
}
};
In 2022 the current version is 3.9.1 here is a working snippet:
const $canvas = document.getElementById('chart')
const popData = {
datasets: [{
label: ['Deer Population'],
data: [{
x: 100,
y: 0,
r: 25,
label: 'Russia',
}, {
x: 60,
y: 30,
r: 20,
label: 'China',
}, {
x: 40,
y: 60,
r: 25,
label: 'Canada',
}, {
x: 80,
y: 80,
r: 40,
label: 'US',
}, {
x: 20,
y: 30,
r: 25,
label: 'Africa',
}, {
x: 0,
y: 100,
r: 5,
label: 'Europe',
}],
backgroundColor: "#FF9966"
}]
};
const bubbleChart = new Chart($canvas, {
type: 'bubble',
data: popData
});
const fontSize = Chart.defaults.font.size
Chart.register({
id: 'permanentLabel',
afterDatasetsDraw: (chart, args, options) => {
const ctx = chart.ctx
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
chart.data.datasets.forEach((dataset, i) => {
const meta = chart.getDatasetMeta(i)
if (meta.type !== 'bubble') return
meta.data.forEach((element, index) => {
const item = dataset.data[index]
const position = element.tooltipPosition()
ctx.fillText(item.label.toString(), position.x, position.y - item.r - fontSize)
})
})
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<canvas id="chart" width="600" height="180"></canvas>

Is There any way to show image on top of the stacked bar, Am getting image on every color Instead of that i need only on top of each bar

Am returning Image inside labels, Its rendering image on every color , But i need only on top of the bar and image should be dynamically change.
this.options = {
legend: {
display:false,
},
plugins: {
datalabels: {
display: false,
},
labels: {
render: (args) => {
return { src: "https://i.stack.imgur.com/9EMtU.png", width: 16, height: 16 };
}
}
},
You could get rid of chartjs-plugin-labels and directly use the Plugin Core API. It offers a range of hooks that can be used for performing custom code. You can for example use the afterDraw hook to draw the images through CanvasRenderingContext2D.drawImage().
afterDraw: chart => {
let ctx = chart.chart.ctx;
let xAxis = chart.scales['x-axis-0'];
let yAxis = chart.scales['y-axis-0'];
xAxis.ticks.forEach((value, index) => {
let sum = chart.chart.data.datasets.filter(ds => !ds._meta[0].hidden).reduce((sum, ds) => sum + ds.data[index], 0);
let x = xAxis.getPixelForTick(index);
let y = yAxis.getPixelForValue(sum);
let image = new Image();
image.src = images[index];
ctx.drawImage(image, x - 12, y - 25);
});
}
To make sure that the top located image does not overlap the legend, the following code should be invoked prior to create the chart.
Chart.Legend.prototype.afterFit = function() {
this.height = this.height + 25;
};
Please take a look at below runnable code and see how it works.
const images = ['https://i.stack.imgur.com/2RAv2.png', 'https://i.stack.imgur.com/Tq5DA.png', 'https://i.stack.imgur.com/3KRtW.png', 'https://i.stack.imgur.com/iLyVi.png'];
Chart.Legend.prototype.afterFit = function() {
this.height = this.height + 25;
};
new Chart("canvas", {
type: 'bar',
plugins: [{
afterDraw: chart => {
let ctx = chart.chart.ctx;
let xAxis = chart.scales['x-axis-0'];
let yAxis = chart.scales['y-axis-0'];
xAxis.ticks.forEach((value, index) => {
let sum = chart.chart.data.datasets.filter(ds => !ds._meta[0].hidden).reduce((sum, ds) => sum + ds.data[index], 0);
let x = xAxis.getPixelForTick(index);
let y = yAxis.getPixelForValue(sum);
let image = new Image();
image.src = images[index];
ctx.drawImage(image, x - 12, y - 25);
});
}
}],
data: {
labels: ["A", "B", "C", "D"],
datasets: [{
label: 'X',
backgroundColor: "rgba(220,220,220,0.5)",
data: [50, 40, 23, 45]
}, {
label: 'Y',
backgroundColor: "rgba(151,187,205,0.5)",
data: [50, 40, 78, 23]
}, {
label: 'Z',
backgroundColor: "rgba(82,154,190,0.5)",
data: [50, 67, 78, 23]
}]
},
options: {
responsive: true,
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas" height="100"></canvas>

Stacked Highcharts- How to plot a given point and remove color from the stack block

I need to plot users office timings (in and out time) of a day in a graph using Angular JS.
For example I have reached office at 10 and then gone out for lunch at 1, then again came at 2 and then gone out at 2:30 for some work and so on.....
So in graph, y axis should show time from 10 to 6 and it should plot time on graph, like 1st it should point at 10, then on 1, then on 2 and then on 2:30 and so on...
So my questions are:
1) Using which graph, this could be achieved in a single bar?
2) I am using stacked highchart, however since stacked chart add the points, I am sending difference between the two data, so first I am sending 10, another I want to point at 1, so I am sending 3 and so on..., however it fill the entire block with a color, like from 10-1 one color, 1-2 one color and so on..., what I need is, first it should point at 10 then at 1,then at 2...and so on it should not fill it with any color.
What I have achieved so far is :https://plnkr.co/edit/CgnFfTbJ3BkyjHzErQGk?p=preview
but what I want to achieve is something like this
Please help.
You could also check the code below:
<html>
<head>
<title>Highcharts Tutorial</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
</head>
<body>
<div id="container" style="width: 550px; height: 400px; margin: 0 auto"> </div>
<script language="JavaScript">
$(document).ready(function() {
var chart = {
type: 'column'
};
var title = {
text: 'Stacked column chart'
};
var xAxis = {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
};
var yAxis ={
min: 10,
max:18,
tickInterval:1,
title: {
text: 'Total fruit consumption'
},
stackLabels: {
enabled: false,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
};
var legend = {
enabled:false
};
var tooltip = {
enabled:false
};
var plotOptions = {
column: {
stacking: 'normal',
dataLabels: {
enabled: false,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px black'
}
}
}
};
var credits = {
enabled: false
};
var series= [
{ name: 'John',
data: [1]
},
{ name: 'John',
data: [0.5]
},
{ name: 'John',
data: [1]
},
{
name: 'Jane',
data: [3]
}, {
name: 'Joe',
data: [10]
}];
var json = {};
json.chart = chart;
json.title = title;
json.xAxis = xAxis;
json.yAxis = yAxis;
json.legend = legend;
json.tooltip = tooltip;
json.plotOptions = plotOptions;
json.credits = credits;
json.series = series;
$('#container').highcharts(json);
});
</script>
</body>
</html>
</script>
</body>
</html>
Here is a example using columnrange series.
Live example: https://jsfiddle.net/mzb3bpg2/
const options = {
chart: {
type: 'columnrange'
},
series: [{
name: 'Temperatures',
data: [{
borderWidth: 2,
borderColor: Highcharts.getOptions().colors[1],
color: 'rgba(0,0,0,0)',
x: 0,
low: 0,
high: 10
}, {
borderWidth: 2,
borderColor: Highcharts.getOptions().colors[1],
color: 'rgba(0,0,0,0)',
x: 0,
low: 10,
high: 16
}, {
borderWidth: 2,
borderColor: Highcharts.getOptions().colors[1],
color: 'rgba(0,0,0,0)',
x: 0,
low: 16,
high: 20
}]
}]
}
const chart = Highcharts.chart('container', options);
[EDIT]
More complete one:
Live example:
https://jsfiddle.net/fzv2jd3c/

Responsive d3 area

I'm new to d3 and trying to mixup some samples I looked at, and fill like I almost cracked it.
I'm trying to make this area be responsive.
I'm getting the resize event and recalculating the outer radius, but for some reason, the ui does not update.
view it in full screen to play with window size
// Generated by CoffeeScript 1.8.0
(function() {
var app;
app = angular.module('infra');
app.directive('channelSelectivity', function() {
var link;
link = function(scope, element, attrs) {
var data, el, height, resize, type, update, width;
el = element[0];
width = el.clientWidth;
height = el.clientHeight;
data = [
{
"key": 'a',
"value": 17,
"time": 0,
audience: "Man"
}, {
"key": 'a',
"value": 22,
"time": 1,
audience: "Man1"
}, {
"key": 'a',
"value": 47,
"time": 2,
audience: "Man2"
}, {
"key": 'a',
"value": 97,
"time": 3,
audience: "Man3"
}, {
"key": 'a',
"value": 100,
"time": 4,
audience: "Man"
}
];
resize = function() {
var angle, area, innerRadius, l, layers, line, max, min, nest, outerRadius, radius, stack, svg, svg_root, z;
svg = void 0;
radius = d3.scale.linear();
outerRadius = Math.min(width, height) / 2 - 20;
radius.range([0, outerRadius]);
angle = d3.scale.linear().range([0, 2 * Math.PI]);
z = d3.scale.category20c();
stack = d3.layout.stack().offset('zero').values(function(d) {
return d.values;
}).x(function(d) {
return d.time;
}).y(function(d) {
return d.value;
});
nest = d3.nest().key(function(d) {
return d.key;
});
line = d3.svg.line.radial().interpolate('cardinal-closed').angle(function(d) {
return angle(d.time);
}).radius(function(d) {
return radius(d.y0 + d.y);
});
max = void 0;
min = void 0;
innerRadius = 0;
svg_root = d3.select(element.find('svg')[0]);
svg_root.attr("width", width).attr("height", height).append('g');
layers = stack(nest.entries(data));
svg = d3.selectAll('g').data(layers);
svg.enter().append('g').attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
svg.exit().remove();
angle.domain([
0, d3.max(data, function(d) {
return d.time + 1;
})
]);
outerRadius = Math.min(width, height) / 2 - 20;
svg_root.attr("width", width).attr("height", height);
svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
radius.range([0, outerRadius]);
radius.domain([
0, d3.max(data, function(d) {
return d.y0 + d.y;
})
]);
area = d3.svg.area.radial().interpolate('cardinal-closed').angle(function(d) {
return angle(d.time);
}).innerRadius(function(d) {
return radius(d.y0);
}).outerRadius(function(d) {
return radius(d.y0 + d.y);
});
l = svg.selectAll('.layer').data(layers);
l.enter().append('path').attr('class', 'layer').attr('d', (function(d) {
return area(d.values);
})).style('fill', (function(d, i) {
return z(i);
}));
return l.exit().remove();
};
update = function(data, oldData) {
return resize();
};
type = function(d) {
d.time = +d.time;
d.value = +d.value;
return d;
};
scope.$watch('data', update);
return scope.$watch((function() {
return el.clientWidth * el.clientHeight;
}), (function() {
width = el.clientWidth;
height = el.clientHeight;
return resize();
}));
};
return {
template: '<svg></svg>',
restrict: 'AE',
scope: {
data: '=',
max: '=',
min: '='
},
link: link
};
});
}).call(this);
//# sourceMappingURL=channelSelectivityDirective.js.map
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
html{
height: 100%;
width: 100%;
}
body {
font: 10px sans-serif;
height: 100%;
width: 100%;
}
.axis line {
stroke: #000;
}
.axis path {
fill: none;
stroke: #000;
}
.axis + .axis g text {
display: none;
}
channel-selectivity{
width: 100%;
height: 100%;
display: block;
overflow: hidden;
margin: 0;
padding: 0;
}
</style>
</head>
<body ng-app="infra" ng-controller="MainCtrl">
<channel-selectivity data="dats"></channel-selectivity>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var app = angular.module('infra', []);
app.controller('MainCtrl', function ($scope, $window, $interval){
$scope.dats =[];
angular.element($window).on('resize', $scope.$apply.bind($scope));
});
</script>
</html>
You missed one small thing, to remove all old svg elements from the svg first.
I have update your code snippet with a single line added after getting the svg_root add svg_root.selectAll('*').remove(); and this will allow your resized elements to be rendered.
// Generated by CoffeeScript 1.8.0
(function() {
var app;
app = angular.module('infra');
app.directive('channelSelectivity', function() {
var link;
link = function(scope, element, attrs) {
var data, el, height, resize, type, update, width;
el = element[0];
width = el.clientWidth;
height = el.clientHeight;
data = [
{
"key": 'a',
"value": 17,
"time": 0,
audience: "Man"
}, {
"key": 'a',
"value": 22,
"time": 1,
audience: "Man1"
}, {
"key": 'a',
"value": 47,
"time": 2,
audience: "Man2"
}, {
"key": 'a',
"value": 97,
"time": 3,
audience: "Man3"
}, {
"key": 'a',
"value": 100,
"time": 4,
audience: "Man"
}
];
resize = function() {
var angle, area, innerRadius, l, layers, line, max, min, nest, outerRadius, radius, stack, svg, svg_root, z;
svg = void 0;
radius = d3.scale.linear();
outerRadius = Math.min(width, height) / 2 - 20;
radius.range([0, outerRadius]);
angle = d3.scale.linear().range([0, 2 * Math.PI]);
z = d3.scale.category20c();
stack = d3.layout.stack().offset('zero').values(function(d) {
return d.values;
}).x(function(d) {
return d.time;
}).y(function(d) {
return d.value;
});
nest = d3.nest().key(function(d) {
return d.key;
});
line = d3.svg.line.radial().interpolate('cardinal-closed').angle(function(d) {
return angle(d.time);
}).radius(function(d) {
return radius(d.y0 + d.y);
});
max = void 0;
min = void 0;
innerRadius = 0;
svg_root = d3.select(element.find('svg')[0]);
svg_root.selectAll('*').remove();
svg_root.attr("width", width).attr("height", height).append('g');
layers = stack(nest.entries(data));
svg = d3.selectAll('g').data(layers);
svg.enter().append('g').attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
svg.exit().remove();
angle.domain([
0, d3.max(data, function(d) {
return d.time + 1;
})
]);
outerRadius = Math.min(width, height) / 2 - 20;
svg_root.attr("width", width).attr("height", height);
svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
radius.range([0, outerRadius]);
radius.domain([
0, d3.max(data, function(d) {
return d.y0 + d.y;
})
]);
area = d3.svg.area.radial().interpolate('cardinal-closed').angle(function(d) {
return angle(d.time);
}).innerRadius(function(d) {
return radius(d.y0);
}).outerRadius(function(d) {
return radius(d.y0 + d.y);
});
l = svg.selectAll('.layer').data(layers);
l.enter().append('path').attr('class', 'layer').attr('d', (function(d) {
return area(d.values);
})).style('fill', (function(d, i) {
return z(i);
}));
return l.exit().remove();
};
update = function(data, oldData) {
return resize();
};
type = function(d) {
d.time = +d.time;
d.value = +d.value;
return d;
};
scope.$watch('data', update);
return scope.$watch((function() {
return el.clientWidth * el.clientHeight;
}), (function() {
width = el.clientWidth;
height = el.clientHeight;
return resize();
}));
};
return {
template: '<svg></svg>',
restrict: 'AE',
scope: {
data: '=',
max: '=',
min: '='
},
link: link
};
});
}).call(this);
//# sourceMappingURL=channelSelectivityDirective.js.map
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
html{
height: 100%;
width: 100%;
}
body {
font: 10px sans-serif;
height: 100%;
width: 100%;
}
.axis line {
stroke: #000;
}
.axis path {
fill: none;
stroke: #000;
}
.axis + .axis g text {
display: none;
}
channel-selectivity{
width: 100%;
height: 100%;
display: block;
overflow: hidden;
margin: 0;
padding: 0;
}
</style>
</head>
<body ng-app="infra" ng-controller="MainCtrl">
<channel-selectivity data="dats"></channel-selectivity>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var app = angular.module('infra', []);
app.controller('MainCtrl', function ($scope, $window, $interval){
$scope.dats =[];
angular.element($window).on('resize', $scope.$apply.bind($scope));
});
</script>
</html>

Resources