User:Chieftain Alex/API javascripts

From Guild Wars 2 Wiki
Jump to navigationJump to search
See also: User:Chieftain Alex/Wiki javascripts
<div id="apidata">[[File:Mediawiki loading animation.gif]]</div>
Mediawiki loading animation.gif (nothing is loading until you paste a script from below into your javascript scratchpad)

Achievements[edit]

/* GW2 API query tool for achievements */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th></tr>';
    $.each(data, function(index, val) {
        var id = val['id'];
        var name = val['name'];
        result += '<tr><td>'+id+'</td><td>'+name+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible achievement IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/achievements').done(function (ids) {

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/achievements?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Achievements rewarding mastery points[edit]

/* GW2 API query tool for mastery achievements */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th><th>Mastery ID</th></tr>';
    $.each(data, function(index, val) {
        var id = val['id'];
        var name = val['name'];

        // Filter for mastery point achievements only
        if ('rewards' in val) {
            $.each(val.rewards, function(i, v) {
                if ('type' in v && v.type == 'Mastery') {
                    var mid = v.id;
                    result += '<tr><td>'+id+'</td><td>'+name+'</td><td>'+mid+'</td></tr>';
                }
            });
        }
    });
    result += '</table>';
    return result;
}

// Fetch all the possible achievement IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/achievements').done(function (ids) {

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/achievements?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Account achievements[edit]

/* GW2 API query tool for account achievements */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var columns = Object.keys(data[0]);
    var result = '<p>'+data.length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible achievement IDs
(function fetchAPIData() {
    var token = ''; // token goes here
    $.getJSON('https://api.guildwars2.com/v2/account/achievements?access_token='+token).done(function (data) {

        // Write to console
        console.log(data);

        // Write to document
        $('#apidata').html(makeTableHTML(data));
    });
})();

Characters[edit]

// For debugging character endpoints - will probably need to update [[Widget:Account build summary]] in a bit for legendary armory when the API data is fixed.
var token = '' // api key goes here
var version = 'latest'; // optionally could be a schema date
var a = 'https://api.guildwars2.com/v2/characters?ids=all&v=' + version + '&access_token=' + token + '&lang=en';
$.getJSON(a, function(data){
   $('#apidata').html('<' + 'pre id="apidatapre"></pr' + 'e>');
   
  var charname = 'Warlock Alexis';
  var a = {};
  
  $.each(data, function(i,v){
    if (v.name == charname) {
      a = v;
    }
  });
  
  delete a.backstory;
  delete a.wvw_abilities;
  delete a.recipes;
  delete a.training;
  
   $('#apidatapre').text(JSON.stringify(a,null,2));
})

Colors and dyes[edit]

/* GW2 API query tool for colors and dyes */
// This tool is a bit more complex than the others because we need to fetch all of the dye item names too.
// Plus some dyes don't have items (i.e. the default dyes)

// Function to convert an object variable into a table
function makeTableHTML(data, item_data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>Color ID</th><th>Color Name</th><th>Dye item id</th><th>Dye item name</th></tr>';
    $.each(data, function(index, val) {
        var item_name = '';
        if (typeof item_data[val['item']] != 'undefined'){
            item_name = item_data[val['item']]['name'];
        }
        result += '<tr><td>'+val['id']+'</td><td>'+val['name']+'</td><td>'+val['item']+'</td><td>'+item_name+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible colour and dye IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/colors').done(function (ids) {
        console.log('Number of colors: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/colors?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate the api results into data, and collect the dye item ids
            var data = {}, item_ids = [];
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                    item_ids.push(val['item']);
                });
            });

          console.log(data);
          console.log(item_ids);

            // Do further requests
            var morepromises = [];
            for (var i=0; i<item_ids.length; i+=maxsize) {
                var current_ids = item_ids.slice(i,i+maxsize).join(',');
                var promise = $.getJSON('https://api.guildwars2.com/v2/items?ids='+current_ids);
                morepromises.push(promise);
            }
            $.when.apply($,morepromises).done(function() {
              console.log('finished morepromises');
                var morenewarguments = {};
                if ( morepromises.length > 1 ) {
                    morenewarguments = arguments;
                } else {
                    morenewarguments[0] = arguments;
                }
                var item_data = {};
                $.each(morenewarguments, function(index, element){
                    $.each(element[0], function(key, val){
                        item_data[val['id']] = val;
                    });
                });

                // Write to console
                console.log(item_data);

                // Write to document
                $('#apidata').html(makeTableHTML(data, item_data));
            });
        });
    });
})();

Dungeons[edit]

function ucFirst(text){
  text = text.split('_');
  text = $.map(text, function(v){
    return v.charAt(0).toUpperCase() + v.slice(1);
  }).join(' ');
  text = text.replace(' Of ',' of ');
  text = text.replace(' The ',' the ');
  return text;
}

function makeTableHTML(fullData, accountData){
  var t = '<table class="table"><tbody>\n';
  t += '<tr><th>Dungeon</th><th>Type</th><th>Path</th><th>Done?</th></tr>\n';
  $.map(fullData, function(v){
    var d = v.id;
    $.map(v.paths, function(x,k){
      var p = x.id;
      var s = 'No';
      if (accountData.indexOf(p) != -1){
        s = 'Yes';
      }
      if (x.type == 'Story'){
        p = 'Story';
      } else {
        p = k + '_-_' + p;
      }
      t += '<tr ' + (k == 0 ? 'class="line-top"' : '') + '><td>' + ucFirst(d) + '</td><td>' + x.type + '</td><td>'+ ucFirst(p) + '</td><td>'+ s + '</td></tr>\n';
    });
  })
  t += '\n</tbody></table>';
  return t;
}

var token = ''; // your key goes here
$.getJSON('https://api.guildwars2.com/v2/dungeons?ids=all')
.done(function(data){
  $.getJSON('https://api.guildwars2.com/v2/account/dungeons?access_token=' + token)
  .done(function(accountData){
    $('#apidata').html(makeTableHTML(data, accountData));
  });
});

Events[edit]

// Function to convert an object variable into a table
function makeTableHTML(data) {
    var columns = Object.keys(data[0]);
    var result = '<p>'+data.length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Function to convert local event coordinate system into continent coordinate system
function recalc_coords(continent_rect, map_rect, coords){
	return [
		Math.round(continent_rect[0][0]+(continent_rect[1][0]-continent_rect[0][0])*(coords[0]-map_rect[0][0])/(map_rect[1][0]-map_rect[0][0])),
		Math.round(continent_rect[0][1]+(continent_rect[1][1]-continent_rect[0][1])*(1-(coords[1]-map_rect[0][1])/(map_rect[1][1]-map_rect[0][1])))
	]
}

// Retrieve the maps API (required for continent_rect and map_rect)
$.getJSON('https://api.guildwars2.com/v1/maps.json').done(function(mapsv1){
  var map_event_details = {};

  // Retrieve the event_details API
  $.getJSON('https://api.guildwars2.com/v1/event_details.json').done(function(data){
    $.each(data['events'], function(k, v) {
      // Save map id for later usage
      var n = v.map_id; // map number

      // Calculate new location and overwrite old coordinate system
      //  also check if event map exists in maps API (e.g. Labyrinthine Cliffs does not)
      if (n in mapsv1['maps']) {
        var newcenter = recalc_coords(mapsv1['maps'][n]['continent_rect'], mapsv1['maps'][n]['map_rect'], v.location.center);
        newcenter.push(v.location.center[2]);
        v.location.center = newcenter;
      } else {
        // console.log('Did not find map_id '+n+' within mapsv1 object');
      }

      // Add event id
      v.id = k;

      // Remove keys we didn't want
      delete v.map_id;

      // Check if map exists in object, if not create it.
      if (!(n in map_event_details)) {
        map_event_details[n] = { "name": "", "events": [] };
      }

      // Add the name if the map exists in the maps API.
      if (n in mapsv1['maps']) {
        map_event_details[n]['name'] = mapsv1['maps'][n]['map_name'];
      }
      map_event_details[n]['events'].push(v);
    });
    // console.log(map_event_details);

    // Print available events for the desired map
    var map_id_required = 1195;
    $('#apidata').html('<h2>' + map_event_details[map_id_required]['name'] + '</h2>\n'
                       + makeTableHTML(map_event_details[map_id_required]['events'])
                       + '\n<p' + 're>' + JSON.stringify(map_event_details[map_id_required]['events']) + '</pr' + 'e>');
  });
});

Finishers[edit]

/* GW2 API query tool for finishers */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var firstindex = Object.keys(data)[0];
    var columns = Object.keys(data[firstindex]);
    var result = '<p>'+Object.keys(data).length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible mount skin IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/finishers').done(function (ids) {
        console.log('Number of skins: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/finishers?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Guild Upgrades[edit]

/* GW2 API query tool for guild upgrades */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var columns = Object.keys(data[0]);
    var result = '<p>'+data.length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible map IDs via "?ids=all"
(function fetchAPIData() {
    // Query API until all the ids have been requested
    $.getJSON('https://api.guildwars2.com/v2/guild/upgrades?ids=all').done(function (data) {

        // Write to document
        $('#apidata').html(makeTableHTML(data));
    });
})();

Items (query of two halves)[edit]

/* GW2 API query tool for items - note this is a hideously large query, be kind to the api servers and don't use this more than you have to! */

// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th></tr>';
    $.each(data, function(index, val) {
        var id = val['id'];
        var name = val['name'];
        result += '<tr><td>'+id+'</td><td>'+name+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible itemsIDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/items').done(function (ids) {
        console.log('Number of items: ' + ids.length);

        // Originally used to be able to request all ids at once, but nowadays its 60000+ items, which is 325 requests at once (too many, greater than the api limit which is about 300 requests per minute)
        // Easiest to just run the request twice
        var half = (ids.length / 2);
        var ids_half = 1; // var ids_half = 1;
      
        ids = ids.slice(ids_half * half, (ids_half + 1) * half);
       
        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/items?lang=en&ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            // console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Items in different languages[edit]

/* GW2 API query tool for item interwikis - for given item ids */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>EN Name</th><th>DE Name</th><th>ES Name</th><th>FR Name</th></tr>';
    var ids = Object.keys(data['en']);
    $.map(ids, function(id) {
        var en_name = data['en'][id]['name'];
        var de_name = data['de'][id]['name'];
        var es_name = data['es'][id]['name'];
        var fr_name = data['fr'][id]['name'];
        result += '<tr><td>'+id+'</td><td>'+en_name+'</td><td>'+de_name+'</td><td>'+es_name+'</td><td>'+fr_name+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible itemsIDs
(function fetchAPIData() {
    var ids = [];
    console.log('Number of items: ' + ids.length);

    // Possible languages
    var langs = ['en', 'de', 'es', 'fr'];

    // Query API until all the ids have been requested
    var data = {}, promises = [], promiseslang = [], langtemp, maxsize = 200;
    for (var j=0; j<langs.length; j++) {
        langtemp = langs[j];
        data[langtemp] = {};

        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/items?lang='+langtemp+'&ids='+current_ids);
            promises.push(promise);
            promiseslang.push(langtemp);
        }
    }

    // Wait until all the GET requests have finished
    $.when.apply($,promises).done(function() {
        // Ensure data is an object
        var newarguments = {};
        if ( promises.length > 1 ) {
            newarguments = arguments;
        } else {
            newarguments[0] = arguments;
        }

        // Concatenate data into data
        $.each(newarguments, function(index, element){
            $.each(element[0], function(key, val){
                data[promiseslang[index]][val['id']] = val;
            });
        });

        // Write to console
        console.log(data);

        // Write to document
        $('#apidata').html(makeTableHTML(data));
    });
})();

Items which are equippable[edit]

/* GW2 API query tool for equippable items - note this is a hideously large query, be kind to the api servers and don't use this more than you have to! */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th><th>Rarity</th><th>Type</th><th>Level</th><th>Details subtype</th><th>Details attr adj</th></tr>';
    $.each(data, function(index, val) {
        var id = val['id'];
        var name = val['name'];
		var rarity = val['rarity'];
		var typ = val['type'] || 'N/A';
		var level = val['level'];
		var details_type = val['details'].type || 'N/A';
		var details_attr_adj = val['details'].attribute_adjustment || 0;
        result += '<tr><td>'+id+'</td><td>'+name+'</td><td>'+rarity+'</td><td>'+typ+'</td><td>'+level+'</td><td>'+details_type+'</td><td>'+details_attr_adj+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible itemsIDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/items').done(function (ids) {
        console.log('Number of items: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/items?lang=en&ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
					if (val.type == 'Trinket' || val.type == 'Weapon' || val.type == 'Armor' || val.type == 'Back') {
						if ('details' in val) {
							data[val['id']] = val;
						} else {
							console.log('Note: Item #' + val.id + ' lacks details object');
						}
					}
                });
            });

            // Write to console
            // console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Items unlocking recipes[edit]

/* GW2 API query tool for items - note this is a hideously large query, be kind to the api servers and don't use this more than you have to! */
// Function to convert an object variable into a table
function makeTableHTML(item_data, recipe_data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>Source recipe ID</th><th>Source name</th><th>P/S</th><th>Taught recipe ID</th><th>Taught recipe output item ID</th><th>Taught recipe output item name</th></tr>';
    $.each(item_data, function(index, val) {
        if (!('details' in val)) {
          return;
        }
        if (!('recipe_id' in val.details)) {
          return;
        }

        var id = val['id'];
        var name = val['name'];
        result += '<tr><td>'+id+'</td><td>'+name+'</td><td>Primary</td><td>'+ val.details.recipe_id +'</td>';
        if (val.details.recipe_id in recipe_data) {
          result += '<td>' + recipe_data[val.details.recipe_id].output_item_id +'</td>';
          if (recipe_data[val.details.recipe_id].output_item_id in item_data) {
            result += '<td>'+ item_data[recipe_data[val.details.recipe_id].output_item_id].name +'</td>';
          } else {
            result += '<td>'+ '?' +'</td>';
          }
        } else {
          result += '<td>' + '?' +'</td><td>'+ '?' +'</td>';
        }
        result += '</tr>';

        if ('extra_recipe_ids' in val.details) {
          $.each(val.details.extra_recipe_ids, function(i, v){
            result += '<tr><td>'+id+'</td><td>'+name+'</td><td>Secondary</td><td>'+ v +'</td>';
            if (v in recipe_data) {
              result += '<td>' + recipe_data[v].output_item_id +'</td>';
              if (recipe_data[v].output_item_id in item_data) {
                result += '<td>'+ item_data[recipe_data[v].output_item_id].name +'</td>';
              } else {
                result += '<td>'+ '?' +'</td>';
              }
            } else {
              result += '<td>' + '?' +'</td><td>'+ '?' +'</td></tr>';
            }
            result += '</tr>';
          });
        }
    });
    result += '</table>';
    return result;
}

// Removes duplicates, blanks and undefined, then sorts. Usage: a.unique()
Array.prototype.unique = function() {
    return this.filter(function (el, i, self) {
        return self.indexOf(el) === i;
    });
};

// Fetch all the possible itemsIDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/items').done(function (ids) {
        // ITEM START
        console.log('Number of items: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/items?lang=en&ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // RECIPE START
            // Acquire unlocked recipe ids from items
            var recipe_ids = [];
            $.each(data, function(key, val){
                if ('details' in val && 'recipe_id' in val.details) {
                  recipe_ids.push(val.details.recipe_id);
                  if ('extra_recipe_ids' in val.details) {
                    recipe_ids.push(val.details.extra_recipe_ids);
                  }
                }
            });

            // Flatten recipe ids and remove duplicates
            recipe_ids = $.map(recipe_ids, function(v){ return v; }).unique();
            console.log('Number of recipes: ' + recipe_ids.length);

            // Query API until all the recipe_ids have been requested
            var promises2 = [];
            for (var i=0; i<recipe_ids.length; i+=maxsize) {
                var current_recipe_ids = recipe_ids.slice(i,i+maxsize).join(',');
                var promise2 = $.getJSON('https://api.guildwars2.com/v2/recipes?lang=en&ids='+current_recipe_ids);
                promises2.push(promise2);
            }

            // Wait until all the GET requests have finished
            $.when.apply($,promises2).done(function() {
                // Ensure data is an object
                var newarguments2 = {};
                if ( promises2.length > 1 ) {
                    newarguments2 = arguments;
                } else {
                    newarguments2[0] = arguments;
                }

                // Concatenate data into data
                var recipe_data = {};
                $.each(newarguments2, function(index, element){
                    $.each(element[0], function(key, val){
                        recipe_data[val['id']] = val;
                    });
                });

                // Write to console
                // console.log(recipe_data);

                // Write to document
                $('#apidata').html(makeTableHTML(data, recipe_data));
            });
            // RECIPE END
        });
        // ITEM END
    });
})();

Item stats[edit]

/* GW2 API query tool for item stats */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th><th>Stats</th></tr>';
    var attributenames = {
      'AgonyResistance': 'Agony_Resistance',
      'BoonDuration': 'Concentration',
      'ConditionDamage': 'Condition_Damage',
      'ConditionDuration': 'Expertise',
      'CritDamage': 'Ferocity',
      'Healing': 'Healing_Power',
      'Power': 'Power',
      'Precision': 'Precision',
      'Toughness': 'Toughness',
      'Vitality': 'Vitality'
    };
    $.each(data, function(index, val) {
        var id = val['id'];
        var name = val['name'];
        var sumvalue = 0;
        var summultiplier = 0;
        var stats = $.map(val['attributes'], function(v){
          summultiplier += v.multiplier;
          sumvalue += v.value;
          // Print contribution to stat equation only if non-zero
          var eqn = [];
          if (v.multiplier != 0) { eqn.push('($n * ' + v.multiplier + ')'); }
          if (v.value != 0) { eqn.push(v.value); }
          return attributenames[v.attribute] + ': ' + eqn.join(' + ');
        }).join(', ');
        // var stats = JSON.stringify(val['attributes']);

        // Only print non-blank names, non-blank stats, and non-zero totals
        if ( (name.length > 3) && (stats.length > 3) && ((summultiplier + sumvalue) > 0) ) {
            result += '<tr><td>'+id+'</td><td>'+name+'</td><td>'+stats+'</td></tr>';
        }
    });
    result += '</table>';
    return result;
}

// Fetch all the possible item stat IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/itemstats').done(function (ids) {

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/itemstats?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Item ids to selectable prefixes[edit]

/* GW2 API query tool for item stat select options */
// Function to convert an object variable into a table
function makeTableHTML(data, itemstats) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th><th>Prefixes</th></tr>';
    $.each(data, function(index, val) {
        var prefixids = val['details']['stat_choices'];
        var prefixnames = [];
        $.each(prefixids, function(i,prefixid) {
            prefixnames.push(itemstats[prefixid]['name'])
        });
        prefixnames.sort(function(a,b) {
            return a > b;
        })
        result += '<tr><td>' + val['id'] + '</td><td>' + val['name'] + '</td><td>' + '{{prefix selection|'+prefixnames.join(', ')+'}}' + '</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible stats and the required item details
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/itemstats?ids=all').done(function (itemstatstemp) {
        var itemstats = {};
        $.each(itemstatstemp, function(k,v) {
            v.name = v.name.replace("'s","");
            itemstats[v.id] = v;
        });

        // Write to console
        console.log(itemstats);
        console.log('Number of item stat prefixes: ' + itemstats.length);

        // Item ids we want
        var ids = [30704,30689];
        console.log('Number of items: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/items?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data by id
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data, itemstats));
        });
    });
})();

Legendary armory[edit]

/* GW2 API query tool for legendary armory items */
// Function to convert an object variable into a table
function makeTableHTML(itemdata, armorydata) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>Max count</th><th>Item ID</th><th>Name</th><th>Type</th><th>Subtype</th><th>Weight</th></tr>';
    $.map(armorydata, function(v) {
        var id = v.id;
        var max_count = v.max_count;
        
        var name = '';
        var type = '';
        var subtype = '';
        var weight = '';
        
        if (id in itemdata) {
            if ('name' in itemdata[id]) {
                name = itemdata[id].name;
            }
            if ('type' in itemdata[id]) {
                type = itemdata[id].type;
            }
            if ('details' in itemdata[id]) {
                if ('type' in itemdata[id].details) {
                    subtype = itemdata[id].details.type;
                }
                if ('weight_class' in itemdata[id].details) {
                    weight = itemdata[id].details.weight_class;
                }
            }
        }
        
        result += '<tr><td>'+max_count+'</td><td>'+id+'</td><td>'+name+'</td><td>'+type+'</td><td>'+subtype+'</td><td>'+weight+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch the itemsIDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/legendaryarmory?ids=all').done(function (armorydata) {
        var ids = $.map(armorydata, function(v) {
            return v.id;
        });
        console.log('Number of items: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/items?lang=en&ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure response is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate response into itemdata
            var itemdata = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    itemdata[val['id']] = val;
                });
            });

            // Write to console
            // console.log(itemdata);

            // Write to document
            $('#apidata').html(makeTableHTML(itemdata, armorydata));
        });
    });
})();

Maps[edit]

/* GW2 API query tool for maps */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var columns = Object.keys(data[0]);
    var result = '<p>'+data.length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible map IDs via "?ids=all"
(function fetchAPIData() {
    // Query API until all the ids have been requested
    $.getJSON('https://api.guildwars2.com/v2/maps?ids=all').done(function (data) {

        // Write to document
        $('#apidata').html(makeTableHTML(data));
    });
})();

Map sector polygon area[edit]

/* GW2 API query tool for finding the polygon area within any map using v2/continents and v2/maps */

// Function to find the area of a 2D polygon
// https://stackoverflow.com/a/33670691 but then changed from xy object [ {x: 1, y: 2}, {x: 1, y: 2}] to an array of pairs [ [1,2], [1,2] ]
function calcPolygonArea(vertices) {
    var total = 0;

    for (var i = 0, l = vertices.length; i < l; i++) {
        var addX = vertices[i][0];
        var addY = vertices[i == vertices.length - 1 ? 0 : i + 1][1];
        var subX = vertices[i == vertices.length - 1 ? 0 : i + 1][0];
        var subY = vertices[i][1];

        total += (addX * addY * 0.5);
        total -= (subX * subY * 0.5);
    }
    return Math.abs(total);
}

