Coverage for lasso/dimred/svd/html_str_eles.py: 100%
4 statements
« prev ^ index » next coverage.py v7.2.4, created at 2023-04-28 18:42 +0100
« prev ^ index » next coverage.py v7.2.4, created at 2023-04-28 18:42 +0100
1OVERHEAD_STRING = """
2<html>
3 <title>3D Beta Embedding</title>
4<head>
5 <meta charset="utf-8">
6 <style>
7 :root{--background:#cfd8dc;--menue-background:#ffffff;--menue-option-background:#ffffff;--menue-option-text-color:#000000;--menue-option-active:#e2f0fb;--content-background:#ffffff;--content-border:1px solid #9ea7aa;--content-shadow:0 4px 8px 0 rgba(0, 0, 0, 0.2),0 6px 20px 0 rgba(0, 0, 0, 0.19);--plot-option-color:#455a64}body{font-family:Lato,sans-serif;background-color:var(--background)}.inputHidden{padding:0;width:0;height:0;display:none;transition:1s}.inputSelected{padding:0 8px 8px 16px;padding-top:15px;display:block;overflow:auto;transition:1s}.menuOption{padding:8px 8px 8px 32px;background-color:var(--menue-option-background)}.navClosed{margin-top:15px;position:fixed;left:1%;transition:.2s;display:flex;min-height:100vh}.navOpen{margin-top:15px;position:fixed;transition:.2s;display:flex;min-height:100vh}.sidenav{height:100%;width:0;position:fixed;z-index:1;top:0;left:0;background-color:var(--menue-background);overflow-x:hidden;transition:.2s;padding-top:60px}.sidenav a{text-decoration:none;font-size:20px;color:var(--menue-option-text-color);display:block;opacity:.7;cursor:pointer}.slider{-webkit-appearance:none;width:90%;background:#137a94;height:5px;border-radius:5px;outline:0}.slider:hover{box-shadow:0 0 .5px .5px #2dceda}.slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:15px;height:15px;background:#137a94;border-radius:20px;cursor:pointer}.slider::-moz-range-thumb{width:15px;height:15px;background:#137a94;border-radius:20px;cursor:pointer}.sidenav input[type=text]{background-color:var(--menue-background);border-color:#137a94;width:100%}input[type=text]:focus{outline:1px solid #1995b4}.sidenav a:hover{opacity:.9;background-color:var(--menue-option-active)}.sidenav .closebtn{position:absolute;top:0;right:10px;font-size:36px;margin-left:50px;z-index:100}.plotDiv{border-radius:5px;box-shadow:var(--content-shadow);border:var(--content-border);position:relative;background-color:var(--content-background)}.plotDiv p{position:absolute;top:5px;right:15px}#plotOptions{position:absolute;top:5px;left:15px;font-size:30px;cursor:pointer}#downloadPlot{position:absolute;left:0;color:var(--plot-option-color);text-decoration:underline;text-decoration-thickness:3px;text-underline-offset:5px}#resetPlot{position:absolute;margin-left:30px;color:var(--plot-option-color);font-size:35px}#sizeDrag{cursor:col-resize;width:2%}#dragLineDiv{width:0;border:var(--content-border);margin-left:45%;margin-right:49%}.imgDiv{border-radius:5px;box-shadow:var(--content-shadow);border:var(--content-border);display:flex;justify-content:center;align-items:center;background-color:var(--content-background)}.alignedIMG{width:99%;height:auto}.imgDiv :is(p,h2){margin-top:0;padding-left:15px;display:inline-block;vertical-align:middle}.noImgDescr{position:relative;display:none}.traceContainerClass{float:left;padding-bottom:5px}.traceContainerClass :is(p,canvas){float:left}.traceContainerClass p{font-size:16px;padding-left:5px;padding-right:50px;color:var(--menue-option-text-color);margin-top:15px;opacity:.7}.traceContainerClass p:hover{opacity:.9}.traceContainerClass canvas{border-radius:24px;margin-bottom:15px;margin-top:5px}.traceContainerClass canvas:hover{box-shadow:0 0 3px 2px #12678f;transition:.4s}.colorwheel{border-radius:128px!important;border-color:#f1f1f1;position:relative;z-index:10;top:0;left:0}
8 </style>
9</head>
10<body onresize="resizeContents()">
11 <div id="mySidenav" class="sidenav">
12 <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">×</a>
13 <div class="menuOption">
14 <a href="#" id="imgDirBtn" onclick="showInputField('imgDirDiv', 'imgDirBtn')">Image Directory</a>
15 <div id="imgDirDiv" class="inputHidden">
16 <input id="imageDir" type="text" onchange="updateIMGPath(event)"
17 placeholder="Enter path to img directory">
18 </div>
19 </div>
20 <div class="menuOption">
21 <a href="#" id="imgEndBtn" onclick="showInputField('imgEndDiv', 'imgEndBtn')">Image Filetype</a>
22 <div id="imgEndDiv" class="inputHidden">
23 <input id="imageEnd" type="text" onchange="updateIMGEnd(event)"
24 placeholder="Enter img type ending">
25 </div>
26 </div>
27 <div class="menuOption">
28 <a href="#" id="pointSliderBtn" onclick="showInputField('sliderDiv', 'pointSliderBtn')">Point Size</a>
29 <div id="sliderDiv" class="inputHidden"><input id="slider_pt_size" type="range" class="slider"></div>
30 </div>
31 <div class="menuOption">
32 <a href="#" id="borderSliderBtn" onclick="showInputField('borderSliderDiv', 'borderSliderBtn')">Border Size</a>
33 <div id="borderSliderDiv" class="inputHidden"><input id="slider_border_size" type="range" class="slider"></div>
34 </div>
35 <div class="menuOption">
36 <a href="#" id="traceColorBtn" onclick="showInputField('traceColorDiv', 'traceColorBtn')">Point Color</a>
37 <div id="traceColorDiv" class="inputHidden"></div>
38 </div>
39 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
40 <svg id="lassoLogo" style="position: absolute; top: 15px; left: 32px;" height="50px" preserveAspectRatio="none" data-name="Ebene 1" version="1.1" viewBox="0 0 171.61 53.835" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink">
41 <metadata>
42 <rdf:RDF>
43 <cc:Work rdf:about="">
44 <dc:format>image/svg+xml</dc:format>
45 <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
46 <dc:title>Zeichenfläche 1</dc:title>
47 </cc:Work>
48 </rdf:RDF>
49 </metadata>
50 <defs>
51 <style>.cls-1{fill:url(#a);}.cls-2{fill:#328ccc;}</style>
52 <linearGradient id="a" x1="55.32" x2="149.78" y1="73.4" y2="-21.07" gradientTransform="translate(-12 -.18)" gradientUnits="userSpaceOnUse">
53 <stop stop-color="#006eb7" offset="0"/>
54 <stop stop-color="#1178be" offset=".26"/>
55 <stop stop-color="#2987c8" offset=".72"/>
56 <stop stop-color="#328ccc" offset="1"/>
57 </linearGradient>
58 <linearGradient id="b" x1="55.32" x2="149.78" y1="73.4" y2="-21.07" gradientTransform="translate(-21,-9.18)" gradientUnits="userSpaceOnUse" xlink:href="#a"/>
59 </defs>
60 <title>Zeichenfläche 1</title>
61 <path class="cls-1" d="m153 1h-38.39-40.2a8.5 8.5 0 1 0 0 17h4.94a7.09 7.09 0 0 1 0 14.17h-39.53a2.5 2.5 0 1 1 0-5h12a3.89 3.89 0 0 0 3.65-5.22l-6.22-17.13a5.64 5.64 0 0 0-10.62 0l-8.95 24.59a4.25 4.25 0 0 1-4 2.8h-17.62a4.25 4.25 0 0 1-4.23-4.25v-26.92h-2.83v26.92a7.08 7.08 0 0 0 7.06 7.08h17.65a7.08 7.08 0 0 0 6.64-4.66l8.95-24.64a2.82 2.82 0 0 1 5.3 0l6.23 17.26a1.07 1.07 0 0 1-1 1.43h-12a5.31 5.31 0 0 0 0 10.62h74.82a9.915 9.915 0 0 0 0-19.83h-4.94a5.67 5.67 0 1 1 0-11.34h33.93a16.92 16.92 0 1 0 9.4-2.87zm-43.33 17h4.94a7.09 7.09 0 0 1 0 14.17h-28.4a9.91 9.91 0 0 0-6.9-17h-4.9a5.67 5.67 0 1 1 0-11.34h29a8.49 8.49 0 0 0 6.29 14.17zm43.33 14.17a14.16 14.16 0 0 1-0.77-28.3h0.79a14.17 14.17 0 0 1 0 28.34z" fill="url(#b)"/>
62 </svg>
63 </div>
64 <span style="font-size: 30px; cursor: pointer;" onclick="openNav()">☰ <span style="font-size: 25px;">Options</span>
65 </span>
66 <div id="content" class="navClosed">
67 <div id="plotDiv" class="plotDiv">
68 <p id="plotInfo"></p>
69 <div id="plotOptions">
70 <span id="downloadPlot" onclick="downloadPlot()" title="Download Plot as png"><a>↓</a></span>
71 <span id="resetPlot" title="Reset Plot"><a onclick="resetRenderer()">↺</a></span>
72 </div>
73 </div>
74 <div id="sizeDrag">
75 <div id="dragLineDiv"></div>
76 </div>
77 <div id="imgDiv" class="imgDiv">
78 <div><p id="messageP">Hover over points to see the corresponding image </p></div>
79 <div style="display: none;"><img id="hoverIMG" class="alignedIMG"></div>
80 <div id="noImgDescr" class="noImgDescr">
81 <h2>No Image</h2>
82 <br>
83 <p>You can set the image directory in the options tab.</p>
84 <p>Every image must have a number as name which corresponds to the run id.</p>
85 </div>
86 </div>
87 </div>
88""" # noqa: E501
90TRACE_STRING = """
91 {_traceNr_} =
92 {{
93 name: '{_name_}',
94 color: '{_color_}',
95 border: '#555555',
96 text: {_runIDs_},
97 x: {_x_},
98 y: {_y_},
99 z: {_z_},
100 vertices: []
101 }},
102"""
104CONST_STRING = """
105 {_three_min_}
106 <script>
107 path = "{_path_str_}"
108 imgType = "png"
109 const runIDs = {_runIdEntries_}
110"""
112SCRIPT_STRING = """
113 const pointSlider = document.getElementById("slider_pt_size")
114 const borderSlider = document.getElementById("slider_border_size")
115 const plotDiv = document.getElementById("plotDiv")
116 const imgDiv = document.getElementById("imgDiv")
117 const drag = document.getElementById("sizeDrag")
119 let plotDivMult = 0.7
120 let sideNavWidthMult = 0.15
122 const camera = new THREE.PerspectiveCamera(40, 2, 0.1, 10000)//(fov, aspect, near, far);
123 const cameraStartZ = 500
124 camera.position.z = cameraStartZ
126 const renderer = new THREE.WebGLRenderer({alpha: true, preserveDrawingBuffer: true})
128 const scene = new THREE.Scene()
129 const renderObjects = new THREE.Group()
130 const centeredGroup = new THREE.Group()
131 centeredGroup.add(renderObjects)
132 scene.add(centeredGroup)
136 mouseProps = {
137 start_x : 0,
138 start_y : 0,
139 is_middle_down : false,
140 is_left_down : false,
141 is_right_down : false,
142 }
144 const dragFunc = (e) => {
146 let widthModi = parseFloat(document.getElementById("mySidenav").style.width)
147 let userWidth = window.innerWidth - widthModi
149 const startWidth = parseFloat(plotDiv.style.width)
150 document.selection ? document.selection.empty() : window.getSelection().removeAllRanges()
151 const newPlotWidth = (e.pageX - drag.offsetWidth / 2 - widthModi)
153 const newPlotDivMult = newPlotWidth / userWidth
155 if(!(newPlotDivMult < 0.1) && !(newPlotDivMult > 0.9)) {
156 plotDivMult = newPlotDivMult
157 resizeContents()
158 }
159 }
161 function initDocument(){
162 pointSlider.min = 5
163 pointSlider.max = 35
164 pointSlider.step = 1
165 pointSlider.value = 20
167 borderSlider.min = 1
168 borderSlider.max = 10
169 borderSlider.step = 1
170 borderSlider.value = 3
172 document.getElementById("mySidenav").style.width = 0
174 const plotDivWidth = window.innerWidth * plotDivMult
175 const imgDivWidth = window.innerWidth * (1 - plotDivMult - 0.02)
177 plotDiv.style.width = plotDivWidth
178 imgDiv.style.width = imgDivWidth
180 plotDiv.style.height = 0.9 * window.innerHeight
181 imgDiv.style.height = 0.9 * window.innerHeight
182 drag.children[0].style.height = parseFloat(plotDiv.style.height)
184 renderer.setSize(plotDivWidth, Math.min(0.9*window.innerHeight, plotDivWidth), false)
185 plotDiv.appendChild(renderer.domElement)
187 if(path !== ""){
188 document.getElementById("imageDir").value = path
189 }
190 document.getElementById("imageEnd").value = imgType
192 drag.addEventListener("mousedown", () => {
193 document.addEventListener("mousemove", dragFunc)
194 })
195 document.addEventListener("mouseup", () => {
196 document.removeEventListener("mousemove", dragFunc)
197 })
198 traceList.forEach(trace =>{
199 for (let n=0; n < trace.x.length; n++){
200 trace.vertices.push(trace.x[n], trace.y[n], trace.z[n])
201 }
202 })
203 }
205 function resizeContents(){
206 const sideNav = document.getElementById("mySidenav")
207 if(plotDiv.parentElement.className === "navOpen"){
208 sideNav.style.width = Math.min(250, window.innerWidth*sideNavWidthMult) + "px";
209 document.getElementById("lassoLogo").style.width = parseFloat(sideNav.style.width) * 0.6 - 30
210 }
212 let sideNavWidth = parseFloat(sideNav.style.width)
213 let userWidth = window.innerWidth - sideNavWidth
214 let contentBound = window.innerWidth * 0.01
216 plotDiv.parentElement.style.left = sideNavWidth + contentBound
217 plotDiv.style.width = userWidth * plotDivMult + 'px'
218 imgDiv.style.width = userWidth * (1-plotDivMult) - 2*contentBound + 'px';
219 plotDiv.style.height = 0.9 * window.innerHeight
220 imgDiv.style.height = 0.9 * window.innerHeight
221 plotDiv.removeChild(renderer.domElement)
222 renderer.setSize(userWidth*plotDivMult, Math.min(0.9*window.innerHeight, userWidth*plotDivMult), false)
223 plotDiv.appendChild(renderer.domElement)
224 drag.children[0].style.height = parseFloat(plotDiv.style.height)
225 }
227 function openNav(){
228 const sideNav = document.getElementById("mySidenav")
229 sideNav.style.boxShadow = "var(--content-shadow)"
230 document.getElementById("content").setAttribute("class", "navOpen");
231 resizeContents()
232 }
233 function closeNav(){
234 const sideNav = document.getElementById("mySidenav")
235 sideNav.style.width = "0";
236 sideNav.style.boxShadow = ""
237 document.getElementById("content").setAttribute("class", "navClosed");
238 hideAll();
239 resizeContents();
240 }
242 function showInputField(div, aClicked){
243 hideAll()
244 document.getElementById(div).setAttribute("class", "inputSelected")
245 document.getElementById(aClicked).setAttribute("onclick", `hideInputField('${div}', '${aClicked}')`)
246 document.getElementById(aClicked).style.background = "var(--menue-option-active)"
247 }
249 function hideInputField(div, aClicked){
250 document.getElementById(div).setAttribute("class", "inputHidden")
251 document.getElementById(aClicked).setAttribute("onclick", `showInputField('${div}', '${aClicked}')`)
252 document.getElementById(aClicked).style.background = "var(--menue-option-background)"
253 }
255 function hideAll(){
256 document.getElementById("sliderDiv").setAttribute('class', 'inputHidden')
257 document.getElementById("imgDirDiv").setAttribute('class', 'inputHidden')
258 document.getElementById("imgEndDiv").setAttribute('class', 'inputHidden')
259 document.getElementById("traceColorDiv").setAttribute('class', 'inputHidden')
260 document.getElementById("borderSliderDiv").setAttribute('class', 'inputHidden')
261 document.getElementById("pointSliderBtn").setAttribute("onclick", "showInputField('sliderDiv', 'pointSliderBtn')")
262 document.getElementById("imgDirBtn").setAttribute("onclick", "showInputField('imgDirDiv', 'imgDirBtn')")
263 document.getElementById("imgEndBtn").setAttribute("onclick", "showInputField('imgEndDiv', 'imgEndBtn')")
264 document.getElementById("traceColorBtn").setAttribute("onclick", "showInputField('traceColorDiv', 'traceColorBtn')")
265 document.getElementById("borderSliderBtn").setAttribute("onclick", "showInputField('borderSliderDiv','borderSliderBtn')")
266 Array.from(document.getElementById("mySidenav").children).forEach(node => {
267 if(node.childElementCount > 0){
268 node.children[0].style.background = "var(--menue-option-background)"
269 }
270 })
271 }
273 let mouseDownInWheel = false
274 let colorWheelActive = false
276 document.addEventListener('mousedown', function(event){
277 if (!(event.target.id.slice(0, 5) === "color")){
278 if(colorWheelActive){
279 document.getElementById("colorwheel").remove()
280 colorWheelActive = false
281 }
282 }
283 })
285 function openWheel(event){
286 if(colorWheelActive){
287 document.getElementById("colorwheel").remove()
288 }
289 const traceId = parseInt(event.target.id.slice(-1))
290 const wheel = makeWheel(128)
291 wheel.className = "colorwheel"
292 wheel.id = "colorwheel"
293 wheel.addEventListener('mousedown', function(event){
294 mouseDownInWheel = true
295 let wheelCanvas = this
296 updateMarkerColor(event, wheelCanvas)
297 })
298 wheel.addEventListener('mousemove', function(event){
299 let wheelCanvas = this
300 updateMarkerColor(event, wheelCanvas)
301 })
302 wheel.addEventListener('mouseup', removeColorWheel)
303 wheel.addEventListener('mouseout', removeColorWheel)
304 event.target.parentElement.appendChild(wheel)
305 colorWheelActive = true
306 }
308 function updateMarkerColor(event, wheelCanvas){
309 if (mouseDownInWheel) {
310 let traceID = parseInt(event.target.parentElement.id.slice(-1)) ? parseInt(event.target.parentElement.id.slice(-1)) : 0
311 console.log(traceID)
312 let targetTrace = traceList[traceID]
313 let wheelCtx = wheelCanvas.getContext('2d')
314 let data = wheelCtx.getImageData(event.offsetX, event.offsetY, 1, 1).data
315 let rgba = 'rgba(' + data[0] + ',' + data[1] +
316 ',' + data[2] + ',' + (data[3] / 255) + ')'
317 targetTrace.color = rgba
318 const markerSize = document.getElementById("slider_pt_size").value
319 const borderSize = document.getElementById("slider_border_size").value
320 // renderObjects.children = []
321 const targetCanvas = event.target.parentElement.children[0]
322 createMarker(16, 3, rgba, targetTrace.border, targetCanvas)
323 // traceList.forEach(trace => {
324 // addPoints(trace, markerSize, borderSize)
325 // })
326 const newTexture = createMarker(markerSize, borderSize, rgba, targetTrace.border,document.createElement("canvas"))
327 renderObjects.children[traceID].material.map.image = newTexture
328 renderObjects.children[traceID].material.map.needsUpdate = true
331 }
332 }
334 function removeColorWheel(event){
335 if(mouseDownInWheel){
336 mouseDownInWheel = false
337 let wheelCanvas = this
338 this.remove()
339 colorWheelActive = false
340 }
341 }
343 function updateIMGPath(){
344 path = document.getElementById("imageDir").value
345 }
347 function updateIMGEnd(){
348 imgType = document.getElementById("imageEnd").value
349 }
351 function createMarker(radius, boundary, color, border, canv){
353 const ctx = canv.getContext('2d')
354 ctx.canvas.height = radius * 2 + 10
355 ctx.canvas.width = radius * 2 + 10
356 ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
357 ctx.beginPath();
358 ctx.arc(ctx.canvas.width / 2, ctx.canvas.height / 2, radius, 0, Math.PI * 2)
359 ctx.fillStyle = color
360 ctx.fill()
361 ctx.beginPath();
362 ctx.arc(ctx.canvas.width / 2, ctx.canvas.height / 2, radius, 0, Math.PI * 2)
363 ctx.strokeStyle = border
364 ctx.lineWidth = boundary
365 ctx.stroke()
367 return ctx.canvas
368 }
370 function createHoverPoint(point, color) {
371 const radius = parseFloat(document.getElementById("slider_pt_size").value)+1
372 const outerRadius = radius+1+Math.floor(2*radius/3)
373 vertices=[]
374 vertices.push(point.x, point.y, point.z)
376 var geometry = new THREE.BufferGeometry()
378 const canv = document.createElement("canvas")
379 canv.width = 2 * outerRadius
380 canv.height = 2 * outerRadius
381 const ctx = canv.getContext('2d')
382 const grd = ctx.createRadialGradient(canv.width/2, canv.height/2, 0.5 * radius, canv.width/2, canv.height/2, outerRadius)
383 grd.addColorStop(0, color)
384 grd.addColorStop(1, "transparent")
385 ctx.fillStyle = grd
386 ctx.fillRect(0, 0, 2*(outerRadius)+10, 2*(outerRadius)+10)
388 const texture = new THREE.CanvasTexture(ctx.canvas)
389 geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3))
390 material = new THREE.PointsMaterial({size: outerRadius, sizeAttenuation: false, map: texture, alphaTest: 0.5, transparent: true})
391 var particle = new THREE.Points(geometry, material)
392 return particle
393 }
395 function addPoints(trace, radius, boundary){
397 var geometry = new THREE.BufferGeometry();
399 const newCanv = document.createElement("canvas")
400 const texture = new THREE.CanvasTexture(createMarker(radius, boundary, trace.color, trace.border, newCanv))
402 geometry.setAttribute('position', new THREE.Float32BufferAttribute(trace.vertices, 3))
403 material = new THREE.PointsMaterial({ size: radius, sizeAttenuation: false, map: texture, alphaTest: 0.5, transparent: true })
404 var particles = new THREE.Points(geometry, material)
405 particles.name = trace.name
406 renderObjects.add(particles)
407 renderer.render(scene, camera)
408 }
411 let hsv2rgb = function(hsv) {
412 let h = hsv.hue, s = hsv.sat, v = hsv.val;
413 let rgb, i, data = [];
414 if (s === 0) {
415 rgb = [v,v,v];
416 } else {
417 h = h / 60;
418 i = Math.floor(h);
419 data = [v*(1-s), v*(1-s*(h-i)), v*(1-s*(1-(h-i)))];
420 switch(i) {
421 case 0:
422 rgb = [v, data[2], data[0]];
423 break;
424 case 1:
425 rgb = [data[1], v, data[0]];
426 break;
427 case 2:
428 rgb = [data[0], v, data[2]];
429 break;
430 case 3:
431 rgb = [data[0], data[1], v];
432 break;
433 case 4:
434 rgb = [data[2], data[0], v];
435 break;
436 default:
437 rgb = [v, data[0], data[1]];
438 break;
439 }
440 }
441 return rgb;
442 };
444 function clamp(min, max, val)
445 {
446 if (val < min) return min;
447 if (val > max) return max;
448 return val;
449 }
451 function makeWheel(diameter)
452 {
453 let can = document.createElement('canvas');
454 let ctx = can.getContext('2d');
455 const divisor = 1.8 // how "zoomed in" the colorwheel is
456 can.width = diameter;
457 can.height = diameter;
458 let imgData = ctx.getImageData(0,0,diameter,diameter);
459 let maxRange = diameter / divisor;
460 for (let y=0; y<diameter; y++) {
461 for (let x=0; x<diameter; x++) {
462 let xPos = x - (diameter/2);
463 let yPos = (diameter-y) - (diameter/2);
465 let polar = pos2polar( {x:xPos, y:yPos} );
466 let sat = clamp(0,1,polar.len / ((maxRange/2)));
467 let val = clamp(0,1, (maxRange-polar.len) / (maxRange/2) );
469 let rgb = hsv2rgb( {hue:polar.ang, sat:sat, val:val} );
471 let index = 4 * (x + y*diameter);
472 imgData.data[index + 0] = rgb[0]*255;
473 imgData.data[index + 1] = rgb[1]*255;
474 imgData.data[index + 2] = rgb[2]*255;
475 imgData.data[index + 3] = 255;
476 }
477 }
478 ctx.putImageData(imgData, 0,0);
479 return can;
480 }
482 function rad2deg(rad)
483 {
484 return (rad / (Math.PI * 2)) * 360;
485 }
487 function pos2polar(inPos)
488 {
489 let vecLen = Math.sqrt( inPos.x*inPos.x + inPos.y*inPos.y );
490 let something = Math.atan2(inPos.y,inPos.x);
491 while (something < 0)
492 something += 2*Math.PI;
494 return { ang: rad2deg(something), len: vecLen };
495 }
497 function downloadPlot(){
498 let downloadLink = document.createElement('a');
499 downloadLink.setAttribute('download', 'PointEmbedding.png');
500 let canvas = renderer.domElement;
501 let dataURL = canvas.toDataURL('image/png');
502 let url = dataURL.replace(/^data:image\\/png/,'data:application/octet-stream');
503 downloadLink.setAttribute('href',url);
504 downloadLink.click();
505 }
507 initDocument()
509 traceList.forEach(trace =>{
510 const traceDiv = document.getElementById('traceColorDiv')
511 const borderDiv = document.getElementById('borderColorDiv')
512 const traceContainDiv = document.createElement('div')
513 const traceMarkCanvas = createMarker(16, 3, trace.color, trace.border, document.createElement("canvas"))
514 const borderContainDiv = document.createElement('div')
515 const borderMarkCanvas = createMarker(16, 3, trace.color, trace.border, document.createElement("canvas"))
516 const traceMarkName = document.createElement('p')
517 traceMarkName.innerHTML = trace.name
518 traceContainDiv.id = "contain" + trace.name
519 traceMarkCanvas.id = "color" + trace.name
520 traceMarkCanvas.addEventListener('mousedown', openWheel)
521 traceDiv.appendChild(traceContainDiv)
522 traceContainDiv.appendChild(traceMarkCanvas)
523 traceContainDiv.appendChild(traceMarkName)
524 traceContainDiv.setAttribute("class", "traceContainerClass")
526 addPoints(trace, pointSlider.value, borderSlider.value)
527 })
529 const box = new THREE.BoxHelper(renderObjects)
531 function moveObjectsToBoundingBoxCenter(box) {
533 const positions = box.geometry.attributes.position.array
534 let xValue = 0
535 let yValue = 0
536 let zValue = 0
537 positions.forEach((pos, ind) => {
538 switch(ind%3){
539 case 0:
540 xValue += pos
541 break;
542 case 1:
543 yValue += pos
544 break;
545 case 2:
546 zValue += pos
547 }
548 })
549 renderObjects.translateX(xValue/-8)
550 renderObjects.translateY(yValue/-8)
551 renderObjects.translateZ(zValue/-8)
553 }
555 moveObjectsToBoundingBoxCenter(box)
557 pointSlider.oninput = event => {
558 const marker_size = parseFloat(event.target.value)
559 renderObjects.children = []
560 traceList.forEach(trace =>{
561 addPoints(trace, marker_size, borderSlider.value)
562 })
563 }
565 borderSlider.oninput = event => {
566 const marker_border = parseFloat(event.target.value)
567 renderObjects.children = []
568 traceList.forEach(trace => {
569 addPoints(trace, pointSlider.value, marker_border)
570 })
571 }
573 class PickHelper {
574 constructor() {
575 this.hitIndex = null
576 this.pickedObject = null
577 }
578 pick(normalizedPosition, scene, camera) {
580 // pick depending on point size and scale
581 const hitRadius = parseFloat(document.getElementById("slider_pt_size").value) * 0.3 / centeredGroup.scale.x
582 const raycaster = new THREE.Raycaster()
583 raycaster.params.Points.threshold = hitRadius
584 raycaster.setFromCamera(normalizedPosition, camera)
585 // get the list of objects the ray intersected
586 const intersectedObjects = raycaster.intersectObjects(renderObjects.children)
588 if (intersectedObjects.length) {
589 // we pick the first object, as it is the closest
590 this.hitIndex = intersectedObjects[0].index
591 this.pickedObject = intersectedObjects[0].object
592 } else {
593 this.hitIndex = null
594 this.pickedObject = null
595 }
596 }
597 }
598 const pickPosition = {x: 0, y: 0};
599 const pickHelper = new PickHelper();
600 clearPickPosition();
602 function getCanvasRelativePosition(event) {
603 const rect = renderer.domElement.getBoundingClientRect();
604 return {
605 x: (event.clientX - rect.left) * renderer.domElement.width / rect.width,
606 y: (event.clientY - rect.top ) * renderer.domElement.height / rect.height,
607 };
608 }
609 function setPickPosition(event) {
610 const pos = getCanvasRelativePosition(event);
611 pickPosition.x = (pos.x / renderer.domElement.width ) * 2 - 1;
612 pickPosition.y = (pos.y / renderer.domElement.height) * -2 + 1;
613 }
615 function imageExists(imgPath){
616 let http = new XMLHttpRequest()
617 http.open("HEAD", imgPath, false)
618 http.send()
619 return http.status != 404;
620 }
622 const hoverPointInfo = {
623 hoverPointSet: false,
624 currentTraceIndex: null,
625 currentPointIndex: null
626 }
628 function resetHoverPointInfo(){
629 hoverPointInfo.hoverPointSet = false,
630 hoverPointInfo.currentTraceIndex = null,
631 hoverPointInfo.currentPointIndex = null
632 }
634 function checkForImageUpdate(){
635 if(pickHelper.pickedObject){
636 // first we select the trace
637 let traceIndex
638 let validTraceIndex = false
639 for(let i = 0; i<traceList.length; i++){
640 if (traceList[i].name === pickHelper.pickedObject.name){
641 traceIndex = i
642 i = traceList.length
643 validTraceIndex = true
644 }
645 }
646 if(validTraceIndex){
647 document.getElementById("messageP").parentElement.setAttribute("style" , "display:none")
649 const runID = runIDs[traceIndex][pickHelper.hitIndex]
650 const img = document.getElementById("hoverIMG")
651 img.onerror = function() {
652 document.getElementById("noImgDescr").style.display = "block"
653 img.parentElement.style.display = "none"
654 }
655 img.onload = function() {
656 document.getElementById("noImgDescr").style.display = "none"
657 img.parentElement.style.display = "block"
658 }
659 img.src = path+`/${runID}.`+imgType
660 let infoP = document.getElementById("plotInfo")
661 infoP.innerHTML = `${traceList[traceIndex].text[pickHelper.hitIndex]}`
663 if(!hoverPointInfo.hoverPointSet || (hoverPointInfo.currentTraceIndex != traceIndex) || (hoverPointInfo.currentPointIndex != pickHelper.hitIndex)){
664 if(hoverPointInfo.hoverPointSet){
665 renderObjects.children.pop()
666 }
667 renderObjects.add(createHoverPoint({
668 x: traceList[traceIndex].x[pickHelper.hitIndex],
669 y: traceList[traceIndex].y[pickHelper.hitIndex],
670 z: traceList[traceIndex].z[pickHelper.hitIndex],
671 }, traceList[traceIndex].color))
672 hoverPointInfo.hoverPointSet = true
673 hoverPointInfo.currentTraceIndex = traceIndex
674 hoverPointInfo.currentPointIndex = pickHelper.hitIndex
675 }
676 }
677 } else if(hoverPointInfo.hoverPointSet){
678 renderObjects.children.pop()
679 resetHoverPointInfo()
680 }
681 }
683 function clearPickPosition() {
684 pickPosition.x = -100000;
685 pickPosition.y = -100000;
686 }
688 function initMouseProps(event) {
689 mouseProps.start_x = event.offsetX
690 mouseProps.start_y = event.offsetY
691 }
693 function mouseClickSelector(event) {
694 event.preventDefault()
695 if(event.button === 0){
696 mouseProps.is_left_down = true
697 initMouseProps(event)
698 } else if(event.button === 1){
699 mouseProps.is_middle_down = true
700 initMouseProps(event)
701 } else if(event.button === 2){
702 mouseProps.is_right_down = true
703 initMouseProps(event)
704 }
705 }
707 function toRadians(angle) {
708 return angle * (Math.PI / 180);
709 }
711 function dragMouse(e) {
713 let delta_x = e.offsetX - mouseProps.start_x
714 let delta_y = e.offsetY - mouseProps.start_y
715 mouseProps.start_x = e.offsetX
716 mouseProps.start_y = e.offsetY
718 if(mouseProps.is_left_down){
719 // here we rotate around x and y axis
721 var deltaQuaternion = new THREE.Quaternion().setFromEuler(
722 new THREE.Euler( toRadians(delta_y), toRadians(delta_x), 0, 'XYZ')
723 )
724 centeredGroup.quaternion.multiplyQuaternions(deltaQuaternion, centeredGroup.quaternion)
726 } else if (mouseProps.is_middle_down) {
727 // here we rotate around z axis
729 const normPos = getCanvasRelativePosition(event)
730 if(normPos.x > parseFloat(plotDiv.style.width) / 2){
731 delta_y *= -1
732 }
733 if(normPos.y < parseFloat(plotDiv.style.height)/2){
734 delta_x *= -1
735 }
736 let rotationRate = (delta_x + delta_y)
738 var deltaQuaternion = new THREE.Quaternion().setFromEuler(
739 new THREE.Euler( 0, 0, toRadians(rotationRate), 'XYZ')
740 )
741 centeredGroup.quaternion.multiplyQuaternions(deltaQuaternion, centeredGroup.quaternion)
743 } else if (mouseProps.is_right_down) {
744 centeredGroup.position.x += delta_x
745 centeredGroup.position.y -= delta_y
746 }
747 }
749 function mouseUpHandler(event) {
750 if(event.button === 0){
751 mouseProps.is_left_down = false
752 } else if(event.button === 1){
753 mouseProps.is_middle_down = false
754 } else if(event.button === 2){
755 mouseProps.is_right_down = false
756 }
757 }
760 function onMouseScroll(event) {
761 event.preventDefault()
762 let deltaY = event.deltaY
763 let dirMult = 1
765 if(deltaY < 0){
766 deltaY *= -1
767 dirMult = -1
768 }
770 const newScale = 0.1 * centeredGroup.scale.x * Math.exp(3/-10)
771 centeredGroup.scale.addScalar((newScale * dirMult))
772 }
774 function resetMouseProps(event) {
775 mouseProps.is_left_down = false
776 mouseProps.is_middle_down = false
777 mouseProps.is_right_down = false
778 }
780 function resetRenderer() {
781 centeredGroup.quaternion.set(0, 0, 0, 1)
782 centeredGroup.scale.set(1, 1, 1)
783 centeredGroup.position.set(0, 0, 0)
784 }
786 // events for hover image display
787 renderer.domElement.addEventListener('mousemove', setPickPosition);
788 renderer.domElement.addEventListener('mouseout', clearPickPosition);
789 renderer.domElement.addEventListener('mouseleave', clearPickPosition);
791 //events for screen movement
792 plotDiv.addEventListener('mousemove', dragMouse)
793 plotDiv.addEventListener('mousedown', mouseClickSelector)
794 plotDiv.addEventListener('mouseup', mouseUpHandler)
795 plotDiv.addEventListener('wheel', onMouseScroll)
796 plotDiv.addEventListener('contextmenu', function(event){
797 event.preventDefault()
798 })
799 plotDiv.addEventListener('mouseout', resetMouseProps)
801 window.onresize = () => {
802 resizeContents()
803 }
805 function action(time){
807 renderer.render(scene, camera)
809 requestAnimationFrame(action)
810 pickHelper.pick(pickPosition, scene, camera);
811 checkForImageUpdate()
812 }
814 requestAnimationFrame(action)
815 </script>
816</body>
817</html>
818""" # noqa: E501