You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					524 lines
				
				12 KiB
			
		
		
			
		
	
	
					524 lines
				
				12 KiB
			|   
											11 years ago
										 | /*! | ||
|  |   jCanvas v2.2.1 | ||
|  |   Caleb Evans | ||
|  |   2.2.1 revisions by Thinkyhead | ||
|  | */ | ||
|  | 
 | ||
|  | (function($, document, Math, Number, undefined) { | ||
|  | 
 | ||
|  | // jC global object
 | ||
|  | var jC = {}; | ||
|  | jC.originals = { | ||
|  | 	width: 20, | ||
|  | 	height: 20, | ||
|  | 	cornerRadius: 0, | ||
|  | 	fillStyle: 'transparent', | ||
|  | 	strokeStyle: 'transparent', | ||
|  | 	strokeWidth: 5, | ||
|  | 	strokeCap: 'butt', | ||
|  | 	strokeJoin: 'miter', | ||
|  | 	shadowX: 0, | ||
|  | 	shadowY: 0, | ||
|  | 	shadowBlur: 10, | ||
|  | 	shadowColor: 'transparent', | ||
|  | 	x: 0, y: 0, | ||
|  | 	x1: 0, y1: 0, | ||
|  | 	radius: 10, | ||
|  | 	start: 0, | ||
|  | 	end: 360, | ||
|  | 	ccw: false, | ||
|  | 	inDegrees: true, | ||
|  | 	fromCenter: true, | ||
|  | 	closed: false, | ||
|  | 	sides: 3, | ||
|  | 	angle: 0, | ||
|  | 	text: '', | ||
|  | 	font: 'normal 12pt sans-serif', | ||
|  | 	align: 'center', | ||
|  | 	baseline: 'middle', | ||
|  | 	source: '', | ||
|  | 	repeat: 'repeat' | ||
|  | }; | ||
|  | // Duplicate original defaults
 | ||
|  | jC.defaults = $.extend({}, jC.originals); | ||
|  | 
 | ||
|  | // Set global properties
 | ||
|  | function setGlobals(context, map) { | ||
|  | 	context.fillStyle = map.fillStyle; | ||
|  | 	context.strokeStyle = map.strokeStyle; | ||
|  | 	context.lineWidth = map.strokeWidth; | ||
|  | 	context.lineCap = map.strokeCap; | ||
|  | 	context.lineJoin = map.strokeJoin; | ||
|  | 	context.shadowOffsetX = map.shadowX; | ||
|  | 	context.shadowOffsetY = map.shadowY; | ||
|  | 	context.shadowBlur = map.shadowBlur; | ||
|  | 	context.shadowColor = map.shadowColor; | ||
|  | } | ||
|  | 
 | ||
|  | // Close path if chosen
 | ||
|  | function closePath(context, map) { | ||
|  | 	if (map.closed === true) { | ||
|  | 		context.closePath(); | ||
|  | 		context.fill(); | ||
|  | 		context.stroke(); | ||
|  | 	} else { | ||
|  | 		context.fill(); | ||
|  | 		context.stroke(); | ||
|  | 		context.closePath(); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // Measure angles in degrees if chosen
 | ||
|  | function checkUnits(map) { | ||
|  | 	if (map.inDegrees === true) { | ||
|  | 		return Math.PI / 180; | ||
|  | 	} else { | ||
|  | 		return 1; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // Set canvas defaults
 | ||
|  | $.fn.canvas = function(args) { | ||
|  | 	// Reset defaults if no value is passed
 | ||
|  | 	if (typeof args === 'undefined') { | ||
|  | 		jC.defaults = jC.originals; | ||
|  | 	} else { | ||
|  | 		jC.defaults = $.extend({}, jC.defaults, args); | ||
|  | 	} | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Load canvas
 | ||
|  | $.fn.loadCanvas = function(context) { | ||
|  | 	if (typeof context === 'undefined') {context = '2d';} | ||
|  | 	return this[0].getContext(context); | ||
|  | }; | ||
|  | 
 | ||
|  | // Create gradient
 | ||
|  | $.fn.gradient = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		// Specify custom defaults
 | ||
|  | 		gDefaults = { | ||
|  | 			x1: 0, y1: 0, | ||
|  | 			x2: 0, y2: 0, | ||
|  | 			r1: 10, r2: 100 | ||
|  | 		}, | ||
|  | 		params = $.extend({}, gDefaults, args), | ||
|  | 		gradient, stops = 0, percent, i; | ||
|  | 		 | ||
|  | 	// Create radial gradient if chosen
 | ||
|  | 	if (typeof args.r1 === 'undefined' && typeof args.r2 === 'undefined') { | ||
|  | 		gradient = ctx.createLinearGradient(params.x1, params.y1, params.x2, params.y2); | ||
|  | 	} else { | ||
|  | 		gradient = ctx.createRadialGradient(params.x1, params.y1, params.r1, params.x2, params.y2, params.r2); | ||
|  | 	} | ||
|  | 	 | ||
|  | 	// Count number of color stops
 | ||
|  | 	for (i=1; i<=Number.MAX_VALUE; i+=1) { | ||
|  | 		if (params['c' + i]) { | ||
|  | 			stops += 1; | ||
|  | 		} else { | ||
|  | 			break; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	 | ||
|  | 	// Calculate color stop percentages if absent
 | ||
|  | 	for (i=1; i<=stops; i+=1) { | ||
|  | 		percent = Math.round((100 / (stops-1)) * (i-1)) / 100; | ||
|  | 		if (typeof params['s' + i] === 'undefined') { | ||
|  | 			params['s' + i] = percent; | ||
|  | 		} | ||
|  | 		gradient.addColorStop(params['s' + i], params['c' + i]); | ||
|  | 	} | ||
|  | 	return gradient; | ||
|  | }; | ||
|  | 
 | ||
|  | // Create pattern
 | ||
|  | $.fn.pattern = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args), | ||
|  | 		pattern, | ||
|  | 		img = document.createElement('img'); | ||
|  | 	img.src = params.source; | ||
|  | 	 | ||
|  | 	// Create pattern
 | ||
|  | 	function create() { | ||
|  | 		if (img.complete === true) { | ||
|  | 			// Create pattern
 | ||
|  | 			pattern = ctx.createPattern(img, params.repeat); | ||
|  | 		} else { | ||
|  | 			throw "The pattern has not loaded yet"; | ||
|  | 		} | ||
|  | 	} | ||
|  | 	try { | ||
|  | 		create(); | ||
|  | 	} catch(error) { | ||
|  | 		img.onload = create; | ||
|  | 	} | ||
|  | 	return pattern; | ||
|  | }; | ||
|  | 
 | ||
|  | // Clear canvas
 | ||
|  | $.fn.clearCanvas = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args); | ||
|  | 
 | ||
|  | 	// Draw from center if chosen
 | ||
|  | 	if (params.fromCenter === true) { | ||
|  | 		params.x -= params.width / 2; | ||
|  | 		params.y -= params.height / 2; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// Clear entire canvas if chosen
 | ||
|  | 	ctx.beginPath(); | ||
|  | 	if (typeof args === 'undefined') { | ||
|  | 		ctx.clearRect(0, 0, this.width(), this.height()); | ||
|  | 	} else { | ||
|  | 		ctx.clearRect(params.x, params.y, params.width, params.height); | ||
|  | 	}  | ||
|  | 	ctx.closePath(); | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Save canvas
 | ||
|  | $.fn.saveCanvas = function() { | ||
|  | 	var ctx = this.loadCanvas(); | ||
|  | 	ctx.save(); | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Restore canvas
 | ||
|  | $.fn.restoreCanvas = function() { | ||
|  | 	var ctx = this.loadCanvas(); | ||
|  | 	ctx.restore(); | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Scale canvas
 | ||
|  | $.fn.scaleCanvas = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args); | ||
|  | 	ctx.save(); | ||
|  | 	ctx.translate(params.x, params.y); | ||
|  | 	ctx.scale(params.width, params.height); | ||
|  | 	ctx.translate(-params.x, -params.y) | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Translate canvas
 | ||
|  | $.fn.translateCanvas = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args); | ||
|  | 	ctx.save(); | ||
|  | 	ctx.translate(params.x, params.y);		 | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Rotate canvas
 | ||
|  | $.fn.rotateCanvas = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args), | ||
|  | 		toRad = checkUnits(params); | ||
|  | 	 | ||
|  | 	ctx.save(); | ||
|  | 	ctx.translate(params.x, params.y); | ||
|  | 	ctx.rotate(params.angle * toRad); | ||
|  | 	ctx.translate(-params.x, -params.y); | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Draw rectangle
 | ||
|  | $.fn.drawRect = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args), | ||
|  | 		toRad = checkUnits(params), | ||
|  | 		x1, y1, x2, y2, r; | ||
|  | 	setGlobals(ctx, params); | ||
|  | 	 | ||
|  | 	// Draw from center if chosen
 | ||
|  | 	if (params.fromCenter === true) { | ||
|  | 		params.x -= params.width / 2; | ||
|  | 		params.y -= params.height / 2; | ||
|  | 	} | ||
|  | 		 | ||
|  | 	// Draw rounded rectangle if chosen
 | ||
|  | 	if (params.cornerRadius > 0) { | ||
|  | 		x1 = params.x; | ||
|  | 		y1 = params.y; | ||
|  | 		x2 = params.x + params.width; | ||
|  | 		y2 = params.y + params.height; | ||
|  | 		r = params.cornerRadius; | ||
|  | 		if ((x2 - x1) - (2 * r) < 0) { | ||
|  | 			r = (x2 - x1) / 2; | ||
|  | 		} | ||
|  | 		if ((y2 - y1) - (2 * r) < 0) { | ||
|  | 			r = (y2 - y1) / 2; | ||
|  | 		} | ||
|  | 		ctx.beginPath(); | ||
|  | 		ctx.moveTo(x1+r,y1); | ||
|  | 		ctx.lineTo(x2-r,y1); | ||
|  | 		ctx.arc(x2-r, y1+r, r, 270*toRad, 360*toRad, false); | ||
|  | 		ctx.lineTo(x2,y2-r); | ||
|  | 		ctx.arc(x2-r, y2-r, r, 0, 90*toRad, false); | ||
|  | 		ctx.lineTo(x1+r,y2); | ||
|  | 		ctx.arc(x1+r, y2-r, r, 90*toRad, 180*toRad, false); | ||
|  | 		ctx.lineTo(x1,y1+r); | ||
|  | 		ctx.arc(x1+r, y1+r, r, 180*toRad, 270*toRad, false); | ||
|  | 		ctx.fill(); | ||
|  | 		ctx.stroke(); | ||
|  | 		ctx.closePath(); | ||
|  | 	} else { | ||
|  | 		ctx.fillRect(params.x, params.y, params.width, params.height); | ||
|  | 		ctx.strokeRect(params.x, params.y, params.width, params.height); | ||
|  | 	} | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Draw arc
 | ||
|  | $.fn.drawArc = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args), | ||
|  | 		toRad = checkUnits(params); | ||
|  | 		setGlobals(ctx, params); | ||
|  | 	 | ||
|  | 	// Draw from center if chosen
 | ||
|  | 	if (params.fromCenter === false) { | ||
|  | 		params.x += params.radius; | ||
|  | 		params.y += params.radius; | ||
|  | 	} | ||
|  | 	 | ||
|  | 	ctx.beginPath(); | ||
|  | 	ctx.arc(params.x, params.y, params.radius, (params.start*toRad)-(Math.PI/2), (params.end*toRad)-(Math.PI/2), params.ccw); | ||
|  | 	// Close path if chosen
 | ||
|  | 	closePath(ctx, params); | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Draw ellipse
 | ||
|  | $.fn.drawEllipse = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args), | ||
|  | 		controlW = params.width * (4/3); | ||
|  | 		setGlobals(ctx, params); | ||
|  | 	 | ||
|  | 	// Draw from center if chosen
 | ||
|  | 	if (params.fromCenter === false) { | ||
|  | 		params.x += params.width / 2; | ||
|  | 		params.y += params.height / 2; | ||
|  | 	} | ||
|  | 	 | ||
|  | 	// Increment coordinates to prevent negative values
 | ||
|  | 	params.x += 1e-10; | ||
|  | 	params.y += 1e-10; | ||
|  | 	 | ||
|  | 	// Create ellipse
 | ||
|  | 	ctx.beginPath(); | ||
|  | 	ctx.moveTo(params.x, params.y-params.height/2); | ||
|  | 	ctx.bezierCurveTo(params.x-controlW/2,params.y-params.height/2, | ||
|  | 		params.x-controlW/2,params.y+params.height/2, | ||
|  | 		params.x,params.y+params.height/2); | ||
|  | 	ctx.bezierCurveTo(params.x+controlW/2,params.y+params.height/2, | ||
|  | 		params.x+controlW/2,params.y-params.height/2, | ||
|  | 		params.x,params.y-params.height/2); | ||
|  | 	ctx.closePath(); | ||
|  | 	ctx.fill(); | ||
|  | 	ctx.stroke(); | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Draw line
 | ||
|  | $.fn.drawLine = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args), | ||
|  | 		max = Number.MAX_VALUE, l, | ||
|  | 		lx, ly; | ||
|  | 	setGlobals(ctx, params); | ||
|  | 	 | ||
|  | 	// Draw each point
 | ||
|  | 	ctx.beginPath(); | ||
|  | 	ctx.moveTo(params.x1, params.y1); | ||
|  | 	for (l=2; l<max; l+=1) { | ||
|  | 		lx = params['x' + l]; | ||
|  | 		ly = params['y' + l]; | ||
|  | 		// Stop loop when all points are drawn
 | ||
|  | 		if (typeof lx === 'undefined' || typeof ly === 'undefined') { | ||
|  | 			break; | ||
|  | 		} | ||
|  | 		ctx.lineTo(lx, ly); | ||
|  | 	} | ||
|  | 	// Close path if chosen
 | ||
|  | 	closePath(ctx, params); | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Draw quadratic curve
 | ||
|  | $.fn.drawQuad = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args), | ||
|  | 		max = Number.MAX_VALUE, l, | ||
|  | 		lx, ly, lcx, lcy; | ||
|  | 	setGlobals(ctx, params); | ||
|  | 	 | ||
|  | 	// Draw each point
 | ||
