Remove chart.js canvas padding and margin - css

I am using chart.js to show a line chart in an Angular component. The code does not have any padding or margins added for the chart. I added styling to set the padding and margin to zero both in the create the chart in the .ts file and in the style sheets and nothing makes any difference. When I inspect the element in Chrome developer mode it does not show any padding or margins, so I think the styling is internal to chart.js. Below is a screenshot with the chart element highlighted in Chrome developer mode.
As you can see, there is a margin or border on the left, bottom and right of the chart canvas element, but strangely not at the top. The spacing between the Y-Axis labels and the left of the chart are especially bad when viewed on a mobile phone so I really need to remove it. I have spent hours setting every element I can think of to have 0 padding and 0 margins and trying different changes to the code and style sheets and searching through other articles on the Internet including Stackoverflow but none of them seem to answer this specific question.
I also tried adding box-sizing:border-box; to the div container containing the chart but it did not make any difference, i.e. as suggested in this article:
Why is chart.js canvas not respecting the padding of the container element?
Here is my chart configuration:
this.myChart = new Chart("chartCanvas", {
type: 'line',
data: {
labels: labelVars,
datasets: datasets
},
options: {
elements: {
point: {
radius: 0
},
},
responsive: true,
maintainAspectRatio: false,
tooltips: {
mode: 'index',
intersect: false,
enabled: width > 640
},
hover: {
mode: 'nearest',
intersect: true
},
legend: {
display: false,
position: 'bottom',
labels: {
}
},
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'week',
tooltipFormat: 'MM/DD/YYYY'
},
display: true,
scaleLabel: {
display: true,
labelString: ''
},
ticks: {
autoSkip: true,
padding: 0,
maxTicksLimit: this.getTickLimit(),
maxRotation: this.getRotation(),
minRotation: this.getRotation()
},
gridLines: {
display: false,
offsetGridLines: true
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: ''
},
ticks: {
maxTicksLimit: 6,
beginAtZero: false
}
}]
}
}
});
Here is the current html:
<div class="chartContainer">
<canvas *ngIf="displayChart" id="chartCanvas"></canvas>
</div>
And here is the current css:
#chartCanvas {
padding-left: 0;
margin-left: 0;
}
.chartContainer {
height: 500px;
margin: 0;
padding: 0;
align-items: left;
align-self: left;
align-content: left;
}
Has anyone else encountered this problem?

