Where is this extra whitespace coming from? - javascript

I'm creating gauge charts using c3.js. I'm setting the height and width both to 75 because that's the right size of the gauge that I'm wanting, however when they get generated, there's always extra whitespace in the container that's messing me up.
I really want the svg that gets created to have a height of 60 in order to move the label up properly. The problem, is that when I set the height/width of the chart to 60, the size of the gauge itself gets way too small because of this extra whitespace.
I've tried setting the padding of everything that I know of to 0. I've searched through the documentation, there's always a chance that I've overlooked something. I can always try to do some hacky css to get around it, but before I do that, I'd like to change something in the configuration if I can.
Essentially, I want the chart to take up the full size that I specify. It seems that the legend, that I've specified to not show, is still taking up space that the chart should use.
http://jsfiddle.net/kLsox4ya/1/
<div class='row'>
<div class="col-12" id="chart"></div>
<p class="col-12 f-small">PERFECT</p>
</div>
var chart = c3.generate({
bindto: '#chart',
data: {
columns: [['data', 0]],
type: 'gauge'
},
gauge: {
fullCircle: true,
startingAngle: 2 * Math.PI,
width: 3,
expand: false,
label: {
show: false
}
},
size: {
height: 75,
width: 75
},
legend: {
show: false
},
interaction: {
enabled: false
}
});

