最近在学线性代数想树立几何直观于是试试踩地图的坑:
有些边界线没有绘制,请勿上纲上线。
数据来源于阿里的datav, 请自行下载,link.js内部为向量数据参考当前各式即可。
支持鼠标滚轮缩放,拖拽移动(请忽略小问题,位移拖拽bug,如有解决方法请在下方留言)。
废话少说直接上代码。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body{
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
</style>
<script src="../rxjs.umd.js"></script>
<script src="link.js"></script>
<script>
let dip = 3;
let startX = 0;
let startY = 0;
let endX = 0;
let endY = 0;
function draw() {
const canvas = document.getElementById('canvas');
let windowGlobalSize = getWindowSize();
canvas.width = windowGlobalSize.width;
canvas.height = windowGlobalSize.height;
setTimeout(() => {
setRect(canvas);
}, 1000);
window.addEventListener('resize', () => {
setTimeout(() => {
let windowGlobalSize = getWindowSize();
canvas.width = windowGlobalSize.width;
canvas.height = windowGlobalSize.height;
setRect(canvas);
}, 1000);
})
window.addEventListener('mousewheel', (event) => {
if (event.wheelDelta > 0) {
dip++;
let windowGlobalSize = getWindowSize();
canvas.width = windowGlobalSize.width;
canvas.height = windowGlobalSize.height;
setRect(canvas);
} else {
if (dip > 1) {
dip--;
}
let windowGlobalSize = getWindowSize();
canvas.width = windowGlobalSize.width;
canvas.height = windowGlobalSize.height;
setRect(canvas);
}
});
const mouseDown = rxjs.fromEvent(canvas, "mousedown");
const mouseUp = rxjs.fromEvent(document, "mouseup");
const mouseMove = rxjs.fromEvent(document, "mousemove");
let isMove = false;
mouseDown
.pipe(
rxjs.map((e) => {
return {
x: e.pageX,
y: e.pageY
};
})
).subscribe(e => {
if (!isMove) {
startX = e.x;
startY = e.y;
isMove = true;
}
})
mouseUp
.pipe(
rxjs.map((e) => {
return {
x: e.pageX,
y: e.pageY
};
})
).subscribe(e => {
startX = e.x - endX;
startY = e.y - endY;
})
mouseDown
.pipe(
rxjs.switchMap(e => {
return mouseMove.pipe(rxjs.takeUntil(mouseUp))
}),
rxjs.map((e) => {
return {
x: e.pageX,
y: e.pageY
};
})
)
.subscribe(e => {
endY = e.y - startY
endX = e.x - startX
let windowGlobalSize = getWindowSize();
canvas.width = windowGlobalSize.width;
canvas.height = windowGlobalSize.height;
setRect(canvas);
})
}
function setRect(canvas) {
// 当前画布宽度
const width = canvas.width;
// 当前画布高度
const height = canvas.height;
// 当前X轴原点处于Y轴位置
const x = height / 2;
// 当前Y轴原点处于X轴位置
const y = width / 2;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(0,0,0,.3)'
ctx.fillRect(0, 0, width, height);
setColY(ctx, x, width, height);
setRowX(ctx, y, width, height);
setXY(ctx, x, y, width, height);
const arrX = []
const arrY = []
map.features.forEach(item => {
let coordinates = item.geometry.coordinates;
coordinates.forEach(data => {
data.forEach(data1 => {
if (data1.length > 2) {
data1.forEach((data2, i) => {
arrX.push(data2[0]);
arrY.push(data2[1]);
});
}
});
});
});
const left = Math.min(...arrX);
const right = Math.max(...arrX);
const top = Math.min(...arrY);
const bottom = Math.max(...arrY);
let movex = (y - ((right + left) / 2));
let moveY = (x - ((top + bottom) / 2));
map.features.forEach(item => {
let coordinates = item.geometry.coordinates;
coordinates.forEach(data => {
data.forEach(data1 => {
if (data1.length > 2) {
ctx.beginPath();
data1.forEach((data2, i) => {
let mapX = data2[0] + movex;
let mapY = data2[1] + moveY;
const valX = mapX - y;
const valY = mapY - x;
if (valX) {
mapX += (valX * dip)
} else {
mapX -= (valX * dip)
}
if (valY) {
mapY += (valY * dip)
} else {
mapY -= (valY * dip)
}
if (mapY < x) {
mapY = x + (x - mapY)
} else {
mapY = x - (mapY - x)
}
if (i === 0) {
ctx.moveTo(mapX + endX, mapY + endY);
}
ctx.lineTo(mapX + endX, mapY + endY);
});
ctx.stroke();
}
});
});
});
}
// 绘制X轴刻度线
function setColY(ctx, x, w, h) {
/**
* 当前从那个位置开始画Y轴刻度线
* @param colYPositive {number} 向正半轴开始绘制
* @param colYMinus {number} 向负半轴开始绘制
*/
const obj = {
colYPositive: x,
colYMinus: x
};
ctx.strokeStyle = 'rgb(213,208,208)'
ctx.beginPath();
while (obj.colYPositive > 0) {
obj.colYPositive = obj.colYPositive - 30;
ctx.moveTo(0, obj.colYPositive);
ctx.lineTo(0, obj.colYPositive);
ctx.lineTo(w, obj.colYPositive);
}
while (obj.colYMinus <= h) {
obj.colYMinus = obj.colYMinus + 30;
ctx.moveTo(0, obj.colYMinus);
ctx.lineTo(0, obj.colYMinus);
ctx.lineTo(w, obj.colYMinus);
}
ctx.stroke();
}
// 绘制X轴单元格
function setRowX(ctx, y, w, h) {
// 当前从那个位置开始画Y轴刻度线
/**
* 当前从那个位置开始画Y轴刻度线
* @param colYPositive {number} 向正半轴开始绘制
* @param colYMinus {number} 向负半轴开始绘制
*/
const obj = {
rowXPositive: y,
rowXMinus: y
};
ctx.strokeStyle = 'rgb(213,208,208)'
ctx.beginPath();
while (obj.rowXPositive > 0) {
obj.rowXPositive = obj.rowXPositive - 30;
ctx.moveTo(obj.rowXPositive, 0);
ctx.lineTo(obj.rowXPositive, 0);
ctx.lineTo(obj.rowXPositive, h);
}
while (obj.rowXMinus <= w) {
obj.rowXMinus = obj.rowXMinus + 30;
ctx.moveTo(obj.rowXMinus, 0);
ctx.lineTo(obj.rowXMinus, 0);
ctx.lineTo(obj.rowXMinus, h);
}
ctx.stroke();
}
function setXY(ctx, x, y, w, h) {
ctx.strokeStyle = 'rgb(0,0,0)'
ctx.beginPath();
ctx.moveTo(0, x);
ctx.lineTo(0, x);
ctx.lineTo(w, x);
ctx.stroke();
ctx.strokeStyle = 'rgb(0,0,0)'
ctx.beginPath();
ctx.moveTo(y, 0);
ctx.lineTo(y, 0);
ctx.lineTo(y, h);
ctx.stroke();
}
function getWindowSize() {
const width = document.documentElement.clientWidth;
const height = document.documentElement.clientHeight;
return {
width,
height
}
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="150" height="150"></canvas>
</body>
</html>