Chart.js color is not updating dynamically - javascript

I am working with a custom gauge using chart.js doughnut type and it's working fine. Now I am trying to change the color of each elements of gauge when the theme button is triggered. So, I have created a update function to do the task. But the plugins are updating but inversely. Also, don't know how to get the needleColor plugin path location for changing the needle color dynamically.
Images are linked below:
lightmood-without-trigger
darkmood-without-trigger
lightmood-after-trigger-theme-button-from-night-to-day
darkmood-after-trigger-theme-button-from-day-to-night
HTML
<div class="gauge_container">
<canvas class="gauge" id="gauge"> </canvas>
</div>
<i onclick="changeColor();" class="uil uil-moon change-theme" id="theme-button"
><span class="theme-name">Dark</span>
</i>
CSS
:root {
--hue-color: 5;
--gauge-color: hsl(var(--hue-color), 69%, 61%);
--gauge-color-border: #fff;
}
body.dark-theme {
--gauge-color: #fff;
--gauge-color-border: hsl(var(--hue-color), 30%, 8%);
}
.gauge_container {
width: 250px;
height: 200px;
margin-left: auto;
margin-right: auto;
}
JavaScript
const gaugeStyle = getComputedStyle(document.body);
var gaugeColor = gaugeStyle.getPropertyValue("--gauge-color");
var gaugeColorBorder = gaugeStyle.getPropertyValue("--gauge-color-border");
function changeColor() {
var gaugeColor = gaugeStyle.getPropertyValue("--gauge-color");
var gaugeColorBorder = gaugeStyle.getPropertyValue("--gauge-color-border");
myGauge.options.plugins.tooltip.backgroundColor = gaugeColor;
myGauge.options.plugins.tooltip.bodyColor = gaugeColorBorder;
myGauge.data.datasets[0].borderColor = gaugeColorBorder;
// Don't know how to get the needle color location path
myGauge.update();
}
const gaugeData = {
labels: ["Safe", "Risky", "High Risk"],
datasets: [
{
label: "Gauge",
data: [100, 65, 35],
backgroundColor: [
"rgba(75, 192, 192, 0.8)",
"rgba(255, 206, 86, 0.8)",
"rgba(255, 26, 104, 0.8)",
],
needleValue: 50,
borderColor: gaugeColorBorder,
borderWidth: 1,
cutout: "95%",
circumference: 180,
rotation: 270,
borderRadius: 5,
},
],
};
//gaugeNeedle
const gaugeNeedle = {
id: "gaugeNeedle",
afterDatasetDraw(chart) {
const {
ctx,
data,
chartArea: { width, height },
} = chart;
ctx.save();
const needleValue = data.datasets[0].needleValue;
if (needleValue <= 100) {
var angle = Math.PI + (1 / 200) * needleValue * Math.PI;
} else if (needleValue <= 10000) {
var angle =
Math.PI +
(1 / 200) * 100 * Math.PI +
((1 / 200) * needleValue * Math.PI * 65) / 10000;
} else if (needleValue <= 1000000) {
var angle =
Math.PI +
(1 / 200) * 100 * Math.PI +
((1 / 200) * 10000 * Math.PI * 65) / 10000 +
((1 / 200) * needleValue * Math.PI * 35) / 1000000;
} else {
var angle = 0;
}
const cx = width / 2;
const cy = chart._metasets[0].data[0].y;
//needle
ctx.translate(cx, cy);
ctx.rotate(angle);
ctx.beginPath();
ctx.moveTo(0, -2);
ctx.lineTo(height - ctx.canvas.offsetTop - 130, 0);
ctx.lineTo(0, 2);
ctx.fillStyle = gaugeColor; // Don't how to get this in changeColor function
ctx.fill();
//needle dot
ctx.translate(-cx, -cy);
ctx.beginPath();
ctx.arc(cx, cy, 5, 0, 10);
ctx.fill();
ctx.restore();
//text
ctx.font = "20px Ubuntu";
ctx.fillStyle = gaugeColor;
ctx.fillText(needleValue + " CPM", cx, cy + 50);
ctx.font = "10px Ubuntu";
ctx.fillText(0, 3, cy + 20);
ctx.fillText(100, cx, 50);
ctx.fillText("10k", cx + 115, 115);
ctx.fillText("1M", cx + 118, 205);
ctx.textAlign = "center";
ctx.restore();
},
};
// config
const gaugeConfig = {
type: "doughnut",
data: gaugeData,
options: {
plugins: {
legend: {
display: false,
},
tooltip: {
yAlign: "bottom",
displayColors: false,
callbacks: {
label: function (tooltipItem) {
return tooltipItem.label;
},
},
backgroundColor: gaugeColor,
bodyColor: gaugeColorBorder,
},
},
},
plugins: [gaugeNeedle],
};
// render init block
var myGauge = new Chart(document.getElementById("gauge"), gaugeConfig);

