// // 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; };