Questa pagina illustra i passaggi per la creazione di un'applicazione che utilizza diverse API per rappresentare in un grafico le statistiche di visualizzazione relative ai video di YouTube di un utente. L'applicazione esegue le seguenti attività:
- Utilizza l'API YouTube Data per recuperare un elenco dei video caricati dall'utente attualmente autenticato e poi mostra un elenco dei titoli dei video.
- Quando l'utente fa clic su un determinato video, l'applicazione chiama l'API YouTube Analytics per recuperare i dati e le analisi relativi al video.
- L'applicazione utilizza l'API Google Visualization per creare grafici dei dati di analisi.
I passaggi seguenti descrivono la procedura di creazione dell'applicazione. Al passaggio 1, creerai i file HTML e CSS dell'applicazione. I passaggi da 2 a 5 descrivono le diverse parti del codice JavaScript utilizzato dall'applicazione. Il codice di esempio completo è incluso anche alla fine del documento.
- Passaggio 1: crea la pagina HTML e il file CSS
- Passaggio 2: attiva l'autenticazione OAuth 2.0
- Passaggio 3: recupera i dati per l'utente che ha eseguito l'accesso
- Passaggio 4: richiedi i dati di Analytics per un video
- Passaggio 5: visualizza i dati di Analytics in un grafico
Importante:devi registrare la tua applicazione con Google per ottenere un ID client OAuth 2.0 per la tua applicazione.
Passaggio 1: crea la pagina HTML e il file CSS
In questo passaggio, creerai una pagina HTML che carica le librerie JavaScript che verranno utilizzate dall'applicazione. Il seguente codice HTML mostra il codice della pagina:
<!doctype html> <html> <head> <title>Google I/O YouTube Codelab</title> <link type="text/css" rel="stylesheet" href="index.css"> <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> <script type="text/javascript" src="//www.google.com/jsapi"></script> <script type="text/javascript" src="index.js"></script> <script type="text/javascript" src="https://apis.google.com/js/client.js?onload=onJSClientLoad"></script> </head> <body> <div id="login-container" class="pre-auth">This application requires access to your YouTube account. Please <a href="#" id="login-link">authorize</a> to continue. </div> <div class="post-auth"> <div id="message"></div> <div id="chart"></div> <div>Choose a Video:</div> <ul id="video-list"></ul> </div> </body> </html>
Come mostrato nel tag <head>
della pagina di esempio, l'applicazione utilizza le seguenti librerie:
- jQuery fornisce metodi di assistenza per semplificare la scansione dei documenti HTML, la gestione degli eventi, l'animazione e le interazioni Ajax.
- Il caricatore di API di Google (
www.google.com/jsapi
) ti consente di importare facilmente una o più API di Google. Questa applicazione di esempio utilizza il caricatore di API per caricare l'API Google Visualization, che viene utilizzata per creare grafici dei dati di Analytics recuperati. - La libreria index.js contiene funzioni specifiche per l'applicazione di esempio. Questo tutorial illustra i passaggi per creare queste funzioni.
- La libreria client delle API di Google per JavaScript ti aiuta a implementare l'autenticazione OAuth 2.0 e a chiamare l'API YouTube Analytics.
L'applicazione di esempio include anche il file index.css. Di seguito è riportato un file CSS di esempio che puoi salvare nella stessa directory della pagina HTML:
body { font-family: Helvetica, sans-serif; } .pre-auth { display: none; } .post-auth { display: none; } #chart { width: 500px; height: 300px; margin-bottom: 1em; } #video-list { padding-left: 1em; list-style-type: none; } #video-list > li { cursor: pointer; } #video-list > li:hover { color: blue; }
Passaggio 2: attiva l'autenticazione OAuth 2.0
In questo passaggio inizierai a creare il file index.js chiamato dalla pagina HTML. Tenendo presente questo, crea un file denominato index.js nella stessa directory della pagina HTML e inserisci il codice seguente nel file. Sostituisci la stringa YOUR_CLIENT_ID con l'ID client della tua applicazione registrata.
(function() { // Retrieve your client ID from the Google API Console at // https://console.cloud.google.com/. var OAUTH2_CLIENT_ID = 'YOUR_CLIENT_ID'; var OAUTH2_SCOPES = [ 'https://www.googleapis.com/auth/yt-analytics.readonly', 'https://www.googleapis.com/auth/youtube.readonly' ]; // Upon loading, the Google APIs JS client automatically invokes this callback. // See https://developers.google.com/api-client-library/javascript/features/authentication window.onJSClientLoad = function() { gapi.auth.init(function() { window.setTimeout(checkAuth, 1); }); }; // Attempt the immediate OAuth 2.0 client flow as soon as the page loads. // If the currently logged-in Google Account has previously authorized // the client specified as the OAUTH2_CLIENT_ID, then the authorization // succeeds with no user intervention. Otherwise, it fails and the // user interface that prompts for authorization needs to display. function checkAuth() { gapi.auth.authorize({ client_id: OAUTH2_CLIENT_ID, scope: OAUTH2_SCOPES, immediate: true }, handleAuthResult); } // Handle the result of a gapi.auth.authorize() call. function handleAuthResult(authResult) { if (authResult) { // Authorization was successful. Hide authorization prompts and show // content that should be visible after authorization succeeds. $('.pre-auth').hide(); $('.post-auth').show(); loadAPIClientInterfaces(); } else { // Authorization was unsuccessful. Show content related to prompting for // authorization and hide content that should be visible if authorization // succeeds. $('.post-auth').hide(); $('.pre-auth').show(); // Make the #login-link clickable. Attempt a non-immediate OAuth 2.0 // client flow. The current function is called when that flow completes. $('#login-link').click(function() { gapi.auth.authorize({ client_id: OAUTH2_CLIENT_ID, scope: OAUTH2_SCOPES, immediate: false }, handleAuthResult); }); } } // This helper method displays a message on the page. function displayMessage(message) { $('#message').text(message).show(); } // This helper method hides a previously displayed message on the page. function hideMessage() { $('#message').hide(); } /* In later steps, add additional functions above this line. */ })();
Passaggio 3: recupera i dati dell'utente che ha eseguito l'accesso
In questo passaggio, aggiungerai al file index.js una funzione che recupera il feed dei video caricati dall'utente che attualmente ha eseguito l'accesso utilizzando l'API di dati di YouTube (v2.0). Questo feed specificherà l'ID canale YouTube dell'utente, necessario quando chiami l'API di YouTube Analytics. Inoltre, l'app di esempio elencherà i video caricati dall'utente in modo che quest'ultimo possa recuperare i dati di Analytics per ogni singolo video.
Apporta le seguenti modifiche al file index.js:
-
Aggiungi una funzione che carichi l'interfaccia client per le API YouTube Analytics e Data. Questo è un prerequisito per l'utilizzo del client JavaScript per le API di Google.
Una volta caricate entrambe le interfacce client API, la funzione chiama la funzione
getUserChannel
.// Load the client interfaces for the YouTube Analytics and Data APIs, which // are required to use the Google APIs JS client. More info is available at // https://developers.google.com/api-client-library/javascript/dev/dev_jscript#loading-the-client-library-and-the-api function loadAPIClientInterfaces() { gapi.client.load('youtube', 'v3', function() { gapi.client.load('youtubeAnalytics', 'v1', function() { // After both client interfaces load, use the Data API to request // information about the authenticated user's channel. getUserChannel(); }); }); }
-
Aggiungi la variabile
channelId
e la funzionegetUserChannel
. La funzione chiama l'API YouTube Data (v3) e include il parametromine
, che indica che la richiesta riguarda le informazioni del canale dell'utente attualmente autenticato. Il valorechannelId
verrà inviato all'API Analytics per identificare il canale per cui stai recuperando i dati di Analytics.// Keep track of the currently authenticated user's YouTube channel ID. var channelId; // Call the Data API to retrieve information about the currently // authenticated user's YouTube channel. function getUserChannel() { // Also see: https://developers.google.com/youtube/v3/docs/channels/list var request = gapi.client.youtube.channels.list({ // Setting the "mine" request parameter's value to "true" indicates that // you want to retrieve the currently authenticated user's channel. mine: true, part: 'id,contentDetails' }); request.execute(function(response) { if ('error' in response) { displayMessage(response.error.message); } else { // We need the channel's channel ID to make calls to the Analytics API. // The channel ID value has the form "UCdLFeWKpkLhkguiMZUp8lWA". channelId = response.items[0].id; // Retrieve the playlist ID that uniquely identifies the playlist of // videos uploaded to the authenticated user's channel. This value has // the form "UUdLFeWKpkLhkguiMZUp8lWA". var uploadsListId = response.items[0].contentDetails.relatedPlaylists.uploads; // Use the playlist ID to retrieve the list of uploaded videos. getPlaylistItems(uploadsListId); } }); }
-
Aggiungi la funzione
getPlaylistItems
, che recupera gli elementi di una playlist specificata. In questo caso, la playlist elenca i video caricati sul canale dell'utente. Tieni presente che la funzione di esempio riportata di seguito recupera solo i primi 50 elementi del feed e che devi implementare la paginazione per recuperare altri elementi.Dopo aver recuperato l'elenco di elementi della playlist, la funzione chiama la funzione
getVideoMetadata()
. La funzione ottiene quindi i metadati di ogni video nell'elenco e li aggiunge all'elenco visualizzato dall'utente.// Call the Data API to retrieve the items in a particular playlist. In this // example, we are retrieving a playlist of the currently authenticated user's // uploaded videos. By default, the list returns the most recent videos first. function getPlaylistItems(listId) { // See https://developers.google.com/youtube/v3/docs/playlistitems/list var request = gapi.client.youtube.playlistItems.list({ playlistId: listId, part: 'snippet' }); request.execute(function(response) { if ('error' in response) { displayMessage(response.error.message); } else { if ('items' in response) { // The jQuery.map() function iterates through all of the items in // the response and creates a new array that only contains the // specific property we're looking for: videoId. var videoIds = $.map(response.items, function(item) { return item.snippet.resourceId.videoId; }); // Now that we know the IDs of all the videos in the uploads list, // we can retrieve information about each video. getVideoMetadata(videoIds); } else { displayMessage('There are no videos in your channel.'); } } }); } // Given an array of video IDs, this function obtains metadata about each // video and then uses that metadata to display a list of videos. function getVideoMetadata(videoIds) { // https://developers.google.com/youtube/v3/docs/videos/list var request = gapi.client.youtube.videos.list({ // The 'id' property's value is a comma-separated string of video IDs. id: videoIds.join(','), part: 'id,snippet,statistics' }); request.execute(function(response) { if ('error' in response) { displayMessage(response.error.message); } else { // Get the jQuery wrapper for the #video-list element before starting // the loop. var videoList = $('#video-list'); $.each(response.items, function() { // Exclude videos that do not have any views, since those videos // will not have any interesting viewcount Analytics data. if (this.statistics.viewCount == 0) { return; } var title = this.snippet.title; var videoId = this.id; // Create a new <li> element that contains an <a> element. // Set the <a> element's text content to the video's title, and // add a click handler that will display Analytics data when invoked. var liElement = $('<li>'); var aElement = $('<a>'); // Setting the href value to '#' ensures that the browser renders the // <a> element as a clickable link. aElement.attr('href', '#'); aElement.text(title); aElement.click(function() { displayVideoAnalytics(videoId); }); // Call the jQuery.append() method to add the new <a> element to // the <li> element, and the <li> element to the parent // list, which is identified by the 'videoList' variable. liElement.append(aElement); videoList.append(liElement); }); if (videoList.children().length == 0) { // Display a message if the channel does not have any viewed videos. displayMessage('Your channel does not have any videos that have been viewed.'); } } }); }
Passaggio 4: richiedi i dati di Analytics per un video
In questo passaggio, modificherai l'applicazione di esempio in modo che, quando fai clic sul titolo di un video, l'applicazione chiami l'API YouTube Analytics per recuperare i dati di Analytics relativi al video. Per farlo, apporta le seguenti modifiche all'applicazione di esempio:
-
Aggiungi una variabile che specifichi l'intervallo di date predefinito per i dati dei report di Analytics recuperati.
var ONE_MONTH_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 30;
-
Aggiungi il codice che crea una stringa
YYYY-MM-DD
per un oggetto Data e aggiunge zeri ai numeri di giorno e mese nelle date per ottenere due cifre:// This boilerplate code takes a Date object and returns a YYYY-MM-DD string. function formatDateString(date) { var yyyy = date.getFullYear().toString(); var mm = padToTwoCharacters(date.getMonth() + 1); var dd = padToTwoCharacters(date.getDate()); return yyyy + '-' + mm + '-' + dd; } // If number is a single digit, prepend a '0'. Otherwise, return the number // as a string. function padToTwoCharacters(number) { if (number < 10) { return '0' + number; } else { return number.toString(); } }
-
Definisci la funzione
displayVideoAnalytics
, che recupera i dati di YouTube Analytics per un video. Questa funzione viene eseguita quando l'utente fa clic su un video nell'elenco. La funzionegetVideoMetadata
, che stampa l'elenco dei video ed è stata definita nel passaggio 3, definisce il gestore dell'evento di clic.// This function requests YouTube Analytics data for a video and displays // the results in a chart. function displayVideoAnalytics(videoId) { if (channelId) { // To use a different date range, modify the ONE_MONTH_IN_MILLISECONDS // variable to a different millisecond delta as desired. var today = new Date(); var lastMonth = new Date(today.getTime() - ONE_MONTH_IN_MILLISECONDS); var request = gapi.client.youtubeAnalytics.reports.query({ // The start-date and end-date parameters must be YYYY-MM-DD strings. 'start-date': formatDateString(lastMonth), 'end-date': formatDateString(today), // At this time, you need to explicitly specify channel==channelId. // See https://developers.google.com/youtube/analytics/v1/#ids ids: 'channel==' + channelId, dimensions: 'day', sort: 'day', // See https://developers.google.com/youtube/analytics/v1/available_reports // for details about the different filters and metrics you can request // if the "dimensions" parameter value is "day". metrics: 'views', filters: 'video==' + videoId }); request.execute(function(response) { // This function is called regardless of whether the request succeeds. // The response contains YouTube Analytics data or an error message. if ('error' in response) { displayMessage(response.error.message); } else { displayChart(videoId, response); } }); } else { // The currently authenticated user's channel ID is not available. displayMessage('The YouTube channel ID for the current user is not available.'); } }
Per ulteriori informazioni sui dati che possono essere recuperati e sulle combinazioni di valori validi per i parametri
metrics
,dimensions
efilters
, consulta la pagina Report disponibili della documentazione dell'API.
Passaggio 5: visualizza i dati di Analytics in un grafico
In questo passaggio, aggiungerai la funzione displayChart
, che invia i dati di YouTube Analytics all'API Google Visualization. L'API poi crea un grafico delle informazioni.
-
Carica l'API Google Visualization, che mostrerà i dati in un grafico. Per ulteriori dettagli sulle opzioni di rappresentazione dei grafici, consulta la documentazione dell'API Visualization.
google.load('visualization', '1.0', {'packages': ['corechart']});
-
Definisci una nuova funzione denominata
displayChart
che utilizzi l'API di visualizzazione di Google per generare dinamicamente un grafico che mostra i dati di Analytics.// Call the Google Chart Tools API to generate a chart of Analytics data. function displayChart(videoId, response) { if ('rows' in response) { hideMessage(); // The columnHeaders property contains an array of objects representing // each column's title -- e.g.: [{name:"day"},{name:"views"}] // We need these column titles as a simple array, so we call jQuery.map() // to get each element's "name" property and create a new array that only // contains those values. var columns = $.map(response.columnHeaders, function(item) { return item.name; }); // The google.visualization.arrayToDataTable() function wants an array // of arrays. The first element is an array of column titles, calculated // above as "columns". The remaining elements are arrays that each // represent a row of data. Fortunately, response.rows is already in // this format, so it can just be concatenated. // See https://developers.google.com/chart/interactive/docs/datatables_dataviews#arraytodatatable var chartDataArray = [columns].concat(response.rows); var chartDataTable = google.visualization.arrayToDataTable(chartDataArray); var chart = new google.visualization.LineChart(document.getElementById('chart')); chart.draw(chartDataTable, { // Additional options can be set if desired as described at: // https://developers.google.com/chart/interactive/docs/reference#visdraw title: 'Views per Day of Video ' + videoId }); } else { displayMessage('No data available for video ' + videoId); } }
Visualizza il file index.js completo
Il file index.js riportato di seguito incorpora tutte le modifiche dei passaggi mostrati sopra. Ricorda di sostituire la stringa YOUR_CLIENT_ID con l'ID cliente della tua applicazione registrata.
(function() { // Retrieve your client ID from the Google API Console at // https://console.cloud.google.com/. var OAUTH2_CLIENT_ID = 'YOUR_CLIENT_ID'; var OAUTH2_SCOPES = [ 'https://www.googleapis.com/auth/yt-analytics.readonly', 'https://www.googleapis.com/auth/youtube.readonly' ]; var ONE_MONTH_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 30; // Keep track of the currently authenticated user's YouTube channel ID. var channelId; // For information about the Google Chart Tools API, see: // https://developers.google.com/chart/interactive/docs/quick_start google.load('visualization', '1.0', {'packages': ['corechart']}); // Upon loading, the Google APIs JS client automatically invokes this callback. // See https://developers.google.com/api-client-library/javascript/features/authentication window.onJSClientLoad = function() { gapi.auth.init(function() { window.setTimeout(checkAuth, 1); }); }; // Attempt the immediate OAuth 2.0 client flow as soon as the page loads. // If the currently logged-in Google Account has previously authorized // the client specified as the OAUTH2_CLIENT_ID, then the authorization // succeeds with no user intervention. Otherwise, it fails and the // user interface that prompts for authorization needs to display. function checkAuth() { gapi.auth.authorize({ client_id: OAUTH2_CLIENT_ID, scope: OAUTH2_SCOPES, immediate: true }, handleAuthResult); } // Handle the result of a gapi.auth.authorize() call. function handleAuthResult(authResult) { if (authResult) { // Authorization was successful. Hide authorization prompts and show // content that should be visible after authorization succeeds. $('.pre-auth').hide(); $('.post-auth').show(); loadAPIClientInterfaces(); } else { // Authorization was unsuccessful. Show content related to prompting for // authorization and hide content that should be visible if authorization // succeeds. $('.post-auth').hide(); $('.pre-auth').show(); // Make the #login-link clickable. Attempt a non-immediate OAuth 2.0 // client flow. The current function is called when that flow completes. $('#login-link').click(function() { gapi.auth.authorize({ client_id: OAUTH2_CLIENT_ID, scope: OAUTH2_SCOPES, immediate: false }, handleAuthResult); }); } } // Load the client interfaces for the YouTube Analytics and Data APIs, which // are required to use the Google APIs JS client. More info is available at // https://developers.google.com/api-client-library/javascript/dev/dev_jscript#loading-the-client-library-and-the-api function loadAPIClientInterfaces() { gapi.client.load('youtube', 'v3', function() { gapi.client.load('youtubeAnalytics', 'v1', function() { // After both client interfaces load, use the Data API to request // information about the authenticated user's channel. getUserChannel(); }); }); } // Call the Data API to retrieve information about the currently // authenticated user's YouTube channel. function getUserChannel() { // Also see: https://developers.google.com/youtube/v3/docs/channels/list var request = gapi.client.youtube.channels.list({ // Setting the "mine" request parameter's value to "true" indicates that // you want to retrieve the currently authenticated user's channel. mine: true, part: 'id,contentDetails' }); request.execute(function(response) { if ('error' in response) { displayMessage(response.error.message); } else { // We need the channel's channel ID to make calls to the Analytics API. // The channel ID value has the form "UCdLFeWKpkLhkguiMZUp8lWA". channelId = response.items[0].id; // Retrieve the playlist ID that uniquely identifies the playlist of // videos uploaded to the authenticated user's channel. This value has // the form "UUdLFeWKpkLhkguiMZUp8lWA". var uploadsListId = response.items[0].contentDetails.relatedPlaylists.uploads; // Use the playlist ID to retrieve the list of uploaded videos. getPlaylistItems(uploadsListId); } }); } // Call the Data API to retrieve the items in a particular playlist. In this // example, we are retrieving a playlist of the currently authenticated user's // uploaded videos. By default, the list returns the most recent videos first. function getPlaylistItems(listId) { // See https://developers.google.com/youtube/v3/docs/playlistitems/list var request = gapi.client.youtube.playlistItems.list({ playlistId: listId, part: 'snippet' }); request.execute(function(response) { if ('error' in response) { displayMessage(response.error.message); } else { if ('items' in response) { // The jQuery.map() function iterates through all of the items in // the response and creates a new array that only contains the // specific property we're looking for: videoId. var videoIds = $.map(response.items, function(item) { return item.snippet.resourceId.videoId; }); // Now that we know the IDs of all the videos in the uploads list, // we can retrieve information about each video. getVideoMetadata(videoIds); } else { displayMessage('There are no videos in your channel.'); } } }); } // Given an array of video IDs, this function obtains metadata about each // video and then uses that metadata to display a list of videos. function getVideoMetadata(videoIds) { // https://developers.google.com/youtube/v3/docs/videos/list var request = gapi.client.youtube.videos.list({ // The 'id' property's value is a comma-separated string of video IDs. id: videoIds.join(','), part: 'id,snippet,statistics' }); request.execute(function(response) { if ('error' in response) { displayMessage(response.error.message); } else { // Get the jQuery wrapper for the #video-list element before starting // the loop. var videoList = $('#video-list'); $.each(response.items, function() { // Exclude videos that do not have any views, since those videos // will not have any interesting viewcount Analytics data. if (this.statistics.viewCount == 0) { return; } var title = this.snippet.title; var videoId = this.id; // Create a new <li> element that contains an <a> element. // Set the <a> element's text content to the video's title, and // add a click handler that will display Analytics data when invoked. var liElement = $('<li>'); var aElement = $('<a>'); // Setting the href value to '#' ensures that the browser renders the // <a> element as a clickable link. aElement.attr('href', '#'); aElement.text(title); aElement.click(function() { displayVideoAnalytics(videoId); }); // Call the jQuery.append() method to add the new <a> element to // the <li> element, and the <li> element to the parent // list, which is identified by the 'videoList' variable. liElement.append(aElement); videoList.append(liElement); }); if (videoList.children().length == 0) { // Display a message if the channel does not have any viewed videos. displayMessage('Your channel does not have any videos that have been viewed.'); } } }); } // This function requests YouTube Analytics data for a video and displays // the results in a chart. function displayVideoAnalytics(videoId) { if (channelId) { // To use a different date range, modify the ONE_MONTH_IN_MILLISECONDS // variable to a different millisecond delta as desired. var today = new Date(); var lastMonth = new Date(today.getTime() - ONE_MONTH_IN_MILLISECONDS); var request = gapi.client.youtubeAnalytics.reports.query({ // The start-date and end-date parameters must be YYYY-MM-DD strings. 'start-date': formatDateString(lastMonth), 'end-date': formatDateString(today), // At this time, you need to explicitly specify channel==channelId. // See https://developers.google.com/youtube/analytics/v1/#ids ids: 'channel==' + channelId, dimensions: 'day', sort: 'day', // See https://developers.google.com/youtube/analytics/v1/available_reports // for details about the different filters and metrics you can request // if the "dimensions" parameter value is "day". metrics: 'views', filters: 'video==' + videoId }); request.execute(function(response) { // This function is called regardless of whether the request succeeds. // The response contains YouTube Analytics data or an error message. if ('error' in response) { displayMessage(response.error.message); } else { displayChart(videoId, response); } }); } else { // The currently authenticated user's channel ID is not available. displayMessage('The YouTube channel ID for the current user is not available.'); } } // This boilerplate code takes a Date object and returns a YYYY-MM-DD string. function formatDateString(date) { var yyyy = date.getFullYear().toString(); var mm = padToTwoCharacters(date.getMonth() + 1); var dd = padToTwoCharacters(date.getDate()); return yyyy + '-' + mm + '-' + dd; } // If number is a single digit, prepend a '0'. Otherwise, return the number // as a string. function padToTwoCharacters(number) { if (number < 10) { return '0' + number; } else { return number.toString(); } } // Call the Google Chart Tools API to generate a chart of Analytics data. function displayChart(videoId, response) { if ('rows' in response) { hideMessage(); // The columnHeaders property contains an array of objects representing // each column's title -- e.g.: [{name:"day"},{name:"views"}] // We need these column titles as a simple array, so we call jQuery.map() // to get each element's "name" property and create a new array that only // contains those values. var columns = $.map(response.columnHeaders, function(item) { return item.name; }); // The google.visualization.arrayToDataTable() function wants an array // of arrays. The first element is an array of column titles, calculated // above as "columns". The remaining elements are arrays that each // represent a row of data. Fortunately, response.rows is already in // this format, so it can just be concatenated. // See https://developers.google.com/chart/interactive/docs/datatables_dataviews#arraytodatatable var chartDataArray = [columns].concat(response.rows); var chartDataTable = google.visualization.arrayToDataTable(chartDataArray); var chart = new google.visualization.LineChart(document.getElementById('chart')); chart.draw(chartDataTable, { // Additional options can be set if desired as described at: // https://developers.google.com/chart/interactive/docs/reference#visdraw title: 'Views per Day of Video ' + videoId }); } else { displayMessage('No data available for video ' + videoId); } } // This helper method displays a message on the page. function displayMessage(message) { $('#message').text(message).show(); } // This helper method hides a previously displayed message on the page. function hideMessage() { $('#message').hide(); } })();