// Function to convert an object variable into a table
function makeTableHTML(data) {
    var first = Object.keys(data); first = first[0];
    var columns = Object.keys(data[first]);
    var result = '<p>'+Object.keys(data).length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Query
$.getJSON('https://api.guildwars2.com/v2/maps?ids=all', function(maps){
    // Rearrange metadata info by map id
    var data = {}, map_ids = [];
    $.each(maps, function(i,v){
        // copy data from v2/maps
        data[v.id] = v;
        
        // add placeholder for sectors
        data[v.id]['sectors'] = {};
        data[v.id]['totalarea'] = 0;
    });
    map_ids = Object.keys(data);

    // Get detailed information
    $.getJSON('https://api.guildwars2.com/v2/continents/1/floors?ids=all', function(continentsdata){
        $.each(continentsdata, function(fi,floorv){
            $.each(floorv['regions'], function(ri, regionv){
                $.each(regionv['maps'], function(mi, mapv){
                    var mapid = mapv.id;
                    if ( map_ids.indexOf(String(mapid)) == -1) {
                        console.log('rejecting map id ' + mapid);
                        return;
                    }
                    
                    $.each(mapv['sectors'], function(si, sv){
                        if (!(data[mapid]['sectors'].hasOwnProperty(sv.id))) {
                            data[mapid]['sectors'][sv.id] = sv;
                        }
                    });
                });
            });
        });

        // Remove maps without any sectors
        $.each(data, function(k,v){
            if (Object.keys(v['sectors']).length === 0) {
                console.log('discarding map ' + k + ', name = ' + v.name);
                delete data[k];
            }
        });
        
        // For each zone, for each sector, find the polygon area and summate it
        $.each(data, function(k,v){
            var running_total = 0;
            $.each(v['sectors'], function(x,val){
                running_total += calcPolygonArea(val.bounds);
            });
            data[k]['totalarea'] = Math.round(running_total);
            delete data[k]['sectors'];
        });

        // Display results
        // console.log(data);
        $('#apidata').html( makeTableHTML(data) );
    });
});

Sector names[edit]

/* GW2 API query tool for locations within one map using v2/continents and v2/maps */
// Get information for one map within continent 1, from all floors

// Function to convert an object variable into a table
function makeTableHTML(data) {
    var first = Object.keys(data);
    if (first.length > 0) { first = first[1] } else { return '(none)' };
    var columns = Object.keys(data[first]);
    var result = '<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Query
$.getJSON('https://api.guildwars2.com/v2/maps?ids=all', function(maps){
  // Rearrange metadata info by map id
  var data = {}, map_names = {};
  $.each(maps, function(i,v){
    // Comment this next line out if you want to include non-public maps.
    if (v.type !== 'Public'){
      return;
    }
    
    map_names[v.id] = v.name || '(blank area name ingame)';
    
    data[v.id] = v;
    data[v.id]['points_of_interest'] = {};
    data[v.id]['mastery_points'] = {};
    data[v.id]['sectors'] = {};
  });

  // Get detailed information
  var data2 = {};
  $.getJSON('https://api.guildwars2.com/v2/continents/1/floors?ids=all', function(continentsdata){
    $.each(continentsdata, function(fi,floorv){
      $.each(floorv['regions'], function(ri, regionv){
        $.each(regionv['maps'], function(mi, mapv){
          var mapid = mapv.id;
          if (mapid in map_names) {
            $.each(mapv['sectors'], function(si, sv){
              if (!(sv.id in data2)) {
                sv.sectorname = sv.name || '(blank area name ingame)';
                sv.sectorname = sv.sectorname.replace('<br>',' ');
                sv.zoneid = mapid;
                sv.zonename = map_names[mapid];
                delete sv.bounds;
                delete sv.level;
                delete sv.chat_link;
                delete sv.name;
                data2[sv.id] = sv;
              }
            });
            }
        });
      });
    });

    // Display results
    $('#apidata').html( '<h3>Sectors</h3>\n' + makeTableHTML(data2) );
  });
});

Regions[edit]

/* GW2 API query tool for regions */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var columns = Object.keys(data[0]);
    var result = '<p>'+data.length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

function getData() {
    // Query
    var data = [];
    $.getJSON('https://api.guildwars2.com/v2/continents/1/floors?ids=all', function(continentsdata){
        $.each(continentsdata, function(fi,floorv){
            $.each(floorv['regions'], function(k, regionv){
                data.push({
                    floor_id: floorv.id,
                    region_id: regionv.id,
                    name: regionv.name,
                    continent_rect: regionv.continent_rect,
                    label_coord: regionv.label_coord
                });
            });
        });
   
        // Display results
    	  $('#apidata').html( makeTableHTML(data) );
    });
}
getData();

Continents whitelisted data[edit]

See also: Widget:Interactive map data builder

Map details[edit]

/* GW2 API query tool for locations within one map using v2/continents and v2/maps */
// Get information for one map within continent 1, from all floors
var usermapid = 1211;

// Function to convert an object variable into a table
function makeTableHTML(data) {
    var first = Object.keys(data);
    if (first.length > 0) { first = first[1] } else { return '(none)' };
    var columns = Object.keys(data[first]);
    var result = '<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Query
$.getJSON('https://api.guildwars2.com/v2/maps?ids=all', function(maps){
  // Rearrange metadata info by map id
  var data = {};
  $.each(maps, function(i,v){
    data[v.id] = v;
    data[v.id]['points_of_interest'] = {};
    data[v.id]['mastery_points'] = {};
    data[v.id]['sectors'] = {};
  });

  // Get detailed information
  $.getJSON('https://api.guildwars2.com/v2/continents/1/floors?ids=all', function(continentsdata){
    $.each(continentsdata, function(fi,floorv){
      $.each(floorv['regions'], function(ri, regionv){
        $.each(regionv['maps'], function(mi, mapv){
          var mapid = mapv.id;
          if (!(mapid == usermapid)) {
            return
          }
          $.each(mapv['points_of_interest'], function(pi, poiv){
            if (!(poiv.id in data[mapid]['points_of_interest'])) {
              data[mapid]['points_of_interest'][poiv.id] = poiv;
            }
          });
          $.each(mapv['mastery_points'], function(mi, mv){
            if (!(mv.id in data[mapid]['mastery_points'])) {
              data[mapid]['mastery_points'][mv.id] = mv;
            }
          });
          $.each(mapv['sectors'], function(si, sv){
            if (!(sv.id in data[mapid]['sectors'])) {
              data[mapid]['sectors'][sv.id] = sv;
            }
          });
        });
      });
    });

    // Remove maps without any points of interest
    $.each(data, function(k,v){
      if (Object.keys(v['points_of_interest']).length === 0) {
        delete data[k];
      }
    });

    // Display results
    $('#apidata').html( '<h3>Landmarks</h3>\n' + makeTableHTML(data[usermapid]['points_of_interest'])
                    + '\n<h3>Mastery points</h3>\n' + makeTableHTML(data[usermapid]['mastery_points'])
                    + '\n<h3>Sectors</h3>\n' + makeTableHTML(data[usermapid]['sectors']) );
  });
});

Zones in different languages[edit]

/* GW2 API query tool for map ids in different langages */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>EN Name</th><th>DE Name</th><th>ES Name</th><th>FR Name</th></tr>';
    var ids = Object.keys(data['en']);
    $.each(ids, function(index, id) {
        result += '<tr><td>' + id + '</td><td>' + data['en'][id]['name'] + '</td><td>' + data['de'][id]['name'] + '</td><td>' + data['es'][id]['name'] + '</td><td>' + data['fr'][id]['name'] + '</td></tr>';
    });
    result += '</table>';
    return result;
}

// Query API until all the languages have been requested
var zones = {}, langs = ['en', 'de', 'es', 'fr'], promises = [];
$.each(langs, function(li, lang){
  zones[lang] = {};
  promises.push( $.getJSON('https://api.guildwars2.com/v2/maps?ids=all&lang='+lang) );
});

// Wait until all the GET requests have finished
$.when.apply($,promises).done(function() {
  $.each(arguments, function(i,v){
    var thislang = langs[i];
    $.each(v[0], function(i,v){
        zones[thislang][v.id] = v;
    });
  });
  console.log(zones);

  // Display results
  $('#apidata').html( makeTableHTML(zones) );
});

Areas in different languages[edit]

/* GW2 API query tool for sector ids (aka, areas) in different langages */
// Function to cleanup the name
function cleanName(name, id) {
  if (typeof name == 'undefined') { name = '(name ' + id + ' missing from API)'; }
  name = name.replace('\n',' ').replace('<br>',' ');
  return name;
}

// Function to convert an object variable into a table
function makeTableHTML(data, zones) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Associated Zone</th><th>EN Name</th><th>DE Name</th><th>ES Name</th><th>FR Name</th></tr>';
    var ids = Object.keys(data['en']);
    $.each(ids, function(index, id) {
        result += '<tr><td>' + id + '</td>'
                     +'<td>' + cleanName(zones[id], id) + '</td>'
                     +'<td>' + cleanName(data['en'][id]['name'], id) + '</td>'
                     +'<td>' + cleanName(data['de'][id]['name'], id) + '</td>'
                     +'<td>' + cleanName(data['es'][id]['name'], id) + '</td>'
                     +'<td>' + cleanName(data['fr'][id]['name'], id) + '</td>'
                  +'</tr>';
    });
    result += '</table>';
    return result;
}

// Query API until all the languages have been requested
var sectors = {}, parent_zone_names = {}, langs = ['en', 'de', 'es', 'fr'], promises = [];
$.each(langs, function(li, lang){
  sectors[lang] = {};
  promises.push( $.getJSON('https://api.guildwars2.com/v2/continents/1/floors?ids=all&lang='+lang) );
});

// Wait until all the GET requests have finished
$.when.apply($,promises).done(function() {
  $.each(arguments, function(i,v){
    var thislang = langs[i];
    $.each(v[0], function(bi,floorv){
      $.each(floorv['regions'], function(ri, regionv){
        $.each(regionv['maps'], function(mi, mapv){
          $.each(mapv['sectors'], function(si, sv){
            if (!(sv.id in sectors[thislang] )) {
              sectors[thislang][sv.id] = sv;
            }
            if (!(sv.id in parent_zone_names )) {
              parent_zone_names[sv.id] = mapv.name;
            }
          });
        });
      });
    });
  });
  // console.log(sectors);

  // Display results
  $('#apidata').html( makeTableHTML(sectors, parent_zone_names) );
});

Continents/x explorer[edit]

// CONTINENTS EXPLORER
var mapObj = { floors: {} };
$.getJSON('https://api.guildwars2.com/v2/continents/1/floors?ids=all').done(function(APIDATA) {
    
    // Floors
    $.each(APIDATA, function(floorKey, floorVal) {
        var floorID = floorVal.id;
        mapObj.floors[floorID] = { regions: {} };
        
        // Regions
        $.each(floorVal.regions, function(regionKey, regionVal) {
            var regionID = regionVal.id;
            var regionNAME = regionVal.name;
            mapObj.floors[floorID].regions[regionID] = {
                name: regionNAME,
                maps: {}
            };
            
            // Maps
            $.each(regionVal.maps, function(mapKey, mapVal) {
                var mapID = mapVal.id;
                mapObj.floors[floorID].regions[regionID].maps[mapID] = mapVal.name;
            });
            
        });
        
    });
    
    
    // Print to console
    console.log(mapObj);
    
    
    // Print results to page
    $('#apidata').html( makeTableHTML(mapObj) );
});

function makeTableHTML(mV) {
    var result = '<table class="table mech1" style="margin-bottom:0px;">'
        + '<tr><th>Floor</th><th>Region</th><th>Region name</th><th>Map</th><th>Map name</th></tr>';
    $.each(mV.floors, function(fID, fV){
        $.each(fV.regions, function(rID, rV){
            $.each(rV.maps, function(mID, mName){
                result += '<tr><td>' + fID + '</td><td>' + rID + '</td><td>' + rV.name + '</td><td>' + mID + '</td><td>' + mName + '</td></tr>'
            });
        });
    });
    result += '</table>';
    return result;
}

Minis[edit]

/* GW2 API query tool for minis */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th><th>Order</th><th>Item id</th></tr>';
    $.each(data, function(index, val) {
        result += '<tr><td>' + val['id'] + '</td><td>' + val['name'] + '</td><td>' + val['order'] + '</td><td>' + val['item_id'] + '</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible miniature IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/minis').done(function (ids) {
        console.log('Number of minis: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/minis?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Mount skins[edit]

/* GW2 API query tool for mount skins */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var firstindex = Object.keys(data)[0];
    var columns = Object.keys(data[firstindex]);
    var result = '<p>'+Object.keys(data).length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible mount skin IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/mounts/skins').done(function (ids) {
        console.log('Number of skins: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/mounts/skins?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Novelties[edit]

/* GW2 API query tool for novelties */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var firstindex = Object.keys(data)[0];
    var columns = Object.keys(data[firstindex]);
    var result = '<p>'+Object.keys(data).length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible mount skin IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/novelties').done(function (ids) {
        console.log('Number of skins: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/novelties?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Outfits[edit]

/* GW2 API query tool for outfits */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th><th>Unlock item id</th></tr>';
    $.each(data, function(index, val) {
        result += '<tr><td>' + val['id'] + '</td><td>' + val['name'] + '</td><td>' + val['unlock_items'][0] + '</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible outfit IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/outfits?ids=all').done(function (data) {
        console.log('Number of outfits: ' + data.length);

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
    });
})();

Profession explorer[edit]

var prof = 'Elementalist';

/* GW2 API query tool for traits */
console.clear();

// Function to convert an object variable into a table
function makeTableHTML(sortarray, tdata, specdata, prof) {
    var result = '<table class="table '+prof.toLowerCase()+'" style="margin-bottom:0px;"><tr><th>ID</th><th>Spec</th><th>Tier</th><th>Sort</th>'
               + '<th>I</th><th>Name</th><th>Description</th>'
                +'</tr>';
    var prev_spec = '', this_spec = '';
    $.each(sortarray, function(index, val) {
        this_spec = specdata[val[1]]['name'];
        //var id = val['id'], name = val['name'], position = val['order'] + 1;
        //result += '<tr><td>'+id+'</td><td>'+name+'</td><td>'+position+'</td></tr>';
        var r = '<tr class="' + (this_spec == prev_spec ? '' : 'line-top') + '"><td>'+val[0]+'</td><td>'+specdata[val[1]]['name']+'</td><td>'+val[2]+'</td><td>'+val[3]+'</td>'
                + '<td><img style="width:64px; height: 64px; background-color: #000;" src="'+tdata[val[0]]['icon']+'"></img></td><td>'+tdata[val[0]]['name']+'</td><td>'+tdata[val[0]]['description']+'</td>'
                +'</tr>';
        prev_spec = specdata[val[1]]['name'];
        result += r
    });
    result += '</table>';
    return result;
}

// Fetch all the possible trait IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/professions/'+prof).done(function (profdata) {
        console.log('profdata: ',profdata);
        // Collate ids
        var skillids = [];
        $.each(profdata['weapons'], function(i,v){
          $.each(v['skills'], function(ii,vv){
            skillids.push(vv.id);
          });
        });
        $.each(profdata['skills'], function(i,v){
          skillids.push(v.id);
        });
                
        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<skillids.length; i+=maxsize) {
            var current_ids = skillids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/skills?ids='+current_ids);
            promises.push(promise);
        }
        $.when.apply($,promises).done(function() {
            var newarguments = {}; if ( promises.length > 1 ) { newarguments = arguments; } else { newarguments[0] = arguments; }
            var skill_data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    skill_data[val.id] = val;
                });
            });
            console.log('skills: ', skill_data);

            $.getJSON('https://api.guildwars2.com/v2/specializations?ids='+profdata['specializations'].join(',')).done(function (specdata) {
                var specs = {};
                $.each(specdata, function(i,v){
                    specs[v.id] = v;
                });

                // Collate ids
                var traitids = [];
                $.each(specs, function(i,v){
                   $.each(v.minor_traits, function(ii,vv){
                       traitids.push(vv);
                   });
                   $.each(v.major_traits, function(ii,vv){
                       traitids.push(vv);
                   });
                });

                // Get trait details
                $.getJSON('https://api.guildwars2.com/v2/traits?ids='+traitids.join(',')).done(function(tdata){
                    var trait_data = {}
                    $.each(tdata, function(k,v){
                       trait_data[v.id] = v;
                    });
                  console.log(trait_data);

                    var trait_sort = [];
                    $.each(trait_data, function(k,v){
                        var pos = v.order || 0;
                        if (v.slot == 'Major') { pos += 1; }
                        trait_sort.push( [v.id, v.specialization, v.tier, pos] );
                    });

                    trait_sort.sort(function(a,b){
                        return a[1] - b[1] || a[2] - b[2] || a[3] - b[3];
                    });

                    // console.log('traits: ', trait_data, ', trait sort: ', trait_sort);
                    var text = '<h2>Traits</h2>\n';
                    text += makeTableHTML(trait_sort, trait_data, specs, prof);

                    // Weapon skills
                    var prev_wep = '';
                    text += '<h2>Weapon skills</h2>\n';
                    text += '<table class="table '+prof.toLowerCase()+'"><tr><th>ID</th><th>Weapon</th><th>Slot</th><th>Icon</th><th>Name</th><th>Description</th></tr>';
                    $.each(profdata['weapons'], function(weapontype,weaponobj){
                      $.each(weaponobj['skills'], function(i,v){
                        var this_wep = weapontype;
                        text += '<tr class="' + (this_wep == prev_wep ? '' : 'line-top') + '">'
                          + '<td>'+v.id+'</td>'
                          + '<td>'+weapontype+'</td>'
                          + '<td>'+v.slot+'</td>'
                          + '<td><img style="width:64px; height: 64px; background-color: #000;" src="'+skill_data[v.id]['icon']+'"></img></td>'
                          + '<td>'+skill_data[v.id]['name']+'</td>'
                          + '<td>'+skill_data[v.id]['description']+'</td>'
                          +'</tr>';
                        prev_wep = weapontype;
                      });
                    });
                    text += '</table>\n';

                    // Heal/Utility/Elite skills
                    text += '<h2>Non-weapon skills</h2>\n';
                    text += '<table class="table '+prof.toLowerCase()+'"><tr><th>ID</th><th>Type</th><th>Icon</th><th>Name</th><th>Description</th></tr>';
                    $.each(profdata['skills'], function(i,v){
                        text += '<tr>'
                          + '<td>'+v.id+'</td>'
                          + '<td>'+v.type+'</td>'
                          + '<td><img style="width:64px; height: 64px; background-color: #000;" src="'+skill_data[v.id]['icon']+'"></img></td>'
                          + '<td>'+skill_data[v.id]['name']+'</td>'
                          + '<td>'+skill_data[v.id]['description']+'</td>'
                          +'</tr>';
                    });
                    text += '</table>\n';

                    $('#apidata').html(text)
                });
            });
        });
    });
})();

