Cannot use 'in' operator to search for 'length' - javascript

My Website receives the following string from my WCF Service:
[
{
"Value": 5,
"Color": "#44A9FF",
"HighlightColor": "#5AD3D1",
"Label": "N/A"
},
{
"Value": 79,
"Color": "#009900",
"HighlightColor": "#5AD3D1",
"Label": "On Track"
},
{
"Value": 31,
"Color": "#66FF33",
"HighlightColor": "#5AD3D1",
"Label": "Done"
},
{
"Value": 4,
"Color": "#F3F300",
"HighlightColor": "#5AD3D1",
"Label": "Issue"
},
{
"Value": 7,
"Color": "#FF0000",
"HighlightColor": "#5AD3D1",
"Label": "Behind"
},
{
"Value": 9,
"Color": "#979797",
"HighlightColor": "#5AD3D1",
"Label": "Abandoned"
}
]
But for some reason I can't use $.each but I swear that I've called that on a similar structure before. It just gives me the following error:
Uncaught TypeError: Cannot use 'in' operator to search for 'length' in [{"Value":5,"Color":"#44A9FF","HighlightColor":"#5AD3D1","Label":"N/A"},{"Value":79,"Color":"#009900","HighlightColor":"#5AD3D1","Label":"On Track"},{"Value":31,"Color":"#66FF33","HighlightColor":"#5AD3D1","Label":"Done"},{"Value":4,"Color":"#F3F300","HighlightColor":"#5AD3D1","Label":"Issue"},{"Value":7,"Color":"#FF0000","HighlightColor":"#5AD3D1","Label":"Behind"},{"Value":9,"Color":"#979797","HighlightColor":"#5AD3D1","Label":"Abandoned"}] (10:24:26:561 | error, javascript)
at s (public_html/js/jquery-2.1.4.min.js:2:4004)
at n.extend.each (public_html/js/jquery-2.1.4.min.js:2:2737)
at (anonymous function) (public_html/js/test/chart-test.js:42:11)
at j (public_html/js/jquery-2.1.4.min.js:2:26925)
at k.fireWith (public_html/js/jquery-2.1.4.min.js:2:27738)
at x (public_html/js/jquery-2.1.4.min.js:4:11253)
at (anonymous function) (public_html/js/jquery-2.1.4.min.js:4:14765)
>
From what I understand I can't use $.each on a string but I thought I made it into an Object. My JavaScript looks like this:
$.getJSON("http://localhost:52535/PUendeligService.svc/GetStatusOverview", function (data) {
var object = $.parseJSON(data);
var parsedData = [];
$.each(object, function () {
var value = object["Value"];
var color = object["Color"];
var highLight = object["HighlightColor"];
var label = object["Label"];
parsedData.push(
{
value: value,
color: color,
highlight: highLight,
label: label
}
);
});
var ctx = $('#myChart').get(0).getContext('2d');
var myPieChart = new Chart(ctx).Pie(parsedData, options);
var myPieChartLegend = $('#pie-chart-legend-tbody');
var tBodyContent = '';
var valueTotal = 0;
$.each(data, function (index) {
var value = data[index]["value"];
valueTotal += value;
});
$.each(data, function (index) {
var value = data[index]["value"];
var color = data[index]["color"];
var label = data[index]["label"];
var element =
'<tr>' +
'<td>' +
'<span class="fa fa-square" style="color:' + color + '"></span>\t' + label +
'</td>' +
'<td>' +
value +
'</td>' +
'<td>' +
((value / valueTotal) * 100).toFixed(2) +
'</td>' +
'</tr>';
tBodyContent += element;
});
tBodyContent +=
'<tr>' +
'<td>Total</td>' +
'<td>' + valueTotal + '</td>' +
'<td>' + 100 + '</td>' +
'</tr>';
myPieChartLegend.html(tBodyContent);
});
The C# code that is run for the example that doesnt't work:
public String GetStatusOverview()
{
StatusOverviewObject soo = new StatusOverviewObject();
soo.Value = 5;
soo.Color = "#44A9FF";
soo.HighlightColor = "#5AD3D1";
soo.Label = "N/A";
StatusOverviewObject soo2 = new StatusOverviewObject();
soo2.Value = 79;
soo2.Color = "#009900";
soo2.HighlightColor = "#5AD3D1";
soo2.Label = "On Track";
StatusOverviewObject soo3 = new StatusOverviewObject();
soo3.Value = 31;
soo3.Color = "#66FF33";
soo3.HighlightColor = "#5AD3D1";
soo3.Label = "Done";
StatusOverviewObject soo4 = new StatusOverviewObject();
soo4.Value = 4;
soo4.Color = "#F3F300";
soo4.HighlightColor = "#5AD3D1";
soo4.Label = "Issue";
StatusOverviewObject soo5 = new StatusOverviewObject();
soo5.Value = 7;
soo5.Color = "#FF0000";
soo5.HighlightColor = "#5AD3D1";
soo5.Label = "Behind";
StatusOverviewObject soo6 = new StatusOverviewObject();
soo6.Value = 9;
soo6.Color = "#979797";
soo6.HighlightColor = "#5AD3D1";
soo6.Label = "Abandoned";
List<StatusOverviewObject> list = new List<StatusOverviewObject>();
list.Add(soo);
list.Add(soo2);
list.Add(soo3);
list.Add(soo4);
list.Add(soo5);
list.Add(soo6);
return JsonConvert.SerializeObject(list);
}

