zoukankan      html  css  js  c++  java
  • canvas 笔记整理

    canvas 判断点是否在多边形内部

    射线法判断点是否在多边形内部

     /**
       * @description 射线法判断点是否在多边形内部
       * @param {Object} p 待判断的点,格式:{ x: X坐标, y: Y坐标 }
       * @param {Array} poly 多边形顶点,数组成员的格式同 p
       * @return {String} 点 p 和多边形 poly 的几何关系
       */
      function rayCasting(p, poly) {
        var px = p.x,
            py = p.y,
            flag = false
    
        for(var i = 0, l = poly.length, j = l - 1; i < l; j = i, i++) {
          var sx = poly[i].x,
              sy = poly[i].y,
              tx = poly[j].x,
              ty = poly[j].y
    
          // 点与多边形顶点重合
          if((sx === px && sy === py) || (tx === px && ty === py)) {
            return 'on'
          }
    
          // 判断线段两端点是否在射线两侧
          if((sy < py && ty >= py) || (sy >= py && ty < py)) {
            // 线段上与射线 Y 坐标相同的点的 X 坐标
            var x = sx + (py - sy) * (tx - sx) / (ty - sy)
    
            // 点在多边形的边上
            if(x === px) {
              return 'on'
            }
    
            // 射线穿过多边形的边界
            if(x > px) {
              flag = !flag
            }
          }
        }
    
        // 射线穿过多边形边界的次数为奇数时点在多边形内
        return flag ? 'in' : 'out'
      }

    回转数法实现 判断点是否在多边形内部

    /**
       * @description 回转数法判断点是否在多边形内部
       * @param {Object} p 待判断的点,格式:{ x: X坐标, y: Y坐标 }
       * @param {Array} poly 多边形顶点,数组成员的格式同 p
       * @return {String} 点 p 和多边形 poly 的几何关系
       */
      function windingNumber(p, poly) {
        var px = p.x,
            py = p.y,
            sum = 0
    
        for(var i = 0, l = poly.length, j = l - 1; i < l; j = i, i++) {
          var sx = poly[i].x,
              sy = poly[i].y,
              tx = poly[j].x,
              ty = poly[j].y
    
          // 点与多边形顶点重合或在多边形的边上
          if((sx - px) * (px - tx) >= 0 && (sy - py) * (py - ty) >= 0 && (px - sx) * (ty - sy) === (py - sy) * (tx - sx)) {
            return 'on'
          }
    
          // 点与相邻顶点连线的夹角
          var angle = Math.atan2(sy - py, sx - px) - Math.atan2(ty - py, tx - px)
    
          // 确保夹角不超出取值范围(-π 到 π)
          if(angle >= Math.PI) {
            angle = angle - Math.PI * 2
          } else if(angle <= -Math.PI) {
            angle = angle + Math.PI * 2
          }
    
          sum += angle
        }
    
        // 计算回转数并判断点和多边形的几何关系
        return Math.round(sum / Math.PI) === 0 ? 'out' : 'in'
      }

    参考:

    http://www.html-js.com/article/1538

    isPointInPath()方法
    定义与用法:  isPointInPath()方法返回true,如果给定的点的坐标位于路径之内的话(包括路径的边),否则返回 false。
    语法:  context.isPointInPath(x,y);//其中x,y分别是给定点的横、纵坐标
    isPointInStroke()
    是 Canvas 2D API 用于检测某点是否在路径的描边线上的方法。返回值是一个布尔值,当这个点在路径的描边线上,则返回true,否则返回false。
    

     结合 isPointInPath,然后判断 点与边界重合,这样兼容点在线上的点击事件;

     

    canvas Retina 屏幕优化

    /**
     * HiDPI Canvas Polyfill (1.0.9)
     *
     * Author: Jonathan D. Johnson (http://jondavidjohn.com)
     * Homepage: https://github.com/jondavidjohn/hidpi-canvas-polyfill
     * Issue Tracker: https://github.com/jondavidjohn/hidpi-canvas-polyfill/issues
     * License: Apache 2.0
    */
    ;(function(prototype) {
     
        var pixelRatio = (function(context) {
                var backingStore = context.backingStorePixelRatio ||
                            context.webkitBackingStorePixelRatio ||
                            context.mozBackingStorePixelRatio ||
                            context.msBackingStorePixelRatio ||
                            context.oBackingStorePixelRatio ||
                            context.backingStorePixelRatio || 1;
     
                return (window.devicePixelRatio || 1) / backingStore;
            })(prototype),
     
            forEach = function(obj, func) {
                for (var p in obj) {
                    if (obj.hasOwnProperty(p)) {
                        func(obj[p], p);
                    }
                }
            },
     
            ratioArgs = {
                'fillRect': 'all',
                'clearRect': 'all',
                'strokeRect': 'all',
                'moveTo': 'all',
                'lineTo': 'all',
                'arc': [0,1,2],
                'arcTo': 'all',
                'bezierCurveTo': 'all',
                'isPointinPath': 'all',
                'isPointinStroke': 'all',
                'quadraticCurveTo': 'all',
                'rect': 'all',
                'translate': 'all',
                'createRadialGradient': 'all',
                'createLinearGradient': 'all'
            };
     
        if (pixelRatio === 1) return;
     
        forEach(ratioArgs, function(value, key) {
            prototype[key] = (function(_super) {
                return function() {
                    var i, len,
                        args = Array.prototype.slice.call(arguments);
     
                    if (value === 'all') {
                        args = args.map(function(a) {
                            return a * pixelRatio;
                        });
                    }
                    else if (Array.isArray(value)) {
                        for (i = 0, len = value.length; i < len; i++) {
                            args[value[i]] *= pixelRatio;
                        }
                    }
     
                    return _super.apply(this, args);
                };
            })(prototype[key]);
        });
     
         // Stroke lineWidth adjustment
        prototype.stroke = (function(_super) {
            return function() {
                this.lineWidth *= pixelRatio;
                _super.apply(this, arguments);
                this.lineWidth /= pixelRatio;
            };
        })(prototype.stroke);
     
        // Text
        //
        prototype.fillText = (function(_super) {
            return function() {
                var args = Array.prototype.slice.call(arguments);
     
                args[1] *= pixelRatio; // x
                args[2] *= pixelRatio; // y
     
                this.font = this.font.replace(
                    /(d+)(px|em|rem|pt)/g,
                    function(w, m, u) {
                        return (m * pixelRatio) + u;
                    }
                );
     
                _super.apply(this, args);
     
                this.font = this.font.replace(
                    /(d+)(px|em|rem|pt)/g,
                    function(w, m, u) {
                        return (m / pixelRatio) + u;
                    }
                );
            };
        })(prototype.fillText);
     
        prototype.strokeText = (function(_super) {
            return function() {
                var args = Array.prototype.slice.call(arguments);
     
                args[1] *= pixelRatio; // x
                args[2] *= pixelRatio; // y
     
                this.font = this.font.replace(
                    /(d+)(px|em|rem|pt)/g,
                    function(w, m, u) {
                        return (m * pixelRatio) + u;
                    }
                );
     
                _super.apply(this, args);
     
                this.font = this.font.replace(
                    /(d+)(px|em|rem|pt)/g,
                    function(w, m, u) {
                        return (m / pixelRatio) + u;
                    }
                );
            };
        })(prototype.strokeText);
    })(CanvasRenderingContext2D.prototype);
    ;(function(prototype) {
        prototype.getContext = (function(_super) {
            return function(type) {
                var backingStore, ratio,
                    context = _super.call(this, type);
     
                if (type === '2d') {
     
                    backingStore = context.backingStorePixelRatio ||
                                context.webkitBackingStorePixelRatio ||
                                context.mozBackingStorePixelRatio ||
                                context.msBackingStorePixelRatio ||
                                context.oBackingStorePixelRatio ||
                                context.backingStorePixelRatio || 1;
     
                    ratio = (window.devicePixelRatio || 1) / backingStore;
     
                    if (ratio > 1) {
                        this.style.height = this.height + 'px';
                        this.style.width = this.width + 'px';
                        this.width *= ratio;
                        this.height *= ratio;
                    }
                }
     
                return context;
            };
        })(prototype.getContext);
    })(HTMLCanvasElement.prototype);
    

      

     

    jcanvascript.js类库 备份

    /*!
     * jCanvaScript JavaScript Library v 1.5.18
     * http://jcscript.com/
     *
     * Copyright 2012, Alexander Savin
     * Dual licensed under the MIT or GPL Version 2 licenses.
     */
    (function (window, undefined) {
        var canvases = [],
            m = Math,
            m_pi = m.PI,
            pi2 = m_pi * 2,
            lastCanvas = 0, lastLayer = 0,
            underMouse = false,
            underMouseLayer = false,
            regHasLetters = /[A-z]+?/,
            regNumsWithMeasure = /d.ww/,
            FireFox = window.navigator.userAgent.match(/Firefox/w+.w+/i),
            radian = 180 / m_pi,
            m_max = m.max,
            m_min = m.min,
            m_cos = m.cos,
            m_sin = m.sin,
            m_floor = m.floor,
            m_round = m.round,
            m_abs = m.abs,
            m_pow = m.pow,
            m_sqrt = m.sqrt,
            fps = 1000 / 60,
            requestAnimFrame = (function () {
                return window.requestAnimationFrame ||
                    window.webkitRequestAnimationFrame ||
                    window.mozRequestAnimationFrame ||
                    window.oRequestAnimationFrame ||
                    window.msRequestAnimationFrame ||
                    function (callback, element) {
                        return setTimeout(callback, fps);
                    }
            })(),
            cancelRequestAnimFrame = (function () {
                return window.cancelAnimationFrame ||
                    window.webkitCancelRequestAnimationFrame ||
                    window.mozCancelRequestAnimationFrame ||
                    window.oCancelRequestAnimationFrame ||
                    window.msCancelRequestAnimationFrame ||
                    clearTimeout
            })();
        if (FireFox != "" && FireFox !== null)
            var FireFox_lt_7 = (parseInt(FireFox[0].split(/[ /.]/i)[1]) < 7);
    
        function findById(i, j, stroke) {
            var objs = canvases[i].layers[j].objs,
                grdntsnptrns = canvases[i].layers[j].grdntsnptrns,
                objsLength = objs.length,
                grdntsnptrnsLength = grdntsnptrns.length;
            stroke = stroke.slice(1);
            for (var k = 0; k < objsLength; k++)
                if (objs[k].optns.id == stroke)return objs[k];
            for (k = 0; k < grdntsnptrnsLength; k++)
                if (grdntsnptrns[k].optns.id == stroke)return grdntsnptrns[k];
            return false;
        }
    
        function findByName(i, j, myGroup, stroke) {
            var objs = canvases[i].layers[j].objs,
                grdntsnptrns = canvases[i].layers[j].grdntsnptrns,
                strokes = stroke.slice(1).split('.');
            findByNames(myGroup, strokes, objs);
            findByNames(myGroup, strokes, grdntsnptrns);
            return myGroup;
            function findByNames(myGroup, strokes, objs){
                var objsLength = objs.length,
                    names, l, k, m;
                for (k = 0; k < objsLength; k++) {
                    names = objs[k]._name.split(' ');
                    if(strokes.length > names.length){
                        continue;
                    }
                    var strokesClone = strokes.concat();
                    for(l = 0; l < names.length; l++){
                        for(m = 0; m < strokesClone.length; m++){
                            if (names[l] === strokesClone[m]) {
                                strokesClone.splice(m, 1);
                                m--;
                                continue;
                            }
                        }
                        if(!strokesClone.length){
                            myGroup.elements.push(objs[k]);
                            break;
                        }
                    }
                }
            }
        }
    
        function findByCanvasAndLayer(i, j, myGroup) {
            var objs = canvases[i].layers[j].objs,
                grdntsnptrns = canvases[i].layers[j].grdntsnptrns,
                objsLength = objs.length,
                grdntsnptrnsLength = grdntsnptrns.length;
            for (var k = 0; k < objsLength; k++)
                myGroup.elements.push(objs[k]);
            for (k = 0; k < grdntsnptrnsLength; k++)
                myGroup.elements.push(grdntsnptrns[k]);
            return myGroup;
        }
    
        var jCanvaScript = function (stroke, map) {
            if (stroke === undefined)return this;
            if (typeof stroke == 'object') {
                map = stroke;
                stroke = undefined;
            }
            var canvasNumber = -1, layerNumber = -1, limitC = canvases.length, myGroup = group(), i, j, canvas, layer, layers, element, limitL;
            if (map === undefined) {
                if (stroke.charAt(0) === '#') {
                    for (i = 0; i < limitC; i++) {
                        limitL = canvases[i].layers.length;
                        for (j = 0; j < limitL; j++) {
                            element = findById(i, j, stroke);
                            if (element)return element;
                        }
                    }
                }
                if (stroke.charAt(0) === '.') {
                    for (i = 0; i < limitC; i++) {
                        limitL = canvases[i].layers.length;
                        for (j = 0; j < limitL; j++)
                            myGroup = findByName(i, j, myGroup, stroke);
                    }
                }
            }
            else {
                if (map.canvas !== undefined) {
                    for (i = 0; i < limitC; i++)
                        if (canvases[i].optns.id == map.canvas) {
                            canvasNumber = i;
                            canvas = canvases[i];
                            break;
                        }
                }
                if (map.layer !== undefined) {
                    if (canvasNumber != -1) {
                        limitL = canvas.layers.length;
                        for (i = 0; i < limitL; i++)
                            if (canvas.layers[i].optns.id == map.layer) {
                                layerNumber = i;
                                layer = canvas.layers[i];
                                break;
                            }
                    }
                    else {
                        for (i = 0; i < limitC; i++) {
                            layers = canvases[i].layers;
                            limitL = layers.length;
                            for (j = 0; j < limitL; j++) {
                                if (layers[j].optns.id == map.layer) {
                                    canvasNumber = i;
                                    layerNumber = j;
                                    canvas = canvases[i]
                                    layer = canvas.layers[j];
                                    break;
                                }
                            }
                            if (layer > -1)break;
                        }
                    }
                }
                if (layerNumber < 0 && canvasNumber < 0)return group();
                if (layerNumber < 0) {
                    layers = canvas.layers;
                    limitL = layers.length;
                    if (stroke === undefined) {
                        for (j = 0; j < limitL; j++)
                            myGroup = findByCanvasAndLayer(canvasNumber, j, myGroup);
                    }
                    else if (stroke.charAt(0) === '#') {
                        for (j = 0; j < limitL; j++) {
                            element = findById(canvasNumber, j, stroke);
                            if (element)return element;
                        }
                    }
                    else if (stroke.charAt(0) === '.') {
                        for (j = 0; j < limitL; j++)
                            myGroup = findByName(canvasNumber, j, myGroup, stroke);
                    }
                }
                else {
                    if (stroke === undefined) {
                        myGroup = findByCanvasAndLayer(canvasNumber, layerNumber, myGroup);
                    }
                    if (stroke.charAt(0) === '#') {
                        return findById(canvasNumber, layerNumber, stroke);
                    }
                    if (stroke.charAt(0) === '.') {
                        myGroup = findByName(canvasNumber, layerNumber, myGroup, stroke)
                    }
                }
            }
            if (map !== undefined)
                if (map.attrs !== undefined || map.fns !== undefined)
                    return myGroup.find(map);
            if (myGroup.elements.length)return myGroup;
            return group();
        }
    
    
        
    function changeMatrix(object)
    {
    	var optns=object.optns;
    	object.matrix(multiplyM(multiplyM(multiplyM(optns.transformMatrix,optns.translateMatrix),optns.scaleMatrix),optns.rotateMatrix));
    	redraw(object);
    }
    function checkDefaults(check,def)
    {
    	for(var key in def)
    	{
    		if(check[key]===undefined)check[key]=def[key];
    	}
    	return check;
    }
    
    function redraw(object)
    {
    	objectCanvas(object).optns.redraw=1;
    }
    
    function animating(canvasOptns)
    {
    	var timeDiff=canvasOptns.timeDiff,
    		progress=1;
    	for(var q=0;q<this.animateQueue.length;q++)
    	{
    		var queue=this.animateQueue[q],
    			duration=queue['duration'],
    			easing=queue['easing'],
    			step=queue.step,
    			onstep=queue['onstep'],
    			easingIn=easing['type']=='in' || (easing['type']=='inOut' && progress<0.5),
    			easingOut=easing['type']=='out' || (easing['type']=='inOut' && progress>0.5);
    			queue['step']+=timeDiff;
    			progress=step/duration;
    		for(var key in queue)
    		{
    			if(this[key]!==undefined && queue[key])
    			{
    				var property=queue[key],
    					to=property['to'],
    					from=property['from'];
    				animateTransforms(key,this,queue);
    				if(easingIn)this[key]=(to-from)*animateFunctions[easing['fn']](progress,easing)+from;
    				if(easingOut)this[key]=(to-from)*(1-animateFunctions[easing['fn']](1-progress,easing))+from;
    				if(onstep)onstep.fn.call(this,onstep);
    				if(step>=duration)
    				{
    					this[key]=to;
    					animateTransforms(key,this,queue);
    					queue[key]=false;
    					queue.animateKeyCount--;
    					if(!queue.animateKeyCount)
    					{
    						if(queue.animateFn)queue.animateFn.apply(this);
    						this.animateQueue.splice(q,1);
    						q--;
    					}
    				}
    			}
    		}
    	}
    	if (this.animateQueue.length)redraw(this);
    	else this.optns.animated=false;
    	return this;
    }
    function animateTransforms(key,object,queue)
    {
    	var val=object[key];
    	var prev=queue[key]['prev'];
    	switch(key)
    	{
    		case '_rotateAngle':
    			object.rotate(val-prev,object._rotateX,object._rotateY);
    			break;
    		case '_translateX':
    			object.translate(val-prev,0);
    			break;
    		case '_translateY':
    			object.translate(0,val-prev);
    			break;
    		case '_translateToX':
    			object.translateTo(val,undefined);
    			break;
    		case '_translateToY':
    			object.translateTo(undefined,val);
    			break;
    		case '_scaleX':
    			if(!prev)prev=1;
    			object.scale(val/prev,1);
    			break;
    		case '_scaleY':
    			if(!prev)prev=1;
    			object.scale(1,val/prev);
    			break;
    		default:
    			return;
    	}
    	queue[key]['prev']=val;
    }
    function keyEvent(e,key,optns)
    {
    	e=e||window.event;
    	optns[key].event=e;
    	optns[key].code=e.charCode||e.keyCode;
    	optns[key].val=true;
    	optns.redraw=1;
    }
    function mouseEvent(e,key,optns)
    {
    	if(!optns[key].val)return;
    	e=e||window.event;
    	var point= {
    		pageX:e.pageX||e.clientX,
    		pageY:e.pageY||e.clientY
    	};
    	optns[key].event=e;
    	optns[key].x=point.pageX - optns.x;
    	optns[key].y=point.pageY - optns.y;
    	optns.redraw=1;
    }
    function setMouseEvent(fn,eventName)
    {
    	if(fn===undefined)this['on'+eventName]();
    	else this['on'+eventName] = fn;
    	if(eventName=='mouseover'||eventName=='mouseout')eventName='mousemove';
    	objectCanvas(this).optns[eventName].val=true;
    	return this;
    }
    function setKeyEvent(fn,eventName)
    {
    	if(fn===undefined)this[eventName]();
    	else this[eventName] = fn;
    	return this;
    }
    var animateFunctions={
    	linear:function(progress,params){
    		return progress;
    	},
    	exp:function(progress,params){
    		var n=params.n||2;
    		return m_pow(progress,n);
    	},
    	circ:function(progress,params){
    		return 1 - m_sqrt(1-progress*progress);
    	},
    	sine:function(progress,params){
    		return 1 - m_sin((1 - progress) * m_pi/2);
    	},
    	back:function(progress,params){
    		var n=params.n||2;
    		var x=params.x||1.5;
    		return m_pow(progress, n) * ((x + 1) * progress - x);
    	},
    	elastic:function(progress,params){
    		var n=params.n||2;
    		var m=params.m||20;
    		var k=params.k||3;
    		var x=params.x||1.5;
    		return m_pow(n,10 * (progress - 1)) * m_cos(m * progress * m_pi * x / k);
    	},
    	bounce:function(progress,params)
    	{
    		var n=params.n||4;
    		var b=params.b||0.25;
    		var sum = [1];
    		for(var i=1; i<n; i++) sum[i] = sum[i-1] + m_pow(b, i/2);
    		var x = 2*sum[n-1]-1;
    		for(i=0; i<n; i++)
    		{
    			if(x*progress >= (i>0 ? 2*sum[i-1]-1 : 0) && x*progress <= 2*sum[i]-1)
    				return m_pow(x*(progress-(2*sum[i]-1-m_pow(b, i/2))/x), 2)+1-m_pow(b, i);
    		}
    		return 1;
    	}
    },
    imageDataFilters={
    	color:{fn:function(width,height,matrix,type){
    		var old,i,j;
    		matrix=matrix[type];
    		for(i=0;i<width;i++)
    		for(j=0;j<height;j++)
    		{
    			old=this.getPixel(i,j);
    			old[matrix[0]]=old[matrix[0]]*2-old[matrix[1]]-old[matrix[2]];
    			old[matrix[1]]=0;
    			old[matrix[2]]=0;
    			old[matrix[0]]=old[matrix[0]]>255?255:old[matrix[0]];
    			this.setPixel(i,j,old);
    		}
    	},matrix:
    		{
    			red:[0,1,2],
    			green:[1,0,2],
    			blue:[2,0,1]
    		}},
    	linear:{fn:function(width,height,matrix,type){
    		var newMatrix=[],old,i,j,k,m,n;
    		matrix=matrix[type];
    		m=matrix.length;
    		n=matrix[0].length;
    			for(i=0;i<width;i++)
    			{
    				newMatrix[i]=[];
    				for(j=0;j<height;j++)
    				{
    					newMatrix[i][j]=[0,0,0,1];
    					for(m=0;m<3;m++)
    					for(n=0;n<3;n++)
    					{
    						old=this.getPixel(i-parseInt(m/2),j-parseInt(n/2));
    						for(k=0;k<3;k++)
    						{
    							newMatrix[i][j][k]+=old[k]*matrix[m][n];
    						}
    					}
    				}
    			}
    			for(i=0;i<width;i++)
    			{
    				for(j=0;j<height;j++)
    					this.setPixel(i,j,newMatrix[i][j]);
    			}
    	},
    		matrix:{
    			sharp:[[-0.375,-0.375,-0.375],[-0.375,4,-0.375],[-0.375,-0.375,-0.375]],
    			blur:[[0.111,0.111,0.111],[0.111,0.111,0.111],[0.111,0.111,0.111]]
    		}
    	}
    }
    
    function multiplyM(m1,m2)
    {
    	return [[(m1[0][0]*m2[0][0]+m1[0][1]*m2[1][0]),(m1[0][0]*m2[0][1]+m1[0][1]*m2[1][1]),(m1[0][0]*m2[0][2]+m1[0][1]*m2[1][2]+m1[0][2])],[(m1[1][0]*m2[0][0]+m1[1][1]*m2[1][0]),(m1[1][0]*m2[0][1]+m1[1][1]*m2[1][1]),(m1[1][0]*m2[0][2]+m1[1][1]*m2[1][2]+m1[1][2])]];
    }
    function multiplyPointM(x,y,m)
    {
    	return {
    		x:(x*m[0][0]+y*m[0][1]+m[0][2]),
    		y:(x*m[1][0]+y*m[1][1]+m[1][2])
    	}
    }
    function transformPoint(x,y,m)
    {
    	return{
    		x:(x*m[1][1]-y*m[0][1]+m[0][1]*m[1][2]-m[1][1]*m[0][2])/(m[0][0]*m[1][1]-m[1][0]*m[0][1]),
    		y:(-x*m[1][0]+y*m[0][0]-m[0][0]*m[1][2]+m[1][0]*m[0][2])/(m[0][0]*m[1][1]-m[1][0]*m[0][1])
    	}
    }
    function getRect(object,rect,type)
    {
    	if(type=='poor')return rect;
    	var min={x:rect.x,y:rect.y},max={x:rect.x+rect.width,y:rect.y+rect.height},
    	m=multiplyM(object.matrix(),objectLayer(object).matrix()),
    	lt=multiplyPointM(min.x,min.y,m),
    	rt=multiplyPointM(max.x,min.y,m),
    	lb=multiplyPointM(min.x,max.y,m),
    	rb=multiplyPointM(max.x,max.y,m),
    	coords=[[lt.x,lt.y],[rt.x,rt.y],[lb.x,lb.y],[rb.x,rb.y]];
    	if(type=='coords')return coords;
    	var minX, minY,
    	maxX=minX=lt.x,
    	maxY=minY=lt.y;
    	for(var i=0;i<4;i++)
    	{
    		if(maxX<coords[i][0])maxX=coords[i][0];
    		if(maxY<coords[i][1])maxY=coords[i][1];
    		if(minX>coords[i][0])minX=coords[i][0];
    		if(minY>coords[i][1])minY=coords[i][1];
    	}
    	return {x:minX,y:minY,maxX-minX,height:maxY-minY};
    }
    function getCenter(object,point,type)
    {
    	if(type=='poor')return point;
    	return multiplyPointM(point.x,point.y,multiplyM(object.matrix(),objectLayer(object).matrix()));
    }
    function parseColor(color)
    {
    	var colorKeeper={
    		color:{
    			val:color,
    			notColor:undefined
    		},
    		r:0,
    		g:0,
    		b:0,
    		a:1};
    	if(color.id!==undefined)
    	{
    		colorKeeper.color.notColor={
    			level:color._level,
    			canvas:color.optns.canvas.number,
    			layer:color.optns.layer.number
    		}
    		return colorKeeper;
    	}
    	if(color.r!==undefined)
    	{
    		colorKeeper=checkDefaults(color,{r:0,g:0,b:0,a:1});
    		colorKeeper.color={
    			val:'rgba('+colorKeeper.r+','+colorKeeper.g+','+colorKeeper.b+','+colorKeeper.a+')',
    			notColor:undefined
    		}
    		return colorKeeper;
    	}
    	if(color.charAt(0)=='#')
    	{
            if (color.length > 4) {
                colorKeeper.r = parseInt(color.substr(1, 2), 16);
                colorKeeper.g = parseInt(color.substr(3, 2), 16);
                colorKeeper.b = parseInt(color.substr(5, 2), 16);
            }
            else {
                var r = color.charAt(1), g = color.charAt(2), b = color.charAt(3);
                colorKeeper.r = parseInt(r + r, 16);
                colorKeeper.g = parseInt(g + g, 16);
                colorKeeper.b = parseInt(b + b, 16);
            }
    	}
    	else
    	{
    		var arr=color.split(',');
    		if(arr.length==4)
    		{
    			var colorR = arr[0].split('(');
    			var alpha = arr[3].split(')');
    			colorKeeper.r=parseInt(colorR[1]);
    			colorKeeper.g=parseInt(arr[1]);
    			colorKeeper.b=parseInt(arr[2]);
    			colorKeeper.a=parseFloat(alpha[0]);
    		}
    		if(arr.length==3)
    		{
    			colorR = arr[0].split('(');
    			var colorB = arr[2].split(')');
    			colorKeeper.r=parseInt(colorR[1]);
    			colorKeeper.g=parseInt(arr[1]);
    			colorKeeper.b=parseInt(colorB[0]);
    		}
    	}
    	colorKeeper.color.notColor = undefined;
    	return colorKeeper;
    }
    function getOffset(elem) {
    	if (elem.getBoundingClientRect) {
    		return getOffsetRect(elem)
    	} else {
    		return getOffsetSum(elem)
    	}
    }
    
    function getOffsetSum(elem) {
    	var top=0, left=0
    	while(elem) {
    		top = top + parseInt(elem.offsetTop)
    		left = left + parseInt(elem.offsetLeft)
    		elem = elem.offsetParent
    	}
    	return {
    		top: top,
    		left: left
    	}
    }
    
    function getOffsetRect(elem) {
    	var box = elem.getBoundingClientRect()
    	var body = document.body||{};
    	var docElem = document.documentElement
    	var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop
    	var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft
    	var clientTop = docElem.clientTop || body.clientTop || 0
    	var clientLeft = docElem.clientLeft || body.clientLeft || 0
    	var top  = box.top +  scrollTop - clientTop
    	var left = box.left + scrollLeft - clientLeft
    	return {
    		top: m_round(top),
    		left: m_round(left)
    	}
    }
    function checkEvents(object,optns)
    {
    	checkMouseEvents(object,optns);
    	checkKeyboardEvents(object,optns);
    }
    function checkKeyboardEvents(object,optns)
    {
    	if(!object.optns.focused)return;
    	if(optns.keyDown.val!=false)if(typeof object.onkeydown=='function')object.onkeydown(optns.keyDown);
    	if(optns.keyUp.val!=false)if(typeof object.onkeyup=='function')object.onkeyup(optns.keyUp);
    	if(optns.keyPress.val!=false)if(typeof object.onkeypress=='function')object.onkeypress(optns.keyPress);
    }
    function isPointInPath(object,x,y)
    {
    	var point={};
    	var canvas=objectCanvas(object);
    	var ctx=canvas.optns.ctx;
    	var layer=canvas.layers[object.optns.layer.number];
    	point.x=x;
    	point.y=y;
    	if(FireFox_lt_7)
    	{
    		point=transformPoint(x,y,layer.matrix());
    		point=transformPoint(point.x,point.y,object.matrix());
    	}
    	if(ctx.isPointInPath===undefined || object._img!==undefined || object._imgData!==undefined || object._proto=='text')
    	{
    		var rectangle=object.getRect('poor');
    		var poorPoint=transformPoint(x,y,multiplyM(object.matrix(),layer.matrix()));
    		if(rectangle.x<=poorPoint.x && rectangle.y<=poorPoint.y && (rectangle.x+rectangle.width)>=poorPoint.x && (rectangle.y+rectangle.height)>=poorPoint.y)return point;
    	}
    	else
    	{
    		if(ctx.isPointInPath(point.x,point.y)){
    			return point;
    		}
    	}
    	return false
    }
    function checkMouseEvents(object,optns)
    {
    	var point=false,
    		mm=optns.mousemove,
    		md=optns.mousedown,
    		mu=optns.mouseup,
    		c=optns.click,
    		dc=optns.dblclick,
    		x=mm.x||md.x||mu.x||dc.x||c.x,
    		y=mm.y||md.y||mu.y||dc.y||c.y;
    	if(x!=false)
    	{
    		point=isPointInPath(object,x,y);
    	}
    	if(point)
    	{
    		
    		if(mm.x!=false)
    			mm.object=object;
    		if(md.x!=false)
    			md.objects[md.objects.length]=object;
    		if(c.x!=false)
    			c.objects[c.objects.length]=object;
    		if(dc.x!=false)
                dc.objects[dc.objects.length]=object;
    		if(mu.x!=false)
    			mu.objects[mu.objects.length]=object;
    		optns.point=point;
    	}
    }
    
    function objectLayer(object)
    {
    	return objectCanvas(object).layers[object.optns.layer.number];
    }
    function objectCanvas(object)
    {
    	return canvases[object.optns.canvas.number];
    }
    function layer(idLayer,object,array)
    {
    	redraw(object);
    	var objectCanvas=object.optns.canvas;
    	var objectLayer=object.optns.layer;
    
    	if (idLayer===undefined)return objectLayer.id;
    	if(objectLayer.id==idLayer)return object;
    	var oldIndex={
    		i:objectCanvas.number,
    		j:objectLayer.number
    	};
    	objectLayer.id=idLayer;
    	var newLayer=jCanvaScript.layer(idLayer);
    	var newIndex={
    		i:newLayer.optns.canvas.number,
    		j:newLayer.optns.number
    	};
    	var oldArray=canvases[oldIndex.i].layers[oldIndex.j][array],newArray=canvases[newIndex.i].layers[newIndex.j][array];
    	oldArray.splice(object.optns.number,1);
    	object._level=object.optns.number=newArray.length;
    	newArray[object._level]=object;
    	objectLayer.number=newIndex.j;
    	objectCanvas.number=newIndex.i;
    	objectCanvas.id=newLayer.optns.canvas.id;
    	redraw(object);
    	return object;
    }
    
    function take(f,s) {
    	for(var key in s)
    	{
    		switch(typeof s[key])
    		{
    			case 'function':
    				if(key.substr(0,2)=='on')break;
    				if(f[key]===undefined)f[key]=s[key];
    				break;
    			case 'object':
    				if(key=='optns' || key=='animateQueue')break;
    				if(key=='objs' || key=='grdntsnptrns')
    				{
    					for(var i in s[key])
    					{
    						if(s[key].hasOwnProperty(i))
    							s[key][i].clone().layer(f.optns.id);
    					}
    					break;
    				}
    				if(!s[key] || key==='ctx')continue;
    				f[key]=typeof s[key].pop === 'function' ? []:{};
    				take(f[key],s[key]);
    				break;
    			default:
    				if(key=='_level')break;
    				f[key]=s[key];
    		}
    	}
    }
    function canvas(idCanvas,object,array)
    {
    	redraw(object);
    	var objectCanvas=object.optns.canvas;
    	var objectLayer=object.optns.layer;
    	if(idCanvas===undefined)return canvases[objectCanvas.number].optns.id;
    	if(canvases[objectCanvas.number].optns.id==idCanvas)return object;
    	var oldIndex={
    		i:objectCanvas.number,
    		j:objectLayer.number
    	};
    	jCanvaScript.canvas(idCanvas);
    	for(var i=0;i<canvases.length;i++)
    	{
    		var canvasItem=canvases[i];
    		if(canvasItem.optns.id==idCanvas)
    		{
    			var oldArray=canvases[oldIndex.i].layers[oldIndex.j][array],newArray=canvasItem.layers[0][array];
    			oldArray.splice(object.optns.number,1);
    			normalizeLevels(oldArray);
    			object._level=object.optns.number=newArray.length;
    			newArray[object._level]=object;
    			objectLayer.number=0;
    			objectCanvas.number=i;
    			objectCanvas.id=canvasItem.optns.id;
    			objectLayer.id=canvasItem.layers[0].optns.id;
    		}
    	}
    	redraw(object);
    	return object;
    }
    function normalizeLevels(array)
    {
    	for(var i=0;i<array.length;i++)
    	{
    		array[i].optns.number=i;
    	}
    }
    function setLayerAndCanvasToArray(array,newLayerId,newLayerNumber,newCanvasId,newCanvasNumber)
    {
    	var limit=array.length,
    	optns,canvas,layer;
    	for(var i=0;i<limit;i++)
    	{
    		optns=array[i].optns;
    		canvas=optns.canvas;
    		layer=optns.layer;
    		canvas.id=newCanvasId;
    		canvas.number=newCanvasNumber;
    		layer.id=newLayerId;
    		layer.number=newLayerNumber;
    	}
    }
    function levelChanger(array)
    {
    	array.sort(function(a,b){
    		if(a._level>b._level)return 1;
    		if(a._level<b._level)return -1;
    		return 0;
    	});
    	normalizeLevels(array);
    	return array.length;
    }
    function objDeleter(array)
    {
    	var isAnyObjectDeleted;
    	do{
    		isAnyObjectDeleted=false;
    		for(var i=0;i<array.length;i++)
    		{
    			if(array[i].optns.deleted)
    			{
    				array.splice(i,1);
    				isAnyObjectDeleted=true;
    			}
    		}
    	}while(isAnyObjectDeleted);
    	normalizeLevels(array);
    	return array.length;
    }
    var proto={};
    
    
        
    proto.object=function()
    {
    	this.getCenter=function(type){
    		var rect=this.getRect('poor'),
    		point = {
    					x:(rect.x*2+rect.width)/2,
    					y:(rect.y*2+rect.height)/2
    				};
    		return getCenter(this,point,type);
    	}
    	this.position=function(){
    		return multiplyPointM(this._x,this._y,multiplyM(this.matrix(),objectLayer(this).matrix()));
    	}
    	this.buffer=function(doBuffering){
    		var bufOptns=this.optns.buffer;
    		if(doBuffering===undefined)
    			if(bufOptns.val)return bufOptns.cnv;
    			else return false;
    		if(bufOptns.val===doBuffering)return this;
    		if(doBuffering)
    		{
    			var cnv=bufOptns.cnv=document.createElement('canvas'),
    				ctx=bufOptns.ctx=cnv.getContext('2d'),
    				rect=bufOptns.rect=this.getRect(),
    				oldM=this.transform();
    			cnv.setAttribute('width',rect.width);
    			cnv.setAttribute('height',rect.height);
    			bufOptns.x=this._x;
    			bufOptns.y=this._y;
    			bufOptns.dx=this._transformdx;
    			bufOptns.dy=this._transformdy;
    			this._x=this._y=0;
    			this.transform(1, 0, 0, 1, -rect.x+bufOptns.dx, -rect.y+bufOptns.dy,true);
    			this.setOptns(ctx);
    			take(bufOptns.optns={},objectCanvas(this).optns);
    			bufOptns.optns.ctx=ctx;
    			this.draw(bufOptns.optns);
    			this._x=bufOptns.x;
    			this._y=bufOptns.y;
    			this.transform(oldM[0][0], oldM[1][0], oldM[0][1], oldM[1][1], rect.x, rect.y,true);
    			bufOptns.val=true;
    		}
    		else
    		{
    			this.translate(-bufOptns.rect.x+bufOptns.dx,-bufOptns.rect.y+bufOptns.dy);
    			this.optns.buffer={val:false};
    		}
    		return this;
    	}
    	this.clone=function(params)
    	{
    		var clone=new proto[this._proto];
    		proto[this._proto].prototype.base.call(clone);
    		take(clone,this);
    		clone.layer(objectLayer(this).optns.id);
    		take(clone.optns.transformMatrix,this.optns.transformMatrix);
    		take(clone.optns.translateMatrix,this.optns.translateMatrix);
    		take(clone.optns.scaleMatrix,this.optns.scaleMatrix);
    		take(clone.optns.rotateMatrix,this.optns.rotateMatrix);
    		if(params===undefined) return clone;
    		return clone.animate(params);
    	}
    	this.shadow= function(options)
    	{
    		for(var key in options)
    		switch (key)
    		{
    			case 'x':
    				this._shadowX=options.x;
    				break;
    			case 'y':
    				this._shadowY=options.y;
    				break;
    			case 'blur':
    				this._shadowBlur=options.blur;
    				break;
    			case 'color':
    				var colorKeeper = parseColor(options.color);
    				this._shadowColor = options.color.val;
    				this._shadowColorR = colorKeeper.r;
    				this._shadowColorG = colorKeeper.g;
    				this._shadowColorB = colorKeeper.b;
    				this._shadowColorA = colorKeeper.a;
    				break;
    		}
    		redraw(this);
    		return this;
    	}
    	this.setOptns=function(ctx)
    	{
    		ctx.globalAlpha = this._opacity;
    		ctx.shadowOffsetX = this._shadowX;
    		ctx.shadowOffsetY = this._shadowY;
    		ctx.shadowBlur = this._shadowBlur;
    		ctx.globalCompositeOperation=this._composite;
            var rInt = parseInt(this._shadowColorR),
                gInt = parseInt(this._shadowColorG),
                bInt = parseInt(this._shadowColorB),
                aInt = parseInt(this._shadowColorA * 100) / 100;
            if (this._shadowColorRPrev !== rInt || this._shadowColorGPrev !== gInt || this._shadowColorBPrev !== bInt || this._shadowColorAPrev !== aInt) {
                ctx.shadowColor = this._shadowColor = 'rgba(' + rInt + ', ' + gInt + ', ' + bInt + ', ' + aInt+ ')';
                this._shadowColorRPrev = rInt;
                this._shadowColorGPrev = gInt;
                this._shadowColorBPrev = bInt;
                this._shadowColorAPrev = aInt;
            }
            else {
                ctx.shadowColor = this._shadowColor;
            }
    		ctx.transform(this._transform11,this._transform12,this._transform21,this._transform22,this._transformdx,this._transformdy);
    		return this;
    	}
    	this.up=function(n)
    	{
    		if(n === undefined)n=1;
    		if(n=='top')this.level(n);
    		else {
    			var next=objectLayer(this).objs[this.optns.number+n];
    			if(next!==undefined)
    			{
    				n=next._level+1-this._level;
    			}
    			this.level(this._level+n);
    		}
    		return this;
    	}
    	this.down=function(n)
    	{
    		if(n == undefined)n=1;
    		if(n == 'bottom')this.level(n);
    		else {
    			var previous=objectLayer(this).objs[this.optns.number-n];
    			if(previous!==undefined)
    			{
    				n=this._level-(previous._level-1);
    			}
    			this.level(this._level-n);
    		}
    		return this;
    	}
    	this.level=function(n)
    	{
    		if(n == undefined)return this._level;
    		var layer=objectLayer(this);
    		if(n=='bottom')
    		{
    			if(this.optns.number==0)n=this._level;
    			else n=layer.objs[0]._level-1;
    		}
    		if(n=='top')
    		{
    			if(this.optns.number==layer.objs.length)n=this._level;
    			else n=layer.objs[layer.objs.length-1]._level+1;
    		}
    		this._level=n;
    		layer.optns.anyObjLevelChanged = true;
    		redraw(this);
    		return this;
    	}
    	this.del=function()
    	{
    		this.optns.deleted=true;
    		objectLayer(this).optns.anyObjDeleted = true;
    		redraw(this);
    	}
    	this.focus=function(fn)
    	{
    		if(fn===undefined)
    		{
    			this.optns.focused=true;
    			if(typeof this.onfocus=='function')this.onfocus();
    		}
    		else this.onfocus=fn;
    		return this;
    	}
    	this.blur=function(fn)
    	{
    		if(fn===undefined)
    		{
    			this.optns.focused=false;
    			if(typeof this.onblur == 'function')this.onblur();
    		}
    		else this.onblur=fn;
    		return this;
    	}
    	this.click= function(fn)
    	{
    		return setMouseEvent.call(this,fn,'click');
    	}
    	this.dblclick = function(fn)
    	{
    		return setMouseEvent.call(this,fn,'dblclick');
    	}
    	this.keypress= function(fn)
    	{
    		return setKeyEvent.call(this,fn,'onkeypress');
    	}
    	this.keydown= function(fn)
    	{
    		return setKeyEvent.call(this,fn,'onkeydown');
    	}
    	this.keyup= function(fn)
    	{
    		return setKeyEvent.call(this,fn,'onkeyup');
    	}
    	this.mousedown= function(fn)
    	{
    		return setMouseEvent.call(this,fn,'mousedown');
    	}
    	this.mouseup= function(fn)
    	{
    		return setMouseEvent.call(this,fn,'mouseup');
    	}
    	this.mousemove= function(fn)
    	{
    		return setMouseEvent.call(this,fn,'mousemove');
    	}
    	this.mouseover= function(fn)
    	{
    		return setMouseEvent.call(this,fn,'mouseover');
    	}
    	this.mouseout= function(fn)
    	{
    		return setMouseEvent.call(this,fn,'mouseout');
    	}
    	this.attr=function(parameter,value)
    	{
    		if(typeof parameter==='object')
    			var parameters=parameter;
    		else
    		{
    			if(value===undefined)
    				return this['_'+parameter];
    			parameters={};
    			parameters[parameter]=value;
    		}
    		return this.animate(parameters);
    	}
    	this.queue=function(){
    		var animateQueueLength=this.animateQueue.length, queue,i,j,duration=0,longFn=0,fn,args=arguments;
    		for (i=0;i<args.length;i++)
    		{
    			if(typeof args[i]=='function'){
    				args[i].apply(this);
    				args[i]=false;
    				i++;
    				if(this.animateQueue.length>animateQueueLength)
    				{
    					for (j=animateQueueLength;j<this.animateQueue.length;j++)
    					{
    						queue=this.animateQueue[j];
    						if(queue.duration!==undefined){
    							if(queue.duration>duration)
    							{
    								duration=queue.duration;
    								longFn=j;
    							}
    							break;
    						}
    					}
    					if(duration){
    						queue=this.animateQueue[longFn];
    						if(queue.animateFn){
    							fn=queue.animateFn;
    							queue.animateFn=function(){
    								fn.apply(this);
    								this.queue.apply(this,args)
    							}
    						}
    						else queue.animateFn=function(){this.queue.apply(this,args)};
    						break;
    					}
    				}
    			}
    		}
    	}
    	this.stop=function(jumpToEnd,runCallbacks)
    	{
    		this.optns.animated=false;
    		if(runCallbacks===undefined)runCallbacks=false;
    		if(jumpToEnd===undefined)jumpToEnd=false;
    		for(var q=0;q<this.animateQueue.length;q++)
    		{
    			var queue=this.animateQueue[q];
    			if(runCallbacks)queue.animateFn.call(this);
    			if(jumpToEnd)
    			for(var key in queue)
    			{
    				if(queue[key]['from']!==undefined)
    				{
    					this[key]=queue[key]['to'];
    					animateTransforms(key,this,queue);
    				}
    			}
    		}
    		this.animateQueue=[];
    		return this;
    	}
    	this.animate=function(options,duration,easing,onstep,fn)
    	{
    		if(duration===undefined)duration=1;
    		else
    		{
    			if(typeof duration == 'function')
    			{
    				fn=duration;
    				duration=1;
    			}
    			if(typeof duration == 'object')
    			{
    				easing=duration;
    				duration=1;
    			}
    		}
    		if (easing===undefined)easing={fn:'linear',type:'in'};
    		else
    		{
    			if(typeof easing == 'function')
    			{
    				fn=easing;
    				easing={fn:'linear',type:'in'};
    			}
    			if (easing.type===undefined)easing.type='in';
    		}
    		if(onstep===undefined)onstep=false;
    		else
    		{
    			if(typeof onstep == 'function')
    			{
    				fn=onstep;
    				onstep=false;
    			}
    		}
    		if(options.scale!==undefined)
    		{
    			this._scaleX=this._scaleY=1;
    			if(typeof options.scale!='object')
    			{
    				options.scaleX=options.scaleY=options.scale;
    			}
    			else
    			{
    				options.scaleX=options.scale.x||1;
    				options.scaleY=options.scale.y||1;
    			}
    		}
    		if(options.translate!==undefined)
    		{
    			this._translateX=this._translateY=0;
    
    			if(typeof options.translate!='object')
    			{
    				options.translateX=options.translateY=options.translate;
    			}
    			else
    			{
    				options.translateX=options.translate.x||0;
    				options.translateY=options.translate.y||0;
    			}
    			options.translate=undefined;
    		}
    		if(options.translateTo!==undefined)
    		{
    			var point=this.position();
    			this._translateToX=point.x;
    			this._translateToY=point.y;
    			if(typeof options.translateTo!='object')
    			{
    				options.translateToX=options.translateToY=options.translateTo;
    			}
    			else
    			{
    				options.translateToX=options.translateTo.x||0;
    				options.translateToY=options.translateTo.y||0;
    			}
    			options.translateTo=undefined;
    		}
    		if(options.rotate!==undefined)
    		{
    			options.rotateAngle=options.rotate.angle;
    			this._rotateAngle=0;
    			this._rotateX=options.rotate.x||0;
    			this._rotateY=options.rotate.y||0;
    			options.rotate=undefined;
    		}
    		if(options.color !== undefined)
    		{
    			var colorKeeper=parseColor(options.color);
    			if(colorKeeper.color.notColor)
    				this.optns.color.notColor=colorKeeper.color.notColor;
    			else
    			{
    				options.colorR=colorKeeper.r;
    				options.colorG=colorKeeper.g;
    				options.colorB=colorKeeper.b;
    				options.alpha=colorKeeper.a;
    			}
    			options.color = undefined;
    		}
    		if(options.shadowColor !== undefined)
    		{
    			colorKeeper=parseColor(options.shadowColor);
    			options.shadowColorR=colorKeeper.r;
    			options.shadowColorG=colorKeeper.g;
    			options.shadowColorB=colorKeeper.b;
    			options.shadowColorA=colorKeeper.a;
    			options.shadowColor = undefined;
    		}
    		if(duration>1)
    		{
    			var queue=this.animateQueue[this.animateQueue.length]={animateKeyCount:0};
    			queue.animateFn=fn||false;
    			this.optns.animated=true;
    			queue.duration=duration;
    			queue.step=0;
    			queue.easing=easing;
    			queue.onstep=onstep;
    		}
    		for(var key in options)
    		{
    			if(this['_'+key] !== undefined && options[key]!==undefined)
    			{
    				var keyValue=options[key],privateKey='_'+key;
    				if(keyValue!=this[privateKey])
    				{
    					if(keyValue.charAt)
    					{
    						if(key=='string')this._string=keyValue;
    						else if(keyValue.charAt(1)=='=')
    						{
    							keyValue=this[privateKey]+parseInt(keyValue.charAt(0)+'1')*parseInt(keyValue.substr(2));
    						}
    						else if(!regHasLetters.test(keyValue))keyValue=parseInt(keyValue);
    						else this[privateKey]=keyValue;
    					}
    					if(duration==1)this[privateKey]=keyValue;
    					else
    					{
    						queue[privateKey]={
    							from:this[privateKey],
    							to:keyValue,
    							prev:0
    						}
    						queue.animateKeyCount++;
    					}
    				}
    			}
    		}
    		if(duration==1)
    		{
    			if(options['rotateAngle'])
    				this.rotate(this._rotateAngle,this._rotateX,this._rotateY);
    			if(options['translateX']||options['translateY'])
    				this.translate(this._translateX,this._translateY);
    			if(options['translateToX']||options['translateToY'])
    				this.translate(this._translateToX,this._translateToY);
    			if(options['scaleX']||options['scaleY'])
    				this.scale(this._scaleX,this._scaleY);
    		}
    		redraw(this);
    		return this;
    	}
    	this.matrix=function(m)
    	{
    		if(m===undefined)return [[this._transform11,this._transform21,this._transformdx],[this._transform12,this._transform22,this._transformdy]];
    		this._transform11=m[0][0];
    		this._transform21=m[0][1];
    		this._transform12=m[1][0];
    		this._transform22=m[1][1];
    		this._transformdx=m[0][2];
    		this._transformdy=m[1][2];
    		return this;
    	}
    	this.translateTo=function(newX,newY,duration,easing,onstep,fn)
    	{
    		if(duration!==undefined)
    			return this.animate({translateTo:{x:newX,y:newY}},duration,easing,onstep,fn);
    		var point=this.position(),
    			x=0,y=0;
    		if(newX!==undefined)
    			x=newX-point.x;
    		if(newY!==undefined)
    			y=newY-point.y;
    		return this.translate(x,y);
    	}
    	this.translate=function(x,y,duration,easing,onstep,fn)
    	{
    		if(duration!==undefined)
    			return this.animate({translate:{x:x,y:y}},duration,easing,onstep,fn);
    		this.optns.translateMatrix=multiplyM(this.optns.translateMatrix,[[1,0,x],[0,1,y]]);
    		changeMatrix(this);
    		return this;
    	}
    	this.scale=function(x,y,duration,easing,onstep,fn)
    	{
    		if(duration!==undefined)
    			return this.animate({scale:{x:x,y:y}},duration,easing,onstep,fn);
    		if(y===undefined)y=x;
    		this.optns.scaleMatrix=multiplyM(this.optns.scaleMatrix,[[x,0,this._x*(1-x)],[0,y,this._y*(1-y)]]);
    		changeMatrix(this);
    		return this;
    	}
    	this.rotate=function(x,x1,y1,duration,easing,onstep,fn)
    	{
    		if(duration!==undefined)
    			return this.animate({rotate:{angle:x,x:x1,y:y1}},duration,easing,onstep,fn);
    		x=x/radian;
    		var cos=m_cos(x),
    			sin=m_sin(x),
    			translateX=0,
    			translateY=0;
    		if(x1!==undefined)
    		{
    			if(x1=='center')
    			{
    				var point=this.getCenter('poor');
    				if(y1===undefined)
    				{
    					x1=point.x;
    					y1=point.y;
    				}
    				else
    				{
    					x1=point.x+y1.x;
    					y1=point.y+y1.y;
    				}
    			}
    			translateX=-x1*(cos-1)+y1*sin;
    			translateY=-y1*(cos-1)-x1*sin;
    		}
    		this.optns.rotateMatrix=multiplyM(this.optns.rotateMatrix,[[cos,-sin,translateX],[sin,cos,translateY]]);
    		changeMatrix(this);
    		return this;
    	}
    	this.transform=function(m11,m12,m21,m22,dx,dy,reset)
    	{
    		if(m11===undefined)return this.matrix();
    		var optns=this.optns;
    		if(reset!==undefined)
    		{
    			optns.transformMatrix=[[m11,m21,dx],[m12,m22,dy]];
    			optns.rotateMatrix=[[1,0,0],[0,1,0]];
    			optns.scaleMatrix=[[1,0,0],[0,1,0]];
    			optns.translateMatrix=[[1,0,0],[0,1,0]];
    		}
    		else
    		{
    			optns.transformMatrix=multiplyM(optns.transformMatrix,[[m11,m21,dx],[m12,m22,dy]]);
    		}
    		changeMatrix(this);
    		return this;
    	}
    	this.beforeDraw=function(canvasOptns)
    	{
    		if(!this._visible)return false;
    		var ctx=canvasOptns.ctx;
    		ctx.save();
    		if(this.optns.clipObject)
    		{
    			var clipObject=this.optns.clipObject;
    			clipObject._visible=true;
    			if (clipObject.optns.animated)animating.call(clipObject,canvasOptns);
    			clipObject.setOptns(ctx);
    			ctx.beginPath();
    			clipObject.draw(ctx);
    			ctx.clip();
    		}
    		this.setOptns(ctx);
    		if (this.optns.animated)animating.call(this,canvasOptns);
    		ctx.beginPath();
    		return true;
    	}
    	this.clip=function(object)
    	{
    		if(object===undefined)return this.optns.clipObject;
    		objectLayer(this).objs.splice(object.optns.number,1);
    		this.optns.clipObject=object;
    		return this;
    	}
    	this.afterDraw=function(optns)
    	{
    		optns.ctx.closePath();
    		checkEvents(this,optns);
    		optns.ctx.restore();
    		if(this.optns.clipObject)
    		{
    			proto.shape.prototype.afterDraw.call(this.optns.clipObject,optns);
    		}
    	}
    	this.isPointIn=function(x,y,global)
    	{
    		var canvasOptns=objectCanvas(this).optns,
    			ctx=canvasOptns.ctx,
    			thisAnimated=false,
    			optns=this.optns,
    			clipAnimated=false;
    		if(global!==undefined)
    		{
    			x-=canvasOptns.x;
    			y-=canvasOptns.y;
    		}
    		if(optns.animated)thisAnimated=true;
    		optns.animated=false;
    		if(optns.clipObject)
    		{
    			var clipObject=optns.clipObject,
    				clipOptns=clipObject.optns;
    			if(clipOptns.animated)
    			{
    				clipAnimated=true;
    				clipOptns.animated=false;
    			}
    		}
    		objectLayer(this).setOptns(ctx);
    		this.beforeDraw(canvasOptns);
    		this.draw(ctx);
    		var point=isPointInPath(this,x,y);
    		ctx.closePath();
    		ctx.restore();
    		ctx.setTransform(1,0,0,1,0,0);
    		optns.animated=thisAnimated;
    		if(clipAnimated)
    		{
    			clipOptns.animated=clipAnimated;
    		}
    		return point;
    	}
    	this.layer=function(idLayer)
    	{
    		return layer(idLayer,this,'objs');
    	}
    	this.canvas=function(idCanvas)
    	{
    		return canvas(idCanvas,this,'objs');
    	}
    	this.draggable=function(object,params,drag)
    	{
    		if(params===undefined && typeof object=='object' && object.optns===undefined)
    		{
    			params=object.params;
    			drag=object.drag;
    			var start=object.start,
    				stop=object.stop,
    				disabled=object.disabled;
    			object=object.object;
    		}
    		var dragObj=this;
    		var dragOptns=this.optns.drag;
    		if(typeof params==='function')
    		{
    			drag=params;
    			params=undefined;
    		}
    		if(typeof object=='function')
    		{
    			drag=object;
    			object=undefined;
    		}
    		dragOptns.shiftX=0;
    		dragOptns.shiftY=0;
    		if(params!==undefined)
    		{
    			if(params.shiftX!==undefined){dragOptns.shiftX=params.shiftX;params.shiftX=undefined;}
    			if(params.shiftY!==undefined){dragOptns.shiftY=params.shiftY;params.shiftY=undefined;}
    		}
    		if(object!==undefined)
    		{
    			if(object.id)dragObj=(params===undefined)? object.visible(false) : object.animate(params).visible(false);
    			if(object=='clone')
    			{
    				dragObj=this.clone(params).visible(false);
    				dragOptns.type='clone';
    			}
    		}
    		dragOptns.val=true;
    		dragOptns.x=this._x;
    		dragOptns.y=this._y;
    		dragOptns.dx=this._transformdx;
    		dragOptns.dy=this._transformdy;
    		dragOptns.object=dragObj;
    		dragOptns.params=params;
    		dragOptns.drag=drag||false;
    		dragOptns.start=start||false;
    		dragOptns.stop=stop||false;
    		dragOptns.disabled=disabled||false;
    		var optns=objectCanvas(this).optns;
    		optns.mousemove.val=true;
    		optns.mousedown.val=true;
    		optns.mouseup.val=true;
    		return this;
    	}
    	this.droppable=function(fn)
    	{
    		this.optns.drop.val=true;
    		if(fn!==undefined)this.optns.drop.fn=fn;
    		return this;
    	}
    	this.name = function(name)
    	{
    		return this.attr('name',name);
    	}
        this.hasName = function(name){
            var namesArray = this.attr('name').split(' '), i = 0;
            while(i < namesArray.length){
                if(namesArray[i] === name){
                    return true;
                }
                i++;
            }
            return false;
        }
        this.addName = function(name)
        {
            var namesArray = this.attr('name').split(' '), i = 0;
            while(i < namesArray.length){
                if(namesArray[i] === name){
                    return this;
                }
                i++;
            }
            namesArray.push(name);
            return this.attr('name', namesArray.join(' '));
        }
        this.removeName = function(name)
        {
            var namesArray = this.attr('name').split(' '), i = 0;
            while(i < namesArray.length){
                if(namesArray[i] === name){
                    namesArray.splice(i, 1);
                    return this.attr('name', namesArray.join(' '));
                }
                i++;
            }
            return this;
        }
    	this.visible=function(visibility)
    	{
    		return this.attr('visible',visibility);
    	}
    	this.composite=function(composite)
    	{
    		return this.attr('composite',composite);
    	}
    	this.id=function(id)
    	{
    		if(id===undefined)return this.optns.id;
    		this.optns.id=id;
    		return this;
    	}
    	this.opacity=function(n)
    	{
    		return this.attr('opacity',n);
    	}
    	this.fadeIn=function(duration,easing,onstep,fn)
    	{
    		return this.fadeTo(1,duration,easing,onstep,fn);
    	}
    	this.fadeOut=function(duration,easing,onstep,fn)
    	{
    		return this.fadeTo(0,duration,easing,onstep,fn);
    	}
    	this.fadeTo=function(val,duration,easing,onstep,fn)
    	{
    		if(duration===undefined)duration=600;
    		return this.animate({opacity:val},duration,easing,onstep,fn);
    	}
    	this.fadeToggle=function(duration,easing,onstep,fn)
    	{
    		if(this._opacity)
    			this.fadeOut(duration,easing,onstep,fn);
    		else
    			this.fadeIn(duration,easing,onstep,fn);
    		return this;
    	}
    	this.instanceOf=function(name)
    	{
    		if(name===undefined)return this._proto;
    		return this instanceof proto[name];
    	}
    	this.base=function(x,y,service)
    	{
    		if(typeof x == 'object'){
    			x=checkDefaults(x,{x:0,y:0,service:false});
    			service=x.service;
    			y=x.y;
    			x=x.x;
    		}
    		else{if(service===undefined)service=false;}
    		var canvasItem=canvases[lastCanvas];
    		this.optns={
    			animated:false,
    			clipObject:false,
    			drop:{val:false,fn:function(){}},
    			drag:{val:false},
    			layer:{id:canvasItem.optns.id+"Layer0",number:0},
    			canvas:{number:0},
    			focused:false,
    			buffer:{val:false},
    			rotateMatrix:[[1,0,0],[0,1,0]],
    			scaleMatrix:[[1,0,0],[0,1,0]],
    			translateMatrix:[[1,0,0],[0,1,0]],
    			transformMatrix:[[1,0,0],[0,1,0]]
    		}
    		this.animateQueue = [];
    		this._x=x;
    		this._y=y;
    		if(service==false && canvasItem!==undefined && canvasItem.layers[0]!==undefined)
    		{
    			this.optns.layer.number=0;
    			this.optns.canvas.number=lastCanvas;
    			var layer=objectLayer(this),
    			limit=layer.objs.length;
    			this.optns.number=limit;
    			this._level=limit?(layer.objs[limit-1]._level+1):0;
    			layer.objs[limit]=this;
    			this.optns.layer.id=layer.optns.id;
    			redraw(this);
    		}
    		return this;
    	}
    	this._visible=true;
    	this._composite='source-over';
    	this._name="";
    	this._opacity=1;
    	this._shadowX=0;
    	this._shadowY=0;
    	this._shadowBlur= 0;
    	this._shadowColor= 'rgba(0,0,0,0)';
    	this._shadowColorR= 0;
    	this._shadowColorG= 0;
    	this._shadowColorB= 0;
    	this._shadowColorA= 0;
        this._shadowColorRPrev= 0;
        this._shadowColorGPrev= 0;
        this._shadowColorBPrev= 0;
        this._shadowColorAPrev= 0;
    	this._translateX=0;
    	this._translateY=0;
    	this._scaleX=1;
    	this._scaleY=1;
    	this._rotateAngle=0;
    	this._rotateX=0;
    	this._rotateY=0;
    	this._transform11=1;
    	this._transform12=0;
    	this._transform21=0;
    	this._transform22=1;
    	this._transformdx=0;
    	this._transformdy=0;
    	this._matrixChanged=false;
    }
    proto.object.prototype=new proto.object();
    
    proto.shape=function()
    {
    	this.color = function(color)
    	{
    		if (color===undefined)return [this._colorR,this._colorG,this._colorB,this._alpha];
    		return this.attr('color',color);
    	}
    	this.lineStyle = function(options)
    	{
    		return this.attr(options);
    	}
    	this.setOptns = function(ctx)
    	{
    		proto.shape.prototype.setOptns.call(this,ctx);
    		ctx.lineWidth = this._lineWidth;
    		ctx.lineCap = this._cap;
    		ctx.lineJoin = this._join;
    		ctx.miterLimit = this._miterLimit;
    		var color=this.optns.color;
    		if(color.notColor===undefined){
                var rInt = parseInt(this._colorR),
                    gInt = parseInt(this._colorG),
                    bInt = parseInt(this._colorB),
                    aInt = parseInt(this._alpha * 100) / 100;
                if (this._colorRPrev !== rInt || this._colorGPrev !== gInt || this._colorBPrev !== bInt || this._alphaPrev !== aInt) {
                    color.val = this._color = 'rgba(' + rInt + ', ' + gInt + ', ' + bInt + ', ' + aInt + ')';
                    this._colorRPrev = rInt;
                    this._colorGPrev = gInt;
                    this._colorBPrev = bInt;
                    this._alphaPrev = aInt;
                }
                else {
                    color.val = this._color;
                }
            }
    		else
    		{
    			var notColor=color.notColor;
    			var notColorLayer=canvases[notColor.canvas].layers[notColor.layer];
    			if(notColorLayer.grdntsnptrns[notColor.level]!==undefined){color.val=notColorLayer.grdntsnptrns[notColor.level].val;}
    		}
    		if(this._fill) ctx.fillStyle = color.val;
    		else ctx.strokeStyle = color.val;
    	}
    	this.afterDraw=function(optns)
    	{
    		if(this._fill)
    			optns.ctx.fill();
    		else
    			optns.ctx.stroke();
    		proto.shape.prototype.afterDraw.call(this,optns);
    	}
    	this.base=function(x)
    	{
    		if(x===undefined)x={};
    		if(x.color===undefined)x.color='rgba(0,0,0,1)';
    		else
    		{
    			if(!x.color.charAt && x.color.id===undefined && x.color.r===undefined)
    			{
    				x.fill=x.color;
    				x.color='rgba(0,0,0,1)';
    			}
    		}
    		x=checkDefaults(x,{color:'rgba(0,0,0,1)',fill:0});
    		proto.shape.prototype.base.call(this,x);
    		this._fill=x.fill;
    		this.optns.color={val:x.color,notColor:undefined};
    		return this.color(x.color);
    	}
    	this._colorR=0;
    	this._colorG=0;
    	this._colorB=0;
    	this._alpha=0;
        this._colorRPrev=0;
        this._colorGPrev=0;
        this._colorBPrev=0;
        this._alphaPrev=0;
        this._color = 'rgba(0,0,0,0)';
    	this._lineWidth = 1;
    	this._cap = 'butt';
    	this._join = 'miter';
    	this._miterLimit= 1;
    }
    proto.shape.prototype=new proto.object;
    
    proto.lines=function()
    {
    	this.getCenter=function(type)
    	{
    		var point={
    			x:this._x0,
    			y:this._y0
    		};
    		for(var i=1;i<this.shapesCount;i++)
    		{
    			point.x+=this['_x'+i];
    			point.y+=this['_y'+i];
    		}
    		point.x=point.x/this.shapesCount;
    		point.y=point.y/this.shapesCount;
    		return getCenter(this,point,type);
    	}
    	this.position=function(){
    		return multiplyPointM(this._x0,this._y0,multiplyM(this.matrix(),objectLayer(this).matrix()));
    	}
    	this.getRect=function(type){
    		var minX, minY,
    		maxX=minX=this._x0,
    		maxY=minY=this._y0;
    		for(var i=1;i<this.shapesCount;i++)
    		{
    			if(maxX<this['_x'+i])maxX=this['_x'+i];
    			if(maxY<this['_y'+i])maxY=this['_y'+i];
    			if(minX>this['_x'+i])minX=this['_x'+i];
    			if(minY>this['_y'+i])minY=this['_y'+i];
    		}
    		var points={x:minX,y:minY,maxX-minX,height:maxY-minY};
    		return getRect(this,points,type);
    	}
    	this.addPoint=function(){
    		redraw(this);
    		var names=this.pointNames;
    		for(var i=0;i<names.length;i++)
    				this[names[i]+this.shapesCount]=arguments[i];
    		this.shapesCount++;
    		return this;
    	}
    	this.delPoint=function(x,y,radius){
    		redraw(this);
    		if(y===undefined)
    		{
    			var points=this.points();
    			points.splice(x,1)
    			this.points(points);
    		}
    		else{
    			radius=radius||0;
    			for(var j=0;j<this.shapesCount;j++)
    				if(this['_x'+j]<x+radius && this['_x'+j]>x-radius && this['_y'+j]<y+radius && this['_y'+j]<y+radius)
    				{
    					this.delPoint(j);
    					j--;
    				}
    		}
    		return this;
    	}
    	this.points=function(points)
    	{
    		var names=this.pointNames;
    		if(points===undefined){
    			points=[];
    			for(var j=0;j<this.shapesCount;j++)
    			{
    				points[j]=[];
    				for(var i=0;i<names.length;i++)
    					points[j][i]=this[names[i]+j];
    			}
    			return points;
    		}
    		redraw(this);
    		var oldCount=this.shapesCount;
    		this.shapesCount=points.length;
    		for(j=0;j<this.shapesCount;j++)
    			for(i=0;i<names.length;i++)
    				this[names[i]+j]=points[j][i];
    		for(j=this.shapesCount;j<oldCount;j++)
    			for(i=0;i<names.length;i++)
    				this[names[i]+j]=undefined;
    		return this;
    	}
    	this.base=function(points,color,fill)
    	{
    		if(points!==undefined)
    		{
    			if(typeof points.pop == 'function')
    				points={points:points,color:color,fill:fill};
    		}
    		proto.lines.prototype.base.call(this,points);
    		this.shapesCount=0;
    		if(points!==undefined)
    			if(points.points!==undefined)
    				this.points(points.points);
    		return this;
    	}
    }
    proto.lines.prototype=new proto.shape;
    
    proto.line=function(){
    	this.draw=function(ctx)
    	{
    		if(this._x0===undefined)return;
    		ctx.moveTo(this._x0,this._y0);
    		for(var j=1;j<this.shapesCount;j++)
    		{
    			ctx.lineTo(this['_x'+j],this['_y'+j]);
    		}
    	}
    	this.base=function(points,color,fill)
    	{
    		proto.line.prototype.base.call(this,points,color,fill);
    		return this;
    	}
    	this._proto='line';
    	this.pointNames=['_x','_y'];
    }
    proto.line.prototype=new proto.lines;
    proto.qCurve=function(){
    	this.draw=function(ctx)
    	{
    		if(this._x0===undefined)return;
    		ctx.moveTo(this._x0,this._y0);
    		for(var j=1;j<this.shapesCount;j++)
    		{
    			ctx.quadraticCurveTo(this['_cp1x'+j],this['_cp1y'+j],this['_x'+j],this['_y'+j]);
    		}
    	}
    	this.base=function(points,color,fill)
    	{
    		proto.qCurve.prototype.base.call(this,points,color,fill);
    		return this;
    	}
    	this._proto='qCurve';
    	this.pointNames=['_x','_y','_cp1x','_cp1y'];
    }
    proto.qCurve.prototype=new proto.lines;
    proto.bCurve=function(){
    	this.draw=function(ctx)
    	{
    		if(this._x0===undefined)return;
    		ctx.moveTo(this._x0,this._y0);
    		for(var j=1;j<this.shapesCount;j++)
    		{
    			ctx.bezierCurveTo(this['_cp1x'+j],this['_cp1y'+j],this['_cp2x'+j],this['_cp2y'+j],this['_x'+j],this['_y'+j]);
    		}
    	}
    	this.base=function(points,color,fill)
    	{
    		proto.bCurve.prototype.base.call(this,points,color,fill);
    		return this;
    	}
    	this._proto='bCurve';
    	this.pointNames=['_x','_y','_cp1x','_cp1y','_cp2x','_cp2y'];
    }
    proto.bCurve.prototype=new proto.lines;
    
    proto.circle = function () {
        this.getCenter = function (type) {
            return getCenter(this, {x:this._x, y:this._y}, type);
        }
        this.getRect = function (type) {
            var points = {x:Math.floor(this._x - this._radius), y:Math.floor(this._y - this._radius)};
            points.width = points.height = Math.ceil(this._radius) * 2;
            return getRect(this, points, type);
        }
        this.draw = function (ctx) {
            ctx.arc(this._x, this._y, this._radius, 0, pi2, true);
        }
        this.base = function (x, y, radius, color, fill) {
            if (typeof x != 'object')
                x = {x:x, y:y, radius:radius, color:color, fill:fill};
            x = checkDefaults(x, {radius:0});
            proto.circle.prototype.base.call(this, x);
            this._radius = x.radius;
            return this;
        }
        this._proto = 'circle';
    }
    proto.circle.prototype = new proto.shape;
    proto.rect = function () {
        this.getRect = function (type) {
            return getRect(this, {x:this._x, y:this._y, this._width, height:this._height}, type);
        }
        this.draw = function (ctx) {
            ctx.rect(this._x, this._y, this._width, this._height);
        }
        this.base = function (x, y, width, height, color, fill) {
            if (typeof x != 'object')
                x = {x:x, y:y, width, height:height, color:color, fill:fill};
            x = checkDefaults(x, {0, height:0});
            proto.rect.prototype.base.call(this, x);
            this._width = x.width;
            this._height = x.height;
            return this;
        }
        this._proto = 'rect';
    }
    proto.rect.prototype = new proto.shape;
    proto.arc = function () {
        this.getRect = function (type) {
            var points = {x:this._x, y:this._y},
                startAngle = this._startAngle, endAngle = this._endAngle, radius = this._radius,
                startY = m_floor(m_sin(startAngle / radian) * radius), startX = m_floor(m_cos(startAngle / radian) * radius),
                endY = m_floor(m_sin(endAngle / radian) * radius), endX = m_floor(m_cos(endAngle / radian) * radius),
                positiveXs = startX > 0 && endX > 0, negtiveXs = startX < 0 && endX < 0, positiveYs = startY > 0 && endY > 0, negtiveYs = startY < 0 && endY < 0;
            points.width = points.height = radius;
            if ((this._anticlockwise && startAngle < endAngle) || (!this._anticlockwise && startAngle > endAngle)) {
                if (((negtiveXs || (positiveXs && (negtiveYs || positiveYs)))) || (startX == 0 && endX == 0)) {
                    points.y -= radius;
                    points.height += radius;
                }
                else {
                    if (positiveXs && endY < 0 && startY > 0) {
                        points.y += endY;
                        points.height += endY;
                    }
                    else
                    if (endX > 0 && endY < 0 && startX < 0) {
                        points.y += m_min(endY, startY);
                        points.height -= m_min(endY, startY);
                    }
                    else {
                        if (negtiveYs)points.y -= m_max(endY, startY);
                        else points.y -= radius;
                        points.height += m_max(endY, startY);
                    }
                }
                if (((positiveYs || (negtiveYs && (negtiveXs || positiveXs) ))) || (startY == 0 && endY == 0)) {
                    points.x -= radius;
                    points.width += radius;
                }
                else {
                    if (endY < 0 && startY > 0) {
                        points.x += m_min(endX, startX);
                        points.width -= m_min(endX, startX);
                    }
                    else {
                        if (negtiveXs)points.x -= m_max(endX, startX);
                        else points.x -= radius;
                        points.width += m_max(endX, startX);
                    }
                }
            }
            else {
                positiveXs = startX >= 0 && endX >= 0;
                positiveYs = startY >= 0 && endY >= 0;
                negtiveXs = startX <= 0 && endX <= 0;
                negtiveYs = startY <= 0 && endY <= 0;
                if (negtiveYs && positiveXs) {
                    points.x += m_min(endX, startX);
                    points.width -= m_min(endX, startX);
                    points.y += m_min(endY, startY);
                    points.height += m_max(endY, startY);
                }
                else if (negtiveYs && negtiveXs) {
                    points.x += m_min(endX, startX);
                    points.width += m_max(endX, startX);
                    points.y += m_min(endY, startY);
                    points.height += m_max(endY, startY);
                }
                else if (negtiveYs) {
                    points.x += m_min(endX, startX);
    
                    points.width += m_max(endX, startX);
                    points.y -= radius;
                    points.height += m_max(endY, startY);
                }
                else if (positiveXs && positiveYs) {
                    points.x += m_min(endX, startX);
                    points.width = m_abs(endX - startX);
                    points.y += m_min(endY, startY);
                    points.height -= m_min(endY, startY);
                }
                else if (positiveYs) {
                    points.x += m_min(endX, startX);
                    points.width = m_abs(endX) + m_abs(startX);
                    points.y += m_min(endY, startY);
                    points.height -= m_min(endY, startY);
                }
                else if (negtiveXs) {
                    points.x -= radius;
                    points.width += m_max(endX, startX);
                    points.y -= radius;
                    points.height += m_max(endY, startY);
                }
                else if (positiveXs) {
                    points.x -= radius;
                    points.width += m_max(endX, startX);
                    points.y -= radius;
                    points.height += radius;
                }
            }
            return getRect(this, points, type);
        }
        this.draw = function (ctx) {
            ctx.arc(this._x, this._y, this._radius, this._startAngle / radian, this._endAngle / radian, this._anticlockwise);
        }
        this.base = function (x, y, radius, startAngle, endAngle, anticlockwise, color, fill) {
            if (anticlockwise !== undefined) {
                if (anticlockwise.charAt)color = anticlockwise;
                if (anticlockwise)anticlockwise = true;
                else anticlockwise = false;
            }
            if (typeof x != 'object')
                x = {x:x, y:y, radius:radius, startAngle:startAngle, endAngle:endAngle, anticlockwise:anticlockwise, color:color, fill:fill};
            x = checkDefaults(x, {radius:0, startAngle:0, endAngle:0, anticlockwise:true});
            proto.arc.prototype.base.call(this, x);
            this._radius = x.radius;
            this._startAngle = x.startAngle;
            this._endAngle = x.endAngle;
            this._anticlockwise = x.anticlockwise;
            return this;
        }
        this._proto = 'arc';
    }
    proto.arc.prototype = new proto.shape;
    proto.text = function () {
        this.font = function (font) {
            return this.attr('font', font);
        }
        this._font = "10px sans-serif";
        this.align = function (align) {
            return this.attr('align', align);
        }
        this._align = "start";
        this.baseline = function (baseline) {
            return this.attr('baseline', baseline);
        }
        this._baseline = "alphabetic";
        this.string = function (string) {
            return this.attr('string', string);
        }
        this.position = function () {
            var points = {x:this._x, y:this._y}, ctx = objectCanvas(this).optns.ctx;
            points.height = parseInt(this._font.match(regNumsWithMeasure)[0]);
            points.y -= points.height;
            ctx.save();
            ctx.textBaseline = this._baseline;
            ctx.font = this._font;
            ctx.textAlign = this._align;
            points.width = ctx.measureText(this._string).width;
            ctx.restore();
            return getRect(this, points);
        }
        this.getRect = function (type) {
            var points = {x:this._x, y:this._y}, ctx = objectCanvas(this).optns.ctx;
            points.height = parseInt(this._font.match(regNumsWithMeasure)[0]);
            points.y -= points.height;
            ctx.save();
            ctx.textBaseline = this._baseline;
            ctx.font = this._font;
            ctx.textAlign = this._align;
            points.width = ctx.measureText(this._string).width;
            if (this._align == 'center')points.x -= points.width / 2;
            if (this._align == 'right')points.x -= points.width;
            ctx.restore();
            return getRect(this, points, type);
        }
        this.setOptns = function (ctx) {
            proto.text.prototype.setOptns.call(this, ctx);
            ctx.textBaseline = this._baseline;
            ctx.font = this._font;
            ctx.textAlign = this._align;
        }
        this.draw = function (ctx) {
            if (this._maxWidth === false) {
                if (this._fill)ctx.fillText(this._string, this._x, this._y);
                else ctx.strokeText(this._string, this._x, this._y);
            }
            else {
                if (this._fill) ctx.fillText(this._string, this._x, this._y, this._maxWidth);
                else ctx.strokeText(this._string, this._x, this._y, this._maxWidth);
            }
        }
        this.base = function (string, x, y, maxWidth, color, fill) {
            if (maxWidth !== undefined) {
                if (maxWidth.charAt) {
                    if (color !== undefined)fill = color;
                    color = maxWidth;
                    maxWidth = false;
                }
            }
            if (typeof string != 'object')
                string = {string:string, x:x, y:y, maxWidth:maxWidth, color:color, fill:fill};
            string = checkDefaults(string, {string:'', maxWidth:false, fill:1});
            proto.text.prototype.base.call(this, string);
            this._string = string.string;
            this._maxWidth = string.maxWidth;
            return this;
        }
        this._proto = 'text';
    }
    proto.text.prototype = new proto.shape;
    
    proto.grdntsnptrn=function()
    {
    	this.layer=function(idLayer)
    	{
    		return layer(idLayer,this,'grdntsnptrns');
    	}
    	this.canvas=function(idCanvas)
    	{
    		return canvas(idCanvas,this,'grdntsnptrns');
    	}
    	var tmpObj=new proto.object;
    	this.animate=tmpObj.animate;
    	this.attr=tmpObj.attr;
    	this.id=tmpObj.id;
    	this.name=tmpObj.name;
    	this.level=tmpObj.level;
    	this.base=function()
    	{
    		this.animateQueue=[];
    		this.optns={
    			animated:false,
    			name:"",
    			layer:{id:canvases[0].optns.id+'Layer_0',number:0},
    			canvas:{number:0},
    			visible:true
    		}
    		this.optns.layer.id=canvases[lastCanvas].optns.id+'Layer_0';
    		this.optns.layer.number=0
    		this.optns.canvas.number=lastCanvas;
    		var grdntsnptrnsArray=canvases[lastCanvas].layers[0].grdntsnptrns;
    		this._level=grdntsnptrnsArray.length;
    		grdntsnptrnsArray[this._level]=this;
    		redraw(this);
    	}
    	return this;
    }
    proto.gradients=function()
    {
    	this.colorStopsCount=0;
    	this.paramNames=['_pos','_colorR','_colorG','_colorB','_alpha'];
    	this.addColorStop=function(pos,color){
    		redraw(this);
    		var colorKeeper = parseColor(color);
    		var i=this.colorStopsCount;
    		this['_pos'+i] = pos;
    		this['_colorR'+i] = colorKeeper.r;
    		this['_colorG'+i] = colorKeeper.g;
    		this['_colorB'+i] = colorKeeper.b;
    		this['_alpha'+i] = colorKeeper.a;
    		this.colorStopsCount++;
    		return this;
    	}
    	this.animate=function(parameters,duration,easing,onstep,fn){
    		for(var key in parameters)
    		{
    			if(key.substr(0,5)=='color')
    			{
    				var i=key.substring(5);
    				var colorKeeper=parseColor(parameters[key]);
    				parameters['colorR'+i] = colorKeeper.r;
    				parameters['colorG'+i] = colorKeeper.g;
    				parameters['colorB'+i] = colorKeeper.b;
    				parameters['alpha'+i] = colorKeeper.a;
    			}
    		}
    		proto.gradients.prototype.animate.call(this,parameters,duration,easing,onstep,fn);
    	}
    	this.delColorStop=function(i)
    	{
    		redraw(this);
    		var colorStops=this.colorStops();
    		colorStops.splice(i,1);
    		if(colorStops.length>0)this.colorStops(colorStops);
    		else this.colorStopsCount=0;
    		return this;
    	}
    	this.colorStops=function(array)
    	{
    		var names=this.paramNames;
    		if(array===undefined){
    			array=[];
    			for(var j=0;j<this.colorStopsCount;j++)
    			{
    				array[j]=[];
    				for(var i=0;i<names.length;i++)
    					array[j][i]=this[names[i]+j];
    			}
    			return array;
    		}
    		redraw(this);
    		var oldCount=this.colorStopsCount;
    		var limit=array.length;
    		if(array[0].length==2)
    			for(j=0;j<limit;j++)
    				this.addColorStop(array[j][0], array[j][1]);
    		else
    			for(j=0;j<limit;j++)
    				for(i=0;i<names.length;i++)
    					this[names[i]+j]=array[j][i];
    		for(j=limit;j<oldCount;j++)
    			for(i=0;i<names.length;i++)
    				this[names[i]+j]=undefined;
    		this.colorStopsCount=limit;
    		return this;
    	}
    	this.base=function(colors)
    	{
    		proto.gradients.prototype.base.call(this);
    		if (colors==undefined)
    			return this;
    		else return this.colorStops(colors);
    	}
    }
    proto.gradients.prototype=new proto.grdntsnptrn;
    
    proto.pattern = function()
    {
    	this.create = function(canvasOptns)
    	{
    		if(this.optns.animated)animating.call(this,canvasOptns);
    		this.val = canvasOptns.ctx.createPattern(this._img,this._type);
    	}
    	this.base=function(image,type)
    	{
    		if(image.onload)
    			image={image:image,type:type};
    		image=checkDefaults(image,{type:'repeat'});
    		proto.pattern.prototype.base.call(this);
    		this._img=image.image;
    		this._type=image.type;
    		return this;
    	}
    	this._proto='pattern';
    }
    proto.pattern.prototype=new proto.grdntsnptrn;
    proto.lGradient=function()
    {
    	this.create = function(canvasOptns)
    	{
    		if(this.optns.animated)animating.call(this,canvasOptns);
    		this.val=canvasOptns.ctx.createLinearGradient(this._x1,this._y1,this._x2,this._y2);
    		for(var i=0;i<this.colorStopsCount;i++)
    		{
    			this.val.addColorStop(this['_pos'+i],'rgba('+parseInt(this['_colorR'+i])+','+parseInt(this['_colorG'+i])+','+parseInt(this['_colorB'+i])+','+this['_alpha'+i]+')');
    		}
    	}
    	this.base=function(x1,y1,x2,y2,colors)
    	{
    		if(typeof x1!=='object')
    			x1={x1:x1,y1:y1,x2:x2,y2:y2,colors:colors};
    		x1=checkDefaults(x1,{x1:0,y1:0,x2:0,y2:0})
    		proto.lGradient.prototype.base.call(this,x1.colors);
    		this._x1 = x1.x1;
    		this._y1 = x1.y1;
    		this._x2 = x1.x2;
    		this._y2 = x1.y2;
    		return this;
    	}
    	this._proto='lGradient';
    }
    proto.lGradient.prototype=new proto.gradients;
    proto.rGradient=function()
    {
    	this.create = function(canvasOptns)
    	{
    		if(this.optns.animated)animating.call(this);
    		this.val=canvasOptns.ctx.createRadialGradient(this._x1,this._y1,this._r1,this._x2,this._y2,this._r2);
    		for(var i=0;i<this.colorStopsCount;i++)
    		{
    			this.val.addColorStop(this['_pos'+i],'rgba('+parseInt(this['_colorR'+i])+','+parseInt(this['_colorG'+i])+','+parseInt(this['_colorB'+i])+','+this['_alpha'+i]+')');
    		}
    	}
    	this.base=function(x1,y1,r1,x2,y2,r2,colors)
    	{
    		if(typeof x1!=='object')
    			x1={x1:x1,y1:y1,r1:r1,x2:x2,y2:y2,r2:r2,colors:colors};
    		x1=checkDefaults(x1,{x1:0,y1:0,r1:0,x2:0,y2:0,r2:0})
    		proto.rGradient.prototype.base.call(this,x1.colors);
    		this._x1 = x1.x1;
    		this._y1 = x1.y1;
    		this._r1 = x1.r1;
    		this._x2 = x1.x2;
    		this._y2 = x1.y2;
    		this._r2 = x1.r2;
    		return this;
    	}
    	this._proto='rGradient';
    }
    proto.rGradient.prototype=new proto.gradients;
    
    
    proto.layer=function()
    {
    	this.position=function(){
    		var objs=this.objs,
    		points,point,i,
    		limit=objs.length;
    		for(i=0;i<limit;i++)
    		{
    			point=objs[i].position();
    			if(points===undefined)points=point;
    			if(points.x>point.x)points.x=point.x;
    			if(points.y>point.y)points.y=point.y;
    		}
    		return points;
    	}
    	this.getRect=function(type){
    		var objs=this.objs,
    		points,rect,i,
    		limit=objs.length;
    		if (objs.length==0)return false;
    		if(type=='coords')
    		{
    			for(i=0;i<limit;i++)
    			{
    				rect=objs[i].getRect(type);
    				if(points===undefined)points=rect;
    				if(points[0][0]>rect[0][0])points[0][0]=rect[0][0];
    				if(points[0][1]>rect[0][1])points[0][1]=rect[0][1];
    				if(points[1][0]<rect[1][0])points[1][0]=rect[1][0];
    				if(points[1][1]>rect[1][1])points[1][1]=rect[1][1];
    				if(points[2][0]>rect[2][0])points[2][0]=rect[2][0];
    				if(points[2][1]<rect[2][1])points[2][1]=rect[2][1];
    				if(points[3][0]<rect[3][0])points[3][0]=rect[3][0];
    				if(points[3][1]<rect[3][1])points[3][1]=rect[3][1];
    			}
    			return points;
    		}
    		for(i=0;i<limit;i++)
    		{
    			rect=objs[i].getRect(type);
    			rect.right=rect.width+rect.x;
    			rect.bottom=rect.height+rect.y;
    			if(points===undefined)points=rect;
    			if(points.x>rect.x)points.x=rect.x;
    			if(points.y>rect.y)points.y=rect.y;
    			if(points.right<rect.right)points.right=rect.right;
    			if(points.bottom<rect.bottom)points.bottom=rect.bottom;
    		}
    		points.width=points.right-points.x;
    		points.height=points.bottom-points.y;
    		return points;
    	}
    	this.canvas=function(idCanvas)
    	{
    		if (idCanvas===undefined)return this.idCanvas;
    		if(this.optns.canvas.id==idCanvas)return this;
    		var newCanvas=-1,oldCanvas=0,limitC=canvases.length;
    		for(var i=0;i<limitC;i++)
    		{
    			var idCanvasItem=canvases[i].optns.id;
    			if (idCanvasItem==idCanvas)newCanvas=i;
    			if (idCanvasItem==this.optns.canvas.id)oldCanvas=i;
    		}
    		if(newCanvas<0){newCanvas=canvases.length;jCanvaScript.canvas(idCanvas);}
    		this.optns.canvas.id=idCanvas;
    		this.optns.canvas.number=newCanvas;
    		canvases[oldCanvas].layers.splice(this.optns.number,1);
    		var layersArray=canvases[newCanvas].layers;
    		this._level=this.optns.number=layersArray.length;
    		layersArray[this._level]=this;
    		setLayerAndCanvasToArray(this.objs,this.optns.id,this._level,idCanvas,newCanvas);
    		setLayerAndCanvasToArray(this.grdntsnptrns,this.optns.id,this._level,idCanvas,newCanvas);
    		canvases[newCanvas].optns.redraw=1;
    		return this;
    	}
    	this.up=function(n)
    	{
    		if(n === undefined)n=1;
    		if(n=='top')this.level(n);
    		else {
    			var next=objectCanvas(this).layers[this.optns.number+n];
    			if(next!==undefined)
    			{
    				n=next._level+1-this._level;
    			}
    			this.level(this._level+n);
    		}
    		return this;
    	}
    	this.down=function(n)
    	{
    		if(n == undefined)n=1;
    		if(n == 'bottom')this.level(n);
    		else {
    			var previous=objectCanvas(this).layers[this.optns.number-n];
    			if(previous!==undefined)
    			{
    				n=this._level-(previous._level-1);
    			}
    			this.level(this._level-n);
    		}
    		return this;
    	}
    	this.level=function(n)
    	{
    		if(n == undefined)return this._level;
    		var canvas=objectCanvas(this),
    			optns=canvas.optns;
    		if(n=='bottom')
    			if(this.optns.number==0)n=this._level;
    			else n=canvas.layers[0]._level-1;
    		if(n=='top')
    			if(this.optns.number==canvas.layers.length-1)n=this._level;
    			else n=canvas.layers[canvas.layers.length-1]._level+1;
    		this._level=n;
    		optns.anyLayerLevelChanged = true;
    		optns.redraw=1;
    		return this;
    	}
    	this.del=function()
    	{
    		var optns=objectCanvas(this).optns;
    		optns.anyLayerDeleted = true;
    		this.optns.deleted = true;
    		this.draw = false;
    		optns.redraw=1;
    		return;
    	}
    	this.setOptns=function(ctx)
    	{
    		ctx.setTransform(1,0,0,1,0,0);
    		proto.layer.prototype.setOptns.call(this,ctx);
    		return this;
    	}
    	this.afterDraw=function(optns)
    	{
    		optns.ctx.closePath();
    		optns.ctx.restore();
    		if(this.optns.clipObject)
    		{
    			proto.layer.prototype.afterDraw.call(this.optns.clipObject,optns);
    		}
    	}
    	this.clone=function(idLayer,params)
    	{
    		var clone=jCanvaScript.layer(idLayer);
    		take(clone,this);
    		take(clone.optns.transformMatrix,this.optns.transformMatrix);
    		take(clone.optns.translateMatrix,this.optns.translateMatrix);
    		take(clone.optns.scaleMatrix,this.optns.scaleMatrix);
    		take(clone.optns.rotateMatrix,this.optns.rotateMatrix);
    		clone.canvas(objectCanvas(this).optns.id);
    		if(params===undefined) return clone;
    		return clone.animate(params);
    	}
    	this.isPointIn=function(x,y,global)
    	{
    		var objs=this.objs,i;
    		for(i=0;i<objs.length;i++)
    			if(objs[i].isPointIn(x,y,global))
    				return true;
    		return false;
    	}
    	this.opacity=function(n)
    	{
    		var objs=this.objs;
    		for(var i=0;i<objs.length;i++)
    			objs[i].attr('opacity',n);
    		return this;
    	}
    	this.fadeTo=function(val,duration,easing,onstep,fn)
    	{
    		if(duration===undefined)duration=600;
    		var objs=this.objs;
    		for(var i=0;i<objs.length;i++)
    			objs[i].animate({opacity:val},duration,easing,onstep,fn);
    		return this;
    	}
    	this.draw=function(canvasOptns)
    	{
    		var optns=this.optns,
    			bufOptns=optns.buffer,
    			ctx=canvasOptns.ctx;
    		if(bufOptns.val)
    		{
    			ctx.drawImage(bufOptns.cnv,bufOptns.x,bufOptns.y);
    			return this;
    		}
    		for(var i=0;i<this.grdntsnptrns.length;i++)
    			this.grdntsnptrns[i].create(canvasOptns);
    		if(optns.anyObjLevelChanged)
    		{
    			levelChanger(this.objs);
    			optns.anyObjLevelChanged = false;
    		}
    		if(optns.anyObjDeleted)
    		{
    			objDeleter(this.objs);
    			optns.anyObjDeleted = false;
    		}
    		ctx.globalCompositeOperation = optns.gCO;
    		for(i=0;i<this.objs.length;i++)
    		{
    			var object=this.objs[i];
    			if(typeof (object.draw)=='function')
    			{
    				this.setOptns(ctx);
    				if(object.beforeDraw(canvasOptns))
    				{
    					if(typeof (object.draw)=='function')
    					{
    						var objBufOptns=object.optns.buffer;
    						if(objBufOptns.val)
    							ctx.drawImage(objBufOptns.cnv,objBufOptns.x,objBufOptns.y);
    						else
    							object.draw(ctx);
    						if(bufOptns.optns)
    							object.afterDraw(bufOptns.optns);
    						else
    							object.afterDraw(canvasOptns);
    					}
    				}
    			}
    		}
    		return this;
    	}
    	this.objects=function(map)
    	{
    		var myGroup=group(),i=0;
    		while(this.objs[i]!==undefined)
    				myGroup.elements[i]=this.objs[i++];
    		if(map!==undefined)
    			return myGroup.find(map);
    		return myGroup;
    	}
    	this.base=function(idLayer)
    	{
    		var canvas=canvases[lastCanvas],
    		lastCanvasLayers=canvas.layers,
    		lastCanvasOptns=canvas.optns;
    		proto.layer.prototype.base.call(this,0,0,true);
    		var limit=lastCanvasLayers.length;
    		lastCanvasLayers[limit]=this;
    		this.objs = [];
    		this.grdntsnptrns = [];
    		this._level=limit?(lastCanvasLayers[limit-1]._level+1):0;
    		this.optns.number=limit;
    		this.optns.id=idLayer;
    		var thisOptns=this.optns
    		thisOptns.anyObjDeleted= false;
    		thisOptns.anyObjLevelChanged= false;
    		thisOptns.gCO= lastCanvasOptns.gCO;
    		thisOptns.canvas.id=lastCanvasOptns.id;
    		thisOptns.canvas.number=lastCanvas;
    		return this;
    	}
    	this._proto='layer';
    }
    proto.layer.prototype=new proto.object;
    function layers(idLayer)
    {
    	var layer=new proto.layer();
    	return layer.base(idLayer);
    }
    
    proto.imageData=function()
    {
    	this.filter=function(filterName,filterType)
    	{
    		var filter=imageDataFilters[filterName];
    		filter.fn.call(this,this._width,this._height,filter.matrix,filterType);
    		return this;
    	};
    	this.getRect=function(type)
    	{
    		var points={x:this._x,y:this._y,this._width,height:this._height};
    		return getRect(this,points,type);
    	}
    	this.setPixel=function(x,y,color)
    	{
    		var colorKeeper,index=(x + y * this._width) * 4;
    		if (color.r !== undefined) colorKeeper=color;
    		else if (color[0] !== undefined)
    			if (!color.charAt) colorKeeper={r:color[0],g:color[1],b:color[2],a:color[3]};
    			else colorKeeper = parseColor(color);
    		this._data[index+0] = colorKeeper.r;
    		this._data[index+1] = colorKeeper.g;
    		this._data[index+2] = colorKeeper.b;
    		this._data[index+3] = colorKeeper.a*255;
    		redraw(this);
    		return this;
    	}
    	this.getPixel=function(x,y)
    	{
    		var index=(x + y * this._width) * 4;
    		return [this._data[index+0],this._data[index+1],this._data[index+2],this._data[index+3]/255];
    	}
    	this._getX=0;
    	this._getY=0;
    	this.getData=function(x,y,width,height)
    	{
    		this._getX=x;
    		this._getY=y;
    		this._width=width;
    		this._height=height;
    		var ctx=objectCanvas(this).optns.ctx;
    		try{
    				this._imgData=ctx.getImageData(this._getX,this._getY,this._width,this._height);
    			}catch(e){
    				netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
    				this._imgData=ctx.getImageData(this._getX,this._getY,this._width,this._height);
    		}
    		this._data=this._imgData.data;
    		redraw(this);
    		return this;
    	}
    	this.putData=function(x,y)
    	{
    		if(x!==undefined)this._x=x;
    		if(y!==undefined)this._y=y;
    		this._putData=true;
    		redraw(this);
    		return this;
    	}
    	this.clone=function(){
    		var clone=proto.imageData.prototype.clone.call(this);
    		clone._imgData=undefined;
    		return clone;
    	}
    	this.draw=function(ctx)
    	{
    		if(this._imgData===undefined)
    		{
    			this._imgData=ctx.createImageData(this._width,this._height);
    			for(var i=0;i<this._width*this._height*4;i++)
    				this._imgData.data[i]=this._data[i];
    			this._data=this._imgData.data;
    		}
    		if(this._putData)
    			ctx.putImageData(this._imgData,this._x,this._y);
    	}
    	this.base=function(width,height)
    	{
    		proto.imageData.prototype.base.call(this);
    		if(height===undefined)
    		{
    			var oldImageData=width;
    			if(oldImageData._width!==undefined)
    			{
    				width=oldImageData._width;
    				height=oldImageData._height;
    			}
    			else
    			{
    				width=checkDefaults(width,{0,height:0});
    				height=width.height;
    				width=width.width;
    			}
    		}
    		this._width=width;
    		this._height=height;
    		this._data=[];
    		for(var i=0;i<this._width;i++)
    			for(var j=0;j<this._height;j++)
    			{
    				var index=(i+j*this._width)*4;
    				this._data[index+0]=0;
    				this._data[index+1]=0;
    				this._data[index+2]=0;
    				this._data[index+3]=0;
    			}
    		return this;
    	}
    	this._putData=false;
    	this._proto='imageData';
    }
    proto.imageData.prototype=new proto.object;
    proto.image=function()
    {
    	this.getRect=function(type)
    	{
    		var points={x:this._x,y:this._y,this._width,height:this._height};
    		return getRect(this,points,type);
    	}
    	this.draw=function(ctx)
    	{
    		ctx.drawImage(this._img,this._sx,this._sy,this._swidth,this._sheight,this._x,this._y,this._width,this._height);
    	}
    	this.base=function(image,x,y,width,height,sx,sy,swidth,sheight)
    	{
    		if(typeof image!='object' || image.src!==undefined || image.nodeName !== undefined)
    			image={image:image,x:x,y:y,width,height:height,sx:sx,sy:sy,sswidth,sheight:sheight};
    		image=checkDefaults(image,{false,height:false,sx:0,sy:0,sfalse,sheight:false});
    		if(image.width===false)
    		{
    			image.width=image.image.width;
    			image.height=image.image.height;
    		}
    		if(image.swidth===false)
    		{
    			image.swidth=image.image.width;
    			image.sheight=image.image.height;
    		}
    		proto.image.prototype.base.call(this,image);
    		this._img=image.image;
    		this._width=image.width;
    		this._height=image.height;
    		this._sx=image.sx;
    		this._sy=image.sy;
    		this._swidth=image.swidth;
    		this._sheight=image.sheight;
    		return this;
    	}
    	this._proto='image';
    }
    proto.image.prototype=new proto.object;
    
    
    proto.groups=function()
    {
    	for(var Class in proto)
    	{
    		if(Class=='group'||Class=='groups')continue;
    		var tmp=new proto[Class];
    		for(var key in tmp)
    		{
    			if(typeof tmp[key]=='function' && this[key]===undefined)
    			{
    				(function(group,key)
    				{
    				group[key]=function(){
    					var argumentsClone=[];
    					var args=[];
    					var i=0;
    					while(arguments[i]!==undefined)
    						args[i]=arguments[i++];
    					for(i=0;i<this.elements.length;i++)
    					{
    						var element=this.elements[i];
    						take(argumentsClone,args);
    						if(typeof element[key]=='function')
    						{
    							element[key].apply(element,argumentsClone);
    						}
    					}
    					return this;
    				}
    				})(this,key);
    			}
    		}
    	}
    	this.reverse=function(){
    		var tmpArray=this.elements;
    		this.elements=this.unmatchedElements;
    		this.unmatchedElements=tmpArray;
    		return this;
    	}
    	this.end=function(n){
    		if(this.previousGroup===undefined || n===0)return this;
    		if(n!==undefined)n--;
    		return this.previousGroup.end(n);
    	}
    	this.find=function(map){
    		var subgroup=group(),
    			attrs=map.attrs,
    			fns=map.fns||[],
    			i,j,
    			element,rel,fn,value1,value2;
    		subgroup.previousGroup=this;
    		for(i=0;i<this.elements.length;i++)
    		{
    			subgroup.elements[i]=this.elements[i];
    		}
    		if(attrs!==undefined)
    		{
    			for(j in attrs)
    			{
    				if(attrs.hasOwnProperty(j))
    				{
    					if(typeof attrs[j]!='object')
    					{
    						attrs[j]={val:attrs[j],rel:'=='};
    					}
    					fns[fns.length]={
    						fn:'attr',
    						args:[j],
    						val:attrs[j].val,
    						rel:attrs[j].rel
    					};
    				}
    			}
    		}
    		if(fns.length)
    		{
    			for(i=0;i<subgroup.elements.length;i++)
    			{
    				element=subgroup.elements[i];
    				for(j=0;j<fns.length;j++)
    				{
    					fn=fns[j];
    					value2=fn.val;
    					rel=fn.rel;
    					if(typeof element[fn.fn]=='function')
    						value1=element[fn.fn].apply(element,fn.args);
    					else rel='del';
    					switch(rel)
    					{
    						case '!=':
    							if(!(value1!=value2))rel='del';
    							break;
    						case '!==':
    							if(!(value1!==value2))rel='del';
    							break;
    						case '==':
    							if(!(value1==value2))rel='del';
    							break;
    						case '===':
    							if(!(value1===value2))rel='del';
    							break;
    						case '>=':
    							if(!(value1>=value2))rel='del';
    							break;
    						case '<=':
    							if(!(value1<=value2))rel='del';
    							break;
    						case '>':
    							if(!(value1>value2))rel='del';
    							break;
    						case '<':
    							if(!(value1<value2))rel='del';
    							break;
    						case 'typeof':
    							if(!(typeof value1==value2))rel='del';
    							break;
    					}
    					if(rel=='del')
    					{
    						subgroup.unmatchedElements[subgroup.unmatchedElements.length]=element;
    						subgroup.elements.splice(i,1);
    						i--;
    						break;
    					}
    				}
    			}
    		}
    		return subgroup;
    	}
    	this.base=function(){
    		this.elements=[];
    		this.unmatchedElements=[];
    		return this;
    	}
    }
    proto.group=function()
    {
    	this._proto='group';
    };
    proto.group.prototype=new proto.groups;
    function group()
    {
    	var group=new proto.group;
    	return group.base();
    }
    
        
    jCanvaScript.addFunction=function(name,fn,prototype)
    {
    	proto[prototype||'object'].prototype[name]=fn;
    	return jCanvaScript;
    }
    jCanvaScript.addObject=function(name,parameters,drawfn,parent)
    {
    	proto[name]=function(name){
    		this.draw=proto[name].draw;
    		this.base=proto[name].base;
    		this._proto=name;
    	};
    	var protoItem=proto[name];
    	if(parent===undefined)parent='shape';
    	protoItem.prototype=new proto[parent];
    	protoItem.draw=drawfn;
    	protoItem.base=function(name,parameters,args)
    	{
    		protoItem.prototype.base.call(this,parameters);
    		var i=0;
    		for(var key in parameters)
    		{
    			var parameter = (args[i] !== undefined)?args[i]:parameters[key];
    			this['_'+key]=parameter;
    			if(key=='color')this.color(parameter);
    			i++;
    		}
    		return this;
    	};
    	(function(name,parameters)
    	{
    		jCanvaScript[name]=function()
    		{
    			var object=new proto[name](name);
    			return object.base(name,parameters,arguments);
    		}
    	})(name,parameters);
    	return jCanvaScript;
    }
    jCanvaScript.addAnimateFunction=function(name,fn)
    {
    	animateFunctions[name]=fn;
    	return jCanvaScript;
    }
    jCanvaScript.addImageDataFilter=function(name,properties)
    {
    	if(imageDataFilters[name]===undefined)imageDataFilters[name]={};
    	if(properties.fn!==undefined)imageDataFilters[name].fn=properties.fn;
    	if(properties.matrix!==undefined && properties.type===undefined)imageDataFilters[name].matrix=properties.matrix;
    	if(properties.type!==undefined)imageDataFilters[name].matrix[type]=properties.matrix;
    	return jCanvaScript;
    }
    jCanvaScript.clear=function(idCanvas)
    {
    	if(canvases[0]===undefined)return jCanvaScript;
    	if(idCanvas===undefined){canvases[0].clear();return jCanvaScript;}
    	jCanvaScript.canvas(idCanvas).clear();
    	return jCanvaScript;
    }
    jCanvaScript.pause=function(idCanvas)
    {
    	if(idCanvas===undefined){canvases[0].pause();return jCanvaScript;}
    	jCanvaScript.canvas(idCanvas).pause();
    	return jCanvaScript;
    }
    jCanvaScript.start=function(idCanvas,isAnimated)
    {
    	jCanvaScript.canvas(idCanvas).start(isAnimated);
    	return jCanvaScript;
    }
    
        
    
    jCanvaScript.pattern = function(img,type)
    {
    	var pattern = new proto.pattern;
    	return pattern.base(img,type);
    }
    
    jCanvaScript.lGradient=function(x1,y1,x2,y2,colors)
    {
    	var lGrad = new proto.lGradient;
    	return lGrad.base(x1,y1,x2,y2,colors);
    }
    jCanvaScript.rGradient=function(x1,y1,r1,x2,y2,r2,colors)
    {
    	var rGrad = new proto.rGradient;
    	return rGrad.base(x1,y1,r1,x2,y2,r2,colors);
    }
    
    jCanvaScript.line=function(points,color,fill)
    {
    	var line = new proto.line;
    	return line.base(points,color,fill);
    }
    jCanvaScript.qCurve=function(points,color,fill)
    {
    	var qCurve = new proto.qCurve;
    	return qCurve.base(points,color,fill);
    }
    jCanvaScript.bCurve=function(points,color,fill)
    {
    	var bCurve = new proto.bCurve;
    	return bCurve.base(points,color,fill);
    }
    
    jCanvaScript.imageData=function(width,height)
    {
    	var imageData=new proto.imageData;
    	return imageData.base(width,height);
    }
    jCanvaScript.image=function(img,x,y,width,height,sx,sy,swidth,sheight)
    {
    	var image=new proto.image;
    	return image.base(img,x,y,width,height,sx,sy,swidth,sheight);
    }
    
    jCanvaScript.circle=function(x,y,radius,color,fill)
    {
    	var circle=new proto.circle;
    	return circle.base(x,y,radius,color,fill);
    }
    jCanvaScript.rect=function(x,y,width,height,color,fill)
    {
    	var rect = new proto.rect;
    	return rect.base(x,y,width,height,color,fill);
    }
    jCanvaScript.arc=function(x,y,radius,startAngle,endAngle,anticlockwise,color,fill)
    {
    	var arc=new proto.arc;
    	return arc.base(x,y,radius,startAngle,endAngle,anticlockwise,color,fill);
    }
    jCanvaScript.text = function(string,x,y,maxWidth,color,fill)
    {
    	var text=new proto.text;
    	return text.base(string,x,y,maxWidth,color,fill);
    }
    
        
    jCanvaScript.canvas = function(idCanvas)
    {
    	if(idCanvas===undefined)return canvases[0];
    	var limit=canvases.length;
    	for (var i=0;i<limit;i++)
    		if(canvases[i].optns)
    			if(canvases[i].optns.id==idCanvas)return canvases[i];
    	var canvas={
    		id:function(id)
    		{
    			if(id===undefined)return this.optns.id;
    			this.optns.id=id;
    			return this;
    		}
    	};
    	canvases[limit]=canvas;
    	lastCanvas=limit;
    	canvas.cnv=document.getElementById(idCanvas);
    	if ('v'=='v')
    	{
    		if(typeof G_vmlCanvasManager!=='undefined')
    			G_vmlCanvasManager.initElement(canvas.cnv);
    		if(typeof FlashCanvas !=='undefined')
    			FlashCanvas.initElement(canvas.cnv);
    	}
        canvas.width = function(width){
            if(width === undefined)
                return this.cnv.width;
            this.optns.width = this.cnv.width = width;
            this.cnv.style.width = width + 'px';
            this.optns.redraw = 1;
            return this;
        }
        canvas.height = function(height){
            if(height === undefined)
                return this.cnv.height;
            this.optns.heigth = this.cnv.height = height;
            this.cnv.style.height = height + 'px';
            this.optns.redraw = 1;
            return this;
        }
    	canvas.optns =
    	{
    		id:idCanvas,
    		number:lastCanvas,
    		ctx: canvas.cnv.getContext('2d'),
    		 canvas.cnv.offsetWidth||canvas.cnv.width,
    		height: canvas.cnv.offsetHeight||canvas.cnv.height,
    		anyLayerDeleted: false,
    		anyLayerLevelChanged:false,
    		keyDown:{val:false,code:false},
    		keyUp:{val:false,code:false},
    		keyPress:{val:false,code:false},
    		mousemove:{val:false,x:false,y:false,object:false},
    		click:{val:false,x:false,y:false,objects:[]},
    		dblclick:{val:false,x:false,y:false,objects:[]},
    		mouseup:{val:false,x:false,y:false,objects:[]},
    		mousedown:{val:false,x:false,y:false,objects:[]},
    		drag:{object:false,x:0,y:0},
    		gCO: 'source-over',
    		redraw:1
    	}
    	canvas.toDataURL=function(){return canvas.cnv.toDataURL.apply(canvas.cnv,arguments);}
    	canvas.layers=[];
    	canvas.interval=0;
    	jCanvaScript.layer(idCanvas+'Layer_0').canvas(idCanvas);
        canvas.recalculateOffset = function() {
            var offset=getOffset(this.cnv);
            this.optns.x=offset.left+(parseInt(this.cnv.style.borderTopWidth)||0);
            this.optns.y=offset.top+(parseInt(this.cnv.style.borderLeftWidth)||0);
            return this;
        }
    	canvas.start=function(isAnimated) {
    		lastCanvas=this.optns.number;
    		if(isAnimated)
    		{
    			if(this.interval)return this;
    			this.isAnimated=isAnimated;
    			this.recalculateOffset();
    			var canvas=canvases[this.optns.number],
    			optns=canvas.optns;
    			this.cnv.onclick=function(e){
    				mouseEvent(e,'click',optns);
    			}
    			this.cnv.ondblclick=function(e){
    				mouseEvent(e,'dblclick',optns);
    				var tmp=optns.mousemove.val;
    				optns.mousemove.val=true;
    				setTimeout(function(){optns.mousemove.val=tmp;},3000);
    			}
    			this.cnv.onmousedown=function(e){
    				mouseEvent(e,'mousedown',optns);
    			}
    			this.cnv.onmouseup=function(e){
    				mouseEvent(e,'mouseup',optns);
    			}
    			this.cnv.onkeyup=function(e){
    				keyEvent(e,'keyUp',optns);
    			}
    			this.cnv.onkeydown=function(e)
    			{
    				keyEvent(e,'keyDown',optns);
    			}
    			this.cnv.onkeypress=function(e)
    			{
    				keyEvent(e,'keyPress',optns);
    			}
    			this.cnv.onmouseout=this.cnv.onmousemove=function(e)
    			{
    				mouseEvent(e,'mousemove',optns);
    			};
    			optns.timeLast=new Date();
    			this.interval=requestAnimFrame(function(time){
    					canvas.interval=canvas.interval||1;
    					canvas.frame(time);},
    				this.cnv);
    		}
    		else return this.frame();
    		return this;
    	}
    	canvas.pause=function() {
    		cancelRequestAnimFrame(this.interval);
    		this.interval=0;
            return this;
    	}
        canvas.restart = function() {
            return this.pause().start(true);
        }
    	canvas.del=function()
    	{
    		cancelRequestAnimFrame(this.interval);
    		this.layers=[];
    		canvases.splice(this.optns.number,1);
    		for(var i=0;i<canvases.length;i++)
    		{
    			var canvas=canvases[i],
    			layers=canvas.layers,
    			limitL=layers.length;
    			canvas.optns.number=i;
    			for(var j=0;j<limitL;j++)
    			{
    				var layer=layers[j];
    				layer.optns.canvas.number=i;
    				setLayerAndCanvasToArray(layer.objs,layer.optns.id,layer.optns.number,canvas.optns.id,canvas.optns.number);
    				setLayerAndCanvasToArray(layer.grdntsnptrns,layer.optns.id,layer.optns.number,canvas.optns.id,canvas.optns.number);
    			}
    		}
    		if(this.cnv.parentNode)this.cnv.parentNode.removeChild(this.cnv);
    		lastCanvas=0;
    		return false;
    	}
    	canvas.clear=function()
    	{
    		cancelRequestAnimFrame(this.interval);
    		this.interval=0;
    		this.layers=[];
    		jCanvaScript.layer(this.optns.id+'Layer_0').canvas(this.optns.id);
    		this.optns.ctx.clearRect(0,0,this.optns.width,this.optns.height);
    		this.optns.redraw++;
    		return this;
    	}
    	canvas.frame=function(time)
    	{
    		var optns=this.optns,thisCanvas=this;
    		time=time||(new Date());
    		optns.timeDiff=time-optns.timeLast;
    		optns.timeLast=time;
    		if(this.interval)
    		{
    			this.interval=requestAnimFrame(function(time){thisCanvas.frame(time);},thisCanvas.cnv);
    			this.interval=this.interval||1;
    		}
    		if(!optns.redraw)return this;
    		optns.redraw--;
    		optns.ctx.clearRect(0,0,optns.width,optns.height);
    		if(this.layers.length==0)return this;
    		limit=this.layers.length;
    		if(optns.anyLayerLevelChanged)
    			limit=levelChanger(this.layers);
    		if(optns.anyLayerDeleted)
    			limit=objDeleter(this.layers);
    		if(optns.anyLayerLevelChanged || optns.anyLayerDeleted)
    		{
    			optns.anyLayerLevelChanged=optns.anyLayerDeleted=false;
    			for(var i=0;i<limit;i++)
    			{
    				var layer=this.layers[i],layerOptns=layer.optns;
    				setLayerAndCanvasToArray(layer.objs,layerOptns.id,layerOptns.number,this.optns.id,this.optns.number);
    				setLayerAndCanvasToArray(layer.grdntsnptrns,layerOptns.id,layerOptns.number,idCanvas,this.optns.number);
    			}
    		}
    		for(i=0;i<limit;i++)
    		{
    			var object=this.layers[i];
    			if(typeof (object.draw)=='function')
    				if(object.beforeDraw(optns))
    				{
    					if(typeof (object.draw)=='function')
    					{
    						object.draw(optns);
    						object.afterDraw(optns);
    					}
    				}
    		}
    		var mm=optns.mousemove;
    		var mouseDown=optns.mousedown;
    		var mouseUp=optns.mouseup;
    		var click=this.optns.click;
    		var dblClick=this.optns.dblclick;
    		if(mm.x!=false)
    		{
    			if(optns.drag.object!=false)
    			{
    				var drag=optns.drag,
    					dobject=drag.object;
    				dobject.translate(mm.x-drag.x,mm.y-drag.y);
    				drag.x=mm.x;
    				drag.y=mm.y;
    				if(drag.drag)drag.drag.call(dobject,{x:mm.x,y:mm.y});
    			}
    			var point = this.optns.point||{};
    			point.event=mm.event;
    			if(mm.object!=false)
    			{
    				var mousemoveObject=mm.object,
                        mousemoveLayer = objectLayer(mousemoveObject);
                    if(underMouse===mousemoveObject)
                    {
                        if(typeof mousemoveObject.onmousemove === 'function'){
                            mousemoveObject.onmousemove(point);
                        }
                        if(mousemoveLayer === underMouseLayer){
                            if(typeof mousemoveLayer.onmousemove === 'function'){
                                mousemoveLayer.onmousemove(point);
                            }
                        }
                        else {
                            if(underMouseLayer){
                                if(typeof underMouseLayer.onmouseout === 'function'){
                                    underMouseLayer.onmouseout(point);
                                }
                            }
                            if(typeof mousemoveLayer.onmouseover === 'function'){
                                mousemoveLayer.onmouseover(point);
                            }
                            underMouseLayer = mousemoveLayer;
    
                        }
                    }
                    else
                    {
                        if(underMouse){
                            if(typeof underMouse.onmouseout === 'function'){
                                underMouse.onmouseout(point);
                            }
                        }
                        if(typeof mousemoveObject.onmouseover === 'function'){
                            mousemoveObject.onmouseover(point);
                        }
                        underMouse = mousemoveObject;
                    }
    			}
    			else
    			{
                    if(underMouse)
                    {
                        if(typeof underMouse.onmouseout=='function')
                        {
                            underMouse.onmouseout(point);
                        }
                        underMouse=false;
                    }
                    if(underMouseLayer)
                    {
                        if(typeof underMouseLayer.onmouseout=='function')
                        {
                            underMouseLayer.onmouseout(point);
                        }
                        underMouseLayer=false;
                    }
    			}
    			optns.mousemove.object=false;
    		}
    		if(mouseDown.objects.length)
    		{
    			var mdObjectsLength = mouseDown.objects.length - 1;
    			mdCicle:
    			for(i=mdObjectsLength;i>-1;i--)
    			{
    				var mouseDownObjects=[mouseDown.objects[i],objectLayer(mouseDown.objects[i])], mdObject;
    				for(var j=0;j<2;j++)
    				{
    					mdObject=mouseDownObjects[j];
    					if(mdObject.optns.drag.val==true && mdObject.optns.drag.disabled==false && i == mdObjectsLength)
    					{
    						drag=optns.drag;
    						dobject=drag.object=mdObject.optns.drag.object.visible(true);
    						drag.drag=mdObject.optns.drag.drag;
    						drag.init=mdObject;
    						var initoptns=drag.init.optns;
    						if(initoptns.drag.params!==undefined)dobject.animate(initoptns.drag.params);
    						drag.x=drag.startX=mouseDown.x;
    						drag.y=drag.startY=mouseDown.y;
    						if(dobject!=drag.init && initoptns.drag.type!='clone')
    						{
    							point=transformPoint(mouseDown.x,mouseDown.y,dobject.matrix());
    							dobject.translate(point.x-dobject._x,point.y-dobject._y);
    						}
    						dobject.translate(initoptns.drag.shiftX,initoptns.drag.shiftY);
    						if(typeof initoptns.drag.start=='function')
    							initoptns.drag.start.call(dobject,{x:mouseDown.x,y:mouseDown.y});
    					}
    					if(typeof mdObject.onmousedown=='function')
    						if(mdObject.onmousedown({x:mouseDown.x,y:mouseDown.y,event:mouseDown.event})===false)
    							break mdCicle;
    				}
    			}
    			mouseDown.objects=[];
    		}
    		if(mouseUp.objects.length)
    		{
    			muCicle:
    			for(i=mouseUp.objects.length-1;i>-1;i--)
    			{
    				var mouseUpObjects=[mouseUp.objects[i],objectLayer(mouseUp.objects[i])],muObject;
    				for(j=0;j<2;j++)
    				{
    					muObject=mouseUpObjects[j];
    					if(stopDrag(muObject, mouseUp, optns))click.objects=[];
    					if(typeof muObject.onmouseup=='function')
    						if(muObject.onmouseup({x:mouseUp.x,y:mouseUp.y,event:mouseUp.event})===false)
    							break muCicle;
    				}
    			}
    			this.optns.drag={object:false,x:0,y:0};
    			mouseUp.objects=[];
    		}
    		if(click.objects.length)
    		{
    			cCicle:
    			for(i=click.objects.length-1;i>-1;i--)
    			{
    				var mouseClickObjects=[click.objects[i],objectLayer(click.objects[i])], clickObject;
    				for(j=0;j<2;j++)
    				{
                        clickObject = mouseClickObjects[j];
                        stopDrag(clickObject, click, optns);
    					if(typeof clickObject.onclick == 'function')
    						if(clickObject.onclick({x:click.x,y:click.y,event:click.event})===false)
    							break cCicle;
    				}
    			}
                this.optns.drag={object:false,x:0,y:0};
    			click.objects=[];
    		}
    		if(dblClick.objects.length)
            {
    			dcCicle:
    			for(i=dblClick.objects.length-1;i>-1;i--)
    			{
    				var mouseDblClickObjects=[dblClick.objects[i],objectLayer(dblClick.objects[i])];
    				for(j=0;j<2;j++)
    				{
    					if(typeof mouseDblClickObjects[j].ondblclick == 'function')
    						if(mouseDblClickObjects[j].ondblclick({x:dblClick.x,y:dblClick.y, event:dblClick.event})===false)
    							break dcCicle;
    				}
    			}
                dblClick.objects=[];
            }
    		optns.keyUp.val=optns.keyDown.val=optns.keyPress.val=click.x=dblClick.x=mouseUp.x=mouseDown.x=mm.x=false;
    		return this;
    	}
    	return canvas;
    }
    function stopDrag(object, event, optns){
        var drag=optns.drag;
        if(optns.drag.init && optns.drag.object)
        {
            if(object.optns.drop.val==true)
            {
    
                if(drag.init==drag.object)
                    drag.init.visible(true);
                if(typeof object.optns.drop.fn=='function')
                    object.optns.drop.fn.call(object,drag.init);
            }
            else
            {
                drag.object.visible(false);
                drag.init.visible(true);
                drag.init.optns.translateMatrix[0][2]=drag.object.optns.translateMatrix[0][2];
                drag.init.optns.translateMatrix[1][2]=drag.object.optns.translateMatrix[1][2];
                changeMatrix(drag.init);
                if(drag.object!=drag.init)drag.object.visible(false);
                if(typeof drag.init.optns.drag.stop=='function')
                    drag.init.optns.drag.stop.call(drag.init,{x:event.x,y:event.y});
            }
            return (drag.x!=drag.startX || drag.y!==drag.startY)
        }
        return false;
    }
    
    jCanvaScript.layer=function(idLayer)
    {
    	if(idLayer===undefined)return canvases[0].layers[0];
    	for(var i=0;i<canvases.length;i++)
    	{
    		var layersArray=canvases[i].layers;
    		for (var j=0;j<layersArray.length;j++)
    			if(layersArray[j].optns.id==idLayer)
    				return layersArray[j];
    	}
    	return layers(idLayer);
    }
    
    
        window.jCanvaScript = window.jc = jCanvaScript;
    })(window, undefined);
    

      

    实例

    jCanvaScript使用心得1(—常用图绘制方法)

    绘制圆形

    第一种写法:
    circle(x, y, radius, [color], [fill]);
        x、y轴圆心坐标,半径,颜色,是否填充(默认为false||0不填充)如:
    jc.circle(100,120,50,'rgba(255,0,0,0.5)',true);
    
    第二种写法1 circle(object parameters); 将对象作为参数,如: jc.circle({x:100,y:120,radius:50,color:'#ff0000',fill:1});

     

    绘制矩形

     

    rect(x, y, width, height, [color], [fill]);
        x、y轴左上角坐标,宽高,颜色,是否填充(默认为false||0不填充)如:
    jc.rect(80,100,120,50,'rgba(255,156,135,0.5)',1);
    

     

    绘制弧线

    arc(x, y, radius, startAngle, endAngle, [anticlockwise], [color], [fill]);
        x、y轴圆心坐标,半径,起始结束角度,方向(默认为true||1逆时针),颜色,是否填充(默认为false||0不填充)如:
    jc.arc(60,100,60,90,180,1,'rgb(25,99,253)',0);
    

     

    绘制路径

    line(points, [color], [fill])
        用多个[X,Y]设置路径的点,颜色,是否填充(默认为false||0不填充)如:
    jc.line([[60,20],[75,132],[220,60]],'#ff5587');
    

    绘制二次曲线,数组的点包含数组(x,y,x控制点,控制点y),用于创建曲线应至少两个数组。

    qCurve(points, [color], [fill])
    用多个[x,y,x of control point,y of control point]设置路径的点,颜色,是否填充(默认为false||0不填充)如:
    var arr=[];
    arr[0]=[40,30,30,40];
    arr[1]=[30,40,40,30];
    arr[2]=[30,180,180,30];
    arr[3]=[40,190,190,40];
    arr[4]=[180,190,190,180];
    arr[5]=[190,180,180,190];
    arr[6]=[190,40,40,190];
    arr[7]=[180,30,30,180];
    jc.qCurve(arr,'#ffbbcc',true);
    

      


    绘制贝塞尔曲线绘制贝塞尔曲线,数组的点包含数组(x,y,x控制点1,y控制点1,x控制点2,y控制点2]。用于创建曲线应至少两个数组。

    bCurve(points, [color], [fill])
    用多个 [x, y, x of control point 1, y of control point 1, x of control point 2, y of control point 2]设置路径的点,颜色,是否填充(默认为false||0不填充)如:
    var arr=[];
    arr[0]=[40,30,30,40,40,30];
    arr[1]=[130,140,40,130,130,40];
    arr[2]=[30,180,180,30,30,180];
    jc.bCurve(arr,true);
    

      

    绘制渐变创建一个新的空白jCanvaScript ImageData对象与指定的尺寸。通过循环改变setPixel里面颜色的方式绘制渐变

    var imgData=jc.imageData(100,100); //设置渐变区域的大小
    for(var i=0;i<100;i++){
    for(var j=0;j<100;j++){
    imgData.setPixel(i,j,'rgba('+i+','+j+','+(i+j)+','+(i/100)+')'); 
    //绘制像素点i,j为像素点坐标
    }
    }
    imgData.putData(0,0); //设置渐变区域的位置
    

      


    绘制图像

    image(img, x, y, width, height, sX, sY, sWidth, sHeight);
    图像对象,x、y轴坐标,图像宽高,从图像X、Y位置选择宽高的图像,如:
    var img=new Image(); //创建图像对象
    img.src="logo.png"; //设置图像地址
    img.onload=function(){ //加载图片(canvas绘制图像需要在图片加载结束后)
    jc.start("can1");
    jc.image(img,0,0);
    jc.rect(50, 50, 24, 24, '#FF0000');
    jc.image(img,140,140,48,48,50,50,24,24); //将rect所选区域放大后绘制
    jc.start("can1");}
    

    绘制文字

    text(text, x, y, [maxWidth], [color], [fill]);
    文字字符串,x、y轴坐标,文字显示最大宽度(如果超出会整体压缩文字),颜色,是否填充(默认为true||1不填充)如:
    jc.text("Colored stroked text",80,140,80,'rgb(255,0,0)', 0);
    

      

      --------------------------------------------------------------分割线--------------------------------------------------------

    canvas 公式

       

     // 把角度转换为弧度
        function angleToRadian( angle ) {
            return Math.PI / 180 * angle;
        }
     ## 角度旋转
        dx = mouse.x - object.x;
        dy = mouse.y - object.y;
        object.rotation = Math.atan2(dy,dx)*180/Math.PI
     
        ## 平滑运动
           value = center + Math.sin(angle)*range;
           angle += speed;
     
        ## 正圆运动
           x_position = centerX + Math.sin(angle)*radius;
           y_position = centerY + Math.cos(angle)*radius;
           angle += speed;
     
        ## 椭圆运动
           x_position = centerX + Math.cos(angle)*radiusX;
           y_position = centerY + Math.sin(angle)*radiusY;
           angle += speed;
     
        ##两点间距离
        dx = x2 - x1;
        dy = y2 - y1;
        dist = Math.sqrt(dx*dx + dy*dy);
     

    canvas文字居中

    context.textAlign = 'center';
    context.textBaseline = 'middle';
    context.strokeText(n.toFixed(0) + '%', centerX, centerY);
    //计算两点间的中点:
    function middle(start,end){
        return [(start.x+end.x)/2, (start.y+end.y)/2];
    }
     
    //计算两点间的角度:
    function angle(start,end){
        var diff_x = end.x - start.x,
            diff_y = end.y - start.y;
        return 360*Math.atan(diff_y/diff_x)/(2*Math.PI);
    }
     
    //注意:角度的计算方式要在地图上使用,需要先转换成地理坐标
    function angleFn(start,end,map) {
        var p_start = map.lngLatToContainer(new AMap.LngLat(start[0],start[1]));
        var p_end = map.lngLatToContainer(new AMap.LngLat(end[0],end[1]));
        var diff_x = p_end.x - p_start.x,
            diff_y = p_end.y - p_start.y;
        return 360*Math.atan(diff_y/diff_x)/(2*Math.PI);
    }
    

     

    Canvas 

     

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div>
            <h2>绘制圆形</h2>
            <canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
                当前浏览器不支持 canvas
            </canvas>
        </div>
    </body>
    <script type="text/javascript">
        /*
            该方法负责绘制圆角矩形
            x1 , y2 : 圆角矩形左上角的坐标
            width,height:控制圆角矩形的宽度和高度
            radius:控制圆角矩形的四个圆角的半径
        */
    
        function creatRoundRect(ctx, x1, y1, width, height, radius){
            // 移动到左上角的开始点
            ctx.moveTo(x1 + radius, y1);
            // 添加一条连接开始点到右上角的线段
            ctx.lineTo(x1 + width - radius, y1);
            // 添加右上角的一段圆弧
            ctx.arcTo(x1 + width, y1, x1 + width, y1 + radius, radius);
            // 添加一条连接到右下角的线段
            ctx.lineTo(x1 + width, y1 + height - radius);
            // 添加右下角的一段圆弧
            ctx.arcTo(x1 + width, y1 + height, x1 + width - radius, y1 + height, radius);
            // 添加一条由右下角连接到左下角的线段
            ctx.lineTo(x1 + radius, y1 + height);
            // 添加左下的圆弧
            ctx.arcTo(x1, y1 + height, x1, y1 + height - radius,radius);
            // 添加一条由左下角连接到左上角的线段
            ctx.lineTo(x1, y1 + radius);
            // 添加一段圆弧
            ctx.arcTo(x1, y1, x1 + radius, y1, radius);
            ctx.closePath();
        }
        // 获取 canvas 元素对应的 DOM 对象
        var canvas_1 = document.getElementById("canvas_1");
    
        // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
        var ctx = canvas_1.getContext("2d");
    
        ctx.lineWidth = 3;
        creatRoundRect(ctx, 30, 30, 200, 100, 20);
        ctx.stroke();
    </script>
    </html>
    --------------------- 
    作者:MR_LP 
    来源:CSDN 
    原文:https://blog.csdn.net/MR_LP/article/details/51919800?utm_source=copy 
    版权声明:本文为博主原创文章,转载请附上博文链接!
    

      

     多边形
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div>
            <h2>绘制多角形</h2>
            <canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
                当前浏览器不支持 canvas
            </canvas>
        </div>
    </body>
    <script type="text/javascript">
        /*
            该方法用于绘制多角形
                n:该参数通常设置为奇数,控制绘制 N 角星
                dx、dy:控制 N 角星的位置
                size:控制 N 角星的大小
        */
        function creatStar(context, n, dx, dy, size){
            // 开始创建路径
            context.beginPath();
            var dig = Math.PI / n * 4;
            context.moveTo(dx, y + dy);
            for(var i = 0; i <= n; i++){
                var x = Math.sin(i * dig);
                var y = Math.cos(i * dig);
                // 绘制从当前点连接到指定点的线条
                context.lineTo(x * size + dx, y * size + dy);
            }
            // 关闭路径
            context.closePath();
        }
    
        // 获取 canvas 元素对应的 DOM 对象
        var canvas_1 = document.getElementById("canvas_1");
    
        // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
        var ctx = canvas_1.getContext("2d");
    
        // 绘制三角星
        creatStar(ctx, 3, 60, 60, 50);
        ctx.fillStyle = '#f00';
        ctx.fill();
        // 绘制五角星
        creatStar(ctx, 5, 160, 60, 50);
        ctx.fillStyle = '#0f0';
        ctx.fill();
        // 绘制七角星
        creatStar(ctx, 7, 260, 60, 50);
        ctx.fillStyle = '#00f';
        ctx.fill();
        // 绘制九角星
        creatStar(ctx, 9, 360, 60, 50);
        ctx.fillStyle = '#f0f';
        ctx.fill();
    </script>
    </html>
    --------------------- 
    作者:MR_LP 
    来源:CSDN 
    原文:https://blog.csdn.net/MR_LP/article/details/51919800?utm_source=copy 
    版权声明:本文为博主原创文章,转载请附上博文链接!
    

      多边形

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div>
            <h2>绘制花朵</h2>
            <canvas id="canvas_1" width="1000" height="500" style="box-shadow: 0px 0px 20px black;">
                当前浏览器不支持 canvas
            </canvas>
        </div>
    </body>
    <script type="text/javascript">
        /*
            该方法负责绘制花朵
                n:该参数控制花朵的花瓣数
                dx,dy:控制花朵的位置
                size:控制花朵的大小
                length:控制花瓣的长度
        */
        function creatFlower(context, n, dx, dy, size, length){
            // 开始创建路径
            context.beginPath();
            context.moveTo(dx, dy + size);
            var dig = 2 * Math.PI / n;
            for(var i = 1; i < n + 1; i++){
                // 计算控制点的坐标
                var ctrlX = Math.sin((i - 0.5) * dig) * length + dx;
                var ctrlY = Math.cos((i - 0.5) * dig) * length + dy;
                // 计算结束点的坐标
                var x = Math.sin(i * dig) * size + dx;
                var y = Math.cos(i * dig) * size + dy;
                // 绘制二次曲线
                context.quadraticCurveTo(ctrlX, ctrlY, x, y);
            }
            context.closePath();
        }
        // 获取 canvas 元素对应的 DOM 对象
        var canvas_1 = document.getElementById("canvas_1");
        // 获取在 canvas 上绘图的 canvasRenderingContent2D 对象
        var ctx = canvas_1.getContext("2d");
        // 绘制五瓣的花朵
        creatFlower(ctx, 5, 70, 100, 30, 80);
        ctx.fillStyle = "#f00";
        ctx.fill();
        // 绘制六瓣的花朵
        creatFlower(ctx, 6, 220, 100, 30, 80);
        ctx.fillStyle = "#ff0";
        ctx.fill();
        // 绘制七瓣的花朵
        creatFlower(ctx, 7, 370, 100, 30, 80);
        ctx.fillStyle = "#f0f";
        ctx.fill();
    </script>
    </html>
    --------------------- 
    作者:MR_LP 
    来源:CSDN 
    原文:https://blog.csdn.net/MR_LP/article/details/51919800?utm_source=copy 
    版权声明:本文为博主原创文章,转载请附上博文链接!
    

     

    雷达图

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <style type="text/css">
        canvas{
        }
      </style>
    </head>
    <body>
    <script type="text/javascript"> 
        var mW = 400;
        var mH = 400;
        var mData = [['速度', 77],
                                ['力量', 72],
                                ['防守', 46],
                                ['射门', 50],
                                ['传球', 80],
                                ['耐力', 60]];
        var mCount = mData.length; //边数 
        var mCenter = mW /2; //中心点
        var mRadius = mCenter - 50; //半径(减去的值用于给绘制的文本留空间)
        var mAngle = Math.PI * 2 / mCount; //角度
        var mCtx = null;
        var mColorPolygon = '#B8B8B8'; //多边形颜色
        var mColorLines = '#B8B8B8'; //顶点连线颜色
        var mColorText = '#000000';
    
        //初始化
        (function(){
          var canvas = document.createElement('canvas');
          document.body.appendChild(canvas);
          canvas.height = mH;
          canvas.width = mW;
          mCtx = canvas.getContext('2d');
    
          drawPolygon(mCtx);
          drawLines(mCtx);
          drawText(mCtx);
          drawRegion(mCtx);
          drawCircle(mCtx);
        })();
    
          // 绘制多边形边
          function drawPolygon(ctx){
            ctx.save();
    
            ctx.strokeStyle = mColorPolygon;
            var r = mRadius/ mCount; //单位半径
            //画6个圈
            for(var i = 0; i < mCount; i ++){
                ctx.beginPath();        
                var currR = r * ( i + 1); //当前半径
                //画6条边
                for(var j = 0; j < mCount; j ++){
                    var x = mCenter + currR * Math.cos(mAngle * j);
                    var y = mCenter + currR * Math.sin(mAngle * j);
    
                    ctx.lineTo(x, y);
                }
                ctx.closePath()
                ctx.stroke();
            }
    
            ctx.restore();
          }
    
        //顶点连线
        function drawLines(ctx){
            ctx.save();
    
            ctx.beginPath();
            ctx.strokeStyle = mColorLines;
    
            for(var i = 0; i < mCount; i ++){
                var x = mCenter + mRadius * Math.cos(mAngle * i);
                var y = mCenter + mRadius * Math.sin(mAngle * i);
    
                ctx.moveTo(mCenter, mCenter);
                ctx.lineTo(x, y);
            }
    
            ctx.stroke();
    
            ctx.restore();
        }
    
        //绘制文本
        function drawText(ctx){
            ctx.save();
    
            var fontSize = mCenter / 12;
            ctx.font = fontSize + 'px Microsoft Yahei';
            ctx.fillStyle = mColorText;
    
            for(var i = 0; i < mCount; i ++){
                var x = mCenter + mRadius * Math.cos(mAngle * i);
                var y = mCenter + mRadius * Math.sin(mAngle * i);
    
                if( mAngle * i >= 0 && mAngle * i <= Math.PI / 2 ){
                    ctx.fillText(mData[i][0], x, y + fontSize); 
                }else if(mAngle * i > Math.PI / 2 && mAngle * i <= Math.PI){
                    ctx.fillText(mData[i][0], x - ctx.measureText(mData[i][0]).width, y + fontSize);    
                }else if(mAngle * i > Math.PI && mAngle * i <= Math.PI * 3 / 2){
                    ctx.fillText(mData[i][0], x - ctx.measureText(mData[i][0]).width, y);   
                }else{
                    ctx.fillText(mData[i][0], x, y);
                }
    
            }
    
            ctx.restore();
        }
    
        //绘制数据区域
        function drawRegion(ctx){
            ctx.save();
    
            ctx.beginPath();
            for(var i = 0; i < mCount; i ++){
                var x = mCenter + mRadius * Math.cos(mAngle * i) * mData[i][1] / 100;
                var y = mCenter + mRadius * Math.sin(mAngle * i) * mData[i][1] / 100;
    
                ctx.lineTo(x, y);
            }
            ctx.closePath();
            ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
            ctx.fill();
    
            ctx.restore();
        }
    
        //画点
        function drawCircle(ctx){
            ctx.save();
    
            var r = mCenter / 18;
            for(var i = 0; i < mCount; i ++){
                var x = mCenter + mRadius * Math.cos(mAngle * i) * mData[i][1] / 100;
                var y = mCenter + mRadius * Math.sin(mAngle * i) * mData[i][1] / 100;
    
                ctx.beginPath();            
                ctx.arc(x, y, r, 0, Math.PI * 2);
                ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';
                ctx.fill();
            }       
    
            ctx.restore();
        }
    </script>
    
    </body>
    </html>
    --------------------- 
    作者:王乐平 
    来源:CSDN 
    原文:https://blog.csdn.net/lecepin/article/details/60466711?utm_source=copy 
    版权声明:本文为博主原创文章,转载请附上博文链接! 

    基础图标

    <!DOCTYPE html> 
    <html lang="en"> 
    <head> 
    <meta charset="utf-8" /> 
    </head>
    
    
       <body>
          <canvas id="bar" width="450" height="250">
          </canvas>
          <canvas id="pie" width="450" height="250"></canvas>
          <br />
          <canvas id="line" width="450" height="250"></canvas>
          <canvas id="curve" width="450" height="250"></canvas>
    
    
    <script>
    window.onload = function() {
    
       var bar = document.getElementById("bar"),
          data = {
             label: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],//x轴的标题
             dataSets: [{
                bDistance: 30, //绘制的边框距离画布边框的距离
                bInterval: 20, //两个柱状图之间的距离
                values: [300, 50, 100, 50, 80, 150, 120], //对应标签的值
                fillColor: "rgba(0,0,255,0.5)" //矩形填充颜色
             }, {
                txtfont: "14px microsoft yahei",//绘制文本的字体
                txtalgin: "center",//文本对齐方式
                txtbaseline: "middle"//文本的基线
             }, {
                fillColor: "black", //矩形填充颜色
                xtitle: "订单总数(个)", //x轴标题
                ytitle: "星期几" //y轴标题
             }]
          };
       barChart(bar, data); //画柱状图
    
    
    
    
       var pie = document.getElementById("pie"),
          datasets = {
             colors: ["blue", "yellow", "black", "red", "green"], //颜色
             labels: ["第一周", "第二周", "第三周", "第四周", "第五周"], //标签
             values: [30, 60, 80, 70, 150], //值
             x: 125, //圆心x坐标
             y: 125, //圆心y坐标
             radius: 100 //半径
          };
       pieChart(pie, datasets); //画饼状图
    
    
    
       var line = document.getElementById("line"),
          datas = {
             labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],//标签
             values: [50, 180, 100, 150, 110, 130, 30],//值
             txtSet: {//绘制文本设置
                txtfont: "14px microsoft yahei",
                txtalgin: "center",
                txtbaseline: "middle",
                txtColor:"#000000"
             },
             bgSet:{//绘制背景线设置
                lineColor:"#C0C0C0",
                lineWidth:1,
    
             },
             lineColor:"#000000",//折线颜色
             circleColor:"blue",//折线上原点颜色
             yAxis:{//y轴表示什么,及绘制文本的位置
                x:50,
                y:11,
                title:"完成件数(个)"
             }
          },
          newData = {
             labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
             values: [100, 40, 200, 50, 10, 80, 100],
             txtSet: {
                txtfont: "14px microsoft yahei",
                txtalgin: "center",
                txtbaseline: "middle",
                txtColor:"#000000"
             },
             bgSet:{
                lineColor:"#C0C0C0",
                lineWidth:1,
             },
             lineColor:"blue",
             circleColor:"red",
             yAxis:{
                x:50,
                y:11,
                title:"完成件数(个)"
             }
          };
       lineChart(line,datas);//画折线图
       //lineChart(line,newData);//在同一个canvas画第二条折线图
       //curveChart();//绘制曲线
    
    
    
    
       var bg = document.getElementById("curve")
       linedata = {
          labels: ["1月", "2月", "3月", "4月", "5月", "6月", "7月"],//标签
          datas: [115, 35, 210, 100, 300, 220, 40],//数据
          xTitle: "月份",//x轴标题
          yTitle: "产量(个)",//y轴标题
          ctxSets:{
             strokeColor:"#C0C0C0",//背景线颜色
             lineWidth:1,//线的宽度
             txtColor:"#000000",//绘制文本颜色
             txtFont:"12px microsoft yahei",//字体
             txtAlign:"center",//对齐方式
             txtBase:"middle",//基线
             lineColor:"blue",//折线颜色
             circleColor:"#FF0000"//折线上圆点颜色
          }
       };
       setBg(bg,linedata);//绘制图标背景及折线
    }
    
    
    //数组sort()排序传的参数为该函数(降序排列),绘制柱状图需要
    function compare(value1, value2) {
          return value2 - value1;
       }
    /*柱状图
     * elem:要操作的画布元素
     * data:所需格式的数据*/
    function barChart(elem, data) {
          if (elem.getContext) {
             var ctx = elem.getContext("2d"),
                mywidth = elem.width, //画布的宽高
                myheight = elem.height,
                bDistance = parseInt(data.dataSets[0].bDistance), //图标边框到画布间距
                bInterval = data.dataSets[0].bInterval, //矩形间间距
                labels = data.label, //矩形对应标题
                len = labels.length,//标签/数据个数
                //矩形宽度
                bWidth = Math.floor((mywidth - bDistance * 2 - (len + 1) * bInterval) / len),
                bheight = myheight - bDistance * 2, //边框高度
                values = data.dataSets[0].values, //绘图的值
                sortValues = values.slice(0), //基于当前数组中的一个或多个项创建一个新数组(解决了该数组排序原数组也被排序的问题)
                serialValues = new Array(); //用于存储序列化后的值
             sortValues.sort(compare);
             if (sortValues[0] > bheight) {
                (function() {
                   //数值超过边框高度时序列化值
                   for (var i = 0; i < len; i++) {
                      serialValues[i] = values[i] * bheight / sortValues[0];
                   }
                })(); //块级作用域
             }
             //绘制边框
             ctx.beginPath(); //要绘制路径,必须先调用该方法,表示开始绘制新路径
             ctx.moveTo(bDistance, bDistance);
             ctx.lineTo(bDistance, myheight - bDistance);
             ctx.lineTo(mywidth - bDistance, myheight - bDistance);
             ctx.stroke(); //把图形绘制到画布上
             //绘制矩形,组成条形图
             ctx.fillStyle = data.dataSets[0].fillColor;
             //绘制文字
             ctx.font = data.dataSets[1].txtfont; //字体样式、大小、字体
             ctx.textAlign = data.dataSets[1].txtalgin; //文本对齐方式
             ctx.textBaseline = data.dataSets[1].txtbaseline; //文本的基线
             for (var i = 0; i < len; i++) {
                var x = (bInterval + bDistance) + i * (bWidth + bInterval),
                   y = myheight - serialValues[i] - bDistance,
                   x1 = x + Math.round(bWidth / 2);
                y1 = myheight - bDistance + 15,
                   y2 = y - 10;
                ctx.fillRect(x, y, bWidth, serialValues[i]); //x,y,width,height单位都为px
                ctx.fillText(labels[i], x1, y1); //绘制标题文字
                ctx.fillText(values[i], x1, y2); //绘制柱状图数据
             }
             ctx.fillStyle = data.dataSets[2].fillColor;
             ctx.fillText(data.dataSets[2].xtitle, 49, 7); //x轴代表什么
             ctx.fillText(data.dataSets[2].ytitle, mywidth - bDistance, myheight - bDistance + 15); //y轴代表什么
          }
       }
       //求和,计算百分比(画饼图时需要)
    
    function sumFunc(data) {
          var sum = 0;
          for (var i = 0, len = data.length; i < len; i++) {
             sum += data[i];
          }
          return sum;
       }
    /*饼图
     * elem:要操作的画布元素
     * data:所需格式的数据*/
    
    function pieChart(elem, data) {
       if (elem.getContext) {
          var ctx = elem.getContext("2d"),
             vdata = data.values, //绘图数据
             sum = sumFunc(vdata), //对绘图数据求和,用于计算百分比
             startangle = 0, //绘制扇形的开始角度
             labels = data.labels, //绘图的对应文字
             x = data.x, //圆心x坐标
             y = data.y, //圆心y坐标
             rad = data.radius, //圆半径
             x1 = x + rad + 30, //绘制右侧文字和标注的x坐标
             y1 = y - rad, //绘制右侧文字和标注的y坐标
             endangle; //绘制扇形的结束角度
          for (var i = 0, len = vdata.length; i < len; i++) {
             //绘制饼图
             //计算下一次绘制扇形的结束角度,即根据绘制数据占有总数据和的比例求的弧度
             var percent = vdata[i] / sum;
             endangle = startangle + Math.PI * 2 * (percent);
             ctx.beginPath(); //开始绘制新路径
             ctx.fillStyle = data.colors[i]; //绘制颜色
             ctx.moveTo(x, y); //移动到圆心(注:画饼图一定要回到圆心,不然会有问题)
             ctx.arc(x, y, rad, startangle, endangle, false); //画扇形
             //绘制右侧文字和标注
             ctx.moveTo(x1, y1); //移动到绘制文字和标注的位置
             ctx.fillRect(x1, y1, 30, 14); //绘制矩形表示比列图
             //计算四舍五入后的扇形每份的百分比
             var perc = (percent * 100).toFixed(2) + "%"; //tofixed()自动四舍五入返回指定小数位数的字符串
             //设置绘制文字的属性
             ctx.font = "bold 12px microsoft yahei";
             ctx.txtalgin = "center";
             ctx.textBaseline = "top";
             //绘制文字
             ctx.fillText(labels[i] + ":" + perc, x1 + 35, y1);
             ctx.fill(); //指定颜色填充以上绘制
             startangle = endangle; //下一次绘制扇形的开始角度
             y1 += 20; //下一次绘制文字和标注的y坐标
          }
       }
    }
    /*绘制折线
     elem:操作的元素
     data:所需格式数据*/
    function lineChart(elem, data) {
       if (elem.getContext) {
          var ctx = elem.getContext("2d"),
             labels = data.labels,//数值对应标签
             values = data.values,//数值
             len = labels.length,//标签/数值个数
             elemWidth = elem.width,//画布宽度
             elemHeight = elem.height,//画布高度
             gridHeight = Math.ceil(elemHeight / 5),//每行之间高度
             gridWidth = Math.floor(elemWidth / len),//每列之间看度
             actualHeight = 4 * gridHeight + 20;//绘制区域实际高度
          //设置绘制直线的属性
          ctx.strokeStyle = data.bgSet.lineColor;
          ctx.lineWidth = data.bgSet.lineWidth;
          //设置绘制文本的属性
          ctx.font = data.txtSet.txtfont;
          ctx.textAlign = data.txtSet.txtalgin;
          ctx.txtbaseline = data.txtSet.txtbaseline;
          //绘制背景
          //绘制背景横线
          ctx.beginPath();
          for (var i = 0; i < 5; i++) {
             var hgridY = gridHeight * i + 20,
                hgridX = gridWidth * len;
             ctx.moveTo(0, hgridY);
             ctx.lineTo(hgridX, hgridY);
          }
          ctx.stroke();
    
          //绘制背景的竖线,表示每个label
          ctx.beginPath();
          for (var j = 0; j < len + 1; j++) {
             var vgridX = gridWidth * j,
                vgridY = actualHeight;
             ctx.moveTo(vgridX, vgridY);
             ctx.lineTo(vgridX, vgridY + 10);
          }
          ctx.stroke();
          //绘制标签文字
          ctx.fillStyle = data.txtSet.txtColor;
          for (var k = 0; k < len; k++) {
             var txtX = gridWidth * (k + 0.5),
                txtY = actualHeight + 15;
             ctx.fillText(labels[k], txtX, txtY);
          }
          ctx.fill();
    
    
          //获取画图数据的最大值用于序列换数据
          var maxValue = 0,
             cData = new Array();
          for (var i = 0; i < len; i++) {
             if (values[i] > maxValue) {
                maxValue = values[i];
             }
          }
          //当最大值大于画布可绘制区域的高度时,对数据进行转化,然后进行画图
          if ((4 * gridHeight) < maxValue) {
             for (var i = 0; i < len; i++) {
                //转换后的数据
                cData[i] = values[i] * 4 * gridHeight / maxValue;
             }
          } else {
             cData = values;
          }
          //绘制折线
          ctx.strokeStyle = data.lineColor;
          ctx.beginPath();
          var pointX = gridWidth / 2,
             pointY = actualHeight - cData[0];
          ctx.moveTo(pointX, pointY);
          for (var i = 1; i < len; i++) {
             pointX += gridWidth;
             pointY = actualHeight - cData[i];
             ctx.lineTo(pointX, pointY);
          }
          ctx.stroke();
          //绘制坐标圆形
          ctx.beginPath();
          ctx.fillStyle = data.circleColor; //圆点的颜色
          for (var i = 0; i < len; i++) {
             var circleX = gridWidth / 2 + gridWidth * i,
                circleY = actualHeight - cData[i];
             ctx.moveTo(circleX, circleY); //假如不每次绘制之前确定开始绘制新路径,可以每次绘制之前移动到新的圆心
             ctx.arc(circleX, circleY, 4, 0, Math.PI * 2, false);
          }
          ctx.fill();
          //绘制坐标圆形对应的值
          ctx.beginPath();
          ctx.fillStyle = data.txtSet.txtColor;; //文本颜色
          for (var i = 0; i < len; i++) {
             var circleX = gridWidth / 2 + gridWidth * i,
                circleY = actualHeight - cData[i];
             ctx.fillText(values[i], circleX, circleY - 8);
    
          }
          ctx.fill();
          //绘制y轴代表什么
          ctx.fillText(data.yAxis.title, data.yAxis.x, data.yAxis.y);
          ctx.fill();
    
       }
    }
    
    function curveChart() {
          var elem = document.getElementById("curve");
          if (elem.getContext) {
             var ctx = elem.getContext("2d");
             //       ctx.lineWidth = 2;
             ctx.lineCap = "square";
             ctx.beginPath();
             ctx.moveTo(100, 70);
             ctx.bezierCurveTo(120, 150, 150, 150, 200, 60); //三次贝赛尔曲线
             ctx.moveTo(40, 100);
             ctx.quadraticCurveTo(60, 60, 100, 70); //二次贝塞尔曲线
             ctx.moveTo(200, 60);
             ctx.arcTo(240, 40, 300, 50, 50); //绘制弧线
             ctx.stroke();
    
          }
       }
       /* 绘制背景
        * elem:要操作的元素
        * data:所需格式的数据*/
    
    
    function setBg(elem, data) {
    
       if (elem.getContext) {
          var ctx = elem.getContext("2d"),//获取元素上下文
             startX = 40,//左上角开始绘制的x坐标
             startY = 40,//左上角开始绘制的y坐标
             labels = data.labels,//对应数据的标签,即列数
             cols = labels.length,//数据个数
             datas = data.datas,//数据
             gWidth = elem.width - 80,//背景总宽度,elem.width为画布宽度
             gHeight = elem.height - 80,//背景总长度
             pgWidth = gWidth / cols,//背景每个格的宽度
             rows = 10,//背景表格行数
             pgHeight = gHeight / rows;//背景表格高度
    
    
          //绘制背景
          ctx.beginPath(); //开始绘制新路径
          ctx.strokeStyle = data.ctxSets.strokeColor;//描边颜色
          ctx.lineWidth = data.ctxSets.lineWidth;//描边线条宽度
          //绘制横线
          for (var i = 0; i < rows; i++) {
             var pY = startX + pgHeight * i;
             ctx.moveTo(startX, pY); //移动到绘制的起点
             ctx.lineTo(gWidth + startX, pY);
          }
          //最后一根横线
          var pY1 = startY + pgHeight * rows;
          ctx.moveTo(startX, pY1); //移动到绘制的起点
          ctx.lineTo(gWidth + startX + 20, pY1);
          //绘制竖线
          //第一根竖线
          ctx.moveTo(startX, startY - 20); //移动到绘制的起点
          ctx.lineTo(startX, gHeight + startY + 10);
          for (var i = 1; i < cols + 1; i++) {
             var pX = startX + pgWidth * i;
             ctx.moveTo(pX, startY); //移动到绘制的起点
             ctx.lineTo(pX, gHeight + startY + 10);
          }
    
          ctx.stroke();//把图形绘制到画布上
          //绘制文字
          ctx.fillStyle = data.ctxSets.txtColor;//填充颜色
          ctx.font = data.ctxSets.txtFont;//文本字体
          ctx.textAlign = data.ctxSets.txtAlign;//文本对齐方式
          ctx.textBaseline = data.ctxSets.txtBase;//文本基线
          //绘制横轴文字
          for (var i = 0; i < cols; i++) {
             var px = startX + pgWidth / 2 + pgWidth * i;
             ctx.fillText(labels[i], px, startY + gHeight + 10);
          }
          //绘制竖轴文字
          //判断最大值是否大于行高,确定每行的数值
          var maxValue = 0,
             newValues = new Array(),
             j = 0;
          for (var i = 0; i < cols; i++) {
             if (datas[i] > maxValue) {
                maxValue = datas[i];
             }
          }
          //重新计算每隔数据值及转换值
          if (maxValue > gHeight) {
             pgValues = maxValue / rows;
             for (var i = 0; i < cols; i++) {
                newValues[i] = datas[i] * gHeight / maxValue;
             }
          } else {
             pgValues = pgHeight;
             newValues = datas;
          }
          //绘制竖轴文字
          for (var i = rows; i >= 0; i--) {
             ctx.fillText(pgValues * i, 20, startY + pgHeight * j);
             j++;
          }
    
          //绘制标题
          //x轴标题
          ctx.fillText(data.xTitle, gWidth + startX + 15, gHeight + startY + 10);
          //y轴标题
          ctx.fillText(data.yTitle, startX + 25, startY - 10);
    
    
          //画图
          //绘制折线
          ctx.strokeStyle = data.ctxSets.lineColor;;
          ctx.beginPath();
          var pointX = pgWidth / 2 + startX,
             pointY = startY + gHeight - newValues[0];
          ctx.moveTo(pointX, pointY);
          for (var i = 1; i < cols; i++) {
             pointX += pgWidth;
             pointY = startY + gHeight - newValues[i];
             ctx.lineTo(pointX, pointY);
          }
          ctx.stroke();
          //绘制坐标圆形
          ctx.beginPath();
          ctx.fillStyle = data.ctxSets.circleColor;; //圆点的颜色
          for (var i = 0; i < cols; i++) {
             var circleX = pgWidth / 2 + startX + pgWidth * i,
                circleY = startY + gHeight - newValues[i];
             ctx.moveTo(circleX, circleY); //假如不每次绘制之前确定开始绘制新路径,可以每次绘制之前移动到新的圆心
             ctx.arc(circleX, circleY, 4, 0, Math.PI * 2, false);
          }
          ctx.fill();
          //绘制坐标圆形对应的值
          ctx.beginPath();
          ctx.fillStyle = data.ctxSets.txtColor; //文本颜色
          for (var i = 0; i < cols; i++) {
             var circleX = pgWidth / 2 + startX + pgWidth * i,
                circleY = startY + gHeight - newValues[i];
             ctx.fillText(datas[i], circleX, circleY - 10);
          }
          ctx.fill();
    
       }
    
    }
    
    
    </script>
    </body>
    </html>
    

     

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
        <style>
            .main{
                padding: 50px;
                text-align: center;
            }
        </style>
    </head>
    <body>
    	
    	https://www.cnblogs.com/linxin/p/6892389.html
        <div class="main"><canvas id="canvas" width="500" height="400"></canvas></div>
        
    
        <script >
        	
        	function sBarChart(canvas, data, options) {
        this.canvas = document.getElementById(canvas);
        this.ctx = this.canvas.getContext('2d');
        this.data = data;                           // 存放图表数据
        this.dataLength = this.data.length;         // 图表数据的长度
        this.width = this.canvas.width;             // canvas 宽度
        this.height = this.canvas.height;           // canvas 高度
        this.padding = 50;                          // canvas 内边距
        this.yEqual = 5;                            // y轴分成5等分
        this.yLength = 0;                           // y轴坐标点之间的真实长度
        this.xLength = 0;                           // x轴坐标点之间的真实长度
        this.yFictitious = 0;                       // y轴坐标点之间显示的间距
        this.yRatio = 0;                            // y轴坐标真实长度和坐标间距的比
        this.bgColor = '#ffffff';                   // 默认背景颜色
        this.fillColor = '#1E9FFF';                 // 默认填充颜色
        this.axisColor = '#666666';                 // 坐标轴颜色
        this.contentColor = '#eeeeee';              // 内容横线颜色
        this.titleColor = '#000000';                // 图表标题颜色
    	this.title = '';                            // 图表标题
    	this.titlePosition = 'top';                 // 图表标题位置: top / bottom
        this.looped = null;                         // 是否循环
        this.current = 0;                           // 当前加载柱状图高度的百分数
        this.currentIndex = -1;
        this.onceMove = -1;
        this.init(options);
    }
    sBarChart.prototype = {
        init: function(options) {
            if(options){
                this.padding = options.padding || 50;
                this.yEqual = options.yEqual || 5;
                this.bgColor = options.bgColor || '#ffffff';
                this.fillColor = options.fillColor || '#1E9FFF';
                this.axisColor = options.axisColor || '#666666';
                this.contentColor = options.contentColor || '#eeeeee';
                this.titleColor = options.titleColor || '#000000';
                this.title = options.title;
                this.titlePosition = options.titlePosition || 'top';
            }
            this.yLength = Math.floor((this.height - this.padding * 2 - 10) / this.yEqual);
            this.xLength = Math.floor((this.width - this.padding * 1.5 - 10) / this.dataLength);
            this.yFictitious = this.getYFictitious(this.data);
            this.yRatio = this.yLength / this.yFictitious;
            this.looping();
        },
        looping: function() {
            this.looped = requestAnimationFrame(this.looping.bind(this));
            if(this.current < 100){
    			this.current = (this.current + 3) > 100 ? 100 : (this.current + 3);
                this.drawAnimation();
            }else{
                window.cancelAnimationFrame(this.looped);
                this.looped = null;
                this.watchHover();
            }
        },
        drawAnimation: function() {
            for(var i = 0; i < this.dataLength; i++) {
                var x = Math.ceil(this.data[i].value * this.current / 100 * this.yRatio);
                var y = this.height - this.padding - x;
                
                this.data[i].left = this.padding + this.xLength * (i + 0.25);
                this.data[i].top = y;
                this.data[i].right = this.padding + this.xLength * (i + 0.75);
                this.data[i].bottom = this.height - this.padding;
                this.drawUpdate();
            }
        },
        drawUpdate: function() {
            this.ctx.fillStyle = this.bgColor;
            this.ctx.fillRect(0, 0, this.width, this.height);
            this.drawAxis();
            this.drawPoint();
            this.drawTitle();
            this.drawChart();
        },
        drawChart: function() {
            this.ctx.fillStyle = this.fillColor;
            for(var i = 0; i < this.dataLength; i++) {
                this.ctx.fillRect(
                    this.data[i].left, 
                    this.data[i].top, 
                    this.data[i].right - this.data[i].left, 
                    this.data[i].bottom - this.data[i].top
                );
                this.ctx.font = '12px Arial'
                this.ctx.fillText(
                    this.data[i].value * this.current / 100,
                    this.data[i].left + this.xLength / 4, 
                    this.data[i].top - 5
                );
            }
        },
        drawAxis: function() {
            this.ctx.beginPath();
            this.ctx.strokeStyle = this.axisColor;
            // y轴线, +0.5是为了解决canvas画1像素会显示成2像素的问题
    		this.ctx.moveTo(this.padding + 0.5, this.height - this.padding + 0.5);
    		this.ctx.lineTo(this.padding + 0.5, this.padding + 0.5);
    		// x轴线
    		this.ctx.moveTo(this.padding + 0.5, this.height - this.padding + 0.5);
    		this.ctx.lineTo(this.width - this.padding / 2 + 0.5, this.height - this.padding + 0.5);
    		this.ctx.stroke();
        },
        drawPoint: function() {
            // x轴坐标点
            this.ctx.beginPath();
            this.ctx.font = '12px Microsoft YaHei';
            this.ctx.textAlign = 'center';
            this.ctx.fillStyle = this.axisColor; 
            for(var i = 0; i < this.dataLength; i ++){
    			var xAxis = this.data[i].xAxis;
    			var xlen = this.xLength * (i + 1);
    			this.ctx.moveTo(this.padding + xlen + 0.5, this.height - this.padding + 0.5);
    			this.ctx.lineTo(this.padding + xlen + 0.5, this.height - this.padding + 5.5);
    			this.ctx.fillText(xAxis, this.padding + xlen - this.xLength / 2, this.height - this.padding + 15);
    		}
            this.ctx.stroke();
    
            // y轴坐标点
            this.ctx.beginPath();
            this.ctx.font = '12px Microsoft YaHei';
            this.ctx.textAlign = 'right';
            this.ctx.fillStyle = this.axisColor;
            this.ctx.moveTo(this.padding + 0.5, this.height - this.padding + 0.5);
            this.ctx.lineTo(this.padding - 4.5, this.height - this.padding + 0.5);
            this.ctx.fillText(0, this.padding - 10, this.height - this.padding + 5);
            for(var i=0; i < this.yEqual; i ++){
    			var y = this.yFictitious * (i + 1);
    			var ylen = this.yLength * (i + 1);
                this.ctx.beginPath();
                this.ctx.strokeStyle = this.axisColor;
    			this.ctx.moveTo(this.padding + 0.5, this.height - this.padding - ylen + 0.5);
    			this.ctx.lineTo(this.padding - 4.5, this.height - this.padding - ylen + 0.5);
    			this.ctx.stroke();
    			this.ctx.fillText(y,this.padding - 10, this.height - this.padding - ylen + 5);
                this.ctx.beginPath();
    			this.ctx.strokeStyle = this.contentColor;
    			this.ctx.moveTo(this.padding + 0.5, this.height - this.padding - ylen + 0.5)
    			this.ctx.lineTo(this.width - this.padding / 2 + 0.5, this.height - this.padding - ylen+0.5);
                this.ctx.stroke();
    		}
        },
        drawTitle: function() {
            if(this.title){
                this.ctx.beginPath();
    			this.ctx.textAlign = 'center';
    			this.ctx.fillStyle = this.titleColor;
    			this.ctx.font = '16px Microsoft YaHei';
    			if(this.titlePosition === 'bottom' && this.padding >= 40){
    				this.ctx.fillText(this.title, this.width / 2, this.height - 5)
    			}else{
    				this.ctx.fillText(this.title, this.width / 2, this.padding / 2)
    			}
    		}
        },
        /**
         * 监听鼠标移动事件
         */
        watchHover: function() {
            var self = this;
            self.canvas.addEventListener('mousemove', function(ev) {
    			ev = ev || window.event;
                self.currentIndex = -1;
    			for (var i = 0; i < self.data.length; i ++){
    				if( ev.offsetX > self.data[i].left &&
                        ev.offsetX < self.data[i].right &&
                        ev.offsetY > self.data[i].top &&
                        ev.offsetY < self.data[i].bottom )
                    {
    					self.currentIndex = i;
    				}
    			}
                self.drawHover();
    		})
        },
        drawHover: function() {
            if(this.currentIndex !== -1){
                if(this.onceMove === -1){
                    this.onceMove = this.currentIndex;
                    this.canvas.style.cursor = 'pointer';
                }
            }else{
                if(this.onceMove !== -1){
                    this.onceMove = -1;
                    this.canvas.style.cursor = 'inherit';
                }
            }
        },
        /**
         * y轴坐标点之间显示的间距
         * @param data 
         * @return y轴坐标间距
         */
        getYFictitious: function(data) {
            var arr = data.slice(0);
            arr.sort(function(a,b){
                return -(a.value-b.value);
            });
            var len = Math.ceil(arr[0].value / this.yEqual);
            var pow = len.toString().length - 1;
            pow = pow > 2 ? 2 : pow;
            return Math.ceil(len / Math.pow(10,pow)) * Math.pow(10,pow);
        }
    }
        </script>
        <script>
            var data = [
                {xAxis:'2012',value:2141},
                {xAxis:'2013',value:1499},
                {xAxis:'2014',value:3260},
                {xAxis:'2015',value:1170},
                {xAxis:'2016',value:970},
                {xAxis:'2017',value:2350}
            ]
            var chart = new sBarChart('canvas',data,{
                title: 'xxx公司年度盈利',
                bgColor: '#829dba',
                titleColor: '#ffffff',      // 标题颜色
                titlePosition: 'top',       // 标题位置
                fillColor: '#72f6ff',       // 柱状填充色
                axisColor: '#eeeeee',       // 坐标轴颜色
                contentColor: '#bbbbbb'     // 内容横线颜色
            });
        </script>
    </body>
    </html>
    

      

     

     多个环形

     

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title>asd</title>
    	</head>
    	<body>
    		
    		
    <div class="canvas">
    
           <canvas id="pTestPassRate1" width="242" height="270"></canvas>
    
           <div class='canvasTxt'>用例通过数</div>
           
           
           
            <canvas id="canvas2" width="242" height="270"></canvas>
    </div>
    
    
    
    <script></script>
    
    
    
    <script>
    	
    	window.onload=function(){
    		function degToRad(deg){//角度转弧度
    			
    			return deg*(Math.PI/180); ;
    		}
    		
    	   var pTestPassRate1 =document.getElementById("pTestPassRate1");
    
         var ctx = pTestPassRate1.getContext("2d");
         ctx.lineWidth = 10;
        //Background
    //    gradient = ctx.createRadialGradient(250, 250, 5, 250, 250, 300);
    //    gradient.addColorStop(0, "#03303a");
    //    gradient.addColorStop(1, "black");
    //    ctx.fillStyle = gradient;
        ctx.fillStyle = '#999';
        ctx.fillRect(0, 0, 500, 500);
        //用例数
        ctx.beginPath();
        ctx.strokeStyle = '#FE47FC'
        ctx.arc(60, 100, 50, degToRad(-90), degToRad(-300),true ); //总数
        ctx.stroke();
        //Minutes
        ctx.beginPath();
        ctx.strokeStyle = '#3AF8F8';
        ctx.arc(60, 100, 38, degToRad(-90), degToRad(-220),true );//通过
        ctx.stroke();
    
        ctx.beginPath();
        ctx.strokeStyle = '#f00';
        ctx.arc(60, 100, 24, degToRad(-90), degToRad(-180),true ); //未通过
        ctx.stroke();
    
    
    
        //font
        ctx.font = "oblique 12px Helvetica"; //设置字体样式
        ctx.fillStyle = '#3AF8F8'
        ctx.fillText(" 通过数", 92, 80);// 多个ctx.fillText可以达到文字换行效果
        ctx.fillText("______", 92, 82);
        ctx.fillStyle = 'red'
        ctx.fillText(" 未通过数", 92, 110);
        ctx.fillText("_____", 92, 112);
        ctx.fillStyle = '#FE47FC'
        ctx.fillText(" 总用例数", 92, 140);
        ctx.fillText("_____", 92, 142);
    }
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	
    	//--------------------------
    	
    	var oQuadraticCurveTo = document.getElementById("canvas2");
    var oContext = oQuadraticCurveTo.getContext("2d");
    var x=2;
     
        function drawLine(){
            oContext.beginPath();
            oContext.moveTo(0,0);                       //起始点(x,y)
            oContext.quadraticCurveTo(100, 0, 200, 200);    //创建二次贝塞尔曲线
            oContext.lineWidth = 2;
            oContext.strokeStyle = "tomato";
            oContext.stroke();
            oContext.closePath();
        }
        function drawPoint(x,y){
            oContext.beginPath();
            oContext.arc(x, y, 3, 0, 2 * Math.PI, false);
            oContext.fillStyle="red";
            oContext.fill();
             
            oContext.stroke();
            oContext.closePath();
     
        }
     
        //画移动的线
        function drawMivie(){
             
            y=Math.pow(x,2)*0.005;
           
                 
            if(x > 198){
                x=0;
            }else{
            //防止首位相连<br>     //清楚之前的图,重新绘制
            oContext.clearRect(0, 0, 500, 500);
            oContext.closePath();
            drawStatic(oContext);
            //
            x=x+1;  
            y=Math.pow(x,2)*0.005;
            //画圆球
            oContext.beginPath();
            oContext.strokeStyle = "white";
            oContext.arc(x,y,5,0,2*Math.PI,false);
            oContext.fillStyle="white";
            oContext.fill();
            oContext.stroke();
            oContext.closePath();
            }
        }
        //画静态元素,红线和两端
        function drawStatic(){
            drawLine();
            drawPoint(0,0);
            drawPoint(200,200);
        }
     
     
        setInterval(function(){
                drawMivie(oContext);
            },20);
    	
    	
    </script>
    //原文:https://blog.csdn.net/qq_36436877/article/details/80184749?utm_source=copy 
    //版权声明:本文为博主原创文章,转载请附上博文链接!
    
    
    
    
    	</body>
    </html>
    

      

     canvas 简易扇形图

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style>
            #graph {
    /*            border: 1px solid black;
                height: 100%;
                 100%;
                box-sizing: border-box;*/
            }
        </style>
    </head>
    <body>
    <div id="circle" style=" 500px;float: left;"></div>
    </body>
    </html>
    <script type="text/javascript">
    	
    	    Math.formatFloat = function(f, digit) { 
        var m = Math.pow(10, digit); 
        return parseInt(f * m, 10) / m; 
    } 
    var A = 0.1; 
    var B = 0.2;
    console.log("浮点",Math.formatFloat(A + B, 1) === 0.3);
    
    	
    	
    	
    (function(window,undefined){
    	
    	
    	
        var data = [
            {"product":"产品1","value":25,"color":"green"},
            {"product":"产品2","value":5,"color":"red"},
            {"product":"产品3","value":60,"color":"yellow"},
            {"product":"产品4","value":10,"color":"blue"}
        ]
         
       // 把角度转换为弧度
        function angleToRadian( angle ) {
            return Math.PI / 180 * angle;
    //       var val=Math.PI / 180 * angle;
    //       var num=num||2;
    //  	 var m= Math.pow(10,num)
    //  	
    //      return parseInt(val * m, 10) / m;
            
        }  
        
        // 弧度  换为角度
        function RadianToangle( hd,num ) {
        	 var val=180/Math.PI * hd;
        	 var num=num||2;
        	
        	 var m= Math.pow(10,num)
        	
            return parseInt(val * m, 10) / m;
    
        }  
         
        
        
        var dom_circle = document.getElementById('circle');
        if(dom_circle){
            var canvas = document.createElement("canvas");
            dom_circle.appendChild(canvas);
            var ctx = canvas.getContext('2d');
            
             var speed=6;
            
            var defaultStyle = function(Dom,canvas){
                if(Dom.clientWidth <= 300)
                {
                    canvas.width = 300;
                    Dom.style.overflowX = "auto";
                }
                else{
                    canvas.width = Dom.clientWidth;
                }
                if(Dom.clientHeight <= 300)
                {
                    canvas.height = 300;
                    Dom.style.overflowY = "auto";
                }
                else
                {
                    canvas.height = Dom.clientHeight;
                }
                
              
                
                //坐标轴区域
                //注意,实际画折线图区域还要比这个略小一点
                return {
                    p1:'green',
                    p2:'red',
                    p3:'yellow',
                    p4:'blue',
                    x: 0 ,    //坐标轴在canvas上的left坐标
                    y: 0 ,    //坐标轴在canvas上的top坐标
                    maxX: canvas.width ,   //坐标轴在canvas上的right坐标
                    maxY: canvas.height ,   //坐标轴在canvas上的bottom坐标
                    r:(canvas.width)/2,  //起点
                    ry:(canvas.height)/2,  //起点
                    cr: (canvas.width)/4, //半径
                    startAngle:angleToRadian(-90),               //开始角度  起始角,以弧度计。(弧的圆形的三点钟位置是 0 度)。
                    endAngle:angleToRadian(270),     //结束角度
                 
                    xAngle:angleToRadian(speed)        //每次偏移量
                };
            }
            //画圆
            var tmpAngle = -(1/2*Math.PI);//90弧度  每个结束角度
            var ds = null;
            var sum = 0;
                for(var s=0;s<data.length;s++){
                	
                	sum+=data[s].value;
                }
            
            console.log("tmpAngle弧度",tmpAngle,angleToRadian(-90))
            ////每个数据占据的比重弧度   
            var percent1 = data[0].value/sum * Math.PI * 2 ;//36*1=36 
            var percent2 = data[1].value/sum * Math.PI * 2 + percent1; //36*2+36=108
            var percent3 = data[2].value/sum * Math.PI * 2 + percent2;//36*6+108=324
            var percent4 = data[3].value/sum * Math.PI * 2 + percent3;//36*1+324=360
            console.log(data[0].value/sum,"1结束角度",RadianToangle(percent1));
            console.log(data[1].value/sum,"2结束角度",RadianToangle(percent2));
            console.log(data[2].value/sum,"3结束角度",RadianToangle(percent3));
            console.log(data[3].value/sum,"4结束角度",RadianToangle(percent4));
            
            var arrs=[];
            var sta=null;
            for(var i=0;i<data.length;i++){
            	
            }
            
            
             function draw2(x,y,r,startAngle,endAngle,color){
         	 
               ctx.save();
               ctx.beginPath();
               ctx.moveTo(x, y);
               ctx.arc(x, y, r, startAngle, endAngle,false);
               ctx.fillStyle = color;
               ctx.fill();
               ctx.closePath();   
               ctx.restore();
            }
            
        
    
        
        
            
            var tmpSum = 0;
            var drawCircle = function(){
                
                 
                if(tmpAngle >= ds.endAngle){
                	console.log("绘制完成1",ds.xAngle);
                    return false;
                }else if(tmpAngle+ ds.xAngle > ds.endAngle){
                	console.log("绘制完成2");
                    tmpAngle = ds.endAngle;
                    
                }else{
    //          	if(RadianToangle(ds.xAngle)>speed*0.25){
    //               ds.xAngle=ds.xAngle*0.21;
    //             }
                	
                  tmpAngle += (ds.xAngle);// 每个结束
                  
                  tmpSum += (ds.xAngle); //每个开始 弧度
                    //console.log("之前",tmpSum,RadianToangle(tmpSum))
                  tmpAngle=RadianToangle(angleToRadian(tmpAngle),2);//弧度转角度  角度转弧度
                  tmpSum=RadianToangle(angleToRadian(tmpSum),2);//弧度转角度  角度转弧度
                  console.log("之后",RadianToangle(tmpSum))
                  // tmpAngle=float_calculator.add(tmpAngle+ds.xAngle)
                   //tmpSum=float_calculator.add(tmpSum+ds.xAngle)
                }
               // console.log(tmpSum,ds.startAngle+'***'+tmpAngle);
                // console.log(tmpSum);
                // ctx.clearRect(ds.x,ds.y,canvas.width,canvas.height);
                
                
                //if(RadianToangle(tmpSum) > RadianToangle(percent1) && RadianToangle(tmpSum) <=RadianToangle(percent2))
                if(tmpSum > percent1 && tmpSum<=percent2)
                {
                	var srartAngel= ds.startAngle+percent1;
                  console.log("最小2red",RadianToangle(percent1),"第一个运动感角度",RadianToangle(tmpSum),"最大",RadianToangle(percent2));
                  draw2(ds.r,ds.ry,ds.cr,srartAngel,tmpAngle,ds.p2)
                    
                }
                else if(tmpSum > percent2 &&tmpSum <=percent3)
                {    
                	
                     //console.log("最小3yellow",RadianToangle(percent1),"第一个运动感角度",RadianToangle(tmpSum),"最大",RadianToangle(percent2));
                    draw2(ds.r,ds.ry,ds.cr,ds.startAngle+percent2,tmpAngle,ds.p3)
                }
                else if(tmpSum > percent3 )
                {
    
                     draw2(ds.r,ds.ry,ds.cr,ds.startAngle+percent3,tmpAngle,ds.p4)
                }
                else{
    
                     draw2(ds.r,ds.ry,ds.cr,ds.startAngle,tmpAngle,ds.p1)
                }
                
                
                
                
       
                requestAnimationFrame(drawCircle);
            }
            
            
            this.toDraw = function(){
                ds= defaultStyle(dom_circle,canvas);
                // console.log(tmpAngle);
                // console.log(ds.xAngle)
                ctx.clearRect(ds.x,ds.y,canvas.width,canvas.height);
                drawCircle();
            }
            
            
            this.toDraw();
            var self = this;
            window.onresize = function(){
                //self.toDraw()
            }
        }
     
    })(window);    
    </script>
    

    上面的存在bug,扇形2 可以

    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
        <style>
            canvas{
                border: 1px solid #A4E2F9;
            }
        </style>
    </head>
    <body>
    	https://github.com/sutianbinde/charts
    	https://www.cnblogs.com/chengduxiaoc/p/7649048.html
    	https://www.cnblogs.com/chengduxiaoc/p/7705727.html
    	
        <div height="400" width="600" style="margin:50px">
            <canvas id="chart"> 你的浏览器不支持HTML5 canvas </canvas>
        </div>
        
        <script type="text/javascript">
            function goChart(dataArr){
                
                     
       // 把角度转换为弧度
        function angleToRadian( angle ) {
            return Math.PI / 180 * angle;
    //       var val=Math.PI / 180 * angle;
    //       var num=num||2;
    //  	 var m= Math.pow(10,num)
    //  	
    //      return parseInt(val * m, 10) / m;
            
        }  
        
        // 弧度  换为角度
        function RadianToangle( hd,num ) {
        	 var val=180/Math.PI * hd;
        	 var num=num||2;
        	
        	 var m= Math.pow(10,num)
        	
            return parseInt(val * m, 10) / m;
    
        }  
                
                
                
                var animated=true;
                // 声明所需变量
                var canvas,ctx;
                // 图表属性
                var cWidth, cHeight, cMargin, cSpace;
                // 饼状图属性
                var radius,ox,oy;//半径 圆心
                var tWidth, tHeight;//图例宽高
                var posX, posY, textX, textY;
                var startAngle, endAngle;
                var totleNb;
                // 运动相关变量
                var ctr, numctr, speed;
                //鼠标移动
                var mousePosition = {};
                
                //线条和文字
                var lineStartAngle,line,textPadding,textMoveDis;
            
                // 获得canvas上下文
                canvas = document.getElementById("chart");
                if(canvas && canvas.getContext){
                    ctx = canvas.getContext("2d");
                }
                initChart(); 
                
                // 图表初始化
                function initChart(){
                    // 图表信息
                    cMargin = 20;
                    cSpace = 40;
                    
                    canvas.width = canvas.parentNode.getAttribute("width")* 2 ;
                    canvas.height = canvas.parentNode.getAttribute("height")* 2;
                    canvas.style.height = canvas.height/2 + "px";
                    canvas.style.width = canvas.width/2 + "px";
                    cHeight = canvas.height - cMargin*2;
                    cWidth = canvas.width - cMargin*2;
            
                    //饼状图信息
                    radius = cHeight*2/6;  //半径  高度的2/6
                    ox = canvas.width/2 + cSpace;  //圆心
                    oy = canvas.height/2;
                    tWidth = 60; //图例宽和高
                    tHeight = 20; 
                    posX = cMargin;
                    posY = cMargin;   //
                    textX = posX + tWidth + 15
                    textY = posY + 18;
                    startAngle = endAngle = -90*Math.PI/180; //起始弧度 结束弧度
                   
        
                    //将传入的数据转化百分比
                    totleNb = 0;
                    new_data_arr = [];
                    for (var i = 0; i < dataArr.length; i++){
                        totleNb += dataArr[i][0];
                    }
                    
                    console.log("总数值totleNb",totleNb);
                    for (var i = 0; i < dataArr.length; i++){
                        new_data_arr.push( dataArr[i][0]/totleNb );
                    }
                 
                    
                    
                    
                    // 运动相关
                    ctr = 3;//初始步骤
                    numctr = 50;//步骤
                    speed = 1.2; //毫秒 timer速度
                    
                    //指示线 和 文字
                    lineStartAngle = -startAngle;
                    line=40;         //画线的时候超出半径的一段线长
                    textPadding=10;  //文字与线之间的间距
                    textMoveDis = 200; //文字运动开始的间距
                }
            
    
                console.log("每个 百分比 new_data_arr",new_data_arr);
                
                
                
                //绘制动画
                pieDraw();
                function pieDraw(mouseMove){
                    
    
                    
                    //设置旋转
                    ctx.save();
                   // ctx.translate(ox, oy);
                   // ctx.rotate((Math.PI*2/numctr)*ctr/2);
                   
                   var percent=ctr/numctr;//运动的百分比
                   
                    for (var j = 0; j < dataArr.length; j++){
                        
                        //绘制饼图
                        //endAngle = endAngle + (new_data_arr[j]*percent)* Math.PI * 2; //结束弧度
                        if(animated){
                        	endAngle = endAngle + (new_data_arr[j]*percent)* Math.PI * 2; //结束弧度
                        }else{
                            endAngle = endAngle + new_data_arr[j]* Math.PI * 2; //结束弧度	
                        }
                        
                        ctx.beginPath();
                        
                       // ctx.moveTo(0,0); //移动到到圆心
                       // ctx.arc(0, 0, radius*ctr/numctr, startAngle, endAngle, false); //绘制圆弧
                        
                        ctx.moveTo(ox, oy); //移动到到圆心
                        ctx.arc(ox, oy, radius, startAngle, endAngle, false); //绘制圆弧
                        
                        
                        ctx.fillStyle = dataArr[j][1];
                        ctx.fill();
                        
                        
                        ctx.closePath();
                       
                      
                        
                        startAngle = endAngle; //设置起始弧度
                        if( j == dataArr.length-1 ){
                            startAngle = endAngle =270*Math.PI/180; //起始弧度 结束弧度
                        }
                        
                         
                    }
                    
                   ctx.restore();
                     //console.log("ctr",ctr,"numctr",numctr,(ctr/numctr).toFixed(2));  
                    if(ctr<numctr){
                        ctr++;
                        setTimeout(function(){
                            //ctx.clearRect(-canvas.width,-canvas.width,canvas.width*2, canvas.height*2);
                            //ctx.clearRect(-canvas.width, -canvas.height,canvas.width*2, canvas.height*2);
                         
                            pieDraw();
                        }, speed*=1.02);
                    }
                }
                
    
                
            }
            
            var chartData = [[25,"#2dc6c8","瓜子"], [12.5,"#b6a2dd", "花生"], [12.5,"#5ab1ee","土豆"], [50,"#d7797f","南瓜四号"]];
            
            goChart(chartData);
    
    
        </script>
    </body>
    </html>
    

      

     canvas 火花漂移

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            
        <style>
            
            :root {
      --blur: 2;
    }
    * {
      box-sizing: border-box;
    }
    html,
    body {
      font-family: 'Arial', sans-serif;
      background: #111;
    }
    canvas {
      position: fixed;
      height: 100vh;
      width: 100vw;
      -webkit-filter: blur(calc(var(--blur) * 1px));
              filter: blur(calc(var(--blur) * 1px));
    }
    input {
      cursor: pointer;
      display: block;
    }
    label {
      margin-bottom: 30px;
    }
    label:last-of-type {
      margin-bottom: 0;
    }
    .menu {
      position: absolute;
      top: 0;
      left: 0;
      color: #fafafa;
      background: rgba(0,0,0,0.15);
      display: flex;
      flex-direction: column;
      padding: 30px;
      -webkit-transform: translate(-100%, 0);
              transform: translate(-100%, 0);
      transition: -webkit-transform 0.25s ease-out;
      transition: transform 0.25s ease-out;
      transition: transform 0.25s ease-out, -webkit-transform 0.25s ease-out;
    }
    .menu--open {
      -webkit-transform: translate(0, 0);
              transform: translate(0, 0);
    }
    .icon {
      height: 60%;
      width: 60%;
      position: absolute;
      top: 50%;
      left: 50%;
      -webkit-transform: translate(-50%, -50%);
              transform: translate(-50%, -50%);
    }
    button {
      height: 44px;
      width: 44px;
      background: 0;
      cursor: pointer;
      border: 0;
      background: rgba(0,0,0,0.15);
      padding: 0;
      margin: 0;
      position: absolute;
      left: 100%;
      top: 0;
    }
    button span {
      width: 100%;
      height: 20%;
      border-radius: 4px;
      background: #fff;
      display: block;
      position: absolute;
      top: 0;
      transition: -webkit-transform 0.25s ease-out;
      transition: transform 0.25s ease-out;
      transition: transform 0.25s ease-out, -webkit-transform 0.25s ease-out;
    }
    button span:nth-child(1) {
      -webkit-transform-origin: top left;
              transform-origin: top left;
    }
    button span:nth-child(2) {
      top: 40%;
    }
    button span:nth-child(3) {
      -webkit-transform-origin: top left;
              transform-origin: top left;
      top: 80%;
    }
    .menu--open span:nth-child(1) {
      -webkit-transform: translate(5px, 3px) rotate(45deg);
              transform: translate(5px, 3px) rotate(45deg);
    }
    .menu--open span:nth-child(2) {
      -webkit-transform: scaleX(0);
              transform: scaleX(0);
    }
    .menu--open span:nth-child(3) {
      -webkit-transform: translate(2px, 0) rotate(-45deg);
              transform: translate(2px, 0) rotate(-45deg);
    }
    
        </style>    
            <canvas></canvas>
    <div class="menu">
      <button>
        <div class="icon"><span></span><span></span><span></span></div>
      </button>
      <label>Amount
        <input type="range" min="1" max="500" step="1" value="100" id="AMOUNT"/>
      </label>
      <label>Upper Velocity Bounds
        <input type="range" min="1" max="50" step="1" value="20" id="UPPER_LIMIT"/>
      </label>
      <label>Lower Velocity Bounds
        <input type="range" min="1" max="50" step="1" value="1" id="LOWER_LIMIT"/>
      </label>
      <label>Blur
        <input type="range" min="0" max="10" step="1" value="2" id="BLUR"/>
      </label>
    </div>
    
    
    <script>
        
        var canvas = document.querySelector('canvas');
    var context = canvas.getContext('2d');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    
    requestAnimationFrame = requestAnimationFrame || webkitRequestAnimationFrame;
    
    var menu = document.querySelector('.menu');
    var modify = function modify(e) {
      OPTIONS[e.target.id] = parseInt(e.target.value, 10);
      if (e.target.id === 'AMOUNT') {
        context.clearRect(0, 0, canvas.width, canvas.height);
        particles = genParticles();
      }
      if (e.target.id === 'BLUR') {
        document.documentElement.style.setProperty('--blur', parseInt(e.target.value, 10));
      }
    };
    menu.addEventListener('change', modify);
    
    var button = document.querySelector('button');
    var handleClick = function handleClick(e) {
      return menu.classList.toggle('menu--open');
    };
    button.addEventListener('click', handleClick);
    
    var OPTIONS = {
      AMOUNT: 100,
      UPPER_LIMIT: 20,
      LOWER_LIMIT: 1
    };
    
    var UPPER_SIZE = 10;
    var LOWER_SIZE = 4;
    
    var doIt = function doIt() {
      return Math.random() > 0.5;
    };
    var update = function update(p) {
      return doIt() ? Math.max(OPTIONS.LOWER_LIMIT, p - 1) : Math.min(p + 1, OPTIONS.UPPER_LIMIT);
    };
    var reset = function reset(p) {
      p.x = p.startX;
      p.y = p.startY;
    };
    var floored = function floored(r) {
      return Math.floor(Math.random() * r);
    };
    var genParticles = function genParticles() {
      return new Array(OPTIONS.AMOUNT).fill().map(function (p) {
        var size = floored(UPPER_SIZE) + LOWER_SIZE;
        var c = document.createElement('canvas');
        var ctx = c.getContext('2d');
        var r = Math.PI / 180 * floored(360);
        var color = 'rgba(255,' + (100 + Math.floor(Math.random() * 70)) + ', 0, ' + Math.random() + ')';
        var xDelayed = doIt();
        var startX = xDelayed ? -(size + floored(canvas.width)) : floored(canvas.width * 0.25);
        var startY = xDelayed ? size + floored(canvas.height * 0.25) + Math.floor(canvas.height * 0.75) : canvas.height + size + floored(canvas.height);
        c.height = size;
        c.width = size;
        context.globalCompositeOperation = 'multiply';
        // ctx.filter = `blur(${Math.random() * size}px)`
        ctx.translate(size / 2, size / 2);
        ctx.rotate(r);
        ctx.translate(-(size / 2), -(size / 2));
        ctx.fillStyle = color;
        ctx.fillRect(0, 0, size, size);
        return {
          x: startX,
          y: startY,
          startY: startY,
          startX: startX,
          c: c,
          r: r,
          vx: floored(OPTIONS.UPPER_LIMIT / 4),
          vy: floored(OPTIONS.UPPER_LIMIT / 4),
          size: size
        };
      });
    };
    
    var particles = genParticles();
    var FRAME_COUNT = 0;
    
    var draw = function draw() {
      if (canvas.width !== window.innerWidth || canvas.height !== window.innerHeight) {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        particles = genParticles();
      }
      // context.restore()
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;
    
      try {
        for (var _iterator = particles[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var particle = _step.value;
    
          context.clearRect(particle.x, particle.y, particle.size, particle.size);
          FRAME_COUNT++;
          if (particle.y < canvas.height || particle.startX < 0) particle.x += particle.vx;
          if (particle.x > 0 || particle.startY > canvas.height) particle.y -= particle.vy;
          if (FRAME_COUNT % 11 === 0 && doIt()) particle.vx = update(particle.vx);
          if (FRAME_COUNT % 13 === 0 && doIt()) particle.vy = update(particle.vy);
          context.drawImage(particle.c, particle.x, particle.y);
          if (particle.x > canvas.width || particle.y < -particle.size) reset(particle);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }
    
      requestAnimationFrame(draw);
    };
    requestAnimationFrame(draw);
        
    </script>
        </body>
    </html>

      

     参考

    https://github.com/sutianbinde/charts

    https://www.cnblogs.com/chengduxiaoc/p/7705727.html

  • 相关阅读:
    Windows phone 墓碑机制的一些源码
    关于Image一些比较抽象的东西(Build Type与 同步以及异步加载的差异)
    自定义控件之Button控件的自定义
    Java集合最全解析,学集合,看这篇就够用了!!!
    看完让你彻底搞懂Websocket原理
    别人的前途我不敢决定
    花一年的时间让自己过得像个人样
    开篇
    你看得懂吗?
    反思
  • 原文地址:https://www.cnblogs.com/surfaces/p/9777666.html
Copyright © 2011-2022 走看看