feat: Enable 3D constructions when adapting Geometry Applet (#40)

Turns on 3D viewing only for the constructions that use a 3D primitive, but loads the more extensive web3d bundle from the embedded GeoGebra package whenever any applet on the page uses 3d. (The idea is to only require the loading of one bundle per page.) Provides progress on #36.

Reviewed-on: #40
Co-authored-by: Glen Whitney <glen@studioinfinity.org>
Co-committed-by: Glen Whitney <glen@studioinfinity.org>
This commit is contained in:
Glen Whitney 2023-10-08 17:10:59 +00:00 committed by Glen Whitney
parent c99b51dafa
commit 25ba69c621
29 changed files with 29236 additions and 59 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
$wnd.web3d.runAsyncCallback14("function Uyg(a){qpf.call(this,a)}\nfunction pDd(a){qDd.call(this,a,1.0E-11)}\nfunction $nd(a){Wnd(a,0,a.length,null)}\nfunction xWg(a,b){return new zXg(a.k,a,(Aij(),Fhj),b)}\nfunction IJf(a,b){var c,d;d=new snd;for(c=0;c<b.n.r.length;c++){bnd(d,fnd(b.n,c))}HJf(a,d)}\nfunction XKh(a,b,c){BYd();var d,e;d=Lbf(a.VU(),b.VU());e=Lbf(a.VU(),c.VU());return !taf(d,e)}\nfunction gLh(a,b,c,d,e,f,g,h){BYd();var i,j,k,l;i=a.VU();j=b.VU();k=c.VU();l=I9e(I9e(Aaf(T9e(i),d/g),j,e/g),k,f/g);h.AV(l,false)}\nfunction uCd(a,b,c){var d,e;vDd(a,b);e=a.b==null?0:a.b.length;if(c.length!=e){throw Ftc(new uDd(c.length,1,e,1))}for(d=0;d<e;++d){ECd(a,d,b,c[d])}}\nfunction vCd(a,b,c){var d,e;xDd(a,b);e=a.b==null||a.b[0]==null?0:a.b[0].length;if(c.length!=e){throw Ftc(new uDd(1,c.length,1,e))}for(d=0;d<e;++d){ECd(a,b,d,c[d])}}\nfunction sDd(a,b){var c,d,e,f,g,h,i;h=a.b.length;if(b.a.length!=h){throw Ftc(new oAd(b.a.length,h))}if(a.c){throw Ftc(new UDd)}c=me(tf,w2m,5,h,15,1);for(i=0;i<h;i++){c[i]=MCd(b,a.b[i])}for(f=0;f<h;f++){d=c[f];for(g=f+1;g<h;g++){c[g]-=d*a.a[g][f]}}for(e=h-1;e>=0;e--){c[e]/=a.a[e][e];d=c[e];for(g=0;g<e;g++){c[g]-=d*a.a[g][e]}}return new QCd(c)}\nfunction HJf(a,b){var c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,A,B,C,D,F,G,H;if(pf($wnd.Math.sqrt(9+8*b.r.length))!=$wnd.Math.sqrt(9+8*b.r.length)){a.o=false;wJf(a);return}d=pf(0.5*$wnd.Math.sqrt(8*(1+b.r.length)))-1;A=d;e=new HCd(b.r.length,b.r.length+1);t=new HCd(b.r.length,b.r.length);c=ke(tf,[Bbn,w2m],[20,5],15,[d+1,d+1],2);u=me(tf,w2m,5,b.r.length+1,15,1);for(g=0;g<b.r.length;g++){G=($wd(g,b.r.length),b.r[g]).WU();H=($wd(g,b.r.length),b.r[g]).XU();for(n=0,s=0;n<d+1;n++){for(r=0;n+r!=d+1;r++){u[s++]=$wnd.Math.pow(G,n)*$wnd.Math.pow(H,r)}}vCd(e,g,u)}D=0;v=b.r.length;do{if(D>v){v=v-A-1;if(v<2){a.o=false;wJf(a);return}e=new HCd(v,v+1);A-=1;u=me(tf,w2m,5,v+1,15,1);for(h=0;h<v;h++){G=($wd(h,b.r.length),b.r[h]).gV();H=($wd(h,b.r.length),b.r[h]).hV();for(n=0,s=0;n<A+1;n++){for(r=0;n+r!=A+1;r++){u[s++]=$wnd.Math.pow(G,n)*$wnd.Math.pow(H,r)}}vCd(e,h,u)}t=new HCd(v,v);D=0}B=tCd(e,D);for(i=0,o=0;i<v+1;i++){if(i==D){continue}uCd(t,o++,tCd(e,i))}++D;F=oDd(new pDd(t))}while(F.c);for(j=0;j<B.length;j++){B[j]*=-1}w=sDd(F,new PCd(B)).a;C=me(tf,w2m,5,w.length+1,15,1);for(k=0,p=0;k<C.length;k++){if(k==D-1){C[k]=1}else{C[k]=ynj(w[p])?0:w[p];++p}}for(l=0,q=0;l<A+1;l++){for(m=0;l+m<A+1;m++){c[l][m]=C[q++]}}yJf(a,c);a.o=true;for(f=0;f<b.r.length;f++){if(!uJf(a,($wd(f,b.r.length),b.r[f]))){a.o=false;wJf(a);return}}}\nvar C2n=')(',p4n=' and ',F4n={16:1,29:1,19:1,24:1,30:1,247:1},G4n={3:1,4:1,8:1,7:1,125:1},K4n={3:1,4:1,8:1,7:1,93:1};luc(F5m,1,{},pDd);luc(34,15,csn);_.UR=function(a,b){return this.K};luc(1677,25,Wrn);_.VP=function(a,b){var c;c=hpf(this,a,new Lrh(false));if(c.length!=1){throw Ftc(Zof(this,a,a.c.r.length))}if(!ff(c[0],49)){throw Ftc(Wof(this,a.i,c[0]))}return pe(ie(Zdb,1),fhn,15,0,[this.j_(c[0],Ktf(a))])};var cbb=Cgd(1677);luc(141,260,VEn);_.UR=function(a,b){return IYg(this,a,b)};luc(77,15,yGn);_.UR=function(a,b){if(cid(TCh(this,($qg(),wqg)),'y')){return NDh(this,b)}return !this.d?NaN:this.d.pk(a)};luc(185,15,BGn);_.UR=function(a,b){return lEh(this,a,b)};luc(c3m,1,{});var ekb=Cgd(c3m);dXm(Tc)(14);\n//# sourceURL=web3d-14.js\n")

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,23 @@
function web3d(){var H='bootstrap',I='begin',J='gwt.codesvr.web3d=',K='gwt.codesvr=',L='web3d',M='startup',N='DUMMY',O=0,P=1,Q='iframe',R='position:absolute; width:0; height:0; border:none; left: -1000px;',S=' top: -1000px;',T='Chrome',U='CSS1Compat',V='<!doctype html>',W='',X='<html><head><\/head><body><\/body><\/html>',Y='undefined',Z='readystatechange',$=10,_='script',ab='javascript',bb='Failed to load ',cb='moduleStartup',db='scriptTagAdded',eb='moduleRequested',fb='meta',gb='name',hb='web3d::',ib='::',jb='gwt:property',kb='content',lb='=',mb='gwt:onPropertyErrorFn',nb='Bad handler "',ob='" for "gwt:onPropertyErrorFn"',pb='gwt:onLoadErrorFn',qb='" for "gwt:onLoadErrorFn"',rb='#',sb='?',tb='/',ub='img',vb='clear.cache.gif',wb='baseUrl',xb='web3d.nocache.js',yb='base',zb='//',Ab='selectingPermutation',Bb='web3d.devmode.js',Cb='1ACC6399F984FD07A949D6F3D28D2FA3',Db=':',Eb='.cache.js',Fb='loadExternalRefs',Gb='end';var n=window;var o=document;q(H,I);function p(){var a=n.location.search;return a.indexOf(J)!=-1||a.indexOf(K)!=-1}
function q(a,b){if(n.__gwtStatsEvent){n.__gwtStatsEvent({moduleName:L,sessionId:n.__gwtStatsSessionId,subSystem:M,evtGroup:a,millis:(new Date).getTime(),type:b})}}
web3d.__sendStats=q;web3d.__moduleName=L;web3d.__errFn=null;web3d.__moduleBase=N;web3d.__softPermutationId=O;web3d.__computePropValue=null;web3d.__getPropMap=null;web3d.__installRunAsyncCode=function(){};web3d.__gwtStartLoadingFragment=function(){return null};web3d.__gwt_isKnownPropertyValue=function(){return false};web3d.__gwt_getMetaProperty=function(){return null};var r=null;var s=n.__gwt_activeModules=n.__gwt_activeModules||{};s[L]={moduleName:L};web3d.__moduleStartupDone=function(e){var f=s[L].bindings;s[L].bindings=function(){var a=f?f():{};var b=e[web3d.__softPermutationId];for(var c=O;c<b.length;c++){var d=b[c];a[d[O]]=d[P]}return a}};var t;function u(){v();return t}
function v(){if(t){return}var a=o.createElement(Q);a.id=L;a.style.cssText=R+S;a.tabIndex=-1;o.body.appendChild(a);t=a.contentWindow.document;if(navigator.userAgent.indexOf(T)==-1){t.open();var b=document.compatMode==U?V:W;t.write(b+X);t.close()}}
function w(f){function g(a){function b(){if(typeof o.readyState==Y){return typeof o.body!=Y&&o.body!=null}return /loaded|complete/.test(o.readyState)}
var c=b();if(c){a();return}function d(){if(!c){if(!b()){return}c=true;a();if(o.removeEventListener){o.removeEventListener(Z,d,false)}if(e){clearInterval(e)}}}
if(o.addEventListener){o.addEventListener(Z,d,false)}var e=setInterval(function(){d()},$)}
function h(a){var b=u();var c=b.body;var d=b.createElement(_);d.language=ab;d.crossOrigin=W;d.src=a;if(web3d.__errFn){d.onerror=function(){web3d.__errFn(L,new Error(bb+a))}}c.appendChild(d);q(cb,db)}
q(cb,eb);g(function(){h(f)})}
web3d.__startLoadingFragment=function(a){return C(a)};web3d.__installRunAsyncCode=function(a){var b=u();var c=b.body;var d=b.createElement(_);d.language=ab;d.text=a;c.appendChild(d);c.removeChild(d)};function A(){var c={};var d;var e;var f=o.getElementsByTagName(fb);for(var g=O,h=f.length;g<h;++g){var i=f[g],j=i.getAttribute(gb),k;if(j){j=j.replace(hb,W);if(j.indexOf(ib)>=O){continue}if(j==jb){k=i.getAttribute(kb);if(k){var l,m=k.indexOf(lb);if(m>=O){j=k.substring(O,m);l=k.substring(m+P)}else{j=k;l=W}c[j]=l}}else if(j==mb){k=i.getAttribute(kb);if(k){try{d=eval(k)}catch(a){alert(nb+k+ob)}}}else if(j==pb){k=i.getAttribute(kb);if(k){try{e=eval(k)}catch(a){alert(nb+k+qb)}}}}}__gwt_getMetaProperty=function(a){var b=c[a];return b==null?null:b};r=d;web3d.__errFn=e}
function B(){function e(a){var b=a.lastIndexOf(rb);if(b==-1){b=a.length}var c=a.indexOf(sb);if(c==-1){c=a.length}var d=a.lastIndexOf(tb,Math.min(c,b));return d>=O?a.substring(O,d+P):W}
function f(a){if(a.match(/^\w+:\/\//)){}else{var b=o.createElement(ub);b.src=a+vb;a=e(b.src)}return a}
function g(){var a=__gwt_getMetaProperty(wb);if(a!=null){return a}return W}
function h(){var a=o.getElementsByTagName(_);for(var b=O;b<a.length;++b){if(a[b].src.indexOf(xb)!=-1){return e(a[b].src)}}return W}
function i(){var a=o.getElementsByTagName(yb);if(a.length>O){return a[a.length-P].href}return W}
function j(){var a=o.location;return a.href==a.protocol+zb+a.host+a.pathname+a.search+a.hash}
var k=g();if(k==W){k=h()}if(k==W){k=i()}if(k==W&&j()){k=e(o.location.href)}k=f(k);return k}
function C(a){if(a.match(/^\//)){return a}if(a.match(/^[a-zA-Z]+:\/\//)){return a}return web3d.__moduleBase+a}
function D(){var f=[];var g=O;var h=[];var i=[];function j(a){var b=i[a](),c=h[a];if(b in c){return b}var d=[];for(var e in c){d[c[e]]=e}if(r){r(a,d,b)}throw null}
__gwt_isKnownPropertyValue=function(a,b){return b in h[a]};web3d.__getPropMap=function(){var a={};for(var b in h){if(h.hasOwnProperty(b)){a[b]=j(b)}}return a};web3d.__computePropValue=j;n.__gwt_activeModules[L].bindings=web3d.__getPropMap;q(H,Ab);if(p()){return C(Bb)}var k;try{k=Cb;var l=k.indexOf(Db);if(l!=-1){g=parseInt(k.substring(l+P),$);k=k.substring(O,l)}}catch(a){}web3d.__softPermutationId=g;return C(k+Eb)}
function F(){if(!n.__gwt_stylesLoaded){n.__gwt_stylesLoaded={}}q(Fb,I);q(Fb,Gb)}
A();web3d.__moduleBase=B();s[L].moduleBase=web3d.__moduleBase;var G=D();F();q(H,Gb);w(G);return true}
web3d.succeeded=web3d();

View File

@ -35,7 +35,16 @@
"deps/GeoGebra/HTML5/5.0/webSimple/webSimple.nocache.js", "deps/GeoGebra/HTML5/5.0/webSimple/webSimple.nocache.js",
"deps/GeoGebra/HTML5/5.0/webSimple/clear.cache.gif", "deps/GeoGebra/HTML5/5.0/webSimple/clear.cache.gif",
"deps/GeoGebra/HTML5/5.0/webSimple/deferredjs/*", "deps/GeoGebra/HTML5/5.0/webSimple/deferredjs/*",
"deps/GeoGebra/HTML5/5.0/css/bundles/simple-bundle.css" "deps/GeoGebra/HTML5/5.0/web3d/web3d.nocache.js",
"deps/GeoGebra/HTML5/5.0/web3d/clear.cache.gif",
"deps/GeoGebra/HTML5/5.0/web3d/1ACC6399F984FD07A949D6F3D28D2FA3.cache.js",
"deps/GeoGebra/HTML5/5.0/web3d/deferredjs/*",
"deps/GeoGebra/HTML5/5.0/css/bundles/bundle.css",
"deps/GeoGebra/HTML5/5.0/css/keyboard-styles.css",
"deps/GeoGebra/HTML5/5.0/css/fonts.css",
"deps/GeoGebra/HTML5/5.0/css/greek-font.css",
"deps/GeoGebra/HTML5/5.0/css/bundles/simple-bundle.css",
"deps/GeoGebra/HTML5/5.0/web3d/fonts/base/jlm_cmmi10.js"
] ]
}], }],
"permissions": ["storage"] "permissions": ["storage"]

View File

@ -16,8 +16,10 @@
<br/> <br/>
<br/> <br/>
Alter execution of the translated applet: <br/> Alter execution of the translated applet: <br/>
<label for="showall">Show all entities, even hidden ones</label> <label for="showall">Show all applet entities, even hidden ones</label>
<input type="checkbox" id="showall"> <input type="checkbox" id="showall"><br/>
<label for="showaux">Show geogebra auxiliaries (not in applet)</label>
<input type="checkbox" id="showaux">
<script src="options.js" type="module"></script> <script src="options.js" type="module"></script>
</body> </body>

View File

@ -34,11 +34,11 @@
url: 'https://code.studioinfinity.org/glen/archematics.git', url: 'https://code.studioinfinity.org/glen/archematics.git',
}, },
devDependencies: { devDependencies: {
'@danielx/civet': '^0.6.39', '@danielx/civet': '^0.6.42',
'@types/firefox-webext-browser': '^111.0.2', '@types/firefox-webext-browser': '^111.0.2',
'@types/jquery': '^3.5.19', '@types/jquery': '^3.5.21',
'http-server': '^14.1.1', 'http-server': '^14.1.1',
rollup: '^3.29.3', rollup: '^4.0.2',
typescript: '^5.2.2', typescript: '^5.2.2',
}, },
dependencies: { dependencies: {

View File

@ -14,20 +14,20 @@ dependencies:
devDependencies: devDependencies:
'@danielx/civet': '@danielx/civet':
specifier: ^0.6.39 specifier: ^0.6.42
version: 0.6.39(typescript@5.2.2) version: 0.6.42(typescript@5.2.2)
'@types/firefox-webext-browser': '@types/firefox-webext-browser':
specifier: ^111.0.2 specifier: ^111.0.2
version: 111.0.2 version: 111.0.2
'@types/jquery': '@types/jquery':
specifier: ^3.5.19 specifier: ^3.5.21
version: 3.5.19 version: 3.5.21
http-server: http-server:
specifier: ^14.1.1 specifier: ^14.1.1
version: 14.1.1 version: 14.1.1
rollup: rollup:
specifier: ^3.29.3 specifier: ^4.0.2
version: 3.29.3 version: 4.0.2
typescript: typescript:
specifier: ^5.2.2 specifier: ^5.2.2
version: 5.2.2 version: 5.2.2
@ -41,8 +41,8 @@ packages:
'@jridgewell/trace-mapping': 0.3.9 '@jridgewell/trace-mapping': 0.3.9
dev: true dev: true
/@danielx/civet@0.6.39(typescript@5.2.2): /@danielx/civet@0.6.42(typescript@5.2.2):
resolution: {integrity: sha512-rePpUAVruQAY5QgYp3gWlNoGSnua0TBu1PkhXZtFjbixrvdGiu0umEZ2eeV1DJ6wFpYGxzYMhqq0Ca9sY3jIUw==} resolution: {integrity: sha512-/f45hkJxLFKuyNnaroZlImf0NwimQPeetAk/w+88B/bY/qHwVHOMa67Nrz73lPwfZYaFX7h2U6PnkzD2c9Uw9Q==}
engines: {node: '>=19 || ^18.6.0 || ^16.17.0'} engines: {node: '>=19 || ^18.6.0 || ^16.17.0'}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -72,12 +72,108 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/sourcemap-codec': 1.4.15
dev: true dev: true
/@rollup/rollup-android-arm-eabi@4.0.2:
resolution: {integrity: sha512-xDvk1pT4vaPU2BOLy0MqHMdYZyntqpaBf8RhBiezlqG9OjY8F50TyctHo8znigYKd+QCFhCmlmXHOL/LoaOl3w==}
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-android-arm64@4.0.2:
resolution: {integrity: sha512-lqCglytY3E6raze27DD9VQJWohbwCxzqs9aSHcj5X/8hJpzZfNdbsr4Ja9Hqp6iPyF53+5PtPx0pKRlkSvlHZg==}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-darwin-arm64@4.0.2:
resolution: {integrity: sha512-nkBKItS6E6CCzvRwgiKad+j+1ibmL7SIInj7oqMWmdkCjiSX6VeVZw2mLlRKIUL+JjsBgpATTfo7BiAXc1v0jA==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-darwin-x64@4.0.2:
resolution: {integrity: sha512-vX2C8xvWPIbpEgQht95+dY6BReKAvtDgPDGi0XN0kWJKkm4WdNmq5dnwscv/zxvi+n6jUTBhs6GtpkkWT4q8Gg==}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-arm-gnueabihf@4.0.2:
resolution: {integrity: sha512-DVFIfcHOjgmeHOAqji4xNz2wczt1Bmzy9MwBZKBa83SjBVO/i38VHDR+9ixo8QpBOiEagmNw12DucG+v55tCrg==}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-arm64-gnu@4.0.2:
resolution: {integrity: sha512-GCK/a9ItUxPI0V5hQEJjH4JtOJO90GF2Hja7TO+EZ8rmkGvEi8/ZDMhXmcuDpQT7/PWrTT9RvnG8snMd5SrhBQ==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-arm64-musl@4.0.2:
resolution: {integrity: sha512-cLuBp7rOjIB1R2j/VazjCmHC7liWUur2e9mFflLJBAWCkrZ+X0+QwHLvOQakIwDymungzAKv6W9kHZnTp/Mqrg==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-x64-gnu@4.0.2:
resolution: {integrity: sha512-Zqw4iVnJr2naoyQus0yLy7sLtisCQcpdMKUCeXPBjkJtpiflRime/TMojbnl8O3oxUAj92mxr+t7im/RbgA20w==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-linux-x64-musl@4.0.2:
resolution: {integrity: sha512-jJRU9TyUD/iMqjf8aLAp7XiN3pIj5v6Qcu+cdzBfVTKDD0Fvua4oUoK8eVJ9ZuKBEQKt3WdlcwJXFkpmMLk6kg==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-win32-arm64-msvc@4.0.2:
resolution: {integrity: sha512-ZkS2NixCxHKC4zbOnw64ztEGGDVIYP6nKkGBfOAxEPW71Sji9v8z3yaHNuae/JHPwXA+14oDefnOuVfxl59SmQ==}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-win32-ia32-msvc@4.0.2:
resolution: {integrity: sha512-3SKjj+tvnZ0oZq2BKB+fI+DqYI83VrRzk7eed8tJkxeZ4zxJZcLSE8YDQLYGq1tZAnAX+H076RHHB4gTZXsQzw==}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@rollup/rollup-win32-x64-msvc@4.0.2:
resolution: {integrity: sha512-MBdJIOxRauKkry7t2q+rTHa3aWjVez2eioWg+etRVS3dE4tChhmt5oqZYr48R6bPmcwEhxQr96gVRfeQrLbqng==}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@types/firefox-webext-browser@111.0.2: /@types/firefox-webext-browser@111.0.2:
resolution: {integrity: sha512-NS7izfYOnQI/Opf3YdZSKkI5Ox89SqEffJHK2zfGY2BYEVuWuM6pSwDRglGl4W0SM84oUQfvLyYH4X6EQZAJ2w==} resolution: {integrity: sha512-NS7izfYOnQI/Opf3YdZSKkI5Ox89SqEffJHK2zfGY2BYEVuWuM6pSwDRglGl4W0SM84oUQfvLyYH4X6EQZAJ2w==}
dev: true dev: true
/@types/jquery@3.5.19: /@types/jquery@3.5.21:
resolution: {integrity: sha512-KFbmk+dXfphHGuVCmlopgcNRCegN/21mkeoD4BzuJhVH0SJW3Uo2mLuAwb6oqTNV79EsRp6J7yC1BbKymjpx/g==} resolution: {integrity: sha512-BgCalH4OX2JcjbnD9E86L+WeN6IcCGZle+Iy0I6eOMuraAfcMb0Z1x9E51rC2Dqq+m8KexEoDBW6GIJxUPmLEg==}
dependencies: dependencies:
'@types/sizzle': 2.3.3 '@types/sizzle': 2.3.3
dev: true dev: true
@ -438,11 +534,23 @@ packages:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
dev: true dev: true
/rollup@3.29.3: /rollup@4.0.2:
resolution: {integrity: sha512-T7du6Hum8jOkSWetjRgbwpM6Sy0nECYrYRSmZjayFcOddtKJWU4d17AC3HNUk7HRuqy4p+G7aEZclSHytqUmEg==} resolution: {integrity: sha512-MCScu4usMPCeVFaiLcgMDaBQeYi1z6vpWxz0r0hq0Hv77Y2YuOTZldkuNJ54BdYBH3e+nkrk6j0Rre/NLDBYzg==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'} engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true hasBin: true
optionalDependencies: optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.0.2
'@rollup/rollup-android-arm64': 4.0.2
'@rollup/rollup-darwin-arm64': 4.0.2
'@rollup/rollup-darwin-x64': 4.0.2
'@rollup/rollup-linux-arm-gnueabihf': 4.0.2
'@rollup/rollup-linux-arm64-gnu': 4.0.2
'@rollup/rollup-linux-arm64-musl': 4.0.2
'@rollup/rollup-linux-x64-gnu': 4.0.2
'@rollup/rollup-linux-x64-musl': 4.0.2
'@rollup/rollup-win32-arm64-msvc': 4.0.2
'@rollup/rollup-win32-ia32-msvc': 4.0.2
'@rollup/rollup-win32-x64-msvc': 4.0.2
fsevents: 2.3.3 fsevents: 2.3.3
dev: true dev: true

View File

@ -1,11 +1,12 @@
{AppletDescription, AdapParams, params, flags, ConfigType} from ./adapptypes.ts { AppletDescription, AdapParams, ConfigType,
params, flags, contains3d } from ./adapptypes.ts
// (At least some of) Joyce's pages have inline scripts that remove their // (At least some of) Joyce's pages have inline scripts that remove their
// own applet nodes, so we have to watch for them as they are added. Hence, // own applet nodes, so we have to watch for them as they are added. Hence,
// this script runs at document_start, and watches for applets being added, // this script runs at document_start, and watches for applets being added,
// setting up the joyceApplets structure as it goes // setting up the joyceApplets structure as it goes
joyceApplets: AppletDescription[] := [] joyceApplets: AppletDescription[] .= []
obs := new MutationObserver (mutationList) => obs := new MutationObserver (mutationList) =>
for each change of mutationList for each change of mutationList
for each newGenericNode of change.addedNodes for each newGenericNode of change.addedNodes
@ -38,13 +39,32 @@ function addScriptTag(url: string, module = false)
document.head.appendChild script document.head.appendChild script
document.addEventListener "DOMContentLoaded", async => document.addEventListener "DOMContentLoaded", async =>
finalJoyceApplet := document.querySelector "applet[code='Geometry']" finalJoyceApplets := document.querySelectorAll "applet[code='Geometry']"
if joyceApplets.length or finalJoyceApplet if finalJoyceApplets.length
joyceApplets = []
for jApp of finalJoyceApplets
jParent := jApp.parentNode as HTMLElement
unless jParent then continue
id .= jParent.getAttribute 'id'
unless id
id = 'joyceApplet' + joyceApplets.length
jParent.setAttribute 'id', id
joyceApplets.push {
html: jApp.outerHTML,
params(jApp.children),
id,
width: parseInt(jApp.getAttribute('width') ?? '200'),
height: parseInt(jApp.getAttribute('height') ?? '200') }
if joyceApplets.length
config := await browser.storage.local.get(flags) as ConfigType config := await browser.storage.local.get(flags) as ConfigType
adapParams: AdapParams := { use3d .= false
codebase: browser.runtime.getURL('deps/GeoGebra/HTML5/5.0/webSimple'), for each jApp of joyceApplets
config, if contains3d jApp.params
joyceApplets } use3d = true
break
codebase .= browser.runtime.getURL 'deps/GeoGebra/HTML5/5.0/'
codebase += use3d ? 'web3d' : 'webSimple'
adapParams: AdapParams := {codebase, config, joyceApplets }
// @ts-ignore // @ts-ignore
window.wrappedJSObject.adapParams = cloneInto(adapParams, window) window.wrappedJSObject.adapParams = cloneInto(adapParams, window)
addScriptTag(browser.runtime.getURL 'deps/GeoGebra/deployggb.js').then => addScriptTag(browser.runtime.getURL 'deps/GeoGebra/deployggb.js').then =>

View File

@ -1,6 +1,6 @@
import ./deps/jquery.js import ./deps/jquery.js
import type {AppletObject} from ./deps/geotypes/api.ts import type {AppletObject} from ./deps/geotypes/api.ts
import {AppletDescription, AdapParams, params} from ./adapptypes.ts import {AppletDescription, AdapParams, params, contains3d} from ./adapptypes.ts
colorsea from ./deps/colorsea.js colorsea from ./deps/colorsea.js
joyceApplets: AppletDescription[] := [] joyceApplets: AppletDescription[] := []
@ -46,13 +46,37 @@ function postApplets(jApplets: AppletDescription[], codebase = '')
appletOnLoad: (api: AppletObject) => appletOnLoad: (api: AppletObject) =>
elements: JoyceElements := {} elements: JoyceElements := {}
backgroundRGB := [255, 255, 255] as RGB backgroundRGB := [255, 255, 255] as RGB
config3d := contains3d jApp.params
if config3d
worked := api.enable3D true
api.setPerspective 'T'
// Get rid of the xy-plane indicator
xml .= api.getXML()
xml = xml.replace /plate.show="\w+"/, 'plate show="false"'
console.log 'Trying', xml
api.setXML xml
else
api.setPerspective 'G'
for name, value in jApp.params for name, value in jApp.params
dispatchJcommand api, name, value, elements, backgroundRGB dispatchJcommand
api.setCoordSystem -10, 10 + jApp.width, -10, 10 + jApp.height api, name, value, elements, backgroundRGB, config3d
api.setAxesVisible false, false if config3d
api.setGridVisible false depth .= jApp.width
if jApp.height > depth then depth = jApp.height
api.setCoordSystem
-10, 10 + jApp.width,
-10, 10 + jApp.height,
-depth - 10, depth + 10,
false
api.setAxesVisible 3, false, false, false
api.setGridVisible 3, false
else
api.setCoordSystem -10, 10 + jApp.width, -10, 10 + jApp.height
api.setAxesVisible false, false
api.setGridVisible false
} as const } as const
geoApp := new GGBApplet params geoApp := new GGBApplet params
console.log 'About to inject', jApp.id, 'with', codebase
if codebase then geoApp.setHTML5Codebase codebase if codebase then geoApp.setHTML5Codebase codebase
geoApp.inject jApp.id geoApp.inject jApp.id
@ -98,7 +122,11 @@ function freshCommander(): Commander
type JoyceArguments = type JoyceArguments =
Partial<Record<JoyceClass|'subpoints', GeoName[]> & {scalar: number[]}> Partial<Record<JoyceClass|'subpoints', GeoName[]> & {scalar: number[]}>
type ClassHandler = ( type ClassHandler = (
name: GeoName, m: string, args: JoyceArguments, index: number) => Commander name: GeoName,
method: string,
args: JoyceArguments,
index: number,
is3d: boolean) => Commander
type RGB = [number, number, number] type RGB = [number, number, number]
type XYZ = RGB type XYZ = RGB
@ -110,7 +138,8 @@ function dispatchJcommand(
name: string, name: string,
value: string, value: string,
elements: JoyceElements elements: JoyceElements
backgroundRGB: RGB): void backgroundRGB: RGB,
is3d: boolean): void
switch name switch name
'background' 'background'
newback := joyce2rgb value, backgroundRGB newback := joyce2rgb value, backgroundRGB
@ -123,15 +152,18 @@ function dispatchJcommand(
'title' 'title'
if adapParams.config?.commands if adapParams.config?.commands
console.log 'Setting title to', value console.log 'Setting title to', value
api.evalCommand `TitlePoint = Corner(1,1) corner := is3d ? 'Corner(-1,1)' : 'Corner(1,1)'
api.evalCommand `TitlePoint = ${corner}
Text("${value}", TitlePoint + (2,5))` Text("${value}", TitlePoint + (2,5))`
/e\[\d+\]/ /e\[\d+\]/
num := parseInt(name.slice(2)) num := parseInt(name.slice(2))
{commands, callbacks, parts} := {commands, callbacks, parts} :=
jToG value, elements, num, backgroundRGB jToG value, elements, num, backgroundRGB, is3d
if commands.length if commands.length
lastTried .= 0 lastTried .= 0
if commands.filter((&)).every (cmd) => if commands.filter((&)).every (cmd) =>
if adapParams.config?.commands
console.log 'Translated to:', cmd
api.evalCommand(cmd) and ++lastTried api.evalCommand(cmd) and ++lastTried
callbacks.forEach &(api, parts) callbacks.forEach &(api, parts)
else console.warn else console.warn
@ -147,7 +179,8 @@ function jToG(
jCom: string, jCom: string,
elements: JoyceElements, elements: JoyceElements,
index: number, index: number,
backgroundRGB: RGB): Commander backgroundRGB: RGB
is3d: boolean): Commander
[jname, klass, method, data, ...colors] := jCom.split ';' [jname, klass, method, data, ...colors] := jCom.split ';'
if adapParams.config?.commands if adapParams.config?.commands
console.log 'Defining', jname, 'as a', klass, 'constructed by', console.log 'Defining', jname, 'as a', klass, 'constructed by',
@ -175,11 +208,11 @@ function jToG(
(args.subpoints ?= []).push depGeo (args.subpoints ?= []).push depGeo
else if depKlass is 'line' else if depKlass is 'line'
(args.subpoints ?= []).push ...ends ?? [] (args.subpoints ?= []).push ...ends ?? []
cmdr = classHandler[klass] name, method, args, index cmdr = classHandler[klass] name, method, args, index, is3d
unless name is jname then cmdr.callbacks.push (api: AppletObject) => unless name is jname then cmdr.callbacks.push (api: AppletObject) =>
api.setCaption name, jname api.setCaption name, jname
api.setLabelStyle name, 3 // style CAPTION = 3 api.setLabelStyle name, 3 // style CAPTION = 3
if cmdr.auxiliaries.length if cmdr.auxiliaries.length and not adapParams.config?.showaux
cmdr.callbacks.push (api: AppletObject) => cmdr.callbacks.push (api: AppletObject) =>
for each aux of cmdr.auxiliaries for each aux of cmdr.auxiliaries
api.setAuxiliary aux, true api.setAuxiliary aux, true
@ -373,14 +406,14 @@ function geoname(jname: JoyceName, elements: JoyceElements): GeoName
// All of the detailed semantics of each available command lies in this // All of the detailed semantics of each available command lies in this
// function. // function.
classHandler: Record<JoyceClass, ClassHandler> := classHandler: Record<JoyceClass, ClassHandler> :=
point: (name, method, args): Commander => point: (name, method, args, index, is3d): Commander =>
return := freshCommander() return := freshCommander()
{commands, callbacks, parts, auxiliaries} := return.value {commands, callbacks, parts, auxiliaries} := return.value
aux := name + 'aUx' aux := name + 'aUx'
parts[0].push name parts[0].push name
switch method switch method
'angleDivider' /angle(?:Bisector|Divider)/
// Note doesn't yet handle plane argument // Note we just ignore a possible plane argument; it's irrelevant
unless args.subpoints return unless args.subpoints return
[start, center, end] := args.subpoints [start, center, end] := args.subpoints
// see if we need to make the destination segment from start to end // see if we need to make the destination segment from start to end
@ -390,19 +423,21 @@ classHandler: Record<JoyceClass, ClassHandler> :=
auxiliaries.push destination auxiliaries.push destination
commands.push `${destination} = Segment(${start}, ${end})` commands.push `${destination} = Segment(${start}, ${end})`
else destination = args.line[0] else destination = args.line[0]
n := args.scalar?[0] n := method is 'angleBisector' ? 2 : args.scalar?[0]
console.log 'Dividing angle', start, center, end, 'by', n
inPlane := is3d ? `, Plane(${start}, ${center}, ${end})` : ''
commands.push commands.push
`${aux}2 = Angle(${start}, ${center}, ${end})` `${aux}2 = Angle(${start}, ${center}, ${end}${inPlane})`
`${aux}3 = If(${aux}2 > pi, ${aux}2 - 2*pi, ${aux}2)` `${aux}3 = If(${aux}2 > pi, ${aux}2 - 2*pi, ${aux}2)`
`${aux}4 = Rotate(${start}, ${aux}3/${n}, ${center})` `${aux}4 = Rotate(${start}, ${aux}3/${n}, ${center}${inPlane})`
`${name} = Intersect(${destination}, Ray(${center}, ${aux}4))` `${name} = Intersect(${destination}, Ray(${center}, ${aux}4))`
auxiliaries.push ...[2..4].map (i) => `${aux}${i}` auxiliaries.push ...[2..4].map (i) => `${aux}${i}`
'extend' 'extend'
unless args.subpoints then return
sp := args.subpoints sp := args.subpoints
unless sp then return
direction .= `UnitVector(Vector(${sp[0]},${sp[1]}))` direction .= `UnitVector(Vector(${sp[0]},${sp[1]}))`
if args.line and ( if args.line and (
not args.point or args.point[0] !== args.subpoints[0]) not args.point or args.point[0] !== sp[0])
direction = `UnitVector(${args.line[0]})` direction = `UnitVector(${args.line[0]})`
displacement := `Distance(${sp[2]}, ${sp[3]})*${direction}` displacement := `Distance(${sp[2]}, ${sp[3]})*${direction}`
commands.push `${name} = Translate(${sp[1]}, ${displacement})` commands.push `${name} = Translate(${sp[1]}, ${displacement})`
@ -410,21 +445,27 @@ classHandler: Record<JoyceClass, ClassHandler> :=
unless args.subpoints then return unless args.subpoints then return
commands.push `${name} = ${args.subpoints[0]}` commands.push `${name} = ${args.subpoints[0]}`
/fixed|free/ /fixed|free/
commands.push `${name} = (${args.scalar?.join ','})` coords := args.scalar
unless coords then return
commands.push `${name} = (${coords.join ','})`
if method is 'fixed' if method is 'fixed'
callbacks.push (api: AppletObject) => api.setFixed name, true callbacks.push (api: AppletObject) => api.setFixed name, true
'foot' 'foot'
pt := args.subpoints pt := args.subpoints
unless pt then return unless pt then return
destination := args.plane
? args.plane[0]
: `Line(${pt[1]},${pt[2]})`
commands.push commands.push
`${name} = ClosestPoint(Line(${pt[1]},${pt[2]}), ${pt[0]})` `${name} = ClosestPoint(${destination}, ${pt[0]})`
'intersection' 'intersection'
// Checking Joyce source, means intersection of lines, not // Checking Joyce source, means intersection of lines, not
// intersection of line segments // intersection of line segments
unless args.subpoints then return pt := args.subpoints
l1 := `Line(${args.subpoints[0]},${args.subpoints[1]})` unless pt then return
l2 := `Line(${args.subpoints[2]},${args.subpoints[3]})` l1 := `Line(${pt[0]},${pt[1]})`
commands.push `${name} = Intersect(${l1},${l2})` e2 := args.plane ? args.plane[0] : `Line(${pt[2]},${pt[3]})`
commands.push `${name} = Intersect(${l1},${e2})`
'last' 'last'
unless args.subpoints then return unless args.subpoints then return
commands.push `${name} = ${args.subpoints.at(-1)}` commands.push `${name} = ${args.subpoints.at(-1)}`
@ -590,14 +631,61 @@ classHandler: Record<JoyceClass, ClassHandler> :=
// https://www.reddit.com/r/geogebra/comments/12cbr85/setlineopacity_command/ // https://www.reddit.com/r/geogebra/comments/12cbr85/setlineopacity_command/
// I don't really understand how/why it works, but it seems to // I don't really understand how/why it works, but it seems to
// So that's good enough for me // So that's good enough for me
xml := api.getXML name xml .= api.getXML name
xml.replace(/opacity="\d+"/, 'opacity="0"') xml = xml.replace /opacity="\d+"/, 'opacity="0"'
api.evalXML(xml) api.evalXML xml
// This last step is especially confusing... I think // This last step is especially confusing... I think
// evaluating the modified XML created a sort of second // evaluating the modified XML created a sort of second
// copy of the entity, and so we have to hide the original one // copy of the entity, and so we have to hide the original one
api.setVisible name, false api.setVisible name, false
plane: (name, method, args) => freshCommander() plane: (name, method, args) =>
return := freshCommander()
{commands, callbacks, parts, auxiliaries} := return.value
parts[2].push name
switch method
'3points'
unless args.subpoints?.length is 3 then return
commands.push `${name} = Plane(${args.subpoints.join ','})`
'perpendicular'
unless args.subpoints?.length is 2 then return
[thru, perp] := args.subpoints
commands.push
`${name} = PerpendicularPlane(${thru}, Line(${thru}, ${perp}))`
sphere: (name, method, args) => freshCommander() sphere: (name, method, args) => freshCommander()
polyhedron: (name, method, args) => freshCommander()
polyhedron: (name, method, args, index) =>
return := freshCommander()
return.value.ends = ['', '']
{commands, callbacks, parts, auxiliaries, ends} := return.value
aux := name + 'aUx'
switch method
'tetrahedron'
pt := args.subpoints
unless pt and pt.length is 4 then return
commands.push '' // hack, make sure there is a command
parts[0].push ...pt
ends[0] = aux + 1
ends[1] = pt[3]
callbacks.push (api: AppletObject, moreParts: DimParts) =>
madeBase := api.evalCommandGetLabels
`${ends[0]} = Polygon(${pt[0]},${pt[1]},${pt[2]})`
if not madeBase return
for each obj of madeBase.split ','
if obj is ends[0] continue
newObj := 'GeoAux' + index + obj
api.renameObject obj, newObj
moreParts[1].push newObj
made := api.evalCommandGetLabels
`${name} = Pyramid(${aux}1, ${pt[3]})`
if not made return
for each obj of made.split ','
if obj is name continue
newObj := 'GeoAux' + index + obj
api.renameObject obj, newObj
switch api.getObjectType newObj
'segment'
moreParts[1].push newObj
'triangle'
moreParts[2].push newObj

View File

@ -1,4 +1,4 @@
export const flags = ['color', 'commands', 'showall'] as const export const flags = ['color', 'commands', 'showall', 'showaux'] as const
export type FlagType = (typeof flags)[number] export type FlagType = (typeof flags)[number]
export type ConfigType = Partial<Record<FlagType, boolean>> export type ConfigType = Partial<Record<FlagType, boolean>>
@ -23,3 +23,9 @@ export function params(kids: HTMLCollection): Record<string, string>
value := kid.getAttribute 'value' value := kid.getAttribute 'value'
unless name and value then continue unless name and value then continue
return.value[name] = value return.value[name] = value
prim3d := /polyhedron|sphere|plane|face/
export function contains3d(params: Record<string, string>): boolean
for value of Object.values(params)
if prim3d.test(value) then return true
return false