I have charts
<div class="col-xs-2"><canvas id="device"></canvas></div>
<div class="col-xs-2"><canvas id="host_name"></canvas></div>
<div class="col-xs-2"><canvas id="city"></canvas></div>
<div class="col-xs-2"><canvas id="org"></canvas></div>
<div class="col-xs-2"><canvas id="country"></canvas></div>
<div class="col-xs-2"><canvas id="region"></canvas></div>
CSS
<style type="text/css">
.chart-inner {
margin-top: -100px;
margin-bottom: 100px;
}
.chart-inner h5 {
margin-bottom: 5px;
margin-top: 27px;
font-size: 200px;
color: red;
}
</style>
I've tried to append text to the center
$('canvas#' + selector).append('<div class="chart-inner"><h5>' + selector + '</h5></div>');
It doesn't seem to come through.
But when I hide(), it works. All charts are hidden.
$('canvas#' + selector).hide();
What am I missing ?
Updated
<script>
function renderChart(selector, chartType, colors, labels, values, chartLine ) {
let chart = document.getElementById(selector).getContext('2d');
new Chart(chart, {
type:chartType, // bar, horizontalBar, pie, line, doughnut, radar, polarArea
data:{
labels:labels,
datasets:[{
data:values,
// backgroundColor:colors,
backgroundColor:colors,
borderWidth:1,
borderColor:'white',
hoverBorderWidth:2,
hoverBorderColor:colors,
hoverBorderWidth: 2,
borderAlign: 'inner',
}]
},
options:{
title:{
display:true,
text:selector
},
legend:{
display:false,
position:'right',
labels:{
fontColor:'#000'
}
},
cutoutPercentage: 70,
animation:{
animateScale:true,
},
}
});
// $('canvas#' + selector).append('<div class="chart-inner"><h5>' + selector + '</h5></div>');
// $('canvas#' + selector).hide();
//$('canvas#device').append('<div class="chart-inner"><h5>1234</h5></div>');
}
/*=========================================
= deviceType =
=========================================*/
var ajax = $.ajax({url: '/visitor/summary/device'});
ajax.done(function (response) {
deviceTypeLabels = [];
deviceTypeValues = [];
$.each(response, function(key,val) {
deviceTypeLabels.push(key);
deviceTypeValues.push(val);
});
renderChart('device', 'doughnut', colors, deviceTypeLabels, deviceTypeValues );
});
... and more charts ...
</script>
I've tried to append text to the center
You're appending elements inside of the canvas tag. That's only displayed as a fallback when your browser lacks canvas support.
What you're looking for is using the canvas getContext method.
Jsfiddle example
Adapted to what you provided, it would go something like this:
var centerX = chart.width / 2;
var centerY = chart.height / 2;
chart.fillStyle = 'black';
chart.font = '200px';
chart.textAlign = 'center';
chart.fillText(selector, centerX, centerY);
You may need to offset centerX or centerY depending on how the width of your doughnut charts is calculated.
Related
I'm having trouble trying to figure out the correct setup to have a ChartJS Bar Chart that has a fixed canvas height but allows the width be overflow-x. I have found an example here...http://jsfiddle.net/mbhavfwm/ which uses ChartJS 1.0, but I'm using ChartJS 2.6. So, I found another example here http://jsfiddle.net/jmpxgufu/ which uses ChartJS 2, but this example shows the chart rendered with only a few values and then ADDS more to it using javascript which then causes the width to overflow. Not quite the same.
My problem is I can not figure out how to make the chart render at the fixed height with all the data already in it, but NOT try to constrain the canvas to the width of the parent container. I want it to overflow.
Here is what I have so far.
https://jsfiddle.net/fed79b7t/
HTML
<div class="chartWrapper">
<div class="chartAreaWrapper">
<canvas id="chart-FuelSpend" height="300" width="1200"></canvas>
</div>
<canvas id="axis-FuelSpend" height="300" width="0"></canvas>
</div>
CSS
.chartWrapper {
position: relative;
}
.chartWrapper > canvas {
position: absolute;
left: 0;
top: 0;
pointer-events: none;
}
.chartAreaWrapper {
width: 600px;
overflow-x: scroll;
}
JAVASCRIPT
function generateLabels() {
var chartLabels = [];
for (x = 0; x < 100; x++) {
chartLabels.push("Label" + x);
}
return chartLabels;
}
function generateData() {
var chartData = [];
for (x = 0; x < 100; x++) {
chartData.push(Math.floor((Math.random() * 100) + 1));
}
return chartData;
}
var chartData = {
labels: generateLabels(),
datasets: [{
label: "Test Data Set",
data: generateData()
}]
};
$(function() {
var canvasFuelSpend = $('#chart-FuelSpend');
var chartFuelSpend = new Chart(canvasFuelSpend, {
type: 'bar',
data: chartData,
maintainAspectRatio: false,
responsive: true,
options: {
tooltips: {
titleFontSize: 0,
titleMarginBottom: 0,
bodyFontSize: 12
},
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
fontSize: 12,
display: false
}
}],
yAxes: [{
ticks: {
fontSize: 12,
beginAtZero: true
}
}]
},
animation: {
onComplete: function() {
var sourceCanvas = chartFuelSpend.chart.canvas;
var copyWidth = chartFuelSpend.scales['y-axis-0'].width - 10;
var copyHeight = chartFuelSpend.scales['y-axis-0'].height + chartFuelSpend.scales['y-axis-0'].top + 10;
var targetCtx = document.getElementById("axis-FuelSpend").getContext("2d");
targetCtx.canvas.width = copyWidth;
targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);
}
}
}
});
});
So, my goal is to have the chart the full 1200 pixels as defined by the canvas width, but for the container div to only show the 600 pixel amount where I can scroll the container to see the rest of the chart while keeping the Y-axis in place.
Can anyone shed some light on what I'm doing wrong? What am I missing?
Thank you!!!!!
It seems to have something to do with the fact you're missing a wrapper around the canvas. Here's an updated version of your fiddle. I've added a function called addData that takes the number of new entries you want to add and the chart variable. It's not as good as it can be (because i'm not 100% sure how you want to add new data) but it's a great starting point. The trick is to not initialize the chart with all data included, you want to create the chart and then add to it later to expand the canvas, otherwise the initial render will work to fit all of the data in at that width.
https://jsfiddle.net/qmqmg82z/3/
Additional JavaScript code:
function addData(numData, chart){
for (var i = 0; i < numData; i++){
chart.data.datasets[0].data.push(Math.random() * 100);
chart.data.labels.push("Label" + i);
var newwidth = $('.chartAreaWrapper2').width() +60;
$('.chartAreaWrapper2').width(newwidth);
}
}
and then at the end of your page load function (or wherever you want to be adding new data) add this function call:
addData(5, chartFuelSpend);
But bear in mind this will require however much data you want to add and the chart instance.
And the HTML:
<div class="chartWrapper">
<div class="chartAreaWrapper">
<div class="chartAreaWrapper2">
<canvas id="chart-FuelSpend" height="300" width="1200"></canvas>
</div>
</div>
<canvas id="axis-FuelSpend" height="300" width="0"></canvas>
</div>
I'm guessing the problem was that because the width of the single wrapper you had was changing along with the chart, it meant that the horizontal scroll wasn't being applied, this way the outer wrapper has the fixed width while the inside one and the canvas can expand.
I'm struggling with left & right margins on a donut chart I have created using Chart.js. More specifically, it seems impossible to reduce the seemingly 25% side margins on the donut charts. Does anyone know how I accomplish this or if it's even possible? I've been looking over all the github issues and documentation I can find, but it seems like nothing is working.
Github Issues I've found:
Issue-449
Issue-1266
Currently this is what I have
The issue is the large margins on the sides, I can't get them to go away no matter what properties I adjust
Dimension-wise I'd like both charts to take up 50% of the blue container's width and 75% of its height. I'm trying to use percentages for everything so it's responsive. If I use the responsive property in the chart.js config it keeps those side margins in tact. Ultimately, this is what I am trying to do roughly (the desired height isn't accurate in this example).
Right now I'm generating the charts like so
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.0/Chart.bundle.min.js"></script>
<script>
window.onload = function() {
Chart.pluginService.register({
afterUpdate: function (chart) {
if (chart.config.options.elements.center) {
var helpers = Chart.helpers;
var centerConfig = chart.config.options.elements.center;
var globalConfig = Chart.defaults.global;
var ctx = chart.chart.ctx;
var fontStyle = helpers.getValueOrDefault(centerConfig.fontStyle, globalConfig.defaultFontStyle);
var fontFamily = helpers.getValueOrDefault(centerConfig.fontFamily, globalConfig.defaultFontFamily);
if (centerConfig.fontSize)
var fontSize = centerConfig.fontSize;
// figure out the best font size, if one is not specified
else {
ctx.save();
var fontSize = helpers.getValueOrDefault(centerConfig.minFontSize, 1);
var maxFontSize = helpers.getValueOrDefault(centerConfig.maxFontSize, 256);
var maxText = helpers.getValueOrDefault(centerConfig.maxText, centerConfig.text);
do {
ctx.font = helpers.fontString(fontSize, fontStyle, fontFamily);
var textWidth = ctx.measureText(maxText).width;
// check if it fits, is within configured limits and that we are not simply toggling back and forth
if (textWidth < chart.innerRadius * 2 && fontSize < maxFontSize)
fontSize += 1;
else {
// reverse last step
fontSize -= 1;
break;
}
} while (true)
ctx.restore();
}
// save properties
chart.center = {
font: helpers.fontString(fontSize, fontStyle, fontFamily),
fillStyle: helpers.getValueOrDefault(centerConfig.fontColor, globalConfig.defaultFontColor)
};
}
},
afterDraw: function (chart) {
if (chart.center) {
var centerConfig = chart.config.options.elements.center;
var ctx = chart.chart.ctx;
ctx.save();
ctx.font = chart.center.font;
ctx.fillStyle = chart.center.fillStyle;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
var centerX = (chart.chartArea.left + chart.chartArea.right) / 2;
var centerY = (chart.chartArea.top + chart.chartArea.bottom) / 2;
ctx.fillText(centerConfig.text, centerX, centerY);
ctx.restore();
}
},
})
var config = {
type: 'doughnut',
data: {
labels: [
"Savings",
"Checking"
],
datasets: [{
data: [300, 50],
backgroundColor: [
"#FF6384",
"#36A2EB"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB"
]
}]
},
options: {
responsive:false,
maintainAspectRatio:false,
title: {
fullWidth: false,
display: true,
text: 'Current Balance'
},
legend: {
position:'bottom',
labels: {
boxWidth:15
}
},
elements: {
center: {
// the longest text that could appear in the center
maxText: '$000000',
text: '$40,000',
fontColor: 'black',
fontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
fontStyle: 'normal',
minFontSize: 1,
maxFontSize: 256,
}
}
}
};
var ctx = document.getElementById("myDoughnutChart").getContext("2d");
var myDoughnutChart = new Chart(ctx, config);
var ctx2 = document.getElementById("myDoughnutChart2").getContext("2d");
var myDoughnutChart2 = new Chart(ctx2, config);
};
</script>
</head>
With the portion of the HTML looking like this
<div class="col left">
<div class="section side-sm" style="background-color:blue;">
</div>
<div class="section side-sm" style="background-color:black;">
</div>
<div class="section side-lg">
<div class="accountContainer" style="height:75%;overflow:hidden;">
<canvas id="myDoughnutChart" style="background-color:white;"></canvas>
</div>
<div class="expenseContainer" style="height:75%;overflow:hidden;">
<canvas id="myDoughnutChart2" style="background-color:white;"></canvas>
</div>
</div>
</div>
With the applicable CSS for that HTML looking like this
html, body {
margin: 0;
height: 100%;
font-family: 'Roboto', sans-serif;
}
/* Start: Column-Specific */
.col {
height:100%;
float:left;
}
.left, .right {
width:25%;
height:97%;
background-color:white;
}
/*Start: Section-Specific */
.section {
width:100%;
clear: both;
margin:auto;
border-radius: 10px;
display:table;
}
.col.left>.section, .col.right>.section {
width:97%;
}
.side-lg {
height:40%;
background-color:blue;
margin-top:1%;
}
Can anyone help me figure out how to get rid of those large margins and accomplish the look that I've described/shown? Is it possible?
I misread your question, I thought you need google charts. Anyway, there is potential solution for chart js. You will need to add width and height attributes. For example:
<canvas id="myDoughnutChart" width="250%" height="310%"></canvas>
Here is a link to JsFiddle with your code + updated width and height attributes for the first chart (second one is the same for comparison):
https://jsfiddle.net/cncdf4od/2/
there is actually a simple solution i found in one of the issues
aspectRatio: 1 in the chart options
https://github.com/chartjs/Chart.js/issues/449
I'm generating a Chart.JS bar chart that renders like so:
As you can see, the bottom of the legend and the top of the grid/graph are crammed together. Also, the individual bars are scrunched together more than strictly necessary, making the values a little hard to read; note that there is plenty of room left of the red bar and right of the blue bar. And there is plenty of space in the quadrant itself to add a shim or shiv of space between the legend the grid/graph.
How can I "air out" these elements to make the data more legible and the presentation more appealing?
Here is the code being used:
HTML
<div class="row">
<div class="col-md-6">
<div class="bottomleft">
<h2 class="sectiontext">Forecast/Impact Analysis</h2>
<div class="graph_container">
<canvas id="forecastLineChart"></canvas>
</div>
</div>
</div>
. . .
CSS
The "row" and "col-md-6" classes are Bootstrap. "graph_container" must be a Chart.JS class (it's not one of mine).
.bottomleft {
margin-left: 16px;
padding: 16px;
border: 1px solid black;
}
.sectiontext {
font-size: 1.5em;
font-weight: bold;
font-family: Candara, Calibri, Cambria, serif;
color: green;
margin-top: -4px;
}
JAVASCRIPT/jQuery
var ctxForecastChart = $("#forecastLineChart");
var forecastChartData = {
labels: ["Total Sales"],
datasets: [
{
label: "8/28/2016 - 9/3/2016",
backgroundColor: "rgba(255,0,0,0.75)",
hoverBackgroundColor: "rgba(255,0,0,1)",
data: [1631437.17]
},
{
label: "9/4/2016 - 9/10/2016",
backgroundColor: "rgba(255,153,0,0.75)",
hoverBackgroundColor: "rgba(255,153,0,1)",
data: [1523898.94]
},
{
label: "9/11/2016 - 9/17/2016",
backgroundColor: "rgba(255,255,0,0.75)",
hoverBackgroundColor: "rgba(255,255,0,1)",
data: [1755669.93]
},
{
label: "9/18/2016 - 9/24/2016",
backgroundColor: "rgba(0,255,0,0.75)",
hoverBackgroundColor: "rgba(0,255,0,1)",
data: [1873205.42]
},
{
label: "9/25/2016 - 10/1/2016",
backgroundColor: "rgba(0,0,255,0.75)",
hoverBackgroundColor: "rgba(0,0,255,1)",
data: [1838204.79]
}]
};
var forecastOptions = {
tooltips: {
enabled: true
},
animation: {
duration: 500,
easing: "easeOutQuart",
onComplete: function () {
var ctx = this.chart.ctx;
ctx.font
Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal'
Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var model = dataset._meta[Object.keys(dataset._met
[0]].data[i]._model, scale_max = dataset._meta[Object.keys(dataset._met
[0]].data[i]._yScale.maxHeight;
ctx.fillStyle = '#444';
var y_pos = model.y - 5;
if ((scale_max - model.y) / scale_max >= 0.93)
y_pos = model.y + 20;
ctx.fillText(addCommas(dataset.data[i]), model.x
y_pos);
}
});
}
}
};
var forecastBarChart = new Chart(ctxForecastChart, {
type: 'bar',
data: forecastChartData,
options: forecastOptions
});
UPDATE
It's not a complete solution, but I improved it this way:
<canvas id="forecastLineChart" height="190"></canvas>
IOW, I added the height value to the canvas, so that the grid/graph now fills the quadrant better:
It sill could use commas, perhaps, for the y axis numbers, and the bars could spread out horizontally more, though.
Inside your variable forecastOptions, you just need to add the so-called scales option.
var forecastOptions = {
scales: {
xAxes: [{
barPercentage: 0.7,
categoryPercentage: 1
}]
},
tooltips...
This adjusts the width of the bars (barPercentage) and that of all the bars as a whole (categoryPercentage)
You can change 0.7 to however wide you want it to get. The extra space around all the bars is due to the fact that they fall under the same category, and that option is set to 0.8 as default, meaning that the 5 bars will only take up 80% as a whole.
Hope this helps
I have updated fabric CurvedText extension because of our requirement is something different. I want to set auto spacing between characters as it covers full circle. I got solutions after updating code in fabric CurvedText extension. While I am changing text of the object (on keyup event of textbox), I recalculate spacing and setting that spacing and text via setText and set("spacing", val) properties. In some situations, I can not see object on canvas but I can see pointer of the object on canvas mouse hover effect.
Remove characters from the textbox in this snippet and object will be hide after you will remove some characters.
Same thing happens when I add characters in the textbox.
Updated curved text extension.
var radius = 100;
var circum = Math.floor(2 * Math.PI * radius);
var spacing = 0;
var fontFamily = 'Arial';
var fontSize = 30;
var text;
var lineHeight = 1;
var topa = 100;
var left = 200;
var char = 0;
var textWidth = 0;
var obj;
var canvas, ctx;
$(document).ready(function () {
canvas = new fabric.Canvas('c');
ctx = canvas.getContext("2d");
text = $('#uppertext').val();
spacingOperation();
var upperText = new fabric.CurvedText(text, {
radius: radius,
top: topa,
left: left,
fontFamily: fontFamily,
fontSize: fontSize,
lineHeight: lineHeight,
spacing: spacing,
originX: 'center',
hasControls: true,
hasBorders: true,
selectable: true,
textAlign: 'center'
});
canvas.add(upperText).renderAll();
$('#uppertext').on('keyup', function () {
text = $('#uppertext').val();
setObjects();
if (spacingOperation())
{
setProps();
canvas.renderAll();
}
});
});
function spacingOperation() {
textWidth = getTotalTextWidth();
spacing = 0;
textWidth = getTotalTextWidth();
var diff = Math.ceil(circum - textWidth);
spacing = Math.ceil(diff / char);
return true;
}
function getTotalTextWidth()
{
ctx.font = fontSize + 'px ' + fontFamily;
char = text.length;
txtWidth = Math.ceil(ctx.measureText(text).width + (spacing * char));
return txtWidth;
}
function setObjects() {
canvas.setActiveObject(canvas.item(0));
obj = canvas.getActiveObject();
}
function setProps() {
obj.set('spacing', spacing);
obj.setText(text);
obj.setCoords();
}
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.js"></script>
<script src="http://www.trimantra.com/demo/fabric.curvedText_done.js"></script>
</head>
<body>
<div class="row">
<div class="row canvas-container" style="width: 50%; float: left;">
<canvas id="c" width="400" height="400" style="border:1px dotted #000;"></canvas>
</div>
<div class="row" style="float: left; width: 50%; height: 150px;">
Upper Text : <input type="text" id="uppertext" value="UTXXXXXXXXXXXXXUTXXXXXaaaaaaaawwwwwwwwwXXXXXXXXUTXXXXXXXXXXXXXUTXXXXXXXXXXXXX" />
</div>
</div>
</body>
</html>
I have looked into you code and changed one line in fabric curvedtext extension from ctx = new fabric.Canvas('c').getContext('2d'); to ctx = fabric.util.createCanvasElement().getContext('2d'); and it is working perfectly fine.
I want to create a donut chart with a thin gray background in it.
The only way I found to create it is adding a second donut chart to create the background.
Is there any way to do it simpler?
HTML:
<div class="chart-cont">
<canvas id="pointsUsed" height="200"></canvas>
<canvas id="pointsUsedBg" height="200"></canvas>
</div>
CSS:
.chart-cont {
position: relative;
}
#pointsUsed {
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
#pointsUsedBg {
position: absolute;
top: 0;
left: 0;
transform: scale(0.96,0.96);
}
JavaScript:
var pointsUsed = [
{
value: 44250,
color: "#FF5F33",
},
{
value: 100000,
color: "transparent",
},
];
var pointsUsedBg = [
{
value: 100000,
color: "#EEEEEE",
},
];
var pointsUsed_ctx = document.getElementById("pointsUsed").getContext("2d");
var pointsUsedBg_ctx = document.getElementById("pointsUsedBg").getContext("2d");
var pointsUsed = new Chart(pointsUsed_ctx).Doughnut(pointsUsed, {
segmentShowStroke: false,
segmentStrokeWidth : 0,
percentageInnerCutout: 87,
showTooltips: false,
animationEasing: 'easeInOutCubic',
responsive: true
});
var pointsUsedBg = new Chart(pointsUsedBg_ctx).Doughnut(pointsUsedBg, {
segmentShowStroke: false,
segmentStrokeWidth : 0,
percentageInnerCutout: 94,
showTooltips: false,
animation: false,
responsive: true
});
JSFiddle
Thanks!
You can extend the Doughnut chart to do this, like so
Chart.types.Doughnut.extend({
name: "DoughnutAlt",
initialize: function (data) {
// call the actual initialize
Chart.types.Doughnut.prototype.initialize.apply(this, arguments);
// save the actual clear method
var originalClear = this.clear;
// override the clear method to draw the background after each clear
this.clear = function () {
// call the original clear method first
originalClear.apply(this, arguments)
var ctx = this.chart.ctx;
// use any one of the segments to get the inner and outer radius and center x and y
var firstSegment = this.segments[0];
// adjust 0.3 to increaase / decrease the width of the background
var gap = (firstSegment.outerRadius - firstSegment.innerRadius) * (1 - 0.3) / 2;
// draw the background
ctx.save();
ctx.fillStyle = "#EEE";
ctx.beginPath();
ctx.arc(firstSegment.x, firstSegment.y, firstSegment.outerRadius - gap, 0, 2 * Math.PI);
ctx.arc(firstSegment.x, firstSegment.y, firstSegment.innerRadius + gap, 0, 2 * Math.PI, true);
ctx.closePath();
ctx.fill();
ctx.restore();
}
}
});
You would call it like this
var pointsUsed = new Chart(pointsUsed_ctx).DoughnutAlt(pointsUsed, {
...
Fiddle - http://jsfiddle.net/7nfL1m7d/