{"version":3,"sources":["jsdelivr-header.js","/npm/cytoscape-navigator@2.0.2/cytoscape-navigator.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA,CCNC,WAAa,aAEZ,IAqBM,EAiBA,EAtCF,EAAW,CACX,WAAW,EACX,kBAAmB,EACnB,cAAe,IACf,uBAAuB,EACvB,cAAe,KAGf,GAaE,EAAY,KAAK,IAiBjB,EAhBY,KAAK,KAgBE,WACrB,OAAO,IAAI,MAAO,SACpB,EAiEA,SAAkB,EAAM,EAAM,GAC5B,IAAI,EACA,EACA,EACA,EACA,EACA,EACA,EAyHY,EAGZ,EA3HA,EAAa,EACb,GAAU,EACV,GAAW,EAEf,GAAmB,mBAAR,EACT,MAAM,IAAI,UApGQ,uBAuGpB,GADA,EAAO,EAAO,EAAI,GAAM,GAAQ,GAChB,IAAZ,EAAkB,CACpB,IAAI,GAAU,EACd,GAAW,CACb,MAgHI,SAHY,EA7GI,IAiHX,GAAkB,UAAR,GAA4B,YAAR,IAhHrC,IAAY,EAAQ,QACpB,EAAU,YAAa,GAAW,GAAW,EAAQ,SAAW,EAAG,GACnE,EAAW,aAAc,IAAY,EAAQ,SAAW,GAc1D,SAAS,EAAS,EAAU,GACtB,GACF,aAAa,GAEf,EAAe,EAAY,OAAe,EACtC,IACF,EAAa,IACb,EAAS,EAAK,MAAM,EAAS,GACxB,GAAc,IACjB,EAAO,OAAU,GAGvB,CAEA,SAAS,IACP,IAAI,EAAY,GAAQ,IAAQ,GAC5B,GAAa,GAAK,EAAY,EAChC,EAAS,EAAc,GAEvB,EAAY,WAAW,EAAS,EAEpC,CAEA,SAAS,IACP,EAAS,EAAU,EACrB,CAEA,SAAS,IAMP,GALA,EAAO,UACP,EAAQ,IACR,EAAU,KACV,EAAe,IAAa,IAAc,IAE1B,IAAZ,EACF,IAAI,EAAc,IAAY,MACzB,CACA,GAAiB,IACpB,EAAa,GAEf,IAAI,EAAY,GAAW,EAAQ,GAC/B,EAAW,GAAa,GAAK,EAAY,EAEzC,GACE,IACF,EAAe,aAAa,IAE9B,EAAa,EACb,EAAS,EAAK,MAAM,EAAS,IAErB,IACR,EAAe,WAAW,EAAY,GAE1C,CAcA,OAbI,GAAY,EACd,EAAY,aAAa,GAEjB,GAAa,IAAS,IAC9B,EAAY,WAAW,EAAS,IAE9B,IACF,GAAW,EACX,EAAS,EAAK,MAAM,EAAS,KAE3B,GAAa,GAAc,IAC7B,EAAO,OAAU,GAEZ,CACT,CAEA,OADA,EAAU,OA/EV,WACM,GACF,aAAa,GAEX,GACF,aAAa,GAEf,EAAa,EACb,EAAe,EAAY,OAAe,CAC5C,EAuEO,CACT,GAoDE,EAAY,SAAW,EAAS,GAClC,KAAK,MAAM,EAAS,EACtB,EAEI,EAAS,WACX,IAAI,IAAI,EAAI,EAAG,EAAI,UAAU,OAAQ,IACnC,IAAI,IAAI,KAAO,UAAU,GACpB,UAAU,GAAG,eAAe,KAC7B,UAAU,GAAG,GAAO,UAAU,GAAG,IAIvC,OAAO,UAAU,EACnB,EAEI,EAAM,SAAS,GACjB,OAAO,EAAK,wBAAwB,KACtC,EAEI,EAAM,SAAS,GACjB,OAAO,EAAK,wBAAwB,MACtC,EAEA,EAAU,UAAY,CAEpB,YAAa,EAMb,GAAI,WACJ,IAAI,EAAK,KAAK,GAAG,WAAW,cAE5B,OAAa,IAAT,EAAG,GAAoB,IAAT,EAAG,EACZ,CACL,GAAI,EACJ,GAAI,IACJ,GAAI,EACJ,GAAI,IACJ,EAAG,IACH,EAAG,KAIA,CACT,EAEE,eAAgB,SAAS,EAAQ,GACjC,KAAK,aAAa,KAAK,CACrB,OAAQ,EACR,QAAS,IAGX,KAAK,GAAG,GAAG,EAAQ,EACrB,EAEE,mBAAoB,WACpB,IAAI,EAAK,KAAK,GAEd,KAAK,aAAa,SAAQ,SAAS,GACjC,EAAG,IAAI,EAAE,OAAQ,EAAE,QACrB,IAEA,EAAG,UAAU,KAAK,iBACpB,EAEE,MAAO,SAAW,EAAI,GACpB,KAAK,aAAe,GAEpB,KAAK,SAAW,EAAG,YACnB,KAAK,QAAU,EAAO,CAAC,EAAG,EAAU,GAEpC,KAAK,GAAK,EAGV,KAAK,YAAc,KAAK,KAGxB,KAAK,MAAQ,EAAI,KAAK,UACtB,KAAK,OAAS,EAAI,KAAK,UAGvB,KAAK,aACL,KAAK,iBACL,KAAK,YACL,KAAK,cACP,EAEA,QAAS,WACP,KAAK,wBAGD,KAAK,QAAQ,YAAc,KAAK,QAAQ,sBAC1C,KAAK,OAAO,UAAY,GAExB,KAAK,OAAO,cAAc,YAAY,KAAK,OAE/C,EAYA,WAAY,WACV,IAAI,EAAU,KAAK,QAChB,EAAQ,WAA0C,iBAAtB,EAAQ,WAA0B,EAAQ,UAAU,OAAS,GAElD,IAApC,EAAQ,UAAU,QAAQ,KAC5B,KAAK,OAAS,SAAS,eAAe,EAAQ,UAAU,QAAQ,IAAK,KAErE,KAAK,OAAS,SAAS,uBAAuB,EAAQ,UAAU,QAAQ,IAAK,KAAK,IAGpF,KAAK,OAAS,SAAS,cAAc,OACrC,KAAK,OAAO,UAAY,sBACxB,SAAS,KAAK,YAAY,KAAK,SAEjC,KAAK,cACL,KAAK,eAAe,SAAU,KAAK,OAAO,KAAK,MACjD,EAEA,YAAa,WAEX,KAAK,WAAa,EAAI,KAAK,QAC3B,KAAK,YAAc,EAAI,KAAK,OAC9B,EAQA,eAAgB,WAEd,KAAK,WAAa,SAAS,cAAc,OAEzC,KAAK,WAAW,aAAa,MAAO,mBAGpC,KAAK,OAAO,YAAY,KAAK,YAG7B,KAAK,uBACL,KAAK,iBACP,EAEA,gBAAiB,WACf,KAAK,uBACP,EAEA,qBAAsB,WAEpB,KAAK,YAAc,KAAK,KAExB,KAAK,cAAgB,KAAK,IAAI,KAAK,YAAc,KAAK,YAAY,EAAG,KAAK,WAAa,KAAK,YAAY,GAGxG,KAAK,aAAe,CAClB,GAAI,KAAK,WAAa,KAAK,eAAiB,KAAK,YAAY,GAAK,KAAK,YAAY,KAAK,EACxF,GAAI,KAAK,YAAc,KAAK,eAAiB,KAAK,YAAY,GAAK,KAAK,YAAY,KAAK,EAE7F,EAIA,8BAA+B,WAE7B,IAAI,EAAQ,KAAK,cACb,EAAS,KAAK,aAAa,EAC3B,EAAS,KAAK,aAAa,EAE/B,KAAK,uBAED,GAAS,KAAK,eAAiB,GAAU,KAAK,aAAa,GAAK,GAAU,KAAK,aAAa,GAC9F,KAAK,kBACL,KAAK,cAEL,KAAK,uBAET,EAYA,UAAW,WACT,KAAK,MAAQ,SAAS,cAAc,OACpC,KAAK,MAAM,UAAY,0BACvB,KAAK,OAAO,YAAY,KAAK,OAE7B,KAAK,cAAgB,SAAS,KAAK,MAAM,MAAM,oBAAqB,KAAO,EAC3E,KAAK,gBAAkB,SAAS,KAAK,MAAM,MAAM,sBAAuB,KAAO,EAC/E,KAAK,iBAAmB,SAAS,KAAK,MAAM,MAAM,uBAAwB,KAAO,EACjF,KAAK,eAAiB,SAAS,KAAK,MAAM,MAAM,qBAAsB,KAAO,EAG7E,KAAK,qBAAuB,KAAK,eAAiB,KAAK,gBACvD,KAAK,mBAAqB,KAAK,cAAgB,KAAK,iBAEpD,KAAK,aAGL,KAAK,eAAe,WAAY,KAAK,WAAW,KAAK,MACvD,EAEA,WAAY,WACV,IAAI,KAAK,WAAT,CAGA,IAAI,EAAS,KAAK,GAAG,OACjB,EAAQ,KAAK,GAAG,MAGpB,KAAK,MAAQ,KAAK,MAAQ,EAAS,KAAK,cACxC,KAAK,OAAS,EAAM,EAAI,KAAK,MAAQ,KAAK,MAAQ,KAAK,aAAa,EAAI,KAAK,eAG7E,KAAK,MAAQ,KAAK,OAAS,EAAS,KAAK,cACzC,KAAK,OAAS,EAAM,EAAI,KAAK,MAAQ,KAAK,OAAS,KAAK,aAAa,EAAI,KAAK,cAG9E,KAAK,MAAM,MAAa,MAAI,KAAK,MAAQ,KACzC,KAAK,MAAM,MAAc,OAAI,KAAK,MAAQ,KAC1C,KAAK,MAAM,MAAgB,SAAI,WAC/B,KAAK,MAAM,MAAY,KAAI,KAAK,MAAQ,KACxC,KAAK,MAAM,MAAW,IAAI,KAAK,MAAQ,IAlBrC,CAmBJ,EAUA,aAAc,WAEZ,KAAK,SAAW,SAAS,cAAc,OACvC,KAAK,SAAS,UAAY,6BAG1B,KAAK,OAAO,YAAY,KAAK,UAG7B,KAAK,kBAAoB,EACzB,KAAK,kBAAoB,EAGzB,KAAK,qBACP,EAMA,OAAQ,WAEN,KAAK,MAAQ,EAAI,KAAK,UACtB,KAAK,OAAS,EAAI,KAAK,UACvB,KAAK,iBAAkB,EACvB,KAAK,cACL,KAAK,gCACL,KAAK,YACP,EAEA,oBAAqB,WAmJnB,IAlJA,IAAI,EAAO,KACP,EAAc,CAEd,YACA,aACA,iBAEA,cAEA,EAAe,CACf,UACA,WACA,YAEA,YACA,YAIA,EAAkB,SAAU,GAe9B,GAbe,cAAX,EAAG,OAEL,OAAO,eAAe,EAAI,UAAW,CACnC,MAAO,EAAK,MAAQ,EAAK,MAAQ,EACjC,UAAU,IAEZ,OAAO,eAAe,EAAI,UAAW,CACnC,MAAO,EAAK,MAAQ,EAAK,MAAQ,EACjC,UAAU,UAKK,IAAf,EAAG,cAAwC,IAAf,EAAG,QAAuB,CACxD,IAAI,EAAO,EAAG,OAAO,wBACjB,EAAe,CACjB,IAAK,EAAK,IAAM,OAAO,QACvB,KAAM,EAAK,KAAO,OAAO,SAE3B,OAAO,eAAe,EAAI,UAAW,CACnC,MAAO,EAAG,MAAQ,EAAa,KAC/B,UAAU,IAEZ,OAAO,eAAe,EAAI,UAAW,CACnC,MAAO,EAAG,MAAQ,EAAa,IAC/B,UAAU,GAEd,CAUA,MARe,aAAX,EAAG,MAAkC,cAAX,EAAG,KAC/B,EAAK,gBAAgB,GACD,cAAX,EAAG,MAAmC,kBAAX,EAAG,MACvC,EAAK,WAAW,IAKX,CACT,EAGI,EAAiB,SAAU,GAG7B,GAAK,EAAK,kBAAV,CA2BA,GAvBe,YAAX,EAAG,MAEL,OAAO,eAAe,EAAI,UAAW,CACnC,MAAO,EAAK,MAAQ,EAAK,MAAQ,EACjC,UAAU,IAEZ,OAAO,eAAe,EAAI,UAAW,CACnC,MAAO,EAAK,MAAQ,EAAK,MAAQ,EACjC,UAAU,KAEQ,aAAX,EAAG,OAEZ,OAAO,eAAe,EAAI,QAAS,CACjC,MAAO,EAAG,cAAc,QAAQ,GAAG,MACnC,UAAU,IAEZ,OAAO,eAAe,EAAI,QAAS,CACjC,MAAO,EAAG,cAAc,QAAQ,GAAG,MACnC,UAAU,UAKK,IAAf,EAAG,cAAwC,IAAf,EAAG,QAAuB,CACxD,IACI,EAAe,CACjB,KAFE,EAAO,EAAG,OAAO,yBAET,IAAM,OAAO,QACvB,KAAM,EAAK,KAAO,OAAO,SAE3B,OAAO,eAAe,EAAI,UAAW,CACnC,MAAO,EAAG,MAAQ,EAAa,KAC/B,UAAU,IAEZ,OAAO,eAAe,EAAI,UAAW,CACnC,MAAO,EAAG,MAAQ,EAAa,IAC/B,UAAU,GAEd,CAGA,GAAI,EAAG,SAAW,EAAK,SAAU,CAC/B,IAAI,EAAO,EAAG,OAAO,wBACjB,EAAQ,EAAK,SAAS,wBAKtB,GAJA,EAAe,CACjB,IAAK,EAAK,IAAM,OAAO,QACvB,KAAM,EAAK,KAAO,OAAO,SAEP,CAClB,IAAK,EAAM,IAAM,OAAO,QACxB,KAAM,EAAM,KAAO,OAAO,UAG5B,IAAG,IAAgB,EAUjB,OAAO,EATP,OAAO,eAAe,EAAI,UAAW,CACnC,MAAO,EAAG,QAAU,EAAc,KAAO,EAAa,KACtD,UAAU,IAEZ,OAAO,eAAe,EAAI,UAAW,CACnC,MAAO,EAAG,QAAU,EAAc,IAAM,EAAa,IACrD,UAAU,GAKhB,CAUA,MARe,aAAX,EAAG,MAAkC,aAAX,EAAG,KAC/B,EAAK,WAAW,GACI,WAAX,EAAG,MAAgC,YAAX,EAAG,MACpC,EAAK,cAAc,IAKd,CA7EC,CA8EV,EAES,EAAI,EAAG,EAAI,EAAY,OAAQ,IACtC,KAAK,SAAS,iBAAiB,EAAY,GAAI,GAAiB,GAGlE,IAAS,EAAI,EAAG,EAAI,EAAa,OAAQ,IACvC,OAAO,iBAAiB,EAAa,GAAI,GAAgB,GAG3D,KAAK,sBAAwB,WAE3B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAY,OAAQ,IACtC,KAAK,SAAS,oBAAoB,EAAY,GAAI,GAGpD,IAAS,EAAI,EAAG,EAAI,EAAa,OAAQ,IACvC,OAAO,oBAAoB,EAAa,GAAI,EAEhD,CACF,EAEA,gBAAiB,SAAU,GACzB,IAAI,GAAM,IAAI,MAAO,UAGjB,KAAK,0BACJ,KAAK,yBAA2B,KAAK,QAAQ,cAAgB,GAEhE,KAAK,yBAA2B,EAEhC,KAAK,mBAAoB,EAGzB,KAAK,kBAAoB,KAAK,MAAQ,EACtC,KAAK,kBAAoB,KAAK,MAAQ,GAGC,IAAnC,KAAK,QAAQ,kBACf,KAAK,WAAW,CACd,QAAS,KAAK,WAAa,EAC3B,QAAS,KAAK,YAAc,IAG9B,KAAK,cAAc,CACjB,QAAS,KAAK,WAAa,EAC3B,QAAS,KAAK,YAAc,IAKhC,KAAK,mBAAoB,IAKzB,KAAK,yBAA2B,EAChC,KAAK,mBAAoB,EAEzB,KAAK,YAAa,EAGd,EAAG,SAAW,KAAK,OAAS,EAAG,SAAW,KAAK,MAAQ,KAAK,OAC3D,EAAG,SAAW,KAAK,OAAS,EAAG,SAAW,KAAK,MAAQ,KAAK,OAE/D,KAAK,kBAAoB,EAAG,QAAU,KAAK,MAC3C,KAAK,kBAAoB,EAAG,QAAU,KAAK,QAK3C,KAAK,kBAAoB,KAAK,MAAQ,EACtC,KAAK,kBAAoB,KAAK,MAAQ,EAGtC,KAAK,WAAW,IAGtB,EAEA,WAAY,SAAU,GACpB,IAAI,EAAO,KAEX,KAAK,oBAAoB,GAGpB,KAAK,oBAKV,KAAK,MAAQ,EAAG,QAAU,KAAK,kBAC/B,KAAK,MAAQ,EAAG,QAAU,KAAK,kBAG/B,KAAK,MAAM,MAAY,KAAI,KAAK,MAAQ,KACxC,KAAK,MAAM,MAAW,IAAI,KAAK,MAAQ,MAGA,IAAnC,KAAK,QAAQ,oBAEuB,GAAlC,KAAK,QAAQ,kBACf,KAAK,UAGG,KAAK,iBAEb,KAAK,eAAiB,YAAW,WAC/B,EAAK,UACL,EAAK,gBAAiB,CACxB,GAAG,IAAO,KAAK,QAAQ,qBAG7B,EAEA,oBAAqB,SAAU,GAE1B,EAAG,QAAU,KAAK,OAAS,EAAG,QAAU,KAAK,MAAQ,KAAK,qBAAuB,KAAK,OACpF,EAAG,QAAU,KAAK,OAAS,EAAG,QAAU,KAAK,MAAQ,KAAK,mBAAqB,KAAK,MACvF,KAAK,OAAO,UAAU,IAAI,kBAE1B,KAAK,OAAO,UAAU,OAAO,iBAEjC,EAEA,cAAe,SAAU,GAEvB,KAAK,YAAa,EAGlB,KAAK,OAAO,UAAU,OAAO,kBAExB,KAAK,oBAKV,KAAK,WAAW,IAGuB,IAAnC,KAAK,QAAQ,mBACf,KAAK,UAIP,KAAK,mBAAoB,EAC3B,EAEA,WAAY,SAAU,GACpB,IAAI,EAAM,EAAO,CAAC,EAAG,EAAG,eACpB,EAAQ,EAAG,YAAc,KAAQ,EAAG,WAAa,KAAQ,EAAG,QAAU,IAAM,EAAI,YAAc,KAAQ,EAAI,WAAa,KAAQ,EAAI,QAAU,GAC7I,EAAW,KAAK,IAAI,GAAI,GACxB,EAAgB,CACd,KAAM,EAAG,QACT,IAAK,EAAG,SAGV,KAAK,GAAG,kBACV,KAAK,QAAQ,EAAU,EAE3B,EAEA,sBAAuB,WACvB,IAAI,EAAO,KAEX,IAAI,KAAK,mBAAT,CAIA,KAAK,oBAAqB,EAE1B,IAtmBuB,EAAM,EAAM,EAC/B,EACA,EAuoBJ,KAAK,kBAzoBkB,EAsmBV,WACX,EAAK,gCACL,EAAK,aAEL,IAAI,EAAO,EAAK,WACZ,EAAM,EAEN,EAAI,EAAK,WACT,EAAI,EAAK,YACT,EAAK,EAAK,YACV,EAAO,KAAK,IAAK,EAAE,EAAG,EAAG,EAAE,EAAG,GAE9B,EAAM,EAAK,GAAG,IAAI,CACpB,MAAM,EACN,MAAO,EACP,UAAW,EACX,SAAU,IAER,EAAI,QAAQ,aAAe,EAC7B,EAAI,gBAAiB,OAErB,EAAI,aAAc,MAAO,GAG3B,IAAI,GACE,EAAI,EAAO,EAAK,GAAG,EADrB,GAEE,EAAI,EAAO,EAAK,GAAG,EAGzB,EAAK,MAAgB,SAAI,WACzB,EAAK,MAAY,KAAI,EAAc,KACnC,EAAK,MAAW,IAAI,EAAc,IAEpC,EAvoB6B,EAyoBY,EAAK,QAAQ,cAxoBlD,GAAU,EACV,GAAW,GAEC,IAAZ,EACF,GAAU,EACkB,iBAAZ,IAChB,EAAU,YAAa,EAAU,EAAQ,QAAU,EACnD,EAAW,aAAc,EAAU,EAAQ,SAAW,IAExD,EAAU,GAAW,CAAC,GACd,QAAU,EAClB,EAAQ,QAAU,EAClB,EAAQ,SAAW,EAEZ,EAAU,EAAM,EAAM,IA4nB7B,KAAK,GAAG,SAAU,KAAK,iBAzCvB,CA0CF,EAME,QAAS,WACP,KAAK,GAAG,IAAI,CACV,IAAK,KAAK,MAAQ,KAAK,eAAiB,KAAK,aAAa,GAAK,KAAK,MAAQ,KAAK,MACjF,IAAK,KAAK,MAAQ,KAAK,eAAiB,KAAK,aAAa,GAAK,KAAK,OAAS,KAAK,OAEtF,EAQA,QAAS,SAAU,EAAU,GAC3B,IAAI,EAGJ,EAAa,CACX,EAAG,KAAK,MAAQ,EAChB,EAAG,KAAK,OAAS,GAGnB,KAAK,GAAG,KAAK,CACX,MAAO,KAAK,GAAG,OAAS,EACxB,iBAAkB,GAEtB,GAIF,IAAI,EAAW,SAAU,GAElB,GAEL,EAAW,OAAQ,aAAa,SAAU,GAGxC,OAAO,IAAI,EAFF,KAEiB,EAC5B,GAEF,EAEsB,oBAAX,QAA0B,OAAO,QAC1C,OAAO,QAAU,SAAU,GACzB,EAAU,EACZ,EAC2B,oBAAX,QAA0B,OAAO,KACjD,OAAO,uBAAuB,WAC5B,OAAO,CACT,IAGuB,oBAAd,WACT,EAAS,UAGZ,CAj8BA","file":"/npm/cytoscape-navigator@2.0.2/cytoscape-navigator.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/cytoscape-navigator@2.0.2/cytoscape-navigator.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n",";(function(){ 'use strict';\n\n  var defaults = {\n      container: false // can be a HTML or jQuery element or jQuery selector\n    , viewLiveFramerate: 0 // set false to update graph pan only on drag end; set 0 to do it instantly; set a number (frames per second) to update not more than N times per second\n    , dblClickDelay: 200 // milliseconds\n    , removeCustomContainer: true // destroy the container specified by user on plugin destroy\n    , rerenderDelay: 500 // ms to throttle rerender updates to the panzoom for performance\n  };\n\n  var debounce = (function(){\n    /**\n     * lodash 3.1.1 (Custom Build) <https://lodash.com/>\n     * Build: `lodash modern modularize exports=\"npm\" -o ./`\n     * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>\n     * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n     * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n     * Available under MIT license <https://lodash.com/license>\n     */\n    /** Used as the `TypeError` message for \"Functions\" methods. */\n    var FUNC_ERROR_TEXT = 'Expected a function';\n\n    /* Native method references for those with the same name as other `lodash` methods. */\n    var nativeMax = Math.max,\n        nativeNow = Date.now;\n\n    /**\n     * Gets the number of milliseconds that have elapsed since the Unix epoch\n     * (1 January 1970 00:00:00 UTC).\n     *\n     * @static\n     * @memberOf _\n     * @category Date\n     * @example\n     *\n     * _.defer(function(stamp) {\n     *   console.log(_.now() - stamp);\n     * }, _.now());\n     * // => logs the number of milliseconds it took for the deferred function to be invoked\n     */\n    var now = nativeNow || function() {\n      return new Date().getTime();\n    };\n\n    /**\n     * Creates a debounced function that delays invoking `func` until after `wait`\n     * milliseconds have elapsed since the last time the debounced function was\n     * invoked. The debounced function comes with a `cancel` method to cancel\n     * delayed invocations. Provide an options object to indicate that `func`\n     * should be invoked on the leading and/or trailing edge of the `wait` timeout.\n     * Subsequent calls to the debounced function return the result of the last\n     * `func` invocation.\n     *\n     * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked\n     * on the trailing edge of the timeout only if the the debounced function is\n     * invoked more than once during the `wait` timeout.\n     *\n     * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)\n     * for details over the differences between `_.debounce` and `_.throttle`.\n     *\n     * @static\n     * @memberOf _\n     * @category Function\n     * @param {Function} func The function to debounce.\n     * @param {number} [wait=0] The number of milliseconds to delay.\n     * @param {Object} [options] The options object.\n     * @param {boolean} [options.leading=false] Specify invoking on the leading\n     *  edge of the timeout.\n     * @param {number} [options.maxWait] The maximum time `func` is allowed to be\n     *  delayed before it's invoked.\n     * @param {boolean} [options.trailing=true] Specify invoking on the trailing\n     *  edge of the timeout.\n     * @returns {Function} Returns the new debounced function.\n     * @example\n     *\n     * // avoid costly calculations while the window size is in flux\n     * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n     *\n     * // invoke `sendMail` when the click event is fired, debouncing subsequent calls\n     * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {\n     *   'leading': true,\n     *   'trailing': false\n     * }));\n     *\n     * // ensure `batchLog` is invoked once after 1 second of debounced calls\n     * var source = new EventSource('/stream');\n     * jQuery(source).on('message', _.debounce(batchLog, 250, {\n     *   'maxWait': 1000\n     * }));\n     *\n     * // cancel a debounced call\n     * var todoChanges = _.debounce(batchLog, 1000);\n     * Object.observe(models.todo, todoChanges);\n     *\n     * Object.observe(models, function(changes) {\n     *   if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {\n     *     todoChanges.cancel();\n     *   }\n     * }, ['delete']);\n     *\n     * // ...at some point `models.todo` is changed\n     * models.todo.completed = true;\n     *\n     * // ...before 1 second has passed `models.todo` is deleted\n     * // which cancels the debounced `todoChanges` call\n     * delete models.todo;\n     */\n    function debounce(func, wait, options) {\n      var args,\n          maxTimeoutId,\n          result,\n          stamp,\n          thisArg,\n          timeoutId,\n          trailingCall,\n          lastCalled = 0,\n          maxWait = false,\n          trailing = true;\n\n      if (typeof func != 'function') {\n        throw new TypeError(FUNC_ERROR_TEXT);\n      }\n      wait = wait < 0 ? 0 : (+wait || 0);\n      if (options === true) {\n        var leading = true;\n        trailing = false;\n      } else if (isObject(options)) {\n        leading = !!options.leading;\n        maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);\n        trailing = 'trailing' in options ? !!options.trailing : trailing;\n      }\n\n      function cancel() {\n        if (timeoutId) {\n          clearTimeout(timeoutId);\n        }\n        if (maxTimeoutId) {\n          clearTimeout(maxTimeoutId);\n        }\n        lastCalled = 0;\n        maxTimeoutId = timeoutId = trailingCall = undefined;\n      }\n\n      function complete(isCalled, id) {\n        if (id) {\n          clearTimeout(id);\n        }\n        maxTimeoutId = timeoutId = trailingCall = undefined;\n        if (isCalled) {\n          lastCalled = now();\n          result = func.apply(thisArg, args);\n          if (!timeoutId && !maxTimeoutId) {\n            args = thisArg = undefined;\n          }\n        }\n      }\n\n      function delayed() {\n        var remaining = wait - (now() - stamp);\n        if (remaining <= 0 || remaining > wait) {\n          complete(trailingCall, maxTimeoutId);\n        } else {\n          timeoutId = setTimeout(delayed, remaining);\n        }\n      }\n\n      function maxDelayed() {\n        complete(trailing, timeoutId);\n      }\n\n      function debounced() {\n        args = arguments;\n        stamp = now();\n        thisArg = this;\n        trailingCall = trailing && (timeoutId || !leading);\n\n        if (maxWait === false) {\n          var leadingCall = leading && !timeoutId;\n        } else {\n          if (!maxTimeoutId && !leading) {\n            lastCalled = stamp;\n          }\n          var remaining = maxWait - (stamp - lastCalled),\n              isCalled = remaining <= 0 || remaining > maxWait;\n\n          if (isCalled) {\n            if (maxTimeoutId) {\n              maxTimeoutId = clearTimeout(maxTimeoutId);\n            }\n            lastCalled = stamp;\n            result = func.apply(thisArg, args);\n          }\n          else if (!maxTimeoutId) {\n            maxTimeoutId = setTimeout(maxDelayed, remaining);\n          }\n        }\n        if (isCalled && timeoutId) {\n          timeoutId = clearTimeout(timeoutId);\n        }\n        else if (!timeoutId && wait !== maxWait) {\n          timeoutId = setTimeout(delayed, wait);\n        }\n        if (leadingCall) {\n          isCalled = true;\n          result = func.apply(thisArg, args);\n        }\n        if (isCalled && !timeoutId && !maxTimeoutId) {\n          args = thisArg = undefined;\n        }\n        return result;\n      }\n      debounced.cancel = cancel;\n      return debounced;\n    }\n\n    /**\n     * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.\n     * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n     *\n     * @static\n     * @memberOf _\n     * @category Lang\n     * @param {*} value The value to check.\n     * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n     * @example\n     *\n     * _.isObject({});\n     * // => true\n     *\n     * _.isObject([1, 2, 3]);\n     * // => true\n     *\n     * _.isObject(1);\n     * // => false\n     */\n    function isObject(value) {\n      // Avoid a V8 JIT bug in Chrome 19-20.\n      // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.\n      var type = typeof value;\n      return !!value && (type == 'object' || type == 'function');\n    }\n\n    return debounce;\n\n  })();\n\n  // ported lodash throttle function\n  var throttle = function( func, wait, options ){\n    var leading = true,\n        trailing = true;\n\n    if( options === false ){\n      leading = false;\n    } else if( typeof options === typeof {} ){\n      leading = 'leading' in options ? options.leading : leading;\n      trailing = 'trailing' in options ? options.trailing : trailing;\n    }\n    options = options || {};\n    options.leading = leading;\n    options.maxWait = wait;\n    options.trailing = trailing;\n\n    return debounce( func, wait, options );\n  };\n\n  var Navigator = function ( element, options ) {\n    this._init(element, options)\n  };\n\n  var extend = function() {\n    for(var i = 1; i < arguments.length; i++) {\n      for(var key in arguments[i]) {\n        if(arguments[i].hasOwnProperty(key)) {\n          arguments[0][key] = arguments[i][key];\n        }\n      }\n    }\n    return arguments[0];\n  };\n\n  var wid = function(elem) {\n    return elem.getBoundingClientRect().width;\n  };\n\n  var hei = function(elem) {\n    return elem.getBoundingClientRect().height;\n  };\n\n  Navigator.prototype = {\n\n    constructor: Navigator\n\n  /****************************\n    Main functions\n  ****************************/\n\n  , bb: function(){\n    var bb = this.cy.elements().boundingBox()\n\n    if( bb.w === 0 || bb.h === 0 ){\n      return {\n        x1: 0,\n        x2: Infinity,\n        y1: 0,\n        y2: Infinity,\n        w: Infinity,\n        h: Infinity\n      } // => hide interactive overlay\n    }\n\n    return bb\n  }\n\n  , _addCyListener: function(events, handler){\n    this._cyListeners.push({\n      events: events,\n      handler: handler\n    })\n\n    this.cy.on(events, handler)\n  }\n\n  , _removeCyListeners: function(){\n    var cy = this.cy\n\n    this._cyListeners.forEach(function(l){\n      cy.off(l.events, l.handler)\n    })\n\n    cy.offRender(this._onRenderHandler)\n  }\n\n  , _init: function ( cy, options ) {\n      this._cyListeners = []\n\n      this.$element = cy.container()\n      this.options = extend({}, defaults, options)\n\n      this.cy = cy\n\n      // Cache bounding box\n      this.boundingBox = this.bb()\n\n      // Cache sizes\n      this.width = wid(this.$element);\n      this.height = hei(this.$element)\n\n      // Init components\n      this._initPanel()\n      this._initThumbnail()\n      this._initView()\n      this._initOverlay()\n    }\n\n  , destroy: function () {\n      this._removeEventsHandling();\n\n      // If container is not created by navigator and its removal is prohibited\n      if (this.options.container && !this.options.removeCustomContainer) {\n        this.$panel.innerHTML = '';\n      } else {\n        this.$panel.parentElement.removeChild(this.$panel);\n      }\n    }\n\n  /****************************\n    Navigator elements functions\n  ****************************/\n\n    /*\n     * Used inner attributes\n     *\n     * w {number} width\n     * h {number} height\n     */\n  , _initPanel: function () {\n      var options = this.options\n      if(options.container && typeof options.container === 'string' && options.container.length > 0) {\n        // to not break users which gives a jquery string selector\n        if (options.container.indexOf('#') !== -1) {\n          this.$panel = document.getElementById(options.container.replace('#', ''));\n        } else {\n          this.$panel = document.getElementsByClassName(options.container.replace('.', ''))[0];\n        } \n      } else {\n        this.$panel = document.createElement('div');\n        this.$panel.className = 'cytoscape-navigator';\n        document.body.appendChild(this.$panel);\n      }\n      this._setupPanel()\n      this._addCyListener('resize', this.resize.bind(this))\n    }\n\n  , _setupPanel: function () {\n      // Cache sizes\n      this.panelWidth = wid(this.$panel);\n      this.panelHeight = hei(this.$panel);\n    }\n\n    /*\n     * Used inner attributes\n     *\n     * zoom {number}\n     * pan {object} - {x: 0, y: 0}\n     */\n  , _initThumbnail: function () {\n      // Create thumbnail\n      this.$thumbnail = document.createElement('img');\n\n      this.$thumbnail.setAttribute(\"alt\", \"Graph navigator\");\n\n      // Add thumbnail canvas to the DOM\n      this.$panel.appendChild(this.$thumbnail);\n\n      // Setup thumbnail\n      this._setupThumbnailSizes()\n      this._setupThumbnail()\n    }\n\n  , _setupThumbnail: function () {\n      this._updateThumbnailImage()\n    }\n\n  , _setupThumbnailSizes: function () {\n      // Update bounding box cache\n      this.boundingBox = this.bb()\n\n      this.thumbnailZoom = Math.min(this.panelHeight / this.boundingBox.h, this.panelWidth / this.boundingBox.w)\n\n      // Used on thumbnail generation\n      this.thumbnailPan = {\n        x: (this.panelWidth - this.thumbnailZoom * (this.boundingBox.x1 + this.boundingBox.x2))/2\n      , y: (this.panelHeight - this.thumbnailZoom * (this.boundingBox.y1 + this.boundingBox.y2))/2\n      }\n    }\n\n    // If bounding box has changed then update sizes\n    // Otherwise just update the thumbnail\n  , _checkThumbnailSizesAndUpdate: function () {\n      // Cache previous values\n      var _zoom = this.thumbnailZoom\n        , _pan_x = this.thumbnailPan.x\n        , _pan_y = this.thumbnailPan.y\n\n      this._setupThumbnailSizes()\n\n      if (_zoom != this.thumbnailZoom || _pan_x != this.thumbnailPan.x || _pan_y != this.thumbnailPan.y) {\n        this._setupThumbnail()\n        this._setupView()\n      } else {\n        this._updateThumbnailImage()\n      }\n    }\n\n    /*\n     * Used inner attributes\n     *\n     * w {number} width\n     * h {number} height\n     * x {number}\n     * y {number}\n     * borderWidth {number}\n     * locked {boolean}\n     */\n  , _initView: function () {\n      this.$view = document.createElement('div');\n      this.$view.className = 'cytoscape-navigatorView';\n      this.$panel.appendChild(this.$view)\n      // Compute borders\n      this.viewBorderTop = parseInt(this.$view.style['border-top-width'], 10) || 0;\n      this.viewBorderRight = parseInt(this.$view.style['border-right-width'], 10) || 0;\n      this.viewBorderBottom = parseInt(this.$view.style['border-bottom-width'], 10) || 0;\n      this.viewBorderLeft = parseInt(this.$view.style['border-left-width'], 10) || 0;\n      \n      // Abstract borders\n      this.viewBorderHorizontal = this.viewBorderLeft + this.viewBorderRight\n      this.viewBorderVertical = this.viewBorderTop + this.viewBorderBottom\n\n      this._setupView()\n\n      // Hook graph zoom and pan\n      this._addCyListener('zoom pan', this._setupView.bind(this))\n    }\n\n  , _setupView: function () {\n      if (this.viewLocked)\n        return\n\n      var cyZoom = this.cy.zoom()\n        , cyPan = this.cy.pan()\n\n      // Horizontal computation\n      this.viewW = this.width / cyZoom * this.thumbnailZoom\n      this.viewX = -cyPan.x * this.viewW / this.width + this.thumbnailPan.x - this.viewBorderLeft\n\n      // Vertical computation\n      this.viewH = this.height / cyZoom * this.thumbnailZoom\n      this.viewY = -cyPan.y * this.viewH / this.height + this.thumbnailPan.y - this.viewBorderTop\n\n      // CSS view\n      this.$view.style['width'] = this.viewW + 'px';\n      this.$view.style['height'] = this.viewH + 'px';\n      this.$view.style['position'] = 'absolute';\n      this.$view.style['left'] = this.viewX + 'px';\n      this.$view.style['top'] = this.viewY + 'px';\n    }\n\n    /*\n     * Used inner attributes\n     *\n     * timeout {number} used to keep stable frame rate\n     * lastMoveStartTime {number}\n     * inMovement {boolean}\n     * hookPoint {object} {x: 0, y: 0}\n     */\n  , _initOverlay: function () {\n      // Used to capture mouse events\n      this.$overlay = document.createElement('div');\n      this.$overlay.className = 'cytoscape-navigatorOverlay';\n\n      // Add overlay to the DOM\n      this.$panel.appendChild(this.$overlay)\n\n      // Init some attributes\n      this.overlayHookPointX = 0;\n      this.overlayHookPointY = 0;\n\n      // Listen for events\n      this._initEventsHandling()\n    }\n\n  /****************************\n    Event handling functions\n  ****************************/\n\n  , resize: function () {\n      // Cache sizes\n      this.width = wid(this.$element);\n      this.height = hei(this.$element);\n      this._thumbnailSetup = false\n      this._setupPanel()\n      this._checkThumbnailSizesAndUpdate()\n      this._setupView()\n    }\n\n  , _initEventsHandling: function () {\n      var that = this\n        , eventsLocal = [\n        // Mouse events\n          'mousedown'\n        , 'mousewheel'\n        , 'DOMMouseScroll' // Mozilla specific event\n        // Touch events\n        , 'touchstart'\n        ]\n        , eventsGlobal = [\n          'mouseup'\n        , 'mouseout'\n        , 'mousemove'\n        // Touch events\n        , 'touchmove'\n        , 'touchend'\n        ]\n\n      // handle events and stop their propagation\n      var overlayListener = function (ev) {\n        // Touch events\n        if (ev.type == 'touchstart') {\n          // Will count as middle of View\n          Object.defineProperty(ev, 'offsetX', {\n            value: that.viewX + that.viewW / 2,\n            writable: true\n          });\n          Object.defineProperty(ev, 'offsetY', {\n            value: that.viewY + that.viewH / 2,\n            writable: true\n          });\n        }\n\n        // Normalize offset for browsers which do not provide that value\n        if (ev.offsetX === undefined || ev.offsetY === undefined) {\n          var rect = ev.target.getBoundingClientRect();\n          var targetOffset = { \n            top: rect.top + window.scrollY, \n            left: rect.left + window.scrollX, \n          };\n          Object.defineProperty(ev, 'offsetX', {\n            value: ev.pageX - targetOffset.left,\n            writable: true\n          });\n          Object.defineProperty(ev, 'offsetY', {\n            value: ev.pageY - targetOffset.top,\n            writable: true\n          });\n        }\n\n        if (ev.type == 'mousedown' || ev.type == 'touchstart') {\n          that._eventMoveStart(ev)\n        } else if (ev.type == 'mousewheel' || ev.type == 'DOMMouseScroll') {\n          that._eventZoom(ev)\n        }\n\n        // Prevent default and propagation\n        // Don't use peventPropagation as it breaks mouse events\n        return false;\n      };\n\n      // Hook global events\n      var globalListener = function (ev) {\n\n        // Do not make any computations if it is has no effect on Navigator\n        if (!that.overlayInMovement)\n          return;\n\n        // Touch events\n        if (ev.type == 'touchend') {\n          // Will count as middle of View\n          Object.defineProperty(ev, 'offsetX', {\n            value: that.viewX + that.viewW / 2,\n            writable: true\n          });\n          Object.defineProperty(ev, 'offsetY', {\n            value: that.viewY + that.viewH / 2,\n            writable: true\n          });\n        } else if (ev.type == 'touchmove') {\n          // Hack - we take in account only first touch\n          Object.defineProperty(ev, 'pageX', {\n            value: ev.originalEvent.touches[0].pageX,\n            writable: true\n          });\n          Object.defineProperty(ev, 'pageY', {\n            value: ev.originalEvent.touches[0].pageY,\n            writable: true\n          });\n        }\n\n        // Normalize offset for browsers which do not provide that value\n        if (ev.offsetX === undefined || ev.offsetY === undefined) {\n          var rect = ev.target.getBoundingClientRect();\n          var targetOffset = { \n            top: rect.top + window.scrollY, \n            left: rect.left + window.scrollX, \n          };\n          Object.defineProperty(ev, 'offsetX', {\n            value: ev.pageX - targetOffset.left,\n            writable: true\n          });\n          Object.defineProperty(ev, 'offsetY', {\n            value: ev.pageY - targetOffset.top,\n            writable: true\n          });\n        }\n\n        // Translate global events into local coordinates\n        if (ev.target !== that.$overlay) {\n          var rect = ev.target.getBoundingClientRect();\n          var rect2 = that.$overlay.getBoundingClientRect();\n          var targetOffset = { \n            top: rect.top + window.scrollY, \n            left: rect.left + window.scrollX, \n          };\n          var overlayOffset = { \n            top: rect2.top + window.scrollY, \n            left: rect2.left + window.scrollX, \n          };\n          \n          if(targetOffset && overlayOffset) {\n            Object.defineProperty(ev, 'offsetX', {\n              value: ev.offsetX - overlayOffset.left + targetOffset.left,\n              writable: true\n            });\n            Object.defineProperty(ev, 'offsetY', {\n              value: ev.offsetY - overlayOffset.top + targetOffset.top,\n              writable: true\n            });\n          } else {\n            return false;\n          }\n        }\n\n        if (ev.type == 'mousemove' || ev.type == 'touchmove') {\n          that._eventMove(ev)\n        } else if (ev.type == 'mouseup' || ev.type == 'touchend') {\n          that._eventMoveEnd(ev)\n        }\n\n        // Prevent default and propagation\n        // Don't use peventPropagation as it breaks mouse events\n        return false;\n      };\n\n      for (var i = 0; i < eventsLocal.length; i++) {\n        this.$overlay.addEventListener(eventsLocal[i], overlayListener, false);\n      }\n\n      for (var i = 0; i < eventsGlobal.length; i++) {\n        window.addEventListener(eventsGlobal[i], globalListener, false);\n      }\n\n      this._removeEventsHandling = function(){\n\n        for (var i = 0; i < eventsLocal.length; i++) {\n          this.$overlay.removeEventListener(eventsLocal[i], overlayListener);\n        }\n\n        for (var i = 0; i < eventsGlobal.length; i++) {\n          window.removeEventListener(eventsGlobal[i], globalListener);\n        }\n      }\n    }\n\n  , _eventMoveStart: function (ev) {\n      var now = new Date().getTime()\n\n      // Check if it was double click\n      if (this.overlayLastMoveStartTime\n        && this.overlayLastMoveStartTime + this.options.dblClickDelay > now) {\n        // Reset lastMoveStartTime\n        this.overlayLastMoveStartTime = 0\n        // Enable View in order to move it to the center\n        this.overlayInMovement = true\n\n        // Set hook point as View center\n        this.overlayHookPointX = this.viewW / 2\n        this.overlayHookPointY = this.viewH / 2\n\n        // Move View to start point\n        if (this.options.viewLiveFramerate !== false) {\n          this._eventMove({\n            offsetX: this.panelWidth / 2\n          , offsetY: this.panelHeight / 2\n          })\n        } else {\n          this._eventMoveEnd({\n            offsetX: this.panelWidth / 2\n          , offsetY: this.panelHeight / 2\n          })\n        }\n\n        // View should be inactive as we don't want to move it right after double click\n        this.overlayInMovement = false\n      }\n      // This is a single click\n      // Take care as single click happens before double click 2 times\n      else {\n        this.overlayLastMoveStartTime = now\n        this.overlayInMovement = true\n        // Lock view moving caused by cy events\n        this.viewLocked = true\n\n        // if event started in View\n        if (ev.offsetX >= this.viewX && ev.offsetX <= this.viewX + this.viewW\n          && ev.offsetY >= this.viewY && ev.offsetY <= this.viewY + this.viewH\n        ) {\n          this.overlayHookPointX = ev.offsetX - this.viewX\n          this.overlayHookPointY = ev.offsetY - this.viewY\n        }\n        // if event started in Thumbnail (outside of View)\n        else {\n          // Set hook point as View center\n          this.overlayHookPointX = this.viewW / 2\n          this.overlayHookPointY = this.viewH / 2\n\n          // Move View to start point\n          this._eventMove(ev)\n        }\n      }\n    }\n\n  , _eventMove: function (ev) {\n      var that = this\n\n      this._checkMousePosition(ev)\n\n      // break if it is useless event\n      if (!this.overlayInMovement) {\n        return;\n      }\n\n      // Update cache\n      this.viewX = ev.offsetX - this.overlayHookPointX\n      this.viewY = ev.offsetY - this.overlayHookPointY\n\n      // Update view position\n      this.$view.style['left'] = this.viewX + 'px';\n      this.$view.style['top'] = this.viewY + 'px';\n\n      // Move Cy\n      if (this.options.viewLiveFramerate !== false) {\n        // trigger instantly\n        if (this.options.viewLiveFramerate == 0) {\n          this._moveCy()\n        }\n        // trigger less often than frame rate\n        else if (!this.overlayTimeout) {\n          // Set a timeout for graph movement\n          this.overlayTimeout = setTimeout(function () {\n            that._moveCy()\n            that.overlayTimeout = false\n          }, 1000 / this.options.viewLiveFramerate)\n        }\n      }\n    }\n\n  , _checkMousePosition: function (ev) {\n      // If mouse in over View\n      if(ev.offsetX > this.viewX && ev.offsetX < this.viewX + this.viewBorderHorizontal + this.viewW\n        && ev.offsetY > this.viewY && ev.offsetY < this.viewY + this.viewBorderVertical + this.viewH) {\n        this.$panel.classList.add('mouseover-view')\n      } else {\n        this.$panel.classList.remove('mouseover-view')\n      }\n    }\n\n  , _eventMoveEnd: function (ev) {\n      // Unlock view changing caused by graph events\n      this.viewLocked = false\n\n      // Remove class when mouse is not over Navigator\n      this.$panel.classList.remove('mouseover-view')\n\n      if (!this.overlayInMovement) {\n        return;\n      }\n\n      // Trigger one last move\n      this._eventMove(ev)\n\n      // If mode is not live then move graph on drag end\n      if (this.options.viewLiveFramerate === false) {\n        this._moveCy()\n      }\n\n      // Stop movement permission\n      this.overlayInMovement = false\n    }\n\n  , _eventZoom: function (ev) {\n      var ev2 = extend({}, ev.originalEvent);\n      var delta = ev.wheelDeltaY / 1000 || ev.wheelDelta / 1000 || ev.detail / -32 || ev2.wheelDeltaY / 1000 || ev2.wheelDelta / 1000 || ev2.detail / -32;\n      var zoomRate = Math.pow(10, delta)\n        , mousePosition = {\n            left: ev.offsetX\n          , top: ev.offsetY\n          }\n\n      if (this.cy.zoomingEnabled()) {\n        this._zoomCy(zoomRate, mousePosition)\n      }\n    }\n\n  , _updateThumbnailImage: function () {\n    var that = this;\n\n    if( this._thumbnailUpdating ){\n      return;\n    }\n\n    this._thumbnailUpdating = true;\n\n    var render = function() {\n      that._checkThumbnailSizesAndUpdate();\n      that._setupView();\n\n      var $img = that.$thumbnail;\n      var img = $img;\n\n      var w = that.panelWidth;\n      var h = that.panelHeight;\n      var bb = that.boundingBox;\n      var zoom = Math.min( w/bb.w, h/bb.h );\n\n      var png = that.cy.png({\n        full: true,\n        scale: zoom,\n        maxHeight: h,\n        maxWidth: w\n      });\n      if( png.indexOf('image/png') < 0 ){\n        img.removeAttribute( 'src' );\n      } else {\n        img.setAttribute( 'src', png );\n      }\n\n      var translate = {\n        x: (w - zoom*( bb.w ))/2,\n        y: (h - zoom*( bb.h ))/2\n      };\n\n      $img.style['position'] = 'absolute';\n      $img.style['left'] = translate.x + 'px';\n      $img.style['top'] = translate.y + 'px';\n\n    }\n\n    this._onRenderHandler = throttle(render, that.options.rerenderDelay)\n\n    this.cy.onRender( this._onRenderHandler )\n  }\n\n  /****************************\n    Navigator view moving\n  ****************************/\n\n  , _moveCy: function () {\n      this.cy.pan({\n        x: -(this.viewX + this.viewBorderLeft - this.thumbnailPan.x) * this.width / this.viewW\n      , y: -(this.viewY + this.viewBorderLeft - this.thumbnailPan.y) * this.height / this.viewH\n      })\n    }\n\n  /**\n   * Zooms graph.\n   *\n   * @this {cytoscapeNavigator}\n   * @param {number} zoomRate The zoom rate value. 1 is 100%.\n   */\n  , _zoomCy: function (zoomRate, zoomCenterRaw) {\n      var zoomCenter\n        , isZoomCenterInView = false\n\n      zoomCenter = {\n        x: this.width / 2\n      , y: this.height / 2\n      };\n\n      this.cy.zoom({\n        level: this.cy.zoom() * zoomRate\n      , renderedPosition: zoomCenter\n      })\n    }\n  }\n\n  // registers the extension on a cytoscape lib ref\n  var register = function( cytoscape ){\n\n    if (!cytoscape){ return; } // can't register if cytoscape unspecified\n\n    cytoscape( 'core', 'navigator', function( options ){\n      var cy = this;\n\n      return new Navigator( cy, options );\n    } );\n\n  };\n\n  if (typeof module !== 'undefined' && module.exports) { // expose as a commonjs module\n    module.exports = function( cytoscape ){\n      register( cytoscape );\n    };\n  } else if (typeof define !== 'undefined' && define.amd) { // expose as an amd/requirejs module\n    define('cytoscape-navigator', function(){\n      return register;\n    });\n  }\n\n  if (typeof cytoscape !== 'undefined') { // expose to global cytoscape (i.e. window.cytoscape)\n    register(cytoscape);\n  }\n\n})();\n"]}