import { PopupDialog } from "./popup_dialog.js"; class Trajectory extends PopupDialog{ mouseDown = false; constructor(ui) { super(ui); this.ui = ui; this.ui.addEventListener("keydown", (event)=>{ //anykey if (!event.ctrlKey && !event.shiftKey && !event.altKey) { this.hide(); event.preventDefault(); event.stopPropagation(); } }); this.tracksUi = this.ui.querySelector("#svg-arrows"); this.svgUi = this.ui.querySelector("#object-track-svg"); this.svgUi.addEventListener("wheel", (event)=>{ console.log("wheel", event.wheelDelta); let scaleRatio = event.wheelDelta/2400; if (event.ctrlKey) { this.objScale *= 1 + (scaleRatio); } else { let clientLength = Math.min(this.svgUi.clientWidth, this.svgUi.clientHeight); let currentTargetRect = event.currentTarget.getBoundingClientRect(); let eventOffsetX = event.pageX - currentTargetRect.left; let eventOffsetY = event.pageY - currentTargetRect.top; let x = eventOffsetX/clientLength*1000; let y = eventOffsetY/clientLength*1000; this.posTrans.x = x - (x-this.posTrans.x) * (1+scaleRatio); this.posTrans.y = y - (y-this.posTrans.y) * (1+scaleRatio); this.posScale *= 1 + (scaleRatio); } this.redrawAll(); event.preventDefault(); event.stopPropagation(); return false; }); this.inMovingCanvas = false; this.startPosForMovingCanvas = {}; this.svgUi.addEventListener("mousedown", (event)=>{ this.inMovingCanvas = true; this.startPosForMovingCanvas = {x: event.pageX, y:event.pageY}; }); this.svgUi.addEventListener("mouseup", (event)=>{ this.inMovingCanvas = false; }); this.svgUi.addEventListener("mousemove", (event)=>{ if (this.inMovingCanvas) { let delta = { x: event.pageX - this.startPosForMovingCanvas.x, y: event.pageY - this.startPosForMovingCanvas.y }; let clientLength = Math.min(this.svgUi.clientWidth, this.svgUi.clientHeight); this.posTrans.x += delta.x / clientLength * 1000; this.posTrans.y += delta.y / clientLength * 1000; this.startPosForMovingCanvas = {x: event.pageX, y:event.pageY}; this.redrawAll(); } }); this.resizeObserver = new ResizeObserver(elements=>{ if (elements[0].contentRect.height == 0) return; this.redrawAll(); }); this.resizeObserver.observe(this.viewUi); } viewScale = 1; objScale = 1; updateObjectScale() { let v = this.viewUi; this.viewScale = Math.max(1000/v.clientHeight, 1000/v.clientWidth); } object = {}; setObject(objType, objId, tracks, funcOnExit) //tracks is a list of [frameId, x, y, direction], in order { this.object = { type: objType, id: objId, tracks:tracks }; this.funcOnExit = funcOnExit; //console.log(objType, objId, tracks); this.calculateCoordinateTransform(this.object.tracks); this.redrawAll(); this.ui.focus(); } redrawAll() { this.show(); this.clear(); this.updateObjectScale(); this.drawTracks(this.object); this.drawScaler(); } clear(){ let arrows = this.ui.querySelector("#svg-arrows").children; if (arrows.length>0){ for (var c=arrows.length-1; c >= 0; c--){ arrows[c].remove(); } } let scaler = this.ui.querySelector("#svg-scaler").children; if (scaler.length>0){ for (var c=scaler.length-1; c >= 0; c--){ scaler[c].remove(); } } } /* the viewbox is 1000 by 1000 the drawing area is [100,900] by [100,900] viewbox coordinate system x goes right y goes down utm coordinate system x goes east (right) y goes north (up) */ calculateCoordinateTransform(tracks) { tracks = tracks.filter(x=>x[1]); let xs = tracks.map(x=> x[1].psr.position.x); let max_x = Math.max(...xs);//, 0); let min_x = Math.min(...xs);//, 0); let ys = tracks.map(x=> x[1].psr.position.y); let max_y = Math.max(...ys);//, 0); let min_y = Math.min(...ys);//, 0); let scale = Math.max(max_x - min_x, max_y - min_y); if (scale == 0) scale = 1; else scale = 800/scale; // svg view is 1000*1000 this.posScale = scale; this.posTrans = { x: - min_x * this.posScale + 100, y: max_y * this.posScale + 100 }; } transform(x,y,theta,label, highlight) { return [ x * this.posScale + this.posTrans.x, - y * this.posScale + this.posTrans.y, x, y, theta , label, highlight ]; } drawOneTrace(x, y, orgX, orgY, theta, label, highlight) { let svg = this.ui.querySelector("#svg-arrows"); let g = document.createElementNS("http://www.w3.org/2000/svg", 'g'); g.innerHTML = `${label}`; g.setAttribute("class","one-track"); g.ondblclick = (e)=>{ if (this.funcOnExit){ this.hide(); this.funcOnExit(label); } }; if (highlight) { g.setAttribute("class", "one-track object-track-current-frame"); } svg.appendChild(g); let r = 5 * this.objScale; let d = 25 * this.objScale; let a = 5 * this.objScale; //wrapper circle let p = document.createElementNS("http://www.w3.org/2000/svg", 'circle'); p.setAttribute("cx", x + (d-r)/2 * this.viewScale * Math.cos(theta)); p.setAttribute("cy", y - (d-r)/2 * this.viewScale* Math.sin(theta)); p.setAttribute("r", (d+2*r)/2 * this.viewScale); p.setAttribute("class","track-wrapper"); g.appendChild(p); //object p = document.createElementNS("http://www.w3.org/2000/svg", 'circle'); p.setAttribute("cx", x); p.setAttribute("cy", y); p.setAttribute("r", r * this.viewScale); g.appendChild(p); // //arrow head // p = document.createElementNS("http://www.w3.org/2000/svg", 'line'); // p.setAttribute("x1", x + d * this.viewScale * Math.cos(theta)); // p.setAttribute("y1", y - d * this.viewScale* Math.sin(theta)); // p.setAttribute("x2", x + d * this.viewScale * Math.cos(theta) - a * this.viewScale * Math.cos(Math.PI/6+theta)); // p.setAttribute("y2", y - d * this.viewScale * Math.sin(theta) + a * this.viewScale * Math.sin(Math.PI/6+theta)); // g.appendChild(p); // p = document.createElementNS("http://www.w3.org/2000/svg", 'line'); // p.setAttribute("x1", x + d * this.viewScale * Math.cos(theta)); // p.setAttribute("y1", y - d * this.viewScale * Math.sin(theta)); // p.setAttribute("x2", x + d * this.viewScale * Math.cos(theta) - a * this.viewScale * Math.cos(-Math.PI/6+theta)); // p.setAttribute("y2", y - d * this.viewScale * Math.sin(theta) + a * this.viewScale * Math.sin(-Math.PI/6+theta)); // g.appendChild(p); // direction p = document.createElementNS("http://www.w3.org/2000/svg", 'line'); p.setAttribute("x1", x + r * this.viewScale * Math.cos(theta)); p.setAttribute("y1", y - r * this.viewScale* Math.sin(theta)); p.setAttribute("x2", x + d * this.viewScale * Math.cos(theta)); p.setAttribute("y2", y - d * this.viewScale* Math.sin(theta)); g.appendChild(p); // frame // p = document.createElementNS("http://www.w3.org/2000/svg", 'text'); // p.setAttribute("x", x + 50 * this.scale); // p.setAttribute("y", y); // p.textContent = track[0]; // g.appendChild(p); p = document.createElementNS("http://www.w3.org/2000/svg", 'foreignObject'); p.setAttribute("x", x + 50 * this.viewScale); p.setAttribute("y", y); // p.setAttribute("width", 200 * this.scale); p.setAttribute("font-size", 10 * this.viewScale+"px"); p.setAttribute("class",'track-label'); let text = document.createElementNS("http://www.w3.org/1999/xhtml", 'div'); text.textContent = label; p.appendChild(text); g.appendChild(p); } calculateScalerUnit() { let x = 100/this.posScale; let e = 0; while (x >= 10 || x < 1) { if (x >= 10) { e += 1; x /= 10; } else if (x < 1) { e -= 1; x *= 10; } } x = 10 * Math.pow(10, e); return x; } drawScaler() { let x = this.calculateScalerUnit(); let lineLen = x * this.posScale; let svg = this.ui.querySelector("#svg-scaler"); let g = document.createElementNS("http://www.w3.org/2000/svg", 'g'); svg.appendChild(g); //direction let p = document.createElementNS("http://www.w3.org/2000/svg", 'line'); p.setAttribute("x1", 100); p.setAttribute("y1", 900); p.setAttribute("x2", 100+lineLen); p.setAttribute("y2", 900); g.appendChild(p); p = document.createElementNS("http://www.w3.org/2000/svg", 'line'); p.setAttribute("x1", 100); p.setAttribute("y1", 900); p.setAttribute("x2", 100); p.setAttribute("y2", 900-lineLen); g.appendChild(p); p = document.createElementNS("http://www.w3.org/2000/svg", 'foreignObject'); p.setAttribute("x", 105); p.setAttribute("y", 875); // p.setAttribute("width", 200 * this.scale); p.setAttribute("font-size", 10 * this.viewScale+"px"); p.setAttribute("class",'scaler-label'); let text = document.createElementNS("http://www.w3.org/1999/xhtml", 'div'); text.textContent = x.toString() + 'm'; p.appendChild(text); g.appendChild(p); } drawTracks(object) { this.titleUi.innerText = object.type + " "+ + object.id; let tracks = object.tracks; tracks.filter(x=>x[1]) .map(track=>[track[1].psr.position.x, track[1].psr.position.y, track[1].psr.rotation.z, track[0], track[2]]) .map(x=>this.transform(...x)) .forEach(x=>this.drawOneTrace(...x)); //ego car //this.draw_ego_car(...this.transform(0,0,0,"",false).slice(0,2)); } draw_ego_car(x,y) { let svg = this.ui.querySelector("#svg-arrows"); let g = document.createElementNS("http://www.w3.org/2000/svg", 'g'); g.innerHTML = `Ego car`; g.setAttribute("id", "track-ego-car"); svg.appendChild(g); let p = document.createElementNS("http://www.w3.org/2000/svg", 'line'); p.setAttribute("x1", x-10 * this.viewScale); p.setAttribute("y1", y); p.setAttribute("x2", x+10 * this.viewScale); p.setAttribute("y2", y); g.appendChild(p); p = document.createElementNS("http://www.w3.org/2000/svg", 'line'); p.setAttribute("x1", x); p.setAttribute("y1", y-10 * this.viewScale); p.setAttribute("x2", x); p.setAttribute("y2", y+10 * this.viewScale); g.appendChild(p); } } export {Trajectory};