I found the problem. I had the scaleLabel turned on but was not showing a scale label, which was adding extra space. I changed scaleLabel display to false as shown below and the space went away:
yAxes: [{
display: true,
scaleLabel: {
display: false,
labelString: ''
},

Depending on your chartjs config, you just have to set the padding of the chart.js config.
Info: Offset's in the canvas cannot be altered with css, since the chart is "drawn" on it.
(details: in the documentation)
For a example:
const config = {
type: 'line',
data: data,
options: {
...
plugins: {
....
},
scales:{
x: {
ticks:{ padding:0 }
}
},
}
};

Related

Using chartjs, how to define relative width and height of canvas?

Using Chart.js version 4.2.0, I try to display a chart on a maximized window on Windows 11 where height of chart is 100% of screen's height and width of chart is 80% of screen's width.
I tried with following code
<body>
<div height="100%" width="80%">
<canvas id="canvas">
But this simple attributes don't do the job.
Finally, I have found this solution
<body>
<div>
<canvas id="canvas">
</canvas>
</div>
, options:
{ responsive: true
, maintainAspectRatio: true
, aspectRatio: 1.65
var ctx = document.getElementById("canvas").getContext("2d");
var myChart = new Chart(ctx, config);
myChart.canvas.parentNode.style.width = '80%';
This works correctly but is a little tricky because width (not height) is set dynamically in Javascript code and aspectRatio must be manually fixed in options.
Is there a simple solution to define width to 80% of screen and height to 100% of screen ?
My current screen size are 1920x1080.
What I obtain is
When I suppress aspectRatio in options, I obtains following chart
It seems that the standard way for a chart.js plot to fill a certain area with a size set in css, is to do these:
include the canvas in a div that doesn't contain anything else
set the size in the style of the div, not the canvas (that is already done in your code)
have at least one size in absolute units, (that is not both in %) - in your case
<div style="height:100vh; width:80vw">
<canvas id="myChart"></canvas>
</div>
See also this comment from the docs.
set chart options maintainAspectRatio: false and responsive: true - the latter for the chart to be redrawn when you resize the window.
Here's a code snippet doing these, including a plugin I wrote that displays the current sizes of the canvas, div and window
const plugin = {
id: 'canvasSizeMonitor',
currentWidth: 0,
currentHeight: 0,
resizing: false,
displaySizes(chart){
const canvas = chart.canvas,
div = canvas.parentElement;
document.querySelector('#sizes').innerText+=
`div: ${div.offsetWidth}x${div.offsetHeight}\n`+
`canvas: ${canvas.offsetWidth}x${canvas.offsetHeight}\n`+
`window:${window.innerWidth}x${window.innerHeight}\n`+
`0.8 * ${window.innerWidth} = ${Math.round(0.8*window.innerWidth)}\n`+
'---------\n'//`aspRatio: ${chart.options.aspectRatio.toFixed(3).replace(/[.]?0*$/, '')}\n\n`;
},
afterRender(chart){
if(!plugin.resizing &&
(chart.canvas.offsetWidth !== plugin.currentWidth ||
chart.canvas.offsetHeight !== plugin.currentHeight)){
plugin.resizing = true;
setTimeout(
function(){
plugin.resizing = false;
plugin.currentWidth = chart.canvas.offsetWidth;
plugin.currentHeight = chart.canvas.offsetHeight;
plugin.displaySizes(chart);
}, 500
)
}
}
};
chart = new Chart(document.getElementById("myChart"), {
type: 'line',
data: {
datasets: Array.from({length: 8}, (_, i)=>({
label: `k = ${i+1}`,
data: Array.from({length: 100}, (_, j)=>({
x: j/50, y: Math.exp(-j/10)*Math.cos((i+1)*j*Math.PI/100)
}))
}))
},
options: {
parsing: {
xAxisKey: 'x',
yAxisKey: 'y'
},
pointStyle: false,
borderWidth: 1,
responsive: true,
maintainAspectRatio: false,
//aspectRatio: 1,
scales: {
x: {
type: 'linear',
grid: {
drawOnChartArea: true,
lineWidth: 1
},
border:{
color: '#000',
},
ticks: {
display: true,
color: '#000',
padding: 10
},
title: {
display: true,
text: 'x',
align: 'end'
}
},
y: {
type: 'linear',
ticks: {
padding: 10,
color: '#000',
},
grid: {
drawOnChartArea: true,
lineWidth: 1
},
border:{
color: '#000',
},
title: {
display: true,
text: 'f[k](x)',
align: 'end'
}
}
},
plugins:{
legend:{
position: 'right'
}
},
animation: {duration: 0}
},
plugins: [plugin]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.1.2/chart.umd.js"
integrity="sha512-t41WshQCxr9T3SWH3DBZoDnAT9gfVLtQS+NKO60fdAwScoB37rXtdxT/oKe986G0BFnP4mtGzXxuYpHrMoMJLA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<body style="margin: 0">
<pre id="sizes" style="position: absolute; top: 0; right: 10px; text-align: right;background-color:rgba(255, 200, 100,0.4)"></pre>
<div style="height:100vh; width:80vw; padding:0; margin: 0; background: red">
<canvas style="background: #ddd" id="myChart"></canvas>
</div>
</body>

Set custom sizes for width and height in Tailwind

I want to set A4 size (210 x 297 mm) in Tailwind. I guess what I'm looking for is something like below
theme: {
extend: {
spacing: {
width: {
a4: "210mm",
},
height: {
a4: "297mm"
}
},
},
<div class="w-a4 h-a4">
</div>
Spacing is kinda a group of sizes
By default the spacing scale is inherited by the padding, margin, width, height, maxHeight, gap, inset, space, and translate core plugins.
So when you're register spacing like
theme: {
extend: {
spacing: {
a4: '210mm',
},
},
You will be able to use p-a4, m-a4, h-a4, w-a4 etc. All of them will have size of 210mm
If you wish to split sizes, no need in spacing key - just pass width and height
theme: {
extend: {
width: {
a4: '210mm',
},
height: {
a4: '297mm',
},
},
Per docs You should have been written like this:
spacing: {
width: {
'a4': "210mm",
},
height: {
'a4': "297mm"
}
},
Or using Arbitrary values If you don't want to extend.
If your using vscode install Tailwind CSS IntelliSense for autocompleting.
custom size(number)
custom is usually in .w-{number} and .w-px two type ,at number In terms of what rem do Relative unit,px Is the absolute unit of pixels 。In rem, each unit is 0.25rem, or 1/4 of a font size.
like this the classname like w-1
<div class="w-1"></div>
.w-1 { width: 1rem; }

ApexCharts polarArea — background colour for rings

I'm trying to give a background colour to my ApexCharts polarArea chart (I want the areas marked by red dots in the image to be grey/white):
I can't find a way to do this. I've tried adding fill to the various options, but nothing. I thought it might be possible with polygons like the radar chart, but no.
The closest I have come is by adding a CSS class to the chart on the containing Vue component:
<Chart class="chart" :myValues='this.myValues' :key="componentKey" />
.chart {
width: 320px;
height: 320px;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
border-radius: 50%;
margin: auto;
padding-top: 3px;
padding-right: 4px;
}
But annoyingly it's not centred on the chart origin and even with pixel precise increments to padding it's not quite right! Also, if possible I'd like alternating colours for each of the rings, like is possible with the radar chart.
My full chart Vue component:
<template>
<div class="polarChart">
<apexcharts height="360" type="polarArea" :options="chartOptions" :series="series"></apexcharts>
</div>
</template>
<style scoped>
.polarChart {
align-items: center;
}
</style>
<script>
import VueApexCharts from 'vue-apexcharts'
export default {
name: 'Chart',
components: {
apexcharts: VueApexCharts,
},
props: ['myValues'],
data: function() {
return {
series: this.myValues,
plotOptions: {
polarArea: {
dataLabels: {
offset: 30
},
}
},
chartOptions: {
labels: ['A', 'B', 'C', 'D', 'E', 'F'],
colors:['#403d39', '#ffbe0b', '#00b4d8', '#e73265', '#90be6d', '#ada7c9'],
legend: {
show: false
},
yaxis: {
max: 100,
show: false
},
xaxis: {
categories: ['A.', 'B.', 'C.', 'D.', 'E.', 'F.']
},
dataLabels: {
enabled: true,
formatter: function (val, opts) {
return Math.round(opts.w.globals.series[opts.seriesIndex]) + "% " + opts.w.globals.labels[opts.seriesIndex]
},
background: {
enabled: true,
borderRadius:2,
},
style: {
colors: ['#403d39', '#ffbe0b', '#00b4d8', '#e73265', '#90be6d', '#ada7c9'],
}
},
tooltip: {
// enabled: false
},
chart: {
type: 'polarArea',
},
stroke: {
colors: ['#fff']
},
fill: {
opacity: 1
},
responsive: [{
breakpoint: 480,
options: {
chart: {
width: '100%'
},
legend: {
position: 'bottom'
}
}
}]
},
}
},
methods: {
addData(){
this.updateChart();
},
updateChart() {
this.series = [{
data: this.freshnessValues
}]
}
},
}
</script>

How can I ensure my Highcharts don't break my flexbox layout?

I basically have two graphs and a sidebar.
Here's a fiddle demonstrating it:
https://jsfiddle.net/NibblyPig/b54qjavu/
Without min-width: 0 in the CSS the layout is badly broken with it stretching off the screen somehow even though that shouldn't be possible with a parent width of 100%.
Without calling the chart reflow method at the bottom of the javascript, the charts overflow off the screen.
Reflow kinda fixes it but despite both divs having flex-grow:1 they end up different sizes, again despite both having flex-grow: 1
If you resize the window itself, i.e. restore/maximise it the layout breaks even more, with the left div taking something like 20% of the width.
Any idea how I can fix this?
Pasted JS fiddle code below:
<div id='parent'>
<div id='columns'>
<div id='leftcolumn'>
<div id='chart1'>
</div>
<div id='chart2'>
</div>
</div>
<div id='rightcolumn'>
This is the right column.
</div>
</div>
</div>
CSS:
#parent {
display: flex;
width: 100%;
flex-direction: row;
height: 100vh;
min-width: 0;
}
#columns {
display: flex;
width: 100%;
flex-direction: row;
flex-grow: 1;
flex-shrink: 1;
min-width: 0;
}
#leftcolumn {
display:flex;
flex-grow: 1;
flex-direction: row;
flex-shrink: 1;
min-width: 0;
}
#rightcolumn: {
flex-grow: 0;
display: flex;
width: 200px;
min-width: 0;
}
JS:
$(function () {
var myChart = Highcharts.chart('chart1', {
chart: {
type: 'bar'
},
title: {
text: 'Monthly Statistics'
},
xAxis: {
categories: ['ABC', 'DEF']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: [{
name: 'This Month',
data: [4, 1]
}, {
name: 'Average',
data: [3, 2]
}]
});
var myChart2 = Highcharts.chart('chart2', {
chart: {
type: 'pie'
},
title: {
text: 'ABCDEF'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %'
}
}
},
series: [{
name: 'Brands',
colorByPoint: true,
data: [{
name: 'AXD',
y: 67.34,
sliced: true,
selected: true
}, {
name: 'ERT',
y: 11.88
}, {
name: 'ASD',
y: 20.78
}]
}]
});
});
I've fixed this by applying flex-basis: 50% to the parent container and a call to resize upon first loading the page with window.setTimeout(function () { myChart.reflow(); myChart2.reflow(); });
Here is the updated fiddle:
https://jsfiddle.net/NibblyPig/b54qjavu/2/

Using icons with List items

I am using Sencha Touch 2.2.1 . I want to display list items with icons, for that I am using itemTpl config property of the list. The image is rendered as icon but the list item is not getting aligned properly- it appears starting from much below. I want the text to get started from the top- it must be aligned horizontally with the image. I also tried changing 'margin' property but it didn't seem to work.
Please find my code below:
Ext.define('BBraunSencha.view.ListPanel',{
extend: 'Ext.Panel',
xtype: 'listpanel',
config:{
layout:{
type: 'vbox',
align: 'stretch'
},
items:[
{
xtype: 'label',
html: '<div style="margin-left: 20px;">List one</div>'
},{
xtype: 'list',
flex: 1,
ui:'round',
scrollable: true,
data:[
{ name: 'item1', price:'2000',in_stock : 'no'},
{ name: 'item2', price: '3000',in_stock :'yes'}
],
itemTpl: '<img src="images/Tulips.jpg" style="height: 50px;width: 50px;display:inline-block;margin-right:50px;"/>{name}'
}
]
} });
What can be the other way to achieve it?
Add a class to your css, then use that class for your itemTpl:
CSS file:
.tulip-icon {
background-image: url(images/Tulips.jpg);
background-size: 50px 50px;
background-repeat: no-repeat;
padding-left: 50px;
}
JS Code:
itemTpl: '<div class="tulip-icon">{name}</div>'
Add css:
.list-image{
height:20px;
width:20px;
float: left;
}
in js file:
itemTpl:'<div><img src="images/Tulips.jpg" class="list-image">{name}</div>'

Resources