You have 3 $.each in your code.
The first one takes the JSON instance named object and populates the array parsedData just fine.
The problem is in your rest of the iterators, you are passing data(the string of JSON) to them. You should rather pass parsedData instance to them.
$.each(parsedData, function (index) { //"parsedData" instead of "data"
var value = this[index]["value"]; //you can use "this" to access the object passed in argument
valueTotal += value;
});
$.each(parsedData, function (index) { //"parsedData" instead of "data"
var value = this[index]["value"];
var color = this[index]["color"];
var label = this[index]["label"];
var element =
'<tr>' +
'<td>' +
'<span class="fa fa-square" style="color:' + color + '"></span>\t' + label +
'</td>' +
'<td>' +
value +
'</td>' +
'<td>' +
((value / valueTotal) * 100).toFixed(2) +
'</td>' +
'</tr>';
tBodyContent += element;
});

Related

JSON parse variable result

I have a JSON which I query with xhr. The objects (person) contain a key-value pair called "serviceLevel" that I have to split.
When I stack this in a variable (services) and log it like this:
let main = document.getElementsByTagName('main');
getXHR("GET", './db/orga.json', (success) => {
format(success)
}, (error) => {
console.error(error)
});
function format() {
let people = arguments[0];
for (let i in people) {
let person = people[i];
let services = person.serviceLevel.split(".");
console.log(services);
console.log(person.serviceLevel.split("."));
let idCard = document.createElement('div');
idCard.id = person.firstName + person.familyName;
idCard.classList.add('person');
idCard.innerHTML = "<div class=\"item nom\"><span class=\"prenom\">" + person.firstName + "</span><span class=\"famille\">" + person.familyName + "</span></div>";
idCard.innerHTML += "<span class=\"job\">" + person.jobTitle_1 + "</span>";
idCard.innerHTML += "<span class=\"mail\"><a href=\"mailto:" + person.mail + "\">" + person.mail + "</span>";
idCard.innerHTML += "<span class=\"tel\"><a href=\"tel:" + person.phone_1 + "\">" + person.phone_1 + "</span>";
idCard.innerHTML += "<span class=\"tel\"><a href=\"tel:" + person.mobile + "\">" + person.mobile + "</span>";
for (let j in services) {
let serviceElement = document.getElementById(services[j]);
if (!serviceElement) {
let serviceElement = document.createElement('div');
serviceElement.id = services[j];
serviceElement.classList.add('n' + j, "service");
serviceElement.innerHTML = "<span class=\"title\">" + services[j] + "</span>";
if (j == 0) {
if (services[services.length - 1] = j) {
serviceElement.appendChild(idCard);
main[0].appendChild(serviceElement);
}
} else {
let parent = services[j - 1],
parentService = document.getElementById(parent);
if (services[services.length - 1] = j) {
serviceElement.appendChild(idCard);
}
parentService.appendChild(serviceElement);
}
} else {
serviceElement.appendChild(idCard);
}
}
}
}
const data = [{
"Tri": "blablablabla, CSMSI.SAFS, n, XXXX, YYYY",
"Department": "The best department",
"serviceLevel": "CSMSI.SAFS",
"organisationLevel": "blablablabla",
"rang": "n",
"familyName": "XXXX",
"firstName": "YYYY",
"jobTitle_2": "Directeur",
"jobTitle_1": "Directeur",
"phone_1": "nn nn nn nn nn",
"phone_2": "",
"mobile": "nn nn nn nn nn",
"mail": "xxxx.yyyy#zzzz.fr",
"location": "france"
}];
format(data);
The results are different:
(2) ["CSMSI", "SAFS"]
0: "CSMSI"
1: "SAFS"
length: 2
(2) ["CSMSI", "SAFS"]
0: "CSMSI"
1: "1"
length: 2
As we can see, content of "services" are good, but when I extend the tree, the value of the second key value is "1" ... which is a problem. Is there a way to change this?
when I use a for loop with "classical" (i = 0; i < people.length; i++), i don't have the problem....

