尝试使用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();
}
}
}
答案 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:基于您的代码的完整工作示例。