• 在hexo静态博客中利用d3-cloud来展现标签云


    效果: http://lucyhao.com/tags/

    hexo自带的tag cloud的标签展现不太美观,想能够展现出“云”效果的标签。在网上找到了d3-cloud这个项目,github地址:https://github.com/jasondavies/d3-cloud demo地址:https://www.jasondavies.com/wordcloud/

    hexo生成的是静态博客,所以最后在网上看到的都是静态的内容,也就是说,我们的看到的标签云也是静态的已经生成好的内容,并不会随着刷新页面而重新计算生成另外样式的标签云。

    当然d3-cloud这个项目,提供了浏览器端和node端运行的版本,见它的例子,我们可以在客户端运行,也可以在服务端作为 node运行。

    如何在hexo搭建的博客系统中使用呢?

    (1)hexo中提供的tag cloud.js的方法,在你的blog项目中,node_modules -> hexo ->plugins -> helper -> tagcloud.js

    (2)本博客使用的是icarus主题,在主题下的layout->tags.ejs 文件中加载目录tags下面的内容

    //这里加载了标签云,tagcloud也就是(1)中tagcloud.js提供的功能
      <div class="layout-wrap-inner tag-cloud">
        <% if(site.tags.length) { %>
            <%- tagcloud() %>
        <% } %>
      </div>
    

      

    由上所知 ,要修改hexo中的tagcloud, 只要修改tag cloud.js函数就可以啦~

    现在我们来看看d3-cloud这个项目,如何把它与tagcloud结合起来。 首先,d3-cloud提供了在浏览器和在服务端运行的方式,见他的例子node.js和browserify.js。两个不同版本的原因,是因为在计算字符串的宽度的时候,利用了canvas的mesureText接口。在d3-cloud的 index.js源码中可以看到,有一行代码是

    function cloudCanvas() {
      return document.createElement("canvas");//生成虚拟的canvas
    }
    

      

    因为在计算标签云的时候,要保证标签之间不重叠,需要知道标签的宽度,高度;而js语言是不具备这个能力可以计算出来的,要不就是借助浏览器,生成一个dom,比如span标签,把字符串的内容放到span中,设置span的属性为字符串需要显示的属性,然后获取span的宽度。在d3-cloud中,则是直接利用canvas的接口来实现的。所以在客户端的版本中,浏览器提供的canvas功能;而在node版本中则需要 node-canvas模块。

    由于我们是在hexo的“后台”来运行标签云的算法,得到静态的构造好的标签输出到页面上,所以我们应该选择用node版本。当然也可以用browserify.js版本,毕竟他就是一个运行在浏览器中的js, 放到博客的js中也是可以的,后续会介绍。

    利用node-canvas遇到的问题

    node-canvas模块的mesureText对于中文的支持有bug,在chrome中,同样的中文字符串"你好"的宽度是33.*;而用node-canvas的到的“你好”的宽度只有8.*

    怎么办?我投机取巧的用两个英文字符“ab”代替一个中文字符,然后计算字符串的长度,这样的到的长度只是近似长度。

    正式开始修改hexo的到d3-cloud的标签云

    (1)安装需要的模块:

    $ npm install canvas --save
    $ npm install d3-cloud --save
    $ npm install d3 --save(可选)
    

      

    (2)找到文件: 你的 blog项目 -> node_modules -> hexo ->plugins -> helper -> index.js

      var tagcloud = require('./tagcloud');
      helper.register('tagcloud', tagcloud);
      helper.register('tag_cloud', tagcloud);
    ​
      //修改为下面的代码:目的是不直接修改tagcloud.js,保留代码
      var tagcloud = require('./tagcloud');
      var tagcloudd3 = require('./tagcloudd3');
      helper.register('tagcloud', tagcloudd3);
      helper.register('tag_cloud', tagcloudd3);
    

      

    (3)新建文件tagcloudd3.js :位置在blog项目 -> node_modules -> hexo ->plugins -> helper -> tagcloudd3.js

    (4)tagcloudd3.js的 内容如下:

    • 代码中引用了d3 来给标签fill颜色,可以去掉,也可以像tagcloud一样根据是否需要颜色来设置

    'use strict';
    ​
    var Canvas = require("canvas");
    var cloud = require("d3-cloud");
    var d3 = require("d3");
    ​
    var layout = cloud()//利用d3-cloud计算每个标签的位置
        .size([600, 400])
        .canvas(function() { return new Canvas(1, 1); })
        .padding(7)
        .rotate(function() { return ~~(Math.random() * 2) * 90; })
        .font("Impact")
        .fontSize(function(d) { return d.size; });
    var fill = d3.scale.category20();//利用d3的接口给每个标签颜色
    ​
    function tagcloudHelper(tags){
      /****与tagcloud.js一样,获得tags 开始***/
      if ((!tags || !tags.hasOwnProperty('length'))){
        tags = this.site.tags;
      }
    ​
      if (!tags || !tags.length) return '';
      
      var result = [];
    ​
      tags = tags.sort('name', 1);
    ​
      // Ignore tags with zero posts
      tags = tags.filter(function(tag){
        return tag.length;
      });
     /****与tagcloud.js一样,获得tags 结束***/
      
      //计算标签出现次数最大值,比如,博客中一共有两个标签,一个是hello,一个是world,hello出现2次,world 出现1次,那么maxsize就是2
      var maxsize = 1;
    ​
      tags.sort('length').forEach(function(tag){
        var length = tag.length;
        if(length > maxsize)
            maxsize = length;
      });
    ​
     //构建传入layout的words
      var arr = [],words;
      tags.forEach(function(tag){
         arr.push({"name": tag.name,"num" : tag.length});
      });
      words = arr.map(function(d) {
          var text = d.name.replace(/[^x00-xff]/g,"ab");//对中文的投机处理,用ab代替中文字符
          return {name:d.name, text: text, size : Math.log(d.num)/(Math.log(maxsize)-Math.log(1)) * 15 + 30};//size的计算取对数,是为了让标签之间的大小相对平均一些。因为博客侧重前端内容,所以某一些标签会比较多,标签最大最小次数的差距会比较大。
        
      });
      layout.words(words);
      layout.start();
    ​
      result.push('<svg width="600" height="400"><g transform="translate(300,200)">');
      words.forEach(function(word,i){
    ​
        result.push(
          '<text text-anchor="middle" fill="'+fill(i)+'" transform="translate('+word.x+','+word.y+')rotate('+
            word.rotate+')" style="font-size:'+word.size+'px;font-family:Impact">'+
            word.name+
          '</text>'
        );
      });
      result.push('</g></svg>');
      
      return result.join('');
      
    }
    module.exports = tagcloudHelper;
    

      

    (5)运行hexo

    $ hexo s
    

      

    如图所示得到自己的标签云:

    tags

    (6)上传自己的博客, 没问题以后,就生成静态博客,并上传

    $ hexo g
    $ hexo d
    

    简单说下在客户端引用d3-cloud

     (1) browserify编译d3-cloud提供的browserify.js例子,得到tagtest.js 文件,里面把d3,d3-cloud,d3-dispatch打包到了一起

    $ browserify broswerify.js > tagtest.js

    (2)把index.js放到目录: 你的主题->source -> js -> tagtest.js

    (3)把index引用入到你的主题中 <%- js('js/tagtest') %>

    (4)修改tagtest.js中的代码,把words的部分修改成接受传参的形式,在tags.ejs中用site.tags把tags的参数传进去

    这样会在博客中增加很多js,个人觉得有点违背了静态博客小而轻的感觉。。。

  • 相关阅读:
    href 和src 的区别
    一道返回不重复数组的测试题
    使用Node.js+Socket.IO搭建WebSocket实时应用
    WebSocket 是什么原理?为什么可以实现持久连接?
    图片异步加载
    30分钟新手git教程
    通过ajax异步调用返回值
    [JS] 让人犯晕的JavaScript变量赋值
    javaScript字符串操作
    (String),toString(),String.valueOf()
  • 原文地址:https://www.cnblogs.com/lilyimage/p/5207697.html
Copyright © 2020-2023  润新知