- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
问题,简而言之:如何使用 Google Maps API 以外的其他东西在墨卡托中准确地投影环绕的大圆半径?
问题,长篇大论:
所以我有一个难题。我运行了一个 map 应用程序,它使用 Google Maps API 将巨大的圆圈投影到墨卡托 map 上——它试图显示非常大、精确的半径,比如 13,000 公里的数量级。但是我不想再使用 Google Maps API,因为 Google 的新定价方案太疯狂了。所以我试图将代码转换为 Leaflet、Mapbox 或任何非 Google 的东西,但没有任何东西可以正确处理这些圆圈。
以下是 Google Maps API 如何处理以非洲北部为中心、半径为 13,000 公里的测地线圆:
这在直觉上看起来很奇怪,但却是正确的。波浪图案是由环绕地球的圆圈引起的。
D3.js 可以在正交投影中正确渲染它。所以这里是在 D3.js 中用 d3.geo.circle() 在地球上渲染的同一个圆,旋转两次:
这使得二维“波浪”图案更有意义,对吗?对。我喜欢它。完全适用于我的科学传播和所有目的。
但是当我将代码转换为 Leaflet 时,它根本不起作用。为什么?因为Leaflet的圆类根本就不是大圆。相反,它似乎只是一个随纬度稍微扭曲的椭圆,但不是以真正的测地线方式。相同的圆,相同的半径,相同的原点,我们得到:
大错特错,大错特错!除了看起来完全不现实之外,这是不正确的——澳大利亚不会在这样的圆半径内。这对我的申请很重要!这是做不到的。
好吧,我想,也许诀窍是尝试实现我自己的大圆圈类。我采用的方法是将圆点迭代为距原点的距离,但使用来自 this very helpful website 的“给定距离和距起点的方位角的目标点”计算来计算距离。 ,然后将它们投影为 Leaflet 中的多边形。这就是我得到的结果:
这看起来很糟糕,但实际上更接近准确!我们得到了波浪效应,这是正确的。像我一样,你可能会问,“这里到底发生了什么?”所以我做了一个版本,让我可以突出每个迭代点:
你可以很清楚地看到它正确地渲染了圆,但多边形错误地加入了它。它应该做的(人们可能会天真地认为)是将波形图包裹在墨卡托 map 投影的多个实例周围,不是在顶部天真地将它们连接起来,而是将它们球形地连接起来。像这个粗略的 Photoshop 渲染:
然后多边形会以某种方式“关闭”,表明多边形上方的所有内容也都包含在其中。
不过,我不知道如何在 Leaflet 中实现类似的功能。或者其他任何事情。也许我必须以某种方式自己处理原始 SVG,考虑到缩放状态?或者其他的东西?在我进入那些危险的杂草之前,我想我会征求任何建议/想法/等。也许有一些更明显的方法。
哦,我还尝试了另一件事:使用相同的 d3.geo.circle 构造函数,该构造函数在墨卡托/传单投影的正交投影中效果很好。它产生的结果或多或少与我的“天真”传单大圆实现相同:
我猜这是有希望的。但是,如果您移动原点的经度,D3.js 版本会以更奇怪的方式包装(红色的 D3.js,绿松石色的 Leaflet 类):
如果 D3.js 中有某种方法可以改变它的工作方式,我不会感到惊讶,但我还没有完全深入 D3.js 的兔子洞。我希望 D3.js 能让这个“更容易”(因为它是比 Leaflet 更完整的制图工具),所以我将继续研究这个。
我还没有尝试在 Mapbox-gl 中执行此操作(我想这是“尝试”列表中的下一个)。
反正。谢谢阅读。重申这个问题:如何使用 Google Maps API 以外的其他东西在墨卡托中准确地投影环绕的大圆半径?
最佳答案
是antimeridian cutting那是 GeoJSON需要在传单或 map 框中正确绘制。
对于 d3,它很简单 d3.geoCircle()
, 对于其他不处理反子午线切割的 map 服务,您可以使用 d3 来正确计算输入 json。
主要思想是将 d3 计算的坐标取消投影回 lat-lng,在其计算出的未 protected 特征上使用相同的投影,将被 d3 的反子午线分割。
见 projection.invert()
我开发了示例,运行代码片段并在 d3 绘图上拖动圆圈。
这是结果截图:
<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css"/>
</head>
<body style="margin: 0">
<svg style="display: inline-block"></svg>
<div id="map" style="display: inline-block; width: 350px; height: 260px"></div>
<script>
var tileLayer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png');
var map = L.map('map').setView([0,0], 0).addLayer(tileLayer);
var bounds = [260, 260];
var colorGenerator = d3.scaleOrdinal(d3.schemeCategory10);
var projection = d3.geoMercator().translate([bounds[0] / 2, bounds[1] / 2]).scale(40);
var geoPath = d3.geoPath().projection(projection);
var geoCircle = d3.geoCircle();
var svg = d3.select('svg')
.attr("width", bounds[0])
.attr("height", bounds[1])
.attr("viewbox", "0 0 " + bounds[0] + " " + bounds[1])
.append('g');
svg.append("g")
.append("path")
.datum(d3.geoGraticule())
.attr("stroke", "gray")
.attr('d', geoPath);
function addCircle(center, radius, color) {
var g = svg.append("g");
var drag = d3.drag().on("drag", dragged);
var xy = projection(center);
var path = g.append("path")
.datum({
type: "Polygon",
coordinates: [[]],
x: xy[0],
y: xy[1]
})
.classed("zone", "true")
.attr("fill", color)
.attr("stroke", color)
.attr("fill-opacity", 0.3)
.call(drag);
update(path.datum());
function dragged(d) {
g.raise();
d.x = d3.event.x;
d.y = d3.event.y;
update(d)
}
function update(d) {
center = projection.invert([d.x, d.y]);
var poly = geoCircle.center(center).radius(radius)();
d.coordinates[0] = poly.coordinates[0];
path.attr('d', geoPath);
d.geojson && d.geojson.remove();
d.geojson = L.geoJSON(unproject(path.attr('d')), {
color: color,
}).addTo(map);
}
function unproject(d) {
var features = d.toLowerCase().split('z').join('').split('m');
features.shift();
var coords = features.map(function (feature) {
return feature.split('l').map(function (pt) {
var xy = pt.split(',');
return projection.invert([+xy[0], +xy[1]]);
});
});
return {
type: 'MultiPolygon',
coordinates: [coords]
}
}
}
d3.range(0, 4).forEach(function (i) {
addCircle([-120 + i * 60, 0], i * 10 + 10, colorGenerator(i));
});
</script>
</body>
</html>
function unproject(d, projection) {
var features = d.toLowerCase().split('z').join('').split('m');
features.shift();
var coords = features.map(function (feature) {
return feature.split('l').map(function (pt) {
var xy = pt.split(',');
return projection.invert([+xy[0], +xy[1]]);
});
});
return {
type: 'MultiPolygon',
coordinates: [coords]
}
}
function unproject(geojson) {
var projected = d3.geoProject(geojson, projection);
if (projected.type === "MultiPolygon") {
projected.coordinates = projected.coordinates.map(function(arr) {
return [invert(arr[0])];
});
} else {
projected.coordinates[0] = invert(projected.coordinates[0]);
}
return projected;
}
function invert(coords) {
return coords.map(function(c) {
return projection.invert(c);
});
}
关于d3.js - 使用 D3.js、Leaflet 或 Mapbox 用墨卡托 map 包裹大圆圈,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53022549/
我正在学习构建单页应用程序 (SPA) 所需的所有技术。总而言之,我想将我的应用程序实现为单独的层,其中前端仅使用 API Web 服务(json 通过 socket.io)与后端通信。前端基本上是
当我看到存储在我的数据库中的日期时。 这是 正常 。日期和时间就是这样。 但是当我运行 get 请求来获取数据时。 此格式与存储在数据库 中的格式不同。为什么会发生这种情况? 最佳答案 我认为您可以将
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在尝试使用backbone.js 实现一些代码 和 hogan.js (http://twitter.github.com/hogan.js/) Hogan.js was developed ag
我正在使用 Backbone.js、Node.js 和 Express.js 制作一个 Web 应用程序,并且想要添加用户功能(登录、注销、配置文件、显示内容与该用户相关)。我打算使用 Passpor
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 8 年前。 Improve this ques
我尝试在 NodeJS 中加载数据,然后将其传递给 ExpressJS 以在浏览器中呈现 d3 图表。 我知道我可以通过这种方式加载数据 - https://github.com/mbostock/q
在 node.js 中,我似乎遇到了相同的 3 个文件名来描述应用程序的主要入口点: 使用 express-generator 包时,会创建一个 app.js 文件作为生成应用的主要入口点。 通过 n
最近,我有机会观看了 john papa 关于构建单页应用程序的精彩类(class)。我会喜欢的。它涉及服务器端和客户端应用程序的方方面面。 我更喜欢客户端。在他的实现过程中,papa先生在客户端有类
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我是一个图形新手,需要帮助了解各种 javascript 2D 库的功能。 . . 我从 Pixi.js 中得到了什么,而我没有从 Konva 等基于 Canvas 的库中得到什么? 我从 Konva
我正在尝试将一些 LESS 代码(通过 ember-cli-less)构建到 CSS 文件中。 1) https://almsaeedstudio.com/ AdminLTE LESS 文件2) Bo
尝试查看 Express Passport 中所有登录用户的所有 session ,并希望能够查看当前登录的用户。最好和最快的方法是什么? 我在想也许我可以在登录时执行此操作并将用户模型数据库“在线”
我有一个 React 应用程序,但我需要在组件加载完成后运行一些客户端 js。一旦渲染函数完成并加载,运行与 DOM 交互的 js 的最佳方式是什么,例如 $('div').mixItUp() 。对
请告诉我如何使用bodyparser.raw()将文件上传到express.js服务器 客户端 // ... onFilePicked(file) { const url = 'upload/a
我正在尝试从 Grunt 迁移到 Gulp。这个项目在 Grunt 下运行得很好,所以我一定是在 Gulp 中做错了什么。 除脚本外,所有其他任务均有效。我现在厌倦了添加和注释部分。 我不断收到与意外
我正在尝试更改我的网站名称。找不到可以设置标题或应用程序名称的位置。 最佳答案 您可以在 config/ 目录中创建任何文件,例如 config/app.js 包含如下内容: module.expor
经过多年的服务器端 PHP/MySQL 开发,我正在尝试探索用于构建现代 Web 应用程序的新技术。 我正在尝试对所有 JavaScript 内容进行排序,如果我理解得很好,一个有效的解决方案可以是服
我是 Nodejs 的新手。我在 route 目录中有一个 app.js 和一个 index.js。我有一个 app.use(multer....)。我还定义了 app.post('filter-re
我正在使用 angular-seed用于构建我的应用程序的模板。最初,我将所有 JavaScript 代码放入一个文件 main.js。该文件包含我的模块声明、 Controller 、指令、过滤器和
我是一名优秀的程序员,十分优秀!