Related
How do I prevent the first and last bars from being cut off (showing half)?
I need to show the short month names on the x-axis. I've tried playing around with various min/max settings, but I can't seem to get it right.
var graphData = {
dates: [
'2016-06-01',
'2016-07-01',
'2016-08-01',
'2016-09-01',
'2016-10-01',
'2016-11-01',
'2016-12-01',
'2017-01-01',
'2017-02-01',
'2017-03-01',
'2017-04-01',
'2017-05-01'
],
wins: [23, 5, 13, 24, 8, 11, 23, 5, 13, 24, 8, 11],
draws: [2, 1, 2, 0, 2, 2, 3, 1, 2, 4, 0, 1],
losses: [3, 1, 2, 10, 8, 8, 3, 1, 2, 10, 8, 8],
winRates: [50, 40, 72, 30, 46, 80, 50, 40, 72, 30, 46, 80]
};
var winsMax = Math.max.apply(Math, graphData.wins);
var lossesMax = Math.max.apply(Math, graphData.losses);
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels: graphData.dates.map((date) => moment(date)),
datasets: [
{
type: "bar",
backgroundColor: "green",
hoverBackgroundColor: "green",
data: graphData.wins,
yAxisID: "winsAndLosses"
},
{
type: "bar",
backgroundColor: "red",
hoverBackgroundColor: "red",
data: graphData.losses.map((i) => -i),
yAxisID: "winsAndLosses"
},
{
type: "line",
data: graphData.winRates,
fill: true,
backgroundColor: "gray",
pointRadius: 0,
pointHoverRadius: 0,
yAxisID: "winRate"
}
]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
type: "time",
time: {
unit: "month",
displayFormats: {
month: "MMM"
}
},
stacked: true,
gridLines: {
display: false
},
ticks: {
callback: (label) => label.toUpperCase(),
fontSize: 10
}
}],
yAxes: [
{
id: "winsAndLosses",
stacked: true,
ticks: {
min: (lossesMax + 10) * -1,
max: winsMax + 10,
callback: (label) => Math.abs(label) // TODO: Localization (number formatting).
},
display: false
},
{
id: "winRate",
ticks: {
min: 0,
max: 100,
stepSize: 10,
callback: (label) => label + "%", // TODO: Localization (number formatting).
fontSize: 10
}
}
]
}
}
});
.myChartDiv {
max-width: 800px;
max-height: 400px;
}
<script src="https://npmcdn.com/chart.js#latest/dist/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="800" height="400"></canvas>
</div>
</body>
</html>
There's a setting called offset which seems to work for me:
xAxes: [{
offset: true
}]
var graphData = {
dates: [
'2016-06-01',
'2016-07-01',
'2016-08-01',
'2016-09-01',
'2016-10-01',
'2016-11-01',
'2016-12-01',
'2017-01-01',
'2017-02-01',
'2017-03-01',
'2017-04-01',
'2017-05-01'
],
wins: [23, 5, 13, 24, 8, 11, 23, 5, 13, 24, 8, 11],
draws: [2, 1, 2, 0, 2, 2, 3, 1, 2, 4, 0, 1],
losses: [3, 1, 2, 10, 8, 8, 3, 1, 2, 10, 8, 8],
winRates: [50, 40, 72, 30, 46, 80, 50, 40, 72, 30, 46, 80]
};
var winsMax = Math.max.apply(Math, graphData.wins);
var lossesMax = Math.max.apply(Math, graphData.losses);
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels: graphData.dates.map((date) => moment(date)),
datasets: [
{
type: "bar",
backgroundColor: "green",
hoverBackgroundColor: "green",
data: graphData.wins,
yAxisID: "winsAndLosses"
},
{
type: "bar",
backgroundColor: "red",
hoverBackgroundColor: "red",
data: graphData.losses.map((i) => -i),
yAxisID: "winsAndLosses"
},
{
type: "line",
data: graphData.winRates,
fill: true,
backgroundColor: "gray",
pointRadius: 0,
pointHoverRadius: 0,
yAxisID: "winRate"
}
]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
type: "time",
time: {
unit: "month",
displayFormats: {
month: "MMM"
}
},
stacked: true,
gridLines: {
display: false
},
ticks: {
callback: (label) => label.toUpperCase(),
fontSize: 10
},
offset:true
}],
yAxes: [
{
id: "winsAndLosses",
stacked: true,
ticks: {
min: (lossesMax + 10) * -1,
max: winsMax + 10,
callback: (label) => Math.abs(label) // TODO: Localization (number formatting).
},
display: false
},
{
id: "winRate",
ticks: {
min: 0,
max: 100,
stepSize: 10,
callback: (label) => label + "%", // TODO: Localization (number formatting).
fontSize: 10
}
}
]
}
}
});
.myChartDiv {
max-width: 800px;
max-height: 400px;
}
<script src="https://npmcdn.com/chart.js#latest/dist/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="800" height="400"></canvas>
</div>
</body>
</html>
I know this is very trivial but there is nothing in the documentation. I am using google charts treemap for monitoring something. If all the parent level rectangles are green, the distinct boxes aren't much clear because they are just divided by very thin white line. Can we customize the borders of each rectangle, like black line or increasing the width among each rectangle.
You can provide your own css, just keep in mind the chart is svg.
To change the border color, something like this should work.
rect {
stroke: black;
stroke-width: 2;
}
See following example...
google.charts.load('current', {
callback: function () {
var data = google.visualization.arrayToDataTable([
['Location', 'Parent', 'Market trade volume (size)', 'Market increase/decrease (color)'],
['Global', null, 0, 0],
['America', 'Global', 0, 0],
['Europe', 'Global', 0, 0],
['Asia', 'Global', 0, 0],
['Australia', 'Global', 0, 0],
['Africa', 'Global', 0, 0],
['Brazil', 'America', 11, 10],
['USA', 'America', 52, 31],
['Mexico', 'America', 24, 12],
['Canada', 'America', 16, -23],
['France', 'Europe', 42, -11],
['Germany', 'Europe', 31, -2],
['Sweden', 'Europe', 22, -13],
['Italy', 'Europe', 17, 4],
['UK', 'Europe', 21, -5],
['China', 'Asia', 36, 4],
['Japan', 'Asia', 20, -12],
['India', 'Asia', 40, 63],
['Laos', 'Asia', 4, 34],
['Mongolia', 'Asia', 1, -5],
['Israel', 'Asia', 12, 24],
['Iran', 'Asia', 18, 13],
['Pakistan', 'Asia', 11, -52],
['Egypt', 'Africa', 21, 0],
['S. Africa', 'Africa', 30, 43],
['Sudan', 'Africa', 12, 2],
['Congo', 'Africa', 10, 12],
['Zaire', 'Africa', 8, 10]
]);
new google.visualization.TreeMap(document.getElementById('chart_div')).draw(data, {
minColor: '#f00',
midColor: '#ddd',
maxColor: '#0d0',
headerHeight: 15,
fontColor: 'black',
showScale: true
});
},
packages:['treemap']
});
rect {
stroke: black;
stroke-width: 2;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
I am using ASP.NET MVC 4 with aspx.
I want from my controller to produce code at my view.
Therefore I have a line at my controller which is
ViewBag.Chart = "var c = r.barchart(10, 10, 600, 440, [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55]], { stacked: true, type: \"soft\" }).hoverColumn(fin2, fout2);";
However, when it shows at my code, it does not shows the character (") but instead it replaces it with a & quot;
What I can do in order to produce the character " at the code?
You need to use %= instead of %:
<%= ViewBag.Chart %>
if you are using %: it is automatically HTML encodes your string while the %= does not.
Sidenote: it is not a good practice to emit JavaScript from your controller into your view...
Hi try placing \ in front of the quote and before closing the quotes. It works fine for me
\"var c = r.barchart(10, 10, 600, 440, [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55]], { stacked: true, type: \"soft\" }).hoverColumn(fin2, fout2);\";
Anyone able to help with the following problem:
Trying to draw a chart with four data series, two of which are scatter and one is spline. Purpose of the spline is just to draw a line between specific spots on the chart, not joining all of them together. The following is my code so far:
$(function () {
var chart;
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'scatter',
zoomType: 'xy'
},
title: {
text: ''
},
xAxis: {
type: 'datetime',
ordinal: false,
labels: {
formatter: function() {
return Highcharts.dateFormat('%H', this.value);
}
}
},
yAxis: {
categories: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
gridLineWidth: 0,
step: 1,
title: '',
labels: {
style: {
color: '#6D869F',
fontSize: '9px',
}
},
},
tooltip: {
formatter: function() {
return ''+
this.x +' cm, '+ this.y +' kg';
}
},
legend: {
layout: 'vertical',
align: 'left',
verticalAlign: 'top',
x: 100,
y: 70,
floating: true,
backgroundColor: '#FFFFFF',
borderWidth: 1
},
plotOptions: {
scatter: {
marker: {
radius: 5,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
states: {
hover: {
marker: {
enabled: false
}
}
}
}
},
series: [{
name: 'sleep time',
marker: {
symbol: 'circle',
},
color: '#81c65b',
data: [[Date.UTC(2012, 1, 1, 22, 15), 0],
[Date.UTC(2012, 1, 1, 20, 30), 3],
[Date.UTC(2012, 1, 1, 21, 45), 5],
[Date.UTC(2012, 1, 1, 22, 00), 6]]
},
{
name: 'wakeup time',
marker: {
symbol: 'circle',
fillColor: '#76a4fb',
},
data: [[Date.UTC(2012, 1, 2, 08, 15), 0],
[Date.UTC(2012, 1, 2, 07, 10), 1],
[Date.UTC(2012, 1, 2, 09, 20), 2],
[Date.UTC(2012, 1, 2, 07, 40), 3],
[Date.UTC(2012, 1, 2, 07, 30), 4],
[Date.UTC(2012, 1, 2, 08, 20), 5],
[Date.UTC(2012, 1, 2, 09, 30), 6]],
},
{
name: 'sleep time over average',
color: 'rgba(119, 152, 191, .5)',
marker: {
symbol: 'square',
fillColor: '#000',
},
data: [[Date.UTC(2012, 1, 1, 20, 15), 1],
[Date.UTC(2012, 1, 1, 23, 40), 2],
[Date.UTC(2012, 1, 1, 21, 20), 4]]
},
{
name: '',
legend: {
enabled: false,
},
color: '#d62a9c',
type: 'spline',
marker: {
enabled: false,
},
data: [[Date.UTC(2012, 1, 1, 22, 15), 0],
[Date.UTC(2012, 1, 2, 08, 15), 0],
[Date.UTC(2012, 1, 1, 20, 15), 1],
[Date.UTC(2012, 1, 2, 07, 10), 1],
[Date.UTC(2012, 1, 1, 23, 40), 2],
[Date.UTC(2012, 1, 2, 09, 20), 2],
[Date.UTC(2012, 1, 1, 20, 30), 3],
[Date.UTC(2012, 1, 2, 07, 40), 3],
[Date.UTC(2012, 1, 1, 21, 20), 4],
[Date.UTC(2012, 1, 2, 07, 30), 4],
[Date.UTC(2012, 1, 1, 21, 45), 5],
[Date.UTC(2012, 1, 2, 08, 20), 5],
[Date.UTC(2012, 1, 1, 22, 00), 6],
[Date.UTC(2012, 1, 2, 09, 30), 6]]
}]
});
});
});
My problem now is, in the spline series, if I add a null between elements to prevent plotting the line between two points, the whole plot goes mayhem. The idea is to draw lines only so that points which are vertically on the same line get joined, eg. in this case "sleep time" and "wakeup time". For example,
data: [
[Date.UTC(2012, 1, 1, 22, 15), 0],
[Date.UTC(2012, 1, 2, 08, 15), 0], null,
[Date.UTC(2012, 1, 1, 20, 15), 1],
[Date.UTC(2012, 1, 2, 07, 10), 1], null,
[Date.UTC(2012, 1, 1, 23, 40), 2],
...
You may try out the code at this jsfiddle.
Try the following.
data: [
[Date.UTC(2012, 1, 1, 22, 15), 0],
[Date.UTC(2012, 1, 2, 08, 15), 0],
[Date.UTC(2012, 1, 2, 08, 15), null],
[Date.UTC(2012, 1, 1, 20, 15), 1],
[Date.UTC(2012, 1, 2, 07, 10), 1],
[Date.UTC(2012, 1, 2, 08, 15), null],
[Date.UTC(2012, 1, 1, 23, 40), 2],
[Date.UTC(2012, 1, 2, 09, 20), 2],
[Date.UTC(2012, 1, 2, 08, 15), null],
...
]
As you can see you have to pass an array which the first value have to be any date.
Demo
I am attempting to add infowindows to the markers with PlaceDetails that are returned after a google searchbox search. When I click on the markers no infowindows open. I cannot figure out where I went wrong?
var infowindow = new google.maps.InfoWindow();
//Function for search box
var input = document.getElementById('target');
var searchBox = new google.maps.places.SearchBox(input);
var markers = [];
google.maps.event.addListener(searchBox, 'places_changed', function() {
var places = searchBox.getPlaces();
for (var i = 0, marker; marker = markers[i]; i++) {
marker.setMap(null);
}
markers = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0, place; place = places[i]; i++) {
var image = new google.maps.MarkerImage(
'img/pin_blue.png',
new google.maps.Size(15,29),
new google.maps.Point(0,0),
new google.maps.Point(8,29)
);
var shadow = new google.maps.MarkerImage(
'img/pin_shadow.png',
new google.maps.Size(33,29),
new google.maps.Point(0,0),
new google.maps.Point(8,29)
);
var shape = {
coord: [11,1,12,2,13,3,14,4,14,5,14,6,14,7,14,8,14,9,14,10,14,11,14,12,13,13,12,14,11,15,8,16,8,17,8,18,8,19,8,20,8,21,8,22,8,23,8,24,11,25,11,26,11,27,3,27,3,26,3,25,6,24,6,23,6,22,6,21,6,20,6,19,6,18,6,17,6,16,3,15,2,14,1,13,0,12,0,11,0,10,0,9,0,8,0,7,0,6,0,5,0,4,1,3,2,2,3,1,11,1],
type: 'poly'
};
var marker = new google.maps.Marker({
map: map,
icon: image,
shadow: shadow,
shape: shape,
title: place.name,
position: place.geometry.location
});
markers.push(marker);
bounds.extend(place.geometry.location);
}
map.fitBounds(bounds);
//add an infowindow
google.maps.event.addListener(markers, 'click', function() {
infowindow.setContent(place.name);
infowindow.open(map, markers[i]);
});
});
google.maps.event.addListener(map, 'bounds_changed', function() {
//var bounds = map.getBounds();
searchBox.bindTo('bounds', map);
});
};
To get the Place Details to use in the InfoWindow, you need to make a second request to the Places API (when the marker is clicked). Inside the createMarker function (which has function closure on the "place"):
var request = {
reference: place.reference
};
google.maps.event.addListener(marker,'click',function(){
service.getDetails(request, function(place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
var contentStr = '<h5>'+place.name+'</h5><p>'+place.formatted_address;
if (!!place.formatted_phone_number) contentStr += '<br>'+place.formatted_phone_number;
if (!!place.website) contentStr += '<br><a target="_blank" href="'+place.website+'">'+place.website+'</a>';
contentStr += '<br>'+place.types+'</p>';
infowindow.setContent(contentStr);
infowindow.open(map,marker);
} else {
var contentStr = "<h5>No Result, status="+status+"</h5>";
infowindow.setContent(contentStr);
infowindow.open(map,marker);
}
});
});
Example
I little bit changed your code.
Try this one.
<html>
<head>
<script src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script>
<script type='text/javascript'>
var map, infowindow;
var searchBox;
var markers = [];
function initialize() {
var mapDiv = document.getElementById("map_canvas");
map = new google.maps.Map(mapDiv, {
center : new google.maps.LatLng(35, 138),
zoom : 7,
mapTypeId : google.maps.MapTypeId.ROADMAP
});
infowindow = new google.maps.InfoWindow();
//Function for search box
var input = document.getElementById('target');
searchBox = new google.maps.places.SearchBox(input);
google.maps.event.addListener(searchBox, 'places_changed', function() {
var places = searchBox.getPlaces();
for (var i = 0, marker; marker = markers[i]; i++) {
marker.setMap(null);
}
markers = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0, place; place = places[i]; i++) {
var image = new google.maps.MarkerImage('img/pin_blue.png', new google.maps.Size(15, 29), new google.maps.Point(0, 0), new google.maps.Point(8, 29));
var shadow = new google.maps.MarkerImage('img/pin_shadow.png', new google.maps.Size(33, 29), new google.maps.Point(0, 0), new google.maps.Point(8, 29));
var shape = {
coord : [11, 1, 12, 2, 13, 3, 14, 4, 14, 5, 14, 6, 14, 7, 14, 8, 14, 9, 14, 10, 14, 11, 14, 12, 13, 13, 12, 14, 11, 15, 8, 16, 8, 17, 8, 18, 8, 19, 8, 20, 8, 21, 8, 22, 8, 23, 8, 24, 11, 25, 11, 26, 11, 27, 3, 27, 3, 26, 3, 25, 6, 24, 6, 23, 6, 22, 6, 21, 6, 20, 6, 19, 6, 18, 6, 17, 6, 16, 3, 15, 2, 14, 1, 13, 0, 12, 0, 11, 0, 10, 0, 9, 0, 8, 0, 7, 0, 6, 0, 5, 0, 4, 1, 3, 2, 2, 3, 1, 11, 1],
type : 'poly'
};
var marker = createMarker({
map : map,
//icon : image,
//shadow : shadow,
//shape : shape,
title : place.name,
position : place.geometry.location,
place_name : place.name
})
markers.push(marker);
bounds.extend(place.geometry.location);
}
map.fitBounds(bounds);
});
google.maps.event.addListener(map, 'bounds_changed', function() {
//var bounds = map.getBounds();
searchBox.bindTo('bounds', map);
});
}
function createMarker(options) {
var marker = new google.maps.Marker(options);
//add an infowindow
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(options.place_name);
infowindow.open(map, marker);
});
return marker;
}
google.maps.event.addDomListener(window, "load", initialize);
</script>
</head>
<body>
<input type="text" id="target" />
<div id="map_canvas" style="width: 500px;height:400px"></div>
</body>
</html>