Profession training[edit]

/* GW2 API query tool for training */
var prof = 'all'; // Warrior etc with uppercase if specifying an actual profession

// Helper function
function ucFirstType(text){
    switch (text) {
        case 'skills': text = 'Skill'; break;
        case 'traits': text = 'Trait'; break;
        default: text = text.charAt(0).toUpperCase() + text.slice(1); break;
    }
    return text;
}

// Function to convert an object variable into a table
function makeHTML(profData, detailData) {
    var result = '', r, x, prevh2, prev_cost, current_cost, s;

    $.each(profData, function(profIndex, profValue){
console.log(profData.length);
        if (profData.length !== 1) {
            result += '<h1>' + profValue.name + '</h1>\n';
        }

        prevh2 = '';
        $.each(profValue.training, function(trainingKey, trainingValue){
            if (prevh2 !== trainingValue.category) {
                result += '<h2>' + trainingValue.category + '</h2>\n';
            }
            result += '<h3>' + trainingValue.name + '</h3>';
            result += '<table class="table training ' + profValue.name.toLowerCase() + '">\n';
            result += '<thead><tr><th>Unlock order</th><th>Cost</th><th>Cumulative cost</th><th>Type</th><th>Name</th><th>Description</th></tr></thead>\n';
            result += '<tbody>';

            prev_cost = 0;
            r = $.map(trainingValue.track, function(v,i){
                if (v.type in detailData && v.id in detailData[v.type]) {
                    x = detailData[v.type][v.id];
                } else {
                    x =  { 'name': v.type + ' #' + v.id, 'icon' : '', 'description': '' };
                }

                // Calculate running cost
                current_cost = v.cost - prev_cost;
                // Update for next loop
                prev_cost = v.cost;

                // Don't show icons if profession is equal to 'all'
                if (prof == 'all') {
                    return '<tr>'
                        + '<td>'+i+'</td>'
                        + '<td>'+current_cost+'</td>'
                        + '<td>'+v.cost+'</td>'
                        + '<td>'+ucFirstType(v.type)+'</td>'
                        + '<td>'+ '<a href="/wiki/'+x.name+'">' + x.name + '</a>' +'</td>'
                        + '<td>'+x.description+'</td>'
                    + '</tr>';
                } else {
                    // Figure out the slot type if its a trait so we can clip it with a hexagon path mask
                    s = x.slot || '';

                    return '<tr>'
                        + '<td>'+i+'</td>'
                        + '<td>'+current_cost+'</td>'
                        + '<td>'+v.cost+'</td>'
                        + '<td>'+ucFirstType(v.type)+'</td>'
                        + '<td>'+ '<img class="mask-'+v.type+' '+s+'" style="width:20px; height: 20px;" src="'+x.icon+'"/> <a href="/wiki/'+x.name+'">' + x.name + '</a>' +'</td>'
                        + '<td>'+x.description+'</td>'
                    + '</tr>';
                }
            });
            result += r.join('\n');
            result += '</tbody>\n';
            result += '</table>\n';

            prevh2 = trainingValue.category;
        });

    });
    return result;
}

// Fetch all the possible trait IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/professions?ids=' + prof + '&wiki=1&lang=en')
    .done(function (profData) {

        // Delete the keys if they are not 'training' or 'name'
        $.each(profData, function(profIndex, profValue){
            $.each(profValue, function(k, v){
                if (!(k == 'name' || k == 'training')) {
                    delete profData[profIndex][k];
                }
            });
        });

        // Collate ids
        var skillids = [], traitids = [];

        // In each PROFESSION's TRAINING object, in each line's TRACK object, check type (context) and add to appropriate array
        $.each(profData, function(profIndex, profValue){
            $.each(profValue.training, function(trainingIndex, trainingValue){
                $.each(trainingValue.track, function(i, v){
                    // Extract useful id and overwrite type with something matching an epi endpoint
                    if (v.type == 'Skill') {
                        skillids.push(v.skill_id);
                        profData[profIndex].training[trainingIndex].track[i].id = v.skill_id;
                        profData[profIndex].training[trainingIndex].track[i].type = 'skills';

                        delete profData[profIndex].training[trainingIndex].track[i].skill_id;
                    } else if (v.type == 'Trait') {
                        traitids.push(v.trait_id);
                        profData[profIndex].training[trainingIndex].track[i].id = v.trait_id;
                        profData[profIndex].training[trainingIndex].track[i].type = 'traits';

                        delete profData[profIndex].training[trainingIndex].track[i].trait_id;
                    } else {
                        console.log('unexpected training track item type ',v.type);
                    }
                });

                // Fix the category name
                if (trainingValue.category == 'EliteSpecializations') {
                    profData[profIndex].training[trainingIndex].category = 'Elite Specializations';
                }
            });

            // Sort each training track by Category and then by Name
            profData[profIndex].training = profData[profIndex].training.sort(function(a,b){
                var categorySortOrder = ['Skills', 'Specializations', 'Elite Specializations'];

                // Sort Elite Specs by ID (release order), but otherwise sort by Name
                if (a.category == 'Elite Specializations') {
                    return categorySortOrder.indexOf(a.category) - categorySortOrder.indexOf(b.category) || a.id - b.id;
                } else {
                    return categorySortOrder.indexOf(a.category) - categorySortOrder.indexOf(b.category) || a.name > b.name;
                }
            });
        });

        // Queue up the requests for names
        var promises = [], promisestype = [], current_ids = [], ids = [], current_type = '', maxsize = 200;

        // Skills
        current_type = 'skills';
        ids = skillids;
        for (var i=0; i<ids.length; i+=maxsize) {
            current_ids = ids.slice(i,i+maxsize).join(',');
            promises.push( $.getJSON('https://api.guildwars2.com/v2/'+current_type+'?ids='+current_ids+'&wiki=1&lang=en') );
            promisestype.push(current_type)
        }

        // Traits
        current_type = 'traits';
        ids = traitids;
        for (var i=0; i<ids.length; i+=maxsize) {
            current_ids = ids.slice(i,i+maxsize).join(',');
            promises.push( $.getJSON('https://api.guildwars2.com/v2/'+current_type+'?ids='+current_ids+'&wiki=1&lang=en') );
            promisestype.push(current_type)
        }

        // Wait until all the GET requests have finished
        var detailData = { 'skills': {}, 'traits': {} };
        $.when.apply($,promises)
        .done(function() {

            // Concatenate results into detailData
            $.each(arguments, function(index, element){
                current_type = promisestype[index];
                $.each(element[0], function(key, val){
                    detailData[current_type][val['id']] = val;
                });
            });

            // Write to console
            // console.log(profData, detailData);

            // Write to document
            $('#apidata').html(makeHTML(profData, detailData));
        })
        .fail( function(d, textStatus, error) {
            console.error("Skills or Traits API getJSON failed (request #2, possible invalid ids), status: " + textStatus + ", error: "+error);
            $('#apidata').addClass('apierror');
            $('#apidata').html('<b>Skills or Traits API failed to load.</b>' + '<p>Error: ' + error + '</p>');
        });
    })
    .fail( function(d, textStatus, error) {
        console.error("Professions API getJSON failed (request #1, profession possibly wrong case (use Uppercase-first) or invalid), status: " + textStatus + ", error: "+error);
        $('#apidata').addClass('apierror');
        $('#apidata').html('<b>Professions API failed to load.</b>' + '<p>Error: ' + error + '</p>');
    });
})();

Quests (story chapters)[edit]

/* GW2 API query tool for quests */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th></tr>';
    $.each(data, function(index, val) {
        var id = val['id'];
        var name = val['name'];
        result += '<tr><td>'+id+'</td><td>'+name+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible questIDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/quests').done(function (ids) {
        console.log('Number of items: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/quests?lang=en&ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            // console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Recipes[edit]

/* GW2 API query tool for recipes - note this is a large query, don't use this more than you have to! */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>Recipe ID</th><th>Type</th><th>Disciplines</th><th>Rating</th><th>Output item ID</th></tr>';
    $.each(data, function(index, val) {
        result += '<tr><td>'+val['id']+'</td><td>'+val['type']+'</td><td>'+JSON.stringify(val['disciplines'])+'</td><td>'+val['min_rating']+'</td><td>'+val['output_item_id']+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible recipe IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/recipes').done(function (ids) {
        console.log('Number of recipes: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/recipes?lang=en&ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            // console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Recipes 2[edit]

/* GW2 API query tool for recipes AND item names - note this is a large query, don't use this more than you have to! */
/*  Note this does not work for all output item names and ingredients; that would be too many items! */
// Function to convert an object variable into a table
function processdata (data) {
    var a = $.map(data, function(v){ return v; });
    $('#apidata').html('<pre'+'></pre'+'>');
    $('#apidata pre').text(JSON.stringify(a, null, 2)
                          .replace(new RegExp("\n(  ){4}", "g")," ")
                          .replace(new RegExp("\n(  ){3}\}", "g")," }")
                         );
    console.log('Query and formatting complete.');
}

// Fetch all the possible recipe IDs
(function fetchAPIData() {
    // $.getJSON('https://api.guildwars2.com/v2/recipes').done(function (ids) {
        var ids = [2841,2842,2843,2844,2845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2860,2861,2862,2863,2864,2865,2866,2868,2869,2870,2873,2874,2875,2877,2878,2879,2880,2881,2882,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2909,2910,2911,2912,2914,2915,2916,2917,2918,2919,2920,2922,2923,2925,2928,2929,2930,2931,2932,2933,2934,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2949,2950,2951,2952,2953,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,3269,3270,3271,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,6470,6471,6472,6473,6474,6475,6476,6477,6478,6479,6480,6481,6482,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,6565,6566,6802,6803,6804,6805,6806,6807,6808,6809,7008,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,7229,7230,7234,7842,9261,9262,9263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273,9706,9707,9708,9709,9710,9711,9712,9713,9714,9715,9716,9717,9718,9719,9720,9721,9790,9909,9949,9993,10100,10234,10481,10513,10596,10648,10704,10741,10742,10747,10909,10950,11002,11073,11093,11199,11251,11311,11359,11396,11404,11417,11426,11485,11502,11583,11585,11620,11670,11673,11747,11751,11755,11855,11856,11868,11876,11879,11881,11882,11883,11906,11928,12050,12052,12058,12059,12062,12063,12065,12068,12084,12096,12111,12140,12160,12207,12271,12289,12310,12642,12643,12644,12647,12656,12658,12661,13168,13247,13255,13256,13257,13258,13261,13262];
        console.log('Number of recipes: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/recipes?lang=en&ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var datatemp = [];
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    datatemp.push(val);
                });
            });

            // Delete the dross and acquire item ids
            var item_ids = [];
            var recipedata = $.map(datatemp, function(v){
                v.recipe_id = v.id;
                v.output_item_name = '';
                item_ids.push(v.output_item_id);

                v.ingredients = $.map(v.ingredients, function(x){
                    x.name = '';
                    item_ids.push(x.item_id);
                    return x;
                });

                delete v.id;
                delete v.type;
                delete v.min_rating;
                delete v.time_to_craft_ms;
                delete v.disciplines;
                delete v.flags;
                delete v.chat_link;

                return v;
            });

            // Fetch item names
            (function fetchItemAPIData() {
                console.log('Number of items: ' + item_ids.length);

                // Query API until all the ids have been requested
                var promises = [], maxsize = 200;
                for (var i=0; i<item_ids.length; i+=maxsize) {
                    var current_ids = item_ids.slice(i,i+maxsize).join(',');
                    var promise = $.getJSON('https://api.guildwars2.com/v2/items?lang=en&ids='+current_ids);
                    promises.push(promise);
                }

                // Wait until all the GET requests have finished
                $.when.apply($,promises).done(function() {
                    // Ensure data is an object
                    var newarguments = {};
                    if ( promises.length > 1 ) {
                        newarguments = arguments;
                    } else {
                        newarguments[0] = arguments;
                    }

                    // Concatenate data into data
                    var itemdata = {};
                    $.each(newarguments, function(index, element){
                        $.each(element[0], function(key, val){
                            itemdata[val['id']] = val.name;
                        });
                    });

                    // Insert names
                    var data = $.map(recipedata, function(v){
                        v.ingredients = $.map(v.ingredients, function(x){
                            if (x.item_id in itemdata){
                                x.name = itemdata[x.item_id];
                            }
                            return x;
                        });
                        if (v.output_item_id in itemdata){
                            v.output_item_name = itemdata[v.output_item_id];
                        }
                        return v;
                    });

                    // Write to document
                    processdata(data);
                });
            })();
        });
    //});
})();

Recipes with output item names[edit]

/* GW2 API query tool for recipes - note this is a large query, don't use this more than you have to! */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var columns = Object.keys(data[0]);
    var result = '<p>'+data.length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}


