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.\w\w/,
        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;q0.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= (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;i255?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;icoords[i][0])minX=coords[i][0];
		if(minY>coords[i][1])minY=coords[i][1];
	}
	return {x:minX,y:minY,width: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;ib._level)return 1;
		if(a._levelanimateQueueLength)
				{
					for (j=animateQueueLength;jduration)
							{
								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;q1)
		{
			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;ithis['_x'+i])minX=this['_x'+i];
			if(minY>this['_y'+i])minY=this['_y'+i];
		}
		var points={x:minX,y:minY,width:maxX-minX,height:maxY-minY};
		return getRect(this,points,type);
	}
	this.addPoint=function(){
		redraw(this);
		var names=this.pointNames;
		for(var i=0;ix-radius && this['_y'+j] 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;jpoint.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;irect[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][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.x)points.x=rect.x;
			if(points.y>rect.y)points.y=rect.y;
			if(points.right=':
							if(!(value1>=value2))rel='del';
							break;
						case '<=':
							if(!(value1<=value2))rel='del';
							break;
						case '>':
							if(!(value1>value2))rel='del';
							break;
						case '<':
							if(!(value1-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



实例

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 




    
    Document


    

绘制圆形

当前浏览器不支持 canvas
--------------------- 作者:MR_LP 来源:CSDN 原文:https://blog.csdn.net/MR_LP/article/details/51919800?utm_source=copy 版权声明:本文为博主原创文章,转载请附上博文链接!
 多边形



    
    Document


    

绘制多角形

当前浏览器不支持 canvas
--------------------- 作者:MR_LP 来源:CSDN 原文:https://blog.csdn.net/MR_LP/article/details/51919800?utm_source=copy 版权声明:本文为博主原创文章,转载请附上博文链接!

  多边形




    
    Document


    

绘制花朵

当前浏览器不支持 canvas
--------------------- 作者:MR_LP 来源:CSDN 原文:https://blog.csdn.net/MR_LP/article/details/51919800?utm_source=copy 版权声明:本文为博主原创文章,转载请附上博文链接!

雷达图




  
  Document
  






--------------------- 
作者:王乐平 
来源:CSDN 
原文:https://blog.csdn.net/lecepin/article/details/60466711?utm_source=copy 
版权声明:本文为博主原创文章,转载请附上博文链接! 

基础图标

 
 
 
 



   
      
      
      
      



    
    
    
    


	
	https://www.cnblogs.com/linxin/p/6892389.html
    

 多个环形



	
		
		asd
	
	
		
		
用例通过数
//原文:https://blog.csdn.net/qq_36436877/article/details/80184749?utm_source=copy //版权声明:本文为博主原创文章,转载请附上博文链接!

 canvas 简易扇形图




    
    
    


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




    
    
    


	https://github.com/sutianbinde/charts
	https://www.cnblogs.com/chengduxiaoc/p/7649048.html
	https://www.cnblogs.com/chengduxiaoc/p/7705727.html
	
    
你的浏览器不支持HTML5 canvas

 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

相关