Related

How to find X,Y coordinates on Half Doughnut Chart JS react

I've got the doughnut part of the chart complete and the gauge needle. I want to add this circular pointer on the doughnut instead of the needle. I was able to draw the circular pointer but couldn't find the right X,Y coordinates to place the pointer.
Here is the DEMO
Here in the below image, the circle should be placed at the gauge needle pointer
The code I've used is the following for the circular pointer.
const pointer = {
id: "pointer",
afterDatasetsDraw: (chart) => {
const { ctx } = chart;
var data = chart._metasets[0].data[0];
var radius = data.innerRadius + (data.outerRadius - data.innerRadius) / 2;
var centerX = data.x;
var centerY = data.y;
const angle = (180 / 1000) * speed;
// this thing needs to be fixed
var x = centerX + radius * Math.cos(angle * Math.PI);
var y = centerY + radius * Math.sin(angle * Math.PI);
ctx.save();
ctx.beginPath();
ctx.lineWidth = 6;
ctx.arc(x, y, 12, 0, 2 * Math.PI);
ctx.stroke();
ctx.restore();
}
};
Target to achive:
Basically you want 75% of 180 Degrees (because the speed = 75):
const angle = Math.PI * ( speed / 100) + Math.PI;
And than Math.cos and Math.sin expect a radiant value(link to mdn documentation), which you already have, so no multiplication with Math.PI is needed anymore.
var x = centerX + radius * Math.cos( angle );
var y = centerY + radius * Math.sin( angle );
Full working demo (Updated Example, now with animation):
const speed = 75;
let animationAngle = 0;
var pointer = {
id: 'pointer',
defaults:{
percentage: 0,
maxAngle: 0
},
afterDraw: function(chart, args, opt) {
const { ctx } = chart;
var data = chart._metasets[0].data[0];
var radius = data.innerRadius + (data.outerRadius - data.innerRadius) / 2;
var centerX = data.x;
var centerY = data.y;
const angle = (Math.PI * ( speed / 100) * chart.options.plugins.pointer.percentage) + Math.PI;
var x = centerX + radius * Math.cos( angle );
var y = centerY + radius * Math.sin( angle );
ctx.save();
ctx.beginPath();
ctx.lineWidth = 6;
ctx.arc(x, y, 12, 0, 2 * Math.PI);
ctx.stroke();
ctx.restore();
},
}
var options = {
type: 'doughnut',
data: {
datasets: [{
data: [20, 50, 30],
backgroundColor: [
'rgba(231, 76, 60, 1)',
'rgba(255, 164, 46, 1)',
'rgba(46, 204, 113, 1)'
],
borderColor: [
'rgba(255, 255, 255 ,1)',
'rgba(255, 255, 255 ,1)',
'rgba(255, 255, 255 ,1)'
],
borderWidth: 0
}]},
options: {
cutout: 80,
rotation: -90,
circumference: 180,
animation:{
onProgress: function(context){
if(context.initial){
this.options.plugins.pointer.percentage = context.currentStep / context.numSteps;
}
}
},
maintainAspectRatio: false,
legend: { display: false },
plugins:{
tooltip: { enabled: false },
pointer: {currentAngle: 1}
}
},
plugins:[pointer]
}
const chart = document.getElementById('chart1')
new Chart(chart, options);
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div style="width:500px;height:184px">
<canvas id="chart1" width="500" height="184"></canvas>
<div>

How to create more than one circular progress bar?

I find this code for progress bar circle, But this code just creates one progress bar circle.
I need to create more one progress bar.
This code:
http://jsfiddle.net/Aapn8/3410/
<div class="chart" id="graph" data-percent="88"></div>
JS
var el = document.getElementById('graph'); // get canvas
var options = {
percent: el.getAttribute('data-percent') || 25,
size: el.getAttribute('data-size') || 220,
lineWidth: el.getAttribute('data-line') || 15,
rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2, options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (options.size - options.lineWidth) / 2;
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(0, percent || 1), 1);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = lineWidth
ctx.stroke();
};
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#555555', options.lineWidth, options.percent / 100);
Thank you.
You have already done the hard-work. wrap your code in a function which accepts a DOM element and create circle based on it.
var elems = document.querySelectorAll('.chart'); // get canvas
elems.forEach(function(el) {
createCircle(el);
})
function createCircle(el) {
//Logic to create circle
}
var elems = document.querySelectorAll('.chart'); // get canvas
elems.forEach(function(el) {
createCircle(el);
})
function createCircle(el) {
var options = {
percent: el.getAttribute('data-percent') || 25,
size: el.getAttribute('data-size') || 220,
lineWidth: el.getAttribute('data-line') || 15,
rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2, options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (options.size - options.lineWidth) / 2;
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(0, percent || 1), 1);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = lineWidth
ctx.stroke();
};
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#555555', options.lineWidth, options.percent / 100);
}
div {
position: relative;
margin: 80px;
width: 220px;
height: 220px;
}
canvas {
display: block;
position: absolute;
top: 0;
left: 0;
}
span {
color: #555;
display: block;
line-height: 220px;
text-align: center;
width: 220px;
font-family: sans-serif;
font-size: 40px;
font-weight: 100;
margin-left: 5px;
}
input {
width: 200px;
}
span {}
<div class="chart" data-percent="88"></div>
<div class="chart" data-percent="32"></div>
Update Fiddle

