I am trying to use unicode character for highchart marker symbol, but it does not display. Here my code:
marker: {
symbol: "⭐",
lineColor: null,
lineWidth: 2
}
You can wrap symbol method to add support for unicode characters:
H.wrap(H.SVGRenderer.prototype, 'symbol', function(proceed, symbol, x, y, w, h) {
if (symbol.indexOf('text:') === 0) {
var text = symbol.split(':')[1],
svgElem = this.text(text, x, y + h)
return svgElem;
}
return proceed.apply(this, Array.prototype.slice.call(arguments, 1));
});
Live demo: https://jsfiddle.net/BlackLabel/eu9avqw5/
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#text
Docs: https://www.highcharts.com/docs/extending-highcharts
Related
In a grouped column chart of two groups, I would like to center the column when the other column has height 0.
So for example,
The bars for the years 2013 to 2016 should be centered on the year label. This is because the second value in the group is 0, so the height of the bar is 0, so no bar displays:
data = [
["2012", 900, 950],
["2013", 1000, 0],
["2014", 1170, 0],
["2015", 1250, 0],
["2016", 1530, 0]
];
How can I do this with google charts?
see following working snippet...
the bars are centered where their counterpart is blank.
however, it breaks once the user hovers a bar.
the bars are represented by <rect> elements,
which are used to draw the chart itself, the gridlines, the legend bars, etc.
3 <rect> elements are used to highlight the hovered bar.
this is what breaks the code below, it throws off the routine to find the bars.
here's how it works now...
there will be the same number of bars / <rect> elements as there are rows and series,
even if a bar is not visible.
they will be next to last in the list of elements.
the last <rect> element is the x-axis.
the code below works backwards, skipping the last element,
and counts the number of rows / series to gather the bars that may need to be moved.
when the users hovers, there are 3 elements inserted, so the routine will need to change to accommodate.
and they will also need to be moved in order to highlight properly.
otherwise, you can just turn off interactivity and be done...
enableInteractivity: false
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
["Year", "Asia", "Mama"],
["2012", 900, 950],
["2013", 1000, 0],
["2014", 1170, 0],
["2015", 1250, 0],
["2016", 1530, 0]
]);
var options = {
chartArea: {
height: '100%',
width: '100%',
top: 32,
left: 48,
right: 128,
bottom: 48
},
height: 400,
width: '100%'
};
var container = document.getElementById('chart');
var chart = new google.visualization.ColumnChart(container);
google.visualization.events.addListener(chart, 'ready', function () {
// get chart layout
var chartLayout = chart.getChartLayoutInterface();
// create mutation observer
var observer = new MutationObserver(function () {
// get bar elements
var rects = container.getElementsByTagName('rect');
var barLength = data.getNumberOfRows() * (data.getNumberOfColumns() - 1);
var bars = [];
for (var i = rects.length - 1; i > ((rects.length - 1) - (barLength + 1)); i--) {
if (i < (rects.length - 1)) {
bars.unshift(rects[i]);
}
}
// process each row
for (var r = 0; r < data.getNumberOfRows(); r++) {
// process each series
for (var s = 1; s < data.getNumberOfColumns(); s++) {
// get chart element bounds
var boundsBar = chartLayout.getBoundingBox('bar#' + (s - 1) + '#' + r);
var boundsLabel = chartLayout.getBoundingBox('hAxis#0#label#' + r);
// determine if bar is hidden
if (boundsBar.height < 1) {
// determine series shown, new x coordinate
var seriesShown = (s === 1) ? 1 : 0;
var xCoord = boundsLabel.left + (boundsLabel.width / 2);
// move bar
bars[r + (data.getNumberOfRows() * seriesShown)].setAttribute('x', (xCoord - (boundsBar.width / 2)));
}
}
}
});
observer.observe(container, {
childList: true,
subtree: true
});
});
chart.draw(data, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart"></div>
There is a line chart shown on the pic:
And its code is:
var data = google.visualization.arrayToDataTable(data);
var options = {
title: settings.title,
curveType: "function",
legend: { position: "bottom" }
};
// Create and draw the visualization.
new google.visualization.LineChart(
document.getElementById("chart_div")
).draw(data, options);
}
How to show only integer values on axis Y? I have pointed by red what I need to remove.
use the ticks option to show only integers
vAxis: {
ticks: [0, 1, 2]
}
remove this option to remove the dip below the baseline
curveType: "function"
I have two markers placed at the same coordinates in a Nokia Here map.
The problem is I can access only at one marker. The other is below the first one.
Is there any options or something else to manage this case, in order to have access to all markers placed at the same coordinates ?
The only way to ensure that all markers are separately visible is to put the overlapping markers at slightly different locations. The best effect I have found is to use the clustering functionality down to zoom 15 and add a separate set of jittered markers to display at zoom 16+.
/**
* This is a H.clustering.ITheme which displays ordinary markers as
* noise points
*/
function SpiderifyTheme() {
var baseTheme = new H.clustering.DefaultTheme();
this.getClusterPresentation = function (cluster) {
var clusterIcon = baseTheme.getClusterPresentation(cluster).getIcon();
return new H.map.Marker(cluster.getPosition(), {
icon: clusterIcon,
min: cluster.getMinZoom(),
max: cluster.getMaxZoom()
});
};
this.getNoisePresentation = function (noisePoint) {
return new H.map.Marker(noisePoint.getPosition(), {
min: noisePoint.getMinZoom()
});
};
}
// dataPoints is an array of H.clustering.DataPoint elements
var len = dataPoints.length + 1;
var SCATTER = 0.0001; // When exploding a group this is the size of the ring.
var group = new H.map.Group();
var truncate = function(number, places) {
var shift = Math.pow(10, places);
return ((number * shift) | 0) / shift;
};
// Ensure that all markers are offset by a set amount.
dataPoints.forEach(function (dataPoint, index ) {
var jitteredPoint = {
lng: truncate(dataPoint.lng, 3) + SCATTER + (Math.cos(index) * SCATTER),
lat: truncate(dataPoint.lat, 3) + SCATTER + (Math.sin(index) * SCATTER)
},
marker = new H.map.Marker(jitteredPoint, {
min: 16}); // This needs to be one more than the max cluster level
group.addObject(marker);
});
var clusteredDataProvider = new H.clustering.Provider(dataPoints, {
clusteringOptions: {
eps: 32,
minWeight: 2
},
max : 15,
theme: new SpiderifyTheme()
});
// First add cluster for zooms 1-15
var clusteringLayer = new H.map.layer.ObjectLayer(clusteredDataProvider);
map.addLayer(clusteringLayer);
// Add the group for zooms 16+
map.addObject(group);
The result looks something like this - the first image shows clustered markers at low zoom. The second shows jittered markers at high zoom. You can alter the eps value of the clusterer to get other effects.
I am facing an issue with tooltip showing date in x-axis.
Can anyone help on this?
fiddle code
grid: {
hoverable: true //IMPORTANT! this is needed for tooltip to work
},
tooltip: true,
tooltipOpts: {
content: "<h4>%s</h4><ul><li>Date is %x</li><li>Total Count: %y</li></ul>",
defaultTheme: false
},
points:
{
show: true
},
series: {
bars: {
show: true,
barWidth: 0.1,
order: 1
}
}
You need a function to convert the x value (which is only a number / timestamp) to an actual date.
Use something like this:
tooltipOpts: {
content: function (label, x, y) {
var date = new Date(+x);
var tooltip = '<h4>' + label + '</h4><ul>';
tooltip += '<li>Date is ' + date.toLocaleDateString() + '</li>';
tooltip += '<li>Total Count: ' + y + '</li></ul>';
return tooltip;
},
See this update fiddle.
I use Chart.js to display a Radar Chart. My problem is that some labels are very long :
the chart can't be display or it appears very small.
So, is there a way to break lines or to assign a max-width to the labels?
Thank you for your help!
For Chart.js 2.0+ you can use an array as label:
Quoting the DOCs:
"Usage: If a label is an array as opposed to a string i.e. [["June","2015"], "July"] then each element is treated as a seperate line."
var data = {
labels: [["My", "long", "long", "long", "label"], "another label",...],
...
}
With ChartJS 2.1.6 and using #ArivanBastos answer
Just pass your long label to the following function, it will return your label in an array form, each element respecting your assigned maxWidth.
/**
* Takes a string phrase and breaks it into separate phrases
* no bigger than 'maxwidth', breaks are made at complete words.
*/
function formatLabel(str, maxwidth){
var sections = [];
var words = str.split(" ");
var temp = "";
words.forEach(function(item, index){
if(temp.length > 0)
{
var concat = temp + ' ' + item;
if(concat.length > maxwidth){
sections.push(temp);
temp = "";
}
else{
if(index == (words.length-1)) {
sections.push(concat);
return;
}
else {
temp = concat;
return;
}
}
}
if(index == (words.length-1)) {
sections.push(item);
return;
}
if(item.length < maxwidth) {
temp = item;
}
else {
sections.push(item);
}
});
return sections;
}
console.log(formatLabel("This string is a bit on the longer side, and contains the long word Supercalifragilisticexpialidocious for good measure.", 10))
To wrap the xAxes label, put the following code into optoins. (this will split from white space and wrap into multiple lines)
scales: {
xAxes: [
{
ticks: {
callback: function(label) {
if (/\s/.test(label)) {
return label.split(" ");
}else{
return label;
}
}
}
}
]
}
You can write a javascript function to customize the label:
// Interpolated JS string - can access value
scaleLabel: "<%=value%>",
See http://www.chartjs.org/docs/#getting-started-global-chart-configuration
Unfortunately there is no solution for this until now (April 5th 2016).
There are multiple issues on Chart.js to deal with this:
https://github.com/nnnick/Chart.js/issues/358 (closed with fix)
https://github.com/nnnick/Chart.js/issues/608 (closed with no fix)
https://github.com/nnnick/Chart.js/issues/358 (closed with no fix)
https://github.com/nnnick/Chart.js/issues/780 (closed with no fix)
https://github.com/nnnick/Chart.js/issues/752 (closed with no fix)
This is a workaround: Remove x-axis label/text in chart.js
It seems you might be actually be talking about data labels and not the scale labels. In this case you'd want to use the pointLabelFontSize option. See below example:
var ctx = $("#myChart").get(0).getContext("2d");
var data = {
labels: ["Eating", "Sleeping", "Coding"],
datasets: [
{
label: "First",
strokeColor: "#f00",
pointColor: "#f00",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "#ccc",
data: [45, 59, 90]
},
{
label: "Second",
strokeColor: "#00f",
pointColor: "#00f",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "#ccc",
data: [68, 48, 40]
}
]
};
// This is the important part
var options = {
pointLabelFontSize : 20
};
var myRadarChart = new Chart(ctx).Radar(data, options);
Finally you may want to play with the dimensions of your < canvas > element as I've found sometimes giving the Radar chart more height helps the auto scaling of everything.
I found the best way to manipulate the labels on the radar chart was by using the pointlabels configuration from Chartjs.
let skillChartOptions = {
scale: {
pointLabels: {
callback: (label: any) => {
return label.length > 5 ? label.substr(0, 5) + '...' : label;
},
}, ...
}, ...
}
I'd like to further extend on Fermin's answer with a slightly more readable version. As previously pointed out, it's possible to give Chart.js an array of strings to make it wrap the text. To make this array of strings from a longer string, I propose this function:
function chunkString(str, maxWidth){
const sections = [];
const words = str.split(" ");
let builder = "";
for (const word of words) {
if(word.length > maxWidth) {
sections.push(builder.trim())
builder = ""
sections.push(word.trim())
continue
}
let temp = `${builder} ${word}`
if(temp.length > maxWidth) {
sections.push(builder.trim())
builder = word
continue
}
builder = temp
}
sections.push(builder.trim())
return sections;
}
const str = "This string is a bit on the longer side, and contains the long word Supercalifragilisticexpialidocious for good measure."
console.log(str)
console.log(chunkString(str, 10))
.as-console-wrapper {
max-height: 100vh!important;
}
For most of the recent versions of chart.js, the labels can be mentioned as array of arrays. That's your labels can be:
labels = [['a', 'label1'],['the', 'lable2'],label3] '$'
You can use following function which is fast and compatible across all versions for converting your labels array into array of array in case the labels contain multiple words:
function splitLongLabels(labels){
//labels = ["ABC PQR", "XYZ"];
var i = 0, len = labels.length;
var splitlabels = labels;
while (i < len) {
var words = labels[i].trim().split(' ');
if(words.length>1){
for(var j=0; j<words.length; j++){
}
splitlabels[i] = words;
}
i++
}
return splitlabels;
}