|  | 	ctx.beginPath(); | ||
|  | 	ctx.moveTo(params.x1, params.y1); | ||
|  | 	for (l=2; l<max; l+=1) { | ||
|  | 		lx = params['x' + l]; | ||
|  |     if (typeof lx === 'undefined') break; | ||
|  | 		ly = params['y' + l]; | ||
|  |     if (typeof ly === 'undefined') break; | ||
|  | 		lcx = params['cx' + (l-1)]; | ||
|  |     if (typeof lcx === 'undefined') break; | ||
|  | 		lcy = params['cy' + (l-1)]; | ||
|  |     if (typeof lcy === 'undefined') break; | ||
|  | 		ctx.quadraticCurveTo(lcx, lcy, lx, ly); | ||
|  | 	} | ||
|  | 	// Close path if chosen
 | ||
|  | 	closePath(ctx, params); | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Draw Bezier curve
 | ||
|  | $.fn.drawBezier = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args), | ||
|  | 		max = Number.MAX_VALUE, | ||
|  | 		l=2, lc=1, lx, ly, lcx1, lcy1, lcx2, lcy2, i; | ||
|  | 	setGlobals(ctx, params); | ||
|  | 
 | ||
|  | 	// Draw each point
 | ||
|  | 	ctx.beginPath(); | ||
|  | 	ctx.moveTo(params.x1, params.y1); | ||
|  | 	for (i=2; i<max; i+=1) { | ||
|  | 		lx = params['x' + l]; | ||
|  |     if (typeof lx === 'undefined') break; | ||
|  | 		ly = params['y' + l]; | ||
|  |     if (typeof ly === 'undefined') break; | ||
|  | 		lcx1 = params['cx' + lc]; | ||
|  |     if (typeof lcx1 === 'undefined') break; | ||
|  | 		lcy1 = params['cy' + lc]; | ||
|  |     if (typeof lcy1 === 'undefined') break; | ||
|  | 		lcx2 = params['cx' + (lc+1)]; | ||
|  |     if (typeof lcx2 === 'undefined') break; | ||
|  | 		lcy2 = params['cy' + (lc+1)]; | ||
|  |     if (typeof lcy2 === 'undefined') break; | ||
|  | 		ctx.bezierCurveTo(lcx1, lcy1, lcx2, lcy2, lx, ly); | ||
|  | 		l += 1; | ||
|  | 		lc += 2; | ||
|  | 	} | ||
|  | 	// Close path if chosen
 | ||