You are going to have a hard time getting that much control over c3. It's doing a lot under the hood to calculate positions for axis, legends, etc... that you aren't even using.
I think you have two options:
Code it yourself using straight d3
Resort to a little hackery. For instance here, I've manually adjust the height after it renders.
var chart = c3.generate({
bindto: '#chart',
data: {
columns: [['data', 90]],
type: 'gauge'
},
tooltip: {
show: false
},
color: {
pattern: ['#565656', '#cfd628', '#e8b532', '#28d632'],
threshold: {
values: [40, 80, 90, 100]
}
},
gauge: {
fullCircle: true,
startingAngle: 2 * Math.PI,
width: 3,
label: {
format: function (value, ratio) {
return '';
},
extents: function (value) {
return '';
}
}
},
size: {
height: 75,
width: 75
},
legend: {
show: false
},
interaction: {
enabled: false
},
axis: {
x: {
show: false
},
y: {
show: false
}
},
padding: {
top: 0,
right: 0,
bottom: 0,
left: 0
},
onrendered: function(){
this.svg.attr('height', 55);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.12/c3.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.12/c3.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div class='row'>
<div class="col-12" id="chart"></div>
<p class="col-12 f-small">PERFECT</p>
</div>

Related

Apex Charts JS fill to size

So I've got a pretty small div, in which I gotta get a small timeline chart shoved in. The current problem is, that due to the chart being perfectly centered, I have a lot of whitespace I could really use, to make the actual data and chart much larger.:
I think showing the parent div shouldn't matter(because changing around these sizes doesn't really affect the chart itself). It feels like there's some option in the configuration that I'm missing. I've tried setting offsetY and even offsetX to negative values, because I was desperate, but to no avail.
<html>
<div id="chartTarget" style="height: 100; width: 100%;">
<canvas id="chartCanvas" height="100"></canvas>
<div style="opacity:0;" class="chartTooltip center">
</div>
</div>
</html>
Relevant code is pretty much straight up copied from the example, but since I'm bound to get questions about it, here goes:
var options = {
series: [
{
name: 'Pending',
data: [
{
x: 'Trip',
y: [
new Date('2021-04-21T03:24:00').getTime(),
new Date('2021-04-21T04:24:00').getTime()
]
}
]
},
{
name: 'Active',
data: [
{
x: 'Trip',
y: [
new Date('2021-04-21T05:24:00').getTime(),
new Date('2021-04-21T08:24:00').getTime()
]
}
]
},
{
name: 'Deleted',
data: [
{
x: 'Trip',
y: [
new Date('2021-04-21T11:24:00').getTime(),
new Date('2021-04-21T12:24:00').getTime()
]
}
]
}
],
chart: {
height: 75,
width: 250,
type: 'rangeBar',
offsetY: -25,
toolbar: {
show: false,
tools: {
download: false,
selection: false,
zoom: false,
zoomin: false,
zoomout: false,
pan: true,
reset: true
}
},
events: {
dataPointMouseEnter: function (event, chartContext, config) {
config.w.config.chart.toolbar.show = false;
},
dataPointMouseLeave: function (event, chartContext, config) {
config.w.config.chart.toolbar.show = false;
}
}
},
plotOptions: {
bar: {
horizontal: true,
barHeight: '50%',
rangeBarGroupRows: true
}
},
colors: [
"#008FFB", "#00E396", "#FEB019", "#FF4560", "#775DD0",
"#3F51B5", "#546E7A", "#D4526E", "#8D5B4C", "#F86624",
"#D7263D", "#1B998B", "#2E294E", "#F46036", "#E2C044"
],
fill: {
type: 'solid'
},
xaxis: {
type: 'datetime',
labels: {
maxHeight: 25,
style: {
fontSize: '9px'
},
offsetY: -8
},
tooltip: {
enabled: false
}
},
yaxis: {
show: false,
lines: {
show: true
}
},
legend: {
show: false,
position: 'top'
}
};
var chart = new ApexCharts(document.querySelector("#chartTarget"), options);
chart.render();
I need the label, so things like sparkline aren't useful.
A negative offset at the chart level seems to have fixed for my needs.
chart.offsetY: -25
I assume everyone else can play with negative offset values, where available for more fine tuning.

HighChart plots not displaying correctly on small div

I am using a javascript library called Highcharts https://www.highcharts.com/
to plot JSON data on a stock/line graph.
Reference the image below to get an understanding of the terms I am using in this post.
https://www.highcharts.com/images/docs/understanding_highstock.png
So everything works fine when clicking on the range selector buttons to zoom in. But when I use the navigator to specify a huge range (years), the final line plot is incorrect. I have created some images to help you understand what I mean.
Using the range selector buttons to specify a smaller range works perfectly when trying to plot [1519162460000,246.39649367343821] as my final price:
But now, let me resize the navigator in order to show the entire price history:
If you look carefully at the image you should be able to see that the last plot on the chart is incorrect and shows $230.72 when it should display $246.40 246.39649367343821 <- rounded
As you can probably tell, this is a major issue for someone who is trying to display relevant price information on my website.
If I do not restrict the width of the chart div or resize the browser window the plots display fine but I still dont know the issue. (note: what I just described does not work in codepen because the viewport width is restricted so the plots mess up regardless when I navigate a big enough range)
Below is a snippet of my js and html along with a link to the codepen I created.
JS
Highcharts.setOptions({
lang: {
thousandsSep: ","
}
});
Highcharts.stockChart("chart", {
chart: {
width: 290,
padding: [5, 5, 5, 5]
},
title: {
text: "Litecoin Price" // make dynamic
},
series: [
{
name: "Price",
data: JSON.parse(data)["stats"],
tooltip: {
valueDecimals: 2,
valuePrefix: "$",
valueSuffix: " USD"
}
}
],
responsive: {
rules: [
{
condition: {
maxWidth: 500
},
chartOptions: {
chart: {
zoomType: "none"
},
credits: {
enabled: false
},
scrollbar: {
enabled: false
} //,
//navigator: {
//enabled: false
//},
//rangeSelector: {
//enabled: false
//}
}
}
]
},
scrollbar: {
liveRedraw: false
},
rangeSelector: {
allButtonsEnabled: false,
buttons: [
{
type: "month",
count: 1,
text: "1m"
},
{
type: "month",
count: 3,
text: "3m"
},
{
type: "month",
count: 6,
text: "6m"
},
{
type: "year",
count: 1,
text: "1y"
},
{
type: "ytd",
count: 1,
text: "YTD"
}
],
selected: 4,
inputEnabled: true,
enabled: true,
inputStyle: {
color: "#757575"
},
labelStyle: {
color: "#757575"
}
}
});
HTML
<div class="card" style="padding: 10px; min-width: 330px;">
<div class="card chart-card" style="height: 350px; overflow: hidden; width: 300px;">
<div id="chart" style="height: 350px; min-width: 300px;">
<div id="highcharts-loading">
<div style="display: block; margin: 0 auto; position: absolute; top: calc(50% - 24px); left: calc(50% - 24px);"><span class="loading1"></span></div>
</div>
<div id="highcharts-nodata" style="display:none; text-align: center;">No chart data found</div>
</div>
</div>
</div>
That's because when you zoom out enough, Highcharts groups the data and displays the average value. If you look at the tooltip it says "Week from Monday, Feb 19, 2018", which means the value that is being displayed is the average for that week. I believe there are some settings that allow you to disable that grouping, but at the expense of the graph interaction possibly becoming laggy due to rendering so many data points.
Data grouping is the concept of sampling the data values into larger
blocks in order to ease readability and increase performance of the
JavaScript charts. Highstock by default applies data grouping when the
points become closer than a certain pixel value, determined by the
groupPixelWidth option.
The settings for data grouping on line charts are here: series.line.dataGrouping

c3 bar graph align tick values with non-centered ticks

I'm trying to push the values on the x category axis to be on the sides of the bars, not in the middle. Apparently it is possible to put the ticks there, but can values go under the ticks as well?
var chart;
chart = c3.generate({
data: {
columns: [
['data', 30, 200, 100, 400, 150, 250]
],
type: 'bar'
},
bar: {
width: {
ratio: 0.98
}
},
axis: {
x: {
type: 'category',
categories: [10, 50, 100, 500, 2000, 5000],
tick: {
centered: false
}
}
},
legend: {
show: false
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
<div id="chart" class="c3" style="max-height: 280px; position: relative;"></div>
It's not the prettiest answer, and the last label gets chopped off (you'll have to investigate c3's padding options), but these 2 lines after you've rendered the chart do the trick:
// use c3's internal x scale to get the width of one bar
var width = chart.internal.x(1) - chart.internal.x(0);
// shuffle all the tick label tspans along by half a bar's width
d3.select(".c3-axis").selectAll(".tick text tspan").attr("dx", width/2);
var chart;
chart = c3.generate({
data: {
columns: [
['data', 30, 200, 100, 400, 150, 250]
],
type: 'bar'
},
bar: {
width: {
ratio: 0.98
}
},
axis: {
x: {
type: 'category',
categories: [10, 50, 100, 500, 2000, 5000],
tick: {
centered: false
}
}
},
legend: {
show: false
}
});
var width = chart.internal.x(1) - chart.internal.x(0);
d3.select(".c3-axis").selectAll(".tick text tspan").attr("dx", width/2);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.11/c3.min.js"></script>
<div id="chart" class="c3" style="max-height: 280px; position: relative;"></div>

Custom chart suggestions

I've always use flot.js for common charting requirements, but I'd like to explore new ways to visualize data that might be beyond this charting library. I'd appreciate any advice or recommendations as to how others might programmatically render the custom display chart below. Maybe CSS?
I know you probably weren't looking for an answer spelling out how to implement this in flot, but it was a fun exercise.
Getting creative with hiding and stacking bars with the stack plugin allows you to represent your bounds. For each set of bounds, you'll need to create a hidden bar with your lower bound value and then create a visible bar with your upper bound value (and stack the two). Specifying which bars should stack on each other is easy by setting the stack option to the same key.
Once the bars are setup, the next step is to set the options of the chart. A grid marking handles displaying the current value. Hiding both axes effectively hides the grid.
The rest comes down to creating methods to append div elements to placeholder to show the bar values, labels, and marking value.
This is a basic implementation of your example image that really focuses on the flot component of the chart. With a bit more time, the extra appended div elements could be styled in such a way to more closely match your example.
This JSFiddle contains the code below for easier review.
$(function() {
var data = [{
data: [ [0, 21.51] ],
lines: { show: false },
bars: { show: false },
stack: 0,
label: 'Hidden'
},{
data: [ [1, 32.50] ],
lines: { show: false },
bars: { show: false },
stack: 1,
label: 'Hidden'
},{
data: [ [2, 47.14] ],
lines: { show: false },
bars: { show: false },
stack: 2,
label: 'Hidden'
},{
data: [ [0, 37.77] ],
stack: 0,
label: 'Last Year'
},{
data: [ [1, 24.65] ],
stack: 1,
label: 'Last Month'
}, {
data: [ [2, 7.67] ],
stack: 2,
label: 'Last Week'
}];
var options = {
series: {
bars: { show: true },
points: { show: false }
},
xaxis: { show: false },
yaxis: { show: false },
grid: {
show: true,
borderWidth: 0,
backgroundColor: null,
markings: [{
xaxis: { from: 0, to: 3 },
yaxis: { from: 48.01, to: 48.01 },
color: "#000000"
}]
},
legend: { show: false }
};
var plot = $.plot($('#graph'), data, options);
var plotData = plot.getData();
var markings = plot.getOptions().grid.markings;
displayBarValues(plotData);
displayBarLabels(plotData);
displayMarkingValues(markings);
// display values next to bars
function displayBarValues(plotData) {
$.each(plotData, function(i, data) {
var stackedValue = data.data[0][1];
if (data.bars.show) {
stackedValue = findStackedValue(plotData, data.stack);
}
var offset = plot.pointOffset({x: data.data[0][0], y: stackedValue});
$('<div class="data-point-value">-- $' + stackedValue + '</div>').css( {
left: offset.left + 30,
top: offset.top - 8,
}).appendTo(plot.getPlaceholder());
});
}
function findStackedValue(dataSeries, stackNumber) {
var stackedValue = 0;
for (var i =0; i < dataSeries.length; i++) {
if (dataSeries[i].stack === stackNumber) {
stackedValue = stackedValue + dataSeries[i].data[0][1];
}
}
return stackedValue;
}
// display a marking value
function displayMarkingValues(markings) {
$.each(markings, function(i, marking) {
var offset = plot.pointOffset({x: marking.xaxis.to, y: marking.yaxis.to });
$('<div class="data-point-value">------ $' + marking.yaxis.to + '</div>').css( {
left: offset.left,
top: offset.top - 8,
}).appendTo(plot.getPlaceholder());
});
}
function displayBarLabels(plotData) {
$.each(plotData, function(i, data) {
if (data.bars.show) {
var stackedValue = findStackedValue(plotData, data.stack);
var offset = plot.pointOffset({x: data.data[0][0], y: stackedValue});
$('<div class="data-point-label">' + data.label + '</div>').css({
left: offset.left - 35,
top: offset.top + 50,
}).appendTo(plot.getPlaceholder());
}
});
}
});
#graph {
margin: 0 auto;
text-align: center;
width: 100px;
height: 600px;
}
.data-point-value {
position: absolute;
white-space: nowrap;
font-size: 11px;
}
.data-point-label {
position: absolute;
white-space: nowrap;
width: 100px;
font-size: 11px;
text-align: right;
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flot/0.8.3/jquery.flot.js"></script>
<script src="https://rawgit.com/emmerich/flot-orderBars/master/js/jquery.flot.orderBars.js"></script>
<script src="https://rawgit.com/flot/flot/master/source/jquery.flot.stack.js"></script>
<div id="graph"></div>
I have used Fusion Charts. Its pretty easy to customize and it works well in all browsers. Also have a look at Chart JS. Its pretty cool and its open source
I'v been using Chart.js for a while. While it is sweet at first glance, and you really can do super awesome stuff with it out of the box, it can be really limiting later on when you come across the need to do some simple/custom details that are not in documentation. For example: label outside the chart; turning off background for bar chart, doughnut bar with 1 value (for example - i have doughnut chart, with value 20%, i want the difference to be colored - you cant do that).
Of course all these stuff can be addressed and made with customizing .js file, and extending it but if you don't have time for that and you want out of the box solution, you can be stuck on simple detail so i suggest reading full docs to see if it is up to your expetations.
I would recommend D3.js with the caveat the the learning curve is steep; let me try to explain:
In something like chart.js, chartist,etc you provide the data, chart type and some configuration and you have your chart. In D3, it is a bit more complicated in the sense that D3 provides the framework for displaying and interacting with data via the Dom elements you design and specify.( Mostly svg's although you can also use divs,spans etc)
While it feels daunting at first and the documentation is basically an API Reference, there are hundreds of examples you can use as base or inspiration.
I'v been using (ChartJS, Morris, Inline Charts) for dashboard. It may help you much to customize the chart
I would recommend Chartist.js. It is fully responsive with great flexibility and DPI dependent.
you're able to style your charts with CSS in #media queries and lot of animation options. they have given examples for line chart, bar chart, pie chart with code. So it will definitely help you.
I like amCharts.
Can do all kinds of stuff and is free to use.
Google gives you an interesting charting library.
May want to try that but it requires you to be connected to Google for it to work (can't run it offline).
Here's a shot at it with HighCharts. I adapted the 'Stacked and grouped column' example at http://www.highcharts.com/demo/column-stacked-and-grouped.
Obviously there's work to be done in getting the labels and axes right, but I think this is a good start.
jsFiddle at http://jsfiddle.net/saevj2n4/1/
HTML:
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
JavaScript
$(function () {
Highcharts.chart('container', {
chart: {
type: 'column',
width: 200,
height: 1000
},
title: {
text: 'Total fruit consumtion, grouped by gender'
},
xAxis: {
categories: ['Profit']
},
yAxis: {
allowDecimals: false,
min: 0,
title: {
text: 'Number of fruits'
}
},
tooltip: {
formatter: function () {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'Total: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal',
//groupPadding: .45,
pointPadding: 0,
//pointWidth: 40,
}
},
series: [{
name: 'Min',
data: [59.28 - 21.58 ],
stack: 'Last Year',
color: "#919191"
}, {
name: 'Max',
data: [21.58 ],
stack: 'Last Year',
color: "transparent"
}, {
name: 'Min',
data: [ 57.15 - 32.5 ],
stack: 'Last Month',
color: "#6095c9"
}, {
name: 'Max',
data: [32.50],
stack: 'Last Month',
color: "transparent"
}, {
name: 'Min',
data: [54.81 - 47.14 ],
stack: 'Last Week',
color: "#745f8e"
}, {
name: 'Max',
data: [47.14],
stack: 'Last Week',
color: "transparent"
}]
});
});

How to get rounded columns in c3.js bar chart

I was wondering if anyone know how to round the corners of the columns in a c3.js bar chart? The hacks I have found online, doesn't seem to work, so I hope somewhere here can help!
Thank you :)
var mph_chart = c3.generate({
bindto: '#mph_chart',
padding: {
top: 10,
right: 50,
bottom: 10,
left: 190
},
bar: {
width: 35,
},
color: {
pattern: ['#3366ff']
},
data: {
x: 'x',
labels:true,
columns: [
['x', 'Porsche Macan','Porsche Macan S','Porsche Macan S Diesel','Porsche Macan Turbo','Porsche Macan GTS'],
['0-62 mph in seconds', 6.7, 5.4, 6.3, 4.8, 5.2]
],
type: 'bar',
},
legend: {
show: true
},
axis: {
rotated: true,
x: {
type: 'category',
tick: {
multiline: false
} // this needed to load string x value
}
},
tooltip: {
show:false
},
bar: {
width: {
ration: .7
},
spacing: 2
}
});
I have tried it for simple bar charts, which provides bars with rounded corner as shown below:-
Here is the jsFiddle:- jsFiddle: Rounded bar charts
.c3-legend-item-tile, .c3-xgrid-focus, .c3-ygrid, .c3-event-rect, .c3-bars path {
shape-rendering: auto;
}
You need to basically override certain c3.js functions and provide logic for getting rounded corner by providing multiple points near the corner.
Otherwise all bars in a bar chart are polygons with 4 points. Solution is to provide bars with more points.

Categories