Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html>
- <head>
- <meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>CAP</title>
- <style>
- body{
- margin:0;
- padding:0;
- }
- #toolbox{
- position:fixed;
- margin:0;
- padding:7px;
- left:0;
- right:0;
- background-color:#aaccff;
- }
- canvas{
- position:absolute;
- top:0;
- left:0;
- border:2px solid black;
- }
- dot{
- position:absolute;
- width:10px;
- height:10px;
- margin-left:-5px;
- margin-top:-5px;
- z-index:99999;
- background-color:black;
- opacity:0.25;
- border-radius:15px;
- }
- dot.slct{
- background-color:#c000c0;
- }
- dot:hover, dot.slct:hover, dot.hovr{
- background-color:#00ff10;
- }
- #dtbx{
- position:absolute;
- left:5px;
- padding:0;
- }
- #dbx2{
- position:fixed;
- padding:5pt;
- }
- button.slct{
- border-style:inset;
- }
- #toolbox button{
- font-size:12pt;
- border: 1px solid #d0d0d0;
- }
- #toolbox button.slct{
- border:2px solid black;
- }
- #toolbox button:hover{
- background-color:#808080;
- }
- button c{
- display: inline-block;
- position: relative;
- top: 2px;
- width:20px;
- height:11px;
- background-color:black;
- }
- #sWdh{
- position:fixed;
- top:50px;
- left:50%;
- width:300px;
- height:100px;
- background-color:white;
- border:2px solid black;
- padding:5px;
- margin-left:-205px;
- }
- dot div{
- top:5px;left:5px;width:0;height:0;margin:0;position:absolute;z-index:-200;
- }
- dot div div{
- margin:-2px 0px 0px;height:4px;background-color:black;top:0;left:0;z-index:-20;pointer-events:none;
- }
- #ctx_mnu{
- background-color: white;
- border: 1px solid grey;
- z-index: 9999999;
- position: fixed;
- margin: 3px;
- padding: 7px;
- }
- #ctx_mnu button {
- border: none;
- border-bottom: 1px solid gray;
- background-color: inherit;
- flex-wrap: wrap;
- flex-direction: column;
- display: block;
- width: 100%;
- text-align: left;
- padding: 3px;
- }
- #ctx_mnu button:hover {
- background-color: #3072FF;
- color:white;
- }
- #fib_1{
- position:fixed;
- z-index:9999999;
- padding:10px;
- margin-left:-150px;
- top:150px;
- left:50%;
- width:300px;
- height:150px;
- border:; 2px solid black;
- background-color:white;
- }
- .hid{
- display:none;
- }
- button.tlsy{
- width: 145pt;
- }
- </style>
- </head>
- <body>
- <script type="text/javascript" src="https://docs.google.com/uc?id=0Bxb5iFgmM3V6eTRINGZ0Zm1zMkk"></script>
- <div id="toolbox">
- Edit Mode:
- <select id="emod" title="Select an Edit Mode">
- <option value="draw">Draw</option>
- <option value="ani">Animate</option>
- <option value="vid">Video edit</option>
- </select>
- <!-- modified change box (cbx) span with a different span for each mode -->
- <span id="cbx">
- <span id="draw_mod">
- Line Cap Style: <select title="Select a Line Cap Style"><option value="butt">flat</option><option value="round">round</option><option value="square">square</option></select>
- Line Join Style: <select title="Select a Line Join Style (very most corner)"><option value="miter">sharp</option><option value="bevel">flat</option><option value="round">round</option></select>
- Shape Fill Style: <select title="Select a shape fill-in style"><option value="none">none (no fill)</option><option value="color">solid color</option><option value="gradient">gradient</option><option value="pattern">pattern</option></select>
- <button class="tlsy">
- <span name="none">---</span>
- <span name="color" class="hid">choose a color <c></c></span>
- <span name="gradient" class="hid">configure a gradient</span>
- <span name="pattern" class="hid">choose a pattern</span>
- </button>
- Line Style: <select title="Select a Line Style"><option value="color">solid color</option><option value="gradient">gradient</option><option value="pattern">pattern</option></select>
- <button class="tlsy">
- <span name="color">choose a color <c></c></span>
- <span name="gradient" class="hid">configure a gradient</span>
- <span name="pattern" class="hid">choose a pattern</span>
- </button>
- <button title="Set Line width">Line Width</button>
- <!-- paintbrush 🖌 -->
- <span name="atool">
- Shape/Draw tools:
- <button name="line" title="line"> \ </button>
- <button name="bezi" title="bezier curve"> S </button>
- <button name="arc" title="arc">◝</button>
- <button name="elps" title="ellipse / circle">◯</button>
- <button name="rect" title="rectangle">▭</button>
- <button name="trig" title="triangle">△</button>
- <button name="poly" title="polygon" disabled>\_/|_\</button>
- <button name="fill" title="fill (with solid color)" disabled><sub>💧</sub>🔿</button>
- <button name="n0t" class="slct">nothing</button>
- </span>
- </span>
- <span id="vid_mod" class="hid">
- <button title="Add (load) new video source file">+ New Vid Src</button>
- </span>
- <span id="ani_mod" class="hid">
- </span>
- </span>
- </div>
- <div id="dbx2">
- <div id="dtbx">
- <canvas id="Canvas1" width="800" height="500"></canvas>
- <canvas id="CnvsTop" width="800" height="500"></canvas>
- </div>
- </div>
- <div id="sWdh" class="hid">
- Adjust slider or type # of pixels:<input type="range"><input type="number"><button >Done</button>
- </div>
- <div id="ctx_mnu" class="hid">
- <button>Copy (Ctrl+C)</button>
- <button>Cut (Ctrl+X)</button>
- <button>Paste (Ctrl+V)</button>
- <button title="Delete Selected" >Delete (Ctrl+D)</button>
- <button title="Merge Stacked dots at clicked location" >Merge (Ctrl+M)</button>
- <button title="Show the real Context (right click) Menu" >Real ContextMenu</button>
- </div>
- <div id="fib_1" class="hid">
- <button title="upload a file from your computer" >Upload file</button>
- or enter url below:<br>
- <input><button title="Load the URL typed in the input box" >Load URL</button>
- </div>
- <script type="text/javascript">
- /*
- note, for all triginometric systems, be sure to correct cos error with: ang=+(xi<0?Math.PI:0);
- xo=cos(ang)*r, yo=sin(ang)*r;
- where "xi" is x-input, "ang" is angle mesure, "r" is radius, "xo" is x-output, "yo" is y-output;
- when addition or subtraction is performed on ang (theta) with another cartiesian originating angle measure ("ang2"), use this
- ang+ang2+(((xi<0)^(xi2<0))?Math.PI:0);
- where xi2 is the source x input of ang2. "^" is the javascript binary XOR, you know
- NOTE: Math.arctan2(x,y) automatically corrects this
- */
- HTMLCollection.prototype.forEach=Array.prototype.forEach;// << temp
- var d=document,cE="createElement",aC="appendChild",cTN="createTextNode",cN="cloneNode",gI="getElementById",gT="getElementsByTagName",qS="querySelector",qSA="querySelectorAll",aEL="addEventListener",
- frms_sec,res=[800,500],
- tlbx=d[gI]("toolbox"),dtbx=d[gI]("dtbx"), //dtbx= dot-box (for click point circles)
- Canvs1=d[gI]("Canvas1"),ctx=Canvs1.getContext('2d'),
- Cnvs2=d[gI]("CnvsTop"),ctx2=Cnvs2.getContext('2d'),
- IDB=ctx.createImageData(800,500), //rgba
- tIDB=ctx.createImageData(800,500), //tmp
- ldfrm=function(){
- ctx.putImageData(IDB,0,0);
- },
- Dps=function(x,y){ //Determine? PoSition (in ImageData.data array)
- if(x>res[0]||x<0||y>res[1]||y<1) return -1;
- y=res[1]-y;
- return ((y*res[0])+x)*4;
- },
- dTPM=function(){
- var i=0;
- while(i<IDB.data.length){
- if(tIDB.data[i]>0){
- IDB.data[i]=tIDB.data[i];
- tIDB.data[i]=0;
- }
- i++;
- }},
- pxC=function(D,b,c){ //set a pixel value (c) in an image data object (D) at data array index (b)
- if(b+1&&b<D.data.length){D.data[b]=c[0];
- D.data[b+1]=c[1];
- D.data[b+2]=c[2];
- D.data[b+3]=c[3];}
- },
- VGBI2=(function(){
- var pt="prototype",is_=function VectorGraphicBoxInstance2D(w,h,cs,shp){//use this to create 2D boxes for orientations of segments of animatable characters; cs=centers (joints/attach points); shp=all the lines and curves; later, make function to average several boxes together: seemingly differant shapes and centers, properties of different VGBI2s, with the same name where the said VGBI2s are part of the same VGBI3: the shapes are actually the same shapes seen from differant angles
- var rt={'constructor':is_,'__proto__':is_p,'width':w||is_p.width,'height':h||is_p.height,'centers':cs||[],'shapes':shp||{}};
- return rt;},
- is_p=is_[pt]?is_[pt]:{};
- Object.assign(is_p,{"width":0,"height":0,"centers":[],"shapes":{}});
- return is_;}()),
- VGBI3=(function(){
- var pt="prototype",get2Pweight=function(ar,ro){
- var gots=[[361,-1],[361,-1]]; //[lesser angle,greater angle] than ro
- ar.forEach(function(v,i){var dif=Math.abs(i-ro);if(i==ro)gots=[[0,i]];else
- if(i>ro&&dif<gots[1][0])gots[1]=[dif,i];else
- if(i<ro&&dif<gots[0][0])gots[0]=[dif,i];});
- var gi_=gots[0][0]+gots[1][0];
- gots[0][2]=gi_/gots[0][0];//get weight (multiply each value by its weight, add weights & put in denominator);
- gots[1][2]=gi_/gots[1][0];
- return gots;},
- is_=function VectorGraphicBoxInstance3D(arg/*arg=xr[yr[zr]] is a 3d array of all x-rotations (available viewing angles used to compute 3d apperance), containing all y rotations containing all z rotations*/){
- var rt={'constructor':is_,'__proto__':is_p,'arg':arg?arg:is_p.arg};
- return rt;}, //14 viewing angle 2D boxes by default (cube); include x & y mirroring functions
- is_p=is_[pt]?is_[pt]:{};
- is_p.arg=[];
- is_p.Get2DBox=function(xr,yr,zr){/*the arguments declare the viewing angle;round to the nearest degree;take averages (usually weighted) of nearest existing 2D boxes of the angle ceilinged and floord on all axies.*/};
- return is_;}()),
- //2020Jun15 edit note: I might not use the VectorGraphicBoxInstance system after all; I might invent a system that uses 3d shapes converted to 2d shapes.
- // new:
- AllShps=[], //all shapes (for save)
- AllVids=[], //all video sources
- xp=0,yp=0,zm=1, //x pan, y pan, zoom (global)
- hPI=Math.PI/2,
- eAePt=function ElementAddEventPassThru(elm,evn,evf,b){
- elm[aEL](evn,evf.bind(elm),b);
- if(!elm["LF_"+evn])elm["LF_"+evn]=[]; //temp debug?
- elm["LF_"+evn].push([evf,b]);
- return elm;
- },
- nwDot=function(p){
- var D=d[cE]("dot");
- if(typeof p=="number")D.p=p;
- dtbx[aC](D);
- return D;
- },
- avgCo=function(ca){//average an array of coordinates
- var i=ca.length,j=i/2,ac0=0,ac1=0;
- while(i-=2){ac0+=ca[i];ac1+=ca[i+1];}
- return [ac0/j,ac1/j];
- },
- PyThg=function(x,y){//pythagorean theorem 2 short sides input
- return Math.sqrt((x*x)+(y*y));
- },
- /*
- Cnv_Coa=function(coa,fC){//convert coordinate array; use the center coordinate given in fC to convert from standard carteseian to HTML5 canvas coordinate values
- var i=coa.length,coa2=[],y;
- while(i--){y=i%2;coa2[i]=fC[y]+((y?-1:1)*(coa[i]+(y?yp:xp)));}//add x, subtract y
- return coa2;
- },
- */
- Clr=function(c,C){ //clear the canvas given by its ctx object (c)
- c.clearRect(0,0,(C=c.canvas).width,C.height);
- },
- P2mO=function(oa,pn,pv){//property to multiple objects
- oa.forEach(function(O){O[pn]=pv;});
- },
- NpGs=function(DO,so,pn,dpn){ //new property get/set (make a new object property (dpn)(destination property name) of destination object (DO) that is a link to another object property (pn) of source object (so)
- var _F=function(v){return v?so[pn]=v:so[pn];};
- Object.defineProperty(DO,dpn||pn,{"get":_F,"set":_F});
- return DO;
- },
- dotSlct=function(shp,slc,v){ //toggle selection of all the dots in a shape (shp)
- v=slc?"slct":"";for(var i=0;i<shp.dots.length;i++)shp.dots[i].className=v;
- },
- $B={"bc":[ctx2,ctx],"ef":function(){},
- //mtf is supposed to be for saving drawing tool options
- "mtf":{"lineWidth":1,"lineCap":"round","lineJoin":"miter","strokeStyle":"#000000","fillStyle":"#000000","doFill":!1},
- "kdc":function(sy){/*keep draw customization (line & fill options etc.)*/Object.assign($B.bc[0],sy);Object.assign($B.bc[1],sy); }
- };
- $B.mtf2=Object.assign({},$B.mtf);//buffer variable (use to store temp data & save html file bytes)
- Object.defineProperties(HTMLCanvasElement.prototype,{
- "cx":{"get":function(){return (this.width/2);}},
- "cy":{"get":function(){return (this.height/2);}}
- });
- var hdAll=function(nL){
- var i=nL.length;
- while(i--)nL[i].className="hid";
- },
- dbx2=d[gI]("dbx2");
- self.onresize=function(){
- var tlbh=tlbx.clientHeight+20,
- wkw=d.body.clientWidth-20,
- wkh=d.documentElement.clientHeight-tlbh-50;
- dbx2.style.top=tlbh+"px";
- dbx2.style.width=wkw+"px";
- dbx2.style.height=wkh+"px";
- };
- var shapD={}; //shape draw
- //main toolbox handler functions
- Object.assign(tlbx,
- {"emod":d[gI]("emod"),"slcT":!1, //slcT = selcted Tool
- "sClr":Object.assign(d[cE]("input"),{"type":"color"}), //color select dialog
- "sWdh":(function(){ //set Width
- var sWdh=d[gI]("sWdh"),n1=sWdh[qS]("input[type=range]"),
- n2=sWdh[qS]("input[type=number]"),
- cls=function(){ sWdh.className="hid"; },
- F=function(n){
- if(!isNaN(n)){ $B.mtf.lineWidth=n;dtbx.slctS?dtbx.slctS.mtf.lineWidth=n:0;}
- };
- n1[aEL]("mousemove",function(){F(n2.value=n1.value/2);});
- n2[aEL]("keyup",function(){var n=n2.value*1;isNaN(n)?0:(n>50?n2.value=(n=50):0)+F(n)+(n1.value=n*2);});
- n1.value=2;n2.value=1;
- sWdh[gT]("button")[0][aEL]("click",cls);
- sWdh[aEL]("mouseleave",cls);
- return sWdh;
- })(),
- "uslo":function(){tlbx.emdT[tlbx.emod.value].cntnr[qS]("[name=atool]").geta("button").forEach(function(b){b.className="";});},//unselect buttons
- "cbx":d[gI]("cbx"),
- "emdT":{ //emod (edit mode) Tools
- "draw":$B.ted={
- "cntnr":$B.dbc=d[gI]("draw_mod"),
- "btns":{
- "lnCpSty":eAePt(($B.dbc_s=$B.dbc[gT]("select"))[0],"change",function(){$B.mtf.lineCap=this.value;dtbx.slctS?dtbx.slctS.mtf.lineCap=this.value:0;}),
- "lnJnSty":eAePt($B.dbc_s[1],"change",function(){$B.mtf.lineJoin=this.value;dtbx.slctS?dtbx.slctS.mtf.lineJoin=this.value:0;}),
- "SpFlSty":eAePt($B.sfc=$B.dbc_s[2],"change",function(){var v=this.value,btn=$B.ted.btns.SpFlBtn;
- hdAll(btn.children);
- if(v=="none"){ $B.mtf.doFill=!1; }else{ $B.mtf.doFill=!0; }
- btn[qS]("[name="+v+"]").className="";
- if(v=="color")btn[gT]("c")[0].backgroundColor=$B.mtf.fillStyle;
- }), //end SpFlSty
- "SpFlBtn":Object.assign(NpGs(eAePt(($B.dbc_b=$B.dbc[gT]("button"))[0],"click",$B.sty_d=function(){
- var v=this.sle.value;
- if(v=="color"){var T=this,C=tlbx.sClr,c=T.geta('c')[0].style,bc='backgroundColor';C.onchange=function(){T.put=(c[bc]=this.value);dtbx.slctS?dtbx.slctS.mtf[T.nm]=T.put:0;};c[bc]=(C.value=$B.mtf[T.nm]);C.click();}
- else if(v=="gradient"){}
- else if(v=="pattern"){}
- }),
- $B.mtf,"fillStyle","put"),{"nm":"fillStyle","sle":$B.sfc}),
- "lnSty":eAePt($B.lsy=$B.dbc_s[3],"change",function(){var v=this.value,btn=$B.ted.btns.lnSyBtn;
- hdAll(btn.children); btn[qS]("[name="+v+"]").className="";
- if(v=="color")btn[gT]("c")[0].backgroundColor=$B.mtf.fillStyle;
- }), //end lnSty
- "lnSyBtn":Object.assign(NpGs(eAePt($B.dbc_b[1],"click",$B.sty_d),
- $B.mtf,"strokeStyle","put"),{"nm":"strokeStyle","sle":$B.lsy}),
- "lnWdh":eAePt($B.dbc_b[2],"click",function(){tlbx.sWdh.className="";}),
- "line":eAePt($B.dbc[qS]("button[name=line]"),"click",function(){tlbx.uslo();tlbx.slcT=$B.ted.line;this.className="slct";}),
- "bezierCurve":eAePt($B.dbc[qS]("button[name=bezi]"),"click",function(){tlbx.uslo();tlbx.slcT=$B.ted.bezierCurve;this.className="slct";}),
- "arc":eAePt($B.dbc[qS]("button[name=arc]"),"click",function(){tlbx.uslo();tlbx.slcT=$B.ted.arc;this.className="slct";}),
- "ellipse":eAePt($B.dbc[qS]("button[name=elps]"),"click",function(){tlbx.uslo();tlbx.slcT=$B.ted.ellipse;this.className="slct";}),
- "rectangle":eAePt($B.dbc[qS]("button[name=rect]"),"click",function(){tlbx.uslo();tlbx.slcT=$B.ted.rectangle;this.className="slct";}),
- "triangle":eAePt($B.dbc[qS]("button[name=trig]"),"click",function(){tlbx.uslo();tlbx.slcT=$B.ted.triangle;this.className="slct";}),
- //polygon
- //fill tool
- "nothing":eAePt($B.dbc[qS]("button[name=n0t]"),"click",function(){tlbx.uslo();tlbx.slcT=!1;this.className="slct";})
- },
- //end buttons, begin shape maker objects with drawer functions
- /*
- 2020Jun30 edit: try to reduce function calls and instances? : => store shape draw instructions as object properties dont forget Cnv_Coa(c0,[Canvs1.cx,Canvs1.cy]) !
- use the number identifier passed to nwDot to determine which c0 (point array) indexes to move and how. Also use the cxf & cmt properties to determine how to draw each shape inside the onmousemove function that draws shapes & also possible onmousedown. ; shapD[shapeInstance.type].cxf; c0 array should always literally be an array of arguments for the ctx shape function minus the 1st two elements if there is moveTo included (cmt==true && not_part_of_complex_path); Cnv_Coa: Oh that is why I didn't make c0 always be an exact list of arguments
- 2020July3 : could just use the shapeObj.type property inside the main shape moving function (where the action happens (all besides creating new shape object instances anyway));
- the main func gets called by any user action event on the canvas area, "if" statements inside the main func decide what should be done in response to the action (like move or rotate shape(s));
- the same main func is used for every? user event handler on the canvas.
- my own efficiency mesure of bezier curve not draw if drawing withing the last 200 milliseconds or something is what caused the flashing bezier curves on zooming and panning the viewport
- */
- "line":shapD.line={"type":"line",
- "cxf":"lineTo",
- "cmt":!0, // <-- cmt == call moveTo for regular
- "nw":function newLine(co){ /*draw new line*/
- var c0=co.length==4?co:co.concat(co),
- D0=nwDot(0),
- D1=(dtbx.slctD=nwDot(2)),
- sho={"type":this.type,"points":c0,"dots":[D0,D1],"mtf":Object.assign({},$B.mtf)}; D1.oS=(D0.oS=sho); AllShps.push(sho); dotSlct(dtbx.slctS=sho);//.oS = owning Shape
- //replace AllShps.push etc with "return sho;" ?
- }
- },
- "bezierCurve":shapD.bezierCurve={"type":"bezierCurve",
- "cxf":"bezierCurveTo",
- "cmt":!0,
- //will need itm?
- "itm":function(){if(this.mmwe){
- //in the middle: (move D1 & D2 when either D0 or D3 moves)
- var ev,ev2,mvD={1:[D0.co[0]-D0.lc[0],D0.co[1]-D0.lc[1]],4:[D3.co[0]-D3.lc[0],D3.co[1]-D3.lc[1]]},
- oc=[(D0.lc[0]+D3.lc[0])/2,(D0.lc[1]+D3.lc[1])/2], oma=Math.atan2((D3.lc[1]-D0.lc[1]),(D3.lc[0]-D0.lc[0])),
- nc=[(D0.co[0]+D3.co[0])/2,(D0.co[1]+D3.co[1])/2], or=PyThg(D0.lc[0]-oc[0],D0.lc[1]-oc[1]), nr=PyThg(D0.co[0]-nc[0],D0.co[1]-nc[1]), rc=or?nr/or:1, n1,n2,
- ops={2:{'r':PyThg(n1=D1.co[0]-oc[0],D1.co[1]-oc[1],1),'a':Math.atan2((D1.co[1]-oc[1]),(D1.co[0]-oc[0]))}, 3:{'r':PyThg(n2=D2.co[0]-oc[0],D2.co[1]-oc[1],1),'a':Math.atan((D2.co[1]-oc[1])/(ev=D2.co[0]-oc[0]))+(ev<0?(Math.PI):0)}};
- mvD.a=Math.atan2((D3.co[1]-D0.co[1]),(ev=D3.co[0]-D0.co[0]))-oma;
- var r_=ops[2].r*rc,a_=mvD.a+ops[2].a;
- D1.rps((Math.cos(a_)*r_)+nc[0],(Math.sin(a_)*r_)+nc[1]);
- D2.rps((Math.cos(a_=mvD.a+ops[3].a)*(r_=ops[3].r*rc))+nc[0],(Math.sin(a_)*r_)+nc[1]);
- //D1 & D2 by a line between D0 & D3, & move parallel to that line keeping relative distances between points the same along the line; AKA make D1 and D2 move about the same axis, and same angle degrees as D0 & D3 movements, changing their distance to the axis based on the change of D0 and D3 axis distance change and their coordinate closeness to each
- } },
- "nw":function newBezierCurve(co){/*draw new bezierCurve*/
- var c0=co.length>=8?co:co.concat.apply(co,(new Array(4-(co.length/2))).fill(co)),
- D0=nwDot(0), //beggining dot
- D1=nwDot(2), //1st control point dot
- D2=nwDot(4), //2nd control point dot
- D3=(dtbx.slctD=nwDot(6)), //ending dot (select it so you can streatch the curve out)
- //put this whole curve onto Cnvs2 and adjust curve & Cnvs2 as needed when the Dots are moved (simillar process for other draw shapes); need to add rotation option that rotates the whole shape (use the dot rps functions as part), move whole option also;
- sho={"type":this.type,"points":c0,"dots":[D0,D1,D2,D3],"izNew":!0,"mtf":Object.assign({},$B.mtf)}; P2mO([D0,D1,D2,D3],"oS",sho); AllShps.push(sho); dotSlct(dtbx.slctS=sho);
- },
- "mmwe":!0 //move middle with ends (see line 160ish in function 'itm' in bezierCurve.nw)
- },
- "arc":shapD={"type":"arc",
- "cxf":"arcTo",
- "cmt":!0, //could build cxf & cmt into main shape editor func and leave them out here?
- "itm":function(){if(this.mmwe){
- //in the middle: (move D1 & D2 when either D0 or D3 moves)
- var mvD={1:[D0.co[0]-D0.lc[0],D0.co[1]-D0.lc[1]],3:[D2.co[0]-D2.lc[0],D2.co[1]-D2.lc[1]]},
- oc=[(D0.lc[0]+D2.lc[0])/2,(D0.lc[1]+D2.lc[1])/2], oma=Math.atan2((D2.lc[1]-D0.lc[1]),(D2.lc[0]-D0.lc[0])),
- nc=[(D0.co[0]+D2.co[0])/2,(D0.co[1]+D2.co[1])/2], or=PyThg(D0.lc[0]-oc[0],D0.lc[1]-oc[1]), nr=PyThg(D0.co[0]-nc[0],D0.co[1]-nc[1]), rc=or?nr/or:1, n1,n2,
- ops={'r':PyThg(n1=D1.co[0]-oc[0],D1.co[1]-oc[1],1),'a':Math.atan2((D1.co[1]-oc[1]),(D1.co[0]-oc[0]))};
- mvD.a=Math.atan2((D2.co[1]-D0.co[1]),(D2.co[0]-D0.co[0]))-oma;
- var r_=ops.r*rc,a_=mvD.a+ops.a;
- D1.rps((Math.cos(a_)*r_)+nc[0],(Math.sin(a_)*r_)+nc[1]);
- //D1 by a line between D0 & D2, & move parallel to that line keeping relative distances between points the same along the line; AKA make D1 move about the same axis, and same angle degrees as D0 & D2 movements, changing it's distance to the axis based on the change of D0 and D2 axis distance change and it's coordinate closeness to each
- }},
- "crft":function crft(){ //ClacRadiusFromTangent
- var d1_3x=D0.co[0]-D2.co[0],d1_3y=D0.co[1]-D2.co[1],d1_3d=PyThg(d1_3x,d1_3y), d1_2x=D0.co[0]-D1.co[0],d1_2y=D0.co[1]-D1.co[1],
- d1_2ang=Math.atan2(d1_2y,d1_2x),d1_3ang=Math.atan2(d1_3y,d1_3x); sho.R=zm*(d1_3d/2)/Math.abs(Math.cos((Math.PI/2)-Math.abs(d1_2ang-d1_3ang)));
- if(crft.caller==D1.om){
- var d3_2x=D2.co[0]-D1.co[0],d3_2y=D2.co[1]-D1.co[1],d3_2d=PyThg(d3_2x,d3_2y),d1_2d=PyThg(d1_2x,d1_2y), aang=(d1_3ang+(Math.PI/2)), ad2=(d3_2d+d1_2d)/2; //Math.tan(?);
- }
- },
- "D1_rps":function tf(x,y,S){ /*confine x & y:
- need to find point of intersection the x & y axis of this point have with a the line bisecting and perpendicular to line D0-D1,
- choose the point of intersection that is closest to this point and move this point there
- use a point on the line that I know (middle of D0-D1), use rise/run to find intersection point of coordinate using other coordinate
- wait actually, make imaginary line paralel to D0-D1 with one end at x,y and the other on the line perpendicular to D0-D1,
- move x,y to where this imag line is on perpendicular line,
- could do this by averaging x_i_y & y_i_x ?*/
- x==null?x=this.co[0]:0;y==null?y=this.co[1]:0;//keep
- var ctr=[(D0.co[0]+D2.co[0])/2,(D0.co[1]+D2.co[1])/2],cx,cy,rise=D2.co[1]-D0.co[1],run=D2.co[0]-D0.co[0],ang=Math.atan2(rise,run)+(Math.PI/2);
- var x_i_y=((x-ctr[0])*Math.tan(ang))+ctr[1]; //y coord of x-intercept ?
- var y_i_x=((y-ctr[1])/Math.tan(ang))+ctr[0]; //x coord of y-intercept ?
- var x_i_dis=PyThg(x-ctr[0],x_i_y-ctr[1]); //inefficient code, fix later, works, but needs improving
- var y_i_dis=PyThg(y_i_x-ctr[0],y-ctr[1]);
- //test:
- //self.to1=function(a,b){return (a/(a+b))+(b/(a+b));}
- var y_i_m,x_i_m,both=y_i_dis+x_i_dis;
- if(x_i_dis==0){y_i_m=1;x_i_m=0;}
- else if(y_i_dis==0){x_i_m=1;y_i_m=0;}
- else{x_i_m=y_i_dis/both;y_i_m=x_i_dis/both;}
- var newcoord=[((y_i_x*y_i_m)+(x*x_i_m)),((x_i_y*x_i_m)+(y*y_i_m))]; x=newcoord[0];y=newcoord[1]; //gets wacky as distance between pointer (mouse) and D1 increases, works mostly the way I want at realy close range
- //if(x_i_dis>y_i_dis){x=y_i_x;}else{y=x_i_y;} //uncomment this if test fail
- S=this.style;S.left=(((x+xp))+Canvs1.cx)+"px";S.top=(Canvs1.cy-((y+yp)))+"px";this.lc=this.co;this.co=[x,y];if(typeof this.om=="function")this.om();//keep
- },
- "nw":function newArc(co){
- var c0=co.length>=6?co:co.concat.apply(co,(new Array(3-(co.length/2))).fill(co)),
- //DR is not needed. D1 makes 2 mirrored right triangles with a combined hypotonoose, 1 with D0 at the right angle & 1 with D2 at the right angle, the hypotonose is not the radius, it's a side other than the one(s) made by lines D1-D0, D1-D2, the hypotonoose is always perpendicular to a line D0-D2, D1 is always the same distance from D0 as from D2, the hypotonoose is always lined up along D0-D2 with D1
- D0=nwDot(0),
- D1=nwDot(2),
- D2=(dtbx.slctD=nwDot(4)),
- sho={"type":this.type,"points":c0,"R":0,"dots":[D0,D1,D2],"mtf":Object.assign({},$B.mtf)};
- //D1.rps=D1_rps.bind(D1);
- P2mO([D0,D1,D2],"oS",sho); AllShps.push(sho);
- //crft();
- dotSlct(dtbx.slctS=sho);
- },
- "mmwe":!0
- },
- //end simple shapes, begin combo shapes
- "ellipse":{"type":"ellipse", //2 bezier curves? << NO!
- "cxf":"ellipse",
- "cmt":!1,
- "nw":function newElps(co){
- //there should be a total of at least 4 dots (top,bottom,left,right), possible 8 (corners:top-left,top-right,bottom-left,bottom-right)
- //will need to add a "temporary select all dots in shape and move whole shape without changing it" option to all shapes and a scale(resize) option
- var c0=co.concat(co,co,co),
- D0=nwDot(0),
- D1=nwDot(2),
- D2=nwDot(4),
- D3=(dtbx.slctD=nwDot(6));
- sho={"type":this.type,"points":c0,"Rot":0,"dots":[D0,D1,D2,D3],"izNew":!0,"mtf":Object.assign({},$B.mtf)};
- //D1.rps=D1_rps.bind(D1);
- P2mO([D0,D1,D2,D3],"oS",sho); AllShps.push(sho);
- //crft();
- dotSlct(dtbx.slctS=sho);
- }
- },
- "rectangle":{"type":"rectangle",
- //4 lines
- "cxf":"lineTo", "cxr":4,
- "cmt":!0,
- "nw":function newTrig(co){
- var c0=co.concat(co,co,co),
- D0=nwDot(0),
- D1=nwDot(2),
- D2=nwDot(4),
- D3=(dtbx.slctD=nwDot(6));
- sho={"type":this.type,"points":c0,"dots":[D0,D1,D2,D3],"mtf":Object.assign({},$B.mtf)};
- //D1.rps=D1_rps.bind(D1);
- P2mO([D0,D1,D2,D3],"oS",sho); AllShps.push(sho);
- dotSlct(dtbx.slctS=sho);
- }
- },
- "triangle":{"type":"triangle",
- //3 lines
- "cxf":"lineTo", "cxr":3,
- "cmt":!0,
- "nw":function newTrig(co){
- var c0=co.concat(co,co),
- D0=nwDot(0),
- D1=nwDot(2),
- D2=(dtbx.slctD=nwDot(4));
- sho={"type":this.type,"points":c0,"dots":[D0,D1,D2],"mtf":Object.assign({},$B.mtf)};
- //D1.rps=D1_rps.bind(D1);
- P2mO([D0,D1,D2],"oS",sho); AllShps.push(sho);
- dotSlct(dtbx.slctS=sho);
- }
- },
- "polygon":{
- //any amount of lines (no curves)
- }
- //end shape maker objects
- },
- "ani":{
- "cntnr":$B.anc=d[gI]("ani_mod")
- },
- "vid":{
- "cntnr":$B.vbc=d[gI]("vid_mod"),
- "doon":function(){if(!self.v_edity)TJA.require("https://docs.google.com/uc?id=0Bxb5iFgmM3V6TXVsakNTYV9hZVU");},
- "btns":{
- "nVidSrc":eAePt(($B.vbc_b=$B.vbc[gT]("button"))[0],"click",function(){ FIB_.cb=function F(dat,inf){ AllVids.push({"dat":dat,"nm":F.nm||inf.name,"type":inf?inf.type:F.xhr.getResponseHeader("Content-Type")});}; d.body[aC](FIB_); })
- }
- }
- }
- });
- //main toolbox handler functions END
- tlbx.emod.onchange=function(){
- hdAll(tlbx.cbx.children);
- (mo=tlbx.emdT[this.value]).cntnr.className="";
- if(typeof mo.doon=="function")mo.doon();
- self.onresize();
- };
- tlbx.emod.onchange();
- /*dtbx.oca=[]; //on click array (probably won't use this now)
- dtbx.onclick=function(e){
- var co=[e.clientX,e.ClientY],t2=this;
- t2.oca.forEach(function(v){v.call(t2,co,t2.lc);});
- t2.lc=co;
- };*/
- //needs some more conversion work, I'm basically changing the whole flow chart to reduce function calls to an absolute minimum
- //use WeakMap for Dot element to shape object mappings?
- var sacm={"arc":5,"line":2,"bezierCurve":6,"ellipse":8,"rectangle":2,"triangle":2,"arcTo":5,"lineTo":2,"bezierCurveTo":6},
- Rndr2=function Rndr2(e){
- var tar=e.target||e.srcElement,
- etype=e.type,
- co=[
- (((e.clientX-(dtbx.offsetLeft+dbx2.offsetLeft)))/zm)-xp,
- (((e.clientY-(dtbx.offsetTop +dbx2.offsetTop )))/zm)-yp
- ],
- b,slm, MMV,
- Dot,dap,mvDs=!1, shp,spa,ospa,
- g0=!1,pass=0,Lim=65535; //(1<<144)-1;
- MMV=!0;
- if(etype=="mousemove"){
- if(slm=(dtbx.md&&dtbx.slctD)){
- //this function will soon be the catch-all event handler function for drawing shapes
- Dot=dtbx.slctD; shp=Dot.oS; //selected dot owner shape
- spa=shp.points; ospa=spa.slice();
- spa[dap=Dot.p]=co[0]; spa[dap+1]=co[1]; //correct?
- //Clr(ctx2); //duplicate for this run
- if(shp){g0=!0; mvDs=!0; }
- dtbx.lc=co;
- }else if(b=dtbx.dc_){ xp=-(b[0]-e.clientX);yp=b[1]-e.clientY; Clr(ctx);
- g0=!0;
- }
- }else if(etype=="mousedown"){
- if(e.button==1){ dtbx.dc_=[e.clientX,e.clientY];
- }else if(e.button==0){
- var T=dtbx; T.md=!0;T.fc=co;
- if(tar.nodeName=="DOT"){T.slctD=tar; //selected Dot
- Clr(ctx); Clr(ctx2); g0=!0;
- if(T.slctD.oS){
- if(T.slctS)dotSlct(T.slctS);Object.assign($B.mtf,(T.slctS=T.slctD.oS).mtf);dotSlct(T.slctS,!0);
- } //selected Shape
- }else if(tar==Canvs1||tar==Cnvs2){
- //g0=!0; // <- need this?
- //for clicking on blank canvas, if there is a shape selected, move from temp canvas to main canvas and disselect
- if(dtbx.slctS){ dotSlct(dtbx.slctS,!1);}
- dtbx.slctS=!1;Object.assign($B.mtf,$B.mtf2);
- if(typeof tlbx.slcT.nw=="function"){
- tlbx.slcT.nw(co); dotSlct(dtbx.slctS,!0);
- } //"new" function for SeLecTed tool (this might only be for draw mode)
- g0=!0; mvDs=!0;
- }
- }
- }else if(etype=="mouseup"){
- if(dtbx.md){
- if(dtbx.slctD){ Clr(ctx);
- if(dtbx.slctD.oS.izNew)delete dtbx.slctD.oS.izNew;
- g0=!0;
- }
- }
- dtbx.md=!1;dtbx.slctD=!1;dtbx.lc=co;
- if(dtbx.dc_){Clr(ctx);
- g0=!0;
- dtbx.dc_=!1;
- }
- }else if(etype=="loadShps"){ MMV=!1;
- g0=!0; mvDs=!0;
- }
- var styp,mt,df,dst,dbp,Slcts,c_x,pa2, //use pa2 set to convert spa from coord array and radius data to plain coord array
- dots,di,ds, j, ac, p2=0, L3;
- while(g0&&pass^Lim){
- if(!slm){
- shp=AllShps[pass];
- spa=shp.points;
- }
- dots=shp.dots;di=dots.length;
- //do draw all shapes, set g0 to false when done
- styp=shp.type; mt=!0; //mt== moveTo
- df=""; dst=!0; dbp=!0; //df==drawFunc, dst=doSTroke, dbp=doBeginPath;
- Slcts=slm||(shp==dtbx.slctS);c_x=Slcts?ctx2:ctx;
- if(styp=="line"){ //handlers begin
- df="lineTo";
- pa2=spa;
- }else if(styp=="bezierCurve"){
- df="bezierCurveTo";
- pa2=spa;
- }else if(styp=="arc"){
- df="arcTo";
- var D0_D2_x=spa[0]-spa[4],D0_D2_y=spa[1]-spa[5],D0_D2_2=Math.sqrt((D0_D2_x*D0_D2_x)+(D0_D2_y*D0_D2_y))/2,
- D0_D2_cx=(spa[0]+spa[4])/2,D0_D2_cy=(spa[1]+spa[5])/2,
- C_D1_x=D0_D2_cx-spa[2],C_D1_y=D0_D2_cy-spa[3],C_D1=Math.sqrt((C_D1_y*C_D1_y)+(C_D1_x*C_D1_x)),
- ang1=Math.atan(C_D1/D0_D2_2);
- shp.R=D0_D2_2/Math.cos((Math.PI/2)-ang1);
- pa2=spa.concat([shp.R]);
- }else if(styp=="ellipse"){ //left,right,top,bottom
- df="ellipse"; mt=!1;
- var f0s=0;
- if(MMV){
- var di2=dots.indexOf(Dot);
- var D0_D1_x=spa[0]-spa[2],D0_D1_y=spa[1]-spa[3],
- D2_D3_x=spa[4]-spa[6],D2_D3_y=spa[5]-spa[7],
- RoRi,RoRu;
- if(di2<2){/*f0s=0;*/ RoRi=D0_D1_y;RoRu=D0_D1_x;
- //needs more code
- }else{ f0s=4; RoRi=D2_D3_y;RoRu=D2_D3_x; }
- if(RoRu) shp.Rot=Math.atan(RoRi/RoRu);
- }
- var C_x=(spa[0+f0s]+spa[2+f0s])/2, C_y=(spa[1+f0s]+spa[3+f0s])/2;
- if(MMV){ var fOs
- if(shp.izNew)fOs=0;else fOs=f0s;
- var xcd=spa[4-fOs]-spa[6-fOs],ycd=spa[5-fOs]-spa[7-fOs], dc=Math.sqrt(xcd*xcd+ycd*ycd)/2;
- spa[4-f0s]=C_x+(Math.cos(shp.Rot+hPI)*dc); spa[5-f0s]=C_y+(Math.sin(shp.Rot+hPI)*dc);
- spa[6-f0s]=C_x+(Math.cos(shp.Rot-hPI)*dc); spa[7-f0s]=C_y+(Math.sin(shp.Rot-hPI)*dc);
- }
- var C_D1_y=C_y-spa[3+f0s], C_D1_x=C_x-spa[2+f0s], C_D3_y=C_y-spa[7-f0s], C_D3_x=C_x-spa[6-f0s],
- x_r=Math.sqrt((C_D1_y*C_D1_y)+(C_D1_x*C_D1_x)), y_r=Math.sqrt((C_D3_y*C_D3_y)+(C_D3_x*C_D3_x)), s_r;
- //if(f0s){ s_r=x_r; x_r=y_r; y_r=s_r; }
- pa2=[
- C_x, C_y,
- x_r, y_r,
- shp.Rot,
- 0,
- Math.PI*2,
- !1
- ];
- }else if(styp=="rectangle"){
- df="lineTo";
- pa2=spa;
- }else if(styp=="triangle"){
- df="lineTo";
- pa2=spa;
- }
- //finally, draw the shape(s)
- if(dbp){ if(Slcts)Clr(ctx2); c_x.beginPath(); } //Clr is inside here in case of multi shape paths that are counted as one shape
- if(mt)c_x.moveTo(pa2[0],pa2[1]);
- if(L3=(shp.cxr||$B.ted[styp].cxr)){ L3*=(ac=sacm[styp]);
- if(mt){j=2; L3+=2; }else j=0;
- while(j<L3){ p2=pa2.slice(j,j+ac); if(p2.length<ac) p2=p2.concat(pa2.slice(0,ac)); c_x[df].apply(c_x,p2); j+=ac;}
- }else c_x[df].apply(c_x,mt?pa2.slice(2):pa2);
- if(dst)c_x.stroke();
- while(mvDs&&di--){
- Dot=dots[di];
- ds=Dot.style;
- ds.left=spa[dap=Dot.p]+"px"; ds.top=spa[dap+1]+"px";
- }
- pass++;
- if(slm||(pass==AllShps.length))g0=!1;
- }
- };
- self.onmousemove=Rndr2;
- dtbx.onmousedown=Rndr2;
- self.onmouseup=Rndr2;
- self.ondrag=function(e){e.preventDefault();};
- /*dtbx.onwheel=function(e){
- if(e.deltaY>0){ zm*=1.02; Rndr2({"type":"zoom"}); }else if(zm>0.2&&e.deltaY<0){ zm*=0.98; Rndr2({"type":"zoom"}); }
- dtbx.style.transform="scale("+zm+")";
- }; */
- var sh0wy=function(e){ var tar=e.target||e.srcElement;
- if(tar.nodeName=="DOT"){
- var dts=tar.oS.dots,i=dts.length;
- while(i--)dts[i].classList[e.type=="mouseover"?"add":"remove"]("hovr");
- }
- };
- dtbx.onmouseover=sh0wy;
- dtbx.onmouseout=sh0wy;
- //ctx mnu
- var ctx_mnu=dtbx.ctx_mnu=d[gI]("ctx_mnu"),$n=null;
- ctx_mnu.onclick=(self.onclick=function(e){ if(e.button!=2)ctx_mnu.className="hid";});
- dtbx.oncontextmenu=function(e){ if(!ctx_mnu.ldf){ e.preventDefault(); ctx_mnu.le=e; var sy=dtbx.ctx_mnu.style; ctx_mnu.dfm=e.default; ctx_mnu.className=""; sy.top=(e.clientY-7)+"px"; sy.left=(e.clientX-7)+"px"; return !1;}else{ ctx_mnu.ldf--; return !0;}};
- ctx_mnu.copy=eAePt(($B.ctxmB=ctx_mnu[gT]("button"))[0],"click",function Copy(){});
- ctx_mnu.cut=eAePt($B.ctxmB[1],"click",function Cut(){});
- ctx_mnu.paste=eAePt($B.ctxmB[2],"click",function Paste(){});
- ctx_mnu.delete=eAePt($B.ctxmB[3],"click",function Delete(e,s){ if(s=dtbx.slctS){var i=AllShps.indexOf(s);dtbx.slctD=(dtbx.slctS=!1);AllShps.splice(i,1);ctx2.clearRect(0,0,Cnvs2.width,Cnvs2.height);i=s.dots.length;while(i--)s.dots[i].remove(); }});
- ctx_mnu.merge=eAePt($B.ctxmB[4],"click",function Merge(e){ var cd,ec=[ctx_mnu.le.clientX-Canvs1.cx,Canvs1.cy-ctx_mnu.le.ClientY],dts=dtbx.geta("dot"),i=dts.length; while(i--)if(PyThg((cd=dts[i]).co[0]-ec[0],cd.co[1]-ec[1])<5) "merge"; });
- ctx_mnu.rctxm=eAePt($B.ctxmB[5],"click",function Real_ctxmnu(e){ ctx_mnu.ldf=1; ctx_mnu.className="hid"; /*ctx_mnu.le.initEvent("contextmenu",!0,!1); dtbx.dispatchEvent(ctx_mnu.le); */});
- //File Input Box
- self.FIB_=d[gI]("fib_1");
- (FIB_.b=FIB_[gT]("button"))[0][aEL]("click",function(){if(typeof FIB_.cb=="function")TJA.openf(FIB_.cb);FIB_.remove();});
- var hACAO=(self.location.host+",ve.media.tumblr.com,media.tumblr.com,a.tumblr.com,cors-anywhere.herokuapp.com").split(",");
- FIB_.ub=FIB_[gT]("input")[0];
- $B.lfu_=function(){ if(typeof FIB_.cb=="function"){v_edity.load2(FIB_.cb.nm=FIB_.ub.value,FIB_.cb,hACAO.indexOf(TJA.gurl(FIB_.ub.value,"://","/"))>=0);} FIB_.className="hid";};
- FIB_.ub.onkeydown=function(e){if(e.keyCode==13)$B.lfu_();};
- FIB_.b[1][aEL]("click",$B.lfu_);
- //convert drawing to a save-able string
- self.saveShps=function(){ var A=AllShps,i=A.length,L=i,da=[],m,ma=[],j; while(i--){m=JSON.stringify(A[i].mtf); if((j=ma.indexOf(m))+1)m="A"+j;else ma[i]=m; da[i]=(A[i].type+";"+m+";"+A[i].points.join()); } return da.join("|"); };
- self.loadShps=function(d){ var A=d.split("|"),i=A.length,L=i,b; while(i--)A[i]=A[i].split(";");i=L;while(i--){b=A[i];$B.mtf=JSON.parse(b[1][0]=="A"?(A[b[1].substr(1)*1][1]):b[1]);tlbx.emdT.draw[b[0]].nw(b[2].split(",").map(function(n){return n*1;}));} Rndr2({"type":"loadShps"}); };
- /*
- multiplier vars for x and y and radius, panning (scrolling vertical or horizontal) vars for x and y,
- apply to all ctx.draw functions and all onclick or event coordinate functions, so that user can zoom in on shapes at different coords in their drawing without it looking pixelated
- self.hidd="data:text/css;base64,"+btoa("dot{ display:none; }");
- self.l2=Object.assign(d[cE]("link"),{type:"text/css",rel:"stylesheet",href:hidd});
- d.head[aC](l2); //append for hide dots,
- */
- </script>
- </body>
- </html>
Add Comment
Please, Sign In to add comment