diagram-minimap.umd.js 121 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DiagramJSMinimap = factory());
  5. })(this, (function () { 'use strict';
  6. function _mergeNamespaces$1(n, m) {
  7. m.forEach(function (e) {
  8. e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
  9. if (k !== 'default' && !(k in n)) {
  10. var d = Object.getOwnPropertyDescriptor(e, k);
  11. Object.defineProperty(n, k, d.get ? d : {
  12. enumerable: true,
  13. get: function () { return e[k]; }
  14. });
  15. }
  16. });
  17. });
  18. return Object.freeze(n);
  19. }
  20. /**
  21. * Set attribute `name` to `val`, or get attr `name`.
  22. *
  23. * @param {Element} el
  24. * @param {String} name
  25. * @param {String} [val]
  26. * @api public
  27. */
  28. function attr$1(el, name, val) {
  29. // get
  30. if (arguments.length == 2) {
  31. return el.getAttribute(name);
  32. }
  33. // remove
  34. if (val === null) {
  35. return el.removeAttribute(name);
  36. }
  37. // set
  38. el.setAttribute(name, val);
  39. return el;
  40. }
  41. /**
  42. * Taken from https://github.com/component/classes
  43. *
  44. * Without the component bits.
  45. */
  46. /**
  47. * toString reference.
  48. */
  49. const toString$1 = Object.prototype.toString;
  50. /**
  51. * Wrap `el` in a `ClassList`.
  52. *
  53. * @param {Element} el
  54. * @return {ClassList}
  55. * @api public
  56. */
  57. function classes$1(el) {
  58. return new ClassList$1(el);
  59. }
  60. /**
  61. * Initialize a new ClassList for `el`.
  62. *
  63. * @param {Element} el
  64. * @api private
  65. */
  66. function ClassList$1(el) {
  67. if (!el || !el.nodeType) {
  68. throw new Error('A DOM element reference is required');
  69. }
  70. this.el = el;
  71. this.list = el.classList;
  72. }
  73. /**
  74. * Add class `name` if not already present.
  75. *
  76. * @param {String} name
  77. * @return {ClassList}
  78. * @api public
  79. */
  80. ClassList$1.prototype.add = function(name) {
  81. this.list.add(name);
  82. return this;
  83. };
  84. /**
  85. * Remove class `name` when present, or
  86. * pass a regular expression to remove
  87. * any which match.
  88. *
  89. * @param {String|RegExp} name
  90. * @return {ClassList}
  91. * @api public
  92. */
  93. ClassList$1.prototype.remove = function(name) {
  94. if ('[object RegExp]' == toString$1.call(name)) {
  95. return this.removeMatching(name);
  96. }
  97. this.list.remove(name);
  98. return this;
  99. };
  100. /**
  101. * Remove all classes matching `re`.
  102. *
  103. * @param {RegExp} re
  104. * @return {ClassList}
  105. * @api private
  106. */
  107. ClassList$1.prototype.removeMatching = function(re) {
  108. const arr = this.array();
  109. for (let i = 0; i < arr.length; i++) {
  110. if (re.test(arr[i])) {
  111. this.remove(arr[i]);
  112. }
  113. }
  114. return this;
  115. };
  116. /**
  117. * Toggle class `name`, can force state via `force`.
  118. *
  119. * For browsers that support classList, but do not support `force` yet,
  120. * the mistake will be detected and corrected.
  121. *
  122. * @param {String} name
  123. * @param {Boolean} force
  124. * @return {ClassList}
  125. * @api public
  126. */
  127. ClassList$1.prototype.toggle = function(name, force) {
  128. if ('undefined' !== typeof force) {
  129. if (force !== this.list.toggle(name, force)) {
  130. this.list.toggle(name); // toggle again to correct
  131. }
  132. } else {
  133. this.list.toggle(name);
  134. }
  135. return this;
  136. };
  137. /**
  138. * Return an array of classes.
  139. *
  140. * @return {Array}
  141. * @api public
  142. */
  143. ClassList$1.prototype.array = function() {
  144. return Array.from(this.list);
  145. };
  146. /**
  147. * Check if class `name` is present.
  148. *
  149. * @param {String} name
  150. * @return {ClassList}
  151. * @api public
  152. */
  153. ClassList$1.prototype.has =
  154. ClassList$1.prototype.contains = function(name) {
  155. return this.list.contains(name);
  156. };
  157. var componentEvent = {};
  158. var bind$1, unbind$1, prefix;
  159. function detect () {
  160. bind$1 = window.addEventListener ? 'addEventListener' : 'attachEvent';
  161. unbind$1 = window.removeEventListener ? 'removeEventListener' : 'detachEvent';
  162. prefix = bind$1 !== 'addEventListener' ? 'on' : '';
  163. }
  164. /**
  165. * Bind `el` event `type` to `fn`.
  166. *
  167. * @param {Element} el
  168. * @param {String} type
  169. * @param {Function} fn
  170. * @param {Boolean} capture
  171. * @return {Function}
  172. * @api public
  173. */
  174. var bind_1 = componentEvent.bind = function(el, type, fn, capture){
  175. if (!bind$1) detect();
  176. el[bind$1](prefix + type, fn, capture || false);
  177. return fn;
  178. };
  179. /**
  180. * Unbind `el` event `type`'s callback `fn`.
  181. *
  182. * @param {Element} el
  183. * @param {String} type
  184. * @param {Function} fn
  185. * @param {Boolean} capture
  186. * @return {Function}
  187. * @api public
  188. */
  189. var unbind_1 = componentEvent.unbind = function(el, type, fn, capture){
  190. if (!unbind$1) detect();
  191. el[unbind$1](prefix + type, fn, capture || false);
  192. return fn;
  193. };
  194. var event = /*#__PURE__*/_mergeNamespaces$1({
  195. __proto__: null,
  196. bind: bind_1,
  197. unbind: unbind_1,
  198. 'default': componentEvent
  199. }, [componentEvent]);
  200. var bugTestDiv;
  201. if (typeof document !== 'undefined') {
  202. bugTestDiv = document.createElement('div');
  203. // Setup
  204. bugTestDiv.innerHTML = ' <link/><table></table><a href="/a">a</a><input type="checkbox"/>';
  205. // Make sure that link elements get serialized correctly by innerHTML
  206. // This requires a wrapper element in IE
  207. !bugTestDiv.getElementsByTagName('link').length;
  208. bugTestDiv = undefined;
  209. }
  210. function query(selector, el) {
  211. el = el || document;
  212. return el.querySelector(selector);
  213. }
  214. function ensureImported(element, target) {
  215. if (element.ownerDocument !== target.ownerDocument) {
  216. try {
  217. // may fail on webkit
  218. return target.ownerDocument.importNode(element, true);
  219. } catch (e) {
  220. // ignore
  221. }
  222. }
  223. return element;
  224. }
  225. /**
  226. * appendTo utility
  227. */
  228. /**
  229. * Append a node to a target element and return the appended node.
  230. *
  231. * @param {SVGElement} element
  232. * @param {SVGElement} target
  233. *
  234. * @return {SVGElement} the appended node
  235. */
  236. function appendTo(element, target) {
  237. return target.appendChild(ensureImported(element, target));
  238. }
  239. /**
  240. * append utility
  241. */
  242. /**
  243. * Append a node to an element
  244. *
  245. * @param {SVGElement} element
  246. * @param {SVGElement} node
  247. *
  248. * @return {SVGElement} the element
  249. */
  250. function append(target, node) {
  251. appendTo(node, target);
  252. return target;
  253. }
  254. /**
  255. * attribute accessor utility
  256. */
  257. var LENGTH_ATTR = 2;
  258. var CSS_PROPERTIES = {
  259. 'alignment-baseline': 1,
  260. 'baseline-shift': 1,
  261. 'clip': 1,
  262. 'clip-path': 1,
  263. 'clip-rule': 1,
  264. 'color': 1,
  265. 'color-interpolation': 1,
  266. 'color-interpolation-filters': 1,
  267. 'color-profile': 1,
  268. 'color-rendering': 1,
  269. 'cursor': 1,
  270. 'direction': 1,
  271. 'display': 1,
  272. 'dominant-baseline': 1,
  273. 'enable-background': 1,
  274. 'fill': 1,
  275. 'fill-opacity': 1,
  276. 'fill-rule': 1,
  277. 'filter': 1,
  278. 'flood-color': 1,
  279. 'flood-opacity': 1,
  280. 'font': 1,
  281. 'font-family': 1,
  282. 'font-size': LENGTH_ATTR,
  283. 'font-size-adjust': 1,
  284. 'font-stretch': 1,
  285. 'font-style': 1,
  286. 'font-variant': 1,
  287. 'font-weight': 1,
  288. 'glyph-orientation-horizontal': 1,
  289. 'glyph-orientation-vertical': 1,
  290. 'image-rendering': 1,
  291. 'kerning': 1,
  292. 'letter-spacing': 1,
  293. 'lighting-color': 1,
  294. 'marker': 1,
  295. 'marker-end': 1,
  296. 'marker-mid': 1,
  297. 'marker-start': 1,
  298. 'mask': 1,
  299. 'opacity': 1,
  300. 'overflow': 1,
  301. 'pointer-events': 1,
  302. 'shape-rendering': 1,
  303. 'stop-color': 1,
  304. 'stop-opacity': 1,
  305. 'stroke': 1,
  306. 'stroke-dasharray': 1,
  307. 'stroke-dashoffset': 1,
  308. 'stroke-linecap': 1,
  309. 'stroke-linejoin': 1,
  310. 'stroke-miterlimit': 1,
  311. 'stroke-opacity': 1,
  312. 'stroke-width': LENGTH_ATTR,
  313. 'text-anchor': 1,
  314. 'text-decoration': 1,
  315. 'text-rendering': 1,
  316. 'unicode-bidi': 1,
  317. 'visibility': 1,
  318. 'word-spacing': 1,
  319. 'writing-mode': 1
  320. };
  321. function getAttribute(node, name) {
  322. if (CSS_PROPERTIES[name]) {
  323. return node.style[name];
  324. } else {
  325. return node.getAttributeNS(null, name);
  326. }
  327. }
  328. function setAttribute(node, name, value) {
  329. var hyphenated = name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
  330. var type = CSS_PROPERTIES[hyphenated];
  331. if (type) {
  332. // append pixel unit, unless present
  333. if (type === LENGTH_ATTR && typeof value === 'number') {
  334. value = String(value) + 'px';
  335. }
  336. node.style[hyphenated] = value;
  337. } else {
  338. node.setAttributeNS(null, name, value);
  339. }
  340. }
  341. function setAttributes(node, attrs) {
  342. var names = Object.keys(attrs), i, name;
  343. for (i = 0, name; (name = names[i]); i++) {
  344. setAttribute(node, name, attrs[name]);
  345. }
  346. }
  347. /**
  348. * Gets or sets raw attributes on a node.
  349. *
  350. * @param {SVGElement} node
  351. * @param {Object} [attrs]
  352. * @param {String} [name]
  353. * @param {String} [value]
  354. *
  355. * @return {String}
  356. */
  357. function attr(node, name, value) {
  358. if (typeof name === 'string') {
  359. if (value !== undefined) {
  360. setAttribute(node, name, value);
  361. } else {
  362. return getAttribute(node, name);
  363. }
  364. } else {
  365. setAttributes(node, name);
  366. }
  367. return node;
  368. }
  369. /**
  370. * Taken from https://github.com/component/classes
  371. *
  372. * Without the component bits.
  373. */
  374. /**
  375. * toString reference.
  376. */
  377. const toString = Object.prototype.toString;
  378. /**
  379. * Wrap `el` in a `ClassList`.
  380. *
  381. * @param {Element} el
  382. * @return {ClassList}
  383. * @api public
  384. */
  385. function classes(el) {
  386. return new ClassList(el);
  387. }
  388. function ClassList(el) {
  389. if (!el || !el.nodeType) {
  390. throw new Error('A DOM element reference is required');
  391. }
  392. this.el = el;
  393. this.list = el.classList;
  394. }
  395. /**
  396. * Add class `name` if not already present.
  397. *
  398. * @param {String} name
  399. * @return {ClassList}
  400. * @api public
  401. */
  402. ClassList.prototype.add = function(name) {
  403. this.list.add(name);
  404. return this;
  405. };
  406. /**
  407. * Remove class `name` when present, or
  408. * pass a regular expression to remove
  409. * any which match.
  410. *
  411. * @param {String|RegExp} name
  412. * @return {ClassList}
  413. * @api public
  414. */
  415. ClassList.prototype.remove = function(name) {
  416. if ('[object RegExp]' == toString.call(name)) {
  417. return this.removeMatching(name);
  418. }
  419. this.list.remove(name);
  420. return this;
  421. };
  422. /**
  423. * Remove all classes matching `re`.
  424. *
  425. * @param {RegExp} re
  426. * @return {ClassList}
  427. * @api private
  428. */
  429. ClassList.prototype.removeMatching = function(re) {
  430. const arr = this.array();
  431. for (let i = 0; i < arr.length; i++) {
  432. if (re.test(arr[i])) {
  433. this.remove(arr[i]);
  434. }
  435. }
  436. return this;
  437. };
  438. /**
  439. * Toggle class `name`, can force state via `force`.
  440. *
  441. * For browsers that support classList, but do not support `force` yet,
  442. * the mistake will be detected and corrected.
  443. *
  444. * @param {String} name
  445. * @param {Boolean} force
  446. * @return {ClassList}
  447. * @api public
  448. */
  449. ClassList.prototype.toggle = function(name, force) {
  450. if ('undefined' !== typeof force) {
  451. if (force !== this.list.toggle(name, force)) {
  452. this.list.toggle(name); // toggle again to correct
  453. }
  454. } else {
  455. this.list.toggle(name);
  456. }
  457. return this;
  458. };
  459. /**
  460. * Return an array of classes.
  461. *
  462. * @return {Array}
  463. * @api public
  464. */
  465. ClassList.prototype.array = function() {
  466. return Array.from(this.list);
  467. };
  468. /**
  469. * Check if class `name` is present.
  470. *
  471. * @param {String} name
  472. * @return {ClassList}
  473. * @api public
  474. */
  475. ClassList.prototype.has =
  476. ClassList.prototype.contains = function(name) {
  477. return this.list.contains(name);
  478. };
  479. function remove(element) {
  480. var parent = element.parentNode;
  481. if (parent) {
  482. parent.removeChild(element);
  483. }
  484. return element;
  485. }
  486. /**
  487. * Clear utility
  488. */
  489. /**
  490. * Removes all children from the given element
  491. *
  492. * @param {DOMElement} element
  493. * @return {DOMElement} the element (for chaining)
  494. */
  495. function clear(element) {
  496. var child;
  497. while ((child = element.firstChild)) {
  498. remove(child);
  499. }
  500. return element;
  501. }
  502. function clone(element) {
  503. return element.cloneNode(true);
  504. }
  505. var ns = {
  506. svg: 'http://www.w3.org/2000/svg'
  507. };
  508. /**
  509. * DOM parsing utility
  510. */
  511. var SVG_START = '<svg xmlns="' + ns.svg + '"';
  512. function parse(svg) {
  513. var unwrap = false;
  514. // ensure we import a valid svg document
  515. if (svg.substring(0, 4) === '<svg') {
  516. if (svg.indexOf(ns.svg) === -1) {
  517. svg = SVG_START + svg.substring(4);
  518. }
  519. } else {
  520. // namespace svg
  521. svg = SVG_START + '>' + svg + '</svg>';
  522. unwrap = true;
  523. }
  524. var parsed = parseDocument(svg);
  525. if (!unwrap) {
  526. return parsed;
  527. }
  528. var fragment = document.createDocumentFragment();
  529. var parent = parsed.firstChild;
  530. while (parent.firstChild) {
  531. fragment.appendChild(parent.firstChild);
  532. }
  533. return fragment;
  534. }
  535. function parseDocument(svg) {
  536. var parser;
  537. // parse
  538. parser = new DOMParser();
  539. parser.async = false;
  540. return parser.parseFromString(svg, 'text/xml');
  541. }
  542. /**
  543. * Create utility for SVG elements
  544. */
  545. /**
  546. * Create a specific type from name or SVG markup.
  547. *
  548. * @param {String} name the name or markup of the element
  549. * @param {Object} [attrs] attributes to set on the element
  550. *
  551. * @returns {SVGElement}
  552. */
  553. function create(name, attrs) {
  554. var element;
  555. if (name.charAt(0) === '<') {
  556. element = parse(name).firstChild;
  557. element = document.importNode(element, true);
  558. } else {
  559. element = document.createElementNS(ns.svg, name);
  560. }
  561. if (attrs) {
  562. attr(element, attrs);
  563. }
  564. return element;
  565. }
  566. /**
  567. * Flatten array, one level deep.
  568. *
  569. * @param {Array<?>} arr
  570. *
  571. * @return {Array<?>}
  572. */
  573. const nativeToString = Object.prototype.toString;
  574. const nativeHasOwnProperty = Object.prototype.hasOwnProperty;
  575. function isUndefined(obj) {
  576. return obj === undefined;
  577. }
  578. function isArray(obj) {
  579. return nativeToString.call(obj) === '[object Array]';
  580. }
  581. function isObject(obj) {
  582. return nativeToString.call(obj) === '[object Object]';
  583. }
  584. function isNumber(obj) {
  585. return nativeToString.call(obj) === '[object Number]';
  586. }
  587. /**
  588. * Return true, if target owns a property with the given key.
  589. *
  590. * @param {Object} target
  591. * @param {String} key
  592. *
  593. * @return {Boolean}
  594. */
  595. function has(target, key) {
  596. return nativeHasOwnProperty.call(target, key);
  597. }
  598. /**
  599. * Iterate over collection; returning something
  600. * (non-undefined) will stop iteration.
  601. *
  602. * @param {Array|Object} collection
  603. * @param {Function} iterator
  604. *
  605. * @return {Object} return result that stopped the iteration
  606. */
  607. function forEach(collection, iterator) {
  608. let val,
  609. result;
  610. if (isUndefined(collection)) {
  611. return;
  612. }
  613. const convertKey = isArray(collection) ? toNum : identity;
  614. for (let key in collection) {
  615. if (has(collection, key)) {
  616. val = collection[key];
  617. result = iterator(val, convertKey(key));
  618. if (result === false) {
  619. return val;
  620. }
  621. }
  622. }
  623. }
  624. /**
  625. * Reduce collection, returning a single result.
  626. *
  627. * @param {Object|Array} collection
  628. * @param {Function} iterator
  629. * @param {Any} result
  630. *
  631. * @return {Any} result returned from last iterator
  632. */
  633. function reduce(collection, iterator, result) {
  634. forEach(collection, function(value, idx) {
  635. result = iterator(result, value, idx);
  636. });
  637. return result;
  638. }
  639. /**
  640. * Return true if every element in the collection
  641. * matches the criteria.
  642. *
  643. * @param {Object|Array} collection
  644. * @param {Function} matcher
  645. *
  646. * @return {Boolean}
  647. */
  648. function every(collection, matcher) {
  649. return !!reduce(collection, function(matches, val, key) {
  650. return matches && matcher(val, key);
  651. }, true);
  652. }
  653. function identity(arg) {
  654. return arg;
  655. }
  656. function toNum(arg) {
  657. return Number(arg);
  658. }
  659. /**
  660. * Convenience wrapper for `Object.assign`.
  661. *
  662. * @param {Object} target
  663. * @param {...Object} others
  664. *
  665. * @return {Object} the target
  666. */
  667. function assign(target, ...others) {
  668. return Object.assign(target, ...others);
  669. }
  670. var hammerExports = {};
  671. var hammer = {
  672. get exports(){ return hammerExports; },
  673. set exports(v){ hammerExports = v; },
  674. };
  675. /*! Hammer.JS - v2.0.7 - 2016-04-22
  676. * http://hammerjs.github.io/
  677. *
  678. * Copyright (c) 2016 Jorik Tangelder;
  679. * Licensed under the MIT license */
  680. (function (module) {
  681. (function(window, document, exportName, undefined$1) {
  682. var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
  683. var TEST_ELEMENT = document.createElement('div');
  684. var TYPE_FUNCTION = 'function';
  685. var round = Math.round;
  686. var abs = Math.abs;
  687. var now = Date.now;
  688. /**
  689. * set a timeout with a given scope
  690. * @param {Function} fn
  691. * @param {Number} timeout
  692. * @param {Object} context
  693. * @returns {number}
  694. */
  695. function setTimeoutContext(fn, timeout, context) {
  696. return setTimeout(bindFn(fn, context), timeout);
  697. }
  698. /**
  699. * if the argument is an array, we want to execute the fn on each entry
  700. * if it aint an array we don't want to do a thing.
  701. * this is used by all the methods that accept a single and array argument.
  702. * @param {*|Array} arg
  703. * @param {String} fn
  704. * @param {Object} [context]
  705. * @returns {Boolean}
  706. */
  707. function invokeArrayArg(arg, fn, context) {
  708. if (Array.isArray(arg)) {
  709. each(arg, context[fn], context);
  710. return true;
  711. }
  712. return false;
  713. }
  714. /**
  715. * walk objects and arrays
  716. * @param {Object} obj
  717. * @param {Function} iterator
  718. * @param {Object} context
  719. */
  720. function each(obj, iterator, context) {
  721. var i;
  722. if (!obj) {
  723. return;
  724. }
  725. if (obj.forEach) {
  726. obj.forEach(iterator, context);
  727. } else if (obj.length !== undefined$1) {
  728. i = 0;
  729. while (i < obj.length) {
  730. iterator.call(context, obj[i], i, obj);
  731. i++;
  732. }
  733. } else {
  734. for (i in obj) {
  735. obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
  736. }
  737. }
  738. }
  739. /**
  740. * wrap a method with a deprecation warning and stack trace
  741. * @param {Function} method
  742. * @param {String} name
  743. * @param {String} message
  744. * @returns {Function} A new function wrapping the supplied method.
  745. */
  746. function deprecate(method, name, message) {
  747. var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n';
  748. return function() {
  749. var e = new Error('get-stack-trace');
  750. var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '')
  751. .replace(/^\s+at\s+/gm, '')
  752. .replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
  753. var log = window.console && (window.console.warn || window.console.log);
  754. if (log) {
  755. log.call(window.console, deprecationMessage, stack);
  756. }
  757. return method.apply(this, arguments);
  758. };
  759. }
  760. /**
  761. * extend object.
  762. * means that properties in dest will be overwritten by the ones in src.
  763. * @param {Object} target
  764. * @param {...Object} objects_to_assign
  765. * @returns {Object} target
  766. */
  767. var assign;
  768. if (typeof Object.assign !== 'function') {
  769. assign = function assign(target) {
  770. if (target === undefined$1 || target === null) {
  771. throw new TypeError('Cannot convert undefined or null to object');
  772. }
  773. var output = Object(target);
  774. for (var index = 1; index < arguments.length; index++) {
  775. var source = arguments[index];
  776. if (source !== undefined$1 && source !== null) {
  777. for (var nextKey in source) {
  778. if (source.hasOwnProperty(nextKey)) {
  779. output[nextKey] = source[nextKey];
  780. }
  781. }
  782. }
  783. }
  784. return output;
  785. };
  786. } else {
  787. assign = Object.assign;
  788. }
  789. /**
  790. * extend object.
  791. * means that properties in dest will be overwritten by the ones in src.
  792. * @param {Object} dest
  793. * @param {Object} src
  794. * @param {Boolean} [merge=false]
  795. * @returns {Object} dest
  796. */
  797. var extend = deprecate(function extend(dest, src, merge) {
  798. var keys = Object.keys(src);
  799. var i = 0;
  800. while (i < keys.length) {
  801. if (!merge || (merge && dest[keys[i]] === undefined$1)) {
  802. dest[keys[i]] = src[keys[i]];
  803. }
  804. i++;
  805. }
  806. return dest;
  807. }, 'extend', 'Use `assign`.');
  808. /**
  809. * merge the values from src in the dest.
  810. * means that properties that exist in dest will not be overwritten by src
  811. * @param {Object} dest
  812. * @param {Object} src
  813. * @returns {Object} dest
  814. */
  815. var merge = deprecate(function merge(dest, src) {
  816. return extend(dest, src, true);
  817. }, 'merge', 'Use `assign`.');
  818. /**
  819. * simple class inheritance
  820. * @param {Function} child
  821. * @param {Function} base
  822. * @param {Object} [properties]
  823. */
  824. function inherit(child, base, properties) {
  825. var baseP = base.prototype,
  826. childP;
  827. childP = child.prototype = Object.create(baseP);
  828. childP.constructor = child;
  829. childP._super = baseP;
  830. if (properties) {
  831. assign(childP, properties);
  832. }
  833. }
  834. /**
  835. * simple function bind
  836. * @param {Function} fn
  837. * @param {Object} context
  838. * @returns {Function}
  839. */
  840. function bindFn(fn, context) {
  841. return function boundFn() {
  842. return fn.apply(context, arguments);
  843. };
  844. }
  845. /**
  846. * let a boolean value also be a function that must return a boolean
  847. * this first item in args will be used as the context
  848. * @param {Boolean|Function} val
  849. * @param {Array} [args]
  850. * @returns {Boolean}
  851. */
  852. function boolOrFn(val, args) {
  853. if (typeof val == TYPE_FUNCTION) {
  854. return val.apply(args ? args[0] || undefined$1 : undefined$1, args);
  855. }
  856. return val;
  857. }
  858. /**
  859. * use the val2 when val1 is undefined
  860. * @param {*} val1
  861. * @param {*} val2
  862. * @returns {*}
  863. */
  864. function ifUndefined(val1, val2) {
  865. return (val1 === undefined$1) ? val2 : val1;
  866. }
  867. /**
  868. * addEventListener with multiple events at once
  869. * @param {EventTarget} target
  870. * @param {String} types
  871. * @param {Function} handler
  872. */
  873. function addEventListeners(target, types, handler) {
  874. each(splitStr(types), function(type) {
  875. target.addEventListener(type, handler, false);
  876. });
  877. }
  878. /**
  879. * removeEventListener with multiple events at once
  880. * @param {EventTarget} target
  881. * @param {String} types
  882. * @param {Function} handler
  883. */
  884. function removeEventListeners(target, types, handler) {
  885. each(splitStr(types), function(type) {
  886. target.removeEventListener(type, handler, false);
  887. });
  888. }
  889. /**
  890. * find if a node is in the given parent
  891. * @method hasParent
  892. * @param {HTMLElement} node
  893. * @param {HTMLElement} parent
  894. * @return {Boolean} found
  895. */
  896. function hasParent(node, parent) {
  897. while (node) {
  898. if (node == parent) {
  899. return true;
  900. }
  901. node = node.parentNode;
  902. }
  903. return false;
  904. }
  905. /**
  906. * small indexOf wrapper
  907. * @param {String} str
  908. * @param {String} find
  909. * @returns {Boolean} found
  910. */
  911. function inStr(str, find) {
  912. return str.indexOf(find) > -1;
  913. }
  914. /**
  915. * split string on whitespace
  916. * @param {String} str
  917. * @returns {Array} words
  918. */
  919. function splitStr(str) {
  920. return str.trim().split(/\s+/g);
  921. }
  922. /**
  923. * find if a array contains the object using indexOf or a simple polyFill
  924. * @param {Array} src
  925. * @param {String} find
  926. * @param {String} [findByKey]
  927. * @return {Boolean|Number} false when not found, or the index
  928. */
  929. function inArray(src, find, findByKey) {
  930. if (src.indexOf && !findByKey) {
  931. return src.indexOf(find);
  932. } else {
  933. var i = 0;
  934. while (i < src.length) {
  935. if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
  936. return i;
  937. }
  938. i++;
  939. }
  940. return -1;
  941. }
  942. }
  943. /**
  944. * convert array-like objects to real arrays
  945. * @param {Object} obj
  946. * @returns {Array}
  947. */
  948. function toArray(obj) {
  949. return Array.prototype.slice.call(obj, 0);
  950. }
  951. /**
  952. * unique array with objects based on a key (like 'id') or just by the array's value
  953. * @param {Array} src [{id:1},{id:2},{id:1}]
  954. * @param {String} [key]
  955. * @param {Boolean} [sort=False]
  956. * @returns {Array} [{id:1},{id:2}]
  957. */
  958. function uniqueArray(src, key, sort) {
  959. var results = [];
  960. var values = [];
  961. var i = 0;
  962. while (i < src.length) {
  963. var val = key ? src[i][key] : src[i];
  964. if (inArray(values, val) < 0) {
  965. results.push(src[i]);
  966. }
  967. values[i] = val;
  968. i++;
  969. }
  970. if (sort) {
  971. if (!key) {
  972. results = results.sort();
  973. } else {
  974. results = results.sort(function sortUniqueArray(a, b) {
  975. return a[key] > b[key];
  976. });
  977. }
  978. }
  979. return results;
  980. }
  981. /**
  982. * get the prefixed property
  983. * @param {Object} obj
  984. * @param {String} property
  985. * @returns {String|Undefined} prefixed
  986. */
  987. function prefixed(obj, property) {
  988. var prefix, prop;
  989. var camelProp = property[0].toUpperCase() + property.slice(1);
  990. var i = 0;
  991. while (i < VENDOR_PREFIXES.length) {
  992. prefix = VENDOR_PREFIXES[i];
  993. prop = (prefix) ? prefix + camelProp : property;
  994. if (prop in obj) {
  995. return prop;
  996. }
  997. i++;
  998. }
  999. return undefined$1;
  1000. }
  1001. /**
  1002. * get a unique id
  1003. * @returns {number} uniqueId
  1004. */
  1005. var _uniqueId = 1;
  1006. function uniqueId() {
  1007. return _uniqueId++;
  1008. }
  1009. /**
  1010. * get the window object of an element
  1011. * @param {HTMLElement} element
  1012. * @returns {DocumentView|Window}
  1013. */
  1014. function getWindowForElement(element) {
  1015. var doc = element.ownerDocument || element;
  1016. return (doc.defaultView || doc.parentWindow || window);
  1017. }
  1018. var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
  1019. var SUPPORT_TOUCH = ('ontouchstart' in window);
  1020. var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined$1;
  1021. var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
  1022. var INPUT_TYPE_TOUCH = 'touch';
  1023. var INPUT_TYPE_PEN = 'pen';
  1024. var INPUT_TYPE_MOUSE = 'mouse';
  1025. var INPUT_TYPE_KINECT = 'kinect';
  1026. var COMPUTE_INTERVAL = 25;
  1027. var INPUT_START = 1;
  1028. var INPUT_MOVE = 2;
  1029. var INPUT_END = 4;
  1030. var INPUT_CANCEL = 8;
  1031. var DIRECTION_NONE = 1;
  1032. var DIRECTION_LEFT = 2;
  1033. var DIRECTION_RIGHT = 4;
  1034. var DIRECTION_UP = 8;
  1035. var DIRECTION_DOWN = 16;
  1036. var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
  1037. var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
  1038. var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
  1039. var PROPS_XY = ['x', 'y'];
  1040. var PROPS_CLIENT_XY = ['clientX', 'clientY'];
  1041. /**
  1042. * create new input type manager
  1043. * @param {Manager} manager
  1044. * @param {Function} callback
  1045. * @returns {Input}
  1046. * @constructor
  1047. */
  1048. function Input(manager, callback) {
  1049. var self = this;
  1050. this.manager = manager;
  1051. this.callback = callback;
  1052. this.element = manager.element;
  1053. this.target = manager.options.inputTarget;
  1054. // smaller wrapper around the handler, for the scope and the enabled state of the manager,
  1055. // so when disabled the input events are completely bypassed.
  1056. this.domHandler = function(ev) {
  1057. if (boolOrFn(manager.options.enable, [manager])) {
  1058. self.handler(ev);
  1059. }
  1060. };
  1061. this.init();
  1062. }
  1063. Input.prototype = {
  1064. /**
  1065. * should handle the inputEvent data and trigger the callback
  1066. * @virtual
  1067. */
  1068. handler: function() { },
  1069. /**
  1070. * bind the events
  1071. */
  1072. init: function() {
  1073. this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
  1074. this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
  1075. this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
  1076. },
  1077. /**
  1078. * unbind the events
  1079. */
  1080. destroy: function() {
  1081. this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
  1082. this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
  1083. this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
  1084. }
  1085. };
  1086. /**
  1087. * create new input type manager
  1088. * called by the Manager constructor
  1089. * @param {Hammer} manager
  1090. * @returns {Input}
  1091. */
  1092. function createInputInstance(manager) {
  1093. var Type;
  1094. var inputClass = manager.options.inputClass;
  1095. if (inputClass) {
  1096. Type = inputClass;
  1097. } else if (SUPPORT_POINTER_EVENTS) {
  1098. Type = PointerEventInput;
  1099. } else if (SUPPORT_ONLY_TOUCH) {
  1100. Type = TouchInput;
  1101. } else if (!SUPPORT_TOUCH) {
  1102. Type = MouseInput;
  1103. } else {
  1104. Type = TouchMouseInput;
  1105. }
  1106. return new (Type)(manager, inputHandler);
  1107. }
  1108. /**
  1109. * handle input events
  1110. * @param {Manager} manager
  1111. * @param {String} eventType
  1112. * @param {Object} input
  1113. */
  1114. function inputHandler(manager, eventType, input) {
  1115. var pointersLen = input.pointers.length;
  1116. var changedPointersLen = input.changedPointers.length;
  1117. var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
  1118. var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));
  1119. input.isFirst = !!isFirst;
  1120. input.isFinal = !!isFinal;
  1121. if (isFirst) {
  1122. manager.session = {};
  1123. }
  1124. // source event is the normalized value of the domEvents
  1125. // like 'touchstart, mouseup, pointerdown'
  1126. input.eventType = eventType;
  1127. // compute scale, rotation etc
  1128. computeInputData(manager, input);
  1129. // emit secret event
  1130. manager.emit('hammer.input', input);
  1131. manager.recognize(input);
  1132. manager.session.prevInput = input;
  1133. }
  1134. /**
  1135. * extend the data with some usable properties like scale, rotate, velocity etc
  1136. * @param {Object} manager
  1137. * @param {Object} input
  1138. */
  1139. function computeInputData(manager, input) {
  1140. var session = manager.session;
  1141. var pointers = input.pointers;
  1142. var pointersLength = pointers.length;
  1143. // store the first input to calculate the distance and direction
  1144. if (!session.firstInput) {
  1145. session.firstInput = simpleCloneInputData(input);
  1146. }
  1147. // to compute scale and rotation we need to store the multiple touches
  1148. if (pointersLength > 1 && !session.firstMultiple) {
  1149. session.firstMultiple = simpleCloneInputData(input);
  1150. } else if (pointersLength === 1) {
  1151. session.firstMultiple = false;
  1152. }
  1153. var firstInput = session.firstInput;
  1154. var firstMultiple = session.firstMultiple;
  1155. var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
  1156. var center = input.center = getCenter(pointers);
  1157. input.timeStamp = now();
  1158. input.deltaTime = input.timeStamp - firstInput.timeStamp;
  1159. input.angle = getAngle(offsetCenter, center);
  1160. input.distance = getDistance(offsetCenter, center);
  1161. computeDeltaXY(session, input);
  1162. input.offsetDirection = getDirection(input.deltaX, input.deltaY);
  1163. var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
  1164. input.overallVelocityX = overallVelocity.x;
  1165. input.overallVelocityY = overallVelocity.y;
  1166. input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y;
  1167. input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
  1168. input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
  1169. input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length >
  1170. session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers);
  1171. computeIntervalInputData(session, input);
  1172. // find the correct target
  1173. var target = manager.element;
  1174. if (hasParent(input.srcEvent.target, target)) {
  1175. target = input.srcEvent.target;
  1176. }
  1177. input.target = target;
  1178. }
  1179. function computeDeltaXY(session, input) {
  1180. var center = input.center;
  1181. var offset = session.offsetDelta || {};
  1182. var prevDelta = session.prevDelta || {};
  1183. var prevInput = session.prevInput || {};
  1184. if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
  1185. prevDelta = session.prevDelta = {
  1186. x: prevInput.deltaX || 0,
  1187. y: prevInput.deltaY || 0
  1188. };
  1189. offset = session.offsetDelta = {
  1190. x: center.x,
  1191. y: center.y
  1192. };
  1193. }
  1194. input.deltaX = prevDelta.x + (center.x - offset.x);
  1195. input.deltaY = prevDelta.y + (center.y - offset.y);
  1196. }
  1197. /**
  1198. * velocity is calculated every x ms
  1199. * @param {Object} session
  1200. * @param {Object} input
  1201. */
  1202. function computeIntervalInputData(session, input) {
  1203. var last = session.lastInterval || input,
  1204. deltaTime = input.timeStamp - last.timeStamp,
  1205. velocity, velocityX, velocityY, direction;
  1206. if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined$1)) {
  1207. var deltaX = input.deltaX - last.deltaX;
  1208. var deltaY = input.deltaY - last.deltaY;
  1209. var v = getVelocity(deltaTime, deltaX, deltaY);
  1210. velocityX = v.x;
  1211. velocityY = v.y;
  1212. velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
  1213. direction = getDirection(deltaX, deltaY);
  1214. session.lastInterval = input;
  1215. } else {
  1216. // use latest velocity info if it doesn't overtake a minimum period
  1217. velocity = last.velocity;
  1218. velocityX = last.velocityX;
  1219. velocityY = last.velocityY;
  1220. direction = last.direction;
  1221. }
  1222. input.velocity = velocity;
  1223. input.velocityX = velocityX;
  1224. input.velocityY = velocityY;
  1225. input.direction = direction;
  1226. }
  1227. /**
  1228. * create a simple clone from the input used for storage of firstInput and firstMultiple
  1229. * @param {Object} input
  1230. * @returns {Object} clonedInputData
  1231. */
  1232. function simpleCloneInputData(input) {
  1233. // make a simple copy of the pointers because we will get a reference if we don't
  1234. // we only need clientXY for the calculations
  1235. var pointers = [];
  1236. var i = 0;
  1237. while (i < input.pointers.length) {
  1238. pointers[i] = {
  1239. clientX: round(input.pointers[i].clientX),
  1240. clientY: round(input.pointers[i].clientY)
  1241. };
  1242. i++;
  1243. }
  1244. return {
  1245. timeStamp: now(),
  1246. pointers: pointers,
  1247. center: getCenter(pointers),
  1248. deltaX: input.deltaX,
  1249. deltaY: input.deltaY
  1250. };
  1251. }
  1252. /**
  1253. * get the center of all the pointers
  1254. * @param {Array} pointers
  1255. * @return {Object} center contains `x` and `y` properties
  1256. */
  1257. function getCenter(pointers) {
  1258. var pointersLength = pointers.length;
  1259. // no need to loop when only one touch
  1260. if (pointersLength === 1) {
  1261. return {
  1262. x: round(pointers[0].clientX),
  1263. y: round(pointers[0].clientY)
  1264. };
  1265. }
  1266. var x = 0, y = 0, i = 0;
  1267. while (i < pointersLength) {
  1268. x += pointers[i].clientX;
  1269. y += pointers[i].clientY;
  1270. i++;
  1271. }
  1272. return {
  1273. x: round(x / pointersLength),
  1274. y: round(y / pointersLength)
  1275. };
  1276. }
  1277. /**
  1278. * calculate the velocity between two points. unit is in px per ms.
  1279. * @param {Number} deltaTime
  1280. * @param {Number} x
  1281. * @param {Number} y
  1282. * @return {Object} velocity `x` and `y`
  1283. */
  1284. function getVelocity(deltaTime, x, y) {
  1285. return {
  1286. x: x / deltaTime || 0,
  1287. y: y / deltaTime || 0
  1288. };
  1289. }
  1290. /**
  1291. * get the direction between two points
  1292. * @param {Number} x
  1293. * @param {Number} y
  1294. * @return {Number} direction
  1295. */
  1296. function getDirection(x, y) {
  1297. if (x === y) {
  1298. return DIRECTION_NONE;
  1299. }
  1300. if (abs(x) >= abs(y)) {
  1301. return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
  1302. }
  1303. return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
  1304. }
  1305. /**
  1306. * calculate the absolute distance between two points
  1307. * @param {Object} p1 {x, y}
  1308. * @param {Object} p2 {x, y}
  1309. * @param {Array} [props] containing x and y keys
  1310. * @return {Number} distance
  1311. */
  1312. function getDistance(p1, p2, props) {
  1313. if (!props) {
  1314. props = PROPS_XY;
  1315. }
  1316. var x = p2[props[0]] - p1[props[0]],
  1317. y = p2[props[1]] - p1[props[1]];
  1318. return Math.sqrt((x * x) + (y * y));
  1319. }
  1320. /**
  1321. * calculate the angle between two coordinates
  1322. * @param {Object} p1
  1323. * @param {Object} p2
  1324. * @param {Array} [props] containing x and y keys
  1325. * @return {Number} angle
  1326. */
  1327. function getAngle(p1, p2, props) {
  1328. if (!props) {
  1329. props = PROPS_XY;
  1330. }
  1331. var x = p2[props[0]] - p1[props[0]],
  1332. y = p2[props[1]] - p1[props[1]];
  1333. return Math.atan2(y, x) * 180 / Math.PI;
  1334. }
  1335. /**
  1336. * calculate the rotation degrees between two pointersets
  1337. * @param {Array} start array of pointers
  1338. * @param {Array} end array of pointers
  1339. * @return {Number} rotation
  1340. */
  1341. function getRotation(start, end) {
  1342. return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
  1343. }
  1344. /**
  1345. * calculate the scale factor between two pointersets
  1346. * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
  1347. * @param {Array} start array of pointers
  1348. * @param {Array} end array of pointers
  1349. * @return {Number} scale
  1350. */
  1351. function getScale(start, end) {
  1352. return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
  1353. }
  1354. var MOUSE_INPUT_MAP = {
  1355. mousedown: INPUT_START,
  1356. mousemove: INPUT_MOVE,
  1357. mouseup: INPUT_END
  1358. };
  1359. var MOUSE_ELEMENT_EVENTS = 'mousedown';
  1360. var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
  1361. /**
  1362. * Mouse events input
  1363. * @constructor
  1364. * @extends Input
  1365. */
  1366. function MouseInput() {
  1367. this.evEl = MOUSE_ELEMENT_EVENTS;
  1368. this.evWin = MOUSE_WINDOW_EVENTS;
  1369. this.pressed = false; // mousedown state
  1370. Input.apply(this, arguments);
  1371. }
  1372. inherit(MouseInput, Input, {
  1373. /**
  1374. * handle mouse events
  1375. * @param {Object} ev
  1376. */
  1377. handler: function MEhandler(ev) {
  1378. var eventType = MOUSE_INPUT_MAP[ev.type];
  1379. // on start we want to have the left mouse button down
  1380. if (eventType & INPUT_START && ev.button === 0) {
  1381. this.pressed = true;
  1382. }
  1383. if (eventType & INPUT_MOVE && ev.which !== 1) {
  1384. eventType = INPUT_END;
  1385. }
  1386. // mouse must be down
  1387. if (!this.pressed) {
  1388. return;
  1389. }
  1390. if (eventType & INPUT_END) {
  1391. this.pressed = false;
  1392. }
  1393. this.callback(this.manager, eventType, {
  1394. pointers: [ev],
  1395. changedPointers: [ev],
  1396. pointerType: INPUT_TYPE_MOUSE,
  1397. srcEvent: ev
  1398. });
  1399. }
  1400. });
  1401. var POINTER_INPUT_MAP = {
  1402. pointerdown: INPUT_START,
  1403. pointermove: INPUT_MOVE,
  1404. pointerup: INPUT_END,
  1405. pointercancel: INPUT_CANCEL,
  1406. pointerout: INPUT_CANCEL
  1407. };
  1408. // in IE10 the pointer types is defined as an enum
  1409. var IE10_POINTER_TYPE_ENUM = {
  1410. 2: INPUT_TYPE_TOUCH,
  1411. 3: INPUT_TYPE_PEN,
  1412. 4: INPUT_TYPE_MOUSE,
  1413. 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
  1414. };
  1415. var POINTER_ELEMENT_EVENTS = 'pointerdown';
  1416. var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
  1417. // IE10 has prefixed support, and case-sensitive
  1418. if (window.MSPointerEvent && !window.PointerEvent) {
  1419. POINTER_ELEMENT_EVENTS = 'MSPointerDown';
  1420. POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
  1421. }
  1422. /**
  1423. * Pointer events input
  1424. * @constructor
  1425. * @extends Input
  1426. */
  1427. function PointerEventInput() {
  1428. this.evEl = POINTER_ELEMENT_EVENTS;
  1429. this.evWin = POINTER_WINDOW_EVENTS;
  1430. Input.apply(this, arguments);
  1431. this.store = (this.manager.session.pointerEvents = []);
  1432. }
  1433. inherit(PointerEventInput, Input, {
  1434. /**
  1435. * handle mouse events
  1436. * @param {Object} ev
  1437. */
  1438. handler: function PEhandler(ev) {
  1439. var store = this.store;
  1440. var removePointer = false;
  1441. var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
  1442. var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
  1443. var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
  1444. var isTouch = (pointerType == INPUT_TYPE_TOUCH);
  1445. // get index of the event in the store
  1446. var storeIndex = inArray(store, ev.pointerId, 'pointerId');
  1447. // start and mouse must be down
  1448. if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
  1449. if (storeIndex < 0) {
  1450. store.push(ev);
  1451. storeIndex = store.length - 1;
  1452. }
  1453. } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
  1454. removePointer = true;
  1455. }
  1456. // it not found, so the pointer hasn't been down (so it's probably a hover)
  1457. if (storeIndex < 0) {
  1458. return;
  1459. }
  1460. // update the event in the store
  1461. store[storeIndex] = ev;
  1462. this.callback(this.manager, eventType, {
  1463. pointers: store,
  1464. changedPointers: [ev],
  1465. pointerType: pointerType,
  1466. srcEvent: ev
  1467. });
  1468. if (removePointer) {
  1469. // remove from the store
  1470. store.splice(storeIndex, 1);
  1471. }
  1472. }
  1473. });
  1474. var SINGLE_TOUCH_INPUT_MAP = {
  1475. touchstart: INPUT_START,
  1476. touchmove: INPUT_MOVE,
  1477. touchend: INPUT_END,
  1478. touchcancel: INPUT_CANCEL
  1479. };
  1480. var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
  1481. var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
  1482. /**
  1483. * Touch events input
  1484. * @constructor
  1485. * @extends Input
  1486. */
  1487. function SingleTouchInput() {
  1488. this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
  1489. this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
  1490. this.started = false;
  1491. Input.apply(this, arguments);
  1492. }
  1493. inherit(SingleTouchInput, Input, {
  1494. handler: function TEhandler(ev) {
  1495. var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
  1496. // should we handle the touch events?
  1497. if (type === INPUT_START) {
  1498. this.started = true;
  1499. }
  1500. if (!this.started) {
  1501. return;
  1502. }
  1503. var touches = normalizeSingleTouches.call(this, ev, type);
  1504. // when done, reset the started state
  1505. if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
  1506. this.started = false;
  1507. }
  1508. this.callback(this.manager, type, {
  1509. pointers: touches[0],
  1510. changedPointers: touches[1],
  1511. pointerType: INPUT_TYPE_TOUCH,
  1512. srcEvent: ev
  1513. });
  1514. }
  1515. });
  1516. /**
  1517. * @this {TouchInput}
  1518. * @param {Object} ev
  1519. * @param {Number} type flag
  1520. * @returns {undefined|Array} [all, changed]
  1521. */
  1522. function normalizeSingleTouches(ev, type) {
  1523. var all = toArray(ev.touches);
  1524. var changed = toArray(ev.changedTouches);
  1525. if (type & (INPUT_END | INPUT_CANCEL)) {
  1526. all = uniqueArray(all.concat(changed), 'identifier', true);
  1527. }
  1528. return [all, changed];
  1529. }
  1530. var TOUCH_INPUT_MAP = {
  1531. touchstart: INPUT_START,
  1532. touchmove: INPUT_MOVE,
  1533. touchend: INPUT_END,
  1534. touchcancel: INPUT_CANCEL
  1535. };
  1536. var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
  1537. /**
  1538. * Multi-user touch events input
  1539. * @constructor
  1540. * @extends Input
  1541. */
  1542. function TouchInput() {
  1543. this.evTarget = TOUCH_TARGET_EVENTS;
  1544. this.targetIds = {};
  1545. Input.apply(this, arguments);
  1546. }
  1547. inherit(TouchInput, Input, {
  1548. handler: function MTEhandler(ev) {
  1549. var type = TOUCH_INPUT_MAP[ev.type];
  1550. var touches = getTouches.call(this, ev, type);
  1551. if (!touches) {
  1552. return;
  1553. }
  1554. this.callback(this.manager, type, {
  1555. pointers: touches[0],
  1556. changedPointers: touches[1],
  1557. pointerType: INPUT_TYPE_TOUCH,
  1558. srcEvent: ev
  1559. });
  1560. }
  1561. });
  1562. /**
  1563. * @this {TouchInput}
  1564. * @param {Object} ev
  1565. * @param {Number} type flag
  1566. * @returns {undefined|Array} [all, changed]
  1567. */
  1568. function getTouches(ev, type) {
  1569. var allTouches = toArray(ev.touches);
  1570. var targetIds = this.targetIds;
  1571. // when there is only one touch, the process can be simplified
  1572. if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
  1573. targetIds[allTouches[0].identifier] = true;
  1574. return [allTouches, allTouches];
  1575. }
  1576. var i,
  1577. targetTouches,
  1578. changedTouches = toArray(ev.changedTouches),
  1579. changedTargetTouches = [],
  1580. target = this.target;
  1581. // get target touches from touches
  1582. targetTouches = allTouches.filter(function(touch) {
  1583. return hasParent(touch.target, target);
  1584. });
  1585. // collect touches
  1586. if (type === INPUT_START) {
  1587. i = 0;
  1588. while (i < targetTouches.length) {
  1589. targetIds[targetTouches[i].identifier] = true;
  1590. i++;
  1591. }
  1592. }
  1593. // filter changed touches to only contain touches that exist in the collected target ids
  1594. i = 0;
  1595. while (i < changedTouches.length) {
  1596. if (targetIds[changedTouches[i].identifier]) {
  1597. changedTargetTouches.push(changedTouches[i]);
  1598. }
  1599. // cleanup removed touches
  1600. if (type & (INPUT_END | INPUT_CANCEL)) {
  1601. delete targetIds[changedTouches[i].identifier];
  1602. }
  1603. i++;
  1604. }
  1605. if (!changedTargetTouches.length) {
  1606. return;
  1607. }
  1608. return [
  1609. // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
  1610. uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
  1611. changedTargetTouches
  1612. ];
  1613. }
  1614. /**
  1615. * Combined touch and mouse input
  1616. *
  1617. * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
  1618. * This because touch devices also emit mouse events while doing a touch.
  1619. *
  1620. * @constructor
  1621. * @extends Input
  1622. */
  1623. var DEDUP_TIMEOUT = 2500;
  1624. var DEDUP_DISTANCE = 25;
  1625. function TouchMouseInput() {
  1626. Input.apply(this, arguments);
  1627. var handler = bindFn(this.handler, this);
  1628. this.touch = new TouchInput(this.manager, handler);
  1629. this.mouse = new MouseInput(this.manager, handler);
  1630. this.primaryTouch = null;
  1631. this.lastTouches = [];
  1632. }
  1633. inherit(TouchMouseInput, Input, {
  1634. /**
  1635. * handle mouse and touch events
  1636. * @param {Hammer} manager
  1637. * @param {String} inputEvent
  1638. * @param {Object} inputData
  1639. */
  1640. handler: function TMEhandler(manager, inputEvent, inputData) {
  1641. var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
  1642. isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
  1643. if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
  1644. return;
  1645. }
  1646. // when we're in a touch event, record touches to de-dupe synthetic mouse event
  1647. if (isTouch) {
  1648. recordTouches.call(this, inputEvent, inputData);
  1649. } else if (isMouse && isSyntheticEvent.call(this, inputData)) {
  1650. return;
  1651. }
  1652. this.callback(manager, inputEvent, inputData);
  1653. },
  1654. /**
  1655. * remove the event listeners
  1656. */
  1657. destroy: function destroy() {
  1658. this.touch.destroy();
  1659. this.mouse.destroy();
  1660. }
  1661. });
  1662. function recordTouches(eventType, eventData) {
  1663. if (eventType & INPUT_START) {
  1664. this.primaryTouch = eventData.changedPointers[0].identifier;
  1665. setLastTouch.call(this, eventData);
  1666. } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
  1667. setLastTouch.call(this, eventData);
  1668. }
  1669. }
  1670. function setLastTouch(eventData) {
  1671. var touch = eventData.changedPointers[0];
  1672. if (touch.identifier === this.primaryTouch) {
  1673. var lastTouch = {x: touch.clientX, y: touch.clientY};
  1674. this.lastTouches.push(lastTouch);
  1675. var lts = this.lastTouches;
  1676. var removeLastTouch = function() {
  1677. var i = lts.indexOf(lastTouch);
  1678. if (i > -1) {
  1679. lts.splice(i, 1);
  1680. }
  1681. };
  1682. setTimeout(removeLastTouch, DEDUP_TIMEOUT);
  1683. }
  1684. }
  1685. function isSyntheticEvent(eventData) {
  1686. var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY;
  1687. for (var i = 0; i < this.lastTouches.length; i++) {
  1688. var t = this.lastTouches[i];
  1689. var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
  1690. if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
  1691. return true;
  1692. }
  1693. }
  1694. return false;
  1695. }
  1696. var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
  1697. var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined$1;
  1698. // magical touchAction value
  1699. var TOUCH_ACTION_COMPUTE = 'compute';
  1700. var TOUCH_ACTION_AUTO = 'auto';
  1701. var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
  1702. var TOUCH_ACTION_NONE = 'none';
  1703. var TOUCH_ACTION_PAN_X = 'pan-x';
  1704. var TOUCH_ACTION_PAN_Y = 'pan-y';
  1705. var TOUCH_ACTION_MAP = getTouchActionProps();
  1706. /**
  1707. * Touch Action
  1708. * sets the touchAction property or uses the js alternative
  1709. * @param {Manager} manager
  1710. * @param {String} value
  1711. * @constructor
  1712. */
  1713. function TouchAction(manager, value) {
  1714. this.manager = manager;
  1715. this.set(value);
  1716. }
  1717. TouchAction.prototype = {
  1718. /**
  1719. * set the touchAction value on the element or enable the polyfill
  1720. * @param {String} value
  1721. */
  1722. set: function(value) {
  1723. // find out the touch-action by the event handlers
  1724. if (value == TOUCH_ACTION_COMPUTE) {
  1725. value = this.compute();
  1726. }
  1727. if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
  1728. this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
  1729. }
  1730. this.actions = value.toLowerCase().trim();
  1731. },
  1732. /**
  1733. * just re-set the touchAction value
  1734. */
  1735. update: function() {
  1736. this.set(this.manager.options.touchAction);
  1737. },
  1738. /**
  1739. * compute the value for the touchAction property based on the recognizer's settings
  1740. * @returns {String} value
  1741. */
  1742. compute: function() {
  1743. var actions = [];
  1744. each(this.manager.recognizers, function(recognizer) {
  1745. if (boolOrFn(recognizer.options.enable, [recognizer])) {
  1746. actions = actions.concat(recognizer.getTouchAction());
  1747. }
  1748. });
  1749. return cleanTouchActions(actions.join(' '));
  1750. },
  1751. /**
  1752. * this method is called on each input cycle and provides the preventing of the browser behavior
  1753. * @param {Object} input
  1754. */
  1755. preventDefaults: function(input) {
  1756. var srcEvent = input.srcEvent;
  1757. var direction = input.offsetDirection;
  1758. // if the touch action did prevented once this session
  1759. if (this.manager.session.prevented) {
  1760. srcEvent.preventDefault();
  1761. return;
  1762. }
  1763. var actions = this.actions;
  1764. var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
  1765. var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
  1766. var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
  1767. if (hasNone) {
  1768. //do not prevent defaults if this is a tap gesture
  1769. var isTapPointer = input.pointers.length === 1;
  1770. var isTapMovement = input.distance < 2;
  1771. var isTapTouchTime = input.deltaTime < 250;
  1772. if (isTapPointer && isTapMovement && isTapTouchTime) {
  1773. return;
  1774. }
  1775. }
  1776. if (hasPanX && hasPanY) {
  1777. // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
  1778. return;
  1779. }
  1780. if (hasNone ||
  1781. (hasPanY && direction & DIRECTION_HORIZONTAL) ||
  1782. (hasPanX && direction & DIRECTION_VERTICAL)) {
  1783. return this.preventSrc(srcEvent);
  1784. }
  1785. },
  1786. /**
  1787. * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
  1788. * @param {Object} srcEvent
  1789. */
  1790. preventSrc: function(srcEvent) {
  1791. this.manager.session.prevented = true;
  1792. srcEvent.preventDefault();
  1793. }
  1794. };
  1795. /**
  1796. * when the touchActions are collected they are not a valid value, so we need to clean things up. *
  1797. * @param {String} actions
  1798. * @returns {*}
  1799. */
  1800. function cleanTouchActions(actions) {
  1801. // none
  1802. if (inStr(actions, TOUCH_ACTION_NONE)) {
  1803. return TOUCH_ACTION_NONE;
  1804. }
  1805. var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
  1806. var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
  1807. // if both pan-x and pan-y are set (different recognizers
  1808. // for different directions, e.g. horizontal pan but vertical swipe?)
  1809. // we need none (as otherwise with pan-x pan-y combined none of these
  1810. // recognizers will work, since the browser would handle all panning
  1811. if (hasPanX && hasPanY) {
  1812. return TOUCH_ACTION_NONE;
  1813. }
  1814. // pan-x OR pan-y
  1815. if (hasPanX || hasPanY) {
  1816. return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
  1817. }
  1818. // manipulation
  1819. if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
  1820. return TOUCH_ACTION_MANIPULATION;
  1821. }
  1822. return TOUCH_ACTION_AUTO;
  1823. }
  1824. function getTouchActionProps() {
  1825. if (!NATIVE_TOUCH_ACTION) {
  1826. return false;
  1827. }
  1828. var touchMap = {};
  1829. var cssSupports = window.CSS && window.CSS.supports;
  1830. ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) {
  1831. // If css.supports is not supported but there is native touch-action assume it supports
  1832. // all values. This is the case for IE 10 and 11.
  1833. touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true;
  1834. });
  1835. return touchMap;
  1836. }
  1837. /**
  1838. * Recognizer flow explained; *
  1839. * All recognizers have the initial state of POSSIBLE when a input session starts.
  1840. * The definition of a input session is from the first input until the last input, with all it's movement in it. *
  1841. * Example session for mouse-input: mousedown -> mousemove -> mouseup
  1842. *
  1843. * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
  1844. * which determines with state it should be.
  1845. *
  1846. * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
  1847. * POSSIBLE to give it another change on the next cycle.
  1848. *
  1849. * Possible
  1850. * |
  1851. * +-----+---------------+
  1852. * | |
  1853. * +-----+-----+ |
  1854. * | | |
  1855. * Failed Cancelled |
  1856. * +-------+------+
  1857. * | |
  1858. * Recognized Began
  1859. * |
  1860. * Changed
  1861. * |
  1862. * Ended/Recognized
  1863. */
  1864. var STATE_POSSIBLE = 1;
  1865. var STATE_BEGAN = 2;
  1866. var STATE_CHANGED = 4;
  1867. var STATE_ENDED = 8;
  1868. var STATE_RECOGNIZED = STATE_ENDED;
  1869. var STATE_CANCELLED = 16;
  1870. var STATE_FAILED = 32;
  1871. /**
  1872. * Recognizer
  1873. * Every recognizer needs to extend from this class.
  1874. * @constructor
  1875. * @param {Object} options
  1876. */
  1877. function Recognizer(options) {
  1878. this.options = assign({}, this.defaults, options || {});
  1879. this.id = uniqueId();
  1880. this.manager = null;
  1881. // default is enable true
  1882. this.options.enable = ifUndefined(this.options.enable, true);
  1883. this.state = STATE_POSSIBLE;
  1884. this.simultaneous = {};
  1885. this.requireFail = [];
  1886. }
  1887. Recognizer.prototype = {
  1888. /**
  1889. * @virtual
  1890. * @type {Object}
  1891. */
  1892. defaults: {},
  1893. /**
  1894. * set options
  1895. * @param {Object} options
  1896. * @return {Recognizer}
  1897. */
  1898. set: function(options) {
  1899. assign(this.options, options);
  1900. // also update the touchAction, in case something changed about the directions/enabled state
  1901. this.manager && this.manager.touchAction.update();
  1902. return this;
  1903. },
  1904. /**
  1905. * recognize simultaneous with an other recognizer.
  1906. * @param {Recognizer} otherRecognizer
  1907. * @returns {Recognizer} this
  1908. */
  1909. recognizeWith: function(otherRecognizer) {
  1910. if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
  1911. return this;
  1912. }
  1913. var simultaneous = this.simultaneous;
  1914. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
  1915. if (!simultaneous[otherRecognizer.id]) {
  1916. simultaneous[otherRecognizer.id] = otherRecognizer;
  1917. otherRecognizer.recognizeWith(this);
  1918. }
  1919. return this;
  1920. },
  1921. /**
  1922. * drop the simultaneous link. it doesnt remove the link on the other recognizer.
  1923. * @param {Recognizer} otherRecognizer
  1924. * @returns {Recognizer} this
  1925. */
  1926. dropRecognizeWith: function(otherRecognizer) {
  1927. if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
  1928. return this;
  1929. }
  1930. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
  1931. delete this.simultaneous[otherRecognizer.id];
  1932. return this;
  1933. },
  1934. /**
  1935. * recognizer can only run when an other is failing
  1936. * @param {Recognizer} otherRecognizer
  1937. * @returns {Recognizer} this
  1938. */
  1939. requireFailure: function(otherRecognizer) {
  1940. if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
  1941. return this;
  1942. }
  1943. var requireFail = this.requireFail;
  1944. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
  1945. if (inArray(requireFail, otherRecognizer) === -1) {
  1946. requireFail.push(otherRecognizer);
  1947. otherRecognizer.requireFailure(this);
  1948. }
  1949. return this;
  1950. },
  1951. /**
  1952. * drop the requireFailure link. it does not remove the link on the other recognizer.
  1953. * @param {Recognizer} otherRecognizer
  1954. * @returns {Recognizer} this
  1955. */
  1956. dropRequireFailure: function(otherRecognizer) {
  1957. if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
  1958. return this;
  1959. }
  1960. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
  1961. var index = inArray(this.requireFail, otherRecognizer);
  1962. if (index > -1) {
  1963. this.requireFail.splice(index, 1);
  1964. }
  1965. return this;
  1966. },
  1967. /**
  1968. * has require failures boolean
  1969. * @returns {boolean}
  1970. */
  1971. hasRequireFailures: function() {
  1972. return this.requireFail.length > 0;
  1973. },
  1974. /**
  1975. * if the recognizer can recognize simultaneous with an other recognizer
  1976. * @param {Recognizer} otherRecognizer
  1977. * @returns {Boolean}
  1978. */
  1979. canRecognizeWith: function(otherRecognizer) {
  1980. return !!this.simultaneous[otherRecognizer.id];
  1981. },
  1982. /**
  1983. * You should use `tryEmit` instead of `emit` directly to check
  1984. * that all the needed recognizers has failed before emitting.
  1985. * @param {Object} input
  1986. */
  1987. emit: function(input) {
  1988. var self = this;
  1989. var state = this.state;
  1990. function emit(event) {
  1991. self.manager.emit(event, input);
  1992. }
  1993. // 'panstart' and 'panmove'
  1994. if (state < STATE_ENDED) {
  1995. emit(self.options.event + stateStr(state));
  1996. }
  1997. emit(self.options.event); // simple 'eventName' events
  1998. if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...)
  1999. emit(input.additionalEvent);
  2000. }
  2001. // panend and pancancel
  2002. if (state >= STATE_ENDED) {
  2003. emit(self.options.event + stateStr(state));
  2004. }
  2005. },
  2006. /**
  2007. * Check that all the require failure recognizers has failed,
  2008. * if true, it emits a gesture event,
  2009. * otherwise, setup the state to FAILED.
  2010. * @param {Object} input
  2011. */
  2012. tryEmit: function(input) {
  2013. if (this.canEmit()) {
  2014. return this.emit(input);
  2015. }
  2016. // it's failing anyway
  2017. this.state = STATE_FAILED;
  2018. },
  2019. /**
  2020. * can we emit?
  2021. * @returns {boolean}
  2022. */
  2023. canEmit: function() {
  2024. var i = 0;
  2025. while (i < this.requireFail.length) {
  2026. if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
  2027. return false;
  2028. }
  2029. i++;
  2030. }
  2031. return true;
  2032. },
  2033. /**
  2034. * update the recognizer
  2035. * @param {Object} inputData
  2036. */
  2037. recognize: function(inputData) {
  2038. // make a new copy of the inputData
  2039. // so we can change the inputData without messing up the other recognizers
  2040. var inputDataClone = assign({}, inputData);
  2041. // is is enabled and allow recognizing?
  2042. if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
  2043. this.reset();
  2044. this.state = STATE_FAILED;
  2045. return;
  2046. }
  2047. // reset when we've reached the end
  2048. if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
  2049. this.state = STATE_POSSIBLE;
  2050. }
  2051. this.state = this.process(inputDataClone);
  2052. // the recognizer has recognized a gesture
  2053. // so trigger an event
  2054. if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
  2055. this.tryEmit(inputDataClone);
  2056. }
  2057. },
  2058. /**
  2059. * return the state of the recognizer
  2060. * the actual recognizing happens in this method
  2061. * @virtual
  2062. * @param {Object} inputData
  2063. * @returns {Const} STATE
  2064. */
  2065. process: function(inputData) { }, // jshint ignore:line
  2066. /**
  2067. * return the preferred touch-action
  2068. * @virtual
  2069. * @returns {Array}
  2070. */
  2071. getTouchAction: function() { },
  2072. /**
  2073. * called when the gesture isn't allowed to recognize
  2074. * like when another is being recognized or it is disabled
  2075. * @virtual
  2076. */
  2077. reset: function() { }
  2078. };
  2079. /**
  2080. * get a usable string, used as event postfix
  2081. * @param {Const} state
  2082. * @returns {String} state
  2083. */
  2084. function stateStr(state) {
  2085. if (state & STATE_CANCELLED) {
  2086. return 'cancel';
  2087. } else if (state & STATE_ENDED) {
  2088. return 'end';
  2089. } else if (state & STATE_CHANGED) {
  2090. return 'move';
  2091. } else if (state & STATE_BEGAN) {
  2092. return 'start';
  2093. }
  2094. return '';
  2095. }
  2096. /**
  2097. * direction cons to string
  2098. * @param {Const} direction
  2099. * @returns {String}
  2100. */
  2101. function directionStr(direction) {
  2102. if (direction == DIRECTION_DOWN) {
  2103. return 'down';
  2104. } else if (direction == DIRECTION_UP) {
  2105. return 'up';
  2106. } else if (direction == DIRECTION_LEFT) {
  2107. return 'left';
  2108. } else if (direction == DIRECTION_RIGHT) {
  2109. return 'right';
  2110. }
  2111. return '';
  2112. }
  2113. /**
  2114. * get a recognizer by name if it is bound to a manager
  2115. * @param {Recognizer|String} otherRecognizer
  2116. * @param {Recognizer} recognizer
  2117. * @returns {Recognizer}
  2118. */
  2119. function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
  2120. var manager = recognizer.manager;
  2121. if (manager) {
  2122. return manager.get(otherRecognizer);
  2123. }
  2124. return otherRecognizer;
  2125. }
  2126. /**
  2127. * This recognizer is just used as a base for the simple attribute recognizers.
  2128. * @constructor
  2129. * @extends Recognizer
  2130. */
  2131. function AttrRecognizer() {
  2132. Recognizer.apply(this, arguments);
  2133. }
  2134. inherit(AttrRecognizer, Recognizer, {
  2135. /**
  2136. * @namespace
  2137. * @memberof AttrRecognizer
  2138. */
  2139. defaults: {
  2140. /**
  2141. * @type {Number}
  2142. * @default 1
  2143. */
  2144. pointers: 1
  2145. },
  2146. /**
  2147. * Used to check if it the recognizer receives valid input, like input.distance > 10.
  2148. * @memberof AttrRecognizer
  2149. * @param {Object} input
  2150. * @returns {Boolean} recognized
  2151. */
  2152. attrTest: function(input) {
  2153. var optionPointers = this.options.pointers;
  2154. return optionPointers === 0 || input.pointers.length === optionPointers;
  2155. },
  2156. /**
  2157. * Process the input and return the state for the recognizer
  2158. * @memberof AttrRecognizer
  2159. * @param {Object} input
  2160. * @returns {*} State
  2161. */
  2162. process: function(input) {
  2163. var state = this.state;
  2164. var eventType = input.eventType;
  2165. var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
  2166. var isValid = this.attrTest(input);
  2167. // on cancel input and we've recognized before, return STATE_CANCELLED
  2168. if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
  2169. return state | STATE_CANCELLED;
  2170. } else if (isRecognized || isValid) {
  2171. if (eventType & INPUT_END) {
  2172. return state | STATE_ENDED;
  2173. } else if (!(state & STATE_BEGAN)) {
  2174. return STATE_BEGAN;
  2175. }
  2176. return state | STATE_CHANGED;
  2177. }
  2178. return STATE_FAILED;
  2179. }
  2180. });
  2181. /**
  2182. * Pan
  2183. * Recognized when the pointer is down and moved in the allowed direction.
  2184. * @constructor
  2185. * @extends AttrRecognizer
  2186. */
  2187. function PanRecognizer() {
  2188. AttrRecognizer.apply(this, arguments);
  2189. this.pX = null;
  2190. this.pY = null;
  2191. }
  2192. inherit(PanRecognizer, AttrRecognizer, {
  2193. /**
  2194. * @namespace
  2195. * @memberof PanRecognizer
  2196. */
  2197. defaults: {
  2198. event: 'pan',
  2199. threshold: 10,
  2200. pointers: 1,
  2201. direction: DIRECTION_ALL
  2202. },
  2203. getTouchAction: function() {
  2204. var direction = this.options.direction;
  2205. var actions = [];
  2206. if (direction & DIRECTION_HORIZONTAL) {
  2207. actions.push(TOUCH_ACTION_PAN_Y);
  2208. }
  2209. if (direction & DIRECTION_VERTICAL) {
  2210. actions.push(TOUCH_ACTION_PAN_X);
  2211. }
  2212. return actions;
  2213. },
  2214. directionTest: function(input) {
  2215. var options = this.options;
  2216. var hasMoved = true;
  2217. var distance = input.distance;
  2218. var direction = input.direction;
  2219. var x = input.deltaX;
  2220. var y = input.deltaY;
  2221. // lock to axis?
  2222. if (!(direction & options.direction)) {
  2223. if (options.direction & DIRECTION_HORIZONTAL) {
  2224. direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
  2225. hasMoved = x != this.pX;
  2226. distance = Math.abs(input.deltaX);
  2227. } else {
  2228. direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
  2229. hasMoved = y != this.pY;
  2230. distance = Math.abs(input.deltaY);
  2231. }
  2232. }
  2233. input.direction = direction;
  2234. return hasMoved && distance > options.threshold && direction & options.direction;
  2235. },
  2236. attrTest: function(input) {
  2237. return AttrRecognizer.prototype.attrTest.call(this, input) &&
  2238. (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
  2239. },
  2240. emit: function(input) {
  2241. this.pX = input.deltaX;
  2242. this.pY = input.deltaY;
  2243. var direction = directionStr(input.direction);
  2244. if (direction) {
  2245. input.additionalEvent = this.options.event + direction;
  2246. }
  2247. this._super.emit.call(this, input);
  2248. }
  2249. });
  2250. /**
  2251. * Pinch
  2252. * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
  2253. * @constructor
  2254. * @extends AttrRecognizer
  2255. */
  2256. function PinchRecognizer() {
  2257. AttrRecognizer.apply(this, arguments);
  2258. }
  2259. inherit(PinchRecognizer, AttrRecognizer, {
  2260. /**
  2261. * @namespace
  2262. * @memberof PinchRecognizer
  2263. */
  2264. defaults: {
  2265. event: 'pinch',
  2266. threshold: 0,
  2267. pointers: 2
  2268. },
  2269. getTouchAction: function() {
  2270. return [TOUCH_ACTION_NONE];
  2271. },
  2272. attrTest: function(input) {
  2273. return this._super.attrTest.call(this, input) &&
  2274. (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
  2275. },
  2276. emit: function(input) {
  2277. if (input.scale !== 1) {
  2278. var inOut = input.scale < 1 ? 'in' : 'out';
  2279. input.additionalEvent = this.options.event + inOut;
  2280. }
  2281. this._super.emit.call(this, input);
  2282. }
  2283. });
  2284. /**
  2285. * Press
  2286. * Recognized when the pointer is down for x ms without any movement.
  2287. * @constructor
  2288. * @extends Recognizer
  2289. */
  2290. function PressRecognizer() {
  2291. Recognizer.apply(this, arguments);
  2292. this._timer = null;
  2293. this._input = null;
  2294. }
  2295. inherit(PressRecognizer, Recognizer, {
  2296. /**
  2297. * @namespace
  2298. * @memberof PressRecognizer
  2299. */
  2300. defaults: {
  2301. event: 'press',
  2302. pointers: 1,
  2303. time: 251, // minimal time of the pointer to be pressed
  2304. threshold: 9 // a minimal movement is ok, but keep it low
  2305. },
  2306. getTouchAction: function() {
  2307. return [TOUCH_ACTION_AUTO];
  2308. },
  2309. process: function(input) {
  2310. var options = this.options;
  2311. var validPointers = input.pointers.length === options.pointers;
  2312. var validMovement = input.distance < options.threshold;
  2313. var validTime = input.deltaTime > options.time;
  2314. this._input = input;
  2315. // we only allow little movement
  2316. // and we've reached an end event, so a tap is possible
  2317. if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
  2318. this.reset();
  2319. } else if (input.eventType & INPUT_START) {
  2320. this.reset();
  2321. this._timer = setTimeoutContext(function() {
  2322. this.state = STATE_RECOGNIZED;
  2323. this.tryEmit();
  2324. }, options.time, this);
  2325. } else if (input.eventType & INPUT_END) {
  2326. return STATE_RECOGNIZED;
  2327. }
  2328. return STATE_FAILED;
  2329. },
  2330. reset: function() {
  2331. clearTimeout(this._timer);
  2332. },
  2333. emit: function(input) {
  2334. if (this.state !== STATE_RECOGNIZED) {
  2335. return;
  2336. }
  2337. if (input && (input.eventType & INPUT_END)) {
  2338. this.manager.emit(this.options.event + 'up', input);
  2339. } else {
  2340. this._input.timeStamp = now();
  2341. this.manager.emit(this.options.event, this._input);
  2342. }
  2343. }
  2344. });
  2345. /**
  2346. * Rotate
  2347. * Recognized when two or more pointer are moving in a circular motion.
  2348. * @constructor
  2349. * @extends AttrRecognizer
  2350. */
  2351. function RotateRecognizer() {
  2352. AttrRecognizer.apply(this, arguments);
  2353. }
  2354. inherit(RotateRecognizer, AttrRecognizer, {
  2355. /**
  2356. * @namespace
  2357. * @memberof RotateRecognizer
  2358. */
  2359. defaults: {
  2360. event: 'rotate',
  2361. threshold: 0,
  2362. pointers: 2
  2363. },
  2364. getTouchAction: function() {
  2365. return [TOUCH_ACTION_NONE];
  2366. },
  2367. attrTest: function(input) {
  2368. return this._super.attrTest.call(this, input) &&
  2369. (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
  2370. }
  2371. });
  2372. /**
  2373. * Swipe
  2374. * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
  2375. * @constructor
  2376. * @extends AttrRecognizer
  2377. */
  2378. function SwipeRecognizer() {
  2379. AttrRecognizer.apply(this, arguments);
  2380. }
  2381. inherit(SwipeRecognizer, AttrRecognizer, {
  2382. /**
  2383. * @namespace
  2384. * @memberof SwipeRecognizer
  2385. */
  2386. defaults: {
  2387. event: 'swipe',
  2388. threshold: 10,
  2389. velocity: 0.3,
  2390. direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
  2391. pointers: 1
  2392. },
  2393. getTouchAction: function() {
  2394. return PanRecognizer.prototype.getTouchAction.call(this);
  2395. },
  2396. attrTest: function(input) {
  2397. var direction = this.options.direction;
  2398. var velocity;
  2399. if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
  2400. velocity = input.overallVelocity;
  2401. } else if (direction & DIRECTION_HORIZONTAL) {
  2402. velocity = input.overallVelocityX;
  2403. } else if (direction & DIRECTION_VERTICAL) {
  2404. velocity = input.overallVelocityY;
  2405. }
  2406. return this._super.attrTest.call(this, input) &&
  2407. direction & input.offsetDirection &&
  2408. input.distance > this.options.threshold &&
  2409. input.maxPointers == this.options.pointers &&
  2410. abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
  2411. },
  2412. emit: function(input) {
  2413. var direction = directionStr(input.offsetDirection);
  2414. if (direction) {
  2415. this.manager.emit(this.options.event + direction, input);
  2416. }
  2417. this.manager.emit(this.options.event, input);
  2418. }
  2419. });
  2420. /**
  2421. * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
  2422. * between the given interval and position. The delay option can be used to recognize multi-taps without firing
  2423. * a single tap.
  2424. *
  2425. * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
  2426. * multi-taps being recognized.
  2427. * @constructor
  2428. * @extends Recognizer
  2429. */
  2430. function TapRecognizer() {
  2431. Recognizer.apply(this, arguments);
  2432. // previous time and center,
  2433. // used for tap counting
  2434. this.pTime = false;
  2435. this.pCenter = false;
  2436. this._timer = null;
  2437. this._input = null;
  2438. this.count = 0;
  2439. }
  2440. inherit(TapRecognizer, Recognizer, {
  2441. /**
  2442. * @namespace
  2443. * @memberof PinchRecognizer
  2444. */
  2445. defaults: {
  2446. event: 'tap',
  2447. pointers: 1,
  2448. taps: 1,
  2449. interval: 300, // max time between the multi-tap taps
  2450. time: 250, // max time of the pointer to be down (like finger on the screen)
  2451. threshold: 9, // a minimal movement is ok, but keep it low
  2452. posThreshold: 10 // a multi-tap can be a bit off the initial position
  2453. },
  2454. getTouchAction: function() {
  2455. return [TOUCH_ACTION_MANIPULATION];
  2456. },
  2457. process: function(input) {
  2458. var options = this.options;
  2459. var validPointers = input.pointers.length === options.pointers;
  2460. var validMovement = input.distance < options.threshold;
  2461. var validTouchTime = input.deltaTime < options.time;
  2462. this.reset();
  2463. if ((input.eventType & INPUT_START) && (this.count === 0)) {
  2464. return this.failTimeout();
  2465. }
  2466. // we only allow little movement
  2467. // and we've reached an end event, so a tap is possible
  2468. if (validMovement && validTouchTime && validPointers) {
  2469. if (input.eventType != INPUT_END) {
  2470. return this.failTimeout();
  2471. }
  2472. var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
  2473. var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
  2474. this.pTime = input.timeStamp;
  2475. this.pCenter = input.center;
  2476. if (!validMultiTap || !validInterval) {
  2477. this.count = 1;
  2478. } else {
  2479. this.count += 1;
  2480. }
  2481. this._input = input;
  2482. // if tap count matches we have recognized it,
  2483. // else it has began recognizing...
  2484. var tapCount = this.count % options.taps;
  2485. if (tapCount === 0) {
  2486. // no failing requirements, immediately trigger the tap event
  2487. // or wait as long as the multitap interval to trigger
  2488. if (!this.hasRequireFailures()) {
  2489. return STATE_RECOGNIZED;
  2490. } else {
  2491. this._timer = setTimeoutContext(function() {
  2492. this.state = STATE_RECOGNIZED;
  2493. this.tryEmit();
  2494. }, options.interval, this);
  2495. return STATE_BEGAN;
  2496. }
  2497. }
  2498. }
  2499. return STATE_FAILED;
  2500. },
  2501. failTimeout: function() {
  2502. this._timer = setTimeoutContext(function() {
  2503. this.state = STATE_FAILED;
  2504. }, this.options.interval, this);
  2505. return STATE_FAILED;
  2506. },
  2507. reset: function() {
  2508. clearTimeout(this._timer);
  2509. },
  2510. emit: function() {
  2511. if (this.state == STATE_RECOGNIZED) {
  2512. this._input.tapCount = this.count;
  2513. this.manager.emit(this.options.event, this._input);
  2514. }
  2515. }
  2516. });
  2517. /**
  2518. * Simple way to create a manager with a default set of recognizers.
  2519. * @param {HTMLElement} element
  2520. * @param {Object} [options]
  2521. * @constructor
  2522. */
  2523. function Hammer(element, options) {
  2524. options = options || {};
  2525. options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
  2526. return new Manager(element, options);
  2527. }
  2528. /**
  2529. * @const {string}
  2530. */
  2531. Hammer.VERSION = '2.0.7';
  2532. /**
  2533. * default settings
  2534. * @namespace
  2535. */
  2536. Hammer.defaults = {
  2537. /**
  2538. * set if DOM events are being triggered.
  2539. * But this is slower and unused by simple implementations, so disabled by default.
  2540. * @type {Boolean}
  2541. * @default false
  2542. */
  2543. domEvents: false,
  2544. /**
  2545. * The value for the touchAction property/fallback.
  2546. * When set to `compute` it will magically set the correct value based on the added recognizers.
  2547. * @type {String}
  2548. * @default compute
  2549. */
  2550. touchAction: TOUCH_ACTION_COMPUTE,
  2551. /**
  2552. * @type {Boolean}
  2553. * @default true
  2554. */
  2555. enable: true,
  2556. /**
  2557. * EXPERIMENTAL FEATURE -- can be removed/changed
  2558. * Change the parent input target element.
  2559. * If Null, then it is being set the to main element.
  2560. * @type {Null|EventTarget}
  2561. * @default null
  2562. */
  2563. inputTarget: null,
  2564. /**
  2565. * force an input class
  2566. * @type {Null|Function}
  2567. * @default null
  2568. */
  2569. inputClass: null,
  2570. /**
  2571. * Default recognizer setup when calling `Hammer()`
  2572. * When creating a new Manager these will be skipped.
  2573. * @type {Array}
  2574. */
  2575. preset: [
  2576. // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
  2577. [RotateRecognizer, {enable: false}],
  2578. [PinchRecognizer, {enable: false}, ['rotate']],
  2579. [SwipeRecognizer, {direction: DIRECTION_HORIZONTAL}],
  2580. [PanRecognizer, {direction: DIRECTION_HORIZONTAL}, ['swipe']],
  2581. [TapRecognizer],
  2582. [TapRecognizer, {event: 'doubletap', taps: 2}, ['tap']],
  2583. [PressRecognizer]
  2584. ],
  2585. /**
  2586. * Some CSS properties can be used to improve the working of Hammer.
  2587. * Add them to this method and they will be set when creating a new Manager.
  2588. * @namespace
  2589. */
  2590. cssProps: {
  2591. /**
  2592. * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
  2593. * @type {String}
  2594. * @default 'none'
  2595. */
  2596. userSelect: 'none',
  2597. /**
  2598. * Disable the Windows Phone grippers when pressing an element.
  2599. * @type {String}
  2600. * @default 'none'
  2601. */
  2602. touchSelect: 'none',
  2603. /**
  2604. * Disables the default callout shown when you touch and hold a touch target.
  2605. * On iOS, when you touch and hold a touch target such as a link, Safari displays
  2606. * a callout containing information about the link. This property allows you to disable that callout.
  2607. * @type {String}
  2608. * @default 'none'
  2609. */
  2610. touchCallout: 'none',
  2611. /**
  2612. * Specifies whether zooming is enabled. Used by IE10>
  2613. * @type {String}
  2614. * @default 'none'
  2615. */
  2616. contentZooming: 'none',
  2617. /**
  2618. * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
  2619. * @type {String}
  2620. * @default 'none'
  2621. */
  2622. userDrag: 'none',
  2623. /**
  2624. * Overrides the highlight color shown when the user taps a link or a JavaScript
  2625. * clickable element in iOS. This property obeys the alpha value, if specified.
  2626. * @type {String}
  2627. * @default 'rgba(0,0,0,0)'
  2628. */
  2629. tapHighlightColor: 'rgba(0,0,0,0)'
  2630. }
  2631. };
  2632. var STOP = 1;
  2633. var FORCED_STOP = 2;
  2634. /**
  2635. * Manager
  2636. * @param {HTMLElement} element
  2637. * @param {Object} [options]
  2638. * @constructor
  2639. */
  2640. function Manager(element, options) {
  2641. this.options = assign({}, Hammer.defaults, options || {});
  2642. this.options.inputTarget = this.options.inputTarget || element;
  2643. this.handlers = {};
  2644. this.session = {};
  2645. this.recognizers = [];
  2646. this.oldCssProps = {};
  2647. this.element = element;
  2648. this.input = createInputInstance(this);
  2649. this.touchAction = new TouchAction(this, this.options.touchAction);
  2650. toggleCssProps(this, true);
  2651. each(this.options.recognizers, function(item) {
  2652. var recognizer = this.add(new (item[0])(item[1]));
  2653. item[2] && recognizer.recognizeWith(item[2]);
  2654. item[3] && recognizer.requireFailure(item[3]);
  2655. }, this);
  2656. }
  2657. Manager.prototype = {
  2658. /**
  2659. * set options
  2660. * @param {Object} options
  2661. * @returns {Manager}
  2662. */
  2663. set: function(options) {
  2664. assign(this.options, options);
  2665. // Options that need a little more setup
  2666. if (options.touchAction) {
  2667. this.touchAction.update();
  2668. }
  2669. if (options.inputTarget) {
  2670. // Clean up existing event listeners and reinitialize
  2671. this.input.destroy();
  2672. this.input.target = options.inputTarget;
  2673. this.input.init();
  2674. }
  2675. return this;
  2676. },
  2677. /**
  2678. * stop recognizing for this session.
  2679. * This session will be discarded, when a new [input]start event is fired.
  2680. * When forced, the recognizer cycle is stopped immediately.
  2681. * @param {Boolean} [force]
  2682. */
  2683. stop: function(force) {
  2684. this.session.stopped = force ? FORCED_STOP : STOP;
  2685. },
  2686. /**
  2687. * run the recognizers!
  2688. * called by the inputHandler function on every movement of the pointers (touches)
  2689. * it walks through all the recognizers and tries to detect the gesture that is being made
  2690. * @param {Object} inputData
  2691. */
  2692. recognize: function(inputData) {
  2693. var session = this.session;
  2694. if (session.stopped) {
  2695. return;
  2696. }
  2697. // run the touch-action polyfill
  2698. this.touchAction.preventDefaults(inputData);
  2699. var recognizer;
  2700. var recognizers = this.recognizers;
  2701. // this holds the recognizer that is being recognized.
  2702. // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
  2703. // if no recognizer is detecting a thing, it is set to `null`
  2704. var curRecognizer = session.curRecognizer;
  2705. // reset when the last recognizer is recognized
  2706. // or when we're in a new session
  2707. if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
  2708. curRecognizer = session.curRecognizer = null;
  2709. }
  2710. var i = 0;
  2711. while (i < recognizers.length) {
  2712. recognizer = recognizers[i];
  2713. // find out if we are allowed try to recognize the input for this one.
  2714. // 1. allow if the session is NOT forced stopped (see the .stop() method)
  2715. // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
  2716. // that is being recognized.
  2717. // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
  2718. // this can be setup with the `recognizeWith()` method on the recognizer.
  2719. if (session.stopped !== FORCED_STOP && ( // 1
  2720. !curRecognizer || recognizer == curRecognizer || // 2
  2721. recognizer.canRecognizeWith(curRecognizer))) { // 3
  2722. recognizer.recognize(inputData);
  2723. } else {
  2724. recognizer.reset();
  2725. }
  2726. // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
  2727. // current active recognizer. but only if we don't already have an active recognizer
  2728. if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
  2729. curRecognizer = session.curRecognizer = recognizer;
  2730. }
  2731. i++;
  2732. }
  2733. },
  2734. /**
  2735. * get a recognizer by its event name.
  2736. * @param {Recognizer|String} recognizer
  2737. * @returns {Recognizer|Null}
  2738. */
  2739. get: function(recognizer) {
  2740. if (recognizer instanceof Recognizer) {
  2741. return recognizer;
  2742. }
  2743. var recognizers = this.recognizers;
  2744. for (var i = 0; i < recognizers.length; i++) {
  2745. if (recognizers[i].options.event == recognizer) {
  2746. return recognizers[i];
  2747. }
  2748. }
  2749. return null;
  2750. },
  2751. /**
  2752. * add a recognizer to the manager
  2753. * existing recognizers with the same event name will be removed
  2754. * @param {Recognizer} recognizer
  2755. * @returns {Recognizer|Manager}
  2756. */
  2757. add: function(recognizer) {
  2758. if (invokeArrayArg(recognizer, 'add', this)) {
  2759. return this;
  2760. }
  2761. // remove existing
  2762. var existing = this.get(recognizer.options.event);
  2763. if (existing) {
  2764. this.remove(existing);
  2765. }
  2766. this.recognizers.push(recognizer);
  2767. recognizer.manager = this;
  2768. this.touchAction.update();
  2769. return recognizer;
  2770. },
  2771. /**
  2772. * remove a recognizer by name or instance
  2773. * @param {Recognizer|String} recognizer
  2774. * @returns {Manager}
  2775. */
  2776. remove: function(recognizer) {
  2777. if (invokeArrayArg(recognizer, 'remove', this)) {
  2778. return this;
  2779. }
  2780. recognizer = this.get(recognizer);
  2781. // let's make sure this recognizer exists
  2782. if (recognizer) {
  2783. var recognizers = this.recognizers;
  2784. var index = inArray(recognizers, recognizer);
  2785. if (index !== -1) {
  2786. recognizers.splice(index, 1);
  2787. this.touchAction.update();
  2788. }
  2789. }
  2790. return this;
  2791. },
  2792. /**
  2793. * bind event
  2794. * @param {String} events
  2795. * @param {Function} handler
  2796. * @returns {EventEmitter} this
  2797. */
  2798. on: function(events, handler) {
  2799. if (events === undefined$1) {
  2800. return;
  2801. }
  2802. if (handler === undefined$1) {
  2803. return;
  2804. }
  2805. var handlers = this.handlers;
  2806. each(splitStr(events), function(event) {
  2807. handlers[event] = handlers[event] || [];
  2808. handlers[event].push(handler);
  2809. });
  2810. return this;
  2811. },
  2812. /**
  2813. * unbind event, leave emit blank to remove all handlers
  2814. * @param {String} events
  2815. * @param {Function} [handler]
  2816. * @returns {EventEmitter} this
  2817. */
  2818. off: function(events, handler) {
  2819. if (events === undefined$1) {
  2820. return;
  2821. }
  2822. var handlers = this.handlers;
  2823. each(splitStr(events), function(event) {
  2824. if (!handler) {
  2825. delete handlers[event];
  2826. } else {
  2827. handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
  2828. }
  2829. });
  2830. return this;
  2831. },
  2832. /**
  2833. * emit event to the listeners
  2834. * @param {String} event
  2835. * @param {Object} data
  2836. */
  2837. emit: function(event, data) {
  2838. // we also want to trigger dom events
  2839. if (this.options.domEvents) {
  2840. triggerDomEvent(event, data);
  2841. }
  2842. // no handlers, so skip it all
  2843. var handlers = this.handlers[event] && this.handlers[event].slice();
  2844. if (!handlers || !handlers.length) {
  2845. return;
  2846. }
  2847. data.type = event;
  2848. data.preventDefault = function() {
  2849. data.srcEvent.preventDefault();
  2850. };
  2851. var i = 0;
  2852. while (i < handlers.length) {
  2853. handlers[i](data);
  2854. i++;
  2855. }
  2856. },
  2857. /**
  2858. * destroy the manager and unbinds all events
  2859. * it doesn't unbind dom events, that is the user own responsibility
  2860. */
  2861. destroy: function() {
  2862. this.element && toggleCssProps(this, false);
  2863. this.handlers = {};
  2864. this.session = {};
  2865. this.input.destroy();
  2866. this.element = null;
  2867. }
  2868. };
  2869. /**
  2870. * add/remove the css properties as defined in manager.options.cssProps
  2871. * @param {Manager} manager
  2872. * @param {Boolean} add
  2873. */
  2874. function toggleCssProps(manager, add) {
  2875. var element = manager.element;
  2876. if (!element.style) {
  2877. return;
  2878. }
  2879. var prop;
  2880. each(manager.options.cssProps, function(value, name) {
  2881. prop = prefixed(element.style, name);
  2882. if (add) {
  2883. manager.oldCssProps[prop] = element.style[prop];
  2884. element.style[prop] = value;
  2885. } else {
  2886. element.style[prop] = manager.oldCssProps[prop] || '';
  2887. }
  2888. });
  2889. if (!add) {
  2890. manager.oldCssProps = {};
  2891. }
  2892. }
  2893. /**
  2894. * trigger dom event
  2895. * @param {String} event
  2896. * @param {Object} data
  2897. */
  2898. function triggerDomEvent(event, data) {
  2899. var gestureEvent = document.createEvent('Event');
  2900. gestureEvent.initEvent(event, true, true);
  2901. gestureEvent.gesture = data;
  2902. data.target.dispatchEvent(gestureEvent);
  2903. }
  2904. assign(Hammer, {
  2905. INPUT_START: INPUT_START,
  2906. INPUT_MOVE: INPUT_MOVE,
  2907. INPUT_END: INPUT_END,
  2908. INPUT_CANCEL: INPUT_CANCEL,
  2909. STATE_POSSIBLE: STATE_POSSIBLE,
  2910. STATE_BEGAN: STATE_BEGAN,
  2911. STATE_CHANGED: STATE_CHANGED,
  2912. STATE_ENDED: STATE_ENDED,
  2913. STATE_RECOGNIZED: STATE_RECOGNIZED,
  2914. STATE_CANCELLED: STATE_CANCELLED,
  2915. STATE_FAILED: STATE_FAILED,
  2916. DIRECTION_NONE: DIRECTION_NONE,
  2917. DIRECTION_LEFT: DIRECTION_LEFT,
  2918. DIRECTION_RIGHT: DIRECTION_RIGHT,
  2919. DIRECTION_UP: DIRECTION_UP,
  2920. DIRECTION_DOWN: DIRECTION_DOWN,
  2921. DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
  2922. DIRECTION_VERTICAL: DIRECTION_VERTICAL,
  2923. DIRECTION_ALL: DIRECTION_ALL,
  2924. Manager: Manager,
  2925. Input: Input,
  2926. TouchAction: TouchAction,
  2927. TouchInput: TouchInput,
  2928. MouseInput: MouseInput,
  2929. PointerEventInput: PointerEventInput,
  2930. TouchMouseInput: TouchMouseInput,
  2931. SingleTouchInput: SingleTouchInput,
  2932. Recognizer: Recognizer,
  2933. AttrRecognizer: AttrRecognizer,
  2934. Tap: TapRecognizer,
  2935. Pan: PanRecognizer,
  2936. Swipe: SwipeRecognizer,
  2937. Pinch: PinchRecognizer,
  2938. Rotate: RotateRecognizer,
  2939. Press: PressRecognizer,
  2940. on: addEventListeners,
  2941. off: removeEventListeners,
  2942. each: each,
  2943. merge: merge,
  2944. extend: extend,
  2945. assign: assign,
  2946. inherit: inherit,
  2947. bindFn: bindFn,
  2948. prefixed: prefixed
  2949. });
  2950. // this prevents errors when Hammer is loaded in the presence of an AMD
  2951. // style loader but by script tag, not by the loader.
  2952. var freeGlobal = (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); // jshint ignore:line
  2953. freeGlobal.Hammer = Hammer;
  2954. if (typeof undefined$1 === 'function' && undefined$1.amd) {
  2955. undefined$1(function() {
  2956. return Hammer;
  2957. });
  2958. } else if (module.exports) {
  2959. module.exports = Hammer;
  2960. } else {
  2961. window[exportName] = Hammer;
  2962. }
  2963. })(window, document, 'Hammer');
  2964. } (hammer));
  2965. var Hammer = hammerExports;
  2966. /**
  2967. * @param {string} str
  2968. * @returns {string}
  2969. */
  2970. function escapeCSS(str) {
  2971. return CSS.escape(str);
  2972. }
  2973. /**
  2974. * SVGs for elements are generated by the {@link GraphicsFactory}.
  2975. *
  2976. * This utility gives quick access to the important semantic
  2977. * parts of an element.
  2978. */
  2979. /**
  2980. * Returns the visual part of a diagram element.
  2981. *
  2982. * @param {SVGElement} gfx
  2983. *
  2984. * @return {SVGElement}
  2985. */
  2986. function getVisual(gfx) {
  2987. return gfx.childNodes[0];
  2988. }
  2989. var MINIMAP_VIEWBOX_PADDING = 50;
  2990. var RANGE = { min: 0.2, max: 4 },
  2991. NUM_STEPS = 10;
  2992. var DELTA_THRESHOLD = 0.1;
  2993. var LOW_PRIORITY = 250;
  2994. /**
  2995. * A minimap that reflects and lets you navigate the diagram.
  2996. */
  2997. function Minimap(
  2998. config, injector, eventBus,
  2999. canvas, elementRegistry) {
  3000. var self = this;
  3001. this._canvas = canvas;
  3002. this._elementRegistry = elementRegistry;
  3003. this._eventBus = eventBus;
  3004. this._injector = injector;
  3005. this._state = {
  3006. isOpen: undefined,
  3007. isDragging: false,
  3008. initialDragPosition: null,
  3009. offsetViewport: null,
  3010. cachedViewbox: null,
  3011. dragger: null,
  3012. svgClientRect: null,
  3013. parentClientRect: null,
  3014. zoomDelta: 0
  3015. };
  3016. this._init();
  3017. var documentManager = new Hammer.Manager(document);
  3018. documentManager.add(new Hammer.Pan());
  3019. documentManager.on('panmove', onMousemove);
  3020. documentManager.on('panend', onMouseup);
  3021. var svgManager = new Hammer.Manager(this._svg);
  3022. svgManager.add(new Hammer.Pan());
  3023. svgManager.on('panstart', mousedown(true));
  3024. svgManager.add(new Hammer.Tap());
  3025. svgManager.on('tap', function(event) {
  3026. centerViewbox(getPoint(event));
  3027. });
  3028. var viewportDomManager = new Hammer.Manager(this._viewportDom);
  3029. viewportDomManager.add(new Hammer.Pan());
  3030. viewportDomManager.on('panstart', mousedown(false));
  3031. this.toggle((config && config.open) || false);
  3032. function centerViewbox(point) {
  3033. // getBoundingClientRect might return zero-dimensional when called for the first time
  3034. if (!self._state._svgClientRect || isZeroDimensional(self._state._svgClientRect)) {
  3035. self._state._svgClientRect = self._svg.getBoundingClientRect();
  3036. }
  3037. var diagramPoint = mapMousePositionToDiagramPoint({
  3038. x: point.x - self._state._svgClientRect.left,
  3039. y: point.y - self._state._svgClientRect.top
  3040. }, self._svg, self._lastViewbox);
  3041. setViewboxCenteredAroundPoint(diagramPoint, self._canvas);
  3042. self._update();
  3043. }
  3044. function mousedown(center) {
  3045. return function onMousedown(event$1) {
  3046. var point = getPoint(event$1);
  3047. // getBoundingClientRect might return zero-dimensional when called for the first time
  3048. if (!self._state._svgClientRect || isZeroDimensional(self._state._svgClientRect)) {
  3049. self._state._svgClientRect = self._svg.getBoundingClientRect();
  3050. }
  3051. if (center) {
  3052. centerViewbox(point);
  3053. }
  3054. var diagramPoint = mapMousePositionToDiagramPoint({
  3055. x: point.x - self._state._svgClientRect.left,
  3056. y: point.y - self._state._svgClientRect.top
  3057. }, self._svg, self._lastViewbox);
  3058. var viewbox = canvas.viewbox();
  3059. var offsetViewport = getOffsetViewport(diagramPoint, viewbox);
  3060. var initialViewportDomRect = self._viewportDom.getBoundingClientRect();
  3061. // take border into account (regardless of width)
  3062. var offsetViewportDom = {
  3063. x: point.x - initialViewportDomRect.left + 1,
  3064. y: point.y - initialViewportDomRect.top + 1
  3065. };
  3066. // init dragging
  3067. assign(self._state, {
  3068. cachedViewbox: viewbox,
  3069. initialDragPosition: {
  3070. x: point.x,
  3071. y: point.y
  3072. },
  3073. isDragging: true,
  3074. offsetViewport: offsetViewport,
  3075. offsetViewportDom: offsetViewportDom,
  3076. viewportClientRect: self._viewport.getBoundingClientRect(),
  3077. parentClientRect: self._parent.getBoundingClientRect()
  3078. });
  3079. event.bind(document, 'mousemove', onMousemove);
  3080. event.bind(document, 'mouseup', onMouseup);
  3081. };
  3082. }
  3083. function onMousemove(event) {
  3084. var point = getPoint(event);
  3085. // set viewbox if dragging active
  3086. if (self._state.isDragging) {
  3087. // getBoundingClientRect might return zero-dimensional when called for the first time
  3088. if (!self._state._svgClientRect || isZeroDimensional(self._state._svgClientRect)) {
  3089. self._state._svgClientRect = self._svg.getBoundingClientRect();
  3090. }
  3091. // update viewport DOM
  3092. var offsetViewportDom = self._state.offsetViewportDom,
  3093. viewportClientRect = self._state.viewportClientRect,
  3094. parentClientRect = self._state.parentClientRect;
  3095. assign(self._viewportDom.style, {
  3096. top: (point.y - offsetViewportDom.y - parentClientRect.top) + 'px',
  3097. left: (point.x - offsetViewportDom.x - parentClientRect.left) + 'px'
  3098. });
  3099. // update overlay
  3100. var clipPath = getOverlayClipPath(parentClientRect, {
  3101. top: point.y - offsetViewportDom.y - parentClientRect.top,
  3102. left: point.x - offsetViewportDom.x - parentClientRect.left,
  3103. width: viewportClientRect.width,
  3104. height: viewportClientRect.height
  3105. });
  3106. assign(self._overlay.style, {
  3107. clipPath: clipPath
  3108. });
  3109. var diagramPoint = mapMousePositionToDiagramPoint({
  3110. x: point.x - self._state._svgClientRect.left,
  3111. y: point.y - self._state._svgClientRect.top
  3112. }, self._svg, self._lastViewbox);
  3113. setViewboxCenteredAroundPoint({
  3114. x: diagramPoint.x - self._state.offsetViewport.x,
  3115. y: diagramPoint.y - self._state.offsetViewport.y
  3116. }, self._canvas);
  3117. }
  3118. }
  3119. function onMouseup(event$1) {
  3120. var point = getPoint(event$1);
  3121. if (self._state.isDragging) {
  3122. // treat event as click
  3123. if (self._state.initialDragPosition.x === point.x
  3124. && self._state.initialDragPosition.y === point.y) {
  3125. centerViewbox(event$1);
  3126. }
  3127. self._update();
  3128. // end dragging
  3129. assign(self._state, {
  3130. cachedViewbox: null,
  3131. initialDragPosition: null,
  3132. isDragging: false,
  3133. offsetViewport: null,
  3134. offsetViewportDom: null
  3135. });
  3136. event.unbind(document, 'mousemove', onMousemove);
  3137. event.unbind(document, 'mouseup', onMouseup);
  3138. }
  3139. }
  3140. // dragging viewport scrolls canvas
  3141. event.bind(this._viewportDom, 'mousedown', mousedown(false));
  3142. event.bind(this._svg, 'mousedown', mousedown(true));
  3143. event.bind(this._parent, 'wheel', function(event) {
  3144. // stop propagation and handle scroll differently
  3145. event.preventDefault();
  3146. event.stopPropagation();
  3147. // only zoom in on ctrl; this aligns with diagram-js navigation behavior
  3148. if (!event.ctrlKey) {
  3149. return;
  3150. }
  3151. // getBoundingClientRect might return zero-dimensional when called for the first time
  3152. if (!self._state._svgClientRect || isZeroDimensional(self._state._svgClientRect)) {
  3153. self._state._svgClientRect = self._svg.getBoundingClientRect();
  3154. }
  3155. // disallow zooming through viewport outside of minimap as it is very confusing
  3156. if (!isPointInside(event, self._state._svgClientRect)) {
  3157. return;
  3158. }
  3159. var factor = event.deltaMode === 0 ? 0.020 : 0.32;
  3160. var delta = (
  3161. Math.sqrt(
  3162. Math.pow(event.deltaY, 2) +
  3163. Math.pow(event.deltaX, 2)
  3164. ) * sign(event.deltaY) * -factor
  3165. );
  3166. // add until threshold reached
  3167. self._state.zoomDelta += delta;
  3168. if (Math.abs(self._state.zoomDelta) > DELTA_THRESHOLD) {
  3169. var direction = delta > 0 ? 1 : -1;
  3170. var currentLinearZoomLevel = Math.log(canvas.zoom()) / Math.log(10);
  3171. // zoom with half the step size of stepZoom
  3172. var stepSize = getStepSize(RANGE, NUM_STEPS * 2);
  3173. // snap to a proximate zoom step
  3174. var newLinearZoomLevel = Math.round(currentLinearZoomLevel / stepSize) * stepSize;
  3175. // increase or decrease one zoom step in the given direction
  3176. newLinearZoomLevel += stepSize * direction;
  3177. // calculate the absolute logarithmic zoom level based on the linear zoom level
  3178. // (e.g. 2 for an absolute x2 zoom)
  3179. var newLogZoomLevel = Math.pow(10, newLinearZoomLevel);
  3180. canvas.zoom(cap(RANGE, newLogZoomLevel), diagramPoint);
  3181. // reset
  3182. self._state.zoomDelta = 0;
  3183. var diagramPoint = mapMousePositionToDiagramPoint({
  3184. x: event.clientX - self._state._svgClientRect.left,
  3185. y: event.clientY - self._state._svgClientRect.top
  3186. }, self._svg, self._lastViewbox);
  3187. setViewboxCenteredAroundPoint(diagramPoint, self._canvas);
  3188. self._update();
  3189. }
  3190. });
  3191. event.bind(this._toggle, 'click', function(event) {
  3192. event.preventDefault();
  3193. event.stopPropagation();
  3194. self.toggle();
  3195. });
  3196. // add shape on shape/connection added
  3197. eventBus.on([ 'shape.added', 'connection.added' ], function(context) {
  3198. var element = context.element;
  3199. self._addElement(element);
  3200. self._update();
  3201. });
  3202. // remove shape on shape/connection removed
  3203. eventBus.on([ 'shape.removed', 'connection.removed' ], function(context) {
  3204. var element = context.element;
  3205. self._removeElement(element);
  3206. self._update();
  3207. });
  3208. // update on elements changed
  3209. eventBus.on('elements.changed', LOW_PRIORITY, function(context) {
  3210. var elements = context.elements;
  3211. elements.forEach(function(element) {
  3212. self._updateElement(element);
  3213. });
  3214. self._update();
  3215. });
  3216. // update on element ID update
  3217. eventBus.on('element.updateId', function(context) {
  3218. var element = context.element,
  3219. newId = context.newId;
  3220. self._updateElementId(element, newId);
  3221. });
  3222. // update on viewbox changed
  3223. eventBus.on('canvas.viewbox.changed', function() {
  3224. if (!self._state.isDragging) {
  3225. self._update();
  3226. }
  3227. });
  3228. eventBus.on('canvas.resized', function() {
  3229. // only update if present in DOM
  3230. if (document.body.contains(self._parent)) {
  3231. if (!self._state.isDragging) {
  3232. self._update();
  3233. }
  3234. self._state._svgClientRect = self._svg.getBoundingClientRect();
  3235. }
  3236. });
  3237. eventBus.on([ 'root.set', 'plane.set' ], function(event) {
  3238. self._clear();
  3239. var element = event.element || event.plane.rootElement;
  3240. element.children.forEach(function(el) {
  3241. self._addElement(el);
  3242. });
  3243. self._update();
  3244. });
  3245. }
  3246. Minimap.$inject = [
  3247. 'config.minimap',
  3248. 'injector',
  3249. 'eventBus',
  3250. 'canvas',
  3251. 'elementRegistry'
  3252. ];
  3253. Minimap.prototype._init = function() {
  3254. var canvas = this._canvas,
  3255. container = canvas.getContainer();
  3256. // create parent div
  3257. var parent = this._parent = document.createElement('div');
  3258. classes$1(parent).add('djs-minimap');
  3259. container.appendChild(parent);
  3260. // create toggle
  3261. var toggle = this._toggle = document.createElement('div');
  3262. classes$1(toggle).add('toggle');
  3263. parent.appendChild(toggle);
  3264. // create map
  3265. var map = this._map = document.createElement('div');
  3266. classes$1(map).add('map');
  3267. parent.appendChild(map);
  3268. // create svg
  3269. var svg = this._svg = create('svg');
  3270. attr(svg, { width: '100%', height: '100%' });
  3271. append(map, svg);
  3272. // add groups
  3273. var elementsGroup = this._elementsGroup = create('g');
  3274. append(svg, elementsGroup);
  3275. var viewportGroup = this._viewportGroup = create('g');
  3276. append(svg, viewportGroup);
  3277. // add viewport SVG
  3278. var viewport = this._viewport = create('rect');
  3279. classes(viewport).add('viewport');
  3280. append(viewportGroup, viewport);
  3281. // prevent drag propagation
  3282. event.bind(parent, 'mousedown', function(event) {
  3283. event.stopPropagation();
  3284. });
  3285. // add viewport DOM
  3286. var viewportDom = this._viewportDom = document.createElement('div');
  3287. classes$1(viewportDom).add('viewport-dom');
  3288. this._parent.appendChild(viewportDom);
  3289. // add overlay
  3290. var overlay = this._overlay = document.createElement('div');
  3291. classes$1(overlay).add('overlay');
  3292. this._parent.appendChild(overlay);
  3293. };
  3294. Minimap.prototype._update = function() {
  3295. var viewbox = this._canvas.viewbox(),
  3296. innerViewbox = viewbox.inner,
  3297. outerViewbox = viewbox.outer;
  3298. if (!validViewbox(viewbox)) {
  3299. return;
  3300. }
  3301. var x, y, width, height;
  3302. var widthDifference = outerViewbox.width - innerViewbox.width,
  3303. heightDifference = outerViewbox.height - innerViewbox.height;
  3304. // update viewbox
  3305. // x
  3306. if (innerViewbox.width < outerViewbox.width) {
  3307. x = innerViewbox.x - widthDifference / 2;
  3308. width = outerViewbox.width;
  3309. if (innerViewbox.x + innerViewbox.width < outerViewbox.width) {
  3310. x = Math.min(0, innerViewbox.x);
  3311. }
  3312. } else {
  3313. x = innerViewbox.x;
  3314. width = innerViewbox.width;
  3315. }
  3316. // y
  3317. if (innerViewbox.height < outerViewbox.height) {
  3318. y = innerViewbox.y - heightDifference / 2;
  3319. height = outerViewbox.height;
  3320. if (innerViewbox.y + innerViewbox.height < outerViewbox.height) {
  3321. y = Math.min(0, innerViewbox.y);
  3322. }
  3323. } else {
  3324. y = innerViewbox.y;
  3325. height = innerViewbox.height;
  3326. }
  3327. // apply some padding
  3328. x = x - MINIMAP_VIEWBOX_PADDING;
  3329. y = y - MINIMAP_VIEWBOX_PADDING;
  3330. width = width + MINIMAP_VIEWBOX_PADDING * 2;
  3331. height = height + MINIMAP_VIEWBOX_PADDING * 2;
  3332. this._lastViewbox = {
  3333. x: x,
  3334. y: y,
  3335. width: width,
  3336. height: height
  3337. };
  3338. attr(this._svg, {
  3339. viewBox: x + ', ' + y + ', ' + width + ', ' + height
  3340. });
  3341. // update viewport SVG
  3342. attr(this._viewport, {
  3343. x: viewbox.x,
  3344. y: viewbox.y,
  3345. width: viewbox.width,
  3346. height: viewbox.height
  3347. });
  3348. // update viewport DOM
  3349. var parentClientRect = this._state._parentClientRect = this._parent.getBoundingClientRect();
  3350. var viewportClientRect = this._viewport.getBoundingClientRect();
  3351. var withoutParentOffset = {
  3352. top: viewportClientRect.top - parentClientRect.top,
  3353. left: viewportClientRect.left - parentClientRect.left,
  3354. width: viewportClientRect.width,
  3355. height: viewportClientRect.height
  3356. };
  3357. assign(this._viewportDom.style, {
  3358. top: withoutParentOffset.top + 'px',
  3359. left: withoutParentOffset.left + 'px',
  3360. width: withoutParentOffset.width + 'px',
  3361. height: withoutParentOffset.height + 'px'
  3362. });
  3363. // update overlay
  3364. var clipPath = getOverlayClipPath(parentClientRect, withoutParentOffset);
  3365. assign(this._overlay.style, {
  3366. clipPath: clipPath
  3367. });
  3368. };
  3369. Minimap.prototype.open = function() {
  3370. assign(this._state, { isOpen: true });
  3371. classes$1(this._parent).add('open');
  3372. var translate = this._injector.get('translate', false) || function(s) { return s; };
  3373. attr$1(this._toggle, 'title', translate('Close minimap'));
  3374. this._update();
  3375. this._eventBus.fire('minimap.toggle', { open: true });
  3376. };
  3377. Minimap.prototype.close = function() {
  3378. assign(this._state, { isOpen: false });
  3379. classes$1(this._parent).remove('open');
  3380. var translate = this._injector.get('translate', false) || function(s) { return s; };
  3381. attr$1(this._toggle, 'title', translate('Open minimap'));
  3382. this._eventBus.fire('minimap.toggle', { open: false });
  3383. };
  3384. Minimap.prototype.toggle = function(open) {
  3385. var currentOpen = this.isOpen();
  3386. if (typeof open === 'undefined') {
  3387. open = !currentOpen;
  3388. }
  3389. if (open == currentOpen) {
  3390. return;
  3391. }
  3392. if (open) {
  3393. this.open();
  3394. } else {
  3395. this.close();
  3396. }
  3397. };
  3398. Minimap.prototype.isOpen = function() {
  3399. return this._state.isOpen;
  3400. };
  3401. Minimap.prototype._updateElement = function(element) {
  3402. try {
  3403. // if parent is null element has been removed, if parent is undefined parent is root
  3404. if (element.parent !== undefined && element.parent !== null) {
  3405. this._removeElement(element);
  3406. this._addElement(element);
  3407. }
  3408. } catch (error) {
  3409. console.warn('Minimap#_updateElement errored', error);
  3410. }
  3411. };
  3412. Minimap.prototype._updateElementId = function(element, newId) {
  3413. try {
  3414. var elementGfx = query('#' + escapeCSS(element.id), this._elementsGroup);
  3415. if (elementGfx) {
  3416. elementGfx.id = newId;
  3417. }
  3418. } catch (error) {
  3419. console.warn('Minimap#_updateElementId errored', error);
  3420. }
  3421. };
  3422. /**
  3423. * Checks if an element is on the currently active plane.
  3424. */
  3425. Minimap.prototype.isOnActivePlane = function(element) {
  3426. var canvas = this._canvas;
  3427. // diagram-js@8
  3428. if (canvas.findRoot) {
  3429. return canvas.findRoot(element) === canvas.getRootElement();
  3430. }
  3431. // diagram-js>=7.4.0
  3432. if (canvas.findPlane) {
  3433. return canvas.findPlane(element) === canvas.getActivePlane();
  3434. }
  3435. // diagram-js<7.4.0
  3436. return true;
  3437. };
  3438. /**
  3439. * Adds an element to the minimap.
  3440. */
  3441. Minimap.prototype._addElement = function(element) {
  3442. var self = this;
  3443. this._removeElement(element);
  3444. if (!this.isOnActivePlane(element)) {
  3445. return;
  3446. }
  3447. var parent,
  3448. x, y;
  3449. var newElementGfx = this._createElement(element);
  3450. var newElementParentGfx = query('#' + escapeCSS(element.parent.id), this._elementsGroup);
  3451. if (newElementGfx) {
  3452. var elementGfx = this._elementRegistry.getGraphics(element);
  3453. var parentGfx = this._elementRegistry.getGraphics(element.parent);
  3454. var index = getIndexOfChildInParentChildren(elementGfx, parentGfx);
  3455. // index can be 0
  3456. if (index !== 'undefined') {
  3457. if (newElementParentGfx) {
  3458. // in cases of doubt add as last child
  3459. if (newElementParentGfx.childNodes.length > index) {
  3460. insertChildAtIndex(newElementGfx, newElementParentGfx, index);
  3461. } else {
  3462. insertChildAtIndex(newElementGfx, newElementParentGfx, newElementParentGfx.childNodes.length - 1);
  3463. }
  3464. } else {
  3465. this._elementsGroup.appendChild(newElementGfx);
  3466. }
  3467. } else {
  3468. // index undefined
  3469. this._elementsGroup.appendChild(newElementGfx);
  3470. }
  3471. if (isConnection(element)) {
  3472. parent = element.parent;
  3473. x = 0;
  3474. y = 0;
  3475. if (typeof parent.x !== 'undefined' && typeof parent.y !== 'undefined') {
  3476. x = -parent.x;
  3477. y = -parent.y;
  3478. }
  3479. attr(newElementGfx, { transform: 'translate(' + x + ' ' + y + ')' });
  3480. } else {
  3481. x = element.x;
  3482. y = element.y;
  3483. if (newElementParentGfx) {
  3484. parent = element.parent;
  3485. x -= parent.x;
  3486. y -= parent.y;
  3487. }
  3488. attr(newElementGfx, { transform: 'translate(' + x + ' ' + y + ')' });
  3489. }
  3490. if (element.children && element.children.length) {
  3491. element.children.forEach(function(child) {
  3492. self._addElement(child);
  3493. });
  3494. }
  3495. return newElementGfx;
  3496. }
  3497. };
  3498. Minimap.prototype._removeElement = function(element) {
  3499. var elementGfx = this._svg.getElementById(element.id);
  3500. if (elementGfx) {
  3501. remove(elementGfx);
  3502. }
  3503. };
  3504. Minimap.prototype._createElement = function(element) {
  3505. var gfx = this._elementRegistry.getGraphics(element),
  3506. visual;
  3507. if (gfx) {
  3508. visual = getVisual(gfx);
  3509. if (visual) {
  3510. var elementGfx = clone(visual);
  3511. attr(elementGfx, { id: element.id });
  3512. return elementGfx;
  3513. }
  3514. }
  3515. };
  3516. Minimap.prototype._clear = function() {
  3517. clear(this._elementsGroup);
  3518. };
  3519. function isConnection(element) {
  3520. return element.waypoints;
  3521. }
  3522. function getOffsetViewport(diagramPoint, viewbox) {
  3523. var viewboxCenter = {
  3524. x: viewbox.x + (viewbox.width / 2),
  3525. y: viewbox.y + (viewbox.height / 2)
  3526. };
  3527. return {
  3528. x: diagramPoint.x - viewboxCenter.x,
  3529. y: diagramPoint.y - viewboxCenter.y
  3530. };
  3531. }
  3532. function mapMousePositionToDiagramPoint(position, svg, lastViewbox) {
  3533. // firefox returns 0 for clientWidth and clientHeight
  3534. var boundingClientRect = svg.getBoundingClientRect();
  3535. // take different aspect ratios of default layers bounding box and minimap into account
  3536. var bBox =
  3537. fitAspectRatio(lastViewbox, boundingClientRect.width / boundingClientRect.height);
  3538. // map click position to diagram position
  3539. var diagramX = map(position.x, 0, boundingClientRect.width, bBox.x, bBox.x + bBox.width),
  3540. diagramY = map(position.y, 0, boundingClientRect.height, bBox.y, bBox.y + bBox.height);
  3541. return {
  3542. x: diagramX,
  3543. y: diagramY
  3544. };
  3545. }
  3546. function setViewboxCenteredAroundPoint(point, canvas) {
  3547. // get cached viewbox to preserve zoom
  3548. var cachedViewbox = canvas.viewbox(),
  3549. cachedViewboxWidth = cachedViewbox.width,
  3550. cachedViewboxHeight = cachedViewbox.height;
  3551. canvas.viewbox({
  3552. x: point.x - cachedViewboxWidth / 2,
  3553. y: point.y - cachedViewboxHeight / 2,
  3554. width: cachedViewboxWidth,
  3555. height: cachedViewboxHeight
  3556. });
  3557. }
  3558. function fitAspectRatio(bounds, targetAspectRatio) {
  3559. var aspectRatio = bounds.width / bounds.height;
  3560. // assigning to bounds throws exception in IE11
  3561. var newBounds = assign({}, {
  3562. x: bounds.x,
  3563. y: bounds.y,
  3564. width: bounds.width,
  3565. height: bounds.height
  3566. });
  3567. if (aspectRatio > targetAspectRatio) {
  3568. // height needs to be fitted
  3569. var height = newBounds.width * (1 / targetAspectRatio),
  3570. y = newBounds.y - ((height - newBounds.height) / 2);
  3571. assign(newBounds, {
  3572. y: y,
  3573. height: height
  3574. });
  3575. } else if (aspectRatio < targetAspectRatio) {
  3576. // width needs to be fitted
  3577. var width = newBounds.height * targetAspectRatio,
  3578. x = newBounds.x - ((width - newBounds.width) / 2);
  3579. assign(newBounds, {
  3580. x: x,
  3581. width: width
  3582. });
  3583. }
  3584. return newBounds;
  3585. }
  3586. function map(x, inMin, inMax, outMin, outMax) {
  3587. var inRange = inMax - inMin,
  3588. outRange = outMax - outMin;
  3589. return (x - inMin) * outRange / inRange + outMin;
  3590. }
  3591. /**
  3592. * Returns index of child in children of parent.
  3593. *
  3594. * g
  3595. * '- g.djs-element // parentGfx
  3596. * '- g.djs-children
  3597. * '- g
  3598. * '-g.djs-element // childGfx
  3599. */
  3600. function getIndexOfChildInParentChildren(childGfx, parentGfx) {
  3601. var childrenGroup = query('.djs-children', parentGfx.parentNode);
  3602. if (!childrenGroup) {
  3603. return;
  3604. }
  3605. var childrenArray = [].slice.call(childrenGroup.childNodes);
  3606. var indexOfChild = -1;
  3607. childrenArray.forEach(function(childGroup, index) {
  3608. if (query('.djs-element', childGroup) === childGfx) {
  3609. indexOfChild = index;
  3610. }
  3611. });
  3612. return indexOfChild;
  3613. }
  3614. function insertChildAtIndex(childGfx, parentGfx, index) {
  3615. var childContainer = getChildContainer(parentGfx);
  3616. var childrenArray = [].slice.call(childContainer.childNodes);
  3617. var childAtIndex = childrenArray[index];
  3618. if (childAtIndex) {
  3619. parentGfx.insertBefore(childGfx, childAtIndex.nextSibling);
  3620. } else {
  3621. parentGfx.appendChild(childGfx);
  3622. }
  3623. }
  3624. function getChildContainer(parentGfx) {
  3625. var container = query('.children', parentGfx);
  3626. if (!container) {
  3627. container = create('g', { class: 'children' });
  3628. append(parentGfx, container);
  3629. }
  3630. return container;
  3631. }
  3632. function isZeroDimensional(clientRect) {
  3633. return clientRect.width === 0 && clientRect.height === 0;
  3634. }
  3635. function isPointInside(point, rect) {
  3636. return point.x > rect.left
  3637. && point.x < rect.left + rect.width
  3638. && point.y > rect.top
  3639. && point.y < rect.top + rect.height;
  3640. }
  3641. var sign = Math.sign || function(n) {
  3642. return n >= 0 ? 1 : -1;
  3643. };
  3644. /**
  3645. * Get step size for given range and number of steps.
  3646. *
  3647. * @param {Object} range - Range.
  3648. * @param {number} range.min - Range minimum.
  3649. * @param {number} range.max - Range maximum.
  3650. */
  3651. function getStepSize(range, steps) {
  3652. var minLinearRange = Math.log(range.min) / Math.log(10),
  3653. maxLinearRange = Math.log(range.max) / Math.log(10);
  3654. var absoluteLinearRange = Math.abs(minLinearRange) + Math.abs(maxLinearRange);
  3655. return absoluteLinearRange / steps;
  3656. }
  3657. function cap(range, scale) {
  3658. return Math.max(range.min, Math.min(range.max, scale));
  3659. }
  3660. function getOverlayClipPath(outer, inner) {
  3661. var coordinates = [
  3662. toCoordinatesString(inner.left, inner.top),
  3663. toCoordinatesString(inner.left + inner.width, inner.top),
  3664. toCoordinatesString(inner.left + inner.width, inner.top + inner.height),
  3665. toCoordinatesString(inner.left, inner.top + inner.height),
  3666. toCoordinatesString(inner.left, outer.height),
  3667. toCoordinatesString(outer.width, outer.height),
  3668. toCoordinatesString(outer.width, 0),
  3669. toCoordinatesString(0, 0),
  3670. toCoordinatesString(0, outer.height),
  3671. toCoordinatesString(inner.left, outer.height)
  3672. ].join(', ');
  3673. return 'polygon(' + coordinates + ')';
  3674. }
  3675. function toCoordinatesString(x, y) {
  3676. return x + 'px ' + y + 'px';
  3677. }
  3678. function validViewbox(viewBox) {
  3679. return every(viewBox, function(value) {
  3680. // check deeper structures like inner or outer viewbox
  3681. if (isObject(value)) {
  3682. return validViewbox(value);
  3683. }
  3684. return isNumber(value) && isFinite(value);
  3685. });
  3686. }
  3687. function getPoint(event) {
  3688. if (event.center) {
  3689. return event.center;
  3690. }
  3691. return {
  3692. x: event.clientX,
  3693. y: event.clientY
  3694. };
  3695. }
  3696. var index = {
  3697. __init__: [ 'minimap' ],
  3698. minimap: [ 'type', Minimap ]
  3699. };
  3700. return index;
  3701. }));