I'm trying to get data point to work for bar charts, I found the plugin for line chart, but can't get it to work for bars, can anyone help? the data point should show above the bar. https://jsfiddle.net/x79b1m2w/1/
<div class="ct-chart ct-golden-section" id="chart1"></div>
<div class="ct-chart ct-golden-section" id="chart2"></div>
<script>
new Chartist.Bar('#chart1', {
labels: ['M', 'T', 'W', 'T', 'F'],
series: [8, 19, 24, 37, 12]
}, {
distributeSeries: true
});
new Chartist.Line('#chart2', {
labels: ['M', 'T', 'W', 'T', 'F'],
series: [
[12, 9, 7, 8, 5]
]
}, {
plugins: [
Chartist.plugins.ctPointLabels({
textAnchor: 'middle'
})
]
});
</script>
<script>
(function(window, document, Chartist) {
'use strict';
var defaultOptions = {
labelClass: 'ct-label',
labelOffset: {
x: 0,
y: -10
},
textAnchor: 'middle',
labelInterpolationFnc: Chartist.noop
};
Chartist.plugins = Chartist.plugins || {};
Chartist.plugins.ctPointLabels = function(options) {
options = Chartist.extend({}, defaultOptions, options);
return function ctPointLabels(chart) {
if(chart instanceof Chartist.Line) {
chart.on('draw', function(data) {
if(data.type === 'point') {
data.group.elem('text', {
x: data.x + options.labelOffset.x,
y: data.y + options.labelOffset.y,
style: 'text-anchor: ' + options.textAnchor
}, options.labelClass).text(options.labelInterpolationFnc(data.value.x === undefined ? data.value.y : data.value.x + ', ' + data.value.y));
}
});
}
if(chart instanceof Chartist.Bar) {
chart.on('draw', function(data) {
if(data.type === 'bar') {
data.group.elem('text', {
x: data.x + options.labelOffset.x,
y: data.y + options.labelOffset.y,
style: 'text-anchor: ' + options.textAnchor
}, options.labelClass).text(options.labelInterpolationFnc(data.value.x === undefined ? data.value.y : data.value.x + ', ' + data.value.y));
}
});
}
};
};
}(window, document, Chartist));
There's a plugin to add labels to bar and column charts.
See here: https://github.com/YorkshireInteractive/chartist-bar-labels
I then borrowed the label position calculations from the following github comments:
https://github.com/gionkunz/chartist-js/issues/281
In short, I have the following in the ctBarLabels plugin options:
position: {
x: function(data) {
return data.x1 + (data.element.width() * .5);
},
y: function(data) {
return data.y1 + (data.element.height() * -1) - 10;
}
I can now style the labels with a stylesheet. I can also use functions to format the labels (for example, currency vs. the plain value).
Change your plugin code to :
if(chart instanceof Chartist.Bar) {
chart.on('draw', function(data) {
if(data.type === 'bar') {
data.group.elem('text', {
x: (data.x === undefined ? data.x1 : data.x ) + options.labelOffset.x,
y: (data.y === undefined ? data.y2 : data.y) + options.labelOffset.y,
style: 'text-anchor: ' + options.textAnchor
}, options.labelClass).text(options.labelInterpolationFnc(data.value.x === undefined ? data.value.y : data.value.x + ', ' + data.value.y));
}
});
}
Related
Is there a possibility to accomplish a Google barchart to look like this?
The end of each bar with custom styling
Annotation comes below the line (GOAL 10.3)
you can use the chart layout method to add an icon, or any element, to the end of the bar.
// add icon to bar
var barBounds = layout.getBoundingBox('bar#0#0');
var icon = chart.getContainer().appendChild(document.createElement('span'));
icon.className = 'icon';
icon.style.top = (barBounds.top + containerBounds.top - 3) + 'px';
icon.style.left = (barBounds.left + containerBounds.left + (barBounds.width) - 24) + 'px';
icon.innerHTML = '<i class="fas fa-arrow-alt-circle-right"></i>';
also, instead of drawing the annotation and trying to prevent the chart from moving it,
we can leave it out and add our own custom annotation...
// add annotation
var labelCopy = svg.getElementsByTagName('text')[0];
var annotation = labelCopy.cloneNode(true);
svg.appendChild(annotation);
annotation.setAttribute('text-anchor', 'middle');
annotation.textContent = data.getValue(0, data.getNumberOfColumns() -1);
annotation.setAttribute('x', xLoc);
annotation.setAttribute('y',
layout.getYLocation(0) + (parseInt(annotation.getAttribute('font-size')) * 3)
);
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(drawHorizontalChart_portal_name_stella_york_horz_month_points);
function drawHorizontalChart_portal_name_stella_york_horz_month_points() {
var data = google.visualization.arrayToDataTable([
["", "Goal Achieved", {role: 'style'}, "GOAL 13.1 points", {role: 'style'}, {role: 'annotation'}],
[1, 1.5, "opacity: .75;", 13.1, "opacity: 0;", "GOAL 13.1 points"]
]);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, 3, 4]);
var options = {
title: '',
width: '100%',
height: 132,
chartArea: {
height: '100%',
width: '100%',
top: 36,
left: 18,
right: 18,
bottom: 48
},
hAxis: {
title: '',
minValue: 0,
gridlines: {
count: 6
},
format: '0'
},
bar: {
groupWidth: "60%"
},
legend: {
position: "top"
},
series: {
0: {
color: '#70b5c5',
visibleInLegend: false
}, // Goal Achieved
1: {
color: '#000000',
type: 'line',
annotations: {
textStyle: {
color: '#000000'
},
stem: {
color: 'transparent',
length: -128
},
vertical: true
}
} // Target Goal
},
vAxis: {
gridlines: {
color: 'transparent'
},
ticks: [{v: 1, f: ''}]
}
};
var chart = new google.visualization.BarChart(document.getElementById("portal-name-stella-york-horz-month-points"));
google.visualization.events.addListener(chart, 'click', function(e) {
console.log(JSON.stringify(e));
});
google.visualization.events.addListener(chart, 'ready', function () {
// init variables
var layout = chart.getChartLayoutInterface();
var containerBounds = chart.getContainer().getBoundingClientRect();
var svg = chart.getContainer().getElementsByTagName('svg')[0];
var svgNS = svg.namespaceURI;
var xLoc = drawVAxisLine(chart, layout, data.getValue(0, 3));
// add image to bar
var barBounds = layout.getBoundingBox('bar#0#0');
var icon = chart.getContainer().appendChild(document.createElement('span'));
icon.className = 'icon';
icon.style.top = (barBounds.top + containerBounds.top - 3) + 'px';
icon.style.left = (barBounds.left + containerBounds.left + (barBounds.width) - 24) + 'px';
icon.innerHTML = '<i class="fas fa-arrow-alt-circle-right"></i>';
// add annotation
var labelCopy = svg.getElementsByTagName('text')[0];
var annotation = labelCopy.cloneNode(true);
svg.appendChild(annotation);
annotation.setAttribute('text-anchor', 'middle');
annotation.textContent = data.getValue(0, data.getNumberOfColumns() -1);
annotation.setAttribute('x', xLoc);
annotation.setAttribute('y',
layout.getYLocation(0) + (parseInt(annotation.getAttribute('font-size')) * 3)
);
});
chart.draw(view, options);
}
jQuery(window).resize(function() {
drawHorizontalChart_portal_name_stella_york_horz_month_points();
});
function drawVAxisLine(chart, layout, value) {
var chartArea = layout.getChartAreaBoundingBox();
var svg = chart.getContainer().getElementsByTagName('svg')[0];
var xLoc = layout.getXLocation(value)
svg.appendChild(createLine(xLoc, chartArea.top + chartArea.height, xLoc, chartArea.top, '#000000', 2)); // axis line
return xLoc;
}
function createLine(x1, y1, x2, y2, color, w) {
var line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', x1);
line.setAttribute('y1', y1);
line.setAttribute('x2', x2);
line.setAttribute('y2', y2);
line.setAttribute('stroke', color);
line.setAttribute('stroke-width', w);
return line;
}
.icon {
font-size: 32px;
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
<div id="portal-name-stella-york-horz-month-points"></div>
I am working on leaflet map and showing markers on it. on click of marker I am opening the popup and on click of that navigating it to another page, this all works fine but when I click back from the navigated page to map then the .bindPopup() is not working and I am not able to open the popup again.
here is my code:
var marker = leaflet.circleMarker([marker.latitude, marker.longitude], { renderer, radius: 8, weight: 1, color: '#fff', fillColor: markerColor, fillOpacity: 1 })
.addTo(this.map)
.bindPopup(marker.id + '<br/>' + marker.status + '<br/>');
marker.on('click', (e) => {
var popup = e.target.getPopup();
this.issueServiceProvider.getIssue(marker.id, false).subscribe((result) => {
var div = leaflet.DomUtil.create('div', 'command');
div.innerHTML = marker.id + '<br/>' + marker.status + '<br/>' + result.description + '<br/><a id = "command">More Details</a> <br/>';
popup.setContent(div);
leaflet.DomEvent.addListener(div, 'click', () => {
this.navCtrl.push(Constants.Page.IssueDetails, { markerId: marker.id }, Constants.Animation['TransitionForward']);
});
}, (err) => {
console.error('Error' + err);
});
});
How could I make it work?
This popup works, but does not reference your specific function. Try this and then add your function call once the basic setup is complete.
var marker = leaflet.circleMarker([39, -105], { radius: 8, weight: 1, color: "#274FCA", fillOpacity: 1 })
.addTo(map)
.bindPopup(this.id + '<br/>' + this.status + '<br/>');
marker.on('click', (e) => {
var popup = e.target.getPopup();
var div = L.DomUtil.create('div', 'command');
div.innerHTML = 'marker.id' + '<br/>' + 'marker.status' + '<br/>' + 'result.description' + '<br/><a id = "command">More Details</a> <br/>';
popup.setContent(div);
leaflet.DomEvent.addListener(div, 'click', () => {
this.navCtrl.push(Constants.Page.IssueDetails, { markerId: marker.id }, Constants.Animation['TransitionForward']);
});
});
I looked at other posts and I see how to get edit, change, delete events from SchedulerEventRecorder. One thing i cant find is how to listen for drag events? I dont seem to be bale to find any docs on that. Below is my code:
YUI().use(
'aui-scheduler',
function(Y) {
var events = [
{
color: '#8B0000',
repeated: true,
content: 'Event1',
endDate: new Date(2017, 12, 1, 16),
startDate: new Date(2017, 12, 1, 1)
}
];
var agendaView = new Y.SchedulerAgendaView();
var dayView = new Y.SchedulerDayView();
var monthView = new Y.SchedulerMonthView();
var weekView = new Y.SchedulerWeekView();
var eventRecorder = new Y.SchedulerEventRecorder({
on: {
save: function(event) {
alert('Save Event:' + this.isNew() + ' --- ' + this.getContentNode().val()+'-----startDate='+this.get('startDate')+'-----EndDate='+this.get('endDate'));
},
edit: function(event) {
alert('Edit Event:' + this.isNew() + ' --- ' + this.getContentNode().val());
},
delete: function(event) {
alert('Delete Event:' + this.isNew() + ' --- ' + this.getContentNode().val());
// Note: The cancel event seems to be buggy and occurs at the wrong times, so I commented it out.
// },
// cancel: function(event) {
// alert('Cancel Event:' + this.isNew() + ' --- ' + this.getContentNode().val());
}
}
});
schedule =new Y.Scheduler(
{
activeView: weekView,
boundingBox: '#myScheduler',
date: new Date(2017, 12, 1),
eventRecorder: eventRecorder,
items: events,
render: true,
views: [dayView, weekView, monthView, agendaView]
}
);
}
);
Add "drag:end" property while initializing Scheduler
new Y.Scheduler({
activeView: ...,
boundingBox: '#myScheduler',
eventRecorder: ...,
render: true,
views: [dayView, weekView, monthView, agendaView],
on: {
"drag:end": function (event) {
// DO SOMETHING HERE
}
}
});
To listen any attr change put on your save callback like bellow:
event.newSchedulerEvent.on("endDateChange",function(event){
});
In this case i'm listening endDate.
Right so I have my chart set up but the side labels or bar titles are cut off if they don't fit in the div of the graph, so my question is, is there anyway to overflow the bar titles of the graph(the font size is getting too small to read so I can't make it any smaller) or even wrap the text.
Well seeing as I don't think the code will help I'll show it regardless, mind you I have limited space and I am showing 2 graphs in that space. All I need is the side labels to have overflow: show(so if the specific bar label overflows the area it displays..
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1.1','packages':['corechart']}]}"></script>
</head>
<body>
<div>
<div id="myChart" style="width:50%"></div>
</div>
<script type="text/javascript">
$(function(){
var id = "myChart";
var chartData= [["The big label that is the issue in this case we need this to display its overflow","74","",""],["Louise","71","",""],["Louise.v.2","0","",""],["member1","72","",""],["member3","67","",""]];
var defaultColors = ["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099", "#0099c6", "#dd4477", "#66aa00",
"#b82e2e", "#316395", "#994499", "#22aa99", "#aaaa11", "#6633cc", "#e67300", "#8b0707", "#651067", "#329262",
"#5574a6", "#3b3eac", "#b77322", "#16d620", "#b91383", "#f4359e", "#9c5935", "#a9c413", "#2a778d", "#668d1c",
"#bea413", "#0c5922", "#743411"];
var counter = 0;
var data = new google.visualization.DataTable();
data.addColumn('string', 'Name');
data.addColumn('number', '');
data.addColumn({ type: 'string', role: "style" });
data.addColumn({ type: 'string', role: 'annotation' });
if (chartData[0][3].length > 0) {
data.addColumn('number', '');
}
data.addRows(chartData.length + 1);
for (var i = 0; i < chartData.length; i++) {
var thisItem = chartData[i];
data.setCell(i, 0, thisItem[0]);
data.setCell(i, 1, thisItem[1]);
if (thisItem[2].length > 0) {
data.setCell(i, 2, "color: #000000");
} else {
data.setCell(i, 2, "color: " + defaultColors[counter]);
}
data.setCell(i, 3, thisItem[1] + "%");
if (thisItem[3].length > 0) {
data.setCell(i, 4, thisItem[3]);
}
counter = counter + 1;
if (counter == 31) {
counter = 0;
}
}
var barChart = null;
var options = null;
barChart = new google.visualization.ComboChart(document.getElementById(id));
var fullHeight = ((chartData.length + 1) * 20) + 50;
var minHieght = 200;
options = {
height: fullHeight,
tooltip: { isHtml: true },
max: 100,
label: 'value',
orientation: 'vertical',
fontSize: 15,
width: (((($(window).width() / 3) * 2) / 5) * 3),
legend: { position: 'none' },
bar: { groupWidth: 15, width: 20 },
chartArea: { height: fullHeight - 50, width: "47%", left: "50%", top: 0 },
backgroundColor: 'transparent',
enableInteractivity: false,
legend: 'none',
seriesType: 'bars',
series: { 1: { type: 'line', lineWidth: 5, enableInteractivity: false, color: 'grey' } },
annotations: {
alwaysOutside: true
}
};
barChart.draw(data, options);
});
</script>
</body>
</html>
I hope you can help me with this:
I have a chart of stacked columns, all of them with two values to stack in each column. I have successfully created the chart BUT I need to add an annotation for each piece of each column (I don't know the proper name for it) indicating the percentage of the total represented by the piece in it's own column.
In the example given below, I would need to set the annotations so it would show the stacked columns and, for the first column should have an annotation on the "Good" area with value "60%" and another annotation for the "Bad" area of "40%", and so on.
So far, I have managed to include one annotation that shows the percentage value for the "Bad" area, which floates to the top of each column. I would need help to properly define the annotation for each area of the column and, hopefully, place it centered in it's given area.
Thank you in advance for your help.
TL;DR: I need centered annotations for each piece of each column.
<body>
<div id="chart" style="width: 900px; height: 500px; border: 1px solid black;">
</div>
</body>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", { packages: ["corechart"] });
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Date', 'Good', 'Bad'],
[Date(2013, 11, 1), 3, 2],
[Date(2013, 11, 2), 5, 3],
[Date(2013, 11, 3), 9, 2],
[Date(2013, 11, 4), 6, 3]
]);
var view = new google.visualization.DataView(data);
view.setColumns([{
label: 'Date',
type: 'string',
calc: function (dt, row) {
var str = dt.getValue(row, 0);
return { v: str, f: str.toString('dd/MM/aaaa') };
}
}
, {
label: 'Good',
type: 'number',
calc: function (dt, row) {
var good = dt.getValue(row, 1);
var bad = dt.getValue(row, 2);
return { v: good / (good + bad), f: good.toString() };
}
}, {
label: 'Bad',
type: 'number',
calc: function (dt, row) {
var good = dt.getValue(row, 1);
var bad = dt.getValue(row, 2);
return { v: bad / (good + bad), f: bad.toString() };
}
},
{
role: 'annotation',
type: 'string',
calc: function (dt, row) {
var good = dt.getValue(row, 1);
var bad = dt.getValue(row, 2);
var perc = (bad / (good + bad)) * 100;
var ann = parseFloat(Math.round(perc).toFixed(2)) + "%";
return { v: ann, f: ann.toString() };
}
}]);
var options = {
title: 'Daily deeds',
isStacked: true,
vAxis: { format: '#.##%' }
};
var chart = new google.visualization.ColumnChart(document.getElementById('chart'));
chart.draw(view, options);
}
</script>
You need to add another annotation column after your "Good" column:
view.setColumns([{
label: 'Date',
type: 'string',
calc: function (dt, row) {
var str = dt.getValue(row, 0);
return { v: str, f: str.toString('dd/MM/aaaa') };
}
}, {
label: 'Good',
type: 'number',
calc: function (dt, row) {
var good = dt.getValue(row, 1);
var bad = dt.getValue(row, 2);
return { v: good / (good + bad), f: good.toString() };
}
}, {
role: 'annotation',
type: 'string',
calc: function (dt, row) {
var good = dt.getValue(row, 1);
var bad = dt.getValue(row, 2);
var perc = (good / (good + bad)) * 100;
var ann = perc.toFixed(2) + "%";
return ann;
}
}, {
label: 'Bad',
type: 'number',
calc: function (dt, row) {
var good = dt.getValue(row, 1);
var bad = dt.getValue(row, 2);
return { v: bad / (good + bad), f: bad.toString() };
}
}, {
role: 'annotation',
type: 'string',
calc: function (dt, row) {
var good = dt.getValue(row, 1);
var bad = dt.getValue(row, 2);
var perc = (bad / (good + bad)) * 100;
var ann = perc.toFixed(2) + "%";
return ann;
}
}]);