You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
9.1 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

//椭球相关参数计算
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;
}
}