答案 0 :(得分:3)
我是function-plot的作者,它能够将事件分派到多个图表中,其中一个是mouseover
,例如
var width = 300
var height = 180
var a = functionPlot({
target: '#a',
height: height,
width: width,
data: [{ fn: 'x^2' }]
})
var b = functionPlot({
target: '#b',
height: height,
width: width,
data: [{ fn: 'x' }]
})
a.addLink(b)
b.addLink(a)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/function-plot/1.16.5/function-plot.js"></script>
<span id="a" />
<span id="b" />
解决方案涉及让每个图表在某个事件被触发时执行某些操作,例如d3调度事件的方式是
// create a dispatcher with the events you will fire in the future
var dispatch = d3.dispatch('mycustomevent');
// add some callbacks (note the namespace)
dispatcher.on('mycustomevent.graph1, function (str) {
// when called str === 'hello world'
})
dispatcher.on('mycustomevent.graph2, function (str) {
// when called str === 'hello world'
})
// fire the event from the dispatcher
// the two callbacks attached are called in the same order
dispatch.mycustomevent('hello world')
实际上,只要您在图表上执行鼠标悬停而不是立即执行操作,就可以触发自定义事件并让每个图表执行鼠标悬停时需要执行的操作
// create a dispatcher
var dispatch = d3.dispatch('mymouseover');
function graphWrapper(graph) {
return function (xCoord) {
// do something with `xCoord` in `graph`
}
}
dispatcher.on('mymouseover.graph1, graphWrapper(graph1))
dispatcher.on('mymouseover.graph2, graphWrapper(graph2))
// graph1 and graph2 need to fire the custom event
function dispatchMouseOver() {
var xCoord = x.invert(d3.mouse(this)[0])
dispatch.mymouseover(xCoord)
}
graph1.on('mousemove', dispatchMouseOver)
graph2.on('mousemove', dispatchMouseOver)
对于我在@In code veritas引用的可重复使用的图表修改an example made by d3's author的实现
如您所见,每个图表彼此独立,在执行pub-sub模式后,它看起来像这样
作为旁注,我使用节点的事件模块在功能图中实现了这个特征,基本上是因为在d3中你在相同的命名空间下使用不同的名称添加回调,例如mymouseover.1
,mymouseover.2
等等,但在节点的事件模块中,您只需多次执行graph.on('event', callback)
答案 1 :(得分:2)
这取决于您创建图表的方式。
如果您使用嵌套的输入模式(绑定数据,输入svgs,然后从嵌套数据输入每个图表),那么它与您有两个单独创建的图表略有不同。
但一般情况下,请查看at this example以获取示例。
您首先会创建未显示的文字和圆圈叠加层:
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
在您的情况下,为每个图表创建它们。
然后设置叠加并捕获鼠标悬停:
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
focus.select("text").text(formatCurrency(d.close));
}
在您的情况下,由于您的图表具有相同的宽度,因此您可以对每个图表的x(d.date)比例返回使用相同的x转换。
对于y值来说,事情有点琐碎。
如果你使用不同的数据集,你可能会有类似的东西。如果要嵌套单个数据集,则需要以不同方式使用密钥索引:
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
var d02 = data2[i - 1],
d12 = data2[i],
d2 = x0 - d02.date > d12.date - x0 ? d12 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
focus.select("text").text(formatCurrency(d.close));
focuslowerchart.attr("transform", "translate(" + x(d.date) + "," + (yLower(d2.close) + ")");
focuslowerchart.select("text").text(formatCurrencyLower(d.close));
}
以上假设图表之间的i
索引相同。如果数据集的排序方式不同,则需要进行不同的分割。