I'm using showArea: true but can't find the appropriate setting to make that fill all the way. Example:
I assume this is because I don't have any data points after where it ends, but I don't want the green line to extend all the way across the top. Is there another way to accomplish this?
You're using showArea:true to render the area. But as you've noted, showArea fills the area associated only with the drawn line.
What you're looking for is an additional area without a line.
In order to achieve this effect, you'll need to create two different lines: The first line will have showArea: false and extend to W3 as shown in your example. This will render the light green line as you have already.
The second line will be invisible have showLine: false and showArea: true and extend all the way across the top to W8.
In other words, you're actually looking to render two different things. One is a line, and one is a fill area.
I guess that the key solution to your problem is to use display:inline-block;
for example:
div.page {
color: white;
background: black;
margin: auto;
padding: 1em;
display:inline-block;
}
In order for the area to highlight you need to insert appropriate data. The showArea property extend as much as the data it has. Here is a proof of concept:
/* Add a basic data series with six labels and values */
var data = {
labels: [1, 2, 3, 4, 5],
series: [
[1, 5, 10, 15, 20],
[1, 20]
]
};
/* Set some base options (settings will override the default settings in Chartist.js *see default settings*). We are adding a basic label interpolation function for the xAxis labels. */
var options = {
showArea: true,
axisX: {
labelInterpolationFnc: function (value) {
return 'Week ' + value;
}
}
};
/* Initialize the chart with the above settings */
new Chartist.Line('.ct-chart', data, options);
.ct-chart {
width: 450px;
height: 250px;
}
<link href="https://rawgit.com/gionkunz/chartist-js/master/dist/chartist.min.css" rel="stylesheet"/>
<script src="https://rawgit.com/gionkunz/chartist-js/master/dist/chartist.min.js"></script>
<div class="ct-chart ct-square"></div>
The two areas are highlighted within the data they represent.
Hope this helps.
Related
What I have
I've created 2 graphs like shown in the first image below. I need these 2 graphs to be perfectly aligned on the 0 axis (which is shown in the section below).
Wanted result
In the image below, the graphs are perfectly aligned and should therefore contain 2 different datasets. One should be placed on the left grid and the other one on the right grid.
The options I thought of
I have not seen a way to implement this in ChartJS. Therefore, I thought of some possible solutions that could solve this issue in a different way.
Because both datasets don't have negative values, I could convert the left dataset to negative values (on the x-axis). The downside is that the range would be incorrect. Also, this would give issues with the popup message if you hover your mouse on a value.
Maybe, two canvas objects can be combined that could result in the wanted result
Question
Is there a way to achieve the wanted result within ChartJS? Or can I perform some wizardry to combine two charts nicely into one? Or should I move to the D3.js library for this particular graph?
I did not find a way to "nicely" implement this. I've changed the source code of the ChartJS library to implement this.
This method uses 2 different graphs that render in 2 different canvas objects. These canvas objects are placed side-by-side to let it look like one graph.
This is my result (The code in here is not exactly like the graph in the picture because I changed it to my specific needs).
I've added a custom variable in the options.layout category named sidePadding.
The code of creating the graph:
new Chart(document.getElementById(this.element), {
type: 'scatter',
data: {
datasets: [{
borderColor: this.lineColor,
borderWidth: 1,
pointBackgroundColor: '#000',
pointBorderColor: '#000',
pointRadius: 0,
fill: false,
tension: 0,
showLine: true,
data: [],
}],
},
options: {
aspectRatio: 0.3,
maintainAspectRatio: false,
responsive: true,
layout: {
sidePadding: {
left: 3,
right: -3,
}
}
}
});
The padding on the sides is by default 3 so it does not touch the border of the canvas. I wanted it to touch the border of the canvas, and therefore set it to -3.
Two different graphs need to be created, one for the left side and one for the right side.
The left graph should have the sidePadding.right set to -3. The right graph should have the sidePadding.left set to -3.
Changes in the ChartJS library
I've worked with ChartJS version v2.9.3. This method will possibly not work anymore in a new version.
I've changed the following in the Chart.js file:
Replace (line number around 11800):
// Adjust padding taking into account changes in offsets
// and add 3 px to move away from canvas edges
me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + 3;
me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - offsetRight), 0) + 3;
to:
// Adjust padding taking into account changes in offsets
// and add 3 px to move away from canvas edges
var layoutOptions = chart.options.layout || {};
var sidePadding = helpers$1.options.toPadding(layoutOptions.sidePadding);
me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + sidePadding.left;
me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - offsetRight), 0) + sidePadding.right;
Also you must add the sidePadding.left and sidePadding.right parameter to ChartJS.
This can be done by changing (line number around 7180):
core_defaults._set('global', {
layout: {
padding: {
top: 0,
right: 0,
bottom: 0,
left: 0
},
// Custom added parameter
sidePadding: {
left: 3,
right: 3,
}
}
});
to:
core_defaults._set('global', {
layout: {
padding: {
top: 0,
right: 0,
bottom: 0,
left: 0
},
// Custom added parameter
sidePadding: {
left: 3,
right: 3,
}
}
});
Note
This is probably not the best way to achieve this. Changing the ChartJS library is bad-practice and updating the library could revert these changes.
If someone has a better way to achieve this, please post your methods or comment below.
Following is my resultant chart
Here the value of legends Happy and Very Happy is 0, hence it is overlapping each other and unable to read. So, How can I hide these values and strike through the legends while loading itself like in the below image? And yes, it is a dynamically loaded chart.
Link - Reference Pie Chart
Thanks in advance.
I am posting this answer hoping that, it will be helpful for someone later. You can also post a better solution if found.
After some deep diving into the library the files, I realised that is there are no direct answers to my question. But we can achieve that by emptying the label text in case of 0 data values.
For that, we must edit the chart options as follows,
public pieChartOptions: ChartOptions = {
responsive: true,
legend: {
position: 'top',
},
plugins: {
datalabels: {
formatter: (value, ctx) => {
const label = ctx.chart.data.labels[ctx.dataIndex];
if (ctx.dataset.data[ctx.dataIndex] > 0)
return label + " : " + ctx.dataset.data[ctx.dataIndex];
else
return "" // retun empty if the data for label is empty
},
}
},
showLines: true,
spanGaps: true,
cutoutPercentage: 1,
rotation: 15, // rotate the chart
};
Here in the function returns empty value in case the data for the corresponding label is 0. Also I rotate the chart 15deg to make the labels horizontal align in most cases.
Reference - Chart.js documentation
Hence I achieved a better view to the user and the overlapping issues are resolved. Thanks.
I'm trying to merge two jvectormaps: italy-regions and italy-provinces, i
would like to achieve something similar to the drill-down example or even just have the map diveded both in regions and provinces.
I think i cannot use multimap like in the demo because italy-provinces map is just one script with all the provinces inside, so the main function for retrieve the map of each region is useless:
mapUrlByCode: function(code, multiMap){
return '/js/us-counties/jquery-jvectormap-data-'+
code.toLowerCase()+'-'+
multiMap.defaultProjection+'-en.js';
}
In this pen i've reproduced something similar to what i'm trying to achieve.
Obviously this solution is really bad, because i'm using two maps and once i click in a random region of the first map the second map will not zoom, so the two maps looks not synchronized.
Someone know or can suggest a way to achieve what i need?
Luckily, the great jVectorMap also supports focus on more than one region, so what you need is just to create the association among regions and provinces and invoke that functions twice.
I revorked a bit your code to be in some way more "explicit" about Provinces and Regions:
HTML:
<div id="map-provinces"></div>
<div id="map-regions"></div>
CSS:
#map-provinces{
height:500px;
width: 500px;
left:-500px;
opacity:0.5;
}
#map-regions{
top: 8px; /* Body margin wasn't set correctly in the CodePen */
position : absolute;
height:500px;
width: 500px;
opacity:0.5;
}
Here is how i do it with the Region of Sicily, up to you to complete this example with the whole list of Province codes:
var provinces ={"IT-82": ["TP","PA","AG","CL","EN","ME","CT","RG","SR"]};
$('#map-provinces').vectorMap({
map: 'it_mill'
});
$('#map-regions').vectorMap({
map: 'it_regions_mill',
backgroundColor : 'white',
zoomOnScroll : false,
zoomMin : 0,
zoomMax :220,
regionStyle :{
initial: {
fill: 'blue',
"fill-opacity": 1,
stroke: 'none',
"stroke-width": 0,
"stroke-opacity": 1
},
hover: {
"fill-opacity": 1,
cursor: 'pointer'
},
selected: {
fill: 'blue',
"fill-opacity": 1,
},
selectedHover: {
"fill-opacity": 1,
cursor: 'pointer'
}
},
onRegionClick: function(e, code, isSelected, selectedRegions){
var codes = [];
provinces[code].forEach(function(province) {
codes.push("IT-"+province);
});
$('#map-regions').vectorMap('get','mapObject').setFocus({region: code});
$('#map-provinces').vectorMap('get', 'mapObject').setFocus({regions: codes});
}
});
Whit that in mind, you can easily implement the drill-down sample provided on the jVectorMap website, and have both maps correctly aligned after the zoom on region click, like in this picture below, where both overlapped maps are displayed, like you did it in your CodePen:
I am using Primefaces 6 for my companys charting needs, which relies on jQplot.
For a project, I am trying to overlay a line chart on a stacked bar chart with negative values, to obtain something like this:
The problem is that when I try to add a linechartseries to the same model as the two barchartseries , the linechart becomes a part of the stack when setting setStacked(true); on the model, because Primefaces seems to not allow individual disabling of stacking on series, only per model. So I end up with this when rendering the chart with
<p:chart type="bar" model="#{backingBean.cartesianChartModel}"/>
After some investigation I have notoced that jQplot is capable of disabling Stacking on individual series by passing disableStack : true in the JS options, so the question is if it's posssible to override this in some way on the rendered page,either via PF or via some JS hack? I feel that using the extender only apples to the entire model?
Related issues: Disable individual stacking
By pouring through the documentation I found a solution to the problem, if not the question:
It seems that Primefaces allows for individual series to be excempt from the stack in the series creation in this version, by passing
LineChartSeries.setDisableStack(true);
Simple as that.
I guess it may be possible. I used the extender functionality for some jqPlot hacks in the past.
In my case, for example, I had a Donut Chart defined with an extender function as follows:
private void createDonutModel() {
donutModel = new DonutChartModel();
donutModel.setLegendPosition("s");
donutModel.setLegendPlacement(LegendPlacement.OUTSIDE);
donutModel.setSliceMargin(4);
donutModel.setDataFormat("value");
donutModel.setShadow(false);
donutModel.setExtender("donutExtender");
donutModel.setSeriesColors("B81C40, FFA600, 79B54A");
}
The corresponding javascript was doing some changes to the jqPlot:
/**
* Customized jqPlot JQuery layout of the Donut Chart for Status Dashboard.
*/
function donutExtender() {
this.cfg.seriesDefaults = {
// make this a donut chart.
renderer:$.jqplot.DonutRenderer,
rendererOptions:{
thickness: 26,
ringMargin: 0,
fill: true,
padding: 0,
sliceMargin: 4,
// Pies and donuts can start at any arbitrary angle.
startAngle: -90,
showDataLabels: false,
// By default, data labels show the percentage of the donut/pie.
// You can show the data 'value' or data 'label' instead, or 'percent'
dataLabels: 'value',
shadow: false
}
}
this.cfg.gridPadding = {
top: 0, right: 0, bottom: 0, left: 0
}
this.cfg.legend = {
show: false
}
this.cfg.grid = { drawBorder: false,
shadow: false,
background: "transparent"
};
}
So you may try something like this in your case ?
Leave the extension configuration of your series empty, except for the one you are interested in...
function chartExtender() {
this.cfg.series = [
{ //...
},
{ // ...
},
{
disableStack: true
}
]
}
Worth having a shot ...
Since I could not find and answer for this question, I hope it's not a duplicate. I'm using chartist.js, and I make a simple donut, that's pretty easy and straight forward, but now I'd like to disable the labels, which works fine and add a single lable inside of the donut (Thhis is the problem). It's not needed, that the label gets greated, by the chart itself, it would be sufficient if it's just a new div or something else.
My Code so far:
<div class="ct-chart1 ct-chart ct-perfect-fourth"></div>
and
new Chartist.Pie('.ct-chart1', {
labels: [],
series: [75, 25]
}, {
donut: true,
width: '300px',
height: '200px',
donutWidth: 30,
startAngle: 0,
total: 100
});
I already tried to make the chart itself a flexbox and add the label as child and center it that way, but that did not work and I tried to surround the chart with a new div, but that let's the chart disappear.
<div>
<div class="ct-chart1 ct-chart ct-perfect-fourth"></div>
</div>
I'd use the draw event to center labels to the middle of the chart. Check this bin http://jsbin.com/hipafu/edit?html,css,js,output
Also watch out for the styles:
.ct-label {
dominant-baseline: central;
text-anchor: middle;
}