前端圖片驗證碼(相容ie8)
阿新 • • 發佈:2019-01-22
讓可愛的我mack一下
前提
最後會附上原始碼的~
圖片驗證碼外掛名稱: GVerify.js
GVerify主要使用canvas生成圖片驗證碼,但是ie8還沒有canvas。
針對ie8 解決canvas外掛:excanvas.js
主要是解決沒有canvas方法getContext。
改變html頁面為
<div id="v_container" style="width: 100px;height: 40px;position: relative; z-index:10000;">
<canvas id="verifyCanvas" width ="100" height="40" style="cursor: pointer;"></canvas>
</div>
js部分
this.verifyCode = new GVerify({
id: "v_container", //容器Id
type: "number" //圖形驗證碼預設型別blend:數字字母混合型別、number:純數字、letter:純字母
});
對GVerify.js外掛做的修改
/**初始化方法**/
_init: function() {
var con = document.getElementById(this .options.id);
// var canvas = document.createElement("canvas");
//獲得畫布 IE不能支援canvas,可以增加excanvas.js外掛,但是還是不支援createelement()的形式
var canvas = document.getElementById(this.options.canvasId);
this.options.width = con.offsetWidth > 0 ? con.offsetWidth : "124";
this .options.height = con.offsetHeight > 0 ? con.offsetHeight : "35";
console.log(con, canvas,document.getElementById('img-code'));
// 為了相容ie去掉
// canvas.id = this.options.canvasId;
// canvas.width = this.options.width;
// canvas.height = this.options.height;
// canvas.style.cursor = "pointer";
// canvas.innerHTML = "您的瀏覽器版本不支援canvas";
// con.appendChild(canvas);
var parent = this;
parent.refresh();
canvas.onclick = function(){
parent.refresh();
}
},
遇到的問題
在某種情況下:比如。圖片二維碼是append上去的。
或許你發現在網上下載的excanvas.js出現了有事不生效的情況。
excanvas.js檢視原始碼發現
var G_vmlCanvasManager_ = {
init: function(opt_doc) {
var doc = opt_doc || document;
// Create a dummy element so that IE will allow canvas elements to be
// recognized.
doc.createElement('canvas');
使用了事件監聽,註釋掉直接掉用就可以。
// doc.attachEvent('onreadystatechange', bind(this.init_, this,
this.init_(doc);
doc));
},
原始碼保留
GVerify.js
function GVerify(options) { //建立一個圖形驗證碼物件,接收options物件為引數
this.options = { //預設options引數值
id: "", //容器Id
canvasId: "verifyCanvas", //canvas的ID
width: "100", //預設canvas寬度
height: "30", //預設canvas高度
type: "blend", //圖形驗證碼預設型別blend:數字字母混合型別、number:純數字、letter:純字母
code: ""
}
if(Object.prototype.toString.call(options) == "[object Object]"){//判斷傳入引數型別
for(var i in options) { //根據傳入的引數,修改預設引數值
this.options[i] = options[i];
}
}else{
this.options.id = options;
}
this.options.numArr = "0,1,2,3,4,5,6,7,8,9".split(",");
this.options.letterArr = getAllLetter();
this._init();
this.refresh();
/**生成字母陣列**/
function getAllLetter() {
var letterStr = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
return letterStr.split(",");
}
}
GVerify.prototype = {
/**版本號**/
version: '1.0.0',
/**初始化方法**/
_init: function() {
var con = document.getElementById(this.options.id);
// var canvas = document.createElement("canvas");
//獲得畫布 IE不能支援canvas,可以增加excanvas.js外掛,但是還是不支援createelement()的形式
var canvas = document.getElementById(this.options.canvasId);
this.options.width = con.offsetWidth > 0 ? con.offsetWidth : "124";
this.options.height = con.offsetHeight > 0 ? con.offsetHeight : "35";
console.log(con, canvas,document.getElementById('img-code'));
// 為了相容ie去掉
// canvas.id = this.options.canvasId;
// canvas.width = this.options.width;
// canvas.height = this.options.height;
// canvas.style.cursor = "pointer";
// canvas.innerHTML = "您的瀏覽器版本不支援canvas";
// con.appendChild(canvas);
var parent = this;
parent.refresh();
canvas.onclick = function(){
parent.refresh();
}
},
/**生成驗證碼**/
refresh: function() {
this.options.code = "";
var canvas = document.getElementById(this.options.canvasId);
if(canvas.getContext) {
var ctx = canvas.getContext('2d');
}else{
return;
}
ctx.textBaseline = "middle";
ctx.fillStyle = randomColor(180, 240);
ctx.fillRect(0, 0, this.options.width, this.options.height);
if(this.options.type == "blend") { //判斷驗證碼型別
var txtArr = this.options.numArr.concat(this.options.letterArr);
} else if(this.options.type == "number") {
var txtArr = this.options.numArr;
} else {
var txtArr = this.options.letterArr;
}
for(var i = 1; i <= 4; i++) {
var txt = txtArr[randomNum(0, txtArr.length)];
this.options.code += txt;
ctx.font = randomNum(this.options.height/2, this.options.height) + 'px SimHei'; //隨機生成字型大小
ctx.fillStyle = randomColor(50, 160); //隨機生成字型顏色
ctx.shadowOffsetX = randomNum(-3, 3);
ctx.shadowOffsetY = randomNum(-3, 3);
ctx.shadowBlur = randomNum(-3, 3);
ctx.shadowColor = "rgba(0, 0, 0, 0.3)";
var x = this.options.width / 5 * i;
var y = this.options.height / 2;
var deg = randomNum(-30, 30);
/**設定旋轉角度和座標原點**/
ctx.translate(x, y);
ctx.rotate(deg * Math.PI / 180);
ctx.fillText(txt, 0, 0);
/**恢復旋轉角度和座標原點**/
ctx.rotate(-deg * Math.PI / 180);
ctx.translate(-x, -y);
}
/**繪製干擾線**/
for(var i = 0; i < 4; i++) {
ctx.strokeStyle = randomColor(40, 180);
ctx.beginPath();
ctx.moveTo(randomNum(0, this.options.width), randomNum(0, this.options.height));
ctx.lineTo(randomNum(0, this.options.width), randomNum(0, this.options.height));
ctx.stroke();
}
/**繪製干擾點**/
for(var i = 0; i < this.options.width/4; i++) {
ctx.fillStyle = randomColor(0, 255);
ctx.beginPath();
ctx.arc(randomNum(0, this.options.width), randomNum(0, this.options.height), 1, 0, 2 * Math.PI);
ctx.fill();
}
/**生成一個隨機數**/
function randomNum(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
/**生成一個隨機色**/
function randomColor(min, max) {
var r = randomNum(min, max);
var g = randomNum(min, max);
var b = randomNum(min, max);
return "rgb(" + r + "," + g + "," + b + ")";
}
},
/**驗證驗證碼**/
validate: function(code){
// var code = code.toLowerCase();
var code = code;
// var v_code = this.options.code.toLowerCase();
var v_code = this.options.code;
console.log(222222222, v_code);
if(code == v_code){
return true;
}else{
this.refresh();
return false;
}
}
};
module.exports = GVerify;
excanvas.js
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Known Issues:
//
// * Patterns only support repeat.
// * Radial gradient are not implemented. The VML version of these look very
// different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
// width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
// Quirks mode will draw the canvas using border-box. Either change your
// doctype to HTML5
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
// or use Box Sizing Behavior from WebFX
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Non uniform scaling does not correctly scale strokes.
// * Optimize. There is always room for speed improvements.
// Only add this code if we do not already have a canvas implementation
if (!document.createElement('canvas').getContext) {
(function() {
// alias some functions to make (compiled) code shorter
var m = Math;
var mr = m.round;
var ms = m.sin;
var mc = m.cos;
var abs = m.abs;
var sqrt = m.sqrt;
// this is used for sub pixel precision
var Z = 10;
var Z2 = Z / 2;
var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];
/**
* This funtion is assigned to the <canvas> elements as element.getContext().
* @this {HTMLElement}
* @return {CanvasRenderingContext2D_}
*/
function getContext() {
return this.context_ ||
(this.context_ = new CanvasRenderingContext2D_(this));
}
var slice = Array.prototype.slice;
/**
* Binds a function to an object. The returned function will always use the
* passed in {@code obj} as {@code this}.
*
* Example:
*
* g = bind(f, obj, a, b)
* g(c, d) // will do f.call(obj, a, b, c, d)
*
* @param {Function} f The function to bind the object to
* @param {Object} obj The object that should act as this when the function
* is called
* @param {*} var_args Rest arguments that will be used as the initial
* arguments when the function is called
* @return {Function} A new function that has bound this
*/
function bind(f, obj, var_args) {
var a = slice.call(arguments, 2);
return function() {
return f.apply(obj, a.concat(slice.call(arguments)));
};
}
function encodeHtmlAttribute(s) {
return String(s).replace(/&/g, '&').replace(/"/g, '"');
}
function addNamespace(doc, prefix, urn) {
if (!doc.namespaces[prefix]) {
doc.namespaces.add(prefix, urn, '#default#VML');
}
}
function addNamespacesAndStylesheet(doc) {
addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
// Setup default CSS. Only add one style sheet per document
if (!doc.styleSheets['ex_canvas_']) {
var ss = doc.createStyleSheet();
ss.owningElement.id = 'ex_canvas_';
ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
// default size is 300x150 in Gecko and Opera
'text-align:left;width:300px;height:150px}';
}
}
// Add namespaces and stylesheet at startup.
addNamespacesAndStylesheet(document);
var G_vmlCanvasManager_ = {
init: function(opt_doc) {
var doc = opt_doc || document;
// Create a dummy element so that IE will allow canvas elements to be
// recognized.
doc.createElement('canvas');
this.init_(doc);
// doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
},
init_: function(doc) {
// find all canvas elements
var els = doc.getElementsByTagName('canvas');
console.log(els);
for (var i = 0; i < els.length; i++) {
this.initElement(els[i]);
}
},
/**
* Public initializes a canvas element so that it can be used as canvas
* element from now on. This is called automatically before the page is
* loaded but if you are creating elements using createElement you need to
* make sure this is called on the element.
* @param {HTMLElement} el The canvas element to initialize.
* @return {HTMLElement} the element that was created.
*/
initElement: function(el) {
if (!el.getContext) {
el.getContext = getContext;
// Add namespaces and stylesheet to document of the element.
addNamespacesAndStylesheet(el.ownerDocument);
// Remove fallback content. There is no way to hide text nodes so we
// just remove all childNodes. We could hide all elements and remove
// text nodes but who really cares about the fallback content.
el.innerHTML = '';
// do not use inline function because that will leak memory
el.attachEvent('onpropertychange', onPropertyChange);
el.attachEvent('onresize', onResize);
var attrs = el.attributes;
if (attrs.width && attrs.width.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setWidth_(attrs.width.nodeValue);
el.style.width = attrs.width.nodeValue + 'px';
} else {
el.width = el.clientWidth;
}
if (attrs.height && attrs.height.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setHeight_(attrs.height.nodeValue);
el.style.height = attrs.height.nodeValue + 'px';
} else {
el.height = el.clientHeight;
}
//el.getContext().setCoordsize_()
}
return el;
}
};
function onPropertyChange(e) {
var el = e.srcElement;
switch (e.propertyName) {
case 'width':
el.getContext().clearRect();
el.style.width = el.attributes.width.nodeValue + 'px';
// In IE8 this does not trigger onresize.
el.firstChild.style.width = el.clientWidth + 'px';
break;
case 'height':
el.getContext().clearRect();
el.style.height = el.attributes.height.nodeValue + 'px';
el.firstChild.style.height = el.clientHeight + 'px';
break;
}
}
function onResize(e) {
var el = e.srcElement;
if (el.firstChild) {
el.firstChild.style.width = el.clientWidth + 'px';
el.firstChild.style.height = el.clientHeight + 'px';
}
}
G_vmlCanvasManager_.init();
// precompute "00" to "FF"
var decToHex = [];
for (var i = 0; i < 16; i++) {
for (var j = 0; j < 16; j++) {
decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
}
}
function createMatrixIdentity() {
return [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]
];
}
function matrixMultiply(m1, m2) {
var result = createMatrixIdentity();
for (var x = 0; x < 3; x++) {
for (var y = 0; y < 3; y++) {
var sum = 0;
for (var z = 0; z < 3; z++) {
sum += m1[x][z] * m2[z][y];
}
result[x][y] = sum;
}
}
return result;
}
function copyState(o1, o2) {
o2.fillStyle = o1.fillStyle;
o2.lineCap = o1.lineCap;
o2.lineJoin = o1.lineJoin;
o2.lineWidth = o1.lineWidth;
o2.miterLimit = o1.miterLimit;
o2.shadowBlur = o1.shadowBlur;
o2.shadowColor = o1.shadowColor;
o2.shadowOffsetX = o1.shadowOffsetX;
o2.shadowOffsetY = o1.shadowOffsetY;
o2.strokeStyle = o1.strokeStyle;
o2.globalAlpha = o1.globalAlpha;
o2.font = o1.font;
o2.textAlign = o1.textAlign;
o2.textBaseline = o1.textBaseline;
o2.arcScaleX_ = o1.arcScaleX_;
o2.arcScaleY_ = o1.arcScaleY_;
o2.lineScale_ = o1.lineScale_;
}
var colorData = {
aliceblue: '#F0F8FF',
antiquewhite: '#FAEBD7',
aquamarine: '#7FFFD4',
azure: '#F0FFFF',
beige: '#F5F5DC',
bisque: '#FFE4C4',
black: '#000000',
blanchedalmond: '#FFEBCD',
blueviolet: '#8A2BE2',
brown: '#A52A2A',
burlywood: '#DEB887',
cadetblue: '#5F9EA0',
chartreuse: '#7FFF00',
chocolate: '#D2691E',
coral: '#FF7F50',
cornflowerblue: '#6495ED',
cornsilk: '#FFF8DC',
crimson: '#DC143C',
cyan: '#00FFFF',
darkblue: '#00008B',
darkcyan: '#008B8B',
darkgoldenrod: '#B8860B',
darkgray: '#A9A9A9',
darkgreen: '#006400',
darkgrey: '#A9A9A9',
darkkhaki: '#BDB76B',
darkmagenta: '#8B008B',
darkolivegreen: '#556B2F',
darkorange: '#FF8C00',
darkorchid: '#9932CC',
darkred: '#8B0000',
darksalmon: '#E9967A',
darkseagreen: '#8FBC8F',
darkslateblue: '#483D8B',
darkslategray: '#2F4F4F',
darkslategrey: '#2F4F4F',
darkturquoise: '#00CED1',
darkviolet: '#9400D3',
deeppink: '#FF1493',
deepskyblue: '#00BFFF',
dimgray: '#696969',
dimgrey: '#696969',
dodgerblue: '#1E90FF',
firebrick: '#B22222',
floralwhite: '#FFFAF0',
forestgreen: '#228B22',
gainsboro: '#DCDCDC',
ghostwhite: '#F8F8FF',
gold: '#FFD700',
goldenrod: '#DAA520',
grey: '#808080',
greenyellow: '#ADFF2F',
honeydew: '#F0FFF0',
hotpink: '#FF69B4',
indianred: '#CD5C5C',
indigo: '#4B0082',
ivory: '#FFFFF0',
khaki: '#F0E68C',
lavender: '#E6E6FA',
lavenderblush: '#FFF0F5',
lawngreen: '#7CFC00',
lemonchiffon: '#FFFACD',
lightblue: '#ADD8E6',
lightcoral: '#F08080',
lightcyan: '#E0FFFF',
lightgoldenrodyellow: '#FAFAD2',
lightgreen: '#90EE90',
lightgrey: '#D3D3D3',
lightpink: '#FFB6C1',
lightsalmon: '#FFA07A',
lightseagreen: '#20B2AA',
lightskyblue: '#87CEFA',
lightslategray: '#778899',
lightslategrey: '#778899',
lightsteelblue: '#B0C4DE',
lightyellow: '#FFFFE0',
limegreen: '#32CD32',
linen: '#FAF0E6',
magenta: '#FF00FF',
mediumaquamarine: '#66CDAA',
mediumblue: '#0000CD',
mediumorchid: '#BA55D3',
mediumpurple: '#9370DB',
mediumseagreen: '#3CB371',
mediumslateblue: '#7B68EE',
mediumspringgreen: '#00FA9A',
mediumturquoise: '#48D1CC',
mediumvioletred: '#C71585',
midnightblue: '#191970',
mintcream: '#F5FFFA',
mistyrose: '#FFE4E1',
moccasin: '#FFE4B5',
navajowhite: '#FFDEAD',
oldlace: '#FDF5E6',
olivedrab: '#6B8E23',
orange: '#FFA500',
orangered: '#FF4500',
orchid: '#DA70D6',
palegoldenrod: '#EEE8AA',
palegreen: '#98FB98',
paleturquoise: '#AFEEEE',
palevioletred: '#DB7093',
papayawhip: '#FFEFD5',
peachpuff: '#FFDAB9',
peru: '#CD853F',
pink: '#FFC0CB',
plum: '#DDA0DD',
powderblue: '#B0E0E6',
rosybrown: '#BC8F8F',
royalblue: '#4169E1',
saddlebrown: '#8B4513',
salmon: '#FA8072',
sandybrown: '#F4A460',
seagreen: '#2E8B57',
seashell: '#FFF5EE',
sienna: '#A0522D',
skyblue: '#87CEEB',
slateblue: '#6A5ACD',
slategray: '#708090',
slategrey: '#708090',
snow: '#FFFAFA',
springgreen: '#00FF7F',
steelblue: '#4682B4',
tan: '#D2B48C',
thistle: '#D8BFD8',
tomato: '#FF6347',
turquoise: '#40E0D0',
violet: '#EE82EE',
wheat: '#F5DEB3',
whitesmoke: '#F5F5F5',
yellowgreen: '#9ACD32'
};
function getRgbHslContent(styleString) {
var start = styleString.indexOf('(', 3);
var end = styleString.indexOf(')', start + 1);
var parts = styleString.substring(start + 1, end).split(',');
// add alpha if needed
if (parts.length != 4 || styleString.charAt(3) != 'a') {
parts[3] = 1;
}
return parts;
}
function percent(s) {
return parseFloat(s) / 100;
}
function clamp(v, min, max) {
return Math.min(max, Math.max(min, v));
}
function hslToRgb(parts){
var r, g, b, h, s, l;
h = parseFloat(parts[0]) / 360 % 360;
if (h < 0)
h++;
s = clamp(percent(parts[1]), 0, 1);
l = clamp(percent(parts[2]), 0, 1);
if (s == 0) {
r = g = b = l; // achromatic
} else {
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hueToRgb(p, q, h + 1 / 3);
g = hueToRgb(p, q, h);
b = hueToRgb(p, q, h - 1 / 3);
}
return '#' + decToHex[Math.floor(r * 255)] +
decToHex[Math.floor(g * 255)] +
decToHex[Math.floor(b * 255)];
}
function hueToRgb(m1, m2, h) {
if (h < 0)
h++;
if (h > 1)
h--;
if (6 * h < 1)
return m1 + (m2 - m1) * 6 * h;
else if (2 * h < 1)
return m2;
else if (3 * h < 2)
return m1 + (m2 - m1) * (2 / 3 - h) * 6;
else
return m1;
}
var processStyleCache = {};
function processStyle(styleString) {
if (styleString in processStyleCache) {
return processStyleCache[styleString];
}
var str, alpha = 1;
styleString = String(styleString);
if (styleString.charAt(0) == '#') {
str = styleString;
} else if (/^rgb/.test(styleString)) {
var parts = getRgbHslContent(styleString);
var str = '#', n;
for (var i = 0; i < 3; i++) {
if (parts[i].indexOf('%') != -1) {
n = Math.floor(percent(parts[i]) * 255);
} else {
n = +parts[i];
}
str += decToHex[clamp(n, 0, 255)];
}
alpha = +parts[3];
} else if (/^hsl/.test(styleString)) {
var parts = getRgbHslContent(styleString);
str = hslToRgb(parts);
alpha = parts[3];
} else {
str = colorData[styleString] || styleString;
}
return processStyleCache[styleString] = {color: str, alpha: alpha};
}
var DEFAULT_STYLE = {
style: 'normal',
variant: 'normal',
weight: 'normal',
size: 10,
family: 'sans-serif'
};
// Internal text style cache
var fontStyleCache = {};
function processFontStyle(styleString) {
if (fontStyleCache[styleString]) {
return fontStyleCache[styleString];
}
var el = document.createElement('div');
var style = el.style;
try {
style.font = styleString;
} catch (ex) {
// Ignore failures to set to invalid font.
}
return fontStyleCache[styleString] = {
style: style.fontStyle || DEFAULT_STYLE.style,
variant: style.fontVariant || DEFAULT_STYLE.variant,
weight: style.fontWeight || DEFAULT_STYLE.weight,
size: style.fontSize || DEFAULT_STYLE.size,
family: style.fontFamily || DEFAULT_STYLE.family
};
}
function getComputedStyle(style, element) {
var computedStyle = {};
for (var p in style) {
computedStyle[p] = style[p];
}
// Compute the size
var canvasFontSize = parseFloat(element.currentStyle.fontSize),
fontSize = parseFloat(style.size);
if (typeof style.size == 'number') {
computedStyle.size = style.size;
} else if (style.size.indexOf('px') != -1) {
computedStyle.size = fontSize;
} else if (style.size.indexOf('em') != -1) {
computedStyle.size = canvasFontSize * fontSize;
} else if(style.size.indexOf('%') != -1) {
computedStyle.size = (canvasFontSize / 100) * fontSize;
} else if (style.size.indexOf('pt') != -1) {
computedStyle.size = fontSize / .75;
} else {
computedStyle.size = canvasFontSize;
}
// Different scaling between normal text and VML text. This was found using
// trial and error to get the same size as non VML text.
computedStyle.size *= 0.981;
return computedStyle;
}
function buildStyle(style) {
return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
style.size + 'px ' + style.family;
}
var lineCapMap = {
'butt': 'flat',
'round': 'round'
};
function processLineCap(lineCap) {
return lineCapMap[lineCap] || 'square';
}
/**
* This class implements CanvasRenderingContext2D interface as described by
* the WHATWG.
* @param {HTMLElement} canvasElement The element that the 2D context should
* be associated with
*/
function CanvasRenderingContext2D_(canvasElement) {
this.m_ = createMatrixIdentity();
this.mStack_ = [];
this.aStack_ = [];
this.currentPath_ = [];
// Canvas context properties
this.strokeStyle = '#000';
this.fillStyle = '#000';
this.lineWidth = 1;
this.lineJoin = 'miter';
this.lineCap = 'butt';
this.miterLimit = Z * 1;
this.globalAlpha = 1;
this.font = '10px sans-serif';
this.textAlign = 'left';
this.textBaseline = 'alphabetic';
this.canvas = canvasElement;
var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
var el = canvasElement.ownerDocument.createElement('div');
el.style.cssText = cssText;
canvasElement.appendChild(el);
var overlayEl = el.cloneNode(false);
// Use a non transparent background.
overlayEl.style.backgroundColor = 'red';
overlayEl.style.filter = 'alpha(opacity=0)';
canvasElement.appendChild(overlayEl);
this.element_ = el;
this.arcScaleX_ = 1;
this.arcScaleY_ = 1;
this.lineScale_ = 1;
}
var contextPrototype = CanvasRenderingContext2D_.prototype;
contextPrototype.clearRect = function() {
if (this.textMeasureEl_) {
this.textMeasureEl_.removeNode(true);
this.textMeasureEl_ = null;
}
this.element_.innerHTML = '';
};
contextPrototype.beginPath = function() {
// TODO: Branch current matrix so that save/restore has no effect
// as per safari docs.
this.currentPath_ = [];
};
contextPrototype.moveTo = function(aX, aY) {
var p = getCoords(this, aX, aY);
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
this.currentX_ = p.x;
this.currentY_ = p.y;
};
contextPrototype.lineTo = function(aX, aY) {
var p = getCoords(this, aX, aY);
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
this.currentX_ = p.x;
this.currentY_ = p.y;
};
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
aCP2x, aCP2y,
aX, aY) {
var p = getCoords(this, aX, aY);
var cp1 = getCoords(this, aCP1x, aCP1y);
var cp2 = getCoords(this, aCP2x, aCP2y);
bezierCurveTo(this, cp1, cp2, p);
};
// Helper function that takes the already fixed cordinates.
function bezierCurveTo(self, cp1, cp2, p) {
self.currentPath_.push({
type: 'bezierCurveTo',
cp1x: cp1.x,
cp1y: cp1.y,
cp2x: cp2.x,
cp2y: cp2.y,
x: p.x,
y: p.y
});
self.currentX_ = p.x;
self.currentY_ = p.y;
}
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
// the following is lifted almost directly from
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
var cp = getCoords(this, aCPx, aCPy);
var p = getCoords(this, aX, aY);
var cp1 = {
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
};
var cp2 = {
x: cp1.x + (p.x - this.currentX_) / 3.0,
y: cp1.y + (p.y - this.currentY_) / 3.0
};
bezierCurveTo(this, cp1, cp2, p);
};
contextPrototype.arc = function(aX, aY, aRadius,
aStartAngle, aEndAngle, aClockwise) {
aRadius *= Z;
var arcType = aClockwise ? 'at' : 'wa';
var xStart = aX + mc(aStartAngle) * aRadius - Z2;
var yStart = aY + ms(aStartAngle) * aRadius - Z2;
var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
// IE won't render arches drawn counter clockwise if xStart == xEnd.
if (xStart == xEnd && !aClockwise) {
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
// that can be represented in binary
}
var p = getCoords(this, aX, aY);
var pStart = getCoords(this, xStart, yStart);
var pEnd = getCoords(this, xEnd, yEnd);
this.currentPath_.push({type: arcType,
x: p.x,
y: p.y,
radius: aRadius,
xStart: pStart.x,
yStart: pStart.y,
xEnd: pEnd.x,
yEnd: pEnd.y});
};
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
};
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
var oldPath = this.currentPath_;
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.stroke();
this.currentPath_ = oldPath;
};
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
var oldPath = this.currentPath_;
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.fill();
this.currentPath_ = oldPath;
};
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
var gradient = new CanvasGradient_('gradient');
gradient.x0_ = aX0;
gradient.y0_ = aY0;
gradient.x1_ = aX1;
gradient.y1_ = aY1;
return gradient;
};
contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
aX1, aY1, aR1) {
var gradient = new CanvasGradient_('gradientradial');
gradient.x0_ = aX0;
gradient.y0_ = aY0;
gradient.r0_ = aR0;