- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在制作具有点击缩放功能的世界地图。单击一个国家/地区时, map 会放大,但该国家/地区并不总是居中-单击并重复时也会发生同样的情况,它似乎永远不会提供相同的结果。
注意:如果禁用过渡功能,缩放和居中确实有效,只有在添加旋转时才会显示不正确。
我的代码有什么问题?
我创建了一个 plunker
为方便起见 http://plnkr.co/edit/tgIHG76bM3cbBLktjTX0?p=preview
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.background {
fill: none;
pointer-events: all;
stroke:grey;
}
.feature, {
fill: #ccc;
cursor: pointer;
}
.feature.active {
fill: orange;
}
.mesh,.land {
fill: black;
stroke: #ddd;
stroke-linecap: round;
stroke-linejoin: round;
}
.water {
fill: #00248F;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script src="//d3js.org/queue.v1.min.js"></script>
<script>
var width = 960,
height = 600,
active = d3.select(null);
var projection = d3.geo.orthographic()
.scale(250)
.translate([width / 2, height / 2])
.clipAngle(90);
var path = d3.geo.path()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.on("click", reset);
var g = svg.append("g")
.style("stroke-width", "1.5px");
var countries;
var countryIDs;
queue()
.defer(d3.json, "js/world-110m.json")
.defer(d3.tsv, "js/world-110m-country-names.tsv")
.await(ready)
function ready(error, world, countryData) {
if (error) throw error;
countries = topojson.feature(world, world.objects.countries).features;
countryIDs = countryData;
//Adding water
g.append("path")
.datum({type: "Sphere"})
.attr("class", "water")
.attr("d", path);
var world = g.selectAll("path.land")
.data(countries)
.enter().append("path")
.attr("class", "land")
.attr("d", path)
.on("click", clicked)
};
function clicked(d) {
if (active.node() === this) return reset();
active.classed("active", false);
active = d3.select(this).classed("active", true);
var bounds = path.bounds(d),
dx = bounds[1][0] - bounds[0][0],
dy = bounds[1][1] - bounds[0][1],
x = (bounds[0][0] + bounds[1][0]) / 2,
y = (bounds[0][1] + bounds[1][1]) / 2,
scale = 0.5 / Math.max(dx / width, dy / height),
translate = [width / 2 - scale * x, height / 2 - scale * y];
g.transition()
.duration(750)
.style("stroke-width", 1.5 / scale + "px")
.attr("transform", "translate(" + translate + ")scale(" + scale + ")");
var countryCode;
for (i=0;i<countryIDs.length;i++) {
if(countryIDs[i].id==d.id) {
countryCode = countryIDs[i];
}
}
var rotate = projection.rotate();
var focusedCountry = country(countries, countryCode);
var p = d3.geo.centroid(focusedCountry);
(function transition() {
d3.transition()
.duration(2500)
.tween("rotate", function() {
var r = d3.interpolate(projection.rotate(), [-p[0], -p[1]]);
return function(t) {
projection.rotate(r(t));
g.selectAll("path").attr("d", path)
//.classed("focused", function(d, i) { return d.id == focusedCountry.id ? focused = d : false; });
};
})
})();
function country(cnt, sel) {
for(var i = 0, l = cnt.length; i < l; i++) {
console.log(sel.id)
if(cnt[i].id == sel.id) {
return cnt[i];
}
}
};
}
function reset() {
active.classed("active", false);
active = d3.select(null);
g.transition()
.duration(750)
.style("stroke-width", "1.5px")
.attr("transform", "");
}
</script>
最佳答案
这是一个困难的问题 - 我很惊讶地看到没有很好的例子(这个问题可能已经提出 previously 没有解决)。根据问题和您要实现的目标,我认为您的转换过于复杂(也许可以使补间功能更清晰)。而不是在 g
上同时使用转换和投影的修改,您只需修改投影即可实现此目的。
当前方法
当前您平移和缩放 g
,这将平移和缩放 g
到预定的目的地。点击后,g
定位使特征位于中间,然后缩放以展示特征。因此,g
不再以 svg
为中心(因为它已被缩放和平移),换句话说,地球被移动和拉伸(stretch),以便要素居中。没有路径被改变。
此时,您旋转投影,它会根据新旋转重新计算路径。这会将选定的特征移动到 g
的中心,不再以 svg
为中心- 因为该功能已经在 svg
内居中,任何运动都会使它偏心。例如,如果您删除重新缩放和翻译 g
的代码。 ,您会注意到您的功能以点击为中心。
潜在解决方案
你似乎在经历了两次转变:
g
的任一操作来完成。或在 d3 投影内。因此,仅使用 d3 投影来处理 map 转换可能更简单。
path
并稍后转换绘制的路径。
// Store the current rotation and scale:
var currentRotate = projection.rotate();
var currentScale = projection.scale();
p
为了获得我们要缩放到的特征质心,我通过应用的旋转计算出特征的边界框(但我实际上还没有旋转 map )。使用 bbox,我可以获得缩放到所选功能所需的比例:
projection.rotate([-p[0], -p[1]]);
path.projection(projection);
// calculate the scale and translate required:
var b = path.bounds(d);
var nextScale = currentScale * 1 / Math.max((b[1][0] - b[0][0]) / (width/2), (b[1][1] - b[0][1]) / (height/2));
var nextRotate = projection.rotate(); // as projection has already been updated.
// Update the map:
d3.selectAll("path")
.transition()
.attrTween("d", function(d) {
var r = d3.interpolate(currentRotate, nextRotate);
var s = d3.interpolate(currentScale, nextScale);
return function(t) {
projection
.rotate(r(t))
.scale(s(t));
path.projection(projection);
return path(d);
}
})
.duration(1000);
g
.
// Clicked on feature:
var p = d3.geo.centroid(d);
g
,而不是投影,那么您可以实现这一点,但缩放必须在旋转之后 - 因为该特征将在
g
中居中它将以
svg
为中心.看到这个
plunker .您可以在旋转之前计算 bbox,但是如果同时进行两个转换(旋转和缩放),缩放会暂时将地球移离中心。
.attrTween
.
.attrTween
方法是设置从一条路径到另一条路径的过渡,我们需要同时进行缩放。我们不能使用:
path.transition()
.attrTween("d", function()...) // set rotation
.attr("d", path) // set scale
关于d3.js - 带有国家/地区单击和缩放的 d3 世界地图几乎无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45595422/
我正在用 C 写一个高级计算器。正如你所猜到的,它目前有很多函数,我使用一个开关来对每个函数名进行适当的操作。它是这样的: switch(hash_of(function_name_currently
在大约四天的时间里,我一直在收集托管应用程序的性能计数器。在此期间,发生了以下垃圾回收: 第 0 代:133,695 第一代:133,413 第 2 代:133,254 其中一些是使用GC.Colle
我构建了这个: [ Workshop_templates 表 ] id_template | Workshop_name 1 | Conflict resolution 2 | Building tr
我有一个 N 的列表元素,我想抽样 M ( N/2 . IE。当超过一半的值被采样时。但它非常适合 M N/2 时反转问题。 : 注意:这实际上是创建一个大小为 N 的屏蔽列表对于 M 是 Fals
伙计们,我是竞争性编程的新手,我遇到了一个小问题在提供输入的同时在问题中,顶点数从 1 到 n但是我编写程序时考虑到节点是从 0 开始的 但是当我通过从每个边的每个顶点减少 1 来输入测试用例时,我的
在一次旅行中,有多个停靠点,(一个停靠点 = 一个或多个订单加载或交付的地址),按特定顺序排列。 例如: Trip A Trip_order Action Place Ord
我有一个关于由微服务组成的应用程序架构的问题。 我的微服务很少,但在这个问题的上下文中有趣的是: 人力资源 - 这里存储了所有用户数据,如用户名、性别、用户体验等。 工作机会 - 这里存储了每个招聘广
假设我的工作空间(全局环境)中有许多对象,并且我想将大多数对象存储在列表中。这是一个简化的示例: # Put some objects in the workspace A <- 1 B <- 2 C
当我获得与本地时间相同的时间戳时,firebase 生成的服务器时间戳是否会自动转换为本地时间,或者我错过了什么? _firestore.collection("9213903123").docume
我需要帮助才能将未知整数分成给定数量的偶数部分——或者至少尽可能地均匀。各部分之和应为原值,但各部分应为整数,且应尽可能接近。 参数 num: Integer - 应该被分成相等部分的数字 parts
我的 Java 程序中有一个带有 JPanel 的 ScrollPane,它附加了大量文本。我需要 ScrollPane 在每次添加后滚动到最底部。我对以下代码的问题是它“几乎”滚动到底部但不是一直滚
我想检查两个稀疏数组是否(几乎)相等。而对于 numpy 数组,你可以这样做: import numpy as np a = np.ones(200) np.testing.assert_array_
我有以下一组几乎相同的 each 语句。我需要添加大约 20 个遵循类似模式的内容。我正在尝试找出如何获取小变量并将它们更新为单个语句(而不是 20 次相同但略有不同的内容)。 $.each(main
所以我想获取两个字典中(几乎)匹配的键的值并将它们连接起来。我尝试过: dict3 = {key:dict1[key].strip() for key in dict2.keys() if key.p
我的表看起来像这样: | id (int) | sentence (varchar) | 我想找到除了一个特定单词之外几乎相同的所有行。例如: | 230 | test | | 321 | test
起始情况:MS SQL 中有一个现有的数据库模式,它与 MySQL 中的现有模式完全相同(数据库优先 - 无法更改,因为已广泛安装)。但是,它们在用于相应列的数据类型方面可能略有不同。该数据库系统必须
对于复杂的元素,一个很好的做法是(几乎)总是在闭包中定义 Polymer 以保持所有只应在内部修改的变量和方法私有(private),而不是将它们附加到元素(例如 'this ')? 喜欢以下内容:
我正在解析 Java 中的 RestAssured 调用,该调用返回对象列表。如果我使用此代码,Idea 会生成未经检查的分配警告: List availableInventories = ListP
我真的被难住了。我所拥有的是一个样式化为矩形的 div,其中包含作为页面主要标题的文本。相关代码如下: HTML: SIN CSS: h1 { text-align:right
我需要将单选按钮及其旁边的文本包装在标签中,只是为了更加用户友好。 几天前我遇到了类似的问题,我有一个复选框,并且在我有一个 span 元素之后立即出现。我可以包装这两个元素。 我有这个 HTML:
我是一名优秀的程序员,十分优秀!