Commit f6cebd3f authored by Ole Laursen's avatar Ole Laursen

Update excanvas and remove previous eventholder work-around to fix hover/click...

Update excanvas and remove previous eventholder work-around to fix hover/click bug in IE 8 (test case by Ara Anjargolian); add support for setting the redraw overlay period and set it to 60 frames/s
parent 9f060ec8
...@@ -679,6 +679,10 @@ Customizing the grid ...@@ -679,6 +679,10 @@ Customizing the grid
mouseActiveRadius: number mouseActiveRadius: number
} }
interaction: {
redrawOverlayInterval: number or -1
}
The grid is the thing with the axes and a number of ticks. Many of the The grid is the thing with the axes and a number of ticks. Many of the
things in the grid are configured under the individual axes, but not things in the grid are configured under the individual axes, but not
all. "color" is the color of the grid itself whereas "backgroundColor" all. "color" is the color of the grid itself whereas "backgroundColor"
...@@ -798,6 +802,11 @@ If you want to disable interactivity for a specific data series, you ...@@ -798,6 +802,11 @@ If you want to disable interactivity for a specific data series, you
can set "hoverable" and "clickable" to false in the options for that can set "hoverable" and "clickable" to false in the options for that
series, like this { data: [...], label: "Foo", clickable: false }. series, like this { data: [...], label: "Foo", clickable: false }.
"redrawOverlayInterval" specifies the maximum time to delay a redraw
of interactive things (this works as a rate limiting device). The
default is capped to 60 frames per second. You can set it to -1 to
disable the rate limiting.
Specifying gradients Specifying gradients
==================== ====================
......
...@@ -49,6 +49,8 @@ if (!document.createElement('canvas').getContext) { ...@@ -49,6 +49,8 @@ if (!document.createElement('canvas').getContext) {
var Z = 10; var Z = 10;
var Z2 = Z / 2; 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 funtion is assigned to the <canvas> elements as element.getContext().
* @this {HTMLElement} * @this {HTMLElement}
...@@ -88,18 +90,16 @@ if (!document.createElement('canvas').getContext) { ...@@ -88,18 +90,16 @@ if (!document.createElement('canvas').getContext) {
return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;'); return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
} }
function addNamespacesAndStylesheet(doc) { function addNamespace(doc, prefix, urn) {
// create xmlns if (!doc.namespaces[prefix]) {
if (!doc.namespaces['g_vml_']) { doc.namespaces.add(prefix, urn, '#default#VML');
doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
'#default#VML');
} }
if (!doc.namespaces['g_o_']) {
doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
'#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 // Setup default CSS. Only add one style sheet per document
if (!doc.styleSheets['ex_canvas_']) { if (!doc.styleSheets['ex_canvas_']) {
var ss = doc.createStyleSheet(); var ss = doc.createStyleSheet();
...@@ -115,13 +115,11 @@ if (!document.createElement('canvas').getContext) { ...@@ -115,13 +115,11 @@ if (!document.createElement('canvas').getContext) {
var G_vmlCanvasManager_ = { var G_vmlCanvasManager_ = {
init: function(opt_doc) { init: function(opt_doc) {
if (/MSIE/.test(navigator.userAgent) && !window.opera) {
var doc = opt_doc || document; var doc = opt_doc || document;
// Create a dummy element so that IE will allow canvas elements to be // Create a dummy element so that IE will allow canvas elements to be
// recognized. // recognized.
doc.createElement('canvas'); doc.createElement('canvas');
doc.attachEvent('onreadystatechange', bind(this.init_, this, doc)); doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
}
}, },
init_: function(doc) { init_: function(doc) {
...@@ -398,9 +396,7 @@ if (!document.createElement('canvas').getContext) { ...@@ -398,9 +396,7 @@ if (!document.createElement('canvas').getContext) {
var end = styleString.indexOf(')', start + 1); var end = styleString.indexOf(')', start + 1);
var parts = styleString.substring(start + 1, end).split(','); var parts = styleString.substring(start + 1, end).split(',');
// add alpha if needed // add alpha if needed
if (parts.length == 4 && styleString.substr(3, 1) == 'a') { if (parts.length != 4 || styleString.charAt(3) != 'a') {
alpha = Number(parts[3]);
} else {
parts[3] = 1; parts[3] = 1;
} }
return parts; return parts;
...@@ -415,7 +411,7 @@ if (!document.createElement('canvas').getContext) { ...@@ -415,7 +411,7 @@ if (!document.createElement('canvas').getContext) {
} }
function hslToRgb(parts){ function hslToRgb(parts){
var r, g, b; var r, g, b, h, s, l;
h = parseFloat(parts[0]) / 360 % 360; h = parseFloat(parts[0]) / 360 % 360;
if (h < 0) if (h < 0)
h++; h++;
...@@ -452,7 +448,13 @@ if (!document.createElement('canvas').getContext) { ...@@ -452,7 +448,13 @@ if (!document.createElement('canvas').getContext) {
return m1; return m1;
} }
var processStyleCache = {};
function processStyle(styleString) { function processStyle(styleString) {
if (styleString in processStyleCache) {
return processStyleCache[styleString];
}
var str, alpha = 1; var str, alpha = 1;
styleString = String(styleString); styleString = String(styleString);
...@@ -465,11 +467,11 @@ if (!document.createElement('canvas').getContext) { ...@@ -465,11 +467,11 @@ if (!document.createElement('canvas').getContext) {
if (parts[i].indexOf('%') != -1) { if (parts[i].indexOf('%') != -1) {
n = Math.floor(percent(parts[i]) * 255); n = Math.floor(percent(parts[i]) * 255);
} else { } else {
n = Number(parts[i]); n = +parts[i];
} }
str += decToHex[clamp(n, 0, 255)]; str += decToHex[clamp(n, 0, 255)];
} }
alpha = parts[3]; alpha = +parts[3];
} else if (/^hsl/.test(styleString)) { } else if (/^hsl/.test(styleString)) {
var parts = getRgbHslContent(styleString); var parts = getRgbHslContent(styleString);
str = hslToRgb(parts); str = hslToRgb(parts);
...@@ -477,7 +479,7 @@ if (!document.createElement('canvas').getContext) { ...@@ -477,7 +479,7 @@ if (!document.createElement('canvas').getContext) {
} else { } else {
str = colorData[styleString] || styleString; str = colorData[styleString] || styleString;
} }
return {color: str, alpha: alpha}; return processStyleCache[styleString] = {color: str, alpha: alpha};
} }
var DEFAULT_STYLE = { var DEFAULT_STYLE = {
...@@ -550,25 +552,22 @@ if (!document.createElement('canvas').getContext) { ...@@ -550,25 +552,22 @@ if (!document.createElement('canvas').getContext) {
style.size + 'px ' + style.family; style.size + 'px ' + style.family;
} }
var lineCapMap = {
'butt': 'flat',
'round': 'round'
};
function processLineCap(lineCap) { function processLineCap(lineCap) {
switch (lineCap) { return lineCapMap[lineCap] || 'square';
case 'butt':
return 'flat';
case 'round':
return 'round';
case 'square':
default:
return 'square';
}
} }
/** /**
* This class implements CanvasRenderingContext2D interface as described by * This class implements CanvasRenderingContext2D interface as described by
* the WHATWG. * the WHATWG.
* @param {HTMLElement} surfaceElement The element that the 2D context should * @param {HTMLElement} canvasElement The element that the 2D context should
* be associated with * be associated with
*/ */
function CanvasRenderingContext2D_(surfaceElement) { function CanvasRenderingContext2D_(canvasElement) {
this.m_ = createMatrixIdentity(); this.m_ = createMatrixIdentity();
this.mStack_ = []; this.mStack_ = [];
...@@ -587,14 +586,19 @@ if (!document.createElement('canvas').getContext) { ...@@ -587,14 +586,19 @@ if (!document.createElement('canvas').getContext) {
this.font = '10px sans-serif'; this.font = '10px sans-serif';
this.textAlign = 'left'; this.textAlign = 'left';
this.textBaseline = 'alphabetic'; this.textBaseline = 'alphabetic';
this.canvas = surfaceElement; 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 el = surfaceElement.ownerDocument.createElement('div'); var overlayEl = el.cloneNode(false);
el.style.width = surfaceElement.clientWidth + 'px'; // Use a non transparent background.
el.style.height = surfaceElement.clientHeight + 'px'; overlayEl.style.backgroundColor = 'red';
el.style.overflow = 'hidden'; overlayEl.style.filter = 'alpha(opacity=0)';
el.style.position = 'absolute'; canvasElement.appendChild(overlayEl);
surfaceElement.appendChild(el);
this.element_ = el; this.element_ = el;
this.arcScaleX_ = 1; this.arcScaleX_ = 1;
...@@ -618,14 +622,14 @@ if (!document.createElement('canvas').getContext) { ...@@ -618,14 +622,14 @@ if (!document.createElement('canvas').getContext) {
}; };
contextPrototype.moveTo = function(aX, aY) { contextPrototype.moveTo = function(aX, aY) {
var p = this.getCoords_(aX, aY); var p = getCoords(this, aX, aY);
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y}); this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
this.currentX_ = p.x; this.currentX_ = p.x;
this.currentY_ = p.y; this.currentY_ = p.y;
}; };
contextPrototype.lineTo = function(aX, aY) { contextPrototype.lineTo = function(aX, aY) {
var p = this.getCoords_(aX, aY); var p = getCoords(this, aX, aY);
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y}); this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
this.currentX_ = p.x; this.currentX_ = p.x;
...@@ -635,9 +639,9 @@ if (!document.createElement('canvas').getContext) { ...@@ -635,9 +639,9 @@ if (!document.createElement('canvas').getContext) {
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y, contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
aCP2x, aCP2y, aCP2x, aCP2y,
aX, aY) { aX, aY) {
var p = this.getCoords_(aX, aY); var p = getCoords(this, aX, aY);
var cp1 = this.getCoords_(aCP1x, aCP1y); var cp1 = getCoords(this, aCP1x, aCP1y);
var cp2 = this.getCoords_(aCP2x, aCP2y); var cp2 = getCoords(this, aCP2x, aCP2y);
bezierCurveTo(this, cp1, cp2, p); bezierCurveTo(this, cp1, cp2, p);
}; };
...@@ -660,8 +664,8 @@ if (!document.createElement('canvas').getContext) { ...@@ -660,8 +664,8 @@ if (!document.createElement('canvas').getContext) {
// the following is lifted almost directly from // the following is lifted almost directly from
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
var cp = this.getCoords_(aCPx, aCPy); var cp = getCoords(this, aCPx, aCPy);
var p = this.getCoords_(aX, aY); var p = getCoords(this, aX, aY);
var cp1 = { var cp1 = {
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_), x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
...@@ -692,9 +696,9 @@ if (!document.createElement('canvas').getContext) { ...@@ -692,9 +696,9 @@ if (!document.createElement('canvas').getContext) {
// that can be represented in binary // that can be represented in binary
} }
var p = this.getCoords_(aX, aY); var p = getCoords(this, aX, aY);
var pStart = this.getCoords_(xStart, yStart); var pStart = getCoords(this, xStart, yStart);
var pEnd = this.getCoords_(xEnd, yEnd); var pEnd = getCoords(this, xEnd, yEnd);
this.currentPath_.push({type: arcType, this.currentPath_.push({type: arcType,
x: p.x, x: p.x,
...@@ -808,7 +812,7 @@ if (!document.createElement('canvas').getContext) { ...@@ -808,7 +812,7 @@ if (!document.createElement('canvas').getContext) {
throw Error('Invalid number of arguments'); throw Error('Invalid number of arguments');
} }
var d = this.getCoords_(dx, dy); var d = getCoords(this, dx, dy);
var w2 = sw / 2; var w2 = sw / 2;
var h2 = sh / 2; var h2 = sh / 2;
...@@ -844,9 +848,9 @@ if (!document.createElement('canvas').getContext) { ...@@ -844,9 +848,9 @@ if (!document.createElement('canvas').getContext) {
// Bounding box calculation (need to minimize displayed area so that // Bounding box calculation (need to minimize displayed area so that
// filters don't waste time on unused pixels. // filters don't waste time on unused pixels.
var max = d; var max = d;
var c2 = this.getCoords_(dx + dw, dy); var c2 = getCoords(this, dx + dw, dy);
var c3 = this.getCoords_(dx, dy + dh); var c3 = getCoords(this, dx, dy + dh);
var c4 = this.getCoords_(dx + dw, dy + dh); var c4 = getCoords(this, dx + dw, dy + dh);
max.x = m.max(max.x, c2.x, c3.x, c4.x); max.x = m.max(max.x, c2.x, c3.x, c4.x);
max.y = m.max(max.y, c2.y, c3.y, c4.y); max.y = m.max(max.y, c2.y, c3.y, c4.y);
...@@ -1015,8 +1019,8 @@ if (!document.createElement('canvas').getContext) { ...@@ -1015,8 +1019,8 @@ if (!document.createElement('canvas').getContext) {
var y0 = fillStyle.y0_ / arcScaleY; var y0 = fillStyle.y0_ / arcScaleY;
var x1 = fillStyle.x1_ / arcScaleX; var x1 = fillStyle.x1_ / arcScaleX;
var y1 = fillStyle.y1_ / arcScaleY; var y1 = fillStyle.y1_ / arcScaleY;
var p0 = ctx.getCoords_(x0, y0); var p0 = getCoords(ctx, x0, y0);
var p1 = ctx.getCoords_(x1, y1); var p1 = getCoords(ctx, x1, y1);
var dx = p1.x - p0.x; var dx = p1.x - p0.x;
var dy = p1.y - p0.y; var dy = p1.y - p0.y;
angle = Math.atan2(dx, dy) * 180 / Math.PI; angle = Math.atan2(dx, dy) * 180 / Math.PI;
...@@ -1032,7 +1036,7 @@ if (!document.createElement('canvas').getContext) { ...@@ -1032,7 +1036,7 @@ if (!document.createElement('canvas').getContext) {
angle = 0; angle = 0;
} }
} else { } else {
var p0 = ctx.getCoords_(fillStyle.x0_, fillStyle.y0_); var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
focus = { focus = {
x: (p0.x - min.x) / width, x: (p0.x - min.x) / width,
y: (p0.y - min.y) / height y: (p0.y - min.y) / height
...@@ -1105,11 +1109,8 @@ if (!document.createElement('canvas').getContext) { ...@@ -1105,11 +1109,8 @@ if (!document.createElement('canvas').getContext) {
this.currentPath_.push({type: 'close'}); this.currentPath_.push({type: 'close'});
}; };
/** function getCoords(ctx, aX, aY) {
* @private var m = ctx.m_;
*/
contextPrototype.getCoords_ = function(aX, aY) {
var m = this.m_;
return { return {
x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2, x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2 y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
...@@ -1270,7 +1271,7 @@ if (!document.createElement('canvas').getContext) { ...@@ -1270,7 +1271,7 @@ if (!document.createElement('canvas').getContext) {
break; break;
} }
var d = this.getCoords_(x + offset.x, y + offset.y); var d = getCoords(this, x + offset.x, y + offset.y);
lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ', lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
' coordsize="100 100" coordorigin="0 0"', ' coordsize="100 100" coordorigin="0 0"',
......
This diff is collapsed.
...@@ -764,9 +764,8 @@ ...@@ -764,9 +764,8 @@
ctx = canvas.getContext("2d"); ctx = canvas.getContext("2d");
octx = overlay.getContext("2d"); octx = overlay.getContext("2d");
// we include the canvas in the event holder too, because IE 7 // define which element we're listening for events on
// sometimes has trouble with the stacking order eventHolder = $(overlay);
eventHolder = $([overlay, canvas]);
if (reused) { if (reused) {
// run shutdown in the old plot object // run shutdown in the old plot object
...@@ -2434,7 +2433,7 @@ ...@@ -2434,7 +2433,7 @@
function triggerRedrawOverlay() { function triggerRedrawOverlay() {
if (!redrawTimeout) if (!redrawTimeout)
redrawTimeout = setTimeout(drawOverlay, 30); redrawTimeout = setTimeout(drawOverlay, 1000/60);
} }
function drawOverlay() { function drawOverlay() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment