我无法使正射投影通过旋转d3.drag()。它没有响应:
var projection = d3.geoOrthographic()
.scale(100)
.translate([500, 300])
.rotate([55,-40])
.center([0,0])
.clipAngle(90);
var geoPath = d3.geoPath().projection(projection);
svg.call(d3.drag().on('drag', dragged));
function dragged() {
var transform = d3.event.transform;
var r = {x: ?(transform.x), y: ?(transform.y)};
projection.rotate([origin.x + r.x * k, origin.y + r.y]);
updatePaths(svg, graticule, geoPath);
};
Run Code Online (Sandbox Code Playgroud)
我尝试用dragged()a 替换,console.log()即使在这种情况下也没有任何反应(显然没有调用该函数)。我d3.zoom()以类似的方式实施,没有任何问题。我究竟做错了什么?
jsFiddle:https ://jsfiddle.net/sirallen/2L4ajskL/
拖动没有响应的原因是您已经在该SVG上调用了缩放,并且缩放处理了平移。因此,d3.drag要使它起作用,必须使拖动行为优先于平移。
除此之外,没有d3.event.transform拖动事件。根据API,这些是事件对象中的属性:
- target-关联的拖动行为。
- 类型-字符串“开始”,“拖动”或“结束”;参见drag.on。
- subject-拖动主题,由drag.subject定义。
- x-主题的新x坐标;参见drag.container。
- y-主题的新y坐标;参见drag.container。
- dx-自上一次拖动事件以来的x坐标更改。
- dy-自上次拖动事件以来y坐标的变化。
- 标识符-字符串“ mouse”或数字触摸标识符。
- active-当前活动的拖动手势的数量
- sourceEvent-基础输入事件,例如mousemove或touchmove。
所以,你transform会undefined...... 如果你可以调用dragged。
只需将放下d3.drag,即可使用缩放的单击和拖动(平移)旋转地球仪。
这是您的代码,只需最少的更改(我将所有内容放入zoomed)。使用鼠标滚轮进行缩放,然后单击地球以将其拖动:
function createMap() {
var width = 400,
height = 300,
scale = 100,
lastX = 0,
lastY = 0,
origin = {
x: 55,
y: -40
};
var svg = d3.select('body').append('svg')
.style('width', 400)
.style('height', 300)
.style('border', '1px lightgray solid')
var projection = d3.geoOrthographic()
.scale(scale)
.translate([width / 2, height / 2])
.rotate([origin.x, origin.y])
.center([0, 0])
.clipAngle(90);
var geoPath = d3.geoPath()
.projection(projection);
var graticule = d3.geoGraticule();
// zoom AND rotate
svg.call(d3.zoom().on('zoom', zoomed));
// code snippet from http://stackoverflow.com/questions/36614251
var ? = d3.scaleLinear()
.domain([-width, width])
.range([-180, 180])
var ? = d3.scaleLinear()
.domain([-height, height])
.range([90, -90]);
svg.append('path')
.datum(graticule)
.attr('class', 'graticule')
.attr('d', geoPath);
function zoomed() {
var transform = d3.event.transform;
var r = {
x: ?(transform.x),
y: ?(transform.y)
};
var k = Math.sqrt(100 / projection.scale());
if (d3.event.sourceEvent.wheelDelta) {
projection.scale(scale * transform.k)
transform.x = lastX;
transform.y = lastY;
} else {
projection.rotate([origin.x + r.x, origin.y + r.y]);
lastX = transform.x;
lastY = transform.y;
}
updatePaths(svg, graticule, geoPath);
};
};
function updatePaths(svg, graticule, geoPath) {
svg.selectAll('path.graticule').datum(graticule).attr('d', geoPath);
};
createMap();Run Code Online (Sandbox Code Playgroud)
.graticule {
fill: none;
stroke: #777;
stroke-width: .5px;
stroke-opacity: .5;
}Run Code Online (Sandbox Code Playgroud)
<script src="https://d3js.org/d3.v4.min.js"></script>Run Code Online (Sandbox Code Playgroud)
如果您真的想使用d3.drag,这是我建议的解决方案:
首先,创建一个小组来举行您的地球仪:
var group = svg.append("g")
Run Code Online (Sandbox Code Playgroud)
然后,调用拖动到该组:
group.call(d3.drag().on('drag', dragged));
Run Code Online (Sandbox Code Playgroud)
最后,在dragged函数中,使用d3.event.x和d3.event.y:
function dragged(d) {
var r = {
x: ?((d.x = d3.event.x)),
y: ?((d.y = d3.event.y))
};
projection.rotate([origin.x + r.x, origin.y + r.y]);
updatePaths(svg, graticule, geoPath);
};
Run Code Online (Sandbox Code Playgroud)
另外,不要忘记将pointer-events的路径设置为all:由于其填充为none,因此很难在细线上精确地单击。
这是更新的代码,单击地球并拖动它:
var group = svg.append("g")
Run Code Online (Sandbox Code Playgroud)
group.call(d3.drag().on('drag', dragged));
Run Code Online (Sandbox Code Playgroud)
function dragged(d) {
var r = {
x: ?((d.x = d3.event.x)),
y: ?((d.y = d3.event.y))
};
projection.rotate([origin.x + r.x, origin.y + r.y]);
updatePaths(svg, graticule, geoPath);
};
Run Code Online (Sandbox Code Playgroud)