我在同一个网页上制作了散点图和等值线图。数据存储在.CSV
和.json
中,元素与"名称"字段。
我已经在鼠标悬停上做了一个工具提示。我现在想要它们之间的一些交互性:当鼠标在散点图上的一个元素上时,这个元素在等值线上会起作用,当鼠标在等值线上时,地图散点图反应。
Scatterplot和choropleth是不同的div
,具体为ID
,我不知道如何从一个到另一个。我尝试了d3.select("this#scatterplot");
this example,但它对我不起作用。
如何选择不同DIV
和不同functions
?
我想要这样的事情:
function handleMouseOverMap(d, i) {
d3.select('this#choropleth').style('stroke-width', 3);
d3.select('this#scatterplot').attr('r', 8);
}
function handleMouseOverGraph(d, i) {
d3.select('this#scatterplot').attr('r', 8);
d3.select('this#choropleth').style('stroke-width', 3);
}
代码
<div id="scatterplot"></div>
<div id="choropleth"></div>
<script>
d3.queue()
.defer(d3.csv, 'data.csv', function (d) {
return {
name: d.name,
sau: +d.sau,
uta: +d.uta
}
})
.defer(d3.json, 'dept.json')
.awaitAll(initialize)
var color = d3.scaleThreshold()
.domain([150000, 300000, 450000])
.range(['#5cc567', '#e7dc2b', '#e59231', '#cb0000'])
function initialize(error, results) {
if (error) { throw error }
var data = results[0]
var features = results[1].features
var components = [
choropleth(features),
scatterplot(onBrush)
]
function update() {
components.forEach(function (component) { component(data) })
}
function onBrush(x0, x1, y0, y1) {
var clear = x0 === x1 || y0 === y1
data.forEach(function (d) {
d.filtered = clear ? false
: d.uta < x0 || d.uta > x1 || d.sau < y0 || d.sau > y1
})
update()
}
update()
}
/* Graphique */
function scatterplot(onBrush) {
var margin = { top: 10, right: 15, bottom: 40, left: 75 }
var width = 680 - margin.left - margin.right
var height = 550 - margin.top - margin.bottom
var x = d3.scaleLinear()
.range([0, width])
var y = d3.scaleLinear()
.range([height, 0])
// Tooltip
var xValue = function(d) { return d.sau;};
var yValue = function(d) { return d.uta;};
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var xAxis = d3.axisBottom()
.scale(x)
.tickFormat(d3.format(''))
var yAxis = d3.axisLeft()
.scale(y)
.tickFormat(d3.format(''))
// Selection
var brush = d3.brush()
.extent([[0, 0], [width, height]])
.on('start brush', function () {
var selection = d3.event.selection
var x0 = x.invert(selection[0][0])
var x1 = x.invert(selection[1][0])
var y0 = y.invert(selection[1][1])
var y1 = y.invert(selection[0][1])
onBrush(x0, x1, y0, y1)
})
var svg = d3.select('#scatterplot')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
var bg = svg.append('g')
var gx = svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
var gy = svg.append('g')
.attr('class', 'y axis')
gx.append('text')
.attr('x', width)
.attr('y', 35)
.style('text-anchor', 'end')
.style('fill', '#000')
.style('font-weight', 'bold')
.text('UTA')
gy.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', 0)
.attr('y', -55)
.style('text-anchor', 'end')
.style('fill', '#000')
.style('font-weight', 'bold')
.text('SAU - ha')
svg.append('g')
.attr('class', 'brush')
.call(brush)
return function update(data) {
x.domain(d3.extent(data, function (d) { return d.uta })).nice()
y.domain(d3.extent(data, function (d) { return d.sau })).nice()
gx.call(xAxis)
gy.call(yAxis)
var bgRect = bg.selectAll('rect')
.data(d3.pairs(d3.merge([[y.domain()[0]], color.domain(), [y.domain()[1]]])))
bgRect.exit().remove()
bgRect.enter().append('rect')
.attr('x', 0)
.attr('width', width)
.merge(bgRect)
.attr('y', function (d) { return y(d[1]) })
.attr('height', function (d) { return y(d[0]) - y(d[1]) })
.style('fill', function (d) { return color(d[0]) })
var circle = svg.selectAll('circle')
.data(data, function (d) { return d.name })
circle.exit().remove()
circle.enter().append('circle')
.attr('r', 4)
.style('stroke', '#fff')
.merge(circle)
.attr('cx', function (d) { return x(d.uta) })
.attr('cy', function (d) { return y(d.sau) })
.style('fill', function (d) { return color(d.sau) })
.style('opacity', function (d) { return d.filtered ? 0.5 : 1 })
.style('stroke-width', function (d) { return d.filtered ? 1 : 2 })
// Event
.on("mouseover", function(d) {
tooltipOverGraph.call(this, d);
handleMouseOverGraph.call(this, d);
})
.on("mouseout", function(d) {
tooltipOutGraph.call(this, d);
handleMouseOutGraph.call(this, d);
})
}
// Tooltip
function tooltipOverGraph(d) {
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(d["name"] + "<br>" + xValue(d)
+ " ha" +", " + yValue(d) + " UTA" )
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
}
function tooltipOutGraph(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
}
}
// Create Event Handlers for mouse
function handleMouseOverGraph(d, i) {
d3.select(this).attr('r', 8);
}
function handleMouseOutGraph(d, i) {
d3.select(this).attr('r', 4);
}
/* Carte */
function choropleth(features) {
var width = 680
var height = 550
// Tooltip
var xValue = function(d) { return d.sau;};
var yValue = function(d) { return d.uta;};
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Projection et centrage de la carte
var projection = d3.geoMercator()
.center([ 3, 46.5 ])
.scale([width * 3.1])
.translate([width / 2, height / 2])
var path = d3.geoPath().projection(projection)
var svg = d3.select('#choropleth')
.append('svg')
.attr('width', width)
.attr('height', height)
svg.selectAll('path')
.data(features)
.enter()
.append('path')
.attr('d', path)
.style('stroke', '#fff')
.style('stroke-width', 1)
// Event
.on("mouseover", function(d) {
tooltipOverMap.call(this, d);
handleMouseOverMap.call(this, d);
})
.on("mouseout", function(d) {
tooltipOutMap.call(this, d);
handleMouseOutMap.call(this, d);
})
// Tooltip
function tooltipOverMap(d) {
tooltip.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(d["name"] + "<br>" + xValue(d)
+ " ha" +", " + yValue(d) + " UTA" )
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 28) + "px");
}
function tooltipOutMap(d) {
tooltip.transition()
.duration(500)
.style("opacity", 0);
}
return function update(data) {
svg.selectAll('path')
.data(data, function (d) { return d.name || d.properties.name })
.style('fill', function (d) { return d.filtered ? '#ddd' : color(d.sau) })
}
}
// Create Event Handlers for mouse
function handleMouseOverMap(d, i) {
d3.select(this).style('stroke-width', 3);
}
function handleMouseOutMap(d, i) {
d3.select(this).style('stroke-width', 1);
}
</script>
答案 0 :(得分:0)
首先,当您输入+追加它们时,为class
和rect
项添加不同的circle
属性:
bgRect.enter().append('rect')
.attr('class', function(d,i) { return 'classRect' + i; })
circle.enter().append('circle')
.attr('class', function(d,i) { return 'classCircle' + i; })
然后,将鼠标更新为功能:
function handleMouseOverMap(d) {
// update the choropleth //
d3.select(d).style('stroke-width', 3);
// update the scatterplot //
// capture the number contained in class (e.g. "1" for "classRect1")
var i = d3.select(d).class.substr(-1);
// select corresponding circle in scatter and update
d3.select('circle.classCircle'+i).attr('r', 8);
}
function handleMouseOverGraph(d) {
// update the scatter //
d3.select(d).attr('r', 8);
// update the choropleth //
// capture the number contained in class (e.g. "1" for "classCircle1")
var i = d3.select(d).class.substr(-1);
// select corresponding rect in the choropleth and update
d3.select('rect.classRect'+i).style('stroke-width', 3);
}