// Fetch all the possible recipe IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/recipes').done(function (ids) {
        console.log('Number of recipes: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/recipes?lang=en&ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var datatemp = [];
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    datatemp.push(val);
                });
            });

            // Delete the dross and acquire item ids
            var item_ids = [];
            var recipedata = $.map(datatemp, function(v){
                v.recipe_id = v.id;
                v.output_item_name = '';
                item_ids.push(v.output_item_id);

                delete v.ingredients;
                // v.ingredients = $.map(v.ingredients, function(x){
                //     x.name = '';
                //     item_ids.push(x.item_id);
                //     return x;
                // });

                delete v.id;
                delete v.type;
                delete v.min_rating;
                delete v.time_to_craft_ms;
                delete v.disciplines;
                delete v.flags;
                delete v.chat_link;

                return v;
            });

            // Fetch item names
            (function fetchItemAPIData() {
                console.log('Number of items: ' + item_ids.length);

                // Query API until all the ids have been requested
                var promises = [], maxsize = 200;
                for (var i=0; i<item_ids.length; i+=maxsize) {
                    var current_ids = item_ids.slice(i,i+maxsize).join(',');
                    var promise = $.getJSON('https://api.guildwars2.com/v2/items?lang=en&ids='+current_ids);
                    promises.push(promise);
                }

                // Wait until all the GET requests have finished
                $.when.apply($,promises).done(function() {
                    // Ensure data is an object
                    var newarguments = {};
                    if ( promises.length > 1 ) {
                        newarguments = arguments;
                    } else {
                        newarguments[0] = arguments;
                    }

                    // Concatenate data into data
                    var itemdata = {};
                    $.each(newarguments, function(index, element){
                        $.each(element[0], function(key, val){
                            itemdata[val['id']] = val.name;
                        });
                    });

                    // Insert names
                    var data = $.map(recipedata, function(v){
                        // v.ingredients = $.map(v.ingredients, function(x){
                        //     if (x.item_id in itemdata){
                        //         x.name = itemdata[x.item_id];
                        //     }
                        //     return x;
                        // });
                        if (v.output_item_id in itemdata){
                            v.output_item_name = itemdata[v.output_item_id];
                        }
                        return v;
                    });

                    // Write to document
                    $('#apidata').html(makeTableHTML(data));
                });
            })();
        });
    });
})();

Recipes for given recipe sheet (item) ids[edit]

/* GW2 API query tool for recipe sheet items */
// Function to convert an object variable into a table
function makeTableHTML(recipe_data, item_data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;">'
    +'<tr><th>Recipe ID</th><th>Crafted item</th><th>Ingredients</th></tr>';

    $.each(recipe_data, function(i,recipe){
      result += '<tr>'+ '<td>'+recipe.id+'</td>';
      if (recipe.output_item_id in item_data) {
        result += '<td>'+ item_data[recipe.output_item_id].name +'</td>'
      } else {
        result += '<td>(unknown item name)</td>'
      }
      var c = $.map(recipe.ingredients, function(v){
        return v.count + ' ' + (v.item_id in item_data ? item_data[v.item_id].name : '(unknown item name)' );
      });
      result += '<td>'+ c.join('<br>') +'</td>'
      result += '</tr>';
    })

    result += '</table>';
    return result;
}

// Removes duplicates, blanks and undefined, then sorts. Usage: a.unique()
Array.prototype.unique = function() {
    return this.filter(function (el, i, self) {
        return self.indexOf(el) === i;
    });
};

// Fetch all the possible itemsIDs
(function fetchAPIData() {
        // recipe_sheet_ids
        var ids = [89262,89226,89173,89165,89205,89166,89270,89147,89130,89139,89187,89250];
      
        // ITEM START
        console.log('Number of recipe sheet items: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/items?lang=en&ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // RECIPE START
            // Acquire unlocked recipe ids from items
            var recipe_ids = [];
            $.each(data, function(key, val){
                if ('details' in val && 'recipe_id' in val.details) {
                  recipe_ids.push(val.details.recipe_id);
                  if ('extra_recipe_ids' in val.details) {
                    recipe_ids.push(val.details.extra_recipe_ids);
                  }
                }
            });

            // Flatten recipe ids and remove duplicates
            recipe_ids = $.map(recipe_ids, function(v){ return v; }).unique();
            console.log('Number of recipes: ' + recipe_ids.length);

            // Query API until all the recipe_ids have been requested
            var promises2 = [];
            for (var i=0; i<recipe_ids.length; i+=maxsize) {
                var current_recipe_ids = recipe_ids.slice(i,i+maxsize).join(',');
                var promise2 = $.getJSON('https://api.guildwars2.com/v2/recipes?lang=en&ids='+current_recipe_ids);
                promises2.push(promise2);
            }

            // Wait until all the GET requests have finished
            $.when.apply($,promises2).done(function() {
                // Ensure data is an object
                var newarguments2 = {};
                if ( promises2.length > 1 ) {
                    newarguments2 = arguments;
                } else {
                    newarguments2[0] = arguments;
                }

                // Concatenate data into data
                var recipe_data = {};
                $.each(newarguments2, function(index, element){
                    $.each(element[0], function(key, val){
                        recipe_data[val['id']] = val;
                    });
                });

                // Write to console
                console.log(recipe_data);

                // Scan through recipes, dig out all item ids
                var item_ids = [];
                $.each(recipe_data, function(i,v){
                  item_ids.push(v.output_item_id);
                  $.each(v.ingredients, function(ii,vv){
                    item_ids.push(vv.item_id);
                  });
                });

                // Remove duplicates
                item_ids = item_ids.unique();

                // Get more item ids
                // Query API until all the ids have been requested
                var promises3 = [];
                for (var i=0; i<item_ids.length; i+=maxsize) {
                    var current_ids = item_ids.slice(i,i+maxsize).join(',');
                    var promise3 = $.getJSON('https://api.guildwars2.com/v2/items?lang=en&ids='+current_ids);
                    promises3.push(promise3);
                }
                // Wait until all the GET requests have finished
                $.when.apply($,promises3).done(function() {
                    // Ensure data is an object
                    var newarguments3 = {};
                    if ( promises3.length > 1 ) {
                        newarguments3 = arguments;
                    } else {
                        newarguments3[0] = arguments;
                    }
                    // Concatenate data into data
                    var item_data = {};
                    $.each(newarguments3, function(index, element){
                        $.each(element[0], function(key, val){
                            item_data[val['id']] = val;
                        });
                    });

                    // Write to console
                    console.log(item_data);

                    // Write to document
                    $('#apidata').html(makeTableHTML(recipe_data, item_data));
                });
            });
            // RECIPE END
        });
        // ITEM END
})();

Recipes for given input item ids[edit]

/* GW2 API query tool for recipes using given item ids - see line marked "inputitemids" */
// Function to convert an object variable into a table
function makeTableHTML(data, itemdata, inputitemids) {
    var result = '<table class="table mech1" style="margin-bottom:0px;">'
                  +'<tr><th>Recipe ID</th><th>Type</th><th>Disciplines</th><th>Output item ID</th>'
                  // +'<th>Input item ID 1</th><th>Input item ID 2</th><th>Input item ID 3</th><th>Input item ID 4</th>'
                  +'<th>Output item name</th>'+'<th>Output item level</th>'+'<th>Output item rarity</th>'
                  +'<th>Input item name 1</th><th>Input item name 2</th><th>Input item name 3</th><th>Input item name 4</th>'
                +'</tr>';
    $.each(data, function(index, val) {

        // Shuffle the array sequence until the input item is at the beginning
        $.each(val['ingredients'], function(i, v){
          var n = inputitemids.indexOf(v.item_id)
          if ( n > -1 ){
            val['ingredients'].splice(i,1);
            val['ingredients'].unshift(v);
          }
        });

        // Add a fourth element if necessary to maintain table width
        if (val['ingredients'].length < 4) {
          val['ingredients'].push({'item_id': -1});
        };

        // Figure out the row
        result += '<tr><td>'+val['id']+'</td><td>'+val['type']+'</td><td>'+JSON.stringify(val['disciplines'])+'</td>'+'<td>'+val['output_item_id']+'</td>'
                   //+ $.map(val['ingredients'], function(v){ return '<td>' + v.item_id + '</td>' }).join('')
                   + '<td>'+ ( itemdata.hasOwnProperty(val['output_item_id']) ? itemdata[val['output_item_id']]['name']   : '' ) +'</td>'
                   + '<td>'+ ( itemdata.hasOwnProperty(val['output_item_id']) ? itemdata[val['output_item_id']]['level']  : '' ) +'</td>'
                   + '<td>'+ ( itemdata.hasOwnProperty(val['output_item_id']) ? itemdata[val['output_item_id']]['rarity'] : '' ) +'</td>'
                   + $.map(val['ingredients'], function(v){
                       if ( itemdata.hasOwnProperty(v.item_id) ){
                         return '<td>' + itemdata[v.item_id]['name'] + '</td>'
                       } else {
                         return '<td>' + '' + '</td>'
                       }
                     }).join('')
                 +'</tr>';
    });
    result += '</table>';
    return result;
}

// Removes duplicates, blanks and undefined, then sorts. Usage: a.unique()
Array.prototype.unique = function() {
    return this.filter(function (el, i, self) {
        return self.indexOf(el) === i;
    });
};

