diff --git a/README.md b/README.md
index bc2fb14..3814a00 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,13 @@
-对接他人提供的底图服务
-
-然后是开发自己的底图服务,结构可以参考现成已有的
-
-
-## 参考链接
-https://xcsf.github.io/blog/2020/06/12/%E7%93%A6%E7%89%87Tile%E5%9C%B0%E5%9B%BE%E5%8E%9F%E7%90%86/
-https://xcsf.github.io/blog/2020/06/12/%E7%93%A6%E7%89%87Tile%E8%A1%8C%E5%88%97%E5%8F%B7%E8%AE%A1%E7%AE%97%E6%96%B9%E6%B3%95/
-https://github.com/RLwu/GIS
-https://switch2osm.org/using-tiles/getting-started-with-leaflet/
-https://leafletjs.cn/
-https://zh.wikipedia.org/wiki/%E9%BA%A5%E5%8D%A1%E6%89%98%E6%8A%95%E5%BD%B1%E6%B3%95
-https://zh.wikipedia.org/wiki/Web%E5%A2%A8%E5%8D%A1%E6%89%98%E6%8A%95%E5%BD%B1
-https://web.archive.org/web/20220421120137/https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
-https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
-https://en.wikipedia.org/wiki/Web_Mercator_projection
-https://web.archive.org/web/20141009142830/http://earth-info.nga.mil/GandG/wgs84/web_mercator/(U)%20NGA_SIG_0011_1.0.0_WEBMERC.pdf
-https://www.openstreetmap.org/#map=15/22.7602/114.3888&layers=D
-https://en.wikipedia.org/wiki/Eccentricity_(mathematics)#:~:text=The%20eccentricity%20of%20an%20ellipse%20is%2C%20most%20simply%2C%20the%20ratio,of%20the%20semimajor%20axis%20a.&text=(Flattening%20may%20be%20denoted%20by,if%20f%20is%20linear%20eccentricity.)
-
-http://wiki.gis.com/wiki/index.php/Geodetic_system
-https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/textBaseline
-https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/textAlign
\ No newline at end of file
+## 项目概述
+为地图类网页app添加底图支持,目前仅支持加载web墨卡托的瓦片底图
+暂时选择的是gaode的普通底图,可无缝切换为openstreetmap底图服务
+
+## Features
+将屏幕坐标系映射到投影平面,为坐标转化提供支持,见viewport
+将viewport和底图加载的逻辑分离开
+事件和绘制逻辑在basemap中,对外直接使用basemap挂载到canvas就行 (参考index.js)
+支持设置初始位置,和记忆上次查看位置
+
+## tips
+坐标转化 是直接进行像素级的映射
+缩放在瓦片地图那一层已经定义好了,不需要再额外转化
\ No newline at end of file
diff --git a/add web b/add web
deleted file mode 100644
index 89c71db..0000000
--- a/add web
+++ /dev/null
@@ -1,32 +0,0 @@
- web:
- image: nginx
- ports:
- - 1080:80
- volumes:
- - ./nginx_conf/nginx:/etc/nginx
- - ./dist:/usr/share/nginx/html:ro
-
-#include /etc/nginx/conf.d/*.conf;
- server {
- listen 80;
- #listen [::]:80;
- server_name localhost;
-
- location / {
- root /usr/share/nginx/html;
- index index.html index.htm;
- }
-
- location /m {
- rewrite .* /index.html permanent;
- }
-
- #error_page 404 /404.html;
- # redirect server error pages to the static page /50x.html
- #
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root /usr/share/nginx/html;
- }
- }
-
diff --git a/ellipsode.js b/ellipsode.js
deleted file mode 100644
index 5cbca6e..0000000
--- a/ellipsode.js
+++ /dev/null
@@ -1,305 +0,0 @@
-//椭球相关参数计算
-const a = 6378137; //长半轴 a
-const f = 1 / 298.257223563; //扁率 (a-b)/a
-const b = a * (1 - f);//短半轴 b
-const e = Math.sqrt(a * a - b * b) / a;//椭球第一偏心率
-
-// console.log(a);
-// console.log(f);
-// console.log(b);
-// console.log(e);
-// console.log(e*e);
-
-function degToRad(deg) {
- return deg / 180 * Math.PI;
-}
-
-function radToDeg(rad) {
- return rad / Math.PI * 180;
-}
-
-function wgs84ToWebMercator(lat, lon) {
- let x = a * lon;
- let y = a * Math.log(Math.tan(Math.PI / 4 + lat / 2));
- return { x: x, y: y };
-}
-
-function webMercatorToWgs84(x, y) {
- let lon = x / a;
- let lat = 2 * Math.atan(Math.pow(Math.E, y / a)) - Math.PI / 2;
- return { lon: lon, lat: lat }
-}
-
-// console.log(wgs84ToWebMercator(degToRad(50), degToRad(50)));
-// console.log(wgs84ToWebMercator(degToRad(49.99999999999999), degToRad(49.99999999999999)));
-// let wgs = webMercatorToWgs84(5565974.539663678, 6446275.841017158);
-// console.log(wgs);
-// console.log('lat: ' + radToDeg(wgs.lat) + ','
-// + 'lon:' + radToDeg(wgs.lon));
-
-
-// console.log(2 * Math.atan(Math.pow(Math.E, 0 / a)) - Math.PI / 2);
-// console.log(radToDeg(webMercatorToWgs84(5565974.539663678, 0).lat));
-
-function lon2tile(lon, z) {
- return (Math.floor((lon + 180) / 360 * Math.pow(2, z)));
-}
-
-function lat2tile(lat, z) {
- return (Math.floor((1 - Math.log(Math.tan(lat * Math.PI / 180)
- + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI)
- / 2 * Math.pow(2, z)));
-}
-
-function lon2x(lon, z) {
- return ((lon + 180) / 360 * Math.pow(2, z));
-}
-
-function lat2y(lat, z) {
- return ((1 - Math.log(Math.tan(lat * Math.PI / 180)
- + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI)
- / 2 * Math.pow(2, z));
-}
-
-function tile2long(x, z) {
- return (x / Math.pow(2, z) * 360 - 180);
-}
-function tile2lat(y, z) {
- var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
- return (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))));
-}
-
-//test
-//22.7490073, 114.3781213 z=15
-//let mappiece = Math.pow(2, zoom_level); //一个方向的地图块数 1块256个像素
-
-// console.log(lon2tile(long, zoom_level));
-// console.log(lat2tile(lat, zoom_level));
-// console.log(lon2x(long, zoom_level));
-// console.log(lat2y(lat, zoom_level));
-
-// console.log('----------------------');
-// console.log(tile2long(26794, zoom_level));
-// console.log(tile2long(26794 + 1 / 256, zoom_level));
-
-//https://tile.openstreetmap.org/z/x/y.png
-//https://tile.openstreetmap.org/15/26794/14256.png
-
-//已知条件 lat long zoom_level 显示范围的宽高
-let zoom_level = 15;
-let lat = 22.7490073;
-let long = 114.3781213;
-let width = 1600;
-let height = 900;
-
-function calBasetile(lat, long, zoom_level) {
- let basetile = {};
- basetile.x = lon2x(long, zoom_level);//对应zoomlevel下long的x坐标
- basetile.y = lat2y(lat, zoom_level);//对应zoomlevel下lat的y坐标
- basetile.tilex = lon2tile(long, zoom_level);//对应zoomlevel下long的x tile编号
- basetile.tiley = lat2tile(lat, zoom_level);//对应zoomlevel下lat的y tile编号
- basetile.offsetx = Math.floor((basetile.x - basetile.tilex) * 256);//相对于左上角,其点的x偏移值
- basetile.offsety = Math.floor((basetile.y - basetile.tiley) * 256);//相对于左上角,其点的y偏移值
-
- basetile.minx = width / 2 - basetile.offsetx;
- basetile.maxx = basetile.minx + 256;
- basetile.miny = height / 2 - basetile.offsety;
- basetile.maxy = basetile.miny + 256;
-
- basetile.p1 = Math.floor(basetile.maxy / 256 + 0.5);
- basetile.p2 = Math.floor((height - basetile.miny) / 256 + 0.5);
- basetile.p3 = Math.floor(basetile.maxx / 256 + 0.5);
- basetile.p4 = Math.floor((width - basetile.minx) / 256 + 0.5);
- console.log(basetile);
- return basetile;
-}
-
-let basetile = calBasetile(lat, long, zoom_level);
-
-// let x = lon2x(long, zoom_level);
-// let y = lat2y(lat, zoom_level);
-
-// let tilex = lon2tile(long, zoom_level);
-// let tiley = lat2tile(lat, zoom_level);
-
-// let offsetx = Math.floor((x - tilex) * 256);
-// let offsety = Math.floor((y - tiley) * 256);
-
-// //计算出瓦片地图的基准坐标,假设显示的宽高为1600*900
-// let minx = width / 2 - offsetx;
-// let maxx = minx + 256;
-// let miny = height / 2 - offsety;
-// let maxy = miny + 256;
-
-//计算出四个方向各需要的块数
-//p1 p2 p3 p4 上 下 左 右
-// let p1 = Math.floor(maxy / 256 + 0.5);
-// let p2 = Math.floor((height - miny) / 256 + 0.5);
-// let p3 = Math.floor(maxx / 256 + 0.5);
-// let p4 = Math.floor((width - minx) / 256 + 0.5);
-
-//基于已知条件计算需要的各个tile
-function needtiles(basetile, p1, p2, p3, p4) {
- let tiles = new Array();
- let tilex = basetile.tilex;
- let tiley = basetile.tiley;
- tiles.push({ x: tilex, y: tiley });
- for (let i = 0; i < p4; i++) {
- tiles.push({ x: tilex + i + 1, y: tiley });
- }
- for (let i = 0; i < p3; i++) {
- tiles.push({ x: tilex - i - 1, y: tiley });
- }
- for (let i = 0; i < p1; i++) {
- for (let j = 0; j < p3 + p4 + 1; j++) {
- tiles.push({ x: tilex - p3 + j, y: tiley - i - 1 });
- }
- }
- for (let i = 0; i < p2; i++) {
- for (let j = 0; j < p3 + p4 + 1; j++) {
- tiles.push({ x: tilex - p3 + j, y: tiley + i + 1 });
- }
- }
- //console.log(tiles);
- //console.log(tiles.length);
- return tiles;
-}
-
-let tiles = needtiles(basetile, basetile.p1, basetile.p2, basetile.p3, basetile.p4);
-
-
-//渲染问题
-//通过与基准之间的位置关系计算渲染的坐标
-//minx miny 即为基准tile当前渲染位置
-
-// for (let i = 0; i < tiles.length; i++) {
-// const element = tiles[i];
-// let renderx = (element.x - tilex) * 256 + minx;
-// let rendery = (element.y - tiley) * 256 + miny;
-// console.log({ x: renderx, y: rendery });
-// }
-
-let canvas = document.getElementById('map');
-canvas.width = map.clientWidth;
-canvas.height = map.clientHeight;
-let ctx = canvas.getContext('2d');
-
-function clearcanvas() {
- ctx.clearRect(0, 0, canvas.width, canvas.height);
-}
-
-function drawPoint(x, y) {
- ctx.fillStyle = "white"
- ctx.strokeStyle = "#a35312"
- ctx.beginPath();
- ctx.arc(x, y, 3, 0, Math.PI * 2, true);
- ctx.closePath();
- ctx.fill();
- ctx.stroke();
-}
-
-function drawRect(x, y) {
- ctx.strokeStyle = "white"
- ctx.strokeRect(x, y, 256, 256);
-}
-
-function drawtext(text, x, y) {
- ctx.fillStyle = "white"
- ctx.font = "18px serif";
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.fillText(text, x, y);
-}
-
-function drawgrid(basetile, tiles) {
- let minx = basetile.minx;
- let miny = basetile.miny;
- let offsetx = basetile.offsetx;
- let offsety = basetile.offsety;
- let tilex = basetile.tilex;
- let tiley = basetile.tiley;
- clearcanvas();
- drawPoint(minx + offsetx, miny + offsety);
- for (let i = 0; i < tiles.length; i++) {
- const element = tiles[i];
- let renderx = (element.x - tilex) * 256 + minx;
- let rendery = (element.y - tiley) * 256 + miny;
- //console.log({ x: renderx, y: rendery });
- drawPoint(renderx, rendery);
- drawRect(renderx, rendery);
- const showtext = 'x:' + element.x + ' ' + 'y:' + element.y;
- //drawtext(showtext, renderx + 256 / 2, rendery + 256 / 2);
- drawtext(showtext, renderx + showtext.length / 4 * 18 + 4, rendery + 9);
- }
-}
-
-drawgrid(basetile, tiles);
-
-// drawPoint(width / 2, height / 2);
-
-// const element = tiles[0];
-// let renderx = (element.x - tilex) * 256 + minx;
-// let rendery = (element.y - tiley) * 256 + miny;
-// drawPoint(renderx, rendery);
-// drawPoint(renderx + 256 / 2, rendery + 256 / 2);
-// drawRect(renderx, rendery);
-
-// drawtext(showtext, renderx + 256 / 2, rendery + 256 / 2);
-// console.log({ x: renderx, y: rendery });
-
-//实现移动缩放方法
-//缩放
-map.onwheel = (e) => {
- //console.log(e);
- const zoomleveloffset = (e.deltaY > 0) ? 1 : -1;
- zoom_level -= zoomleveloffset;
- if (zoom_level < 0) {
- zoom_level = 0;
- return;
- }
-
- if (zoom_level > 19) {
- zoom_level = 19;
- return;
- }
- console.log(zoom_level);
- //clearcanvas();
- //重新计算basetile
- basetile = calBasetile(lat, long, zoom_level);
- tiles = needtiles(basetile, basetile.p1, basetile.p2, basetile.p3, basetile.p4);
- drawgrid(basetile, tiles);
-}
-
-let moveflag = false;
-let downpoing = { x: 0, y: 0 };
-
-map.onmousedown = (e) => {
- console.log('鼠标按下');
- moveflag = true;
- downpoing.x = e.offsetX;
- downpoing.y = e.offsetY;
-}
-
-map.onmouseup = (e) => {
- console.log('鼠标松开');
- moveflag = false;
-}
-
-map.onmousemove = (e) => {
- if (moveflag) {
- console.log('有效位移');
- const movex = downpoing.x - e.offsetX;
- const movey = downpoing.y - e.offsetY;
- //实现移动逻辑
- let xp = basetile.x + movex / 256;//注意像素移动要除以256
- let yp = basetile.y + movey / 256;
- long = tile2long(xp, zoom_level);
- lat = tile2lat(yp, zoom_level);
- basetile = calBasetile(lat, long, zoom_level);
- tiles = needtiles(basetile, basetile.p1, basetile.p2, basetile.p3, basetile.p4);
- drawgrid(basetile, tiles);
-
- downpoing.x = e.offsetX;
- downpoing.y = e.offsetY;
- }
-}
\ No newline at end of file
diff --git a/index.html b/index.html
index 097895d..5d801cc 100644
--- a/index.html
+++ b/index.html
@@ -1,43 +1,51 @@
-
-
-
-
-
+
+
+
+
+
+
tilerendertest
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..8e4255c
--- /dev/null
+++ b/index.js
@@ -0,0 +1,10 @@
+import * as Basemap from './src/basemap.js'
+document.addEventListener('contextmenu', function (event) {
+ event.preventDefault() // 阻止浏览器默认右键菜单的显示
+})
+
+Basemap.setDomById('map')
+Basemap.setCanvasSize()
+window.addEventListener('resize', Basemap.setCanvasSize)
+
+// Basemap.setCenterByWgs84(22.54, 114.06, 18)
diff --git a/mayfinal.js b/mayfinal.js
deleted file mode 100644
index f700297..0000000
--- a/mayfinal.js
+++ /dev/null
@@ -1,333 +0,0 @@
-let map = document.getElementById('map');
-let coord = document.getElementById('coord');
-map.width = map.clientWidth;
-map.height = map.clientHeight;
-let ctx = map.getContext('2d');
-
-const tilesize = 256;
-const minlevel = 3;
-const maxlevel = 18;
-let zoom_level = 3; //默认
-
-let viewport = {};
-viewport.width = map.width; //默认已知
-viewport.height = map.height; //默认已知
-viewport.centerx = Math.pow(2, zoom_level) * 256 / 2; //默认
-viewport.centery = Math.pow(2, zoom_level) * 256 / 2; //默认
-
-viewport.xoffset = (viewport.width / 2 - viewport.centerx);
-viewport.yoffset = (viewport.height / 2 - viewport.centery);
-
-let needtiles = new Array();
-let cache = new Array();
-
-let alltilecount = 0;
-let downtilecount = 0;
-let drecord = new Array();
-
-function calTileSize() {
- let etsize = tilesize;
- if (zoom_level != Math.floor(zoom_level)) {
- etsize = tilesize * Math.pow(2, zoom_level - Math.floor(zoom_level + 1));
- }
- return etsize;
-}
-
-function calTileNum(coord) {
- return Math.floor(coord / calTileSize());
-}
-
-function tilesfilter(tails) {
- let news = new Array();
- let max = Math.pow(2, zoom_level);
- if (zoom_level != Math.floor(zoom_level)) {
- max = Math.pow(2, Math.floor(zoom_level + 1));
- }
- for (let i = 0; i < tails.length; i++) {
- const e = tails[i];
- if (e.x >= 0 && e.y >= 0 && e.x < max && e.y < max) {
- news.push(e);
- }
- }
- return news;
-}
-
-
-function clearcanvas() {
- ctx.clearRect(0, 0, map.width, map.height);
-}
-
-function drawRect(x, y, width, height) {
- ctx.strokeStyle = "white"
- ctx.strokeRect(x, y, width, height);
-}
-
-function drawtext(text, x, y) {
- ctx.fillStyle = "white"
- ctx.font = "18px serif";
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.fillText(text, x, y);
-}
-
-function mplat2viewport(mx, my) {
- const vx = mx + viewport.xoffset;
- const vy = my + viewport.yoffset;
- return { x: vx, y: vy };
-}
-
-function viewport2mplat(vx, vy) {
- const mx = vx - viewport.xoffset;
- const my = vy - viewport.yoffset;
- return { x: mx, y: my };
-}
-
-function viewport2wgs84(vx, vy) {
- const mlc = viewport2mplat(vx, vy);
- //数据超界处理, 这里对应缩放等级的地图的大小是
- const limit = calTileSize() * Math.pow(2, zoom_level);
- console.log(calTileSize());
- if (vx <= 0 || vy <= 0 || vx >= limit || vy >= limit) {
- throw "OutMapRange";
- }
- const lat = tile2lat(mlc.y / tilesize, zoom_level);
- const lng = tile2long(mlc.x / tilesize, zoom_level);
- return { lat: lat, lng: lng }
-}
-
-function wgs84toviewport(lat, lng) {
- //数据超界处理 经度 -180 180
- //85.0511287798066 (2*Math.atan(Math.pow(Math.E,Math.PI))-Math.PI/2)/Math.PI*180
- const latlimit = 85.051128;
- const lngp = lng - Math.floor((lng + 180) / 360) * 360;
- if (lat < (0 - latlimit) || lat > latlimit) {
- throw "OutMapRange";
- }
- const my = lat2y(lat, zoom_level) * tilesize;
- const mx = lon2x(lngp, zoom_level) * tilesize;
- const vp = mplat2viewport(mx, my);
- return { x: vp.x, y: vp.y };
-}
-
-
-function updateviewporttest(scrollx, scrolly, oldz, newz) {
- //计算出缩放后坐标系的偏移值
- // xv = xm + offset ; offset = xv - xm
- //const newz = zoom_level;
- const scrollm = viewport2mplat(scrollx, scrolly);
- //const basescale = 2 * Math.pow(2, newz) / Math.pow(2, Math.floor(newz) + 1);
- console.log('zoomlevel : ', newz, oldz);
- const basescale = Math.pow(2, newz - oldz);
- console.log('basescale: ', basescale);
- const newscrollm = { x: scrollm.x * basescale, y: scrollm.y * basescale };
- console.log('缩放点新坐标 ', newscrollm);
- viewport.xoffset = scrollx - newscrollm.x;
- viewport.yoffset = scrolly - newscrollm.y;
-}
-
-//test
-function drawtest() {
- ctx.clearRect(0, 0, map.width, map.height);
- const viewport_left_top = viewport2mplat(0, 0);
- const viewport_right_bottom = viewport2mplat(viewport.width, viewport.height);
- const mixnum = calTileNum(viewport_left_top.x);
- const miynum = calTileNum(viewport_left_top.y);
- const maxnum = calTileNum(viewport_right_bottom.x);
- const maynum = calTileNum(viewport_right_bottom.y);
- const horicount = maxnum - mixnum + 1;
- const verticount = maynum - miynum + 1;
-
- clearcanvas();
- let tails = new Array();
- for (let i = 0; i < horicount; i++) {
- for (let j = 0; j < verticount; j++) {
- const x = mixnum + i;
- const y = miynum + j;
- tails.push({ x: x, y: y });
- }
- }
- needtiles = tilesfilter(tails);
- alltilecount += needtiles.length;
- //console.log(needtiles.length, needtiles);
- needtiles.forEach(et => {
- const etsize = calTileSize();
- //const tilev = mplat2viewport(et.x * etsize, et.y * etsize);
- //drawRect(tilev.x, tilev.y, etsize, etsize);
- let z = zoom_level;
- if (zoom_level != Math.floor(zoom_level)) {
- z = Math.floor(zoom_level + 1);
- }
- const text = `${z}/${et.x}/${et.y}.png`;
- console.log(text);
- //drawtext(text, tilev.x + etsize / 2, tilev.y + etsize / 2);
- drawTileImg(z, et.x, et.y);
- });
- debug();
-}
-
-let moveflag = false;
-let downpoing = { x: 0, y: 0 };
-map.onmousedown = (e) => {
- console.log('鼠标按下');
- moveflag = true;
- downpoing.x = e.offsetX;
- downpoing.y = e.offsetY;
- console.log(zoom_level, e.offsetX, e.offsetY);
- const wgs84 = viewport2wgs84(e.offsetX, e.offsetY);
- console.log(wgs84, 'check', wgs84toviewport(wgs84.lat, wgs84.lng));
-}
-map.onmouseup = (e) => {
- console.log('鼠标松开');
- moveflag = false;
-}
-map.onmousemove = (e) => {
- //输出latlng
- //const mlc = viewport2mplat(e.offsetX, e.offsetY);
- //let lat = tile2lat(mlc.y / tilesize, zoom_level);
- //let lng = tile2long(mlc.x / tilesize, zoom_level);
- //const coordstr = `(${e.offsetX},${e.offsetY}) - (${mlc.x.toFixed(3)},${mlc.y.toFixed(3)}) - (${lat},${lng})`;
- //coord.innerText = coordstr;
- //console.log(e.offsetX, e.offsetY);
- if (moveflag) {
- console.log('有效位移');
- const movex = downpoing.x - e.offsetX;
- const movey = downpoing.y - e.offsetY;
- //实现移动逻辑
- viewport.xoffset -= movex;
- viewport.yoffset -= movey;
-
- drawtest();
- downpoing.x = e.offsetX;
- downpoing.y = e.offsetY;
- }
-}
-
-map.onwheel = (e) => {
- //console.log(e);
- const ds = 0.25;
- const zoomleveloffset = (e.deltaY > 0) ? 1 * ds : -1 * ds;
- const oldz = zoom_level;
- zoom_level = zoom_level - zoomleveloffset;
- if (zoom_level < minlevel) {
- zoom_level = minlevel;
- return;
- }
-
- if (zoom_level > maxlevel) {
- zoom_level = maxlevel;
- return;
- }
- console.log(zoom_level, e.offsetX, e.offsetY);
- updateviewporttest(e.offsetX, e.offsetY, oldz, zoom_level);
- drawtest();
-}
-
-drawtest();
-
-
-
-Array.prototype.remove = function (val) {
- const index = this.indexOf(val);
- if (index > -1) {
- return this.splice(index, 1);
- }
- return this;
-}
-
-//add opeenstreetmap
-function downloadimg(z, x, y) {
- return new Promise((resolve, reject) => {
- //const url = `https://tile.openstreetmap.org/${z}/${x}/${y}.png`;
- const url = 'http://webrd01.is.autonavi.com/' +
- 'appmaptile?lang=zh_cn&size=1&scale=1&style=8' +
- `&x=${x}&y=${y}&z=${z}`;
- //add downloadcheck
- const obj = { z: z, x: x, y: y };
- drecord.push(obj); //下载前加入记录
- let img = new Image();
- img.onload = () => {
- console.log('downloaded' + z + '/' + x + '/' + y + '.png');
- cache.push({ img: img, z: z, x: x, y: y });
- drecord.remove(obj); //下载完成后从记录中移除
- downtilecount += 1;
- resolve(img);
- }
- img.src = url;
- });
-}
-
-async function getImg(z, x, y) {
- //先判断是否加入下载记录
- const isdownloading = drecord.includes({ z: z, x: x, y: y });
- if (isdownloading) {
- //return getImg(z, x, y);
- return setTimeout(() => {
- getImg(z, x, y);
- }, 100);
- }
- const found = cache.find(e => (e.z == z && e.x == x && e.y == y));
- if (found == undefined) {
- let p = await downloadimg(z, x, y);
- return p;
- } else {
- console.log('exist' + z + '/' + x + '/' + y + '.png');
- return found.img;
- }
-}
-
-function drawTileImg(z, x, y) {
- const img = getImg(z, x, y);
- img.then((e) => {
- const etsize = calTileSize();
- const tilev = mplat2viewport(x * etsize, y * etsize);
- let fz = zoom_level;
- if (zoom_level != Math.floor(zoom_level)) {
- fz = Math.floor(zoom_level + 1);
- }
- if (needtiles.find(t => z == fz && t.x == x && t.y == y)) {
- ctx.drawImage(e, tilev.x, tilev.y, etsize, etsize);
- }
- });
-}
-
-function debug() {
- console.log('=============debug=================');
- console.log('zoom_level', zoom_level);
- console.log('alltilecount', alltilecount);
- console.log('downtilecount', downtilecount);
- console.log('cachecount', caches.length);
- console.log('drecord count', drecord.length);
- console.log('=============debug=================');
-}
-
-//=====coord about=====
-function lon2tile(lon, z) {
- return (Math.floor((lon + 180) / 360 * Math.pow(2, z)));
-}
-
-function lat2tile(lat, z) {
- return (Math.floor((1 - Math.log(Math.tan(lat * Math.PI / 180) +
- 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) /
- 2 * Math.pow(2, z)));
-}
-
-function lon2x(lon, z) {
- return ((lon + 180) / 360 * Math.pow(2, z));
-}
-
-function lat2y(lat, z) {
- return ((1 - Math.log(Math.tan(lat * Math.PI / 180) +
- 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) /
- 2 * Math.pow(2, z));
-}
-
-function tile2long(x, z) {
- return (x / Math.pow(2, z) * 360 - 180);
-}
-
-function tile2lat(y, z) {
- var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
- return (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))));
-}
-
-//=========
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..8335f9e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "formaptile",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "type": "module",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "http://atsw.top:3000/alimu/formaptile.git"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC"
+}
diff --git a/src/basemap.js b/src/basemap.js
new file mode 100644
index 0000000..d9a9d44
--- /dev/null
+++ b/src/basemap.js
@@ -0,0 +1,220 @@
+import {
+ viewport,
+ calTileNum,
+ calTileSize,
+ setViewportSize,
+ setViewportCenterByWgs84,
+ setViewportCenterByMap,
+ map2viewport,
+ viewport2map,
+ updateZoomLevel,
+} from './viewport.js'
+
+import * as Tiles from './tiles.js'
+
+let map = undefined
+
+export function setDomById(id) {
+ map = document.getElementById(id)
+ console.debug('底图挂载在', map)
+ //添加响应事件
+ // let moveflag = false
+ // let downpoing = { x: 0, y: 0 }
+ const minlevel = 3
+ const maxlevel = 18
+ map.onwheel = (e) => {
+ const ds = 0.25
+ const zoomleveloffset = e.deltaY > 0 ? 1 * ds : -1 * ds
+ let newz = viewport.zoom_level
+ newz = newz - zoomleveloffset
+ if (newz < minlevel) {
+ newz = minlevel
+ return
+ }
+
+ if (newz > maxlevel) {
+ newz = maxlevel
+ return
+ }
+ updateZoomLevel(e.offsetX, e.offsetY, newz)
+ savePosInfo()
+ drawGrid()
+ }
+
+ let moveflag = false
+ let downpoing = { x: 0, y: 0 }
+ map.onmousedown = (e) => {
+ //console.log('鼠标按下')
+ moveflag = true
+ downpoing.x = e.offsetX
+ downpoing.y = e.offsetY
+ //console.log(viewport.zoom_level, e.offsetX, e.offsetY)
+ // try {
+ // const wgs84 = viewport2wgs84(e.offsetX, e.offsetY)
+ // console.log(
+ // 'check',
+ // { x: e.offsetX, y: e.offsetY },
+ // wgs84,
+ // wgs84toviewport(wgs84.lat, wgs84.lon)
+ // )
+ // } catch (error) {
+ // //console.log(error)
+ // }
+ }
+ map.onmouseup = (e) => {
+ //console.log('鼠标松开')
+ moveflag = false
+ }
+ map.onmousemove = (e) => {
+ //输出latlng
+ //const mlc = viewport2map(e.offsetX, e.offsetY)
+ // const wgs84 = viewport2wgs84(e.offsetX, e.offsetY)
+ // const coordstr = `(${e.offsetX},${e.offsetY})->(${mlc.x.toFixed(
+ // 3
+ // )},${mlc.y.toFixed(3)})->(${wgs84.lat},${wgs84.lon})`
+ // console.log(coordstr)
+ if (moveflag) {
+ //console.log('有效位移')
+ const movex = downpoing.x - e.offsetX
+ const movey = downpoing.y - e.offsetY
+ //实现移动逻辑
+ viewport.xoffset -= movex
+ viewport.yoffset -= movey
+ savePosInfo()
+ drawGrid()
+ downpoing.x = e.offsetX
+ downpoing.y = e.offsetY
+ }
+ }
+}
+export function getContext() {
+ if (map) {
+ return map.getContext('2d')
+ }
+}
+
+function savePosInfo() {
+ const mcenter = viewport2map(viewport.width / 2, viewport.height / 2)
+ let poseInfo = {
+ mx: mcenter.x,
+ my: mcenter.y,
+ zoom_level: viewport.zoom_level,
+ }
+ localStorage.setItem('poseInfo-nas22udfh12', JSON.stringify(poseInfo))
+}
+
+export function setCanvasSize() {
+ if (map) {
+ map.width = map.clientWidth
+ map.height = map.clientHeight
+ //console.debug('重新设置大小', map.width, map.height)
+ //init
+ setViewportSize(map.width, map.height)
+ //随机用一个标识
+ const poseInfoStr = localStorage.getItem('poseInfo-nas22udfh12')
+ const poseInfo = JSON.parse(poseInfoStr)
+ if (poseInfo) {
+ setViewportCenterByMap(
+ poseInfo.mx,
+ poseInfo.my,
+ poseInfo.zoom_level
+ )
+ } else {
+ setViewportCenterByWgs84(0, 0, 3)
+ }
+ //draw
+ drawGrid()
+ }
+}
+
+export function setCenterByWgs84(lat, lon, z) {
+ setViewportCenterByWgs84(lat, lon, z)
+ drawGrid()
+}
+
+function drawRect(x, y, width, height) {
+ const ctx = getContext()
+ ctx.strokeStyle = 'white'
+ ctx.strokeRect(x, y, width, height)
+}
+
+function clear() {
+ const ctx = getContext()
+ ctx.clearRect(0, 0, map.width, map.height)
+}
+
+function drawtext(text, x, y) {
+ const ctx = getContext()
+ ctx.fillStyle = 'white'
+ ctx.font = '18px serif'
+ ctx.textAlign = 'center'
+ ctx.textBaseline = 'middle'
+ ctx.fillText(text, x, y)
+}
+
+function drawTileImg(z, x, y) {
+ const img = Tiles.getImg(z, x, y)
+ img.then((e) => {
+ const etsize = calTileSize()
+ const tilev = map2viewport(x * etsize, y * etsize)
+ let fz = viewport.zoom_level
+ if (fz != Math.floor(fz)) {
+ fz = Math.floor(fz + 1)
+ }
+ if (needtiles.find((t) => z == fz && t.x == x && t.y == y)) {
+ const ctx = getContext()
+ ctx.drawImage(e, tilev.x, tilev.y, etsize, etsize)
+ }
+ })
+}
+
+function tilesfilter(tails) {
+ const zoom_level = viewport.zoom_level
+ let news = new Array()
+ let max = Math.pow(2, zoom_level)
+ if (zoom_level != Math.floor(zoom_level)) {
+ max = Math.pow(2, Math.floor(zoom_level + 1))
+ }
+ for (let i = 0; i < tails.length; i++) {
+ const e = tails[i]
+ if (e.x >= 0 && e.y >= 0 && e.x < max && e.y < max) {
+ news.push(e)
+ }
+ }
+ return news
+}
+
+let needtiles = new Array()
+export function drawGrid() {
+ clear()
+ const viewport_left_top = viewport2map(0, 0)
+ const viewport_right_bottom = viewport2map(viewport.width, viewport.height)
+ const mixnum = calTileNum(viewport_left_top.x)
+ const miynum = calTileNum(viewport_left_top.y)
+ const maxnum = calTileNum(viewport_right_bottom.x)
+ const maynum = calTileNum(viewport_right_bottom.y)
+ const horicount = maxnum - mixnum + 1
+ const verticount = maynum - miynum + 1
+ let tails = new Array()
+ for (let i = 0; i < horicount; i++) {
+ for (let j = 0; j < verticount; j++) {
+ const x = mixnum + i
+ const y = miynum + j
+ tails.push({ x: x, y: y })
+ }
+ }
+ needtiles = tilesfilter(tails)
+ needtiles.forEach((et) => {
+ let z = viewport.zoom_level
+ if (z != Math.floor(z)) {
+ z = Math.floor(z + 1)
+ }
+ // const etsize = calTileSize()
+ // const tilev = map2viewport(et.x * etsize, et.y * etsize)
+ //drawRect(tilev.x, tilev.y, etsize, etsize)
+ //const text = `${z}/${et.x}/${et.y}.png`
+ //console.log(text)
+ //drawtext(text, tilev.x + etsize / 2, tilev.y + etsize / 2)
+ drawTileImg(z, et.x, et.y)
+ })
+}
diff --git a/src/tiles.js b/src/tiles.js
new file mode 100644
index 0000000..2cce68c
--- /dev/null
+++ b/src/tiles.js
@@ -0,0 +1,52 @@
+Array.prototype.remove = function (val) {
+ const index = this.indexOf(val)
+ if (index > -1) {
+ return this.splice(index, 1)
+ }
+ return this
+}
+
+const cache = new Array()
+const downloadingRecord = new Array()
+
+//const tileserverUrl =
+//openstreetmap
+//const url = `https://tile.openstreetmap.org/${z}/${x}/${y}.png`;
+
+function downloadimg(z, x, y) {
+ return new Promise((resolve, reject) => {
+ const url =
+ 'https://webrd01.is.autonavi.com/' +
+ 'appmaptile?lang=zh_cn&size=1&scale=1&style=8' +
+ `&x=${x}&y=${y}&z=${z}`
+ //add downloadcheck
+ const obj = { z: z, x: x, y: y }
+ downloadingRecord.push(obj) //下载前加入记录
+ let img = new Image()
+ img.onload = () => {
+ cache.push({ img: img, z: z, x: x, y: y })
+ downloadingRecord.remove(obj) //下载完成后从记录中移除
+ resolve(img)
+ }
+ img.referrerPolicy = 'no-referrer'
+ img.src = url
+ })
+}
+
+export async function getImg(z, x, y) {
+ //先判断是否加入下载记录
+ const isdownloading = downloadingRecord.includes({ z: z, x: x, y: y })
+ if (isdownloading) {
+ //return getImg(z, x, y);
+ return setTimeout(() => {
+ getImg(z, x, y)
+ }, 100)
+ }
+ const found = cache.find((e) => e.z == z && e.x == x && e.y == y)
+ if (found == undefined) {
+ let p = await downloadimg(z, x, y)
+ return p
+ } else {
+ return found.img
+ }
+}
diff --git a/src/utils.js b/src/utils.js
new file mode 100644
index 0000000..63e8535
--- /dev/null
+++ b/src/utils.js
@@ -0,0 +1,45 @@
+//=====coord about=====
+export function lon2tile(lon, z) {
+ return Math.floor(((lon + 180) / 360) * Math.pow(2, z))
+}
+
+export function lat2tile(lat, z) {
+ return Math.floor(
+ ((1 -
+ Math.log(
+ Math.tan((lat * Math.PI) / 180) +
+ 1 / Math.cos((lat * Math.PI) / 180)
+ ) /
+ Math.PI) /
+ 2) *
+ Math.pow(2, z)
+ )
+}
+
+export function lon2x(lon, z) {
+ return ((lon + 180) / 360) * Math.pow(2, z)
+}
+
+export function lat2y(lat, z) {
+ return (
+ ((1 -
+ Math.log(
+ Math.tan((lat * Math.PI) / 180) +
+ 1 / Math.cos((lat * Math.PI) / 180)
+ ) /
+ Math.PI) /
+ 2) *
+ Math.pow(2, z)
+ )
+}
+
+export function tile2long(x, z) {
+ return (x / Math.pow(2, z)) * 360 - 180
+}
+
+export function tile2lat(y, z) {
+ var n = Math.PI - (2 * Math.PI * y) / Math.pow(2, z)
+ return (180 / Math.PI) * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))
+}
+
+//=========
diff --git a/src/viewport.js b/src/viewport.js
new file mode 100644
index 0000000..918fb49
--- /dev/null
+++ b/src/viewport.js
@@ -0,0 +1,109 @@
+import * as Utils from './utils.js'
+
+export const viewport = {
+ width: 256,
+ height: 256,
+ zoom_level: 0,
+ xoffset: 0,
+ yoffset: 0,
+}
+
+//计算所有情况下的底图大小,包括非整数z
+export function calTileSize() {
+ let etsize = 256
+ const zoom_level = viewport.zoom_level
+ if (zoom_level != Math.floor(zoom_level)) {
+ etsize = 256 * Math.pow(2, zoom_level - Math.floor(zoom_level + 1))
+ }
+ return etsize
+}
+
+export function calTileNum(coord) {
+ return Math.floor(coord / calTileSize())
+}
+
+export function setViewportSize(width, height) {
+ viewport.width = width
+ viewport.height = height
+}
+
+export function updateOffset() {
+ const z = viewport.zoom_level
+}
+
+export function map2viewport(mx, my) {
+ const vx = mx + viewport.xoffset
+ const vy = my + viewport.yoffset
+ return { x: vx, y: vy }
+}
+
+export function viewport2map(vx, vy) {
+ const mx = vx - viewport.xoffset
+ const my = vy - viewport.yoffset
+ return { x: mx, y: my }
+}
+
+export function setViewportCenterByWgs84(lat, lon, z) {
+ viewport.zoom_level = z
+ const size = calTileSize()
+ const mx = Utils.lon2x(lon, z) * size
+ const my = Utils.lat2y(lat, z) * size
+ console.log('测试', mx, my)
+ // const { vx, vy } = map2viewport(mx, my)
+ const cx = viewport.width / 2
+ const cy = viewport.height / 2
+ viewport.xoffset = cx - mx
+ viewport.yoffset = cy - my
+}
+
+export function setViewportCenterByMap(mx, my, z) {
+ viewport.zoom_level = z
+ const cx = viewport.width / 2
+ const cy = viewport.height / 2
+ viewport.xoffset = cx - mx
+ viewport.yoffset = cy - my
+}
+
+export function updateZoomLevel(vx, vy, newz) {
+ const oldz = viewport.zoom_level
+ const mxy = viewport2map(vx, vy)
+ viewport.zoom_level = newz
+ const scale = Math.pow(2, newz - oldz)
+ const newmxy = { x: mxy.x * scale, y: mxy.y * scale }
+ viewport.xoffset = vx - newmxy.x
+ viewport.yoffset = vy - newmxy.y
+}
+
+// //test
+// setViewportSize(512, 512)
+// setViewportCenter(0, 0, 0)
+// console.log(map2viewport(0, 0))
+// console.log(map2viewport(128, 128))
+
+export function viewport2wgs84(vx, vy) {
+ const mlc = viewport2map(vx, vy)
+ const z = viewport.zoom_level
+ //数据超界处理, 这里对应缩放等级的地图的大小是
+ const limit = calTileSize() * Math.pow(2, z)
+ if (vx <= 0 || vy <= 0 || vx >= limit || vy >= limit) {
+ throw `OutMapRange limit ${limit}`
+ }
+ const lat = Utils.tile2lat(mlc.y / 256, z)
+ const lon = Utils.tile2long(mlc.x / 256, z)
+ return { lat: lat, lon: lon }
+}
+
+export function wgs84toviewport(lat, lon) {
+ //数据超界处理 经度自动限制在 -180 180
+ //85.0511287798066 (2*Math.atan(Math.pow(Math.E,Math.PI))-Math.PI/2)/Math.PI*180
+ const latlimit = 85.051128
+ const lonp = lon - Math.floor((lon + 180) / 360) * 360
+ if (lat < 0 - latlimit || lat > latlimit) {
+ throw 'OutMapRange'
+ }
+ const z = viewport.zoom_level
+ const my = Utils.lat2y(lat, z) * 256
+ const mx = Utils.lon2x(lonp, z) * 256
+ const vp = map2viewport(mx, my)
+ return { x: vp.x, y: vp.y }
+}
diff --git a/temp.txt b/temp.txt
deleted file mode 100644
index e5769bf..0000000
--- a/temp.txt
+++ /dev/null
@@ -1,316 +0,0 @@
-//椭球相关参数计算
-const a = 6378137; //长半轴 a
-const f = 1 / 298.257223563; //扁率 (a-b)/a
-const b = a * (1 - f); //短半轴 b
-const e = Math.sqrt(a * a - b * b) / a; //椭球第一偏心率
-
-function degToRad(deg) {
- return deg / 180 * Math.PI;
-}
-
-function radToDeg(rad) {
- return rad / Math.PI * 180;
-}
-
-function wgs84ToWebMercator(lat, lon) {
- let x = a * lon;
- let y = a * Math.log(Math.tan(Math.PI / 4 + lat / 2));
- return { x: x, y: y };
-}
-
-function webMercatorToWgs84(x, y) {
- let lon = x / a;
- let lat = 2 * Math.atan(Math.pow(Math.E, y / a)) - Math.PI / 2;
- return { lon: lon, lat: lat }
-}
-
-function lon2tile(lon, z) {
- return (Math.floor((lon + 180) / 360 * Math.pow(2, z)));
-}
-
-function lat2tile(lat, z) {
- return (Math.floor((1 - Math.log(Math.tan(lat * Math.PI / 180) +
- 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) /
- 2 * Math.pow(2, z)));
-}
-
-function lon2x(lon, z) {
- return ((lon + 180) / 360 * Math.pow(2, z));
-}
-
-function lat2y(lat, z) {
- return ((1 - Math.log(Math.tan(lat * Math.PI / 180) +
- 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) /
- 2 * Math.pow(2, z));
-}
-
-function tile2long(x, z) {
- return (x / Math.pow(2, z) * 360 - 180);
-}
-
-function tile2lat(y, z) {
- var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
- return (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))));
-}
-
-//https://tile.openstreetmap.org/z/x/y.png
-//https://tile.openstreetmap.org/15/26794/14256.png
-
-let cache = new Array();
-
-function downloadimg(z, x, y) {
- const src = 'https://tile.openstreetmap.org/' + z + '/' + x + '/' + y + '.png';
- let img = new Image();
- img.src = src;
- img.onload = () => {
- console.log('downloaded' + z + '/' + x + '/' + y + '.png');
- cache.push({ img: img, z: z, x: x, y: y });
- }
-}
-
-function getIndex(z, x, y) {
- for (let i = 0; i < cache.length; i++) {
- const e = cache[i];
- if (e.z == z && e.x == x && e.y == y) {
- return i;
- } else {
- continue;
- }
- }
- //last
- downloadimg(z, x, y);
- return cache.length;
-}
-
-//已知条件 lat long zoom_level 显示范围的宽高
-let zoom_level = 15;
-let lat = 22.7490073;
-let long = 114.3781213;
-let width = 1600;
-let height = 900;
-
-function calBasetile(lat, long, zoom_level) {
- let basetile = {};
- basetile.x = lon2x(long, zoom_level); //对应zoomlevel下long的x坐标
- basetile.y = lat2y(lat, zoom_level); //对应zoomlevel下lat的y坐标
- basetile.tilex = lon2tile(long, zoom_level); //对应zoomlevel下long的x tile编号
- basetile.tiley = lat2tile(lat, zoom_level); //对应zoomlevel下lat的y tile编号
- basetile.offsetx = Math.floor((basetile.x - basetile.tilex) * 256); //相对于左上角,其点的x偏移值
- basetile.offsety = Math.floor((basetile.y - basetile.tiley) * 256); //相对于左上角,其点的y偏移值
-
- basetile.minx = width / 2 - basetile.offsetx;
- basetile.maxx = basetile.minx + 256;
- basetile.miny = height / 2 - basetile.offsety;
- basetile.maxy = basetile.miny + 256;
-
- basetile.p1 = Math.floor(basetile.maxy / 256 + 0.5);
- basetile.p2 = Math.floor((height - basetile.miny) / 256 + 0.5);
- basetile.p3 = Math.floor(basetile.maxx / 256 + 0.5);
- basetile.p4 = Math.floor((width - basetile.minx) / 256 + 0.5);
- console.log(basetile);
- return basetile;
-}
-
-//基于已知条件计算需要的各个tile
-function needtiles(basetile, p1, p2, p3, p4) {
- let tiles = new Array();
- let tilex = basetile.tilex;
- let tiley = basetile.tiley;
- tiles.push({ x: tilex, y: tiley });
- for (let i = 0; i < p4; i++) {
- tiles.push({ x: tilex + i + 1, y: tiley });
- }
- for (let i = 0; i < p3; i++) {
- tiles.push({ x: tilex - i - 1, y: tiley });
- }
- for (let i = 0; i < p1; i++) {
- for (let j = 0; j < p3 + p4 + 1; j++) {
- tiles.push({ x: tilex - p3 + j, y: tiley - i - 1 });
- }
- }
- for (let i = 0; i < p2; i++) {
- for (let j = 0; j < p3 + p4 + 1; j++) {
- tiles.push({ x: tilex - p3 + j, y: tiley + i + 1 });
- }
- }
- //console.log(tiles);
- //console.log(tiles.length);
- return tilesfilter(tiles, zoom_level);
-}
-
-//过滤超过限制的tiles
-function tilesfilter(tiles, zoom_level) {
- const maxrange = Math.pow(2, zoom_level) - 1;
- let newtiles = new Array();
- for (let i = 0; i < tiles.length; i++) {
- if (tiles[i].x < 0 || tiles[i].x > maxrange) {
- continue;
- }
- if (tiles[i].y < 0 || tiles[i].y > maxrange) {
- continue;
- }
- newtiles.push(tiles[i]);
- }
- return newtiles;
-}
-
-let basetile = calBasetile(lat, long, zoom_level);
-let tiles = needtiles(basetile, basetile.p1, basetile.p2, basetile.p3, basetile.p4);
-
-
-//渲染问题
-//通过与基准之间的位置关系计算渲染的坐标
-//minx miny 即为基准tile当前渲染位置
-
-// for (let i = 0; i < tiles.length; i++) {
-// const element = tiles[i];
-// let renderx = (element.x - tilex) * 256 + minx;
-// let rendery = (element.y - tiley) * 256 + miny;
-// console.log({ x: renderx, y: rendery });
-// }
-
-let canvas = document.getElementById('map');
-canvas.width = map.clientWidth;
-canvas.height = map.clientHeight;
-let ctx = canvas.getContext('2d');
-
-function clearcanvas() {
- ctx.clearRect(0, 0, canvas.width, canvas.height);
-}
-
-function drawPoint(x, y) {
- ctx.fillStyle = "white"
- ctx.strokeStyle = "#a35312"
- ctx.beginPath();
- ctx.arc(x, y, 3, 0, Math.PI * 2, true);
- ctx.closePath();
- ctx.fill();
- ctx.stroke();
-}
-
-function drawRect(x, y) {
- ctx.strokeStyle = "white"
- ctx.strokeRect(x, y, 256, 256);
-}
-
-function drawImg(z, tilex, tiley, x, y, ) {
- const index = getIndex(z, tilex, tiley);
- if (cache[index]) {
- ctx.drawImage(cache[index].img, x, y);
- }
-}
-
-function drawtext(text, x, y) {
- ctx.fillStyle = "white"
- ctx.font = "18px serif";
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.fillText(text, x, y);
-}
-
-function drawgrid(basetile, tiles) {
- let minx = basetile.minx;
- let miny = basetile.miny;
- let offsetx = basetile.offsetx;
- let offsety = basetile.offsety;
- let tilex = basetile.tilex;
- let tiley = basetile.tiley;
- clearcanvas();
- drawPoint(minx + offsetx, miny + offsety);
- for (let i = 0; i < tiles.length; i++) {
- const element = tiles[i];
- let renderx = (element.x - tilex) * 256 + minx;
- let rendery = (element.y - tiley) * 256 + miny;
- //console.log({ x: renderx, y: rendery });
- drawPoint(renderx, rendery);
- drawRect(renderx, rendery);
- drawImg(zoom_level, tiles[i].x, tiles[i].y, renderx, rendery);
- const showtext = 'x:' + element.x + ' ' + 'y:' + element.y;
- drawtext(zoom_level, renderx + 256 / 2, rendery + 256 / 2);
- drawtext(showtext, renderx + showtext.length / 4 * 18 + 4, rendery + 9);
- }
-}
-
-drawgrid(basetile, tiles);
-
-// drawPoint(width / 2, height / 2);
-
-// const element = tiles[0];
-// let renderx = (element.x - tilex) * 256 + minx;
-// let rendery = (element.y - tiley) * 256 + miny;
-// drawPoint(renderx, rendery);
-// drawPoint(renderx + 256 / 2, rendery + 256 / 2);
-// drawRect(renderx, rendery);
-
-// drawtext(showtext, renderx + 256 / 2, rendery + 256 / 2);
-// console.log({ x: renderx, y: rendery });
-
-//实现移动缩放方法
-//缩放
-map.onwheel = (e) => {
- //console.log(e);
- const zoomleveloffset = (e.deltaY > 0) ? 1 : -1;
- zoom_level -= zoomleveloffset;
- if (zoom_level < 0) {
- zoom_level = 0;
- return;
- }
-
- if (zoom_level > 19) {
- zoom_level = 19;
- return;
- }
- console.log(zoom_level);
- //clearcanvas();
- //重新计算basetile
- basetile = calBasetile(lat, long, zoom_level);
- tiles = needtiles(basetile, basetile.p1, basetile.p2, basetile.p3, basetile.p4);
- drawgrid(basetile, tiles);
-}
-
-let moveflag = false;
-let downpoing = { x: 0, y: 0 };
-
-map.onmousedown = (e) => {
- console.log('鼠标按下');
- moveflag = true;
- downpoing.x = e.offsetX;
- downpoing.y = e.offsetY;
-}
-
-map.onmouseup = (e) => {
- console.log('鼠标松开');
- moveflag = false;
-}
-
-map.onmousemove = (e) => {
- if (moveflag) {
- //console.log('有效位移');
- const movex = downpoing.x - e.offsetX;
- const movey = downpoing.y - e.offsetY;
- //实现移动逻辑
- let xp = basetile.x + movex / 256; //注意像素移动要除以256
- let yp = basetile.y + movey / 256;
- long = tile2long(xp, zoom_level);
- let latp = tile2lat(yp, zoom_level);
- //需要在y方向限制移动范围
- //(2*Math.atan(Math.pow(Math.E,Math.PI))-Math.PI/2)/Math.PI*180
- //85.0511287798066
- if (Math.abs(latp) > 89.99999) return;
- // if (lat2y(latp, zoom_level) == Infinity || lat2y(latp, zoom_level) == NaN) {
- // console.log('outrange');
- // return;
- // }
- lat = latp;
- console.log(long + ' ' + lat);
- basetile = calBasetile(lat, long, zoom_level);
- tiles = needtiles(basetile, basetile.p1, basetile.p2, basetile.p3, basetile.p4);
- drawgrid(basetile, tiles);
-
- downpoing.x = e.offsetX;
- downpoing.y = e.offsetY;
- }
-}
-
-//
-
diff --git a/test.js b/test.js
deleted file mode 100644
index 5df298e..0000000
--- a/test.js
+++ /dev/null
@@ -1,251 +0,0 @@
-let map = document.getElementById('map');
-map.width = map.clientWidth;
-map.height = map.clientHeight;
-let ctx = map.getContext('2d');
-
-const tilesize = 256;
-const minlevel = 0;
-const maxlevel = 19;
-let zoom_level = 0; //默认
-
-let viewport = {};
-viewport.width = map.width; //默认已知
-viewport.height = map.height; //默认已知
-viewport.centerx = Math.pow(2, zoom_level) * 256 / 2; //默认
-viewport.centery = Math.pow(2, zoom_level) * 256 / 2; //默认
-
-viewport.xoffset = (viewport.width / 2 - viewport.centerx);
-viewport.yoffset = (viewport.height / 2 - viewport.centery);
-
-let needtiles = new Array();
-let cache = new Array();
-let xhrmanager = new Array();
-
-function calTileSize() {
- let etsize = tilesize;
- if (zoom_level != Math.floor(zoom_level)) {
- etsize = tilesize * Math.pow(2, zoom_level - Math.floor(zoom_level + 1));
- }
- return etsize;
-}
-
-function calTileNum(coord) {
- return Math.floor(coord / calTileSize());
-}
-
-function tilesfilter(tails) {
- let news = new Array();
- let max = Math.pow(2, zoom_level);
- if (zoom_level != Math.floor(zoom_level)) {
- max = Math.pow(2, Math.floor(zoom_level + 1));
- }
- for (let i = 0; i < tails.length; i++) {
- const e = tails[i];
- if (e.x >= 0 && e.y >= 0 && e.x < max && e.y < max) {
- news.push(e);
- }
- }
- return news;
-}
-
-
-function clearcanvas() {
- ctx.clearRect(0, 0, map.width, map.height);
-}
-
-function drawRect(x, y, width, height) {
- ctx.strokeStyle = "white"
- ctx.strokeRect(x, y, width, height);
-}
-
-function drawtext(text, x, y) {
- ctx.fillStyle = "white"
- ctx.font = "18px serif";
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.fillText(text, x, y);
-}
-
-function mplat2viewport(mx, my) {
- const vx = mx + viewport.xoffset;
- const vy = my + viewport.yoffset;
- return { x: vx, y: vy };
-}
-
-function viewport2mplat(vx, vy) {
- const mx = vx - viewport.xoffset;
- const my = vy - viewport.yoffset;
- return { x: mx, y: my };
-}
-
-function updateviewporttest(scrollx, scrolly, oldz, newz) {
- //计算出缩放后坐标系的偏移值
- // xv = xm + offset ; offset = xv - xm
- //const newz = zoom_level;
- const scrollm = viewport2mplat(scrollx, scrolly);
- //const basescale = 2 * Math.pow(2, newz) / Math.pow(2, Math.floor(newz) + 1);
- console.log('zoomlevel : ', newz, oldz);
- const basescale = Math.pow(2, newz - oldz);
- console.log('basescale: ', basescale);
- const newscrollm = { x: scrollm.x * basescale, y: scrollm.y * basescale };
- console.log('缩放点新坐标 ', newscrollm);
- viewport.xoffset = scrollx - newscrollm.x;
- viewport.yoffset = scrolly - newscrollm.y;
-}
-
-//test
-function drawtest() {
- ctx.clearRect(0, 0, map.width, map.height);
- const viewport_left_top = viewport2mplat(0, 0);
- const viewport_right_bottom = viewport2mplat(viewport.width, viewport.height);
- const mixnum = calTileNum(viewport_left_top.x);
- const miynum = calTileNum(viewport_left_top.y);
- const maxnum = calTileNum(viewport_right_bottom.x);
- const maynum = calTileNum(viewport_right_bottom.y);
- const horicount = maxnum - mixnum + 1;
- const verticount = maynum - miynum + 1;
-
- clearcanvas();
- xhrabort();
- let tails = new Array();
- for (let i = 0; i < horicount; i++) {
- for (let j = 0; j < verticount; j++) {
- const x = mixnum + i;
- const y = miynum + j;
- tails.push({ x: x, y: y });
- }
- }
- needtiles = tilesfilter(tails);
- //console.log(needtiles.length, needtiles);
- needtiles.forEach(et => {
- const etsize = calTileSize();
- const tilev = mplat2viewport(et.x * etsize, et.y * etsize);
- //drawRect(tilev.x, tilev.y, etsize, etsize);
- let z = zoom_level;
- if (zoom_level != Math.floor(zoom_level)) {
- z = Math.floor(zoom_level + 1);
- }
- const text = `${z}/${et.x}/${et.y}.png`;
- console.log(text);
- drawtext(text, tilev.x + etsize / 2, tilev.y + etsize / 2);
- drawTileImg(z, et.x, et.y);
- });
-}
-
-let moveflag = false;
-let downpoing = { x: 0, y: 0 };
-map.onmousedown = (e) => {
- console.log('鼠标按下');
- moveflag = true;
- downpoing.x = e.offsetX;
- downpoing.y = e.offsetY;
- //console.log(viewport2mplat(e.offsetX, e.offsetY));
-}
-map.onmouseup = (e) => {
- console.log('鼠标松开');
- moveflag = false;
-}
-map.onmousemove = (e) => {
- if (moveflag) {
- console.log('有效位移');
- const movex = downpoing.x - e.offsetX;
- const movey = downpoing.y - e.offsetY;
- //实现移动逻辑
- viewport.xoffset -= movex;
- viewport.yoffset -= movey;
-
- drawtest();
- downpoing.x = e.offsetX;
- downpoing.y = e.offsetY;
- }
-}
-
-map.onwheel = (e) => {
- //console.log(e);
- const ds = 0.25;
- const zoomleveloffset = (e.deltaY > 0) ? 1 * ds : -1 * ds;
- const oldz = zoom_level;
- zoom_level = zoom_level - zoomleveloffset;
- if (zoom_level < minlevel) {
- zoom_level = minlevel;
- return;
- }
-
- if (zoom_level > maxlevel) {
- zoom_level = maxlevel;
- return;
- }
- console.log(zoom_level, e.offsetX, e.offsetY);
- updateviewporttest(e.offsetX, e.offsetY, oldz, zoom_level);
- drawtest();
-}
-
-drawtest();
-
-//add opeenstreetmap
-function downloadimg(z, x, y) {
- return new Promise((resolve, reject) => {
- const url = `https://tile.openstreetmap.org/${z}/${x}/${y}.png`;
- let img = new Image();
- img.onload = () => {
- console.log('downloaded' + z + '/' + x + '/' + y + '.png');
- cache.push({ img: img, z: z, x: x, y: y });
- resolve(img);
- }
- img.src = url;
- });
-}
-
-//尝试优化图片下载机制
-function xhrdownloadimg(z, x, y) {
- return new Promise((resolve, reject) => {
- const url = `https://tile.openstreetmap.org/${z}/${x}/${y}.png`;
- let imgxhr = new XMLHttpRequest();
- imgxhr.open('GET', url, true);
- //imgxhr.withCredentials = true;
- imgxhr.responseType = 'blob';
- imgxhr.onload = function (e) {
- if (this.status === 200 && imgxhr.response) {
- let blob = new Blob([imgxhr.response], { type: 'image/png' });
- let img = createImageBitmap(blob);
- cache.push({ img: img, z: z, x: x, y: y });
- resolve(img);
- }
- };
- xhrmanager.push(imgxhr);
- imgxhr.send(null);
- });
-}
-
-function xhrabort() {
- xhrmanager.forEach(element => {
- element.abort();
- });
- xhrmanager = new Array();
-}
-
-async function getImg(z, x, y) {
- const found = cache.find(e => (e.z == z && e.x == x && e.y == y));
- if (found == undefined) {
- let p = await xhrdownloadimg(z, x, y);
- return p;
- } else {
- console.log('exist' + z + '/' + x + '/' + y + '.png');
- return found.img;
- }
-}
-
-function drawTileImg(z, x, y) {
- const img = getImg(z, x, y);
- img.then((e) => {
- const etsize = calTileSize();
- const tilev = mplat2viewport(x * etsize, y * etsize);
- let fz = zoom_level;
- if (zoom_level != Math.floor(zoom_level)) {
- fz = Math.floor(zoom_level + 1);
- }
- if (needtiles.find(t => z == fz && t.x == x && t.y == y)) {
- ctx.drawImage(e, tilev.x, tilev.y, etsize, etsize);
- }
- });
-}
\ No newline at end of file
diff --git a/update.7z b/update.7z
deleted file mode 100644
index 29b5240..0000000
Binary files a/update.7z and /dev/null differ
diff --git a/viewport.js b/viewport.js
deleted file mode 100644
index 034bae8..0000000
--- a/viewport.js
+++ /dev/null
@@ -1,437 +0,0 @@
-//help array;
-let Caches = new Array(); //cache
-//let downloadRecord = new Array();
-let dm = new Array(); //尝试增加下载管理 downloadmanager
-
-let alltilecount = 0;
-let downtilecount = 0;
-
-
-function ViewPort(canvasId, options) {
- // allow without 'new'
- if (!(this instanceof ViewPort)) return new ViewPort(canvasId, options);
- this.TILESIZE = 256; //实际的底图大小
- //init
- this.canvas = document.getElementById(canvasId);
- this.canvas.width = this.canvas.clientWidth;
- this.canvas.height = this.canvas.clientHeight;
-
- this.ctx = this.canvas.getContext('2d');
- this.width = this.canvas.clientWidth;
- this.height = this.canvas.clientHeight;
- if (!options) options = {}; //options could be null or undefine
- this.minZoomLevel = options.minZoomLevel ?? 0;
- this.maxZoomLevel = options.maxZoomLevel ?? 21;
- this.zoomLevel = options.zoomLevel ?? 0;
- this.dzl = options.dzl ?? 0.25; // zoomlevel offset value
- this.rtSize = calTileSize(this.TILESIZE, this.zoomLevel); //named rtSize because real time tile size
-
- const defaultCenterX = Math.pow(2, this.zoomLevel) * this.TILESIZE / 2;
- const defaultCenterY = Math.pow(2, this.zoomLevel) * this.TILESIZE / 2;
- this.xoffset = this.width / 2 - defaultCenterX;
- this.yoffset = this.height / 2 - defaultCenterY;
-
- //如果在options中有指定地图中心点
- //options.centerLng && options.centerLat
- if (options.centerLat != null && options.centerLng != null &&
- !isNaN(options.centerLat) && !isNaN(options.centerLng)) {
- console.log('指定中心点');
- try {
- ({ lat: lat, lng: lng } = this.latlngPreCheck(options.centerLat, options.centerLng));
- const my = lat2y(lat, this.zoomLevel) * this.TILESIZE;
- const mx = lon2x(lng, this.zoomLevel) * this.TILESIZE;
- this.xoffset = this.width / 2 - mx;
- this.yoffset = this.height / 2 - my;
- //console.log('check ', this.viewport2Latlng(this.width / 2, this.height / 2));
- } catch (error) {
- console.log('使用默认中心点');
- }
- }
-
- this.needtiles = new Array(); //需要加载的底图 实时变化
-
- //move
- let moveflag = false;
- let downpoing = { x: 0, y: 0 };
- this.canvas.onmousedown = (e) => {
- moveflag = true;
- [downpoing.x, downpoing.y] = [e.offsetX, e.offsetY];
- //坐标转换 debug
- //console.log(this.zoomLevel, e.offsetX, e.offsetY);
- const wgs84 = this.viewport2Latlng(e.offsetX, e.offsetY);
- console.log('clicked', wgs84);
- }
- this.canvas.onmouseup = (e) => {
- moveflag = false;
- }
- this.canvas.onmouseout = () => {
- moveflag = false; //从元素范围外移动回来时不会继续移动,必须松开左键,按下左键后再进行移动
- }
- this.canvas.onmousemove = (e) => {
- if (moveflag) {
- const movex = downpoing.x - e.offsetX;
- const movey = downpoing.y - e.offsetY;
- //实现移动逻辑
- this.xoffset -= movex;
- this.yoffset -= movey;
-
- this.drawTiles();
- downpoing.x = e.offsetX;
- downpoing.y = e.offsetY;
- }
- }
-
- //scale
- this.canvas.onwheel = (e) => {
- const dzl = this.dzl;
- const zoomleveloffset = (e.deltaY > 0) ? 1 * dzl : -1 * dzl;
- const oldz = this.zoomLevel;
- this.zoomLevel = this.zoomLevel - zoomleveloffset;
- if (this.zoomLevel < this.minZoomLevel) {
- this.zoomLevel = this.minZoomLevel;
- return;
- }
-
- if (this.zoomLevel > this.maxZoomLevel) {
- this.zoomLevel = this.maxZoomLevel;
- return;
- }
- //console.log(this.zoomLevel, e.offsetX, e.offsetY);
- this.updateViewport(e.offsetX, e.offsetY, oldz, this.zoomLevel);
- this.drawTiles();
- }
-
- this.drawTiles();
-
- // setInterval(() => {
- // debug();
- // }, 1000);
-}
-
-//扩展一下Array 用以辅助进行加载底图
-Array.prototype.remove = function (val) {
- const index = this.indexOf(val);
- if (index > -1) {
- return this.splice(index, 1);
- }
- return this;
-}
-
-ViewPort.prototype = {
- latlngPreCheck(lat, lng) {
- //数据超界处理 经度 -180 180
- //纬度 < 85.0511287798066 (2*Math.atan(Math.pow(Math.E,Math.PI))-Math.PI/2)/Math.PI*180
- const latlimit = 85.0511287798066; //取近似值
- const lngp = lng - Math.floor((lng + 180) / 360) * 360;
- if (lat < (0 - latlimit) || lat > latlimit) {
- throw "OutMapRange";
- }
- return { lat: lat, lng: lngp };
- },
-
- mplatPreCheck(mx, my) {
- //数据超界处理, 这里是对应缩放等级的地图的大小,底图大小*底图块数 注意底图块数始终为整数level时的底图块数
- //实际只改变的底图大小,没有改变块数
- let limit = calTileSize(this.TILESIZE, this.zoomLevel) * Math.pow(2, this.zoomLevel);
- if (this.zoomLevel != Math.floor(this.zoomLevel)) {
- limit = calTileSize(this.TILESIZE, this.zoomLevel) * Math.pow(2, Math.floor(this.zoomLevel + 1));
- }
- if (mx <= 0 || my <= 0 || mx >= limit || my >= limit) {
- throw "OutMapRange";
- }
- return { x: mx, y: my };
- },
-
- //-------------------------------------
- //这几个函数是坐标转换函数
- mplat2Viewport(mx, my) {
- const vx = mx + this.xoffset;
- const vy = my + this.yoffset;
- return { x: vx, y: vy };
- },
-
- viewport2Mplat(vx, vy) {
- const mx = vx - this.xoffset;
- const my = vy - this.yoffset;
- return { x: mx, y: my };
- },
-
- viewport2Latlng(vx, vy) {
- let mplatc = this.viewport2Mplat(vx, vy); //mplat coordinates
- mplatc = this.mplatPreCheck(mplatc.x, mplatc.y);
- const lat = tile2lat(mplatc.y / this.TILESIZE, this.zoomLevel);
- const lng = tile2long(mplatc.x / this.TILESIZE, this.zoomLevel);
- return { lat: lat, lng: lng }
- },
- latlng2Viewport(lat, lng) {
- ({ lat: lat, lng: lng } = this.latlngPreCheck(lat, lng)); //尝试使用解构赋值
- const my = lat2y(lat, this.zoomLevel) * this.TILESIZE;
- const mx = lon2x(lng, this.zoomLevel) * this.TILESIZE;
- const vp = this.mplat2Viewport(mx, my);
- return { x: vp.x, y: vp.y };
- },
- //----------------------------------------
-
- //更新偏移值
- updateViewport(scrollx, scrolly, oldz, newz) {
- //计算出缩放后坐标系的偏移值
- // xv = xm + offset ; offset = xv - xm
- const scrollm = this.viewport2Mplat(scrollx, scrolly);
- const basescale = Math.pow(2, newz - oldz);
- const newscrollm = { x: scrollm.x * basescale, y: scrollm.y * basescale };
- this.xoffset = scrollx - newscrollm.x;
- this.yoffset = scrolly - newscrollm.y;
- },
-
- //过滤需要加载的底图
- tilesFilter(tails) {
- let news = new Array();
- let max = Math.pow(2, this.zoomLevel);
- if (this.zoomLevel != Math.floor(this.zoomLevel)) {
- max = Math.pow(2, Math.floor(this.zoomLevel + 1));
- }
- for (let i = 0; i < tails.length; i++) {
- const e = tails[i];
- if (e.x >= 0 && e.y >= 0 && e.x < max && e.y < max) {
- news.push(e);
- }
- }
- return news;
- },
-
-
- //一些绘制函数
- clearCanvas() {
- this.ctx.clearRect(0, 0, this.width, this.height);
- },
- drawRect(x, y, width, height) {
- this.ctx.strokeStyle = "white"
- this.ctx.strokeRect(x, y, width, height);
- },
- drawtext(text, x, y) {
- this.ctx.fillStyle = "white"
- this.ctx.font = "18px serif";
- this.ctx.textAlign = "center";
- this.ctx.textBaseline = "middle";
- this.ctx.fillText(text, x, y);
- },
- drawTiles() {
- this.clearCanvas();
- const viewport_left_top = this.viewport2Mplat(0, 0);
- const viewport_right_bottom = this.viewport2Mplat(this.width, this.height);
- const mixnum = calTileNum(viewport_left_top.x, this.TILESIZE, this.zoomLevel);
- const miynum = calTileNum(viewport_left_top.y, this.TILESIZE, this.zoomLevel);
- const maxnum = calTileNum(viewport_right_bottom.x, this.TILESIZE, this.zoomLevel);
- const maynum = calTileNum(viewport_right_bottom.y, this.TILESIZE, this.zoomLevel);
- const horicount = maxnum - mixnum + 1;
- const verticount = maynum - miynum + 1;
- let tails = new Array();
- for (let i = 0; i < horicount; i++) {
- for (let j = 0; j < verticount; j++) {
- const x = mixnum + i;
- const y = miynum + j;
- tails.push({ x: x, y: y });
- }
- }
- this.needtiles = this.tilesFilter(tails); //获取当前视口要渲染的底图
- let z = this.zoomLevel; //这里的几行代码的逻辑是用到了5个函数里面,后面可以想一下怎么重构
- if (this.zoomLevel != Math.floor(this.zoomLevel)) {
- z = Math.floor(this.zoomLevel + 1);
- }
-
- //尝试在这里移除不需要继续下载的内容
- let indexs = new Array();
- dm.forEach(d => {
- if (d.z !=z) {
- if(this.needtiles.find(e=>e.x==d.x&&e.y==d.y)==undefined){
- d.xhr.abort();
- console.log('中断请求');
- dm.remove(d);
- }
- }
- });
-
-
-
- alltilecount += this.needtiles.length; //for debug
- //console.log(this.needtiles);
- this.needtiles.forEach(et => {
- const etsize = calTileSize(this.TILESIZE, this.zoomLevel);
- const tilev = this.mplat2Viewport(et.x * etsize, et.y * etsize);
- this.drawRect(tilev.x, tilev.y, etsize, etsize);
- const text = `${z}/${et.x}/${et.y}.png`;
- // console.log(text);
- this.drawtext(text, tilev.x + etsize / 2, tilev.y + etsize / 2);
- this.drawTileImg(z, et.x, et.y);
- });
- //debug();
- },
- drawTileImg(z, x, y) {
-
- const img = getImg(this, z, x, y);
- img.then((e) => {
- if (isTileShouldDownload(this, z, x, y)) {
- //对e添加判断,似乎不是每一个e都是一个图片
- if (e instanceof ImageBitmap) {
- const etsize = calTileSize(this.TILESIZE, this.zoomLevel);
- const tilev = this.mplat2Viewport(x * etsize, y * etsize);
- this.ctx.drawImage(e, tilev.x, tilev.y, etsize, etsize);
- }
- }
- }).catch((e) => {
- console.log(e);
- });
- },
-
-}
-
-//计算实时底图大小
-function calTileSize(tilesize, zoomLevel) {
- let rtSize = tilesize;
- if (zoomLevel != Math.floor(zoomLevel)) {
- rtSize = tilesize * Math.pow(2, zoomLevel - Math.floor(zoomLevel + 1));
- }
- return rtSize;
-}
-
-//计算当前坐标值所在的底图编号
-function calTileNum(coord, tilesize, zoomLevel) {
- return Math.floor(coord / calTileSize(tilesize, zoomLevel));
-}
-
-//=====coord about 地理坐标与墨卡托投影的相关转换方法=====
-function lon2tile(lon, z) {
- return (Math.floor((lon + 180) / 360 * Math.pow(2, z)));
-}
-
-function lat2tile(lat, z) {
- return (Math.floor((1 - Math.log(Math.tan(lat * Math.PI / 180) +
- 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) /
- 2 * Math.pow(2, z)));
-}
-
-function lon2x(lon, z) {
- return ((lon + 180) / 360 * Math.pow(2, z));
-}
-
-function lat2y(lat, z) {
- return ((1 - Math.log(Math.tan(lat * Math.PI / 180) +
- 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) /
- 2 * Math.pow(2, z));
-}
-
-function tile2long(x, z) {
- return (x / Math.pow(2, z) * 360 - 180);
-}
-
-function tile2lat(y, z) {
- var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
- return (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))));
-}
-
-//=========下载图片相关==================
-//将其和viewpoint分离,方便后续修复问题和增加新的下载方式或者底图源
-
-//判断一张底图需不需要继续下载,这里采用保守一点的下载策略,必须是先判定为需要加载的底图才开始下载
-//传入vp以获取相关参数
-function isTileShouldDownload(vp, z, x, y) {
- let fz = vp.zoomLevel;
- if (vp.zoomLevel != Math.floor(vp.zoomLevel)) {
- fz = Math.floor(vp.zoomLevel + 1);
- }
- if (vp.needtiles.find(t => z == fz && t.x == x && t.y == y)) {
- return true;
- }
- return false;
-}
-
-//add autonavi
-function downloadimg(z, x, y) {
- return new Promise((resolve) => {
- //const url = `https://tile.openstreetmap.org/${z}/${x}/${y}.png`;
- const url = 'http://webrd01.is.autonavi.com/' +
- 'appmaptile?lang=zh_cn&size=1&scale=1&style=8' +
- `&x=${x}&y=${y}&z=${z}`;
- //add downloadcheck
- const obj = { z: z, x: x, y: y };
- downloadRecord.push(obj); //下载前加入记录
- let img = new Image();
- const dmobj = { img: img, z: z, x: x, y: y };
- img.onload = () => {
- //console.log('downloaded' + z + '/' + x + '/' + y + '.png');
- downloadRecord.remove(obj); //下载完成后从记录中移除
- dm.remove(dmobj);
- Caches.push({ img: img, z: z, x: x, y: y }); //下载完成后加入缓存
- downtilecount += 1;
- resolve(img);
- }
- img.src = url;
- dm.push(dmobj); //尝试添加管理
- });
-}
-
-//尝试优化图片下载机制 //采用下载速度比较慢的openstreetmap 测试
-function xhrdownloadimg(z, x, y) {
- return new Promise((resolve, reject) => {
- const url = `https://b.tile.openstreetmap.org/${z}/${x}/${y}.png`;
- let imgxhr = new XMLHttpRequest();
- imgxhr.open('GET', url, true);
-
- //add downloadcheck
- //const obj = { z: z, x: x, y: y };
- //downloadRecord.push(obj); //下载前加入一条记录
- const dmobj = { xhr: imgxhr, z: z, x: x, y: y };
-
- //imgxhr.withCredentials = true;
- imgxhr.responseType = 'blob';
- imgxhr.onload = function (e) {
- if (this.status === 200 && imgxhr.response) {
- let blob = new Blob([imgxhr.response], { type: 'image/png' });
- let img = createImageBitmap(blob);
- Caches.push({ img: img, z: z, x: x, y: y });
- downtilecount += 1;
- //downloadRecord.remove(obj); //下载完成后将记录移除
- dm.remove(dmobj);
- console.log('dm下载完成减少');
- resolve(img);
- } else {
- reject('下载似乎失败了');
- dm.remove(dmobj);
- console.log('dm下载失败减少');
- }
- };
- dm.push(dmobj); //保存xhr对象 和xyz索引
- imgxhr.send(null);
- });
-}
-
-async function getImg(vp, z, x, y) {
- const found = Caches.find(e => (e.z == z && e.x == x && e.y == y)); //查找缓存
- if (found == undefined) { //缓存中没有
- console.log('缓存中没有' + z + '/' + x + '/' + y + '.png');
- //这里不需要判断是否继续加载,在还未开始下载图片前,这里可以说是立即执行的
- console.log(isTileShouldDownload(vp, z, x, y));//always true
- const dmobj = dm.find(e => (e.z == z && e.x == x && e.y == y));
- if (dmobj == undefined) {
- //如果缓存中没有,并且没有下载记录 发起下载请求并等待结果
- let p = await xhrdownloadimg(z, x, y);
- return p;
- }
- else {//有下载记录就不用继续下载了
- console.log(vp.zoomLevel, vp.xoffset, vp.yoffset);
- return Promise.reject('需要等待下载完成');
- }
- } else { //缓存中有直接返回
- console.log('缓存中有' + z + '/' + x + '/' + y + '.png');
- return found.img;
- }
-}
-
-function debug() {
- console.log('=============debug=================');
- console.log('alltilecount', alltilecount);
- console.log('downtilecount', downtilecount);
- console.log('cachecount', Caches.length);
- console.log('dm count', dm.length);
- console.log('=============debug=================');
-}
\ No newline at end of file