- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我是 d3 的新手,现在已经为一个问题奋斗了两周。
我的目标是将多个 svg:foreignobjects(包含 xhtml:divs)渲染到 d3 地球上。 xhtml:div 的内容/数据来自 csv。初始设置到目前为止有效,因此当页面初始加载时,div(当前显示城市名称,从 csv 中获取的城市位置)位于其相应的正确位置。
但是当用鼠标旋转地球时,xhtml:foreignobjects(或 xhtml:divs)的位置被弄乱了:
任何人都可以在这里提供帮助或者可以给出正确方向的提示吗?
代码:
<script>
var width = 960, height = 500, rotate = [ 0, 0 ], graticule = d3.geo.graticule();
var projection = d3.geo.orthographic().scale(width / (2 * Math.PI)).clipAngle(90);
var mercator = d3.geo.mercator().scale(width / (2 * Math.PI));
var path = d3.geo.path().projection(projection);
var m0, o0;
var cx, cy = {};
var svg;
var cities_csv;
var drag = d3.behavior.drag().on("dragstart", function() {
d3.event.sourceEvent.stopPropagation();
// Adapted from http://mbostock.github.io/d3/talk/20111018/azimuthal.html and updated for d3 v3
var proj = projection.rotate();
m0 = [ d3.event.sourceEvent.pageX, d3.event.sourceEvent.pageY ];
o0 = [ -proj[0], -proj[1] ];
}).on(
"drag",
function() {
if (m0) {
var m1 = [ d3.event.sourceEvent.pageX, d3.event.sourceEvent.pageY ], o1 = [
o0[0] + (m0[0] - m1[0]) / 4, o0[1] + (m1[1] - m0[1]) / 4 ];
projection.rotate([ -o1[0], -o1[1] ]);
}
// Update the map
path = d3.geo.path().projection(projection);
d3.selectAll("path").attr("d", path);
var group = svg.selectAll("g");
//console.log(d3);
d3.selectAll(".point").each(function(d, i) {
console.log(d);
d3.select("#f" + i).attr("x",
projection([ d.coordinates[0], d.coordinates[1] ])[1]+200);
d3.select("#f" + i).attr("y",
projection([ d.coordinates[0], d.coordinates[1] ])[0]-200);
console.log("NR:" + i);
});
});
d3.select("svg").on("mousedown", function() {
console.log("mouse: " + projection.invert(d3.mouse(this)));
});
svg = d3.select("#map").append("svg").attr("width", width).attr("height", height).call(drag).call(
d3.behavior.zoom().on("zoom", redraw));
function redraw() {
//Yet commented out because I just want to scale, not translate
//svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
};
svg.append("defs").append("path").datum({
type : "Sphere"
}).attr("id", "sphere").attr("d", path);
svg.append("use").attr("class", "stroke").attr("xlink:href", "#sphere");
svg.append("use").attr("class", "fill").attr("xlink:href", "#sphere");
svg.append("path").datum(graticule).attr("class", "graticule").attr("d", path);
svg.style("shape-rendering", null);
d3.json("world-110m2.json", function(error, data) {
svg.insert("path", ".graticule").datum(topojson.feature(data, data.objects.countries))
.attr("class", "land").attr("d", path);
});
d3.csv("cities.csv", function(error, data) {
var cities_csv = data;
data.forEach(function(d, i) {
var group = d3.select("svg").append("svg:g").attr("class", "group").attr("id", "g" + i);
var point = group.append("path", ".foreground").datum({
type : "Point",
coordinates : [ d['lon'], d['lat'] ]
}).attr("class", "point").attr("id", "p" + i).attr("data-id", i).attr("d", path).on("click",
function() {
window.open("http://google.com");
}).attr("r", 4).style("fill", "red");
point.select("div").html('<a href= "http://google.com">' + // The first <a> tag
(d.date) + "</a>" + // closing </a> tag
"<br/>" + d.close);
//check if location is clipped
var clipped = false;
clip_test_path = d3.geo.path().projection(projection);
if (typeof (clip_test_path({
type : "MultiPoint",
coordinates : [ [ d.lon, d.lat ] ]
})) === "undefined") {
clipped = true
}
if (clipped == false) {
group.append("foreignObject").attr("d", path).attr("id", "f" + i).attr("data-id", i).attr('class',
'city').attr('width', '100px').attr('height', '100px').attr("x",
projection([ d.lon, d.lat ])[0]).attr("y", projection([ d.lon, d.lat ])[1]).append(
'xhtml:div').style("width", "20px").style("height", "20px").style("padding", "2px").html(
"<small>" + d.city + "</small>");
}
});
});
</script>
最佳答案
我想我已经按照您期望的方式工作了。
更新后的代码是
var width = 960, height = 500, rotate = [ 0, 0 ], graticule = d3.geo.graticule();
var projection = d3.geo.orthographic().scale(width / (2 * Math.PI)).clipAngle(90);
var mercator = d3.geo.mercator().scale(width / (2 * Math.PI));
var path = d3.geo.path().projection(projection);
var m0, o0;
var cx, cy = {};
var svg;
var cities_csv;
var drag = d3.behavior.drag().on("dragstart", function() {
d3.event.sourceEvent.stopPropagation();
// Adapted from http://mbostock.github.io/d3/talk/20111018/azimuthal.html and updated for d3 v3
var proj = projection.rotate();
m0 = [ d3.event.sourceEvent.pageX, d3.event.sourceEvent.pageY ];
o0 = [ -proj[0], -proj[1] ];
}).on(
"drag",
function() {
if (m0) {
var m1 = [ d3.event.sourceEvent.pageX, d3.event.sourceEvent.pageY ], o1 = [
o0[0] + (m0[0] - m1[0]) / 4, o0[1] + (m1[1] - m0[1]) / 4 ];
projection.rotate([ -o1[0], -o1[1] ]);
}
// Update the map
path = d3.geo.path().projection(projection);
d3.selectAll("path").attr("d", path);
d3.selectAll("g").attr("d", path);
var group = svg.selectAll("g");
//console.log(d3);
d3.selectAll(".point").each(function(d, i) {
console.log(d);
var clipped = false;
clip_test_path = d3.geo.path().projection(projection);
if (typeof (clip_test_path({
type : "MultiPoint",
coordinates : [ [ d.coordinates[0], d.coordinates[1] ] ]
})) === "undefined") {
clipped = true
}
console.log(d, clipped)
if (clipped) {
d3.select("#f" + i).style("display", "none");
} else {
d3.select("#f" + i).style("display", null);
}
d3.select("#f" + i).attr("x",
projection([ d.coordinates[0], d.coordinates[1] ])[0]);
d3.select("#f" + i).attr("y",
projection([ d.coordinates[0], d.coordinates[1] ])[1]);
console.log("NR:" + i);
});
});
d3.select("svg").on("mousedown", function() {
console.log("mouse: " + projection.invert(d3.mouse(this)));
});
svg = d3.select("#map").append("svg").attr("width", width).attr("height", height).call(drag).call(
d3.behavior.zoom().on("zoom", redraw));
function redraw() {
//Yet commented out because I just want to scale, not translate
//svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
};
svg.append("defs").append("path").datum({
type : "Sphere"
}).attr("id", "sphere").attr("d", path);
svg.append("use").attr("class", "stroke").attr("xlink:href", "#sphere");
svg.append("use").attr("class", "fill").attr("xlink:href", "#sphere");
svg.append("path").datum(graticule).attr("class", "graticule").attr("d", path);
svg.style("shape-rendering", null);
d3.json("world-110m2.json", function(error, data) {
svg.insert("path", ".graticule").datum(topojson.feature(data, data.objects.countries))
.attr("class", "land").attr("d", path);
});
d3.csv("cities.csv", function(error, data) {
var cities_csv = data;
data.forEach(function(d, i) {
var group = d3.select("svg").append("svg:g").attr("class", "group").attr("id", "g" + i);
var point = group.append("path", ".foreground").datum({
type : "Point",
coordinates : [ d['lon'], d['lat'] ]
}).attr("class", "point").attr("id", "p" + i).attr("data-id", i).attr("d", path).on("click",
function() {
window.open("http://google.com");
}).attr("r", 4).style("fill", "red");
point.select("div").html('<a href= "http://google.com">' + // The first <a> tag
(d.date) + "</a>" + // closing </a> tag
"<br/>" + d.close);
group.append("foreignObject").attr("d", path).attr("id", "f" + i).attr("data-id", i).attr('class',
'city').attr('width', '100px').attr('height', '100px').attr("x",
projection([ d.lon, d.lat ])[0]).attr("y", projection([ d.lon, d.lat ])[1]).append(
'xhtml:div').style("width", "20px").style("height", "20px").style("padding", "2px").html(
"<small>" + d.city + "</small>");
//check if location is clipped
var clipped = false;
clip_test_path = d3.geo.path().projection(projection);
if (typeof (clip_test_path({
type : "MultiPoint",
coordinates : [ [ d.lon, d.lat ] ]
})) === "undefined") {
clipped = true
}
if (clipped) {
d3.select("#f" + i).style("display", "none");
}
});
});
我所做的更改是:
在您的拖动
处理程序中,正确设置foreignObjects
的位置。您已经交换了 x
和 y
位置的值,并且您还从投影位置任意添加/减去 200。
d3.select("#f" + i).attr("x",
projection([ d.coordinates[0], d.coordinates[1] ])[0]);
d3.select("#f" + i).attr("y",
projection([ d.coordinates[0], d.coordinates[1] ])[1]);
在您的拖动
处理程序中,检查裁剪,如果该点被裁剪,则隐藏foreignObject
。我只是重复使用了您稍后用来检测剪辑的代码。
var clipped = false;
clip_test_path = d3.geo.path().projection(projection);
if (typeof (clip_test_path({
type : "MultiPoint",
coordinates : [ [ d.coordinates[0], d.coordinates[1] ] ]
})) === "undefined") {
clipped = true
}
console.log(d, clipped)
if (clipped) {
d3.select("#f" + i).style("display", "none");
} else {
d3.select("#f" + i).style("display", null);
}
在处理初始添加 foreignObjects
的代码中,我将其更改为始终添加 foreignObject
,无论是否被剪裁,以及是否被剪裁, 将 display
设置为 none
以隐藏对象。
group.append("foreignObject").attr("d", path).attr("id", "f" + i).attr("data-id", i).attr('class',
'city').attr('width', '100px').attr('height', '100px').attr("x",
projection([ d.lon, d.lat ])[0]).attr("y", projection([ d.lon, d.lat ])[1]).append(
'xhtml:div').style("width", "20px").style("height", "20px").style("padding", "2px").html(
"<small>" + d.city + "</small>");
//check if location is clipped
var clipped = false;
clip_test_path = d3.geo.path().projection(projection);
if (typeof (clip_test_path({
type : "MultiPoint",
coordinates : [ [ d.lon, d.lat ] ]
})) === "undefined") {
clipped = true
}
if (clipped) {
d3.select("#f" + i).style("display", "none");
}
关于javascript - 如何将 svg 组或异物正确定位到 d3 地球上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28201029/
我正在使用 D3 渲染一个简单的网络图。在每个节点中,我想显示使用该外来对象的 html 内容。外部对象里面有 html。网络正在渲染。但我无法查看 html 内容有人知道为什么它不渲染 html 吗
我有一些对象集合,它们之间具有基本的一对多关系。我的目标是编写一个函数(或必要时可以组合的函数),以便解析/将外部 ID 字段注入(inject)外部对象。 例如,我有以下对象: const stor
我是一名优秀的程序员,十分优秀!