JSFiddle - React, Tailwind, and code Playground
by secretgspot
HTML
<canvas id='world' width='465' height='425'></canvas>
スクリーンまでの距離:<input type='text' id='f' value='200' onkeyup='fChanged(this);' />
CSS
body {
background-color: #FFF;
margin: 0;
overflow: hidden;
}
#f {
width: 4em;
}
JavaScript
/**
* 1点透視図法
* Z方向の直線はすべて消失点に収束されます
*
* 遠近法
* http://ja.wikipedia.org/wiki/%E9%81%A0%E8%BF%91%E6%B3%95
*/
var Vertex3D = function(x, y, z) {
// 3D座標
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
// 2D座標
this.screenX = 0;
this.screenY = 0;
this.project = function(scene) {
this.screenX = f * (this.x - vx) / (f + this.z) + vx;
this.screenY = f * (this.y - vy) / (f + this.z) + vy;
};
};
var canvas = document.getElementById('world');
var cxt = canvas.getContext("2d");
// 消失点
var vx = Math.floor(canvas.width / 2);
var vy = Math.floor(canvas.height / 2);
// スクリーンまでの距離
var f = 200;
function render() {
cxt.clearRect(0, 0, 600, 500);
// 消失点を描画
cxt.fillStyle = "#FF0000";
cxt.beginPath();
cxt.arc(vx, vy, 5, 0, Math.PI*2, false);
cxt.fill();
var cx = Math.floor(canvas.width / 2);
var cy = Math.floor(canvas.height / 2);
var v1 = new Vertex3D();
var v2 = new Vertex3D();
var i;
v1.y = v2.y = cy;
for(i = 0; i <= 400; i+=50) {
v1.x = v2.x = cx + i - 200;
v1.z = 0;
v2.z = 400;
drawLine(v1, v2);
v1.x = cx - 200;
v2.x = cx + 200;
v1.z = v2.z = i;
drawLine(v1, v2);
}
v1.x = v2.x = cx;
for(i = 0; i <= 400; i+=50) {
v1.y = v2.y = cy + i - 200;
v1.z = 0;
v2.z = 400;
drawLine(v1, v2);
v1.y = cy - 200;
v2.y = cy + 200;
v1.z = v2.z = i;
drawLine(v1, v2);
}
}
function drawLine(v1, v2) {
v1.project();
v2.project();
cxt.lineWidth = 1;
cxt.strokeStyle = "#FF0000";
cxt.beginPath();
cxt.moveTo(v1.screenX, v1.screenY);
cxt.lineTo(v2.screenX, v2.screenY);
cxt.closePath();
cxt.stroke();
}
function mouseMove(e) {
// 消失点を移動
vx = e.clientX;
vy = e.clientY;
render();
}
function fChanged(txt) {
var n = Number(txt.value);
if(!isNaN(n)) {
f = n;
render();
}
}
canvas.onmousemove = mouseMove;
render();