43 |
44 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/html5kellycolorpicker.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @category html5 widgets
3 | * @package Kelly
4 | * @author Rubchuk Vladimir
5 | * @copyright 2015-2022 Rubchuk Vladimir
6 | * @license GPLv3
7 | * @version 1.22
8 | *
9 | * Usage example :
10 | *
11 | * new KellyColorPicker({place : 'color-picker'});
12 | *
13 | * ToDo :
14 | *
15 | * Add switch color in colorsavers button (analog of X button in Photoshop)
16 | * updateConfig method
17 | *
18 | **/ /**
19 | * Create color picker
20 | * @param {Array} cfg
21 | * @returns {KellyColorPicker}
22 | */ function KellyColorPicker(f){var h,i,j,k,l,m=Math.PI,n=!0,g=new Object;g.radius=4;var o=!1,p=!1,q="quad",r=!1,s=!1,t=!0,u=new Array,v=new Array,w=document.createElement("canvas"),x=!1,y=!1,z=null,A=!1,B=!0,C="mixed",e=new Object;e.tag=!1,e.margin=6;var D=!1,E=this,F=200,G="#000000",H=1,I=!1,J=!1,K=new Array,L=!1,M=new Array;function N(c,b,d){b=!!b;var a=new Object;a.width,a.widthPercentage=22,a.imageData=null,a.align=c,a.selected=b,a.color="#ffffff",a.position,a.paddingY=-4,a.paddingX=4,a.lineWidth=1,a.selectSize=4,"right"==c&&(a.paddingX=-1*a.paddingX),a.selected&&(a.color=G),d&&(a.color=d),a.updateSize=function(){this.width=parseInt(F-F/100*(100-this.widthPercentage)),"left"==this.align?this.position={x:0,y:F-this.width}:"right"==this.align&&(this.position={x:F-this.width,y:F-this.width})},a.calcS=function(a){return Math.abs((a[1].x-a[0].x)*(a[2].y-a[0].y)-(a[2].x-a[0].x)*(a[1].y-a[0].y))/2},a.isDotIn=function(e){var a=new Array;"left"==this.align?(a[0]={x:this.position.x,y:this.position.y},a[1]={x:this.position.x,y:this.position.y+this.width},a[2]={x:this.position.x+this.width,y:this.position.y+this.width}):(a[0]={x:this.position.x+this.width,y:this.position.y},a[1]={x:a[0].x,y:a[0].y+this.width},a[2]={x:a[0].x-this.width,y:this.position.y+this.width});for(var c=0;c<=a.length-1;++c)a[c].x+=this.paddingX,a[c].y+=this.paddingY;var f=this.calcS(a),b=[{x:a[0].x,y:a[0].y},{x:a[1].x,y:a[1].y},{x:e.x,y:e.y}],d=this.calcS(b);return b[1]={x:a[2].x,y:a[2].y},d+=this.calcS(b),b[0]={x:a[1].x,y:a[1].y},d+=this.calcS(b),Math.ceil(d)==Math.ceil(f)},a.draw=function(){w.width=this.width,w.height=this.width,x.clearRect(0,0,this.width,this.width),x.beginPath(),"left"==this.align&&(x.moveTo(this.lineWidth/2,this.width-this.lineWidth),x.lineTo(this.width,this.width-this.lineWidth),x.lineTo(this.lineWidth,this.lineWidth),x.lineTo(this.lineWidth,this.width-this.lineWidth)),"right"==this.align&&(x.moveTo(this.lineWidth/2,this.width-this.lineWidth),x.lineTo(this.width-this.lineWidth,this.width-this.lineWidth),x.lineTo(this.width-this.lineWidth,this.lineWidth),x.lineTo(this.lineWidth,this.width-this.lineWidth)),this.selected&&(x.fillStyle="rgba(255,255,255, 1)",x.fill(),x.strokeStyle="rgba(0, 0, 0, 1)",x.stroke(),x.closePath(),x.beginPath(),x.lineWidth=this.lineWidth,"left"==this.align&&(x.moveTo(this.selectSize,this.width-this.selectSize),x.lineTo(this.width-2*this.selectSize,this.width-this.selectSize),x.lineTo(this.selectSize,2*this.selectSize),x.lineTo(this.selectSize,this.width-this.selectSize)),"right"==this.align&&(x.moveTo(2*this.selectSize,this.width-this.selectSize),x.lineTo(this.width-this.selectSize,this.width-this.selectSize),x.lineTo(this.width-this.selectSize,2*this.selectSize),x.lineTo(2*this.selectSize,this.width-this.selectSize)));var a=W(this.color);x.fillStyle="rgba("+a.r+","+a.g+","+a.b+", 1)",x.fill(),x.strokeStyle="rgba(0, 0, 0, 1)",x.stroke(),this.imageData=x.getImageData(0,0,this.width,this.width),p.drawImage(w,this.position.x+this.paddingX,this.position.y+this.paddingY)};var e=K.length;K[e]=a}var b=new Object;b.width=18,b.imageData=null,b.innerRadius,b.startAngle=0,b.outerRadius,b.outerStrokeStyle="rgba(0,0,0,0.2)",b.innerStrokeStyle="rgba(0,0,0,0.2)",b.pos,b.draw=function(){if(this.imageData)w.width=F,w.height=F,x.putImageData(this.imageData,0,0),p.drawImage(w,0,0);else{for(var b=this.startAngle,a=0;a<=360;a++){var d=Y(a-2),e=Y(a);p.beginPath(),p.moveTo(j,j),p.arc(j,j,this.outerRadius,d,e,!1),p.closePath();var c=U(b/360,1,1);p.fillStyle="rgb("+c.r+", "+c.g+", "+c.b+")",p.fill(),++b>=360&&(b=0)}p.globalCompositeOperation="destination-out",p.beginPath(),p.arc(j,j,this.innerRadius,0,2*m),p.fill(),p.globalCompositeOperation="source-over",p.strokeStyle=this.innerStrokeStyle,p.lineWidth=2,p.stroke(),p.closePath(),p.beginPath(),p.arc(j,j,this.outerRadius,0,2*m),p.strokeStyle=this.outerStrokeStyle,p.lineWidth=2,p.stroke(),p.closePath(),this.imageData=p.getImageData(0,0,F,F)}},b.isDotIn=function(a){return!!(Math.pow(this.pos.x-a.x,2)+Math.pow(this.pos.y-a.y,2)Math.pow(this.innerRadius,2))};var d=new Object;d.lineWeight=2,d.height=4,d.paddingX=2,d.path;var a=new Object;a.width=18,a.padding=4,a.outerStrokeStyle="rgba(0,0,0,0.2)",a.innerStrokeStyle="rgba(0,0,0,0.2)",a.height,a.pos,a.updateSize=function(){this.pos={x:F+a.padding,y:a.padding},this.height=F-2*a.padding},a.draw=function(){var b=p.createLinearGradient(0,0,0,this.height),a=U(k.h,1,1);b.addColorStop(0,"rgba("+a.r+","+a.g+","+a.b+",1)"),b.addColorStop(1,"rgba("+a.r+","+a.g+","+a.b+",0)"),p.beginPath(),p.rect(this.pos.x,this.pos.y,this.width,this.height),p.fillStyle="white",p.fill(),p.fillStyle=b,p.fill(),p.strokeStyle="rgba(0,0,0, 0.2)",p.lineWidth=2,p.stroke(),p.closePath()},a.dotToAlpha=function(a){return 1-Math.abs(this.pos.y-a.y)/this.height},a.alphaToDot=function(a){return{x:0,y:this.height-this.height*a}},a.limitDotPosition=function(b){var a=b.y;return athis.pos.y+this.height&&(a=this.pos.y+this.height),{x:this.pos.x,y:a}},a.isDotIn=function(b){return!(b.xthis.pos.x+a.width)&&!(b.ythis.pos.y+this.height)};var c=new Object;function O(d){var b=d.getBoundingClientRect(),c=0,e=0;return r&&(e=a.width+2*a.padding),d===o?b.width<=b.height?c=b.height:b.heightb.height?c=b.height:b.height>=b.width&&(c=b.width),c=parseInt(c),r&&(c-=e),!(c<=0)&&c}function P(a,i){var c=1,b=!1;if("string"==typeof a){if(-1==(a=a.trim(a)).indexOf("(")){if("#"==a.charAt(0)&&(a=a.slice(1)),(a=a.substr(0,8)).length>=3){if(a.length>6&&a.length<8&&(a=a.substr(0,6)),a.length>3&&a.length<6&&(a=a.substr(0,3)),b=a,a.length>=3&&a.length<=4){b="";for(let d=0;d=3){switch(a.substring(0,3)){case"rgb":vals[0]=vals[0].replace("rgba(",""),vals[0]=vals[0].replace("rgb(","");var e={r:parseInt(vals[0]),g:parseInt(vals[1]),b:parseInt(vals[2])};e.r<=255&&e.g<=255&&e.b<=255&&(b=X(e));break;case"hsl":vals[0]=vals[0].replace("hsl(",""),vals[0]=vals[0].replace("hsla(","");var f=parseFloat(vals[0])/360,g=parseFloat(vals[1])/100,h=parseFloat(vals[2])/100;f>=0&&g<=1&&h<=1&&(b=X(U(f,g,h)))}4==vals.length&&((c=parseFloat(vals[3]))&&!(c<0)||(c=0),c>1&&(c=1))}}else"object"==typeof a&&(void 0!==a.r&& void 0!==a.g&& void 0!==a.b?b=X(a):void 0!==a.h&& void 0!==a.s&& void 0!==a.l&&(a.h=parseFloat(a.h)/360,a.s=parseFloat(a.s)/100,a.l=parseFloat(a.l)/100,a.h>=0&&a.s<=1&&a.l<=1&&(b=X(U(a.h,a.s,a.l)))),void 0!==a.a&&(c=a.a));return(!1!==b||!i)&&(!1===b&&(b="000000"),{h:b="#"!=b.charAt(0)?"#"+(b=b.substr(0,6)):b.substr(0,7),a:c})}function Q(){if(M.quad)return M.quad;var a=new Object;return a.size,a.padding=2,a.path,a.imageData=null,a.dotToSv=function(a){return{s:Math.abs(this.path[3].x-a.x)/this.size,v:Math.abs(this.path[3].y-a.y)/this.size}},a.svToDot=function(d){var g=this.path[0].x,h=this.path[0].y,a=.02;F<150?a=.07:F<100&&(a=.16);for(var b=0;bthis.path[0].x+this.size&&(a=this.path[0].x+this.size),bthis.path[0].y+this.size&&(b=this.path[0].y+this.size),{x:a,y:b}},a.draw=function(){this.imageData||(this.imageData=p.createImageData(this.size,this.size));for(var a=0,e=this.path[0].x,f=this.path[0].y,b=0;bthis.path[0].x+this.size)&&!(a.ythis.path[0].y+this.size)},M.quad=a,a}function R(){if(M.triangle)return M.triangle;var a=new Object;return a.size,a.padding=2,a.path,a.imageData=null,a.followWheel=!0,a.s,a.sOnTop=!1,a.outerRadius,a.limitDotPosition=function(e){var f=e.x,g=e.y,i=this.path[0].x,h=this.path[2].x,a=f,c=g;a=Math.min(Math.max(h,a),i);var d=(this.path[0].y-this.path[1].y)/(this.path[0].x-this.path[1].x),j=Math.ceil(this.path[1].y+d*(a-this.path[1].x));d=(this.path[0].y-this.path[2].y)/(this.path[0].x-this.path[2].x);var k=Math.floor(this.path[2].y+d*(a-this.path[2].x));return fthis.h-1&&(a=this.h);var e=a/this.h,b=Math.abs(aa(c,this.sSide));return b<30&&(b=30),b-=30,b=60-b,{s:b/=60,v:e}},a.isDotIn=function(c){var a=[{x:this.path[0].x,y:this.path[0].y},{x:this.path[1].x,y:this.path[1].y},{x:c.x,y:c.y}],b=this.calcS(a);return a[1]={x:this.path[2].x,y:this.path[2].y},b+=this.calcS(a),a[0]={x:this.path[1].x,y:this.path[1].y},b+=this.calcS(a),Math.ceil(b)==Math.ceil(this.s)},a.updateSize=function(){this.outerRadius=b.innerRadius-d.paddingX-this.padding,this.size=Math.floor(2*this.outerRadius*Math.sin(Y(60)));var e=Math.sqrt(3)/2*this.size;this.h=Math.sqrt(3)/2*this.size,this.path=new Array,this.path[0]={x:this.outerRadius,y:0},this.path[1]={x:this.path[0].x-e,y:-1*(this.size/2)},this.path[2]={x:this.path[1].x,y:this.size/2},this.path[3]={x:this.path[0].x,y:this.path[0].y};for(var c=0;c<=this.path.length-1;++c)this.path[c].x+=b.pos.x,this.path[c].y+=b.pos.y;if(this.vol=new Array,this.s=this.calcS(this.path),this.sOnTop){var a=$(this.path[0],this.path[2]);this.vol[0]={x:this.path[1].x,y:this.path[1].y},this.vol[1]={x:a.x,y:a.y},this.sSide=this.path[1]}else{var a=$(this.path[0],this.path[1]);this.vol[0]={x:this.path[2].x,y:this.path[2].y},this.vol[1]={x:a.x,y:a.y},this.sSide=this.path[2]}},M.triangle=a,a}function S(a,b,d,c){return"object"!=typeof a&&(a=document.getElementById(a)),!!a&&(c||(c=""),u[c+b]=d,a.addEventListener?a.addEventListener(b,u[c+b]):a.attachEvent("on"+b,u[c+b]),!0)}function T(a,b,c){return"object"!=typeof a&&(a=document.getElementById(a)),!!a&&(c||(c=""),!!u[c+b]&&(a.removeEventListener?a.removeEventListener(b,u[c+b]):a.detachEvent("on"+b,u[c+b]),u[c+b]=null,!0))}function U(b,g,a){var c,d,e,j,k,f,h,i;switch(b&& void 0===g&& void 0===a&&(g=b.s,a=b.v,b=b.h),j=Math.floor(6*b),k=6*b-j,f=a*(1-g),h=a*(1-k*g),i=a*(1-(1-k)*g),j%6){case 0:c=a,d=i,e=f;break;case 1:c=h,d=a,e=f;break;case 2:c=f,d=a,e=i;break;case 3:c=f,d=h,e=a;break;case 4:c=i,d=f,e=a;break;case 5:c=a,d=f,e=h}return{r:Math.floor(255*c),g:Math.floor(255*d),b:Math.floor(255*e)}}function V(a,b,c){a&& void 0===b&& void 0===c&&(b=a.g,c=a.b,a=a.r);var d,g,e=Math.max(a/=255,b/=255,c/=255),h=Math.min(a,b,c),f=e-h;if(g=0==e?0:f/e,e==h)d=0;else{switch(e){case a:d=(b-c)/f+(b>16,g:b>>8&255,b:255&b}}function X(a){var b=function(b){var a=b.toString(16);return 1===a.length?"0"+a:a};return"#"+b(a.r)+b(a.g)+b(a.b)}function Y(a){return a*(m/180)}function Z(a,b){return Math.sqrt(Math.pow(a.x-b.x,2)+Math.pow(a.y-b.y,2))}function $(a,b){return{x:(a.x+b.x)/2,y:(a.y+b.y)/2}}function _(d,a){var e=(a[0].x-a[1].x)*(a[0].x-a[1].x)+(a[0].y-a[1].y)*(a[0].y-a[1].y),f=(d.x-a[0].x)*(a[1].x-a[0].x)+(d.y-a[0].y)*(a[1].y-a[0].y),c=!0,b=f/e;return b<0&&(b=0,c=!1),b>1&&(b=1,c=!1),{x:a[0].x+b*(a[1].x-a[0].x),y:a[0].y+b*(a[1].y-a[0].y),pt:c}}function aa(c,a,d){a||(a={x:0,y:0});var e=c.x-a.x,f=c.y-a.y,b=180*Math.atan2(f,e)/m;return d&&b<0&&(b=360+b),b}function ab(){i=2+d.paddingX,y=!1,b.imageData=null,j=F/2,b.pos={x:j,y:j},b.outerRadius=j-i,b.innerRadius=b.outerRadius-b.width,d.path=[{x:b.innerRadius-d.paddingX,y:-1*d.height},{x:b.outerRadius+d.paddingX,y:-1*d.height},{x:b.outerRadius+d.paddingX,y:d.height},{x:b.innerRadius-d.paddingX,y:d.height},{x:b.innerRadius-d.paddingX,y:-((d.height+d.lineWeight/2)*1)}];var c=F;r&&(c+=a.width+2*a.padding),"canvas"!=D.tagName.toLowerCase()&&(D.style.width=c+"px",D.style.height=F+"px"),o.width=c,o.height=F,I!=o&&(o.style.width=c+"px",o.style.height=F+"px");for(var e=0;e<=K.length-1;++e)K[e].updateSize();L&&(L.imageData.triangle=null,L.imageData.quad=null,L.updateSize()),h.updateSize(),r&&a.updateSize()}function ac(b){if(!A||v.updateinput&&!(0,v.updateinput)(E,A,b))return;let c=H.toFixed(2),a="rgba("+l.r+", "+l.g+", "+l.b+", "+c+")";if(!b)switch(C){case"mixed":H<1?A.value=a:A.value=G;break;case"hex":A.value=G;break;case"hsla":A.value="hsla("+(360*k.h).toFixed(2)+", "+(100*k.s).toFixed(2)+"%, "+(100*k.v).toFixed(2)+"%, "+c+")";break;default:A.value=a}B&&(k.v<.5?A.style.color="#FFF":A.style.color="#000",A.style.background=a)}function ad(){S(o,"mousedown",function(a){E.mouseDownEvent(a)},"wait_action_"),S(o,"touchstart",function(a){E.mouseDownEvent(a)},"wait_action_"),S(o,"mouseout",function(a){E.mouseOutEvent(a)},"wait_action_"),S(window,"touchmove",function(a){E.touchMoveEvent(a)},"wait_action_"),S(o,"mousemove",function(a){E.mouseMoveRest(a)},"wait_action_")}function ae(){T(o,"mousedown","wait_action_"),T(o,"touchstart","wait_action_"),T(o,"mouseout","wait_action_"),T(window,"touchmove","wait_action_"),T(o,"mousemove","wait_action_")}function af(a){a=a||window.event;var b,c,d=document.body.scrollLeft+document.documentElement.scrollLeft,e=document.body.scrollTop+document.documentElement.scrollTop;"touchend"==a.type?(b=a.changedTouches[0].clientX+d,c=a.changedTouches[0].clientY+e):"touchmove"==a.type||a.touches?(b=a.touches[0].clientX+d,c=a.touches[0].clientY+e):(b=a.clientX+d,c=a.clientY+e);var f=o.getBoundingClientRect();return b-=f.left+d,c-=f.top+e,{x:b,y:c}}function ag(d){for(var c=!1,a=0;a<=K.length-1;++a)K[a].selected&&(c=a),K[a].selected=!1;for(var b=!1,a=0;a<=K.length-1;++a)if(a==d){K[a].selected=!0,E.setColorByHex(K[a].color),b=!0;break}return b&&v.selectcolorsaver&&(0,v.selectcolorsaver)(E,K[d]),b|| !1===c||(K[c].selected=!0),b}function ah(){for(var a=0;a<=K.length-1;++a)K[a].selected&&(K[a].color=G)}function ai(){if(K.length)for(var a=0;a<=K.length-1;++a)K[a].draw()}function aj(){if(!(p&&((p.clearRect(0,0,o.width,o.height),y)?(p.putImageData(z,0,0),ai(),!0):(b.draw(),h.draw(),r&&a.draw(),ai(),L&&L.draw(),s||(z=p.getImageData(0,0,o.width,o.height),y=!0),!0))))return!1;var j=360*k.h-b.startAngle;if(r){p.beginPath();var f=2,i=2,l=a.height*(1-H);p.rect(a.pos.x-i,a.padding+l-f/2,a.width+2*i,f),p.strokeStyle="rgba(0,0,0, 0.8)",p.lineWidth=2,p.stroke(),p.closePath()}p.beginPath();for(var e=function(c,b){b=Y(b);for(var d=new Array,a=0;a<=c.length-1;++a)d[a]={x:c[a].x*Math.cos(b)-c[a].y*Math.sin(b),y:c[a].x*Math.sin(b)+c[a].y*Math.cos(b)};return d}(d.path,j,{x:b.pos.x,y:b.pos.y}),c=0;c<=e.length-1;++c)e[c].x+=b.pos.x,e[c].y+=b.pos.y,0==c?p.moveTo(e[c].x,e[c].y):p.lineTo(e[c].x,e[c].y);return p.strokeStyle="rgba(0,0,0,0.8)",p.lineWidth=d.lineWeight,p.stroke(),p.closePath(),k.v>.5&&k.s<.5?p.strokeStyle="rgba(0, 0, 0, 1)":p.strokeStyle="rgba(255, 255, 255, 1)",p.beginPath(),p.lineWidth=2,p.arc(k.x,k.y,g.radius,0,2*m),p.stroke(),p.closePath(),!1}c.svCursorData=null,c.stCursor=null,c.curType=0,c.size=16,c.cEl=document.body,c.initSvCursor=function(){if(!o)return!1;if(this.curType=1,this.stCursor||(this.stCursor=window.getComputedStyle(this.cEl).cursor,this.stCursor||(this.stCursor="auto")),this.svCursorData)return this.cEl.style.cursor=this.svCursorData,!0;if(!w)return!1;var a=this.size+2;w.width=a,w.height=a,x.clearRect(0,0,this.size,this.size),x.strokeStyle="rgba(255, 255, 255, 1)",x.beginPath(),x.lineWidth=2,x.arc(a/2,a/2,this.size/2,0,2*m),x.stroke(),x.closePath();var b=a,c=w.toDataURL();return this.svCursorData="url("+c+") "+b/2+" "+b/2+", auto",!!this.svCursorData&&(this.cEl.style.cursor=this.svCursorData,-1===this.cEl.style.cursor.indexOf(c)&&(this.svCursorData="crosshair",this.cEl.style.cursor="crosshair"),!0)},c.initStandartCursor=function(){this.stCursor&&(c.curType=0,this.cEl.style.cursor=this.stCursor)},c.updateCursor=function(a){n&&(KellyColorPicker.cursorLock||(h.isDotIn(a)?c.initSvCursor():c.initStandartCursor()))},this.popUpClose=function(a){if(!1!==e.tag){if(a&&(a.target==A||a.target==o||a.target==e.tag))return!1;(!v.popupclose||v.popupclose(E,a))&&(e.tag.style.display="none",KellyColorPicker.activePopUp==E&&(KellyColorPicker.activePopUp=!1))}},this.popUpShow=function(g){if(!1!==e.tag&&(!v.popupshow||v.popupshow(E,g))){KellyColorPicker.popupEventsInclude||(S(document,"click",function(a){return!!KellyColorPicker.activePopUp&&KellyColorPicker.activePopUp.popUpClose(a)},"popup_close_"),S(window,"resize",function(a){if(KellyColorPicker.activePopUp)return KellyColorPicker.activePopUp.popUpShow(a)},"popup_resize_"),KellyColorPicker.popupEventsInclude=!0),KellyColorPicker.activePopUp&&KellyColorPicker.activePopUp.popUpClose(!1);var c=E.getCanvas().width,a=E.getAlphaFig();a&&(c-=a.width+a.padding);var d=window.getComputedStyle(e.tag),b=parseInt(d.paddingBottom)+parseInt(d.paddingTop);b<=0&&(b=0);var f=A.getBoundingClientRect(),h=f.top+(window.scrollY||window.pageYOffset||document.body.scrollTop)-b,i=f.left+(window.scrollX||window.pageXOffset||document.body.scrollLeft);return e.tag.style.top=h-c-e.margin+"px",e.tag.style.left=i+"px",e.tag.style.display="block",KellyColorPicker.activePopUp=E,!1}},this.setHueByDot=function(c){var a=aa(c,b.pos)+b.startAngle;a<0&&(a=360+a),k.h=a/360,l=U(k.h,k.s,k.v),G=X(l),ah(),v.change&&(0,v.change)(E),ac(),y=!1,aj()},this.setColorForColorSaver=function(a,d){var b=P(a,!0);if(b){var c=E.getColorSaver(d);return c.selected?this.setColorByHex(a,!1):(c.color=b.h,aj()),!0}},this.setColor=function(a,b){E.setColorByHex(a,b)},this.setColorByHex=function(a,c){c||(c=!1);var b=H;if(!1!==a){if(!a||!a.length)return;var d=P(a,!0);if(!d)return;a=d.h,r&&(b=d.a)}else a=G;if(r&&a==G&&y&&b!=H){H=b,aj();return}if(!G||a!=G||!y){H=b,l=W(a),G=a,k=V(l);var e=h.svToDot(k);k.x=e.x,k.y=e.y,y=!1,ah(),aj(),v.change&&(0,v.change)(E),ac(c)}},this.setAlphaByDot=function(b){H=a.dotToAlpha(b),v.change&&(0,v.change)(E),ac(),aj()},this.setAlpha=function(a){H=a,ac(),aj()},this.setColorByDot=function(a){var b=h.dotToSv(a);k.s=b.s,k.v=b.v,k.x=a.x,k.y=a.y,k.s>1&&(k.s=1),k.s<0&&(k.s=0),k.v>1&&(k.v=1),k.v<0&&(k.v=0),l=U(k.h,k.s,k.v),G=X(l),ah(),v.change&&(0,v.change)(E),ac(),aj()},this.mouseOutEvent=function(a){c.curType>0&&!KellyColorPicker.cursorLock&&c.initStandartCursor()},this.mouseMoveRest=function(a){if(!s&&t){t=!1;var b=af(a);c.updateCursor(b),requestAnimationFrame(function(){t=!0}),v.mousemoverest&&(0,v.mousemoverest)(a,E,b)}},this.touchMoveEvent=function(a){s&&event.preventDefault()},this.mouseDownEvent=function(g){g.preventDefault();var d,e=!1,c=af(g);if(b.isDotIn(c))s="wheel",E.setHueByDot(c),d=function(a){E.wheelMouseMove(a,c)},e=function(a){KellyColorPicker.cursorLock=!1,E.wheelMouseUp(a,c)};else if(h.isDotIn(c))s="sv",E.setColorByDot(c),d=function(a){E.svMouseMove(a,c)},e=function(a){KellyColorPicker.cursorLock=!1,E.svMouseUp(a,c)};else if(r&&a.isDotIn(c))s="alpha",E.setAlphaByDot(c),d=function(a){E.alphaMouseMove(a,c)},e=function(a){KellyColorPicker.cursorLock=!1,E.alphaMouseUp(a,c)};else if(L&&L.isDotIn(c))E.setMethod();else if(K.length){for(var f=0;f<=K.length-1;++f)if(K[f].isDotIn(c)){ag(f);break}}d&&e&&(ae(),KellyColorPicker.cursorLock=E,S(document,"mouseup",e,"action_process_"),S(document,"mousemove",d,"action_process_"),S(document,"touchend",e,"action_process_"),S(document,"touchmove",d,"action_process_"))},this.wheelMouseMove=function(a,c){if(a.preventDefault(),s&&t){t=!1;var b=af(a);requestAnimationFrame(function(){t=!0}),E.setHueByDot(b),v.mousemoveh&&(0,v.mousemoveh)(a,E,b)}},this.wheelMouseUp=function(a,d){if(a.preventDefault(),s){T(document,"mouseup","action_process_"),T(document,"mousemove","action_process_"),T(document,"touchend","action_process_"),T(document,"touchmove","action_process_"),ad(),s=!1,y=!1,aj();var b=af(a);c.updateCursor(b),v.mouseuph&&(0,v.mouseuph)(a,E,b)}},this.alphaMouseMove=function(c,d){if(c.preventDefault(),s&&t){t=!1;var b=af(c);b=a.limitDotPosition(b),requestAnimationFrame(function(){t=!0}),E.setAlphaByDot(b),v.mousemovealpha&&(0,v.mousemovealpha)(c,E,b)}},this.alphaMouseUp=function(a,d){if(a.preventDefault(),s){T(document,"mouseup","action_process_"),T(document,"mousemove","action_process_"),T(document,"touchend","action_process_"),T(document,"touchmove","action_process_"),ad(),s=!1;var b=af(a);c.updateCursor(b),v.mouseupalpha&&(0,v.mouseupalpha)(a,E,b)}},this.svMouseMove=function(b,c){if(b.preventDefault(),s&&t){t=!1;var a=af(b);a=h.limitDotPosition(a),requestAnimationFrame(function(){t=!0}),E.setColorByDot(a),v.mousemovesv&&(0,v.mousemovesv)(b,E,a)}},this.svMouseUp=function(a,d){if(a.preventDefault(),s){T(document,"mouseup","action_process_"),T(document,"mousemove","action_process_"),T(document,"touchend","action_process_"),T(document,"touchmove","action_process_"),ad(),s=!1;var b=af(a);c.updateCursor(b),r&&(y=!1,aj()),v.mouseupsv&&(0,v.mouseupsv)(a,E,b)}},this.addUserEvent=function(a,b){return v[a]=b,!0},this.removeUserEvent=function(a){return!!v[a]&&(v[a]=null,!0)},this.getCanvas=function(){return!!p&&o},this.getCtx=function(){return!!p&&p},this.getInput=function(){return A},this.getSvFig=function(){return h},this.getSvFigCursor=function(){return g},this.getWheel=function(){return b},this.getWheelCursor=function(){return d},this.getCurColorHsv=function(){return k},this.getCurColorRgb=function(){return l},this.getCurColorHex=function(){return G},this.getCurColorRgba=function(){return{r:l.r,g:l.g,b:l.b,a:H}},this.getCurAlpha=function(){return H},this.getAlphaFig=function(){return!!r&&a},this.getPopup=function(){return e},this.getSize=function(){return F},this.getColorSaver=function(b){for(var a=0;a<=K.length-1;++a)if(!b&&K[a].selected||K[a].align==b)return K[a].rgb=W(K[a].color),K[a].hsv=V(K[a].rgb.r,K[a].rgb.g,K[a].rgb.b),K[a]},this.setColorSaver=function(b){if(!b)return!1;for(var a=0;a<=K.length-1;++a)if(K[a].align==b)return ag(a),K[a]},this.updateView=function(a){return!!p&&(a&&(b.imageData=null,h.imageData=null,z=null),y=!1,ab(),aj(),!0)},this.resize=function(a,c){return!!p&&(a==F&&!c||(y=!1,b.imageData=null,h.imageData=null,z=null,F=a,ab(),E.setColorByHex(!1),!1))},this.syncSize=function(b){if(!I)return!1;var a=O(I);return a&&E.resize(a),!1},this.setMethod=function(a){return a||(a="triangle","triangle"!=q||(a="quad")),a!=q&&("quad"==q||"triangle"==q)&&("quad"==(q=a)&&(h=Q()),"triangle"==q&&(h=R()),E.resize(F,!0),v.setmethod&&(0,v.setmethod)(E,q),!0)},this.destroy=function(){if(!E)return!1;c.curType>0&&(KellyColorPicker.cursorLock=!1,c.initStandartCursor()),s&&(T(document,"mouseup","action_process_"),T(document,"mousemove","action_process_"),T(document,"touchend","action_process_"),T(document,"touchmove","action_process_"),s=!1),e.tag&&T(A,"click","popup_"),A&&(T(A,"click","input_edit_"),T(A,"change","input_edit_"),T(A,"keyup","input_edit_"),T(A,"keypress","input_edit_")),KellyColorPicker.popupEventsInclude&&u.popup_close_click&&(KellyColorPicker.activePopUp&&KellyColorPicker.activePopUp.popUpClose(!1),T(document,"click","popup_close_"),T(window,"resize","popup_resize_"),KellyColorPicker.popupEventsInclude=!1),b.imageData=null,h.imageData=null,z=null,w=null,D&&D.parentNode&&D.parentNode.removeChild(D),I&&T(window,"resize","canvas_"),ae(),E=null},function(a){var c="",f="";(void 0!==a.alpha_slider&&(a.alphaSlider=a.alpha_slider),void 0!==a.input_color&&(a.inputColor=a.input_color),void 0!==a.input_format&&(a.inputFormat=a.input_format),a.input&&"object"!=typeof a.input?(a.input=document.getElementById(a.input),A=a.input):"object"==typeof a.input&&(A=a.input),void 0!==a.changeCursor&&(n=a.changeCursor),void 0!==a.alpha&&(H=a.alpha),void 0!==a.alphaSlider&&(r=a.alphaSlider),void 0!==a.inputColor&&(B=a.inputColor),void 0!==a.inputFormat&&(C=a.inputFormat),a.userEvents&&(v=a.userEvents),a.place&&"object"!=typeof a.place&&(f=a.place,a.place=document.getElementById(a.place)),a.place)?D=a.place:A?(e.tag=document.createElement("div"),e.tag.className="popup-kelly-color",a.popupClass?e.tag.className=a.popupClass:(e.tag.className="popup-kelly-color",e.tag.style.position="absolute",e.tag.style.bottom="0px",e.tag.style.left="0px",e.tag.style.display="none",e.tag.style.backgroundColor="#e1e1e1",e.tag.style.border="1px solid #bfbfbf",e.tag.style.boxShadow="7px 7px 14px -3px rgba(0,0,0,0.24)",e.tag.style.borderTopLeftRadius="4px",e.tag.style.borderTopRightRadius="4px",e.tag.style.borderBottomLeftRadius="4px",e.tag.style.borderBottomRightRadius="4px",e.tag.style.padding="12px",e.tag.style.boxSizing="content-box"),D=e.tag,document.getElementsByTagName("body")[0].appendChild(e.tag),S(A,"click",function(a){return E.popUpShow(a)},"popup_")):c+='| "place" ('+f+") not not found";var b=!1;if(a.color?b=P(a.color):A&&A.value&&(b=P(A.value)),b&&(G=b.h,r&&(H=b.a)),a.method&&("triangle"==a.method||"quad"==a.method)&&(q=a.method),D&&("CANVAS"!=D.tagName?(o=document.createElement("CANVAS"),D.appendChild(o)):o=D,void 0!==window.G_vmlCanvasManager&&(o=window.G_vmlCanvasManager.initElement(o),w=window.G_vmlCanvasManager.initElement(w)),o.getContext&&o.getContext("2d")&&(p=o.getContext("2d"),x=w.getContext("2d"),1))||(c+=" | cant init canvas context"),a.resizeWith&&("object"!=typeof a.resizeWith&&"boolean"!=typeof a.resizeWith&&(a.resizeWith=document.getElementById(a.resizeWith)),I=!0===a.resizeWith?o:a.resizeWith,a.resizeSide&&(J=a.resizeSide),I)&&(O(I)&&(a.size=O(I)),S(window,"resize",function(a){return E.syncSize(a)},"canvas_")),a.size&&a.size>0&&(F=a.size),c){"undefined"!=typeof console&&console.log("KellyColorPicker : "+c);return}if("quad"==q&&(h=Q()),"triangle"==q&&(h=R()),A){var d=function(a){var a=a||window.event;a.target||(a.target=a.srcElement),E.setColorByHex(a.target.value,!0)};S(A,"click",d,"input_edit_"),S(A,"change",d,"input_edit_"),S(A,"keyup",d,"input_edit_"),S(A,"keypress",d,"input_edit_")}a.colorSaver&&(N("left",!0),N("right")),a.methodSwitch&&((L=new Object).size,L.sizePercentage=10,L.position,L.paddingY=4,L.paddingX=4,L.imageData=new Array,L.lineWidth=2,L.color="#c1ebf5",L.updateSize=function(){this.size=parseInt(F-F/100*(100-this.sizePercentage)),this.size<16&&(this.size=16),this.position={x:this.paddingX,y:this.paddingY}},L.draw=function(){if(this.imageData[q]){p.putImageData(this.imageData[q],this.position.x,this.position.y);return}var b,e=W(this.color);w.width=this.size,w.height=this.size,x.clearRect(0,0,this.size,this.size),x.beginPath();var f="triangle";if("triangle"==q&&(f="quad"),x.beginPath(),this.size<35)var d=w.width/2,c=d;else{var d=w.width/2-this.lineWidth;x.arc(this.size/2,this.size/2,d,0,2*m),x.strokeStyle="rgba(0, 0, 0, 0.4)",x.lineWidth=this.lineWidth,x.stroke();var c=d-6;x.closePath(),x.beginPath(),x.arc(this.size/2,this.size/2,c,0,2*m),x.strokeStyle="rgba(0, 0, 0, 0.4)",x.lineWidth=this.lineWidth,x.stroke(),x.closePath()}if(x.beginPath(),"quad"==f){b=Math.floor((2*c-4)/Math.sqrt(2));var g=(this.size-b)/2,a={x:g+b,y:g+b/2};a.y=a.y-b/2,x.moveTo(a.x,a.y),x.lineTo(a.x-b,a.y),x.lineTo(a.x-b,a.y+b),x.lineTo(a.x,a.y+b)}else{b=Math.floor((2*c-4)*Math.sin(Y(60)));var a={x:2*c+(d-c),y:this.size/2},h=Math.sqrt(3)/2*b;x.moveTo(a.x,a.y),x.lineTo(a.x-h,a.y-b/2),x.lineTo(a.x-h,a.y+b/2),x.lineTo(a.x,a.y)}x.lineTo(a.x,a.y),x.fillStyle="rgba("+e.r+","+e.g+","+e.b+", 1)",x.fill(),x.lineWidth=this.lineWidth,x.strokeStyle="rgba(0, 0, 0, 0.6)",x.stroke(),x.closePath(),this.imageData[q]=x.getImageData(0,0,w.width,w.width),p.drawImage(w,this.position.x,this.position.y)},L.isDotIn=function(a){return a.x>=this.position.x&&a.x<=this.position.x+this.size&&a.y>=this.position.y&&a.y<=this.position.y+this.size}),ad(),ab(),E.setColorByHex(!1)}(f)}KellyColorPicker.cursorLock=!1,KellyColorPicker.activePopUp=!1,KellyColorPicker.popupEventsInclude=!1,KellyColorPicker.attachToInputByClass=function(e,a){for(var d=new Array,c=document.getElementsByClassName(e),b=0;b
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/html5kellycolorpicker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @category html5 widgets
3 | * @package Kelly
4 | * @author Rubchuk Vladimir
5 | * @copyright 2015-2022 Rubchuk Vladimir
6 | * @license GPLv3
7 | * @version 1.22
8 | *
9 | * Usage example :
10 | *
11 | * new KellyColorPicker({place : 'color-picker'});
12 | *
13 | * ToDo :
14 | *
15 | * Add switch color in colorsavers button (analog of X button in Photoshop)
16 | * updateConfig method
17 | *
18 | **/
19 |
20 | /**
21 | * Create color picker
22 | * @param {Array} cfg
23 | * @returns {KellyColorPicker}
24 | */
25 |
26 | function KellyColorPicker(cfg) {
27 | var PI = Math.PI;
28 |
29 | var svFig; // current method SV figure object
30 |
31 | var changeCursor = true;
32 |
33 | var svCursor = new Object;
34 | svCursor.radius = 4;
35 |
36 | var canvas = false;
37 | var ctx = false;
38 |
39 | var method = 'quad';
40 | var alpha = false; // is alpha slider enabled
41 | var drag = false;
42 | var cursorAnimReady = true; // sets by requestAnimationFrame to limit FPS on events like mousemove etc. when draging
43 |
44 | var events = new Array();
45 | var userEvents = new Array();
46 |
47 | var canvasHelper = document.createElement("canvas");
48 | var canvasHelperCtx = false; // used if needed to copy image data throw ctx.drawImage for save alpha channel
49 | var rendered = false; // is colorpicker rendered (without side alpha bar and cursors, rendered image stores in canvasHelperData
50 | var canvasHelperData = null; // rendered interface without cursors and without alpha slider [wheelBlockSize x wheelBlockSize]
51 |
52 | var input = false;
53 |
54 | // used by updateInput() function if not overloaded by user event
55 | var inputColor = true; // update input color according to picker
56 | var inputFormat = 'mixed'; // text format of colorpicker color displayed in input element | values : mixed | hex | rgba
57 |
58 | var popup = new Object; // popup block for input
59 | popup.tag = false; // Dom element if popup is enabled
60 | popup.margin = 6; // margin from input in pixels
61 |
62 | // container, or canvas element
63 | var place = false;
64 | var handler = this;
65 |
66 | var basePadding = 2;
67 |
68 | var padding;
69 | var wheelBlockSize = 200;
70 | var center;
71 |
72 | // current color
73 | var hsv;
74 | var rgb;
75 | var hex = '#000000';
76 | var a = 1;
77 |
78 | var resizeWith = false;
79 | var resizeSide = false;
80 |
81 | var colorSavers = new Array();
82 |
83 | var styleSwitch = false; // change method from square to triangle
84 | var svFigsPool = new Array(); // if we have button for switch method, better store already created figure object to buffer
85 |
86 | // style switch from triange to quad and backwards
87 | function initStyleSwitch() {
88 |
89 | styleSwitch = new Object;
90 | styleSwitch.size;
91 | styleSwitch.sizePercentage = 10;
92 | styleSwitch.position;
93 | styleSwitch.paddingY = 4;
94 | styleSwitch.paddingX = 4;
95 | styleSwitch.imageData = new Array();
96 | styleSwitch.lineWidth = 2;
97 | styleSwitch.color = '#c1ebf5';
98 |
99 | styleSwitch.updateSize = function () {
100 | this.size = parseInt(wheelBlockSize - (wheelBlockSize / 100) * (100 - this.sizePercentage));
101 |
102 | if (this.size < 16)
103 | this.size = 16;
104 |
105 | this.position = {x: this.paddingX, y: this.paddingY};
106 | }
107 |
108 | styleSwitch.draw = function () {
109 |
110 | if (this.imageData[method]) {
111 | ctx.putImageData(this.imageData[method], this.position.x, this.position.y);
112 | return;
113 | }
114 |
115 | var rgb = hexToRgb(this.color);
116 |
117 | canvasHelper.width = this.size;
118 | canvasHelper.height = this.size;
119 |
120 | canvasHelperCtx.clearRect(0, 0, this.size, this.size);
121 | canvasHelperCtx.beginPath();
122 |
123 | var switchFig = 'triangle';
124 | if (method == 'triangle')
125 | switchFig = 'quad';
126 |
127 | canvasHelperCtx.beginPath();
128 |
129 | if (this.size < 35) {
130 | var circleRadiusMain = canvasHelper.width / 2;
131 | var circleRadius = circleRadiusMain;
132 | } else {
133 |
134 | var circleRadiusMain = (canvasHelper.width / 2) - this.lineWidth;
135 |
136 | canvasHelperCtx.arc(this.size / 2, this.size / 2, circleRadiusMain, 0, PI * 2);
137 | canvasHelperCtx.strokeStyle = 'rgba(0, 0, 0, 0.4)';
138 | canvasHelperCtx.lineWidth = this.lineWidth;
139 | canvasHelperCtx.stroke();
140 |
141 | var circleRadius = circleRadiusMain - 6;
142 | canvasHelperCtx.closePath();
143 | canvasHelperCtx.beginPath();
144 | canvasHelperCtx.arc(this.size / 2, this.size / 2, circleRadius, 0, PI * 2);
145 | canvasHelperCtx.strokeStyle = 'rgba(0, 0, 0, 0.4)';
146 | canvasHelperCtx.lineWidth = this.lineWidth;
147 | canvasHelperCtx.stroke();
148 | canvasHelperCtx.closePath();
149 | }
150 |
151 | canvasHelperCtx.beginPath();
152 | var svmSize;
153 |
154 | if (switchFig == 'quad') {
155 | var workDiametr = (circleRadius * 2) - 4; // may be some paddings here
156 | svmSize = Math.floor(workDiametr / Math.sqrt(2));
157 | var padding = (this.size - svmSize) / 2;
158 | var svmPos = {x: padding + svmSize, y: padding + svmSize / 2}; // start middle point
159 | svmPos.y = svmPos.y - (svmSize / 2);
160 | canvasHelperCtx.moveTo(svmPos.x, svmPos.y); // right top
161 | canvasHelperCtx.lineTo(svmPos.x - svmSize, svmPos.y); // left tp
162 | canvasHelperCtx.lineTo(svmPos.x - svmSize, svmPos.y + svmSize); // left bottom
163 | canvasHelperCtx.lineTo(svmPos.x, svmPos.y + svmSize); // right bottom
164 |
165 | } else {
166 | svmSize = Math.floor((2 * circleRadius - 4) * Math.sin(toRadians(60))); // side size
167 | var svmPos = {x: circleRadius * 2 + (circleRadiusMain - circleRadius), y: this.size / 2}; // start middle point
168 | var h = ((Math.sqrt(3) / 2) * svmSize);
169 | canvasHelperCtx.moveTo(svmPos.x, svmPos.y);
170 | canvasHelperCtx.lineTo(svmPos.x - h, svmPos.y - (svmSize / 2)); // top
171 | canvasHelperCtx.lineTo(svmPos.x - h, svmPos.y + (svmSize / 2)); // bottom
172 | canvasHelperCtx.lineTo(svmPos.x, svmPos.y);
173 | }
174 |
175 | canvasHelperCtx.lineTo(svmPos.x, svmPos.y);
176 |
177 |
178 | canvasHelperCtx.fillStyle = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ', 1)';
179 | canvasHelperCtx.fill();
180 | canvasHelperCtx.lineWidth = this.lineWidth;
181 | canvasHelperCtx.strokeStyle = 'rgba(0, 0, 0, 0.6)';
182 | canvasHelperCtx.stroke();
183 | canvasHelperCtx.closePath();
184 |
185 |
186 | this.imageData[method] = canvasHelperCtx.getImageData(0, 0, canvasHelper.width, canvasHelper.width);
187 | ctx.drawImage(canvasHelper, this.position.x, this.position.y);
188 |
189 | }
190 |
191 | styleSwitch.isDotIn = function (dot) {
192 | if (
193 | dot.x >= this.position.x && dot.x <= this.position.x + this.size &&
194 | dot.y >= this.position.y && dot.y <= this.position.y + this.size
195 | ) {
196 | return true;
197 | }
198 |
199 | //if (Math.pow(this.position.x - dot.x, 2) + Math.pow(this.position.y - dot.y, 2) < Math.pow(this.outerRadius, 2)) {
200 | // return true;
201 | //}
202 |
203 | return false;
204 | }
205 | }
206 |
207 | // triangle colorsavers for left and right side
208 | function initColorSaver(align, selected, color) {
209 |
210 | if (!selected)
211 | selected = false;
212 | else
213 | selected = true;
214 |
215 | var colorSaver = new Object;
216 | colorSaver.width; // size of side of triangle
217 | colorSaver.widthPercentage = 22;
218 |
219 | colorSaver.imageData = null; // last rendered colorsaver image
220 | colorSaver.align = align;
221 | colorSaver.selected = selected; // current color
222 | colorSaver.color = '#ffffff'; // hex color
223 | colorSaver.position; // top point of triangle
224 | colorSaver.paddingY = -4;
225 | colorSaver.paddingX = 4;
226 | colorSaver.lineWidth = 1;
227 | colorSaver.selectSize = 4;
228 |
229 | if (align == 'right') {
230 | colorSaver.paddingX = colorSaver.paddingX * -1;
231 | }
232 |
233 | if (colorSaver.selected) {
234 | colorSaver.color = hex;
235 | }
236 |
237 | if (color) {
238 | colorSaver.color = color;
239 | }
240 |
241 | colorSaver.updateSize = function () {
242 | this.width = parseInt(wheelBlockSize - (wheelBlockSize / 100) * (100 - this.widthPercentage));
243 |
244 | // start render point in global canvas coords
245 | if (this.align == 'left') {
246 | this.position = {x: 0, y: wheelBlockSize - this.width};
247 | } else if (this.align == 'right') {
248 | this.position = {x: wheelBlockSize - this.width, y: wheelBlockSize - this.width};
249 | }
250 | }
251 |
252 | // calc triangle area (same method as for triangle sv figure)
253 | colorSaver.calcS = function (p) {
254 | return Math.abs((p[1].x - p[0].x) * (p[2].y - p[0].y) - (p[2].x - p[0].x) * (p[1].y - p[0].y)) / 2;
255 | }
256 |
257 | colorSaver.isDotIn = function (dot) {
258 |
259 | var path = new Array();
260 |
261 | if (this.align == 'left') {
262 | path[0] = {x: this.position.x, y: this.position.y}; // top
263 | path[1] = {x: this.position.x, y: this.position.y + this.width}; // bottom left
264 | path[2] = {x: this.position.x + this.width, y: this.position.y + this.width}; // bottom right
265 | } else {
266 | path[0] = {x: this.position.x + this.width, y: this.position.y}; // top
267 | path[1] = {x: path[0].x, y: path[0].y + this.width}; // bottom right
268 | path[2] = {x: path[0].x - this.width, y: this.position.y + this.width}; // bottom left
269 | }
270 |
271 | for (var i = 0; i <= path.length - 1; ++i)
272 | {
273 | path[i].x += this.paddingX;
274 | path[i].y += this.paddingY;
275 | }
276 |
277 | var selfS = this.calcS(path);
278 |
279 | var t = [
280 | {x: path[0].x, y: path[0].y},
281 | {x: path[1].x, y: path[1].y},
282 | {x: dot.x, y: dot.y}
283 | ];
284 |
285 | var s = this.calcS(t);
286 | t[1] = {x: path[2].x, y: path[2].y};
287 | s += this.calcS(t);
288 | t[0] = {x: path[1].x, y: path[1].y};
289 | s += this.calcS(t);
290 |
291 | if (Math.ceil(s) == Math.ceil(selfS))
292 | return true;
293 | else
294 | return false;
295 | }
296 |
297 | colorSaver.draw = function () {
298 |
299 | canvasHelper.width = this.width;
300 | canvasHelper.height = this.width;
301 |
302 | canvasHelperCtx.clearRect(0, 0, this.width, this.width);
303 | canvasHelperCtx.beginPath();
304 |
305 | if (this.align == 'left') {
306 | canvasHelperCtx.moveTo(this.lineWidth / 2, this.width - this.lineWidth);
307 | canvasHelperCtx.lineTo(this.width, this.width - this.lineWidth);
308 | canvasHelperCtx.lineTo(this.lineWidth, this.lineWidth);
309 | canvasHelperCtx.lineTo(this.lineWidth, this.width - this.lineWidth);
310 | }
311 |
312 | if (this.align == 'right') {
313 | canvasHelperCtx.moveTo(this.lineWidth / 2, this.width - this.lineWidth);
314 | canvasHelperCtx.lineTo(this.width - this.lineWidth, this.width - this.lineWidth);
315 | canvasHelperCtx.lineTo(this.width - this.lineWidth, this.lineWidth);
316 | canvasHelperCtx.lineTo(this.lineWidth, this.width - this.lineWidth);
317 | }
318 |
319 | if (this.selected) {
320 |
321 | // start draw addition inner figure
322 |
323 | canvasHelperCtx.fillStyle = 'rgba(255,255,255, 1)';
324 | canvasHelperCtx.fill();
325 |
326 | canvasHelperCtx.strokeStyle = 'rgba(0, 0, 0, 1)';
327 | canvasHelperCtx.stroke();
328 | canvasHelperCtx.closePath();
329 | canvasHelperCtx.beginPath();
330 |
331 | canvasHelperCtx.lineWidth = this.lineWidth;
332 |
333 | if (this.align == 'left') {
334 | canvasHelperCtx.moveTo(this.selectSize, this.width - this.selectSize);
335 | canvasHelperCtx.lineTo(this.width - this.selectSize * 2, this.width - this.selectSize);
336 | canvasHelperCtx.lineTo(this.selectSize, this.selectSize * 2);
337 | canvasHelperCtx.lineTo(this.selectSize, this.width - this.selectSize);
338 | }
339 |
340 | if (this.align == 'right') {
341 |
342 | canvasHelperCtx.moveTo(this.selectSize * 2, this.width - this.selectSize);
343 | canvasHelperCtx.lineTo(this.width - this.selectSize, this.width - this.selectSize);
344 | canvasHelperCtx.lineTo(this.width - this.selectSize, this.selectSize * 2);
345 | canvasHelperCtx.lineTo(this.selectSize * 2, this.width - this.selectSize);
346 | }
347 | }
348 |
349 | var rgb = hexToRgb(this.color);
350 | canvasHelperCtx.fillStyle = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ', 1)';
351 | canvasHelperCtx.fill();
352 | canvasHelperCtx.strokeStyle = 'rgba(0, 0, 0, 1)';
353 | canvasHelperCtx.stroke();
354 |
355 | this.imageData = canvasHelperCtx.getImageData(0, 0, this.width, this.width);
356 | ctx.drawImage(canvasHelper, this.position.x + this.paddingX, this.position.y + this.paddingY);
357 |
358 | }
359 |
360 | var colorSaverKey = colorSavers.length;
361 | colorSavers[colorSaverKey] = colorSaver;
362 | }
363 |
364 | var wheel = new Object;
365 | wheel.width = 18;
366 | wheel.imageData = null; // rendered wheel image data
367 | wheel.innerRadius;
368 | wheel.startAngle = 0; // 150
369 | wheel.outerRadius;
370 | wheel.outerStrokeStyle = 'rgba(0,0,0,0.2)';
371 | wheel.innerStrokeStyle = 'rgba(0,0,0,0.2)';
372 | wheel.pos; // updates in updateSize() | center point; wheel cursor \ hsv quad \ hsv triangle positioned relative that point
373 | wheel.draw = function () {
374 |
375 | // put rendered data
376 |
377 | if (this.imageData) {
378 |
379 | canvasHelper.width = wheelBlockSize;
380 | canvasHelper.height = wheelBlockSize;
381 | canvasHelperCtx.putImageData(this.imageData, 0, 0); // use helper only, put image data directly to ctx cause render bug if combine with draw image ontop after (ex. in triangle.draw) in modern chrome versions
382 | ctx.drawImage(canvasHelper, 0, 0); // draw with save overlaps transparent things , not direct putImageData that rewrite all pixels
383 |
384 | } else {
385 | var hAngle = this.startAngle;
386 | for (var angle = 0; angle <= 360; angle++) {
387 |
388 | var startAngle = toRadians(angle - 2);
389 | var endAngle = toRadians(angle);
390 |
391 | ctx.beginPath();
392 | ctx.moveTo(center, center);
393 | ctx.arc(center, center, this.outerRadius, startAngle, endAngle, false);
394 | ctx.closePath();
395 |
396 | var targetRgb = hsvToRgb(hAngle / 360, 1, 1);
397 | ctx.fillStyle = 'rgb(' + targetRgb.r + ', ' + targetRgb.g + ', ' + targetRgb.b + ')';
398 | //ctx.fillStyle = 'hsl('+hAngle+', 100%, 50%)';
399 | ctx.fill();
400 |
401 | hAngle++;
402 | if (hAngle >= 360)
403 | hAngle = 0;
404 | }
405 |
406 | ctx.globalCompositeOperation = "destination-out"; // cut out color wheel inside by circle next
407 | ctx.beginPath();
408 | ctx.arc(center, center, this.innerRadius, 0, PI * 2);
409 |
410 | ctx.fill();
411 |
412 | ctx.globalCompositeOperation = "source-over";
413 | ctx.strokeStyle = this.innerStrokeStyle; // 'rgba(0,0,0,0.2)';
414 | ctx.lineWidth = 2;
415 | ctx.stroke();
416 | ctx.closePath();
417 |
418 | // wheel border
419 | ctx.beginPath();
420 | ctx.arc(center, center, this.outerRadius, 0, PI * 2);
421 | ctx.strokeStyle = this.outerStrokeStyle;
422 | ctx.lineWidth = 2;
423 | ctx.stroke();
424 | ctx.closePath();
425 |
426 | this.imageData = ctx.getImageData(0, 0, wheelBlockSize, wheelBlockSize);
427 | }
428 |
429 | };
430 |
431 | wheel.isDotIn = function (dot) {
432 | // is dot in circle
433 | if (Math.pow(this.pos.x - dot.x, 2) + Math.pow(this.pos.y - dot.y, 2) < Math.pow(this.outerRadius, 2)) {
434 | if (Math.pow(this.pos.x - dot.x, 2) + Math.pow(this.pos.y - dot.y, 2) > Math.pow(this.innerRadius, 2)) {
435 | return true;
436 | }
437 | }
438 | return false;
439 | };
440 |
441 | var wheelCursor = new Object;
442 | wheelCursor.lineWeight = 2;
443 | wheelCursor.height = 4;
444 | wheelCursor.paddingX = 2; // padding from sides of wheel
445 | wheelCursor.path; // rotatePath2 --- поворот по старой функции, в фигуре не приплюсован центр
446 |
447 | var alphaSlider = new Object;
448 | alphaSlider.width = 18;
449 | alphaSlider.padding = 4;
450 | alphaSlider.outerStrokeStyle = 'rgba(0,0,0,0.2)';
451 | alphaSlider.innerStrokeStyle = 'rgba(0,0,0,0.2)';
452 | alphaSlider.height;
453 | alphaSlider.pos; // left top corner position
454 | alphaSlider.updateSize = function () {
455 | this.pos = {x: wheelBlockSize + alphaSlider.padding, y: alphaSlider.padding};
456 | this.height = wheelBlockSize - alphaSlider.padding * 2;
457 | };
458 |
459 | alphaSlider.draw = function () {
460 | var alphaGrd = ctx.createLinearGradient(0, 0, 0, this.height);
461 |
462 | var aRgb = hsvToRgb(hsv.h, 1, 1);
463 |
464 | alphaGrd.addColorStop(0, 'rgba(' + aRgb.r + ',' + aRgb.g + ',' + aRgb.b + ',1)');
465 | alphaGrd.addColorStop(1, 'rgba(' + aRgb.r + ',' + aRgb.g + ',' + aRgb.b + ',0)');
466 |
467 | ctx.beginPath();
468 | ctx.rect(this.pos.x, this.pos.y, this.width, this.height);
469 | ctx.fillStyle = "white";
470 | ctx.fill();
471 | ctx.fillStyle = alphaGrd;
472 | ctx.fill();
473 |
474 | ctx.strokeStyle = 'rgba(0,0,0, 0.2)';
475 | ctx.lineWidth = 2;
476 |
477 | ctx.stroke();
478 | ctx.closePath();
479 | };
480 |
481 | alphaSlider.dotToAlpha = function (dot) {
482 | return 1 - Math.abs(this.pos.y - dot.y) / this.height;
483 | };
484 |
485 | alphaSlider.alphaToDot = function (alpha) {
486 | return {
487 | x: 0,
488 | y: this.height - (this.height * alpha)
489 | };
490 | };
491 |
492 | alphaSlider.limitDotPosition = function (dot) {
493 | var y = dot.y;
494 |
495 | if (y < this.pos.y) {
496 | y = this.pos.y;
497 | }
498 |
499 | if (y > this.pos.y + this.height) {
500 | y = this.pos.y + this.height;
501 | }
502 |
503 | return {x: this.pos.x, y: y};
504 | };
505 |
506 | alphaSlider.isDotIn = function (dot) {
507 | if (dot.x < this.pos.x ||
508 | dot.x > this.pos.x + alphaSlider.width ||
509 | dot.y < this.pos.y ||
510 | dot.y > this.pos.y + this.height) {
511 | return false;
512 | }
513 | return true;
514 | };
515 |
516 | // svCursorMouse - для устройств с мышкой, генератор указателя в зависимости от активной области
517 | // todo on very very small sv when set by hex, cursor may be go out of bounds
518 | var svCursorMouse = new Object;
519 |
520 | svCursorMouse.svCursorData = null;
521 | svCursorMouse.stCursor = null; // cursor before replace
522 | svCursorMouse.curType = 0; // if > 0 cursor switched by KellyColorPicker to custom
523 | svCursorMouse.size = 16;
524 | svCursorMouse.cEl = document.body;
525 |
526 | svCursorMouse.initSvCursor = function () {
527 | if (!canvas)
528 | return false;
529 |
530 | this.curType = 1;
531 |
532 | if (!this.stCursor) {
533 |
534 | this.stCursor = window.getComputedStyle(this.cEl).cursor;
535 |
536 | if (!this.stCursor) {
537 | this.stCursor = 'auto';
538 | }
539 | }
540 |
541 | if (this.svCursorData) {
542 | this.cEl.style.cursor = this.svCursorData;
543 | return true;
544 | }
545 |
546 | if (!canvasHelper)
547 | return false;
548 |
549 | // create canvas on 2 pixels bigger for Opera that cut image
550 | var canvasSize = this.size + 2;
551 |
552 | canvasHelper.width = canvasSize;
553 | canvasHelper.height = canvasSize;
554 |
555 | canvasHelperCtx.clearRect(0, 0, this.size, this.size);
556 | canvasHelperCtx.strokeStyle = 'rgba(255, 255, 255, 1)';
557 |
558 | canvasHelperCtx.beginPath();
559 | canvasHelperCtx.lineWidth = 2;
560 | canvasHelperCtx.arc(canvasSize / 2, canvasSize / 2, this.size / 2, 0, PI * 2);
561 |
562 | canvasHelperCtx.stroke();
563 | canvasHelperCtx.closePath();
564 |
565 | var offset = canvasSize; //if (input.value.indexOf(curImageData) !== -1)
566 | var curImageData = canvasHelper.toDataURL();
567 |
568 | this.svCursorData = 'url(' + curImageData + ') ' + offset / 2 + ' ' + offset / 2 + ', auto';
569 |
570 | if (!this.svCursorData)
571 | return false;
572 |
573 | this.cEl.style.cursor = this.svCursorData;
574 | if (this.cEl.style.cursor.indexOf(curImageData) === -1) { // for autist IE (Edge also), that not support data-uri for cursor -_-
575 | this.svCursorData = 'crosshair';
576 | this.cEl.style.cursor = 'crosshair';
577 | }
578 | return true;
579 | };
580 |
581 | svCursorMouse.initStandartCursor = function () {
582 | if (!this.stCursor)
583 | return;
584 |
585 | svCursorMouse.curType = 0;
586 | this.cEl.style.cursor = this.stCursor;
587 | };
588 |
589 | svCursorMouse.updateCursor = function (newDot) {
590 | if (!changeCursor)
591 | return;
592 |
593 | if (KellyColorPicker.cursorLock)
594 | return;
595 |
596 | if (svFig.isDotIn(newDot)) {
597 | svCursorMouse.initSvCursor();
598 | } else {
599 | svCursorMouse.initStandartCursor();
600 | }
601 | };
602 |
603 | // updateinput
604 |
605 | function constructor(cfg) {
606 | var criticalError = '', placeName = '';
607 |
608 | // save non-camelased old style options compatibility
609 |
610 | if (cfg.alpha_slider !== undefined) {
611 | cfg.alphaSlider = cfg.alpha_slider;
612 | }
613 |
614 | if (cfg.input_color !== undefined) {
615 | cfg.inputColor = cfg.input_color;
616 | }
617 |
618 | if (cfg.input_format !== undefined) {
619 | cfg.inputFormat = cfg.input_format;
620 | }
621 |
622 | // config apply
623 |
624 | if (cfg.input && typeof cfg.input !== 'object') {
625 | cfg.input = document.getElementById(cfg.input);
626 | input = cfg.input;
627 | // if (!cfg.input) log += '| "input" (' + inputName + ') not not found';
628 | } else if (typeof cfg.input === 'object') {
629 | input = cfg.input;
630 | }
631 |
632 | if (cfg.changeCursor !== undefined) {
633 | changeCursor = cfg.changeCursor;
634 | }
635 |
636 | if (cfg.alpha !== undefined) {
637 | a = cfg.alpha;
638 | }
639 |
640 | if (cfg.alphaSlider !== undefined) {
641 | alpha = cfg.alphaSlider;
642 | }
643 |
644 | if (cfg.inputColor !== undefined) {
645 | inputColor = cfg.inputColor;
646 | }
647 |
648 | if (cfg.inputFormat !== undefined) {
649 | inputFormat = cfg.inputFormat;
650 | }
651 |
652 | if (cfg.userEvents)
653 | userEvents = cfg.userEvents;
654 |
655 | if (cfg.place && typeof cfg.place !== 'object') {
656 | placeName = cfg.place;
657 | cfg.place = document.getElementById(cfg.place);
658 | }
659 |
660 | if (cfg.place) {
661 | place = cfg.place;
662 | } else if (input) {
663 |
664 | popup.tag = document.createElement('div');
665 | popup.tag.className = "popup-kelly-color";
666 |
667 | if (!cfg.popupClass) {
668 |
669 | popup.tag.className = "popup-kelly-color";
670 |
671 | popup.tag.style.position = 'absolute';
672 | popup.tag.style.bottom = '0px';
673 | popup.tag.style.left = '0px';
674 | popup.tag.style.display = 'none';
675 | popup.tag.style.backgroundColor = '#e1e1e1';
676 | popup.tag.style.border = "1px solid #bfbfbf";
677 | popup.tag.style.boxShadow = "7px 7px 14px -3px rgba(0,0,0,0.24)";
678 | popup.tag.style.borderTopLeftRadius = '4px';
679 | popup.tag.style.borderTopRightRadius = '4px';
680 | popup.tag.style.borderBottomLeftRadius = '4px';
681 | popup.tag.style.borderBottomRightRadius = '4px';
682 | popup.tag.style.padding = "12px";
683 | popup.tag.style.boxSizing = "content-box";
684 |
685 | } else {
686 | popup.tag.className = cfg.popupClass;
687 | }
688 |
689 | place = popup.tag;
690 |
691 | var body = document.getElementsByTagName('body')[0];
692 | body.appendChild(popup.tag);
693 |
694 | addEventListner(input, "click", function (e) {
695 | return handler.popUpShow(e);
696 | }, 'popup_');
697 |
698 | } // attach directly to input by popup
699 | else
700 | criticalError += '| "place" (' + placeName + ') not not found';
701 |
702 | // hex default #000000
703 | var colorData = false;
704 |
705 | if (cfg.color) {
706 | colorData = readColorData(cfg.color);
707 | } else if (input && input.value) {
708 | colorData = readColorData(input.value);
709 | }
710 |
711 | if (colorData) {
712 | hex = colorData.h;
713 | if (alpha)
714 | a = colorData.a;
715 | }
716 |
717 | //if (hex.charAt(0) == '#') hex = hex.slice(1);
718 | //if (hex.length == 3) hex = hex + hex;
719 | //if (hex.length !== 6) hex = '#000000';
720 |
721 | if (cfg.method && (cfg.method == 'triangle' || cfg.method == 'quad'))
722 | method = cfg.method;
723 |
724 | if (!initCanvas()) {
725 | criticalError += ' | cant init canvas context';
726 | }
727 |
728 | // size of elments init
729 |
730 | if (cfg.resizeWith) {
731 |
732 | if (typeof cfg.resizeWith !== 'object' && typeof cfg.resizeWith !== 'boolean')
733 | cfg.resizeWith = document.getElementById(cfg.resizeWith);
734 |
735 | if (cfg.resizeWith === true) {
736 | resizeWith = canvas;
737 | } else {
738 | resizeWith = cfg.resizeWith;
739 | }
740 |
741 | if (cfg.resizeSide)
742 | resizeSide = cfg.resizeSide;
743 |
744 | if (resizeWith) {
745 | var newSize = getSizeByElement(resizeWith);
746 | if (newSize)
747 | cfg.size = getSizeByElement(resizeWith);
748 |
749 | addEventListner(window, "resize", function (e) {
750 | return handler.syncSize(e);
751 | }, 'canvas_');
752 | }
753 | }
754 |
755 | if (cfg.size && cfg.size > 0) {
756 | wheelBlockSize = cfg.size;
757 | }
758 |
759 | // size init end
760 |
761 | if (criticalError) {
762 | if (typeof console !== 'undefined')
763 | console.log('KellyColorPicker : ' + criticalError);
764 | return;
765 | }
766 |
767 | if (method == 'quad')
768 | svFig = getSvFigureQuad();
769 | if (method == 'triangle')
770 | svFig = getSvFigureTriangle();
771 |
772 | if (input) {
773 | var inputEdit = function (e) {
774 | var e = e || window.event;
775 | if (!e.target) {
776 | e.target = e.srcElement;
777 | }
778 | handler.setColorByHex(e.target.value, true);
779 | };
780 |
781 | addEventListner(input, "click", inputEdit, 'input_edit_');
782 | addEventListner(input, "change", inputEdit, 'input_edit_');
783 | addEventListner(input, "keyup", inputEdit, 'input_edit_');
784 | addEventListner(input, "keypress", inputEdit, 'input_edit_');
785 | }
786 |
787 | if (cfg.colorSaver) {
788 | initColorSaver('left', true);
789 | initColorSaver('right');
790 | }
791 |
792 | if (cfg.methodSwitch) {
793 | initStyleSwitch();
794 | }
795 |
796 | enableEvents();
797 |
798 | updateSize();
799 | handler.setColorByHex(false); // update color info and first draw
800 | }
801 |
802 | // may be zero in some cases / check before applay
803 |
804 | function getSizeByElement(el) {
805 |
806 | var sizeInfo = el.getBoundingClientRect();
807 | var size = 0;
808 | var sizeReduse = 0;
809 | if (alpha) {
810 | sizeReduse = alphaSlider.width + alphaSlider.padding * 2;
811 | }
812 |
813 | if (el === canvas) {
814 | if (sizeInfo.width <= sizeInfo.height)
815 | size = sizeInfo.height;
816 | else if (sizeInfo.height < sizeInfo.width)
817 | size = sizeInfo.width;
818 | } else {
819 |
820 | if (resizeSide) {
821 | if (resizeSide == 'height')
822 | size = sizeInfo.height;
823 | else if (resizeSide == 'width')
824 | size = sizeInfo.width;
825 | } else {
826 | if (sizeInfo.width > sizeInfo.height)
827 | size = sizeInfo.height;
828 | else if (sizeInfo.height >= sizeInfo.width)
829 | size = sizeInfo.width;
830 | }
831 | }
832 |
833 | size = parseInt(size);
834 |
835 | if (alpha) {
836 |
837 | size -= sizeReduse;
838 | }
839 |
840 | if (size <= 0) {
841 | return false;
842 | }
843 |
844 | return size;
845 | }
846 |
847 | // Read color value from string cString in rgb \ rgba \ hex \ hsl \ hsla format or from object ex. rgb {r : 255, g : 255, b : 255, a : 1}, hsv {h : 1, s: 1, l : 1, a : 1}
848 | // return array {h : color in rgb hex format (string #000000), a : alpha (float value from 0 to 1) }
849 | // falseOnFail = false - return default array on fail {h : '#000000', a : 1} or return false on fail if true
850 |
851 | function readColorData(cString, falseOnFail) {
852 |
853 | var alpha = 1;
854 | var h = false;
855 |
856 | if (typeof cString == 'string') {
857 |
858 | cString = cString.trim(cString);
859 |
860 | if (cString.indexOf("(") == -1) { // hex color
861 |
862 | if (cString.charAt(0) == '#')
863 | cString = cString.slice(1);
864 |
865 | cString = cString.substr(0, 8);
866 |
867 | if (cString.length >= 3) {
868 |
869 | if (cString.length > 6 && cString.length < 8) {
870 | cString = cString.substr(0, 6); // bad alpha data
871 | }
872 |
873 | if (cString.length > 3 && cString.length < 6) {
874 | cString = cString.substr(0, 3); // bad full format
875 | }
876 |
877 | h = cString;
878 |
879 | // complite full format, by replicating the R, G, and B values
880 |
881 | if (cString.length >= 3 && cString.length <= 4) {
882 |
883 | h = "";
884 |
885 | for (let i = 0; i < cString.length; i++) {
886 | h += cString[i] + cString[i];
887 | }
888 | }
889 |
890 | if (h.length == 8)
891 | alpha = (parseInt(h, 16) & 255) / 255;
892 |
893 | }
894 |
895 | } else {
896 |
897 | vals = cString.split(",");
898 |
899 | if (vals.length >= 3) {
900 |
901 | switch (cString.substring(0, 3)) {
902 |
903 | case 'rgb':
904 |
905 | vals[0] = vals[0].replace("rgba(", "");
906 | vals[0] = vals[0].replace("rgb(", "");
907 |
908 | var rgb = {r: parseInt(vals[0]), g: parseInt(vals[1]), b: parseInt(vals[2])};
909 |
910 | if (rgb.r <= 255 && rgb.g <= 255 && rgb.b <= 255) {
911 | h = rgbToHex(rgb);
912 | }
913 |
914 | break;
915 |
916 | case 'hsl':
917 |
918 | vals[0] = vals[0].replace("hsl(", "");
919 | vals[0] = vals[0].replace("hsla(", "");
920 |
921 | var hue = parseFloat(vals[0]) / 360.0;
922 | var s = parseFloat(vals[1]) / 100.0; //js will ignore % in the end
923 | var l = parseFloat(vals[2]) / 100.0;
924 |
925 | if (hue >= 0 && s <= 1 && l <= 1) {
926 | h = rgbToHex(hsvToRgb(hue, s, l));
927 | }
928 |
929 | break;
930 | }
931 |
932 | if (vals.length == 4) {
933 |
934 | alpha = parseFloat(vals[3]);
935 |
936 | if (!alpha || alpha < 0)
937 | alpha = 0;
938 |
939 | if (alpha > 1)
940 | alpha = 1;
941 | }
942 | }
943 | }
944 |
945 | } else if (typeof cString == 'object') {
946 |
947 | if (typeof cString.r != 'undefined' &&
948 | typeof cString.g != 'undefined' &&
949 | typeof cString.b != 'undefined') { // rgb input
950 |
951 | h = rgbToHex(cString);
952 |
953 | } else if (
954 | typeof cString.h != 'undefined' &&
955 | typeof cString.s != 'undefined' &&
956 | typeof cString.l != 'undefined') {
957 |
958 | cString.h = parseFloat(cString.h) / 360.0;
959 | cString.s = parseFloat(cString.s) / 100.0;
960 | cString.l = parseFloat(cString.l) / 100.0;
961 |
962 | if (cString.h >= 0 && cString.s <= 1 && cString.l <= 1) {
963 | h = rgbToHex(hsvToRgb(cString.h, cString.s, cString.l));
964 | }
965 | }
966 |
967 | if (typeof cString.a != 'undefined') {
968 |
969 | alpha = cString.a;
970 | }
971 | }
972 |
973 | if (h === false && falseOnFail) {
974 |
975 | return false;
976 | }
977 |
978 | if (h === false) {
979 |
980 | h = '000000';
981 | }
982 |
983 | if (h.charAt(0) != '#') {
984 |
985 | h = h.substr(0, 6);
986 | h = '#' + h;
987 |
988 | } else {
989 |
990 | h = h.substr(0, 7); // for private purposes must contain only rgb part
991 | }
992 |
993 | return {h: h, a: alpha};
994 | }
995 |
996 | function getSvFigureQuad() {
997 |
998 | if (svFigsPool['quad'])
999 | return svFigsPool['quad'];
1000 |
1001 | var quad = new Object;
1002 | quad.size;
1003 | quad.padding = 2;
1004 | quad.path; // крайние точки фигуры на координатной плоскости
1005 | quad.imageData = null; // rendered quad image data
1006 | // перезаписывается существующий, чтобы не вызывать утечек памяти, обнуляя прошлый
1007 | // тк UInt8ClampedArray генерируемый createImageData стандартными способами не
1008 | // во всех браузерах выгружается сразу
1009 |
1010 | quad.dotToSv = function (dot) {
1011 | return {
1012 | s: Math.abs(this.path[3].x - dot.x) / this.size,
1013 | v: Math.abs(this.path[3].y - dot.y) / this.size
1014 | };
1015 | };
1016 |
1017 | quad.svToDot = function (sv) {
1018 | var quadX = this.path[0].x;
1019 | var quadY = this.path[0].y;
1020 |
1021 | var svError = 0.02;
1022 | if (wheelBlockSize < 150) {
1023 | svError = 0.07;
1024 | } else if (wheelBlockSize < 100) {
1025 | svError = 0.16;
1026 | }
1027 |
1028 | for (var y = 0; y < this.size; y++) {
1029 | for (var x = 0; x < this.size; x++) {
1030 | var dot = {x: x + quadX, y: y + quadY};
1031 | var targetSv = this.dotToSv(dot);
1032 | var es = Math.abs(targetSv.s - sv.s), ev = Math.abs(targetSv.v - sv.v);
1033 |
1034 | if (es < svError && ev < svError) {
1035 | return dot;
1036 | }
1037 | }
1038 | }
1039 |
1040 | return {x: 0, y: 0};
1041 | };
1042 |
1043 | quad.limitDotPosition = function (dot) {
1044 | var x = dot.x;
1045 | var y = dot.y;
1046 |
1047 | if (x < this.path[0].x) {
1048 | x = this.path[0].x;
1049 | }
1050 |
1051 | if (x > this.path[0].x + this.size) {
1052 | x = this.path[0].x + this.size;
1053 | }
1054 |
1055 | if (y < this.path[0].y) {
1056 | y = this.path[0].y;
1057 | }
1058 |
1059 | if (y > this.path[0].y + this.size) {
1060 | y = this.path[0].y + this.size;
1061 | }
1062 |
1063 | return {x: x, y: y};
1064 | };
1065 |
1066 | quad.draw = function () {
1067 | if (!this.imageData)
1068 | this.imageData = ctx.createImageData(this.size, this.size);
1069 | var i = 0;
1070 |
1071 | var quadX = this.path[0].x;
1072 | var quadY = this.path[0].y;
1073 |
1074 | for (var y = 0; y < this.size; y++) {
1075 | for (var x = 0; x < this.size; x++) {
1076 | var dot = {x: x + quadX, y: y + quadY};
1077 |
1078 | var sv = this.dotToSv(dot);
1079 | var targetRgb = hsvToRgb(hsv.h, sv.s, sv.v);
1080 | this.imageData.data[i + 0] = targetRgb.r;
1081 | this.imageData.data[i + 1] = targetRgb.g;
1082 | this.imageData.data[i + 2] = targetRgb.b;
1083 | this.imageData.data[i + 3] = 255;
1084 | i += 4;
1085 | }
1086 | }
1087 |
1088 | ctx.putImageData(this.imageData, quadX, quadY);
1089 |
1090 | ctx.beginPath();
1091 | ctx.strokeStyle = 'rgba(0,0,0, 0.2)';
1092 | ctx.lineWidth = 2;
1093 | for (var i = 0; i <= this.path.length - 1; ++i)
1094 | {
1095 | if (i == 0)
1096 | ctx.moveTo(this.path[i].x, this.path[i].y);
1097 | else
1098 | ctx.lineTo(this.path[i].x, this.path[i].y);
1099 | }
1100 |
1101 | ctx.stroke();
1102 |
1103 | ctx.closePath();
1104 | };
1105 |
1106 | quad.updateSize = function () {
1107 | var workD = (wheel.innerRadius * 2) - wheelCursor.paddingX * 2 - this.padding * 2;
1108 |
1109 | // исходя из формулы диагонали квадрата, узнаем длинну стороны на основании доступного диаметра
1110 | this.size = Math.floor(workD / Math.sqrt(2));
1111 |
1112 | this.path = new Array();
1113 |
1114 | // находим верхнюю левую точку и от нее задаем остальные координаты
1115 | this.path[0] = {x: -1 * (this.size / 2), y: -1 * (this.size / 2)};
1116 | this.path[1] = {x: this.path[0].x + this.size, y: this.path[0].y};
1117 | this.path[2] = {x: this.path[1].x, y: this.path[1].y + this.size};
1118 | this.path[3] = {x: this.path[2].x - this.size, y: this.path[2].y};
1119 | this.path[4] = {x: this.path[0].x, y: this.path[0].y};
1120 |
1121 | for (var i = 0; i <= this.path.length - 1; ++i) {
1122 | this.path[i].x += wheel.pos.x;
1123 | this.path[i].y += wheel.pos.y;
1124 | }
1125 | }
1126 |
1127 | quad.isDotIn = function (dot) {
1128 | if (dot.x < this.path[0].x ||
1129 | dot.x > this.path[0].x + this.size ||
1130 | dot.y < this.path[0].y ||
1131 | dot.y > this.path[0].y + this.size) {
1132 | return false;
1133 | }
1134 | return true;
1135 | };
1136 |
1137 | svFigsPool['quad'] = quad;
1138 | return quad;
1139 | }
1140 |
1141 | function getSvFigureTriangle() {
1142 |
1143 | if (svFigsPool['triangle'])
1144 | return svFigsPool['triangle'];
1145 |
1146 | var triangle = new Object;
1147 | triangle.size; // сторона равностороннего треугольника
1148 | triangle.padding = 2;
1149 | triangle.path;
1150 | triangle.imageData = null; // rendered triangle image data
1151 | triangle.followWheel = true;
1152 | triangle.s;
1153 | triangle.sOnTop = false;
1154 | triangle.outerRadius;
1155 |
1156 | triangle.limitDotPosition = function (dot) {
1157 | var x = dot.x;
1158 | var y = dot.y;
1159 |
1160 | var slopeToCtr;
1161 | var maxX = this.path[0].x;
1162 | var minX = this.path[2].x;
1163 | var finalX = x;
1164 | var finalY = y;
1165 |
1166 | finalX = Math.min(Math.max(minX, finalX), maxX);
1167 | var slope = ((this.path[0].y - this.path[1].y) / (this.path[0].x - this.path[1].x));
1168 | var minY = Math.ceil((this.path[1].y + (slope * (finalX - this.path[1].x))));
1169 | slope = ((this.path[0].y - this.path[2].y) / (this.path[0].x - this.path[2].x));
1170 | var maxY = Math.floor((this.path[2].y + (slope * (finalX - this.path[2].x))));
1171 |
1172 | if (x < minX) {
1173 | slopeToCtr = ((wheel.pos.y - y) / (wheel.pos.x - x));
1174 | finalY = y;
1175 | }
1176 |
1177 | finalY = Math.min(Math.max(minY, finalY), maxY);
1178 | return {x: finalX, y: finalY};
1179 | };
1180 |
1181 | triangle.svToDot = function (sv) {
1182 | var svError = 0.02;
1183 | if (wheelBlockSize < 150) {
1184 | svError = 0.07;
1185 | } else if (wheelBlockSize < 100) {
1186 | svError = 0.16;
1187 | }
1188 |
1189 | for (var y = 0; y < this.size; y++) {
1190 | for (var x = 0; x < this.size; x++) {
1191 | var dot = {x: this.path[1].x + x, y: this.path[1].y + y};
1192 | if (svFig.isDotIn(dot)) {
1193 | var targetSv = this.dotToSv(dot);
1194 | var es = Math.abs(targetSv.s - sv.s), ev = Math.abs(targetSv.v - sv.v);
1195 |
1196 | if (es < svError && ev < svError) {
1197 | return dot;
1198 | }
1199 | }
1200 | }
1201 | }
1202 |
1203 | return {
1204 | x: 0,
1205 | y: 0
1206 | };
1207 | };
1208 |
1209 | triangle.draw = function () {
1210 | // no buffer
1211 |
1212 | if (!this.imageData)
1213 | this.imageData = canvasHelperCtx.createImageData(this.size, this.size);
1214 |
1215 | canvasHelper.width = this.size;
1216 | canvasHelper.height = this.size;
1217 |
1218 | var trX = this.path[1].x;
1219 | var trY = this.path[1].y;
1220 | var i = 0;
1221 | for (var y = 0; y < this.size; y++) {
1222 | for (var x = 0; x < this.size; x++) {
1223 | var dot = {x: this.path[1].x + x, y: this.path[1].y + y};
1224 | if (!svFig.isDotIn(dot)) {
1225 | this.imageData.data[i + 0] = 0;
1226 | this.imageData.data[i + 1] = 0;
1227 | this.imageData.data[i + 2] = 0;
1228 | this.imageData.data[i + 3] = 0;
1229 | } else {
1230 | var sv = this.dotToSv(dot);
1231 | var targetRgb = hsvToRgb(hsv.h, sv.s, sv.v);
1232 |
1233 | this.imageData.data[i + 0] = targetRgb.r;
1234 | this.imageData.data[i + 1] = targetRgb.g;
1235 | this.imageData.data[i + 2] = targetRgb.b;
1236 | this.imageData.data[i + 3] = 255;
1237 | }
1238 |
1239 | i += 4;
1240 | }
1241 | }
1242 |
1243 | canvasHelperCtx.putImageData(this.imageData, 0, 0);
1244 | ctx.drawImage(canvasHelper, trX, trY); // draw with save overlaps transparent things , not direct putImageData that rewrite all pixels
1245 |
1246 | ctx.beginPath();
1247 | ctx.strokeStyle = 'rgba(0, 0, 0, 0.3)';
1248 | ctx.lineWidth = 2;
1249 | var trianglePath = this.path; //rotatePath(triangle.path, hsv.h * 360);
1250 | for (var i = 0; i <= trianglePath.length - 1; ++i)
1251 | {
1252 | if (i == 0)
1253 | ctx.moveTo(trianglePath[i].x, trianglePath[i].y);
1254 | else
1255 | ctx.lineTo(trianglePath[i].x, trianglePath[i].y);
1256 | }
1257 |
1258 | ctx.stroke();
1259 | ctx.closePath();
1260 | };
1261 |
1262 | triangle.calcS = function (p) {
1263 | return Math.abs((p[1].x - p[0].x) * (p[2].y - p[0].y) - (p[2].x - p[0].x) * (p[1].y - p[0].y)) / 2;
1264 | };
1265 |
1266 | triangle.dotToSv = function (dot) {
1267 | var p = getP({x: dot.x, y: dot.y}, this.vol);
1268 | var len = getLen(p, this.vol[0]);
1269 |
1270 | // dirty tricks? replace output to interpolation and lerp in future
1271 | if (len < 1)
1272 | len = Math.floor(len);
1273 | if (len > this.h - 1)
1274 | len = this.h;
1275 |
1276 | var vol = len / (this.h);
1277 |
1278 | var angle = Math.abs(getAngle(dot, this.sSide));
1279 | if (angle < 30)
1280 | angle = 30;
1281 | angle -= 30;
1282 | angle = 60 - angle;
1283 | angle = angle / 60; // - saturation from one angle
1284 |
1285 | return {s: angle, v: vol};
1286 | };
1287 |
1288 | triangle.isDotIn = function (dot) {
1289 | var t = [
1290 | {x: this.path[0].x, y: this.path[0].y},
1291 | {x: this.path[1].x, y: this.path[1].y},
1292 | {x: dot.x, y: dot.y}
1293 | ];
1294 |
1295 | var s = this.calcS(t);
1296 | t[1] = {x: this.path[2].x, y: this.path[2].y};
1297 | s += this.calcS(t);
1298 | t[0] = {x: this.path[1].x, y: this.path[1].y};
1299 | s += this.calcS(t);
1300 |
1301 | if (Math.ceil(s) == Math.ceil(this.s))
1302 | return true;
1303 | else
1304 | return false;
1305 | };
1306 |
1307 | triangle.updateSize = function () {
1308 | // из формулы высоты равностороннего треугольника
1309 | this.outerRadius = wheel.innerRadius - wheelCursor.paddingX - this.padding;
1310 | // из теоремы синусов треугольника
1311 | this.size = Math.floor((2 * this.outerRadius) * Math.sin(toRadians(60)));
1312 |
1313 | var h = ((Math.sqrt(3) / 2) * this.size);
1314 | this.h = ((Math.sqrt(3) / 2) * this.size);
1315 |
1316 | this.path = new Array();
1317 | this.path[0] = {x: this.outerRadius, y: 0}; // middle point - h
1318 | this.path[1] = {x: this.path[0].x - h, y: -1 * (this.size / 2)}; // upper - s
1319 | this.path[2] = {x: this.path[1].x, y: this.size / 2}; // bottom - v
1320 | this.path[3] = {x: this.path[0].x, y: this.path[0].y}; // to begin
1321 |
1322 | for (var i = 0; i <= this.path.length - 1; ++i) {
1323 | this.path[i].x += wheel.pos.x;
1324 | this.path[i].y += wheel.pos.y;
1325 | }
1326 |
1327 | this.vol = new Array();
1328 |
1329 |
1330 | this.s = this.calcS(this.path);
1331 | if (this.sOnTop) {
1332 | var middle = getMiddlePoint(this.path[0], this.path[2]);
1333 |
1334 | this.vol[0] = {x: this.path[1].x, y: this.path[1].y};
1335 | this.vol[1] = {x: middle.x, y: middle.y};
1336 |
1337 | this.sSide = this.path[1];
1338 | } else {
1339 | var middle = getMiddlePoint(this.path[0], this.path[1]);
1340 |
1341 | this.vol[0] = {x: this.path[2].x, y: this.path[2].y};
1342 | this.vol[1] = {x: middle.x, y: middle.y};
1343 |
1344 | this.sSide = this.path[2];
1345 | }
1346 | };
1347 |
1348 | svFigsPool['triangle'] = triangle;
1349 | return triangle;
1350 | }
1351 |
1352 | // prefix - for multiple event functions for one object
1353 | function addEventListner(object, event, callback, prefix) {
1354 | if (typeof object !== 'object') {
1355 | object = document.getElementById(object);
1356 | }
1357 |
1358 | if (!object)
1359 | return false;
1360 | if (!prefix)
1361 | prefix = '';
1362 |
1363 | events[prefix + event] = callback;
1364 |
1365 | if (!object.addEventListener) {
1366 | object.attachEvent('on' + event, events[prefix + event]);
1367 | } else {
1368 | object.addEventListener(event, events[prefix + event]);
1369 | }
1370 |
1371 | return true;
1372 | }
1373 |
1374 | function removeEventListener(object, event, prefix) {
1375 | if (typeof object !== 'object') {
1376 | object = document.getElementById(object);
1377 | }
1378 |
1379 | // console.log('remove : : ' + Object.keys(events).length);
1380 | if (!object)
1381 | return false;
1382 | if (!prefix)
1383 | prefix = '';
1384 |
1385 | if (!events[prefix + event])
1386 | return false;
1387 |
1388 | if (!object.removeEventListener) {
1389 | object.detachEvent('on' + event, events[prefix + event]);
1390 | } else {
1391 | object.removeEventListener(event, events[prefix + event]);
1392 | }
1393 |
1394 | events[prefix + event] = null;
1395 | return true;
1396 | }
1397 |
1398 | // [converters]
1399 | // Read more about HSV color model :
1400 | // https://ru.wikipedia.org/wiki/HSV_%28%F6%E2%E5%F2%EE%E2%E0%FF_%EC%EE%E4%E5%EB%FC%29
1401 | // source of converter hsv functions
1402 | // http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
1403 |
1404 | function hsvToRgb(h, s, v) {
1405 | var r, g, b, i, f, p, q, t;
1406 |
1407 | if (h && s === undefined && v === undefined) {
1408 | s = h.s, v = h.v, h = h.h;
1409 | }
1410 |
1411 | i = Math.floor(h * 6);
1412 | f = h * 6 - i;
1413 | p = v * (1 - s);
1414 | q = v * (1 - f * s);
1415 | t = v * (1 - (1 - f) * s);
1416 |
1417 | switch (i % 6) {
1418 | case 0:
1419 | r = v, g = t, b = p;
1420 | break;
1421 | case 1:
1422 | r = q, g = v, b = p;
1423 | break;
1424 | case 2:
1425 | r = p, g = v, b = t;
1426 | break;
1427 | case 3:
1428 | r = p, g = q, b = v;
1429 | break;
1430 | case 4:
1431 | r = t, g = p, b = v;
1432 | break;
1433 | case 5:
1434 | r = v, g = p, b = q;
1435 | break;
1436 | }
1437 |
1438 | return {
1439 | r: Math.floor(r * 255),
1440 | g: Math.floor(g * 255),
1441 | b: Math.floor(b * 255)
1442 | };
1443 | }
1444 |
1445 | function rgbToHsv(r, g, b) {
1446 | if (r && g === undefined && b === undefined) {
1447 | g = r.g, b = r.b, r = r.r;
1448 | }
1449 |
1450 | r = r / 255, g = g / 255, b = b / 255;
1451 | var max = Math.max(r, g, b), min = Math.min(r, g, b);
1452 | var h, s, v = max;
1453 |
1454 | var d = max - min;
1455 | s = max == 0 ? 0 : d / max;
1456 |
1457 | if (max == min) {
1458 | h = 0; // achromatic
1459 | } else {
1460 | switch (max) {
1461 | case r:
1462 | h = (g - b) / d + (g < b ? 6 : 0);
1463 | break;
1464 | case g:
1465 | h = (b - r) / d + 2;
1466 | break;
1467 | case b:
1468 | h = (r - g) / d + 4;
1469 | break;
1470 | }
1471 | h /= 6;
1472 | }
1473 |
1474 | return {h: h, s: s, v: v};
1475 | }
1476 |
1477 | function hexToRgb(hex) {
1478 | var dec = parseInt(hex.charAt(0) == '#' ? hex.slice(1) : hex, 16);
1479 | return {r: dec >> 16, g: dec >> 8 & 255, b: dec & 255};
1480 | }
1481 |
1482 | function rgbToHex(color) {
1483 | var componentToHex = function (c) {
1484 | var hex = c.toString(16);
1485 | return hex.length === 1 ? "0" + hex : hex;
1486 | };
1487 |
1488 | return "#" + componentToHex(color.r) + componentToHex(color.g) + componentToHex(color.b);
1489 | }
1490 |
1491 | function toRadians(i) {
1492 | return i * (PI / 180);
1493 | }
1494 |
1495 | // [converters - end]
1496 |
1497 | function getLen(point1, point2) {
1498 | return Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2));
1499 | }
1500 |
1501 | function getMiddlePoint(point1, point2) {
1502 | return {x: (point1.x + point2.x) / 2, y: (point1.y + point2.y) / 2};
1503 | }
1504 |
1505 | // перпендикуляр от точки
1506 |
1507 | function getP(point1, line1) {
1508 | var l = (line1[0].x - line1[1].x) * (line1[0].x - line1[1].x) + (line1[0].y - line1[1].y) * (line1[0].y - line1[1].y);
1509 | var pr = (point1.x - line1[0].x) * (line1[1].x - line1[0].x) + (point1.y - line1[0].y) * (line1[1].y - line1[0].y);
1510 | var pt = true;
1511 | var cf = pr / l;
1512 |
1513 | if (cf < 0) {
1514 | cf = 0;
1515 | pt = false;
1516 | }
1517 | if (cf > 1) {
1518 | cf = 1;
1519 | pt = false;
1520 | }
1521 |
1522 | return {
1523 | x: line1[0].x + cf * (line1[1].x - line1[0].x),
1524 | y: line1[0].y + cf * (line1[1].y - line1[0].y),
1525 | pt: pt
1526 | };
1527 | }
1528 |
1529 | // translate360 = true 270
1530 | // 180 --- from.x.y --- 0
1531 | // 90
1532 |
1533 | function getAngle(point, from, translate360) {
1534 | if (!from)
1535 | from = {x: 0, y: 0};
1536 |
1537 | var distX = point.x - from.x;
1538 | var distY = point.y - from.y;
1539 |
1540 | var a = Math.atan2(distY, distX) * 180 / (PI);
1541 | if (translate360 && a < 0)
1542 | a = 360 + a;
1543 |
1544 | return a;
1545 | }
1546 |
1547 | // поворот фигуры относительно точки
1548 | function rotatePath2(points, angle) {
1549 | angle = toRadians(angle);
1550 | var newPoints = new Array();
1551 |
1552 | for (var i = 0; i <= points.length - 1; ++i)
1553 | {
1554 | newPoints[i] = {
1555 | x: points[i].x * Math.cos(angle) - points[i].y * Math.sin(angle),
1556 | y: points[i].x * Math.sin(angle) + points[i].y * Math.cos(angle)
1557 | };
1558 | }
1559 |
1560 | return newPoints;
1561 | }
1562 |
1563 | function updateSize() {
1564 | padding = basePadding + wheelCursor.paddingX;
1565 |
1566 | rendered = false;
1567 | wheel.imageData = null;
1568 |
1569 | center = wheelBlockSize / 2;
1570 | wheel.pos = {x: center, y: center};
1571 |
1572 | wheel.outerRadius = center - padding;
1573 | wheel.innerRadius = wheel.outerRadius - wheel.width;
1574 |
1575 | // объект относительно начала координат
1576 | wheelCursor.path = [
1577 | {x: wheel.innerRadius - wheelCursor.paddingX, y: wheelCursor.height * -1},
1578 | {x: wheel.outerRadius + wheelCursor.paddingX, y: wheelCursor.height * -1},
1579 | {x: wheel.outerRadius + wheelCursor.paddingX, y: wheelCursor.height},
1580 | {x: wheel.innerRadius - wheelCursor.paddingX, y: wheelCursor.height},
1581 | {x: wheel.innerRadius - wheelCursor.paddingX, y: (wheelCursor.height + (wheelCursor.lineWeight / 2)) * -1}
1582 | ];
1583 |
1584 | var width = wheelBlockSize;
1585 | if (alpha)
1586 | width += alphaSlider.width + alphaSlider.padding * 2;
1587 |
1588 | if (place.tagName.toLowerCase() != 'canvas') {
1589 | place.style.width = width + 'px';
1590 | place.style.height = wheelBlockSize + 'px';
1591 | }
1592 |
1593 | canvas.width = width;
1594 | canvas.height = wheelBlockSize;
1595 |
1596 | if (resizeWith != canvas) {
1597 | canvas.style.width = width + 'px';
1598 | canvas.style.height = wheelBlockSize + 'px';
1599 | }
1600 |
1601 | for (var i = 0; i <= colorSavers.length - 1; ++i)
1602 | {
1603 | colorSavers[i].updateSize();
1604 | }
1605 |
1606 | if (styleSwitch) {
1607 |
1608 | styleSwitch.imageData['triangle'] = null;
1609 | styleSwitch.imageData['quad'] = null;
1610 |
1611 | styleSwitch.updateSize();
1612 | }
1613 |
1614 | svFig.updateSize();
1615 | if (alpha)
1616 | alphaSlider.updateSize();
1617 | }
1618 |
1619 | // updates input after color changes (manualEnter = true if value entered from input, not from widget)
1620 | // if manualEnter = true - save original text in input, else set input value in configurated format
1621 | // if user event 'updateinput' is setted and return false - prevent default updateInput behavior
1622 |
1623 | function updateInput(manualEnter) {
1624 | if (!input)
1625 | return;
1626 |
1627 | if (userEvents["updateinput"]) {
1628 | var callback = userEvents["updateinput"];
1629 | if (!callback(handler, input, manualEnter))
1630 | return;
1631 | }
1632 |
1633 | let aStr = a.toFixed(2);
1634 | let rgba = 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + aStr + ')';
1635 |
1636 | if (!manualEnter) {
1637 | switch (inputFormat) {
1638 | case 'mixed':
1639 | if (a < 1)
1640 | input.value = rgba;
1641 | else
1642 | input.value = hex;
1643 | break;
1644 | case 'hex':
1645 | input.value = hex;
1646 | break;
1647 | case 'hsla':
1648 | input.value = 'hsla(' + (hsv.h * 360).toFixed(2) + ', ' + (hsv.s * 100).toFixed(2) + '%, ' + (hsv.v * 100).toFixed(2) + '%, ' + aStr + ')';
1649 | break;
1650 | default:
1651 | input.value = rgba;
1652 | break;
1653 | }
1654 | }
1655 |
1656 | if (inputColor) {
1657 | if (hsv.v < 0.5) {
1658 | input.style.color = "#FFF";
1659 | } else {
1660 | input.style.color = "#000";
1661 | }
1662 |
1663 | input.style.background = rgba;
1664 | }
1665 | }
1666 |
1667 | function initCanvas() {
1668 | if (!place)
1669 | return false;
1670 | if (place.tagName != 'CANVAS') {
1671 | canvas = document.createElement('CANVAS');
1672 | place.appendChild(canvas);
1673 | } else {
1674 | canvas = place;
1675 | }
1676 |
1677 | // code for IE browsers
1678 | if (typeof window.G_vmlCanvasManager != 'undefined') {
1679 | canvas = window.G_vmlCanvasManager.initElement(canvas);
1680 | canvasHelper = window.G_vmlCanvasManager.initElement(canvasHelper);
1681 | }
1682 |
1683 | if (!!(canvas.getContext && canvas.getContext('2d'))) {
1684 | ctx = canvas.getContext("2d");
1685 | canvasHelperCtx = canvasHelper.getContext("2d");
1686 | return true;
1687 | } else
1688 | return false;
1689 | }
1690 |
1691 | // temp events until wait mouse click or touch
1692 | function enableEvents() {
1693 | addEventListner(canvas, "mousedown", function (e) {
1694 | handler.mouseDownEvent(e);
1695 | }, 'wait_action_');
1696 | addEventListner(canvas, "touchstart", function (e) {
1697 | handler.mouseDownEvent(e);
1698 | }, 'wait_action_');
1699 | addEventListner(canvas, "mouseout", function (e) {
1700 | handler.mouseOutEvent(e);
1701 | }, 'wait_action_');
1702 | addEventListner(window, "touchmove", function (e) {
1703 | handler.touchMoveEvent(e);
1704 | }, 'wait_action_');
1705 | addEventListner(canvas, "mousemove", function (e) {
1706 | handler.mouseMoveRest(e);
1707 | }, 'wait_action_');
1708 | }
1709 |
1710 | // mouse detect canvas events
1711 |
1712 | function disableEvents() {
1713 | removeEventListener(canvas, "mousedown", 'wait_action_');
1714 | removeEventListener(canvas, "touchstart", 'wait_action_');
1715 | removeEventListener(canvas, "mouseout", 'wait_action_');
1716 | removeEventListener(window, "touchmove", 'wait_action_');
1717 | removeEventListener(canvas, "mousemove", 'wait_action_');
1718 | }
1719 |
1720 | function getEventDot(e) {
1721 |
1722 | e = e || window.event;
1723 | var x, y;
1724 | var scrollX = document.body.scrollLeft + document.documentElement.scrollLeft;
1725 | var scrollY = document.body.scrollTop + document.documentElement.scrollTop;
1726 |
1727 | if (e.type == 'touchend') {
1728 |
1729 | x = e.changedTouches[0].clientX + scrollX;
1730 | y = e.changedTouches[0].clientY + scrollY;
1731 |
1732 | } else if (e.type == 'touchmove' || e.touches) {
1733 |
1734 | x = e.touches[0].clientX + scrollX;
1735 | y = e.touches[0].clientY + scrollY;
1736 |
1737 | } else {
1738 | // e.pageX e.pageY e.x e.y bad for cross-browser
1739 | x = e.clientX + scrollX;
1740 | y = e.clientY + scrollY;
1741 | }
1742 |
1743 | // set point to local coordinates
1744 |
1745 | var rect = canvas.getBoundingClientRect();
1746 | x -= rect.left + scrollX;
1747 | y -= rect.top + scrollY;
1748 |
1749 | return {x: x, y: y};
1750 | }
1751 |
1752 | function selectColorSaver(key) {
1753 |
1754 | // disable current selection
1755 | var previouseSelect = false;
1756 | for (var i = 0; i <= colorSavers.length - 1; ++i)
1757 | {
1758 | if (colorSavers[i].selected)
1759 | previouseSelect = i;
1760 | colorSavers[i].selected = false;
1761 | }
1762 |
1763 | // select new
1764 | var select = false;
1765 | for (var i = 0; i <= colorSavers.length - 1; ++i)
1766 | {
1767 | if (i == key) {
1768 | colorSavers[i].selected = true;
1769 | handler.setColorByHex(colorSavers[i].color);
1770 | select = true;
1771 | break;
1772 | }
1773 | }
1774 |
1775 | if (select && userEvents["selectcolorsaver"]) {
1776 | var callback = userEvents["selectcolorsaver"];
1777 | callback(handler, colorSavers[key]);
1778 | }
1779 |
1780 | if (!select && previouseSelect !== false) {
1781 | colorSavers[previouseSelect].selected = true;
1782 | }
1783 |
1784 | return select;
1785 | }
1786 |
1787 | function updateColorSavers() {
1788 |
1789 | for (var i = 0; i <= colorSavers.length - 1; ++i)
1790 | {
1791 | if (colorSavers[i].selected)
1792 | colorSavers[i].color = hex;
1793 | }
1794 |
1795 | }
1796 |
1797 | function drawColorSavers() {
1798 | if (colorSavers.length) {
1799 | for (var i = 0; i <= colorSavers.length - 1; ++i)
1800 | {
1801 | colorSavers[i].draw();
1802 | }
1803 | }
1804 | }
1805 |
1806 | // вывод интерфейса без курсоров
1807 | // поддерживается буферизация todo добавить буферизацию color saver элементов
1808 | // вынести буфер альфа слайдера отдельно от колеса и sv блока
1809 |
1810 | function drawColorPicker() {
1811 | if (!ctx)
1812 | return false;
1813 |
1814 | ctx.clearRect(0, 0, canvas.width, canvas.height);
1815 |
1816 | // put buffered data
1817 | if (rendered) {
1818 | ctx.putImageData(canvasHelperData, 0, 0);
1819 | drawColorSavers();
1820 | return true;
1821 | }
1822 |
1823 | // форма кольца может измениться только при изменении размеров виджета
1824 | wheel.draw();
1825 | svFig.draw();
1826 |
1827 | if (alpha)
1828 | alphaSlider.draw();
1829 |
1830 | drawColorSavers();
1831 | if (styleSwitch)
1832 | styleSwitch.draw();
1833 |
1834 | // поместить текущее отрисованное изображение кольца + sv селектора в буфер
1835 | // notice :
1836 | // при перемещении курсора кольца сохранять буфер все изображение бессмысленно - sv блок постоянно обновляется, поэтому
1837 | // сохраняем уже на событии выхода из процесса перемещения
1838 |
1839 | if (!drag) {
1840 | //wheelBlockSize
1841 | canvasHelperData = ctx.getImageData(0, 0, canvas.width, canvas.height);
1842 | rendered = true;
1843 | }
1844 | return true;
1845 | }
1846 |
1847 | function draw() {
1848 | if (!drawColorPicker()) {
1849 | return false;
1850 | }
1851 |
1852 | var curAngle = hsv.h * 360 - wheel.startAngle;
1853 |
1854 | // cursors
1855 |
1856 | if (alpha) {
1857 | ctx.beginPath();
1858 | var cursorHeight = 2;
1859 | var cursorPaddingX = 2;
1860 | var pointY = alphaSlider.height * (1 - a);
1861 | ctx.rect(alphaSlider.pos.x - cursorPaddingX, alphaSlider.padding + pointY - cursorHeight / 2, alphaSlider.width + cursorPaddingX * 2, cursorHeight);
1862 | ctx.strokeStyle = 'rgba(0,0,0, 0.8)';
1863 | ctx.lineWidth = 2;
1864 |
1865 | ctx.stroke();
1866 | ctx.closePath();
1867 | }
1868 |
1869 | ctx.beginPath();
1870 |
1871 | var wheelCursorPath = rotatePath2(wheelCursor.path, curAngle, {x: wheel.pos.x, y: wheel.pos.y});
1872 | for (var i = 0; i <= wheelCursorPath.length - 1; ++i)
1873 | {
1874 | wheelCursorPath[i].x += wheel.pos.x;
1875 | wheelCursorPath[i].y += wheel.pos.y;
1876 | if (i == 0)
1877 | ctx.moveTo(wheelCursorPath[i].x, wheelCursorPath[i].y);
1878 | else
1879 | ctx.lineTo(wheelCursorPath[i].x, wheelCursorPath[i].y);
1880 | }
1881 |
1882 | ctx.strokeStyle = 'rgba(0,0,0,0.8)';
1883 | ctx.lineWidth = wheelCursor.lineWeight;
1884 | ctx.stroke();
1885 | ctx.closePath();
1886 |
1887 | // sv cursor
1888 | if (hsv.v > 0.5 && hsv.s < 0.5)
1889 | ctx.strokeStyle = 'rgba(0, 0, 0, 1)';
1890 | else
1891 | ctx.strokeStyle = 'rgba(255, 255, 255, 1)';
1892 | //ctx.strokeStyle='rgba(255,255, 255, 1)';
1893 |
1894 | //document.getElementById('test3').value = 'h' + hsv.h.toFixed(2) + ' s' + hsv.s.toFixed(2) + ' v' + hsv.v.toFixed(2)
1895 |
1896 | ctx.beginPath();
1897 | ctx.lineWidth = 2;
1898 | ctx.arc(hsv.x, hsv.y, svCursor.radius, 0, PI * 2);
1899 |
1900 |
1901 | ctx.stroke();
1902 | ctx.closePath();
1903 |
1904 | return false;
1905 | }
1906 |
1907 | this.popUpClose = function (e) {
1908 |
1909 | if (popup.tag === false)
1910 | return;
1911 |
1912 | if (e) {
1913 | // todo check when select color and then unpress button out of bounds
1914 | if (e.target == input || e.target == canvas)
1915 | return false;
1916 | if (e.target == popup.tag)
1917 | return false;
1918 | }
1919 |
1920 | if (userEvents["popupclose"] && !userEvents["popupclose"](handler, e)) {
1921 | return;
1922 | }
1923 |
1924 | popup.tag.style.display = 'none';
1925 |
1926 | if (KellyColorPicker.activePopUp == handler)
1927 | KellyColorPicker.activePopUp = false;
1928 | }
1929 |
1930 | // if 'popupshow' user event is setted and return false - prevent show popup default behavior
1931 |
1932 | this.popUpShow = function (e) {
1933 | if (popup.tag === false)
1934 | return;
1935 |
1936 | if (userEvents["popupshow"] && !userEvents["popupshow"](handler, e)) {
1937 | return;
1938 | }
1939 |
1940 | // include once
1941 | if (!KellyColorPicker.popupEventsInclude) {
1942 | addEventListner(document, "click", function (e) {
1943 | if (KellyColorPicker.activePopUp)
1944 | return KellyColorPicker.activePopUp.popUpClose(e);
1945 | else
1946 | return false;
1947 | }, 'popup_close_');
1948 | addEventListner(window, "resize", function (e) {
1949 | if (KellyColorPicker.activePopUp)
1950 | return KellyColorPicker.activePopUp.popUpShow(e);
1951 | }, 'popup_resize_');
1952 | KellyColorPicker.popupEventsInclude = true;
1953 | }
1954 |
1955 | if (KellyColorPicker.activePopUp) {
1956 | KellyColorPicker.activePopUp.popUpClose(false);
1957 | }
1958 |
1959 | var topMargin = handler.getCanvas().width;
1960 |
1961 | var alpha = handler.getAlphaFig();
1962 | if (alpha) {
1963 | topMargin -= alpha.width + alpha.padding;
1964 | }
1965 |
1966 | var popupStyle = window.getComputedStyle(popup.tag);
1967 |
1968 | var paddingPopup = parseInt(popupStyle.paddingBottom) + parseInt(popupStyle.paddingTop);
1969 | if (paddingPopup <= 0) {
1970 | paddingPopup = 0;
1971 | }
1972 |
1973 | var viewportOffset = input.getBoundingClientRect();
1974 | var top = viewportOffset.top + (window.scrollY || window.pageYOffset || document.body.scrollTop) - paddingPopup;
1975 | var left = viewportOffset.left + (window.scrollX || window.pageXOffset || document.body.scrollLeft);
1976 | var padding = 6;
1977 |
1978 | popup.tag.style.top = (top - topMargin - popup.margin) + 'px';
1979 | popup.tag.style.left = left + 'px';
1980 | popup.tag.style.display = 'block';
1981 |
1982 | KellyColorPicker.activePopUp = handler;
1983 | return false;
1984 | }
1985 |
1986 | this.setHueByDot = function (dot) {
1987 | var angle = getAngle(dot, wheel.pos) + wheel.startAngle;
1988 | if (angle < 0)
1989 | angle = 360 + angle;
1990 |
1991 | hsv.h = angle / 360;
1992 |
1993 | rgb = hsvToRgb(hsv.h, hsv.s, hsv.v);
1994 | hex = rgbToHex(rgb);
1995 |
1996 | updateColorSavers();
1997 |
1998 | if (userEvents["change"]) {
1999 | var callback = userEvents["change"];
2000 | callback(handler);
2001 | }
2002 |
2003 | updateInput();
2004 |
2005 | rendered = false;
2006 | draw();
2007 | };
2008 |
2009 | this.setColorForColorSaver = function (cString, align) {
2010 |
2011 | var colorData = readColorData(cString, true);
2012 | if (!colorData)
2013 | return;
2014 |
2015 | var colorSaver = handler.getColorSaver(align);
2016 | if (colorSaver.selected) {
2017 | this.setColorByHex(cString, false);
2018 | } else {
2019 | colorSaver.color = colorData.h;
2020 | draw();
2021 | }
2022 |
2023 | return true;
2024 | };
2025 |
2026 | this.setColor = function(inputColor, manualEnter) {
2027 |
2028 | // synonym, since setColorByHex already accept color in different formats, not only in hex
2029 |
2030 | handler.setColorByHex(inputColor, manualEnter);
2031 |
2032 | }
2033 |
2034 | // update color with redraw canvas and update input hex value
2035 | // now support rgba \ rgb string format input
2036 | // and also hsla \ hsl
2037 |
2038 | this.setColorByHex = function (inputHex, manualEnter) {
2039 |
2040 | if (!manualEnter)
2041 | manualEnter = false;
2042 | var inputAlpha = a;
2043 |
2044 | if (inputHex !== false) {
2045 |
2046 | if (!inputHex || !inputHex.length)
2047 | return;
2048 |
2049 | var colorData = readColorData(inputHex, true);
2050 | if (!colorData)
2051 | return;
2052 |
2053 | inputHex = colorData.h;
2054 | if (alpha)
2055 | inputAlpha = colorData.a;
2056 |
2057 | } else
2058 | inputHex = hex;
2059 |
2060 | if (alpha && inputHex == hex && rendered && inputAlpha != a) {
2061 | a = inputAlpha;
2062 |
2063 | draw(); // slider always redraws in current even if part of canvas buffered
2064 | return;
2065 | }
2066 |
2067 | if (hex && inputHex == hex && rendered)
2068 | return;
2069 |
2070 | // set and redraw all
2071 |
2072 | a = inputAlpha;
2073 | rgb = hexToRgb(inputHex);
2074 | hex = inputHex;
2075 | hsv = rgbToHsv(rgb);
2076 |
2077 | var dot = svFig.svToDot(hsv);
2078 | hsv.x = dot.x;
2079 | hsv.y = dot.y;
2080 |
2081 | rendered = false;
2082 | updateColorSavers();
2083 | draw();
2084 |
2085 | if (userEvents["change"]) {
2086 | var callback = userEvents["change"];
2087 | callback(handler);
2088 | }
2089 |
2090 | updateInput(manualEnter);
2091 | };
2092 |
2093 | this.setAlphaByDot = function (dot) {
2094 | a = alphaSlider.dotToAlpha(dot);
2095 |
2096 | if (userEvents["change"]) {
2097 | var callback = userEvents["change"];
2098 | callback(handler);
2099 | }
2100 |
2101 | updateInput();
2102 | draw();
2103 | };
2104 |
2105 | this.setAlpha = function (alpha) {
2106 | a = alpha;
2107 | updateInput();
2108 | draw();
2109 | };
2110 |
2111 | this.setColorByDot = function (dot) {
2112 | var sv = svFig.dotToSv(dot);
2113 |
2114 | hsv.s = sv.s;
2115 | hsv.v = sv.v;
2116 | hsv.x = dot.x;
2117 | hsv.y = dot.y;
2118 |
2119 | if (hsv.s > 1)
2120 | hsv.s = 1;
2121 | if (hsv.s < 0)
2122 | hsv.s = 0;
2123 | if (hsv.v > 1)
2124 | hsv.v = 1;
2125 | if (hsv.v < 0)
2126 | hsv.v = 0;
2127 |
2128 | rgb = hsvToRgb(hsv.h, hsv.s, hsv.v);
2129 | hex = rgbToHex(rgb);
2130 |
2131 | updateColorSavers();
2132 |
2133 | if (userEvents["change"]) {
2134 | var callback = userEvents["change"];
2135 | callback(handler);
2136 | }
2137 |
2138 | updateInput();
2139 | draw();
2140 | };
2141 |
2142 | this.mouseOutEvent = function (e) {
2143 | if (svCursorMouse.curType > 0 && !KellyColorPicker.cursorLock) {
2144 | svCursorMouse.initStandartCursor();
2145 | }
2146 | };
2147 |
2148 | // перемещение указателя по canvas в режиме покоя
2149 | this.mouseMoveRest = function (e) {
2150 | if (drag)
2151 | return;
2152 |
2153 | if (!cursorAnimReady) {
2154 | return;
2155 | }
2156 |
2157 | cursorAnimReady = false;
2158 | var newDot = getEventDot(e);
2159 | svCursorMouse.updateCursor(newDot);
2160 | requestAnimationFrame(function () {
2161 | cursorAnimReady = true;
2162 | });
2163 |
2164 | if (userEvents["mousemoverest"]) {
2165 | var callback = userEvents["mousemoverest"];
2166 | callback(e, handler, newDot);
2167 | }
2168 | };
2169 |
2170 | // to prevent scroll by touches while change color
2171 | // в FireFox под андройд есть "фича" которая скрывает или раскрывает тулбар адресной строки при движении пальцем
2172 | // отключить её можно только через опцию about:config browser.chrome.dynamictoolbar
2173 |
2174 | this.touchMoveEvent = function (e) {
2175 | if (drag) { // todo check number of touches to ignore zoom action
2176 | event.preventDefault();
2177 | }
2178 | };
2179 |
2180 | // маршрутизатор событий нажатий на элементы
2181 | this.mouseDownEvent = function (event) {
2182 | event.preventDefault();
2183 |
2184 | var move, up = false;
2185 | var newDot = getEventDot(event);
2186 | // console.log('mouseDownEvent : cur : ' + newDot.x + ' | ' + newDot.y);
2187 |
2188 | if (wheel.isDotIn(newDot)) {
2189 | drag = 'wheel';
2190 | handler.setHueByDot(newDot);
2191 |
2192 | move = function (e) {
2193 | handler.wheelMouseMove(e, newDot);
2194 | };
2195 | up = function (e) {
2196 | KellyColorPicker.cursorLock = false;
2197 | handler.wheelMouseUp(e, newDot);
2198 | };
2199 |
2200 | } else if (svFig.isDotIn(newDot)) {
2201 | drag = 'sv';
2202 | handler.setColorByDot(newDot);
2203 |
2204 | move = function (e) {
2205 | handler.svMouseMove(e, newDot);
2206 | };
2207 | up = function (e) {
2208 | KellyColorPicker.cursorLock = false;
2209 | handler.svMouseUp(e, newDot);
2210 | };
2211 | } else if (alpha && alphaSlider.isDotIn(newDot)) {
2212 | drag = 'alpha';
2213 | handler.setAlphaByDot(newDot);
2214 |
2215 | move = function (e) {
2216 | handler.alphaMouseMove(e, newDot);
2217 | };
2218 | up = function (e) {
2219 | KellyColorPicker.cursorLock = false;
2220 | handler.alphaMouseUp(e, newDot);
2221 | };
2222 | } else if (styleSwitch && styleSwitch.isDotIn(newDot)) {
2223 | handler.setMethod();
2224 | } else if (colorSavers.length) { // here all items with post check of dot in
2225 |
2226 | for (var i = 0; i <= colorSavers.length - 1; ++i)
2227 | {
2228 | if (colorSavers[i].isDotIn(newDot)) {
2229 | selectColorSaver(i);
2230 | break;
2231 | }
2232 | }
2233 | }
2234 |
2235 | if (move && up) {
2236 | disableEvents();
2237 | KellyColorPicker.cursorLock = handler;
2238 | addEventListner(document, "mouseup", up, 'action_process_');
2239 | addEventListner(document, "mousemove", move, 'action_process_');
2240 | addEventListner(document, "touchend", up, 'action_process_');
2241 | addEventListner(document, "touchmove", move, 'action_process_');
2242 | }
2243 | };
2244 |
2245 | this.wheelMouseMove = function (event, dot) {
2246 | event.preventDefault();
2247 |
2248 | if (!drag)
2249 | return;
2250 |
2251 | if (!cursorAnimReady) {
2252 | return;
2253 | }
2254 | cursorAnimReady = false;
2255 | var newDot = getEventDot(event);
2256 |
2257 | // console.log('wheelMouseMove : start : ' + dot.x + ' | ' + dot.y + ' cur : ' + newDot.x + ' | ' + newDot.y);
2258 | requestAnimationFrame(function () {
2259 | cursorAnimReady = true;
2260 | });
2261 | //setTimeout(function() {cursorAnimReady = true;}, 1000/30);
2262 |
2263 | handler.setHueByDot(newDot);
2264 |
2265 | if (userEvents["mousemoveh"]) {
2266 | var callback = userEvents["mousemoveh"];
2267 | callback(event, handler, newDot);
2268 | }
2269 | };
2270 |
2271 | this.wheelMouseUp = function (event, dot) {
2272 | event.preventDefault();
2273 | if (!drag)
2274 | return;
2275 | //console.log('wheelMouseUp : start : ' + dot.x + ' | ' + dot.y);
2276 |
2277 | removeEventListener(document, "mouseup", 'action_process_');
2278 | removeEventListener(document, "mousemove", 'action_process_');
2279 | removeEventListener(document, "touchend", 'action_process_');
2280 | removeEventListener(document, "touchmove", 'action_process_');
2281 |
2282 | enableEvents();
2283 | drag = false;
2284 |
2285 | rendered = false;
2286 | draw();
2287 |
2288 | var newDot = getEventDot(event);
2289 | svCursorMouse.updateCursor(newDot);
2290 |
2291 | if (userEvents["mouseuph"]) {
2292 | var callback = userEvents["mouseuph"];
2293 | callback(event, handler, newDot);
2294 | }
2295 | };
2296 |
2297 | this.alphaMouseMove = function (event, dot) {
2298 | event.preventDefault();
2299 | if (!drag)
2300 | return;
2301 |
2302 | if (!cursorAnimReady) {
2303 | return;
2304 | }
2305 |
2306 | cursorAnimReady = false;
2307 | var newDot = getEventDot(event);
2308 |
2309 | // console.log('svMouseMove : start : ' + dot.x + ' | ' + dot.y + ' cur : ' + newDot.x + ' | ' + newDot.y);
2310 |
2311 | newDot = alphaSlider.limitDotPosition(newDot);
2312 |
2313 | requestAnimationFrame(function () {
2314 | cursorAnimReady = true;
2315 | });
2316 | //setTimeout(function() {cursorAnimReady = true;}, 1000/30);
2317 |
2318 | handler.setAlphaByDot(newDot);
2319 |
2320 | if (userEvents["mousemovealpha"]) {
2321 | var callback = userEvents["mousemovealpha"];
2322 | callback(event, handler, newDot);
2323 | }
2324 | };
2325 |
2326 | this.alphaMouseUp = function (event, dot) {
2327 | event.preventDefault();
2328 | if (!drag)
2329 | return;
2330 |
2331 | removeEventListener(document, "mouseup", 'action_process_');
2332 | removeEventListener(document, "mousemove", 'action_process_');
2333 | removeEventListener(document, "touchend", 'action_process_');
2334 | removeEventListener(document, "touchmove", 'action_process_');
2335 |
2336 | enableEvents();
2337 | drag = false;
2338 |
2339 | var newDot = getEventDot(event);
2340 | svCursorMouse.updateCursor(newDot);
2341 |
2342 | if (userEvents["mouseupalpha"]) {
2343 | var callback = userEvents["mouseupalpha"];
2344 | callback(event, handler, newDot);
2345 | }
2346 | };
2347 |
2348 | this.svMouseMove = function (event, dot) {
2349 | event.preventDefault();
2350 | if (!drag)
2351 | return;
2352 |
2353 | if (!cursorAnimReady) {
2354 | return;
2355 | }
2356 |
2357 | cursorAnimReady = false;
2358 | var newDot = getEventDot(event);
2359 |
2360 | // console.log('svMouseMove : start : ' + dot.x + ' | ' + dot.y + ' cur : ' + newDot.x + ' | ' + newDot.y);
2361 |
2362 | newDot = svFig.limitDotPosition(newDot);
2363 |
2364 | requestAnimationFrame(function () {
2365 | cursorAnimReady = true;
2366 | });
2367 | //setTimeout(function() {cursorAnimReady = true;}, 1000/30);
2368 |
2369 | handler.setColorByDot(newDot);
2370 |
2371 | if (userEvents["mousemovesv"]) {
2372 | var callback = userEvents["mousemovesv"];
2373 | callback(event, handler, newDot);
2374 | }
2375 | };
2376 |
2377 | this.svMouseUp = function (event, dot) {
2378 | event.preventDefault();
2379 | if (!drag)
2380 | return;
2381 |
2382 | // console.log('svMouseUp : start : ' + dot.x + ' | ' + dot.y);
2383 |
2384 | removeEventListener(document, "mouseup", 'action_process_');
2385 | removeEventListener(document, "mousemove", 'action_process_');
2386 | removeEventListener(document, "touchend", 'action_process_');
2387 | removeEventListener(document, "touchmove", 'action_process_');
2388 |
2389 | enableEvents();
2390 | drag = false;
2391 |
2392 | var newDot = getEventDot(event);
2393 | svCursorMouse.updateCursor(newDot);
2394 |
2395 | // todo
2396 | // split cached data for sv + h wheel and slider, so we can redraw alpha slider without performanse lost in svMouseMove
2397 |
2398 | if (alpha) {
2399 | rendered = false;
2400 | draw();
2401 | }
2402 |
2403 | if (userEvents["mouseupsv"]) {
2404 | var callback = userEvents["mouseupsv"];
2405 | callback(event, handler, newDot);
2406 | }
2407 | };
2408 |
2409 | this.addUserEvent = function (event, callback) {
2410 | userEvents[event] = callback;
2411 | return true;
2412 | };
2413 |
2414 | this.removeUserEvent = function (event) {
2415 | if (!userEvents[event])
2416 | return false;
2417 | userEvents[event] = null;
2418 | return true;
2419 | };
2420 |
2421 | // для кастомизации отображения элементов виджета
2422 |
2423 | this.getCanvas = function () {
2424 | if (!ctx)
2425 | return false;
2426 | return canvas;
2427 | };
2428 |
2429 | this.getCtx = function () {
2430 | if (!ctx)
2431 | return false;
2432 | return ctx;
2433 | };
2434 |
2435 | this.getInput = function () {
2436 | return input;
2437 | };
2438 |
2439 | this.getSvFig = function () {
2440 | return svFig;
2441 | };
2442 |
2443 | this.getSvFigCursor = function () {
2444 | return svCursor;
2445 | };
2446 |
2447 | this.getWheel = function () {
2448 | return wheel;
2449 | };
2450 |
2451 | this.getWheelCursor = function () {
2452 | return wheelCursor;
2453 | };
2454 |
2455 | this.getCurColorHsv = function () {
2456 | return hsv;
2457 | };
2458 |
2459 | this.getCurColorRgb = function () {
2460 | return rgb;
2461 | };
2462 |
2463 | this.getCurColorHex = function () {
2464 | return hex;
2465 | };
2466 |
2467 | this.getCurColorRgba = function () {
2468 | return {r: rgb.r, g: rgb.g, b: rgb.b, a: a};
2469 | };
2470 |
2471 | this.getCurAlpha = function () {
2472 | return a;
2473 | };
2474 |
2475 | this.getAlphaFig = function () {
2476 | if (alpha)
2477 | return alphaSlider;
2478 | else
2479 | return false;
2480 | }
2481 |
2482 | this.getPopup = function () {
2483 | return popup;
2484 | };
2485 |
2486 | this.getSize = function () {
2487 | return wheelBlockSize;
2488 | };
2489 |
2490 | // if align not setted get selected
2491 | this.getColorSaver = function (align) {
2492 | for (var i = 0; i <= colorSavers.length - 1; ++i)
2493 | {
2494 | if ((!align && colorSavers[i].selected) || colorSavers[i].align == align) {
2495 | colorSavers[i].rgb = hexToRgb(colorSavers[i].color);
2496 | colorSavers[i].hsv = rgbToHsv(colorSavers[i].rgb.r, colorSavers[i].rgb.g, colorSavers[i].rgb.b);
2497 | return colorSavers[i];
2498 | }
2499 | }
2500 | };
2501 |
2502 | this.setColorSaver = function (align) {
2503 |
2504 | if (!align)
2505 | return false;
2506 |
2507 | for (var i = 0; i <= colorSavers.length - 1; ++i)
2508 | {
2509 | if (colorSavers[i].align == align) {
2510 | selectColorSaver(i);
2511 | return colorSavers[i];
2512 | }
2513 | }
2514 | }
2515 |
2516 | this.updateView = function (dropBuffer) {
2517 | if (!ctx)
2518 | return false;
2519 |
2520 | if (dropBuffer) {
2521 | wheel.imageData = null;
2522 | svFig.imageData = null;
2523 | canvasHelperData = null;
2524 | }
2525 |
2526 | rendered = false;
2527 | updateSize();
2528 | draw();
2529 | return true;
2530 | };
2531 |
2532 | // resize canvas, with all data \ full refresh view
2533 | // if size same as current and refresh variable setted to true - refresh current view anyway
2534 | // othervise exit with return true
2535 |
2536 | this.resize = function (size, refresh) {
2537 | if (!ctx)
2538 | return false;
2539 | if (size == wheelBlockSize && !refresh)
2540 | return true;
2541 |
2542 | rendered = false;
2543 | wheel.imageData = null;
2544 | svFig.imageData = null;
2545 | canvasHelperData = null;
2546 | wheelBlockSize = size;
2547 | updateSize();
2548 |
2549 | handler.setColorByHex(false);
2550 | return false;
2551 | };
2552 |
2553 | this.syncSize = function (e) {
2554 |
2555 | if (!resizeWith)
2556 | return false;
2557 |
2558 | var newSize = getSizeByElement(resizeWith);
2559 | if (newSize)
2560 | handler.resize(newSize);
2561 | return false;
2562 | }
2563 |
2564 | this.setMethod = function (newMethod) {
2565 | if (!newMethod) {
2566 | newMethod = 'triangle';
2567 | if (method == 'triangle')
2568 | newMethod = 'quad';
2569 | }
2570 |
2571 | if (newMethod == method)
2572 | return false;
2573 | if (method != 'quad' && method != 'triangle')
2574 | return false;
2575 |
2576 | method = newMethod;
2577 |
2578 | if (method == 'quad')
2579 | svFig = getSvFigureQuad();
2580 | if (method == 'triangle')
2581 | svFig = getSvFigureTriangle();
2582 |
2583 | handler.resize(wheelBlockSize, true);
2584 |
2585 | if (userEvents["setmethod"]) {
2586 | var callback = userEvents["setmethod"];
2587 | callback(handler, method);
2588 | }
2589 |
2590 | return true;
2591 | }
2592 |
2593 | // restore color of input ?
2594 |
2595 | this.destroy = function () {
2596 | if (!handler) {
2597 | return false;
2598 | }
2599 |
2600 | if (svCursorMouse.curType > 0) {
2601 | KellyColorPicker.cursorLock = false;
2602 | svCursorMouse.initStandartCursor();
2603 | }
2604 |
2605 | if (drag) {
2606 | removeEventListener(document, "mouseup", 'action_process_');
2607 | removeEventListener(document, "mousemove", 'action_process_');
2608 | removeEventListener(document, "touchend", 'action_process_');
2609 | removeEventListener(document, "touchmove", 'action_process_');
2610 |
2611 | drag = false;
2612 | }
2613 |
2614 | if (popup.tag) {
2615 | removeEventListener(input, "click", "popup_");
2616 | }
2617 |
2618 | if (input) {
2619 | removeEventListener(input, "click", 'input_edit_');
2620 | removeEventListener(input, "change", 'input_edit_');
2621 | removeEventListener(input, "keyup", 'input_edit_');
2622 | removeEventListener(input, "keypress", 'input_edit_');
2623 | }
2624 |
2625 | // remove popup close and resize events if this picker include them erlier
2626 | if (KellyColorPicker.popupEventsInclude && events['popup_close_click']) {
2627 | if (KellyColorPicker.activePopUp)
2628 | KellyColorPicker.activePopUp.popUpClose(false);
2629 |
2630 | removeEventListener(document, "click", 'popup_close_');
2631 | removeEventListener(window, "resize", 'popup_resize_');
2632 |
2633 | KellyColorPicker.popupEventsInclude = false;
2634 | }
2635 |
2636 | wheel.imageData = null;
2637 | svFig.imageData = null;
2638 | canvasHelperData = null;
2639 | canvasHelper = null;
2640 |
2641 | if (place && place.parentNode) {
2642 | place.parentNode.removeChild(place);
2643 | }
2644 |
2645 | if (resizeWith) {
2646 | removeEventListener(window, "resize", 'canvas_');
2647 | }
2648 |
2649 | disableEvents(); // remove canvas events
2650 |
2651 | // debug test for check is all events removed
2652 | // for (var key in events) {
2653 | // console.log('key : ' + key + ' data ' + events[key]);
2654 | // }
2655 |
2656 | handler = null;
2657 | };
2658 |
2659 | constructor(cfg);
2660 | }
2661 |
2662 | /* static methods */
2663 |
2664 | /**
2665 | * Тригер для объектов KellyColorPicker, чтобы не сбрасывали стиль курсора при наведении если уже идет выбор цвета
2666 | * Notice : при выходе курсора за границы текущего canvas, событие неизвестного объекта всегда может сбросить изображение курсора
2667 | */
2668 |
2669 | KellyColorPicker.cursorLock = false; // можно указывать handler объекта
2670 | KellyColorPicker.activePopUp = false;
2671 | KellyColorPicker.popupEventsInclude = false; // include events for document and window once for all elements
2672 |
2673 | KellyColorPicker.attachToInputByClass = function (className, cfg) {
2674 |
2675 | var colorPickers = new Array();
2676 | var inputs = document.getElementsByClassName(className);
2677 |
2678 |
2679 | for (var i = 0; i < inputs.length; i++) {
2680 |
2681 | if (cfg)
2682 | cfg.input = inputs[i];
2683 | else
2684 | cfg = {input: inputs[i], size: 150};
2685 |
2686 | colorPickers.push(new KellyColorPicker(cfg));
2687 | }
2688 |
2689 | return colorPickers;
2690 | };
2691 |
2692 | // KellyColorPicker.dragTrigger = false;
2693 |
--------------------------------------------------------------------------------