Dynamic select drop down box returning null or undefined

I am trying to achieve a dropdown box in my webpage which lists the options from the values in the database. I have achieved showing the listed options for the dropdown, but when I select the option it is not set to a value. In other words I have a doubt whether my dropdown is initialized or not.
I have added the required snippet for the action.
function add_row() {
table = document.getElementById('b_book');
var rowData = document.createElement('tr');
rowData.innerHTML = '<td>' + slno +
'</td><td id="dbSNO"><select id="SNO[' + slno + ']" onchange="detail_fetcher(this.value)" onselect="detail_fetcher(this.value)" onload="detail_fetcher(this.value)"></select></td>' +
'<td id="dbLNO"><input type="text" id="LNO[' + slno + ']" list="lot_srch_list" onkeydown="LNO_COL(event,this.value,this.id)" onfocus="lotNo_select()"/></td>' +
'<td><input type="text" id="dbMTR[' + slno + ']"/></td><td id="dbWT[' + slno + ']"></td><td id="dbMWT[' + slno + ']"></td><td id="GPM[' + slno + ']"></td><td id="dbTONE[' + slno + ']"></td><td><button id="btn_rem[' + slno + ']" onclick="remove_row()">Remove</button></td>';
table.appendChild(rowData);
slno += 1;
}
function LNO_COL(e, lno, hashtag) {
var beg_pos = hashtag.indexOf('[') + 1;
var end_pos = hashtag.indexOf(']');
var hash_pos = hashtag.substring(hashtag.lastIndexOf('[') + 1, hashtag.lastIndexOf(']'));
var postIN = 'par=' + parname.value + '&lno=' + lno;
if (e.ctrlKey) {
sNo_list = document.getElementById('SNO[' + hash_pos + ']');
sNo_list.innerHTML = '';
var XMLhLNO = new XMLHttpRequest();
XMLhLNO.onreadystatechange = function () {
if ((this.readyState === 4) && (this.status === 200)) {
var result = this.responseText;
var JSON_result = JSON.parse(result);
for (z in JSON_result) {
var sno_opt;
sno_opt = document.createElement('option');
sno_opt.value = JSON_result[z].slno;
sno_opt.text = JSON_result[z].slno;
sNo_list.appendChild(sno_opt);
}
}
};
XMLhLNO.open('POST', 'sno_lot_par2.php', true);
XMLhLNO.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
XMLhLNO.send(postIN);
detail_fetcher(hashtag);
}
}
function detail_fetcher(hash_position) {
var row_no = hash_position.substring(hash_position.lastIndexOf('[') + 1, hash_position.lastIndexOf(']'));
var serial_row = document.getElementById('SNO[' + row_no + ']');
alert(serial_row.);
/* var XMLfetcher = new XMLHttpRequest();
XMLfetcher.onreadystatechange = function()
{
if((this.readyState == 4)&&(this.status == 200))
{
var src_result = this.responseText;
var JSON_res = JSON.parse(src_result);
alert(serial_row_db);
alert(src_result);
}
};
XMLfetcher.open('POST','srch_lot2.php',true);
XMLfetcher.setRequestHeader('Content-type','application/x-www-form-urlencoded');
XMLfetcher.send(('row=' + serial_row_db));
*/
}
I have tried using value method, selecteditem(index) method but none of them proves to be successful.
Note: I want to use pure JavaScript as I am quite confused with using jQuery.

Working with / and variables in object names (JSON) [duplicate]

