八、Google+

在主要的社交网站中,Google+是最新的进入者。 虽然是新贵,但它拥有庞大的用户基础,声称拥有超过 3.5 亿的活跃账户(http://ca.ign.com/articles/2013/05/02/report-google-bigger-than-twitter-with-359-million-active-users)。 这并不是谷歌首次尝试进入价值数十亿美元的社交媒体市场。 他们在过去创造了谷歌 Buzz,谷歌 Friend Connect 和 Orkut,试图获得更大的用户基础。 除了 Orkut,其他的都被封存了,其用户基础几乎全部位于巴西。 谷歌有意避免创建写 API,希望它能消除自动发布的垃圾邮件。 Google+提供了一个只读 API,我们可以利用它来创建可视化; 然而,与其他 API 相比,这个 API 是非常有限的——在编写这本书的时候,你甚至不能列出圆的成员。

创建应用

Google+是另一个 OAuth 2.0 网站,所以我们,当然,需要得到一个应用键作为创建任何可视化的第一步。 这也意味着我们将需要一个返回 URL,因此我们将再次需要设置一个 HTTP 服务器来运行可视化。

第一步是使用谷歌帐号登录https://code.google.com/apis/console。 如果您没有这样的帐户,您也可以从该页面创建一个。 一旦进入站点,就会出现一个巨大的按钮,允许您创建应用项目。 这个控制台实际上管理对谷歌所有 api 的访问,谷歌的 api 有很多。

接下来,您将看到一个各种 api 的巨大列表。 如果你向下滚动,你最终会找到 Google+(使用搜索,它将节省滚动数小时)。 将开关拨至“开”位置。 您可能需要同意几个用户协议。 一定要像往常一样阅读完整的协议。

下一步是请求一个新键,如下面的截图所示。 这可以从API 访问选项卡中完成,您应该点击创建一个 OAuth 2.0 客户端 ID…。 在打开的对话框中,您需要填写应用名称和 URL。 这不是 OAuth 交换的 URL; 这是下一个选项卡。 在这个选项卡上,输入一个 URL, OAuth 请求可以从这个 URL 发起,它应该返回到这个 URL。 对于我们的目的,http://localhost:8080将是域:

Creating an app

然后,我们将收到一对准备在应用中使用的密钥。 客户端 ID 是您希望在脚本中使用的字段。

数据检索

与 Facebook 一样,我们可以针对 OAuth 2.0 端点进行手动身份验证,但让我们使用谷歌提供的 API。 连接起来很简单:

document.addEventListener("DOMContentLoaded",
 function() {
    var po = document.createElement('script');
    po.type = 'text/javascript'; po.async = true;
    po.src = 'https://plus.google.com/js/client:plusone.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(po, s);
  });

一旦文档准备好了,它就会运行,通过在包含 jQuery 的标签之前放置一个新的script标签,从谷歌的服务器加载 API 脚本。 加载的文档包含许多 JavaScript 函数,可以用于与谷歌 api 交互,但不是 Google+ api——这在登录后发生。

要添加登录按钮,我们添加以下 HTML 代码:

<button class="g-signin"
   data-scope="https://www.googleapis.com/auth/plus.login"
   data-requestvisibleactions="http://schemas.google.com/AddActivity"
   data-clientId="988552574579.apps.googleusercontent.com"
   data-callback="onSignInCallback"
   data-theme="dark"
   data-cookiepolicy="single_host_origin">
</button>

这将生成登录按钮。 附加到这个按钮的各种data-属性由我们从谷歌加载的脚本处理。 登录的范围是 Google+,而不是其他谷歌 api。 客户端 ID 应该设置为创建应用时检索到的 ID。最重要的是,分配一个回调函数,当登录请求成功时激活。 这个回调函数会动态加载 Google+ API:

function onSignInCallback(authResult) {
      gapi.client.load('plus','v1', function(){
        if (authResult['access_token']) {
          $('#gConnect').hide();
 retrieveFriends();
        } else if (authResult['error']) {
          console.log('There was an error: ' + authResult['error']);
          $('#gConnect').show();
        }
        console.log('authResult', authResult);
      });
    }

一旦 Google+的 API 被加载,我们就可以利用它,就像我们在高亮显示的行中所做的那样。 这个函数还隐藏了登录按钮,这样用户就不会尝试多次登录。 retreiveFriends很简单,只需发送一个请求来检索朋友列表:

retrieveFriends: function(){
      var request = gapi.client.plus.people.list({
        'userId': 'me',
        'collection': 'visible'
      });
      request.execute(retrieveFriendsCallback);
    }

现在我们有一个朋友列表,我们可以设置关于建立一个简单的可视化使用他们。

可视化

d3有目的地避免提供具体的可视化。 没有一个单一的功能,你可以调用以得到一个柱状图或散点图。 相反,它提供了围绕创建可视化的工具; 这些工具反过来提供了高度的灵活性,并允许创建独特的可视化。 其中一个更强大的工具是布局机制。 布局提供了一些样板代码,为了实现某种类型的可视化,必须编写这些代码。

我们将利用力向图布局。 力向图提供了一种可视化相互关联的数据的方法。 节点之间的键的强度通常是节点之间紧密联系的函数。

我们的第一步是将数据转换为节点和边的列表。 由于 API 返回这样有限的数据,我们只能在您和您的朋友之间建立关系。 这些关系将组成边缘或链接,而朋友,节点:

var nodes = [];
 var links = [];
var centerNode = { name: "Me"};
nodes.push(centerNode);
for(i = 0; i< data.items.length; i++){
   var node = { name: data.items[i].displayName, image: data.items[i].image.url};
   nodes.push(node);
   links.push({source: centerNode, target: node});
}

现在我们有了节点和链接,我们可以使用它们创建一个力布局:

var graph = d3.select("#graph");
var force = d3.layout.force().charge(-120).linkDistance(100).size([500,500]).nodes(nodes).start();

chargelinkDistance功能决定了节点分散的范围。 对于链接,我们画一条简单的线来表示它们:

var link = graph.selectAll(".link").data(links).enter().append("line").attr("class", "link");

节点有点复杂,因为对于每个节点,我们需要设置一张从 Google+数据拍摄的图片、初始位置以及尺寸。 我们还需要将一个事件处理程序附加到节点上,以便在拖动时触发force.drag动作:

var node = graph.selectAll(".node").data(nodes)
           .enter()
            .append("image")
             .attr("xlink:href", function(d){ return d.image;})
            .attr("class", "node")
            .attr("r", 15)
            .attr("x", 250)
            .attr("y", 250)
            .attr("width", 50)
            .attr("height", 50)
            .call(force.drag);

最后,我们需要指示d3在动画图形时,应该在每个标记上采取什么动作:

force.on("tick", function () {calculatePosition(link, node);});

这将导致一个图形显示我的朋友在 Google+的链接,如下面的截图所示。 如果你点击并拖动一个节点,它将移动,所有的节点将重新平衡自己的移动:

Visualization

小结

Google+的limitedAPI 确实限制了我们可以创建的一些可视化。 多年来一直有传言说谷歌将在 Google+中增加额外的功能,但到目前为止我还没有看到任何实际行动。 现在您应该能够根据 Google+进行身份验证并从中检索数据。 你也应该能够利用图形上令人愉快的强制性布局,从d3以及任何其他可用的布局。