Google Charts; Offsetting Annotations from horizontal Axis - javascript

I'm looking for a way to offset the annotation labels I have on a Google Chart I'm making. I've included an image below, but essentially what I've done is created a column chart with hidden lines that the annotations are set from.
I did this because the bar type apparently doesn't support annotations. My end goal is to get the percentage of each week to display at the top of the bars. The problem is that because of the way I had to do this the percentage annotations center on the x-axis label and not on the column bar itself.
Image of Chart
As you can see from the image link above, this causes problems with overlapping when the values for each location are similar. I'm looking for a solution to the overlapping.
Here is the code I'm using to impliment the chart (C# string appender for the google api javascript):
str.Append(#"<script type=*text/javascript*> google.load( *visualization*, *1*, {packages:[*corechart*, *bars*]});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn({type: 'string', label: 'Date'});
data.addColumn({type: 'number', label: 'NC'});
data.addColumn({type: 'number', label: 'WA'});
data.addColumn({type: 'number', label: 'Std Cap'});
data.addColumn({type: 'number', label: 'NC'});
data.addColumn({type: 'string', role: 'annotation', label: 'NCa' });
data.addColumn({type: 'number', label: 'WA'});
data.addColumn({type: 'string', role: 'annotation', label: 'WAa' });
data.addRows(" + dt.Rows.Count + ");");
for (int i = 0; i <= dt.Rows.Count - 1; i++)
{
// Data values.
str.Append("data.setValue(" + i + "," + 0 + "," + "'" + dt.Rows[i]["WeekNum"].ToString() + "');");
str.Append("data.setValue(" + i + "," + 1 + "," + "'" + dt.Rows[i]["NC"].ToString() + "');");
str.Append("data.setValue(" + i + "," + 2 + "," + "'" + dt.Rows[i]["WA"].ToString() + "');");
str.Append("data.setValue(" + i + "," + 3 + "," + "'" + dt.Rows[i]["Std Cap"].ToString() + "');");
// Invisible line to set annotations off of.
str.Append("data.setValue(" + i + "," + 4 + "," + "'" + double.Parse(dt.Rows[i]["NC"].ToString()) + "');");
// Annotation value; Multiply value by 100 to get percentage.
str.Append("data.setValue(" + i + "," + 5 + "," + "'" + String.Format("{0}%", (100 * double.Parse(dt.Rows[i]["NC"].ToString()))) + "');");
// Invisible line to set annotations off of.
str.Append("data.setValue(" + i + "," + 6 + "," + "'" + double.Parse(dt.Rows[i]["WA"].ToString()) + "');");
// Annotation value; Multiply value by 100 to get percentage.
str.Append("data.setValue(" + i + "," + 7 + "," + "'" + String.Format("{0}%", (100 * double.Parse(dt.Rows[i]["WA"].ToString()))) + "');");
}
str.Append(" var formatter = new google.visualization.NumberFormat({ pattern:'#.#%' });");
str.Append(" formatter.format(data, 1);");
str.Append(" formatter.format(data, 2);");
str.Append(" var chart = new google.visualization.ComboChart(document.getElementById('chart_div1'));");
str.Append(" chart.draw(data, {width: 1000, height: 600, title: '',");
str.Append(" stackSeries: true, isStacked: false, legend: {alignment: 'end'},");
str.Append(#" vAxes:{
0: { 'maxValue': " + maxVal + #", format: '#%'},
1: { 'maxValue': " + maxVal + #"},
2: { 'maxValue': " + maxVal + #"}
},");
str.Append(#" hAxis: {title: ''},
seriesType: 'bars',
series: {
0: {type: 'bars', color: 'blue'},
1: {type: 'bars', color: 'green'},
2: {type: 'line', color: 'red', lineDashStyle: [4, 4]},
3: {type: 'line', lineWidth: 0, visibleInLegend:false, pointSize: 0},
4: {type: 'line', lineWidth: 0, visibleInLegend:false, pointSize: 0}
},");
str.Append(#" annotations: {
style: 'point',
stemColor: 'none',
textStyle: { color: 'black' },
alwaysOutside: 'true'
}");
str.Append("}); }");
str.Append("<" + "/script>");
Literal lit = this.Master.FindControl("body").FindControl("lt1") as Literal;
lit.Text = str.ToString().Replace('*', '"');
The chart is populated by a dynamic table, named dt. Here's the layout of that table:
Datatable Example
Chart drawing code (Javascript):
var options = { packages: ['corechart'], callback : drawChart};
google.load('visualization', '1', options);
function drawChart() { }
Chart Div on page (HTML/ASP.NET):
<div>
<asp:Literal ID="lt1" runat="server"></asp:Literal>
<div id="chart_div1" style="width:1000px; height:600px"></div>
</div>
I'm not glued to the offset idea, this is just where I've landed from all my research. Ultimately I just want to display the percentages at the top of each column, so if there is a better way to go about that, I'm all ears!
Thank you in advance.
::EDIT::
After considering WhiteHat's comments below. I made the following adjustment to my for loop that does offset them (vertically) when the values are within 10 points of each other. This isn't the most elegant solution, but it does seem to work.
double ncVal;
double waVal;
double ncOffset;
double waOffset;
for (int i = 0; i <= dt.Rows.Count - 1; i++)
{
ncOffset = 0;
waOffset = 0;
ncVal = double.Parse(dt.Rows[i]["NC"].ToString());
waVal = double.Parse(dt.Rows[i]["WA"].ToString());
// If values are within 10 points of each other, offset by 5 each positive/negative.
if ((ncVal - waVal) < 0.10)
{
if ((ncVal - waVal) > 0)
{
if (ncVal < 1)
{
ncOffset = 0.03;
waOffset = -0.03;
}
else
{
ncOffset = -0.03;
waOffset = 0.03;
}
}
}
else
{
if ((waVal - ncVal) < 0.10)
{
if ((waVal - ncVal) > 0)
{
if (ncVal < 1)
{
waOffset = 0.03;
ncOffset = -0.03;
}
else
{
waOffset = -0.03;
ncOffset = 0.03;
}
}
}
}
// Data values.
str.Append("data.setValue(" + i + "," + 0 + "," + "'" + dt.Rows[i]["WeekNum"].ToString() + "');");
str.Append("data.setValue(" + i + "," + 1 + "," + "'" + dt.Rows[i]["NC"].ToString() + "');");
str.Append("data.setValue(" + i + "," + 2 + "," + "'" + dt.Rows[i]["WA"].ToString() + "');");
str.Append("data.setValue(" + i + "," + 3 + "," + "'" + dt.Rows[i]["Std Cap"].ToString() + "');");
// Invisible line to set annotations off of.
str.Append("data.setValue(" + i + "," + 4 + "," + "'" + (ncVal + ncOffset) + "');");
// Annotation value; Multiply value by 100 to get percentage.
str.Append("data.setValue(" + i + "," + 5 + "," + "'" + String.Format("{0}%", (100 * ncVal)) + "');");
// Invisible line to set annotations off of.
str.Append("data.setValue(" + i + "," + 6 + "," + "'" + (waVal + waOffset) + "');");
// Annotation value; Multiply value by 100 to get percentage.
str.Append("data.setValue(" + i + "," + 7 + "," + "'" + String.Format("{0}%", (100 * waVal)) + "');");
}
Still, if anyone knows a way to center them on the columns, that would be ideal.

Related

Null Values in Zones in Highcharts

I have graphs that have zones. Currently if there is a null value, that null value is displayed in the tooltip with the zone color of the point before it. I want the null value to always be the color black.
For example,
The tooltip in graph 1 has all the correct information... but "Strength: null" has a green dot. I want to make this dot black because it is a null value.
Is it possible to make this happen? Thanks so much.
https://codepen.io/austeng/pen/gOppRWY
zones: [
{
value: 0.3,
color: "green"
},
{
value: 0.5,
color: "black",
},
{
color: "red"
}
]
look at this code. change AFTER point = chart.series[0].points[pointIndex]; BEFORE });
if (thisChart === Highcharts.charts[Highcharts.hoverChartIndex]) {
Highcharts.charts.forEach(function(chart) {
point = chart.series[0].points[pointIndex];
// CHANGE START
if (point.y == null) {
// set here your color for null values
result +=
'<span style="color:black' +
'">●</span> ' +
point.series.name +
": <b>" +
point.y +
"</b><br/>";
} else {
result +=
'<span style="color:' +
point.color +
'">●</span> ' +
point.series.name +
": <b>" +
point.y +
"</b><br/>";
}
// CHANGE END
});
} else {
result =
'<span style="color:' +
this.color +
'">●</span> ' +
this.series.name +
": <b>" +
this.y +
"</b><br/>";
}
I have added this functionality by defining the color point like this:
let color = point.y === null ? 'black' : point.color
and use this color variable in the result:
result +=
'<span style="color:' +
color +
'">●</span> ' +
point.series.name +
": <b>" +
point.y +
"</b><br/>";
Demo: https://jsfiddle.net/BlackLabel/7x1oc2pw/
Is that what you had in mind?

Highchart step line chart tooltip show old data when there is no data

On the following JS Fiddle
I have created a chart with a step line.
step: true
I am trying to show the old data in tooltip when there is no data for the series. E.g. on mouse over on 1 July 2015, I have the data so the tooltip show the data. But if you move forwared the tooltip don't show any thing.
Is the HighChart support some thing like show latest old data if no data is present.
You should use the tooltip.formatter and then use loop to find points with the same x. If not exists then extract last point from step series. Simple demo: http://jsfiddle.net/vs6scfch.
tooltip: {
shared: false,
formatter: function() {
var x = this.x,
series = this.series.chart.series,
stepSeries = series[1],
lastPointStepSerie = stepSeries.points[stepSeries.points.length - 1],
each = Highcharts.each,
txt = '<span style="font-size: 10px">' + Highcharts.dateFormat('%A, %b %d, %Y', this.x) + '</span><br/>';
each(series, function(s,i) {
each(s.points, function(p, j) {
if(p.x === x) {
txt += '<span style="color:' + p.color + '">\u25CF</span> ' + s.name + ': <b>' + p.y + '</b><br/>'
}
});
});
if(x > lastPointStepSerie.x) {
txt += '<span style="color:' + lastPointStepSerie.color + '">\u25CF</span> ' + stepSeries.name + ': <b>' + lastPointStepSerie.y + '</b><br/>'
}
return txt;
}
},

