Skip to content

Commit

Permalink
add
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexGyver committed Sep 24, 2024
1 parent c1d0bf8 commit 3f2687b
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 0 deletions.
15 changes: 15 additions & 0 deletions BallClockGen.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BallClock Gen v1.0.0</title>

<script defer>(()=>{"use strict";class t{constructor(e,a={}){a.context=this,this.$root=t.make(e,a)}static make(e,a={}){return e&&"object"==typeof a?a instanceof Node?a:t.config(document.createElement(e),a):null}static makeShadow(e,a={},n=null){if(!e||"object"!=typeof a)return null;let l=e instanceof Node?e:document.createElement(e);return l.attachShadow({mode:"open"}),t.config(l.shadowRoot,{context:a.context,children:[{tag:"style",textContent:n??""},a.child??{},...a.children??[]]}),delete a.children,delete a.child,t.config(l,a),l}static config(e,a){if(!(e instanceof Node)||"object"!=typeof a)return e;const n=a.context;let l=a=>{if(a)if(a instanceof Node)e.appendChild(a);else if(a instanceof t)e.appendChild(a.$root);else if("object"==typeof a){a.context||(a.context=n);let l=t.make(a.tag,a);l&&e.appendChild(l)}else"string"==typeof a&&(e.innerHTML+=a)};for(const[t,r]of Object.entries(a))if(r)switch(t){case"tag":case"context":continue;case"text":e.textContent=r;break;case"html":e.innerHTML=r;break;case"class":e.classList.add(...r.split(" "));break;case"also":n&&r.call(n,e);break;case"export":r[0]=e;break;case"var":n&&(n["$"+r]=e);break;case"events":for(let t in r)r[t]&&e.addEventListener(t,r[t].bind(n));break;case"parent":(r instanceof Node||r instanceof DocumentFragment)&&r.append(e);break;case"attrs":for(let t in r)e.setAttribute(t,r[t]);break;case"props":for(let t in r)e[t]=r[t];break;case"child":l(r);break;case"children":for(const t of r)l(t);break;case"style":if("string"==typeof r)e.style.cssText+=r+";";else for(let t in r)e.style[t]=r[t];break;default:e[t]=r}return e}static makeArray(e){return e&&Array.isArray(e)?e.map((e=>t.make(e.tag,e))):[]}}new Set,new Map;class e{_data;constructor(t){this._data=t}get label(){return this._data.$label.innerText}set label(t){return this._data.$label.innerText=t+""}get value(){return this._data.$control.value}set value(t){return this._data.$control.value=t+""}get input(){return this._data.$control}display(t){this._data.$container.style.display=t?"block":"none"}show(){this.display(1)}hide(){this.display(0)}remove(){this._data.$container.remove()}default(){this.value=this._data.default+"",this._data.$output&&(this._data.$output.innerText=this._data.default+"")}}class a extends e{constructor(t){super(t)}set value(t){return this._data.$control.value=t+""}get value(){return Number(this._data.$control.value)}}class n extends e{constructor(t){super(t)}get value(){return this._data.$control.checked}set value(t){return this._data.$control.checked=t}}class l extends e{constructor(t){super(t)}get value(){return this._data.$control.innerHTML}set value(t){return this._data.$control.innerHTML=t+""}}class r extends e{constructor(t){super(t)}get value(){return this._data.$control.files[0]}set value(t){}}class o extends e{constructor(t){super(t)}set value(t){}get value(){return 1}}class s extends a{constructor(t){super(t)}set options(e){return this._data.$control.replaceChildren(...e.map(((e,a)=>t.make("option",{text:e,value:a+""}))))}}class i extends e{constructor(t){super(t)}set value(t){this._data.$control.innerText=t+""}get value(){return this._data.$control.innerText}}class c{constructor(t={}){return this.init(t)}init(e){return e&&"object"==typeof e?(this.autoVar=e.autoVar??!0,t.make("div",{class:"ui_main theme-"+(e.theme??"light"),style:{zIndex:e.zIndex??3,left:e.x??0,top:e.y??0,width:e.width?"string"==typeof e.width?e.width:e.width+"px":"200px",position:e.parent?"":"absolute"},parent:e.parent??document.body,children:[{tag:"div",class:"ui_title_bar",text:e.title??"UI"},{tag:"div",class:"ui_content",var:"content"}],var:"root",context:this}),this):this}setTheme(t){return this.$root.classList="ui_main theme-"+t,this}destroy(){this.$root&&(this.$root.remove(),this.$root=void 0,this.#t=new Map)}setLabels(t){for(let e in t)this.#t.has(e)&&(this.#t.get(e).label=t[e])}toObject(){let t={};return this.#t.forEach(((e,a)=>{!e.value||e instanceof o||(t[a]=e.value)})),t}toJson(){return JSON.stringify(this.toObject())}fromObject(t){for(let e in t)this.#t.has(e)&&(this.#t.get(e).value=t[e])}fromJson(t){this.fromObject(JSON.parse(t))}control(t){return this.#t.get(t)}get(t){if(this.#t.has(t))return this.#t.get(t).value}set(t,e){if(this.#t.has(t))return this.#t.get(t).value=e}remove(t){this.#t.has(t)&&(this.#t.get(t).remove(),this.#t.delete(t))}addSwitch(e,a,l,r){let o={default:l=l??!1};return t.make("div",{context:o,var:"container",class:"ui_container",parent:this.$content,children:[{tag:"label",class:"ui_checkbox_label",text:a,var:"label"},{tag:"label",class:"ui_checkbox",children:[{tag:"input",type:"checkbox",checked:l,var:"control",also(t){r&&t.addEventListener("click",(()=>r(t.checked)))}},{tag:"span"}]}]}),e&&this.#t.set(e,new n(o)),this._addSetGet(e),this}addNumber(e,n,l,r,o){l=l??0;let s=this._makeContainer(n);return s.default=l,t.make("input",{parent:s.$container,context:s,type:"number",class:"ui_text_input ui_number",step:(r??1)+"",value:l+"",var:"control",also(t){t.addEventListener("input",(()=>{o&&o(Number(t.value))})),t.addEventListener("mousewheel",(t=>{}))}}),e&&this.#t.set(e,new a(s)),this._addSetGet(e),this}addText(a,n,l,r){l=l??"";let o=this._makeContainer(n);return o.default=l,t.make("input",{parent:o.$container,context:o,type:"text",class:"ui_text_input",value:l+"",var:"control",also(t){r&&t.addEventListener("input",(()=>r(t.value)))}}),a&&this.#t.set(a,new e(o)),this._addSetGet(a),this}addRange(e,n,l,r,o,s,i){l=l??0;let c=this._makeContainerOut(n,l);return c.default=l,t.make("input",{parent:c.$container,context:c,type:"range",class:"ui_range",value:l+"",min:(r??0)+"",max:(o??100)+"",step:(s??1)+"",var:"control",also(t){t.addEventListener("input",(()=>{i&&i(Number(t.value)),c.$output.innerText=t.value})),t.addEventListener("mousewheel",(e=>{e.stopPropagation(),e.preventDefault(),t.value=Number(t.value)+Number(t.step)*(e.deltaY>0?-1:1),t.dispatchEvent(new Event("input"))}))}}),e&&this.#t.set(e,new a(c)),this._addSetGet(e),this}addArea(a,n,l,r){l=l??"";let o=this._makeContainer(n);return o.default=l,t.make("textarea",{parent:o.$container,context:o,class:"ui_textarea",rows:5,value:l+"",var:"control",also(t){r&&t.addEventListener("input",(()=>r(t.value)))}}),a&&this.#t.set(a,new e(o)),this._addSetGet(a),this}addHTML(e,a,n){n=n??"";let r=this._makeContainer(a);return r.default=n,t.make("div",{parent:r.$container,context:r,html:n+"",var:"control"}),e&&this.#t.set(e,new l(r)),this._addSetGet(e),this}addElement(t,e,a){let n=this._makeContainer(e);return n.default=a,n.$control=a,n.$container.append(a),t&&this.#t.set(t,new l(n)),this._addSetGet(t),this}addSelect(e,a,n,l){n=n??[];let r=this._makeContainer(a);return r.default=0,t.make("select",{parent:r.$container,context:r,class:"ui_select",var:"control",also(t){l&&t.addEventListener("change",(()=>l(Number(t.value))))},children:n.map(((e,a)=>t.make("option",{text:e,value:a+""})))}),e&&this.#t.set(e,new s(r)),this._addSetGet(e),this}addButton(e,a,n){let l={};return t.make("div",{context:l,var:"container",class:"ui_container",parent:this.$content,children:[this._makeButton(l,e,a,n)]}),l.$label=l.$control,e&&this.#t.set(e,new o(l)),this}addButtons(e){let a=t.make("div",{var:"container",class:"ui_container",parent:this.$content});for(let t in e){let n={$container:a};a.append(this._makeButton(n,t,e[t][0],e[t][1])),n.$label=n.$control,t&&this.#t.set(t,new o(n))}return this}addFile(e,a,n){let l=this._makeContainer(a),o=t=>{n&&n(1==t.length?t[0]:t),l.$filename.innerText=t[0].name};return l.$container.append(...t.makeArray([{tag:"input",context:l,class:"ui_file_chooser",type:"file",var:"control",attrs:{multiple:!0},also(t){t.addEventListener("change",(()=>o(t.files)))}},{tag:"label",context:l,class:"ui_file_chooser_label",text:"...",var:"filename",also(t){t.addEventListener("click",(()=>l.$control.click())),t.addEventListener("drop",(t=>o(t.dataTransfer.files)))}}])),e&&this.#t.set(e,new r(l)),["dragenter","dragover","dragleave","drop"].forEach((t=>{this.$root.addEventListener(t,(t=>{t.preventDefault(),t.stopPropagation()}),!1)})),["dragenter","dragover"].forEach((t=>{this.$root.addEventListener(t,(function(){l.$filename.classList.add("active")}),!1)})),["dragleave","drop"].forEach((t=>{this.$root.addEventListener(t,(function(){l.$filename.classList.remove("active")}),!1)})),this._addSetGet(e),this}addColor(e,n,l,r){l=l??"#000";let o=this._makeContainerOut(n,l);return o.default=l,o.$container.append(t.make("input",{context:o,type:"color",class:"ui_color",value:l,var:"control",attrs:{"colorpick-eyedropper-active":!1},also(t){t.addEventListener("input",(()=>{r&&r(t.value),o.$output.innerText=t.value}))}})),e&&this.#t.set(e,new a(o)),this._addSetGet(e),this}addLabel(t,e,a){a=a??"";let n=this._makeContainerOut(e,a);return n.$control=n.$output,t&&this.#t.set(t,new i(n)),this._addSetGet(t),this}_addSetGet(t){this.autoVar&&t&&Object.defineProperty(this,t,{get:()=>this.get(t),set:e=>this.set(t,e)})}_checkID(t){return t||"_empty_"+this.#e++}_makeButton(e,a,n,l){return t.make("button",{context:e,class:"ui_button",var:"control",text:n+"",also(t){l&&t.addEventListener("click",(()=>l(1)))}})}_makeContainer(e){let a={};return t.make("div",{context:a,var:"container",class:"ui_container",parent:this.$content,children:[{tag:"div",class:"ui_label",children:[{tag:"b",var:"label",text:e}]}]}),a}_makeContainerOut(e,a){let n={};return t.make("div",{context:n,var:"container",class:"ui_container",parent:this.$content,children:[{tag:"div",class:"ui_label",children:[{tag:"b",text:e,var:"label"},{tag:"span",text:": "},{tag:"span",text:a+"",var:"output"}]}]}),n}#t=new Map;#e=0}let d,u,h;const _=72/25.3999;function p(){function t(t){return t*_}function e(e,a,n){u.beginPath(),u.arc(t(e),t(a),t(n),0,2*Math.PI),u.stroke()}function a(e,a){u.lineTo(t(e),t(a))}function n(e,a){u.lineTo(t(e),t(a))}function l(t,e,l,r){u.beginPath(),n(t,e),a(l,r),u.stroke()}function r(t,e,a,n){return a-=t,n-=e,Math.sqrt(a*a+n*n).toFixed(1)}const o=Math.sqrt(3),s=o/2,i=h.ball_d/2/s,c=h.ball_d*h.balls_w+2*(i-h.ball_d/2)+10,p=h.ball_d*(2*h.balls_h*s+1)+10;d.width=t(c),d.height=t(p),u.lineWidth=t(h.stroke_w),u.fillStyle="white",u.fillRect(0,0,d.width,d.height),u.fillStyle="black",u.strokeStyle="black",u.strokeRect(0,0,d.width,d.height);for(let t=0;t<h.balls_h+1;t++)for(let a=-1;a<2;a+=2){for(let n=0;n<h.balls_w-t;n++)e(5+i+h.ball_d*n+t*h.ball_d/2,p/2+t*h.ball_d/2*o*a,h.ball_d/2);if(!t)break}const b=(h.ball_d/2+h.ball_d*h.balls_h*s)*o/3;u.beginPath(),n(5,p/2),a(5+b,5),a(c-(5+b),5),a(c-5,p/2),a(c-(5+b),p-5),a(5+b,p-5),a(5,p/2),u.stroke(),u.font=`${t(5)}px Arial`;let f=0;const v=t(6);u.fillText("Это задняя сторона!",10,f+=v),u.fillText("Ball D = "+h.ball_d,10,f+=v),u.fillText("LED step = "+h.led_step,10,f+=v),u.fillText(`Рейка ${r(5+b,5,c-(5+b),5)}мм х2`,10,f+=v),u.fillText(`Рейка ${r(5,p/2,5+b,5)}мм х4`,10,f+=v),u.fillText("Это верх часов",10,t(p-5));let m=5+i-h.ball_d/4,x=0,k=!(h.balls_h%2),g=0,$=1,w=0,y=0,L=[];function M(a,n){let r=p/2-n*h.led_step*$;for(let o=0;o<2*n+1;o++){let c=r+o*h.led_step*$;e(a,c,5);const d=3;l(a-d,c,a+d,c),l(a,c-d,a,c+d),u.textAlign="center",u.textBaseline="middle";let _=5+i+Math.floor((a-5)/h.ball_d)*h.ball_d-Math.abs((o-n)%2)*h.ball_d/2,p=5+h.ball_d/2+Math.floor((c-5)/(h.ball_d*s))*(h.ball_d*s);u.fillText(g,t(_),t(p));let b=Math.round((_-5-i)/(h.ball_d/2)),f=Math.round((p-5-h.ball_d/2)/(h.ball_d*s/2));L.push([b,f]),w&&y&&(u.lineWidth=t(h.stroke_w/2),l(w,y,a,c),u.lineWidth=t(h.stroke_w)),w=a,y=c,g++}$=-$}for(let t=0;t<h.balls_w;t++)M(m,x),t<Math.ceil((h.balls_h+1)/2)&&(x+=2,x>h.balls_h&&(x=h.balls_h)),t>=h.balls_w-Math.ceil((h.balls_h+1)/2)&&(k?(k=!1,x-=1):x-=2),m+=h.ball_d;function E(t,e){for(let a=0;a<L.length;a++)if(L[a][0]==t&&L[a][1]==e)return a;return-1}const T=2*h.balls_w-1,C=2*(2*h.balls_h+1)-1,S=h.balls_w,N=2*h.balls_h+1;let G="// BallClock Generator\r\n";G+=`#define MX_LED_AMOUNT ${L.length}\r\n`,G+=`#define MX_XY_W ${T}\r\n`,G+=`#define MX_XY_H ${C}\r\n`,G+=`#define MX_DIAG_W ${S}\r\n`,G+=`#define MX_DIAG_H ${N}\r\n`,G+="\r\n\r\n",G+="// BallClock Generator\r\n",G+="static const uint8_t xyToLed[MX_DIAG_H][MX_XY_W] = {\r\n";for(let t=C-1;t>=0;t--)if(!(t%2)){G+="\t{";for(let e=0;e<T;e++){let a=E(e,t);G+=a>=0?a+1:0,e!=T-1&&(G+=", ")}G+="},\r\n"}G+="};\r\n\r\n",G+="static const uint8_t diagToLed[MX_DIAG_H][MX_DIAG_W] = {\r\n";for(let t=N-1;t>=0;t--){G+="\t{";for(let e=0;e<S;e++){let a=5+i+h.balls_h/2*h.ball_d+e*h.ball_d-(N-1-t)*h.ball_d/2,n=5+h.ball_d/2+t*h.ball_d*s,l=E(Math.round((a-5-i)/(h.ball_d/2)),Math.round((n-5-h.ball_d/2)/(h.ball_d*s/2)));G+=l>=0?l+1:0,e!=S-1&&(G+=", ")}G+="},\r\n"}G+="};\r\n",h.code=G}function b(){let t=document.createElement("a");t.href=d.toDataURL("image/png"),t.download="BallClock.png",t.click()}function f(){navigator.clipboard.writeText(h.code)}document.addEventListener("DOMContentLoaded",(()=>{d=document.getElementById("canvas"),u=d.getContext("2d"),h=new c({title:"BallClock",theme:"light"}).addHTML("","","Стандартный размер - 20x3 (20x7 реальный)").addNumber("balls_w","Ширина (шаров)",20,1,p).addNumber("balls_h","Высота x2 + 1 (шаров)",3,1,p).addNumber("ball_d","Диаметр шара (мм)",39.9,.05,p).addNumber("led_step","Шаг светодиодов (мм)",33.15,.05,p).addNumber("stroke_w","Толщина линий (мм)",.4,.05,p).addArea("code","Code","").addButtons({copy:["Copy",f],save:["PNG",b]}),p()}))})();</script><style type="text/css">.ui_main.theme-light{--border:#aaa;--back:#fff;--mid:#ccc;--bright:#eee;--font:#000;--font-mid:#555}.ui_main.theme-dark{--border:#444c56;--back:#1e232a;--mid:#22272e;--bright:#2d333b;--font:#ccc;--font-mid:#999}.ui_main{background-color:var(--mid);border:none;box-shadow:5px 5px 8px rgba(0,0,0,.35);font:12px sans-serif;text-align:left;user-select:none;-webkit-user-select:none}.ui_content{background:var(--mid);overflow-y:auto}.ui_title_bar{font-weight:700;user-select:none;-webkit-user-select:none}.ui_container,.ui_title_bar{background:var(--bright);border:none;color:var(--font);padding:5px}.ui_container{margin:5px;position:relative}.ui_range{-webkit-appearance:none;-moz-appearance:none;background-color:transparent;border:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;height:17px;margin:0;padding:0;width:100%}.ui_range:focus{border:none;outline:none}.ui_range::-webkit-slider-runnable-track{background:var(--back);-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;cursor:pointer;height:15px;width:100%}.ui_range:focus::-webkit-slider-runnable-track{background:var(--back)}.ui_range::-webkit-slider-thumb{-webkit-appearance:none;background:var(--border);-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;cursor:pointer;height:15px;margin-top:0;width:15px}.ui_range::-moz-range-track{background:var(--back);-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;cursor:pointer;height:15px;width:100%}.ui_range::-moz-range-thumb{background:var(--border);border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;cursor:pointer;height:15px;width:15px}.ui_button{background:var(--mid);border:1px solid var(--border);color:var(--font-mid);cursor:pointer;font:12px sans-serif;height:26px;margin:2px}.ui_button:active{background:var(--back)}.ui_checkbox{cursor:pointer;display:inline}.ui_checkbox input{left:-99999px;position:absolute}.ui_checkbox span{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAALklEQVQ4T2OcOXPmfwYKACPIgLS0NLKMmDVrFsOoAaNhMJoOGBioFwZkZUWoJgApdFaxjUM1YwAAAABJRU5ErkJggg==) no-repeat;display:block;height:16px;text-indent:20px;width:100%}.ui_checkbox input:checked+span{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAvElEQVQ4T63Tyw2EIBAA0OFKBxBL40wDRovAUACcKc1IB1zZDAkG18GYZTmSmafzgTnnMgwchoDWGlJKheGcP3JtnPceCqCUAmttSZznuYtgchsXQrgC+77DNE0kUpPbmBOoJaBOIVQylnqWgAAeKhDve/AN+EaklJBzhhgjWRoJVGTbNjiOowAIret6a+4jYIwpX8aDwLIs74C2D0IIYIyVP6Gm898m9kbVm85ljHUTf16k4VUefkwDrxk+zoUEwCt0GbUAAAAASUVORK5CYII=) no-repeat}.ui_checkbox_label{left:30px;pointer-events:none;position:absolute;top:7px}.ui_label{cursor:default;font:12px sans-serif;margin-bottom:3px;user-select:none;-webkit-user-select:none}.ui_text_input{border:1px inset var(--border);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;font-size:12px;outline:none;padding:0 0 0 5px}.ui_select,.ui_text_input{background:var(--back);color:var(--font-mid);height:24px;width:100%}.ui_select{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:1px solid var(--border);-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;cursor:pointer;-moz-outline:none;padding:0 5px}.ui_select,.ui_select option{font-size:14px}.ui_select:focus{outline:none}.ui_number{height:24px}.ui_textarea{background:var(--back);border:1px inset var(--border);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;color:var(--font-mid);font-size:12px;outline:none;padding:3px 5px;resize:vertical;width:100%}.ui_textarea::-webkit-scrollbar{height:7px;width:7px}.ui_textarea::-webkit-scrollbar-track{background:none}.ui_textarea::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}.ui_color{background:none;border:none;cursor:pointer;height:30px;margin:0;outline:none;padding:0;width:100%}.ui_file_chooser{left:-999999px;position:absolute}.ui_file_chooser_label{background:var(--back);border:1px solid var(--border);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;color:var(--font);cursor:pointer;display:block;font:12px sans-serif;height:30px;overflow:hidden;padding:7px;text-overflow:ellipsis;white-space:nowrap;width:100%}.ui_file_chooser_label.active{border:2px solid var(--font)}body,html{height:100%;margin:0;padding:0;width:100%}.cv_cont{padding-left:230px;padding-right:30px;padding-top:30px}#canvas{width:100%}</style></head>

<body>
<div class="cv_cont"><canvas id="canvas"></canvas></div>
</body>

</html>
Binary file added fusion/BallClock v30.f3d
Binary file not shown.

0 comments on commit 3f2687b

Please sign in to comment.