// Fetch all the relevant recipe IDs
(function fetchAPIData() {

    // QUERY GROUP 1
    // Weapon inscriptions
    var inputitemids = [38429, 38430, 38431, 38433, 38432, 86685, 38434];

    // Make recipe enquiries
    var promises = [], maxsize = 1;
    for (var i=0; i<inputitemids.length; i+=maxsize) {
        var current_ids = inputitemids.slice(i,i+maxsize).join(',');
        var promise = $.getJSON('https://api.guildwars2.com/v2/recipes/search?input='+current_ids);
        promises.push(promise);
    }

    $.when.apply($,promises).done(function() {
        // Ensure data is an object
        var newarguments = {};
        if ( promises.length > 1 ) {
            newarguments = arguments;
        } else {
            newarguments[0] = arguments;
        }

        // Concatenate data into data
        var recipeids = [];
        $.each(newarguments, function(index, element){
            $.each(element[0], function(key, val){
                recipeids.push(val);
            });
        });

        // QUERY GROUP 2
        console.log('Number of recipes: ' + recipeids.length);

        // Query API until all the ids have been requested
        var promises2 = [], maxsize = 200;
        for (var i=0; i<recipeids.length; i+=maxsize) {
            var current_ids = recipeids.slice(i,i+maxsize).join(',');
            var promise2 = $.getJSON('https://api.guildwars2.com/v2/recipes?lang=en&ids='+current_ids);
            promises2.push(promise2);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises2).done(function() {
            // Ensure data is an object
            var newarguments2 = {};
            if ( promises2.length > 1 ) {
                newarguments2 = arguments;
            } else {
                newarguments2[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments2, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Now collate item ids so we can look their details up.
            var itemids = [];
            $.each(data, function(index, val) {
                itemids.push(val['output_item_id']);
                $.each(val['ingredients'], function(i,v){
                  itemids.push(v.item_id);
                });
            });

            // Remove duplicates (e.g. axe hafts)
            itemids.unique();

            // QUERY GROUP 3
            console.log('Number of items: ' + itemids.length);

            // Query API until all the ids have been requested
            var promises3 = [], maxsize = 200;
            for (var i=0; i<itemids.length; i+=maxsize) {
                var current_ids = itemids.slice(i,i+maxsize).join(',');
                var promise3 = $.getJSON('https://api.guildwars2.com/v2/items?lang=en&ids='+current_ids);
                promises3.push(promise3);
            }

            // Wait until all the GET requests have finished
            $.when.apply($,promises3).done(function() {
                // Ensure data is an object
                var newarguments3 = {};
                if ( promises3.length > 1 ) {
                    newarguments3 = arguments;
                } else {
                    newarguments3[0] = arguments;
                }

                // Concatenate data into data
                var itemdata = {};
                $.each(newarguments3, function(index, element){
                    $.each(element[0], function(key, val){
                        itemdata[val['id']] = val;
                    });
                });

                // Write to document
                $('#apidata').html(makeTableHTML(data, itemdata, inputitemids));
            });
        });
    });
})();

Skins[edit]

/* GW2 API query tool for skins - another long and cruel query for the api */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var firstindex = Object.keys(data)[0];
    var columns = Object.keys(data[firstindex]);
    var result = '<p>'+Object.keys(data).length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible skin IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/skins').done(function (ids) {
        console.log('Number of skins: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/skins?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Skins with dyes[edit]

/* GW2 API query tool for skins with dyes - another long and cruel query for the api */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var ids = Object.keys(data);
    var columns = Object.keys(data[ids[0]]);
    var result = '<p>'+ids.length+' skin results with dye information returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
            result += '<td>' + v[vv] + '</td>';
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Process the garbage dye data
function postProcess(data) {
    var override_titles_races = {
        "AsuraFemale": "Asura",
        "AsuraMale": "Asura",
        "CharrFemale": "Charr",
        "CharrMale": "Charr",
        "HumanFemale": "Human",
        "HumanMale": "Human",
        "NornFemale": "Norn",
        "NornMale": "Norn",
        "SylvariFemale": "Sylvari",
        "SylvariMale": "Sylvari"
    };
    var override_titles = Object.keys(override_titles_races);
    
    var print_titles_races = {
        "AsuraFemale": "Asura female",
        "AsuraMale": "Asura male",
        "CharrFemale": "Charr female",
        "CharrMale": "Charr male",
        "HumanFemale": "Human female",
        "HumanMale": "Human male",
        "NornFemale": "Norn female",
        "NornMale": "Norn male",
        "SylvariFemale": "Sylvari female",
        "SylvariMale": "Sylvari male"
    };
    
    // Pass #1
    $.each(data, function(k,v) {
        if (!('details' in v && 'dye_slots' in v.details)) {
            // Discard all skins except those with dyes
            delete data[k];
        } else {
            // Restrictions always exists but might be an empty array. Flatten it.
            data[k].restrictions = data[k].restrictions.join('');
            
            // Check if restrictions exist, delete non-matching overrides.
            if (v.restrictions != '' && 'overrides' in v.details.dye_slots) {
                $.each(v.details.dye_slots.overrides, function(kk,vv){
                    // Check if the race of the override is not equal to the restriction
                    if ( override_titles_races[kk] != data[k].restrictions ) {
                        delete data[k].details.dye_slots.overrides[kk]
                    }
                });
            }
            
            // Sometimes there is a null position in the default array or overrides object array in the wrong position.
            // Sorting puts empty/null elements to the end.
            //  example - skin id 691 (Nightmare Court Leggings).
            data[k].details.dye_slots.default = data[k].details.dye_slots.default.sort().removeNulls();
            $.each(data[k].details.dye_slots.overrides, function(kk,vv) {
                data[k].details.dye_slots.overrides[kk] = vv.sort().removeNulls();
            });
            
            // Delete junk
            delete data[k].description;
            delete data[k].type;
            delete data[k].flags;
            delete data[k].rarity;
            delete data[k].icon;
            delete data[k].details.type;
            delete data[k].details.weight_class;
        }
    });
    
    // Pass #2
    // If overrides exist, and the slot count/materials/dye ids are ALL the same as the default, delete the override data.
    //  example - skin id 691 (Nightmare Court Leggings).
    var t0, t1;
    $.each(data, function(k,v) {
        t0 = JSON.stringify(v.details.dye_slots.default);
        $.each(v.details.dye_slots.overrides, function(kk,vv) {
            t1 = JSON.stringify(vv);
            if (t0 == t1) {
                delete data[k].details.dye_slots.overrides[kk];
                // console.log('deleted copy of default on skin #' + k + ', for override ' + kk + '.');
            }
        });
    });
    
    // Pass #3
    // Check if restriction is set AND there are exactly two remaining overrides, in which case delete the default as it is not used.
    var keynames;
    $.each(data, function(k,v) {
        keynames = Object.keys(v.details.dye_slots.overrides);
        if (v.restrictions != '' && keynames.length == 2) {
            data[k].details.dye_slots.default = [];
            // console.log('erased pointless default on skin #' + k + ', with restriction ' + v.restrictions + '.');
            
            // Now check if the remaining two overrides are identical too. If so, delete the overrides and reset the default.
            t0 = JSON.stringify(v.details.dye_slots.overrides[keynames[0]]);
            t1 = JSON.stringify(v.details.dye_slots.overrides[keynames[1]]);
            if (t0 == t1) {
                // Requires shallow copy or the id will be updated when the next loop hits.
                data[k].details.dye_slots.default = shallowCopy(v.details.dye_slots.overrides[keynames[0]]);
                data[k].details.dye_slots.overrides = {};
                // console.log('remapped default on skin #' + k + ', from restriction ' + v.restrictions + '.');
            }
        }
    });
    
    // Pass #4
    // Identify longest array element within each skin (to use the colours from it)
    var lengthdefault, lengthmax, keythis;
    $.each(data, function(k,v) {
        lengthdefault = v.details.dye_slots.default.length;
        lengthmax = 0;
        keythis = 'default';
        $.each(v.details.dye_slots.overrides, function(kk,vv){
            if (vv.length > lengthdefault && vv.length > lengthmax) {
                lengthmax = vv.length;
                keythis = kk;
            }
        });
        if (keythis != 'default') {
            data[k].colors = shallowCopy( v.details.dye_slots.overrides[keythis] );
            // console.log('override on skin #' + k + ' had a longer length ' + lengthmax + ' with key ' + keythis + ' than the default.');
        } else {
            data[k].colors = shallowCopy( v.details.dye_slots.default );
        }
    });
   
    // Build output
    var outputobj = {}, channels = [], default_channel_count;
    $.each(data, function(k,v) {
        channels = [];
        default_channel_count = 0;
        
        if (v.details.dye_slots.default.length > 0) {
            default_channel_count = v.details.dye_slots.default.length;
            channels.push(v.details.dye_slots.default.length)
        }
        $.each(v.details.dye_slots.overrides, function(kk,vv){
            // this needs checking because sometimes the dyes/dye orders or the materials only are different by race but the count is the same.
            //  example skin id #618 (Ascalonian Sentry Boots)
            if (vv.length !== default_channel_count) {
                channels.push(print_titles_races[kk] + ': ' + vv.length);
            } else {
                console.log('caught skin #' + k + ' with key ' + kk + ' of length ' + vv.length + ' which is the same as default ' + default_channel_count);
            }
        });
        
        outputobj[k] = {
            id: v.id,
            name: v.name,
            channels: channels.join(', '),
            colors: $.map(v.colors, function(v) {
                return dye_names[v.color_id]
            }).join(', ')
        }
        
        // Finally check for no data - e.g. skin #330 (Archon Shoulders charr armor after removing sylvari dyes)
        if (outputobj[k].channels == '') {
            outputobj[k].channels = '0';
            outputobj[k].colors = 'none';
        }
    });
    
    // var result = JSON.stringify(data, null, 2);
    // var result = JSON.stringify(outputobj, null, 2);
    // return result;
    
    return outputobj;
}

// Fetch all the possible skin IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/skins').done(function (ids) {
        // console.log('Number of skins: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/skins?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            // console.log(data);

            // Write to document
            $('#apidata').html( makeTableHTML(postProcess(data)) );
        });
    });
})();

function shallowCopy(object) {
    return JSON.parse(JSON.stringify(object));
}

// Remove any null elements from an array. Usage a.removeNulls();
Array.prototype.removeNulls = function() {
    return this.filter(function (el) {
        return el != null;
    });
};

//----- if this wasn't hardcoded, I would need to do SMW to obtain all the item page names, but even then I would be missing Dye Remover -------

