173 lines
4.5 KiB
HTML
173 lines
4.5 KiB
HTML
<!--
|
|
~ Copyright (c) 2020. Pascal Syma <pascal@syma.dev>.
|
|
~ All rights reserved.
|
|
-->
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Editor</title>
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
height: 0;
|
|
user-select: none; /* standard syntax */
|
|
-webkit-user-select: none; /* webkit (safari, chrome) browsers */
|
|
-moz-user-select: none; /* mozilla browsers */
|
|
-khtml-user-select: none; /* webkit (konqueror) browsers */
|
|
-ms-user-select: none; /* IE10+ */
|
|
}
|
|
|
|
div {
|
|
position: fixed;
|
|
right: 0;
|
|
margin: 8px;
|
|
text-align: right;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div>
|
|
<table id="stops">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
</tbody>
|
|
</table>
|
|
<label><textarea id="inp" rows="3"></textarea></label>
|
|
</div>
|
|
<canvas id="canvas"></canvas>
|
|
|
|
<script>
|
|
Number.prototype.mod = function (n) {
|
|
return ((this % n) + n) % n;
|
|
};
|
|
let stops = [];
|
|
let i = 0;
|
|
let canvas = document.getElementById("canvas");
|
|
canvas.focus()
|
|
let ctx = canvas.getContext("2d");
|
|
|
|
let tbl = document.getElementById("stops");
|
|
let inp = document.getElementById("inp");
|
|
inp.addEventListener('input', () => {
|
|
if (inp.value === null || inp.value === '')
|
|
return;
|
|
stops = inp.value.split('\n').map(l => {
|
|
return {
|
|
name: l,
|
|
x: null,
|
|
y: null
|
|
}
|
|
})
|
|
inp.value = ''
|
|
i = 0;
|
|
canvas.focus();
|
|
draw()
|
|
})
|
|
let map = new Image();
|
|
map.onload = () => {
|
|
canvas.width = map.width;
|
|
canvas.height = map.height
|
|
draw()
|
|
|
|
canvas.addEventListener('contextmenu', ev => {
|
|
// right
|
|
ev.preventDefault();
|
|
stops.splice(i, 0, {
|
|
name: null,
|
|
x: ev.offsetX,
|
|
y: ev.offsetY
|
|
})
|
|
|
|
i = (i + 1).mod(stops.length)
|
|
draw();
|
|
return false;
|
|
}, false);
|
|
|
|
canvas.addEventListener('click', ev => {
|
|
// left
|
|
ev.preventDefault();
|
|
|
|
stops[i].x = ev.offsetX
|
|
stops[i].y = ev.offsetY
|
|
|
|
|
|
i = (i + 1).mod(stops.length)
|
|
draw();
|
|
return false;
|
|
}, false);
|
|
|
|
document.addEventListener('keydown', e => {
|
|
if (e.which === 38) {
|
|
// up
|
|
i = (i - 1).mod(stops.length)
|
|
draw()
|
|
e.preventDefault()
|
|
} else if (e.which === 40) {
|
|
// down
|
|
i = (i + 1).mod(stops.length)
|
|
draw()
|
|
e.preventDefault()
|
|
} else if (e.which === 13) {
|
|
// enter
|
|
let output = stops.map(s => `${s.x},${s.y}` + (s.name ? `,,${s.name}` : '')).join('\n')
|
|
|
|
console.log(output)
|
|
}
|
|
})
|
|
}
|
|
map.src = "map.png";
|
|
|
|
|
|
function draw() {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
ctx.drawImage(map, 0, 0)
|
|
tbl.getElementsByTagName('tbody')[0].innerHTML = "";
|
|
let last = null;
|
|
stops.forEach((s, index) => {
|
|
const tr = document.createElement('tr');
|
|
const tdName = document.createElement('td');
|
|
tdName.innerText = s.name ? s.name : '-';
|
|
const tdI = document.createElement('td');
|
|
if (index === i)
|
|
tdI.innerText = '<';
|
|
|
|
|
|
tr.append(tdName, tdI);
|
|
|
|
tbl.getElementsByTagName('tbody')[0].append(tr)
|
|
|
|
if (s.y === null && s.x === null)
|
|
return;
|
|
if (s.name !== null) {
|
|
ctx.beginPath()
|
|
ctx.arc(s.x, s.y, 5, 0, 2 * Math.PI);
|
|
ctx.lineWidth = 1;
|
|
ctx.strokeStyle = index === i ? '#f00' : '#000'
|
|
ctx.stroke()
|
|
ctx.closePath()
|
|
ctx.fillStyle = '#000'
|
|
ctx.textAlign = "center";
|
|
ctx.fillText(s.name, s.x, s.y - 10);
|
|
}
|
|
if (last) {
|
|
ctx.beginPath()
|
|
ctx.moveTo(last.x, last.y)
|
|
ctx.lineWidth = 3;
|
|
ctx.lineTo(s.x, s.y)
|
|
ctx.strokeStyle = '#000'
|
|
ctx.stroke()
|
|
ctx.closePath()
|
|
}
|
|
last = s;
|
|
})
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |