PageRenderTime 81ms CodeModel.GetById 37ms RepoModel.GetById 1ms app.codeStats 0ms

/files/kineticjs/4.3.3/kinetic.js

https://gitlab.com/Mirros/jsdelivr
JavaScript | 1439 lines | 1021 code | 49 blank | 369 comment | 214 complexity | 9384dde401490066ec53371c0317fbea MD5 | raw file
  1. /**
  2. * KineticJS JavaScript Framework v4.3.3
  3. * http://www.kineticjs.com/
  4. * Copyright 2013, Eric Rowell
  5. * Licensed under the MIT or GPL Version 2 licenses.
  6. * Date: Feb 12 2013
  7. *
  8. * Copyright (C) 2011 - 2013 by Eric Rowell
  9. *
  10. * Permission is hereby granted, free of charge, to any person obtaining a copy
  11. * of this software and associated documentation files (the "Software"), to deal
  12. * in the Software without restriction, including without limitation the rights
  13. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14. * copies of the Software, and to permit persons to whom the Software is
  15. * furnished to do so, subject to the following conditions:
  16. *
  17. * The above copyright notice and this permission notice shall be included in
  18. * all copies or substantial portions of the Software.
  19. *
  20. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  26. * THE SOFTWARE.
  27. */
  28. /**
  29. * @namespace
  30. */
  31. var Kinetic = {}; (function() {
  32. Kinetic.version = '4.3.3';
  33. /**
  34. * @namespace
  35. */
  36. Kinetic.Filters = {};
  37. Kinetic.Plugins = {};
  38. Kinetic.Global = {
  39. stages: [],
  40. idCounter: 0,
  41. ids: {},
  42. names: {},
  43. //shapes hash. rgb keys and shape values
  44. shapes: {},
  45. warn: function(str) {
  46. /*
  47. * IE9 on Windows7 64bit will throw a JS error
  48. * if we don't use window.console in the conditional
  49. */
  50. if(window.console && console.warn) {
  51. console.warn('Kinetic warning: ' + str);
  52. }
  53. },
  54. extend: function(c1, c2) {
  55. for(var key in c2.prototype) {
  56. if(!( key in c1.prototype)) {
  57. c1.prototype[key] = c2.prototype[key];
  58. }
  59. }
  60. },
  61. _addId: function(node, id) {
  62. if(id !== undefined) {
  63. this.ids[id] = node;
  64. }
  65. },
  66. _removeId: function(id) {
  67. if(id !== undefined) {
  68. delete this.ids[id];
  69. }
  70. },
  71. _addName: function(node, name) {
  72. if(name !== undefined) {
  73. if(this.names[name] === undefined) {
  74. this.names[name] = [];
  75. }
  76. this.names[name].push(node);
  77. }
  78. },
  79. _removeName: function(name, _id) {
  80. if(name !== undefined) {
  81. var nodes = this.names[name];
  82. if(nodes !== undefined) {
  83. for(var n = 0; n < nodes.length; n++) {
  84. var no = nodes[n];
  85. if(no._id === _id) {
  86. nodes.splice(n, 1);
  87. }
  88. }
  89. if(nodes.length === 0) {
  90. delete this.names[name];
  91. }
  92. }
  93. }
  94. }
  95. };
  96. })();
  97. // Uses Node, AMD or browser globals to create a module.
  98. // If you want something that will work in other stricter CommonJS environments,
  99. // or if you need to create a circular dependency, see commonJsStrict.js
  100. // Defines a module "returnExports" that depends another module called "b".
  101. // Note that the name of the module is implied by the file name. It is best
  102. // if the file name and the exported global have matching names.
  103. // If the 'b' module also uses this type of boilerplate, then
  104. // in the browser, it will create a global .b that is used below.
  105. // If you do not want to support the browser global path, then you
  106. // can remove the `root` use and the passing `this` as the first arg to
  107. // the top function.
  108. // if the module has no dependencies, the above pattern can be simplified to
  109. ( function(root, factory) {
  110. if( typeof exports === 'object') {
  111. // Node. Does not work with strict CommonJS, but
  112. // only CommonJS-like enviroments that support module.exports,
  113. // like Node.
  114. module.exports = factory();
  115. }
  116. else if( typeof define === 'function' && define.amd) {
  117. // AMD. Register as an anonymous module.
  118. define(factory);
  119. }
  120. else {
  121. // Browser globals (root is window)
  122. root.returnExports = factory();
  123. }
  124. }(this, function() {
  125. // Just return a value to define the module export.
  126. // This example returns an object, but the module
  127. // can return a function as the exported value.
  128. return Kinetic;
  129. }));
  130. (function() {
  131. /*
  132. * utilities that handle data type detection, conversion, and manipulation
  133. */
  134. Kinetic.Type = {
  135. /*
  136. * cherry-picked utilities from underscore.js
  137. */
  138. _isElement: function(obj) {
  139. return !!(obj && obj.nodeType == 1);
  140. },
  141. _isFunction: function(obj) {
  142. return !!(obj && obj.constructor && obj.call && obj.apply);
  143. },
  144. _isObject: function(obj) {
  145. return (!!obj && obj.constructor == Object);
  146. },
  147. _isArray: function(obj) {
  148. return Object.prototype.toString.call(obj) == '[object Array]';
  149. },
  150. _isNumber: function(obj) {
  151. return Object.prototype.toString.call(obj) == '[object Number]';
  152. },
  153. _isString: function(obj) {
  154. return Object.prototype.toString.call(obj) == '[object String]';
  155. },
  156. /*
  157. * other utils
  158. */
  159. _hasMethods: function(obj) {
  160. var names = [];
  161. for(var key in obj) {
  162. if(this._isFunction(obj[key]))
  163. names.push(key);
  164. }
  165. return names.length > 0;
  166. },
  167. _isInDocument: function(el) {
  168. while( el = el.parentNode) {
  169. if(el == document) {
  170. return true;
  171. }
  172. }
  173. return false;
  174. },
  175. /*
  176. * The argument can be:
  177. * - an integer (will be applied to both x and y)
  178. * - an array of one integer (will be applied to both x and y)
  179. * - an array of two integers (contains x and y)
  180. * - an array of four integers (contains x, y, width, and height)
  181. * - an object with x and y properties
  182. * - an array of one element which is an array of integers
  183. * - an array of one element of an object
  184. */
  185. _getXY: function(arg) {
  186. if(this._isNumber(arg)) {
  187. return {
  188. x: arg,
  189. y: arg
  190. };
  191. }
  192. else if(this._isArray(arg)) {
  193. // if arg is an array of one element
  194. if(arg.length === 1) {
  195. var val = arg[0];
  196. // if arg is an array of one element which is a number
  197. if(this._isNumber(val)) {
  198. return {
  199. x: val,
  200. y: val
  201. };
  202. }
  203. // if arg is an array of one element which is an array
  204. else if(this._isArray(val)) {
  205. return {
  206. x: val[0],
  207. y: val[1]
  208. };
  209. }
  210. // if arg is an array of one element which is an object
  211. else if(this._isObject(val)) {
  212. return val;
  213. }
  214. }
  215. // if arg is an array of two or more elements
  216. else if(arg.length >= 2) {
  217. return {
  218. x: arg[0],
  219. y: arg[1]
  220. };
  221. }
  222. }
  223. // if arg is an object return the object
  224. else if(this._isObject(arg)) {
  225. return arg;
  226. }
  227. // default
  228. return null;
  229. },
  230. /*
  231. * The argument can be:
  232. * - an integer (will be applied to both width and height)
  233. * - an array of one integer (will be applied to both width and height)
  234. * - an array of two integers (contains width and height)
  235. * - an array of four integers (contains x, y, width, and height)
  236. * - an object with width and height properties
  237. * - an array of one element which is an array of integers
  238. * - an array of one element of an object
  239. */
  240. _getSize: function(arg) {
  241. if(this._isNumber(arg)) {
  242. return {
  243. width: arg,
  244. height: arg
  245. };
  246. }
  247. else if(this._isArray(arg)) {
  248. // if arg is an array of one element
  249. if(arg.length === 1) {
  250. var val = arg[0];
  251. // if arg is an array of one element which is a number
  252. if(this._isNumber(val)) {
  253. return {
  254. width: val,
  255. height: val
  256. };
  257. }
  258. // if arg is an array of one element which is an array
  259. else if(this._isArray(val)) {
  260. /*
  261. * if arg is an array of one element which is an
  262. * array of four elements
  263. */
  264. if(val.length >= 4) {
  265. return {
  266. width: val[2],
  267. height: val[3]
  268. };
  269. }
  270. /*
  271. * if arg is an array of one element which is an
  272. * array of two elements
  273. */
  274. else if(val.length >= 2) {
  275. return {
  276. width: val[0],
  277. height: val[1]
  278. };
  279. }
  280. }
  281. // if arg is an array of one element which is an object
  282. else if(this._isObject(val)) {
  283. return val;
  284. }
  285. }
  286. // if arg is an array of four elements
  287. else if(arg.length >= 4) {
  288. return {
  289. width: arg[2],
  290. height: arg[3]
  291. };
  292. }
  293. // if arg is an array of two elements
  294. else if(arg.length >= 2) {
  295. return {
  296. width: arg[0],
  297. height: arg[1]
  298. };
  299. }
  300. }
  301. // if arg is an object return the object
  302. else if(this._isObject(arg)) {
  303. return arg;
  304. }
  305. // default
  306. return null;
  307. },
  308. /*
  309. * arg will be an array of numbers or
  310. * an array of point arrays or
  311. * an array of point objects
  312. */
  313. _getPoints: function(arg) {
  314. if(arg === undefined) {
  315. return [];
  316. }
  317. // an array of arrays
  318. if(this._isArray(arg[0])) {
  319. /*
  320. * convert array of arrays into an array
  321. * of objects containing x, y
  322. */
  323. var arr = [];
  324. for(var n = 0; n < arg.length; n++) {
  325. arr.push({
  326. x: arg[n][0],
  327. y: arg[n][1]
  328. });
  329. }
  330. return arr;
  331. }
  332. // an array of objects
  333. if(this._isObject(arg[0])) {
  334. return arg;
  335. }
  336. // an array of integers
  337. else {
  338. /*
  339. * convert array of numbers into an array
  340. * of objects containing x, y
  341. */
  342. var arr = [];
  343. for(var n = 0; n < arg.length; n += 2) {
  344. arr.push({
  345. x: arg[n],
  346. y: arg[n + 1]
  347. });
  348. }
  349. return arr;
  350. }
  351. },
  352. /*
  353. * arg can be an image object or image data
  354. */
  355. _getImage: function(arg, callback) {
  356. // if arg is null or undefined
  357. if(!arg) {
  358. callback(null);
  359. }
  360. // if arg is already an image object
  361. else if(this._isElement(arg)) {
  362. callback(arg);
  363. }
  364. // if arg is a string, then it's a data url
  365. else if(this._isString(arg)) {
  366. var imageObj = new Image();
  367. /** @ignore */
  368. imageObj.onload = function() {
  369. callback(imageObj);
  370. }
  371. imageObj.src = arg;
  372. }
  373. //if arg is an object that contains the data property, it's an image object
  374. else if(arg.data) {
  375. var canvas = document.createElement('canvas');
  376. canvas.width = arg.width;
  377. canvas.height = arg.height;
  378. var context = canvas.getContext('2d');
  379. context.putImageData(arg, 0, 0);
  380. var dataUrl = canvas.toDataURL();
  381. var imageObj = new Image();
  382. /** @ignore */
  383. imageObj.onload = function() {
  384. callback(imageObj);
  385. }
  386. imageObj.src = dataUrl;
  387. }
  388. else {
  389. callback(null);
  390. }
  391. },
  392. _rgbToHex: function(r, g, b) {
  393. return ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
  394. },
  395. _hexToRgb: function(hex) {
  396. var bigint = parseInt(hex, 16);
  397. return {
  398. r: (bigint >> 16) & 255,
  399. g: (bigint >> 8) & 255,
  400. b: bigint & 255
  401. };
  402. },
  403. _getRandomColorKey: function() {
  404. var r = Math.round(Math.random() * 255);
  405. var g = Math.round(Math.random() * 255);
  406. var b = Math.round(Math.random() * 255);
  407. return this._rgbToHex(r, g, b);
  408. },
  409. // o1 takes precedence over o2
  410. _merge: function(o1, o2) {
  411. var retObj = this._clone(o2);
  412. for(var key in o1) {
  413. if(this._isObject(o1[key])) {
  414. retObj[key] = this._merge(o1[key], retObj[key]);
  415. }
  416. else {
  417. retObj[key] = o1[key];
  418. }
  419. }
  420. return retObj;
  421. },
  422. // deep clone
  423. _clone: function(obj) {
  424. var retObj = {};
  425. for(var key in obj) {
  426. if(this._isObject(obj[key])) {
  427. retObj[key] = this._clone(obj[key]);
  428. }
  429. else {
  430. retObj[key] = obj[key];
  431. }
  432. }
  433. return retObj;
  434. },
  435. _degToRad: function(deg) {
  436. return deg * Math.PI / 180;
  437. },
  438. _radToDeg: function(rad) {
  439. return rad * 180 / Math.PI;
  440. }
  441. };
  442. })();
  443. (function() {
  444. // calculate pixel ratio
  445. var canvas = document.createElement('canvas'),
  446. context = canvas.getContext('2d'),
  447. devicePixelRatio = window.devicePixelRatio || 1, backingStoreRatio = context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || context.backingStorePixelRatio || 1,
  448. _pixelRatio = devicePixelRatio / backingStoreRatio;
  449. /**
  450. * Canvas Renderer constructor
  451. * @constructor
  452. * @param {Number} width
  453. * @param {Number} height
  454. */
  455. Kinetic.Canvas = function(width, height, pixelRatio) {
  456. this.pixelRatio = pixelRatio || _pixelRatio;
  457. this.width = width;
  458. this.height = height;
  459. this.element = document.createElement('canvas');
  460. this.context = this.element.getContext('2d');
  461. this.setSize(width || 0, height || 0);
  462. };
  463. Kinetic.Canvas.prototype = {
  464. /**
  465. * clear canvas
  466. * @name clear
  467. * @methodOf Kinetic.Canvas.prototype
  468. */
  469. clear: function() {
  470. var context = this.getContext();
  471. var el = this.getElement();
  472. context.clearRect(0, 0, el.width, el.height);
  473. },
  474. /**
  475. * get canvas element
  476. * @name getElement
  477. * @methodOf Kinetic.Canvas.prototype
  478. */
  479. getElement: function() {
  480. return this.element;
  481. },
  482. /**
  483. * get canvas context
  484. * @name getContext
  485. * @methodOf Kinetic.Canvas.prototype
  486. */
  487. getContext: function() {
  488. return this.context;
  489. },
  490. /**
  491. * set width
  492. * @name setWidth
  493. * @methodOf Kinetic.Canvas.prototype
  494. * @param {Number} width
  495. */
  496. setWidth: function(width) {
  497. this.width = width;
  498. // take into account pixel ratio
  499. this.element.width = width * this.pixelRatio;
  500. this.element.style.width = width + 'px';
  501. },
  502. /**
  503. * set height
  504. * @name setHeight
  505. * @methodOf Kinetic.Canvas.prototype
  506. * @param {Number} height
  507. */
  508. setHeight: function(height) {
  509. this.height = height;
  510. // take into account pixel ratio
  511. this.element.height = height * this.pixelRatio;
  512. this.element.style.height = height + 'px';
  513. },
  514. /**
  515. * get width
  516. * @name getWidth
  517. * @methodOf Kinetic.Canvas.prototype
  518. */
  519. getWidth: function() {
  520. return this.width;
  521. },
  522. /**
  523. * get height
  524. * @name getHeight
  525. * @methodOf Kinetic.Canvas.prototype
  526. */
  527. getHeight: function() {
  528. return this.height;
  529. },
  530. /**
  531. * set size
  532. * @name setSize
  533. * @methodOf Kinetic.Canvas.prototype
  534. * @param {Number} width
  535. * @param {Number} height
  536. */
  537. setSize: function(width, height) {
  538. this.setWidth(width);
  539. this.setHeight(height);
  540. },
  541. /**
  542. * to data url
  543. * @name toDataURL
  544. * @methodOf Kinetic.Canvas.prototype
  545. * @param {String} mimeType
  546. * @param {Number} quality between 0 and 1 for jpg mime types
  547. */
  548. toDataURL: function(mimeType, quality) {
  549. try {
  550. // If this call fails (due to browser bug, like in Firefox 3.6),
  551. // then revert to previous no-parameter image/png behavior
  552. return this.element.toDataURL(mimeType, quality);
  553. }
  554. catch(e) {
  555. try {
  556. return this.element.toDataURL();
  557. }
  558. catch(e) {
  559. Kinetic.Global.warn('Unable to get data URL. ' + e.message)
  560. return '';
  561. }
  562. }
  563. },
  564. /**
  565. * fill shape
  566. * @name fill
  567. * @methodOf Kinetic.Canvas.prototype
  568. * @param {Kinetic.Shape} shape
  569. */
  570. fill: function(shape) {
  571. if(shape.getFillEnabled()) {
  572. this._fill(shape);
  573. }
  574. },
  575. /**
  576. * stroke shape
  577. * @name stroke
  578. * @methodOf Kinetic.Canvas.prototype
  579. * @param {Kinetic.Shape} shape
  580. */
  581. stroke: function(shape) {
  582. if(shape.getStrokeEnabled()) {
  583. this._stroke(shape);
  584. }
  585. },
  586. /**
  587. * fill, stroke, and apply shadows
  588. * will only be applied to either the fill or stroke.&nbsp; Fill
  589. * is given priority over stroke.
  590. * @name fillStroke
  591. * @methodOf Kinetic.Canvas.prototype
  592. * @param {Kinetic.Shape} shape
  593. */
  594. fillStroke: function(shape) {
  595. var fillEnabled = shape.getFillEnabled();
  596. if(fillEnabled) {
  597. this._fill(shape);
  598. }
  599. if(shape.getStrokeEnabled()) {
  600. this._stroke(shape, shape.hasShadow() && shape.hasFill() && fillEnabled);
  601. }
  602. },
  603. /**
  604. * apply shadow
  605. * @name applyShadow
  606. * @methodOf Kinetic.Canvas.prototype
  607. * @param {Kinetic.Shape} shape
  608. * @param {Function} drawFunc
  609. */
  610. applyShadow: function(shape, drawFunc) {
  611. var context = this.context;
  612. context.save();
  613. this._applyShadow(shape);
  614. drawFunc();
  615. context.restore();
  616. drawFunc();
  617. },
  618. _applyLineCap: function(shape) {
  619. var lineCap = shape.getLineCap();
  620. if(lineCap) {
  621. this.context.lineCap = lineCap;
  622. }
  623. },
  624. _applyOpacity: function(shape) {
  625. var absOpacity = shape.getAbsoluteOpacity();
  626. if(absOpacity !== 1) {
  627. this.context.globalAlpha = absOpacity;
  628. }
  629. },
  630. _applyLineJoin: function(shape) {
  631. var lineJoin = shape.getLineJoin();
  632. if(lineJoin) {
  633. this.context.lineJoin = lineJoin;
  634. }
  635. },
  636. _applyAncestorTransforms: function(node) {
  637. var context = this.context;
  638. node._eachAncestorReverse(function(no) {
  639. var t = no.getTransform(), m = t.getMatrix();
  640. context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
  641. }, true);
  642. }
  643. };
  644. Kinetic.SceneCanvas = function(width, height, pixelRatio) {
  645. Kinetic.Canvas.call(this, width, height, pixelRatio);
  646. };
  647. Kinetic.SceneCanvas.prototype = {
  648. setWidth: function(width) {
  649. var pixelRatio = this.pixelRatio;
  650. Kinetic.Canvas.prototype.setWidth.call(this, width);
  651. this.context.scale(pixelRatio, pixelRatio);
  652. },
  653. setHeight: function(height) {
  654. var pixelRatio = this.pixelRatio;
  655. Kinetic.Canvas.prototype.setHeight.call(this, height);
  656. this.context.scale(pixelRatio, pixelRatio);
  657. },
  658. _fillColor: function(shape) {
  659. var context = this.context, fill = shape.getFill();
  660. context.fillStyle = fill;
  661. shape._fillFunc(context);
  662. },
  663. _fillPattern: function(shape) {
  664. var context = this.context, fillPatternImage = shape.getFillPatternImage(), fillPatternX = shape.getFillPatternX(), fillPatternY = shape.getFillPatternY(), fillPatternScale = shape.getFillPatternScale(), fillPatternRotation = shape.getFillPatternRotation(), fillPatternOffset = shape.getFillPatternOffset(), fillPatternRepeat = shape.getFillPatternRepeat();
  665. if(fillPatternX || fillPatternY) {
  666. context.translate(fillPatternX || 0, fillPatternY || 0);
  667. }
  668. if(fillPatternRotation) {
  669. context.rotate(fillPatternRotation);
  670. }
  671. if(fillPatternScale) {
  672. context.scale(fillPatternScale.x, fillPatternScale.y);
  673. }
  674. if(fillPatternOffset) {
  675. context.translate(-1 * fillPatternOffset.x, -1 * fillPatternOffset.y);
  676. }
  677. context.fillStyle = context.createPattern(fillPatternImage, fillPatternRepeat || 'repeat');
  678. context.fill();
  679. },
  680. _fillLinearGradient: function(shape) {
  681. var context = this.context, start = shape.getFillLinearGradientStartPoint(), end = shape.getFillLinearGradientEndPoint(), colorStops = shape.getFillLinearGradientColorStops(), grd = context.createLinearGradient(start.x, start.y, end.x, end.y);
  682. // build color stops
  683. for(var n = 0; n < colorStops.length; n += 2) {
  684. grd.addColorStop(colorStops[n], colorStops[n + 1]);
  685. }
  686. context.fillStyle = grd;
  687. context.fill();
  688. },
  689. _fillRadialGradient: function(shape) {
  690. var context = this.context, start = shape.getFillRadialGradientStartPoint(), end = shape.getFillRadialGradientEndPoint(), startRadius = shape.getFillRadialGradientStartRadius(), endRadius = shape.getFillRadialGradientEndRadius(), colorStops = shape.getFillRadialGradientColorStops(), grd = context.createRadialGradient(start.x, start.y, startRadius, end.x, end.y, endRadius);
  691. // build color stops
  692. for(var n = 0; n < colorStops.length; n += 2) {
  693. grd.addColorStop(colorStops[n], colorStops[n + 1]);
  694. }
  695. context.fillStyle = grd;
  696. context.fill();
  697. },
  698. _fill: function(shape, skipShadow) {
  699. var context = this.context, fill = shape.getFill(), fillPatternImage = shape.getFillPatternImage(), fillLinearGradientStartPoint = shape.getFillLinearGradientStartPoint(), fillRadialGradientStartPoint = shape.getFillRadialGradientStartPoint(), fillPriority = shape.getFillPriority();
  700. context.save();
  701. if(!skipShadow && shape.hasShadow()) {
  702. this._applyShadow(shape);
  703. }
  704. // priority fills
  705. if(fill && fillPriority === 'color') {
  706. this._fillColor(shape);
  707. }
  708. else if(fillPatternImage && fillPriority === 'pattern') {
  709. this._fillPattern(shape);
  710. }
  711. else if(fillLinearGradientStartPoint && fillPriority === 'linear-gradient') {
  712. this._fillLinearGradient(shape);
  713. }
  714. else if(fillRadialGradientStartPoint && fillPriority === 'radial-gradient') {
  715. this._fillRadialGradient(shape);
  716. }
  717. // now just try and fill with whatever is available
  718. else if(fill) {
  719. this._fillColor(shape);
  720. }
  721. else if(fillPatternImage) {
  722. this._fillPattern(shape);
  723. }
  724. else if(fillLinearGradientStartPoint) {
  725. this._fillLinearGradient(shape);
  726. }
  727. else if(fillRadialGradientStartPoint) {
  728. this._fillRadialGradient(shape);
  729. }
  730. context.restore();
  731. if(!skipShadow && shape.hasShadow()) {
  732. this._fill(shape, true);
  733. }
  734. },
  735. _stroke: function(shape, skipShadow) {
  736. var context = this.context, stroke = shape.getStroke(), strokeWidth = shape.getStrokeWidth(), dashArray = shape.getDashArray();
  737. if(stroke || strokeWidth) {
  738. context.save();
  739. this._applyLineCap(shape);
  740. if(dashArray && shape.getDashArrayEnabled()) {
  741. if(context.setLineDash) {
  742. context.setLineDash(dashArray);
  743. }
  744. else if('mozDash' in context) {
  745. context.mozDash = dashArray;
  746. }
  747. else if('webkitLineDash' in context) {
  748. context.webkitLineDash = dashArray;
  749. }
  750. }
  751. if(!skipShadow && shape.hasShadow()) {
  752. this._applyShadow(shape);
  753. }
  754. context.lineWidth = strokeWidth || 2;
  755. context.strokeStyle = stroke || 'black';
  756. shape._strokeFunc(context);
  757. context.restore();
  758. if(!skipShadow && shape.hasShadow()) {
  759. this._stroke(shape, true);
  760. }
  761. }
  762. },
  763. _applyShadow: function(shape) {
  764. var context = this.context;
  765. if(shape.hasShadow() && shape.getShadowEnabled()) {
  766. var aa = shape.getAbsoluteOpacity();
  767. // defaults
  768. var color = shape.getShadowColor() || 'black';
  769. var blur = shape.getShadowBlur() || 5;
  770. var offset = shape.getShadowOffset() || {
  771. x: 0,
  772. y: 0
  773. };
  774. if(shape.getShadowOpacity()) {
  775. context.globalAlpha = shape.getShadowOpacity() * aa;
  776. }
  777. context.shadowColor = color;
  778. context.shadowBlur = blur;
  779. context.shadowOffsetX = offset.x;
  780. context.shadowOffsetY = offset.y;
  781. }
  782. }
  783. };
  784. Kinetic.Global.extend(Kinetic.SceneCanvas, Kinetic.Canvas);
  785. Kinetic.HitCanvas = function(width, height, pixelRatio) {
  786. Kinetic.Canvas.call(this, width, height, pixelRatio);
  787. };
  788. Kinetic.HitCanvas.prototype = {
  789. _fill: function(shape) {
  790. var context = this.context;
  791. context.save();
  792. context.fillStyle = '#' + shape.colorKey;
  793. shape._fillFuncHit(context);
  794. context.restore();
  795. },
  796. _stroke: function(shape) {
  797. var context = this.context, stroke = shape.getStroke(), strokeWidth = shape.getStrokeWidth();
  798. if(stroke || strokeWidth) {
  799. this._applyLineCap(shape);
  800. context.save();
  801. context.lineWidth = strokeWidth || 2;
  802. context.strokeStyle = '#' + shape.colorKey;
  803. shape._strokeFuncHit(context);
  804. context.restore();
  805. }
  806. }
  807. };
  808. Kinetic.Global.extend(Kinetic.HitCanvas, Kinetic.Canvas);
  809. })();
  810. (function() {
  811. /*
  812. * The Tween class was ported from an Adobe Flash Tween library
  813. * to JavaScript by Xaric. In the context of KineticJS, a Tween is
  814. * an animation of a single Node property. A Transition is a set of
  815. * multiple tweens
  816. */
  817. Kinetic.Tween = function(obj, propFunc, func, begin, finish, duration) {
  818. this._listeners = [];
  819. this.addListener(this);
  820. this.obj = obj;
  821. this.propFunc = propFunc;
  822. this.begin = begin;
  823. this._pos = begin;
  824. this.setDuration(duration);
  825. this.isPlaying = false;
  826. this._change = 0;
  827. this.prevTime = 0;
  828. this.prevPos = 0;
  829. this.looping = false;
  830. this._time = 0;
  831. this._position = 0;
  832. this._startTime = 0;
  833. this._finish = 0;
  834. this.name = '';
  835. this.func = func;
  836. this.setFinish(finish);
  837. };
  838. /*
  839. * Tween methods
  840. */
  841. Kinetic.Tween.prototype = {
  842. setTime: function(t) {
  843. this.prevTime = this._time;
  844. if(t > this.getDuration()) {
  845. if(this.looping) {
  846. this.rewind(t - this._duration);
  847. this.update();
  848. this.broadcastMessage('onLooped', {
  849. target: this,
  850. type: 'onLooped'
  851. });
  852. }
  853. else {
  854. this._time = this._duration;
  855. this.update();
  856. this.stop();
  857. this.broadcastMessage('onFinished', {
  858. target: this,
  859. type: 'onFinished'
  860. });
  861. }
  862. }
  863. else if(t < 0) {
  864. this.rewind();
  865. this.update();
  866. }
  867. else {
  868. this._time = t;
  869. this.update();
  870. }
  871. },
  872. getTime: function() {
  873. return this._time;
  874. },
  875. setDuration: function(d) {
  876. this._duration = (d === null || d <= 0) ? 100000 : d;
  877. },
  878. getDuration: function() {
  879. return this._duration;
  880. },
  881. setPosition: function(p) {
  882. this.prevPos = this._pos;
  883. this.propFunc(p);
  884. this._pos = p;
  885. this.broadcastMessage('onChanged', {
  886. target: this,
  887. type: 'onChanged'
  888. });
  889. },
  890. getPosition: function(t) {
  891. if(t === undefined) {
  892. t = this._time;
  893. }
  894. return this.func(t, this.begin, this._change, this._duration);
  895. },
  896. setFinish: function(f) {
  897. this._change = f - this.begin;
  898. },
  899. getFinish: function() {
  900. return this.begin + this._change;
  901. },
  902. start: function() {
  903. this.rewind();
  904. this.startEnterFrame();
  905. this.broadcastMessage('onStarted', {
  906. target: this,
  907. type: 'onStarted'
  908. });
  909. },
  910. rewind: function(t) {
  911. this.stop();
  912. this._time = (t === undefined) ? 0 : t;
  913. this.fixTime();
  914. this.update();
  915. },
  916. fforward: function() {
  917. this._time = this._duration;
  918. this.fixTime();
  919. this.update();
  920. },
  921. update: function() {
  922. this.setPosition(this.getPosition(this._time));
  923. },
  924. startEnterFrame: function() {
  925. this.stopEnterFrame();
  926. this.isPlaying = true;
  927. this.onEnterFrame();
  928. },
  929. onEnterFrame: function() {
  930. if(this.isPlaying) {
  931. this.nextFrame();
  932. }
  933. },
  934. nextFrame: function() {
  935. this.setTime((this.getTimer() - this._startTime) / 1000);
  936. },
  937. stop: function() {
  938. this.stopEnterFrame();
  939. this.broadcastMessage('onStopped', {
  940. target: this,
  941. type: 'onStopped'
  942. });
  943. },
  944. stopEnterFrame: function() {
  945. this.isPlaying = false;
  946. },
  947. continueTo: function(finish, duration) {
  948. this.begin = this._pos;
  949. this.setFinish(finish);
  950. if(this._duration !== undefined) {
  951. this.setDuration(duration);
  952. }
  953. this.start();
  954. },
  955. resume: function() {
  956. this.fixTime();
  957. this.startEnterFrame();
  958. this.broadcastMessage('onResumed', {
  959. target: this,
  960. type: 'onResumed'
  961. });
  962. },
  963. yoyo: function() {
  964. this.continueTo(this.begin, this._time);
  965. },
  966. addListener: function(o) {
  967. this.removeListener(o);
  968. return this._listeners.push(o);
  969. },
  970. removeListener: function(o) {
  971. var a = this._listeners;
  972. var i = a.length;
  973. while(i--) {
  974. if(a[i] == o) {
  975. a.splice(i, 1);
  976. return true;
  977. }
  978. }
  979. return false;
  980. },
  981. broadcastMessage: function() {
  982. var arr = [];
  983. for(var i = 0; i < arguments.length; i++) {
  984. arr.push(arguments[i]);
  985. }
  986. var e = arr.shift();
  987. var a = this._listeners;
  988. var l = a.length;
  989. for(var i = 0; i < l; i++) {
  990. if(a[i][e]) {
  991. a[i][e].apply(a[i], arr);
  992. }
  993. }
  994. },
  995. fixTime: function() {
  996. this._startTime = this.getTimer() - this._time * 1000;
  997. },
  998. getTimer: function() {
  999. return new Date().getTime() - this._time;
  1000. }
  1001. };
  1002. Kinetic.Tweens = {
  1003. 'back-ease-in': function(t, b, c, d, a, p) {
  1004. var s = 1.70158;
  1005. return c * (t /= d) * t * ((s + 1) * t - s) + b;
  1006. },
  1007. 'back-ease-out': function(t, b, c, d, a, p) {
  1008. var s = 1.70158;
  1009. return c * (( t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
  1010. },
  1011. 'back-ease-in-out': function(t, b, c, d, a, p) {
  1012. var s = 1.70158;
  1013. if((t /= d / 2) < 1) {
  1014. return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
  1015. }
  1016. return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
  1017. },
  1018. 'elastic-ease-in': function(t, b, c, d, a, p) {
  1019. // added s = 0
  1020. var s = 0;
  1021. if(t === 0) {
  1022. return b;
  1023. }
  1024. if((t /= d) == 1) {
  1025. return b + c;
  1026. }
  1027. if(!p) {
  1028. p = d * 0.3;
  1029. }
  1030. if(!a || a < Math.abs(c)) {
  1031. a = c;
  1032. s = p / 4;
  1033. }
  1034. else {
  1035. s = p / (2 * Math.PI) * Math.asin(c / a);
  1036. }
  1037. return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
  1038. },
  1039. 'elastic-ease-out': function(t, b, c, d, a, p) {
  1040. // added s = 0
  1041. var s = 0;
  1042. if(t === 0) {
  1043. return b;
  1044. }
  1045. if((t /= d) == 1) {
  1046. return b + c;
  1047. }
  1048. if(!p) {
  1049. p = d * 0.3;
  1050. }
  1051. if(!a || a < Math.abs(c)) {
  1052. a = c;
  1053. s = p / 4;
  1054. }
  1055. else {
  1056. s = p / (2 * Math.PI) * Math.asin(c / a);
  1057. }
  1058. return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b);
  1059. },
  1060. 'elastic-ease-in-out': function(t, b, c, d, a, p) {
  1061. // added s = 0
  1062. var s = 0;
  1063. if(t === 0) {
  1064. return b;
  1065. }
  1066. if((t /= d / 2) == 2) {
  1067. return b + c;
  1068. }
  1069. if(!p) {
  1070. p = d * (0.3 * 1.5);
  1071. }
  1072. if(!a || a < Math.abs(c)) {
  1073. a = c;
  1074. s = p / 4;
  1075. }
  1076. else {
  1077. s = p / (2 * Math.PI) * Math.asin(c / a);
  1078. }
  1079. if(t < 1) {
  1080. return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
  1081. }
  1082. return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
  1083. },
  1084. 'bounce-ease-out': function(t, b, c, d) {
  1085. if((t /= d) < (1 / 2.75)) {
  1086. return c * (7.5625 * t * t) + b;
  1087. }
  1088. else if(t < (2 / 2.75)) {
  1089. return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
  1090. }
  1091. else if(t < (2.5 / 2.75)) {
  1092. return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
  1093. }
  1094. else {
  1095. return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
  1096. }
  1097. },
  1098. 'bounce-ease-in': function(t, b, c, d) {
  1099. return c - Kinetic.Tweens['bounce-ease-out'](d - t, 0, c, d) + b;
  1100. },
  1101. 'bounce-ease-in-out': function(t, b, c, d) {
  1102. if(t < d / 2) {
  1103. return Kinetic.Tweens['bounce-ease-in'](t * 2, 0, c, d) * 0.5 + b;
  1104. }
  1105. else {
  1106. return Kinetic.Tweens['bounce-ease-out'](t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
  1107. }
  1108. },
  1109. // duplicate
  1110. /*
  1111. strongEaseInOut: function(t, b, c, d) {
  1112. return c * (t /= d) * t * t * t * t + b;
  1113. },
  1114. */
  1115. 'ease-in': function(t, b, c, d) {
  1116. return c * (t /= d) * t + b;
  1117. },
  1118. 'ease-out': function(t, b, c, d) {
  1119. return -c * (t /= d) * (t - 2) + b;
  1120. },
  1121. 'ease-in-out': function(t, b, c, d) {
  1122. if((t /= d / 2) < 1) {
  1123. return c / 2 * t * t + b;
  1124. }
  1125. return -c / 2 * ((--t) * (t - 2) - 1) + b;
  1126. },
  1127. 'strong-ease-in': function(t, b, c, d) {
  1128. return c * (t /= d) * t * t * t * t + b;
  1129. },
  1130. 'strong-ease-out': function(t, b, c, d) {
  1131. return c * (( t = t / d - 1) * t * t * t * t + 1) + b;
  1132. },
  1133. 'strong-ease-in-out': function(t, b, c, d) {
  1134. if((t /= d / 2) < 1) {
  1135. return c / 2 * t * t * t * t * t + b;
  1136. }
  1137. return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
  1138. },
  1139. 'linear': function(t, b, c, d) {
  1140. return c * t / d + b;
  1141. }
  1142. };
  1143. })();
  1144. (function() {
  1145. /*
  1146. * Last updated November 2011
  1147. * By Simon Sarris
  1148. * www.simonsarris.com
  1149. * sarris@acm.org
  1150. *
  1151. * Free to use and distribute at will
  1152. * So long as you are nice to people, etc
  1153. */
  1154. /*
  1155. * The usage of this class was inspired by some of the work done by a forked
  1156. * project, KineticJS-Ext by Wappworks, which is based on Simon's Transform
  1157. * class.
  1158. */
  1159. /**
  1160. * Transform constructor
  1161. * @constructor
  1162. */
  1163. Kinetic.Transform = function() {
  1164. this.m = [1, 0, 0, 1, 0, 0];
  1165. }
  1166. Kinetic.Transform.prototype = {
  1167. /**
  1168. * Apply translation
  1169. * @param {Number} x
  1170. * @param {Number} y
  1171. */
  1172. translate: function(x, y) {
  1173. this.m[4] += this.m[0] * x + this.m[2] * y;
  1174. this.m[5] += this.m[1] * x + this.m[3] * y;
  1175. },
  1176. /**
  1177. * Apply scale
  1178. * @param {Number} sx
  1179. * @param {Number} sy
  1180. */
  1181. scale: function(sx, sy) {
  1182. this.m[0] *= sx;
  1183. this.m[1] *= sx;
  1184. this.m[2] *= sy;
  1185. this.m[3] *= sy;
  1186. },
  1187. /**
  1188. * Apply rotation
  1189. * @param {Number} rad Angle in radians
  1190. */
  1191. rotate: function(rad) {
  1192. var c = Math.cos(rad);
  1193. var s = Math.sin(rad);
  1194. var m11 = this.m[0] * c + this.m[2] * s;
  1195. var m12 = this.m[1] * c + this.m[3] * s;
  1196. var m21 = this.m[0] * -s + this.m[2] * c;
  1197. var m22 = this.m[1] * -s + this.m[3] * c;
  1198. this.m[0] = m11;
  1199. this.m[1] = m12;
  1200. this.m[2] = m21;
  1201. this.m[3] = m22;
  1202. },
  1203. /**
  1204. * Returns the translation
  1205. * @returns {Object} 2D point(x, y)
  1206. */
  1207. getTranslation: function() {
  1208. return {
  1209. x: this.m[4],
  1210. y: this.m[5]
  1211. };
  1212. },
  1213. /**
  1214. * Transform multiplication
  1215. * @param {Kinetic.Transform} matrix
  1216. */
  1217. multiply: function(matrix) {
  1218. var m11 = this.m[0] * matrix.m[0] + this.m[2] * matrix.m[1];
  1219. var m12 = this.m[1] * matrix.m[0] + this.m[3] * matrix.m[1];
  1220. var m21 = this.m[0] * matrix.m[2] + this.m[2] * matrix.m[3];
  1221. var m22 = this.m[1] * matrix.m[2] + this.m[3] * matrix.m[3];
  1222. var dx = this.m[0] * matrix.m[4] + this.m[2] * matrix.m[5] + this.m[4];
  1223. var dy = this.m[1] * matrix.m[4] + this.m[3] * matrix.m[5] + this.m[5];
  1224. this.m[0] = m11;
  1225. this.m[1] = m12;
  1226. this.m[2] = m21;
  1227. this.m[3] = m22;
  1228. this.m[4] = dx;
  1229. this.m[5] = dy;
  1230. },
  1231. /**
  1232. * Invert the matrix
  1233. */
  1234. invert: function() {
  1235. var d = 1 / (this.m[0] * this.m[3] - this.m[1] * this.m[2]);
  1236. var m0 = this.m[3] * d;
  1237. var m1 = -this.m[1] * d;
  1238. var m2 = -this.m[2] * d;
  1239. var m3 = this.m[0] * d;
  1240. var m4 = d * (this.m[2] * this.m[5] - this.m[3] * this.m[4]);
  1241. var m5 = d * (this.m[1] * this.m[4] - this.m[0] * this.m[5]);
  1242. this.m[0] = m0;
  1243. this.m[1] = m1;
  1244. this.m[2] = m2;
  1245. this.m[3] = m3;
  1246. this.m[4] = m4;
  1247. this.m[5] = m5;
  1248. },
  1249. /**
  1250. * return matrix
  1251. */
  1252. getMatrix: function() {
  1253. return this.m;
  1254. }
  1255. };
  1256. })();
  1257. (function() {
  1258. /**
  1259. * Collection constructor. Collection extends
  1260. * Array. This class is used in conjunction with get()
  1261. * @constructor
  1262. */
  1263. Kinetic.Collection = function() {
  1264. var args = [].slice.call(arguments), length = args.length, i = 0;
  1265. this.length = length;
  1266. for(; i < length; i++) {
  1267. this[i] = args[i];
  1268. }
  1269. return this;
  1270. }
  1271. Kinetic.Collection.prototype = new Array();
  1272. /**
  1273. * apply a method to all nodes in the array
  1274. * @name apply
  1275. * @methodOf Kinetic.Collection.prototype
  1276. * @param {String} method
  1277. * @param val
  1278. */
  1279. Kinetic.Collection.prototype.apply = function(method) {
  1280. args = [].slice.call(arguments);
  1281. args.shift();
  1282. for(var n = 0; n < this.length; n++) {
  1283. if(Kinetic.Type._isFunction(this[n][method])) {
  1284. this[n][method].apply(this[n], args);
  1285. }
  1286. }
  1287. };
  1288. /**
  1289. * iterate through node array
  1290. * @name each
  1291. * @methodOf Kinetic.Collection.prototype
  1292. * @param {Function} func
  1293. */
  1294. Kinetic.Collection.prototype.each = function(func) {
  1295. for(var n = 0; n < this.length; n++) {
  1296. func.call(this[n], n, this[n]);
  1297. }
  1298. };
  1299. })();
  1300. (function() {
  1301. /**
  1302. * Grayscale Filter
  1303. * @function
  1304. * @memberOf Kinetic.Filters
  1305. * @param {Object} imageData
  1306. * @param {Object} config
  1307. */
  1308. Kinetic.Filters.Grayscale = function(imageData, config) {
  1309. var data = imageData.data;
  1310. for(var i = 0; i < data.length; i += 4) {
  1311. var brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];
  1312. // red
  1313. data[i] = brightness;
  1314. // green
  1315. data[i + 1] = brightness;
  1316. // blue
  1317. data[i + 2] = brightness;
  1318. }
  1319. };
  1320. })();
  1321. (function() {
  1322. /**
  1323. * Brighten Filter
  1324. * @function
  1325. * @memberOf Kinetic.Filters
  1326. * @param {Object} imageData
  1327. * @param {Object} config
  1328. * @param {Integer} config.val brightness number from -255 to 255.&nbsp; Positive values increase the brightness and negative values decrease the brightness, making the image darker
  1329. */
  1330. Kinetic.Filters.Brighten = function(imageData, config) {
  1331. var brightness = config.val || 0;
  1332. var data = imageData.data;
  1333. for(var i = 0; i < data.length; i += 4) {
  1334. // red
  1335. data[i] += brightness;
  1336. // green
  1337. data[i + 1] += brightness;
  1338. // blue
  1339. data[i + 2] += brightness;
  1340. }
  1341. };
  1342. })();
  1343. (function() {
  1344. /**
  1345. * Invert Filter
  1346. * @function
  1347. * @memberOf Kinetic.Filters
  1348. * @param {Object} imageData
  1349. * @param {Object} config
  1350. */
  1351. Kinetic.Filters.Invert = function(imageData, config) {
  1352. var data = imageData.data;
  1353. for(var i = 0; i < data.length; i += 4) {
  1354. // red
  1355. data[i] = 255 - data[i];
  1356. // green
  1357. data[i + 1] = 255 - data[i + 1];
  1358. // blue
  1359. data[i + 2] = 255 - data[i + 2];
  1360. }
  1361. };
  1362. })();
  1363. (function() {
  1364. /**
  1365. * Node constructor. Nodes are entities that can be transformed, layered,
  1366. * and have bound events. The stage, layers, groups, and shapes all extend Node.
  1367. * @constructor
  1368. * @param {Object} config
  1369. * @param {Number} [config.x]
  1370. * @param {Number} [config.y]
  1371. * @param {Number} [config.width]
  1372. * @param {Number} [config.height]
  1373. * @param {Boolean} [config.visible]
  1374. * @param {Boolean} [config.listening] whether or not the node is listening for events
  1375. * @param {String} [config.id] unique id
  1376. * @param {String} [config.name] non-unique name
  1377. * @param {Number} [config.opacity] determines node opacity. Can be any number between 0 and 1
  1378. * @param {Object} [config.scale]
  1379. * @param {Number} [config.scale.x]
  1380. * @param {Number} [config.scale.y]
  1381. * @param {Number} [config.rotation] rotation in radians
  1382. * @param {Number} [config.rotationDeg] rotation in degrees
  1383. * @param {Object} [config.offset] offset from center point and rotation point
  1384. * @param {Number} [config.offset.x]
  1385. * @param {Number} [config.offset.y]
  1386. * @param {Boolean} [config.draggable]
  1387. * @param {Function} [config.dragBoundFunc]
  1388. */
  1389. Kinetic.Node = function(config) {
  1390. this._nodeInit(conf