使用RequireJS加载D3和Word云布局

时间:2017-05-03 20:08:52

标签: d3.js svg requirejs

尝试使用RequireJS加载D3 v4.8和文字云布局组件(https://github.com/jasondavies/d3-cloud)时遇到问题。当D3.js和d3.layout.cloud.js都被下载到浏览器时,会抛出异常,表明d3.layout.cloud不是函数。

以下是我配置RequireJS的方法:

require.config({
    waitSeconds: 10,

    baseUrl: './scripts',

    paths: {
        d3: 'd3.min',
        jquery: 'jquery-2.1.0.min',
        cloud: 'd3.layout.cloud'
    },

    shim: {


    cloud: {
        deps:['jquery', 'd3']
    }

}

});

抛出异常的代码行是d3.layout.cloud()。size([width,height]),可以在下面的函数中找到:

function wordCloud(selector) {

    var width = $(selector).width();
    var height = $(selector).height();

    //var fill = d3.scale.category20();

    //Construct the word cloud's SVG element
    var svg = d3.select(selector).append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", "translate("+ width/2 +","+ height/2 +")")

    var fill = d3.scale.category20();

    //Draw the word cloud
    function draw(words) {
        var cloud = svg.selectAll("g text")
            .data(words, function(d) { return d.text; })

        //Entering words
        cloud.enter()
            .append("text")
            .style("font-family", "Impact")
            .style("fill", function(d, i) { return fill(i); })
            .attr("text-anchor", "middle")
            .attr('font-size', 1)
            .style("cursor", "hand")
            .text(function(d) { return d.text; })
            .on("click", function (d, i){
                window.open("http://www.google.com/?q=" + d.text, "_blank");
            });

        //Entering and existing words
        cloud
            .transition()
            .duration(600)
            .style("font-size", function(d) { return d.size + "px"; })
            .attr("transform", function(d) {
                return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
            })
            .style("fill-opacity", 1);

        //Exiting words
        cloud.exit()
            .transition()
            .duration(200)
            .style('fill-opacity', 1e-6)
            .attr('font-size', 1)
            .remove();
    }


    //Use the module pattern to encapsulate the visualisation code. We'll
    // expose only the parts that need to be public.
    return {

        //Recompute the word cloud for a new set of words. This method will
        // asycnhronously call draw when the layout has been computed.
        //The outside world will need to call this function, so make it part
        // of the wordCloud return value.
        update: function(words) {

            // min/max word size
            var minSize = d3.min(words, function(d) { return d.size; });
            var maxSize = d3.max(words, function(d) { return d.size; });

            var textScale = d3.scale.linear()
                .domain([minSize,maxSize])
                .range([15,30]);

            d3.layout.cloud().size([width, height])
                .words(words.map(function(d) {
                    return {text: d.text, size: textScale(d.size) };
                }))
                .padding(5)
                .rotate(function() { return ~~(Math.random() * 2) * 90; })
                .font("Impact")
                .fontSize(function(d) { return d.size; })
                .on("end", draw)
                .start();
        }
    }

}

2 个答案:

答案 0 :(得分:4)

最新版本的d3-cloud仅依赖于d3-dispatch,因此它适用于任何版本的D3。我认为这里的问题是您使用RequireJS(AMD)来引用d3.layout.cloud.js文件,但您并未使用RequireJS来使用库(在您的示例中配置为cloud)。请参阅以下example

requirejs.config({
  baseUrl: ".",
  paths: {
    cloud: "d3.layout.cloud" // refers to ./d3.layout.cloud.js
  }
});

requirejs(["cloud"], function(cloud) { // depends on "cloud" defined above
  cloud()
    .size([100, 100])
    .words([{text: "test"}])
    .on("word", function() {
      console.log("it worked!");
    })
    .start();
});

如果您更喜欢使用CommonJS风格的require(…),如果您使用相应的define(…)语法,也可以将其与RequireJS一起使用,就像在此quick example中一样。

答案 1 :(得分:2)

虽然d3-cloud本身兼容D3 V3和V4,但大多数示例都没有,而且您当前的代码不是,它只适用于V3。

要使其适用于V4,您需要替换对d3.scale的所有引用。 例如,d3.scale.category20()变为d3.scaleOrdinal(d3.schemeCategory20)。 对于与两者兼容的小型可运行示例,请参阅Fiddle #1。它使用RequireJS加载d3,d3-cloud和jQuery。尝试在JS部分顶部的require config中更改D3版本。

现在让我们解决V3,因为你的代码依赖于它。还有一些问题:

你必须使用d3和amp;的对象d3cloud&通过调用require获得的jQuery。使用RequireJS,这是异步的(因为它需要以编程方式获取JS脚本,并且只能以异步方式完成浏览器)。您将代码放在回调函数中(有关详细信息,请参阅RequireJS文档):

[编辑:请参阅Jason的替代语法答案。 ]

require(['d3', 'd3cloud', 'jQuery'], function(d3, d3cloud, $) {
    /* Your code here.
       Inside "require" function that you just called,
       RequireJS will fetch the 3 named dependencies,
       and at the end will invoke this callback function,
       passing the 3 dependencies as arguments in required order.
     */
});

在此上下文(和版本)中,d3云主函数在d3.layout.cloud()下不可用,因此您需要将其替换为d3cloud(),假设该参数的名称作为回调传递给{{ 1}}。

您必须确保从不将宽度或高度0传递给require,否则它将进入无限循环。不幸的是,如果您使用d3cloud.size([width, height]),则会很容易发生,具体取决于您网页的内容和可能的“意外”。我建议$(selector).height()例如。

不是编程问题,但是你传递给var height = $(selector).height() || 10;的函数来自一个例子,也许你想改变它:它只产生2个可能的值,0或90,我发现这单调,默认一个更漂亮。所以我在下面的例子中完全删除了这一行。也许你会想要它,只需添加你的.rotate()行。

Fiddle #2:基于您的代码的完整工作示例。