This question already has answers here:
How can I access object properties containing special characters?
(2 answers)
Closed 5 years ago.
I'm working with JSON to query the API provided by themoviedb.org.
I want to make a list of episodes. To do so I need to access the length property of several objects named "season/1", "season/2", "season/3" etc., but I get errors all the time.
The returned JSON Code looks as follows:
"season/1": {
"_id": "5256c89f19c2956ff6046d47",
"air_date": "2011-04-17",
"episodes": [
{
"air_date": "2011-04-17",
"crew": [],
"episode_number": 1,
"guest_stars": [],
"name": "Der Winter naht",
"overview": "Ein Deserteur der Nachtwache bringt erschreckende Nachrichten von den Ländern nördlich der Mauer, und Lord Eddard \"Ned\" Stark soll die Hand des Königs Robert Baratheon werden.",
"id": 63056,
"production_code": "101",
"season_number": 1,
"still_path": "/wrGWeW4WKxnaeA8sxJb2T9O6ryo.jpg",
"vote_average": 7.493,
"vote_count": 67
},
{...},
.
.
.
]
}
My Javascript code:
var urlBase = 'https://api.themoviedb.org/3/tv/';
var tvId = 'XXX';
var apiKey = '?api_key=MYKEY';
var apiLang = '&language=de_DE';
var descElement = document.getElementById('description');
var titleElement = document.getElementById('title');
var posterElement = document.getElementById('poster');
var castElement = document.getElementById('cast');
var seasonsElement = document.getElementById('seasons');
var episodesElement = document.getElementById('episodes');
var votesElement = document.getElementById('votes');
var epGuideElement = document.getElementById('epGuide');
var showRequest = new XMLHttpRequest();
var showUrl = urlBase + tvId + apiKey + apiLang + '&append_to_response=credits';
showRequest.open('GET', showUrl);
showRequest.send();
showRequest.onload = function() {
var data = JSON.parse(showRequest.responseText);
var title = data.name;
var description = data.overview;
var episodes = data.number_of_episodes;
var seasons = data.number_of_seasons;
var votes = data.vote_average;
var cast = '';
for (i = 0; i < data.credits.cast.length; i++) {
cast +=
'<div style="background-color:#dedede;text-align:center;width:145px;height:215px;margin:10px;padding:10px;display:inline-block;float:left;position:relative;"><img src="http://image.tmdb.org/t/p/w90/'
+ data.credits.cast[i].profile_path
+ '" alt="'
+ data.credits.cast[i].name
+ '" style="margin-top:5px;"><br><div style="width:160px;bottom:20px;left:50%;transform:translate(-50%);position:absolute;"><span style="font-size:14px;">'
+ data.credits.cast[i].character
+ '</span><br><strong>'
+ data.credits.cast[i].name
+ '</strong></div></div>';
}
var epGuide = '';
for (i = 1; i <= seasons; i++) {
epGuide += '<h3>Staffel ' + i + '</h3>';
for (ii = 1; ii < data['season/'+i].episodes.length; ii++) {
epGuide += '<p>Folge ' + (ii + 1) + '</p>';
}
}
titleElement.insertAdjacentHTML('beforeend', title);
descElement.insertAdjacentHTML('beforeend', description);
posterElement.src = 'http://image.tmdb.org/t/p/w92' + data.poster_path;
castElement.insertAdjacentHTML('beforeend', cast);
episodesElement.insertAdjacentHTML('beforeend', episodes);
seasonsElement.insertAdjacentHTML('beforeend', seasons);
votesElement.insertAdjacentHTML('beforeend', votes);
epGuideElement.insertAdjacentHTML('beforeend', epGuide);
};
How can I select the "season/i" object with the slash and a variable inside its name?
//EDIT:
There you go, the whole code. Hope, we can find a solution.
In the javascript every variable is a hashTable data-structure and you can access/change its items like an array/hashTable for example:
var person = {name:'Siamand',family:'Maroufi'};
we can access the name property of person object by :
var name= person.name;
or
var name =person['name']
so in your case you can change you code into follwoing:
var epGuide = '';
for (i = 1; i <= seasons; i++) {
epGuide += '<h3>Staffel ' + i + '</h3>';
for (ii = 1; ii < data['season/'+i].episodes.length; ii++) {
epGuide += '<p>Folge ' + (ii + 1) + '</p>';
}
}
example snippet:
var response = `
{
"season/1": {
"_id": "5256c89f19c2956ff6046d47",
"episodes": [{
"air_date": "2011-04-17"
}]
}
}
`;
var data = JSON.parse(response);
var seasons = 2;
var epGuide ="";
for(var i=1;i<seasons;i++){
epGuide += '<h3>Staffel ' + i + '</h3>';
for (ii = 0; ii < data['season/'+i].episodes.length; ii++) {
epGuide += '<p>Folge ' + (ii + 1) + '</p>';
}
}
console.log(epGuide);
by the way the api that you are use hasent such result you said before , it something like follwoing, it has a simple array for seasons

How to change tooltip content in c3js

