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

663 lines
17 KiB

//
// draw track
//
const RAILWAY_NOTHING = 0;
const RAILWAY_NORMAL = 1;
const RAILWAY_CROSSING = 2;
const RAILWAY_TURNOUT = 3;
const RAILWAY_SENSOR = 4;
const RAILWAY_CONNECTOR = 5;
const RAILWAY_BUTTON = 6;
const RAILWAY_TEXT = 7;
const RAILWAY_BLOCK = 8;
var track = {
size: {x: -1, y: -1},
scale: 24,
dbuf: {},
elements: []
};
var trackMouse = {
pos: {x: -1, y: -1, subx: 0.5, suby: 0.5},
down: {x :-1 , y: -1, subx: 0.5, suby: 0.5}
};
//
// mode: 0 = normal
// mode: 1 = selected
// mode: 2 = mouseover
//
// direktion (object type)
//
// +---+ +---+ +---+ +---+
// | | | | | | | |/ |
// 0| | 1| | | 2|---| 3| |
// | | | | | | | | |
// +---+ +---+ +---+ +---+
//
// +---+ +---+ +---+ +---+
// | \| | | | | | |
// 4| | 5| | 6| | 7| |
// | | | /| |\ | | |
// +---+ +---+ +---+ +---+
//
// direction (arrow type)
//
// 0
// 7 | 1
// \|/
// 6--+--2
// /|\
// 5 | 3
// 4
//
function trackDrawTrack(ctx, pos, dirtype) {
var s = { x:0 , y:0 };
var e = { x:0 , y:0 };
if (dirtype == 1) {
s = { x: 0.5, y: 0.0 };
e = { x: 0.5, y: 1.0 };
}
else if (dirtype == 2) {
s = { x: 0.0, y: 0.5 };
e = { x: 1.0, y: 0.5 };
}
else if (dirtype == 3) {
s = { x: 0.5, y: 0.0 };
e = { x: 0.0, y: 0.5 };
}
else if (dirtype == 4) {
s = { x: 0.5, y: 0.0 };
e = { x: 1.0, y: 0.5 };
}
else if (dirtype == 5) {
s = { x: 0.5, y: 1.0 };
e = { x: 1.0, y: 0.5 };
}
else if (dirtype == 6) {
s = { x: 0.5, y: 1.0 };
e = { x: 0.0, y: 0.5 };
}
else {
s = { x: 0, y: 0 };
e = { x: 0, y: 0 };
}
if (s.x != e.x || s.y != e.x) {
ctx.beginPath();
ctx.moveTo(0.5+(pos.x+s.x) * track.scale, 0.5+(pos.y+s.y) * track.scale);
ctx.lineTo(0.5+(pos.x+e.x) * track.scale, 0.5+(pos.y+e.y) * track.scale);
ctx.stroke();
}
}
function trackDrawElement(ctx, element, mode) {
var dx = 0, dy = 0;
var modcol = "#B0B0B0";
if (element) {
if (mode == 1) modcol = "#FF0000";
if (element.type) {
if (element.type == RAILWAY_TURNOUT) {
//
// turnout
var dir = element.dir;
var altdir = element.altdir;
if (element.name != "") if (turnout_IsActive(element.name)) {
// debug ("draw element:" + element.name + " isActive:" + turnout_IsActive(element.name));
altdir = element.dir;
dir = element.altdir;
}
ctx.lineWidth = 4;
ctx.setLineDash([0,0]);
ctx.strokeStyle = modcol;
trackDrawTrack (ctx, {x: element.x, y: element.y}, dir);
ctx.setLineDash([0,0]);
if (element.name == "") ctx.strokeStyle = "DeepPink";
else ctx.strokeStyle = "DimGray";
trackDrawTrack (ctx, {x: element.x, y: element.y}, altdir);
}
else if (element.type == RAILWAY_NORMAL || element.type == RAILWAY_SENSOR) {
//
// normal
ctx.lineWidth = 2;
ctx.setLineDash([0,0]);
ctx.strokeStyle = modcol;
trackDrawTrack (ctx, {x: element.x, y: element.y}, element.dir);
}
else if (element.type == RAILWAY_CROSSING) {
//
// crossing
ctx.lineWidth = 2;
ctx.setLineDash([0,0]);
ctx.strokeStyle = modcol;
trackDrawTrack (ctx, {x: element.x, y: element.y}, element.dir);
trackDrawTrack (ctx, {x: element.x, y: element.y}, element.altdir);
}
else if (element.type == RAILWAY_TEXT) {
ctx.font = "14px Arial";
ctx.textAlign = "left";
if (element.name != "") {
ctx.fillStyle = "lightblue";
ctx.fillText(element.name, (element.x+0.5) * track.scale, 6+(element.y+0.5) * track.scale);
}
else {
ctx.fillStyle = "DeepPink";
ctx.fillText("------", (element.x+0.5) * track.scale, (element.y+0.5) * track.scale);
}
}
else if (element.type == RAILWAY_CONNECTOR) {
ctx.font = "bold 12px Arial";
ctx.textAlign = "center";
if (element.name != "") {
ctx.fillStyle = "#FFFFFF";
ctx.fillText(element.name, (element.x+0.5) * track.scale, 6+(element.y+0.5) * track.scale);
}
else {
ctx.fillStyle = "DeepPink";
ctx.fillText("------", (element.x+0.5) * track.scale, (element.y+0.5) * track.scale);
}
}
else if (element.type != RAILWAY_NOTHING) {
ctx.beginPath();
ctx.lineWidth = 2;
ctx.setLineDash([0,0]);
ctx.strokeStyle = "DeepPink";
ctx.moveTo((element.x+0.25) * track.scale, (element.y+0.25) * track.scale);
ctx.lineTo((element.x+0.75) * track.scale, (element.y+0.75) * track.scale);
ctx.moveTo((element.x+0.75) * track.scale, (element.y+0.25) * track.scale);
ctx.lineTo((element.x+0.25) * track.scale, (element.y+0.75) * track.scale);
ctx.stroke();
}
//
// additional draing of elements
if (element.type == RAILWAY_SENSOR) {
ctx.beginPath();
ctx.arc((element.x+0.5) * track.scale, (element.y+0.5) * track.scale, track.scale*0.25, 0, 2 * Math.PI);
if (element.name == "") ctx.fillStyle = 'DeepPink';
else if (sensor_IsActive(element.name)) ctx.fillStyle = 'LightGreen';
else ctx.fillStyle = 'DimGray';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = "#000000";
ctx.stroke();
}
//
// draw ref. name
if (element.name && sideBtnModeGet() == "mode-turn") {
if (element.type != RAILWAY_TEXT && element.type != RAILWAY_CONNECTOR) {
ctx.font = "10px Arial";
ctx.textAlign = "left";
if (element.name != "") {
ctx.fillStyle = "black";
ctx.fillText(element.name, (element.x) * track.scale -1, 6+(element.y+0.5) * track.scale );
ctx.fillText(element.name, (element.x) * track.scale +1, 6+(element.y+0.5) * track.scale );
ctx.fillText(element.name, (element.x) * track.scale , 6+(element.y+0.5) * track.scale -1);
ctx.fillText(element.name, (element.x) * track.scale , 6+(element.y+0.5) * track.scale +1);
ctx.fillText(element.name, (element.x) * track.scale +1, 6+(element.y+0.5) * track.scale +1);
ctx.fillText(element.name, (element.x) * track.scale -1, 6+(element.y+0.5) * track.scale -1);
ctx.fillText(element.name, (element.x) * track.scale +1, 6+(element.y+0.5) * track.scale -1);
ctx.fillText(element.name, (element.x) * track.scale +1, 6+(element.y+0.5) * track.scale +1);
ctx.fillText(element.name, (element.x) * track.scale -1, 6+(element.y+0.5) * track.scale +1);
ctx.fillStyle = "white";
ctx.fillText(element.name, (element.x) * track.scale , 6+(element.y+0.5) * track.scale );
}
}
}
}
}
};
function trackDraw() {
var ctx = track.dbuf.getContext("2d");
var elm = {};
// debug ("trackDraw pos: " + trackMouse.pos.x + "," + trackMouse.pos.y +
// " down: " + trackMouse.down.x + "," + trackMouse.down.y);
//
// clear screen
ctx.fillStyle = "#808080";
ctx.fillRect(0, 0, track.size.x * track.scale, track.size.y * track.scale);
//
//
for (var i = 0; i < track.elements.length; i++) {
trackDrawElement(ctx, track.elements[i], 0);
}
//
// draw down position
if (trackMouse.down.x >= 0) {
var p1 = {};
var p2 = {};
if (trackMouse.pos.x < trackMouse.down.x) {
p1.x = trackMouse.pos.x;
p2.x = trackMouse.down.x;
}
else {
p1.x = trackMouse.down.x;
p2.x = trackMouse.pos.x;
}
if (trackMouse.pos.y < trackMouse.down.y) {
p1.y = trackMouse.pos.y;
p2.y = trackMouse.down.y;
}
else {
p1.y = trackMouse.down.y;
p2.y = trackMouse.pos.y;
}
ctx.lineWidth = 1;
ctx.lineJoin="round";
ctx.miterLimit = 1;
ctx.setLineDash([2,2]);
ctx.strokeStyle = "#0000FF";
ctx.beginPath();
ctx.moveTo(0.5+(p1.x + 0) * track.scale, 0.5+(p1.y+0) * track.scale);
ctx.lineTo(0.5+(p2.x + 1) * track.scale, 0.5+(p1.y+0) * track.scale);
ctx.lineTo(0.5+(p2.x + 1) * track.scale, 0.5+(p2.y+1) * track.scale);
ctx.lineTo(0.5+(p1.x + 0) * track.scale, 0.5+(p2.y+1) * track.scale);
ctx.lineTo(0.5+(p1.x + 0) * track.scale, 0.5+(p1.y+0) * track.scale);
ctx.stroke();
}
//
// draw mouse cursor
ctx.lineWidth = 1;
ctx.lineJoin="round";
ctx.miterLimit = 1;
ctx.setLineDash([2,2]);
ctx.strokeStyle = "#000000";
ctx.beginPath();
ctx.moveTo(0.5+(trackMouse.pos.x + 0) * track.scale, 0.5+(trackMouse.pos.y+0) * track.scale);
ctx.lineTo(0.5+(trackMouse.pos.x + 1) * track.scale, 0.5+(trackMouse.pos.y+0) * track.scale);
ctx.lineTo(0.5+(trackMouse.pos.x + 1) * track.scale, 0.5+(trackMouse.pos.y+1) * track.scale);
ctx.lineTo(0.5+(trackMouse.pos.x + 0) * track.scale, 0.5+(trackMouse.pos.y+1) * track.scale);
ctx.lineTo(0.5+(trackMouse.pos.x + 0) * track.scale, 0.5+(trackMouse.pos.y+0) * track.scale);
ctx.stroke();
//
// draw mouseselection
var mode = sideBtnModeGet();
if ((mode == "mode-rail" || mode == "mode-delete") &&
trackMouse.down.x >= 0 && trackMouse.down.y >= 0) {
var selected = new Array();
selected.length = 0;
selected = trackGetElementList(trackMouse.down, trackMouse.pos, trackMouse.direction);
for (i = 0; i < selected.length; i++) {
trackDrawElement(ctx, selected[i], 1);
}
selected.length = 0;
var infoline = document.getElementById("infoline");
if (infoline) infoline.innerHTML = trackMouse.direction;
}
//
// draw possible turnout
else if (mode == "mode-turn") {
var t = trackGetTurnout({x: trackMouse.pos.x, y: trackMouse.pos.y});
}
//
// flip screen - double buffering
trackFlipScreen();
};
function trackFlipScreen() {
var c = document.getElementById("TrackCanvas");
var ctx = c.getContext("2d");
ctx.drawImage(track.dbuf, 0, 0);
};
////////////////////////////////////////////////////////////////////////
//
// callback functionen
//
function trackMouseGetPos(event) {
var p = { x: 0, y: 0, subx: 0.5, suby: 0.5 };
var x, dx;
var y, dy;
p.x = Math.floor((event.pageX - 1 - $('#TrackCanvas').offset().left) / track.scale);
p.y = Math.floor((event.pageY - 1 - $('#TrackCanvas').offset().top) / track.scale);
x = (event.pageX - 1 - $('#TrackCanvas').offset().left) / track.scale;
y = (event.pageY - 1 - $('#TrackCanvas').offset().top) / track.scale;
p.subx = x - p.x;
p.suby = y - p.y;
return p;
}
function trackMousemove(event) {
var mode = sideBtnModeGet();
trackMouse.pos = trackMouseGetPos(event);
// debug ("trackMousemove pos: " + trackMouse.pos.x + "," + trackMouse.pos.y +
// " subx: " + trackMouse.pos.subx + " suby:" + trackMouse.pos.suby);
trackDraw();
};
function trackMousedown(event) {
var mode = sideBtnModeGet();
var tmp = trackMouseGetPos(event);
if (mode == "mode-rail" || mode == "mode-delete") {
trackMouse.down = trackMouseGetPos(event);
}
// debug ("trackMousedown pos: " + tmp.x + "," + tmp.y + " subx: " + tmp.subx + " suby:" + tmp.suby);
trackDraw();
};
//
//
//
function trackMouseup(event) {
var mode = sideBtnModeGet();
var tmp = trackMouseGetPos(event);
debug ("trackMouseup tmp: " + tmp.x + "," + tmp.y + " mode:" + mode);
debug ("trackMouseup down: " + trackMouse.down.x + "," + trackMouse.down.y);
debug ("trackMouseup pos: " + trackMouse.pos.x + "," + trackMouse.pos.y);
if (mode == "mode-rail") {
var pos = {};
var selected = new Array();
selected.length = 0;
selected = trackGetElementList(trackMouse.down, trackMouse.pos, trackMouse.direction);
serverinout_addTrack(selected);
selected.length = 0;
}
else if (mode == "mode-turn") {
rwdetail_show(trackMouse.pos.x, trackMouse.pos.y);
}
else if (mode == "mode-delete") {
var pos = {};
var xs, ys, xe ,ye;
var selected = new Array();
selected.length = 0;
//
// determine which direction to count.
if (trackMouse.down.x <= trackMouse.pos.x) {
xs = trackMouse.down.x;
xe = trackMouse.pos.x;
}
else {
xs = trackMouse.pos.x;
xe = trackMouse.down.x;
}
if (trackMouse.down.y <= trackMouse.pos.y) {
ys = trackMouse.down.y;
ye = trackMouse.pos.y;
}
else {
ys = trackMouse.pos.y;
ye = trackMouse.down.y;
}
debug ("delete: xs: " + xs + " , " + ys + " xe: " + xe + " , " + ye);
for (x = xs; x <= xe; x++) for (y = ys; y <= ye; y++) {
selected.push({x: x, y: y, dir: 1, type: 0});
}
serverinout_delTrack(selected);
selected.length = 0;
}
else {
rw_Click(trackMouse.pos.x, trackMouse.pos.y);
}
trackMouse.down.x = -1;
trackMouse.down.y = -1;
trackMouse.step = 0;
trackDraw();
};
//
// add/or delete element
// fill in element
function trackAddElement(elm) {
//debug ("trackAddElement: pos:" + elm.x + "," + elm.y + " d: " + elm.dir + " name:" + elm.name + " type:" + elm.type);
if (track.size.x > 0 && track.size.y > 0) {
track.elements[elm.x + track.size.y * elm.y] = elm;
}
};
////////////////////////////////////////////////////////////////////////
//
// init the track view screen
// bind callback functions
function trackCreate(sizex, sizey) {
debug ("trackCreate " + sizex + " , " + sizey);
var canvas = document.createElement("canvas");
track.size.x = sizex;
track.size.y = sizey;
canvas.setAttribute("id", "TrackCanvas");
canvas.height = track.size.y * track.scale;
canvas.width = track.size.x * track.scale;
canvas.addEventListener('mousemove', trackMousemove);
canvas.addEventListener('mousedown', trackMousedown);
canvas.addEventListener('mouseup', trackMouseup);
track.dbuf = document.createElement("canvas");
track.dbuf.setAttribute("id", "TrackCanvasDBUF");
track.dbuf.height = track.size.y * track.scale;
track.dbuf.width = track.size.x * track.scale;
track.array = new Array();
return canvas;
};
//
// get the size fo track from server, setup all data
function trackSetup(tracksetup) {
debug ("trackSetup");
var client = document.getElementById("page_main");
var oldc = document.getElementById("TrackCanvas");
var olddbuf = document.getElementById("TrackCanvasDBUF");
if (oldc) oldc.remove();
if (olddbuf) olddbuf.remove();
// client.removeChild(oldc);
var canvas = trackCreate (tracksetup.width, tracksetup.height);
client.appendChild (canvas);
trackDraw();
};
//
// return a new list of railways elements
// this list can be added to the server or deleted from.
// or useing this list for drawing preview
// START: will contain the position with the sub position (clockwise: 0, 3, 6, 9)
//
function trackGetElementList(start, end) {
var list = new Array();
var pstart;
var pend;
if (start.x > end.x) {
pstart = {x: end.x, y:end.y, subx: end.subx, suby: end.suby};
pend = {x: start.x, y:start.y, subx: start.subx, suby: start.suby};
}
else {
pstart = {x: start.x, y:start.y, subx: start.subx, suby: start.suby};
pend = {x: end.x, y:end.y, subx: end.subx, suby: end.suby};
}
//
// clicked on a singlke field.
if (pstart.x == pend.x && pstart.y == pend.y) {
x = pstart.x;
y = pstart.y;
if (pstart.subx <= 0.33 && pstart.suby <= 0.33)
list.push ({x: x, y: y, dir: 3, type: 1});
if (pstart.subx <= 0.33 && pstart.suby >= 0.66)
list.push ({x: x, y: y, dir: 6, type: 1});
if (pstart.subx >= 0.66 && pstart.suby <= 0.33)
list.push ({x: x, y: y, dir: 4, type: 1});
if (pstart.subx >= 0.66 && pstart.suby >= 0.66)
list.push ({x: x, y: y, dir: 5, type: 1});
if (pstart.subx >= 0.33 && pstart.subx <= 0.66 && (pstart.suby <= 0.33 || pstart.suby >= 0.66))
list.push ({x: x, y: y, dir: 1, type: 1});
if (pstart.suby >= 0.33 && pstart.suby <= 0.66 && (pstart.subx <= 0.33 || pstart.subx >= 0.66))
list.push ({x: x, y: y, dir: 2, type: 1});
}
else {
var dx = pend.x - pstart.x;
var dy = pend.y - pstart.y;
var m, x, y;
if (dx != 0 && dy != 0) m = dy / dx;
else if (dx == 0) m = 100; // Y
else m = 0; // X
x = pstart.x;
y = pstart.y;
if (Math.abs(m) > 0.5 && Math.abs(m) < 2) {
var elm; // save last element
if (m < 0) { // "/"
// select starting point
if (pstart.suby < 0.5) elm = 3;
else elm = 5;
for (; x <= pend.x && y >= pend.y;) {
if (elm == 3) {
list.push ({x: x, y: y, dir: elm, type: 1});
elm = 5;
y = y - 1;
}
else if (elm == 5) {
list.push ({x: x, y: y, dir: elm, type: 1});
elm = 3;
x = x + 1;
}
else {
// should not possible but somehow we ended up here
debug ("trackGetElementList: ERROR elm 3 or 5 expected");
break;
}
}
}
else { // "\"
// select starting point
if (pstart.suby < 0.5) elm = 4;
else elm = 6;
for (; x <= pend.x && y <= pend.y;) {
if (elm == 4) {
list.push ({x: x, y: y, dir: elm, type: 1});
elm = 6;
x = x + 1;
}
else if (elm == 6) {
list.push ({x: x, y: y, dir: elm, type: 1});
elm = 4;
y = y + 1;
}
else {
// should not possible but somehow we ended up here
debug ("trackGetElementList: ERROR elm 4 or 6 expected");
break;
}
}
}
}
else if (Math.abs(m) >= 2) {
if (m > 0) {
dirtype = 1;
for (; y <= pend.y; y++)
list.push ({x: x, y: y, dir: dirtype, type: 1});
}
else {
dirtype = 1;
for (; y >= pend.y; y--)
list.push ({x: x, y: y, dir: dirtype, type: 1});
}
}
else { // m < 0.5
if (m >= 0) {
dirtype = 2;
for (; x <= pend.x; x++)
list.push ({x: x, y: y, dir: dirtype, type: 1});
}
else {
dirtype = 2;
for (; x >= pend.x; x--)
list.push ({x: x, y: y, dir: dirtype, type: 1});
}
}
}
return list;
};
//
// returns the element at the givin point
function trackGetTurnout(mousepos) {
var pos = {x: mousepos.x, y: mousepos.y};
var elm = {};
for (var i = 0; i < track.elements.length; i++) {
if (track.elements[i]) {
if (track.elements[i].x == pos.x && track.elements[i].y == pos.y) elm = track.elements[i];
}
}
return elm;
};