I'm using charts.js (last version) inside my project.
I'd like to add styled text inside my doughnut, but I'm not able to archive that. See image with what I want and what I get.
const plugins = [{
id: 'text',
beforeDraw: function(chart, a, b) {
var width = chart.width,
height = chart.height,
ctx = chart.ctx;
ctx.restore();
var fontSize = (height / 240).toFixed(2);
ctx.font = fontSize + "em Nunito";
ctx.textBaseline = "middle";
var text = "Total " + currency + mainTotals,
textX = Math.round((width -ctx.measureText(text).width) / 2),
textY = height / 2;
ctx.fillText(text, textX, textY);
ctx.save();
}
}];
I'm not able to insert tags inside var text = "Total " + currency + mainTotals,.
is there a way to put html code to style in that variable?
Related
I have this chart. line chart using chartjs
How can I draw the last point, I'm using chart.js v4.2.1 and javascript. I have tried this code and it didn't work.
function createRadialGradient3(context, c1, c2, c3) {
const chartArea = context.chart.chartArea;
if (!chartArea) {
// This case happens on initial chart load
return;
}
const chartWidth = chartArea.right - chartArea.left;
const chartHeight = chartArea.bottom - chartArea.top;
if (width !== chartWidth || height !== chartHeight) {
cache.clear();
}
let gradient = cache.get(c1 + c2 + c3);
if (!gradient) {
// Create the gradient because this is either the first render
// or the size of the chart has changed
width = chartWidth;
height = chartHeight;
const centerX = (chartArea.left + chartArea.right) / 2;
const centerY = (chartArea.top + chartArea.bottom) / 2;
const r = Math.min(
(chartArea.right - chartArea.left) / 2,
(chartArea.bottom - chartArea.top) / 2
);
const ctx = context.chart.ctx;
gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, r);
gradient.addColorStop(0, c1);
gradient.addColorStop(0.5, c2);
gradient.addColorStop(1, c3);
cache.set(c1 + c2 + c3, gradient);
}
return gradient;
}
I have this canvas where I place a letter randomly within the canvas.
var w = Math.random() * canvas.width;
var h = Math.random() * canvas.height;
drawRandomCircle(canvas,w,h);
function drawRandomCircle(canvas,w,h)
{
var fontSize = '35';
var ctx = canvas.getContext("2d");
var color = 'rgba(245, 66, 66,1.0)';
ctx.fillStyle = color;
ctx.font = fontSize + 'pt Arial';
ctx.fillText('O', w, h);
}
The results:
I would like to improve further on the function to include an offset in % from the canvas boundary to limit where the letter will appear.
The results would be similar to something similar to this.
Any ideas?
You need to take into account the 10% on the borders.
Try the following which uses this principle... but also remember that the co-ordinates for the canvas are top-left based... but when you do the font it will go UP (not down) so you have to take that into account as well.
var canvas = document.getElementsByTagName("canvas")[0];
var fontSizePx = 35;
// Get 10% of the width/height
var cw = (canvas.width / 10);
var ch = (canvas.height / 10);
// Get 80% of the width/height but minus the size of the font
var cw80 = (cw * 8) - fontSizePx;
var ch80 = (ch * 8) - fontSizePx;
for(var i = 0; i < 10; i++) {
// Get random value within center 80%
var w = (Math.random() * cw80) + cw;
// Add on the size of the font to move it down
var h = (Math.random() * ch80) + ch + fontSizePx;
drawRandomCircle(canvas,w,h);
}
function drawRandomCircle(canvas,w,h) {
var ctx = canvas.getContext("2d");
var color = 'rgba(245, 66, 66,1.0)';
ctx.fillStyle = color;
ctx.font = fontSizePx.toString() + 'px Arial';
ctx.fillText('O', w, h);
}
canvas {
border:1px solid black;
}
<canvas></canvas>
How can i do this , with chart.js 2?
Now I have done this
<canvas id="myChart1" width="960" height="400"></canvas>...
all code here https://jsfiddle.net/semenova_7oa/xLbobm5y/
but I don't know how to do this style
Since you are already drawing the numbers on each point, its just a matter of drawing the text underline and line from point to the text. Basically, you use the same approach of calculating the x and y coordinates and draw away.
Here is an updated function that draws what you are requesting (and applies the correct color for each line as well...which you had left out). Note, it depends on a text underline function that is discussed here.
Chart.plugins.register({
afterDatasetsDraw: function(chartInstance, easing) {
// To only draw at the end of animation, check for easing === 1
var ctx = chartInstance.chart.ctx;
// for each line
chartInstance.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.getDatasetMeta(i);
if (!meta.hidden) {
meta.data.forEach(function(element, index) {
ctx.fillStyle = element._model.borderColor;
var fontSize = 19;
var fontStyle = 'normal';
var fontFamily = 'Helvetica Neue';
ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
// Just naively convert to string for now
var dataString = "";
if ((index != 0) && (index != 4)) {
dataString = number_format(dataset.data[index].toString(), 0, ',', ' ');
}
var padding = 20;
var position = element.tooltipPosition();
var thickness = 1;
position.x -= 10;
ctx.textAlign = 'right';
ctx.textBaseline = 'middle';
// draw text
ctx.fillText(dataString, position.x, position.y - (fontSize / 2) - padding);
// underline text
var underlinePoint = underline(ctx, dataString, position.x, position.y - (fontSize / 2) - padding, fontSize, element._model.borderColor, thickness, -5);
// draw line connecting text underline with point
ctx.beginPath();
ctx.strokeStyle = element._model.borderColor;
ctx.lineWidth = thickness;
ctx.moveTo(element._model.x, element._model.y);
ctx.lineTo(underlinePoint.x, underlinePoint.y);
ctx.stroke();
});
}
});
}
});
Here is a jsfiddle that demonstrates the above approach (forked from your question).
I have managed to make some flow charts (vertical chart and pie chart) but I have a problem,I want to minimize the charts because are occupying almost my entire page.
Here is what I have done:
<form action="listacumparaturi" method="get">
<canvas width="2200" height="2200" id="myCanvas"></canvas>
<script>
var x = "${sumC}";
var y = "${sumG}";
var z = "${sumP}";
var w = "${sumCa}";
total = "${sumT}";
var vertical = {
Calorii: x,
Grasimi: y,
Proteine: z,
Carbohidrati: w
};
var data = Object.keys(vertical);
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
total = "${sumT}";
color = ['orange', 'red', 'blue', 'green', 'black'];
start = 0;
for (var i = 0; i < data.length; i++) {
ctx.fillStyle = color[i];
ctx.fillRect((i * 60) + 50, x, 10, -(vertical[data[i]]));
ctx.font = "13px Arial";
ctx.fillText(data[i], (i * 60) + 51, x * 1.015);
ctx.fillText((1 * i), 20, ((32 * -i) + 920));
ctx.beginPath();
ctx.moveTo(600, 150);
ctx.arc(600, 150, 150, start, start +
(Math.PI * 2 * (vertical[data[i]] / total)), false);
ctx.lineTo(600, 150);
ctx.fillStyle = color[i];
ctx.fill();
start += Math.PI * 2 * (vertical[data[i]] / total);
}
</script>
</form>
Does anyone know how can I minimize this flow charts?I want the values to be the same but the pictures be minimized.
Here you can find a preview: http://codepen.io/nagasai/pen/Meayrb
Thanks!
I just updated the scale in the code pen URL ..Added total while calculating vertical bar height -http://codepen.io/nagasai/pen/Meayrb
ctx.fillRect((i * 60) + 50, 300, 10,( -(vertical[data[i]])*100)/total);
ctx.font = "9px Arial";
ctx.fillText(data[i], (i * 60) + 51, 742);
ctx.fillText((700 * i), 30, (((70) * -i) + 300));
And scale on y-axxis and bar height are dynamic now and adjust automatically based on your inputs.
Hope this is helpful for you
I found out about chart.js and
I am looking to use a doughnut chart for my website, I found a example where I can take the basics from : https://jsfiddle.net/9wp4f693/2/
I've only found something like this, but it was to draw text inside the segments, not to add pictures.
function drawSegmentValues()
{
for(var i=0; i<myDoughnutChart.segments.length; i++)
{
ctx.fillStyle="white";
var textSize = myChart.width/10;
ctx.font= textSize+"px Verdana";
// Get needed variables
var value = myDoughnutChart.segments[i].value;
var startAngle = myDoughnutChart.segments[i].startAngle;
var endAngle = myDoughnutChart.segments[i].endAngle;
var middleAngle = startAngle + ((endAngle - startAngle)/2);
// Compute text location
var posX = (radius/2) * Math.cos(middleAngle) + midX;
var posY = (radius/2) * Math.sin(middleAngle) + midY;
// Text offside by middle
var w_offset = ctx.measureText(value).width/2;
var h_offset = textSize/4;
ctx.fillText(value, posX - w_offset, posY + h_offset);
}
}
But I would like to have pictures inside my segments, something like this but I have no clue how I would do this :
There is no native ChartJS API for drawing an image inside a donut chart.
But you can manually add the images after the chart has been drawn.
For each wedge in the donut:
Warning: untested code ... some tweaking might be required
Translate inward to the middle of the donut.
// calculate donut center (cx,cy) & translate to it
var cx=chart.width/2;
var cy=chart.height/2;
context.translate(cx,cy);
Rotate to the mid-angle of the target donut-wedge
var startAngle = chart.segments[thisWedgeIndex].startAngle;
var endAngle = chart.segments[thisWedgeIndex].endAngle;
var midAngle = startAngle+(endAngle-startAngle)/2;
// rotate by the midAngle
context.rotate(midAngle);
Translate outward to the midpoint of the target donut-wedge:
// given the donut radius (innerRadius) and donut radius (radius)
var midWedgeRadius=chart.innerRadius+(chart.radius-chart.innerRadius)/2;
context.translate(midWedgeRadius,0);
Draw the image offset by half the image width & height:
// given the image width & height
context.drawImage(theImage,-theImage.width/2,-theImage.height/2);
Clean up the transformations by resetting the transform matrix to default:
// undo translate & rotate
context.setTransform(1,0,0,1,0,0);
In the new version use the following example, (it requires chartjs-plugin-labels):
import React from 'react';
import { Doughnut } from 'react-chartjs-2';
import 'chartjs-plugin-labels';
const imageURLs = [
'https://avatars.githubusercontent.com/u/43679262?v=4',
'https://avatars.githubusercontent.com/u/43679262?v=4',
'https://avatars.githubusercontent.com/u/43679262?v=4',
];
const images = imageURLs.map((v) => {
var image = new Image();
image.src = v;
return image;
});
export const data_doughnut = {
labels: ['a', 'b', 'c'],
datasets: [
{
data: [30, 15, 10],
backgroundColor: [
'#B1A9FF',
'#877CF8',
'#6456F2',
],
weight: 1,
},
],
};
export const chartOptions = {
responsive: true,
plugins: {
legend: {
display: false,
},
},
scales: {
ticks: {
display: false,
},
},
};
export const plugins = [
{
afterDatasetsDraw: (chart) => {
var ctx = chart.ctx;
ctx.save();
var xCenter = chart.canvas.width / 2;
var yCenter = chart.canvas.height / 2;
var data = chart.config.data.datasets[0].data;
var vTotal = data.reduce((a, b) => a + b, 0);
data.forEach((v, i) => {
var vAngle =
data.slice(0, i).reduce((a, b) => a + b, 0) + v / 2;
var angle = (360 / vTotal) * vAngle - 90;
var radians = angle * (Math.PI / 180);
var r = yCenter;
// modify position
var x = xCenter + (Math.cos(radians) * r) / 1.4;
var y = yCenter + (Math.sin(radians) * r) / 1.4;
ctx.translate(x, y);
var image = images[i];
ctx.drawImage(image, -image.width / 2, -image.height / 2);
ctx.translate(-x, -y);
});
ctx.restore();
},
},
];
export function DoughnutChartFeekers() {
return (
<Doughnut
data={data_doughnut}
plugins={plugins}
options={chartOptions}
/>
);
}