How to rotate 180 text lables on canvas

Hey I have a canvas element which I am rotate 180 degree using the following code:
-moz-transform: scale(-1, 1);
-webkit-transform: scale(-1, 1);
-o-transform: scale(-1, 1);
transform: scale(-1, 1);
filter: FlipH;
The canvas is get rotated but the text is flipped out.
Here is the the result:
I want to flip the text, after I have rotate the canvas 180 degree,apparently the text get rotate 180 too and I want to reverse it.
I want to rotate only the text and not all the other elements.
The original code is here:
go to ticklines function
http://codepen.io/Barak/pen/PNXROK
$(document).ready(function() {
$(function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.transform(1, 0, 0, -1, 0, canvas.height);
// https://www.researchgate.net/publication/4345236_A_Software_Implementation_of_the_Duval_Triangle_Method
var v0 = {
x: 50 * 10,
y: (86.603 * 10)
};
var v1 = {
x: 0 * 10,
y: (0 * 10)
};
var v2 = {
x: 100 * 10,
y: (0 * 10)
};
var triangle = [v0, v1, v2];
// Define all your segments here
var segments = [{
points: [{
x: 0 * 10,
y: 0 * 10
}, {
x: 43.5 * 10,
y: 75.34461 * 10
}, {
x: 55 * 10,
y: 55.42 * 10
}, {
x: 23 * 10,
y: 0 * 10
}],
fill: 'rgb(172,236,222)',
label: {
text: '',
cx: 300,
cy: 645,
withLine: false,
endX: null,
endY: null
},
}, {
points: [{
x: 23 * 10,
y: 0 * 10
}, {
x: 55 * 10,
y: 55.42 * 10
}, {
x: 63.5 * 10,
y: 40.70 * 10
}, {
x: 55.5 * 10,
y: 26.84 * 10
}, {
x: 71 * 10,
y: 0 * 10
}],
fill: 'deepskyblue',
label: {
text: '',
cx: 490,
cy: 645,
withLine: false,
endX: null,
endY: null
},
}, {
points: [{
x: 71 * 10,
y: 0 * 10
}, {
x: 55.5 * 10,
y: 26.84693 * 10
}, {
x: 63.5 * 10,
y: 40.70341 * 10
}, {
x: 43.5 * 10,
y: 75.34461 * 10
}, {
x: 48 * 10,
y: 83.13888 * 10
}, {
x: 73 * 10,
y: 39.83737 * 10
}, {
x: 67.5 * 10,
y: 30.311 * 10
}, {
x: 85 * 10,
y: 0 * 10
}],
fill: 'lightCyan',
label: {
text: '',
cx: 656,
cy: 645,
withLine: false,
endX: 366,
endY: 120
},
}, { //here - I am in hell.-s5
points: [{
x: 49 * 10,
y: 84.87093999999999 * 10
}, {
x: 50 * 10,
y: 86.603 * 10
}, {
x: 51 * 10,
y: 84.87093999999999 * 10
}],
fill: 'black',
label: {
text: 'PD',
cx: 600,
cy: 52,
withLine: true,
endX: 520,
endY: 70
},
}, {
points: [{
x: 48 * 10,
y: 83.1388 * 10
}, {
x: 49 * 10,
y: 84.87093 * 10
}, {
x: 51 * 10,
y: 84.87093 * 10
}, {
x: 60 * 10,
y: 69.2824 * 10
}, {
x: 58 * 10,
y: 65.81828 * 10
}],
fill: 'navajoWhite',
label: {
text: '',
cx: 670,
cy: 140,
withLine: true,
endX: 574,
endY: 105
},
}, {
points: [{
x: 58 * 10,
y: 65.81828 * 10
}, {
x: 60 * 10,
y: 69.2824 * 10
}, {
x: 75 * 10,
y: 43.3015 * 10
}, {
x: 73 * 10,
y: 39.837 * 10
}],
fill: 'tan',
label: {
text: '',
cx: 800,
cy: 290,
withLine: true,
endX: 662,
endY: 120
},
}, {
points: [{
x: 85 * 10,
y: 0 * 10
}, {
x: 67.5 * 10,
y: 30.311 * 10
}, {
x: 75 * 10,
y: 43.3015 * 10
}, {
x: 100 * 10,
y: 0
}],
fill: 'peru',
label: {
text: '',
cx: 800,
cy: 645,
withLine: false,
endX: null,
endY: null
},
}, ];
// label styles
var labelfontsize = 12;
var labelfontface = 'verdana';
var labelpadding = 3;
// pre-create a canvas-image of the arrowhead
var arrowheadLength = 10;
var arrowheadWidth = 8;
var arrowhead = document.createElement('canvas');
premakeArrowhead();
var legendTexts = ['PD = Partial Discharge',
'DT = Discharges and Thermal',
'T1 = Thermal fault T < 300 ℃',
'T2 = Thermal fault 300 ℃ < T < 700 ℃',
'T3 = Thermal fault T > 700 ℃',
'D1 = Discharges of low energy',
'D2 = Discharges of high energy'
];
// start drawing
/////////////////////
// draw colored segments inside triangle
for (var i = 0; i < segments.length; i++) {
drawSegment(segments[i]);
}
// draw ticklines
//
ticklines(v0, v1, 9, Math.PI * 1.2, 20);
ticklines(v1, v2, 9, Math.PI * 3 / 4, 20);
ticklines(v2, v0, 9, Math.PI * 2, 20);
// molecules
// moleculeLabel(v0, v1, 100, Math.PI / 2, '% CH4');
// moleculeLabel(v1, v2, 100, 0, '% C2H4');
// moleculeLabel(v2, v0, 100, Math.PI, '% C2H2');
// draw outer triangle
drawTriangle(triangle);
// draw legend
//drawLegend(legendTexts, 10, 10, 12.86);
drawCircle(canvas.width / 3, canvas.height / 2, 2.5, 'red');
// end drawing
/////////////////////
function drawCircle(point1, point2, radius, color) {
ctx.beginPath();
ctx.arc(point1, point2, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = color;
ctx.fill();
}
function drawSegment(s) {
// draw and fill the segment path
ctx.beginPath();
ctx.moveTo(s.points[0].x, s.points[0].y);
for (var i = 1; i < s.points.length; i++) {
ctx.lineTo(s.points[i].x, s.points[i].y);
}
ctx.closePath();
ctx.fillStyle = s.fill;
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
// draw segment's box label
/* if (s.label.withLine) {
lineBoxedLabel(s, labelfontsize, labelfontface, labelpadding);
} else {
boxedLabel(s, labelfontsize, labelfontface, labelpadding);
} */
}
function moleculeLabel(start, end, offsetLength, angle, text) {
ctx.textAlign = 'center';
ctx.textBaseline = 'middle'
ctx.font = '14px verdana';
var dx = end.x - start.x;
var dy = end.y - start.y;
var x0 = parseInt(start.x + dx * 0.50);
var y0 = parseInt(start.y + dy * 0.50);
var x1 = parseInt(x0 + offsetLength * Math.cos(angle));
var y1 = parseInt(y0 + offsetLength * Math.sin(angle));
ctx.fillStyle = 'black';
ctx.fillText(text, x1, y1);
// arrow
var x0 = parseInt(start.x + dx * 0.35);
var y0 = parseInt(start.y + dy * 0.35);
var x1 = parseInt(x0 + 50 * Math.cos(angle));
var y1 = parseInt(y0 + 50 * Math.sin(angle));
var x2 = parseInt(start.x + dx * 0.65);
var y2 = parseInt(start.y + dy * 0.65);
var x3 = parseInt(x2 + 50 * Math.cos(angle));
var y3 = parseInt(y2 + 50 * Math.sin(angle));
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x3, y3);
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.stroke();
var angle = Math.atan2(dy, dx);
ctx.save(); // save
ctx.translate(x3, y3);
ctx.rotate(angle);
ctx.drawImage(arrowhead, -arrowheadLength, -arrowheadWidth / 2);
ctx.restore()
}
function boxedLabel(s, fontsize, fontface, padding) {
var centerX = s.label.cx;
var centerY = s.label.cy;
var text = s.label.text;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle'
ctx.font = fontsize + 'px ' + fontface
var textwidth = ctx.measureText(text).width;
var textheight = fontsize * 1.286;
var leftX = centerX - textwidth / 2 - padding;
var topY = centerY - textheight / 2 - padding;
ctx.fillStyle = 'white';
ctx.fillRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
ctx.lineWidth = 1;
ctx.strokeRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
ctx.fillStyle = 'black';
ctx.fillText(text, centerX, centerY);
}
function lineBoxedLabel(s, fontsize, fontface, padding) {
var centerX = s.label.cx;
var centerY = s.label.cy;
var text = s.label.text;
var lineToX = s.label.endX;
var lineToY = s.label.endY;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle'
ctx.font = fontsize + 'px ' + fontface
var textwidth = ctx.measureText(text).width;
var textheight = fontsize * 1.286;
var leftX = centerX - textwidth / 2 - padding;
var topY = centerY - textheight / 2 - padding;
// the line
ctx.beginPath();
ctx.moveTo(leftX, topY + textheight / 2);
ctx.lineTo(lineToX, topY + textheight / 2);
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.stroke();
// the boxed text
ctx.fillStyle = 'white';
ctx.fillRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
ctx.strokeRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
ctx.fillStyle = 'black';
ctx.fillText(text, centerX, centerY);
}
function ticklines(start, end, count, angle, length) {
var dx = end.x - start.x;
var dy = end.y - start.y;
ctx.lineWidth = 1;
for (var i = 1; i < count; i++) {
var x0 = parseInt(start.x + dx * i / count);
var y0 = parseInt(start.y + dy * i / count);
var x1 = parseInt(x0 + length * Math.cos(180 - angle));
var y1 = parseInt(y0 + length * Math.sin(180 - angle));
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.stroke();
if (i == 2 || i == 4 || i == 6 || i == 8) {
var labelOffset = length * 3 / 4;
var x1 = parseInt(x0 - labelOffset * Math.cos(180 - angle));
var y1 = parseInt(y0 - labelOffset * Math.sin(180 - angle));
ctx.save();
ctx.fillStyle = 'black';
ctx.rotate(Math.PI);
ctx.fillText(parseInt(i * 10), x1, y1);
ctx.restore();
}
}
}
function premakeArrowhead() {
var actx = arrowhead.getContext('2d');
arrowhead.width = arrowheadLength;
arrowhead.height = arrowheadWidth;
actx.beginPath();
actx.moveTo(0, 0);
actx.lineTo(arrowheadLength, arrowheadWidth / 2);
actx.lineTo(0, arrowheadWidth);
actx.closePath();
actx.fillStyle = 'black';
actx.fill();
}
function drawTriangle(t) {
ctx.beginPath();
ctx.moveTo(t[0].x, t[0].y);
ctx.lineTo(t[1].x, t[1].y);
ctx.lineTo(t[2].x, t[2].y);
ctx.closePath();
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.stroke();
}
function drawLegend(texts, x, y, lineheight) {
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.fillStyle = 'black';
ctx.font = '12px arial';
for (var i = 0; i < texts.length; i++) {
ctx.fillText(texts[i], x, y + i * lineheight);
}
}
})
});
body {
background-color: ivory;
padding: 10px;
}
#canvas {
border: 1px solid red;
margin: 0 auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<canvas id="canvas" width=1024 height=1024></canvas>
</div>

