【发布时间】:2016-08-18 21:32:33
【问题描述】:
我最近的任务是为我的 Wurm Online 游戏联盟创建地图。我在游戏地图的静态图像上制作了一个天才的基于 SVG 的叠加层。基本上,它从电子表格中获取数据并将村庄呈现为地图上的彩色圆圈。
但是,我们的成员遍布整个地图,因此我开始研究如何创建可缩放的基于网络的我们土地的地图。游戏管理员每年左右都会给我们一个地图转储,因此我们可以根据自己的感觉创建自定义地图应用程序。我下载了我关心的岛屿/服务器 Xanadu 的最新地图转储。
Xanadu 转储文件为 62MB PNG,分辨率为 8192 x 8192 像素。我找到了一个瓷砖制作程序(MapTiler 版本 7),然后我开始制作瓷砖。瓷砖完成渲染后,程序本身会以编程方式创建嵌入了 JavaScript 的 HTML 文件。它让我在使用 OpenLayers3 方面领先一步。
我能够重新计算村庄坐标,并用村庄圆圈拼凑出一张可缩放的平铺地图。不用说,当我得到我的自定义 OpenLayers3 地图时,我非常高兴。 (工作示例:http://jackswurmtools.com/Content/Static/map.html)
按照我的设置方式,每个地图“装饰”或彩色圆圈都是它自己的矢量。
我的游戏玩家对我的可缩放地图的主要抱怨是,彩色村庄圆圈在缩小时太大,而在放大时又太小。 我尝试了各种各样的事情,但我还没有找到合适的例子。我习惯于根据事件查找和转换 SVG 元素,但 OP3 画布渲染在 DOM 中对我来说并不明显。
我的一些问题是:
- 如何检测我的地图何时被缩放?有没有我错过的回调?
- 当检测到缩放时,如何遍历所有向量并更新圆半径。
// jacks fully zoomable xanadu map
var data =
[{
X: "6744",
Y: "-2355.75",
Name: "Amish Creek",
Villagers: ["Aniceset", "Fulano"],
BackColor: "Aquamarine",
LandMarkType: "Member"
}, {
X: "6808.75",
Y: "-2265.125",
Name: "Amish Estates",
Villagers: ["Aniceset", "Villagers"],
BackColor: "Purple",
LandMarkType: "Member"
}];
console.log(data);
var mapExtent = [0.00000000, -8192.00000000, 8192.00000000, 0.00000000];
var mapMinZoom = 0;
var mapMaxZoom = 5;
var mapMaxResolution = 1.00000000;
var tileExtent = [0.00000000, -8192.00000000, 8192.00000000, 0.00000000];
var mapResolutions = [];
for (var z = 0; z <= mapMaxZoom; z++) {
mapResolutions.push(Math.pow(2, mapMaxZoom - z) * mapMaxResolution);
}
var mapTileGrid = new ol.tilegrid.TileGrid({
extent: tileExtent,
minZoom: mapMinZoom,
resolutions: mapResolutions
});
var features = [];
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.XYZ({
projection: 'PNGMAP',
tileGrid: mapTileGrid,
url: "http://jackswurmtools.com/Content/Static/{z}/{x}/{y}.png"
})
}),
],
view: new ol.View({
zoom: 4,
center: [6602.375, -2250.3125],
projection: ol.proj.get('PNGMap'),
maxResolution: mapTileGrid.getResolution(mapMinZoom)
}),
});
map.getView();
map.on('singleclick', function(evt) {
var coord = evt.coordinate;
console.log(coord);
$("#coord-overlay").html("[" + coord[0] + ", " + coord[1] + "]");
});
// zoom stuff?
// add layers via JSON iteration
renderSVG(data);
drawLines();
function renderSVG(data) {
var vectorSource = new ol.layer.Vector({});
console.log(map.getView().getZoom());
jQuery.each(data, function() {
var fill = new ol.style.Fill({
color: this.BackColor
});
var stroke = new ol.style.Stroke({
color: [180, 0, 0, 1],
width: 1
});
var style = new ol.style.Style({
image: new ol.style.Circle({
fill: fill,
stroke: stroke,
radius: map.getView().getZoom() * 5,
opacity: 0.7
}),
fill: fill,
stroke: stroke,
text: new ol.style.Text({
font: '12px helvetica,sans-serif',
text: this.Name,
fill: new ol.style.Fill({
color: '#000'
}),
stroke: new ol.style.Stroke({
color: '#fff',
width: 2
})
})
});
var point_feature = new ol.Feature({});
var point_geom = new ol.geom.Point([this.X, this.Y]);
point_feature.setGeometry(point_geom);
var vector_layer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [point_feature],
})
});
vector_layer.setStyle(style);
map.addLayer(vector_layer);
});
}
function drawLines() {
var stroke = new ol.style.Stroke({
color: [255, 0, 0, 1],
width: 6
});
var style = new ol.style.Style({
fill: null,
stroke: stroke,
text: new ol.style.Text({
font: '12px helvetica,sans-serif',
text: "Sandokhan / Wargasm Canal",
fill: new ol.style.Fill({
color: '#000'
}),
stroke: new ol.style.Stroke({
color: '#fff',
width: 2
})
})
});
var line_feature = new ol.Feature({});
var coords = [
[6607.5, -1921],
[6894, -1921]
];
var layerLines = new ol.layer.Vector({
source: new ol.source.Vector({
features: [new ol.Feature({
geometry: new ol.geom.LineString(coords, 'XY'),
name: 'Line',
})]
})
});
layerLines.setStyle(style);
map.addLayer(layerLines);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.8.2/ol.min.css" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.8.2/ol.min.js" type="text/javascript"></script>
<div id="map"></div>
<div id="coord-overlay">[6612, -2252]</div>
<input id="slider" type="range" min="0" max="1" step="0.1" value="1" oninput="layer.setOpacity(this.value)">
【问题讨论】:
-
我认为我的脱节之一是我将我的所有圈子作为单独的向量添加到我的 Village 数据迭代器中。我的首要任务是将圆圈作为多个特征添加到单个向量中。
-
所以,我对我的代码有点小题大做。我仍然无法摆脱村庄点的多层。现在我需要弄清楚如何以迭代的方式定位向量。
-
嘿伙计们.. 我已经在 OL3 和矢量图层操作方面付出了很多努力。相反,我发现集成 OL3 和 D3 是我想去的地方。按照这个例子:link,我能够在我的 Tile 层上覆盖一个 SVG 层,然后重新计算我的 SVG 与地图渲染后事件协调:map.on('postrender', function (event) { //stuff } );