Make hover text smaller using Tipsy in D3

Tipsy is used to display a lot of text when hovering over my nodes and I'd like to make that text smaller. How do I do that?
$('.node').tipsy({
gravity: 'w',
html: true,
title: function() {
var d = this.__data__, id = d.id, inc_calls = d.inc_calls, out_calls = d.out_calls, inc_texts = d.inc_texts, out_texts = d.out_texts;
return 'Incoming Calls: ' + inc_calls + '<br/>' + 'Outgoing Calls: ' + out_calls + '<br/>' + 'Incoming Texts: ' + inc_texts + '<br/>' + 'Outgoing Texts: ' + out_texts ;
}
});
wrap the text that you are returning for title with a span which has style with font-size that you wish.. for example i have set the font size to 10 px you can reset it to a size which fits for your situation.
<span style="font-size:10px">+ your_title_text +</span>
$('.node').tipsy({
gravity: 'w',
html: true,
title: function() {
var d = this.__data__, id = d.id, inc_calls = d.inc_calls, out_calls = d.out_calls, inc_texts = d.inc_texts, out_texts = d.out_texts;
return '<span style="font-size:10px">Incoming Calls: ' + inc_calls + '<br/>' + 'Outgoing Calls: ' + out_calls + '<br/>' + 'Incoming Texts: ' + inc_texts + '<br/>' + 'Outgoing Texts: ' + out_texts + '</span>' ;
}
});

Random number maker

