From 619afebd550d695ed627c199b8aa7feb61f4b13c Mon Sep 17 00:00:00 2001 From: kovacsv Date: Wed, 8 Dec 2021 10:50:08 +0100 Subject: [PATCH] Add edge display to settings. --- assets/icons/edges.svg | 90 ++++++++++++ source/viewer/domutils.js | 21 +++ source/viewer/viewer.js | 161 ++++++++++++++++++++-- website/o3dv/css/O3DVIcons/O3DVIcons.woff | Bin 6728 -> 6916 bytes website/o3dv/css/icons.css | 65 ++++----- website/o3dv/js/exportdialog.js | 13 +- website/o3dv/js/settings.js | 12 +- website/o3dv/js/sidebar.js | 3 + website/o3dv/js/sidebarpanels.js | 111 +++++++++------ website/o3dv/js/website.js | 10 ++ 10 files changed, 387 insertions(+), 99 deletions(-) create mode 100644 assets/icons/edges.svg diff --git a/assets/icons/edges.svg b/assets/icons/edges.svg new file mode 100644 index 0000000..4b4eec6 --- /dev/null +++ b/assets/icons/edges.svg @@ -0,0 +1,90 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/source/viewer/domutils.js b/source/viewer/domutils.js index afa8a41..8a64d87 100644 --- a/source/viewer/domutils.js +++ b/source/viewer/domutils.js @@ -115,6 +115,27 @@ OV.SetDomElementOuterHeight = function (element, height) OV.SetDomElementHeight (element, height - OV.GetDomElementExternalHeight (style)); }; +OV.AddRadioButton = function (parentElement, name, id, text, onChange) +{ + let label = OV.AddDomElement (parentElement, 'label'); + label.setAttribute ('for', id); + let radio = OV.AddDomElement (label, 'input', 'ov_radio_button'); + radio.setAttribute ('type', 'radio'); + radio.setAttribute ('id', id); + radio.setAttribute ('name', name); + OV.AddDomElement (label, 'span', null, text); + radio.addEventListener ('change', onChange); + return radio; +}; + +OV.SelectRadioButton = function (radioButtons, selectedId) +{ + for (let radioButton of radioButtons) { + let isChecked = radioButton.getAttribute ('id') === selectedId; + radioButton.checked = isChecked; + } +}; + OV.CreateDiv = function (className, innerHTML) { return OV.CreateDomElement ('div', className, innerHTML); diff --git a/source/viewer/viewer.js b/source/viewer/viewer.js index b6ac7f3..223ce7e 100644 --- a/source/viewer/viewer.js +++ b/source/viewer/viewer.js @@ -35,6 +35,23 @@ OV.TraverseThreeObject = function (object, processor) return true; }; +OV.SetThreeMeshPolygonOffset = function (mesh, offset) +{ + function SetMaterialsPolygonOffset (materials, offset) + { + for (let material of materials) { + material.polygonOffset = offset; + material.polygonOffsetUnit = 1; + material.polygonOffsetFactor = 1; + } + } + + SetMaterialsPolygonOffset (mesh.material, offset); + if (mesh.userData.threeMaterials) { + SetMaterialsPolygonOffset (mesh.userData.threeMaterials, offset); + } +}; + OV.GetShadingTypeOfObject = function (mainObject) { let shadingType = null; @@ -112,23 +129,112 @@ OV.ViewerGeometry = class { this.scene = scene; this.mainObject = null; + this.mainEdgeObject = null; + this.edgeSettings = { + showEdges : false, + edgeColor : new OV.Color (0, 0, 0), + edgeThreshold : 1 + }; } SetMainObject (mainObject) { this.mainObject = mainObject; this.scene.add (this.mainObject); + if (this.edgeSettings.showEdges) { + this.GenerateMainEdgeObject (); + } + } + + SetEdgeSettings (show, color, threshold) + { + let needToGenerate = false; + if (show && (!this.edgeSettings.showEdges || this.edgeSettings.edgeThreshold !== threshold)) { + needToGenerate = true; + } + + this.edgeSettings.showEdges = show; + this.edgeSettings.edgeThreshold = threshold; + this.edgeSettings.edgeColor = color; + + if (this.mainObject === null) { + return; + } + + if (this.edgeSettings.showEdges) { + if (needToGenerate) { + this.ClearMainEdgeObject (); + this.GenerateMainEdgeObject (); + } else { + let edgeColor = new THREE.Color ( + this.edgeSettings.edgeColor.r / 255.0, + this.edgeSettings.edgeColor.g / 255.0, + this.edgeSettings.edgeColor.b / 255.0 + ); + this.EnumerateEdges ((edge) => { + edge.material.color = edgeColor; + }); + } + } else { + this.ClearMainEdgeObject (); + } + } + + GenerateMainEdgeObject () + { + let edgeColor = new THREE.Color ( + this.edgeSettings.edgeColor.r / 255.0, + this.edgeSettings.edgeColor.g / 255.0, + this.edgeSettings.edgeColor.b / 255.0 + ); + this.mainEdgeObject = new THREE.Object3D (); + this.mainObject.updateWorldMatrix (true, true); + this.EnumerateMeshes ((mesh) => { + OV.SetThreeMeshPolygonOffset (mesh, true); + let edges = new THREE.EdgesGeometry (mesh.geometry, this.edgeSettings.edgeThreshold); + let line = new THREE.LineSegments (edges, new THREE.LineBasicMaterial ({ + color: edgeColor + })); + line.applyMatrix4 (mesh.matrixWorld); + line.userData = mesh.userData; + this.mainEdgeObject.add (line); + }); + this.scene.add (this.mainEdgeObject); + } + + Clear () + { + this.ClearMainObject (); + this.ClearMainEdgeObject (); } ClearMainObject () { - if (this.mainObject !== null) { - this.EnumerateMeshes ((mesh) => { - mesh.geometry.dispose (); - }); - this.scene.remove (this.mainObject); - this.mainObject = null; + if (this.mainObject === null) { + return; } + + this.EnumerateMeshes ((mesh) => { + mesh.geometry.dispose (); + }); + this.scene.remove (this.mainObject); + this.mainObject = null; + } + + ClearMainEdgeObject () + { + if (this.mainEdgeObject === null) { + return; + } + + this.EnumerateMeshes ((mesh) => { + OV.SetThreeMeshPolygonOffset (mesh, false); + }); + this.EnumerateEdges ((edge) => { + edge.geometry.dispose (); + }); + this.scene.remove (this.mainEdgeObject); + this.mainEdgeObject = null; } EnumerateMeshes (enumerator) @@ -143,6 +249,18 @@ OV.ViewerGeometry = class }); } + EnumerateEdges (enumerator) + { + if (this.mainEdgeObject === null) { + return; + } + this.mainEdgeObject.traverse ((obj) => { + if (obj.isLineSegments) { + enumerator (obj); + } + }); + } + GetModelMeshUnderMouse (mouseCoords, camera, width, height) { if (this.mainObject === null) { @@ -288,20 +406,26 @@ OV.ShadingModel = class this.directionalLight.position.set (lightDir.x, lightDir.y, lightDir.z); } - CreateHighlightMaterial (highlightColor) + CreateHighlightMaterial (highlightColor, withOffset) { + let material = null; if (this.type === OV.ShadingType.Phong) { - return new THREE.MeshPhongMaterial ({ + material = new THREE.MeshPhongMaterial ({ color : highlightColor, side : THREE.DoubleSide }); } else if (this.type === OV.ShadingType.Physical) { - return new THREE.MeshStandardMaterial ({ + material = new THREE.MeshStandardMaterial ({ color : highlightColor, side : THREE.DoubleSide }); } - return null; + if (material !== null && withOffset) { + material.polygonOffset = true; + material.polygonOffsetUnit = 1; + material.polygonOffsetFactor = 1; + } + return material; } }; @@ -367,6 +491,12 @@ OV.Viewer = class this.Render (); } + SetEdgeSettings (show, color, threshold) + { + this.geometry.SetEdgeSettings (show, color, threshold); + this.Render (); + } + SetEnvironmentMap (textures) { this.shading.SetEnvironment (textures, () => { @@ -501,7 +631,7 @@ OV.Viewer = class Clear () { - this.geometry.ClearMainObject (); + this.geometry.Clear (); this.Render (); } @@ -513,6 +643,12 @@ OV.Viewer = class mesh.visible = visible; } }); + this.geometry.EnumerateEdges ((edge) => { + let visible = isVisible (edge.userData); + if (edge.visible !== visible) { + edge.visible = visible; + } + }); this.Render (); } @@ -527,7 +663,8 @@ OV.Viewer = class return highlightMaterials; } - const highlightMaterial = this.shading.CreateHighlightMaterial (highlightColor); + const showEdges = this.geometry.edgeSettings.showEdges; + const highlightMaterial = this.shading.CreateHighlightMaterial (highlightColor, showEdges); this.geometry.EnumerateMeshes ((mesh) => { let highlighted = isHighlighted (mesh.userData); if (highlighted) { diff --git a/website/o3dv/css/O3DVIcons/O3DVIcons.woff b/website/o3dv/css/O3DVIcons/O3DVIcons.woff index 22c8623147045328375f43e14a4f8c555ac8c23f..2046bcb660713803287ac47a4c7f946425f77631 100644 GIT binary patch delta 6269 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 delta 6133 zcmVHq)( zc8MzZXlHDBW&i*JbN~PplmGxHL;x*M|7c}lWB>pc2mk;8G5`PoHd#oZQfO#pVE_OZ zJOBUy9{>OVBm)cr8fa~FcmMzwTmS$7CjbBdoGn@Z>1=OfVE_OZga7~lPyhe`P^lKO zwryc}Z~y={7t{a%0384T03ZQ70O)REZDjxe7xVxC0W<&r0wM=s&*X4#b94Xz87Ke% z0UiJV0jDH3*4vW^0YU*}lS=_7f5xZ-~ z;5$DPv>%)IJFSJ*bRY8CO3#LLVnv58z4YFInjs^`Oqeob&VnT?)@<0ae`C*qBPY&W zxN_spgC|Wotm6NwwG^+vyGH-p@&sCjTAC&qgJ~wQZJKhd47FpZT|?~|YTq>dI55=O z^mTD)s3Sui8|uVRr-nK+)VZN940UO!D??oy>c&vFhPpGYn#Za$? zdNb6!p*{@tX{e3Sd;q(R0$l==b^;!M<>{H}j%U2g#AA{$4l>Ffn_!egBE*gXu}Mh? zv4ujg1yTY+A%qBo#0yA7h!-RjB?6w2$Rk1uNC+vs#Domre{OZpf+2Q@AJRS3UH8L z!);RkF0@eN$zxh*iO<70ekvbtk$3N2hZ&i=$s1S_3ojRw`32ge(Mzwn^V?ezSAHYK-Fta?n?>GBxs7KT^|DYx+@rO`Xv+dJCacl~Yp zU*0&q=1&u=bNq{!c$@B1`vjXW7xT$@WQWEbtg)P83yoQ0b+8AOlrnxfCZ#C8$(FJB zEV4IlSki{<#w(EHU8nuY|LXZ$7v_y{JvqBdFeHu_5?_@N>zy&&7F7SQC(_Z}z`-XqQBU!8> z;R~%&KkCF`Inb&Uq@TKf7%}0i)TS>5sUnhDpi4T)5N*=>u}VMx>cd}rLszE``7%;* zHwiLruv)p^jDwOgbpLpNkoFQ2OH);;TjQ?fY#`}XM?d*SF7A1ui>rusyq-7pE_rYE zZXvcli0Jyb_nR)Z@SP+7kz9ypcGux#g#jbDvqv>kI1|ut%&A}vCQldhah}52%OW+l zY50R0Uuqo)BGQq3*E>TM!Vi2Es&~Iv2&B+o;iu5=ep~XpN(!TY{k{S$-7+MVFq_*O z|Gz=nA!$PKb3auQF)RsCjpWb1r;bfvPZg5ozbm`_sO*`KX&Q1qt3U~gurrt4v+s9^ zvFG+}_-c>3-o$$oe3KT5$?4a~`{G!wQgB>gKYk61_ZlhgLaJeCIG!&T@Y2ns6O^nZ zDWfoJCs+KSy54Ai8C#OEE>+hm=gUe}b6fh2sAO<7VSFW26gGW{V_QQlkp-oC)G8(Q zw3f#^LME+B%Lch^F6u2`+X#p!X-!5!n%as_Mq=HvFxDOA9vt2HA2`Z~lEq;TinDCr z3!=ZLVCGv|t6RjLL1_b&%DX|-DtbbYe1a5epXB#F?RmFvn%~xSZPD6&YZB4cTB_2|E^h;wQ!SdG`7fQf+S{ zGX=d}4NIj5hwF6p+~DeOU88G6OBCWt^~>14{L%=arSwe7xuPvIUb*zoZB2fhTAYk5-#C2Pz`6=%wSA)`<2_@L3D0-Tgc+a zymy|~1;ep{AXsu$Y`CJdoEMdGQlK?{SiDigY=q35Q@p`5YpED=-8{X#`~6S!o1KXt zCVr+WdiP>C4|J_=m7h@tbBEISRaH`J6V=>dE+FH71gDoq`VZq$a0Y9m!9E@`Jf0v@ z;3r{ms5m?5Z=K7lx*|8Uh+qyRR}$#+iIUZ6v)@u>+0sP6EVc9{R>7j61jrJpMW8i& z9;KXv!o7hB_=TXORm@T3y#nt)%IpT7#{q|F;d>b5U_Ry&4*!pUKep>~Yl^s>aWDe- z_9(r73-Tt182B94uB28g_NMOCumi1aT5*B-G*XyCAoa_!v=Q$Lxq~DBkz|HszD+`Y zypkd};6%}`YbB&IY2}lozAU7u;vOMFE5lGA{ZtqbtOrgN2DtWQ!GC}UO>gd9ULiuQ zaQDoC!F*2uGV}d|8lpg6Lg=Qn4WGNpdqT5+-0X=flwY?A$8X}Rn>UpS@bY2l?@Zr` z4>LBXFvMmoeLYI!a&87!{Q(?@9S;W09DacJ zuKhWFs%AbIxZoZ15xNK^p|5?IFs--^SHE@~T!?%M$-V{n|bxp5U$8-scNz#K6 zDIrv|H5dR)t;9RPdXzA&FiTp#yVc}>DKr{r-0`RP4X_*dhCU{tTIp;`mJlPG_T((b(!R2Dg^Bs#tEy|l%U-yhGoor0{ z)<7~ z+rfifRk1qZ+Hz&5u~SiPsWnV^hjW9Ybdk5$R=8GkG=JYQlPSB@xgE>|4mFOg)VOTS z0qHJjtzn2KP*=vg7ezTW%BUbLifb4uE5(KoJ=B%a=zU^3U0VZ-P&Y}DI(|Uv=Y+iJ zYdEl+_=pneN4IW7oZ->ukemX4caP`=;Y+I4Xi42JRjR;h$$Y^V8*3!4DXq7(bB9{# z7Os6A@4UBk^$#avqq~TH%~ua_fc^y{O$z*aZ5Q9~IQmKzVJCZDtRNg_NN#U-o61W=-s?jQDuYHtfyJOt` zE;zs*ZF)b=ClN()oK2Ah6Kf`pJk1v~-gn+O;j-YyK%eGIcX7fb1?O5W2Am+X#w>4S zR1`=@mWzvejy#%iXcmQkmY4Xo@yUj$CzHGo$U!YO(gsE-t)L^~iUP6=)6F8y2@V{9 z2*jZq0RQ1o>7d5rII9Fdz|^P}#*8}*zPQw*cC{+iWHdE7ZK$n>-nw324{&VJCe+a& zMI~ggD9gYAK7dOqi^|pyW0eF-W)*D72fFz_C@#oUxg;gzLd!&dem#(`e<0PaW>8NC zjf=epCL>EOo~7fZyA*pDfayPi*X-yKbfC-Bfon{dRm|j!?wpllu0klPi-LX}0E{n) zLM8J2eYPdreMy;UcZA;EJv>64H=T|_cnTPy(-r%B?V}El_PT1Viop+;GX1>Bs!0+p z_f7Rp%qM1`YG#eduh3=I_x5UFUVZ<}S z&!RXyu=TJMTYDh{!7%gzKJzQLUqN4g=FQ@b-<>G;HT`(F~+E!QgCXaX9QC#b7%xu$a z_SZ+(9obniE%OLAZXT6D=ST5ExVX3X^$*^+>L0xB?!gaHlR*A3cLUyF-LG8EvR+t+ zmVDBC+C^|C*jo+YHS>Uh>!k^ke+?ObLYD)}V+n37o%UeyiNt?WP$_FRQBbuhRr6fX zivbY+!A4yR_4%?d-n^(srA(}?(YXiPw3pYR_kg+9y&T0m2*hKLl{?Xg@V??C)2%jt{f_8G zrC6(ovj@qIFF&m}WncSg6*Vd8q@t+Vs2dUOc~!5CjNgX6z^3xTN>f0ZaH?@1tYc|& zTRVU_IDl{*UZLgw3$%a3wJAO(Ba6Q}i@#_jf;@Fx)>%j|zHO zT^G|qzkm7ogZ+;Lm#^UKa_|vtzxh4Xc=+baK4vbGhR1YGgMY$V< zHBpXh^{kK= zJr~5k3GQhyLqn35JDJZK#p-4)3Yc7;bus?Bniv$_z%&xo2U7)Fl~tH3?&d{lcsleJ z13wI;j52_BtjZ<1%#X9j!LA_oKzQjo>U+DPnMcV{y{1c@j3tsUMG{15 z*_a*o@n$B!B2(*sr-LL+sfaQBM0k`;klIzyaidXXwT5f(aRUZCsNAY{LH%haBFtcx zJ{yYJuw;XJHHKF0p;KOnQIp{ z;A<3C004W>xp<4_u7!>tZjlS*s_Eh6GF*+p!xJhrION8{L2zFjivotvw8kDv^Kv@- zRUn~OWFsqTRik4W=%hqcDns~aW38&yq#tTacFTuI1jbfQk4?P`b4aemLb(DT1Sb2u%sdW`&l6Gp2+#rBNJDvN=0?@shP$# zNc~#3SCw((`zlTntCUTGa-viT5(h<1$a+Ka6EB}YXBt|EX(>xnWrNrcEyM{V44r4m zBg`0oyThSTRf0%q*&;uVFxA*ZWZ~IVl!P)(uuF@{iLllW(g@UnGJJYlgsNnH9iT$g zYf$bA6i(hVP1Qmrny70PYlR<*EqXg;QPR)-An&#8wWI+h>0A z^>&&K$4<`T39)yD!-a9eJq;-y$-bW6b1Yhab)-!vS0IpTtC5pGM!{+1Tk893MBk)# z9lqwI21!G8+{T&`XaKtxtKMl%d#+g0KY8ErwxACm_n!4$^t?^u+IdcUb8=1QPA{&s z68D*%Oyq|a`jp%hQ(0P#?JN~_&NJpZ&M2G~mjt&5_g9Q&rRJRkX9RS7#<&a|uJ{ap zKA}NBvzC`ivR-MgpXe z@0HA7{a#r@XFagRY4;24G<;i?0SQg-^X7@ghK`~rn16U|PF9_*!~qf4*$ z>h9JTeYSW+2i>rK-!Iqh;^%BDZQt-daQd9hIBdU5+dGbjs{_>czwn2k@)` z4PSopPNX zod?Q2={@IqYJE}sMaOK~a01YE31_g;;i4dv+oye>l*0LG zi@1kB5T~+(@17KY*D)TA|4e^?4-WXxMS`G|gr?>m4=W~&NQhR&L`gXaV3}VM8{9Su zK`ow_MykCdd;sx{{`>2USYo7Kg6QlQj1QQ=W=+#HgJ?ZRYg!N7pPyhc5!6gnYa;a& zwOYE`g^&C|09{iW32w`W;jLRzJVHVn*%?y5Pmq`oyiEK-W+;Cfby$B6_82vU+9{Qo z))1vxmad-bPHVwM@(#cSy`?$pOy1p&x<>8Ke=_jyy1r>md41pu&h&EsuPuU5@uJ8 zvu>{roUiwaXO|Ecm0IHay?NVIOnct57Qk7dZwkM>>)Mxt>L5PtS#FhmQUOM+(

?{I7o%=GDC&ROy=q?yXLJ zcT1D6YtBM<3iWcqYNTE~I9jZN@>EYAGtqrvd{Rw~A1?0hbVlP#i80C1#5Bz02ruJ{ zn^p3;BEd#dI~f-GJU}vzjmE2Od49cpskgCk4bZtMkgTo`HflSy&3$B1@p5!v&@@fBpZ*_=JIx0TrkN0EhnuCjfYyV_;xlVAR2f|Nlo~|01CFA4EM& z9kO05{4Y4|0h#d^0HISGRsaA10000g09F8i0J;G70wMzV16~7|1O^0{1pozF1`-Bz z2HXcU2bu^(2)+px3LXkPwhH=Kj{CKIA~oMT{Q zU|>*ZxWmB300K-v%mrru2lE*KBFO?Iv!xh20e{(2!!Qg*bK9(ivhVv2f0c1-xzXU* z8QX1uug4+qh90D&8O^y$CdpXSxW@w?@q}l*;1zGlOgLxzTH4-hjp%sQgmUC{mo2sRR4%R7qVrTq zVt;S72vkT4g0;`3HF3@9qZ39B!@5u^BDoOD_qk$CKXz?}%!bWR6^EJPk7%#0Qq>=t zN=0$4*@skV?(!9fX1&N8mXb`$M%m&wylP`}EMk01z9Bzv*?Tst`X?c4tt4IAj!eCF zIvt?&6hgf4nQw%nEHu { + this.formatParameters.selectedFormat = format; + }); if (i === 0) { formatInput.checked = true; this.formatParameters.selectedFormat = format; } - formatInput.addEventListener ('change', () => { - this.formatParameters.selectedFormat = format; - }); } } diff --git a/website/o3dv/js/settings.js b/website/o3dv/js/settings.js index 4589f99..c0a5c1b 100644 --- a/website/o3dv/js/settings.js +++ b/website/o3dv/js/settings.js @@ -9,6 +9,9 @@ OV.Settings = class { this.backgroundColor = new OV.Color (255, 255, 255); this.defaultColor = new OV.Color (200, 200, 200); + this.showEdges = false; + this.edgeColor = new OV.Color (0, 0, 0); + this.edgeThreshold = 10; this.themeId = OV.Theme.Light; } @@ -16,6 +19,10 @@ OV.Settings = class { this.backgroundColor = cookieHandler.GetColorVal ('ov_background_color', new OV.Color (255, 255, 255)); this.defaultColor = cookieHandler.GetColorVal ('ov_default_color', new OV.Color (200, 200, 200)); + this.showEdges = cookieHandler.GetBoolVal ('ov_show_edges', false); + this.edgeColor = cookieHandler.GetColorVal ('ov_edge_color', new OV.Color (0, 0, 0)); + this.edgeThreshold = cookieHandler.GetIntVal ('ov_edge_threshold', 10); + this.showEdges = cookieHandler.GetBoolVal ('ov_show_edges', false); this.themeId = cookieHandler.GetIntVal ('ov_theme_id', OV.Theme.Light); } @@ -23,6 +30,9 @@ OV.Settings = class { cookieHandler.SetColorVal ('ov_background_color', this.backgroundColor); cookieHandler.SetColorVal ('ov_default_color', this.defaultColor); - cookieHandler.SetStringVal ('ov_theme_id', this.themeId); + cookieHandler.SetBoolVal ('ov_show_edges', this.showEdges); + cookieHandler.SetColorVal ('ov_edge_color', this.edgeColor); + cookieHandler.SetIntVal ('ov_edge_threshold', this.edgeThreshold); + cookieHandler.SetIntVal ('ov_theme_id', this.themeId); } }; diff --git a/website/o3dv/js/sidebar.js b/website/o3dv/js/sidebar.js index 06777b6..2d866b0 100644 --- a/website/o3dv/js/sidebar.js +++ b/website/o3dv/js/sidebar.js @@ -49,6 +49,9 @@ OV.Sidebar = class onDefaultColorChange : () => { this.callbacks.onDefaultColorChange (); }, + onEdgeDisplayChange : () => { + this.callbacks.onEdgeDisplayChange (); + }, onThemeChange : () => { this.callbacks.onThemeChange (); } diff --git a/website/o3dv/js/sidebarpanels.js b/website/o3dv/js/sidebarpanels.js index c4ae1ee..ecabe48 100644 --- a/website/o3dv/js/sidebarpanels.js +++ b/website/o3dv/js/sidebarpanels.js @@ -210,6 +210,7 @@ OV.SettingsSidebarPanel = class extends OV.SidebarPanel this.backgroundColorInput = null; this.defaultColorInput = null; this.defaultColorWarning = null; + this.edgeDisplayInput = null; this.themeInput = null; } @@ -252,6 +253,7 @@ OV.SettingsSidebarPanel = class extends OV.SidebarPanel this.SetDefaultColor (newColor, false); } ); + this.edgeDisplayInput = this.AddEdgeDisplayParameter (this.settings.showEdges, this.settings.edgeColor, this.settings.edgeThreshold); this.themeInput = this.AddThemeParameter (this.settings.themeId); this.AddResetToDefaultsButton (); } @@ -286,12 +288,6 @@ OV.SettingsSidebarPanel = class extends OV.SidebarPanel } } - SetThemeId (themeId) - { - this.settings.themeId = themeId; - this.callbacks.onThemeChange (); - } - AddColorParameter (title, description, warningText, predefinedColors, defaultValue, onChange) { let contentDiv = OV.AddDiv (this.contentDiv, 'ov_sidebar_settings_content'); @@ -344,38 +340,46 @@ OV.SettingsSidebarPanel = class extends OV.SidebarPanel }; } - AddThemeParameter (defaultValue) + AddEdgeDisplayParameter (show, edgeColor, edgeThreshold) { - function AddThemeRadioButton (obj, contentDiv, themeId, themeName, onChange) + function AddRadioButton (contentDiv, id, text, onChange) { let row = OV.AddDiv (contentDiv, 'ov_sidebar_settings_row'); - let label = OV.AddDomElement (row, 'label'); - label.setAttribute ('for', themeId.toString ()); - let radio = OV.AddDomElement (label, 'input', 'ov_radio_button'); - radio.setAttribute ('type', 'radio'); - radio.setAttribute ('id', themeId.toString ()); - radio.setAttribute ('name', 'theme'); - OV.AddDomElement (label, 'span', null, themeName); - radio.addEventListener ('change', () => { - obj.SetThemeId (themeId); - if (themeId === OV.Theme.Light) { - obj.SetBackgroundColor (new OV.Color (255, 255, 255), true); - obj.SetDefaultColor (new OV.Color (200, 200, 200), true); - } else if (themeId === OV.Theme.Dark) { - obj.SetBackgroundColor (new OV.Color (42, 43, 46), true); - obj.SetDefaultColor (new OV.Color (200, 200, 200), true); - } - onChange (); - }); - return radio; + return OV.AddRadioButton (row, 'edge_display', id, text, onChange); } - function Select (radioButtons, defaultValue) - { - for (let i = 0; i < radioButtons.length; i++) { - let radioButton = radioButtons[i]; - radioButton.checked = radioButton.getAttribute ('id') === defaultValue.toString (); + let contentDiv = OV.AddDiv (this.contentDiv, 'ov_sidebar_settings_content'); + let titleDiv = OV.AddDiv (contentDiv, 'ov_sidebar_subtitle'); + OV.AddSvgIconElement (titleDiv, 'edges', 'ov_sidebar_subtitle_icon'); + OV.AddDiv (titleDiv, 'ov_sidebar_subtitle_text', 'Edge Display'); + + let buttonsDiv = OV.AddDiv (contentDiv, 'ov_sidebar_settings_padded'); + let buttons = []; + let offButton = AddRadioButton (buttonsDiv, 'off', 'Don\'t Show Edges', () => { + this.settings.showEdges = false; + this.callbacks.onEdgeDisplayChange (); + }); + let onButton = AddRadioButton (buttonsDiv, 'on', 'Show Edges', () => { + this.settings.showEdges = true; + this.callbacks.onEdgeDisplayChange (); + }); + buttons.push (offButton); + buttons.push (onButton); + + OV.SelectRadioButton (buttons, show ? 'on' : 'off'); + return { + select : (value) => { + OV.SelectRadioButton (buttons, value ? 'on' : 'off'); } + }; + } + + AddThemeParameter (defaultValue) + { + function AddRadioButton (contentDiv, themeId, themeName, onChange) + { + let row = OV.AddDiv (contentDiv, 'ov_sidebar_settings_row'); + return OV.AddRadioButton (row, 'theme', themeId.toString (), themeName, onChange); } let contentDiv = OV.AddDiv (this.contentDiv, 'ov_sidebar_settings_content'); @@ -384,16 +388,28 @@ OV.SettingsSidebarPanel = class extends OV.SidebarPanel OV.AddDiv (titleDiv, 'ov_sidebar_subtitle_text', 'Appearance'); let buttonsDiv = OV.AddDiv (contentDiv, 'ov_sidebar_settings_padded'); - let result = { - buttons : [], - select: (value) => { - Select (result.buttons, value); + let buttons = []; + let lightButton = AddRadioButton (buttonsDiv, OV.Theme.Light, 'Light', () => { + this.SetBackgroundColor (new OV.Color (255, 255, 255), true); + this.SetDefaultColor (new OV.Color (200, 200, 200), true); + this.settings.themeId = OV.Theme.Light; + this.callbacks.onThemeChange (); + }); + let darkButton = AddRadioButton (buttonsDiv, OV.Theme.Dark, 'Dark', () => { + this.SetBackgroundColor (new OV.Color (42, 43, 46), true); + this.SetDefaultColor (new OV.Color (200, 200, 200), true); + this.settings.themeId = OV.Theme.Dark; + this.callbacks.onThemeChange (); + }); + buttons.push (lightButton); + buttons.push (darkButton); + + OV.SelectRadioButton (buttons, defaultValue.toString ()); + return { + select : (value) => { + OV.SelectRadioButton (buttons, value.toString ()); } }; - result.buttons.push (AddThemeRadioButton (this, buttonsDiv, OV.Theme.Light, 'Light', this.callbacks.onThemeChange)); - result.buttons.push (AddThemeRadioButton (this, buttonsDiv, OV.Theme.Dark, 'Dark', this.callbacks.onThemeChange)); - Select (result.buttons, defaultValue); - return result; } AddResetToDefaultsButton () @@ -405,11 +421,16 @@ OV.SettingsSidebarPanel = class extends OV.SidebarPanel this.settings.defaultColor = defaultSettings.defaultColor; this.backgroundColorInput.pickr.setColor ('#' + OV.ColorToHexString (defaultSettings.backgroundColor)); this.defaultColorInput.pickr.setColor ('#' + OV.ColorToHexString (defaultSettings.defaultColor)); - if (this.themeInput !== null) { - this.settings.themeId = defaultSettings.themeId; - this.themeInput.select (defaultSettings.themeId); - this.callbacks.onThemeChange (); - } + + this.settings.showEdges = defaultSettings.showEdges; + this.settings.edgeColor = defaultSettings.edgeColor; + this.settings.edgeThreshold = defaultSettings.edgeThreshold; + this.edgeDisplayInput.select (this.settings.showEdges); + this.callbacks.onEdgeDisplayChange (); + + this.settings.themeId = defaultSettings.themeId; + this.themeInput.select (this.settings.themeId); + this.callbacks.onThemeChange (); }); } }; diff --git a/website/o3dv/js/website.js b/website/o3dv/js/website.js index 59f6545..66cedfd 100644 --- a/website/o3dv/js/website.js +++ b/website/o3dv/js/website.js @@ -378,6 +378,12 @@ OV.Website = class } } + UpdateEdgeDisplay () + { + this.settings.SaveToCookies (this.cookieHandler); + this.viewer.SetEdgeSettings (this.settings.showEdges, this.settings.edgeColor, this.settings.edgeThreshold); + } + SwitchTheme (newThemeId, resetColors) { this.settings.themeId = newThemeId; @@ -398,6 +404,7 @@ OV.Website = class { let canvas = OV.AddDomElement (this.parameters.viewerDiv, 'canvas'); this.viewer.Init (canvas); + this.viewer.SetEdgeSettings (this.settings.showEdges, this.settings.edgeColor, this.settings.edgeThreshold); this.viewer.SetBackgroundColor (this.settings.backgroundColor); this.viewer.SetEnvironmentMap ([ 'assets/envmaps/grayclouds/posx.jpg', @@ -549,6 +556,9 @@ OV.Website = class } this.viewer.Render (); }, + onEdgeDisplayChange : () => { + this.UpdateEdgeDisplay (); + }, onThemeChange : () => { this.SwitchTheme (this.settings.themeId, true); },