|  | 	closePath(ctx, params); | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Draw text
 | ||
|  | $.fn.drawText = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args); | ||
|  | 	setGlobals(ctx, params); | ||
|  | 	 | ||
|  | 	// Set text-specific properties
 | ||
|  | 	ctx.textBaseline = params.baseline; | ||
|  | 	ctx.textAlign = params.align; | ||
|  | 	ctx.font = params.font; | ||
|  | 	 | ||
|  | 	ctx.strokeText(params.text, params.x, params.y); | ||
|  | 	ctx.fillText(params.text, params.x, params.y); | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Draw image
 | ||
|  | $.fn.drawImage = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args), | ||
|  | 		// Define image source
 | ||
|  | 		img = document.createElement('img'); | ||
|  |   	img.src = params.source; | ||
|  | 	  setGlobals(ctx, params); | ||
|  | 
 | ||
|  | 	// Draw image function
 | ||
|  | 	function draw() { | ||
|  | 		if (img.complete) { | ||
|  | 
 | ||
|  |   		var scaleFac = img.width / img.height; | ||
|  | 
 | ||
|  | 			// If width/height are specified
 | ||
|  | 			if (typeof args.width !== 'undefined' && typeof args.height !== 'undefined') { | ||
|  | 				img.width = args.width; | ||
|  | 				img.height = args.height; | ||
|  | 			// If width is specified
 | ||
|  | 			} else if (typeof args.width !== 'undefined' && typeof args.height === 'undefined') { | ||
|  | 				img.width = args.width; | ||
|  | 				img.height = img.width / scaleFac; | ||
|  | 			// If height is specified
 | ||
|  | 			} else if (typeof args.width === 'undefined' && typeof args.height !== 'undefined') { | ||
|  | 				img.height = args.height; | ||
|  | 				img.width = img.height * scaleFac; | ||
|  | 			} | ||
|  | 		 | ||
|  | 			// Draw from center if chosen
 | ||
|  | 			if (params.fromCenter === true) { | ||
|  | 				params.x -= img.width / 2; | ||
|  | 				params.y -= img.height / 2; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			// Draw image
 | ||
|  | 			ctx.drawImage(img, params.x, params.y, img.width, img.height); | ||
|  | 		} else { | ||
|  | 			throw "The image has not loaded yet."; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  |   function dodraw() { | ||
|  |     // console.log("dodraw...");
 | ||
|  |     try { | ||
|  |   	  // console.log("dodraw...try...");
 | ||
|  |       draw(); | ||
|  |     } | ||
|  |     catch(error) { | ||
|  |       // console.log("dodraw...catch: " + error);
 | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  | 	// Draw image if already loaded
 | ||
|  |   // console.log("--------------------");
 | ||
|  |   // console.log("drawImage " + img.src);
 | ||
|  | 	try { | ||
|  |     // console.log("try...");
 | ||
|  | 		draw(); | ||
|  | 	} catch(error) { | ||
|  |     // console.log("catch: " + error);
 | ||
|  | 		img.onload = dodraw; | ||
|  | 	} | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | // Draw polygon
 | ||
|  | $.fn.drawPolygon = function(args) { | ||
|  | 	var ctx = this.loadCanvas(), | ||
|  | 		params = $.extend({}, jC.defaults, args), | ||
|  | 		theta, dtheta, x, y, | ||
|  | 		toRad = checkUnits(params), i; | ||
|  | 	setGlobals(ctx, params); | ||
|  | 	 | ||
|  | 	if (params.sides >= 3) {		 | ||
|  | 		// Calculate points and draw
 | ||
|  | 		theta = (Math.PI/2) + (Math.PI/params.sides) + (params.angle*toRad); | ||
|  | 		dtheta = (Math.PI*2) / params.sides; | ||
|  | 		for (i=0; i<params.sides; i+=1) { | ||
|  | 			x = params.x + (params.radius * Math.cos(theta)) + 1e-10; | ||
|  | 			y = params.y + (params.radius * Math.sin(theta)) + 1e-10; | ||
|  | 			if (params.fromCenter === false) { | ||
|  | 				x += params.radius; | ||
|  | 				y += params.radius; | ||
|  | 			} | ||
|  | 			ctx.lineTo(x, y); | ||
|  | 			theta += dtheta; | ||
|  | 		} | ||
|  | 		closePath(ctx, params); | ||
|  | 	} | ||
|  | 	return this; | ||
|  | }; | ||
|  | 
 | ||
|  | return window.jCanvas = jC; | ||
|  | }(jQuery, document, Math, Number)); |