Comparing version 3.1.0 to 3.1.1
@@ -16,10 +16,3 @@ 'use strict'; | ||
var requestAnimationFrame = (typeof window !== 'undefined' && | ||
(window.requestAnimationFrame | ||
|| window.msRequestAnimationFrame | ||
|| window.mozRequestAnimationFrame | ||
|| window.webkitRequestAnimationFrame)) | ||
|| function (func) { | ||
setTimeout(func, 16); | ||
}; | ||
var requestAnimationFrame = require('./requestAnimationFrame'); | ||
@@ -26,0 +19,0 @@ var Animator = require('./Animator'); |
@@ -319,2 +319,3 @@ /** | ||
// Start from next key | ||
// PENDING start from lastFrame ? | ||
start = Math.min(lastFrame + 1, trackLen - 1); | ||
@@ -326,2 +327,3 @@ for (frame = start; frame >= 0; frame--) { | ||
} | ||
// PENDING really need to do this ? | ||
frame = Math.min(frame, trackLen - 2); | ||
@@ -328,0 +330,0 @@ } |
@@ -52,2 +52,6 @@ 'use strict'; | ||
var t = roots[i]; | ||
// Avoid winding error when intersection point is the connect point of two line of polygon | ||
var unit = (t === 0 || t === 1) ? 0.5 : 1; | ||
var x_ = curve.cubicAt(x0, x1, x2, x3, t); | ||
@@ -70,9 +74,9 @@ if (x_ < x) { // Quick reject | ||
if (t < extrema[0]) { | ||
w += y0_ < y0 ? 1 : -1; | ||
w += y0_ < y0 ? unit : -unit; | ||
} | ||
else if (t < extrema[1]) { | ||
w += y1_ < y0_ ? 1 : -1; | ||
w += y1_ < y0_ ? unit : -unit; | ||
} | ||
else { | ||
w += y3 < y1_ ? 1 : -1; | ||
w += y3 < y1_ ? unit : -unit; | ||
} | ||
@@ -83,6 +87,6 @@ } | ||
if (t < extrema[0]) { | ||
w += y0_ < y0 ? 1 : -1; | ||
w += y0_ < y0 ? unit : -unit; | ||
} | ||
else { | ||
w += y3 < y0_ ? 1 : -1; | ||
w += y3 < y0_ ? unit : -unit; | ||
} | ||
@@ -113,2 +117,5 @@ } | ||
for (var i = 0; i < nRoots; i++) { | ||
// Remove one endpoint. | ||
var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1; | ||
var x_ = curve.quadraticAt(x0, x1, x2, roots[i]); | ||
@@ -119,6 +126,6 @@ if (x_ < x) { // Quick reject | ||
if (roots[i] < t) { | ||
w += y_ < y0 ? 1 : -1; | ||
w += y_ < y0 ? unit : -unit; | ||
} | ||
else { | ||
w += y2 < y_ ? 1 : -1; | ||
w += y2 < y_ ? unit : -unit; | ||
} | ||
@@ -129,2 +136,5 @@ } | ||
else { | ||
// Remove one endpoint. | ||
var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1; | ||
var x_ = curve.quadraticAt(x0, x1, x2, roots[0]); | ||
@@ -134,3 +144,3 @@ if (x_ < x) { // Quick reject | ||
} | ||
return y2 < y0 ? 1 : -1; | ||
return y2 < y0 ? unit : -unit; | ||
} | ||
@@ -221,5 +231,5 @@ } | ||
// 如果被任何一个 subpath 包含 | ||
if (w !== 0) { | ||
return true; | ||
} | ||
// if (w !== 0) { | ||
// return true; | ||
// } | ||
} | ||
@@ -351,3 +361,3 @@ | ||
|| containStroke(x1, y1, x0, y1, lineWidth, x, y) | ||
|| containStroke(x0, y1, x1, y1, lineWidth, x, y) | ||
|| containStroke(x0, y1, x0, y0, lineWidth, x, y) | ||
) { | ||
@@ -375,5 +385,6 @@ return true; | ||
// 如果被任何一个 subpath 包含 | ||
if (w !== 0) { | ||
return true; | ||
} | ||
// FIXME subpaths may overlap | ||
// if (w !== 0) { | ||
// return true; | ||
// } | ||
} | ||
@@ -380,0 +391,0 @@ xi = x0; |
@@ -6,2 +6,3 @@ | ||
} | ||
// Ignore horizontal line | ||
if (y1 === y0) { | ||
@@ -12,2 +13,8 @@ return 0; | ||
var t = (y - y0) / (y1 - y0); | ||
// Avoid winding error when intersection point is the connect point of two line of polygon | ||
if (t === 1 || t === 0) { | ||
dir = y1 < y0 ? 0.5 : -0.5; | ||
} | ||
var x_ = t * (x1 - x0) + x0; | ||
@@ -14,0 +21,0 @@ |
@@ -52,2 +52,4 @@ /** | ||
isGroup: true, | ||
/** | ||
@@ -54,0 +56,0 @@ * @type {string} |
@@ -33,19 +33,19 @@ /** | ||
var browser = {}; | ||
var webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/); | ||
var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); | ||
var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); | ||
var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); | ||
var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/); | ||
var webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/); | ||
var touchpad = webos && ua.match(/TouchPad/); | ||
var kindle = ua.match(/Kindle\/([\d.]+)/); | ||
var silk = ua.match(/Silk\/([\d._]+)/); | ||
var blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/); | ||
var bb10 = ua.match(/(BB10).*Version\/([\d.]+)/); | ||
var rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/); | ||
var playbook = ua.match(/PlayBook/); | ||
var chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/); | ||
var firefox = ua.match(/Firefox\/([\d.]+)/); | ||
var safari = webkit && ua.match(/Mobile\//) && !chrome; | ||
var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome; | ||
// var webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/); | ||
// var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); | ||
// var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); | ||
// var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); | ||
// var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/); | ||
// var webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/); | ||
// var touchpad = webos && ua.match(/TouchPad/); | ||
// var kindle = ua.match(/Kindle\/([\d.]+)/); | ||
// var silk = ua.match(/Silk\/([\d._]+)/); | ||
// var blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/); | ||
// var bb10 = ua.match(/(BB10).*Version\/([\d.]+)/); | ||
// var rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/); | ||
// var playbook = ua.match(/PlayBook/); | ||
// var chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/); | ||
// var firefox = ua.match(/Firefox\/([\d.]+)/); | ||
// var safari = webkit && ua.match(/Mobile\//) && !chrome; | ||
// var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome; | ||
var ie = ua.match(/MSIE\s([\d.]+)/) | ||
@@ -62,30 +62,38 @@ // IE 11 Trident/7.0; rv:11.0 | ||
if (browser.webkit = !!webkit) browser.version = webkit[1]; | ||
// if (browser.webkit = !!webkit) browser.version = webkit[1]; | ||
if (android) os.android = true, os.version = android[2]; | ||
if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.'); | ||
if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.'); | ||
if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null; | ||
if (webos) os.webos = true, os.version = webos[2]; | ||
if (touchpad) os.touchpad = true; | ||
if (blackberry) os.blackberry = true, os.version = blackberry[2]; | ||
if (bb10) os.bb10 = true, os.version = bb10[2]; | ||
if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2]; | ||
if (playbook) browser.playbook = true; | ||
if (kindle) os.kindle = true, os.version = kindle[1]; | ||
if (silk) browser.silk = true, browser.version = silk[1]; | ||
if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true; | ||
if (chrome) browser.chrome = true, browser.version = chrome[1]; | ||
if (firefox) browser.firefox = true, browser.version = firefox[1]; | ||
if (ie) browser.ie = true, browser.version = ie[1]; | ||
if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true; | ||
if (webview) browser.webview = true; | ||
if (ie) browser.ie = true, browser.version = ie[1]; | ||
if (edge) browser.edge = true, browser.version = edge[1]; | ||
// if (android) os.android = true, os.version = android[2]; | ||
// if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.'); | ||
// if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.'); | ||
// if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null; | ||
// if (webos) os.webos = true, os.version = webos[2]; | ||
// if (touchpad) os.touchpad = true; | ||
// if (blackberry) os.blackberry = true, os.version = blackberry[2]; | ||
// if (bb10) os.bb10 = true, os.version = bb10[2]; | ||
// if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2]; | ||
// if (playbook) browser.playbook = true; | ||
// if (kindle) os.kindle = true, os.version = kindle[1]; | ||
// if (silk) browser.silk = true, browser.version = silk[1]; | ||
// if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true; | ||
// if (chrome) browser.chrome = true, browser.version = chrome[1]; | ||
// if (firefox) browser.firefox = true, browser.version = firefox[1]; | ||
// if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true; | ||
// if (webview) browser.webview = true; | ||
if (ie) { | ||
browser.ie = true; browser.version = ie[1]; | ||
} | ||
if (ie) { | ||
browser.ie = true; | ||
browser.version = ie[1]; | ||
} | ||
if (edge) { | ||
browser.edge = true; | ||
browser.version = edge[1]; | ||
} | ||
os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || | ||
(firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/))); | ||
os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos || blackberry || bb10 || | ||
(chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || | ||
(firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/)))); | ||
// os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || | ||
// (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/))); | ||
// os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos || | ||
// (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || | ||
// (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/)))); | ||
@@ -92,0 +100,0 @@ return { |
@@ -15,4 +15,14 @@ 'use strict'; | ||
// BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect | ||
return el.getBoundingClientRect ? el.getBoundingClientRect() : { left: 0, top: 0}; | ||
return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0}; | ||
} | ||
function clientToLocal(el, e, out) { | ||
// clientX/clientY is according to view port. | ||
var box = getBoundingClientRect(el); | ||
out = out || {}; | ||
out.zrX = e.clientX - box.left; | ||
out.zrY = e.clientY - box.top; | ||
return out; | ||
} | ||
/** | ||
@@ -33,5 +43,3 @@ * 如果存在第三方嵌入的一些dom触发的事件,或touch事件,需要转换一下事件坐标 | ||
if (!isTouch) { | ||
var box = getBoundingClientRect(el); | ||
e.zrX = e.clientX - box.left; | ||
e.zrY = e.clientY - box.top; | ||
clientToLocal(el, e, e); | ||
e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3; | ||
@@ -41,10 +49,5 @@ } | ||
var touch = eventType != 'touchend' | ||
? e.targetTouches[0] | ||
: e.changedTouches[0]; | ||
if (touch) { | ||
var rBounding = getBoundingClientRect(el); | ||
// touch事件坐标是全屏的~ | ||
e.zrX = touch.clientX - rBounding.left; | ||
e.zrY = touch.clientY - rBounding.top; | ||
} | ||
? e.targetTouches[0] | ||
: e.changedTouches[0]; | ||
touch && clientToLocal(el, touch, e); | ||
} | ||
@@ -91,2 +94,3 @@ | ||
module.exports = { | ||
clientToLocal: clientToLocal, | ||
normalizeEvent: normalizeEvent, | ||
@@ -93,0 +97,0 @@ addEventListener: addEventListener, |
@@ -7,2 +7,4 @@ 'use strict'; | ||
var eventUtil = require('./event'); | ||
var GestureMgr = function () { | ||
@@ -21,4 +23,4 @@ | ||
recognize: function (event, target) { | ||
this._doTrack(event, target); | ||
recognize: function (event, target, root) { | ||
this._doTrack(event, target, root); | ||
return this._recognize(event); | ||
@@ -32,3 +34,3 @@ }, | ||
_doTrack: function (event, target) { | ||
_doTrack: function (event, target, root) { | ||
var touches = event.touches; | ||
@@ -49,3 +51,4 @@ | ||
var touch = touches[i]; | ||
trackItem.points.push([touch.clientX, touch.clientY]); | ||
var pos = eventUtil.clientToLocal(root, touch); | ||
trackItem.points.push([pos.zrX, pos.zrY]); | ||
trackItem.touches.push(touch); | ||
@@ -52,0 +55,0 @@ } |
@@ -8,7 +8,7 @@ /** | ||
var idStart = 0x0907; | ||
var idStart = 0x0907; | ||
module.exports = function () { | ||
return 'zr_' + (idStart++); | ||
}; | ||
module.exports = function () { | ||
return idStart++; | ||
}; | ||
@@ -150,3 +150,3 @@ 'use strict'; | ||
// Force draw the first segment | ||
|| this._len === 0; | ||
|| this._len < 5; | ||
@@ -427,3 +427,4 @@ this.addData(CMD.L, x, y); | ||
while ((dx >= 0 && x <= x1) || (dx < 0 && x > x1)) { | ||
while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1) | ||
|| (dx == 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) { | ||
idx = this._dashIdx; | ||
@@ -435,3 +436,3 @@ dash = lineDash[idx]; | ||
// Skip positive offset | ||
if ((dx > 0 && x < x0) || (dx < 0 && x > x0)) { | ||
if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) { | ||
continue; | ||
@@ -438,0 +439,0 @@ } |
@@ -5,3 +5,3 @@ /** | ||
var Gradient = require('../graphic/Gradient'); | ||
// 用于处理merge时无法遍历Date等对象的问题 | ||
@@ -13,3 +13,6 @@ var BUILTIN_OBJECT = { | ||
'[object Error]': 1, | ||
'[object CanvasGradient]': 1 | ||
'[object CanvasGradient]': 1, | ||
'[object CanvasPattern]': 1, | ||
// In node-canvas Image can be Canvas.Image | ||
'[object Image]': 1 | ||
}; | ||
@@ -411,4 +414,3 @@ | ||
function isBuildInObject(value) { | ||
return !!BUILTIN_OBJECT[objToString.call(value)] | ||
|| (value instanceof Gradient); | ||
return !!BUILTIN_OBJECT[objToString.call(value)]; | ||
} | ||
@@ -415,0 +417,0 @@ |
@@ -22,4 +22,10 @@ | ||
var out = new ArrayCtor(2); | ||
out[0] = x || 0; | ||
out[1] = y || 0; | ||
if (x == null) { | ||
x = 0; | ||
} | ||
if (y == null) { | ||
y = 0; | ||
} | ||
out[0] = x; | ||
out[1] = y; | ||
return out; | ||
@@ -26,0 +32,0 @@ }, |
@@ -98,3 +98,3 @@ 'use strict'; | ||
this.decomposeTransform(); | ||
this.dirty(); | ||
this.dirty(false); | ||
}, | ||
@@ -174,4 +174,5 @@ | ||
} | ||
this.dirty(); | ||
this.dirty(false); | ||
return this; | ||
@@ -198,3 +199,3 @@ }, | ||
this.dirty(); | ||
this.dirty(false); | ||
}, | ||
@@ -215,3 +216,3 @@ | ||
this.dirty(); | ||
this.dirty(false); | ||
} | ||
@@ -218,0 +219,0 @@ }, |
@@ -38,3 +38,3 @@ // CompoundPath to improve performance | ||
for (var i = 0; i < paths.length; i++) { | ||
paths[i].buildPath(ctx, paths[i].shape); | ||
paths[i].buildPath(ctx, paths[i].shape, true); | ||
} | ||
@@ -41,0 +41,0 @@ }, |
@@ -141,2 +141,9 @@ /** | ||
/** | ||
* Render the element progressively when the value >= 0, | ||
* usefull for large data. | ||
* @type {number} | ||
*/ | ||
progressive: -1, | ||
beforeBrush: function (ctx) {}, | ||
@@ -151,3 +158,3 @@ | ||
// Interface | ||
brush: function (ctx) {}, | ||
brush: function (ctx, prevEl) {}, | ||
@@ -154,0 +161,0 @@ /** |
@@ -31,3 +31,3 @@ /** | ||
brush: function (ctx) { | ||
brush: function (ctx, prevEl) { | ||
var style = this.style; | ||
@@ -37,2 +37,5 @@ var src = style.image; | ||
// Must bind each time | ||
style.bind(ctx, this, prevEl); | ||
// style.image is a url string | ||
@@ -97,6 +100,2 @@ if (typeof src === 'string') { | ||
ctx.save(); | ||
style.bind(ctx); | ||
// 设置transform | ||
@@ -145,2 +144,4 @@ this.setTransform(ctx); | ||
this.restoreTransform(ctx); | ||
// Draw rect text | ||
@@ -151,3 +152,2 @@ if (style.text != null) { | ||
ctx.restore(); | ||
} | ||
@@ -154,0 +154,0 @@ }, |
@@ -15,4 +15,5 @@ 'use strict'; | ||
* @param {Array.<Object>} colorStops | ||
* @param {boolean} [globalCoord=false] | ||
*/ | ||
var LinearGradient = function (x, y, x2, y2, colorStops) { | ||
var LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) { | ||
this.x = x == null ? 0 : x; | ||
@@ -26,2 +27,8 @@ | ||
// Can be cloned | ||
this.type = 'linear'; | ||
// If use global coord | ||
this.global = globalCoord || false; | ||
Gradient.call(this, colorStops); | ||
@@ -32,5 +39,3 @@ }; | ||
constructor: LinearGradient, | ||
type: 'linear' | ||
constructor: LinearGradient | ||
}; | ||
@@ -37,0 +42,0 @@ |
@@ -47,2 +47,6 @@ /** | ||
} | ||
// FIXME | ||
ctx.save(); | ||
var x; | ||
@@ -61,3 +65,2 @@ var y; | ||
var transform = this.transform; | ||
var invTransform = this.invTransform; | ||
if (transform) { | ||
@@ -67,4 +70,2 @@ tmpRect.copy(rect); | ||
rect = tmpRect; | ||
// Transform back | ||
setTransform(ctx, invTransform); | ||
} | ||
@@ -106,4 +107,6 @@ | ||
ctx.textAlign = align; | ||
ctx.textBaseline = baseline; | ||
// Use canvas default left textAlign. Giving invalid value will cause state not change | ||
ctx.textAlign = align || 'left'; | ||
// Use canvas default alphabetic baseline | ||
ctx.textBaseline = baseline || 'alphabetic'; | ||
@@ -117,4 +120,5 @@ var textFill = style.textFill; | ||
// Text shadow | ||
ctx.shadowColor = style.textShadowColor; | ||
// Always set shadowBlur and shadowOffset to avoid leak from displayable | ||
ctx.shadowBlur = style.textShadowBlur; | ||
ctx.shadowColor = style.textShadowColor || 'transparent'; | ||
ctx.shadowOffsetX = style.textShadowOffsetX; | ||
@@ -130,4 +134,3 @@ ctx.shadowOffsetY = style.textShadowOffsetY; | ||
// Transform again | ||
transform && setTransform(ctx, transform); | ||
ctx.restore(); | ||
} | ||
@@ -134,0 +137,0 @@ }; |
@@ -13,14 +13,5 @@ /** | ||
var Gradient = require('./Gradient'); | ||
var Pattern = require('./Pattern'); | ||
var getCanvasPattern = Pattern.prototype.getCanvasPattern; | ||
function pathHasFill(style) { | ||
var fill = style.fill; | ||
return fill != null && fill !== 'none'; | ||
} | ||
function pathHasStroke(style) { | ||
var stroke = style.stroke; | ||
return stroke != null && stroke !== 'none' && style.lineWidth > 0; | ||
} | ||
var abs = Math.abs; | ||
@@ -54,32 +45,41 @@ | ||
brush: function (ctx) { | ||
ctx.save(); | ||
brush: function (ctx, prevEl) { | ||
var style = this.style; | ||
var path = this.path; | ||
var hasStroke = pathHasStroke(style); | ||
var hasFill = pathHasFill(style); | ||
var hasFillGradient = hasFill && !!(style.fill.colorStops); | ||
var hasStrokeGradient = hasStroke && !!(style.stroke.colorStops); | ||
var hasStroke = style.hasStroke(); | ||
var hasFill = style.hasFill(); | ||
var fill = style.fill; | ||
var stroke = style.stroke; | ||
var hasFillGradient = hasFill && !!(fill.colorStops); | ||
var hasStrokeGradient = hasStroke && !!(stroke.colorStops); | ||
var hasFillPattern = hasFill && !!(fill.image); | ||
var hasStrokePattern = hasStroke && !!(stroke.image); | ||
style.bind(ctx, this); | ||
style.bind(ctx, this, prevEl); | ||
this.setTransform(ctx); | ||
if (this.__dirtyPath) { | ||
if (this.__dirty) { | ||
var rect = this.getBoundingRect(); | ||
// Update gradient because bounding rect may changed | ||
if (hasFillGradient) { | ||
this._fillGradient = style.getGradient(ctx, style.fill, rect); | ||
this._fillGradient = style.getGradient(ctx, fill, rect); | ||
} | ||
if (hasStrokeGradient) { | ||
this._strokeGradient = style.getGradient(ctx, style.stroke, rect); | ||
this._strokeGradient = style.getGradient(ctx, stroke, rect); | ||
} | ||
} | ||
// Use the gradient | ||
// Use the gradient or pattern | ||
if (hasFillGradient) { | ||
// PENDING If may have affect the state | ||
ctx.fillStyle = this._fillGradient; | ||
} | ||
else if (hasFillPattern) { | ||
ctx.fillStyle = getCanvasPattern.call(fill, ctx); | ||
} | ||
if (hasStrokeGradient) { | ||
ctx.strokeStyle = this._strokeGradient; | ||
} | ||
else if (hasStrokePattern) { | ||
ctx.strokeStyle = getCanvasPattern.call(stroke, ctx); | ||
} | ||
@@ -111,3 +111,3 @@ var lineDash = style.lineDash; | ||
this.buildPath(path, this.shape); | ||
this.buildPath(path, this.shape, false); | ||
@@ -132,12 +132,21 @@ // Clear path dirty flag | ||
if (lineDash && ctxLineDash) { | ||
// PENDING | ||
// Remove lineDash | ||
ctx.setLineDash([]); | ||
} | ||
this.restoreTransform(ctx); | ||
// Draw rect text | ||
if (style.text != null) { | ||
if (style.text || style.text === 0) { | ||
// var rect = this.getBoundingRect(); | ||
this.drawRectText(ctx, this.getBoundingRect()); | ||
} | ||
ctx.restore(); | ||
}, | ||
buildPath: function (ctx, shapeCfg) {}, | ||
// When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath | ||
// Like in circle | ||
buildPath: function (ctx, shapeCfg, inBundle) {}, | ||
@@ -152,3 +161,3 @@ getBoundingRect: function () { | ||
path.beginPath(); | ||
this.buildPath(path, this.shape); | ||
this.buildPath(path, this.shape, false); | ||
} | ||
@@ -159,3 +168,3 @@ rect = path.getBoundingRect(); | ||
if (pathHasStroke(style)) { | ||
if (style.hasStroke()) { | ||
// Needs update rect with stroke lineWidth when | ||
@@ -173,3 +182,3 @@ // 1. Element changes scale or lineWidth | ||
// Only add extra hover lineWidth when there are no fill | ||
if (!pathHasFill(style)) { | ||
if (!style.hasFill()) { | ||
w = Math.max(w, this.strokeContainThreshold); | ||
@@ -203,3 +212,3 @@ } | ||
var pathData = this.path.data; | ||
if (pathHasStroke(style)) { | ||
if (style.hasStroke()) { | ||
var lineWidth = style.lineWidth; | ||
@@ -210,3 +219,3 @@ var lineScale = style.strokeNoScale ? this.getLineScale() : 1; | ||
// Only add extra hover lineWidth when there are no fill | ||
if (!pathHasFill(style)) { | ||
if (!style.hasFill()) { | ||
lineWidth = Math.max(lineWidth, this.strokeContainThreshold); | ||
@@ -221,3 +230,3 @@ } | ||
} | ||
if (pathHasFill(style)) { | ||
if (style.hasFill()) { | ||
return pathContain.contain(pathData, x, y); | ||
@@ -233,3 +242,3 @@ } | ||
dirty: function (dirtyPath) { | ||
if (arguments.length ===0) { | ||
if (dirtyPath == null) { | ||
dirtyPath = true; | ||
@@ -266,2 +275,4 @@ } | ||
this.setShape(value); | ||
this.__dirtyPath = true; | ||
this._rect = null; | ||
} | ||
@@ -268,0 +279,0 @@ else { |
@@ -14,4 +14,5 @@ 'use strict'; | ||
* @param {Array.<Object>} [colorStops] | ||
* @param {boolean} [globalCoord=false] | ||
*/ | ||
var RadialGradient = function (x, y, r, colorStops) { | ||
var RadialGradient = function (x, y, r, colorStops, globalCoord) { | ||
this.x = x == null ? 0.5 : x; | ||
@@ -23,2 +24,8 @@ | ||
// Can be cloned | ||
this.type = 'radial'; | ||
// If use global coord | ||
this.global = globalCoord || false; | ||
Gradient.call(this, colorStops); | ||
@@ -29,5 +36,3 @@ }; | ||
constructor: RadialGradient, | ||
type: 'radial' | ||
constructor: RadialGradient | ||
}; | ||
@@ -34,0 +39,0 @@ |
@@ -10,3 +10,3 @@ 'use strict'; | ||
module.exports = require('../Path').extend({ | ||
type: 'circle', | ||
@@ -20,9 +20,14 @@ | ||
buildPath : function (ctx, shape) { | ||
buildPath : function (ctx, shape, inBundle) { | ||
// Better stroking in ShapeBundle | ||
ctx.moveTo(shape.cx + shape.r, shape.cy); | ||
// Always do it may have performence issue ( fill may be 2x more cost) | ||
if (inBundle) { | ||
ctx.moveTo(shape.cx + shape.r, shape.cy); | ||
} | ||
// Better stroking in ShapeBundle | ||
// ctx.moveTo(shape.cx + shape.r, shape.cy); | ||
ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true); | ||
return; | ||
} | ||
}); | ||
@@ -6,8 +6,10 @@ /** | ||
var STYLE_LIST_COMMON = [ | ||
'lineCap', 'lineJoin', 'miterLimit', | ||
'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'shadowColor' | ||
var STYLE_COMMON_PROPS = [ | ||
['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'], | ||
['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10] | ||
]; | ||
// var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4); | ||
// var LINE_PROPS = STYLE_COMMON_PROPS.slice(4); | ||
var Style = function (opts) { | ||
@@ -17,2 +19,41 @@ this.extendFrom(opts); | ||
function createLinearGradient(ctx, obj, rect) { | ||
// var size = | ||
var x = obj.x; | ||
var x2 = obj.x2; | ||
var y = obj.y; | ||
var y2 = obj.y2; | ||
if (!obj.global) { | ||
x = x * rect.width + rect.x; | ||
x2 = x2 * rect.width + rect.x; | ||
y = y * rect.height + rect.y; | ||
y2 = y2 * rect.height + rect.y; | ||
} | ||
var canvasGradient = ctx.createLinearGradient(x, y, x2, y2); | ||
return canvasGradient; | ||
} | ||
function createRadialGradient(ctx, obj, rect) { | ||
var width = rect.width; | ||
var height = rect.height; | ||
var min = Math.min(width, height); | ||
var x = obj.x; | ||
var y = obj.y; | ||
var r = obj.r; | ||
if (!obj.global) { | ||
x = x * width + rect.x; | ||
y = y * height + rect.y; | ||
r = r * min; | ||
} | ||
var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r); | ||
return canvasGradient; | ||
} | ||
Style.prototype = { | ||
@@ -134,16 +175,40 @@ | ||
/** | ||
* @type {string} | ||
* https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation | ||
*/ | ||
blend: null, | ||
/** | ||
* @param {CanvasRenderingContext2D} ctx | ||
*/ | ||
bind: function (ctx, el) { | ||
var fill = this.fill; | ||
var stroke = this.stroke; | ||
for (var i = 0; i < STYLE_LIST_COMMON.length; i++) { | ||
var styleName = STYLE_LIST_COMMON[i]; | ||
bind: function (ctx, el, prevEl) { | ||
var style = this; | ||
var prevStyle = prevEl && prevEl.style; | ||
var firstDraw = !prevStyle; | ||
if (this[styleName] != null) { | ||
ctx[styleName] = this[styleName]; | ||
for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) { | ||
var prop = STYLE_COMMON_PROPS[i]; | ||
var styleName = prop[0]; | ||
if (firstDraw || style[styleName] !== prevStyle[styleName]) { | ||
// FIXME Invalid property value will cause style leak from previous element. | ||
ctx[styleName] = style[styleName] || prop[1]; | ||
} | ||
} | ||
if (stroke != null) { | ||
var lineWidth = this.lineWidth; | ||
if ((firstDraw || style.fill !== prevStyle.fill)) { | ||
ctx.fillStyle = style.fill; | ||
} | ||
if ((firstDraw || style.stroke !== prevStyle.stroke)) { | ||
ctx.strokeStyle = style.stroke; | ||
} | ||
if ((firstDraw || style.opacity !== prevStyle.opacity)) { | ||
ctx.globalAlpha = style.opacity == null ? 1 : style.opacity; | ||
} | ||
if ((firstDraw || style.blend !== prevStyle.blend)) { | ||
ctx.globalCompositeOperation = style.blend || 'source-over'; | ||
} | ||
if (this.hasStroke()) { | ||
var lineWidth = style.lineWidth; | ||
ctx.lineWidth = lineWidth / ( | ||
@@ -153,13 +218,14 @@ (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1 | ||
} | ||
// Gradient will be created and set in Path#brush. So ignore it here | ||
if (fill != null && fill !== 'none' && !fill.colorStops) { | ||
ctx.fillStyle = fill; | ||
} | ||
if (stroke != null && stroke !== 'none' && !stroke.colorStops) { | ||
// Use canvas gradient if has | ||
ctx.strokeStyle = stroke; | ||
} | ||
this.opacity != null && (ctx.globalAlpha = this.opacity); | ||
}, | ||
hasFill: function () { | ||
var fill = this.fill; | ||
return fill != null && fill !== 'none'; | ||
}, | ||
hasStroke: function () { | ||
var stroke = this.stroke; | ||
return stroke != null && stroke !== 'none' && this.lineWidth > 0; | ||
}, | ||
/** | ||
@@ -207,31 +273,5 @@ * Extend from other style | ||
createLinearGradient: function (ctx, obj, rect) { | ||
// var size = | ||
var x = obj.x * rect.width + rect.x; | ||
var x2 = obj.x2 * rect.width + rect.x; | ||
var y = obj.y * rect.height + rect.y; | ||
var y2 = obj.y2 * rect.height + rect.y; | ||
var canvasGradient = ctx.createLinearGradient(x, y, x2, y2); | ||
return canvasGradient; | ||
}, | ||
createRadialGradient: function (ctx, obj, rect) { | ||
var width = rect.width; | ||
var height = rect.height; | ||
var min = Math.min(width, height); | ||
var x = obj.x * width + rect.x; | ||
var y = obj.y * height + rect.y; | ||
var r = obj.r * min; | ||
var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r); | ||
return canvasGradient; | ||
}, | ||
getGradient: function (ctx, obj, rect) { | ||
var method = obj.type === 'radial' ? 'createRadialGradient' : 'createLinearGradient'; | ||
var canvasGradient = this[method](ctx, obj, rect); | ||
var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient; | ||
var canvasGradient = method(ctx, obj, rect); | ||
var colorStops = obj.colorStops; | ||
@@ -248,11 +288,12 @@ for (var i = 0; i < colorStops.length; i++) { | ||
var styleProto = Style.prototype; | ||
var name; | ||
var i; | ||
for (i = 0; i < STYLE_LIST_COMMON.length; i++) { | ||
name = STYLE_LIST_COMMON[i]; | ||
if (!(name in styleProto)) { | ||
styleProto[name] = null; | ||
for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) { | ||
var prop = STYLE_COMMON_PROPS[i]; | ||
if (!(prop[0] in styleProto)) { | ||
styleProto[prop[0]] = prop[1]; | ||
} | ||
} | ||
// Provide for others | ||
Style.getGradient = styleProto.getGradient; | ||
module.exports = Style; |
@@ -32,3 +32,3 @@ /** | ||
brush: function (ctx) { | ||
brush: function (ctx, prevEl) { | ||
var style = this.style; | ||
@@ -39,4 +39,2 @@ var x = style.x || 0; | ||
var text = style.text; | ||
var textFill = style.fill; | ||
var textStroke = style.stroke; | ||
@@ -46,14 +44,11 @@ // Convert to string | ||
// Always bind style | ||
style.bind(ctx, this, prevEl); | ||
if (text) { | ||
ctx.save(); | ||
this.style.bind(ctx); | ||
this.setTransform(ctx); | ||
textFill && (ctx.fillStyle = textFill); | ||
textStroke && (ctx.strokeStyle = textStroke); | ||
ctx.font = style.textFont || style.font; | ||
ctx.textAlign = style.textAlign; | ||
var textBaseline; | ||
var textAlign = style.textAlign; | ||
if (style.textVerticalAlign) { | ||
@@ -64,3 +59,3 @@ var rect = textContain.getBoundingRect( | ||
// Ignore textBaseline | ||
ctx.textBaseline = 'middle'; | ||
textBaseline = 'middle'; | ||
switch (style.textVerticalAlign) { | ||
@@ -78,4 +73,17 @@ case 'middle': | ||
else { | ||
ctx.textBaseline = style.textBaseline; | ||
textBaseline = style.textBaseline; | ||
} | ||
ctx.font = style.textFont || style.font; | ||
ctx.textAlign = textAlign || 'left'; | ||
// Use canvas default left textAlign. Giving invalid value will cause state not change | ||
if (ctx.textAlign !== textAlign) { | ||
ctx.textAlign = 'left'; | ||
} | ||
ctx.textBaseline = textBaseline || 'alphabetic'; | ||
// Use canvas default alphabetic baseline | ||
if (ctx.textBaseline !== textBaseline) { | ||
ctx.textBaseline = 'alphabetic'; | ||
} | ||
var lineHeight = textContain.measureText('国', ctx.font).width; | ||
@@ -85,8 +93,8 @@ | ||
for (var i = 0; i < textLines.length; i++) { | ||
textFill && ctx.fillText(textLines[i], x, y); | ||
textStroke && ctx.strokeText(textLines[i], x, y); | ||
style.hasFill() && ctx.fillText(textLines[i], x, y); | ||
style.hasStroke() && ctx.strokeText(textLines[i], x, y); | ||
y += lineHeight; | ||
} | ||
ctx.restore(); | ||
this.restoreTransform(ctx); | ||
} | ||
@@ -93,0 +101,0 @@ }, |
@@ -73,3 +73,3 @@ 'use strict'; | ||
this.root.style.cursor = hovered ? hovered.cursor : this._defaultCursorStyle; | ||
this.root.style.cursor = hovered ? hovered.cursor : 'default'; | ||
// Mouse out on previous hovered element | ||
@@ -224,3 +224,4 @@ if (lastHovered && hovered !== lastHovered && lastHovered.__zr) { | ||
event, | ||
zrHandler.findHover(event.zrX, event.zrY, null) | ||
zrHandler.findHover(event.zrX, event.zrY, null), | ||
zrHandler.root | ||
); | ||
@@ -308,8 +309,2 @@ | ||
* @private | ||
* @type {string} | ||
*/ | ||
this._defaultCursorStyle = 'default'; | ||
/** | ||
* @private | ||
* @type {module:zrender/core/GestureMgr} | ||
@@ -404,6 +399,6 @@ */ | ||
* 设置默认的cursor style | ||
* @param {string} cursorStyle 例如 crosshair | ||
* @param {string} [cursorStyle='default'] 例如 crosshair | ||
*/ | ||
setDefaultCursorStyle: function (cursorStyle) { | ||
this._defaultCursorStyle = cursorStyle; | ||
setCursorStyle: function (cursorStyle) { | ||
this.root.style.cursor = cursorStyle || 'default'; | ||
}, | ||
@@ -410,0 +405,0 @@ |
@@ -9,2 +9,4 @@ /** | ||
var config = require('./config'); | ||
var Style = require('./graphic/Style'); | ||
var Pattern = require('./graphic/Pattern'); | ||
@@ -178,3 +180,3 @@ function returnFalse() { | ||
var haveClearColor = this.clearColor; | ||
var clearColor = this.clearColor; | ||
var haveMotionBLur = this.motionBlur && !clearAll; | ||
@@ -199,5 +201,22 @@ var lastFrameAlpha = this.lastFrameAlpha; | ||
ctx.clearRect(0, 0, width / dpr, height / dpr); | ||
if (haveClearColor) { | ||
if (clearColor) { | ||
var clearColorGradientOrPattern; | ||
// Gradient | ||
if (clearColor.colorStops) { | ||
// Cache canvas gradient | ||
clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, { | ||
x: 0, | ||
y: 0, | ||
width: width / dpr, | ||
height: height / dpr | ||
}); | ||
clearColor.__canvasGradient = clearColorGradientOrPattern; | ||
} | ||
// Pattern | ||
else if (clearColor.image) { | ||
clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx); | ||
} | ||
ctx.save(); | ||
ctx.fillStyle = this.clearColor; | ||
ctx.fillStyle = clearColorGradientOrPattern || clearColor; | ||
ctx.fillRect(0, 0, width / dpr, height / dpr); | ||
@@ -204,0 +223,0 @@ ctx.restore(); |
@@ -10,4 +10,2 @@ /** | ||
var arrySlice = Array.prototype.slice; | ||
var zrUtil = require('../core/util'); | ||
var indexOf = zrUtil.indexOf; | ||
@@ -45,4 +43,6 @@ /** | ||
if (indexOf(_h[event], event) >= 0) { | ||
return this; | ||
for (var i = 0; i < _h[event].length; i++) { | ||
if (_h[event][i].h === handler) { | ||
return this; | ||
} | ||
} | ||
@@ -76,2 +76,8 @@ | ||
for (var i = 0; i < _h[event].length; i++) { | ||
if (_h[event][i].h === handler) { | ||
return this; | ||
} | ||
} | ||
_h[event].push({ | ||
@@ -78,0 +84,0 @@ h: handler, |
@@ -149,2 +149,9 @@ 'use strict'; | ||
transformableProto.restoreTransform = function (ctx) { | ||
var m = this.invTransform; | ||
if (m) { | ||
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]); | ||
} | ||
} | ||
var tmpTransform = []; | ||
@@ -151,0 +158,0 @@ |
@@ -15,5 +15,14 @@ 'use strict'; | ||
var BoundingRect = require('./core/BoundingRect'); | ||
var timsort = require('./core/timsort'); | ||
var Layer = require('./Layer'); | ||
var requestAnimationFrame = require('./animation/requestAnimationFrame'); | ||
// PENDIGN | ||
// Layer exceeds MAX_PROGRESSIVE_LAYER_NUMBER may have some problem when flush directly second time. | ||
// | ||
// Maximum progressive layer. When exceeding this number. All elements will be drawed in the last layer. | ||
var MAX_PROGRESSIVE_LAYER_NUMBER = 5; | ||
function parseInt10(val) { | ||
@@ -46,3 +55,2 @@ return parseInt(val, 10); | ||
function postProcessLayer(layer) { | ||
layer.__dirty = false; | ||
if (layer.__unusedCount == 1) { | ||
@@ -66,2 +74,6 @@ layer.clear(); | ||
function isClipPathChanged(clipPaths, prevClipPaths) { | ||
if (clipPaths == prevClipPaths) { // Can both be null or undefined | ||
return false; | ||
} | ||
if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) { | ||
@@ -105,2 +117,14 @@ return true; | ||
function createRoot(width, height) { | ||
var domRoot = document.createElement('div'); | ||
var domRootStyle = domRoot.style; | ||
// domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬 | ||
domRootStyle.position = 'relative'; | ||
domRootStyle.overflow = 'hidden'; | ||
domRootStyle.width = width + 'px'; | ||
domRootStyle.height = height + 'px'; | ||
return domRoot; | ||
} | ||
/** | ||
@@ -114,2 +138,3 @@ * @alias module:zrender/Painter | ||
var Painter = function (root, storage, opts) { | ||
// In node environment using node-canvas | ||
var singleCanvas = !root.nodeName // In node ? | ||
@@ -137,7 +162,6 @@ || root.nodeName.toUpperCase() === 'CANVAS'; | ||
// In node environment using node-canvas | ||
if (rootStyle) { | ||
rootStyle['-webkit-tap-highlight-color'] = 'transparent'; | ||
rootStyle['-webkit-user-select'] = 'none'; | ||
rootStyle['user-select'] = 'none'; | ||
rootStyle['-webkit-user-select'] = | ||
rootStyle['user-select'] = | ||
rootStyle['-webkit-touch-callout'] = 'none'; | ||
@@ -153,29 +177,28 @@ | ||
/** | ||
* @type {Array.<number>} | ||
* @private | ||
*/ | ||
var zlevelList = this._zlevelList = []; | ||
/** | ||
* @type {Object.<string, module:zrender/Layer>} | ||
* @private | ||
*/ | ||
var layers = this._layers = {}; | ||
/** | ||
* @type {Object.<string, Object>} | ||
* @type {private} | ||
*/ | ||
this._layerConfig = {}; | ||
if (!singleCanvas) { | ||
var width = this._getWidth(); | ||
var height = this._getHeight(); | ||
this._width = width; | ||
this._height = height; | ||
this._width = this._getWidth(); | ||
this._height = this._getHeight(); | ||
var domRoot = document.createElement('div'); | ||
this._domRoot = domRoot; | ||
var domRootStyle = domRoot.style; | ||
// domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬 | ||
domRootStyle.position = 'relative'; | ||
domRootStyle.overflow = 'hidden'; | ||
domRootStyle.width = this._width + 'px'; | ||
domRootStyle.height = this._height + 'px'; | ||
var domRoot = this._domRoot = createRoot( | ||
this._width, this._height | ||
); | ||
root.appendChild(domRoot); | ||
/** | ||
* @type {Object.<key, module:zrender/Layer>} | ||
* @private | ||
*/ | ||
this._layers = {}; | ||
/** | ||
* @type {Array.<number>} | ||
* @private | ||
*/ | ||
this._zlevelList = []; | ||
} | ||
@@ -195,11 +218,18 @@ else { | ||
// mainLayer.resize(width, height); | ||
this._layers = { | ||
0: mainLayer | ||
}; | ||
this._zlevelList = [0]; | ||
layers[0] = mainLayer; | ||
zlevelList.push(0); | ||
} | ||
this._layerConfig = {}; | ||
this.pathToImage = this._createPathToImage(); | ||
this.pathToImage = this._createPathToImage(); | ||
// Layers for progressive rendering | ||
this._progressiveLayers = []; | ||
/** | ||
* @type {module:zrender/Layer} | ||
* @private | ||
*/ | ||
this._hoverlayer; | ||
this._hoverElements = []; | ||
}; | ||
@@ -230,3 +260,5 @@ | ||
refresh: function (paintAll) { | ||
var list = this.storage.getDisplayList(true); | ||
var zlevelList = this._zlevelList; | ||
@@ -245,5 +277,130 @@ | ||
this.refreshHover(); | ||
if (this._progressiveLayers.length) { | ||
this._startProgessive(); | ||
} | ||
return this; | ||
}, | ||
addHover: function (el, hoverStyle) { | ||
if (el.__hoverMir) { | ||
return; | ||
} | ||
var elMirror = new el.constructor({ | ||
style: el.style, | ||
shape: el.shape | ||
}); | ||
elMirror.__from = el; | ||
el.__hoverMir = elMirror; | ||
elMirror.setStyle(hoverStyle); | ||
this._hoverElements.push(elMirror); | ||
}, | ||
removeHover: function (el) { | ||
var elMirror = el.__hoverMir; | ||
var hoverElements = this._hoverElements; | ||
var idx = util.indexOf(hoverElements, elMirror); | ||
if (idx >= 0) { | ||
hoverElements.splice(idx, 1); | ||
} | ||
el.__hoverMir = null; | ||
}, | ||
clearHover: function (el) { | ||
var hoverElements = this._hoverElements; | ||
for (var i = 0; i < hoverElements.length; i++) { | ||
var from = hoverElements[i].__from; | ||
if (from) { | ||
from.__hoverMir = null; | ||
} | ||
} | ||
hoverElements.length = 0; | ||
}, | ||
refreshHover: function () { | ||
var hoverElements = this._hoverElements; | ||
var len = hoverElements.length; | ||
var hoverLayer = this._hoverlayer; | ||
hoverLayer && hoverLayer.clear(); | ||
if (!len) { | ||
return; | ||
} | ||
timsort(hoverElements, this.storage.displayableSortFunc); | ||
// Use a extream large zlevel | ||
// FIXME? | ||
if (!hoverLayer) { | ||
hoverLayer = this._hoverlayer = this.getLayer(1e5); | ||
} | ||
var scope = {}; | ||
hoverLayer.ctx.save(); | ||
for (var i = 0; i < len;) { | ||
var el = hoverElements[i]; | ||
var originalEl = el.__from; | ||
// Original el is removed | ||
// PENDING | ||
if (!(originalEl && originalEl.__zr)) { | ||
hoverElements.splice(i, 1); | ||
originalEl.__hoverMir = null; | ||
len--; | ||
continue; | ||
} | ||
i++; | ||
// Use transform | ||
// FIXME style and shape ? | ||
if (!originalEl.invisible) { | ||
el.transform = originalEl.transform; | ||
el.invTransform = originalEl.invTransform; | ||
el.__clipPaths = originalEl.__clipPaths; | ||
// el. | ||
this._doPaintEl(el, hoverLayer, true, scope); | ||
} | ||
} | ||
hoverLayer.ctx.restore(); | ||
}, | ||
_startProgessive: function () { | ||
var self = this; | ||
if (!self._furtherProgressive) { | ||
return; | ||
} | ||
// Use a token to stop progress steps triggered by | ||
// previous zr.refresh calling. | ||
var token = self._progressiveToken = +new Date(); | ||
self._progress++; | ||
requestAnimationFrame(step); | ||
function step() { | ||
// In case refreshed or disposed | ||
if (token === self._progressiveToken && self.storage) { | ||
self._doPaintList(self.storage.getDisplayList()); | ||
if (self._furtherProgressive) { | ||
self._progress++; | ||
requestAnimationFrame(step); | ||
} | ||
else { | ||
self._progressiveToken = -1; | ||
} | ||
} | ||
} | ||
}, | ||
_clearProgressive: function () { | ||
this._progressiveToken = -1; | ||
this._progress = 0; | ||
util.each(this._progressiveLayers, function (layer) { | ||
layer.__dirty && layer.clear(); | ||
}); | ||
}, | ||
_paintList: function (list, paintAll) { | ||
@@ -257,2 +414,12 @@ | ||
this._clearProgressive(); | ||
this.eachBuildinLayer(preProcessLayer); | ||
this._doPaintList(list, paintAll); | ||
this.eachBuildinLayer(postProcessLayer); | ||
}, | ||
_doPaintList: function (list, paintAll) { | ||
var currentLayer; | ||
@@ -262,15 +429,46 @@ var currentZLevel; | ||
var viewWidth = this._width; | ||
var viewHeight = this._height; | ||
// var invTransform = []; | ||
var scope; | ||
this.eachBuildinLayer(preProcessLayer); | ||
var progressiveLayerIdx = 0; | ||
var currentProgressiveLayer; | ||
// var invTransform = []; | ||
var prevElClipPaths = null; | ||
var width = this._width; | ||
var height = this._height; | ||
var layerProgress; | ||
var frame = this._progress; | ||
function flushProgressiveLayer(layer) { | ||
ctx.save(); | ||
ctx.globalAlpha = 1; | ||
ctx.shadowBlur = 0; | ||
// Avoid layer don't clear in next progressive frame | ||
currentLayer.__dirty = true; | ||
ctx.drawImage(layer.dom, 0, 0, width, height); | ||
ctx.restore(); | ||
currentLayer.ctx.restore(); | ||
} | ||
for (var i = 0, l = list.length; i < l; i++) { | ||
var el = list[i]; | ||
var elZLevel = this._singleCanvas ? 0 : el.zlevel; | ||
var elFrame = el.__frame; | ||
// Flush at current context | ||
// PENDING | ||
if (elFrame < 0 && currentProgressiveLayer) { | ||
flushProgressiveLayer(currentProgressiveLayer); | ||
currentProgressiveLayer = null; | ||
} | ||
// Change draw layer | ||
if (currentZLevel !== elZLevel) { | ||
if (ctx) { | ||
ctx.restore(); | ||
} | ||
// Reset scope | ||
scope = {}; | ||
// Only 0 zlevel if only has one canvas | ||
@@ -288,2 +486,3 @@ currentZLevel = elZLevel; | ||
ctx = currentLayer.ctx; | ||
ctx.save(); | ||
@@ -298,33 +497,43 @@ // Reset the count | ||
if ( | ||
(currentLayer.__dirty || paintAll) | ||
// Ignore invisible element | ||
&& !el.invisible | ||
// Ignore transparent element | ||
&& el.style.opacity !== 0 | ||
// Ignore scale 0 element, in some environment like node-canvas | ||
// Draw a scale 0 element can cause all following draw wrong | ||
&& el.scale[0] && el.scale[1] | ||
// Ignore culled element | ||
&& !(el.culling && isDisplayableCulled(el, viewWidth, viewHeight)) | ||
) { | ||
var clipPaths = el.__clipPaths; | ||
if (!(currentLayer.__dirty || paintAll)) { | ||
continue; | ||
} | ||
if (elFrame >= 0) { | ||
// Progressive layer changed | ||
if (!currentProgressiveLayer) { | ||
currentProgressiveLayer = this._progressiveLayers[ | ||
Math.min(progressiveLayerIdx++, MAX_PROGRESSIVE_LAYER_NUMBER - 1) | ||
]; | ||
// Optimize when clipping on group with several elements | ||
if (isClipPathChanged(clipPaths, prevElClipPaths)) { | ||
// If has previous clipping state, restore from it | ||
if (prevElClipPaths) { | ||
ctx.restore(); | ||
currentProgressiveLayer.ctx.save(); | ||
currentProgressiveLayer.renderScope = {}; | ||
if (currentProgressiveLayer | ||
&& (currentProgressiveLayer.__progress > currentProgressiveLayer.__maxProgress) | ||
) { | ||
// flushProgressiveLayer(currentProgressiveLayer); | ||
// Quick jump all progressive elements | ||
// All progressive element are not dirty, jump over and flush directly | ||
i = currentProgressiveLayer.__nextIdxNotProg - 1; | ||
// currentProgressiveLayer = null; | ||
continue; | ||
} | ||
// New clipping state | ||
if (clipPaths) { | ||
ctx.save(); | ||
doClip(clipPaths, ctx); | ||
layerProgress = currentProgressiveLayer.__progress; | ||
if (!currentProgressiveLayer.__dirty) { | ||
// Keep rendering | ||
frame = layerProgress; | ||
} | ||
prevElClipPaths = clipPaths; | ||
currentProgressiveLayer.__progress = frame + 1; | ||
} | ||
el.beforeBrush && el.beforeBrush(ctx); | ||
el.brush(ctx, false); | ||
el.afterBrush && el.afterBrush(ctx); | ||
if (elFrame === frame) { | ||
this._doPaintEl(el, currentProgressiveLayer, true, currentProgressiveLayer.renderScope); | ||
} | ||
} | ||
else { | ||
this._doPaintEl(el, currentLayer, paintAll, scope); | ||
} | ||
@@ -334,10 +543,68 @@ el.__dirty = false; | ||
// If still has clipping state | ||
if (prevElClipPaths) { | ||
ctx.restore(); | ||
if (currentProgressiveLayer) { | ||
flushProgressiveLayer(currentProgressiveLayer); | ||
} | ||
this.eachBuildinLayer(postProcessLayer); | ||
// Restore the lastLayer ctx | ||
ctx && ctx.restore(); | ||
// If still has clipping state | ||
// if (scope.prevElClipPaths) { | ||
// ctx.restore(); | ||
// } | ||
this._furtherProgressive = false; | ||
util.each(this._progressiveLayers, function (layer) { | ||
if (layer.__maxProgress >= layer.__progress) { | ||
this._furtherProgressive = true; | ||
} | ||
}, this); | ||
}, | ||
_doPaintEl: function (el, currentLayer, forcePaint, scope) { | ||
var ctx = currentLayer.ctx; | ||
if ( | ||
(currentLayer.__dirty || forcePaint) | ||
// Ignore invisible element | ||
&& !el.invisible | ||
// Ignore transparent element | ||
&& el.style.opacity !== 0 | ||
// Ignore scale 0 element, in some environment like node-canvas | ||
// Draw a scale 0 element can cause all following draw wrong | ||
&& el.scale[0] && el.scale[1] | ||
// Ignore culled element | ||
&& !(el.culling && isDisplayableCulled(el, this._width, this._height)) | ||
) { | ||
var clipPaths = el.__clipPaths; | ||
// Optimize when clipping on group with several elements | ||
if (scope.prevClipLayer !== currentLayer | ||
|| isClipPathChanged(clipPaths, scope.prevElClipPaths) | ||
) { | ||
// If has previous clipping state, restore from it | ||
if (scope.prevElClipPaths) { | ||
scope.prevClipLayer.ctx.restore(); | ||
scope.prevClipLayer = scope.prevElClipPaths = null; | ||
// Reset prevEl since context has been restored | ||
scope.prevEl = null; | ||
} | ||
// New clipping state | ||
if (clipPaths) { | ||
ctx.save(); | ||
doClip(clipPaths, ctx); | ||
scope.prevClipLayer = currentLayer; | ||
scope.prevElClipPaths = clipPaths; | ||
} | ||
} | ||
el.beforeBrush && el.beforeBrush(ctx); | ||
el.brush(ctx, scope.prevEl || null); | ||
scope.prevEl = el; | ||
el.afterBrush && el.afterBrush(ctx); | ||
} | ||
}, | ||
/** | ||
@@ -481,10 +748,23 @@ * 获取 zlevel 所在层,如果不存在则会创建一个新的层 | ||
var layers = this._layers; | ||
var progressiveLayers = this._progressiveLayers; | ||
var elCounts = {}; | ||
var elCountsLastFrame = {}; | ||
var progressiveElCountsLastFrame = {}; | ||
this.eachBuildinLayer(function (layer, z) { | ||
elCounts[z] = layer.elCount; | ||
elCountsLastFrame[z] = layer.elCount; | ||
layer.elCount = 0; | ||
layer.__dirty = false; | ||
}); | ||
util.each(progressiveLayers, function (layer, idx) { | ||
progressiveElCountsLastFrame[idx] = layer.elCount; | ||
layer.elCount = 0; | ||
layer.__dirty = false; | ||
}); | ||
var progressiveLayerCount = 0; | ||
var currentProgressiveLayer; | ||
var lastProgressiveKey; | ||
var frameCount = 0; | ||
for (var i = 0, l = list.length; i < l; i++) { | ||
@@ -494,18 +774,71 @@ var el = list[i]; | ||
var layer = layers[zlevel]; | ||
var elProgress = el.progressive; | ||
if (layer) { | ||
layer.elCount++; | ||
// 已经被标记为需要刷新 | ||
if (layer.__dirty) { | ||
continue; | ||
layer.__dirty = layer.__dirty || el.__dirty; | ||
} | ||
/////// Update progressive | ||
if (elProgress >= 0) { | ||
// Fix wrong progressive sequence problem. | ||
if (lastProgressiveKey !== elProgress) { | ||
lastProgressiveKey = elProgress; | ||
frameCount++; | ||
} | ||
layer.__dirty = el.__dirty; | ||
var elFrame = el.__frame = frameCount - 1; | ||
if (!currentProgressiveLayer) { | ||
var idx = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER - 1); | ||
currentProgressiveLayer = progressiveLayers[idx]; | ||
if (!currentProgressiveLayer) { | ||
currentProgressiveLayer = progressiveLayers[idx] = new Layer( | ||
'progressive', this, this.dpr | ||
); | ||
currentProgressiveLayer.initContext(); | ||
} | ||
currentProgressiveLayer.__maxProgress = 0; | ||
} | ||
currentProgressiveLayer.__dirty = currentProgressiveLayer.__dirty || el.__dirty; | ||
currentProgressiveLayer.elCount++; | ||
currentProgressiveLayer.__maxProgress = Math.max( | ||
currentProgressiveLayer.__maxProgress, elFrame | ||
); | ||
if (currentProgressiveLayer.__maxProgress >= currentProgressiveLayer.__progress) { | ||
// Should keep rendering this layer because progressive rendering is not finished yet | ||
layer.__dirty = true; | ||
} | ||
} | ||
else { | ||
el.__frame = -1; | ||
if (currentProgressiveLayer) { | ||
currentProgressiveLayer.__nextIdxNotProg = i; | ||
progressiveLayerCount++; | ||
currentProgressiveLayer = null; | ||
} | ||
} | ||
} | ||
if (currentProgressiveLayer) { | ||
progressiveLayerCount++; | ||
currentProgressiveLayer.__nextIdxNotProg = i; | ||
} | ||
// 层中的元素数量有发生变化 | ||
this.eachBuildinLayer(function (layer, z) { | ||
if (elCounts[z] !== layer.elCount) { | ||
if (elCountsLastFrame[z] !== layer.elCount) { | ||
layer.__dirty = true; | ||
} | ||
}); | ||
progressiveLayers.length = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER); | ||
util.each(progressiveLayers, function (layer, idx) { | ||
if (progressiveElCountsLastFrame[idx] !== layer.elCount) { | ||
el.__dirty = true; | ||
} | ||
if (layer.__dirty) { | ||
layer.__progress = 0; | ||
} | ||
}); | ||
}, | ||
@@ -639,3 +972,2 @@ | ||
var ctx = imageLayer.ctx; | ||
imageLayer.clearColor = opts.backgroundColor; | ||
@@ -646,10 +978,6 @@ imageLayer.clear(); | ||
var scope = {}; | ||
for (var i = 0; i < displayList.length; i++) { | ||
var el = displayList[i]; | ||
if (!el.invisible) { | ||
el.beforeBrush && el.beforeBrush(ctx); | ||
// TODO Check image cross origin | ||
el.brush(ctx, false); | ||
el.afterBrush && el.afterBrush(ctx); | ||
} | ||
this._doPaintEl(el, imageLayer, true, scope); | ||
} | ||
@@ -656,0 +984,0 @@ |
@@ -12,11 +12,19 @@ 'use strict'; | ||
var util = require('./core/util'); | ||
var env = require('./core/env'); | ||
var Group = require('./container/Group'); | ||
// Use timsort because in most case elements are partially sorted | ||
// https://jsfiddle.net/pissang/jr4x7mdm/8/ | ||
var timsort = require('./core/timsort'); | ||
function shapeCompareFunc(a, b) { | ||
if (a.zlevel === b.zlevel) { | ||
if (a.z === b.z) { | ||
if (a.z2 === b.z2) { | ||
return a.__renderidx - b.__renderidx; | ||
} | ||
// if (a.z2 === b.z2) { | ||
// // FIXME Slow has renderidx compare | ||
// // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement | ||
// // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012 | ||
// return a.__renderidx - b.__renderidx; | ||
// } | ||
return a.z2 - b.z2; | ||
@@ -49,2 +57,12 @@ } | ||
/** | ||
* @param {Function} cb | ||
* | ||
*/ | ||
traverse: function (cb, context) { | ||
for (var i = 0; i < this._roots.length; i++) { | ||
this._roots[i].traverse(cb, context); | ||
} | ||
}, | ||
/** | ||
* 返回所有图形的绘制队列 | ||
@@ -80,7 +98,8 @@ * @param {boolean} [update=false] 是否在返回前更新该数组 | ||
for (var i = 0, len = displayList.length; i < len; i++) { | ||
displayList[i].__renderidx = i; | ||
} | ||
// for (var i = 0, len = displayList.length; i < len; i++) { | ||
// displayList[i].__renderidx = i; | ||
// } | ||
displayList.sort(shapeCompareFunc); | ||
// displayList.sort(shapeCompareFunc); | ||
env.canvasSupported && timsort(displayList, shapeCompareFunc); | ||
}, | ||
@@ -96,4 +115,8 @@ | ||
el.update(); | ||
if (el.__dirty) { | ||
el.update(); | ||
} | ||
el.afterUpdate(); | ||
@@ -117,3 +140,3 @@ | ||
if (el.type == 'group') { | ||
if (el.isGroup) { | ||
var children = el._children; | ||
@@ -126,3 +149,5 @@ | ||
// FIXME __dirtyPath ? | ||
child.__dirty = el.__dirty || child.__dirty; | ||
if (el.__dirty) { | ||
child.__dirty = true; | ||
} | ||
@@ -243,3 +268,5 @@ this._updateAndAddDisplayable(child, clipPaths, includeIgnore); | ||
this._roots = null; | ||
} | ||
}, | ||
displayableSortFunc: shapeCompareFunc | ||
}; | ||
@@ -246,0 +273,0 @@ |
@@ -459,6 +459,7 @@ /** | ||
function stringify(arrColor, type) { | ||
if (type === 'rgb' || type === 'hsv' || type === 'hsl') { | ||
arrColor = arrColor.slice(0, 3); | ||
var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2]; | ||
if (type === 'rgba' || type === 'hsva' || type === 'hsla') { | ||
colorStr += ',' + arrColor[3]; | ||
} | ||
return type + '(' + arrColor.join(',') + ')'; | ||
return type + '(' + colorStr + ')'; | ||
} | ||
@@ -465,0 +466,0 @@ |
@@ -381,8 +381,6 @@ | ||
var len = pathEls.length; | ||
var pathEl; | ||
var i; | ||
for (i = 0; i < len; i++) { | ||
pathEl = pathEls[i]; | ||
for (var i = 0; i < len; i++) { | ||
var pathEl = pathEls[i]; | ||
if (pathEl.__dirty) { | ||
pathEl.buildPath(pathEl.path, pathEl.shape); | ||
pathEl.buildPath(pathEl.path, pathEl.shape, true); | ||
} | ||
@@ -389,0 +387,0 @@ pathList.push(pathEl.path); |
@@ -217,11 +217,11 @@ // http://www.w3.org/TR/NOTE-VML | ||
var updateStrokeNode = function (el, style) { | ||
if (style.lineJoin != null) { | ||
el.joinstyle = style.lineJoin; | ||
} | ||
if (style.miterLimit != null) { | ||
el.miterlimit = style.miterLimit * Z; | ||
} | ||
if (style.lineCap != null) { | ||
el.endcap = style.lineCap; | ||
} | ||
// if (style.lineJoin != null) { | ||
// el.joinstyle = style.lineJoin; | ||
// } | ||
// if (style.miterLimit != null) { | ||
// el.miterlimit = style.miterLimit * Z; | ||
// } | ||
// if (style.lineCap != null) { | ||
// el.endcap = style.lineCap; | ||
// } | ||
if (style.lineDash != null) { | ||
@@ -836,2 +836,3 @@ el.dashstyle = style.lineDash.join(' '); | ||
+ fontStyle.size + 'px "' + fontStyle.family + '"'; | ||
var baseline = style.textBaseline; | ||
@@ -838,0 +839,0 @@ var verticalAlign = style.textVerticalAlign; |
@@ -151,2 +151,6 @@ /** | ||
clear: function () { | ||
this.root.removeChild(this.vmlViewport); | ||
}, | ||
_getWidth: function () { | ||
@@ -153,0 +157,0 @@ var root = this.root; |
@@ -31,3 +31,3 @@ /*! | ||
*/ | ||
zrender.version = '3.1.0'; | ||
zrender.version = '3.1.1'; | ||
@@ -139,2 +139,5 @@ /** | ||
} | ||
if (self._needsRefreshHover) { | ||
self.refreshHoverImmediately(); | ||
} | ||
} | ||
@@ -184,3 +187,3 @@ } | ||
* 添加元素 | ||
* @param {string|module:zrender/Element} el | ||
* @param {module:zrender/Element} el | ||
*/ | ||
@@ -194,3 +197,3 @@ add: function (el) { | ||
* 删除元素 | ||
* @param {string|module:zrender/Element} el | ||
* @param {module:zrender/Element} el | ||
*/ | ||
@@ -237,2 +240,51 @@ remove: function (el) { | ||
/** | ||
* Add element to hover layer | ||
* @param {module:zrender/Element} el | ||
* @param {Object} style | ||
*/ | ||
addHover: function (el, style) { | ||
if (this.painter.addHover) { | ||
this.painter.addHover(el, style); | ||
this.refreshHover(); | ||
} | ||
}, | ||
/** | ||
* Add element from hover layer | ||
* @param {module:zrender/Element} el | ||
*/ | ||
removeHover: function (el) { | ||
if (this.painter.removeHover) { | ||
this.painter.removeHover(el); | ||
this.refreshHover(); | ||
} | ||
}, | ||
/** | ||
* Clear all hover elements in hover layer | ||
* @param {module:zrender/Element} el | ||
*/ | ||
clearHover: function () { | ||
if (this.painter.clearHover) { | ||
this.painter.clearHover(); | ||
this.refreshHover(); | ||
} | ||
}, | ||
/** | ||
* Refresh hover in next frame | ||
*/ | ||
refreshHover: function () { | ||
this._needsRefreshHover = true; | ||
}, | ||
/** | ||
* Refresh hover immediately | ||
*/ | ||
refreshHoverImmediately: function () { | ||
this._needsRefreshHover = false; | ||
this.painter.refreshHover && this.painter.refreshHover(); | ||
}, | ||
/** | ||
* Resize the canvas. | ||
@@ -293,6 +345,6 @@ * Should be invoked when container size is changed | ||
* Set default cursor | ||
* @param {string} cursorStyle 例如 crosshair | ||
* @param {string} [cursorStyle='default'] 例如 crosshair | ||
*/ | ||
setDefaultCursorStyle: function (cursorStyle) { | ||
this.handler.setDefaultCursorStyle(cursorStyle); | ||
setCursorStyle: function (cursorStyle) { | ||
this.handler && this.handler.setCursorStyle(cursorStyle); | ||
}, | ||
@@ -299,0 +351,0 @@ |
{ | ||
"name": "zrender", | ||
"version": "3.1.0", | ||
"version": "3.1.1", | ||
"description": "A lightweight canvas library.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -17,10 +17,3 @@ /** | ||
var requestAnimationFrame = (typeof window !== 'undefined' && | ||
(window.requestAnimationFrame | ||
|| window.msRequestAnimationFrame | ||
|| window.mozRequestAnimationFrame | ||
|| window.webkitRequestAnimationFrame)) | ||
|| function (func) { | ||
setTimeout(func, 16); | ||
}; | ||
var requestAnimationFrame = require('./requestAnimationFrame'); | ||
@@ -27,0 +20,0 @@ var Animator = require('./Animator'); |
@@ -319,2 +319,3 @@ /** | ||
// Start from next key | ||
// PENDING start from lastFrame ? | ||
start = Math.min(lastFrame + 1, trackLen - 1); | ||
@@ -326,2 +327,3 @@ for (frame = start; frame >= 0; frame--) { | ||
} | ||
// PENDING really need to do this ? | ||
frame = Math.min(frame, trackLen - 2); | ||
@@ -328,0 +330,0 @@ } |
@@ -53,2 +53,6 @@ define(function (require) { | ||
var t = roots[i]; | ||
// Avoid winding error when intersection point is the connect point of two line of polygon | ||
var unit = (t === 0 || t === 1) ? 0.5 : 1; | ||
var x_ = curve.cubicAt(x0, x1, x2, x3, t); | ||
@@ -71,9 +75,9 @@ if (x_ < x) { // Quick reject | ||
if (t < extrema[0]) { | ||
w += y0_ < y0 ? 1 : -1; | ||
w += y0_ < y0 ? unit : -unit; | ||
} | ||
else if (t < extrema[1]) { | ||
w += y1_ < y0_ ? 1 : -1; | ||
w += y1_ < y0_ ? unit : -unit; | ||
} | ||
else { | ||
w += y3 < y1_ ? 1 : -1; | ||
w += y3 < y1_ ? unit : -unit; | ||
} | ||
@@ -84,6 +88,6 @@ } | ||
if (t < extrema[0]) { | ||
w += y0_ < y0 ? 1 : -1; | ||
w += y0_ < y0 ? unit : -unit; | ||
} | ||
else { | ||
w += y3 < y0_ ? 1 : -1; | ||
w += y3 < y0_ ? unit : -unit; | ||
} | ||
@@ -114,2 +118,5 @@ } | ||
for (var i = 0; i < nRoots; i++) { | ||
// Remove one endpoint. | ||
var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1; | ||
var x_ = curve.quadraticAt(x0, x1, x2, roots[i]); | ||
@@ -120,6 +127,6 @@ if (x_ < x) { // Quick reject | ||
if (roots[i] < t) { | ||
w += y_ < y0 ? 1 : -1; | ||
w += y_ < y0 ? unit : -unit; | ||
} | ||
else { | ||
w += y2 < y_ ? 1 : -1; | ||
w += y2 < y_ ? unit : -unit; | ||
} | ||
@@ -130,2 +137,5 @@ } | ||
else { | ||
// Remove one endpoint. | ||
var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1; | ||
var x_ = curve.quadraticAt(x0, x1, x2, roots[0]); | ||
@@ -135,3 +145,3 @@ if (x_ < x) { // Quick reject | ||
} | ||
return y2 < y0 ? 1 : -1; | ||
return y2 < y0 ? unit : -unit; | ||
} | ||
@@ -222,5 +232,5 @@ } | ||
// 如果被任何一个 subpath 包含 | ||
if (w !== 0) { | ||
return true; | ||
} | ||
// if (w !== 0) { | ||
// return true; | ||
// } | ||
} | ||
@@ -352,3 +362,3 @@ | ||
|| containStroke(x1, y1, x0, y1, lineWidth, x, y) | ||
|| containStroke(x0, y1, x1, y1, lineWidth, x, y) | ||
|| containStroke(x0, y1, x0, y0, lineWidth, x, y) | ||
) { | ||
@@ -376,5 +386,6 @@ return true; | ||
// 如果被任何一个 subpath 包含 | ||
if (w !== 0) { | ||
return true; | ||
} | ||
// FIXME subpaths may overlap | ||
// if (w !== 0) { | ||
// return true; | ||
// } | ||
} | ||
@@ -381,0 +392,0 @@ xi = x0; |
@@ -6,2 +6,3 @@ define(function () { | ||
} | ||
// Ignore horizontal line | ||
if (y1 === y0) { | ||
@@ -12,2 +13,8 @@ return 0; | ||
var t = (y - y0) / (y1 - y0); | ||
// Avoid winding error when intersection point is the connect point of two line of polygon | ||
if (t === 1 || t === 0) { | ||
dir = y1 < y0 ? 0.5 : -0.5; | ||
} | ||
var x_ = t * (x1 - x0) + x0; | ||
@@ -14,0 +21,0 @@ |
@@ -52,2 +52,4 @@ /** | ||
isGroup: true, | ||
/** | ||
@@ -54,0 +56,0 @@ * @type {string} |
@@ -33,19 +33,19 @@ /** | ||
var browser = {}; | ||
var webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/); | ||
var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); | ||
var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); | ||
var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); | ||
var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/); | ||
var webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/); | ||
var touchpad = webos && ua.match(/TouchPad/); | ||
var kindle = ua.match(/Kindle\/([\d.]+)/); | ||
var silk = ua.match(/Silk\/([\d._]+)/); | ||
var blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/); | ||
var bb10 = ua.match(/(BB10).*Version\/([\d.]+)/); | ||
var rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/); | ||
var playbook = ua.match(/PlayBook/); | ||
var chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/); | ||
var firefox = ua.match(/Firefox\/([\d.]+)/); | ||
var safari = webkit && ua.match(/Mobile\//) && !chrome; | ||
var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome; | ||
// var webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/); | ||
// var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); | ||
// var ipad = ua.match(/(iPad).*OS\s([\d_]+)/); | ||
// var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/); | ||
// var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/); | ||
// var webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/); | ||
// var touchpad = webos && ua.match(/TouchPad/); | ||
// var kindle = ua.match(/Kindle\/([\d.]+)/); | ||
// var silk = ua.match(/Silk\/([\d._]+)/); | ||
// var blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/); | ||
// var bb10 = ua.match(/(BB10).*Version\/([\d.]+)/); | ||
// var rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/); | ||
// var playbook = ua.match(/PlayBook/); | ||
// var chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/); | ||
// var firefox = ua.match(/Firefox\/([\d.]+)/); | ||
// var safari = webkit && ua.match(/Mobile\//) && !chrome; | ||
// var webview = ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/) && !chrome; | ||
var ie = ua.match(/MSIE\s([\d.]+)/) | ||
@@ -62,30 +62,38 @@ // IE 11 Trident/7.0; rv:11.0 | ||
if (browser.webkit = !!webkit) browser.version = webkit[1]; | ||
// if (browser.webkit = !!webkit) browser.version = webkit[1]; | ||
if (android) os.android = true, os.version = android[2]; | ||
if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.'); | ||
if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.'); | ||
if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null; | ||
if (webos) os.webos = true, os.version = webos[2]; | ||
if (touchpad) os.touchpad = true; | ||
if (blackberry) os.blackberry = true, os.version = blackberry[2]; | ||
if (bb10) os.bb10 = true, os.version = bb10[2]; | ||
if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2]; | ||
if (playbook) browser.playbook = true; | ||
if (kindle) os.kindle = true, os.version = kindle[1]; | ||
if (silk) browser.silk = true, browser.version = silk[1]; | ||
if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true; | ||
if (chrome) browser.chrome = true, browser.version = chrome[1]; | ||
if (firefox) browser.firefox = true, browser.version = firefox[1]; | ||
if (ie) browser.ie = true, browser.version = ie[1]; | ||
if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true; | ||
if (webview) browser.webview = true; | ||
if (ie) browser.ie = true, browser.version = ie[1]; | ||
if (edge) browser.edge = true, browser.version = edge[1]; | ||
// if (android) os.android = true, os.version = android[2]; | ||
// if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.'); | ||
// if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.'); | ||
// if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null; | ||
// if (webos) os.webos = true, os.version = webos[2]; | ||
// if (touchpad) os.touchpad = true; | ||
// if (blackberry) os.blackberry = true, os.version = blackberry[2]; | ||
// if (bb10) os.bb10 = true, os.version = bb10[2]; | ||
// if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2]; | ||
// if (playbook) browser.playbook = true; | ||
// if (kindle) os.kindle = true, os.version = kindle[1]; | ||
// if (silk) browser.silk = true, browser.version = silk[1]; | ||
// if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true; | ||
// if (chrome) browser.chrome = true, browser.version = chrome[1]; | ||
// if (firefox) browser.firefox = true, browser.version = firefox[1]; | ||
// if (safari && (ua.match(/Safari/) || !!os.ios)) browser.safari = true; | ||
// if (webview) browser.webview = true; | ||
if (ie) { | ||
browser.ie = true; browser.version = ie[1]; | ||
} | ||
if (ie) { | ||
browser.ie = true; | ||
browser.version = ie[1]; | ||
} | ||
if (edge) { | ||
browser.edge = true; | ||
browser.version = edge[1]; | ||
} | ||
os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || | ||
(firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/))); | ||
os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos || blackberry || bb10 || | ||
(chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || | ||
(firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/)))); | ||
// os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || | ||
// (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/))); | ||
// os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos || | ||
// (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || | ||
// (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/)))); | ||
@@ -92,0 +100,0 @@ return { |
@@ -16,4 +16,14 @@ /** | ||
// BlackBerry 5, iOS 3 (original iPhone) don't have getBoundingRect | ||
return el.getBoundingClientRect ? el.getBoundingClientRect() : { left: 0, top: 0}; | ||
return el.getBoundingClientRect ? el.getBoundingClientRect() : {left: 0, top: 0}; | ||
} | ||
function clientToLocal(el, e, out) { | ||
// clientX/clientY is according to view port. | ||
var box = getBoundingClientRect(el); | ||
out = out || {}; | ||
out.zrX = e.clientX - box.left; | ||
out.zrY = e.clientY - box.top; | ||
return out; | ||
} | ||
/** | ||
@@ -34,5 +44,3 @@ * 如果存在第三方嵌入的一些dom触发的事件,或touch事件,需要转换一下事件坐标 | ||
if (!isTouch) { | ||
var box = getBoundingClientRect(el); | ||
e.zrX = e.clientX - box.left; | ||
e.zrY = e.clientY - box.top; | ||
clientToLocal(el, e, e); | ||
e.zrDelta = (e.wheelDelta) ? e.wheelDelta / 120 : -(e.detail || 0) / 3; | ||
@@ -42,10 +50,5 @@ } | ||
var touch = eventType != 'touchend' | ||
? e.targetTouches[0] | ||
: e.changedTouches[0]; | ||
if (touch) { | ||
var rBounding = getBoundingClientRect(el); | ||
// touch事件坐标是全屏的~ | ||
e.zrX = touch.clientX - rBounding.left; | ||
e.zrY = touch.clientY - rBounding.top; | ||
} | ||
? e.targetTouches[0] | ||
: e.changedTouches[0]; | ||
touch && clientToLocal(el, touch, e); | ||
} | ||
@@ -92,2 +95,3 @@ | ||
return { | ||
clientToLocal: clientToLocal, | ||
normalizeEvent: normalizeEvent, | ||
@@ -94,0 +98,0 @@ addEventListener: addEventListener, |
@@ -8,2 +8,4 @@ /** | ||
var eventUtil = require('./event'); | ||
var GestureMgr = function () { | ||
@@ -22,4 +24,4 @@ | ||
recognize: function (event, target) { | ||
this._doTrack(event, target); | ||
recognize: function (event, target, root) { | ||
this._doTrack(event, target, root); | ||
return this._recognize(event); | ||
@@ -33,3 +35,3 @@ }, | ||
_doTrack: function (event, target) { | ||
_doTrack: function (event, target, root) { | ||
var touches = event.touches; | ||
@@ -50,3 +52,4 @@ | ||
var touch = touches[i]; | ||
trackItem.points.push([touch.clientX, touch.clientY]); | ||
var pos = eventUtil.clientToLocal(root, touch); | ||
trackItem.points.push([pos.zrX, pos.zrY]); | ||
trackItem.touches.push(touch); | ||
@@ -53,0 +56,0 @@ } |
@@ -7,10 +7,8 @@ /** | ||
define( | ||
function() { | ||
var idStart = 0x0907; | ||
define(function() { | ||
var idStart = 0x0907; | ||
return function () { | ||
return 'zr_' + (idStart++); | ||
}; | ||
} | ||
); | ||
return function () { | ||
return idStart++; | ||
}; | ||
}); |
@@ -150,3 +150,3 @@ /** | ||
// Force draw the first segment | ||
|| this._len === 0; | ||
|| this._len < 5; | ||
@@ -427,3 +427,4 @@ this.addData(CMD.L, x, y); | ||
while ((dx >= 0 && x <= x1) || (dx < 0 && x > x1)) { | ||
while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1) | ||
|| (dx == 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) { | ||
idx = this._dashIdx; | ||
@@ -435,3 +436,3 @@ dash = lineDash[idx]; | ||
// Skip positive offset | ||
if ((dx > 0 && x < x0) || (dx < 0 && x > x0)) { | ||
if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) { | ||
continue; | ||
@@ -438,0 +439,0 @@ } |
@@ -5,3 +5,3 @@ /** | ||
define(function(require) { | ||
var Gradient = require('../graphic/Gradient'); | ||
// 用于处理merge时无法遍历Date等对象的问题 | ||
@@ -13,3 +13,6 @@ var BUILTIN_OBJECT = { | ||
'[object Error]': 1, | ||
'[object CanvasGradient]': 1 | ||
'[object CanvasGradient]': 1, | ||
'[object CanvasPattern]': 1, | ||
// In node-canvas Image can be Canvas.Image | ||
'[object Image]': 1 | ||
}; | ||
@@ -411,4 +414,3 @@ | ||
function isBuildInObject(value) { | ||
return !!BUILTIN_OBJECT[objToString.call(value)] | ||
|| (value instanceof Gradient); | ||
return !!BUILTIN_OBJECT[objToString.call(value)]; | ||
} | ||
@@ -415,0 +417,0 @@ |
@@ -22,4 +22,10 @@ define(function () { | ||
var out = new ArrayCtor(2); | ||
out[0] = x || 0; | ||
out[1] = y || 0; | ||
if (x == null) { | ||
x = 0; | ||
} | ||
if (y == null) { | ||
y = 0; | ||
} | ||
out[0] = x; | ||
out[1] = y; | ||
return out; | ||
@@ -26,0 +32,0 @@ }, |
@@ -98,3 +98,3 @@ /** | ||
this.decomposeTransform(); | ||
this.dirty(); | ||
this.dirty(false); | ||
}, | ||
@@ -174,4 +174,5 @@ | ||
} | ||
this.dirty(); | ||
this.dirty(false); | ||
return this; | ||
@@ -198,3 +199,3 @@ }, | ||
this.dirty(); | ||
this.dirty(false); | ||
}, | ||
@@ -215,3 +216,3 @@ | ||
this.dirty(); | ||
this.dirty(false); | ||
} | ||
@@ -218,0 +219,0 @@ }, |
@@ -38,3 +38,3 @@ // CompoundPath to improve performance | ||
for (var i = 0; i < paths.length; i++) { | ||
paths[i].buildPath(ctx, paths[i].shape); | ||
paths[i].buildPath(ctx, paths[i].shape, true); | ||
} | ||
@@ -41,0 +41,0 @@ }, |
@@ -141,2 +141,9 @@ /** | ||
/** | ||
* Render the element progressively when the value >= 0, | ||
* usefull for large data. | ||
* @type {number} | ||
*/ | ||
progressive: -1, | ||
beforeBrush: function (ctx) {}, | ||
@@ -151,3 +158,3 @@ | ||
// Interface | ||
brush: function (ctx) {}, | ||
brush: function (ctx, prevEl) {}, | ||
@@ -154,0 +161,0 @@ /** |
@@ -31,3 +31,3 @@ /** | ||
brush: function (ctx) { | ||
brush: function (ctx, prevEl) { | ||
var style = this.style; | ||
@@ -37,2 +37,5 @@ var src = style.image; | ||
// Must bind each time | ||
style.bind(ctx, this, prevEl); | ||
// style.image is a url string | ||
@@ -97,6 +100,2 @@ if (typeof src === 'string') { | ||
ctx.save(); | ||
style.bind(ctx); | ||
// 设置transform | ||
@@ -145,2 +144,4 @@ this.setTransform(ctx); | ||
this.restoreTransform(ctx); | ||
// Draw rect text | ||
@@ -151,3 +152,2 @@ if (style.text != null) { | ||
ctx.restore(); | ||
} | ||
@@ -154,0 +154,0 @@ }, |
@@ -15,4 +15,5 @@ define(function(require) { | ||
* @param {Array.<Object>} colorStops | ||
* @param {boolean} [globalCoord=false] | ||
*/ | ||
var LinearGradient = function (x, y, x2, y2, colorStops) { | ||
var LinearGradient = function (x, y, x2, y2, colorStops, globalCoord) { | ||
this.x = x == null ? 0 : x; | ||
@@ -26,2 +27,8 @@ | ||
// Can be cloned | ||
this.type = 'linear'; | ||
// If use global coord | ||
this.global = globalCoord || false; | ||
Gradient.call(this, colorStops); | ||
@@ -32,5 +39,3 @@ }; | ||
constructor: LinearGradient, | ||
type: 'linear' | ||
constructor: LinearGradient | ||
}; | ||
@@ -37,0 +42,0 @@ |
@@ -47,2 +47,6 @@ /** | ||
} | ||
// FIXME | ||
ctx.save(); | ||
var x; | ||
@@ -61,3 +65,2 @@ var y; | ||
var transform = this.transform; | ||
var invTransform = this.invTransform; | ||
if (transform) { | ||
@@ -67,4 +70,2 @@ tmpRect.copy(rect); | ||
rect = tmpRect; | ||
// Transform back | ||
setTransform(ctx, invTransform); | ||
} | ||
@@ -106,4 +107,6 @@ | ||
ctx.textAlign = align; | ||
ctx.textBaseline = baseline; | ||
// Use canvas default left textAlign. Giving invalid value will cause state not change | ||
ctx.textAlign = align || 'left'; | ||
// Use canvas default alphabetic baseline | ||
ctx.textBaseline = baseline || 'alphabetic'; | ||
@@ -117,4 +120,5 @@ var textFill = style.textFill; | ||
// Text shadow | ||
ctx.shadowColor = style.textShadowColor; | ||
// Always set shadowBlur and shadowOffset to avoid leak from displayable | ||
ctx.shadowBlur = style.textShadowBlur; | ||
ctx.shadowColor = style.textShadowColor || 'transparent'; | ||
ctx.shadowOffsetX = style.textShadowOffsetX; | ||
@@ -130,4 +134,3 @@ ctx.shadowOffsetY = style.textShadowOffsetY; | ||
// Transform again | ||
transform && setTransform(ctx, transform); | ||
ctx.restore(); | ||
} | ||
@@ -134,0 +137,0 @@ }; |
@@ -13,14 +13,5 @@ /** | ||
var Gradient = require('./Gradient'); | ||
var Pattern = require('./Pattern'); | ||
var getCanvasPattern = Pattern.prototype.getCanvasPattern; | ||
function pathHasFill(style) { | ||
var fill = style.fill; | ||
return fill != null && fill !== 'none'; | ||
} | ||
function pathHasStroke(style) { | ||
var stroke = style.stroke; | ||
return stroke != null && stroke !== 'none' && style.lineWidth > 0; | ||
} | ||
var abs = Math.abs; | ||
@@ -54,32 +45,41 @@ | ||
brush: function (ctx) { | ||
ctx.save(); | ||
brush: function (ctx, prevEl) { | ||
var style = this.style; | ||
var path = this.path; | ||
var hasStroke = pathHasStroke(style); | ||
var hasFill = pathHasFill(style); | ||
var hasFillGradient = hasFill && !!(style.fill.colorStops); | ||
var hasStrokeGradient = hasStroke && !!(style.stroke.colorStops); | ||
var hasStroke = style.hasStroke(); | ||
var hasFill = style.hasFill(); | ||
var fill = style.fill; | ||
var stroke = style.stroke; | ||
var hasFillGradient = hasFill && !!(fill.colorStops); | ||
var hasStrokeGradient = hasStroke && !!(stroke.colorStops); | ||
var hasFillPattern = hasFill && !!(fill.image); | ||
var hasStrokePattern = hasStroke && !!(stroke.image); | ||
style.bind(ctx, this); | ||
style.bind(ctx, this, prevEl); | ||
this.setTransform(ctx); | ||
if (this.__dirtyPath) { | ||
if (this.__dirty) { | ||
var rect = this.getBoundingRect(); | ||
// Update gradient because bounding rect may changed | ||
if (hasFillGradient) { | ||
this._fillGradient = style.getGradient(ctx, style.fill, rect); | ||
this._fillGradient = style.getGradient(ctx, fill, rect); | ||
} | ||
if (hasStrokeGradient) { | ||
this._strokeGradient = style.getGradient(ctx, style.stroke, rect); | ||
this._strokeGradient = style.getGradient(ctx, stroke, rect); | ||
} | ||
} | ||
// Use the gradient | ||
// Use the gradient or pattern | ||
if (hasFillGradient) { | ||
// PENDING If may have affect the state | ||
ctx.fillStyle = this._fillGradient; | ||
} | ||
else if (hasFillPattern) { | ||
ctx.fillStyle = getCanvasPattern.call(fill, ctx); | ||
} | ||
if (hasStrokeGradient) { | ||
ctx.strokeStyle = this._strokeGradient; | ||
} | ||
else if (hasStrokePattern) { | ||
ctx.strokeStyle = getCanvasPattern.call(stroke, ctx); | ||
} | ||
@@ -111,3 +111,3 @@ var lineDash = style.lineDash; | ||
this.buildPath(path, this.shape); | ||
this.buildPath(path, this.shape, false); | ||
@@ -132,12 +132,21 @@ // Clear path dirty flag | ||
if (lineDash && ctxLineDash) { | ||
// PENDING | ||
// Remove lineDash | ||
ctx.setLineDash([]); | ||
} | ||
this.restoreTransform(ctx); | ||
// Draw rect text | ||
if (style.text != null) { | ||
if (style.text || style.text === 0) { | ||
// var rect = this.getBoundingRect(); | ||
this.drawRectText(ctx, this.getBoundingRect()); | ||
} | ||
ctx.restore(); | ||
}, | ||
buildPath: function (ctx, shapeCfg) {}, | ||
// When bundling path, some shape may decide if use moveTo to begin a new subpath or closePath | ||
// Like in circle | ||
buildPath: function (ctx, shapeCfg, inBundle) {}, | ||
@@ -152,3 +161,3 @@ getBoundingRect: function () { | ||
path.beginPath(); | ||
this.buildPath(path, this.shape); | ||
this.buildPath(path, this.shape, false); | ||
} | ||
@@ -159,3 +168,3 @@ rect = path.getBoundingRect(); | ||
if (pathHasStroke(style)) { | ||
if (style.hasStroke()) { | ||
// Needs update rect with stroke lineWidth when | ||
@@ -173,3 +182,3 @@ // 1. Element changes scale or lineWidth | ||
// Only add extra hover lineWidth when there are no fill | ||
if (!pathHasFill(style)) { | ||
if (!style.hasFill()) { | ||
w = Math.max(w, this.strokeContainThreshold); | ||
@@ -203,3 +212,3 @@ } | ||
var pathData = this.path.data; | ||
if (pathHasStroke(style)) { | ||
if (style.hasStroke()) { | ||
var lineWidth = style.lineWidth; | ||
@@ -210,3 +219,3 @@ var lineScale = style.strokeNoScale ? this.getLineScale() : 1; | ||
// Only add extra hover lineWidth when there are no fill | ||
if (!pathHasFill(style)) { | ||
if (!style.hasFill()) { | ||
lineWidth = Math.max(lineWidth, this.strokeContainThreshold); | ||
@@ -221,3 +230,3 @@ } | ||
} | ||
if (pathHasFill(style)) { | ||
if (style.hasFill()) { | ||
return pathContain.contain(pathData, x, y); | ||
@@ -233,3 +242,3 @@ } | ||
dirty: function (dirtyPath) { | ||
if (arguments.length ===0) { | ||
if (dirtyPath == null) { | ||
dirtyPath = true; | ||
@@ -266,2 +275,4 @@ } | ||
this.setShape(value); | ||
this.__dirtyPath = true; | ||
this._rect = null; | ||
} | ||
@@ -268,0 +279,0 @@ else { |
@@ -14,4 +14,5 @@ define(function(require) { | ||
* @param {Array.<Object>} [colorStops] | ||
* @param {boolean} [globalCoord=false] | ||
*/ | ||
var RadialGradient = function (x, y, r, colorStops) { | ||
var RadialGradient = function (x, y, r, colorStops, globalCoord) { | ||
this.x = x == null ? 0.5 : x; | ||
@@ -23,2 +24,8 @@ | ||
// Can be cloned | ||
this.type = 'radial'; | ||
// If use global coord | ||
this.global = globalCoord || false; | ||
Gradient.call(this, colorStops); | ||
@@ -29,5 +36,3 @@ }; | ||
constructor: RadialGradient, | ||
type: 'radial' | ||
constructor: RadialGradient | ||
}; | ||
@@ -34,0 +39,0 @@ |
@@ -10,3 +10,3 @@ /** | ||
return require('../Path').extend({ | ||
type: 'circle', | ||
@@ -20,9 +20,14 @@ | ||
buildPath : function (ctx, shape) { | ||
buildPath : function (ctx, shape, inBundle) { | ||
// Better stroking in ShapeBundle | ||
ctx.moveTo(shape.cx + shape.r, shape.cy); | ||
// Always do it may have performence issue ( fill may be 2x more cost) | ||
if (inBundle) { | ||
ctx.moveTo(shape.cx + shape.r, shape.cy); | ||
} | ||
// Better stroking in ShapeBundle | ||
// ctx.moveTo(shape.cx + shape.r, shape.cy); | ||
ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true); | ||
return; | ||
} | ||
}); | ||
}); |
/** | ||
* @module zrender/graphic/Style | ||
*/ | ||
define(function (require) { | ||
var STYLE_LIST_COMMON = [ | ||
'lineCap', 'lineJoin', 'miterLimit', | ||
'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'shadowColor' | ||
var STYLE_COMMON_PROPS = [ | ||
['shadowBlur', 0], ['shadowOffsetX', 0], ['shadowOffsetY', 0], ['shadowColor', '#000'], | ||
['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10] | ||
]; | ||
// var SHADOW_PROPS = STYLE_COMMON_PROPS.slice(0, 4); | ||
// var LINE_PROPS = STYLE_COMMON_PROPS.slice(4); | ||
var Style = function (opts) { | ||
@@ -16,2 +18,41 @@ this.extendFrom(opts); | ||
function createLinearGradient(ctx, obj, rect) { | ||
// var size = | ||
var x = obj.x; | ||
var x2 = obj.x2; | ||
var y = obj.y; | ||
var y2 = obj.y2; | ||
if (!obj.global) { | ||
x = x * rect.width + rect.x; | ||
x2 = x2 * rect.width + rect.x; | ||
y = y * rect.height + rect.y; | ||
y2 = y2 * rect.height + rect.y; | ||
} | ||
var canvasGradient = ctx.createLinearGradient(x, y, x2, y2); | ||
return canvasGradient; | ||
} | ||
function createRadialGradient(ctx, obj, rect) { | ||
var width = rect.width; | ||
var height = rect.height; | ||
var min = Math.min(width, height); | ||
var x = obj.x; | ||
var y = obj.y; | ||
var r = obj.r; | ||
if (!obj.global) { | ||
x = x * width + rect.x; | ||
y = y * height + rect.y; | ||
r = r * min; | ||
} | ||
var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r); | ||
return canvasGradient; | ||
} | ||
Style.prototype = { | ||
@@ -133,16 +174,40 @@ | ||
/** | ||
* @type {string} | ||
* https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation | ||
*/ | ||
blend: null, | ||
/** | ||
* @param {CanvasRenderingContext2D} ctx | ||
*/ | ||
bind: function (ctx, el) { | ||
var fill = this.fill; | ||
var stroke = this.stroke; | ||
for (var i = 0; i < STYLE_LIST_COMMON.length; i++) { | ||
var styleName = STYLE_LIST_COMMON[i]; | ||
bind: function (ctx, el, prevEl) { | ||
var style = this; | ||
var prevStyle = prevEl && prevEl.style; | ||
var firstDraw = !prevStyle; | ||
if (this[styleName] != null) { | ||
ctx[styleName] = this[styleName]; | ||
for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) { | ||
var prop = STYLE_COMMON_PROPS[i]; | ||
var styleName = prop[0]; | ||
if (firstDraw || style[styleName] !== prevStyle[styleName]) { | ||
// FIXME Invalid property value will cause style leak from previous element. | ||
ctx[styleName] = style[styleName] || prop[1]; | ||
} | ||
} | ||
if (stroke != null) { | ||
var lineWidth = this.lineWidth; | ||
if ((firstDraw || style.fill !== prevStyle.fill)) { | ||
ctx.fillStyle = style.fill; | ||
} | ||
if ((firstDraw || style.stroke !== prevStyle.stroke)) { | ||
ctx.strokeStyle = style.stroke; | ||
} | ||
if ((firstDraw || style.opacity !== prevStyle.opacity)) { | ||
ctx.globalAlpha = style.opacity == null ? 1 : style.opacity; | ||
} | ||
if ((firstDraw || style.blend !== prevStyle.blend)) { | ||
ctx.globalCompositeOperation = style.blend || 'source-over'; | ||
} | ||
if (this.hasStroke()) { | ||
var lineWidth = style.lineWidth; | ||
ctx.lineWidth = lineWidth / ( | ||
@@ -152,13 +217,14 @@ (this.strokeNoScale && el && el.getLineScale) ? el.getLineScale() : 1 | ||
} | ||
// Gradient will be created and set in Path#brush. So ignore it here | ||
if (fill != null && fill !== 'none' && !fill.colorStops) { | ||
ctx.fillStyle = fill; | ||
} | ||
if (stroke != null && stroke !== 'none' && !stroke.colorStops) { | ||
// Use canvas gradient if has | ||
ctx.strokeStyle = stroke; | ||
} | ||
this.opacity != null && (ctx.globalAlpha = this.opacity); | ||
}, | ||
hasFill: function () { | ||
var fill = this.fill; | ||
return fill != null && fill !== 'none'; | ||
}, | ||
hasStroke: function () { | ||
var stroke = this.stroke; | ||
return stroke != null && stroke !== 'none' && this.lineWidth > 0; | ||
}, | ||
/** | ||
@@ -206,31 +272,5 @@ * Extend from other style | ||
createLinearGradient: function (ctx, obj, rect) { | ||
// var size = | ||
var x = obj.x * rect.width + rect.x; | ||
var x2 = obj.x2 * rect.width + rect.x; | ||
var y = obj.y * rect.height + rect.y; | ||
var y2 = obj.y2 * rect.height + rect.y; | ||
var canvasGradient = ctx.createLinearGradient(x, y, x2, y2); | ||
return canvasGradient; | ||
}, | ||
createRadialGradient: function (ctx, obj, rect) { | ||
var width = rect.width; | ||
var height = rect.height; | ||
var min = Math.min(width, height); | ||
var x = obj.x * width + rect.x; | ||
var y = obj.y * height + rect.y; | ||
var r = obj.r * min; | ||
var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r); | ||
return canvasGradient; | ||
}, | ||
getGradient: function (ctx, obj, rect) { | ||
var method = obj.type === 'radial' ? 'createRadialGradient' : 'createLinearGradient'; | ||
var canvasGradient = this[method](ctx, obj, rect); | ||
var method = obj.type === 'radial' ? createRadialGradient : createLinearGradient; | ||
var canvasGradient = method(ctx, obj, rect); | ||
var colorStops = obj.colorStops; | ||
@@ -247,12 +287,13 @@ for (var i = 0; i < colorStops.length; i++) { | ||
var styleProto = Style.prototype; | ||
var name; | ||
var i; | ||
for (i = 0; i < STYLE_LIST_COMMON.length; i++) { | ||
name = STYLE_LIST_COMMON[i]; | ||
if (!(name in styleProto)) { | ||
styleProto[name] = null; | ||
for (var i = 0; i < STYLE_COMMON_PROPS.length; i++) { | ||
var prop = STYLE_COMMON_PROPS[i]; | ||
if (!(prop[0] in styleProto)) { | ||
styleProto[prop[0]] = prop[1]; | ||
} | ||
} | ||
// Provide for others | ||
Style.getGradient = styleProto.getGradient; | ||
return Style; | ||
}); |
@@ -32,3 +32,3 @@ /** | ||
brush: function (ctx) { | ||
brush: function (ctx, prevEl) { | ||
var style = this.style; | ||
@@ -39,4 +39,2 @@ var x = style.x || 0; | ||
var text = style.text; | ||
var textFill = style.fill; | ||
var textStroke = style.stroke; | ||
@@ -46,14 +44,11 @@ // Convert to string | ||
// Always bind style | ||
style.bind(ctx, this, prevEl); | ||
if (text) { | ||
ctx.save(); | ||
this.style.bind(ctx); | ||
this.setTransform(ctx); | ||
textFill && (ctx.fillStyle = textFill); | ||
textStroke && (ctx.strokeStyle = textStroke); | ||
ctx.font = style.textFont || style.font; | ||
ctx.textAlign = style.textAlign; | ||
var textBaseline; | ||
var textAlign = style.textAlign; | ||
if (style.textVerticalAlign) { | ||
@@ -64,3 +59,3 @@ var rect = textContain.getBoundingRect( | ||
// Ignore textBaseline | ||
ctx.textBaseline = 'middle'; | ||
textBaseline = 'middle'; | ||
switch (style.textVerticalAlign) { | ||
@@ -78,4 +73,17 @@ case 'middle': | ||
else { | ||
ctx.textBaseline = style.textBaseline; | ||
textBaseline = style.textBaseline; | ||
} | ||
ctx.font = style.textFont || style.font; | ||
ctx.textAlign = textAlign || 'left'; | ||
// Use canvas default left textAlign. Giving invalid value will cause state not change | ||
if (ctx.textAlign !== textAlign) { | ||
ctx.textAlign = 'left'; | ||
} | ||
ctx.textBaseline = textBaseline || 'alphabetic'; | ||
// Use canvas default alphabetic baseline | ||
if (ctx.textBaseline !== textBaseline) { | ||
ctx.textBaseline = 'alphabetic'; | ||
} | ||
var lineHeight = textContain.measureText('国', ctx.font).width; | ||
@@ -85,8 +93,8 @@ | ||
for (var i = 0; i < textLines.length; i++) { | ||
textFill && ctx.fillText(textLines[i], x, y); | ||
textStroke && ctx.strokeText(textLines[i], x, y); | ||
style.hasFill() && ctx.fillText(textLines[i], x, y); | ||
style.hasStroke() && ctx.strokeText(textLines[i], x, y); | ||
y += lineHeight; | ||
} | ||
ctx.restore(); | ||
this.restoreTransform(ctx); | ||
} | ||
@@ -93,0 +101,0 @@ }, |
@@ -74,3 +74,3 @@ /** | ||
this.root.style.cursor = hovered ? hovered.cursor : this._defaultCursorStyle; | ||
this.root.style.cursor = hovered ? hovered.cursor : 'default'; | ||
// Mouse out on previous hovered element | ||
@@ -225,3 +225,4 @@ if (lastHovered && hovered !== lastHovered && lastHovered.__zr) { | ||
event, | ||
zrHandler.findHover(event.zrX, event.zrY, null) | ||
zrHandler.findHover(event.zrX, event.zrY, null), | ||
zrHandler.root | ||
); | ||
@@ -309,8 +310,2 @@ | ||
* @private | ||
* @type {string} | ||
*/ | ||
this._defaultCursorStyle = 'default'; | ||
/** | ||
* @private | ||
* @type {module:zrender/core/GestureMgr} | ||
@@ -405,6 +400,6 @@ */ | ||
* 设置默认的cursor style | ||
* @param {string} cursorStyle 例如 crosshair | ||
* @param {string} [cursorStyle='default'] 例如 crosshair | ||
*/ | ||
setDefaultCursorStyle: function (cursorStyle) { | ||
this._defaultCursorStyle = cursorStyle; | ||
setCursorStyle: function (cursorStyle) { | ||
this.root.style.cursor = cursorStyle || 'default'; | ||
}, | ||
@@ -411,0 +406,0 @@ |
@@ -9,2 +9,4 @@ /** | ||
var config = require('./config'); | ||
var Style = require('./graphic/Style'); | ||
var Pattern = require('./graphic/Pattern'); | ||
@@ -178,3 +180,3 @@ function returnFalse() { | ||
var haveClearColor = this.clearColor; | ||
var clearColor = this.clearColor; | ||
var haveMotionBLur = this.motionBlur && !clearAll; | ||
@@ -199,5 +201,22 @@ var lastFrameAlpha = this.lastFrameAlpha; | ||
ctx.clearRect(0, 0, width / dpr, height / dpr); | ||
if (haveClearColor) { | ||
if (clearColor) { | ||
var clearColorGradientOrPattern; | ||
// Gradient | ||
if (clearColor.colorStops) { | ||
// Cache canvas gradient | ||
clearColorGradientOrPattern = clearColor.__canvasGradient || Style.getGradient(ctx, clearColor, { | ||
x: 0, | ||
y: 0, | ||
width: width / dpr, | ||
height: height / dpr | ||
}); | ||
clearColor.__canvasGradient = clearColorGradientOrPattern; | ||
} | ||
// Pattern | ||
else if (clearColor.image) { | ||
clearColorGradientOrPattern = Pattern.prototype.getCanvasPattern.call(clearColor, ctx); | ||
} | ||
ctx.save(); | ||
ctx.fillStyle = this.clearColor; | ||
ctx.fillStyle = clearColorGradientOrPattern || clearColor; | ||
ctx.fillRect(0, 0, width / dpr, height / dpr); | ||
@@ -204,0 +223,0 @@ ctx.restore(); |
@@ -10,4 +10,2 @@ /** | ||
var arrySlice = Array.prototype.slice; | ||
var zrUtil = require('../core/util'); | ||
var indexOf = zrUtil.indexOf; | ||
@@ -45,4 +43,6 @@ /** | ||
if (indexOf(_h[event], event) >= 0) { | ||
return this; | ||
for (var i = 0; i < _h[event].length; i++) { | ||
if (_h[event][i].h === handler) { | ||
return this; | ||
} | ||
} | ||
@@ -76,2 +76,8 @@ | ||
for (var i = 0; i < _h[event].length; i++) { | ||
if (_h[event][i].h === handler) { | ||
return this; | ||
} | ||
} | ||
_h[event].push({ | ||
@@ -78,0 +84,0 @@ h: handler, |
@@ -150,2 +150,9 @@ /** | ||
transformableProto.restoreTransform = function (ctx) { | ||
var m = this.invTransform; | ||
if (m) { | ||
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]); | ||
} | ||
} | ||
var tmpTransform = []; | ||
@@ -152,0 +159,0 @@ |
@@ -15,5 +15,14 @@ /** | ||
var BoundingRect = require('./core/BoundingRect'); | ||
var timsort = require('./core/timsort'); | ||
var Layer = require('./Layer'); | ||
var requestAnimationFrame = require('./animation/requestAnimationFrame'); | ||
// PENDIGN | ||
// Layer exceeds MAX_PROGRESSIVE_LAYER_NUMBER may have some problem when flush directly second time. | ||
// | ||
// Maximum progressive layer. When exceeding this number. All elements will be drawed in the last layer. | ||
var MAX_PROGRESSIVE_LAYER_NUMBER = 5; | ||
function parseInt10(val) { | ||
@@ -46,3 +55,2 @@ return parseInt(val, 10); | ||
function postProcessLayer(layer) { | ||
layer.__dirty = false; | ||
if (layer.__unusedCount == 1) { | ||
@@ -66,2 +74,6 @@ layer.clear(); | ||
function isClipPathChanged(clipPaths, prevClipPaths) { | ||
if (clipPaths == prevClipPaths) { // Can both be null or undefined | ||
return false; | ||
} | ||
if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) { | ||
@@ -105,2 +117,14 @@ return true; | ||
function createRoot(width, height) { | ||
var domRoot = document.createElement('div'); | ||
var domRootStyle = domRoot.style; | ||
// domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬 | ||
domRootStyle.position = 'relative'; | ||
domRootStyle.overflow = 'hidden'; | ||
domRootStyle.width = width + 'px'; | ||
domRootStyle.height = height + 'px'; | ||
return domRoot; | ||
} | ||
/** | ||
@@ -114,2 +138,3 @@ * @alias module:zrender/Painter | ||
var Painter = function (root, storage, opts) { | ||
// In node environment using node-canvas | ||
var singleCanvas = !root.nodeName // In node ? | ||
@@ -137,7 +162,6 @@ || root.nodeName.toUpperCase() === 'CANVAS'; | ||
// In node environment using node-canvas | ||
if (rootStyle) { | ||
rootStyle['-webkit-tap-highlight-color'] = 'transparent'; | ||
rootStyle['-webkit-user-select'] = 'none'; | ||
rootStyle['user-select'] = 'none'; | ||
rootStyle['-webkit-user-select'] = | ||
rootStyle['user-select'] = | ||
rootStyle['-webkit-touch-callout'] = 'none'; | ||
@@ -153,29 +177,28 @@ | ||
/** | ||
* @type {Array.<number>} | ||
* @private | ||
*/ | ||
var zlevelList = this._zlevelList = []; | ||
/** | ||
* @type {Object.<string, module:zrender/Layer>} | ||
* @private | ||
*/ | ||
var layers = this._layers = {}; | ||
/** | ||
* @type {Object.<string, Object>} | ||
* @type {private} | ||
*/ | ||
this._layerConfig = {}; | ||
if (!singleCanvas) { | ||
var width = this._getWidth(); | ||
var height = this._getHeight(); | ||
this._width = width; | ||
this._height = height; | ||
this._width = this._getWidth(); | ||
this._height = this._getHeight(); | ||
var domRoot = document.createElement('div'); | ||
this._domRoot = domRoot; | ||
var domRootStyle = domRoot.style; | ||
// domRoot.onselectstart = returnFalse; // 避免页面选中的尴尬 | ||
domRootStyle.position = 'relative'; | ||
domRootStyle.overflow = 'hidden'; | ||
domRootStyle.width = this._width + 'px'; | ||
domRootStyle.height = this._height + 'px'; | ||
var domRoot = this._domRoot = createRoot( | ||
this._width, this._height | ||
); | ||
root.appendChild(domRoot); | ||
/** | ||
* @type {Object.<key, module:zrender/Layer>} | ||
* @private | ||
*/ | ||
this._layers = {}; | ||
/** | ||
* @type {Array.<number>} | ||
* @private | ||
*/ | ||
this._zlevelList = []; | ||
} | ||
@@ -195,11 +218,18 @@ else { | ||
// mainLayer.resize(width, height); | ||
this._layers = { | ||
0: mainLayer | ||
}; | ||
this._zlevelList = [0]; | ||
layers[0] = mainLayer; | ||
zlevelList.push(0); | ||
} | ||
this._layerConfig = {}; | ||
this.pathToImage = this._createPathToImage(); | ||
this.pathToImage = this._createPathToImage(); | ||
// Layers for progressive rendering | ||
this._progressiveLayers = []; | ||
/** | ||
* @type {module:zrender/Layer} | ||
* @private | ||
*/ | ||
this._hoverlayer; | ||
this._hoverElements = []; | ||
}; | ||
@@ -230,3 +260,5 @@ | ||
refresh: function (paintAll) { | ||
var list = this.storage.getDisplayList(true); | ||
var zlevelList = this._zlevelList; | ||
@@ -245,5 +277,130 @@ | ||
this.refreshHover(); | ||
if (this._progressiveLayers.length) { | ||
this._startProgessive(); | ||
} | ||
return this; | ||
}, | ||
addHover: function (el, hoverStyle) { | ||
if (el.__hoverMir) { | ||
return; | ||
} | ||
var elMirror = new el.constructor({ | ||
style: el.style, | ||
shape: el.shape | ||
}); | ||
elMirror.__from = el; | ||
el.__hoverMir = elMirror; | ||
elMirror.setStyle(hoverStyle); | ||
this._hoverElements.push(elMirror); | ||
}, | ||
removeHover: function (el) { | ||
var elMirror = el.__hoverMir; | ||
var hoverElements = this._hoverElements; | ||
var idx = util.indexOf(hoverElements, elMirror); | ||
if (idx >= 0) { | ||
hoverElements.splice(idx, 1); | ||
} | ||
el.__hoverMir = null; | ||
}, | ||
clearHover: function (el) { | ||
var hoverElements = this._hoverElements; | ||
for (var i = 0; i < hoverElements.length; i++) { | ||
var from = hoverElements[i].__from; | ||
if (from) { | ||
from.__hoverMir = null; | ||
} | ||
} | ||
hoverElements.length = 0; | ||
}, | ||
refreshHover: function () { | ||
var hoverElements = this._hoverElements; | ||
var len = hoverElements.length; | ||
var hoverLayer = this._hoverlayer; | ||
hoverLayer && hoverLayer.clear(); | ||
if (!len) { | ||
return; | ||
} | ||
timsort(hoverElements, this.storage.displayableSortFunc); | ||
// Use a extream large zlevel | ||
// FIXME? | ||
if (!hoverLayer) { | ||
hoverLayer = this._hoverlayer = this.getLayer(1e5); | ||
} | ||
var scope = {}; | ||
hoverLayer.ctx.save(); | ||
for (var i = 0; i < len;) { | ||
var el = hoverElements[i]; | ||
var originalEl = el.__from; | ||
// Original el is removed | ||
// PENDING | ||
if (!(originalEl && originalEl.__zr)) { | ||
hoverElements.splice(i, 1); | ||
originalEl.__hoverMir = null; | ||
len--; | ||
continue; | ||
} | ||
i++; | ||
// Use transform | ||
// FIXME style and shape ? | ||
if (!originalEl.invisible) { | ||
el.transform = originalEl.transform; | ||
el.invTransform = originalEl.invTransform; | ||
el.__clipPaths = originalEl.__clipPaths; | ||
// el. | ||
this._doPaintEl(el, hoverLayer, true, scope); | ||
} | ||
} | ||
hoverLayer.ctx.restore(); | ||
}, | ||
_startProgessive: function () { | ||
var self = this; | ||
if (!self._furtherProgressive) { | ||
return; | ||
} | ||
// Use a token to stop progress steps triggered by | ||
// previous zr.refresh calling. | ||
var token = self._progressiveToken = +new Date(); | ||
self._progress++; | ||
requestAnimationFrame(step); | ||
function step() { | ||
// In case refreshed or disposed | ||
if (token === self._progressiveToken && self.storage) { | ||
self._doPaintList(self.storage.getDisplayList()); | ||
if (self._furtherProgressive) { | ||
self._progress++; | ||
requestAnimationFrame(step); | ||
} | ||
else { | ||
self._progressiveToken = -1; | ||
} | ||
} | ||
} | ||
}, | ||
_clearProgressive: function () { | ||
this._progressiveToken = -1; | ||
this._progress = 0; | ||
util.each(this._progressiveLayers, function (layer) { | ||
layer.__dirty && layer.clear(); | ||
}); | ||
}, | ||
_paintList: function (list, paintAll) { | ||
@@ -257,2 +414,12 @@ | ||
this._clearProgressive(); | ||
this.eachBuildinLayer(preProcessLayer); | ||
this._doPaintList(list, paintAll); | ||
this.eachBuildinLayer(postProcessLayer); | ||
}, | ||
_doPaintList: function (list, paintAll) { | ||
var currentLayer; | ||
@@ -262,15 +429,46 @@ var currentZLevel; | ||
var viewWidth = this._width; | ||
var viewHeight = this._height; | ||
// var invTransform = []; | ||
var scope; | ||
this.eachBuildinLayer(preProcessLayer); | ||
var progressiveLayerIdx = 0; | ||
var currentProgressiveLayer; | ||
// var invTransform = []; | ||
var prevElClipPaths = null; | ||
var width = this._width; | ||
var height = this._height; | ||
var layerProgress; | ||
var frame = this._progress; | ||
function flushProgressiveLayer(layer) { | ||
ctx.save(); | ||
ctx.globalAlpha = 1; | ||
ctx.shadowBlur = 0; | ||
// Avoid layer don't clear in next progressive frame | ||
currentLayer.__dirty = true; | ||
ctx.drawImage(layer.dom, 0, 0, width, height); | ||
ctx.restore(); | ||
currentLayer.ctx.restore(); | ||
} | ||
for (var i = 0, l = list.length; i < l; i++) { | ||
var el = list[i]; | ||
var elZLevel = this._singleCanvas ? 0 : el.zlevel; | ||
var elFrame = el.__frame; | ||
// Flush at current context | ||
// PENDING | ||
if (elFrame < 0 && currentProgressiveLayer) { | ||
flushProgressiveLayer(currentProgressiveLayer); | ||
currentProgressiveLayer = null; | ||
} | ||
// Change draw layer | ||
if (currentZLevel !== elZLevel) { | ||
if (ctx) { | ||
ctx.restore(); | ||
} | ||
// Reset scope | ||
scope = {}; | ||
// Only 0 zlevel if only has one canvas | ||
@@ -288,2 +486,3 @@ currentZLevel = elZLevel; | ||
ctx = currentLayer.ctx; | ||
ctx.save(); | ||
@@ -298,33 +497,43 @@ // Reset the count | ||
if ( | ||
(currentLayer.__dirty || paintAll) | ||
// Ignore invisible element | ||
&& !el.invisible | ||
// Ignore transparent element | ||
&& el.style.opacity !== 0 | ||
// Ignore scale 0 element, in some environment like node-canvas | ||
// Draw a scale 0 element can cause all following draw wrong | ||
&& el.scale[0] && el.scale[1] | ||
// Ignore culled element | ||
&& !(el.culling && isDisplayableCulled(el, viewWidth, viewHeight)) | ||
) { | ||
var clipPaths = el.__clipPaths; | ||
if (!(currentLayer.__dirty || paintAll)) { | ||
continue; | ||
} | ||
if (elFrame >= 0) { | ||
// Progressive layer changed | ||
if (!currentProgressiveLayer) { | ||
currentProgressiveLayer = this._progressiveLayers[ | ||
Math.min(progressiveLayerIdx++, MAX_PROGRESSIVE_LAYER_NUMBER - 1) | ||
]; | ||
// Optimize when clipping on group with several elements | ||
if (isClipPathChanged(clipPaths, prevElClipPaths)) { | ||
// If has previous clipping state, restore from it | ||
if (prevElClipPaths) { | ||
ctx.restore(); | ||
currentProgressiveLayer.ctx.save(); | ||
currentProgressiveLayer.renderScope = {}; | ||
if (currentProgressiveLayer | ||
&& (currentProgressiveLayer.__progress > currentProgressiveLayer.__maxProgress) | ||
) { | ||
// flushProgressiveLayer(currentProgressiveLayer); | ||
// Quick jump all progressive elements | ||
// All progressive element are not dirty, jump over and flush directly | ||
i = currentProgressiveLayer.__nextIdxNotProg - 1; | ||
// currentProgressiveLayer = null; | ||
continue; | ||
} | ||
// New clipping state | ||
if (clipPaths) { | ||
ctx.save(); | ||
doClip(clipPaths, ctx); | ||
layerProgress = currentProgressiveLayer.__progress; | ||
if (!currentProgressiveLayer.__dirty) { | ||
// Keep rendering | ||
frame = layerProgress; | ||
} | ||
prevElClipPaths = clipPaths; | ||
currentProgressiveLayer.__progress = frame + 1; | ||
} | ||
el.beforeBrush && el.beforeBrush(ctx); | ||
el.brush(ctx, false); | ||
el.afterBrush && el.afterBrush(ctx); | ||
if (elFrame === frame) { | ||
this._doPaintEl(el, currentProgressiveLayer, true, currentProgressiveLayer.renderScope); | ||
} | ||
} | ||
else { | ||
this._doPaintEl(el, currentLayer, paintAll, scope); | ||
} | ||
@@ -334,10 +543,68 @@ el.__dirty = false; | ||
// If still has clipping state | ||
if (prevElClipPaths) { | ||
ctx.restore(); | ||
if (currentProgressiveLayer) { | ||
flushProgressiveLayer(currentProgressiveLayer); | ||
} | ||
this.eachBuildinLayer(postProcessLayer); | ||
// Restore the lastLayer ctx | ||
ctx && ctx.restore(); | ||
// If still has clipping state | ||
// if (scope.prevElClipPaths) { | ||
// ctx.restore(); | ||
// } | ||
this._furtherProgressive = false; | ||
util.each(this._progressiveLayers, function (layer) { | ||
if (layer.__maxProgress >= layer.__progress) { | ||
this._furtherProgressive = true; | ||
} | ||
}, this); | ||
}, | ||
_doPaintEl: function (el, currentLayer, forcePaint, scope) { | ||
var ctx = currentLayer.ctx; | ||
if ( | ||
(currentLayer.__dirty || forcePaint) | ||
// Ignore invisible element | ||
&& !el.invisible | ||
// Ignore transparent element | ||
&& el.style.opacity !== 0 | ||
// Ignore scale 0 element, in some environment like node-canvas | ||
// Draw a scale 0 element can cause all following draw wrong | ||
&& el.scale[0] && el.scale[1] | ||
// Ignore culled element | ||
&& !(el.culling && isDisplayableCulled(el, this._width, this._height)) | ||
) { | ||
var clipPaths = el.__clipPaths; | ||
// Optimize when clipping on group with several elements | ||
if (scope.prevClipLayer !== currentLayer | ||
|| isClipPathChanged(clipPaths, scope.prevElClipPaths) | ||
) { | ||
// If has previous clipping state, restore from it | ||
if (scope.prevElClipPaths) { | ||
scope.prevClipLayer.ctx.restore(); | ||
scope.prevClipLayer = scope.prevElClipPaths = null; | ||
// Reset prevEl since context has been restored | ||
scope.prevEl = null; | ||
} | ||
// New clipping state | ||
if (clipPaths) { | ||
ctx.save(); | ||
doClip(clipPaths, ctx); | ||
scope.prevClipLayer = currentLayer; | ||
scope.prevElClipPaths = clipPaths; | ||
} | ||
} | ||
el.beforeBrush && el.beforeBrush(ctx); | ||
el.brush(ctx, scope.prevEl || null); | ||
scope.prevEl = el; | ||
el.afterBrush && el.afterBrush(ctx); | ||
} | ||
}, | ||
/** | ||
@@ -481,10 +748,23 @@ * 获取 zlevel 所在层,如果不存在则会创建一个新的层 | ||
var layers = this._layers; | ||
var progressiveLayers = this._progressiveLayers; | ||
var elCounts = {}; | ||
var elCountsLastFrame = {}; | ||
var progressiveElCountsLastFrame = {}; | ||
this.eachBuildinLayer(function (layer, z) { | ||
elCounts[z] = layer.elCount; | ||
elCountsLastFrame[z] = layer.elCount; | ||
layer.elCount = 0; | ||
layer.__dirty = false; | ||
}); | ||
util.each(progressiveLayers, function (layer, idx) { | ||
progressiveElCountsLastFrame[idx] = layer.elCount; | ||
layer.elCount = 0; | ||
layer.__dirty = false; | ||
}); | ||
var progressiveLayerCount = 0; | ||
var currentProgressiveLayer; | ||
var lastProgressiveKey; | ||
var frameCount = 0; | ||
for (var i = 0, l = list.length; i < l; i++) { | ||
@@ -494,18 +774,71 @@ var el = list[i]; | ||
var layer = layers[zlevel]; | ||
var elProgress = el.progressive; | ||
if (layer) { | ||
layer.elCount++; | ||
// 已经被标记为需要刷新 | ||
if (layer.__dirty) { | ||
continue; | ||
layer.__dirty = layer.__dirty || el.__dirty; | ||
} | ||
/////// Update progressive | ||
if (elProgress >= 0) { | ||
// Fix wrong progressive sequence problem. | ||
if (lastProgressiveKey !== elProgress) { | ||
lastProgressiveKey = elProgress; | ||
frameCount++; | ||
} | ||
layer.__dirty = el.__dirty; | ||
var elFrame = el.__frame = frameCount - 1; | ||
if (!currentProgressiveLayer) { | ||
var idx = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER - 1); | ||
currentProgressiveLayer = progressiveLayers[idx]; | ||
if (!currentProgressiveLayer) { | ||
currentProgressiveLayer = progressiveLayers[idx] = new Layer( | ||
'progressive', this, this.dpr | ||
); | ||
currentProgressiveLayer.initContext(); | ||
} | ||
currentProgressiveLayer.__maxProgress = 0; | ||
} | ||
currentProgressiveLayer.__dirty = currentProgressiveLayer.__dirty || el.__dirty; | ||
currentProgressiveLayer.elCount++; | ||
currentProgressiveLayer.__maxProgress = Math.max( | ||
currentProgressiveLayer.__maxProgress, elFrame | ||
); | ||
if (currentProgressiveLayer.__maxProgress >= currentProgressiveLayer.__progress) { | ||
// Should keep rendering this layer because progressive rendering is not finished yet | ||
layer.__dirty = true; | ||
} | ||
} | ||
else { | ||
el.__frame = -1; | ||
if (currentProgressiveLayer) { | ||
currentProgressiveLayer.__nextIdxNotProg = i; | ||
progressiveLayerCount++; | ||
currentProgressiveLayer = null; | ||
} | ||
} | ||
} | ||
if (currentProgressiveLayer) { | ||
progressiveLayerCount++; | ||
currentProgressiveLayer.__nextIdxNotProg = i; | ||
} | ||
// 层中的元素数量有发生变化 | ||
this.eachBuildinLayer(function (layer, z) { | ||
if (elCounts[z] !== layer.elCount) { | ||
if (elCountsLastFrame[z] !== layer.elCount) { | ||
layer.__dirty = true; | ||
} | ||
}); | ||
progressiveLayers.length = Math.min(progressiveLayerCount, MAX_PROGRESSIVE_LAYER_NUMBER); | ||
util.each(progressiveLayers, function (layer, idx) { | ||
if (progressiveElCountsLastFrame[idx] !== layer.elCount) { | ||
el.__dirty = true; | ||
} | ||
if (layer.__dirty) { | ||
layer.__progress = 0; | ||
} | ||
}); | ||
}, | ||
@@ -639,3 +972,2 @@ | ||
var ctx = imageLayer.ctx; | ||
imageLayer.clearColor = opts.backgroundColor; | ||
@@ -646,10 +978,6 @@ imageLayer.clear(); | ||
var scope = {}; | ||
for (var i = 0; i < displayList.length; i++) { | ||
var el = displayList[i]; | ||
if (!el.invisible) { | ||
el.beforeBrush && el.beforeBrush(ctx); | ||
// TODO Check image cross origin | ||
el.brush(ctx, false); | ||
el.afterBrush && el.afterBrush(ctx); | ||
} | ||
this._doPaintEl(el, imageLayer, true, scope); | ||
} | ||
@@ -656,0 +984,0 @@ |
@@ -13,11 +13,19 @@ /** | ||
var util = require('./core/util'); | ||
var env = require('./core/env'); | ||
var Group = require('./container/Group'); | ||
// Use timsort because in most case elements are partially sorted | ||
// https://jsfiddle.net/pissang/jr4x7mdm/8/ | ||
var timsort = require('./core/timsort'); | ||
function shapeCompareFunc(a, b) { | ||
if (a.zlevel === b.zlevel) { | ||
if (a.z === b.z) { | ||
if (a.z2 === b.z2) { | ||
return a.__renderidx - b.__renderidx; | ||
} | ||
// if (a.z2 === b.z2) { | ||
// // FIXME Slow has renderidx compare | ||
// // http://stackoverflow.com/questions/20883421/sorting-in-javascript-should-every-compare-function-have-a-return-0-statement | ||
// // https://github.com/v8/v8/blob/47cce544a31ed5577ffe2963f67acb4144ee0232/src/js/array.js#L1012 | ||
// return a.__renderidx - b.__renderidx; | ||
// } | ||
return a.z2 - b.z2; | ||
@@ -50,2 +58,12 @@ } | ||
/** | ||
* @param {Function} cb | ||
* | ||
*/ | ||
traverse: function (cb, context) { | ||
for (var i = 0; i < this._roots.length; i++) { | ||
this._roots[i].traverse(cb, context); | ||
} | ||
}, | ||
/** | ||
* 返回所有图形的绘制队列 | ||
@@ -81,7 +99,8 @@ * @param {boolean} [update=false] 是否在返回前更新该数组 | ||
for (var i = 0, len = displayList.length; i < len; i++) { | ||
displayList[i].__renderidx = i; | ||
} | ||
// for (var i = 0, len = displayList.length; i < len; i++) { | ||
// displayList[i].__renderidx = i; | ||
// } | ||
displayList.sort(shapeCompareFunc); | ||
// displayList.sort(shapeCompareFunc); | ||
env.canvasSupported && timsort(displayList, shapeCompareFunc); | ||
}, | ||
@@ -97,4 +116,8 @@ | ||
el.update(); | ||
if (el.__dirty) { | ||
el.update(); | ||
} | ||
el.afterUpdate(); | ||
@@ -118,3 +141,3 @@ | ||
if (el.type == 'group') { | ||
if (el.isGroup) { | ||
var children = el._children; | ||
@@ -127,3 +150,5 @@ | ||
// FIXME __dirtyPath ? | ||
child.__dirty = el.__dirty || child.__dirty; | ||
if (el.__dirty) { | ||
child.__dirty = true; | ||
} | ||
@@ -244,3 +269,5 @@ this._updateAndAddDisplayable(child, clipPaths, includeIgnore); | ||
this._roots = null; | ||
} | ||
}, | ||
displayableSortFunc: shapeCompareFunc | ||
}; | ||
@@ -247,0 +274,0 @@ |
@@ -459,6 +459,7 @@ /** | ||
function stringify(arrColor, type) { | ||
if (type === 'rgb' || type === 'hsv' || type === 'hsl') { | ||
arrColor = arrColor.slice(0, 3); | ||
var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2]; | ||
if (type === 'rgba' || type === 'hsva' || type === 'hsla') { | ||
colorStr += ',' + arrColor[3]; | ||
} | ||
return type + '(' + arrColor.join(',') + ')'; | ||
return type + '(' + colorStr + ')'; | ||
} | ||
@@ -465,0 +466,0 @@ |
@@ -381,8 +381,6 @@ define(function (require) { | ||
var len = pathEls.length; | ||
var pathEl; | ||
var i; | ||
for (i = 0; i < len; i++) { | ||
pathEl = pathEls[i]; | ||
for (var i = 0; i < len; i++) { | ||
var pathEl = pathEls[i]; | ||
if (pathEl.__dirty) { | ||
pathEl.buildPath(pathEl.path, pathEl.shape); | ||
pathEl.buildPath(pathEl.path, pathEl.shape, true); | ||
} | ||
@@ -389,0 +387,0 @@ pathList.push(pathEl.path); |
@@ -217,11 +217,11 @@ // http://www.w3.org/TR/NOTE-VML | ||
var updateStrokeNode = function (el, style) { | ||
if (style.lineJoin != null) { | ||
el.joinstyle = style.lineJoin; | ||
} | ||
if (style.miterLimit != null) { | ||
el.miterlimit = style.miterLimit * Z; | ||
} | ||
if (style.lineCap != null) { | ||
el.endcap = style.lineCap; | ||
} | ||
// if (style.lineJoin != null) { | ||
// el.joinstyle = style.lineJoin; | ||
// } | ||
// if (style.miterLimit != null) { | ||
// el.miterlimit = style.miterLimit * Z; | ||
// } | ||
// if (style.lineCap != null) { | ||
// el.endcap = style.lineCap; | ||
// } | ||
if (style.lineDash != null) { | ||
@@ -836,2 +836,3 @@ el.dashstyle = style.lineDash.join(' '); | ||
+ fontStyle.size + 'px "' + fontStyle.family + '"'; | ||
var baseline = style.textBaseline; | ||
@@ -838,0 +839,0 @@ var verticalAlign = style.textVerticalAlign; |
@@ -151,2 +151,6 @@ /** | ||
clear: function () { | ||
this.root.removeChild(this.vmlViewport); | ||
}, | ||
_getWidth: function () { | ||
@@ -153,0 +157,0 @@ var root = this.root; |
@@ -31,3 +31,3 @@ /*! | ||
*/ | ||
zrender.version = '3.1.0'; | ||
zrender.version = '3.1.1'; | ||
@@ -139,2 +139,5 @@ /** | ||
} | ||
if (self._needsRefreshHover) { | ||
self.refreshHoverImmediately(); | ||
} | ||
} | ||
@@ -184,3 +187,3 @@ } | ||
* 添加元素 | ||
* @param {string|module:zrender/Element} el | ||
* @param {module:zrender/Element} el | ||
*/ | ||
@@ -194,3 +197,3 @@ add: function (el) { | ||
* 删除元素 | ||
* @param {string|module:zrender/Element} el | ||
* @param {module:zrender/Element} el | ||
*/ | ||
@@ -237,2 +240,51 @@ remove: function (el) { | ||
/** | ||
* Add element to hover layer | ||
* @param {module:zrender/Element} el | ||
* @param {Object} style | ||
*/ | ||
addHover: function (el, style) { | ||
if (this.painter.addHover) { | ||
this.painter.addHover(el, style); | ||
this.refreshHover(); | ||
} | ||
}, | ||
/** | ||
* Add element from hover layer | ||
* @param {module:zrender/Element} el | ||
*/ | ||
removeHover: function (el) { | ||
if (this.painter.removeHover) { | ||
this.painter.removeHover(el); | ||
this.refreshHover(); | ||
} | ||
}, | ||
/** | ||
* Clear all hover elements in hover layer | ||
* @param {module:zrender/Element} el | ||
*/ | ||
clearHover: function () { | ||
if (this.painter.clearHover) { | ||
this.painter.clearHover(); | ||
this.refreshHover(); | ||
} | ||
}, | ||
/** | ||
* Refresh hover in next frame | ||
*/ | ||
refreshHover: function () { | ||
this._needsRefreshHover = true; | ||
}, | ||
/** | ||
* Refresh hover immediately | ||
*/ | ||
refreshHoverImmediately: function () { | ||
this._needsRefreshHover = false; | ||
this.painter.refreshHover && this.painter.refreshHover(); | ||
}, | ||
/** | ||
* Resize the canvas. | ||
@@ -293,6 +345,6 @@ * Should be invoked when container size is changed | ||
* Set default cursor | ||
* @param {string} cursorStyle 例如 crosshair | ||
* @param {string} [cursorStyle='default'] 例如 crosshair | ||
*/ | ||
setDefaultCursorStyle: function (cursorStyle) { | ||
this.handler.setDefaultCursorStyle(cursorStyle); | ||
setCursorStyle: function (cursorStyle) { | ||
this.handler && this.handler.setCursorStyle(cursorStyle); | ||
}, | ||
@@ -299,0 +351,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
963948
177
27965