I have a problem with my code . I want to make a program that generates random numbers and multiplies them by 50 then adds 30 to them then removes the remaining decimals.
I also want to show how these number are calculated by using <h1> tags.
after the equal symbol I want to show the final number that is multiplied by 50 and added by 30 and the decimals are removed.
<html>
<head>
<meta charset="UTF-8"/>
<title>Random Numbers</title>
<script>
function start(){
var num1 = Math.random();
var num2 = Math.random();
var num3 = Math.random();
var num4 = Math.random();
var num5 = Math.random();
var num11 = num1.toFixed(3);
var num22 = num2.toFixed(3);
var num33 = num3.toFixed(3);
var num44 = num4.toFixed(3);
var num55 = num5.toFixed(3);
/*var num111 = (num11 * 50);
var num222 = (num22 * 50);
var num333 = (num33 * 50);
var num444 = (num44 * 50);
var num555 = (num55 * 50);
/* ----------------------------------------------
var num111 = (num11) += 30;
var num222 = (num22) += 30;
var num333 = (num33) += 30;
var num444 = (num44) += 30;
var num555 = (num55) += 30;*/
document.getElementById("show1").innerHTML=num11 + '×' + '50' + '+' + '30' + '=' + num11;
document.getElementById("show2").innerHTML=num22 + '×' + '50' + '+' + '30' + '=' + num22;
document.getElementById("show3").innerHTML=num33 + '×' + '50' + '+' + '30' + '=' + num33;
document.getElementById("show4").innerHTML=num44 + '×' + '50' + '+' + '30' + '=' + num44;
document.getElementById("show5").innerHTML=num55 + '×' + '50' + '+' + '30' + '=' + num55;
}
</script>
</head>
<body>
<button id="btn" onclick="start()">Press the button</button><br/>
<h1 id="show1"></h1>
<h1 id="show2"></h1>
<h1 id="show3"></h1>
<h1 id="show4"></h1>
<h1 id="show5"></h1>
</body>
Check this: http://jsfiddle.net/wc5wnby5/2/
Probably you need to do like below:
document.getElementById("show1").innerHTML=num11 + '×' + '50' + '+' + '30' + '=' + Math.round(num11*50+30);
document.getElementById("show2").innerHTML=num22 + '×' + '50' + '+' + '30' + '=' + Math.round(num22*50+30);
document.getElementById("show3").innerHTML=num33 + '×' + '50' + '+' + '30' + '=' + Math.round(num33*50+30);
document.getElementById("show4").innerHTML=num44 + '×' + '50' + '+' + '30' + '=' + (num44*50+30);
document.getElementById("show5").innerHTML=num55 + '×' + '50' + '+' + '30' + '=' + Math.round(num55*50+30);
Use Math.round() for removing decimal part. Consider following code:
document.getElementById("show1").innerHTML=num11 + '×' + '50' + '+' + '30' + '=' + Math.round(num11*50+30);
document.getElementById("show2").innerHTML=num22 + '×' + '50' + '+' + '30' + '=' + Math.round(num22*50+30);
document.getElementById("show3").innerHTML=num33 + '×' + '50' + '+' + '30' + '=' + Math.round(num33*50+30);
document.getElementById("show4").innerHTML=num44 + '×' + '50' + '+' + '30' + '=' + Math.round(num44*50+30);
document.getElementById("show5").innerHTML=num55 + '×' + '50' + '+' + '30' + '=' + Math.round(num55*50+30);
DEMO
Reference for more details.
If i right understood your problem:
function print(elemID, text){
document.getElementById(elemID).appendChild(document.createTextNode(text));
}
var res;
print('show1', (res = Math.random()));
print('show2', (res = res * 50));
print('show3', (res += 30));
print('show4', (res = res.toFixed(0)));
fiddle

Function in JavaScript that outputs concat url to YUI Chart Library Output

Trying to properly write a function in JavaScript that outputs a concat'd url to Chart Library Output (for chart re-rendering)... based on selected options in dropdown list.
Problem: I am not getting the chart to re-render with the concatenated url (which should be sent each time an option is selected in the dropdown).
JavaScript code in head:
function httpGet(theUrl)
{
var xmlHttp = null;
xmlHttp = new XMLHttpRequest(); // instantiate request
xmlHttp.open( "GET", theUrl, false ); // open url
xmlHttp.send( null ); // sending nothing
return xmlHttp.responseText; // return url's data as text
};
function selectFabric(){
var urlString = "http://localhost:8083/tbl/sparqlmotion?id=LiabilityChart&arg1=";
var fabrics = document.getElementById('fabrics');
var selectedFabric = fabrics.options[fabrics.selectedIndex];
var linkAddTogether = [urlString + selectedFabric.value];
var linkResult = linkAddTogether[0];
var result = httpGet(linkResult);
if (selectedFabric.value != "nothing"){
return linkResult; // update begins // document.write(linkAddTogether)
};
};
function revive (key, value) {
if (value.datatype == "http://www.w3.org/2001/XMLSchema#double" || // if datatype is this
value.datatype == "http://www.w3.org/2001/XMLSchema#integer" || // or, this
value.datatype == "http://www.w3.org/2001/XMLSchema#float") // or, this
{
return (parseInt(value.value)) // if '#double', '#integer', or '#schema', then: 'vars' label + convert the datatype's float value to integer
}
else if (value.type == 'literal')
{
return (value.value) // if datatype's value is a literal: 'vars' label + return as a string
}
else if (value.datatype == 'http://www.w3.org/2001/XMLSchema#date')
{
return value.value // if "XMLSchema#date's" value is a literal: 'vars' label + return as a string
}
else
{
return value // if datatype is anything else: 'vars' label + return value as a string
}
};
var scriptHead = ["YUI().use('charts',function(Y){var myDataValues=\n\n["];
var scriptTail = ["\n];\n\nvar styleDef={series:{Stock:{line:{color:'#EEB647'},marker:{fill:{color:'#eee',alpha:0,wmode:'transparent'},border:{color:'#222',alpha:0,wmode:'transparent'},over:{fill:{color:'#eee'},border:{color:'#000'},width:9,height:9}}},Liability:{line:{color:'#171944'},marker:{fill:{color:'#eee',alpha:0,wmode:'transparent'},border:{color:'#222',alpha:0,wmode:'transparent'},over:{fill:{color:'#eee'},border:{color:'#000'},width:9,height:9}}},Shipment:{line:{color:'#ff0000',alpha:0,wmode:'transparent'},marker:{fill:{color:'#eee',alpha:0,wmode:'transparent'},border:{color:'#ff0000',alpha:0,wmode:'transparent'},over:{fill:{color:'#ff0000',alpha:0,wmode:'transparent'},border:{color:'#000',alpha:0,wmode:'transparent'},width:16,height:16}}},Production:{line:{color:'#FFD700',alpha:0,wmode:'transparent'},marker:{fill:{color:'#eee',alpha:0,wmode:'transparent'},border:{color:'#FFD700',alpha:0,wmode:'transparent'},over:{fill:{color:'#FFD700',alpha:0,wmode:'transparent'},border:{color:'#000',alpha:0,wmode:'transparent'},width:16,height:16}}},Order:{line:{color:'#006400',alpha:0,wmode:'transparent'},marker:{fill:{color:'#eee',alpha:0,wmode:'transparent'},border:{color:'#006400',alpha:0,wmode:'transparent'},over:{fill:{color:'#006400',alpha:0,wmode:'transparent'},border:{color:'#000',alpha:0,wmode:'transparent'},width:16,height:16}}}}};var myAxes={dateRange:{keys:['date'],position:'bottom',type:'category',title:'Date Range',styles:{majorTicks:{display:'none'},label:{rotation:-45,margin:{top:5}},title:{fontSize:'90%'}}}};var mychart=new Y.Chart({dataProvider:myDataValues,interactionType:'planar',render:'#mychart',categoryKey:'Date',styles:styleDef,categoryType:'time',horizontalGridlines:{styles:{line:{color:'#fff'}}},verticalGridlines:{styles:{line:{color:'#fff'}}}})});\n\n"];
var simpleHead = [scriptHead];
var simpleTail = [scriptTail];
var oldData = JSON.parse(result, revive);
HTML code for form (in body):
form style="width:200px; color:#333; padding-right:5px; padding-bottom:2px; padding-left:55px; margin-top:0px; clear:none;" name="properties" id="properties">
select style="width:160px; color:#333; clear:none; display:block;" name="fabrics" id="fabrics" onChange="selectFabric()">
option value="nothing">Select Fabric END option
option value="KOD23-4074-LV">KOD23-4074-LV END option
option value="SGOD2-2858-LV">SGOD2-2858-LV END option
option value="W-897-LV">W-897-LV END option
option value="FF-4084-LV">FF-4084-LV END option
END select
END form
JavaScript code for chart (write script in body to render YUI chart plug-in):
document.write('\x3Cscript type="text/javascript" id="source">');
document.write(simpleHead[0] + '\n{Date: "' + oldData.results.bindings[0].date + '", Liability: ' + oldData.results.bindings[0].liability + ", Stock: " + oldData.results.bindings[0].stock + ", " + oldData.results.bindings[0].event + ": " + oldData.results.bindings[0].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[1].date + '", Liability: ' + oldData.results.bindings[1].liability + ", Stock: " + oldData.results.bindings[1].stock + ", " + oldData.results.bindings[1].event + ": " + oldData.results.bindings[1].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[2].date + '", Liability: ' + oldData.results.bindings[2].liability + ", Stock: " + oldData.results.bindings[2].stock + ", " + oldData.results.bindings[2].event + ": " + oldData.results.bindings[2].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[3].date + '", Liability: ' + oldData.results.bindings[3].liability + ", Stock: " + oldData.results.bindings[3].stock + ", " + oldData.results.bindings[3].event + ": " + oldData.results.bindings[3].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[4].date + '", Liability: ' + oldData.results.bindings[4].liability + ", Stock: " + oldData.results.bindings[4].stock + ", " + oldData.results.bindings[4].event + ": " + oldData.results.bindings[4].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[5].date + '", Liability: ' + oldData.results.bindings[5].liability + ", Stock: " + oldData.results.bindings[5].stock + ", " + oldData.results.bindings[5].event + ": " + oldData.results.bindings[5].current + "}," + "\n\n");
document.write('\n{Date: "' + oldData.results.bindings[6].date + '", Liability: ' + oldData.results.bindings[6].liability + ", Stock: " + oldData.results.bindings[6].stock + ", " + oldData.results.bindings[6].event + ": " + oldData.results.bindings[6].current + "}" + simpleTail[0] + "\n\n");
document.write('\x3C/script>');

Categories