I'm working on a timeline display and I have data that I want to show on the tooltip. currently it only shows the value at each time. and I cannot find a way to change it. the example below shows how to change the value's format but not what values are displayed
var chart = c3.generate({
data: {
columns: [
['data1', 30000, 20000, 10000, 40000, 15000, 250000],
['data2', 100, 200, 100, 40, 150, 250]
],
axes: {
data2: 'y2'
}
},
axis : {
y : {
tick: {
format: d3.format("s")
}
},
y2: {
show: true,
tick: {
format: d3.format("$")
}
}
},
tooltip: {
format: {
title: function (d) { return 'Data ' + d; },
value: function (value, ratio, id) {
var format = id === 'data1' ? d3.format(',') : d3.format('$');
return format(value);
}
//value: d3.format(',') // apply this format to both y and y2
}
}
});
it's taken from http://c3js.org/samples/tooltip_format.html
they do admit that there isn't an example for content editing but I couldn't find anything in the reference or forums, but a suggestion to change the code (it's here: https://github.com/masayuki0812/c3/blob/master/c3.js in line 300) and below:
__tooltip_contents = getConfig(['tooltip', 'contents'], function (d, defaultTitleFormat, defaultValueFormat, color) {
var titleFormat = __tooltip_format_title ? __tooltip_format_title : defaultTitleFormat,
nameFormat = __tooltip_format_name ? __tooltip_format_name : function (name) { return name; },
valueFormat = __tooltip_format_value ? __tooltip_format_value : defaultValueFormat,
text, i, title, value, name, bgcolor;
for (i = 0; i < d.length; i++) {
if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
if (! text) {
title = titleFormat ? titleFormat(d[i].x) : d[i].x;
text = "<table class='" + CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
}
name = nameFormat(d[i].name);
value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
bgcolor = levelColor ? levelColor(d[i].value) : color(d[i].id);
text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
text += "<td class='value'>" + value + "</td>";
text += "</tr>";
}
return text + "</table>";
})
did anyone attempted to do so? developed some function to facilitate the process? have any tips on how to do so correctly? I do not know how to change their code in a way I could use more data or data different than the d value the function gets.
If you use the function getTooltipContent from https://github.com/masayuki0812/c3/blob/master/src/tooltip.js#L27 and add it in the chart declaration, in tooltip.contents, you'll have the same tooltip content that the default one.
You can make changes on this code and customize it as you like. One detail, as CLASS is not defined in the current scope, but it's part chart object, I substituted CLASS for $$.CLASS, maybe you don't even need this Object in your code.
var chart = c3.generate({
/*...*/
tooltip: {
format: {
/*...*/
},
contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
var $$ = this, config = $$.config,
titleFormat = config.tooltip_format_title || defaultTitleFormat,
nameFormat = config.tooltip_format_name || function (name) { return name; },
valueFormat = config.tooltip_format_value || defaultValueFormat,
text, i, title, value, name, bgcolor;
for (i = 0; i < d.length; i++) {
if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
if (! text) {
title = titleFormat ? titleFormat(d[i].x) : d[i].x;
text = "<table class='" + $$.CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
}
name = nameFormat(d[i].name);
value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
text += "<tr class='" + $$.CLASS.tooltipName + "-" + d[i].id + "'>";
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
text += "<td class='value'>" + value + "</td>";
text += "</tr>";
}
return text + "</table>";
}
}
});
If you want to control tooltip render and use default rendering depending on data value you can use something like this:
tooltip: {
contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
if (d[1].value > 0) {
// Use default rendering
return this.getTooltipContent(d, defaultTitleFormat, defaultValueFormat, color);
} else {
return '<div>Show what you want</div>';
}
},
format: {
/**/
}
}
In my case i had to add the day for the date value(x axis) in tool tip. Finally i came came up with the below solution
References for js and css
https://code.jquery.com/jquery-3.2.1.js
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js
https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js
https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css
function toDate(dateStr)
{
var numbers = dateStr.match(/\d+/g);
return new Date(numbers[0], numbers[1]-1, numbers[2]);
}
function GetMonthFromString(month)
{
var months = {'Jan' : '01','Feb' : '02','Mar':'03','Apr':'04',
'May':'05','Jun':'06','Jul':'07','Aug':'08','Sep':'09',
'Oct':'10','Nov':'11','Dec':'12'};
return months[month];
}
function GetFullDayName(formatteddate)
{
var weekday = new Array(7);
weekday[0] = "Sunday";
weekday[1] = "Monday";
weekday[2] = "Tuesday";
weekday[3] = "Wednesday";
weekday[4] = "Thursday";
weekday[5] = "Friday";
weekday[6] = "Saturday";
var dayofdate = weekday[formatteddate.getDay()];
return dayofdate;
}
//Chart Data for x-axis, OnHours and AvgHours
function CollectChartData()
{
var xData = new Array();
var onHoursData = new Array();
var averageHoursData = new Array();
var instanceOccuringDatesArray = ["2017-04-20","2017-04-21","2017-04-22","2017-04-23","2017-04-24","2017-04-25","2017-04-26","2017-04-27","2017-04-28","2017-04-29","2017-04-30","2017-05-01","2017-05-02","2017-05-03","2017-05-04","2017-05-05","2017-05-06","2017-05-07","2017-05-08","2017-05-09","2017-05-10","2017-05-11","2017-05-12","2017-05-13","2017-05-14","2017-05-15","2017-05-16","2017-05-17","2017-05-18","2017-05-19","2017-05-20"];
var engineOnHoursArray = ["4.01","14.38","0.10","0.12","0.01","0.24","0.03","6.56","0.15","0.00","1.15","0.00","1.21","2.06","8.55","1.41","0.03","1.42","0.00","3.35","0.02","3.44","0.05","5.41","4.06","0.02","0.04","7.26","1.02","5.09","0.00"];
var avgUtilizationArray = ["2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29","2.29"];
xData.push('x');
onHoursData.push('OnHours');
averageHoursData.push('Project Average');
for(var index=0;index<instanceOccuringDatesArray.length;index++)
{
xData.push(instanceOccuringDatesArray[index]);
}
for(var index=0;index<engineOnHoursArray.length;index++)
{
onHoursData.push(engineOnHoursArray[index]);
}
for(var index=0;index<avgUtilizationArray.length;index++)
{
averageHoursData.push(avgUtilizationArray[index]);
}
var Data = [xData, onHoursData, averageHoursData];
return Data;
}
function tooltip_contents(d, defaultTitleFormat, defaultValueFormat, color) {
var $$ = this, config = $$.config, CLASS = $$.CLASS,
titleFormat = config.tooltip_format_title || defaultTitleFormat,
nameFormat = config.tooltip_format_name || function (name) { return name; },
valueFormat = config.tooltip_format_value || defaultValueFormat,
text, i, title, value, name, bgcolor;
// You can access all of data like this:
//$$.data.targets;
for (i = 0; i < d.length; i++) {
if (! text) {
title = titleFormat ? titleFormat(d[i].x) : d[i].x;
var arr = title.split(" ");
var datestr = new Date().getFullYear().toString() + "-"+ GetMonthFromString(arr[1]) + "-"+ arr[0];
var formatteddate = toDate(datestr);
var dayname = GetFullDayName(formatteddate);
title = title + " (" + dayname + ")";
text = "<table class='" + $$.CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
}
name = nameFormat(d[i].name);
var initialvalue = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
if (initialvalue.toString().indexOf('.') > -1)
{
var arrval = initialvalue.toString().split(".");
value = arrval[0] + "h " + arrval[1] + "m";
}
else
{
value = initialvalue + "h " + "00m";
}
bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
text += "<tr class='" + CLASS.tooltipName + "-" + d[i].id + "'>";
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
text += "<td class='value'>" + value + "</td>";
text += "</tr>";
}
return text + "</table>";
}
$(document).ready(function () {
var Data = CollectChartData();
var chart = c3.generate({
data: {
x: 'x',
columns: Data
},
axis: {
x: {
type: 'timeseries',
tick: {
rotate: 75,
//format: '%d-%m-%Y'
format: '%d %b'
}
},
y : {
tick : {
format: function (y) {
if (y < 0) {
}
return y;
}
},
min : 0,
padding : {
bottom : 0
}
}
},
tooltip: {
contents: tooltip_contents
}
});
});
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.min.css" rel="stylesheet" />
<div id="chart"></div>
When we have a stacked bar chart and we would like to show "Total" in the tooltip (but not in the chart as a bar/stack) this can come handy.
C3 charts use a array to store the data for tooltips and before the tooltips are displayed we are adding totals (or anyother data as per our requirement). By doing this though the totals is not available as a stack it is shown in the tooltip.
function key_for_sum(arr) {
return arr.value; //value is the key
};
function sum(prev, next) {
return prev + next;
}
var totals_object = {};
totals_object.x = d[0]['x'];
totals_object.value = d.map(key_for_sum).reduce(sum);
totals_object.name = 'total';
totals_object.index = d[0]['index'];
totals_object.id = 'total';
d.push(totals_object);
Above code has been added to ensure that total is available in
C3.js Stacked Bar chart's tooltip
var chart = c3.generate({
/*...*/
tooltip: {
format: {
/*...*/
},
contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
function key_for_sum(arr) {
return arr.value; //value is the key
}
function sum(prev, next) {
return prev + next;
}
var totals_object = {};
totals_object.x = d[0]['x'];
totals_object.value = d.map(key_for_sum).reduce(sum);// sum func
totals_object.name = 'total';//total will be shown in tooltip
totals_object.index = d[0]['index'];
totals_object.id = 'total';//c3 will use this
d.push(totals_object);
var $$ = this,
config = $$.config,
titleFormat = config.tooltip_format_title || defaultTitleFormat,
nameFormat = config.tooltip_format_name || function (name) {
return name;
},
valueFormat = config.tooltip_format_value || defaultValueFormat,
text, i, title, value, name, bgcolor;
for (i = 0; i < d.length; i++) {
if (!(d[i] && (d[i].value || d[i].value === 0))) {
continue;
}
if (!text) {
title = titleFormat ? titleFormat(d[i].x) : d[i].x;
text = "<table class='" + $$.CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
}
name = nameFormat(d[i].name);
value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
text += "<tr class='" + $$.CLASS.tooltipName + "-" + d[i].id + "'>";
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
text += "<td class='value'>" + value + "</td>";
text += "</tr>";
}
return text + "</table>";
}
}
Adding additional content or non-numerical data into the chart tooltips can be done.
This builds on #supita's excellent answer http://stackoverflow.com/a/25750639/1003746.
Its possible to insert additional metadata about each line into the classes parameter when generating/updating the chart. These can then be added as rows to the tooltip.
This doesn't seem to affect the chart - unless you are using the data.classes feature.
data: {
classes: {
data1: [{prop1: 10, prop2: 20}, {prop1: 30, prop2: 40}],
data2: [{prop1: 50, prop2: 60}'{prop1: 70, prop2: 80}]
}
}
To pick up the metadata in the config.
tooltip: {
contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
const $$ = this;
const config = $$.config;
const meta = config.data_classes;
...
for (i = 0; i < d.length; i++) {
if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
if (! text) {
...
}
const line = d[0].id;
const properties = meta.classes[line];
const property = properties? properties[i] : null;
Then add the following rows to the table to show the new properties.
if (property ) {
text += "<tr class='" + $$.CLASS.tooltipName + "-" + d[i].id + "'>";
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>PROP1</td>";
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + property.prop1 + "</td>";
text += "</tr>";
text += "<tr class='" + $$.CLASS.tooltipName + "-" + d[i].id + "'>";
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>PROP2</td>";
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" +
property.prop2+ " cm/s</td>";
If anybody cares, here is a ClojureScript version of the above algorithm (e.g. supita's answer), slightly simplified (without support for config). (This is probably nothing the OP asked for, but as of now there are so few resources on the net on this topic that most people might wind up here.)
:tooltip {
:contents
(fn [d default-title-format default-value-format color]
(this-as this
(let [this-CLASS (js->clj (.-CLASS this) :keywordize-keys true)
tooltip-name-class (:tooltipName this-CLASS)
rows (js->clj d :keywordize-keys true)
title-row (->> (first rows) (#(str "<table class='" (:tooltip this-CLASS)
"'><tr><th colspan='2'>"
(default-title-format (:x %)) "</th></tr>")))
data-rows (->> rows
(map #(str "<tr class='" tooltip-name-class "--" (:id %) "'>"
"<td class='name'><span style='background-color:"
(color (:id %)) "'></span>" (:name %) "</td>"
"<td class='value'>" (default-value-format (:value %)) "</td>"
"</tr>")))]
(str title-row (string/join data-rows) "</table>"))))}
Your question is about changing the content of the tooltip in c3js.
The tooltip has 3 variables
+----------------+
| title |
+----------------+
| name | value |
+----------------+
Plus, you want to add 'name' from an additional variable, other than those used in 'column'.
tooltip: {
format: {
title(x, index) { return ''; },
name(name, ratio, id, index) { return lst[index + 1]; },
value(value, ratio, id, index) { return value; }
}
},
this worked for me, feel free to play around with the arguments, to get what you need.
I faced a problem which is related tooltip position and style for c3 before. in order to arrange tooltip in c3 freely, my suggestion is manipulating tooltip with d3.
// internal = chart.internal()
const mousePos = d3.mouse(internal.svg.node()); // find mouse position
const clientX = mousePos[0]; //for x
const clientY = mousePos[1]; //for y
const tooltip = d3.select("#tooltip"); //select tooltip div (apply your style)
tooltip.style("display", "initial"); //show tooltip
tooltip.style("left", clientX - mouseOffSet.X + "px"); // set position
tooltip.style("top", clientY - mouseOffSet.Y + "px"); // set position
tooltip.html("<span>" + content + "</span>");
// you can arrange all content and style whatever you want
<div
id="tooltip"
className="your-style"
style={{ display: "none", position: "absolute" }}
/>
Good luck!!

eBay API -- can't print buyItNowPrice using Javascript

I'm trying to build a simple site that will check and print out "Buy It Now Prices" for cars. I can't get the JavaScript push function to print out anything but strings.
The eBay API says that buyItNowPrice returns an Amount.
I have experimented with the other Item functions, and the only ones that are working for me are ones that return a String.
The question is, how should the line var itemPrice = item.buyItNowPrice; be formatted to output a number?
function _cb_findItemsByKeywords(root) {
var items = root.findItemsByKeywordsResponse[0].searchResult[0].item || [];
var html = [];
html.push('<table width="100%" border="0" cellspacing="0" cellpadding="3"><tbody>');
for (var i = 0; i < items.length; ++i) {
var item = items[i];
var title = item.title;
var pic = item.galleryURL;
var viewitem = item.viewItemURL;
var itemPrice = item.buyItNowPrice;
var timeLeft = item.watchCount;
if (title != null && null != viewitem) {
html.push('<tr><td>' + '<img src="' + pic + '" border="1">' + '</td>' +
'<td><a href="' + viewitem + '" target="_blank">' +
title + '</a>' // end hyperlink
+
'<br>Item Price: ' + itemPrice +
'<br>Time Remaining: ' + timeLeft +
'</td></tr>');
}
}
html.push('</tbody></table>');
document.getElementById("results").innerHTML = html.join("");
}
// Create a JavaScript array of the item filters you want to use in your request
var filterarray = [{
"name": "MaxPrice",
"value": "250000",
"paramName": "Currency",
"paramValue": "USD"
},
{
"name": "MinPrice",
"value": "15000",
"paramName": "Currency",
"paramValue": "USD"
},
//{"name":"FreeShippingOnly", "value":"false", "paramName":"", "paramValue":""},
{
"name": "ListingType",
"value": ["AuctionWithBIN", "FixedPrice", /*"StoreInventory"*/ ],
"paramName": "",
"paramValue": ""
},
];
// Generates an indexed URL snippet from the array of item filters
var urlfilter = "";
function buildURLArray() {
for (var i = 0; i < filterarray.length; i++) {
var itemfilter = filterarray[i];
for (var index in itemfilter) {
// Check to see if the paramter has a value (some don't)
if (itemfilter[index] !== "") {
if (itemfilter[index] instanceof Array) {
for (var r = 0; r < itemfilter[index].length; r++) {
var value = itemfilter[index][r];
urlfilter += "&itemFilter\(" + i + "\)." + index + "\(" + r + "\)=" + value;
}
} else {
urlfilter += "&itemFilter\(" + i + "\)." + index + "=" + itemfilter[index];
}
}
}
}
}
buildURLArray(filterarray);
// Construct the request
var url = "http://svcs.ebay.com/services/search/FindingService/v1";
url += "?OPERATION-NAME=findItemsByKeywords";
url += "&SERVICE-VERSION=1.0.0";
url += "&SECURITY-APPNAME=REDACTED";
url += "&GLOBAL-ID=EBAY-MOTOR";
url += "&RESPONSE-DATA-FORMAT=JSON";
url += "&callback=_cb_findItemsByKeywords";
url += "&REST-PAYLOAD";
//url += "&categoryId=6001";
url += "&keywords=Ferrari 575";
url += "&paginationInput.entriesPerPage=12";
url += urlfilter;
// Submit the request
s = document.createElement('script'); // create script element
s.src = url;
document.body.appendChild(s);
You are reading the wrong eBay documentation. FindItemsByKeywords is part of the Finding API service. The buyItNowPrice field is found in the item.listingInfo field. Changing the code to the following will output the price.
var itemPrice = '---';
// buyItNowPrice may not be returned for all results.
if(item.listingInfo[0].buyItNowPrice) {
itemPrice = item.listingInfo[0].buyItNowPrice[0]['#currencyId'] + ' ' + item.listingInfo[0].buyItNowPrice[0].__value__;
} else if(item.sellingStatus[0].currentPrice) {
itemPrice = item.sellingStatus[0].currentPrice[0]['#currencyId'] + ' ' + item.sellingStatus[0].currentPrice[0].__value__;
}

Categories

Resources