Около полутора лет назад я создал демо-версию ( Proof of Concept — Dashboard for Google Analytics ) панели инструментов Google Analytics. Это демо было полностью на стороне клиента и использовало библиотеки API, созданные Google. По большей части процесс был довольно прост. После того, как я выяснил, как аутентифицировать пользователя и запросить данные, я потратил больше времени на то, чтобы он выглядел красиво, чем на самом деле работал с API, что хорошо. Совсем недавно я обнаружил новый API Analytics Embed . Отличительной особенностью Embed API является то, что он значительно упрощает аспект аутентификации / авторизации при получении аналитических данных и даже предоставляет встроенные возможности построения диаграмм. Пример блога ( Быстрый пример API Google Analytics Embed)) и я подумал, что было бы забавно пересмотреть мою концепцию панели инструментов с помощью этого более простого API.
Прежде чем я покажу код этой демонстрации, позвольте мне поделиться снимком экрана, чтобы вы могли увидеть его в действии. Я переключился на новую библиотеку графиков для этой демонстрации ( ChartJS ) главным образом потому, что Google использовал ее в одной из своих демонстраций. Я не тратил много времени на то, чтобы сделать это красиво — я собирался получить «быстрое воздействие» с точки зрения визуальных эффектов Очевидно, что могло бы быть и лучше.
Каждый график представляет одно из моих свойств. Каждая строка представляет количество просмотров страниц в сутки, причем темно-синий — самая последняя страница за семь дней, а светло-серый — за семь дней до этого.
Код состоит из нескольких частей. Аутентификация, как я уже сказал, почти полностью обрабатывается API встраивания.
gapi.analytics.ready(function() {
var CLIENT_ID = '818125206534-g1r0datdtu9serq2pf9cp5vkuih3h8pv.apps.googleusercontent.com';
gapi.analytics.auth.authorize({
container: 'auth-button',
clientid: CLIENT_ID,
userInfoLabel:""
});
gapi.analytics.auth.on('success', function(response) {
//hide the auth-button
document.querySelector("#auth-button").style.display='none';
console.log("get profiles");
getProfiles(function(profs) {
window.profiles = profs;
processProfiles();
});
});
Chart.defaults.global.animationSteps = 60;
Chart.defaults.global.animationEasing = 'easeInOutQuart';
Chart.defaults.global.responsive = true;
Chart.defaults.global.maintainAspectRatio = false;
});
Чтобы получить профили для моей учетной записи, я использую API управления. getProfiles
обрабатывает выборку и кеширование, этот результат. (Я использую кеширование, как и планировал, все еще планирую, добавив несколько дополнительных параметров фильтрации в отчет.)
function getProfiles(cb) {
//do we have a cached version?
if(sessionStorage["gaProfiles"]) {
console.log("profiles fetched from cache");
cb(JSON.parse(sessionStorage["gaProfiles"]));
return;
}
gapi.client.analytics.management.accounts.list().then(function(res) {
var accountId = res.result.items[0].id;
var profiles = [];
gapi.client.analytics.management.webproperties.list({'accountId': accountId}).then(function(res) {
res.result.items.forEach(function(item) {
if(item.defaultProfileId) profiles.push({id:"ga:"+item.defaultProfileId,name:item.name});
});
sessionStorage["gaProfiles"] = JSON.stringify(profiles);
cb(profiles);
});
});
}
Обратите внимание, что я не использую обещания в этом блоке, и это ошибка. Я использую его чуть позже в другой функции, поэтому мне нужно (ну, я хочу) быть последовательным. Теперь самое интересное. Для всех моих свойств мне нужно получить данные для каждого сайта. Мне удалось скопировать код из одной из демонстраций Google, но я быстро столкнулся с проблемами ограничения скорости. Чтобы обойти это, я однопотоковую звонки и добавить небольшую задержку.
//Credit: https://ga-dev-tools.appspot.com/embed-api/third-party-visualizations/
function query(params) {
return new Promise(function(resolve, reject) {
var data = new gapi.analytics.report.Data({query: params});
data.once('success', function(response) { resolve(response); })
.once('error', function(response) { reject(response); })
.execute();
});
}
function makeCanvas(id) {
var container = document.getElementById(id);
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
container.innerHTML = '';
canvas.width = container.offsetWidth;
canvas.height = container.offsetHeight;
container.appendChild(canvas);
return ctx;
}
function processProfiles() {
console.log("working on profile "+profiles[curProfile].name);
var now = moment();
var id = profiles[curProfile].id;
var thisWeek = query({
'ids': id,
'dimensions': 'ga:date,ga:nthDay',
'metrics': 'ga:pageviews',
'start-date': moment(now).subtract(8, 'day').format('YYYY-MM-DD'),
'end-date': moment(now).subtract(1,'day').format('YYYY-MM-DD')
});
var lastWeek = query({
'ids': id,
'dimensions': 'ga:date,ga:nthDay',
'metrics': 'ga:pageviews',
'start-date': moment(now).subtract(15, 'day').subtract(1, 'week')
.format('YYYY-MM-DD'),
'end-date': moment(now).subtract(8, 'day').subtract(1, 'week')
.format('YYYY-MM-DD')
});
Promise.all([thisWeek, lastWeek]).then(function(results) {
console.log("Promise.all");console.dir(results);
var data1 = results[0].rows.map(function(row) { return +row[2]; });
var data2 = results[1].rows.map(function(row) { return +row[2]; });
var labels = results[1].rows.map(function(row) { return +row[0]; });
var totalThisWeek = results[0].totalsForAllResults["ga:pageviews"];
var totalLastWeek = results[1].totalsForAllResults["ga:pageviews"];
var percChange = (((totalThisWeek - totalLastWeek) / totalLastWeek) * 100).toFixed(2);
console.log(totalLastWeek, totalThisWeek, percChange);
labels = labels.map(function(label) {
return moment(label, 'YYYYMMDD').format('ddd');
});
var data = {
labels : labels,
datasets : [
{
label: 'Last Week',
fillColor : 'rgba(220,220,220,0.5)',
strokeColor : 'rgba(220,220,220,1)',
pointColor : 'rgba(220,220,220,1)',
pointStrokeColor : '#fff',
data : data2
},
{
label: 'This Week',
fillColor : 'rgba(151,187,205,0.5)',
strokeColor : 'rgba(151,187,205,1)',
pointColor : 'rgba(151,187,205,1)',
pointStrokeColor : '#fff',
data : data1
}
]
};
var titleStr = profiles[curProfile].name + " ";
if(totalLastWeek > 0 && totalThisWeek > 0) {
if(percChange < 0) {
titleStr += "<span class='down'>(Down "+Math.abs(percChange) + "%)</span>";
} else {
titleStr += "<span class='up'>(Up "+percChange + "%)</span>";
}
}
$("body").append("<div class='reportContainer'><div class='chartTitleContainer'>"+titleStr+"</div><div class='chartContainer' id='chart-"+curProfile+"-container'></div></div>");
new Chart(makeCanvas('chart-'+curProfile+'-container')).Line(data);
if(curProfile+1 < profiles.length) {
curProfile++;
//settimeout to try to avoid GA rate limits
setTimeout(processProfiles,200);
}
});
}
И это в основном все. Как я уже сказал, я хотел бы добавить несколько вариантов к этому. В частности, возможность сравнить текущие и прошедшие 30 дней, а также этот год с прошлым. Я также хотел бы иметь возможность отклонять / скрывать некоторые сайты, которые меня не интересуют. Я мог бы использовать LocalStorage, чтобы запомнить эти свойства и скрыть их автоматически.
Хотите увидеть полный код и проверить его самостоятельно? Проверьте онлайн демо здесь: http://static.raymondcamden.com/ga_embed/test10.html