how to create Duval Pentagon in canvas

Hey I have create a Duval Pentagon based on the post of creating duval triangle in canvas: how to create Duval Triangle in canvas.
My final result should be:
my current situation, is that I can created all the segments inside the pentagon,but I didn't figure out a way of placing labels of the gases around each corner(point) of my duval pentagon,any advice or help is welcome.
The creating of the duval pentagon process is like this:
1.creating outer pentagon.
2.creating all the segments in a loop.
3.creating the legend for the pentagon.
Update:
I have tried to build again the the moleculeLabel according to #markE guidance lines. so far no so good tried, I am sure doing something wrong. :(
function moleculeLabel(V,P,text){
var dx=V.x-P.x;
var dy=V.y-P.y;
var rAngle=Math.atan2(dy,dx);
var padding=15; // == how far outside the pentagon you want to go
var outsideX=P.x+(P.radius+padding)*Math.cos(rAngle);
var outsideY=P.y+(P.radius+padding)*Math.sin(rAngle);
ctx.textAlign='center';
ctx.textBaseline='middle';
ctx.fillStyle='black';
ctx.fillText(text,outsideX,outsideY);
}`
$(function() {
//offset :
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var points = [{
x: 397,
y: 149
}, {
x: 318,
y: 346
}, {
x: 112,
y: 347
}, {
x: 44,
y: 147
}, {
x: 221,
y: 27
}, {
x: 397,
y: 149
}];
var cx = 0;
var cy = 0;
for (var i = 0; i < points.lenght; i++) {
cx = cx + points[i].x;
cy = cy + points[i].y;
}
cx = cx / points.lenght;
cy = cy / points.lenght;
var centerPoint = {
x: cy,
y: cy
};
// Define all your segments here
var segments = [{
points: [{
x: 61,
y: 191
}, {
x: 112,
y: 347
}, {
x: 190,
y: 223
}, {
x: 214,
y: 211
}, {
x: 217,
y: 198
}, {
x: 61,
y: 192
}],
fill: 'rgb(172,236,222)',
label: {
text: 'T1',
cx: 130,
cy: 250,
withLine: false,
endX: null,
endY: null
},
}, {
points: [{
x: 61,
y: 191
}, {
x: 217,
y: 198
}, {
x: 220,
y: 26
}, {
x: 44,
y: 149
}],
fill: 'deepskyblue',
label: {
text: 'S',
cx: 140,
cy: 150,
withLine: false,
endX: null,
endY: null
},
}, {
points: [{
x: 220,
y: 26
}, {
x: 217,
y: 198
}, {
x: 239,
y: 135
}, {
x: 365,
y: 230
}, {
x: 397,
y: 149
}, {
x: 221,
y: 27
}],
fill: 'lightCyan',
label: {
text: 'D1',
cx: 270,
cy: 110,
withLine: false,
endX: null,
endY: null
},
}, {
points: [{
x: 214,
y: 211
}, {
x: 239,
y: 135
}, {
x: 365,
y: 231
}, {
x: 320,
y: 336
}, ],
fill: 'navajoWhite',
label: {
text: 'D2',
cx: 270,
cy: 210,
withLine: false,
endX: null,
endY: null
},
}, {
points: [{
x: 190,
y: 223
}, {
x: 214,
y: 211
}, {
x: 320,
y: 336
}, {
x: 318,
y: 346
}, {
x: 223,
y: 346
}],
fill: 'tan',
label: {
text: 'T3',
cx: 250,
cy: 310,
withLine: false,
endX: null,
endY: null
},
}, {
points: [{
x: 112,
y: 347
}, {
x: 190,
y: 223
}, {
x: 223,
y: 346
}],
fill: 'peru',
label: {
text: 'T2',
cx: 175,
cy: 300,
withLine: false,
endX: null,
endY: null
},
}, {
points: [{
x: 210,
y: 105
}, {
x: 219,
y: 105
}, {
x: 219,
y: 68
}, {
x: 210,
y: 67
}],
fill: 'red',
label: {
text: 'PD',
cx: 170,
cy: 87,
withLine: true,
endX: 215,
endY: 88
},
}];
// label styles
var labelfontsize = 12;
var labelfontface = 'verdana';
var labelpadding = 3;
var legendTexts = ['PD = Partial Discharge', 'T1 = Thermal fault < 300 celcius', '...'];
// start drawing
/////////////////////
// draw pentagon
drawPentagon(points);
// draw colored segments inside pentagon
for (var i = 0; i < segments.length; i++) {
drawSegment(segments[i]);
}
moleculeLabel(points[0], centerPoint, 'CH4');
moleculeLabel(points[1], centerPoint, 'CH2');
moleculeLabel(points[2], centerPoint, 'H2');
// draw legend
drawLegend(legendTexts, 10, 10, 12.86);
// end drawing
/////////////////////
function drawSegment(s) {
// draw and fill the segment path
ctx.beginPath();
ctx.moveTo(s.points[0].x, s.points[0].y);
for (var i = 1; i < s.points.length; i++) {
ctx.lineTo(s.points[i].x, s.points[i].y);
}
ctx.closePath();
ctx.fillStyle = s.fill;
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
// draw segment's box label
if (s.label.withLine) {
lineBoxedLabel(s, labelfontsize, labelfontface, labelpadding);
} else {
boxedLabel(s, labelfontsize, labelfontface, labelpadding);
}
}
function boxedLabel(s, fontsize, fontface, padding) {
var centerX = s.label.cx;
var centerY = s.label.cy;
var text = s.label.text;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle'
ctx.font = fontsize + 'px ' + fontface
var textwidth = ctx.measureText(text).width;
var textheight = fontsize * 1.286;
var leftX = centerX - textwidth / 2 - padding;
var topY = centerY - textheight / 2 - padding;
ctx.fillStyle = 'white';
ctx.fillRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
ctx.lineWidth = 1;
ctx.strokeRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
ctx.fillStyle = 'black';
ctx.fillText(text, centerX, centerY);
}
function lineBoxedLabel(s, fontsize, fontface, padding) {
var centerX = s.label.cx;
var centerY = s.label.cy;
var text = s.label.text;
var lineToX = s.label.endX;
var lineToY = s.label.endY;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle'
ctx.font = fontsize + 'px ' + fontface
var textwidth = ctx.measureText(text).width;
var textheight = fontsize * 1.286;
var leftX = centerX - textwidth / 2 - padding;
var topY = centerY - textheight / 2 - padding;
// the line
ctx.beginPath();
ctx.moveTo(leftX, topY + textheight / 2);
ctx.lineTo(lineToX, topY + textheight / 2);
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.stroke();
// the boxed text
ctx.fillStyle = 'white';
ctx.fillRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
ctx.strokeRect(leftX, topY, textwidth + padding * 2, textheight + padding * 2);
ctx.fillStyle = 'black';
ctx.fillText(text, centerX, centerY);
}
function moleculeLabel(V, P, text) {
var dx = V.x - P.x;
var dy = V.y - P.y;
var rAngle = Math.atan2(dy, dx);
var padding = 15; // == how far outside the pentagon you want to go
var outsideX = P.x + (P.radius + padding) * Math.cos(rAngle);
var outsideY = P.y + (P.radius + padding) * Math.sin(rAngle);
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = 'black';
ctx.fillText(text, outsideX, outsideY);
}
/**
* draw basic pentagon.
**/
function drawPentagon(points) {
ctx.beginPath();
for (var i = 0; i < points.length; i++) {
ctx.lineTo(points[i].x, points[i].y);
}
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.stroke();
ctx.closePath();
}
function drawLegend(texts, x, y, lineheight) {
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.fillStyle = 'black';
ctx.font = '12px arial';
for (var i = 0; i < texts.length; i++) {
ctx.fillText(texts[i], x, y + i * lineheight);
}
}
})
body {
background-color: ivory;
padding: 10px;
}
#canvas {
border: 1px solid red;
margin: 0 auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width=650 height=500></canvas>
For each desired molecule label:
Given a pentagon shaped like this: {x:,y:,radius:} and a molecule vertex {x:,y:}
Use Math.atan2 to find the angle between the polygon centerpoint and the molecule vertex.
var dx=V.x-P.x;
var cy=V.y-P.y;
var rAngle=Math.atan2(dy,dx);
Use basic trigonometry to calculate a point outside the polygon along the line between the centerpoint and vertex.
var padding=15; // == how far outside the pentagon you want to go
var outsideX=P.x+(P.radius+padding)*Math.cos(rAngle);
var outsideY=P.y+(P.radius+padding)*Math.sin(rAngle);
Use fillText to draw the desired label at [outsideX,outsideY]
context.textAlign='center';
context.textBaseline='middle';
context.fillStyle='black';
context.fillText('CH4',outsideX,outsideY);
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var points = [{x:397,y:149},{x:318,y:346},{x:112,y:347},{x:44,y:147},{x: 221,y:27},{x:397,y:149}];
// calc the polygon center mass
var cx,cy;
var totx=0;
var toty=0;
for(var i=0;i<points.length-1;i++){ // don't include the "closing" point in points[]
totx+=points[i].x;
toty+=points[i].y;
}
cx=totx/(points.length-1);
cy=toty/(points.length-1);
draw();
function draw(){
// draw the polygon
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var i=1;i<points.length;i++){
ctx.lineTo(points[i].x,points[i].y);
}
ctx.stroke();
// draw the labels at their radial extension points
ctx.textAlign='center';
ctx.textBaseline='middle';
var padding=20;
for(var i=0;i<points.length-1;i++){
var p=points[i];
var dx=p.x-cx;
var dy=p.y-cy;
var dist=Math.sqrt(dx*dx+dy*dy);
var rAngle=Math.atan2(dy,dx);
var labelX=cx+(dist+padding)*Math.cos(rAngle);
var labelY=cy+(dist+padding)*Math.sin(rAngle);
ctx.fillText('label#'+i,labelX,labelY)
// demo only, for points[0] draw the
//centerpoint and the radial extension point
if(i==0){
ctx.beginPath();
ctx.moveTo(cx,cy);
ctx.lineTo(labelX,labelY);
ctx.moveTo(cx,cy);
ctx.arc(cx,cy,5,0,Math.PI*2);
ctx.moveTo(labelX,labelY);
ctx.arc(labelX,labelY,3,0,Math.PI*2);
ctx.strokeStyle='red';
ctx.stroke();
ctx.fillStyle='red';
ctx.fill();
ctx.strokeStyle='black';
ctx.fillStyle='black';
}
}
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=500 height=500></canvas>
Final answer, many thanks to #markE.
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var points = [{x:397,y:149},{x:318,y:346},{x:112,y:347},{x:44,y:147},{x: 221,y:27},{x:397,y:149}];
// calc the polygon center mass
var cx,cy;
var totx=0;
var toty=0;
for(var i=0;i<points.length-1;i++){ // don't include the "closing" point in points[]
totx+=points[i].x;
toty+=points[i].y;
}
cx=totx/(points.length-1);
cy=toty/(points.length-1);
draw();
function draw(){
// draw the polygon
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var i=1;i<points.length;i++){
ctx.lineTo(points[i].x,points[i].y);
}
ctx.stroke();
// draw the labels at their radial extension points
ctx.textAlign='center';
ctx.textBaseline='middle';
var padding=20;
for(var i=0;i<points.length-1;i++){
var p=points[i];
var dx=p.x-cx;
var dy=p.y-cy;
var dist=Math.sqrt(dx*dx+dy*dy);
var rAngle=Math.atan2(dy,dx);
var labelX=cx+(dist+padding)*Math.cos(rAngle);
var labelY=cy+(dist+padding)*Math.sin(rAngle);
ctx.fillText('label#'+i,labelX,labelY)
// demo only, for points[0] draw the
//centerpoint and the radial extension point
if(i==0){
ctx.beginPath();
ctx.moveTo(cx,cy);
ctx.lineTo(labelX,labelY);
ctx.moveTo(cx,cy);
ctx.arc(cx,cy,5,0,Math.PI*2);
ctx.moveTo(labelX,labelY);
ctx.arc(labelX,labelY,3,0,Math.PI*2);
ctx.strokeStyle='red';
ctx.stroke();
ctx.fillStyle='red';
ctx.fill();
ctx.strokeStyle='black';
ctx.fillStyle='black';
}
}
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=500 height=500></canvas>

Chart.js change label color

I am using chart.js library to make polar chart but not able to change the color of the label please help me how can I change the color of the label. My chart look like http://headsocial.com:8080/upload/145448587471822e0922d67c9dd6aae46d70bfeef1623.png, but I want to change the color to grey currently it is showing like orange
function show_polar_chart_data1(data, id){
var jsonData = jQuery.parseJSON(data);
var data = [
{
value: jsonData.IDENTITY_Avg,
color: "#8258FA",
highlight: "#8258FA",
label: "IDENTITY("+jsonData.IDENTITY+")"
},
{
value: jsonData.ROLE_Avg,
color: "#34ED13",
highlight: "#34ED13",
label: "ROLE("+jsonData.ROLE+")"
},
{
value: jsonData.ATTITUDE_Avg,
color: "#FFFF00",
highlight: "#FFFF00",
label: "ATTITUDE("+jsonData.ATTITUDE+")"
},
{
value: jsonData.AGILITY_Avg,
color: "#FF0000",
highlight: "#FF0000",
label: "AGILITY("+jsonData.AGILITY+")"
},
{
value: jsonData.FAIRNESS_Avg,
color: "#00FFFF",
highlight: "#00FFFF",
label: "FAIRNESS("+jsonData.FAIRNESS+")"
},
{
value: jsonData.CONFLICT_Avg,
color: "#EE9A4D",
highlight: "#EE9A4D",
label: "CONFLICT("+jsonData.CONFLICT+")"
}
];
var ctx = document.getElementById("chart").getContext("2d");
var polarChart = new Chart(ctx).PolarArea(data, {
scaleOverride: true,
scaleStartValue: 0,
scaleStepWidth: 1,
scaleShowLabels: false,
scaleSteps: 10,
onAnimationComplete: function () {
this.segments.forEach(function (segment) {
var outerEdge = Chart.Arc.prototype.tooltipPosition.apply({
x: this.chart.width / 2,
y: this.chart.height / 2,
startAngle: segment.startAngle,
endAngle: segment.endAngle,
outerRadius: segment.outerRadius * 2 + 10,
innerRadius: 0
})
var normalizedAngle = (segment.startAngle + segment.endAngle) / 2;
while (normalizedAngle > 2 * Math.PI) {
normalizedAngle -= (2 * Math.PI)
}
if (normalizedAngle < (Math.PI * 0.4) || (normalizedAngle > Math.PI * 1.5))
ctx.textAlign = "start";
else if (normalizedAngle > (Math.PI * 0.4) && (normalizedAngle < Math.PI * 0.6)) {
outerEdge.y += 5;
ctx.textAlign = "center";
}
else if (normalizedAngle > (Math.PI * 1.4) && (normalizedAngle < Math.PI * 1.6)) {
outerEdge.y - 5;
ctx.textAlign = "center";
}
else
ctx.textAlign = "end";
ctx.fillText(segment.label, outerEdge.x, outerEdge.y);
})
done();
}
});
});
}
}
Just add
ctx.fillStyle = 'black';
before your ctx.fillText...
Have you tried adding:
scaleFontColor: "<the color you want to add>"
to the chart initialization like this:
var polarChart = new Chart(ctx).PolarArea(data, {
scaleFontColor: "<the color you want to add>"
...
Check this SO answer: Change label font color for a line chart using Chart.js

Categories