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

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()">&times;</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()">&#9776; <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>&#8595;</a></span> 

71 <span id="resetPlot" title="Reset Plot"><a onclick="resetRenderer()">&#8634;</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 

89 

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""" 

103 

104CONST_STRING = """ 

105 {_three_min_} 

106 <script> 

107 path = "{_path_str_}" 

108 imgType = "png" 

109 const runIDs = {_runIdEntries_} 

110""" 

111 

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") 

118 

119 let plotDivMult = 0.7 

120 let sideNavWidthMult = 0.15 

121 

122 const camera = new THREE.PerspectiveCamera(40, 2, 0.1, 10000)//(fov, aspect, near, far); 

123 const cameraStartZ = 500 

124 camera.position.z = cameraStartZ 

125 

126 const renderer = new THREE.WebGLRenderer({alpha: true, preserveDrawingBuffer: true}) 

127 

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) 

133 

134 

135 

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 } 

143 

144 const dragFunc = (e) => { 

145 

146 let widthModi = parseFloat(document.getElementById("mySidenav").style.width) 

147 let userWidth = window.innerWidth - widthModi 

148 

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) 

152 

153 const newPlotDivMult = newPlotWidth / userWidth 

154 

155 if(!(newPlotDivMult < 0.1) && !(newPlotDivMult > 0.9)) { 

156 plotDivMult = newPlotDivMult 

157 resizeContents() 

158 } 

159 } 

160 

161 function initDocument(){ 

162 pointSlider.min = 5 

163 pointSlider.max = 35 

164 pointSlider.step = 1 

165 pointSlider.value = 20 

166 

167 borderSlider.min = 1 

168 borderSlider.max = 10 

169 borderSlider.step = 1 

170 borderSlider.value = 3 

171 

172 document.getElementById("mySidenav").style.width = 0 

173 

174 const plotDivWidth = window.innerWidth * plotDivMult 

175 const imgDivWidth = window.innerWidth * (1 - plotDivMult - 0.02) 

176 

177 plotDiv.style.width = plotDivWidth 

178 imgDiv.style.width = imgDivWidth 

179 

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) 

183 

184 renderer.setSize(plotDivWidth, Math.min(0.9*window.innerHeight, plotDivWidth), false) 

185 plotDiv.appendChild(renderer.domElement) 

186 

187 if(path !== ""){ 

188 document.getElementById("imageDir").value = path 

189 } 

190 document.getElementById("imageEnd").value = imgType 

191 

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 } 

204 

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 } 

211 

212 let sideNavWidth = parseFloat(sideNav.style.width) 

213 let userWidth = window.innerWidth - sideNavWidth 

214 let contentBound = window.innerWidth * 0.01 

215 

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 } 

226 

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 } 

241 

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 } 

248 

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 } 

254 

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 } 

272 

273 let mouseDownInWheel = false 

274 let colorWheelActive = false 

275 

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 }) 

284 

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 } 

307 

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 

329 

330 

331 } 

332 } 

333 

334 function removeColorWheel(event){ 

335 if(mouseDownInWheel){ 

336 mouseDownInWheel = false 

337 let wheelCanvas = this 

338 this.remove() 

339 colorWheelActive = false 

340 } 

341 } 

342 

343 function updateIMGPath(){ 

344 path = document.getElementById("imageDir").value 

345 } 

346 

347 function updateIMGEnd(){ 

348 imgType = document.getElementById("imageEnd").value 

349 } 

350 

351 function createMarker(radius, boundary, color, border, canv){ 

352 

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() 

366 

367 return ctx.canvas 

368 } 

369 

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) 

375 

376 var geometry = new THREE.BufferGeometry() 

377 

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) 

387 

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 } 

394 

395 function addPoints(trace, radius, boundary){ 

396 

397 var geometry = new THREE.BufferGeometry(); 

398 

399 const newCanv = document.createElement("canvas") 

400 const texture = new THREE.CanvasTexture(createMarker(radius, boundary, trace.color, trace.border, newCanv)) 

401 

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 } 

409 

410 

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

443 

444 function clamp(min, max, val) 

445 { 

446 if (val < min) return min; 

447 if (val > max) return max; 

448 return val; 

449 } 

450 

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); 

464 

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) ); 

468 

469 let rgb = hsv2rgb( {hue:polar.ang, sat:sat, val:val} ); 

470 

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 } 

481 

482 function rad2deg(rad) 

483 { 

484 return (rad / (Math.PI * 2)) * 360; 

485 } 

486 

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; 

493 

494 return { ang: rad2deg(something), len: vecLen }; 

495 } 

496 

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 } 

506 

507 initDocument() 

508 

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") 

525 

526 addPoints(trace, pointSlider.value, borderSlider.value) 

527 }) 

528 

529 const box = new THREE.BoxHelper(renderObjects) 

530 

531 function moveObjectsToBoundingBoxCenter(box) { 

532 

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) 

552 

553 } 

554 

555 moveObjectsToBoundingBoxCenter(box) 

556 

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 } 

564 

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 } 

572 

573 class PickHelper { 

574 constructor() { 

575 this.hitIndex = null 

576 this.pickedObject = null 

577 } 

578 pick(normalizedPosition, scene, camera) { 

579 

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) 

587 

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(); 

601 

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 } 

614 

615 function imageExists(imgPath){ 

616 let http = new XMLHttpRequest() 

617 http.open("HEAD", imgPath, false) 

618 http.send() 

619 return http.status != 404; 

620 } 

621 

622 const hoverPointInfo = { 

623 hoverPointSet: false, 

624 currentTraceIndex: null, 

625 currentPointIndex: null 

626 } 

627 

628 function resetHoverPointInfo(){ 

629 hoverPointInfo.hoverPointSet = false, 

630 hoverPointInfo.currentTraceIndex = null, 

631 hoverPointInfo.currentPointIndex = null 

632 } 

633 

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") 

648 

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]}` 

662 

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 } 

682 

683 function clearPickPosition() { 

684 pickPosition.x = -100000; 

685 pickPosition.y = -100000; 

686 } 

687 

688 function initMouseProps(event) { 

689 mouseProps.start_x = event.offsetX 

690 mouseProps.start_y = event.offsetY 

691 } 

692 

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 } 

706 

707 function toRadians(angle) { 

708 return angle * (Math.PI / 180); 

709 } 

710 

711 function dragMouse(e) { 

712 

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 

717 

718 if(mouseProps.is_left_down){ 

719 // here we rotate around x and y axis 

720 

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) 

725 

726 } else if (mouseProps.is_middle_down) { 

727 // here we rotate around z axis 

728 

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) 

737 

738 var deltaQuaternion = new THREE.Quaternion().setFromEuler( 

739 new THREE.Euler( 0, 0, toRadians(rotationRate), 'XYZ') 

740 ) 

741 centeredGroup.quaternion.multiplyQuaternions(deltaQuaternion, centeredGroup.quaternion) 

742 

743 } else if (mouseProps.is_right_down) { 

744 centeredGroup.position.x += delta_x 

745 centeredGroup.position.y -= delta_y 

746 } 

747 } 

748 

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 } 

758 

759 

760 function onMouseScroll(event) { 

761 event.preventDefault() 

762 let deltaY = event.deltaY 

763 let dirMult = 1 

764 

765 if(deltaY < 0){ 

766 deltaY *= -1 

767 dirMult = -1 

768 } 

769 

770 const newScale = 0.1 * centeredGroup.scale.x * Math.exp(3/-10) 

771 centeredGroup.scale.addScalar((newScale * dirMult)) 

772 } 

773 

774 function resetMouseProps(event) { 

775 mouseProps.is_left_down = false 

776 mouseProps.is_middle_down = false 

777 mouseProps.is_right_down = false 

778 } 

779 

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 } 

785 

786 // events for hover image display 

787 renderer.domElement.addEventListener('mousemove', setPickPosition); 

788 renderer.domElement.addEventListener('mouseout', clearPickPosition); 

789 renderer.domElement.addEventListener('mouseleave', clearPickPosition); 

790 

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) 

800 

801 window.onresize = () => { 

802 resizeContents() 

803 } 

804 

805 function action(time){ 

806 

807 renderer.render(scene, camera) 

808 

809 requestAnimationFrame(action) 

810 pickHelper.pick(pickPosition, scene, camera); 

811 checkForImageUpdate() 

812 } 

813 

814 requestAnimationFrame(action) 

815 </script> 

816</body> 

817</html> 

818""" # noqa: E501