var dye_names = {
  "1": "Dye Remover",
  "2": "Black Dye",
  "3": "Chalk Dye",
  "4": "Gray Dye",
  "5": "Pitch Dye",
  "6": "Celestial Dye",
  "7": "Ocean Dye",
  "8": "Robin Dye",
  "9": "Blue Rose Dye",
  "10": "Sky Dye",
  "11": "Starry Night Dye",
  "12": "Adobe Dye",
  "13": "Calfskin Dye",
  "14": "Camel Dye",
  "15": "Charcoal Dye",
  "16": "Chocolate Dye",
  "17": "Pottery Dye",
  "18": "Earthen Dye",
  "19": "Ebony Dye",
  "20": "Ivory Dye",
  "21": "Mahogany Dye",
  "22": "Natural Dye",
  "23": "Rawhide Dye",
  "24": "Terracotta Dye",
  "25": "Walnut Dye",
  "26": "Wheat Dye",
  "27": "Blueberry Dye",
  "28": "Breeze Dye",
  "29": "Sapphire Dye",
  "30": "Royal Blue Dye",
  "31": "Summer Sky Dye",
  "32": "Blush Dye",
  "33": "Bold Dye",
  "34": "Dusky Dye",
  "35": "Peach Dye",
  "36": "Peach Sunset Dye",
  "37": "Autumn Sky Dye",
  "38": "Country Blue Dye",
  "39": "Country Teal Dye",
  "40": "Dusty Grape Dye",
  "41": "Eucalyptus Dye",
  "42": "Frosted Sea Dye",
  "43": "Old Jeans Dye",
  "44": "Shy Blue Dye",
  "45": "Tea Jeans Dye",
  "46": "Denim Dye",
  "47": "Grape Dye",
  "48": "Grape Gum Dye",
  "49": "Morning Glory Dye",
  "50": "Plum Dye",
  "51": "Wine Dye",
  "52": "Avocado Dye",
  "53": "Ceylon Dye",
  "54": "Chartreuse Dye",
  "55": "Crisp Mint Dye",
  "56": "Emerald Dye",
  "57": "Kelly Dye",
  "58": "Key Lime Dye",
  "59": "Leprechaun Dye",
  "60": "Spearmint Dye",
  "61": "Summer Grass Dye",
  "62": "Antique Bronze Dye",
  "63": "Antique Olive Dye",
  "64": "Brass Dye",
  "65": "Bronze Dye",
  "66": "Copper Dye",
  "67": "Gold Dye",
  "68": "Gunmetal Dye",
  "69": "Iron Dye",
  "70": "Mithril Dye",
  "71": "Oxblood Dye",
  "72": "Pewter Dye",
  "73": "Rust Dye",
  "74": "Silver Dye",
  "75": "Steel Dye",
  "76": "Midnight Blue Dye",
  "77": "Midnight Sky Dye",
  "78": "Midnight Fuchsia Dye",
  "79": "Midnight Gold Dye",
  "80": "Midnight Green Dye",
  "81": "Midnight Olive Dye",
  "82": "Midnight Purple Dye",
  "83": "Midnight Red Dye",
  "84": "Midnight Rose Dye",
  "85": "Midnight Rust Dye",
  "86": "Midnight Teal Dye",
  "87": "Midnight Violet Dye",
  "88": "Midnight Yew Dye",
  "89": "Chalkboard Dye",
  "90": "Cream Dye",
  "91": "Cream Shade Dye",
  "92": "Dusk Dye",
  "93": "Frost Dye",
  "94": "Frosting Dye",
  "96": "Riverbed Dye",
  "97": "Sage Dye",
  "98": "Shy Violet Dye",
  "99": "Silt Dye",
  "100": "Silver Lead Dye",
  "101": "Stone Dye",
  "102": "Strawberry Cream Dye",
  "103": "Truffle Dye",
  "104": "Olive Dye",
  "105": "Grape Leaf Dye",
  "106": "Olive Oil Dye",
  "107": "Pine Dye",
  "108": "Olive Yew Dye",
  "109": "Apricot Dye",
  "110": "Cinnamon Dye",
  "111": "Creamsicle Dye",
  "112": "Orange Dye",
  "113": "Sunset Dye",
  "114": "Grapevine Dye",
  "115": "Indigo Dye",
  "116": "Iris Blush Dye",
  "117": "Orchid Dye",
  "118": "Thistle Dye",
  "119": "Burgundy Dye",
  "120": "Coral Dye",
  "121": "Pink Dye",
  "122": "Ruby Dye",
  "123": "Scarlet Dye",
  "124": "Cotton Candy Dye",
  "125": "Fuchsia Dye",
  "126": "Hot Pink Dye",
  "127": "Lipstick Dye",
  "128": "Maroon Dye",
  "129": "Green Apple Dye",
  "130": "Evergreen Dye",
  "131": "Jalapeno Dye",
  "132": "Lime Dye",
  "133": "Sprout Dye",
  "134": "Seafoam Dye",
  "135": "Sea Green Dye",
  "136": "Spruce Dye",
  "137": "Turquoise Dye",
  "138": "Wintergreen Dye",
  "139": "Violet Dye",
  "140": "Iris Dye",
  "141": "Lilac Dye",
  "142": "Periwinkle Dye",
  "143": "Royal Purple Dye",
  "144": "Butterscotch Dye",
  "145": "Caramel Dye",
  "146": "Harvest Gold Dye",
  "147": "Lemon Dye",
  "148": "Lemonade Dye",
  "314": "Tungsten Dye",
  "315": "White Gold Dye",
  "332": "Shy Peach Dye",
  "333": "Sand Dye",
  "334": "Tang Dye",
  "335": "Pale Dye",
  "336": "Refresh Dye",
  "337": "Far Mountain Dye",
  "338": "Clove Dye",
  "339": "Wasabi Dye",
  "340": "Khaki Dye",
  "341": "Patina Dye",
  "342": "Tarnish Dye",
  "343": "Flush Dye",
  "344": "Orange Frost Dye",
  "345": "Lemon Zest Dye",
  "346": "Quickstalk Dye",
  "347": "Spring Dye",
  "348": "Wintermint Dye",
  "349": "Dapple Dye",
  "350": "Dewdrop Dye",
  "351": "Scenic Dye",
  "352": "Demure Dye",
  "353": "Hint Dye",
  "354": "Pink Tint Dye",
  "355": "Olive Tint Dye",
  "356": "Blue Tint Dye",
  "357": "Rose Tint Dye",
  "358": "Tea Shade Dye",
  "359": "Celery Dye",
  "360": "Mist Dye",
  "361": "Night Air Dye",
  "362": "Winter Sky Dye",
  "363": "Hush Dye",
  "364": "Taro Dye",
  "365": "Crush Dye",
  "366": "Squash Dye",
  "367": "Fern Dye",
  "368": "Warmth Dye",
  "369": "Peanut Butter Dye",
  "370": "Envy Dye",
  "371": "Grapesicle Dye",
  "372": "Night Iris Dye",
  "373": "Malt Dye",
  "374": "Cantaloupe Dye",
  "375": "Sherbert Dye",
  "376": "Salmon Dye",
  "377": "Autumn Dye",
  "378": "Brick Dye",
  "379": "Butter Dye",
  "380": "Honey Dye",
  "381": "Tangerine Dye",
  "382": "Amber Dye",
  "383": "Mohair Dye",
  "384": "Mocha Dye",
  "385": "Burnished Steel Dye",
  "434": "Pumpkin Dye",
  "435": "Dijon Dye",
  "436": "Remembrance Dye",
  "437": "Pumpkin Pie Dye",
  "438": "Moss Dye",
  "439": "Shy Iris Dye",
  "440": "Evening Dye",
  "441": "Brandywine Dye",
  "442": "Matte Dye",
  "443": "White Dye",
  "444": "Olive Silk Dye",
  "445": "Mint Frost Dye",
  "446": "Whisper Dye",
  "447": "Peach Tint Dye",
  "448": "Green Tint Dye",
  "449": "Violet Tint Dye",
  "450": "Mushroom Dye",
  "451": "Blue Shade Dye",
  "452": "Cashmere Dye",
  "453": "Taupe Dye",
  "454": "Tarnished Steel Dye",
  "455": "Oil Slick Dye",
  "456": "Cocoa Dye",
  "457": "Clay Dye",
  "458": "Night Shade Dye",
  "459": "Orange Shade Dye",
  "460": "Purple Tint Dye",
  "461": "Aqua Tint Dye",
  "462": "Lemon Tint Dye",
  "463": "Rose Shade Dye",
  "464": "Grape Shade Dye",
  "465": "Shale Dye",
  "466": "Old Penny Dye",
  "467": "Mudmetal Dye",
  "468": "Copper Pot Dye",
  "469": "Swamp Grass Dye",
  "470": "Marine Dye",
  "471": "Wine Shade Dye",
  "472": "Lemon Shade Dye",
  "473": "Abyss Dye",
  "474": "Ash Dye",
  "475": "Dust Dye",
  "476": "Graphite Dye",
  "477": "Icing Dye",
  "478": "Beige Dye",
  "479": "Latte Dye",
  "480": "Antique Gold Dye",
  "481": "Copper Penny Dye",
  "482": "Midnight Fire Dye",
  "483": "Midnight Ice Dye",
  "484": "Green Shade Dye",
  "485": "Olive Shade Dye",
  "582": "Adobe Sunset Dye",
  "583": "Afternoon Dye",
  "584": "Ancient Silver Dye",
  "585": "Banana Dye",
  "586": "Black Cherry Dye",
  "587": "Blue Ice Dye",
  "588": "Blue Sky Dye",
  "589": "Blurple Dye",
  "590": "Brook Dye",
  "591": "Buttercream Dye",
  "592": "Cherry Dye",
  "593": "Chestnut Dye",
  "594": "Citrus Dye",
  "595": "Citrus Breeze Dye",
  "596": "Citrus Ice Dye",
  "597": "Cobalt Dye",
  "598": "Cornsilk Dye",
  "599": "Cucumber Dye",
  "600": "Daffodil Dye",
  "601": "Dark Chocolate Dye",
  "602": "Dark Olive Dye",
  "603": "Deep Lilac Dye",
  "604": "Deep Maple Dye",
  "605": "Deep Pine Dye",
  "606": "Deep Teal Dye",
  "607": "Evening Grass Dye",
  "608": "Evening Red Dye",
  "609": "Evening Wine Dye",
  "610": "Fluff Dye",
  "611": "Fog Dye",
  "612": "Fresh Green Dye",
  "613": "Freshen Dye",
  "614": "Frost Breeze Dye",
  "615": "Glory Dye",
  "616": "Grapefruit Dye",
  "617": "Green Dye",
  "618": "Hazel Dye",
  "619": "Heather Dye",
  "620": "Heliotrope Dye",
  "621": "Honey Ice Dye",
  "622": "Honeybutter Dye",
  "623": "Honeysuckle Dye",
  "624": "Humiliation Dye",
  "625": "Hydrangea Dye",
  "626": "Lavender Dye",
  "627": "Lead Dye",
  "628": "Lemon Ice Dye",
  "629": "Lifesblood Dye",
  "630": "Lime Breeze Dye",
  "631": "Lime Ice Dye",
  "632": "Limette Dye",
  "633": "Melon Dye",
  "634": "Midday Dye",
  "635": "Mint Dye",
  "636": "Mint Breeze Dye",
  "637": "Mint Ice Dye",
  "638": "Mintay Dye",
  "639": "Morning Sea Dye",
  "640": "Mountain Sky Dye",
  "641": "Mullberry Dye",
  "642": "Nectar Dye",
  "643": "Nickel Dye",
  "644": "Nightsong Dye",
  "645": "Old Nickel Dye",
  "646": "Olive Ice Dye",
  "647": "Orange Spring Dye",
  "648": "Papaya Dye",
  "649": "Pastel Blue Dye",
  "650": "Pastel Citrus Dye",
  "651": "Pastel Honey Dye",
  "652": "Pastel Lemon Dye",
  "653": "Pastel Lime Dye",
  "654": "Pastel Mint Dye",
  "655": "Pastel Olive Dye",
  "656": "Pastel Peach Dye",
  "657": "Pastel Pink Dye",
  "658": "Pastel Purple Dye",
  "659": "Pastel Rose Dye",
  "660": "Pastel Sea Dye",
  "661": "Pastel Spring Dye",
  "662": "Pastel Violet Dye",
  "663": "Pastel Wine Dye",
  "664": "Pastel Winter Dye",
  "665": "Peach Ice Dye",
  "666": "Persephone Dye",
  "667": "Phlox Dye",
  "668": "Pink Ice Dye",
  "669": "Primrose Dye",
  "670": "Purple Dye",
  "671": "Purple Breeze Dye",
  "672": "Purple Ice Dye",
  "673": "Red Dye",
  "674": "Regal Dye",
  "675": "Rich Grape Dye",
  "676": "River Dye",
  "677": "Root Dye",
  "678": "Rose Breeze Dye",
  "679": "Rose Ice Dye",
  "680": "Royal Rose Dye",
  "681": "Sea Breeze Dye",
  "682": "Sea Frost Dye",
  "683": "Sea Ice Dye",
  "684": "Shy Lilac Dye",
  "685": "Shylac Dye",
  "686": "Sienna Dye",
  "687": "Sour Dye",
  "688": "Sour Apple Dye",
  "689": "Sprig Dye",
  "690": "Spring Breeze Dye",
  "691": "Spring Dew Dye",
  "692": "Spring Grass Dye",
  "693": "Spring Ice Dye",
  "694": "Spring Leaf Dye",
  "695": "Spring Moss Dye",
  "696": "Spring Tide Dye",
  "697": "Stem Dye",
  "698": "Strawberry Dye",
  "699": "Strawberry Breeze Dye",
  "700": "Stream Dye",
  "701": "Summer Thistle Dye",
  "702": "Sunrise Breeze Dye",
  "703": "Tarnished Silver Dye",
  "704": "Teal Dye",
  "705": "Umber Dye",
  "706": "Veronica Dye",
  "707": "Violet Breeze Dye",
  "708": "Violet Ice Dye",
  "709": "Viridian Dye",
  "710": "Wine Breeze Dye",
  "711": "Wine Ice Dye",
  "712": "Winter Breeze Dye",
  "713": "Winter Frost Dye",
  "714": "Winter Ice Dye",
  "715": "Zest Dye",
  "1053": "Tulip Dye",
  "1054": "Grass Dye",
  "1149": "Lava Dye",
  "1150": "Wrath Dye",
  "1151": "Spitfire Dye",
  "1152": "Heirloom Dye",
  "1153": "Blood Dye",
  "1154": "Redemption Dye",
  "1155": "Illumination Dye",
  "1156": "Spite Dye",
  "1157": "Forgiveness Dye",
  "1158": "Sincerity Dye",
  "1159": "Pride Dye",
  "1160": "Arrogance Dye",
  "1161": "Mischief Dye",
  "1231": "Glacial Teal Dye",
  "1232": "Glacial Sky Dye",
  "1233": "Shiver Sky Dye",
  "1234": "Shiver Sea Dye",
  "1235": "Deep Glacial Teal Dye",
  "1236": "Deep Glacial Sky Dye",
  "1237": "Pyre Dye",
  "1238": "Flare Dye",
  "1239": "Molten Dye",
  "1240": "Flame Dye",
  "1241": "Charred Dye",
  "1242": "Cinders Dye",
  "1243": "Caustic Dye",
  "1244": "Acrid Dye",
  "1245": "Acid Dye",
  "1246": "Toxin Dye",
  "1247": "Swampblack Dye",
  "1248": "Algae Dye",
  "1249": "Cobolt Dye",
  "1250": "Violite Dye",
  "1251": "Limonite Dye",
  "1252": "Cyanide Dye",
  "1253": "Vincent Dye",
  "1254": "Blacklight Dye",
  "1265": "Fling Dye",
  "1266": "Prosperity Dye",
  "1267": "Perseverance Dye",
  "1268": "Onset Dye",
  "1269": "Amenity Dye",
  "1270": "Recall Dye",
  "1271": "Enameled Legacy Dye",
  "1272": "Enameled Jungle Dye",
  "1273": "Enameled Sky Dye",
  "1274": "Enameled Reign Dye",
  "1275": "Enameled Emblaze Dye",
  "1276": "Enameled Crimson Dye",
  "1277": "Enameled Perseverance Dye",
  "1278": "Enameled Longevity Dye",
  "1279": "Enameled Solitude Dye",
  "1280": "Enameled Sacrifice Dye",
  "1281": "Enameled Generation Dye",
  "1282": "Enameled Anamnesis Dye",
  "1301": "Electro Lime Dye",
  "1302": "Electro Peach Dye",
  "1303": "Electro Lemon Dye",
  "1304": "Electro Pink Dye",
  "1305": "Electro Blue Dye",
  "1306": "Electro Purple Dye",
  "1307": "Glint's Crystal Dye",
  "1308": "Glint's Sanctuary Dye",
  "1309": "Glint's Purview Dye",
  "1310": "Glint's Rebellion Dye",
  "1311": "Glint's Ambition Dye",
  "1312": "Glint's Isolation Dye",
  "1333": "Aureus Dye",
  "1334": "Crimson Lion Dye",
  "1335": "Rosewood Dye",
  "1336": "Imperial Red Dye",
  "1337": "Imperial Gold Dye",
  "1338": "Golden Lion Dye",
  "1348": "Shadow Yellow Dye",
  "1349": "Shadow Red Dye",
  "1350": "Shadow Orange Dye",
  "1351": "Shadow Violet Dye",
  "1352": "Shadow Purple Dye",
  "1353": "Shadow Magenta Dye",
  "1354": "Shadow Abyss Dye",
  "1355": "Shadow Green Dye",
  "1356": "Shadow Turquoise Dye",
  "1357": "Shadow Blue Dye",
  "1358": "Enameled Amenity Dye",
  "1359": "Enameled Morning Glory Dye",
  "1360": "Enameled Onset Dye",
  "1361": "Enameled Banana Dye",
  "1362": "Enameled Brass Dye",
  "1363": "Enameled Strawberry Dye",
  "1364": "Murky Gray Dye",
  "1365": "Matriarch Brass Dye",
  "1366": "Vintage Silver Dye",
  "1367": "Dry Silver Dye",
  "1368": "Gold Fusion Dye",
  "1369": "Golden Sheen Dye",
  "1370": "Ominous Yellow Dye",
  "1371": "Harrowing Maroon Dye",
  "1372": "Eerie Purple Dye",
  "1373": "Carnage Orange Dye",
  "1374": "Crushed Bone Dye",
  "1375": "Ember Red Dye",
  "1376": "Zaffre Dye",
  "1377": "Valor Dye",
  "1378": "Lapis Dye",
  "1379": "Phthalo Blue Dye",
  "1380": "Baby Blue Dye",
  "1381": "Resolution Dye",
  "1382": "Ghost Dye",
  "1383": "Blue Steel Dye",
  "1384": "Powder Blue Dye",
  "1453": "Bloodstone Coral",
  "1454": "Bloodstone Dark Indigo",
  "1455": "Bloodstone Dark Violet",
  "1456": "Bloodstone Dark Coral",
  "1457": "Bloodstone Violet",
  "1458": "Bloodstone Indigo",
  "1477": "Pumpkin Orange Dye",
  "1478": "Midnight Bronze Dye",
  "1481": "Daybreak Dye",
  "1485": "Silver Satin Dye",
  "1486": "Aqua Satin Dye",
  "1489": "Glossy Black Dye",
  "1490": "Magenta Dye",
  "1493": "Blue Orchid Dye",
  "1495": "Slime Green Dye",
  "1497": "Ruby Red Dye",
  "1498": "Blue Whale Dye",
  "1499": "Rose Gold Dye",
  "1537": "Destroyer Orange Dye",
  "1538": "Sunfire Lava Dye",
  "1539": "Incandescent Dye",
  "1540": "Magma Dye",
  "1541": "Scorched Dye",
  "1542": "Bloody Red Dye",
  "1549": "Eternal Ice Dye",
  "1550": "Core Ice Dye",
  "1551": "Frostbite Blue Dye",
  "1552": "Frostbite Green Dye",
  "1553": "Permafrost Dye",
  "1554": "Frozen Scales Dye",
  "1573": "Mesa Dye",
  "1574": "Highland Dye",
  "1575": "Sulfur Dye",
  "1576": "Ruin Dye",
  "1577": "Oasis Dye",
  "1578": "Jacaranda Dye",
  "1579": "Sandstorm Dye",
  "1580": "Abyssal Sea Dye",
  "1581": "Risen Dye",
  "1582": "Grave Dye",
  "1583": "Decay Dye",
  "1584": "Worn Bone Dye",
  "1585": "Darkness Dye",
  "1592": "Choya Dye",
  "1593": "Desert Harpy Dye",
  "1594": "Hydra Dye",
  "1595": "Sand Shark Dye",
  "1596": "Iboga Dye",
  "1597": "Vabbian Bronze Dye",
  "1598": "Embalm Dye",
  "1599": "Tar Dye",
  "1600": "Sarcophagus Dye",
  "1601": "Scourge Dye",
  "1602": "Urn Dye",
  "1617": "Jungle Dye",
  "1618": "Auric Dye",
  "1619": "Bloom Dye",
  "1620": "Arid Dye",
  "1621": "Nightmare Dye",
  "1622": "Abyssal Forest Dye",
  "1623": "Fear Dye",
  "1624": "Shattered Dye",
  "1625": "Crystal Dye",
  "1627": "Branded Dye",
  "1628": "Brandstorm Dye",
  "1629": "Arcane Dye",
  "1633": "Cerulean Night Dye",
  "1634": "Dawn Dye",
  "1635": "Radiant Brass Dye",
  "1636": "Celestial Blue Dye",
  "1637": "Cerulean Sky Dye",
  "1638": "Radiant Gold Dye",
  "1639": "Searing Dye",
  "1640": "Gladium Dye",
  "1641": "Godless Dye",
  "1642": "Legionnaire Dye",
  "1643": "Tribune Dye",
  "1644": "Warband Dye",
  "1645": "Exodus Dye",
  "1646": "Hunt Dye",
  "1647": "Spirits Dye",
  "1648": "Alemoot Dye",
  "1649": "Havroun Dye",
  "1650": "Legend Dye",
  "1651": "Vista Dye",
  "1652": "Alpine Dye",
  "1653": "Blue Lion Dye",
  "1654": "Kyanite Dye",
  "1655": "Underworld Dye",
  "1656": "Growth Dye",
  "1657": "Green Lion Dye",
  "1658": "Canopy Dye",
  "1659": "Red Lion Dye",
  "1660": "Infernal Dye",
  "1661": "Garnet Dye",
  "1662": "Watermelon Dye",
  "1663": "Straw Dye",
  "1664": "Yellow Lion Dye",
  "1665": "Seraphim Dye",
  "1666": "Pineapple Dye",
  "1667": "Foretold Dye",
  "1668": "Vision Dye",
  "1669": "Quartz Dye",
  "1670": "Scion Dye",
  "1671": "Guiding Star Dye",
  "1672": "Prismatic Dye"
};

