diff --git a/test.js b/test.js new file mode 100644 index 0000000..dc21945 --- /dev/null +++ b/test.js @@ -0,0 +1,234 @@ +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(); + +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 testtiles = new Array(); + // testtiles.push({ x: 0, y: 0 }); + // testtiles.push({ x: 0, y: 1 }); + // testtiles.push({ x: 1, y: 0 }); + // testtiles.push({ x: 1, y: 1 }); + // testtiles.forEach(et => { + // let etsize = tilesize; + // if (zoom_level != Math.floor(zoom_level)) { + // etsize = tilesize * Math.pow(2, zoom_level - Math.floor(zoom_level + 1)); + // } + // const tilev = mplat2viewport(et.x * etsize, et.y * etsize); + // drawRect(tilev.x, tilev.y, etsize, etsize); + // }); + 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); + //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; + }); +} + +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 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); + } + }); +} \ No newline at end of file