/*
demo using Bouquet analytics API with D3.js to display data distribution by states and with drill-down support.
*/
var bouquetServer = "//demo.openbouquet.io/release/v4.2";
// login with APiKey and execute function
function login(tokenUrl, updateFunc) {
accessToken = Cookies.get("sq-token");
if (accessToken === undefined) {
requestToken(tokenUrl, updateFunc);
} else {
checkToken(accessToken, tokenUrl, updateFunc);
}
};
// check if a OAtuh2 token is still valid
function checkToken(accessToken, tokenUrl, updateFunc) {
// perform /token request
$.ajax({
type: "GET",
dataType: "json",
url: bouquetServer+"/rs/tokeninfo?access_token=" + accessToken,
}).done(function(response) {
accessToken = response.access_token;
updateFunc(accessToken);
}).fail(function(response) {
requestToken(tokenUrl, updateFunc);
});
};
// request a new OAuth2 token
function requestToken(tokenUrl, updateFunc) {
// perform /token request
$.ajax({
type: "GET",
dataType: "json",
url: tokenUrl,
}).done(function(response) {
// auth done, get the user
accessToken = response.access_token;
expirationDateMillis = response.expirationDateMillis;
Cookies.set("sq-token", accessToken, {
expires: new Date(expirationDateMillis)
});
updateFunc(accessToken);
}).fail(function(response) {
alert("Failed to get auth token");
});
};
function format(f) {
if (f===undefined) return null;
if (!f.startsWith("%")) return null;
f = f.substring(1);
return d3.format(f);
}
// display data as a simple html table using D3
function displayTable(data) {
// column definitions: use the reply header
var columns = [];
data.header.columns.forEach(function(column) {
columns.push({
head: column.name,// this is the name of the column
cl: (column.format===undefined)?"center":"num",// value format to use if defined
html: (column.format===undefined)?ƒ(column.pos):ƒ(column.pos,format(column.format))
});// pos gives the value index in the result array when the format is data=TABLE
});
// reply info
var tableInfo = d3.select("#tableInfo");
var pageSize = data.info.pageSize;
var totalSize = data.info.totalSize;
if (pageSize > 0) {
if (pageSize == totalSize) {
tableInfo.select('#tableText').text("Showing "+pageSize + " Events");
} else {
tableInfo.select('#tableText').text("Showing "+pageSize + " Events out of " + totalSize);
}
} else {
tableInfo.select('#tableText').text("No Event to show");
}
// populate the table
var tableDetails = d3.select('#tableDetails');
tableDetails.selectAll("*").remove();
// create table
var table = tableDetails.append('table').attr("class", "data");
// create table header
table.append('thead').append('tr').selectAll('th').data(columns)
.enter().append('th').attr('class', ƒ('cl')).text(ƒ('head'));
// create table body
table
.append('tbody')
.selectAll('tr')
.data(data.data)
.enter()
.append('tr')
.selectAll('td')
.data(
function(row, i) {
return columns
.map(function(c) {
// compute cell values for this specific row
var cell = {};
d3
.keys(c)
.forEach(
function(k) {
cell[k] = typeof c[k] == 'function' ? c[k]
(row, i) : c[k];
});
return cell;
});
}).enter().append('td').html(ƒ('html')).attr('class',
ƒ('cl'));
}
// run query
function update(accessToken) {
$("#status").text("connected");
var apiUrl = bouquetServer+ "/analytics/@'5899bc6715abcc6bed69d766'.@bookmark:'58a5dc6b45d778b2bdb231c9'/query?";
apiUrl += "envelope=RESULT&data=TABLE";// get the header as well and format data as array of values
apiUrl += "&access_token="+accessToken;// adding the OAuth token
$('#apiUrl').text('requesting data').append($('<i class="fa fa-refresh fa-spin fa-fw"></i>'));
// clear table and diplay spin
var tableDetails = d3.select('#tableDetails');
tableDetails.selectAll("*").remove();
tableDetails.append("i").attr("class", "fa fa-refresh fa-spin fa-fw");
$.getJSON(apiUrl, function (data) {
$('#apiUrl').text('').append($('<a href="'+apiUrl+'&style=HTML" target="_blank">View data in Bouquet API explorer <i class="fa fa-external-link"></i></a>'));
displayTable(data);
}).fail(function(response) {
$('#apiUrl').text('request failed: '+response.responseJSON.error+"("+response.responseJSON.code+")")
});
}
// login and update
$(function() {
var clientId = "api-key-client";
// login with API Key
login(bouquetServer+"/rs/token?assertion=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhcGkta2V5LWNsaWVudCIsInN1YiI6IjU4YWM1Y2FiMTVhYmNjMTJiYjUwYTU0MCIsInVzZXJFbWFpbCI6ImRlbW9AbG9jYWxob3N0LmNvbSIsImN1c3RvbWVySWQiOiI1OGFjNTNjMDE1YWJjYzEyYmI1MGE0NWIiLCJqdGkiOiJnTmF3dHdiZzRaYXRtQ1JXVVRQYnFnIiwiZXhwIjo0NjQxNTM0NTE5LCJpYXQiOjE0ODc5MzQ1MTksIm5iZiI6MTQ4NzkzNDM5OX0.g5f1DHxESj9PvC5meP8UKXmcZzbGZIiW-qwZ7mNAZWTlMlaAdIn1EBOZzB9oAwHzQxS0qez0iRDac874YCmnHrwYI8kgVoJQvbbJedKIJjfP_V_ZPvMiAfsX0wqeCmqG4_uXZoAh_sumvyDkKGfzutAfpR3DCVkWTqfYZ-iornkyYwH89Yqe_yBNQPO4pXpf3Dg68BlruZqc-tiow3ytynyxuEYEOPYIuyRL-fLpjNstRGa_gXIQYBx9v1yVGlZsQFVviJ5PMbCgIduM36g5leA_IXprw46KxjH_snbnEvAHypZCwhNaJJxlLGBEWTMnFKqytR68CGURskRM2D0VPQ&client_id="+clientId, update);
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="//openbouquet.io/js/uStates.js"></script>
<!-- creates uStates. -->
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//rawgit.com/gka/d3-jetpack/master/d3-jetpack.js"></script>
<script src="//openbouquet.io/js/js.cookie.js"></script>
<script src="https://use.fontawesome.com/1ea8d4d975.js"></script>
<h1>
<a href="https://openbouquet.io/bouquet-demo-ob" target="_parent">Bouquet API</a> simple Table demo using D3.js
</h1>
<div id="status">Connecting <i class="fa fa-refresh fa-spin fa-fw"></i></div>
<div id="apiUrl"> </div>
<hr>
<div id="tableInfo">
<p id="tableText"> </p>
</div>
<div id="tableDetails" style="max-height:400px;overflow:scroll;">
</div>
body {
margin:5px;
}
* {
font-family: "Helvetica Neue", Helvetica,Arial,sans-serif;
color: #666;
}
table.data {
border-collapse: collapse;width: 100%;
}
th, td {
text-align: left;padding: 8px; vertical-align: top;
}
.data tr:nth-child(even) {
background-color: #f2f2f2
}
.data th {
background-color: #ee7914;color: white;
}
.state {
fill: none;
stroke: #a9a9a9;
stroke-width: 1;
}
.state:hover {
fill-opacity: 0.5;
}
th {
text-align: left;
}
th,
td {
padding: 0 1em 0.5ex 0;
}
th.center,
td.center {
text-align: center;
}
th.num,
td.num {
text-align: right;
}
External resources loaded into this fiddle: