mirror of
https://github.com/konvajs/konva.git
synced 2026-03-03 16:58:33 +08:00
merge
This commit is contained in:
@@ -2,14 +2,21 @@
|
||||
// calculate pixel ratio
|
||||
var canvas = document.createElement('canvas'),
|
||||
context = canvas.getContext('2d'),
|
||||
devicePixelRatio = window.devicePixelRatio || 1,
|
||||
backingStoreRatio = context.webkitBackingStorePixelRatio
|
||||
|| context.mozBackingStorePixelRatio
|
||||
|| context.msBackingStorePixelRatio
|
||||
|| context.oBackingStorePixelRatio
|
||||
|| context.backingStorePixelRatio
|
||||
|| 1,
|
||||
_pixelRatio = devicePixelRatio / backingStoreRatio;
|
||||
// if using a mobile device, calculate the pixel ratio. Otherwise, just use
|
||||
// 1. For desktop browsers, if the user has zoom enabled, it affects the pixel ratio
|
||||
// and causes artifacts on the canvas. As of 02/26/2014, there doesn't seem to be a way
|
||||
// to reliably calculate the browser zoom for modern browsers, which is why we just set
|
||||
// the pixel ratio to 1 for desktops
|
||||
_pixelRatio = Kinetic.UA.mobile ? (function() {
|
||||
var devicePixelRatio = window.devicePixelRatio || 1,
|
||||
backingStoreRatio = context.webkitBackingStorePixelRatio
|
||||
|| context.mozBackingStorePixelRatio
|
||||
|| context.msBackingStorePixelRatio
|
||||
|| context.oBackingStorePixelRatio
|
||||
|| context.backingStorePixelRatio
|
||||
|| 1;
|
||||
return devicePixelRatio / backingStoreRatio;
|
||||
})() : 1;
|
||||
|
||||
/**
|
||||
* Canvas Renderer constructor
|
||||
|
||||
@@ -50,6 +50,7 @@ var Kinetic = {};
|
||||
traceArrMax: 100,
|
||||
dblClickWindow: 400,
|
||||
pixelRatio: undefined,
|
||||
enableThrottling: true,
|
||||
|
||||
// user agent
|
||||
UA: (function() {
|
||||
@@ -60,11 +61,17 @@ var Kinetic = {};
|
||||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(msie) ([\w.]+)/.exec( ua ) ||
|
||||
ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
|
||||
[];
|
||||
[],
|
||||
|
||||
// adding mobile flag as well
|
||||
mobile = !!(navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i));
|
||||
|
||||
return {
|
||||
browser: match[ 1 ] || '',
|
||||
version: match[ 2 ] || '0'
|
||||
version: match[ 2 ] || '0',
|
||||
|
||||
// adding mobile flab
|
||||
mobile: mobile
|
||||
};
|
||||
})(),
|
||||
|
||||
|
||||
181
src/Stage.js
181
src/Stage.js
@@ -342,58 +342,64 @@
|
||||
}
|
||||
},
|
||||
_mouseover: function(evt) {
|
||||
this._fire(CONTENT_MOUSEOVER, evt);
|
||||
if (!Kinetic.UA.mobile) {
|
||||
this._fire(CONTENT_MOUSEOVER, evt);
|
||||
}
|
||||
},
|
||||
_mouseout: function(evt) {
|
||||
this._setPointerPosition(evt);
|
||||
var targetShape = this.targetShape;
|
||||
if (!Kinetic.UA.mobile) {
|
||||
this._setPointerPosition(evt);
|
||||
var targetShape = this.targetShape;
|
||||
|
||||
if(targetShape && !Kinetic.isDragging()) {
|
||||
targetShape._fireAndBubble(MOUSEOUT, evt);
|
||||
targetShape._fireAndBubble(MOUSELEAVE, evt);
|
||||
this.targetShape = null;
|
||||
}
|
||||
this.pointerPos = undefined;
|
||||
|
||||
this._fire(CONTENT_MOUSEOUT, evt);
|
||||
},
|
||||
_mousemove: function(evt) {
|
||||
this._setPointerPosition(evt);
|
||||
var dd = Kinetic.DD,
|
||||
shape = this.getIntersection(this.getPointerPosition());
|
||||
|
||||
if(shape && shape.isListening()) {
|
||||
if(!Kinetic.isDragging() && (!this.targetShape || this.targetShape._id !== shape._id)) {
|
||||
if(this.targetShape) {
|
||||
this.targetShape._fireAndBubble(MOUSEOUT, evt, shape);
|
||||
this.targetShape._fireAndBubble(MOUSELEAVE, evt, shape);
|
||||
}
|
||||
shape._fireAndBubble(MOUSEOVER, evt, this.targetShape);
|
||||
shape._fireAndBubble(MOUSEENTER, evt, this.targetShape);
|
||||
this.targetShape = shape;
|
||||
}
|
||||
else {
|
||||
shape._fireAndBubble(MOUSEMOVE, evt);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* if no shape was detected, clear target shape and try
|
||||
* to run mouseout from previous target shape
|
||||
*/
|
||||
else {
|
||||
if(this.targetShape && !Kinetic.isDragging()) {
|
||||
this.targetShape._fireAndBubble(MOUSEOUT, evt);
|
||||
this.targetShape._fireAndBubble(MOUSELEAVE, evt);
|
||||
if(targetShape && !Kinetic.isDragging()) {
|
||||
targetShape._fireAndBubble(MOUSEOUT, evt);
|
||||
targetShape._fireAndBubble(MOUSELEAVE, evt);
|
||||
this.targetShape = null;
|
||||
}
|
||||
this.pointerPos = undefined;
|
||||
|
||||
this._fire(CONTENT_MOUSEOUT, evt);
|
||||
}
|
||||
},
|
||||
_mousemove: Kinetic.Util._throttle(function(evt) {
|
||||
if (!Kinetic.UA.mobile) {
|
||||
this._setPointerPosition(evt);
|
||||
var dd = Kinetic.DD,
|
||||
shape = this.getIntersection(this.getPointerPosition());
|
||||
|
||||
// content event
|
||||
this._fire(CONTENT_MOUSEMOVE, evt);
|
||||
if(shape && shape.isListening()) {
|
||||
if(!Kinetic.isDragging() && (!this.targetShape || this.targetShape._id !== shape._id)) {
|
||||
if(this.targetShape) {
|
||||
this.targetShape._fireAndBubble(MOUSEOUT, evt, shape);
|
||||
this.targetShape._fireAndBubble(MOUSELEAVE, evt, shape);
|
||||
}
|
||||
shape._fireAndBubble(MOUSEOVER, evt, this.targetShape);
|
||||
shape._fireAndBubble(MOUSEENTER, evt, this.targetShape);
|
||||
this.targetShape = shape;
|
||||
}
|
||||
else {
|
||||
shape._fireAndBubble(MOUSEMOVE, evt);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* if no shape was detected, clear target shape and try
|
||||
* to run mouseout from previous target shape
|
||||
*/
|
||||
else {
|
||||
if(this.targetShape && !Kinetic.isDragging()) {
|
||||
this.targetShape._fireAndBubble(MOUSEOUT, evt);
|
||||
this.targetShape._fireAndBubble(MOUSELEAVE, evt);
|
||||
this.targetShape = null;
|
||||
}
|
||||
|
||||
if(dd) {
|
||||
dd._drag(evt);
|
||||
}
|
||||
|
||||
// content event
|
||||
this._fire(CONTENT_MOUSEMOVE, evt);
|
||||
|
||||
if(dd) {
|
||||
dd._drag(evt);
|
||||
}
|
||||
}
|
||||
|
||||
// always call preventDefault for desktop events because some browsers
|
||||
@@ -401,21 +407,23 @@
|
||||
if (evt.preventDefault) {
|
||||
evt.preventDefault();
|
||||
}
|
||||
},
|
||||
}, 17),
|
||||
_mousedown: function(evt) {
|
||||
this._setPointerPosition(evt);
|
||||
var shape = this.getIntersection(this.getPointerPosition());
|
||||
if (!Kinetic.UA.mobile) {
|
||||
this._setPointerPosition(evt);
|
||||
var shape = this.getIntersection(this.getPointerPosition());
|
||||
|
||||
Kinetic.listenClickTap = true;
|
||||
Kinetic.listenClickTap = true;
|
||||
|
||||
if (shape && shape.isListening()) {
|
||||
this.clickStartShape = shape;
|
||||
shape._fireAndBubble(MOUSEDOWN, evt);
|
||||
if (shape && shape.isListening()) {
|
||||
this.clickStartShape = shape;
|
||||
shape._fireAndBubble(MOUSEDOWN, evt);
|
||||
}
|
||||
|
||||
// content event
|
||||
this._fire(CONTENT_MOUSEDOWN, evt);
|
||||
}
|
||||
|
||||
// content event
|
||||
this._fire(CONTENT_MOUSEDOWN, evt);
|
||||
|
||||
// always call preventDefault for desktop events because some browsers
|
||||
// try to drag and drop the canvas element
|
||||
if (evt.preventDefault) {
|
||||
@@ -423,45 +431,48 @@
|
||||
}
|
||||
},
|
||||
_mouseup: function(evt) {
|
||||
this._setPointerPosition(evt);
|
||||
var shape = this.getIntersection(this.getPointerPosition()),
|
||||
clickStartShape = this.clickStartShape,
|
||||
fireDblClick = false;
|
||||
if (!Kinetic.UA.mobile) {
|
||||
this._setPointerPosition(evt);
|
||||
var that = this,
|
||||
shape = this.getIntersection(this.getPointerPosition()),
|
||||
clickStartShape = this.clickStartShape,
|
||||
fireDblClick = false;
|
||||
|
||||
if(Kinetic.inDblClickWindow) {
|
||||
fireDblClick = true;
|
||||
Kinetic.inDblClickWindow = false;
|
||||
}
|
||||
else {
|
||||
Kinetic.inDblClickWindow = true;
|
||||
}
|
||||
if(Kinetic.inDblClickWindow) {
|
||||
fireDblClick = true;
|
||||
Kinetic.inDblClickWindow = false;
|
||||
}
|
||||
else {
|
||||
Kinetic.inDblClickWindow = true;
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
Kinetic.inDblClickWindow = false;
|
||||
}, Kinetic.dblClickWindow);
|
||||
setTimeout(function() {
|
||||
Kinetic.inDblClickWindow = false;
|
||||
}, Kinetic.dblClickWindow);
|
||||
|
||||
if (shape && shape.isListening()) {
|
||||
shape._fireAndBubble(MOUSEUP, evt);
|
||||
if (shape && shape.isListening()) {
|
||||
shape._fireAndBubble(MOUSEUP, evt);
|
||||
|
||||
// detect if click or double click occurred
|
||||
if(Kinetic.listenClickTap && clickStartShape && clickStartShape._id === shape._id) {
|
||||
shape._fireAndBubble(CLICK, evt);
|
||||
// detect if click or double click occurred
|
||||
if(Kinetic.listenClickTap && clickStartShape && clickStartShape._id === shape._id) {
|
||||
shape._fireAndBubble(CLICK, evt);
|
||||
|
||||
if(fireDblClick) {
|
||||
shape._fireAndBubble(DBL_CLICK, evt);
|
||||
if(fireDblClick) {
|
||||
shape._fireAndBubble(DBL_CLICK, evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// content events
|
||||
this._fire(CONTENT_MOUSEUP, evt);
|
||||
if (Kinetic.listenClickTap) {
|
||||
this._fire(CONTENT_CLICK, evt);
|
||||
if(fireDblClick) {
|
||||
this._fire(CONTENT_DBL_CLICK, evt);
|
||||
// content events
|
||||
this._fire(CONTENT_MOUSEUP, evt);
|
||||
if (Kinetic.listenClickTap) {
|
||||
this._fire(CONTENT_CLICK, evt);
|
||||
if(fireDblClick) {
|
||||
this._fire(CONTENT_DBL_CLICK, evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kinetic.listenClickTap = false;
|
||||
Kinetic.listenClickTap = false;
|
||||
}
|
||||
|
||||
// always call preventDefault for desktop events because some browsers
|
||||
// try to drag and drop the canvas element
|
||||
@@ -530,7 +541,7 @@
|
||||
|
||||
Kinetic.listenClickTap = false;
|
||||
},
|
||||
_touchmove: function(evt) {
|
||||
_touchmove: Kinetic.Util._throttle(function(evt) {
|
||||
this._setPointerPosition(evt);
|
||||
var dd = Kinetic.DD,
|
||||
shape = this.getIntersection(this.getPointerPosition());
|
||||
@@ -549,7 +560,7 @@
|
||||
if(dd) {
|
||||
dd._drag(evt);
|
||||
}
|
||||
},
|
||||
}, 17),
|
||||
_setPointerPosition: function(evt) {
|
||||
var contentPosition = this._getContentPosition(),
|
||||
offsetX = evt.offsetX,
|
||||
|
||||
34
src/Util.js
34
src/Util.js
@@ -319,6 +319,40 @@
|
||||
_isString: function(obj) {
|
||||
return Object.prototype.toString.call(obj) == OBJECT_STRING;
|
||||
},
|
||||
// Returns a function, that, when invoked, will only be triggered at most once
|
||||
// during a given window of time. Normally, the throttled function will run
|
||||
// as much as it can, without ever going more than once per `wait` duration;
|
||||
// but if you'd like to disable the execution on the leading edge, pass
|
||||
// `{leading: false}`. To disable execution on the trailing edge, ditto.
|
||||
_throttle: function(func, wait, options) {
|
||||
var context, args, result;
|
||||
var timeout = null;
|
||||
var previous = 0;
|
||||
options || (options = {});
|
||||
var later = function() {
|
||||
previous = options.leading === false ? 0 : new Date().getTime();
|
||||
timeout = null;
|
||||
result = func.apply(context, args);
|
||||
context = args = null;
|
||||
};
|
||||
return function() {
|
||||
var now = new Date().getTime();
|
||||
if (!previous && options.leading === false) previous = now;
|
||||
var remaining = wait - (now - previous);
|
||||
context = this;
|
||||
args = arguments;
|
||||
if (remaining <= 0) {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
previous = now;
|
||||
result = func.apply(context, args);
|
||||
context = args = null;
|
||||
} else if (!timeout && options.trailing !== false) {
|
||||
timeout = setTimeout(later, remaining);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
},
|
||||
/*
|
||||
* other utils
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* @param {String} [config.fontFamily] default is Calibri
|
||||
* @param {Number} [config.fontSize] default is 12
|
||||
* @param {String} [config.fontStyle] can be normal, bold, or italic. Default is normal
|
||||
* @param {String} [config.fontVariant] can be normal or small-caps. Default is normal
|
||||
* @param {String} config.text
|
||||
* @param {String} config.data SVG data string
|
||||
* @@shapeParams
|
||||
@@ -380,6 +381,23 @@
|
||||
* @memberof Kinetic.TextPath.prototype
|
||||
*/
|
||||
|
||||
Kinetic.Factory.addGetterSetter(Kinetic.TextPath, 'fontVariant', NORMAL);
|
||||
|
||||
/**
|
||||
* set font variant. Can be 'normal' or 'small-caps'. 'normal' is the default.
|
||||
* @name setFontVariant
|
||||
* @method
|
||||
* @memberof Kinetic.TextPath.prototype
|
||||
* @param {String} fontVariant
|
||||
*/
|
||||
|
||||
/**
|
||||
* @get font variant
|
||||
* @name getFontVariant
|
||||
* @method
|
||||
* @memberof Kinetic.TextPath.prototype
|
||||
*/
|
||||
|
||||
Kinetic.Factory.addGetter(Kinetic.TextPath, 'text', EMPTY_STRING);
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
WORD = 'word',
|
||||
CHAR = 'char',
|
||||
NONE = 'none',
|
||||
ATTR_CHANGE_LIST = ['fontFamily', 'fontSize', 'fontStyle', 'padding', 'align', 'lineHeight', 'text', 'width', 'height', 'wrap'],
|
||||
ATTR_CHANGE_LIST = ['fontFamily', 'fontSize', 'fontStyle', 'fontVariant', 'padding', 'align', 'lineHeight', 'text', 'width', 'height', 'wrap'],
|
||||
|
||||
// cached variables
|
||||
attrChangeListLen = ATTR_CHANGE_LIST.length,
|
||||
@@ -33,6 +33,7 @@
|
||||
* @param {String} [config.fontFamily] default is Arial
|
||||
* @param {Number} [config.fontSize] in pixels. Default is 12
|
||||
* @param {String} [config.fontStyle] can be normal, bold, or italic. Default is normal
|
||||
* @param {String} [config.fontVariant] can be normal or small-caps. Default is normal
|
||||
* @param {String} config.text
|
||||
* @param {String} [config.align] can be left, center, or right
|
||||
* @param {Number} [config.padding]
|
||||
@@ -193,7 +194,7 @@
|
||||
};
|
||||
},
|
||||
_getContextFont: function() {
|
||||
return this.getFontStyle() + SPACE + this.getFontSize() + PX_SPACE + this.getFontFamily();
|
||||
return this.getFontStyle() + SPACE + this.getFontVariant() + SPACE + this.getFontSize() + PX_SPACE + this.getFontFamily();
|
||||
},
|
||||
_addTextLine: function (line, width) {
|
||||
return this.textArr.push({text: line, width: width});
|
||||
@@ -220,7 +221,7 @@
|
||||
|
||||
this.textArr = [];
|
||||
dummyContext.save();
|
||||
dummyContext.font = this.getFontStyle() + SPACE + fontSize + PX_SPACE + this.getFontFamily();
|
||||
dummyContext.font = this._getContextFont();
|
||||
for (var i = 0, max = lines.length; i < max; ++i) {
|
||||
var line = lines[i],
|
||||
lineWidth = this._getTextWidth(line);
|
||||
@@ -364,6 +365,23 @@
|
||||
* text.fontStyle('bold');
|
||||
*/
|
||||
|
||||
Kinetic.Factory.addGetterSetter(Kinetic.Text, 'fontVariant', NORMAL);
|
||||
|
||||
/**
|
||||
* set font variant. Can be 'normal' or 'small-caps'. 'normal' is the default.
|
||||
* @name fontVariant
|
||||
* @method
|
||||
* @memberof Kinetic.Text.prototype
|
||||
* @param {String} fontVariant
|
||||
* @returns {String}
|
||||
* @example
|
||||
* // get font variant<br>
|
||||
* var fontVariant = text.fontVariant();<br><br>
|
||||
*
|
||||
* // set font variant<br>
|
||||
* text.fontVariant('small-caps');
|
||||
*/
|
||||
|
||||
Kinetic.Factory.addGetterSetter(Kinetic.Text, 'padding', 0);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user