Skill challenges[edit]

/* GW2 API query tool for skill challenges - another long and cruel query for the api */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1"><tr><th>SC Coords</th><th>SC ID</th><th>Map ID</th><th>Map Name</th><th>Region ID</th><th>Region Name</th></tr>';
    $.each(data, function(index, val) {
        result += '<tr>'
                     + '<td>'+JSON.stringify(val['coords'])+'</td>'
                     + '<td>'+val['skill_challenge_id']+'</td>'
                     + '<td>'+val['map_id']+'</td><td>'+val['map_name']+'</td>'
                     + '<td>'+val['region_id']+'</td><td>'+val['region_name']+'</td>'
                 +'</tr>';
    });
    result += '</table>';
    return result;
}

var tabledata = [];
$.getJSON('https://api.guildwars2.com/v2/continents/2/floors?ids=all').done(function(data){
  console.log('done fetching.');
  //console.log(data);
  $.each(data, function(i,v){
    $.each(v['regions'], function(regionindex,regionvalue){
      //console.log('scanning region '+regionindex);
      $.each(regionvalue['maps'], function (mapindex, mapvalue){
        //console.log('scanning map '+mapindex);
        $.each(mapvalue['skill_challenges'], function (scindex, scvalue){
          var entry = { "skill_challenge_id": scvalue.id, "coords": scvalue.coord, "map_id": mapindex, "map_name": mapvalue.name, "region_id": regionindex, "region_name": regionvalue.name };
          tabledata.push(entry);
        });
      });
    });
  });
  console.log(tabledata);
  $('#apidata').html(makeTableHTML(tabledata));
});

Skills[edit]

/* GW2 API query tool for skills */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th><th>Spec</th></tr>';
    $.each(data, function(index, val) {
        var id = val['id'];
        var name = val['name'];
        var spec = val['specialization'] || '';
        result += '<tr><td>'+id+'</td><td>'+name+'</td><td>'+spec+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible skill IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/skills').done(function (ids) {

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/skills?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Skill palette ids[edit]

// Function to convert an object variable into a table
function makeTableHTML(data) {
    var columns = Object.keys(data[0]);
    var result = '<p>'+data.length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
            result += '<td>' + v[vv] + '</td>';
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Removes duplicates, blanks and undefined, then sorts. Usage: a.unique()
Array.prototype.unique = function() {
    return this.filter(function (el, i, self) {
        return self.indexOf(el) === i;
    });
};

// Fetch all the possible skill IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/professions?ids=all' + '&v=latest')
    .done(function(pdata){
        var ids = $.map(pdata, function(v){
            return $.map(v.skills_by_palette, function(vv) {
                return vv[1];
            });
        });
        
        var promise, promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            promise = $.getJSON('https://api.guildwars2.com/v2/skills?ids=' + ids.slice(i,i+maxsize).join(',') + '&v=latest');
            promises.push(promise);
        }
        
        // Wait until all the GET requests have finished
        $.when.apply($, promises).done(function() {
            var newarguments = {}; if ( promises.length > 1 ) { newarguments = arguments; } else { newarguments[0] = arguments; }

            var data = {};
            $.each(newarguments, function(i, e){
                $.each(e[0], function(k, v){
                    data[v.id] = v;
                });
            });

            // Write to console
            console.log(data, pdata);
            
            // Putting it all together
            var tabledata_obj = {};
            $.map(pdata, function(v){
                $.map(v.skills_by_palette, function(vv) {
                
                    // Check if type is Elite, Utility, or Heal.
                    // Note this gets rid of rogue Weapon, Pet, Monster, Toolbelt, Bundle and Profession skills - they might have palette ids but these are not needed for decoding build templates.
                    if (['Elite', 'Utility', 'Heal'].indexOf(data[vv[1]].type) !== -1) {
                        if (!(vv[1] in tabledata_obj)) {
                            tabledata_obj[vv[1]] = {
                                profession: [],
                                palette_id: vv[0],
                                skill_id: vv[1],
                                skill_name: data[vv[1]].name,
                                skill_type: data[vv[1]].type
                            };
                        }
                        tabledata_obj[vv[1]].profession.push(v.name)
                    }
                });
            });
            
            var tabledata = $.map(tabledata_obj, function(v){
                return {
                    profession: (v.profession.unique().length > 1 ? "Any" : v.profession.unique().join(',') ),
                    palette_id: v.palette_id,
                    skill_id: v.skill_id,
                    skill_name: v.skill_name,
                    skill_type: v.skill_type
                }
            });
            
            tabledata = tabledata.sort(function(a,b){
                return a.profession.localeCompare(b.profession) || a.skill_type.localeCompare(b.skill_type) || a.palette_id - b.palette_id;
            });

            // Write to console
            console.log(tabledata);

            // Write to document
            $('#apidata').html(makeTableHTML(tabledata));
        });
        
    })
    .fail( function(d, textStatus, error) {
        console.error("Professions API getJSON failed (request #1), status: " + textStatus + ", error: "+error);
    });
})();

Specializations[edit]

/* GW2 API query tool for skins - another long and cruel query for the api */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>Spec ID</th><th>Name</th></tr>';
    $.each(data, function(index, val) {
        result += '<tr><td>'+val['id']+'</td><td>'+val['name']+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible skin IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/specializations?ids=all').done(function (tempdata) {
        var data = {};
        $.each(tempdata, function(i,v){
            data[v.id] = v;
        });

        // Write to console
        console.log(data);

        // Write to document
        $('#apidata').html(makeTableHTML(data));
    });
})();

Seasons, Stories and Quests[edit]

/* GW2 API query tool for Seasons, Stories and Quests */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var columns = Object.keys(data[0]);
    var result = '<p>'+data.length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td style="white-space: pre-wrap;">' + JSON.stringify(v[vv],null,2) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible IDs via "?ids=all"
(function fetchAPIData() {
    // Query API until all the ids have been requested
    $.getJSON('https://api.guildwars2.com/v2/stories/seasons?ids=all')
    .done(function (seasondata) {
        $.getJSON('https://api.guildwars2.com/v2/stories?ids=all')
        .done(function (storydata) {
            $.getJSON('https://api.guildwars2.com/v2/quests?ids=all')
            .done(function (questdata) {
            
                var story_by_id = {};
                $.map(storydata, function(v){
                    story_by_id[v.id] = v;
                });
                
                var quest_by_story = {};
                $.map(questdata, function(v){
                    if (!(v.story in quest_by_story)) {
                        quest_by_story[v.story] = [];
                    }
                    quest_by_story[v.story].push({ quest_id: v.id, name: v.name });
                });
                
                seasondata = seasondata.sort(function(a,b){
                    return a.order - b.order;
                });
                $.map(seasondata, function(v,k){
                    seasondata[k].stories = seasondata[k].stories.sort(function(a,b){
                        return story_by_id[a].order - story_by_id[b].order;
                    });
                    
                    v.stories_names = [];
                    v.quest_names = [];
                    
                    $.map(v.stories, function(x){
                        var t1 = { id: x, name: story_by_id[x].name };
                        if ('chapters' in story_by_id[x] && story_by_id[x].chapters.length != 0) {
                            t1.chapters = story_by_id[x].chapters;
                        } else {
                            t1.missing_chapters = $.map(quest_by_story[x], function(y){
                                return y.quest_id;
                            });
                        }
                        v.stories_names.push(t1);
                        var t2 = { story_id: x };
                      	if (x in quest_by_story) {
                      		t2.quests = quest_by_story[x]
                        } else {
                          t2.quests = ['(missing)'];
                        }
                        v.quest_names.push(t2);
                    });
                });
            
                // Write to document
                $('#apidata').html(makeTableHTML(seasondata));
            });
        });
    });
})();

Titles[edit]

/* GW2 API query tool for titles */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var firstindex = Object.keys(data)[0];
    var columns = Object.keys(data[firstindex]);
    var result = '<p>'+Object.keys(data).length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible mount skin IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/titles').done(function (ids) {
        console.log('Number of titles: ' + ids.length);

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/titles?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

Traits[edit]

/* GW2 API query tool for traits */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var result = '<table class="table mech1" style="margin-bottom:0px;"><tr><th>ID</th><th>Name</th><th>Order</th></tr>';
    $.each(data, function(index, val) {
        var id = val['id'];
        var name = val['name'];
        var position = val['order'] + 1;
        result += '<tr><td>'+id+'</td><td>'+name+'</td><td>'+position+'</td></tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible trait IDs
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/traits').done(function (ids) {

        // Query API until all the ids have been requested
        var promises = [], maxsize = 200;
        for (var i=0; i<ids.length; i+=maxsize) {
            var current_ids = ids.slice(i,i+maxsize).join(',');
            var promise = $.getJSON('https://api.guildwars2.com/v2/traits?ids='+current_ids);
            promises.push(promise);
        }

        // Wait until all the GET requests have finished
        $.when.apply($,promises).done(function() {
            // Ensure data is an object
            var newarguments = {};
            if ( promises.length > 1 ) {
                newarguments = arguments;
            } else {
                newarguments[0] = arguments;
            }

            // Concatenate data into data
            var data = {};
            $.each(newarguments, function(index, element){
                $.each(element[0], function(key, val){
                    data[val['id']] = val;
                });
            });

            // Write to console
            console.log(data);

            // Write to document
            $('#apidata').html(makeTableHTML(data));
        });
    });
})();

WvW Objectives[edit]

/* GW2 API query tool for wvw objectives */
// Function to convert an object variable into a table
function makeTableHTML(data) {
    var firstindex = Object.keys(data)[0];
    var columns = Object.keys(data[firstindex]);
    var result = '<p>'+Object.keys(data).length+' results returned from the API.</p>' + '\n<table class="table mech1" style="margin-bottom:0px;" rules="all"><tr>';
    $.each(columns, function(i,v) { result += '<th>' + v + '</th>' });
    result += '</tr>';
    $.each(data, function(i,v) {
        result += '<tr>';
        $.each(columns, function(ii,vv){
          if (typeof v[vv] == 'object') {
            result += '<td>' + JSON.stringify(v[vv]) + '</td>';
          } else {
            result += '<td>' + v[vv] + '</td>';
          }
        });
        result += '</tr>';
    });
    result += '</table>';
    return result;
}

// Fetch all the possible wvw objectives
(function fetchAPIData() {
    $.getJSON('https://api.guildwars2.com/v2/wvw/objectives?ids=all').done(function (data) {

        // Write to console
        console.log(data);

        // Write to document
        $('#apidata').html(makeTableHTML(data));
    });
})();