vis.js 2.8 MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775307763077730778307793078030781307823078330784307853078630787307883078930790307913079230793307943079530796307973079830799308003080130802308033080430805308063080730808308093081030811308123081330814308153081630817308183081930820308213082230823308243082530826308273082830829308303083130832308333083430835308363083730838308393084030841308423084330844308453084630847308483084930850308513085230853308543085530856308573085830859308603086130862308633086430865308663086730868308693087030871308723087330874308753087630877308783087930880308813088230883308843088530886308873088830889308903089130892308933089430895308963089730898308993090030901309023090330904309053090630907309083090930910309113091230913309143091530916309173091830919309203092130922309233092430925309263092730928309293093030931309323093330934309353093630937309383093930940309413094230943309443094530946309473094830949309503095130952309533095430955309563095730958309593096030961309623096330964309653096630967309683096930970309713097230973309743097530976309773097830979309803098130982309833098430985309863098730988309893099030991309923099330994309953099630997309983099931000310013100231003310043100531006310073100831009310103101131012310133101431015310163101731018310193102031021310223102331024310253102631027310283102931030310313103231033310343103531036310373103831039310403104131042310433104431045310463104731048310493105031051310523105331054310553105631057310583105931060310613106231063310643106531066310673106831069310703107131072310733107431075310763107731078310793108031081310823108331084310853108631087310883108931090310913109231093310943109531096310973109831099311003110131102311033110431105311063110731108311093111031111311123111331114311153111631117311183111931120311213112231123311243112531126311273112831129311303113131132311333113431135311363113731138311393114031141311423114331144311453114631147311483114931150311513115231153311543115531156311573115831159311603116131162311633116431165311663116731168311693117031171311723117331174311753117631177311783117931180311813118231183311843118531186311873118831189311903119131192311933119431195311963119731198311993120031201312023120331204312053120631207312083120931210312113121231213312143121531216312173121831219312203122131222312233122431225312263122731228312293123031231312323123331234312353123631237312383123931240312413124231243312443124531246312473124831249312503125131252312533125431255312563125731258312593126031261312623126331264312653126631267312683126931270312713127231273312743127531276312773127831279312803128131282312833128431285312863128731288312893129031291312923129331294312953129631297312983129931300313013130231303313043130531306313073130831309313103131131312313133131431315313163131731318313193132031321313223132331324313253132631327313283132931330313313133231333313343133531336313373133831339313403134131342313433134431345313463134731348313493135031351313523135331354313553135631357313583135931360313613136231363313643136531366313673136831369313703137131372313733137431375313763137731378313793138031381313823138331384313853138631387313883138931390313913139231393313943139531396313973139831399314003140131402314033140431405314063140731408314093141031411314123141331414314153141631417314183141931420314213142231423314243142531426314273142831429314303143131432314333143431435314363143731438314393144031441314423144331444314453144631447314483144931450314513145231453314543145531456314573145831459314603146131462314633146431465314663146731468314693147031471314723147331474314753147631477314783147931480314813148231483314843148531486314873148831489314903149131492314933149431495314963149731498314993150031501315023150331504315053150631507315083150931510315113151231513315143151531516315173151831519315203152131522315233152431525315263152731528315293153031531315323153331534315353153631537315383153931540315413154231543315443154531546315473154831549315503155131552315533155431555315563155731558315593156031561315623156331564315653156631567315683156931570315713157231573315743157531576315773157831579315803158131582315833158431585315863158731588315893159031591315923159331594315953159631597315983159931600316013160231603316043160531606316073160831609316103161131612316133161431615316163161731618316193162031621316223162331624316253162631627316283162931630316313163231633316343163531636316373163831639316403164131642316433164431645316463164731648316493165031651316523165331654316553165631657316583165931660316613166231663316643166531666316673166831669316703167131672316733167431675316763167731678316793168031681316823168331684316853168631687316883168931690316913169231693316943169531696316973169831699317003170131702317033170431705317063170731708317093171031711317123171331714317153171631717317183171931720317213172231723317243172531726317273172831729317303173131732317333173431735317363173731738317393174031741317423174331744317453174631747317483174931750317513175231753317543175531756317573175831759317603176131762317633176431765317663176731768317693177031771317723177331774317753177631777317783177931780317813178231783317843178531786317873178831789317903179131792317933179431795317963179731798317993180031801318023180331804318053180631807318083180931810318113181231813318143181531816318173181831819318203182131822318233182431825318263182731828318293183031831318323183331834318353183631837318383183931840318413184231843318443184531846318473184831849318503185131852318533185431855318563185731858318593186031861318623186331864318653186631867318683186931870318713187231873318743187531876318773187831879318803188131882318833188431885318863188731888318893189031891318923189331894318953189631897318983189931900319013190231903319043190531906319073190831909319103191131912319133191431915319163191731918319193192031921319223192331924319253192631927319283192931930319313193231933319343193531936319373193831939319403194131942319433194431945319463194731948319493195031951319523195331954319553195631957319583195931960319613196231963319643196531966319673196831969319703197131972319733197431975319763197731978319793198031981319823198331984319853198631987319883198931990319913199231993319943199531996319973199831999320003200132002320033200432005320063200732008320093201032011320123201332014320153201632017320183201932020320213202232023320243202532026320273202832029320303203132032320333203432035320363203732038320393204032041320423204332044320453204632047320483204932050320513205232053320543205532056320573205832059320603206132062320633206432065320663206732068320693207032071320723207332074320753207632077320783207932080320813208232083320843208532086320873208832089320903209132092320933209432095320963209732098320993210032101321023210332104321053210632107321083210932110321113211232113321143211532116321173211832119321203212132122321233212432125321263212732128321293213032131321323213332134321353213632137321383213932140321413214232143321443214532146321473214832149321503215132152321533215432155321563215732158321593216032161321623216332164321653216632167321683216932170321713217232173321743217532176321773217832179321803218132182321833218432185321863218732188321893219032191321923219332194321953219632197321983219932200322013220232203322043220532206322073220832209322103221132212322133221432215322163221732218322193222032221322223222332224322253222632227322283222932230322313223232233322343223532236322373223832239322403224132242322433224432245322463224732248322493225032251322523225332254322553225632257322583225932260322613226232263322643226532266322673226832269322703227132272322733227432275322763227732278322793228032281322823228332284322853228632287322883228932290322913229232293322943229532296322973229832299323003230132302323033230432305323063230732308323093231032311323123231332314323153231632317323183231932320323213232232323323243232532326323273232832329323303233132332323333233432335323363233732338323393234032341323423234332344323453234632347323483234932350323513235232353323543235532356323573235832359323603236132362323633236432365323663236732368323693237032371323723237332374323753237632377323783237932380323813238232383323843238532386323873238832389323903239132392323933239432395323963239732398323993240032401324023240332404324053240632407324083240932410324113241232413324143241532416324173241832419324203242132422324233242432425324263242732428324293243032431324323243332434324353243632437324383243932440324413244232443324443244532446324473244832449324503245132452324533245432455324563245732458324593246032461324623246332464324653246632467324683246932470324713247232473324743247532476324773247832479324803248132482324833248432485324863248732488324893249032491324923249332494324953249632497324983249932500325013250232503325043250532506325073250832509325103251132512325133251432515325163251732518325193252032521325223252332524325253252632527325283252932530325313253232533325343253532536325373253832539325403254132542325433254432545325463254732548325493255032551325523255332554325553255632557325583255932560325613256232563325643256532566325673256832569325703257132572325733257432575325763257732578325793258032581325823258332584325853258632587325883258932590325913259232593325943259532596325973259832599326003260132602326033260432605326063260732608326093261032611326123261332614326153261632617326183261932620326213262232623326243262532626326273262832629326303263132632326333263432635326363263732638326393264032641326423264332644326453264632647326483264932650326513265232653326543265532656326573265832659326603266132662326633266432665326663266732668326693267032671326723267332674326753267632677326783267932680326813268232683326843268532686326873268832689326903269132692326933269432695326963269732698326993270032701327023270332704327053270632707327083270932710327113271232713327143271532716327173271832719327203272132722327233272432725327263272732728327293273032731327323273332734327353273632737327383273932740327413274232743327443274532746327473274832749327503275132752327533275432755327563275732758327593276032761327623276332764327653276632767327683276932770327713277232773327743277532776327773277832779327803278132782327833278432785327863278732788327893279032791327923279332794327953279632797327983279932800328013280232803328043280532806328073280832809328103281132812328133281432815328163281732818328193282032821328223282332824328253282632827328283282932830328313283232833328343283532836328373283832839328403284132842328433284432845328463284732848328493285032851328523285332854328553285632857328583285932860328613286232863328643286532866328673286832869328703287132872328733287432875328763287732878328793288032881328823288332884328853288632887328883288932890328913289232893328943289532896328973289832899329003290132902329033290432905329063290732908329093291032911329123291332914329153291632917329183291932920329213292232923329243292532926329273292832929329303293132932329333293432935329363293732938329393294032941329423294332944329453294632947329483294932950329513295232953329543295532956329573295832959329603296132962329633296432965329663296732968329693297032971329723297332974329753297632977329783297932980329813298232983329843298532986329873298832989329903299132992329933299432995329963299732998329993300033001330023300333004330053300633007330083300933010330113301233013330143301533016330173301833019330203302133022330233302433025330263302733028330293303033031330323303333034330353303633037330383303933040330413304233043330443304533046330473304833049330503305133052330533305433055330563305733058330593306033061330623306333064330653306633067330683306933070330713307233073330743307533076330773307833079330803308133082330833308433085330863308733088330893309033091330923309333094330953309633097330983309933100331013310233103331043310533106331073310833109331103311133112331133311433115331163311733118331193312033121331223312333124331253312633127331283312933130331313313233133331343313533136331373313833139331403314133142331433314433145331463314733148331493315033151331523315333154331553315633157331583315933160331613316233163331643316533166331673316833169331703317133172331733317433175331763317733178331793318033181331823318333184331853318633187331883318933190331913319233193331943319533196331973319833199332003320133202332033320433205332063320733208332093321033211332123321333214332153321633217332183321933220332213322233223332243322533226332273322833229332303323133232332333323433235332363323733238332393324033241332423324333244332453324633247332483324933250332513325233253332543325533256332573325833259332603326133262332633326433265332663326733268332693327033271332723327333274332753327633277332783327933280332813328233283332843328533286332873328833289332903329133292332933329433295332963329733298332993330033301333023330333304333053330633307333083330933310333113331233313333143331533316333173331833319333203332133322333233332433325333263332733328333293333033331333323333333334333353333633337333383333933340333413334233343333443334533346333473334833349333503335133352333533335433355333563335733358333593336033361333623336333364333653336633367333683336933370333713337233373333743337533376333773337833379333803338133382333833338433385333863338733388333893339033391333923339333394333953339633397333983339933400334013340233403334043340533406334073340833409334103341133412334133341433415334163341733418334193342033421334223342333424334253342633427334283342933430334313343233433334343343533436334373343833439334403344133442334433344433445334463344733448334493345033451334523345333454334553345633457334583345933460334613346233463334643346533466334673346833469334703347133472334733347433475334763347733478334793348033481334823348333484334853348633487334883348933490334913349233493334943349533496334973349833499335003350133502335033350433505335063350733508335093351033511335123351333514335153351633517335183351933520335213352233523335243352533526335273352833529335303353133532335333353433535335363353733538335393354033541335423354333544335453354633547335483354933550335513355233553335543355533556335573355833559335603356133562335633356433565335663356733568335693357033571335723357333574335753357633577335783357933580335813358233583335843358533586335873358833589335903359133592335933359433595335963359733598335993360033601336023360333604336053360633607336083360933610336113361233613336143361533616336173361833619336203362133622336233362433625336263362733628336293363033631336323363333634336353363633637336383363933640336413364233643336443364533646336473364833649336503365133652336533365433655336563365733658336593366033661336623366333664336653366633667336683366933670336713367233673336743367533676336773367833679336803368133682336833368433685336863368733688336893369033691336923369333694336953369633697336983369933700337013370233703337043370533706337073370833709337103371133712337133371433715337163371733718337193372033721337223372333724337253372633727337283372933730337313373233733337343373533736337373373833739337403374133742337433374433745337463374733748337493375033751337523375333754337553375633757337583375933760337613376233763337643376533766337673376833769337703377133772337733377433775337763377733778337793378033781337823378333784337853378633787337883378933790337913379233793337943379533796337973379833799338003380133802338033380433805338063380733808338093381033811338123381333814338153381633817338183381933820338213382233823338243382533826338273382833829338303383133832338333383433835338363383733838338393384033841338423384333844338453384633847338483384933850338513385233853338543385533856338573385833859338603386133862338633386433865338663386733868338693387033871338723387333874338753387633877338783387933880338813388233883338843388533886338873388833889338903389133892338933389433895338963389733898338993390033901339023390333904339053390633907339083390933910339113391233913339143391533916339173391833919339203392133922339233392433925339263392733928339293393033931339323393333934339353393633937339383393933940339413394233943339443394533946339473394833949339503395133952339533395433955339563395733958339593396033961339623396333964339653396633967339683396933970339713397233973339743397533976339773397833979339803398133982339833398433985339863398733988339893399033991339923399333994339953399633997339983399934000340013400234003340043400534006340073400834009340103401134012340133401434015340163401734018340193402034021340223402334024340253402634027340283402934030340313403234033340343403534036340373403834039340403404134042340433404434045340463404734048340493405034051340523405334054340553405634057340583405934060340613406234063340643406534066340673406834069340703407134072340733407434075340763407734078340793408034081340823408334084340853408634087340883408934090340913409234093340943409534096340973409834099341003410134102341033410434105341063410734108341093411034111341123411334114341153411634117341183411934120341213412234123341243412534126341273412834129341303413134132341333413434135341363413734138341393414034141341423414334144341453414634147341483414934150341513415234153341543415534156341573415834159341603416134162341633416434165341663416734168341693417034171341723417334174341753417634177341783417934180341813418234183341843418534186341873418834189341903419134192341933419434195341963419734198341993420034201342023420334204342053420634207342083420934210342113421234213342143421534216342173421834219342203422134222342233422434225342263422734228342293423034231342323423334234342353423634237342383423934240342413424234243342443424534246342473424834249342503425134252342533425434255342563425734258342593426034261342623426334264342653426634267342683426934270342713427234273342743427534276342773427834279342803428134282342833428434285342863428734288342893429034291342923429334294342953429634297342983429934300343013430234303343043430534306343073430834309343103431134312343133431434315343163431734318343193432034321343223432334324343253432634327343283432934330343313433234333343343433534336343373433834339343403434134342343433434434345343463434734348343493435034351343523435334354343553435634357343583435934360343613436234363343643436534366343673436834369343703437134372343733437434375343763437734378343793438034381343823438334384343853438634387343883438934390343913439234393343943439534396343973439834399344003440134402344033440434405344063440734408344093441034411344123441334414344153441634417344183441934420344213442234423344243442534426344273442834429344303443134432344333443434435344363443734438344393444034441344423444334444344453444634447344483444934450344513445234453344543445534456344573445834459344603446134462344633446434465344663446734468344693447034471344723447334474344753447634477344783447934480344813448234483344843448534486344873448834489344903449134492344933449434495344963449734498344993450034501345023450334504345053450634507345083450934510345113451234513345143451534516345173451834519345203452134522345233452434525345263452734528345293453034531345323453334534345353453634537345383453934540345413454234543345443454534546345473454834549345503455134552345533455434555345563455734558345593456034561345623456334564345653456634567345683456934570345713457234573345743457534576345773457834579345803458134582345833458434585345863458734588345893459034591345923459334594345953459634597345983459934600346013460234603346043460534606346073460834609346103461134612346133461434615346163461734618346193462034621346223462334624346253462634627346283462934630346313463234633346343463534636346373463834639346403464134642346433464434645346463464734648346493465034651346523465334654346553465634657346583465934660346613466234663346643466534666346673466834669346703467134672346733467434675346763467734678346793468034681346823468334684346853468634687346883468934690346913469234693346943469534696346973469834699347003470134702347033470434705347063470734708347093471034711347123471334714347153471634717347183471934720347213472234723347243472534726347273472834729347303473134732347333473434735347363473734738347393474034741347423474334744347453474634747347483474934750347513475234753347543475534756347573475834759347603476134762347633476434765347663476734768347693477034771347723477334774347753477634777347783477934780347813478234783347843478534786347873478834789347903479134792347933479434795347963479734798347993480034801348023480334804348053480634807348083480934810348113481234813348143481534816348173481834819348203482134822348233482434825348263482734828348293483034831348323483334834348353483634837348383483934840348413484234843348443484534846348473484834849348503485134852348533485434855348563485734858348593486034861348623486334864348653486634867348683486934870348713487234873348743487534876348773487834879348803488134882348833488434885348863488734888348893489034891348923489334894348953489634897348983489934900349013490234903349043490534906349073490834909349103491134912349133491434915349163491734918349193492034921349223492334924349253492634927349283492934930349313493234933349343493534936349373493834939349403494134942349433494434945349463494734948349493495034951349523495334954349553495634957349583495934960349613496234963349643496534966349673496834969349703497134972349733497434975349763497734978349793498034981349823498334984349853498634987349883498934990349913499234993349943499534996349973499834999350003500135002350033500435005350063500735008350093501035011350123501335014350153501635017350183501935020350213502235023350243502535026350273502835029350303503135032350333503435035350363503735038350393504035041350423504335044350453504635047350483504935050350513505235053350543505535056350573505835059350603506135062350633506435065350663506735068350693507035071350723507335074350753507635077350783507935080350813508235083350843508535086350873508835089350903509135092350933509435095350963509735098350993510035101351023510335104351053510635107351083510935110351113511235113351143511535116351173511835119351203512135122351233512435125351263512735128351293513035131351323513335134351353513635137351383513935140351413514235143351443514535146351473514835149351503515135152351533515435155351563515735158351593516035161351623516335164351653516635167351683516935170351713517235173351743517535176351773517835179351803518135182351833518435185351863518735188351893519035191351923519335194351953519635197351983519935200352013520235203352043520535206352073520835209352103521135212352133521435215352163521735218352193522035221352223522335224352253522635227352283522935230352313523235233352343523535236352373523835239352403524135242352433524435245352463524735248352493525035251352523525335254352553525635257352583525935260352613526235263352643526535266352673526835269352703527135272352733527435275352763527735278352793528035281352823528335284352853528635287352883528935290352913529235293352943529535296352973529835299353003530135302353033530435305353063530735308353093531035311353123531335314353153531635317353183531935320353213532235323353243532535326353273532835329353303533135332353333533435335353363533735338353393534035341353423534335344353453534635347353483534935350353513535235353353543535535356353573535835359353603536135362353633536435365353663536735368353693537035371353723537335374353753537635377353783537935380353813538235383353843538535386353873538835389353903539135392353933539435395353963539735398353993540035401354023540335404354053540635407354083540935410354113541235413354143541535416354173541835419354203542135422354233542435425354263542735428354293543035431354323543335434354353543635437354383543935440354413544235443354443544535446354473544835449354503545135452354533545435455354563545735458354593546035461354623546335464354653546635467354683546935470354713547235473354743547535476354773547835479354803548135482354833548435485354863548735488354893549035491354923549335494354953549635497354983549935500355013550235503355043550535506355073550835509355103551135512355133551435515355163551735518355193552035521355223552335524355253552635527355283552935530355313553235533355343553535536355373553835539355403554135542355433554435545355463554735548355493555035551355523555335554355553555635557355583555935560355613556235563355643556535566355673556835569355703557135572355733557435575355763557735578355793558035581355823558335584355853558635587355883558935590355913559235593355943559535596355973559835599356003560135602356033560435605356063560735608356093561035611356123561335614356153561635617356183561935620356213562235623356243562535626356273562835629356303563135632356333563435635356363563735638356393564035641356423564335644356453564635647356483564935650356513565235653356543565535656356573565835659356603566135662356633566435665356663566735668356693567035671356723567335674356753567635677356783567935680356813568235683356843568535686356873568835689356903569135692356933569435695356963569735698356993570035701357023570335704357053570635707357083570935710357113571235713357143571535716357173571835719357203572135722357233572435725357263572735728357293573035731357323573335734357353573635737357383573935740357413574235743357443574535746357473574835749357503575135752357533575435755357563575735758357593576035761357623576335764357653576635767357683576935770357713577235773357743577535776357773577835779357803578135782357833578435785357863578735788357893579035791357923579335794357953579635797357983579935800358013580235803358043580535806358073580835809358103581135812358133581435815358163581735818358193582035821358223582335824358253582635827358283582935830358313583235833358343583535836358373583835839358403584135842358433584435845358463584735848358493585035851358523585335854358553585635857358583585935860358613586235863358643586535866358673586835869358703587135872358733587435875358763587735878358793588035881358823588335884358853588635887358883588935890358913589235893358943589535896358973589835899359003590135902359033590435905359063590735908359093591035911359123591335914359153591635917359183591935920359213592235923359243592535926359273592835929359303593135932359333593435935359363593735938359393594035941359423594335944359453594635947359483594935950359513595235953359543595535956359573595835959359603596135962359633596435965359663596735968359693597035971359723597335974359753597635977359783597935980359813598235983359843598535986359873598835989359903599135992359933599435995359963599735998359993600036001360023600336004360053600636007360083600936010360113601236013360143601536016360173601836019360203602136022360233602436025360263602736028360293603036031360323603336034360353603636037360383603936040360413604236043360443604536046360473604836049360503605136052360533605436055360563605736058360593606036061360623606336064360653606636067360683606936070360713607236073360743607536076360773607836079360803608136082360833608436085360863608736088360893609036091360923609336094360953609636097360983609936100361013610236103361043610536106361073610836109361103611136112361133611436115361163611736118361193612036121361223612336124361253612636127361283612936130361313613236133361343613536136361373613836139361403614136142361433614436145361463614736148361493615036151361523615336154361553615636157361583615936160361613616236163361643616536166361673616836169361703617136172361733617436175361763617736178361793618036181361823618336184361853618636187361883618936190361913619236193361943619536196361973619836199362003620136202362033620436205362063620736208362093621036211362123621336214362153621636217362183621936220362213622236223362243622536226362273622836229362303623136232362333623436235362363623736238362393624036241362423624336244362453624636247362483624936250362513625236253362543625536256362573625836259362603626136262362633626436265362663626736268362693627036271362723627336274362753627636277362783627936280362813628236283362843628536286362873628836289362903629136292362933629436295362963629736298362993630036301363023630336304363053630636307363083630936310363113631236313363143631536316363173631836319363203632136322363233632436325363263632736328363293633036331363323633336334363353633636337363383633936340363413634236343363443634536346363473634836349363503635136352363533635436355363563635736358363593636036361363623636336364363653636636367363683636936370363713637236373363743637536376363773637836379363803638136382363833638436385363863638736388363893639036391363923639336394363953639636397363983639936400364013640236403364043640536406364073640836409364103641136412364133641436415364163641736418364193642036421364223642336424364253642636427364283642936430364313643236433364343643536436364373643836439364403644136442364433644436445364463644736448364493645036451364523645336454364553645636457364583645936460364613646236463364643646536466364673646836469364703647136472364733647436475364763647736478364793648036481364823648336484364853648636487364883648936490364913649236493364943649536496364973649836499365003650136502365033650436505365063650736508365093651036511365123651336514365153651636517365183651936520365213652236523365243652536526365273652836529365303653136532365333653436535365363653736538365393654036541365423654336544365453654636547365483654936550365513655236553365543655536556365573655836559365603656136562365633656436565365663656736568365693657036571365723657336574365753657636577365783657936580365813658236583365843658536586365873658836589365903659136592365933659436595365963659736598365993660036601366023660336604366053660636607366083660936610366113661236613366143661536616366173661836619366203662136622366233662436625366263662736628366293663036631366323663336634366353663636637366383663936640366413664236643366443664536646366473664836649366503665136652366533665436655366563665736658366593666036661366623666336664366653666636667366683666936670366713667236673366743667536676366773667836679366803668136682366833668436685366863668736688366893669036691366923669336694366953669636697366983669936700367013670236703367043670536706367073670836709367103671136712367133671436715367163671736718367193672036721367223672336724367253672636727367283672936730367313673236733367343673536736367373673836739367403674136742367433674436745367463674736748367493675036751367523675336754367553675636757367583675936760367613676236763367643676536766367673676836769367703677136772367733677436775367763677736778367793678036781367823678336784367853678636787367883678936790367913679236793367943679536796367973679836799368003680136802368033680436805368063680736808368093681036811368123681336814368153681636817368183681936820368213682236823368243682536826368273682836829368303683136832368333683436835368363683736838368393684036841368423684336844368453684636847368483684936850368513685236853368543685536856368573685836859368603686136862368633686436865368663686736868368693687036871368723687336874368753687636877368783687936880368813688236883368843688536886368873688836889368903689136892368933689436895368963689736898368993690036901369023690336904369053690636907369083690936910369113691236913369143691536916369173691836919369203692136922369233692436925369263692736928369293693036931369323693336934369353693636937369383693936940369413694236943369443694536946369473694836949369503695136952369533695436955369563695736958369593696036961369623696336964369653696636967369683696936970369713697236973369743697536976369773697836979369803698136982369833698436985369863698736988369893699036991369923699336994369953699636997369983699937000370013700237003370043700537006370073700837009370103701137012370133701437015370163701737018370193702037021370223702337024370253702637027370283702937030370313703237033370343703537036370373703837039370403704137042370433704437045370463704737048370493705037051370523705337054370553705637057370583705937060370613706237063370643706537066370673706837069370703707137072370733707437075370763707737078370793708037081370823708337084370853708637087370883708937090370913709237093370943709537096370973709837099371003710137102371033710437105371063710737108371093711037111371123711337114371153711637117371183711937120371213712237123371243712537126371273712837129371303713137132371333713437135371363713737138371393714037141371423714337144371453714637147371483714937150371513715237153371543715537156371573715837159371603716137162371633716437165371663716737168371693717037171371723717337174371753717637177371783717937180371813718237183371843718537186371873718837189371903719137192371933719437195371963719737198371993720037201372023720337204372053720637207372083720937210372113721237213372143721537216372173721837219372203722137222372233722437225372263722737228372293723037231372323723337234372353723637237372383723937240372413724237243372443724537246372473724837249372503725137252372533725437255372563725737258372593726037261372623726337264372653726637267372683726937270372713727237273372743727537276372773727837279372803728137282372833728437285372863728737288372893729037291372923729337294372953729637297372983729937300373013730237303373043730537306373073730837309373103731137312373133731437315373163731737318373193732037321373223732337324373253732637327373283732937330373313733237333373343733537336373373733837339373403734137342373433734437345373463734737348373493735037351373523735337354373553735637357373583735937360373613736237363373643736537366373673736837369373703737137372373733737437375373763737737378373793738037381373823738337384373853738637387373883738937390373913739237393373943739537396373973739837399374003740137402374033740437405374063740737408374093741037411374123741337414374153741637417374183741937420374213742237423374243742537426374273742837429374303743137432374333743437435374363743737438374393744037441374423744337444374453744637447374483744937450374513745237453374543745537456374573745837459374603746137462374633746437465374663746737468374693747037471374723747337474374753747637477374783747937480374813748237483374843748537486374873748837489374903749137492374933749437495374963749737498374993750037501375023750337504375053750637507375083750937510375113751237513375143751537516375173751837519375203752137522375233752437525375263752737528375293753037531375323753337534375353753637537375383753937540375413754237543375443754537546375473754837549375503755137552375533755437555375563755737558375593756037561375623756337564375653756637567375683756937570375713757237573375743757537576375773757837579375803758137582375833758437585375863758737588375893759037591375923759337594375953759637597375983759937600376013760237603376043760537606376073760837609376103761137612376133761437615376163761737618376193762037621376223762337624376253762637627376283762937630376313763237633376343763537636376373763837639376403764137642376433764437645376463764737648376493765037651376523765337654376553765637657376583765937660376613766237663376643766537666376673766837669376703767137672376733767437675376763767737678376793768037681376823768337684376853768637687376883768937690376913769237693376943769537696376973769837699377003770137702377033770437705377063770737708377093771037711377123771337714377153771637717377183771937720377213772237723377243772537726377273772837729377303773137732377333773437735377363773737738377393774037741377423774337744377453774637747377483774937750377513775237753377543775537756377573775837759377603776137762377633776437765377663776737768377693777037771377723777337774377753777637777377783777937780377813778237783377843778537786377873778837789377903779137792377933779437795377963779737798377993780037801378023780337804378053780637807378083780937810378113781237813378143781537816378173781837819378203782137822378233782437825378263782737828378293783037831378323783337834378353783637837378383783937840378413784237843378443784537846378473784837849378503785137852378533785437855378563785737858378593786037861378623786337864378653786637867378683786937870378713787237873378743787537876378773787837879378803788137882378833788437885378863788737888378893789037891378923789337894378953789637897378983789937900379013790237903379043790537906379073790837909379103791137912379133791437915379163791737918379193792037921379223792337924379253792637927379283792937930379313793237933379343793537936379373793837939379403794137942379433794437945379463794737948379493795037951379523795337954379553795637957379583795937960379613796237963379643796537966379673796837969379703797137972379733797437975379763797737978379793798037981379823798337984379853798637987379883798937990379913799237993379943799537996379973799837999380003800138002380033800438005380063800738008380093801038011380123801338014380153801638017380183801938020380213802238023380243802538026380273802838029380303803138032380333803438035380363803738038380393804038041380423804338044380453804638047380483804938050380513805238053380543805538056380573805838059380603806138062380633806438065380663806738068380693807038071380723807338074380753807638077380783807938080380813808238083380843808538086380873808838089380903809138092380933809438095380963809738098380993810038101381023810338104381053810638107381083810938110381113811238113381143811538116381173811838119381203812138122381233812438125381263812738128381293813038131381323813338134381353813638137381383813938140381413814238143381443814538146381473814838149381503815138152381533815438155381563815738158381593816038161381623816338164381653816638167381683816938170381713817238173381743817538176381773817838179381803818138182381833818438185381863818738188381893819038191381923819338194381953819638197381983819938200382013820238203382043820538206382073820838209382103821138212382133821438215382163821738218382193822038221382223822338224382253822638227382283822938230382313823238233382343823538236382373823838239382403824138242382433824438245382463824738248382493825038251382523825338254382553825638257382583825938260382613826238263382643826538266382673826838269382703827138272382733827438275382763827738278382793828038281382823828338284382853828638287382883828938290382913829238293382943829538296382973829838299383003830138302383033830438305383063830738308383093831038311383123831338314383153831638317383183831938320383213832238323383243832538326383273832838329383303833138332383333833438335383363833738338383393834038341383423834338344383453834638347383483834938350383513835238353383543835538356383573835838359383603836138362383633836438365383663836738368383693837038371383723837338374383753837638377383783837938380383813838238383383843838538386383873838838389383903839138392383933839438395383963839738398383993840038401384023840338404384053840638407384083840938410384113841238413384143841538416384173841838419384203842138422384233842438425384263842738428384293843038431384323843338434384353843638437384383843938440384413844238443384443844538446384473844838449384503845138452384533845438455384563845738458384593846038461384623846338464384653846638467384683846938470384713847238473384743847538476384773847838479384803848138482384833848438485384863848738488384893849038491384923849338494384953849638497384983849938500385013850238503385043850538506385073850838509385103851138512385133851438515385163851738518385193852038521385223852338524385253852638527385283852938530385313853238533385343853538536385373853838539385403854138542385433854438545385463854738548385493855038551385523855338554385553855638557385583855938560385613856238563385643856538566385673856838569385703857138572385733857438575385763857738578385793858038581385823858338584385853858638587385883858938590385913859238593385943859538596385973859838599386003860138602386033860438605386063860738608386093861038611386123861338614386153861638617386183861938620386213862238623386243862538626386273862838629386303863138632386333863438635386363863738638386393864038641386423864338644386453864638647386483864938650386513865238653386543865538656386573865838659386603866138662386633866438665386663866738668386693867038671386723867338674386753867638677386783867938680386813868238683386843868538686386873868838689386903869138692386933869438695386963869738698386993870038701387023870338704387053870638707387083870938710387113871238713387143871538716387173871838719387203872138722387233872438725387263872738728387293873038731387323873338734387353873638737387383873938740387413874238743387443874538746387473874838749387503875138752387533875438755387563875738758387593876038761387623876338764387653876638767387683876938770387713877238773387743877538776387773877838779387803878138782387833878438785387863878738788387893879038791387923879338794387953879638797387983879938800388013880238803388043880538806388073880838809388103881138812388133881438815388163881738818388193882038821388223882338824388253882638827388283882938830388313883238833388343883538836388373883838839388403884138842388433884438845388463884738848388493885038851388523885338854388553885638857388583885938860388613886238863388643886538866388673886838869388703887138872388733887438875388763887738878388793888038881388823888338884388853888638887388883888938890388913889238893388943889538896388973889838899389003890138902389033890438905389063890738908389093891038911389123891338914389153891638917389183891938920389213892238923389243892538926389273892838929389303893138932389333893438935389363893738938389393894038941389423894338944389453894638947389483894938950389513895238953389543895538956389573895838959389603896138962389633896438965389663896738968389693897038971389723897338974389753897638977389783897938980389813898238983389843898538986389873898838989389903899138992389933899438995389963899738998389993900039001390023900339004390053900639007390083900939010390113901239013390143901539016390173901839019390203902139022390233902439025390263902739028390293903039031390323903339034390353903639037390383903939040390413904239043390443904539046390473904839049390503905139052390533905439055390563905739058390593906039061390623906339064390653906639067390683906939070390713907239073390743907539076390773907839079390803908139082390833908439085390863908739088390893909039091390923909339094390953909639097390983909939100391013910239103391043910539106391073910839109391103911139112391133911439115391163911739118391193912039121391223912339124391253912639127391283912939130391313913239133391343913539136391373913839139391403914139142391433914439145391463914739148391493915039151391523915339154391553915639157391583915939160391613916239163391643916539166391673916839169391703917139172391733917439175391763917739178391793918039181391823918339184391853918639187391883918939190391913919239193391943919539196391973919839199392003920139202392033920439205392063920739208392093921039211392123921339214392153921639217392183921939220392213922239223392243922539226392273922839229392303923139232392333923439235392363923739238392393924039241392423924339244392453924639247392483924939250392513925239253392543925539256392573925839259392603926139262392633926439265392663926739268392693927039271392723927339274392753927639277392783927939280392813928239283392843928539286392873928839289392903929139292392933929439295392963929739298392993930039301393023930339304393053930639307393083930939310393113931239313393143931539316393173931839319393203932139322393233932439325393263932739328393293933039331393323933339334393353933639337393383933939340393413934239343393443934539346393473934839349393503935139352393533935439355393563935739358393593936039361393623936339364393653936639367393683936939370393713937239373393743937539376393773937839379393803938139382393833938439385393863938739388393893939039391393923939339394393953939639397393983939939400394013940239403394043940539406394073940839409394103941139412394133941439415394163941739418394193942039421394223942339424394253942639427394283942939430394313943239433394343943539436394373943839439394403944139442394433944439445394463944739448394493945039451394523945339454394553945639457394583945939460394613946239463394643946539466394673946839469394703947139472394733947439475394763947739478394793948039481394823948339484394853948639487394883948939490394913949239493394943949539496394973949839499395003950139502395033950439505395063950739508395093951039511395123951339514395153951639517395183951939520395213952239523395243952539526395273952839529395303953139532395333953439535395363953739538395393954039541395423954339544395453954639547395483954939550395513955239553395543955539556395573955839559395603956139562395633956439565395663956739568395693957039571395723957339574395753957639577395783957939580395813958239583395843958539586395873958839589395903959139592395933959439595395963959739598395993960039601396023960339604396053960639607396083960939610396113961239613396143961539616396173961839619396203962139622396233962439625396263962739628396293963039631396323963339634396353963639637396383963939640396413964239643396443964539646396473964839649396503965139652396533965439655396563965739658396593966039661396623966339664396653966639667396683966939670396713967239673396743967539676396773967839679396803968139682396833968439685396863968739688396893969039691396923969339694396953969639697396983969939700397013970239703397043970539706397073970839709397103971139712397133971439715397163971739718397193972039721397223972339724397253972639727397283972939730397313973239733397343973539736397373973839739397403974139742397433974439745397463974739748397493975039751397523975339754397553975639757397583975939760397613976239763397643976539766397673976839769397703977139772397733977439775397763977739778397793978039781397823978339784397853978639787397883978939790397913979239793397943979539796397973979839799398003980139802398033980439805398063980739808398093981039811398123981339814398153981639817398183981939820398213982239823398243982539826398273982839829398303983139832398333983439835398363983739838398393984039841398423984339844398453984639847398483984939850398513985239853398543985539856398573985839859398603986139862398633986439865398663986739868398693987039871398723987339874398753987639877398783987939880398813988239883398843988539886398873988839889398903989139892398933989439895398963989739898398993990039901399023990339904399053990639907399083990939910399113991239913399143991539916399173991839919399203992139922399233992439925399263992739928399293993039931399323993339934399353993639937399383993939940399413994239943399443994539946399473994839949399503995139952399533995439955399563995739958399593996039961399623996339964399653996639967399683996939970399713997239973399743997539976399773997839979399803998139982399833998439985399863998739988399893999039991399923999339994399953999639997399983999940000400014000240003400044000540006400074000840009400104001140012400134001440015400164001740018400194002040021400224002340024400254002640027400284002940030400314003240033400344003540036400374003840039400404004140042400434004440045400464004740048400494005040051400524005340054400554005640057400584005940060400614006240063400644006540066400674006840069400704007140072400734007440075400764007740078400794008040081400824008340084400854008640087400884008940090400914009240093400944009540096400974009840099401004010140102401034010440105401064010740108401094011040111401124011340114401154011640117401184011940120401214012240123401244012540126401274012840129401304013140132401334013440135401364013740138401394014040141401424014340144401454014640147401484014940150401514015240153401544015540156401574015840159401604016140162401634016440165401664016740168401694017040171401724017340174401754017640177401784017940180401814018240183401844018540186401874018840189401904019140192401934019440195401964019740198401994020040201402024020340204402054020640207402084020940210402114021240213402144021540216402174021840219402204022140222402234022440225402264022740228402294023040231402324023340234402354023640237402384023940240402414024240243402444024540246402474024840249402504025140252402534025440255402564025740258402594026040261402624026340264402654026640267402684026940270402714027240273402744027540276402774027840279402804028140282402834028440285402864028740288402894029040291402924029340294402954029640297402984029940300403014030240303403044030540306403074030840309403104031140312403134031440315403164031740318403194032040321403224032340324403254032640327403284032940330403314033240333403344033540336403374033840339403404034140342403434034440345403464034740348403494035040351403524035340354403554035640357403584035940360403614036240363403644036540366403674036840369403704037140372403734037440375403764037740378403794038040381403824038340384403854038640387403884038940390403914039240393403944039540396403974039840399404004040140402404034040440405404064040740408404094041040411404124041340414404154041640417404184041940420404214042240423404244042540426404274042840429404304043140432404334043440435404364043740438404394044040441404424044340444404454044640447404484044940450404514045240453404544045540456404574045840459404604046140462404634046440465404664046740468404694047040471404724047340474404754047640477404784047940480404814048240483404844048540486404874048840489404904049140492404934049440495404964049740498404994050040501405024050340504405054050640507405084050940510405114051240513405144051540516405174051840519405204052140522405234052440525405264052740528405294053040531405324053340534405354053640537405384053940540405414054240543405444054540546405474054840549405504055140552405534055440555405564055740558405594056040561405624056340564405654056640567405684056940570405714057240573405744057540576405774057840579405804058140582405834058440585405864058740588405894059040591405924059340594405954059640597405984059940600406014060240603406044060540606406074060840609406104061140612406134061440615406164061740618406194062040621406224062340624406254062640627406284062940630406314063240633406344063540636406374063840639406404064140642406434064440645406464064740648406494065040651406524065340654406554065640657406584065940660406614066240663406644066540666406674066840669406704067140672406734067440675406764067740678406794068040681406824068340684406854068640687406884068940690406914069240693406944069540696406974069840699407004070140702407034070440705407064070740708407094071040711407124071340714407154071640717407184071940720407214072240723407244072540726407274072840729407304073140732407334073440735407364073740738407394074040741407424074340744407454074640747407484074940750407514075240753407544075540756407574075840759407604076140762407634076440765407664076740768407694077040771407724077340774407754077640777407784077940780407814078240783407844078540786407874078840789407904079140792407934079440795407964079740798407994080040801408024080340804408054080640807408084080940810408114081240813408144081540816408174081840819408204082140822408234082440825408264082740828408294083040831408324083340834408354083640837408384083940840408414084240843408444084540846408474084840849408504085140852408534085440855408564085740858408594086040861408624086340864408654086640867408684086940870408714087240873408744087540876408774087840879408804088140882408834088440885408864088740888408894089040891408924089340894408954089640897408984089940900409014090240903409044090540906409074090840909409104091140912409134091440915409164091740918409194092040921409224092340924409254092640927409284092940930409314093240933409344093540936409374093840939409404094140942409434094440945409464094740948409494095040951409524095340954409554095640957409584095940960409614096240963409644096540966409674096840969409704097140972409734097440975409764097740978409794098040981409824098340984409854098640987409884098940990409914099240993409944099540996409974099840999410004100141002410034100441005410064100741008410094101041011410124101341014410154101641017410184101941020410214102241023410244102541026410274102841029410304103141032410334103441035410364103741038410394104041041410424104341044410454104641047410484104941050410514105241053410544105541056410574105841059410604106141062410634106441065410664106741068410694107041071410724107341074410754107641077410784107941080410814108241083410844108541086410874108841089410904109141092410934109441095410964109741098410994110041101411024110341104411054110641107411084110941110411114111241113411144111541116411174111841119411204112141122411234112441125411264112741128411294113041131411324113341134411354113641137411384113941140411414114241143411444114541146411474114841149411504115141152411534115441155411564115741158411594116041161411624116341164411654116641167411684116941170411714117241173411744117541176411774117841179411804118141182411834118441185411864118741188411894119041191411924119341194411954119641197411984119941200412014120241203412044120541206412074120841209412104121141212412134121441215412164121741218412194122041221412224122341224412254122641227412284122941230412314123241233412344123541236412374123841239412404124141242412434124441245412464124741248412494125041251412524125341254412554125641257412584125941260412614126241263412644126541266412674126841269412704127141272412734127441275412764127741278412794128041281412824128341284412854128641287412884128941290412914129241293412944129541296412974129841299413004130141302413034130441305413064130741308413094131041311413124131341314413154131641317413184131941320413214132241323413244132541326413274132841329413304133141332413334133441335413364133741338413394134041341413424134341344413454134641347413484134941350413514135241353413544135541356413574135841359413604136141362413634136441365413664136741368413694137041371413724137341374413754137641377413784137941380413814138241383413844138541386413874138841389413904139141392413934139441395413964139741398413994140041401414024140341404414054140641407414084140941410414114141241413414144141541416414174141841419414204142141422414234142441425414264142741428414294143041431414324143341434414354143641437414384143941440414414144241443414444144541446414474144841449414504145141452414534145441455414564145741458414594146041461414624146341464414654146641467414684146941470414714147241473414744147541476414774147841479414804148141482414834148441485414864148741488414894149041491414924149341494414954149641497414984149941500415014150241503415044150541506415074150841509415104151141512415134151441515415164151741518415194152041521415224152341524415254152641527415284152941530415314153241533415344153541536415374153841539415404154141542415434154441545415464154741548415494155041551415524155341554415554155641557415584155941560415614156241563415644156541566415674156841569415704157141572415734157441575415764157741578415794158041581415824158341584415854158641587415884158941590415914159241593415944159541596415974159841599416004160141602416034160441605416064160741608416094161041611416124161341614416154161641617416184161941620416214162241623416244162541626416274162841629416304163141632416334163441635416364163741638416394164041641416424164341644416454164641647416484164941650416514165241653416544165541656416574165841659416604166141662416634166441665416664166741668416694167041671416724167341674416754167641677416784167941680416814168241683416844168541686416874168841689416904169141692416934169441695416964169741698416994170041701417024170341704417054170641707417084170941710417114171241713417144171541716417174171841719417204172141722417234172441725417264172741728417294173041731417324173341734417354173641737417384173941740417414174241743417444174541746417474174841749417504175141752417534175441755417564175741758417594176041761417624176341764417654176641767417684176941770417714177241773417744177541776417774177841779417804178141782417834178441785417864178741788417894179041791417924179341794417954179641797417984179941800418014180241803418044180541806418074180841809418104181141812418134181441815418164181741818418194182041821418224182341824418254182641827418284182941830418314183241833418344183541836418374183841839418404184141842418434184441845418464184741848418494185041851418524185341854418554185641857418584185941860418614186241863418644186541866418674186841869418704187141872418734187441875418764187741878418794188041881418824188341884418854188641887418884188941890418914189241893418944189541896418974189841899419004190141902419034190441905419064190741908419094191041911419124191341914419154191641917419184191941920419214192241923419244192541926419274192841929419304193141932419334193441935419364193741938419394194041941419424194341944419454194641947419484194941950419514195241953419544195541956419574195841959419604196141962419634196441965419664196741968419694197041971419724197341974419754197641977419784197941980419814198241983419844198541986419874198841989419904199141992419934199441995419964199741998419994200042001420024200342004420054200642007420084200942010420114201242013420144201542016420174201842019420204202142022420234202442025420264202742028420294203042031420324203342034420354203642037420384203942040420414204242043420444204542046420474204842049420504205142052420534205442055420564205742058420594206042061420624206342064420654206642067420684206942070420714207242073420744207542076420774207842079420804208142082420834208442085420864208742088420894209042091420924209342094420954209642097420984209942100421014210242103421044210542106421074210842109421104211142112421134211442115421164211742118421194212042121421224212342124421254212642127421284212942130421314213242133421344213542136421374213842139421404214142142421434214442145421464214742148421494215042151421524215342154421554215642157421584215942160421614216242163421644216542166421674216842169421704217142172421734217442175421764217742178421794218042181421824218342184421854218642187421884218942190421914219242193421944219542196421974219842199422004220142202422034220442205422064220742208422094221042211422124221342214422154221642217422184221942220422214222242223422244222542226422274222842229422304223142232422334223442235422364223742238422394224042241422424224342244422454224642247422484224942250422514225242253422544225542256422574225842259422604226142262422634226442265422664226742268422694227042271422724227342274422754227642277422784227942280422814228242283422844228542286422874228842289422904229142292422934229442295422964229742298422994230042301423024230342304423054230642307423084230942310423114231242313423144231542316423174231842319423204232142322423234232442325423264232742328423294233042331423324233342334423354233642337423384233942340423414234242343423444234542346423474234842349423504235142352423534235442355423564235742358423594236042361423624236342364423654236642367423684236942370423714237242373423744237542376423774237842379423804238142382423834238442385423864238742388423894239042391423924239342394423954239642397423984239942400424014240242403424044240542406424074240842409424104241142412424134241442415424164241742418424194242042421424224242342424424254242642427424284242942430424314243242433424344243542436424374243842439424404244142442424434244442445424464244742448424494245042451424524245342454424554245642457424584245942460424614246242463424644246542466424674246842469424704247142472424734247442475424764247742478424794248042481424824248342484424854248642487424884248942490424914249242493424944249542496424974249842499425004250142502425034250442505425064250742508425094251042511425124251342514425154251642517425184251942520425214252242523425244252542526425274252842529425304253142532425334253442535425364253742538425394254042541425424254342544425454254642547425484254942550425514255242553425544255542556425574255842559425604256142562425634256442565425664256742568425694257042571425724257342574425754257642577425784257942580425814258242583425844258542586425874258842589425904259142592425934259442595425964259742598425994260042601426024260342604426054260642607426084260942610426114261242613426144261542616426174261842619426204262142622426234262442625426264262742628426294263042631426324263342634426354263642637426384263942640426414264242643426444264542646426474264842649426504265142652426534265442655426564265742658426594266042661426624266342664426654266642667426684266942670426714267242673426744267542676426774267842679426804268142682426834268442685426864268742688426894269042691426924269342694426954269642697426984269942700427014270242703427044270542706427074270842709427104271142712427134271442715427164271742718427194272042721427224272342724427254272642727427284272942730427314273242733427344273542736427374273842739427404274142742427434274442745427464274742748427494275042751427524275342754427554275642757427584275942760427614276242763427644276542766427674276842769427704277142772427734277442775427764277742778427794278042781427824278342784427854278642787427884278942790427914279242793427944279542796427974279842799428004280142802428034280442805428064280742808428094281042811428124281342814428154281642817428184281942820428214282242823428244282542826428274282842829428304283142832428334283442835428364283742838428394284042841428424284342844428454284642847428484284942850428514285242853428544285542856428574285842859428604286142862428634286442865428664286742868428694287042871428724287342874428754287642877428784287942880428814288242883428844288542886428874288842889428904289142892428934289442895428964289742898428994290042901429024290342904429054290642907429084290942910429114291242913429144291542916429174291842919429204292142922429234292442925429264292742928429294293042931429324293342934429354293642937429384293942940429414294242943429444294542946429474294842949429504295142952429534295442955429564295742958429594296042961429624296342964429654296642967429684296942970429714297242973429744297542976429774297842979429804298142982429834298442985429864298742988429894299042991429924299342994429954299642997429984299943000430014300243003430044300543006430074300843009430104301143012430134301443015430164301743018430194302043021430224302343024430254302643027430284302943030430314303243033430344303543036430374303843039430404304143042430434304443045430464304743048430494305043051430524305343054430554305643057430584305943060430614306243063430644306543066430674306843069430704307143072430734307443075430764307743078430794308043081430824308343084430854308643087430884308943090430914309243093430944309543096430974309843099431004310143102431034310443105431064310743108431094311043111431124311343114431154311643117431184311943120431214312243123431244312543126431274312843129431304313143132431334313443135431364313743138431394314043141431424314343144431454314643147431484314943150431514315243153431544315543156431574315843159431604316143162431634316443165431664316743168431694317043171431724317343174431754317643177431784317943180431814318243183431844318543186431874318843189431904319143192431934319443195431964319743198431994320043201432024320343204432054320643207432084320943210432114321243213432144321543216432174321843219432204322143222432234322443225432264322743228432294323043231432324323343234432354323643237432384323943240432414324243243432444324543246432474324843249432504325143252432534325443255432564325743258432594326043261432624326343264432654326643267432684326943270432714327243273432744327543276432774327843279432804328143282432834328443285432864328743288432894329043291432924329343294432954329643297432984329943300433014330243303433044330543306433074330843309433104331143312433134331443315433164331743318433194332043321433224332343324433254332643327433284332943330433314333243333433344333543336433374333843339433404334143342433434334443345433464334743348433494335043351433524335343354433554335643357433584335943360433614336243363433644336543366433674336843369433704337143372433734337443375433764337743378433794338043381433824338343384433854338643387433884338943390433914339243393433944339543396433974339843399434004340143402434034340443405434064340743408434094341043411434124341343414434154341643417434184341943420434214342243423434244342543426434274342843429434304343143432434334343443435434364343743438434394344043441434424344343444434454344643447434484344943450434514345243453434544345543456434574345843459434604346143462434634346443465434664346743468434694347043471434724347343474434754347643477434784347943480434814348243483434844348543486434874348843489434904349143492434934349443495434964349743498434994350043501435024350343504435054350643507435084350943510435114351243513435144351543516435174351843519435204352143522435234352443525435264352743528435294353043531435324353343534435354353643537435384353943540435414354243543435444354543546435474354843549435504355143552435534355443555435564355743558435594356043561435624356343564435654356643567435684356943570435714357243573435744357543576435774357843579435804358143582435834358443585435864358743588435894359043591435924359343594435954359643597435984359943600436014360243603436044360543606436074360843609436104361143612436134361443615436164361743618436194362043621436224362343624436254362643627436284362943630436314363243633436344363543636436374363843639436404364143642436434364443645436464364743648436494365043651436524365343654436554365643657436584365943660436614366243663436644366543666436674366843669436704367143672436734367443675436764367743678436794368043681436824368343684436854368643687436884368943690436914369243693436944369543696436974369843699437004370143702437034370443705437064370743708437094371043711437124371343714437154371643717437184371943720437214372243723437244372543726437274372843729437304373143732437334373443735437364373743738437394374043741437424374343744437454374643747437484374943750437514375243753437544375543756437574375843759437604376143762437634376443765437664376743768437694377043771437724377343774437754377643777437784377943780437814378243783437844378543786437874378843789437904379143792437934379443795437964379743798437994380043801438024380343804438054380643807438084380943810438114381243813438144381543816438174381843819438204382143822438234382443825438264382743828438294383043831438324383343834438354383643837438384383943840438414384243843438444384543846438474384843849438504385143852438534385443855438564385743858438594386043861438624386343864438654386643867438684386943870438714387243873438744387543876438774387843879438804388143882438834388443885438864388743888438894389043891438924389343894438954389643897438984389943900439014390243903439044390543906439074390843909439104391143912439134391443915439164391743918439194392043921439224392343924439254392643927439284392943930439314393243933439344393543936439374393843939439404394143942439434394443945439464394743948439494395043951439524395343954439554395643957439584395943960439614396243963439644396543966439674396843969439704397143972439734397443975439764397743978439794398043981439824398343984439854398643987439884398943990439914399243993439944399543996439974399843999440004400144002440034400444005440064400744008440094401044011440124401344014440154401644017440184401944020440214402244023440244402544026440274402844029440304403144032440334403444035440364403744038440394404044041440424404344044440454404644047440484404944050440514405244053440544405544056440574405844059440604406144062440634406444065440664406744068440694407044071440724407344074440754407644077440784407944080440814408244083440844408544086440874408844089440904409144092440934409444095440964409744098440994410044101441024410344104441054410644107441084410944110441114411244113441144411544116441174411844119441204412144122441234412444125441264412744128441294413044131441324413344134441354413644137441384413944140441414414244143441444414544146441474414844149441504415144152441534415444155441564415744158441594416044161441624416344164441654416644167441684416944170441714417244173441744417544176441774417844179441804418144182441834418444185441864418744188441894419044191441924419344194441954419644197441984419944200442014420244203442044420544206442074420844209442104421144212442134421444215442164421744218442194422044221442224422344224442254422644227442284422944230442314423244233442344423544236442374423844239442404424144242442434424444245442464424744248442494425044251442524425344254442554425644257442584425944260442614426244263442644426544266442674426844269442704427144272442734427444275442764427744278442794428044281442824428344284442854428644287442884428944290442914429244293442944429544296442974429844299443004430144302443034430444305443064430744308443094431044311443124431344314443154431644317443184431944320443214432244323443244432544326443274432844329443304433144332443334433444335443364433744338443394434044341443424434344344443454434644347443484434944350443514435244353443544435544356443574435844359443604436144362443634436444365443664436744368443694437044371443724437344374443754437644377443784437944380443814438244383443844438544386443874438844389443904439144392443934439444395443964439744398443994440044401444024440344404444054440644407444084440944410444114441244413444144441544416444174441844419444204442144422444234442444425444264442744428444294443044431444324443344434444354443644437444384443944440444414444244443444444444544446444474444844449444504445144452444534445444455444564445744458444594446044461444624446344464444654446644467444684446944470444714447244473444744447544476444774447844479444804448144482444834448444485444864448744488444894449044491444924449344494444954449644497444984449944500445014450244503445044450544506445074450844509445104451144512445134451444515445164451744518445194452044521445224452344524445254452644527445284452944530445314453244533445344453544536445374453844539445404454144542445434454444545445464454744548445494455044551445524455344554445554455644557445584455944560445614456244563445644456544566445674456844569445704457144572445734457444575445764457744578445794458044581445824458344584445854458644587445884458944590445914459244593445944459544596445974459844599446004460144602446034460444605446064460744608446094461044611446124461344614446154461644617446184461944620446214462244623446244462544626446274462844629446304463144632446334463444635446364463744638446394464044641446424464344644446454464644647446484464944650446514465244653446544465544656446574465844659446604466144662446634466444665446664466744668446694467044671446724467344674446754467644677446784467944680446814468244683446844468544686446874468844689446904469144692446934469444695446964469744698446994470044701447024470344704447054470644707447084470944710447114471244713447144471544716447174471844719447204472144722447234472444725447264472744728447294473044731447324473344734447354473644737447384473944740447414474244743447444474544746447474474844749447504475144752447534475444755447564475744758447594476044761447624476344764447654476644767447684476944770447714477244773447744477544776447774477844779447804478144782447834478444785447864478744788447894479044791447924479344794447954479644797447984479944800448014480244803448044480544806448074480844809448104481144812448134481444815448164481744818448194482044821448224482344824448254482644827448284482944830448314483244833448344483544836448374483844839448404484144842448434484444845448464484744848448494485044851448524485344854448554485644857448584485944860448614486244863448644486544866448674486844869448704487144872448734487444875448764487744878448794488044881448824488344884448854488644887448884488944890448914489244893448944489544896448974489844899449004490144902449034490444905449064490744908449094491044911449124491344914449154491644917449184491944920449214492244923449244492544926449274492844929449304493144932449334493444935449364493744938449394494044941449424494344944449454494644947449484494944950449514495244953449544495544956449574495844959449604496144962449634496444965449664496744968449694497044971449724497344974449754497644977449784497944980449814498244983449844498544986449874498844989449904499144992449934499444995449964499744998449994500045001450024500345004450054500645007450084500945010450114501245013450144501545016450174501845019450204502145022450234502445025450264502745028450294503045031450324503345034450354503645037450384503945040450414504245043450444504545046450474504845049450504505145052450534505445055450564505745058450594506045061450624506345064450654506645067450684506945070450714507245073450744507545076450774507845079450804508145082450834508445085450864508745088450894509045091450924509345094450954509645097450984509945100451014510245103451044510545106451074510845109451104511145112451134511445115451164511745118451194512045121451224512345124451254512645127451284512945130451314513245133451344513545136451374513845139451404514145142451434514445145451464514745148451494515045151451524515345154451554515645157451584515945160451614516245163451644516545166451674516845169451704517145172451734517445175451764517745178451794518045181451824518345184451854518645187451884518945190451914519245193451944519545196451974519845199452004520145202452034520445205452064520745208452094521045211452124521345214452154521645217452184521945220452214522245223452244522545226452274522845229452304523145232452334523445235452364523745238452394524045241452424524345244452454524645247452484524945250452514525245253452544525545256452574525845259452604526145262452634526445265452664526745268452694527045271452724527345274452754527645277452784527945280452814528245283452844528545286452874528845289452904529145292452934529445295452964529745298452994530045301453024530345304453054530645307453084530945310453114531245313453144531545316453174531845319453204532145322453234532445325453264532745328453294533045331453324533345334453354533645337453384533945340453414534245343453444534545346453474534845349453504535145352453534535445355453564535745358453594536045361453624536345364453654536645367453684536945370453714537245373453744537545376453774537845379453804538145382453834538445385453864538745388453894539045391453924539345394453954539645397453984539945400454014540245403454044540545406454074540845409454104541145412454134541445415454164541745418454194542045421454224542345424454254542645427454284542945430454314543245433454344543545436454374543845439454404544145442454434544445445454464544745448454494545045451454524545345454454554545645457454584545945460454614546245463454644546545466454674546845469454704547145472454734547445475454764547745478454794548045481454824548345484454854548645487454884548945490454914549245493454944549545496454974549845499455004550145502455034550445505455064550745508455094551045511455124551345514455154551645517455184551945520455214552245523455244552545526455274552845529455304553145532455334553445535455364553745538455394554045541455424554345544455454554645547455484554945550455514555245553455544555545556455574555845559455604556145562455634556445565455664556745568455694557045571455724557345574455754557645577455784557945580455814558245583455844558545586455874558845589455904559145592455934559445595455964559745598455994560045601456024560345604456054560645607456084560945610456114561245613456144561545616456174561845619456204562145622456234562445625456264562745628456294563045631456324563345634456354563645637456384563945640456414564245643456444564545646456474564845649456504565145652456534565445655456564565745658456594566045661456624566345664456654566645667456684566945670456714567245673456744567545676456774567845679456804568145682456834568445685456864568745688456894569045691456924569345694456954569645697456984569945700457014570245703457044570545706457074570845709457104571145712457134571445715457164571745718457194572045721457224572345724457254572645727457284572945730457314573245733457344573545736457374573845739457404574145742457434574445745457464574745748457494575045751457524575345754457554575645757457584575945760457614576245763457644576545766457674576845769457704577145772457734577445775457764577745778457794578045781457824578345784457854578645787457884578945790457914579245793457944579545796457974579845799458004580145802458034580445805458064580745808458094581045811458124581345814458154581645817458184581945820458214582245823458244582545826458274582845829458304583145832458334583445835458364583745838458394584045841458424584345844458454584645847458484584945850458514585245853458544585545856458574585845859458604586145862458634586445865458664586745868458694587045871458724587345874458754587645877458784587945880458814588245883458844588545886458874588845889458904589145892458934589445895458964589745898458994590045901459024590345904459054590645907459084590945910459114591245913459144591545916459174591845919459204592145922459234592445925459264592745928459294593045931459324593345934459354593645937459384593945940459414594245943459444594545946459474594845949459504595145952459534595445955459564595745958459594596045961459624596345964459654596645967459684596945970459714597245973459744597545976459774597845979459804598145982459834598445985459864598745988459894599045991459924599345994459954599645997459984599946000460014600246003460044600546006460074600846009460104601146012460134601446015460164601746018460194602046021460224602346024460254602646027460284602946030460314603246033460344603546036460374603846039460404604146042460434604446045460464604746048460494605046051460524605346054460554605646057460584605946060460614606246063460644606546066460674606846069460704607146072460734607446075460764607746078460794608046081460824608346084460854608646087460884608946090460914609246093460944609546096460974609846099461004610146102461034610446105461064610746108461094611046111461124611346114461154611646117461184611946120461214612246123461244612546126461274612846129461304613146132461334613446135461364613746138461394614046141461424614346144461454614646147461484614946150461514615246153461544615546156461574615846159461604616146162461634616446165461664616746168461694617046171461724617346174461754617646177461784617946180461814618246183461844618546186461874618846189461904619146192461934619446195461964619746198461994620046201462024620346204462054620646207462084620946210462114621246213462144621546216462174621846219462204622146222462234622446225462264622746228462294623046231462324623346234462354623646237462384623946240462414624246243462444624546246462474624846249462504625146252462534625446255462564625746258462594626046261462624626346264462654626646267462684626946270462714627246273462744627546276462774627846279462804628146282462834628446285462864628746288462894629046291462924629346294462954629646297462984629946300463014630246303463044630546306463074630846309463104631146312463134631446315463164631746318463194632046321463224632346324463254632646327463284632946330463314633246333463344633546336463374633846339463404634146342463434634446345463464634746348463494635046351463524635346354463554635646357463584635946360463614636246363463644636546366463674636846369463704637146372463734637446375463764637746378463794638046381463824638346384463854638646387463884638946390463914639246393463944639546396463974639846399464004640146402464034640446405464064640746408464094641046411464124641346414464154641646417464184641946420464214642246423464244642546426464274642846429464304643146432464334643446435464364643746438464394644046441464424644346444464454644646447464484644946450464514645246453464544645546456464574645846459464604646146462464634646446465464664646746468464694647046471464724647346474464754647646477464784647946480464814648246483464844648546486464874648846489464904649146492464934649446495464964649746498464994650046501465024650346504465054650646507465084650946510465114651246513465144651546516465174651846519465204652146522465234652446525465264652746528465294653046531465324653346534465354653646537465384653946540465414654246543465444654546546465474654846549465504655146552465534655446555465564655746558465594656046561465624656346564465654656646567465684656946570465714657246573465744657546576465774657846579465804658146582465834658446585465864658746588465894659046591465924659346594465954659646597465984659946600466014660246603466044660546606466074660846609466104661146612466134661446615466164661746618466194662046621466224662346624466254662646627466284662946630466314663246633466344663546636466374663846639466404664146642466434664446645466464664746648466494665046651466524665346654466554665646657466584665946660466614666246663466644666546666466674666846669466704667146672466734667446675466764667746678466794668046681466824668346684466854668646687466884668946690466914669246693466944669546696466974669846699467004670146702467034670446705467064670746708467094671046711467124671346714467154671646717467184671946720467214672246723467244672546726467274672846729467304673146732467334673446735467364673746738467394674046741467424674346744467454674646747467484674946750467514675246753467544675546756467574675846759467604676146762467634676446765467664676746768467694677046771467724677346774467754677646777467784677946780467814678246783467844678546786467874678846789467904679146792467934679446795467964679746798467994680046801468024680346804468054680646807468084680946810468114681246813468144681546816468174681846819468204682146822468234682446825468264682746828468294683046831468324683346834468354683646837468384683946840468414684246843468444684546846468474684846849468504685146852468534685446855468564685746858468594686046861468624686346864468654686646867468684686946870468714687246873468744687546876468774687846879468804688146882468834688446885468864688746888468894689046891468924689346894468954689646897468984689946900469014690246903469044690546906469074690846909469104691146912469134691446915469164691746918469194692046921469224692346924469254692646927469284692946930469314693246933469344693546936469374693846939469404694146942469434694446945469464694746948469494695046951469524695346954469554695646957469584695946960469614696246963469644696546966469674696846969469704697146972469734697446975469764697746978469794698046981469824698346984469854698646987469884698946990469914699246993469944699546996469974699846999470004700147002470034700447005470064700747008470094701047011470124701347014470154701647017470184701947020470214702247023470244702547026470274702847029470304703147032470334703447035470364703747038470394704047041470424704347044470454704647047470484704947050470514705247053470544705547056470574705847059470604706147062470634706447065470664706747068470694707047071470724707347074470754707647077470784707947080470814708247083470844708547086470874708847089470904709147092470934709447095470964709747098470994710047101471024710347104471054710647107471084710947110471114711247113471144711547116471174711847119471204712147122471234712447125471264712747128471294713047131471324713347134471354713647137471384713947140471414714247143471444714547146471474714847149471504715147152471534715447155471564715747158471594716047161471624716347164471654716647167471684716947170471714717247173471744717547176471774717847179471804718147182471834718447185471864718747188471894719047191471924719347194471954719647197471984719947200472014720247203472044720547206472074720847209472104721147212472134721447215472164721747218472194722047221472224722347224472254722647227472284722947230472314723247233472344723547236472374723847239472404724147242472434724447245472464724747248472494725047251472524725347254472554725647257472584725947260472614726247263472644726547266472674726847269472704727147272472734727447275472764727747278472794728047281472824728347284472854728647287472884728947290472914729247293472944729547296472974729847299473004730147302473034730447305473064730747308473094731047311473124731347314473154731647317473184731947320473214732247323473244732547326473274732847329473304733147332473334733447335473364733747338473394734047341473424734347344473454734647347473484734947350473514735247353473544735547356473574735847359473604736147362473634736447365473664736747368473694737047371473724737347374473754737647377473784737947380473814738247383473844738547386473874738847389473904739147392473934739447395473964739747398473994740047401474024740347404474054740647407474084740947410474114741247413474144741547416474174741847419474204742147422474234742447425474264742747428474294743047431474324743347434474354743647437474384743947440474414744247443474444744547446474474744847449474504745147452474534745447455474564745747458474594746047461474624746347464474654746647467474684746947470474714747247473474744747547476474774747847479474804748147482474834748447485474864748747488474894749047491474924749347494474954749647497474984749947500475014750247503475044750547506475074750847509475104751147512475134751447515475164751747518475194752047521475224752347524475254752647527475284752947530475314753247533475344753547536475374753847539475404754147542475434754447545475464754747548475494755047551475524755347554475554755647557475584755947560475614756247563475644756547566475674756847569475704757147572475734757447575475764757747578475794758047581475824758347584475854758647587475884758947590475914759247593475944759547596475974759847599476004760147602476034760447605476064760747608476094761047611476124761347614476154761647617476184761947620476214762247623476244762547626476274762847629476304763147632476334763447635476364763747638476394764047641476424764347644476454764647647476484764947650476514765247653476544765547656476574765847659476604766147662476634766447665476664766747668476694767047671476724767347674476754767647677476784767947680476814768247683476844768547686476874768847689476904769147692476934769447695476964769747698476994770047701477024770347704477054770647707477084770947710477114771247713477144771547716477174771847719477204772147722477234772447725477264772747728477294773047731477324773347734477354773647737477384773947740477414774247743477444774547746477474774847749477504775147752477534775447755477564775747758477594776047761477624776347764477654776647767477684776947770477714777247773477744777547776477774777847779477804778147782477834778447785477864778747788477894779047791477924779347794477954779647797477984779947800478014780247803478044780547806478074780847809478104781147812478134781447815478164781747818478194782047821478224782347824478254782647827478284782947830478314783247833478344783547836478374783847839478404784147842478434784447845478464784747848478494785047851478524785347854478554785647857478584785947860478614786247863478644786547866478674786847869478704787147872478734787447875478764787747878478794788047881478824788347884478854788647887478884788947890478914789247893478944789547896478974789847899479004790147902479034790447905479064790747908479094791047911479124791347914479154791647917479184791947920479214792247923479244792547926479274792847929479304793147932479334793447935479364793747938479394794047941479424794347944479454794647947479484794947950479514795247953479544795547956479574795847959479604796147962479634796447965479664796747968479694797047971479724797347974479754797647977479784797947980479814798247983479844798547986479874798847989479904799147992479934799447995479964799747998479994800048001480024800348004480054800648007480084800948010480114801248013480144801548016480174801848019480204802148022480234802448025480264802748028480294803048031480324803348034480354803648037480384803948040480414804248043480444804548046480474804848049480504805148052480534805448055480564805748058480594806048061480624806348064480654806648067480684806948070480714807248073480744807548076480774807848079480804808148082480834808448085480864808748088480894809048091480924809348094480954809648097480984809948100481014810248103481044810548106481074810848109481104811148112481134811448115481164811748118481194812048121481224812348124481254812648127481284812948130481314813248133481344813548136481374813848139481404814148142481434814448145481464814748148481494815048151481524815348154481554815648157481584815948160481614816248163481644816548166481674816848169481704817148172481734817448175481764817748178481794818048181481824818348184481854818648187481884818948190481914819248193481944819548196481974819848199482004820148202482034820448205482064820748208482094821048211482124821348214482154821648217482184821948220482214822248223482244822548226482274822848229482304823148232482334823448235482364823748238482394824048241482424824348244482454824648247482484824948250482514825248253482544825548256482574825848259482604826148262482634826448265482664826748268482694827048271482724827348274482754827648277482784827948280482814828248283482844828548286482874828848289482904829148292482934829448295482964829748298482994830048301483024830348304483054830648307483084830948310483114831248313483144831548316483174831848319483204832148322483234832448325483264832748328483294833048331483324833348334483354833648337483384833948340483414834248343483444834548346483474834848349483504835148352483534835448355483564835748358483594836048361483624836348364483654836648367483684836948370483714837248373483744837548376483774837848379483804838148382483834838448385483864838748388483894839048391483924839348394483954839648397483984839948400484014840248403484044840548406484074840848409484104841148412484134841448415484164841748418484194842048421484224842348424484254842648427484284842948430484314843248433484344843548436484374843848439484404844148442484434844448445484464844748448484494845048451484524845348454484554845648457484584845948460484614846248463484644846548466484674846848469484704847148472484734847448475484764847748478484794848048481484824848348484484854848648487484884848948490484914849248493484944849548496484974849848499485004850148502485034850448505485064850748508485094851048511485124851348514485154851648517485184851948520485214852248523485244852548526485274852848529485304853148532485334853448535485364853748538485394854048541485424854348544485454854648547485484854948550485514855248553485544855548556485574855848559485604856148562485634856448565485664856748568485694857048571485724857348574485754857648577485784857948580485814858248583485844858548586485874858848589485904859148592485934859448595485964859748598485994860048601486024860348604486054860648607486084860948610486114861248613486144861548616486174861848619486204862148622486234862448625486264862748628486294863048631486324863348634486354863648637486384863948640486414864248643486444864548646486474864848649486504865148652486534865448655486564865748658486594866048661486624866348664486654866648667486684866948670486714867248673486744867548676486774867848679486804868148682486834868448685486864868748688486894869048691486924869348694486954869648697486984869948700487014870248703487044870548706487074870848709487104871148712487134871448715487164871748718487194872048721487224872348724487254872648727487284872948730487314873248733487344873548736487374873848739487404874148742487434874448745487464874748748487494875048751487524875348754487554875648757487584875948760487614876248763487644876548766487674876848769487704877148772487734877448775487764877748778487794878048781487824878348784487854878648787487884878948790487914879248793487944879548796487974879848799488004880148802488034880448805488064880748808488094881048811488124881348814488154881648817488184881948820488214882248823488244882548826488274882848829488304883148832488334883448835488364883748838488394884048841488424884348844488454884648847488484884948850488514885248853488544885548856488574885848859488604886148862488634886448865488664886748868488694887048871488724887348874488754887648877488784887948880488814888248883488844888548886488874888848889488904889148892488934889448895488964889748898488994890048901489024890348904489054890648907489084890948910489114891248913489144891548916489174891848919489204892148922489234892448925489264892748928489294893048931489324893348934489354893648937489384893948940489414894248943489444894548946489474894848949489504895148952489534895448955489564895748958489594896048961489624896348964489654896648967489684896948970489714897248973489744897548976489774897848979489804898148982489834898448985489864898748988489894899048991489924899348994489954899648997489984899949000490014900249003490044900549006490074900849009490104901149012490134901449015490164901749018490194902049021490224902349024490254902649027490284902949030490314903249033490344903549036490374903849039490404904149042490434904449045490464904749048490494905049051490524905349054490554905649057490584905949060490614906249063490644906549066490674906849069490704907149072490734907449075490764907749078490794908049081490824908349084490854908649087490884908949090490914909249093490944909549096490974909849099491004910149102491034910449105491064910749108491094911049111491124911349114491154911649117491184911949120491214912249123491244912549126491274912849129491304913149132491334913449135491364913749138491394914049141491424914349144491454914649147491484914949150491514915249153491544915549156491574915849159491604916149162491634916449165491664916749168491694917049171491724917349174491754917649177491784917949180491814918249183491844918549186491874918849189491904919149192491934919449195491964919749198491994920049201492024920349204492054920649207492084920949210492114921249213492144921549216492174921849219492204922149222492234922449225492264922749228492294923049231492324923349234492354923649237492384923949240492414924249243492444924549246492474924849249492504925149252492534925449255492564925749258492594926049261492624926349264492654926649267492684926949270492714927249273492744927549276492774927849279492804928149282492834928449285492864928749288492894929049291492924929349294492954929649297492984929949300493014930249303493044930549306493074930849309493104931149312493134931449315493164931749318493194932049321493224932349324493254932649327493284932949330493314933249333493344933549336493374933849339493404934149342493434934449345493464934749348493494935049351493524935349354493554935649357493584935949360493614936249363493644936549366493674936849369493704937149372493734937449375493764937749378493794938049381493824938349384493854938649387493884938949390493914939249393493944939549396493974939849399494004940149402494034940449405494064940749408494094941049411494124941349414494154941649417494184941949420494214942249423494244942549426494274942849429494304943149432494334943449435494364943749438494394944049441494424944349444494454944649447494484944949450494514945249453494544945549456494574945849459494604946149462494634946449465494664946749468494694947049471494724947349474494754947649477494784947949480494814948249483494844948549486494874948849489494904949149492494934949449495494964949749498494994950049501495024950349504495054950649507495084950949510495114951249513495144951549516495174951849519495204952149522495234952449525495264952749528495294953049531495324953349534495354953649537495384953949540495414954249543495444954549546495474954849549495504955149552495534955449555495564955749558495594956049561495624956349564495654956649567495684956949570495714957249573495744957549576495774957849579495804958149582495834958449585495864958749588495894959049591495924959349594495954959649597495984959949600496014960249603496044960549606496074960849609496104961149612496134961449615496164961749618496194962049621496224962349624496254962649627496284962949630496314963249633496344963549636496374963849639496404964149642496434964449645496464964749648496494965049651496524965349654496554965649657496584965949660496614966249663496644966549666496674966849669496704967149672496734967449675496764967749678496794968049681496824968349684496854968649687496884968949690496914969249693496944969549696496974969849699497004970149702497034970449705497064970749708497094971049711497124971349714497154971649717497184971949720497214972249723497244972549726497274972849729497304973149732497334973449735497364973749738497394974049741497424974349744497454974649747497484974949750497514975249753497544975549756497574975849759497604976149762497634976449765497664976749768497694977049771497724977349774497754977649777497784977949780497814978249783497844978549786497874978849789497904979149792497934979449795497964979749798497994980049801498024980349804498054980649807498084980949810498114981249813498144981549816498174981849819498204982149822498234982449825498264982749828498294983049831498324983349834498354983649837498384983949840498414984249843498444984549846498474984849849498504985149852498534985449855498564985749858498594986049861498624986349864498654986649867498684986949870498714987249873498744987549876498774987849879498804988149882498834988449885498864988749888498894989049891498924989349894498954989649897498984989949900499014990249903499044990549906499074990849909499104991149912499134991449915499164991749918499194992049921499224992349924499254992649927499284992949930499314993249933499344993549936499374993849939499404994149942499434994449945499464994749948499494995049951499524995349954499554995649957499584995949960499614996249963499644996549966499674996849969499704997149972499734997449975499764997749978499794998049981499824998349984499854998649987499884998949990499914999249993499944999549996499974999849999500005000150002500035000450005500065000750008500095001050011500125001350014500155001650017500185001950020500215002250023500245002550026500275002850029500305003150032500335003450035500365003750038500395004050041500425004350044500455004650047500485004950050500515005250053500545005550056500575005850059500605006150062500635006450065500665006750068500695007050071500725007350074500755007650077500785007950080500815008250083500845008550086500875008850089500905009150092500935009450095500965009750098500995010050101501025010350104501055010650107501085010950110501115011250113501145011550116501175011850119501205012150122501235012450125501265012750128501295013050131501325013350134501355013650137501385013950140501415014250143501445014550146501475014850149501505015150152501535015450155501565015750158501595016050161501625016350164501655016650167501685016950170501715017250173501745017550176501775017850179501805018150182501835018450185501865018750188501895019050191501925019350194501955019650197501985019950200502015020250203502045020550206502075020850209502105021150212502135021450215502165021750218502195022050221502225022350224502255022650227502285022950230502315023250233502345023550236502375023850239502405024150242502435024450245502465024750248502495025050251502525025350254502555025650257502585025950260502615026250263502645026550266502675026850269502705027150272502735027450275502765027750278502795028050281502825028350284502855028650287502885028950290502915029250293502945029550296502975029850299503005030150302503035030450305503065030750308503095031050311503125031350314503155031650317503185031950320503215032250323503245032550326503275032850329503305033150332503335033450335503365033750338503395034050341503425034350344503455034650347503485034950350503515035250353503545035550356503575035850359503605036150362503635036450365503665036750368503695037050371503725037350374503755037650377503785037950380503815038250383503845038550386503875038850389503905039150392503935039450395503965039750398503995040050401504025040350404504055040650407504085040950410504115041250413504145041550416504175041850419504205042150422504235042450425504265042750428504295043050431504325043350434504355043650437504385043950440504415044250443504445044550446504475044850449504505045150452504535045450455504565045750458504595046050461504625046350464504655046650467504685046950470504715047250473504745047550476504775047850479504805048150482504835048450485504865048750488504895049050491504925049350494504955049650497504985049950500505015050250503505045050550506505075050850509505105051150512505135051450515505165051750518505195052050521505225052350524505255052650527505285052950530505315053250533505345053550536505375053850539505405054150542505435054450545505465054750548505495055050551505525055350554505555055650557505585055950560505615056250563505645056550566505675056850569505705057150572505735057450575505765057750578505795058050581505825058350584505855058650587505885058950590505915059250593505945059550596505975059850599506005060150602506035060450605506065060750608506095061050611506125061350614506155061650617506185061950620506215062250623506245062550626506275062850629506305063150632506335063450635506365063750638506395064050641506425064350644506455064650647506485064950650506515065250653506545065550656506575065850659506605066150662506635066450665506665066750668506695067050671506725067350674506755067650677506785067950680506815068250683506845068550686506875068850689506905069150692506935069450695506965069750698506995070050701507025070350704507055070650707507085070950710507115071250713507145071550716507175071850719507205072150722507235072450725507265072750728507295073050731507325073350734507355073650737507385073950740507415074250743507445074550746507475074850749507505075150752507535075450755507565075750758507595076050761507625076350764507655076650767507685076950770507715077250773507745077550776507775077850779507805078150782507835078450785507865078750788507895079050791507925079350794507955079650797507985079950800508015080250803508045080550806508075080850809508105081150812508135081450815508165081750818508195082050821508225082350824508255082650827508285082950830508315083250833508345083550836508375083850839508405084150842508435084450845508465084750848508495085050851508525085350854508555085650857508585085950860508615086250863508645086550866508675086850869508705087150872508735087450875508765087750878508795088050881508825088350884508855088650887508885088950890508915089250893508945089550896508975089850899509005090150902509035090450905509065090750908509095091050911509125091350914509155091650917509185091950920509215092250923509245092550926509275092850929509305093150932509335093450935509365093750938509395094050941509425094350944509455094650947509485094950950509515095250953509545095550956509575095850959509605096150962509635096450965509665096750968509695097050971509725097350974509755097650977509785097950980509815098250983509845098550986509875098850989509905099150992509935099450995509965099750998509995100051001510025100351004510055100651007510085100951010510115101251013510145101551016510175101851019510205102151022510235102451025510265102751028510295103051031510325103351034510355103651037510385103951040510415104251043510445104551046510475104851049510505105151052510535105451055510565105751058510595106051061510625106351064510655106651067510685106951070510715107251073510745107551076510775107851079510805108151082510835108451085510865108751088510895109051091510925109351094510955109651097510985109951100511015110251103511045110551106511075110851109511105111151112511135111451115511165111751118511195112051121511225112351124511255112651127511285112951130511315113251133511345113551136511375113851139511405114151142511435114451145511465114751148511495115051151511525115351154511555115651157511585115951160511615116251163511645116551166511675116851169511705117151172511735117451175511765117751178511795118051181511825118351184511855118651187511885118951190511915119251193511945119551196511975119851199512005120151202512035120451205512065120751208512095121051211512125121351214512155121651217512185121951220512215122251223512245122551226512275122851229512305123151232512335123451235512365123751238512395124051241512425124351244512455124651247512485124951250512515125251253512545125551256512575125851259512605126151262512635126451265512665126751268512695127051271512725127351274512755127651277512785127951280512815128251283512845128551286512875128851289512905129151292512935129451295512965129751298512995130051301513025130351304513055130651307513085130951310513115131251313513145131551316513175131851319513205132151322513235132451325513265132751328513295133051331513325133351334513355133651337513385133951340513415134251343513445134551346513475134851349513505135151352513535135451355513565135751358513595136051361513625136351364513655136651367513685136951370513715137251373513745137551376513775137851379513805138151382513835138451385513865138751388513895139051391513925139351394513955139651397513985139951400514015140251403514045140551406514075140851409514105141151412514135141451415514165141751418514195142051421514225142351424514255142651427514285142951430514315143251433514345143551436514375143851439514405144151442514435144451445514465144751448514495145051451514525145351454514555145651457514585145951460514615146251463514645146551466514675146851469514705147151472514735147451475514765147751478514795148051481514825148351484514855148651487514885148951490514915149251493514945149551496514975149851499515005150151502515035150451505515065150751508515095151051511515125151351514515155151651517515185151951520515215152251523515245152551526515275152851529515305153151532515335153451535515365153751538515395154051541515425154351544515455154651547515485154951550515515155251553515545155551556515575155851559515605156151562515635156451565515665156751568515695157051571515725157351574515755157651577515785157951580515815158251583515845158551586515875158851589515905159151592515935159451595515965159751598515995160051601516025160351604516055160651607516085160951610516115161251613516145161551616516175161851619516205162151622516235162451625516265162751628516295163051631516325163351634516355163651637516385163951640516415164251643516445164551646516475164851649516505165151652516535165451655516565165751658516595166051661516625166351664516655166651667516685166951670516715167251673516745167551676516775167851679516805168151682516835168451685516865168751688516895169051691516925169351694516955169651697516985169951700517015170251703517045170551706517075170851709517105171151712517135171451715517165171751718517195172051721517225172351724517255172651727517285172951730517315173251733517345173551736517375173851739517405174151742517435174451745517465174751748517495175051751517525175351754517555175651757517585175951760517615176251763517645176551766517675176851769517705177151772517735177451775517765177751778517795178051781517825178351784517855178651787517885178951790517915179251793517945179551796517975179851799518005180151802518035180451805518065180751808518095181051811518125181351814518155181651817518185181951820518215182251823518245182551826518275182851829518305183151832518335183451835518365183751838518395184051841518425184351844518455184651847518485184951850518515185251853518545185551856518575185851859518605186151862518635186451865518665186751868518695187051871518725187351874518755187651877518785187951880518815188251883518845188551886518875188851889518905189151892518935189451895518965189751898518995190051901519025190351904519055190651907519085190951910519115191251913519145191551916519175191851919519205192151922519235192451925519265192751928519295193051931519325193351934519355193651937519385193951940519415194251943519445194551946519475194851949519505195151952519535195451955519565195751958519595196051961519625196351964519655196651967519685196951970519715197251973519745197551976519775197851979519805198151982519835198451985519865198751988519895199051991519925199351994519955199651997519985199952000520015200252003520045200552006520075200852009520105201152012520135201452015520165201752018520195202052021520225202352024520255202652027520285202952030520315203252033520345203552036520375203852039520405204152042520435204452045520465204752048520495205052051520525205352054520555205652057520585205952060520615206252063520645206552066520675206852069520705207152072520735207452075520765207752078520795208052081520825208352084520855208652087520885208952090520915209252093520945209552096520975209852099521005210152102521035210452105521065210752108521095211052111521125211352114521155211652117521185211952120521215212252123521245212552126521275212852129521305213152132521335213452135521365213752138521395214052141521425214352144521455214652147521485214952150521515215252153521545215552156521575215852159521605216152162521635216452165521665216752168521695217052171521725217352174521755217652177521785217952180521815218252183521845218552186521875218852189521905219152192521935219452195521965219752198521995220052201522025220352204522055220652207522085220952210522115221252213522145221552216522175221852219522205222152222522235222452225522265222752228522295223052231522325223352234522355223652237522385223952240522415224252243522445224552246522475224852249522505225152252522535225452255522565225752258522595226052261522625226352264522655226652267522685226952270522715227252273522745227552276522775227852279522805228152282522835228452285522865228752288522895229052291522925229352294522955229652297522985229952300523015230252303523045230552306523075230852309523105231152312523135231452315523165231752318523195232052321523225232352324523255232652327523285232952330523315233252333523345233552336523375233852339523405234152342523435234452345523465234752348523495235052351523525235352354523555235652357523585235952360523615236252363523645236552366523675236852369523705237152372523735237452375523765237752378523795238052381523825238352384523855238652387523885238952390523915239252393523945239552396523975239852399524005240152402524035240452405524065240752408524095241052411524125241352414524155241652417524185241952420524215242252423524245242552426524275242852429524305243152432524335243452435524365243752438524395244052441524425244352444524455244652447524485244952450524515245252453524545245552456524575245852459524605246152462524635246452465524665246752468524695247052471524725247352474524755247652477524785247952480524815248252483524845248552486524875248852489524905249152492524935249452495524965249752498524995250052501525025250352504525055250652507525085250952510525115251252513525145251552516525175251852519525205252152522525235252452525525265252752528525295253052531525325253352534525355253652537525385253952540525415254252543525445254552546525475254852549525505255152552525535255452555525565255752558525595256052561525625256352564525655256652567525685256952570525715257252573525745257552576525775257852579525805258152582525835258452585525865258752588525895259052591525925259352594525955259652597525985259952600526015260252603526045260552606526075260852609526105261152612526135261452615526165261752618526195262052621526225262352624526255262652627526285262952630526315263252633526345263552636526375263852639526405264152642526435264452645526465264752648526495265052651526525265352654526555265652657526585265952660526615266252663526645266552666526675266852669526705267152672526735267452675526765267752678526795268052681526825268352684526855268652687526885268952690526915269252693526945269552696526975269852699527005270152702527035270452705527065270752708527095271052711527125271352714527155271652717527185271952720527215272252723527245272552726527275272852729527305273152732527335273452735527365273752738527395274052741527425274352744527455274652747527485274952750527515275252753527545275552756527575275852759527605276152762527635276452765527665276752768527695277052771527725277352774527755277652777527785277952780527815278252783527845278552786527875278852789527905279152792527935279452795527965279752798527995280052801528025280352804528055280652807528085280952810528115281252813528145281552816528175281852819528205282152822528235282452825528265282752828528295283052831528325283352834528355283652837528385283952840528415284252843528445284552846528475284852849528505285152852528535285452855528565285752858528595286052861528625286352864528655286652867528685286952870528715287252873528745287552876528775287852879528805288152882528835288452885528865288752888528895289052891528925289352894528955289652897528985289952900529015290252903529045290552906529075290852909529105291152912529135291452915529165291752918529195292052921529225292352924529255292652927529285292952930529315293252933529345293552936529375293852939529405294152942529435294452945529465294752948529495295052951529525295352954529555295652957529585295952960529615296252963529645296552966529675296852969529705297152972529735297452975529765297752978529795298052981529825298352984529855298652987529885298952990529915299252993529945299552996529975299852999530005300153002530035300453005530065300753008530095301053011530125301353014530155301653017530185301953020530215302253023530245302553026530275302853029530305303153032530335303453035530365303753038530395304053041530425304353044530455304653047530485304953050530515305253053530545305553056530575305853059530605306153062530635306453065530665306753068530695307053071530725307353074530755307653077530785307953080530815308253083530845308553086530875308853089530905309153092530935309453095530965309753098530995310053101531025310353104531055310653107531085310953110531115311253113531145311553116531175311853119531205312153122531235312453125531265312753128531295313053131531325313353134531355313653137531385313953140531415314253143531445314553146531475314853149531505315153152531535315453155531565315753158531595316053161531625316353164531655316653167531685316953170531715317253173531745317553176531775317853179531805318153182531835318453185531865318753188531895319053191531925319353194531955319653197531985319953200532015320253203532045320553206532075320853209532105321153212532135321453215532165321753218532195322053221532225322353224532255322653227532285322953230532315323253233532345323553236532375323853239532405324153242532435324453245532465324753248532495325053251532525325353254532555325653257532585325953260532615326253263532645326553266532675326853269532705327153272532735327453275532765327753278532795328053281532825328353284532855328653287532885328953290532915329253293532945329553296532975329853299533005330153302533035330453305533065330753308533095331053311533125331353314533155331653317533185331953320533215332253323533245332553326533275332853329533305333153332533335333453335533365333753338533395334053341533425334353344533455334653347533485334953350533515335253353533545335553356533575335853359533605336153362533635336453365533665336753368533695337053371533725337353374533755337653377533785337953380533815338253383533845338553386533875338853389533905339153392533935339453395533965339753398533995340053401534025340353404534055340653407534085340953410534115341253413534145341553416534175341853419534205342153422534235342453425534265342753428534295343053431534325343353434534355343653437534385343953440534415344253443534445344553446534475344853449534505345153452534535345453455534565345753458534595346053461534625346353464534655346653467534685346953470534715347253473534745347553476534775347853479534805348153482534835348453485534865348753488534895349053491534925349353494534955349653497534985349953500535015350253503535045350553506535075350853509535105351153512535135351453515535165351753518535195352053521535225352353524535255352653527535285352953530535315353253533535345353553536535375353853539535405354153542535435354453545535465354753548535495355053551535525355353554535555355653557535585355953560535615356253563535645356553566535675356853569535705357153572535735357453575535765357753578535795358053581535825358353584535855358653587535885358953590535915359253593535945359553596535975359853599536005360153602536035360453605536065360753608536095361053611536125361353614536155361653617536185361953620536215362253623536245362553626536275362853629536305363153632536335363453635536365363753638536395364053641536425364353644536455364653647536485364953650536515365253653536545365553656536575365853659536605366153662536635366453665536665366753668536695367053671536725367353674536755367653677536785367953680536815368253683536845368553686536875368853689536905369153692536935369453695536965369753698536995370053701537025370353704537055370653707537085370953710537115371253713537145371553716537175371853719537205372153722537235372453725537265372753728537295373053731537325373353734537355373653737537385373953740537415374253743537445374553746537475374853749537505375153752537535375453755537565375753758537595376053761537625376353764537655376653767537685376953770537715377253773537745377553776537775377853779537805378153782537835378453785537865378753788537895379053791537925379353794537955379653797537985379953800538015380253803538045380553806538075380853809538105381153812538135381453815538165381753818538195382053821538225382353824538255382653827538285382953830538315383253833538345383553836538375383853839538405384153842538435384453845538465384753848538495385053851538525385353854538555385653857538585385953860538615386253863538645386553866538675386853869538705387153872538735387453875538765387753878538795388053881538825388353884538855388653887538885388953890538915389253893538945389553896538975389853899539005390153902539035390453905539065390753908539095391053911539125391353914539155391653917539185391953920539215392253923539245392553926539275392853929539305393153932539335393453935539365393753938539395394053941539425394353944539455394653947539485394953950539515395253953539545395553956539575395853959539605396153962539635396453965539665396753968539695397053971539725397353974539755397653977539785397953980539815398253983539845398553986539875398853989539905399153992539935399453995539965399753998539995400054001540025400354004540055400654007540085400954010540115401254013540145401554016540175401854019540205402154022540235402454025540265402754028540295403054031540325403354034540355403654037540385403954040540415404254043540445404554046540475404854049540505405154052540535405454055540565405754058540595406054061540625406354064540655406654067540685406954070540715407254073540745407554076540775407854079540805408154082540835408454085540865408754088540895409054091540925409354094540955409654097540985409954100541015410254103541045410554106541075410854109541105411154112541135411454115541165411754118541195412054121541225412354124541255412654127541285412954130541315413254133541345413554136541375413854139541405414154142541435414454145541465414754148541495415054151541525415354154541555415654157541585415954160541615416254163541645416554166541675416854169541705417154172541735417454175541765417754178541795418054181541825418354184541855418654187541885418954190541915419254193541945419554196541975419854199542005420154202542035420454205542065420754208542095421054211542125421354214542155421654217542185421954220542215422254223542245422554226542275422854229542305423154232542335423454235542365423754238542395424054241542425424354244542455424654247542485424954250542515425254253542545425554256542575425854259542605426154262542635426454265542665426754268542695427054271542725427354274542755427654277542785427954280542815428254283542845428554286542875428854289542905429154292542935429454295542965429754298542995430054301543025430354304543055430654307543085430954310543115431254313543145431554316543175431854319543205432154322543235432454325543265432754328543295433054331543325433354334543355433654337543385433954340543415434254343543445434554346543475434854349543505435154352543535435454355543565435754358543595436054361543625436354364543655436654367543685436954370543715437254373543745437554376543775437854379543805438154382543835438454385543865438754388543895439054391543925439354394543955439654397543985439954400544015440254403544045440554406544075440854409544105441154412544135441454415544165441754418544195442054421544225442354424544255442654427544285442954430544315443254433544345443554436544375443854439544405444154442544435444454445544465444754448544495445054451544525445354454544555445654457544585445954460544615446254463544645446554466544675446854469544705447154472544735447454475544765447754478544795448054481544825448354484544855448654487544885448954490544915449254493544945449554496544975449854499545005450154502545035450454505545065450754508545095451054511545125451354514545155451654517545185451954520545215452254523545245452554526545275452854529545305453154532545335453454535545365453754538545395454054541545425454354544545455454654547545485454954550545515455254553545545455554556545575455854559545605456154562545635456454565545665456754568545695457054571545725457354574545755457654577545785457954580545815458254583545845458554586545875458854589545905459154592545935459454595545965459754598545995460054601546025460354604546055460654607546085460954610546115461254613546145461554616546175461854619546205462154622546235462454625546265462754628546295463054631546325463354634546355463654637546385463954640546415464254643546445464554646546475464854649546505465154652546535465454655546565465754658546595466054661546625466354664546655466654667546685466954670546715467254673546745467554676546775467854679546805468154682546835468454685546865468754688546895469054691546925469354694546955469654697546985469954700547015470254703547045470554706547075470854709547105471154712547135471454715547165471754718547195472054721547225472354724547255472654727547285472954730547315473254733547345473554736547375473854739547405474154742547435474454745547465474754748547495475054751547525475354754547555475654757547585475954760547615476254763547645476554766547675476854769547705477154772547735477454775547765477754778547795478054781547825478354784547855478654787547885478954790547915479254793547945479554796547975479854799548005480154802548035480454805548065480754808548095481054811548125481354814548155481654817548185481954820548215482254823548245482554826548275482854829548305483154832548335483454835548365483754838548395484054841548425484354844548455484654847548485484954850548515485254853548545485554856548575485854859548605486154862548635486454865548665486754868548695487054871548725487354874548755487654877548785487954880548815488254883548845488554886548875488854889548905489154892548935489454895548965489754898548995490054901549025490354904549055490654907549085490954910549115491254913549145491554916549175491854919549205492154922549235492454925549265492754928549295493054931549325493354934549355493654937549385493954940549415494254943549445494554946549475494854949549505495154952549535495454955549565495754958549595496054961549625496354964549655496654967549685496954970549715497254973549745497554976549775497854979549805498154982549835498454985549865498754988549895499054991549925499354994549955499654997549985499955000550015500255003550045500555006550075500855009550105501155012550135501455015550165501755018550195502055021550225502355024550255502655027550285502955030550315503255033550345503555036550375503855039550405504155042550435504455045550465504755048550495505055051550525505355054550555505655057550585505955060550615506255063550645506555066550675506855069550705507155072550735507455075550765507755078550795508055081550825508355084550855508655087550885508955090550915509255093550945509555096550975509855099551005510155102551035510455105551065510755108551095511055111551125511355114551155511655117551185511955120551215512255123551245512555126551275512855129551305513155132551335513455135551365513755138551395514055141551425514355144551455514655147551485514955150551515515255153551545515555156551575515855159551605516155162551635516455165551665516755168551695517055171551725517355174551755517655177551785517955180551815518255183551845518555186551875518855189551905519155192551935519455195551965519755198551995520055201552025520355204552055520655207552085520955210552115521255213552145521555216552175521855219552205522155222552235522455225552265522755228552295523055231552325523355234552355523655237552385523955240552415524255243552445524555246552475524855249552505525155252552535525455255552565525755258552595526055261552625526355264552655526655267552685526955270552715527255273552745527555276552775527855279552805528155282552835528455285552865528755288552895529055291552925529355294552955529655297552985529955300553015530255303553045530555306553075530855309553105531155312553135531455315553165531755318553195532055321553225532355324553255532655327553285532955330553315533255333553345533555336553375533855339553405534155342553435534455345553465534755348553495535055351553525535355354553555535655357553585535955360553615536255363553645536555366553675536855369553705537155372553735537455375553765537755378553795538055381553825538355384553855538655387553885538955390553915539255393553945539555396553975539855399554005540155402554035540455405554065540755408554095541055411554125541355414554155541655417554185541955420554215542255423554245542555426554275542855429554305543155432554335543455435554365543755438554395544055441554425544355444554455544655447554485544955450554515545255453554545545555456554575545855459554605546155462554635546455465554665546755468554695547055471554725547355474554755547655477554785547955480554815548255483554845548555486554875548855489554905549155492554935549455495554965549755498554995550055501555025550355504555055550655507555085550955510555115551255513555145551555516555175551855519555205552155522555235552455525555265552755528555295553055531555325553355534555355553655537555385553955540555415554255543555445554555546555475554855549555505555155552555535555455555555565555755558555595556055561555625556355564555655556655567555685556955570555715557255573555745557555576555775557855579555805558155582555835558455585555865558755588555895559055591555925559355594555955559655597555985559955600556015560255603556045560555606556075560855609556105561155612556135561455615556165561755618556195562055621556225562355624556255562655627556285562955630556315563255633556345563555636556375563855639556405564155642556435564455645556465564755648556495565055651556525565355654556555565655657556585565955660556615566255663556645566555666556675566855669556705567155672556735567455675556765567755678556795568055681556825568355684556855568655687556885568955690556915569255693556945569555696556975569855699557005570155702557035570455705557065570755708557095571055711557125571355714557155571655717557185571955720557215572255723557245572555726557275572855729557305573155732557335573455735557365573755738557395574055741557425574355744557455574655747557485574955750557515575255753557545575555756557575575855759557605576155762557635576455765557665576755768557695577055771557725577355774557755577655777557785577955780557815578255783557845578555786557875578855789557905579155792557935579455795557965579755798557995580055801558025580355804558055580655807558085580955810558115581255813558145581555816558175581855819558205582155822558235582455825558265582755828558295583055831558325583355834558355583655837558385583955840558415584255843558445584555846558475584855849558505585155852558535585455855558565585755858558595586055861558625586355864558655586655867558685586955870558715587255873558745587555876558775587855879558805588155882558835588455885558865588755888558895589055891558925589355894558955589655897558985589955900559015590255903559045590555906559075590855909559105591155912559135591455915559165591755918559195592055921559225592355924559255592655927559285592955930559315593255933559345593555936559375593855939559405594155942559435594455945559465594755948559495595055951559525595355954559555595655957559585595955960559615596255963559645596555966559675596855969559705597155972559735597455975559765597755978559795598055981559825598355984559855598655987559885598955990559915599255993559945599555996559975599855999560005600156002560035600456005560065600756008560095601056011560125601356014560155601656017560185601956020560215602256023560245602556026560275602856029560305603156032560335603456035560365603756038560395604056041560425604356044560455604656047560485604956050560515605256053560545605556056560575605856059560605606156062560635606456065560665606756068560695607056071560725607356074560755607656077560785607956080560815608256083560845608556086560875608856089560905609156092560935609456095560965609756098560995610056101561025610356104561055610656107561085610956110561115611256113561145611556116561175611856119561205612156122561235612456125561265612756128561295613056131561325613356134561355613656137561385613956140561415614256143561445614556146561475614856149561505615156152561535615456155561565615756158561595616056161561625616356164561655616656167561685616956170561715617256173561745617556176561775617856179561805618156182561835618456185561865618756188561895619056191561925619356194561955619656197561985619956200562015620256203562045620556206562075620856209562105621156212562135621456215562165621756218562195622056221562225622356224562255622656227562285622956230562315623256233562345623556236562375623856239562405624156242562435624456245562465624756248562495625056251562525625356254562555625656257562585625956260562615626256263562645626556266562675626856269562705627156272562735627456275562765627756278562795628056281562825628356284562855628656287562885628956290562915629256293562945629556296562975629856299563005630156302563035630456305563065630756308563095631056311563125631356314563155631656317563185631956320563215632256323563245632556326563275632856329563305633156332563335633456335563365633756338563395634056341563425634356344563455634656347563485634956350563515635256353563545635556356563575635856359563605636156362563635636456365563665636756368563695637056371563725637356374563755637656377563785637956380563815638256383563845638556386563875638856389563905639156392563935639456395563965639756398563995640056401564025640356404564055640656407564085640956410564115641256413564145641556416564175641856419564205642156422564235642456425564265642756428564295643056431564325643356434564355643656437564385643956440564415644256443564445644556446564475644856449564505645156452564535645456455564565645756458564595646056461564625646356464564655646656467564685646956470564715647256473564745647556476564775647856479564805648156482564835648456485564865648756488564895649056491564925649356494564955649656497564985649956500565015650256503565045650556506565075650856509565105651156512565135651456515565165651756518565195652056521565225652356524565255652656527565285652956530565315653256533565345653556536565375653856539565405654156542565435654456545565465654756548565495655056551565525655356554565555655656557565585655956560565615656256563565645656556566565675656856569565705657156572565735657456575565765657756578565795658056581565825658356584565855658656587565885658956590565915659256593565945659556596565975659856599566005660156602566035660456605566065660756608566095661056611566125661356614566155661656617566185661956620566215662256623566245662556626566275662856629566305663156632566335663456635566365663756638566395664056641566425664356644566455664656647566485664956650566515665256653566545665556656566575665856659566605666156662566635666456665566665666756668566695667056671566725667356674566755667656677566785667956680566815668256683566845668556686566875668856689566905669156692566935669456695566965669756698566995670056701567025670356704567055670656707567085670956710567115671256713567145671556716567175671856719567205672156722567235672456725567265672756728567295673056731567325673356734567355673656737567385673956740567415674256743567445674556746567475674856749567505675156752567535675456755567565675756758567595676056761567625676356764567655676656767567685676956770567715677256773567745677556776567775677856779567805678156782567835678456785567865678756788567895679056791567925679356794567955679656797567985679956800568015680256803568045680556806568075680856809568105681156812568135681456815568165681756818568195682056821568225682356824568255682656827568285682956830568315683256833568345683556836568375683856839568405684156842568435684456845568465684756848568495685056851568525685356854568555685656857568585685956860568615686256863568645686556866568675686856869568705687156872568735687456875568765687756878568795688056881568825688356884568855688656887568885688956890568915689256893568945689556896568975689856899569005690156902569035690456905569065690756908569095691056911569125691356914569155691656917569185691956920569215692256923569245692556926569275692856929569305693156932569335693456935569365693756938569395694056941569425694356944569455694656947569485694956950569515695256953569545695556956569575695856959569605696156962569635696456965569665696756968569695697056971569725697356974569755697656977569785697956980569815698256983569845698556986569875698856989569905699156992569935699456995569965699756998569995700057001570025700357004570055700657007570085700957010570115701257013570145701557016570175701857019570205702157022570235702457025570265702757028570295703057031570325703357034570355703657037570385703957040570415704257043570445704557046570475704857049570505705157052570535705457055570565705757058570595706057061570625706357064570655706657067570685706957070570715707257073570745707557076570775707857079570805708157082570835708457085570865708757088570895709057091570925709357094570955709657097570985709957100571015710257103571045710557106571075710857109571105711157112571135711457115571165711757118571195712057121571225712357124571255712657127571285712957130571315713257133571345713557136571375713857139571405714157142571435714457145571465714757148571495715057151571525715357154571555715657157571585715957160571615716257163571645716557166571675716857169571705717157172571735717457175571765717757178571795718057181571825718357184571855718657187571885718957190571915719257193571945719557196571975719857199572005720157202572035720457205572065720757208572095721057211572125721357214572155721657217572185721957220572215722257223572245722557226572275722857229572305723157232572335723457235572365723757238572395724057241572425724357244572455724657247572485724957250572515725257253572545725557256572575725857259572605726157262572635726457265572665726757268572695727057271572725727357274572755727657277572785727957280572815728257283572845728557286572875728857289572905729157292572935729457295572965729757298572995730057301573025730357304573055730657307573085730957310573115731257313573145731557316573175731857319573205732157322573235732457325573265732757328573295733057331573325733357334573355733657337573385733957340573415734257343573445734557346573475734857349573505735157352573535735457355573565735757358573595736057361573625736357364573655736657367573685736957370573715737257373573745737557376573775737857379573805738157382573835738457385573865738757388573895739057391573925739357394573955739657397573985739957400574015740257403574045740557406574075740857409574105741157412574135741457415574165741757418574195742057421574225742357424574255742657427574285742957430574315743257433574345743557436574375743857439574405744157442574435744457445574465744757448574495745057451574525745357454574555745657457574585745957460574615746257463574645746557466574675746857469574705747157472574735747457475574765747757478574795748057481574825748357484574855748657487574885748957490574915749257493574945749557496574975749857499575005750157502575035750457505575065750757508575095751057511575125751357514575155751657517575185751957520575215752257523575245752557526575275752857529575305753157532575335753457535575365753757538575395754057541575425754357544575455754657547575485754957550575515755257553575545755557556575575755857559575605756157562575635756457565575665756757568575695757057571575725757357574575755757657577575785757957580575815758257583575845758557586575875758857589575905759157592575935759457595575965759757598575995760057601576025760357604576055760657607576085760957610576115761257613576145761557616576175761857619576205762157622576235762457625576265762757628576295763057631576325763357634576355763657637576385763957640576415764257643576445764557646576475764857649576505765157652576535765457655576565765757658576595766057661576625766357664576655766657667576685766957670576715767257673576745767557676576775767857679576805768157682576835768457685576865768757688576895769057691576925769357694576955769657697576985769957700577015770257703577045770557706577075770857709577105771157712577135771457715577165771757718577195772057721577225772357724577255772657727577285772957730577315773257733577345773557736577375773857739577405774157742577435774457745577465774757748577495775057751577525775357754577555775657757577585775957760577615776257763577645776557766577675776857769577705777157772577735777457775577765777757778577795778057781577825778357784577855778657787577885778957790577915779257793577945779557796577975779857799578005780157802578035780457805578065780757808578095781057811578125781357814578155781657817578185781957820578215782257823578245782557826578275782857829578305783157832578335783457835578365783757838578395784057841578425784357844578455784657847578485784957850578515785257853578545785557856578575785857859578605786157862578635786457865578665786757868578695787057871578725787357874578755787657877578785787957880578815788257883578845788557886578875788857889578905789157892578935789457895578965789757898578995790057901579025790357904579055790657907579085790957910579115791257913579145791557916579175791857919579205792157922579235792457925579265792757928579295793057931579325793357934579355793657937579385793957940579415794257943579445794557946579475794857949579505795157952579535795457955579565795757958579595796057961579625796357964579655796657967579685796957970579715797257973579745797557976579775797857979579805798157982579835798457985579865798757988579895799057991579925799357994579955799657997579985799958000580015800258003580045800558006580075800858009580105801158012580135801458015580165801758018580195802058021580225802358024580255802658027580285802958030580315803258033580345803558036580375803858039580405804158042580435804458045580465804758048580495805058051580525805358054580555805658057580585805958060580615806258063580645806558066580675806858069580705807158072580735807458075580765807758078580795808058081580825808358084580855808658087580885808958090580915809258093580945809558096580975809858099581005810158102581035810458105581065810758108581095811058111581125811358114581155811658117581185811958120581215812258123581245812558126581275812858129581305813158132581335813458135581365813758138581395814058141581425814358144581455814658147581485814958150581515815258153581545815558156581575815858159581605816158162581635816458165581665816758168581695817058171581725817358174581755817658177581785817958180581815818258183581845818558186581875818858189581905819158192581935819458195581965819758198581995820058201582025820358204582055820658207582085820958210582115821258213582145821558216582175821858219582205822158222582235822458225582265822758228582295823058231582325823358234582355823658237582385823958240582415824258243582445824558246582475824858249582505825158252582535825458255582565825758258582595826058261582625826358264582655826658267582685826958270582715827258273582745827558276582775827858279582805828158282582835828458285582865828758288582895829058291582925829358294582955829658297582985829958300583015830258303583045830558306583075830858309583105831158312583135831458315583165831758318583195832058321583225832358324583255832658327583285832958330583315833258333583345833558336583375833858339583405834158342583435834458345583465834758348583495835058351583525835358354583555835658357583585835958360583615836258363583645836558366583675836858369583705837158372583735837458375583765837758378583795838058381583825838358384583855838658387583885838958390583915839258393583945839558396583975839858399584005840158402584035840458405584065840758408584095841058411584125841358414584155841658417584185841958420584215842258423584245842558426584275842858429584305843158432584335843458435584365843758438584395844058441584425844358444584455844658447584485844958450584515845258453584545845558456584575845858459584605846158462584635846458465584665846758468584695847058471584725847358474584755847658477584785847958480584815848258483584845848558486584875848858489584905849158492584935849458495584965849758498584995850058501585025850358504585055850658507585085850958510585115851258513585145851558516585175851858519585205852158522585235852458525585265852758528585295853058531585325853358534585355853658537585385853958540585415854258543585445854558546585475854858549585505855158552585535855458555585565855758558585595856058561585625856358564585655856658567585685856958570585715857258573585745857558576585775857858579585805858158582585835858458585585865858758588585895859058591585925859358594585955859658597585985859958600586015860258603586045860558606586075860858609586105861158612586135861458615586165861758618586195862058621586225862358624586255862658627586285862958630586315863258633586345863558636586375863858639586405864158642586435864458645586465864758648586495865058651586525865358654586555865658657586585865958660586615866258663586645866558666586675866858669586705867158672586735867458675586765867758678586795868058681586825868358684586855868658687586885868958690586915869258693586945869558696586975869858699587005870158702587035870458705587065870758708587095871058711587125871358714587155871658717587185871958720587215872258723587245872558726587275872858729587305873158732587335873458735587365873758738587395874058741587425874358744587455874658747587485874958750587515875258753587545875558756587575875858759587605876158762587635876458765587665876758768587695877058771587725877358774587755877658777587785877958780587815878258783587845878558786587875878858789587905879158792587935879458795587965879758798587995880058801588025880358804588055880658807588085880958810588115881258813588145881558816588175881858819588205882158822588235882458825588265882758828588295883058831588325883358834588355883658837588385883958840588415884258843588445884558846588475884858849588505885158852588535885458855588565885758858588595886058861588625886358864588655886658867588685886958870588715887258873588745887558876588775887858879588805888158882588835888458885588865888758888588895889058891588925889358894588955889658897588985889958900589015890258903589045890558906589075890858909589105891158912589135891458915589165891758918589195892058921589225892358924589255892658927589285892958930589315893258933589345893558936589375893858939589405894158942589435894458945589465894758948589495895058951589525895358954589555895658957589585895958960589615896258963589645896558966589675896858969589705897158972589735897458975589765897758978589795898058981589825898358984589855898658987589885898958990589915899258993589945899558996589975899858999590005900159002590035900459005590065900759008590095901059011590125901359014590155901659017590185901959020590215902259023590245902559026590275902859029590305903159032590335903459035590365903759038590395904059041590425904359044590455904659047590485904959050590515905259053590545905559056590575905859059590605906159062590635906459065590665906759068590695907059071590725907359074590755907659077590785907959080590815908259083590845908559086590875908859089590905909159092590935909459095590965909759098590995910059101591025910359104591055910659107591085910959110591115911259113591145911559116591175911859119591205912159122591235912459125591265912759128591295913059131591325913359134591355913659137591385913959140591415914259143591445914559146591475914859149591505915159152591535915459155591565915759158591595916059161591625916359164591655916659167591685916959170591715917259173591745917559176591775917859179591805918159182591835918459185591865918759188591895919059191591925919359194591955919659197591985919959200592015920259203592045920559206592075920859209592105921159212592135921459215592165921759218592195922059221592225922359224592255922659227592285922959230592315923259233592345923559236592375923859239592405924159242592435924459245592465924759248592495925059251592525925359254592555925659257592585925959260592615926259263592645926559266592675926859269592705927159272592735927459275592765927759278592795928059281592825928359284592855928659287592885928959290592915929259293592945929559296592975929859299593005930159302593035930459305593065930759308593095931059311593125931359314593155931659317593185931959320593215932259323593245932559326593275932859329593305933159332593335933459335593365933759338593395934059341593425934359344593455934659347593485934959350593515935259353593545935559356593575935859359593605936159362593635936459365593665936759368593695937059371593725937359374593755937659377593785937959380593815938259383593845938559386593875938859389593905939159392593935939459395593965939759398593995940059401594025940359404594055940659407594085940959410594115941259413594145941559416594175941859419594205942159422594235942459425594265942759428594295943059431594325943359434594355943659437594385943959440594415944259443594445944559446594475944859449594505945159452594535945459455594565945759458594595946059461594625946359464594655946659467594685946959470594715947259473594745947559476594775947859479594805948159482594835948459485594865948759488594895949059491594925949359494594955949659497594985949959500595015950259503595045950559506595075950859509595105951159512595135951459515595165951759518595195952059521595225952359524595255952659527595285952959530595315953259533595345953559536595375953859539595405954159542595435954459545595465954759548595495955059551595525955359554595555955659557595585955959560595615956259563595645956559566595675956859569595705957159572595735957459575595765957759578595795958059581595825958359584595855958659587595885958959590595915959259593595945959559596595975959859599596005960159602596035960459605596065960759608596095961059611596125961359614596155961659617596185961959620596215962259623596245962559626596275962859629596305963159632596335963459635596365963759638596395964059641596425964359644596455964659647596485964959650596515965259653596545965559656596575965859659596605966159662596635966459665596665966759668596695967059671596725967359674596755967659677596785967959680596815968259683596845968559686596875968859689596905969159692596935969459695596965969759698596995970059701597025970359704597055970659707597085970959710597115971259713597145971559716597175971859719597205972159722597235972459725597265972759728597295973059731597325973359734597355973659737597385973959740597415974259743597445974559746597475974859749597505975159752597535975459755597565975759758597595976059761597625976359764597655976659767597685976959770597715977259773597745977559776597775977859779597805978159782597835978459785597865978759788597895979059791597925979359794597955979659797597985979959800598015980259803598045980559806598075980859809598105981159812598135981459815598165981759818598195982059821598225982359824598255982659827598285982959830598315983259833598345983559836598375983859839598405984159842598435984459845598465984759848598495985059851598525985359854598555985659857598585985959860598615986259863598645986559866598675986859869598705987159872598735987459875598765987759878598795988059881598825988359884598855988659887598885988959890598915989259893598945989559896598975989859899599005990159902599035990459905599065990759908599095991059911599125991359914599155991659917599185991959920599215992259923599245992559926599275992859929599305993159932599335993459935599365993759938599395994059941599425994359944599455994659947599485994959950599515995259953599545995559956599575995859959599605996159962599635996459965599665996759968599695997059971599725997359974599755997659977599785997959980599815998259983599845998559986599875998859989599905999159992599935999459995599965999759998599996000060001600026000360004600056000660007600086000960010600116001260013600146001560016600176001860019600206002160022600236002460025600266002760028600296003060031600326003360034600356003660037600386003960040600416004260043600446004560046600476004860049600506005160052600536005460055600566005760058600596006060061600626006360064600656006660067600686006960070600716007260073600746007560076600776007860079600806008160082600836008460085600866008760088600896009060091600926009360094600956009660097600986009960100601016010260103601046010560106601076010860109601106011160112601136011460115601166011760118601196012060121601226012360124601256012660127601286012960130601316013260133601346013560136601376013860139601406014160142601436014460145601466014760148601496015060151601526015360154601556015660157601586015960160601616016260163601646016560166601676016860169601706017160172601736017460175601766017760178601796018060181601826018360184601856018660187601886018960190601916019260193601946019560196601976019860199602006020160202602036020460205602066020760208602096021060211602126021360214602156021660217602186021960220602216022260223602246022560226602276022860229602306023160232602336023460235602366023760238602396024060241602426024360244602456024660247602486024960250602516025260253602546025560256602576025860259602606026160262602636026460265602666026760268602696027060271602726027360274602756027660277602786027960280602816028260283602846028560286602876028860289602906029160292602936029460295602966029760298602996030060301603026030360304603056030660307603086030960310603116031260313603146031560316603176031860319603206032160322603236032460325603266032760328603296033060331603326033360334603356033660337603386033960340603416034260343603446034560346603476034860349603506035160352603536035460355603566035760358603596036060361603626036360364603656036660367603686036960370603716037260373603746037560376603776037860379603806038160382603836038460385603866038760388603896039060391603926039360394603956039660397603986039960400604016040260403604046040560406604076040860409604106041160412604136041460415604166041760418604196042060421604226042360424604256042660427604286042960430604316043260433604346043560436604376043860439604406044160442604436044460445604466044760448604496045060451604526045360454604556045660457604586045960460604616046260463604646046560466604676046860469604706047160472604736047460475604766047760478604796048060481604826048360484604856048660487604886048960490604916049260493604946049560496604976049860499605006050160502605036050460505605066050760508605096051060511605126051360514605156051660517605186051960520605216052260523605246052560526605276052860529605306053160532605336053460535605366053760538605396054060541605426054360544605456054660547605486054960550605516055260553605546055560556605576055860559605606056160562605636056460565605666056760568605696057060571605726057360574605756057660577605786057960580605816058260583605846058560586605876058860589605906059160592605936059460595605966059760598605996060060601606026060360604606056060660607606086060960610606116061260613606146061560616606176061860619606206062160622606236062460625606266062760628606296063060631606326063360634606356063660637606386063960640606416064260643606446064560646606476064860649606506065160652606536065460655606566065760658606596066060661606626066360664606656066660667606686066960670606716067260673606746067560676606776067860679606806068160682606836068460685606866068760688606896069060691606926069360694606956069660697606986069960700607016070260703
  1. /**
  2. * vis.js
  3. * https://github.com/almende/vis
  4. *
  5. * A dynamic, browser-based visualization library.
  6. *
  7. * @version 4.21.0
  8. * @date 2017-10-12
  9. *
  10. * @license
  11. * Copyright (C) 2011-2017 Almende B.V, http://almende.com
  12. *
  13. * Vis.js is dual licensed under both
  14. *
  15. * * The Apache 2.0 License
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * and
  19. *
  20. * * The MIT License
  21. * http://opensource.org/licenses/MIT
  22. *
  23. * Vis.js may be distributed under either license.
  24. */
  25. "use strict";
  26. (function webpackUniversalModuleDefinition(root, factory) {
  27. if (typeof exports === 'object' && typeof module === 'object')
  28. module.exports = factory();
  29. else if (typeof define === 'function' && define.amd)
  30. define([], factory);
  31. else if (typeof exports === 'object')
  32. exports["vis"] = factory();
  33. else
  34. root["vis"] = factory();
  35. })(this, function() {
  36. return /******/ (function(modules) { // webpackBootstrap
  37. /******/ // The module cache
  38. /******/
  39. var installedModules = {};
  40. /******/
  41. /******/ // The require function
  42. /******/
  43. function __webpack_require__(moduleId) {
  44. /******/
  45. /******/ // Check if module is in cache
  46. /******/
  47. if (installedModules[moduleId]) {
  48. /******/
  49. return installedModules[moduleId].exports;
  50. /******/
  51. }
  52. /******/ // Create a new module (and put it into the cache)
  53. /******/
  54. var module = installedModules[moduleId] = {
  55. /******/
  56. i: moduleId,
  57. /******/
  58. l: false,
  59. /******/
  60. exports: {}
  61. /******/
  62. };
  63. /******/
  64. /******/ // Execute the module function
  65. /******/
  66. modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  67. /******/
  68. /******/ // Flag the module as loaded
  69. /******/
  70. module.l = true;
  71. /******/
  72. /******/ // Return the exports of the module
  73. /******/
  74. return module.exports;
  75. /******/
  76. }
  77. /******/
  78. /******/
  79. /******/ // expose the modules object (__webpack_modules__)
  80. /******/
  81. __webpack_require__.m = modules;
  82. /******/
  83. /******/ // expose the module cache
  84. /******/
  85. __webpack_require__.c = installedModules;
  86. /******/
  87. /******/ // define getter function for harmony exports
  88. /******/
  89. __webpack_require__.d = function(exports, name, getter) {
  90. /******/
  91. if (!__webpack_require__.o(exports, name)) {
  92. /******/
  93. Object.defineProperty(exports, name, {
  94. /******/
  95. configurable: false,
  96. /******/
  97. enumerable: true,
  98. /******/
  99. get: getter
  100. /******/
  101. });
  102. /******/
  103. }
  104. /******/
  105. };
  106. /******/
  107. /******/ // getDefaultExport function for compatibility with non-harmony modules
  108. /******/
  109. __webpack_require__.n = function(module) {
  110. /******/
  111. var getter = module && module.__esModule ?
  112. /******/
  113. function getDefault() { return module['default']; } :
  114. /******/
  115. function getModuleExports() { return module; };
  116. /******/
  117. __webpack_require__.d(getter, 'a', getter);
  118. /******/
  119. return getter;
  120. /******/
  121. };
  122. /******/
  123. /******/ // Object.prototype.hasOwnProperty.call
  124. /******/
  125. __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
  126. /******/
  127. /******/ // __webpack_public_path__
  128. /******/
  129. __webpack_require__.p = "";
  130. /******/
  131. /******/ // Load entry module and return exports
  132. /******/
  133. return __webpack_require__(__webpack_require__.s = 123);
  134. /******/
  135. })
  136. /************************************************************************/
  137. /******/
  138. ([
  139. /* 0 */
  140. /***/
  141. (function(module, exports, __webpack_require__) {
  142. "use strict";
  143. exports.__esModule = true;
  144. exports.default = function(instance, Constructor) {
  145. if (!(instance instanceof Constructor)) {
  146. throw new TypeError("Cannot call a class as a function");
  147. }
  148. };
  149. /***/
  150. }),
  151. /* 1 */
  152. /***/
  153. (function(module, exports, __webpack_require__) {
  154. "use strict";
  155. exports.__esModule = true;
  156. var _defineProperty = __webpack_require__(169);
  157. var _defineProperty2 = _interopRequireDefault(_defineProperty);
  158. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  159. exports.default = function() {
  160. function defineProperties(target, props) {
  161. for (var i = 0; i < props.length; i++) {
  162. var descriptor = props[i];
  163. descriptor.enumerable = descriptor.enumerable || false;
  164. descriptor.configurable = true;
  165. if ("value" in descriptor) descriptor.writable = true;
  166. (0, _defineProperty2.default)(target, descriptor.key, descriptor);
  167. }
  168. }
  169. return function(Constructor, protoProps, staticProps) {
  170. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  171. if (staticProps) defineProperties(Constructor, staticProps);
  172. return Constructor;
  173. };
  174. }();
  175. /***/
  176. }),
  177. /* 2 */
  178. /***/
  179. (function(module, exports, __webpack_require__) {
  180. "use strict";
  181. var _getIterator2 = __webpack_require__(77);
  182. var _getIterator3 = _interopRequireDefault(_getIterator2);
  183. var _create = __webpack_require__(29);
  184. var _create2 = _interopRequireDefault(_create);
  185. var _keys = __webpack_require__(8);
  186. var _keys2 = _interopRequireDefault(_keys);
  187. var _typeof2 = __webpack_require__(6);
  188. var _typeof3 = _interopRequireDefault(_typeof2);
  189. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  190. // utility functions
  191. // first check if moment.js is already loaded in the browser window, if so,
  192. // use this instance. Else, load via commonjs.
  193. var moment = __webpack_require__(9);
  194. var uuid = __webpack_require__(157);
  195. /**
  196. * Test whether given object is a number
  197. * @param {*} object
  198. * @return {Boolean} isNumber
  199. */
  200. exports.isNumber = function(object) {
  201. return object instanceof Number || typeof object == 'number';
  202. };
  203. /**
  204. * Remove everything in the DOM object
  205. * @param {Element} DOMobject
  206. */
  207. exports.recursiveDOMDelete = function(DOMobject) {
  208. if (DOMobject) {
  209. while (DOMobject.hasChildNodes() === true) {
  210. exports.recursiveDOMDelete(DOMobject.firstChild);
  211. DOMobject.removeChild(DOMobject.firstChild);
  212. }
  213. }
  214. };
  215. /**
  216. * this function gives you a range between 0 and 1 based on the min and max values in the set, the total sum of all values and the current value.
  217. *
  218. * @param {number} min
  219. * @param {number} max
  220. * @param {number} total
  221. * @param {number} value
  222. * @returns {number}
  223. */
  224. exports.giveRange = function(min, max, total, value) {
  225. if (max == min) {
  226. return 0.5;
  227. } else {
  228. var scale = 1 / (max - min);
  229. return Math.max(0, (value - min) * scale);
  230. }
  231. };
  232. /**
  233. * Test whether given object is a string
  234. * @param {*} object
  235. * @return {Boolean} isString
  236. */
  237. exports.isString = function(object) {
  238. return object instanceof String || typeof object == 'string';
  239. };
  240. /**
  241. * Test whether given object is a Date, or a String containing a Date
  242. * @param {Date | String} object
  243. * @return {Boolean} isDate
  244. */
  245. exports.isDate = function(object) {
  246. if (object instanceof Date) {
  247. return true;
  248. } else if (exports.isString(object)) {
  249. // test whether this string contains a date
  250. var match = ASPDateRegex.exec(object);
  251. if (match) {
  252. return true;
  253. } else if (!isNaN(Date.parse(object))) {
  254. return true;
  255. }
  256. }
  257. return false;
  258. };
  259. /**
  260. * Create a semi UUID
  261. * source: http://stackoverflow.com/a/105074/1262753
  262. * @return {string} uuid
  263. */
  264. exports.randomUUID = function() {
  265. return uuid.v4();
  266. };
  267. /**
  268. * assign all keys of an object that are not nested objects to a certain value (used for color objects).
  269. * @param {object} obj
  270. * @param {number} value
  271. */
  272. exports.assignAllKeys = function(obj, value) {
  273. for (var prop in obj) {
  274. if (obj.hasOwnProperty(prop)) {
  275. if ((0, _typeof3['default'])(obj[prop]) !== 'object') {
  276. obj[prop] = value;
  277. }
  278. }
  279. }
  280. };
  281. /**
  282. * Copy property from b to a if property present in a.
  283. * If property in b explicitly set to null, delete it if `allowDeletion` set.
  284. *
  285. * Internal helper routine, should not be exported. Not added to `exports` for that reason.
  286. *
  287. * @param {object} a target object
  288. * @param {object} b source object
  289. * @param {string} prop name of property to copy to a
  290. * @param {boolean} allowDeletion if true, delete property in a if explicitly set to null in b
  291. * @private
  292. */
  293. function copyOrDelete(a, b, prop, allowDeletion) {
  294. var doDeletion = false;
  295. if (allowDeletion === true) {
  296. doDeletion = b[prop] === null && a[prop] !== undefined;
  297. }
  298. if (doDeletion) {
  299. delete a[prop];
  300. } else {
  301. a[prop] = b[prop]; // Remember, this is a reference copy!
  302. }
  303. }
  304. /**
  305. * Fill an object with a possibly partially defined other object.
  306. *
  307. * Only copies values for the properties already present in a.
  308. * That means an object is not created on a property if only the b object has it.
  309. *
  310. * @param {object} a
  311. * @param {object} b
  312. * @param {boolean} [allowDeletion=false] if true, delete properties in a that are explicitly set to null in b
  313. */
  314. exports.fillIfDefined = function(a, b) {
  315. var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  316. // NOTE: iteration of properties of a
  317. // NOTE: prototype properties iterated over as well
  318. for (var prop in a) {
  319. if (b[prop] !== undefined) {
  320. if (b[prop] === null || (0, _typeof3['default'])(b[prop]) !== 'object') {
  321. // Note: typeof null === 'object'
  322. copyOrDelete(a, b, prop, allowDeletion);
  323. } else {
  324. if ((0, _typeof3['default'])(a[prop]) === 'object') {
  325. exports.fillIfDefined(a[prop], b[prop], allowDeletion);
  326. }
  327. }
  328. }
  329. }
  330. };
  331. /**
  332. * Extend object a with the properties of object b or a series of objects
  333. * Only properties with defined values are copied
  334. * @param {Object} a
  335. * @param {...Object} b
  336. * @return {Object} a
  337. */
  338. exports.extend = function(a, b) {
  339. // eslint-disable-line no-unused-vars
  340. for (var i = 1; i < arguments.length; i++) {
  341. var other = arguments[i];
  342. for (var prop in other) {
  343. if (other.hasOwnProperty(prop)) {
  344. a[prop] = other[prop];
  345. }
  346. }
  347. }
  348. return a;
  349. };
  350. /**
  351. * Extend object a with selected properties of object b or a series of objects
  352. * Only properties with defined values are copied
  353. * @param {Array.<string>} props
  354. * @param {Object} a
  355. * @param {Object} b
  356. * @return {Object} a
  357. */
  358. exports.selectiveExtend = function(props, a, b) {
  359. // eslint-disable-line no-unused-vars
  360. if (!Array.isArray(props)) {
  361. throw new Error('Array with property names expected as first argument');
  362. }
  363. for (var i = 2; i < arguments.length; i++) {
  364. var other = arguments[i];
  365. for (var p = 0; p < props.length; p++) {
  366. var prop = props[p];
  367. if (other && other.hasOwnProperty(prop)) {
  368. a[prop] = other[prop];
  369. }
  370. }
  371. }
  372. return a;
  373. };
  374. /**
  375. * Extend object a with selected properties of object b.
  376. * Only properties with defined values are copied.
  377. *
  378. * **Note:** Previous version of this routine implied that multiple source objects
  379. * could be used; however, the implementation was **wrong**.
  380. * Since multiple (>1) sources weren't used anywhere in the `vis.js` code,
  381. * this has been removed
  382. *
  383. * @param {Array.<string>} props names of first-level properties to copy over
  384. * @param {object} a target object
  385. * @param {object} b source object
  386. * @param {boolean} [allowDeletion=false] if true, delete property in a if explicitly set to null in b
  387. * @returns {Object} a
  388. */
  389. exports.selectiveDeepExtend = function(props, a, b) {
  390. var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
  391. // TODO: add support for Arrays to deepExtend
  392. if (Array.isArray(b)) {
  393. throw new TypeError('Arrays are not supported by deepExtend');
  394. }
  395. for (var p = 0; p < props.length; p++) {
  396. var prop = props[p];
  397. if (b.hasOwnProperty(prop)) {
  398. if (b[prop] && b[prop].constructor === Object) {
  399. if (a[prop] === undefined) {
  400. a[prop] = {};
  401. }
  402. if (a[prop].constructor === Object) {
  403. exports.deepExtend(a[prop], b[prop], false, allowDeletion);
  404. } else {
  405. copyOrDelete(a, b, prop, allowDeletion);
  406. }
  407. } else if (Array.isArray(b[prop])) {
  408. throw new TypeError('Arrays are not supported by deepExtend');
  409. } else {
  410. copyOrDelete(a, b, prop, allowDeletion);
  411. }
  412. }
  413. }
  414. return a;
  415. };
  416. /**
  417. * Extend object `a` with properties of object `b`, ignoring properties which are explicitly
  418. * specified to be excluded.
  419. *
  420. * The properties of `b` are considered for copying.
  421. * Properties which are themselves objects are are also extended.
  422. * Only properties with defined values are copied
  423. *
  424. * @param {Array.<string>} propsToExclude names of properties which should *not* be copied
  425. * @param {Object} a object to extend
  426. * @param {Object} b object to take properties from for extension
  427. * @param {boolean} [allowDeletion=false] if true, delete properties in a that are explicitly set to null in b
  428. * @return {Object} a
  429. */
  430. exports.selectiveNotDeepExtend = function(propsToExclude, a, b) {
  431. var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
  432. // TODO: add support for Arrays to deepExtend
  433. // NOTE: array properties have an else-below; apparently, there is a problem here.
  434. if (Array.isArray(b)) {
  435. throw new TypeError('Arrays are not supported by deepExtend');
  436. }
  437. for (var prop in b) {
  438. if (!b.hasOwnProperty(prop)) continue; // Handle local properties only
  439. if (propsToExclude.indexOf(prop) !== -1) continue; // In exclusion list, skip
  440. if (b[prop] && b[prop].constructor === Object) {
  441. if (a[prop] === undefined) {
  442. a[prop] = {};
  443. }
  444. if (a[prop].constructor === Object) {
  445. exports.deepExtend(a[prop], b[prop]); // NOTE: allowDeletion not propagated!
  446. } else {
  447. copyOrDelete(a, b, prop, allowDeletion);
  448. }
  449. } else if (Array.isArray(b[prop])) {
  450. a[prop] = [];
  451. for (var i = 0; i < b[prop].length; i++) {
  452. a[prop].push(b[prop][i]);
  453. }
  454. } else {
  455. copyOrDelete(a, b, prop, allowDeletion);
  456. }
  457. }
  458. return a;
  459. };
  460. /**
  461. * Deep extend an object a with the properties of object b
  462. *
  463. * @param {Object} a
  464. * @param {Object} b
  465. * @param {boolean} [protoExtend=false] If true, the prototype values will also be extended.
  466. * (ie. the options objects that inherit from others will also get the inherited options)
  467. * @param {boolean} [allowDeletion=false] If true, the values of fields that are null will be deleted
  468. * @returns {Object}
  469. */
  470. exports.deepExtend = function(a, b) {
  471. var protoExtend = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  472. var allowDeletion = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
  473. for (var prop in b) {
  474. if (b.hasOwnProperty(prop) || protoExtend === true) {
  475. if (b[prop] && b[prop].constructor === Object) {
  476. if (a[prop] === undefined) {
  477. a[prop] = {};
  478. }
  479. if (a[prop].constructor === Object) {
  480. exports.deepExtend(a[prop], b[prop], protoExtend); // NOTE: allowDeletion not propagated!
  481. } else {
  482. copyOrDelete(a, b, prop, allowDeletion);
  483. }
  484. } else if (Array.isArray(b[prop])) {
  485. a[prop] = [];
  486. for (var i = 0; i < b[prop].length; i++) {
  487. a[prop].push(b[prop][i]);
  488. }
  489. } else {
  490. copyOrDelete(a, b, prop, allowDeletion);
  491. }
  492. }
  493. }
  494. return a;
  495. };
  496. /**
  497. * Test whether all elements in two arrays are equal.
  498. * @param {Array} a
  499. * @param {Array} b
  500. * @return {boolean} Returns true if both arrays have the same length and same
  501. * elements.
  502. */
  503. exports.equalArray = function(a, b) {
  504. if (a.length != b.length) return false;
  505. for (var i = 0, len = a.length; i < len; i++) {
  506. if (a[i] != b[i]) return false;
  507. }
  508. return true;
  509. };
  510. /**
  511. * Convert an object to another type
  512. * @param {boolean | number | string | Date | Moment | Null | undefined} object
  513. * @param {string | undefined} type Name of the type. Available types:
  514. * 'Boolean', 'Number', 'String',
  515. * 'Date', 'Moment', ISODate', 'ASPDate'.
  516. * @return {*} object
  517. * @throws Error
  518. */
  519. exports.convert = function(object, type) {
  520. var match;
  521. if (object === undefined) {
  522. return undefined;
  523. }
  524. if (object === null) {
  525. return null;
  526. }
  527. if (!type) {
  528. return object;
  529. }
  530. if (!(typeof type === 'string') && !(type instanceof String)) {
  531. throw new Error('Type must be a string');
  532. }
  533. //noinspection FallthroughInSwitchStatementJS
  534. switch (type) {
  535. case 'boolean':
  536. case 'Boolean':
  537. return Boolean(object);
  538. case 'number':
  539. case 'Number':
  540. if (exports.isString(object) && !isNaN(Date.parse(object))) {
  541. return moment(object).valueOf();
  542. } else {
  543. return Number(object.valueOf());
  544. }
  545. case 'string':
  546. case 'String':
  547. return String(object);
  548. case 'Date':
  549. if (exports.isNumber(object)) {
  550. return new Date(object);
  551. }
  552. if (object instanceof Date) {
  553. return new Date(object.valueOf());
  554. } else if (moment.isMoment(object)) {
  555. return new Date(object.valueOf());
  556. }
  557. if (exports.isString(object)) {
  558. match = ASPDateRegex.exec(object);
  559. if (match) {
  560. // object is an ASP date
  561. return new Date(Number(match[1])); // parse number
  562. } else {
  563. return moment(new Date(object)).toDate(); // parse string
  564. }
  565. } else {
  566. throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type Date');
  567. }
  568. case 'Moment':
  569. if (exports.isNumber(object)) {
  570. return moment(object);
  571. }
  572. if (object instanceof Date) {
  573. return moment(object.valueOf());
  574. } else if (moment.isMoment(object)) {
  575. return moment(object);
  576. }
  577. if (exports.isString(object)) {
  578. match = ASPDateRegex.exec(object);
  579. if (match) {
  580. // object is an ASP date
  581. return moment(Number(match[1])); // parse number
  582. } else {
  583. return moment(object); // parse string
  584. }
  585. } else {
  586. throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type Date');
  587. }
  588. case 'ISODate':
  589. if (exports.isNumber(object)) {
  590. return new Date(object);
  591. } else if (object instanceof Date) {
  592. return object.toISOString();
  593. } else if (moment.isMoment(object)) {
  594. return object.toDate().toISOString();
  595. } else if (exports.isString(object)) {
  596. match = ASPDateRegex.exec(object);
  597. if (match) {
  598. // object is an ASP date
  599. return new Date(Number(match[1])).toISOString(); // parse number
  600. } else {
  601. return moment(object).format(); // ISO 8601
  602. }
  603. } else {
  604. throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type ISODate');
  605. }
  606. case 'ASPDate':
  607. if (exports.isNumber(object)) {
  608. return '/Date(' + object + ')/';
  609. } else if (object instanceof Date) {
  610. return '/Date(' + object.valueOf() + ')/';
  611. } else if (exports.isString(object)) {
  612. match = ASPDateRegex.exec(object);
  613. var value;
  614. if (match) {
  615. // object is an ASP date
  616. value = new Date(Number(match[1])).valueOf(); // parse number
  617. } else {
  618. value = new Date(object).valueOf(); // parse string
  619. }
  620. return '/Date(' + value + ')/';
  621. } else {
  622. throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type ASPDate');
  623. }
  624. default:
  625. throw new Error('Unknown type "' + type + '"');
  626. }
  627. };
  628. // parse ASP.Net Date pattern,
  629. // for example '/Date(1198908717056)/' or '/Date(1198908717056-0700)/'
  630. // code from http://momentjs.com/
  631. var ASPDateRegex = /^\/?Date\((\-?\d+)/i;
  632. /**
  633. * Get the type of an object, for example exports.getType([]) returns 'Array'
  634. * @param {*} object
  635. * @return {string} type
  636. */
  637. exports.getType = function(object) {
  638. var type = typeof object === 'undefined' ? 'undefined' : (0, _typeof3['default'])(object);
  639. if (type == 'object') {
  640. if (object === null) {
  641. return 'null';
  642. }
  643. if (object instanceof Boolean) {
  644. return 'Boolean';
  645. }
  646. if (object instanceof Number) {
  647. return 'Number';
  648. }
  649. if (object instanceof String) {
  650. return 'String';
  651. }
  652. if (Array.isArray(object)) {
  653. return 'Array';
  654. }
  655. if (object instanceof Date) {
  656. return 'Date';
  657. }
  658. return 'Object';
  659. } else if (type == 'number') {
  660. return 'Number';
  661. } else if (type == 'boolean') {
  662. return 'Boolean';
  663. } else if (type == 'string') {
  664. return 'String';
  665. } else if (type === undefined) {
  666. return 'undefined';
  667. }
  668. return type;
  669. };
  670. /**
  671. * Used to extend an array and copy it. This is used to propagate paths recursively.
  672. *
  673. * @param {Array} arr
  674. * @param {*} newValue
  675. * @returns {Array}
  676. */
  677. exports.copyAndExtendArray = function(arr, newValue) {
  678. var newArr = [];
  679. for (var i = 0; i < arr.length; i++) {
  680. newArr.push(arr[i]);
  681. }
  682. newArr.push(newValue);
  683. return newArr;
  684. };
  685. /**
  686. * Used to extend an array and copy it. This is used to propagate paths recursively.
  687. *
  688. * @param {Array} arr
  689. * @returns {Array}
  690. */
  691. exports.copyArray = function(arr) {
  692. var newArr = [];
  693. for (var i = 0; i < arr.length; i++) {
  694. newArr.push(arr[i]);
  695. }
  696. return newArr;
  697. };
  698. /**
  699. * Retrieve the absolute left value of a DOM element
  700. * @param {Element} elem A dom element, for example a div
  701. * @return {number} left The absolute left position of this element
  702. * in the browser page.
  703. */
  704. exports.getAbsoluteLeft = function(elem) {
  705. return elem.getBoundingClientRect().left;
  706. };
  707. exports.getAbsoluteRight = function(elem) {
  708. return elem.getBoundingClientRect().right;
  709. };
  710. /**
  711. * Retrieve the absolute top value of a DOM element
  712. * @param {Element} elem A dom element, for example a div
  713. * @return {number} top The absolute top position of this element
  714. * in the browser page.
  715. */
  716. exports.getAbsoluteTop = function(elem) {
  717. return elem.getBoundingClientRect().top;
  718. };
  719. /**
  720. * add a className to the given elements style
  721. * @param {Element} elem
  722. * @param {string} classNames
  723. */
  724. exports.addClassName = function(elem, classNames) {
  725. var classes = elem.className.split(' ');
  726. var newClasses = classNames.split(' ');
  727. classes = classes.concat(newClasses.filter(function(className) {
  728. return classes.indexOf(className) < 0;
  729. }));
  730. elem.className = classes.join(' ');
  731. };
  732. /**
  733. * add a className to the given elements style
  734. * @param {Element} elem
  735. * @param {string} classNames
  736. */
  737. exports.removeClassName = function(elem, classNames) {
  738. var classes = elem.className.split(' ');
  739. var oldClasses = classNames.split(' ');
  740. classes = classes.filter(function(className) {
  741. return oldClasses.indexOf(className) < 0;
  742. });
  743. elem.className = classes.join(' ');
  744. };
  745. /**
  746. * For each method for both arrays and objects.
  747. * In case of an array, the built-in Array.forEach() is applied. (**No, it's not!**)
  748. * In case of an Object, the method loops over all properties of the object.
  749. * @param {Object | Array} object An Object or Array
  750. * @param {function} callback Callback method, called for each item in
  751. * the object or array with three parameters:
  752. * callback(value, index, object)
  753. */
  754. exports.forEach = function(object, callback) {
  755. var i, len;
  756. if (Array.isArray(object)) {
  757. // array
  758. for (i = 0, len = object.length; i < len; i++) {
  759. callback(object[i], i, object);
  760. }
  761. } else {
  762. // object
  763. for (i in object) {
  764. if (object.hasOwnProperty(i)) {
  765. callback(object[i], i, object);
  766. }
  767. }
  768. }
  769. };
  770. /**
  771. * Convert an object into an array: all objects properties are put into the
  772. * array. The resulting array is unordered.
  773. * @param {Object} object
  774. * @returns {Array} array
  775. */
  776. exports.toArray = function(object) {
  777. var array = [];
  778. for (var prop in object) {
  779. if (object.hasOwnProperty(prop)) array.push(object[prop]);
  780. }
  781. return array;
  782. };
  783. /**
  784. * Update a property in an object
  785. * @param {Object} object
  786. * @param {string} key
  787. * @param {*} value
  788. * @return {Boolean} changed
  789. */
  790. exports.updateProperty = function(object, key, value) {
  791. if (object[key] !== value) {
  792. object[key] = value;
  793. return true;
  794. } else {
  795. return false;
  796. }
  797. };
  798. /**
  799. * Throttle the given function to be only executed once per animation frame
  800. * @param {function} fn
  801. * @returns {function} Returns the throttled function
  802. */
  803. exports.throttle = function(fn) {
  804. var scheduled = false;
  805. return function throttled() {
  806. if (!scheduled) {
  807. scheduled = true;
  808. requestAnimationFrame(function() {
  809. scheduled = false;
  810. fn();
  811. });
  812. }
  813. };
  814. };
  815. /**
  816. * Add and event listener. Works for all browsers
  817. * @param {Element} element An html element
  818. * @param {string} action The action, for example "click",
  819. * without the prefix "on"
  820. * @param {function} listener The callback function to be executed
  821. * @param {boolean} [useCapture]
  822. */
  823. exports.addEventListener = function(element, action, listener, useCapture) {
  824. if (element.addEventListener) {
  825. if (useCapture === undefined) useCapture = false;
  826. if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
  827. action = "DOMMouseScroll"; // For Firefox
  828. }
  829. element.addEventListener(action, listener, useCapture);
  830. } else {
  831. element.attachEvent("on" + action, listener); // IE browsers
  832. }
  833. };
  834. /**
  835. * Remove an event listener from an element
  836. * @param {Element} element An html dom element
  837. * @param {string} action The name of the event, for example "mousedown"
  838. * @param {function} listener The listener function
  839. * @param {boolean} [useCapture]
  840. */
  841. exports.removeEventListener = function(element, action, listener, useCapture) {
  842. if (element.removeEventListener) {
  843. // non-IE browsers
  844. if (useCapture === undefined) useCapture = false;
  845. if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) {
  846. action = "DOMMouseScroll"; // For Firefox
  847. }
  848. element.removeEventListener(action, listener, useCapture);
  849. } else {
  850. // IE browsers
  851. element.detachEvent("on" + action, listener);
  852. }
  853. };
  854. /**
  855. * Cancels the event if it is cancelable, without stopping further propagation of the event.
  856. * @param {Event} event
  857. */
  858. exports.preventDefault = function(event) {
  859. if (!event) event = window.event;
  860. if (event.preventDefault) {
  861. event.preventDefault(); // non-IE browsers
  862. } else {
  863. event.returnValue = false; // IE browsers
  864. }
  865. };
  866. /**
  867. * Get HTML element which is the target of the event
  868. * @param {Event} event
  869. * @return {Element} target element
  870. */
  871. exports.getTarget = function(event) {
  872. // code from http://www.quirksmode.org/js/events_properties.html
  873. if (!event) {
  874. event = window.event;
  875. }
  876. var target;
  877. if (event.target) {
  878. target = event.target;
  879. } else if (event.srcElement) {
  880. target = event.srcElement;
  881. }
  882. if (target.nodeType != undefined && target.nodeType == 3) {
  883. // defeat Safari bug
  884. target = target.parentNode;
  885. }
  886. return target;
  887. };
  888. /**
  889. * Check if given element contains given parent somewhere in the DOM tree
  890. * @param {Element} element
  891. * @param {Element} parent
  892. * @returns {boolean}
  893. */
  894. exports.hasParent = function(element, parent) {
  895. var e = element;
  896. while (e) {
  897. if (e === parent) {
  898. return true;
  899. }
  900. e = e.parentNode;
  901. }
  902. return false;
  903. };
  904. exports.option = {};
  905. /**
  906. * Convert a value into a boolean
  907. * @param {Boolean | function | undefined} value
  908. * @param {boolean} [defaultValue]
  909. * @returns {Boolean} bool
  910. */
  911. exports.option.asBoolean = function(value, defaultValue) {
  912. if (typeof value == 'function') {
  913. value = value();
  914. }
  915. if (value != null) {
  916. return value != false;
  917. }
  918. return defaultValue || null;
  919. };
  920. /**
  921. * Convert a value into a number
  922. * @param {Boolean | function | undefined} value
  923. * @param {number} [defaultValue]
  924. * @returns {number} number
  925. */
  926. exports.option.asNumber = function(value, defaultValue) {
  927. if (typeof value == 'function') {
  928. value = value();
  929. }
  930. if (value != null) {
  931. return Number(value) || defaultValue || null;
  932. }
  933. return defaultValue || null;
  934. };
  935. /**
  936. * Convert a value into a string
  937. * @param {string | function | undefined} value
  938. * @param {string} [defaultValue]
  939. * @returns {String} str
  940. */
  941. exports.option.asString = function(value, defaultValue) {
  942. if (typeof value == 'function') {
  943. value = value();
  944. }
  945. if (value != null) {
  946. return String(value);
  947. }
  948. return defaultValue || null;
  949. };
  950. /**
  951. * Convert a size or location into a string with pixels or a percentage
  952. * @param {string | number | function | undefined} value
  953. * @param {string} [defaultValue]
  954. * @returns {String} size
  955. */
  956. exports.option.asSize = function(value, defaultValue) {
  957. if (typeof value == 'function') {
  958. value = value();
  959. }
  960. if (exports.isString(value)) {
  961. return value;
  962. } else if (exports.isNumber(value)) {
  963. return value + 'px';
  964. } else {
  965. return defaultValue || null;
  966. }
  967. };
  968. /**
  969. * Convert a value into a DOM element
  970. * @param {HTMLElement | function | undefined} value
  971. * @param {HTMLElement} [defaultValue]
  972. * @returns {HTMLElement | null} dom
  973. */
  974. exports.option.asElement = function(value, defaultValue) {
  975. if (typeof value == 'function') {
  976. value = value();
  977. }
  978. return value || defaultValue || null;
  979. };
  980. /**
  981. * http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
  982. *
  983. * @param {string} hex
  984. * @returns {{r: *, g: *, b: *}} | 255 range
  985. */
  986. exports.hexToRGB = function(hex) {
  987. // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
  988. var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  989. hex = hex.replace(shorthandRegex, function(m, r, g, b) {
  990. return r + r + g + g + b + b;
  991. });
  992. var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  993. return result ? {
  994. r: parseInt(result[1], 16),
  995. g: parseInt(result[2], 16),
  996. b: parseInt(result[3], 16)
  997. } : null;
  998. };
  999. /**
  1000. * This function takes color in hex format or rgb() or rgba() format and overrides the opacity. Returns rgba() string.
  1001. * @param {string} color
  1002. * @param {number} opacity
  1003. * @returns {String}
  1004. */
  1005. exports.overrideOpacity = function(color, opacity) {
  1006. var rgb;
  1007. if (color.indexOf("rgba") != -1) {
  1008. return color;
  1009. } else if (color.indexOf("rgb") != -1) {
  1010. rgb = color.substr(color.indexOf("(") + 1).replace(")", "").split(",");
  1011. return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + opacity + ")";
  1012. } else {
  1013. rgb = exports.hexToRGB(color);
  1014. if (rgb == null) {
  1015. return color;
  1016. } else {
  1017. return "rgba(" + rgb.r + "," + rgb.g + "," + rgb.b + "," + opacity + ")";
  1018. }
  1019. }
  1020. };
  1021. /**
  1022. *
  1023. * @param {number} red 0 -- 255
  1024. * @param {number} green 0 -- 255
  1025. * @param {number} blue 0 -- 255
  1026. * @returns {String}
  1027. * @constructor
  1028. */
  1029. exports.RGBToHex = function(red, green, blue) {
  1030. return "#" + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1);
  1031. };
  1032. /**
  1033. * Parse a color property into an object with border, background, and
  1034. * highlight colors
  1035. * @param {Object | String} color
  1036. * @return {Object} colorObject
  1037. */
  1038. exports.parseColor = function(color) {
  1039. var c;
  1040. if (exports.isString(color) === true) {
  1041. if (exports.isValidRGB(color) === true) {
  1042. var rgb = color.substr(4).substr(0, color.length - 5).split(',').map(function(value) {
  1043. return parseInt(value);
  1044. });
  1045. color = exports.RGBToHex(rgb[0], rgb[1], rgb[2]);
  1046. }
  1047. if (exports.isValidHex(color) === true) {
  1048. var hsv = exports.hexToHSV(color);
  1049. var lighterColorHSV = { h: hsv.h, s: hsv.s * 0.8, v: Math.min(1, hsv.v * 1.02) };
  1050. var darkerColorHSV = { h: hsv.h, s: Math.min(1, hsv.s * 1.25), v: hsv.v * 0.8 };
  1051. var darkerColorHex = exports.HSVToHex(darkerColorHSV.h, darkerColorHSV.s, darkerColorHSV.v);
  1052. var lighterColorHex = exports.HSVToHex(lighterColorHSV.h, lighterColorHSV.s, lighterColorHSV.v);
  1053. c = {
  1054. background: color,
  1055. border: darkerColorHex,
  1056. highlight: {
  1057. background: lighterColorHex,
  1058. border: darkerColorHex
  1059. },
  1060. hover: {
  1061. background: lighterColorHex,
  1062. border: darkerColorHex
  1063. }
  1064. };
  1065. } else {
  1066. c = {
  1067. background: color,
  1068. border: color,
  1069. highlight: {
  1070. background: color,
  1071. border: color
  1072. },
  1073. hover: {
  1074. background: color,
  1075. border: color
  1076. }
  1077. };
  1078. }
  1079. } else {
  1080. c = {};
  1081. c.background = color.background || undefined;
  1082. c.border = color.border || undefined;
  1083. if (exports.isString(color.highlight)) {
  1084. c.highlight = {
  1085. border: color.highlight,
  1086. background: color.highlight
  1087. };
  1088. } else {
  1089. c.highlight = {};
  1090. c.highlight.background = color.highlight && color.highlight.background || undefined;
  1091. c.highlight.border = color.highlight && color.highlight.border || undefined;
  1092. }
  1093. if (exports.isString(color.hover)) {
  1094. c.hover = {
  1095. border: color.hover,
  1096. background: color.hover
  1097. };
  1098. } else {
  1099. c.hover = {};
  1100. c.hover.background = color.hover && color.hover.background || undefined;
  1101. c.hover.border = color.hover && color.hover.border || undefined;
  1102. }
  1103. }
  1104. return c;
  1105. };
  1106. /**
  1107. * http://www.javascripter.net/faq/rgb2hsv.htm
  1108. *
  1109. * @param {number} red
  1110. * @param {number} green
  1111. * @param {number} blue
  1112. * @returns {{h: number, s: number, v: number}}
  1113. * @constructor
  1114. */
  1115. exports.RGBToHSV = function(red, green, blue) {
  1116. red = red / 255;
  1117. green = green / 255;
  1118. blue = blue / 255;
  1119. var minRGB = Math.min(red, Math.min(green, blue));
  1120. var maxRGB = Math.max(red, Math.max(green, blue));
  1121. // Black-gray-white
  1122. if (minRGB == maxRGB) {
  1123. return { h: 0, s: 0, v: minRGB };
  1124. }
  1125. // Colors other than black-gray-white:
  1126. var d = red == minRGB ? green - blue : blue == minRGB ? red - green : blue - red;
  1127. var h = red == minRGB ? 3 : blue == minRGB ? 1 : 5;
  1128. var hue = 60 * (h - d / (maxRGB - minRGB)) / 360;
  1129. var saturation = (maxRGB - minRGB) / maxRGB;
  1130. var value = maxRGB;
  1131. return { h: hue, s: saturation, v: value };
  1132. };
  1133. var cssUtil = {
  1134. // split a string with css styles into an object with key/values
  1135. split: function split(cssText) {
  1136. var styles = {};
  1137. cssText.split(';').forEach(function(style) {
  1138. if (style.trim() != '') {
  1139. var parts = style.split(':');
  1140. var key = parts[0].trim();
  1141. var value = parts[1].trim();
  1142. styles[key] = value;
  1143. }
  1144. });
  1145. return styles;
  1146. },
  1147. // build a css text string from an object with key/values
  1148. join: function join(styles) {
  1149. return (0, _keys2['default'])(styles).map(function(key) {
  1150. return key + ': ' + styles[key];
  1151. }).join('; ');
  1152. }
  1153. };
  1154. /**
  1155. * Append a string with css styles to an element
  1156. * @param {Element} element
  1157. * @param {string} cssText
  1158. */
  1159. exports.addCssText = function(element, cssText) {
  1160. var currentStyles = cssUtil.split(element.style.cssText);
  1161. var newStyles = cssUtil.split(cssText);
  1162. var styles = exports.extend(currentStyles, newStyles);
  1163. element.style.cssText = cssUtil.join(styles);
  1164. };
  1165. /**
  1166. * Remove a string with css styles from an element
  1167. * @param {Element} element
  1168. * @param {string} cssText
  1169. */
  1170. exports.removeCssText = function(element, cssText) {
  1171. var styles = cssUtil.split(element.style.cssText);
  1172. var removeStyles = cssUtil.split(cssText);
  1173. for (var key in removeStyles) {
  1174. if (removeStyles.hasOwnProperty(key)) {
  1175. delete styles[key];
  1176. }
  1177. }
  1178. element.style.cssText = cssUtil.join(styles);
  1179. };
  1180. /**
  1181. * https://gist.github.com/mjijackson/5311256
  1182. * @param {number} h
  1183. * @param {number} s
  1184. * @param {number} v
  1185. * @returns {{r: number, g: number, b: number}}
  1186. * @constructor
  1187. */
  1188. exports.HSVToRGB = function(h, s, v) {
  1189. var r, g, b;
  1190. var i = Math.floor(h * 6);
  1191. var f = h * 6 - i;
  1192. var p = v * (1 - s);
  1193. var q = v * (1 - f * s);
  1194. var t = v * (1 - (1 - f) * s);
  1195. switch (i % 6) {
  1196. case 0:
  1197. r = v, g = t, b = p;
  1198. break;
  1199. case 1:
  1200. r = q, g = v, b = p;
  1201. break;
  1202. case 2:
  1203. r = p, g = v, b = t;
  1204. break;
  1205. case 3:
  1206. r = p, g = q, b = v;
  1207. break;
  1208. case 4:
  1209. r = t, g = p, b = v;
  1210. break;
  1211. case 5:
  1212. r = v, g = p, b = q;
  1213. break;
  1214. }
  1215. return { r: Math.floor(r * 255), g: Math.floor(g * 255), b: Math.floor(b * 255) };
  1216. };
  1217. exports.HSVToHex = function(h, s, v) {
  1218. var rgb = exports.HSVToRGB(h, s, v);
  1219. return exports.RGBToHex(rgb.r, rgb.g, rgb.b);
  1220. };
  1221. exports.hexToHSV = function(hex) {
  1222. var rgb = exports.hexToRGB(hex);
  1223. return exports.RGBToHSV(rgb.r, rgb.g, rgb.b);
  1224. };
  1225. exports.isValidHex = function(hex) {
  1226. var isOk = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex);
  1227. return isOk;
  1228. };
  1229. exports.isValidRGB = function(rgb) {
  1230. rgb = rgb.replace(" ", "");
  1231. var isOk = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/i.test(rgb);
  1232. return isOk;
  1233. };
  1234. exports.isValidRGBA = function(rgba) {
  1235. rgba = rgba.replace(" ", "");
  1236. var isOk = /rgba\((\d{1,3}),(\d{1,3}),(\d{1,3}),(.{1,3})\)/i.test(rgba);
  1237. return isOk;
  1238. };
  1239. /**
  1240. * This recursively redirects the prototype of JSON objects to the referenceObject
  1241. * This is used for default options.
  1242. *
  1243. * @param {Array.<string>} fields
  1244. * @param {Object} referenceObject
  1245. * @returns {*}
  1246. */
  1247. exports.selectiveBridgeObject = function(fields, referenceObject) {
  1248. if (referenceObject !== null && (typeof referenceObject === 'undefined' ? 'undefined' : (0, _typeof3['default'])(referenceObject)) === "object") {
  1249. // !!! typeof null === 'object'
  1250. var objectTo = (0, _create2['default'])(referenceObject);
  1251. for (var i = 0; i < fields.length; i++) {
  1252. if (referenceObject.hasOwnProperty(fields[i])) {
  1253. if ((0, _typeof3['default'])(referenceObject[fields[i]]) == "object") {
  1254. objectTo[fields[i]] = exports.bridgeObject(referenceObject[fields[i]]);
  1255. }
  1256. }
  1257. }
  1258. return objectTo;
  1259. } else {
  1260. return null;
  1261. }
  1262. };
  1263. /**
  1264. * This recursively redirects the prototype of JSON objects to the referenceObject
  1265. * This is used for default options.
  1266. *
  1267. * @param {Object} referenceObject
  1268. * @returns {*}
  1269. */
  1270. exports.bridgeObject = function(referenceObject) {
  1271. if (referenceObject !== null && (typeof referenceObject === 'undefined' ? 'undefined' : (0, _typeof3['default'])(referenceObject)) === "object") {
  1272. // !!! typeof null === 'object'
  1273. var objectTo = (0, _create2['default'])(referenceObject);
  1274. if (referenceObject instanceof Element) {
  1275. // Avoid bridging DOM objects
  1276. objectTo = referenceObject;
  1277. } else {
  1278. objectTo = (0, _create2['default'])(referenceObject);
  1279. for (var i in referenceObject) {
  1280. if (referenceObject.hasOwnProperty(i)) {
  1281. if ((0, _typeof3['default'])(referenceObject[i]) == "object") {
  1282. objectTo[i] = exports.bridgeObject(referenceObject[i]);
  1283. }
  1284. }
  1285. }
  1286. }
  1287. return objectTo;
  1288. } else {
  1289. return null;
  1290. }
  1291. };
  1292. /**
  1293. * This method provides a stable sort implementation, very fast for presorted data
  1294. *
  1295. * @param {Array} a the array
  1296. * @param {function} compare an order comparator
  1297. * @returns {Array}
  1298. */
  1299. exports.insertSort = function(a, compare) {
  1300. for (var i = 0; i < a.length; i++) {
  1301. var k = a[i];
  1302. for (var j = i; j > 0 && compare(k, a[j - 1]) < 0; j--) {
  1303. a[j] = a[j - 1];
  1304. }
  1305. a[j] = k;
  1306. }
  1307. return a;
  1308. };
  1309. /**
  1310. * This is used to set the options of subobjects in the options object.
  1311. *
  1312. * A requirement of these subobjects is that they have an 'enabled' element
  1313. * which is optional for the user but mandatory for the program.
  1314. *
  1315. * The added value here of the merge is that option 'enabled' is set as required.
  1316. *
  1317. *
  1318. * @param {object} mergeTarget | either this.options or the options used for the groups.
  1319. * @param {object} options | options
  1320. * @param {string} option | option key in the options argument
  1321. * @param {object} globalOptions | global options, passed in to determine value of option 'enabled'
  1322. */
  1323. exports.mergeOptions = function(mergeTarget, options, option) {
  1324. var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
  1325. // Local helpers
  1326. var isPresent = function isPresent(obj) {
  1327. return obj !== null && obj !== undefined;
  1328. };
  1329. var isObject = function isObject(obj) {
  1330. return obj !== null && (typeof obj === 'undefined' ? 'undefined' : (0, _typeof3['default'])(obj)) === 'object';
  1331. };
  1332. // https://stackoverflow.com/a/34491287/1223531
  1333. var isEmpty = function isEmpty(obj) {
  1334. for (var x in obj) {
  1335. if (obj.hasOwnProperty(x)) return false;
  1336. }
  1337. return true;
  1338. };
  1339. // Guards
  1340. if (!isObject(mergeTarget)) {
  1341. throw new Error('Parameter mergeTarget must be an object');
  1342. }
  1343. if (!isObject(options)) {
  1344. throw new Error('Parameter options must be an object');
  1345. }
  1346. if (!isPresent(option)) {
  1347. throw new Error('Parameter option must have a value');
  1348. }
  1349. if (!isObject(globalOptions)) {
  1350. throw new Error('Parameter globalOptions must be an object');
  1351. }
  1352. //
  1353. // Actual merge routine, separated from main logic
  1354. // Only a single level of options is merged. Deeper levels are ref'd. This may actually be an issue.
  1355. //
  1356. var doMerge = function doMerge(target, options, option) {
  1357. if (!isObject(target[option])) {
  1358. target[option] = {};
  1359. }
  1360. var src = options[option];
  1361. var dst = target[option];
  1362. for (var prop in src) {
  1363. if (src.hasOwnProperty(prop)) {
  1364. dst[prop] = src[prop];
  1365. }
  1366. }
  1367. };
  1368. // Local initialization
  1369. var srcOption = options[option];
  1370. var globalPassed = isObject(globalOptions) && !isEmpty(globalOptions);
  1371. var globalOption = globalPassed ? globalOptions[option] : undefined;
  1372. var globalEnabled = globalOption ? globalOption.enabled : undefined;
  1373. /////////////////////////////////////////
  1374. // Main routine
  1375. /////////////////////////////////////////
  1376. if (srcOption === undefined) {
  1377. return; // Nothing to do
  1378. }
  1379. if (typeof srcOption === 'boolean') {
  1380. if (!isObject(mergeTarget[option])) {
  1381. mergeTarget[option] = {};
  1382. }
  1383. mergeTarget[option].enabled = srcOption;
  1384. return;
  1385. }
  1386. if (srcOption === null && !isObject(mergeTarget[option])) {
  1387. // If possible, explicit copy from globals
  1388. if (isPresent(globalOption)) {
  1389. mergeTarget[option] = (0, _create2['default'])(globalOption);
  1390. } else {
  1391. return; // Nothing to do
  1392. }
  1393. }
  1394. if (!isObject(srcOption)) {
  1395. return;
  1396. }
  1397. //
  1398. // Ensure that 'enabled' is properly set. It is required internally
  1399. // Note that the value from options will always overwrite the existing value
  1400. //
  1401. var enabled = true; // default value
  1402. if (srcOption.enabled !== undefined) {
  1403. enabled = srcOption.enabled;
  1404. } else {
  1405. // Take from globals, if present
  1406. if (globalEnabled !== undefined) {
  1407. enabled = globalOption.enabled;
  1408. }
  1409. }
  1410. doMerge(mergeTarget, options, option);
  1411. mergeTarget[option].enabled = enabled;
  1412. };
  1413. /**
  1414. * This function does a binary search for a visible item in a sorted list. If we find a visible item, the code that uses
  1415. * this function will then iterate in both directions over this sorted list to find all visible items.
  1416. *
  1417. * @param {Item[]} orderedItems | Items ordered by start
  1418. * @param {function} comparator | -1 is lower, 0 is equal, 1 is higher
  1419. * @param {string} field
  1420. * @param {string} field2
  1421. * @returns {number}
  1422. * @private
  1423. */
  1424. exports.binarySearchCustom = function(orderedItems, comparator, field, field2) {
  1425. var maxIterations = 10000;
  1426. var iteration = 0;
  1427. var low = 0;
  1428. var high = orderedItems.length - 1;
  1429. while (low <= high && iteration < maxIterations) {
  1430. var middle = Math.floor((low + high) / 2);
  1431. var item = orderedItems[middle];
  1432. var value = field2 === undefined ? item[field] : item[field][field2];
  1433. var searchResult = comparator(value);
  1434. if (searchResult == 0) {
  1435. // jihaa, found a visible item!
  1436. return middle;
  1437. } else if (searchResult == -1) {
  1438. // it is too small --> increase low
  1439. low = middle + 1;
  1440. } else {
  1441. // it is too big --> decrease high
  1442. high = middle - 1;
  1443. }
  1444. iteration++;
  1445. }
  1446. return -1;
  1447. };
  1448. /**
  1449. * This function does a binary search for a specific value in a sorted array. If it does not exist but is in between of
  1450. * two values, we return either the one before or the one after, depending on user input
  1451. * If it is found, we return the index, else -1.
  1452. *
  1453. * @param {Array} orderedItems
  1454. * @param {{start: number, end: number}} target
  1455. * @param {string} field
  1456. * @param {string} sidePreference 'before' or 'after'
  1457. * @param {function} comparator an optional comparator, returning -1,0,1 for <,==,>.
  1458. * @returns {number}
  1459. * @private
  1460. */
  1461. exports.binarySearchValue = function(orderedItems, target, field, sidePreference, comparator) {
  1462. var maxIterations = 10000;
  1463. var iteration = 0;
  1464. var low = 0;
  1465. var high = orderedItems.length - 1;
  1466. var prevValue, value, nextValue, middle;
  1467. comparator = comparator != undefined ? comparator : function(a, b) {
  1468. return a == b ? 0 : a < b ? -1 : 1;
  1469. };
  1470. while (low <= high && iteration < maxIterations) {
  1471. // get a new guess
  1472. middle = Math.floor(0.5 * (high + low));
  1473. prevValue = orderedItems[Math.max(0, middle - 1)][field];
  1474. value = orderedItems[middle][field];
  1475. nextValue = orderedItems[Math.min(orderedItems.length - 1, middle + 1)][field];
  1476. if (comparator(value, target) == 0) {
  1477. // we found the target
  1478. return middle;
  1479. } else if (comparator(prevValue, target) < 0 && comparator(value, target) > 0) {
  1480. // target is in between of the previous and the current
  1481. return sidePreference == 'before' ? Math.max(0, middle - 1) : middle;
  1482. } else if (comparator(value, target) < 0 && comparator(nextValue, target) > 0) {
  1483. // target is in between of the current and the next
  1484. return sidePreference == 'before' ? middle : Math.min(orderedItems.length - 1, middle + 1);
  1485. } else {
  1486. // didnt find the target, we need to change our boundaries.
  1487. if (comparator(value, target) < 0) {
  1488. // it is too small --> increase low
  1489. low = middle + 1;
  1490. } else {
  1491. // it is too big --> decrease high
  1492. high = middle - 1;
  1493. }
  1494. }
  1495. iteration++;
  1496. }
  1497. // didnt find anything. Return -1.
  1498. return -1;
  1499. };
  1500. /*
  1501. * Easing Functions - inspired from http://gizma.com/easing/
  1502. * only considering the t value for the range [0, 1] => [0, 1]
  1503. * https://gist.github.com/gre/1650294
  1504. */
  1505. exports.easingFunctions = {
  1506. // no easing, no acceleration
  1507. linear: function linear(t) {
  1508. return t;
  1509. },
  1510. // accelerating from zero velocity
  1511. easeInQuad: function easeInQuad(t) {
  1512. return t * t;
  1513. },
  1514. // decelerating to zero velocity
  1515. easeOutQuad: function easeOutQuad(t) {
  1516. return t * (2 - t);
  1517. },
  1518. // acceleration until halfway, then deceleration
  1519. easeInOutQuad: function easeInOutQuad(t) {
  1520. return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
  1521. },
  1522. // accelerating from zero velocity
  1523. easeInCubic: function easeInCubic(t) {
  1524. return t * t * t;
  1525. },
  1526. // decelerating to zero velocity
  1527. easeOutCubic: function easeOutCubic(t) {
  1528. return --t * t * t + 1;
  1529. },
  1530. // acceleration until halfway, then deceleration
  1531. easeInOutCubic: function easeInOutCubic(t) {
  1532. return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
  1533. },
  1534. // accelerating from zero velocity
  1535. easeInQuart: function easeInQuart(t) {
  1536. return t * t * t * t;
  1537. },
  1538. // decelerating to zero velocity
  1539. easeOutQuart: function easeOutQuart(t) {
  1540. return 1 - --t * t * t * t;
  1541. },
  1542. // acceleration until halfway, then deceleration
  1543. easeInOutQuart: function easeInOutQuart(t) {
  1544. return t < .5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
  1545. },
  1546. // accelerating from zero velocity
  1547. easeInQuint: function easeInQuint(t) {
  1548. return t * t * t * t * t;
  1549. },
  1550. // decelerating to zero velocity
  1551. easeOutQuint: function easeOutQuint(t) {
  1552. return 1 + --t * t * t * t * t;
  1553. },
  1554. // acceleration until halfway, then deceleration
  1555. easeInOutQuint: function easeInOutQuint(t) {
  1556. return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
  1557. }
  1558. };
  1559. exports.getScrollBarWidth = function() {
  1560. var inner = document.createElement('p');
  1561. inner.style.width = "100%";
  1562. inner.style.height = "200px";
  1563. var outer = document.createElement('div');
  1564. outer.style.position = "absolute";
  1565. outer.style.top = "0px";
  1566. outer.style.left = "0px";
  1567. outer.style.visibility = "hidden";
  1568. outer.style.width = "200px";
  1569. outer.style.height = "150px";
  1570. outer.style.overflow = "hidden";
  1571. outer.appendChild(inner);
  1572. document.body.appendChild(outer);
  1573. var w1 = inner.offsetWidth;
  1574. outer.style.overflow = 'scroll';
  1575. var w2 = inner.offsetWidth;
  1576. if (w1 == w2) w2 = outer.clientWidth;
  1577. document.body.removeChild(outer);
  1578. return w1 - w2;
  1579. };
  1580. exports.topMost = function(pile, accessors) {
  1581. var candidate = void 0;
  1582. if (!Array.isArray(accessors)) {
  1583. accessors = [accessors];
  1584. }
  1585. var _iteratorNormalCompletion = true;
  1586. var _didIteratorError = false;
  1587. var _iteratorError = undefined;
  1588. try {
  1589. for (var _iterator = (0, _getIterator3['default'])(pile), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
  1590. var member = _step.value;
  1591. if (member) {
  1592. candidate = member[accessors[0]];
  1593. for (var i = 1; i < accessors.length; i++) {
  1594. if (candidate) {
  1595. candidate = candidate[accessors[i]];
  1596. } else {
  1597. continue;
  1598. }
  1599. }
  1600. if (typeof candidate != 'undefined') {
  1601. break;
  1602. }
  1603. }
  1604. }
  1605. } catch (err) {
  1606. _didIteratorError = true;
  1607. _iteratorError = err;
  1608. } finally {
  1609. try {
  1610. if (!_iteratorNormalCompletion && _iterator['return']) {
  1611. _iterator['return']();
  1612. }
  1613. } finally {
  1614. if (_didIteratorError) {
  1615. throw _iteratorError;
  1616. }
  1617. }
  1618. }
  1619. return candidate;
  1620. };
  1621. /***/
  1622. }),
  1623. /* 3 */
  1624. /***/
  1625. (function(module, exports, __webpack_require__) {
  1626. module.exports = { "default": __webpack_require__(194), __esModule: true };
  1627. /***/
  1628. }),
  1629. /* 4 */
  1630. /***/
  1631. (function(module, exports, __webpack_require__) {
  1632. "use strict";
  1633. exports.__esModule = true;
  1634. var _typeof2 = __webpack_require__(6);
  1635. var _typeof3 = _interopRequireDefault(_typeof2);
  1636. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  1637. exports.default = function(self, call) {
  1638. if (!self) {
  1639. throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  1640. }
  1641. return call && ((typeof call === "undefined" ? "undefined" : (0, _typeof3.default)(call)) === "object" || typeof call === "function") ? call : self;
  1642. };
  1643. /***/
  1644. }),
  1645. /* 5 */
  1646. /***/
  1647. (function(module, exports, __webpack_require__) {
  1648. "use strict";
  1649. exports.__esModule = true;
  1650. var _setPrototypeOf = __webpack_require__(196);
  1651. var _setPrototypeOf2 = _interopRequireDefault(_setPrototypeOf);
  1652. var _create = __webpack_require__(29);
  1653. var _create2 = _interopRequireDefault(_create);
  1654. var _typeof2 = __webpack_require__(6);
  1655. var _typeof3 = _interopRequireDefault(_typeof2);
  1656. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  1657. exports.default = function(subClass, superClass) {
  1658. if (typeof superClass !== "function" && superClass !== null) {
  1659. throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === "undefined" ? "undefined" : (0, _typeof3.default)(superClass)));
  1660. }
  1661. subClass.prototype = (0, _create2.default)(superClass && superClass.prototype, {
  1662. constructor: {
  1663. value: subClass,
  1664. enumerable: false,
  1665. writable: true,
  1666. configurable: true
  1667. }
  1668. });
  1669. if (superClass) _setPrototypeOf2.default ? (0, _setPrototypeOf2.default)(subClass, superClass) : subClass.__proto__ = superClass;
  1670. };
  1671. /***/
  1672. }),
  1673. /* 6 */
  1674. /***/
  1675. (function(module, exports, __webpack_require__) {
  1676. "use strict";
  1677. exports.__esModule = true;
  1678. var _iterator = __webpack_require__(142);
  1679. var _iterator2 = _interopRequireDefault(_iterator);
  1680. var _symbol = __webpack_require__(144);
  1681. var _symbol2 = _interopRequireDefault(_symbol);
  1682. var _typeof = typeof _symbol2.default === "function" && typeof _iterator2.default === "symbol" ? function(obj) { return typeof obj; } : function(obj) { return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj; };
  1683. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  1684. exports.default = typeof _symbol2.default === "function" && _typeof(_iterator2.default) === "symbol" ? function(obj) {
  1685. return typeof obj === "undefined" ? "undefined" : _typeof(obj);
  1686. } : function(obj) {
  1687. return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj === "undefined" ? "undefined" : _typeof(obj);
  1688. };
  1689. /***/
  1690. }),
  1691. /* 7 */
  1692. /***/
  1693. (function(module, exports) {
  1694. var core = module.exports = { version: '2.5.1' };
  1695. if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
  1696. /***/
  1697. }),
  1698. /* 8 */
  1699. /***/
  1700. (function(module, exports, __webpack_require__) {
  1701. module.exports = { "default": __webpack_require__(140), __esModule: true };
  1702. /***/
  1703. }),
  1704. /* 9 */
  1705. /***/
  1706. (function(module, exports, __webpack_require__) {
  1707. "use strict";
  1708. // first check if moment.js is already loaded in the browser window, if so,
  1709. // use this instance. Else, load via commonjs.
  1710. module.exports = typeof window !== 'undefined' && window['moment'] || __webpack_require__(154);
  1711. /***/
  1712. }),
  1713. /* 10 */
  1714. /***/
  1715. (function(module, exports, __webpack_require__) {
  1716. "use strict";
  1717. /**
  1718. * Setup a mock hammer.js object, for unit testing.
  1719. *
  1720. * Inspiration: https://github.com/uber/deck.gl/pull/658
  1721. *
  1722. * @returns {{on: noop, off: noop, destroy: noop, emit: noop, get: get}}
  1723. */
  1724. function hammerMock() {
  1725. var noop = function noop() {};
  1726. return {
  1727. on: noop,
  1728. off: noop,
  1729. destroy: noop,
  1730. emit: noop,
  1731. get: function get(m) {
  1732. //eslint-disable-line no-unused-vars
  1733. return {
  1734. set: noop
  1735. };
  1736. }
  1737. };
  1738. }
  1739. if (typeof window !== 'undefined') {
  1740. var propagating = __webpack_require__(175);
  1741. var Hammer = window['Hammer'] || __webpack_require__(176);
  1742. module.exports = propagating(Hammer, {
  1743. preventDefault: 'mouse'
  1744. });
  1745. } else {
  1746. module.exports = function() {
  1747. // hammer.js is only available in a browser, not in node.js. Replacing it with a mock object.
  1748. return hammerMock();
  1749. };
  1750. }
  1751. /***/
  1752. }),
  1753. /* 11 */
  1754. /***/
  1755. (function(module, exports, __webpack_require__) {
  1756. "use strict";
  1757. var _stringify = __webpack_require__(19);
  1758. var _stringify2 = _interopRequireDefault(_stringify);
  1759. var _typeof2 = __webpack_require__(6);
  1760. var _typeof3 = _interopRequireDefault(_typeof2);
  1761. var _keys = __webpack_require__(8);
  1762. var _keys2 = _interopRequireDefault(_keys);
  1763. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  1764. var util = __webpack_require__(2);
  1765. var Queue = __webpack_require__(43);
  1766. /**
  1767. * DataSet
  1768. * // TODO: add a DataSet constructor DataSet(data, options)
  1769. *
  1770. * Usage:
  1771. * var dataSet = new DataSet({
  1772. * fieldId: '_id',
  1773. * type: {
  1774. * // ...
  1775. * }
  1776. * });
  1777. *
  1778. * dataSet.add(item);
  1779. * dataSet.add(data);
  1780. * dataSet.update(item);
  1781. * dataSet.update(data);
  1782. * dataSet.remove(id);
  1783. * dataSet.remove(ids);
  1784. * var data = dataSet.get();
  1785. * var data = dataSet.get(id);
  1786. * var data = dataSet.get(ids);
  1787. * var data = dataSet.get(ids, options, data);
  1788. * dataSet.clear();
  1789. *
  1790. * A data set can:
  1791. * - add/remove/update data
  1792. * - gives triggers upon changes in the data
  1793. * - can import/export data in various data formats
  1794. *
  1795. * @param {Array} [data] Optional array with initial data
  1796. * @param {Object} [options] Available options:
  1797. * {string} fieldId Field name of the id in the
  1798. * items, 'id' by default.
  1799. * {Object.<string, string} type
  1800. * A map with field names as key,
  1801. * and the field type as value.
  1802. * {Object} queue Queue changes to the DataSet,
  1803. * flush them all at once.
  1804. * Queue options:
  1805. * - {number} delay Delay in ms, null by default
  1806. * - {number} max Maximum number of entries in the queue, Infinity by default
  1807. * @constructor DataSet
  1808. */
  1809. function DataSet(data, options) {
  1810. // correctly read optional arguments
  1811. if (data && !Array.isArray(data)) {
  1812. options = data;
  1813. data = null;
  1814. }
  1815. this._options = options || {};
  1816. this._data = {}; // map with data indexed by id
  1817. this.length = 0; // number of items in the DataSet
  1818. this._fieldId = this._options.fieldId || 'id'; // name of the field containing id
  1819. this._type = {}; // internal field types (NOTE: this can differ from this._options.type)
  1820. // all variants of a Date are internally stored as Date, so we can convert
  1821. // from everything to everything (also from ISODate to Number for example)
  1822. if (this._options.type) {
  1823. var fields = (0, _keys2['default'])(this._options.type);
  1824. for (var i = 0, len = fields.length; i < len; i++) {
  1825. var field = fields[i];
  1826. var value = this._options.type[field];
  1827. if (value == 'Date' || value == 'ISODate' || value == 'ASPDate') {
  1828. this._type[field] = 'Date';
  1829. } else {
  1830. this._type[field] = value;
  1831. }
  1832. }
  1833. }
  1834. this._subscribers = {}; // event subscribers
  1835. // add initial data when provided
  1836. if (data) {
  1837. this.add(data);
  1838. }
  1839. this.setOptions(options);
  1840. }
  1841. /**
  1842. * @param {Object} options Available options:
  1843. * {Object} queue Queue changes to the DataSet,
  1844. * flush them all at once.
  1845. * Queue options:
  1846. * - {number} delay Delay in ms, null by default
  1847. * - {number} max Maximum number of entries in the queue, Infinity by default
  1848. */
  1849. DataSet.prototype.setOptions = function(options) {
  1850. if (options && options.queue !== undefined) {
  1851. if (options.queue === false) {
  1852. // delete queue if loaded
  1853. if (this._queue) {
  1854. this._queue.destroy();
  1855. delete this._queue;
  1856. }
  1857. } else {
  1858. // create queue and update its options
  1859. if (!this._queue) {
  1860. this._queue = Queue.extend(this, {
  1861. replace: ['add', 'update', 'remove']
  1862. });
  1863. }
  1864. if ((0, _typeof3['default'])(options.queue) === 'object') {
  1865. this._queue.setOptions(options.queue);
  1866. }
  1867. }
  1868. }
  1869. };
  1870. /**
  1871. * Subscribe to an event, add an event listener
  1872. * @param {string} event Event name. Available events: 'add', 'update',
  1873. * 'remove'
  1874. * @param {function} callback Callback method. Called with three parameters:
  1875. * {string} event
  1876. * {Object | null} params
  1877. * {string | number} senderId
  1878. */
  1879. DataSet.prototype.on = function(event, callback) {
  1880. var subscribers = this._subscribers[event];
  1881. if (!subscribers) {
  1882. subscribers = [];
  1883. this._subscribers[event] = subscribers;
  1884. }
  1885. subscribers.push({
  1886. callback: callback
  1887. });
  1888. };
  1889. /**
  1890. * Unsubscribe from an event, remove an event listener
  1891. * @param {string} event
  1892. * @param {function} callback
  1893. */
  1894. DataSet.prototype.off = function(event, callback) {
  1895. var subscribers = this._subscribers[event];
  1896. if (subscribers) {
  1897. this._subscribers[event] = subscribers.filter(function(listener) {
  1898. return listener.callback != callback;
  1899. });
  1900. }
  1901. };
  1902. /**
  1903. * Trigger an event
  1904. * @param {string} event
  1905. * @param {Object | null} params
  1906. * @param {string} [senderId] Optional id of the sender.
  1907. * @private
  1908. */
  1909. DataSet.prototype._trigger = function(event, params, senderId) {
  1910. if (event == '*') {
  1911. throw new Error('Cannot trigger event *');
  1912. }
  1913. var subscribers = [];
  1914. if (event in this._subscribers) {
  1915. subscribers = subscribers.concat(this._subscribers[event]);
  1916. }
  1917. if ('*' in this._subscribers) {
  1918. subscribers = subscribers.concat(this._subscribers['*']);
  1919. }
  1920. for (var i = 0, len = subscribers.length; i < len; i++) {
  1921. var subscriber = subscribers[i];
  1922. if (subscriber.callback) {
  1923. subscriber.callback(event, params, senderId || null);
  1924. }
  1925. }
  1926. };
  1927. /**
  1928. * Add data.
  1929. * Adding an item will fail when there already is an item with the same id.
  1930. * @param {Object | Array} data
  1931. * @param {string} [senderId] Optional sender id
  1932. * @return {Array.<string|number>} addedIds Array with the ids of the added items
  1933. */
  1934. DataSet.prototype.add = function(data, senderId) {
  1935. var addedIds = [],
  1936. id,
  1937. me = this;
  1938. if (Array.isArray(data)) {
  1939. // Array
  1940. for (var i = 0, len = data.length; i < len; i++) {
  1941. id = me._addItem(data[i]);
  1942. addedIds.push(id);
  1943. }
  1944. } else if (data && (typeof data === 'undefined' ? 'undefined' : (0, _typeof3['default'])(data)) === 'object') {
  1945. // Single item
  1946. id = me._addItem(data);
  1947. addedIds.push(id);
  1948. } else {
  1949. throw new Error('Unknown dataType');
  1950. }
  1951. if (addedIds.length) {
  1952. this._trigger('add', { items: addedIds }, senderId);
  1953. }
  1954. return addedIds;
  1955. };
  1956. /**
  1957. * Update existing items. When an item does not exist, it will be created
  1958. * @param {Object | Array} data
  1959. * @param {string} [senderId] Optional sender id
  1960. * @return {Array.<string|number>} updatedIds The ids of the added or updated items
  1961. * @throws {Error} Unknown Datatype
  1962. */
  1963. DataSet.prototype.update = function(data, senderId) {
  1964. var addedIds = [];
  1965. var updatedIds = [];
  1966. var oldData = [];
  1967. var updatedData = [];
  1968. var me = this;
  1969. var fieldId = me._fieldId;
  1970. var addOrUpdate = function addOrUpdate(item) {
  1971. var id = item[fieldId];
  1972. if (me._data[id]) {
  1973. var oldItem = util.extend({}, me._data[id]);
  1974. // update item
  1975. id = me._updateItem(item);
  1976. updatedIds.push(id);
  1977. updatedData.push(item);
  1978. oldData.push(oldItem);
  1979. } else {
  1980. // add new item
  1981. id = me._addItem(item);
  1982. addedIds.push(id);
  1983. }
  1984. };
  1985. if (Array.isArray(data)) {
  1986. // Array
  1987. for (var i = 0, len = data.length; i < len; i++) {
  1988. if (data[i] && (0, _typeof3['default'])(data[i]) === 'object') {
  1989. addOrUpdate(data[i]);
  1990. } else {
  1991. console.warn('Ignoring input item, which is not an object at index ' + i);
  1992. }
  1993. }
  1994. } else if (data && (typeof data === 'undefined' ? 'undefined' : (0, _typeof3['default'])(data)) === 'object') {
  1995. // Single item
  1996. addOrUpdate(data);
  1997. } else {
  1998. throw new Error('Unknown dataType');
  1999. }
  2000. if (addedIds.length) {
  2001. this._trigger('add', { items: addedIds }, senderId);
  2002. }
  2003. if (updatedIds.length) {
  2004. var props = { items: updatedIds, oldData: oldData, data: updatedData };
  2005. // TODO: remove deprecated property 'data' some day
  2006. //Object.defineProperty(props, 'data', {
  2007. // 'get': (function() {
  2008. // console.warn('Property data is deprecated. Use DataSet.get(ids) to retrieve the new data, use the oldData property on this object to get the old data');
  2009. // return updatedData;
  2010. // }).bind(this)
  2011. //});
  2012. this._trigger('update', props, senderId);
  2013. }
  2014. return addedIds.concat(updatedIds);
  2015. };
  2016. /**
  2017. * Get a data item or multiple items.
  2018. *
  2019. * Usage:
  2020. *
  2021. * get()
  2022. * get(options: Object)
  2023. *
  2024. * get(id: number | string)
  2025. * get(id: number | string, options: Object)
  2026. *
  2027. * get(ids: number[] | string[])
  2028. * get(ids: number[] | string[], options: Object)
  2029. *
  2030. * Where:
  2031. *
  2032. * {number | string} id The id of an item
  2033. * {number[] | string{}} ids An array with ids of items
  2034. * {Object} options An Object with options. Available options:
  2035. * {string} [returnType] Type of data to be returned.
  2036. * Can be 'Array' (default) or 'Object'.
  2037. * {Object.<string, string>} [type]
  2038. * {string[]} [fields] field names to be returned
  2039. * {function} [filter] filter items
  2040. * {string | function} [order] Order the items by a field name or custom sort function.
  2041. * @param {Array} args
  2042. * @returns {DataSet}
  2043. * @throws Error
  2044. */
  2045. DataSet.prototype.get = function(args) {
  2046. // eslint-disable-line no-unused-vars
  2047. var me = this;
  2048. // parse the arguments
  2049. var id, ids, options;
  2050. var firstType = util.getType(arguments[0]);
  2051. if (firstType == 'String' || firstType == 'Number') {
  2052. // get(id [, options])
  2053. id = arguments[0];
  2054. options = arguments[1];
  2055. } else if (firstType == 'Array') {
  2056. // get(ids [, options])
  2057. ids = arguments[0];
  2058. options = arguments[1];
  2059. } else {
  2060. // get([, options])
  2061. options = arguments[0];
  2062. }
  2063. // determine the return type
  2064. var returnType;
  2065. if (options && options.returnType) {
  2066. var allowedValues = ['Array', 'Object'];
  2067. returnType = allowedValues.indexOf(options.returnType) == -1 ? 'Array' : options.returnType;
  2068. } else {
  2069. returnType = 'Array';
  2070. }
  2071. // build options
  2072. var type = options && options.type || this._options.type;
  2073. var filter = options && options.filter;
  2074. var items = [],
  2075. item,
  2076. itemIds,
  2077. itemId,
  2078. i,
  2079. len;
  2080. // convert items
  2081. if (id != undefined) {
  2082. // return a single item
  2083. item = me._getItem(id, type);
  2084. if (item && filter && !filter(item)) {
  2085. item = null;
  2086. }
  2087. } else if (ids != undefined) {
  2088. // return a subset of items
  2089. for (i = 0, len = ids.length; i < len; i++) {
  2090. item = me._getItem(ids[i], type);
  2091. if (!filter || filter(item)) {
  2092. items.push(item);
  2093. }
  2094. }
  2095. } else {
  2096. // return all items
  2097. itemIds = (0, _keys2['default'])(this._data);
  2098. for (i = 0, len = itemIds.length; i < len; i++) {
  2099. itemId = itemIds[i];
  2100. item = me._getItem(itemId, type);
  2101. if (!filter || filter(item)) {
  2102. items.push(item);
  2103. }
  2104. }
  2105. }
  2106. // order the results
  2107. if (options && options.order && id == undefined) {
  2108. this._sort(items, options.order);
  2109. }
  2110. // filter fields of the items
  2111. if (options && options.fields) {
  2112. var fields = options.fields;
  2113. if (id != undefined) {
  2114. item = this._filterFields(item, fields);
  2115. } else {
  2116. for (i = 0, len = items.length; i < len; i++) {
  2117. items[i] = this._filterFields(items[i], fields);
  2118. }
  2119. }
  2120. }
  2121. // return the results
  2122. if (returnType == 'Object') {
  2123. var result = {},
  2124. resultant;
  2125. for (i = 0, len = items.length; i < len; i++) {
  2126. resultant = items[i];
  2127. result[resultant.id] = resultant;
  2128. }
  2129. return result;
  2130. } else {
  2131. if (id != undefined) {
  2132. // a single item
  2133. return item;
  2134. } else {
  2135. // just return our array
  2136. return items;
  2137. }
  2138. }
  2139. };
  2140. /**
  2141. * Get ids of all items or from a filtered set of items.
  2142. * @param {Object} [options] An Object with options. Available options:
  2143. * {function} [filter] filter items
  2144. * {string | function} [order] Order the items by
  2145. * a field name or custom sort function.
  2146. * @return {Array.<string|number>} ids
  2147. */
  2148. DataSet.prototype.getIds = function(options) {
  2149. var data = this._data,
  2150. filter = options && options.filter,
  2151. order = options && options.order,
  2152. type = options && options.type || this._options.type,
  2153. itemIds = (0, _keys2['default'])(data),
  2154. i,
  2155. len,
  2156. id,
  2157. item,
  2158. items,
  2159. ids = [];
  2160. if (filter) {
  2161. // get filtered items
  2162. if (order) {
  2163. // create ordered list
  2164. items = [];
  2165. for (i = 0, len = itemIds.length; i < len; i++) {
  2166. id = itemIds[i];
  2167. item = this._getItem(id, type);
  2168. if (filter(item)) {
  2169. items.push(item);
  2170. }
  2171. }
  2172. this._sort(items, order);
  2173. for (i = 0, len = items.length; i < len; i++) {
  2174. ids.push(items[i][this._fieldId]);
  2175. }
  2176. } else {
  2177. // create unordered list
  2178. for (i = 0, len = itemIds.length; i < len; i++) {
  2179. id = itemIds[i];
  2180. item = this._getItem(id, type);
  2181. if (filter(item)) {
  2182. ids.push(item[this._fieldId]);
  2183. }
  2184. }
  2185. }
  2186. } else {
  2187. // get all items
  2188. if (order) {
  2189. // create an ordered list
  2190. items = [];
  2191. for (i = 0, len = itemIds.length; i < len; i++) {
  2192. id = itemIds[i];
  2193. items.push(data[id]);
  2194. }
  2195. this._sort(items, order);
  2196. for (i = 0, len = items.length; i < len; i++) {
  2197. ids.push(items[i][this._fieldId]);
  2198. }
  2199. } else {
  2200. // create unordered list
  2201. for (i = 0, len = itemIds.length; i < len; i++) {
  2202. id = itemIds[i];
  2203. item = data[id];
  2204. ids.push(item[this._fieldId]);
  2205. }
  2206. }
  2207. }
  2208. return ids;
  2209. };
  2210. /**
  2211. * Returns the DataSet itself. Is overwritten for example by the DataView,
  2212. * which returns the DataSet it is connected to instead.
  2213. * @returns {DataSet}
  2214. */
  2215. DataSet.prototype.getDataSet = function() {
  2216. return this;
  2217. };
  2218. /**
  2219. * Execute a callback function for every item in the dataset.
  2220. * @param {function} callback
  2221. * @param {Object} [options] Available options:
  2222. * {Object.<string, string>} [type]
  2223. * {string[]} [fields] filter fields
  2224. * {function} [filter] filter items
  2225. * {string | function} [order] Order the items by
  2226. * a field name or custom sort function.
  2227. */
  2228. DataSet.prototype.forEach = function(callback, options) {
  2229. var filter = options && options.filter,
  2230. type = options && options.type || this._options.type,
  2231. data = this._data,
  2232. itemIds = (0, _keys2['default'])(data),
  2233. i,
  2234. len,
  2235. item,
  2236. id;
  2237. if (options && options.order) {
  2238. // execute forEach on ordered list
  2239. var items = this.get(options);
  2240. for (i = 0, len = items.length; i < len; i++) {
  2241. item = items[i];
  2242. id = item[this._fieldId];
  2243. callback(item, id);
  2244. }
  2245. } else {
  2246. // unordered
  2247. for (i = 0, len = itemIds.length; i < len; i++) {
  2248. id = itemIds[i];
  2249. item = this._getItem(id, type);
  2250. if (!filter || filter(item)) {
  2251. callback(item, id);
  2252. }
  2253. }
  2254. }
  2255. };
  2256. /**
  2257. * Map every item in the dataset.
  2258. * @param {function} callback
  2259. * @param {Object} [options] Available options:
  2260. * {Object.<string, string>} [type]
  2261. * {string[]} [fields] filter fields
  2262. * {function} [filter] filter items
  2263. * {string | function} [order] Order the items by
  2264. * a field name or custom sort function.
  2265. * @return {Object[]} mappedItems
  2266. */
  2267. DataSet.prototype.map = function(callback, options) {
  2268. var filter = options && options.filter,
  2269. type = options && options.type || this._options.type,
  2270. mappedItems = [],
  2271. data = this._data,
  2272. itemIds = (0, _keys2['default'])(data),
  2273. i,
  2274. len,
  2275. id,
  2276. item;
  2277. // convert and filter items
  2278. for (i = 0, len = itemIds.length; i < len; i++) {
  2279. id = itemIds[i];
  2280. item = this._getItem(id, type);
  2281. if (!filter || filter(item)) {
  2282. mappedItems.push(callback(item, id));
  2283. }
  2284. }
  2285. // order items
  2286. if (options && options.order) {
  2287. this._sort(mappedItems, options.order);
  2288. }
  2289. return mappedItems;
  2290. };
  2291. /**
  2292. * Filter the fields of an item
  2293. * @param {Object | null} item
  2294. * @param {string[]} fields Field names
  2295. * @return {Object | null} filteredItem or null if no item is provided
  2296. * @private
  2297. */
  2298. DataSet.prototype._filterFields = function(item, fields) {
  2299. if (!item) {
  2300. // item is null
  2301. return item;
  2302. }
  2303. var filteredItem = {},
  2304. itemFields = (0, _keys2['default'])(item),
  2305. len = itemFields.length,
  2306. i,
  2307. field;
  2308. if (Array.isArray(fields)) {
  2309. for (i = 0; i < len; i++) {
  2310. field = itemFields[i];
  2311. if (fields.indexOf(field) != -1) {
  2312. filteredItem[field] = item[field];
  2313. }
  2314. }
  2315. } else {
  2316. for (i = 0; i < len; i++) {
  2317. field = itemFields[i];
  2318. if (fields.hasOwnProperty(field)) {
  2319. filteredItem[fields[field]] = item[field];
  2320. }
  2321. }
  2322. }
  2323. return filteredItem;
  2324. };
  2325. /**
  2326. * Sort the provided array with items
  2327. * @param {Object[]} items
  2328. * @param {string | function} order A field name or custom sort function.
  2329. * @private
  2330. */
  2331. DataSet.prototype._sort = function(items, order) {
  2332. if (util.isString(order)) {
  2333. // order by provided field name
  2334. var name = order; // field name
  2335. items.sort(function(a, b) {
  2336. var av = a[name];
  2337. var bv = b[name];
  2338. return av > bv ? 1 : av < bv ? -1 : 0;
  2339. });
  2340. } else if (typeof order === 'function') {
  2341. // order by sort function
  2342. items.sort(order);
  2343. }
  2344. // TODO: extend order by an Object {field:string, direction:string}
  2345. // where direction can be 'asc' or 'desc'
  2346. else {
  2347. throw new TypeError('Order must be a function or a string');
  2348. }
  2349. };
  2350. /**
  2351. * Remove an object by pointer or by id
  2352. * @param {string | number | Object | Array.<string|number>} id Object or id, or an array with
  2353. * objects or ids to be removed
  2354. * @param {string} [senderId] Optional sender id
  2355. * @return {Array.<string|number>} removedIds
  2356. */
  2357. DataSet.prototype.remove = function(id, senderId) {
  2358. var removedIds = [],
  2359. removedItems = [],
  2360. ids = [],
  2361. i,
  2362. len,
  2363. itemId,
  2364. item;
  2365. // force everything to be an array for simplicity
  2366. ids = Array.isArray(id) ? id : [id];
  2367. for (i = 0, len = ids.length; i < len; i++) {
  2368. item = this._remove(ids[i]);
  2369. if (item) {
  2370. itemId = item[this._fieldId];
  2371. if (itemId != undefined) {
  2372. removedIds.push(itemId);
  2373. removedItems.push(item);
  2374. }
  2375. }
  2376. }
  2377. if (removedIds.length) {
  2378. this._trigger('remove', { items: removedIds, oldData: removedItems }, senderId);
  2379. }
  2380. return removedIds;
  2381. };
  2382. /**
  2383. * Remove an item by its id
  2384. * @param {number | string | Object} id id or item
  2385. * @returns {number | string | null} id
  2386. * @private
  2387. */
  2388. DataSet.prototype._remove = function(id) {
  2389. var item, ident;
  2390. // confirm the id to use based on the args type
  2391. if (util.isNumber(id) || util.isString(id)) {
  2392. ident = id;
  2393. } else if (id && (typeof id === 'undefined' ? 'undefined' : (0, _typeof3['default'])(id)) === 'object') {
  2394. ident = id[this._fieldId]; // look for the identifier field using _fieldId
  2395. }
  2396. // do the remove if the item is found
  2397. if (ident !== undefined && this._data[ident]) {
  2398. item = this._data[ident];
  2399. delete this._data[ident];
  2400. this.length--;
  2401. return item;
  2402. }
  2403. return null;
  2404. };
  2405. /**
  2406. * Clear the data
  2407. * @param {string} [senderId] Optional sender id
  2408. * @return {Array.<string|number>} removedIds The ids of all removed items
  2409. */
  2410. DataSet.prototype.clear = function(senderId) {
  2411. var i, len;
  2412. var ids = (0, _keys2['default'])(this._data);
  2413. var items = [];
  2414. for (i = 0, len = ids.length; i < len; i++) {
  2415. items.push(this._data[ids[i]]);
  2416. }
  2417. this._data = {};
  2418. this.length = 0;
  2419. this._trigger('remove', { items: ids, oldData: items }, senderId);
  2420. return ids;
  2421. };
  2422. /**
  2423. * Find the item with maximum value of a specified field
  2424. * @param {string} field
  2425. * @return {Object | null} item Item containing max value, or null if no items
  2426. */
  2427. DataSet.prototype.max = function(field) {
  2428. var data = this._data,
  2429. itemIds = (0, _keys2['default'])(data),
  2430. max = null,
  2431. maxField = null,
  2432. i,
  2433. len;
  2434. for (i = 0, len = itemIds.length; i < len; i++) {
  2435. var id = itemIds[i];
  2436. var item = data[id];
  2437. var itemField = item[field];
  2438. if (itemField != null && (!max || itemField > maxField)) {
  2439. max = item;
  2440. maxField = itemField;
  2441. }
  2442. }
  2443. return max;
  2444. };
  2445. /**
  2446. * Find the item with minimum value of a specified field
  2447. * @param {string} field
  2448. * @return {Object | null} item Item containing max value, or null if no items
  2449. */
  2450. DataSet.prototype.min = function(field) {
  2451. var data = this._data,
  2452. itemIds = (0, _keys2['default'])(data),
  2453. min = null,
  2454. minField = null,
  2455. i,
  2456. len;
  2457. for (i = 0, len = itemIds.length; i < len; i++) {
  2458. var id = itemIds[i];
  2459. var item = data[id];
  2460. var itemField = item[field];
  2461. if (itemField != null && (!min || itemField < minField)) {
  2462. min = item;
  2463. minField = itemField;
  2464. }
  2465. }
  2466. return min;
  2467. };
  2468. /**
  2469. * Find all distinct values of a specified field
  2470. * @param {string} field
  2471. * @return {Array} values Array containing all distinct values. If data items
  2472. * do not contain the specified field are ignored.
  2473. * The returned array is unordered.
  2474. */
  2475. DataSet.prototype.distinct = function(field) {
  2476. var data = this._data;
  2477. var itemIds = (0, _keys2['default'])(data);
  2478. var values = [];
  2479. var fieldType = this._options.type && this._options.type[field] || null;
  2480. var count = 0;
  2481. var i, j, len;
  2482. for (i = 0, len = itemIds.length; i < len; i++) {
  2483. var id = itemIds[i];
  2484. var item = data[id];
  2485. var value = item[field];
  2486. var exists = false;
  2487. for (j = 0; j < count; j++) {
  2488. if (values[j] == value) {
  2489. exists = true;
  2490. break;
  2491. }
  2492. }
  2493. if (!exists && value !== undefined) {
  2494. values[count] = value;
  2495. count++;
  2496. }
  2497. }
  2498. if (fieldType) {
  2499. for (i = 0, len = values.length; i < len; i++) {
  2500. values[i] = util.convert(values[i], fieldType);
  2501. }
  2502. }
  2503. return values;
  2504. };
  2505. /**
  2506. * Add a single item. Will fail when an item with the same id already exists.
  2507. * @param {Object} item
  2508. * @return {string} id
  2509. * @private
  2510. */
  2511. DataSet.prototype._addItem = function(item) {
  2512. var id = item[this._fieldId];
  2513. if (id != undefined) {
  2514. // check whether this id is already taken
  2515. if (this._data[id]) {
  2516. // item already exists
  2517. throw new Error('Cannot add item: item with id ' + id + ' already exists');
  2518. }
  2519. } else {
  2520. // generate an id
  2521. id = util.randomUUID();
  2522. item[this._fieldId] = id;
  2523. }
  2524. var d = {},
  2525. fields = (0, _keys2['default'])(item),
  2526. i,
  2527. len;
  2528. for (i = 0, len = fields.length; i < len; i++) {
  2529. var field = fields[i];
  2530. var fieldType = this._type[field]; // type may be undefined
  2531. d[field] = util.convert(item[field], fieldType);
  2532. }
  2533. this._data[id] = d;
  2534. this.length++;
  2535. return id;
  2536. };
  2537. /**
  2538. * Get an item. Fields can be converted to a specific type
  2539. * @param {string} id
  2540. * @param {Object.<string, string>} [types] field types to convert
  2541. * @return {Object | null} item
  2542. * @private
  2543. */
  2544. DataSet.prototype._getItem = function(id, types) {
  2545. var field, value, i, len;
  2546. // get the item from the dataset
  2547. var raw = this._data[id];
  2548. if (!raw) {
  2549. return null;
  2550. }
  2551. // convert the items field types
  2552. var converted = {},
  2553. fields = (0, _keys2['default'])(raw);
  2554. if (types) {
  2555. for (i = 0, len = fields.length; i < len; i++) {
  2556. field = fields[i];
  2557. value = raw[field];
  2558. converted[field] = util.convert(value, types[field]);
  2559. }
  2560. } else {
  2561. // no field types specified, no converting needed
  2562. for (i = 0, len = fields.length; i < len; i++) {
  2563. field = fields[i];
  2564. value = raw[field];
  2565. converted[field] = value;
  2566. }
  2567. }
  2568. if (!converted[this._fieldId]) {
  2569. converted[this._fieldId] = raw.id;
  2570. }
  2571. return converted;
  2572. };
  2573. /**
  2574. * Update a single item: merge with existing item.
  2575. * Will fail when the item has no id, or when there does not exist an item
  2576. * with the same id.
  2577. * @param {Object} item
  2578. * @return {string} id
  2579. * @private
  2580. */
  2581. DataSet.prototype._updateItem = function(item) {
  2582. var id = item[this._fieldId];
  2583. if (id == undefined) {
  2584. throw new Error('Cannot update item: item has no id (item: ' + (0, _stringify2['default'])(item) + ')');
  2585. }
  2586. var d = this._data[id];
  2587. if (!d) {
  2588. // item doesn't exist
  2589. throw new Error('Cannot update item: no item with id ' + id + ' found');
  2590. }
  2591. // merge with current item
  2592. var fields = (0, _keys2['default'])(item);
  2593. for (var i = 0, len = fields.length; i < len; i++) {
  2594. var field = fields[i];
  2595. var fieldType = this._type[field]; // type may be undefined
  2596. d[field] = util.convert(item[field], fieldType);
  2597. }
  2598. return id;
  2599. };
  2600. module.exports = DataSet;
  2601. /***/
  2602. }),
  2603. /* 12 */
  2604. /***/
  2605. (function(module, exports, __webpack_require__) {
  2606. "use strict";
  2607. var _keys = __webpack_require__(8);
  2608. var _keys2 = _interopRequireDefault(_keys);
  2609. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  2610. var util = __webpack_require__(2);
  2611. var DataSet = __webpack_require__(11);
  2612. /**
  2613. * DataView
  2614. *
  2615. * a dataview offers a filtered view on a dataset or an other dataview.
  2616. *
  2617. * @param {DataSet | DataView} data
  2618. * @param {Object} [options] Available options: see method get
  2619. *
  2620. * @constructor DataView
  2621. */
  2622. function DataView(data, options) {
  2623. this._data = null;
  2624. this._ids = {}; // ids of the items currently in memory (just contains a boolean true)
  2625. this.length = 0; // number of items in the DataView
  2626. this._options = options || {};
  2627. this._fieldId = 'id'; // name of the field containing id
  2628. this._subscribers = {}; // event subscribers
  2629. var me = this;
  2630. this.listener = function() {
  2631. me._onEvent.apply(me, arguments);
  2632. };
  2633. this.setData(data);
  2634. }
  2635. // TODO: implement a function .config() to dynamically update things like configured filter
  2636. // and trigger changes accordingly
  2637. /**
  2638. * Set a data source for the view
  2639. * @param {DataSet | DataView} data
  2640. */
  2641. DataView.prototype.setData = function(data) {
  2642. var ids, id, i, len, items;
  2643. if (this._data) {
  2644. // unsubscribe from current dataset
  2645. if (this._data.off) {
  2646. this._data.off('*', this.listener);
  2647. }
  2648. // trigger a remove of all items in memory
  2649. ids = this._data.getIds({ filter: this._options && this._options.filter });
  2650. items = [];
  2651. for (i = 0, len = ids.length; i < len; i++) {
  2652. items.push(this._data._data[ids[i]]);
  2653. }
  2654. this._ids = {};
  2655. this.length = 0;
  2656. this._trigger('remove', { items: ids, oldData: items });
  2657. }
  2658. this._data = data;
  2659. if (this._data) {
  2660. // update fieldId
  2661. this._fieldId = this._options.fieldId || this._data && this._data.options && this._data.options.fieldId || 'id';
  2662. // trigger an add of all added items
  2663. ids = this._data.getIds({ filter: this._options && this._options.filter });
  2664. for (i = 0, len = ids.length; i < len; i++) {
  2665. id = ids[i];
  2666. this._ids[id] = true;
  2667. }
  2668. this.length = ids.length;
  2669. this._trigger('add', { items: ids });
  2670. // subscribe to new dataset
  2671. if (this._data.on) {
  2672. this._data.on('*', this.listener);
  2673. }
  2674. }
  2675. };
  2676. /**
  2677. * Refresh the DataView. Useful when the DataView has a filter function
  2678. * containing a variable parameter.
  2679. */
  2680. DataView.prototype.refresh = function() {
  2681. var id, i, len;
  2682. var ids = this._data.getIds({ filter: this._options && this._options.filter }),
  2683. oldIds = (0, _keys2['default'])(this._ids),
  2684. newIds = {},
  2685. addedIds = [],
  2686. removedIds = [],
  2687. removedItems = [];
  2688. // check for additions
  2689. for (i = 0, len = ids.length; i < len; i++) {
  2690. id = ids[i];
  2691. newIds[id] = true;
  2692. if (!this._ids[id]) {
  2693. addedIds.push(id);
  2694. this._ids[id] = true;
  2695. }
  2696. }
  2697. // check for removals
  2698. for (i = 0, len = oldIds.length; i < len; i++) {
  2699. id = oldIds[i];
  2700. if (!newIds[id]) {
  2701. removedIds.push(id);
  2702. removedItems.push(this._data._data[id]);
  2703. delete this._ids[id];
  2704. }
  2705. }
  2706. this.length += addedIds.length - removedIds.length;
  2707. // trigger events
  2708. if (addedIds.length) {
  2709. this._trigger('add', { items: addedIds });
  2710. }
  2711. if (removedIds.length) {
  2712. this._trigger('remove', { items: removedIds, oldData: removedItems });
  2713. }
  2714. };
  2715. /**
  2716. * Get data from the data view
  2717. *
  2718. * Usage:
  2719. *
  2720. * get()
  2721. * get(options: Object)
  2722. * get(options: Object, data: Array | DataTable)
  2723. *
  2724. * get(id: Number)
  2725. * get(id: Number, options: Object)
  2726. * get(id: Number, options: Object, data: Array | DataTable)
  2727. *
  2728. * get(ids: Number[])
  2729. * get(ids: Number[], options: Object)
  2730. * get(ids: Number[], options: Object, data: Array | DataTable)
  2731. *
  2732. * Where:
  2733. *
  2734. * {number | string} id The id of an item
  2735. * {number[] | string{}} ids An array with ids of items
  2736. * {Object} options An Object with options. Available options:
  2737. * {string} [type] Type of data to be returned. Can
  2738. * be 'DataTable' or 'Array' (default)
  2739. * {Object.<string, string>} [convert]
  2740. * {string[]} [fields] field names to be returned
  2741. * {function} [filter] filter items
  2742. * {string | function} [order] Order the items by
  2743. * a field name or custom sort function.
  2744. * {Array | DataTable} [data] If provided, items will be appended to this
  2745. * array or table. Required in case of Google
  2746. * DataTable.
  2747. * @param {Array} args
  2748. * @return {DataSet|DataView}
  2749. */
  2750. DataView.prototype.get = function(args) {
  2751. // eslint-disable-line no-unused-vars
  2752. var me = this;
  2753. // parse the arguments
  2754. var ids, options, data;
  2755. var firstType = util.getType(arguments[0]);
  2756. if (firstType == 'String' || firstType == 'Number' || firstType == 'Array') {
  2757. // get(id(s) [, options] [, data])
  2758. ids = arguments[0]; // can be a single id or an array with ids
  2759. options = arguments[1];
  2760. data = arguments[2];
  2761. } else {
  2762. // get([, options] [, data])
  2763. options = arguments[0];
  2764. data = arguments[1];
  2765. }
  2766. // extend the options with the default options and provided options
  2767. var viewOptions = util.extend({}, this._options, options);
  2768. // create a combined filter method when needed
  2769. if (this._options.filter && options && options.filter) {
  2770. viewOptions.filter = function(item) {
  2771. return me._options.filter(item) && options.filter(item);
  2772. };
  2773. }
  2774. // build up the call to the linked data set
  2775. var getArguments = [];
  2776. if (ids != undefined) {
  2777. getArguments.push(ids);
  2778. }
  2779. getArguments.push(viewOptions);
  2780. getArguments.push(data);
  2781. return this._data && this._data.get.apply(this._data, getArguments);
  2782. };
  2783. /**
  2784. * Get ids of all items or from a filtered set of items.
  2785. * @param {Object} [options] An Object with options. Available options:
  2786. * {function} [filter] filter items
  2787. * {string | function} [order] Order the items by
  2788. * a field name or custom sort function.
  2789. * @return {Array.<string|number>} ids
  2790. */
  2791. DataView.prototype.getIds = function(options) {
  2792. var ids;
  2793. if (this._data) {
  2794. var defaultFilter = this._options.filter;
  2795. var filter;
  2796. if (options && options.filter) {
  2797. if (defaultFilter) {
  2798. filter = function filter(item) {
  2799. return defaultFilter(item) && options.filter(item);
  2800. };
  2801. } else {
  2802. filter = options.filter;
  2803. }
  2804. } else {
  2805. filter = defaultFilter;
  2806. }
  2807. ids = this._data.getIds({
  2808. filter: filter,
  2809. order: options && options.order
  2810. });
  2811. } else {
  2812. ids = [];
  2813. }
  2814. return ids;
  2815. };
  2816. /**
  2817. * Map every item in the dataset.
  2818. * @param {function} callback
  2819. * @param {Object} [options] Available options:
  2820. * {Object.<string, string>} [type]
  2821. * {string[]} [fields] filter fields
  2822. * {function} [filter] filter items
  2823. * {string | function} [order] Order the items by
  2824. * a field name or custom sort function.
  2825. * @return {Object[]} mappedItems
  2826. */
  2827. DataView.prototype.map = function(callback, options) {
  2828. var mappedItems = [];
  2829. if (this._data) {
  2830. var defaultFilter = this._options.filter;
  2831. var filter;
  2832. if (options && options.filter) {
  2833. if (defaultFilter) {
  2834. filter = function filter(item) {
  2835. return defaultFilter(item) && options.filter(item);
  2836. };
  2837. } else {
  2838. filter = options.filter;
  2839. }
  2840. } else {
  2841. filter = defaultFilter;
  2842. }
  2843. mappedItems = this._data.map(callback, {
  2844. filter: filter,
  2845. order: options && options.order
  2846. });
  2847. } else {
  2848. mappedItems = [];
  2849. }
  2850. return mappedItems;
  2851. };
  2852. /**
  2853. * Get the DataSet to which this DataView is connected. In case there is a chain
  2854. * of multiple DataViews, the root DataSet of this chain is returned.
  2855. * @return {DataSet} dataSet
  2856. */
  2857. DataView.prototype.getDataSet = function() {
  2858. var dataSet = this;
  2859. while (dataSet instanceof DataView) {
  2860. dataSet = dataSet._data;
  2861. }
  2862. return dataSet || null;
  2863. };
  2864. /**
  2865. * Event listener. Will propagate all events from the connected data set to
  2866. * the subscribers of the DataView, but will filter the items and only trigger
  2867. * when there are changes in the filtered data set.
  2868. * @param {string} event
  2869. * @param {Object | null} params
  2870. * @param {string} senderId
  2871. * @private
  2872. */
  2873. DataView.prototype._onEvent = function(event, params, senderId) {
  2874. var i, len, id, item;
  2875. var ids = params && params.items;
  2876. var addedIds = [],
  2877. updatedIds = [],
  2878. removedIds = [],
  2879. oldItems = [],
  2880. updatedItems = [],
  2881. removedItems = [];
  2882. if (ids && this._data) {
  2883. switch (event) {
  2884. case 'add':
  2885. // filter the ids of the added items
  2886. for (i = 0, len = ids.length; i < len; i++) {
  2887. id = ids[i];
  2888. item = this.get(id);
  2889. if (item) {
  2890. this._ids[id] = true;
  2891. addedIds.push(id);
  2892. }
  2893. }
  2894. break;
  2895. case 'update':
  2896. // determine the event from the views viewpoint: an updated
  2897. // item can be added, updated, or removed from this view.
  2898. for (i = 0, len = ids.length; i < len; i++) {
  2899. id = ids[i];
  2900. item = this.get(id);
  2901. if (item) {
  2902. if (this._ids[id]) {
  2903. updatedIds.push(id);
  2904. updatedItems.push(params.data[i]);
  2905. oldItems.push(params.oldData[i]);
  2906. } else {
  2907. this._ids[id] = true;
  2908. addedIds.push(id);
  2909. }
  2910. } else {
  2911. if (this._ids[id]) {
  2912. delete this._ids[id];
  2913. removedIds.push(id);
  2914. removedItems.push(params.oldData[i]);
  2915. } else {
  2916. // nothing interesting for me :-(
  2917. }
  2918. }
  2919. }
  2920. break;
  2921. case 'remove':
  2922. // filter the ids of the removed items
  2923. for (i = 0, len = ids.length; i < len; i++) {
  2924. id = ids[i];
  2925. if (this._ids[id]) {
  2926. delete this._ids[id];
  2927. removedIds.push(id);
  2928. removedItems.push(params.oldData[i]);
  2929. }
  2930. }
  2931. break;
  2932. }
  2933. this.length += addedIds.length - removedIds.length;
  2934. if (addedIds.length) {
  2935. this._trigger('add', { items: addedIds }, senderId);
  2936. }
  2937. if (updatedIds.length) {
  2938. this._trigger('update', { items: updatedIds, oldData: oldItems, data: updatedItems }, senderId);
  2939. }
  2940. if (removedIds.length) {
  2941. this._trigger('remove', { items: removedIds, oldData: removedItems }, senderId);
  2942. }
  2943. }
  2944. };
  2945. // copy subscription functionality from DataSet
  2946. DataView.prototype.on = DataSet.prototype.on;
  2947. DataView.prototype.off = DataSet.prototype.off;
  2948. DataView.prototype._trigger = DataSet.prototype._trigger;
  2949. // TODO: make these functions deprecated (replaced with `on` and `off` since version 0.5)
  2950. DataView.prototype.subscribe = DataView.prototype.on;
  2951. DataView.prototype.unsubscribe = DataView.prototype.off;
  2952. module.exports = DataView;
  2953. /***/
  2954. }),
  2955. /* 13 */
  2956. /***/
  2957. (function(module, exports, __webpack_require__) {
  2958. var store = __webpack_require__(57)('wks');
  2959. var uid = __webpack_require__(40);
  2960. var Symbol = __webpack_require__(18).Symbol;
  2961. var USE_SYMBOL = typeof Symbol == 'function';
  2962. var $exports = module.exports = function(name) {
  2963. return store[name] || (store[name] =
  2964. USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name));
  2965. };
  2966. $exports.store = store;
  2967. /***/
  2968. }),
  2969. /* 14 */
  2970. /***/
  2971. (function(module, exports, __webpack_require__) {
  2972. "use strict";
  2973. // DOM utility methods
  2974. /**
  2975. * this prepares the JSON container for allocating SVG elements
  2976. * @param {Object} JSONcontainer
  2977. * @private
  2978. */
  2979. exports.prepareElements = function(JSONcontainer) {
  2980. // cleanup the redundant svgElements;
  2981. for (var elementType in JSONcontainer) {
  2982. if (JSONcontainer.hasOwnProperty(elementType)) {
  2983. JSONcontainer[elementType].redundant = JSONcontainer[elementType].used;
  2984. JSONcontainer[elementType].used = [];
  2985. }
  2986. }
  2987. };
  2988. /**
  2989. * this cleans up all the unused SVG elements. By asking for the parentNode, we only need to supply the JSON container from
  2990. * which to remove the redundant elements.
  2991. *
  2992. * @param {Object} JSONcontainer
  2993. * @private
  2994. */
  2995. exports.cleanupElements = function(JSONcontainer) {
  2996. // cleanup the redundant svgElements;
  2997. for (var elementType in JSONcontainer) {
  2998. if (JSONcontainer.hasOwnProperty(elementType)) {
  2999. if (JSONcontainer[elementType].redundant) {
  3000. for (var i = 0; i < JSONcontainer[elementType].redundant.length; i++) {
  3001. JSONcontainer[elementType].redundant[i].parentNode.removeChild(JSONcontainer[elementType].redundant[i]);
  3002. }
  3003. JSONcontainer[elementType].redundant = [];
  3004. }
  3005. }
  3006. }
  3007. };
  3008. /**
  3009. * Ensures that all elements are removed first up so they can be recreated cleanly
  3010. * @param {Object} JSONcontainer
  3011. */
  3012. exports.resetElements = function(JSONcontainer) {
  3013. exports.prepareElements(JSONcontainer);
  3014. exports.cleanupElements(JSONcontainer);
  3015. exports.prepareElements(JSONcontainer);
  3016. };
  3017. /**
  3018. * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer
  3019. * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this.
  3020. *
  3021. * @param {string} elementType
  3022. * @param {Object} JSONcontainer
  3023. * @param {Object} svgContainer
  3024. * @returns {Element}
  3025. * @private
  3026. */
  3027. exports.getSVGElement = function(elementType, JSONcontainer, svgContainer) {
  3028. var element;
  3029. // allocate SVG element, if it doesnt yet exist, create one.
  3030. if (JSONcontainer.hasOwnProperty(elementType)) {
  3031. // this element has been created before
  3032. // check if there is an redundant element
  3033. if (JSONcontainer[elementType].redundant.length > 0) {
  3034. element = JSONcontainer[elementType].redundant[0];
  3035. JSONcontainer[elementType].redundant.shift();
  3036. } else {
  3037. // create a new element and add it to the SVG
  3038. element = document.createElementNS('http://www.w3.org/2000/svg', elementType);
  3039. svgContainer.appendChild(element);
  3040. }
  3041. } else {
  3042. // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
  3043. element = document.createElementNS('http://www.w3.org/2000/svg', elementType);
  3044. JSONcontainer[elementType] = { used: [], redundant: [] };
  3045. svgContainer.appendChild(element);
  3046. }
  3047. JSONcontainer[elementType].used.push(element);
  3048. return element;
  3049. };
  3050. /**
  3051. * Allocate or generate an SVG element if needed. Store a reference to it in the JSON container and draw it in the svgContainer
  3052. * the JSON container and the SVG container have to be supplied so other svg containers (like the legend) can use this.
  3053. *
  3054. * @param {string} elementType
  3055. * @param {Object} JSONcontainer
  3056. * @param {Element} DOMContainer
  3057. * @param {Element} insertBefore
  3058. * @returns {*}
  3059. */
  3060. exports.getDOMElement = function(elementType, JSONcontainer, DOMContainer, insertBefore) {
  3061. var element;
  3062. // allocate DOM element, if it doesnt yet exist, create one.
  3063. if (JSONcontainer.hasOwnProperty(elementType)) {
  3064. // this element has been created before
  3065. // check if there is an redundant element
  3066. if (JSONcontainer[elementType].redundant.length > 0) {
  3067. element = JSONcontainer[elementType].redundant[0];
  3068. JSONcontainer[elementType].redundant.shift();
  3069. } else {
  3070. // create a new element and add it to the SVG
  3071. element = document.createElement(elementType);
  3072. if (insertBefore !== undefined) {
  3073. DOMContainer.insertBefore(element, insertBefore);
  3074. } else {
  3075. DOMContainer.appendChild(element);
  3076. }
  3077. }
  3078. } else {
  3079. // create a new element and add it to the SVG, also create a new object in the svgElements to keep track of it.
  3080. element = document.createElement(elementType);
  3081. JSONcontainer[elementType] = { used: [], redundant: [] };
  3082. if (insertBefore !== undefined) {
  3083. DOMContainer.insertBefore(element, insertBefore);
  3084. } else {
  3085. DOMContainer.appendChild(element);
  3086. }
  3087. }
  3088. JSONcontainer[elementType].used.push(element);
  3089. return element;
  3090. };
  3091. /**
  3092. * Draw a point object. This is a separate function because it can also be called by the legend.
  3093. * The reason the JSONcontainer and the target SVG svgContainer have to be supplied is so the legend can use these functions
  3094. * as well.
  3095. *
  3096. * @param {number} x
  3097. * @param {number} y
  3098. * @param {Object} groupTemplate: A template containing the necessary information to draw the datapoint e.g., {style: 'circle', size: 5, className: 'className' }
  3099. * @param {Object} JSONcontainer
  3100. * @param {Object} svgContainer
  3101. * @param {Object} labelObj
  3102. * @returns {vis.PointItem}
  3103. */
  3104. exports.drawPoint = function(x, y, groupTemplate, JSONcontainer, svgContainer, labelObj) {
  3105. var point;
  3106. if (groupTemplate.style == 'circle') {
  3107. point = exports.getSVGElement('circle', JSONcontainer, svgContainer);
  3108. point.setAttributeNS(null, "cx", x);
  3109. point.setAttributeNS(null, "cy", y);
  3110. point.setAttributeNS(null, "r", 0.5 * groupTemplate.size);
  3111. } else {
  3112. point = exports.getSVGElement('rect', JSONcontainer, svgContainer);
  3113. point.setAttributeNS(null, "x", x - 0.5 * groupTemplate.size);
  3114. point.setAttributeNS(null, "y", y - 0.5 * groupTemplate.size);
  3115. point.setAttributeNS(null, "width", groupTemplate.size);
  3116. point.setAttributeNS(null, "height", groupTemplate.size);
  3117. }
  3118. if (groupTemplate.styles !== undefined) {
  3119. point.setAttributeNS(null, "style", groupTemplate.styles);
  3120. }
  3121. point.setAttributeNS(null, "class", groupTemplate.className + " vis-point");
  3122. //handle label
  3123. if (labelObj) {
  3124. var label = exports.getSVGElement('text', JSONcontainer, svgContainer);
  3125. if (labelObj.xOffset) {
  3126. x = x + labelObj.xOffset;
  3127. }
  3128. if (labelObj.yOffset) {
  3129. y = y + labelObj.yOffset;
  3130. }
  3131. if (labelObj.content) {
  3132. label.textContent = labelObj.content;
  3133. }
  3134. if (labelObj.className) {
  3135. label.setAttributeNS(null, "class", labelObj.className + " vis-label");
  3136. }
  3137. label.setAttributeNS(null, "x", x);
  3138. label.setAttributeNS(null, "y", y);
  3139. }
  3140. return point;
  3141. };
  3142. /**
  3143. * draw a bar SVG element centered on the X coordinate
  3144. *
  3145. * @param {number} x
  3146. * @param {number} y
  3147. * @param {number} width
  3148. * @param {number} height
  3149. * @param {string} className
  3150. * @param {Object} JSONcontainer
  3151. * @param {Object} svgContainer
  3152. * @param {string} style
  3153. */
  3154. exports.drawBar = function(x, y, width, height, className, JSONcontainer, svgContainer, style) {
  3155. if (height != 0) {
  3156. if (height < 0) {
  3157. height *= -1;
  3158. y -= height;
  3159. }
  3160. var rect = exports.getSVGElement('rect', JSONcontainer, svgContainer);
  3161. rect.setAttributeNS(null, "x", x - 0.5 * width);
  3162. rect.setAttributeNS(null, "y", y);
  3163. rect.setAttributeNS(null, "width", width);
  3164. rect.setAttributeNS(null, "height", height);
  3165. rect.setAttributeNS(null, "class", className);
  3166. if (style) {
  3167. rect.setAttributeNS(null, "style", style);
  3168. }
  3169. }
  3170. };
  3171. /***/
  3172. }),
  3173. /* 15 */
  3174. /***/
  3175. (function(module, exports, __webpack_require__) {
  3176. "use strict";
  3177. Object.defineProperty(exports, "__esModule", {
  3178. value: true
  3179. });
  3180. exports.printStyle = undefined;
  3181. var _stringify = __webpack_require__(19);
  3182. var _stringify2 = _interopRequireDefault(_stringify);
  3183. var _typeof2 = __webpack_require__(6);
  3184. var _typeof3 = _interopRequireDefault(_typeof2);
  3185. var _keys = __webpack_require__(8);
  3186. var _keys2 = _interopRequireDefault(_keys);
  3187. var _classCallCheck2 = __webpack_require__(0);
  3188. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  3189. var _createClass2 = __webpack_require__(1);
  3190. var _createClass3 = _interopRequireDefault(_createClass2);
  3191. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  3192. var util = __webpack_require__(2);
  3193. var errorFound = false;
  3194. var allOptions = void 0;
  3195. var printStyle = 'background: #FFeeee; color: #dd0000';
  3196. /**
  3197. * Used to validate options.
  3198. */
  3199. var Validator = function() {
  3200. /**
  3201. * @ignore
  3202. */
  3203. function Validator() {
  3204. (0, _classCallCheck3['default'])(this, Validator);
  3205. }
  3206. /**
  3207. * Main function to be called
  3208. * @param {Object} options
  3209. * @param {Object} referenceOptions
  3210. * @param {Object} subObject
  3211. * @returns {boolean}
  3212. * @static
  3213. */
  3214. (0, _createClass3['default'])(Validator, null, [{
  3215. key: 'validate',
  3216. value: function validate(options, referenceOptions, subObject) {
  3217. errorFound = false;
  3218. allOptions = referenceOptions;
  3219. var usedOptions = referenceOptions;
  3220. if (subObject !== undefined) {
  3221. usedOptions = referenceOptions[subObject];
  3222. }
  3223. Validator.parse(options, usedOptions, []);
  3224. return errorFound;
  3225. }
  3226. /**
  3227. * Will traverse an object recursively and check every value
  3228. * @param {Object} options
  3229. * @param {Object} referenceOptions
  3230. * @param {array} path | where to look for the actual option
  3231. * @static
  3232. */
  3233. }, {
  3234. key: 'parse',
  3235. value: function parse(options, referenceOptions, path) {
  3236. for (var option in options) {
  3237. if (options.hasOwnProperty(option)) {
  3238. Validator.check(option, options, referenceOptions, path);
  3239. }
  3240. }
  3241. }
  3242. /**
  3243. * Check every value. If the value is an object, call the parse function on that object.
  3244. * @param {string} option
  3245. * @param {Object} options
  3246. * @param {Object} referenceOptions
  3247. * @param {array} path | where to look for the actual option
  3248. * @static
  3249. */
  3250. }, {
  3251. key: 'check',
  3252. value: function check(option, options, referenceOptions, path) {
  3253. if (referenceOptions[option] === undefined && referenceOptions.__any__ === undefined) {
  3254. Validator.getSuggestion(option, referenceOptions, path);
  3255. return;
  3256. }
  3257. var referenceOption = option;
  3258. var is_object = true;
  3259. if (referenceOptions[option] === undefined && referenceOptions.__any__ !== undefined) {
  3260. // NOTE: This only triggers if the __any__ is in the top level of the options object.
  3261. // THAT'S A REALLY BAD PLACE TO ALLOW IT!!!!
  3262. // TODO: Examine if needed, remove if possible
  3263. // __any__ is a wildcard. Any value is accepted and will be further analysed by reference.
  3264. referenceOption = '__any__';
  3265. // if the any-subgroup is not a predefined object in the configurator,
  3266. // we do not look deeper into the object.
  3267. is_object = Validator.getType(options[option]) === 'object';
  3268. } else {
  3269. // Since all options in the reference are objects, we can check whether
  3270. // they are supposed to be the object to look for the __type__ field.
  3271. // if this is an object, we check if the correct type has been supplied to account for shorthand options.
  3272. }
  3273. var refOptionObj = referenceOptions[referenceOption];
  3274. if (is_object && refOptionObj.__type__ !== undefined) {
  3275. refOptionObj = refOptionObj.__type__;
  3276. }
  3277. Validator.checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path);
  3278. }
  3279. /**
  3280. *
  3281. * @param {string} option | the option property
  3282. * @param {Object} options | The supplied options object
  3283. * @param {Object} referenceOptions | The reference options containing all options and their allowed formats
  3284. * @param {string} referenceOption | Usually this is the same as option, except when handling an __any__ tag.
  3285. * @param {string} refOptionObj | This is the type object from the reference options
  3286. * @param {Array} path | where in the object is the option
  3287. * @static
  3288. */
  3289. }, {
  3290. key: 'checkFields',
  3291. value: function checkFields(option, options, referenceOptions, referenceOption, refOptionObj, path) {
  3292. var log = function log(message) {
  3293. console.log('%c' + message + Validator.printLocation(path, option), printStyle);
  3294. };
  3295. var optionType = Validator.getType(options[option]);
  3296. var refOptionType = refOptionObj[optionType];
  3297. if (refOptionType !== undefined) {
  3298. // if the type is correct, we check if it is supposed to be one of a few select values
  3299. if (Validator.getType(refOptionType) === 'array' && refOptionType.indexOf(options[option]) === -1) {
  3300. log('Invalid option detected in "' + option + '".' + ' Allowed values are:' + Validator.print(refOptionType) + ' not "' + options[option] + '". ');
  3301. errorFound = true;
  3302. } else if (optionType === 'object' && referenceOption !== "__any__") {
  3303. path = util.copyAndExtendArray(path, option);
  3304. Validator.parse(options[option], referenceOptions[referenceOption], path);
  3305. }
  3306. } else if (refOptionObj['any'] === undefined) {
  3307. // type of the field is incorrect and the field cannot be any
  3308. log('Invalid type received for "' + option + '". Expected: ' + Validator.print((0, _keys2['default'])(refOptionObj)) + '. Received [' + optionType + '] "' + options[option] + '"');
  3309. errorFound = true;
  3310. }
  3311. }
  3312. /**
  3313. *
  3314. * @param {Object|boolean|number|string|Array.<number>|Date|Node|Moment|undefined|null} object
  3315. * @returns {string}
  3316. * @static
  3317. */
  3318. }, {
  3319. key: 'getType',
  3320. value: function getType(object) {
  3321. var type = typeof object === 'undefined' ? 'undefined' : (0, _typeof3['default'])(object);
  3322. if (type === 'object') {
  3323. if (object === null) {
  3324. return 'null';
  3325. }
  3326. if (object instanceof Boolean) {
  3327. return 'boolean';
  3328. }
  3329. if (object instanceof Number) {
  3330. return 'number';
  3331. }
  3332. if (object instanceof String) {
  3333. return 'string';
  3334. }
  3335. if (Array.isArray(object)) {
  3336. return 'array';
  3337. }
  3338. if (object instanceof Date) {
  3339. return 'date';
  3340. }
  3341. if (object.nodeType !== undefined) {
  3342. return 'dom';
  3343. }
  3344. if (object._isAMomentObject === true) {
  3345. return 'moment';
  3346. }
  3347. return 'object';
  3348. } else if (type === 'number') {
  3349. return 'number';
  3350. } else if (type === 'boolean') {
  3351. return 'boolean';
  3352. } else if (type === 'string') {
  3353. return 'string';
  3354. } else if (type === undefined) {
  3355. return 'undefined';
  3356. }
  3357. return type;
  3358. }
  3359. /**
  3360. * @param {string} option
  3361. * @param {Object} options
  3362. * @param {Array.<string>} path
  3363. * @static
  3364. */
  3365. }, {
  3366. key: 'getSuggestion',
  3367. value: function getSuggestion(option, options, path) {
  3368. var localSearch = Validator.findInOptions(option, options, path, false);
  3369. var globalSearch = Validator.findInOptions(option, allOptions, [], true);
  3370. var localSearchThreshold = 8;
  3371. var globalSearchThreshold = 4;
  3372. var msg = void 0;
  3373. if (localSearch.indexMatch !== undefined) {
  3374. msg = ' in ' + Validator.printLocation(localSearch.path, option, '') + 'Perhaps it was incomplete? Did you mean: "' + localSearch.indexMatch + '"?\n\n';
  3375. } else if (globalSearch.distance <= globalSearchThreshold && localSearch.distance > globalSearch.distance) {
  3376. msg = ' in ' + Validator.printLocation(localSearch.path, option, '') + 'Perhaps it was misplaced? Matching option found at: ' + Validator.printLocation(globalSearch.path, globalSearch.closestMatch, '');
  3377. } else if (localSearch.distance <= localSearchThreshold) {
  3378. msg = '. Did you mean "' + localSearch.closestMatch + '"?' + Validator.printLocation(localSearch.path, option);
  3379. } else {
  3380. msg = '. Did you mean one of these: ' + Validator.print((0, _keys2['default'])(options)) + Validator.printLocation(path, option);
  3381. }
  3382. console.log('%cUnknown option detected: "' + option + '"' + msg, printStyle);
  3383. errorFound = true;
  3384. }
  3385. /**
  3386. * traverse the options in search for a match.
  3387. * @param {string} option
  3388. * @param {Object} options
  3389. * @param {Array} path | where to look for the actual option
  3390. * @param {boolean} [recursive=false]
  3391. * @returns {{closestMatch: string, path: Array, distance: number}}
  3392. * @static
  3393. */
  3394. }, {
  3395. key: 'findInOptions',
  3396. value: function findInOptions(option, options, path) {
  3397. var recursive = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
  3398. var min = 1e9;
  3399. var closestMatch = '';
  3400. var closestMatchPath = [];
  3401. var lowerCaseOption = option.toLowerCase();
  3402. var indexMatch = undefined;
  3403. for (var op in options) {
  3404. // eslint-disable-line guard-for-in
  3405. var distance = void 0;
  3406. if (options[op].__type__ !== undefined && recursive === true) {
  3407. var result = Validator.findInOptions(option, options[op], util.copyAndExtendArray(path, op));
  3408. if (min > result.distance) {
  3409. closestMatch = result.closestMatch;
  3410. closestMatchPath = result.path;
  3411. min = result.distance;
  3412. indexMatch = result.indexMatch;
  3413. }
  3414. } else {
  3415. if (op.toLowerCase().indexOf(lowerCaseOption) !== -1) {
  3416. indexMatch = op;
  3417. }
  3418. distance = Validator.levenshteinDistance(option, op);
  3419. if (min > distance) {
  3420. closestMatch = op;
  3421. closestMatchPath = util.copyArray(path);
  3422. min = distance;
  3423. }
  3424. }
  3425. }
  3426. return { closestMatch: closestMatch, path: closestMatchPath, distance: min, indexMatch: indexMatch };
  3427. }
  3428. /**
  3429. * @param {Array.<string>} path
  3430. * @param {Object} option
  3431. * @param {string} prefix
  3432. * @returns {String}
  3433. * @static
  3434. */
  3435. }, {
  3436. key: 'printLocation',
  3437. value: function printLocation(path, option) {
  3438. var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'Problem value found at: \n';
  3439. var str = '\n\n' + prefix + 'options = {\n';
  3440. for (var i = 0; i < path.length; i++) {
  3441. for (var j = 0; j < i + 1; j++) {
  3442. str += ' ';
  3443. }
  3444. str += path[i] + ': {\n';
  3445. }
  3446. for (var _j = 0; _j < path.length + 1; _j++) {
  3447. str += ' ';
  3448. }
  3449. str += option + '\n';
  3450. for (var _i = 0; _i < path.length + 1; _i++) {
  3451. for (var _j2 = 0; _j2 < path.length - _i; _j2++) {
  3452. str += ' ';
  3453. }
  3454. str += '}\n';
  3455. }
  3456. return str + '\n\n';
  3457. }
  3458. /**
  3459. * @param {Object} options
  3460. * @returns {String}
  3461. * @static
  3462. */
  3463. }, {
  3464. key: 'print',
  3465. value: function print(options) {
  3466. return (0, _stringify2['default'])(options).replace(/(\")|(\[)|(\])|(,"__type__")/g, "").replace(/(\,)/g, ', ');
  3467. }
  3468. /**
  3469. * Compute the edit distance between the two given strings
  3470. * http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript
  3471. *
  3472. * Copyright (c) 2011 Andrei Mackenzie
  3473. *
  3474. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  3475. *
  3476. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  3477. *
  3478. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  3479. *
  3480. * @param {string} a
  3481. * @param {string} b
  3482. * @returns {Array.<Array.<number>>}}
  3483. * @static
  3484. */
  3485. }, {
  3486. key: 'levenshteinDistance',
  3487. value: function levenshteinDistance(a, b) {
  3488. if (a.length === 0) return b.length;
  3489. if (b.length === 0) return a.length;
  3490. var matrix = [];
  3491. // increment along the first column of each row
  3492. var i;
  3493. for (i = 0; i <= b.length; i++) {
  3494. matrix[i] = [i];
  3495. }
  3496. // increment each column in the first row
  3497. var j;
  3498. for (j = 0; j <= a.length; j++) {
  3499. matrix[0][j] = j;
  3500. }
  3501. // Fill in the rest of the matrix
  3502. for (i = 1; i <= b.length; i++) {
  3503. for (j = 1; j <= a.length; j++) {
  3504. if (b.charAt(i - 1) == a.charAt(j - 1)) {
  3505. matrix[i][j] = matrix[i - 1][j - 1];
  3506. } else {
  3507. matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
  3508. Math.min(matrix[i][j - 1] + 1, // insertion
  3509. matrix[i - 1][j] + 1)); // deletion
  3510. }
  3511. }
  3512. }
  3513. return matrix[b.length][a.length];
  3514. }
  3515. }]);
  3516. return Validator;
  3517. }();
  3518. exports['default'] = Validator;
  3519. exports.printStyle = printStyle;
  3520. /***/
  3521. }),
  3522. /* 16 */
  3523. /***/
  3524. (function(module, exports, __webpack_require__) {
  3525. "use strict";
  3526. var util = __webpack_require__(2);
  3527. /**
  3528. * Prototype for visual components
  3529. * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} [body]
  3530. * @param {Object} [options]
  3531. */
  3532. function Component(body, options) {
  3533. // eslint-disable-line no-unused-vars
  3534. this.options = null;
  3535. this.props = null;
  3536. }
  3537. /**
  3538. * Set options for the component. The new options will be merged into the
  3539. * current options.
  3540. * @param {Object} options
  3541. */
  3542. Component.prototype.setOptions = function(options) {
  3543. if (options) {
  3544. util.extend(this.options, options);
  3545. }
  3546. };
  3547. /**
  3548. * Repaint the component
  3549. * @return {boolean} Returns true if the component is resized
  3550. */
  3551. Component.prototype.redraw = function() {
  3552. // should be implemented by the component
  3553. return false;
  3554. };
  3555. /**
  3556. * Destroy the component. Cleanup DOM and event listeners
  3557. */
  3558. Component.prototype.destroy = function() {
  3559. // should be implemented by the component
  3560. };
  3561. /**
  3562. * Test whether the component is resized since the last time _isResized() was
  3563. * called.
  3564. * @return {Boolean} Returns true if the component is resized
  3565. * @protected
  3566. */
  3567. Component.prototype._isResized = function() {
  3568. var resized = this.props._previousWidth !== this.props.width || this.props._previousHeight !== this.props.height;
  3569. this.props._previousWidth = this.props.width;
  3570. this.props._previousHeight = this.props.height;
  3571. return resized;
  3572. };
  3573. module.exports = Component;
  3574. /***/
  3575. }),
  3576. /* 17 */
  3577. /***/
  3578. (function(module, exports, __webpack_require__) {
  3579. var global = __webpack_require__(18);
  3580. var core = __webpack_require__(7);
  3581. var ctx = __webpack_require__(80);
  3582. var hide = __webpack_require__(26);
  3583. var PROTOTYPE = 'prototype';
  3584. var $export = function(type, name, source) {
  3585. var IS_FORCED = type & $export.F;
  3586. var IS_GLOBAL = type & $export.G;
  3587. var IS_STATIC = type & $export.S;
  3588. var IS_PROTO = type & $export.P;
  3589. var IS_BIND = type & $export.B;
  3590. var IS_WRAP = type & $export.W;
  3591. var exports = IS_GLOBAL ? core : core[name] || (core[name] = {});
  3592. var expProto = exports[PROTOTYPE];
  3593. var target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE];
  3594. var key, own, out;
  3595. if (IS_GLOBAL) source = name;
  3596. for (key in source) {
  3597. // contains in native
  3598. own = !IS_FORCED && target && target[key] !== undefined;
  3599. if (own && key in exports) continue;
  3600. // export native or passed
  3601. out = own ? target[key] : source[key];
  3602. // prevent global pollution for namespaces
  3603. exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key]
  3604. // bind timers to global for call from export context
  3605. :
  3606. IS_BIND && own ? ctx(out, global)
  3607. // wrap global constructors for prevent change them in library
  3608. :
  3609. IS_WRAP && target[key] == out ? (function(C) {
  3610. var F = function(a, b, c) {
  3611. if (this instanceof C) {
  3612. switch (arguments.length) {
  3613. case 0:
  3614. return new C();
  3615. case 1:
  3616. return new C(a);
  3617. case 2:
  3618. return new C(a, b);
  3619. }
  3620. return new C(a, b, c);
  3621. }
  3622. return C.apply(this, arguments);
  3623. };
  3624. F[PROTOTYPE] = C[PROTOTYPE];
  3625. return F;
  3626. // make static versions for prototype methods
  3627. })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;
  3628. // export proto methods to core.%CONSTRUCTOR%.methods.%NAME%
  3629. if (IS_PROTO) {
  3630. (exports.virtual || (exports.virtual = {}))[key] = out;
  3631. // export proto methods to core.%CONSTRUCTOR%.prototype.%NAME%
  3632. if (type & $export.R && expProto && !expProto[key]) hide(expProto, key, out);
  3633. }
  3634. }
  3635. };
  3636. // type bitmap
  3637. $export.F = 1; // forced
  3638. $export.G = 2; // global
  3639. $export.S = 4; // static
  3640. $export.P = 8; // proto
  3641. $export.B = 16; // bind
  3642. $export.W = 32; // wrap
  3643. $export.U = 64; // safe
  3644. $export.R = 128; // real proto method for `library`
  3645. module.exports = $export;
  3646. /***/
  3647. }),
  3648. /* 18 */
  3649. /***/
  3650. (function(module, exports) {
  3651. // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
  3652. var global = module.exports = typeof window != 'undefined' && window.Math == Math ?
  3653. window : typeof self != 'undefined' && self.Math == Math ? self
  3654. // eslint-disable-next-line no-new-func
  3655. :
  3656. Function('return this')();
  3657. if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef
  3658. /***/
  3659. }),
  3660. /* 19 */
  3661. /***/
  3662. (function(module, exports, __webpack_require__) {
  3663. module.exports = { "default": __webpack_require__(160), __esModule: true };
  3664. /***/
  3665. }),
  3666. /* 20 */
  3667. /***/
  3668. (function(module, exports, __webpack_require__) {
  3669. var anObject = __webpack_require__(27);
  3670. var IE8_DOM_DEFINE = __webpack_require__(81);
  3671. var toPrimitive = __webpack_require__(53);
  3672. var dP = Object.defineProperty;
  3673. exports.f = __webpack_require__(21) ? Object.defineProperty : function defineProperty(O, P, Attributes) {
  3674. anObject(O);
  3675. P = toPrimitive(P, true);
  3676. anObject(Attributes);
  3677. if (IE8_DOM_DEFINE) try {
  3678. return dP(O, P, Attributes);
  3679. } catch (e) { /* empty */ }
  3680. if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!');
  3681. if ('value' in Attributes) O[P] = Attributes.value;
  3682. return O;
  3683. };
  3684. /***/
  3685. }),
  3686. /* 21 */
  3687. /***/
  3688. (function(module, exports, __webpack_require__) {
  3689. // Thank's IE8 for his funny defineProperty
  3690. module.exports = !__webpack_require__(28)(function() {
  3691. return Object.defineProperty({}, 'a', { get: function() { return 7; } }).a != 7;
  3692. });
  3693. /***/
  3694. }),
  3695. /* 22 */
  3696. /***/
  3697. (function(module, exports) {
  3698. var hasOwnProperty = {}.hasOwnProperty;
  3699. module.exports = function(it, key) {
  3700. return hasOwnProperty.call(it, key);
  3701. };
  3702. /***/
  3703. }),
  3704. /* 23 */
  3705. /***/
  3706. (function(module, exports, __webpack_require__) {
  3707. "use strict";
  3708. Object.defineProperty(exports, "__esModule", {
  3709. value: true
  3710. });
  3711. var _typeof2 = __webpack_require__(6);
  3712. var _typeof3 = _interopRequireDefault(_typeof2);
  3713. var _classCallCheck2 = __webpack_require__(0);
  3714. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  3715. var _createClass2 = __webpack_require__(1);
  3716. var _createClass3 = _interopRequireDefault(_createClass2);
  3717. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  3718. /**
  3719. * The Base class for all Nodes.
  3720. */
  3721. var NodeBase = function() {
  3722. /**
  3723. * @param {Object} options
  3724. * @param {Object} body
  3725. * @param {Label} labelModule
  3726. */
  3727. function NodeBase(options, body, labelModule) {
  3728. (0, _classCallCheck3['default'])(this, NodeBase);
  3729. this.body = body;
  3730. this.labelModule = labelModule;
  3731. this.setOptions(options);
  3732. this.top = undefined;
  3733. this.left = undefined;
  3734. this.height = undefined;
  3735. this.width = undefined;
  3736. this.radius = undefined;
  3737. this.margin = undefined;
  3738. this.refreshNeeded = true;
  3739. this.boundingBox = { top: 0, left: 0, right: 0, bottom: 0 };
  3740. }
  3741. /**
  3742. *
  3743. * @param {Object} options
  3744. */
  3745. (0, _createClass3['default'])(NodeBase, [{
  3746. key: 'setOptions',
  3747. value: function setOptions(options) {
  3748. this.options = options;
  3749. }
  3750. /**
  3751. *
  3752. * @param {Label} labelModule
  3753. * @private
  3754. */
  3755. }, {
  3756. key: '_setMargins',
  3757. value: function _setMargins(labelModule) {
  3758. this.margin = {};
  3759. if (this.options.margin) {
  3760. if ((0, _typeof3['default'])(this.options.margin) == 'object') {
  3761. this.margin.top = this.options.margin.top;
  3762. this.margin.right = this.options.margin.right;
  3763. this.margin.bottom = this.options.margin.bottom;
  3764. this.margin.left = this.options.margin.left;
  3765. } else {
  3766. this.margin.top = this.options.margin;
  3767. this.margin.right = this.options.margin;
  3768. this.margin.bottom = this.options.margin;
  3769. this.margin.left = this.options.margin;
  3770. }
  3771. }
  3772. labelModule.adjustSizes(this.margin);
  3773. }
  3774. /**
  3775. *
  3776. * @param {CanvasRenderingContext2D} ctx
  3777. * @param {number} angle
  3778. * @returns {number}
  3779. * @private
  3780. */
  3781. }, {
  3782. key: '_distanceToBorder',
  3783. value: function _distanceToBorder(ctx, angle) {
  3784. var borderWidth = this.options.borderWidth;
  3785. this.resize(ctx);
  3786. return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
  3787. }
  3788. /**
  3789. *
  3790. * @param {CanvasRenderingContext2D} ctx
  3791. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  3792. */
  3793. }, {
  3794. key: 'enableShadow',
  3795. value: function enableShadow(ctx, values) {
  3796. if (values.shadow) {
  3797. ctx.shadowColor = values.shadowColor;
  3798. ctx.shadowBlur = values.shadowSize;
  3799. ctx.shadowOffsetX = values.shadowX;
  3800. ctx.shadowOffsetY = values.shadowY;
  3801. }
  3802. }
  3803. /**
  3804. *
  3805. * @param {CanvasRenderingContext2D} ctx
  3806. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  3807. */
  3808. }, {
  3809. key: 'disableShadow',
  3810. value: function disableShadow(ctx, values) {
  3811. if (values.shadow) {
  3812. ctx.shadowColor = 'rgba(0,0,0,0)';
  3813. ctx.shadowBlur = 0;
  3814. ctx.shadowOffsetX = 0;
  3815. ctx.shadowOffsetY = 0;
  3816. }
  3817. }
  3818. /**
  3819. *
  3820. * @param {CanvasRenderingContext2D} ctx
  3821. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  3822. */
  3823. }, {
  3824. key: 'enableBorderDashes',
  3825. value: function enableBorderDashes(ctx, values) {
  3826. if (values.borderDashes !== false) {
  3827. if (ctx.setLineDash !== undefined) {
  3828. var dashes = values.borderDashes;
  3829. if (dashes === true) {
  3830. dashes = [5, 15];
  3831. }
  3832. ctx.setLineDash(dashes);
  3833. } else {
  3834. console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
  3835. this.options.shapeProperties.borderDashes = false;
  3836. values.borderDashes = false;
  3837. }
  3838. }
  3839. }
  3840. /**
  3841. *
  3842. * @param {CanvasRenderingContext2D} ctx
  3843. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  3844. */
  3845. }, {
  3846. key: 'disableBorderDashes',
  3847. value: function disableBorderDashes(ctx, values) {
  3848. if (values.borderDashes !== false) {
  3849. if (ctx.setLineDash !== undefined) {
  3850. ctx.setLineDash([0]);
  3851. } else {
  3852. console.warn("setLineDash is not supported in this browser. The dashed borders cannot be used.");
  3853. this.options.shapeProperties.borderDashes = false;
  3854. values.borderDashes = false;
  3855. }
  3856. }
  3857. }
  3858. /**
  3859. * Determine if the shape of a node needs to be recalculated.
  3860. *
  3861. * @param {boolean} selected
  3862. * @param {boolean} hover
  3863. * @returns {boolean}
  3864. * @protected
  3865. */
  3866. }, {
  3867. key: 'needsRefresh',
  3868. value: function needsRefresh(selected, hover) {
  3869. if (this.refreshNeeded === true) {
  3870. // This is probably not the best location to reset this member.
  3871. // However, in the current logic, it is the most convenient one.
  3872. this.refreshNeeded = false;
  3873. return true;
  3874. }
  3875. return this.width === undefined || this.labelModule.differentState(selected, hover);
  3876. }
  3877. /**
  3878. *
  3879. * @param {CanvasRenderingContext2D} ctx
  3880. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  3881. */
  3882. }, {
  3883. key: 'initContextForDraw',
  3884. value: function initContextForDraw(ctx, values) {
  3885. var borderWidth = values.borderWidth / this.body.view.scale;
  3886. ctx.lineWidth = Math.min(this.width, borderWidth);
  3887. ctx.strokeStyle = values.borderColor;
  3888. ctx.fillStyle = values.color;
  3889. }
  3890. /**
  3891. *
  3892. * @param {CanvasRenderingContext2D} ctx
  3893. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  3894. */
  3895. }, {
  3896. key: 'performStroke',
  3897. value: function performStroke(ctx, values) {
  3898. var borderWidth = values.borderWidth / this.body.view.scale;
  3899. //draw dashed border if enabled, save and restore is required for firefox not to crash on unix.
  3900. ctx.save();
  3901. // if borders are zero width, they will be drawn with width 1 by default. This prevents that
  3902. if (borderWidth > 0) {
  3903. this.enableBorderDashes(ctx, values);
  3904. //draw the border
  3905. ctx.stroke();
  3906. //disable dashed border for other elements
  3907. this.disableBorderDashes(ctx, values);
  3908. }
  3909. ctx.restore();
  3910. }
  3911. /**
  3912. *
  3913. * @param {CanvasRenderingContext2D} ctx
  3914. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  3915. */
  3916. }, {
  3917. key: 'performFill',
  3918. value: function performFill(ctx, values) {
  3919. // draw shadow if enabled
  3920. this.enableShadow(ctx, values);
  3921. // draw the background
  3922. ctx.fill();
  3923. // disable shadows for other elements.
  3924. this.disableShadow(ctx, values);
  3925. this.performStroke(ctx, values);
  3926. }
  3927. /**
  3928. *
  3929. * @param {number} margin
  3930. * @private
  3931. */
  3932. }, {
  3933. key: '_addBoundingBoxMargin',
  3934. value: function _addBoundingBoxMargin(margin) {
  3935. this.boundingBox.left -= margin;
  3936. this.boundingBox.top -= margin;
  3937. this.boundingBox.bottom += margin;
  3938. this.boundingBox.right += margin;
  3939. }
  3940. /**
  3941. * Actual implementation of this method call.
  3942. *
  3943. * Doing it like this makes it easier to override
  3944. * in the child classes.
  3945. *
  3946. * @param {number} x width
  3947. * @param {number} y height
  3948. * @param {CanvasRenderingContext2D} ctx
  3949. * @param {boolean} selected
  3950. * @param {boolean} hover
  3951. * @private
  3952. */
  3953. }, {
  3954. key: '_updateBoundingBox',
  3955. value: function _updateBoundingBox(x, y, ctx, selected, hover) {
  3956. if (ctx !== undefined) {
  3957. this.resize(ctx, selected, hover);
  3958. }
  3959. this.left = x - this.width / 2;
  3960. this.top = y - this.height / 2;
  3961. this.boundingBox.left = this.left;
  3962. this.boundingBox.top = this.top;
  3963. this.boundingBox.bottom = this.top + this.height;
  3964. this.boundingBox.right = this.left + this.width;
  3965. }
  3966. /**
  3967. * Default implementation of this method call.
  3968. * This acts as a stub which can be overridden.
  3969. *
  3970. * @param {number} x width
  3971. * @param {number} y height
  3972. * @param {CanvasRenderingContext2D} ctx
  3973. * @param {boolean} selected
  3974. * @param {boolean} hover
  3975. */
  3976. }, {
  3977. key: 'updateBoundingBox',
  3978. value: function updateBoundingBox(x, y, ctx, selected, hover) {
  3979. this._updateBoundingBox(x, y, ctx, selected, hover);
  3980. }
  3981. /**
  3982. * Determine the dimensions to use for nodes with an internal label
  3983. *
  3984. * Currently, these are: Circle, Ellipse, Database, Box
  3985. * The other nodes have external labels, and will not call this method
  3986. *
  3987. * If there is no label, decent default values are supplied.
  3988. *
  3989. * @param {CanvasRenderingContext2D} ctx
  3990. * @param {boolean} [selected]
  3991. * @param {boolean} [hover]
  3992. * @returns {{width:number, height:number}}
  3993. */
  3994. }, {
  3995. key: 'getDimensionsFromLabel',
  3996. value: function getDimensionsFromLabel(ctx, selected, hover) {
  3997. // NOTE: previously 'textSize' was not put in 'this' for Ellipse
  3998. // TODO: examine the consequences.
  3999. this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
  4000. var width = this.textSize.width;
  4001. var height = this.textSize.height;
  4002. var DEFAULT_SIZE = 14;
  4003. if (width === 0) {
  4004. // This happens when there is no label text set
  4005. width = DEFAULT_SIZE; // use a decent default
  4006. height = DEFAULT_SIZE; // if width zero, then height also always zero
  4007. }
  4008. return { width: width, height: height };
  4009. }
  4010. }]);
  4011. return NodeBase;
  4012. }();
  4013. exports['default'] = NodeBase;
  4014. /***/
  4015. }),
  4016. /* 24 */
  4017. /***/
  4018. (function(module, exports, __webpack_require__) {
  4019. "use strict";
  4020. Object.defineProperty(exports, "__esModule", {
  4021. value: true
  4022. });
  4023. var _getPrototypeOf = __webpack_require__(3);
  4024. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  4025. var _classCallCheck2 = __webpack_require__(0);
  4026. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  4027. var _createClass2 = __webpack_require__(1);
  4028. var _createClass3 = _interopRequireDefault(_createClass2);
  4029. var _possibleConstructorReturn2 = __webpack_require__(4);
  4030. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  4031. var _inherits2 = __webpack_require__(5);
  4032. var _inherits3 = _interopRequireDefault(_inherits2);
  4033. var _NodeBase2 = __webpack_require__(23);
  4034. var _NodeBase3 = _interopRequireDefault(_NodeBase2);
  4035. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  4036. /**
  4037. * Base class for constructing Node/Cluster Shapes.
  4038. *
  4039. * @extends NodeBase
  4040. */
  4041. var ShapeBase = function(_NodeBase) {
  4042. (0, _inherits3['default'])(ShapeBase, _NodeBase);
  4043. /**
  4044. * @param {Object} options
  4045. * @param {Object} body
  4046. * @param {Label} labelModule
  4047. */
  4048. function ShapeBase(options, body, labelModule) {
  4049. (0, _classCallCheck3['default'])(this, ShapeBase);
  4050. return (0, _possibleConstructorReturn3['default'])(this, (ShapeBase.__proto__ || (0, _getPrototypeOf2['default'])(ShapeBase)).call(this, options, body, labelModule));
  4051. }
  4052. /**
  4053. *
  4054. * @param {CanvasRenderingContext2D} ctx
  4055. * @param {boolean} [selected]
  4056. * @param {boolean} [hover]
  4057. * @param {Object} [values={size: this.options.size}]
  4058. */
  4059. (0, _createClass3['default'])(ShapeBase, [{
  4060. key: 'resize',
  4061. value: function resize(ctx) {
  4062. var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
  4063. var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
  4064. var values = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : { size: this.options.size };
  4065. if (this.needsRefresh(selected, hover)) {
  4066. this.labelModule.getTextSize(ctx, selected, hover);
  4067. var size = 2 * values.size;
  4068. this.width = size;
  4069. this.height = size;
  4070. this.radius = 0.5 * this.width;
  4071. }
  4072. }
  4073. /**
  4074. *
  4075. * @param {CanvasRenderingContext2D} ctx
  4076. * @param {string} shape
  4077. * @param {number} sizeMultiplier - Unused! TODO: Remove next major release
  4078. * @param {number} x
  4079. * @param {number} y
  4080. * @param {boolean} selected
  4081. * @param {boolean} hover
  4082. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  4083. * @private
  4084. */
  4085. }, {
  4086. key: '_drawShape',
  4087. value: function _drawShape(ctx, shape, sizeMultiplier, x, y, selected, hover, values) {
  4088. this.resize(ctx, selected, hover, values);
  4089. this.left = x - this.width / 2;
  4090. this.top = y - this.height / 2;
  4091. this.initContextForDraw(ctx, values);
  4092. ctx[shape](x, y, values.size);
  4093. this.performFill(ctx, values);
  4094. if (this.options.label !== undefined) {
  4095. // Need to call following here in order to ensure value for `this.labelModule.size.height`
  4096. this.labelModule.calculateLabelSize(ctx, selected, hover, x, y, 'hanging');
  4097. var yLabel = y + 0.5 * this.height + 0.5 * this.labelModule.size.height;
  4098. this.labelModule.draw(ctx, x, yLabel, selected, hover, 'hanging');
  4099. }
  4100. this.updateBoundingBox(x, y);
  4101. }
  4102. /**
  4103. *
  4104. * @param {number} x
  4105. * @param {number} y
  4106. */
  4107. }, {
  4108. key: 'updateBoundingBox',
  4109. value: function updateBoundingBox(x, y) {
  4110. this.boundingBox.top = y - this.options.size;
  4111. this.boundingBox.left = x - this.options.size;
  4112. this.boundingBox.right = x + this.options.size;
  4113. this.boundingBox.bottom = y + this.options.size;
  4114. if (this.options.label !== undefined && this.labelModule.size.width > 0) {
  4115. this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
  4116. this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
  4117. this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height);
  4118. }
  4119. }
  4120. }]);
  4121. return ShapeBase;
  4122. }(_NodeBase3['default']);
  4123. exports['default'] = ShapeBase;
  4124. /***/
  4125. }),
  4126. /* 25 */
  4127. /***/
  4128. (function(module, exports, __webpack_require__) {
  4129. // to indexed object, toObject with fallback for non-array-like ES3 strings
  4130. var IObject = __webpack_require__(78);
  4131. var defined = __webpack_require__(51);
  4132. module.exports = function(it) {
  4133. return IObject(defined(it));
  4134. };
  4135. /***/
  4136. }),
  4137. /* 26 */
  4138. /***/
  4139. (function(module, exports, __webpack_require__) {
  4140. var dP = __webpack_require__(20);
  4141. var createDesc = __webpack_require__(39);
  4142. module.exports = __webpack_require__(21) ? function(object, key, value) {
  4143. return dP.f(object, key, createDesc(1, value));
  4144. } : function(object, key, value) {
  4145. object[key] = value;
  4146. return object;
  4147. };
  4148. /***/
  4149. }),
  4150. /* 27 */
  4151. /***/
  4152. (function(module, exports, __webpack_require__) {
  4153. var isObject = __webpack_require__(32);
  4154. module.exports = function(it) {
  4155. if (!isObject(it)) throw TypeError(it + ' is not an object!');
  4156. return it;
  4157. };
  4158. /***/
  4159. }),
  4160. /* 28 */
  4161. /***/
  4162. (function(module, exports) {
  4163. module.exports = function(exec) {
  4164. try {
  4165. return !!exec();
  4166. } catch (e) {
  4167. return true;
  4168. }
  4169. };
  4170. /***/
  4171. }),
  4172. /* 29 */
  4173. /***/
  4174. (function(module, exports, __webpack_require__) {
  4175. module.exports = { "default": __webpack_require__(138), __esModule: true };
  4176. /***/
  4177. }),
  4178. /* 30 */
  4179. /***/
  4180. (function(module, exports, __webpack_require__) {
  4181. "use strict";
  4182. exports.__esModule = true;
  4183. var _isIterable2 = __webpack_require__(188);
  4184. var _isIterable3 = _interopRequireDefault(_isIterable2);
  4185. var _getIterator2 = __webpack_require__(77);
  4186. var _getIterator3 = _interopRequireDefault(_getIterator2);
  4187. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  4188. exports.default = function() {
  4189. function sliceIterator(arr, i) {
  4190. var _arr = [];
  4191. var _n = true;
  4192. var _d = false;
  4193. var _e = undefined;
  4194. try {
  4195. for (var _i = (0, _getIterator3.default)(arr), _s; !(_n = (_s = _i.next()).done); _n = true) {
  4196. _arr.push(_s.value);
  4197. if (i && _arr.length === i) break;
  4198. }
  4199. } catch (err) {
  4200. _d = true;
  4201. _e = err;
  4202. } finally {
  4203. try {
  4204. if (!_n && _i["return"]) _i["return"]();
  4205. } finally {
  4206. if (_d) throw _e;
  4207. }
  4208. }
  4209. return _arr;
  4210. }
  4211. return function(arr, i) {
  4212. if (Array.isArray(arr)) {
  4213. return arr;
  4214. } else if ((0, _isIterable3.default)(Object(arr))) {
  4215. return sliceIterator(arr, i);
  4216. } else {
  4217. throw new TypeError("Invalid attempt to destructure non-iterable instance");
  4218. }
  4219. };
  4220. }();
  4221. /***/
  4222. }),
  4223. /* 31 */
  4224. /***/
  4225. (function(module, exports) {
  4226. module.exports = {};
  4227. /***/
  4228. }),
  4229. /* 32 */
  4230. /***/
  4231. (function(module, exports) {
  4232. module.exports = function(it) {
  4233. return typeof it === 'object' ? it !== null : typeof it === 'function';
  4234. };
  4235. /***/
  4236. }),
  4237. /* 33 */
  4238. /***/
  4239. (function(module, exports, __webpack_require__) {
  4240. // 19.1.2.14 / 15.2.3.14 Object.keys(O)
  4241. var $keys = __webpack_require__(84);
  4242. var enumBugKeys = __webpack_require__(58);
  4243. module.exports = Object.keys || function keys(O) {
  4244. return $keys(O, enumBugKeys);
  4245. };
  4246. /***/
  4247. }),
  4248. /* 34 */
  4249. /***/
  4250. (function(module, exports, __webpack_require__) {
  4251. "use strict";
  4252. /**
  4253. * @prototype Point3d
  4254. * @param {number} [x]
  4255. * @param {number} [y]
  4256. * @param {number} [z]
  4257. */
  4258. function Point3d(x, y, z) {
  4259. this.x = x !== undefined ? x : 0;
  4260. this.y = y !== undefined ? y : 0;
  4261. this.z = z !== undefined ? z : 0;
  4262. }
  4263. /**
  4264. * Subtract the two provided points, returns a-b
  4265. * @param {Point3d} a
  4266. * @param {Point3d} b
  4267. * @return {Point3d} a-b
  4268. */
  4269. Point3d.subtract = function(a, b) {
  4270. var sub = new Point3d();
  4271. sub.x = a.x - b.x;
  4272. sub.y = a.y - b.y;
  4273. sub.z = a.z - b.z;
  4274. return sub;
  4275. };
  4276. /**
  4277. * Add the two provided points, returns a+b
  4278. * @param {Point3d} a
  4279. * @param {Point3d} b
  4280. * @return {Point3d} a+b
  4281. */
  4282. Point3d.add = function(a, b) {
  4283. var sum = new Point3d();
  4284. sum.x = a.x + b.x;
  4285. sum.y = a.y + b.y;
  4286. sum.z = a.z + b.z;
  4287. return sum;
  4288. };
  4289. /**
  4290. * Calculate the average of two 3d points
  4291. * @param {Point3d} a
  4292. * @param {Point3d} b
  4293. * @return {Point3d} The average, (a+b)/2
  4294. */
  4295. Point3d.avg = function(a, b) {
  4296. return new Point3d((a.x + b.x) / 2, (a.y + b.y) / 2, (a.z + b.z) / 2);
  4297. };
  4298. /**
  4299. * Calculate the cross product of the two provided points, returns axb
  4300. * Documentation: http://en.wikipedia.org/wiki/Cross_product
  4301. * @param {Point3d} a
  4302. * @param {Point3d} b
  4303. * @return {Point3d} cross product axb
  4304. */
  4305. Point3d.crossProduct = function(a, b) {
  4306. var crossproduct = new Point3d();
  4307. crossproduct.x = a.y * b.z - a.z * b.y;
  4308. crossproduct.y = a.z * b.x - a.x * b.z;
  4309. crossproduct.z = a.x * b.y - a.y * b.x;
  4310. return crossproduct;
  4311. };
  4312. /**
  4313. * Rtrieve the length of the vector (or the distance from this point to the origin
  4314. * @return {number} length
  4315. */
  4316. Point3d.prototype.length = function() {
  4317. return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
  4318. };
  4319. module.exports = Point3d;
  4320. /***/
  4321. }),
  4322. /* 35 */
  4323. /***/
  4324. (function(module, exports, __webpack_require__) {
  4325. "use strict";
  4326. var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;
  4327. /**
  4328. * Created by Alex on 11/6/2014.
  4329. */
  4330. // https://github.com/umdjs/umd/blob/master/returnExports.js#L40-L60
  4331. // if the module has no dependencies, the above pattern can be simplified to
  4332. (function(root, factory) {
  4333. if (true) {
  4334. // AMD. Register as an anonymous module.
  4335. !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
  4336. __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
  4337. (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
  4338. __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  4339. } else if (typeof exports === 'object') {
  4340. // Node. Does not work with strict CommonJS, but
  4341. // only CommonJS-like environments that support module.exports,
  4342. // like Node.
  4343. module.exports = factory();
  4344. } else {
  4345. // Browser globals (root is window)
  4346. root.keycharm = factory();
  4347. }
  4348. }(this, function() {
  4349. function keycharm(options) {
  4350. var preventDefault = options && options.preventDefault || false;
  4351. var container = options && options.container || window;
  4352. var _exportFunctions = {};
  4353. var _bound = { keydown: {}, keyup: {} };
  4354. var _keys = {};
  4355. var i;
  4356. // a - z
  4357. for (i = 97; i <= 122; i++) { _keys[String.fromCharCode(i)] = { code: 65 + (i - 97), shift: false }; }
  4358. // A - Z
  4359. for (i = 65; i <= 90; i++) { _keys[String.fromCharCode(i)] = { code: i, shift: true }; }
  4360. // 0 - 9
  4361. for (i = 0; i <= 9; i++) { _keys['' + i] = { code: 48 + i, shift: false }; }
  4362. // F1 - F12
  4363. for (i = 1; i <= 12; i++) { _keys['F' + i] = { code: 111 + i, shift: false }; }
  4364. // num0 - num9
  4365. for (i = 0; i <= 9; i++) { _keys['num' + i] = { code: 96 + i, shift: false }; }
  4366. // numpad misc
  4367. _keys['num*'] = { code: 106, shift: false };
  4368. _keys['num+'] = { code: 107, shift: false };
  4369. _keys['num-'] = { code: 109, shift: false };
  4370. _keys['num/'] = { code: 111, shift: false };
  4371. _keys['num.'] = { code: 110, shift: false };
  4372. // arrows
  4373. _keys['left'] = { code: 37, shift: false };
  4374. _keys['up'] = { code: 38, shift: false };
  4375. _keys['right'] = { code: 39, shift: false };
  4376. _keys['down'] = { code: 40, shift: false };
  4377. // extra keys
  4378. _keys['space'] = { code: 32, shift: false };
  4379. _keys['enter'] = { code: 13, shift: false };
  4380. _keys['shift'] = { code: 16, shift: undefined };
  4381. _keys['esc'] = { code: 27, shift: false };
  4382. _keys['backspace'] = { code: 8, shift: false };
  4383. _keys['tab'] = { code: 9, shift: false };
  4384. _keys['ctrl'] = { code: 17, shift: false };
  4385. _keys['alt'] = { code: 18, shift: false };
  4386. _keys['delete'] = { code: 46, shift: false };
  4387. _keys['pageup'] = { code: 33, shift: false };
  4388. _keys['pagedown'] = { code: 34, shift: false };
  4389. // symbols
  4390. _keys['='] = { code: 187, shift: false };
  4391. _keys['-'] = { code: 189, shift: false };
  4392. _keys[']'] = { code: 221, shift: false };
  4393. _keys['['] = { code: 219, shift: false };
  4394. var down = function(event) { handleEvent(event, 'keydown'); };
  4395. var up = function(event) { handleEvent(event, 'keyup'); };
  4396. // handle the actualy bound key with the event
  4397. var handleEvent = function(event, type) {
  4398. if (_bound[type][event.keyCode] !== undefined) {
  4399. var bound = _bound[type][event.keyCode];
  4400. for (var i = 0; i < bound.length; i++) {
  4401. if (bound[i].shift === undefined) {
  4402. bound[i].fn(event);
  4403. } else if (bound[i].shift == true && event.shiftKey == true) {
  4404. bound[i].fn(event);
  4405. } else if (bound[i].shift == false && event.shiftKey == false) {
  4406. bound[i].fn(event);
  4407. }
  4408. }
  4409. if (preventDefault == true) {
  4410. event.preventDefault();
  4411. }
  4412. }
  4413. };
  4414. // bind a key to a callback
  4415. _exportFunctions.bind = function(key, callback, type) {
  4416. if (type === undefined) {
  4417. type = 'keydown';
  4418. }
  4419. if (_keys[key] === undefined) {
  4420. throw new Error("unsupported key: " + key);
  4421. }
  4422. if (_bound[type][_keys[key].code] === undefined) {
  4423. _bound[type][_keys[key].code] = [];
  4424. }
  4425. _bound[type][_keys[key].code].push({ fn: callback, shift: _keys[key].shift });
  4426. };
  4427. // bind all keys to a call back (demo purposes)
  4428. _exportFunctions.bindAll = function(callback, type) {
  4429. if (type === undefined) {
  4430. type = 'keydown';
  4431. }
  4432. for (var key in _keys) {
  4433. if (_keys.hasOwnProperty(key)) {
  4434. _exportFunctions.bind(key, callback, type);
  4435. }
  4436. }
  4437. };
  4438. // get the key label from an event
  4439. _exportFunctions.getKey = function(event) {
  4440. for (var key in _keys) {
  4441. if (_keys.hasOwnProperty(key)) {
  4442. if (event.shiftKey == true && _keys[key].shift == true && event.keyCode == _keys[key].code) {
  4443. return key;
  4444. } else if (event.shiftKey == false && _keys[key].shift == false && event.keyCode == _keys[key].code) {
  4445. return key;
  4446. } else if (event.keyCode == _keys[key].code && key == 'shift') {
  4447. return key;
  4448. }
  4449. }
  4450. }
  4451. return "unknown key, currently not supported";
  4452. };
  4453. // unbind either a specific callback from a key or all of them (by leaving callback undefined)
  4454. _exportFunctions.unbind = function(key, callback, type) {
  4455. if (type === undefined) {
  4456. type = 'keydown';
  4457. }
  4458. if (_keys[key] === undefined) {
  4459. throw new Error("unsupported key: " + key);
  4460. }
  4461. if (callback !== undefined) {
  4462. var newBindings = [];
  4463. var bound = _bound[type][_keys[key].code];
  4464. if (bound !== undefined) {
  4465. for (var i = 0; i < bound.length; i++) {
  4466. if (!(bound[i].fn == callback && bound[i].shift == _keys[key].shift)) {
  4467. newBindings.push(_bound[type][_keys[key].code][i]);
  4468. }
  4469. }
  4470. }
  4471. _bound[type][_keys[key].code] = newBindings;
  4472. } else {
  4473. _bound[type][_keys[key].code] = [];
  4474. }
  4475. };
  4476. // reset all bound variables.
  4477. _exportFunctions.reset = function() {
  4478. _bound = { keydown: {}, keyup: {} };
  4479. };
  4480. // unbind all listeners and reset all variables.
  4481. _exportFunctions.destroy = function() {
  4482. _bound = { keydown: {}, keyup: {} };
  4483. container.removeEventListener('keydown', down, true);
  4484. container.removeEventListener('keyup', up, true);
  4485. };
  4486. // create listeners.
  4487. container.addEventListener('keydown', down, true);
  4488. container.addEventListener('keyup', up, true);
  4489. // return the public functions.
  4490. return _exportFunctions;
  4491. }
  4492. return keycharm;
  4493. }));
  4494. /***/
  4495. }),
  4496. /* 36 */
  4497. /***/
  4498. (function(module, exports, __webpack_require__) {
  4499. "use strict";
  4500. /**
  4501. * used in Core to convert the options into a volatile variable
  4502. *
  4503. * @param {function} moment
  4504. * @param {Object} body
  4505. * @param {Array | Object} hiddenDates
  4506. * @returns {number}
  4507. */
  4508. exports.convertHiddenOptions = function(moment, body, hiddenDates) {
  4509. if (hiddenDates && !Array.isArray(hiddenDates)) {
  4510. return exports.convertHiddenOptions(moment, body, [hiddenDates]);
  4511. }
  4512. body.hiddenDates = [];
  4513. if (hiddenDates) {
  4514. if (Array.isArray(hiddenDates) == true) {
  4515. for (var i = 0; i < hiddenDates.length; i++) {
  4516. if (hiddenDates[i].repeat === undefined) {
  4517. var dateItem = {};
  4518. dateItem.start = moment(hiddenDates[i].start).toDate().valueOf();
  4519. dateItem.end = moment(hiddenDates[i].end).toDate().valueOf();
  4520. body.hiddenDates.push(dateItem);
  4521. }
  4522. }
  4523. body.hiddenDates.sort(function(a, b) {
  4524. return a.start - b.start;
  4525. }); // sort by start time
  4526. }
  4527. }
  4528. };
  4529. /**
  4530. * create new entrees for the repeating hidden dates
  4531. *
  4532. * @param {function} moment
  4533. * @param {Object} body
  4534. * @param {Array | Object} hiddenDates
  4535. * @returns {null}
  4536. */
  4537. exports.updateHiddenDates = function(moment, body, hiddenDates) {
  4538. if (hiddenDates && !Array.isArray(hiddenDates)) {
  4539. return exports.updateHiddenDates(moment, body, [hiddenDates]);
  4540. }
  4541. if (hiddenDates && body.domProps.centerContainer.width !== undefined) {
  4542. exports.convertHiddenOptions(moment, body, hiddenDates);
  4543. var start = moment(body.range.start);
  4544. var end = moment(body.range.end);
  4545. var totalRange = body.range.end - body.range.start;
  4546. var pixelTime = totalRange / body.domProps.centerContainer.width;
  4547. for (var i = 0; i < hiddenDates.length; i++) {
  4548. if (hiddenDates[i].repeat !== undefined) {
  4549. var startDate = moment(hiddenDates[i].start);
  4550. var endDate = moment(hiddenDates[i].end);
  4551. if (startDate._d == "Invalid Date") {
  4552. throw new Error("Supplied start date is not valid: " + hiddenDates[i].start);
  4553. }
  4554. if (endDate._d == "Invalid Date") {
  4555. throw new Error("Supplied end date is not valid: " + hiddenDates[i].end);
  4556. }
  4557. var duration = endDate - startDate;
  4558. if (duration >= 4 * pixelTime) {
  4559. var offset = 0;
  4560. var runUntil = end.clone();
  4561. switch (hiddenDates[i].repeat) {
  4562. case "daily":
  4563. // case of time
  4564. if (startDate.day() != endDate.day()) {
  4565. offset = 1;
  4566. }
  4567. startDate.dayOfYear(start.dayOfYear());
  4568. startDate.year(start.year());
  4569. startDate.subtract(7, 'days');
  4570. endDate.dayOfYear(start.dayOfYear());
  4571. endDate.year(start.year());
  4572. endDate.subtract(7 - offset, 'days');
  4573. runUntil.add(1, 'weeks');
  4574. break;
  4575. case "weekly":
  4576. var dayOffset = endDate.diff(startDate, 'days');
  4577. var day = startDate.day();
  4578. // set the start date to the range.start
  4579. startDate.date(start.date());
  4580. startDate.month(start.month());
  4581. startDate.year(start.year());
  4582. endDate = startDate.clone();
  4583. // force
  4584. startDate.day(day);
  4585. endDate.day(day);
  4586. endDate.add(dayOffset, 'days');
  4587. startDate.subtract(1, 'weeks');
  4588. endDate.subtract(1, 'weeks');
  4589. runUntil.add(1, 'weeks');
  4590. break;
  4591. case "monthly":
  4592. if (startDate.month() != endDate.month()) {
  4593. offset = 1;
  4594. }
  4595. startDate.month(start.month());
  4596. startDate.year(start.year());
  4597. startDate.subtract(1, 'months');
  4598. endDate.month(start.month());
  4599. endDate.year(start.year());
  4600. endDate.subtract(1, 'months');
  4601. endDate.add(offset, 'months');
  4602. runUntil.add(1, 'months');
  4603. break;
  4604. case "yearly":
  4605. if (startDate.year() != endDate.year()) {
  4606. offset = 1;
  4607. }
  4608. startDate.year(start.year());
  4609. startDate.subtract(1, 'years');
  4610. endDate.year(start.year());
  4611. endDate.subtract(1, 'years');
  4612. endDate.add(offset, 'years');
  4613. runUntil.add(1, 'years');
  4614. break;
  4615. default:
  4616. console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat);
  4617. return;
  4618. }
  4619. while (startDate < runUntil) {
  4620. body.hiddenDates.push({ start: startDate.valueOf(), end: endDate.valueOf() });
  4621. switch (hiddenDates[i].repeat) {
  4622. case "daily":
  4623. startDate.add(1, 'days');
  4624. endDate.add(1, 'days');
  4625. break;
  4626. case "weekly":
  4627. startDate.add(1, 'weeks');
  4628. endDate.add(1, 'weeks');
  4629. break;
  4630. case "monthly":
  4631. startDate.add(1, 'months');
  4632. endDate.add(1, 'months');
  4633. break;
  4634. case "yearly":
  4635. startDate.add(1, 'y');
  4636. endDate.add(1, 'y');
  4637. break;
  4638. default:
  4639. console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat);
  4640. return;
  4641. }
  4642. }
  4643. body.hiddenDates.push({ start: startDate.valueOf(), end: endDate.valueOf() });
  4644. }
  4645. }
  4646. }
  4647. // remove duplicates, merge where possible
  4648. exports.removeDuplicates(body);
  4649. // ensure the new positions are not on hidden dates
  4650. var startHidden = exports.isHidden(body.range.start, body.hiddenDates);
  4651. var endHidden = exports.isHidden(body.range.end, body.hiddenDates);
  4652. var rangeStart = body.range.start;
  4653. var rangeEnd = body.range.end;
  4654. if (startHidden.hidden == true) {
  4655. rangeStart = body.range.startToFront == true ? startHidden.startDate - 1 : startHidden.endDate + 1;
  4656. }
  4657. if (endHidden.hidden == true) {
  4658. rangeEnd = body.range.endToFront == true ? endHidden.startDate - 1 : endHidden.endDate + 1;
  4659. }
  4660. if (startHidden.hidden == true || endHidden.hidden == true) {
  4661. body.range._applyRange(rangeStart, rangeEnd);
  4662. }
  4663. }
  4664. };
  4665. /**
  4666. * remove duplicates from the hidden dates list. Duplicates are evil. They mess everything up.
  4667. * Scales with N^2
  4668. *
  4669. * @param {Object} body
  4670. */
  4671. exports.removeDuplicates = function(body) {
  4672. var hiddenDates = body.hiddenDates;
  4673. var safeDates = [];
  4674. for (var i = 0; i < hiddenDates.length; i++) {
  4675. for (var j = 0; j < hiddenDates.length; j++) {
  4676. if (i != j && hiddenDates[j].remove != true && hiddenDates[i].remove != true) {
  4677. // j inside i
  4678. if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) {
  4679. hiddenDates[j].remove = true;
  4680. }
  4681. // j start inside i
  4682. else if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].start <= hiddenDates[i].end) {
  4683. hiddenDates[i].end = hiddenDates[j].end;
  4684. hiddenDates[j].remove = true;
  4685. }
  4686. // j end inside i
  4687. else if (hiddenDates[j].end >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) {
  4688. hiddenDates[i].start = hiddenDates[j].start;
  4689. hiddenDates[j].remove = true;
  4690. }
  4691. }
  4692. }
  4693. }
  4694. for (i = 0; i < hiddenDates.length; i++) {
  4695. if (hiddenDates[i].remove !== true) {
  4696. safeDates.push(hiddenDates[i]);
  4697. }
  4698. }
  4699. body.hiddenDates = safeDates;
  4700. body.hiddenDates.sort(function(a, b) {
  4701. return a.start - b.start;
  4702. }); // sort by start time
  4703. };
  4704. exports.printDates = function(dates) {
  4705. for (var i = 0; i < dates.length; i++) {
  4706. console.log(i, new Date(dates[i].start), new Date(dates[i].end), dates[i].start, dates[i].end, dates[i].remove);
  4707. }
  4708. };
  4709. /**
  4710. * Used in TimeStep to avoid the hidden times.
  4711. * @param {function} moment
  4712. * @param {TimeStep} timeStep
  4713. * @param {Date} previousTime
  4714. */
  4715. exports.stepOverHiddenDates = function(moment, timeStep, previousTime) {
  4716. var stepInHidden = false;
  4717. var currentValue = timeStep.current.valueOf();
  4718. for (var i = 0; i < timeStep.hiddenDates.length; i++) {
  4719. var startDate = timeStep.hiddenDates[i].start;
  4720. var endDate = timeStep.hiddenDates[i].end;
  4721. if (currentValue >= startDate && currentValue < endDate) {
  4722. stepInHidden = true;
  4723. break;
  4724. }
  4725. }
  4726. if (stepInHidden == true && currentValue < timeStep._end.valueOf() && currentValue != previousTime) {
  4727. var prevValue = moment(previousTime);
  4728. var newValue = moment(endDate);
  4729. //check if the next step should be major
  4730. if (prevValue.year() != newValue.year()) {
  4731. timeStep.switchedYear = true;
  4732. } else if (prevValue.month() != newValue.month()) {
  4733. timeStep.switchedMonth = true;
  4734. } else if (prevValue.dayOfYear() != newValue.dayOfYear()) {
  4735. timeStep.switchedDay = true;
  4736. }
  4737. timeStep.current = newValue;
  4738. }
  4739. };
  4740. ///**
  4741. // * Used in TimeStep to avoid the hidden times.
  4742. // * @param timeStep
  4743. // * @param previousTime
  4744. // */
  4745. //exports.checkFirstStep = function(timeStep) {
  4746. // var stepInHidden = false;
  4747. // var currentValue = timeStep.current.valueOf();
  4748. // for (var i = 0; i < timeStep.hiddenDates.length; i++) {
  4749. // var startDate = timeStep.hiddenDates[i].start;
  4750. // var endDate = timeStep.hiddenDates[i].end;
  4751. // if (currentValue >= startDate && currentValue < endDate) {
  4752. // stepInHidden = true;
  4753. // break;
  4754. // }
  4755. // }
  4756. //
  4757. // if (stepInHidden == true && currentValue <= timeStep._end.valueOf()) {
  4758. // var newValue = moment(endDate);
  4759. // timeStep.current = newValue.toDate();
  4760. // }
  4761. //};
  4762. /**
  4763. * replaces the Core toScreen methods
  4764. *
  4765. * @param {vis.Core} Core
  4766. * @param {Date} time
  4767. * @param {number} width
  4768. * @returns {number}
  4769. */
  4770. exports.toScreen = function(Core, time, width) {
  4771. var conversion;
  4772. if (Core.body.hiddenDates.length == 0) {
  4773. conversion = Core.range.conversion(width);
  4774. return (time.valueOf() - conversion.offset) * conversion.scale;
  4775. } else {
  4776. var hidden = exports.isHidden(time, Core.body.hiddenDates);
  4777. if (hidden.hidden == true) {
  4778. time = hidden.startDate;
  4779. }
  4780. var duration = exports.getHiddenDurationBetween(Core.body.hiddenDates, Core.range.start, Core.range.end);
  4781. if (time < Core.range.start) {
  4782. conversion = Core.range.conversion(width, duration);
  4783. var hiddenBeforeStart = exports.getHiddenDurationBeforeStart(Core.body.hiddenDates, time, conversion.offset);
  4784. time = Core.options.moment(time).toDate().valueOf();
  4785. time = time + hiddenBeforeStart;
  4786. return -(conversion.offset - time.valueOf()) * conversion.scale;
  4787. } else if (time > Core.range.end) {
  4788. var rangeAfterEnd = { start: Core.range.start, end: time };
  4789. time = exports.correctTimeForHidden(Core.options.moment, Core.body.hiddenDates, rangeAfterEnd, time);
  4790. conversion = Core.range.conversion(width, duration);
  4791. return (time.valueOf() - conversion.offset) * conversion.scale;
  4792. } else {
  4793. time = exports.correctTimeForHidden(Core.options.moment, Core.body.hiddenDates, Core.range, time);
  4794. conversion = Core.range.conversion(width, duration);
  4795. return (time.valueOf() - conversion.offset) * conversion.scale;
  4796. }
  4797. }
  4798. };
  4799. /**
  4800. * Replaces the core toTime methods
  4801. *
  4802. * @param {vis.Core} Core
  4803. * @param {number} x
  4804. * @param {number} width
  4805. * @returns {Date}
  4806. */
  4807. exports.toTime = function(Core, x, width) {
  4808. if (Core.body.hiddenDates.length == 0) {
  4809. var conversion = Core.range.conversion(width);
  4810. return new Date(x / conversion.scale + conversion.offset);
  4811. } else {
  4812. var hiddenDuration = exports.getHiddenDurationBetween(Core.body.hiddenDates, Core.range.start, Core.range.end);
  4813. var totalDuration = Core.range.end - Core.range.start - hiddenDuration;
  4814. var partialDuration = totalDuration * x / width;
  4815. var accumulatedHiddenDuration = exports.getAccumulatedHiddenDuration(Core.body.hiddenDates, Core.range, partialDuration);
  4816. return new Date(accumulatedHiddenDuration + partialDuration + Core.range.start);
  4817. }
  4818. };
  4819. /**
  4820. * Support function
  4821. *
  4822. * @param {Array.<{start: Window.start, end: *}>} hiddenDates
  4823. * @param {number} start
  4824. * @param {number} end
  4825. * @returns {number}
  4826. */
  4827. exports.getHiddenDurationBetween = function(hiddenDates, start, end) {
  4828. var duration = 0;
  4829. for (var i = 0; i < hiddenDates.length; i++) {
  4830. var startDate = hiddenDates[i].start;
  4831. var endDate = hiddenDates[i].end;
  4832. // if time after the cutout, and the
  4833. if (startDate >= start && endDate < end) {
  4834. duration += endDate - startDate;
  4835. }
  4836. }
  4837. return duration;
  4838. };
  4839. /**
  4840. * Support function
  4841. *
  4842. * @param {Array.<{start: Window.start, end: *}>} hiddenDates
  4843. * @param {number} start
  4844. * @param {number} end
  4845. * @returns {number}
  4846. */
  4847. exports.getHiddenDurationBeforeStart = function(hiddenDates, start, end) {
  4848. var duration = 0;
  4849. for (var i = 0; i < hiddenDates.length; i++) {
  4850. var startDate = hiddenDates[i].start;
  4851. var endDate = hiddenDates[i].end;
  4852. if (startDate >= start && endDate <= end) {
  4853. duration += endDate - startDate;
  4854. }
  4855. }
  4856. return duration;
  4857. };
  4858. /**
  4859. * Support function
  4860. * @param {function} moment
  4861. * @param {Array.<{start: Window.start, end: *}>} hiddenDates
  4862. * @param {{start: number, end: number}} range
  4863. * @param {Date} time
  4864. * @returns {number}
  4865. */
  4866. exports.correctTimeForHidden = function(moment, hiddenDates, range, time) {
  4867. time = moment(time).toDate().valueOf();
  4868. time -= exports.getHiddenDurationBefore(moment, hiddenDates, range, time);
  4869. return time;
  4870. };
  4871. exports.getHiddenDurationBefore = function(moment, hiddenDates, range, time) {
  4872. var timeOffset = 0;
  4873. time = moment(time).toDate().valueOf();
  4874. for (var i = 0; i < hiddenDates.length; i++) {
  4875. var startDate = hiddenDates[i].start;
  4876. var endDate = hiddenDates[i].end;
  4877. // if time after the cutout, and the
  4878. if (startDate >= range.start && endDate < range.end) {
  4879. if (time >= endDate) {
  4880. timeOffset += endDate - startDate;
  4881. }
  4882. }
  4883. }
  4884. return timeOffset;
  4885. };
  4886. /**
  4887. * sum the duration from start to finish, including the hidden duration,
  4888. * until the required amount has been reached, return the accumulated hidden duration
  4889. * @param {Array.<{start: Window.start, end: *}>} hiddenDates
  4890. * @param {{start: number, end: number}} range
  4891. * @param {number} [requiredDuration=0]
  4892. * @returns {number}
  4893. */
  4894. exports.getAccumulatedHiddenDuration = function(hiddenDates, range, requiredDuration) {
  4895. var hiddenDuration = 0;
  4896. var duration = 0;
  4897. var previousPoint = range.start;
  4898. //exports.printDates(hiddenDates)
  4899. for (var i = 0; i < hiddenDates.length; i++) {
  4900. var startDate = hiddenDates[i].start;
  4901. var endDate = hiddenDates[i].end;
  4902. // if time after the cutout, and the
  4903. if (startDate >= range.start && endDate < range.end) {
  4904. duration += startDate - previousPoint;
  4905. previousPoint = endDate;
  4906. if (duration >= requiredDuration) {
  4907. break;
  4908. } else {
  4909. hiddenDuration += endDate - startDate;
  4910. }
  4911. }
  4912. }
  4913. return hiddenDuration;
  4914. };
  4915. /**
  4916. * used to step over to either side of a hidden block. Correction is disabled on tablets, might be set to true
  4917. * @param {Array.<{start: Window.start, end: *}>} hiddenDates
  4918. * @param {Date} time
  4919. * @param {number} direction
  4920. * @param {boolean} correctionEnabled
  4921. * @returns {Date|number}
  4922. */
  4923. exports.snapAwayFromHidden = function(hiddenDates, time, direction, correctionEnabled) {
  4924. var isHidden = exports.isHidden(time, hiddenDates);
  4925. if (isHidden.hidden == true) {
  4926. if (direction < 0) {
  4927. if (correctionEnabled == true) {
  4928. return isHidden.startDate - (isHidden.endDate - time) - 1;
  4929. } else {
  4930. return isHidden.startDate - 1;
  4931. }
  4932. } else {
  4933. if (correctionEnabled == true) {
  4934. return isHidden.endDate + (time - isHidden.startDate) + 1;
  4935. } else {
  4936. return isHidden.endDate + 1;
  4937. }
  4938. }
  4939. } else {
  4940. return time;
  4941. }
  4942. };
  4943. /**
  4944. * Check if a time is hidden
  4945. *
  4946. * @param {Date} time
  4947. * @param {Array.<{start: Window.start, end: *}>} hiddenDates
  4948. * @returns {{hidden: boolean, startDate: Window.start, endDate: *}}
  4949. */
  4950. exports.isHidden = function(time, hiddenDates) {
  4951. for (var i = 0; i < hiddenDates.length; i++) {
  4952. var startDate = hiddenDates[i].start;
  4953. var endDate = hiddenDates[i].end;
  4954. if (time >= startDate && time < endDate) {
  4955. // if the start is entering a hidden zone
  4956. return { hidden: true, startDate: startDate, endDate: endDate };
  4957. }
  4958. }
  4959. return { hidden: false, startDate: startDate, endDate: endDate };
  4960. };
  4961. /***/
  4962. }),
  4963. /* 37 */
  4964. /***/
  4965. (function(module, exports, __webpack_require__) {
  4966. "use strict";
  4967. /**
  4968. * Register a touch event, taking place before a gesture
  4969. * @param {Hammer} hammer A hammer instance
  4970. * @param {function} callback Callback, called as callback(event)
  4971. */
  4972. exports.onTouch = function(hammer, callback) {
  4973. callback.inputHandler = function(event) {
  4974. if (event.isFirst) {
  4975. callback(event);
  4976. }
  4977. };
  4978. hammer.on('hammer.input', callback.inputHandler);
  4979. };
  4980. /**
  4981. * Register a release event, taking place after a gesture
  4982. * @param {Hammer} hammer A hammer instance
  4983. * @param {function} callback Callback, called as callback(event)
  4984. * @returns {*}
  4985. */
  4986. exports.onRelease = function(hammer, callback) {
  4987. callback.inputHandler = function(event) {
  4988. if (event.isFinal) {
  4989. callback(event);
  4990. }
  4991. };
  4992. return hammer.on('hammer.input', callback.inputHandler);
  4993. };
  4994. /**
  4995. * Unregister a touch event, taking place before a gesture
  4996. * @param {Hammer} hammer A hammer instance
  4997. * @param {function} callback Callback, called as callback(event)
  4998. */
  4999. exports.offTouch = function(hammer, callback) {
  5000. hammer.off('hammer.input', callback.inputHandler);
  5001. };
  5002. /**
  5003. * Unregister a release event, taking place before a gesture
  5004. * @param {Hammer} hammer A hammer instance
  5005. * @param {function} callback Callback, called as callback(event)
  5006. */
  5007. exports.offRelease = exports.offTouch;
  5008. /**
  5009. * Hack the PinchRecognizer such that it doesn't prevent default behavior
  5010. * for vertical panning.
  5011. *
  5012. * Yeah ... this is quite a hack ... see https://github.com/hammerjs/hammer.js/issues/932
  5013. *
  5014. * @param {Hammer.Pinch} pinchRecognizer
  5015. * @return {Hammer.Pinch} returns the pinchRecognizer
  5016. */
  5017. exports.disablePreventDefaultVertically = function(pinchRecognizer) {
  5018. var TOUCH_ACTION_PAN_Y = 'pan-y';
  5019. pinchRecognizer.getTouchAction = function() {
  5020. // default method returns [TOUCH_ACTION_NONE]
  5021. return [TOUCH_ACTION_PAN_Y];
  5022. };
  5023. return pinchRecognizer;
  5024. };
  5025. /***/
  5026. }),
  5027. /* 38 */
  5028. /***/
  5029. (function(module, exports, __webpack_require__) {
  5030. "use strict";
  5031. var _typeof2 = __webpack_require__(6);
  5032. var _typeof3 = _interopRequireDefault(_typeof2);
  5033. var _keys = __webpack_require__(8);
  5034. var _keys2 = _interopRequireDefault(_keys);
  5035. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  5036. var Hammer = __webpack_require__(10);
  5037. var util = __webpack_require__(2);
  5038. var moment = __webpack_require__(9);
  5039. /**
  5040. * @constructor Item
  5041. * @param {Object} data Object containing (optional) parameters type,
  5042. * start, end, content, group, className.
  5043. * @param {{toScreen: function, toTime: function}} conversion
  5044. * Conversion functions from time to screen and vice versa
  5045. * @param {Object} options Configuration options
  5046. * // TODO: describe available options
  5047. */
  5048. function Item(data, conversion, options) {
  5049. this.id = null;
  5050. this.parent = null;
  5051. this.data = data;
  5052. this.dom = null;
  5053. this.conversion = conversion || {};
  5054. this.options = options || {};
  5055. this.selected = false;
  5056. this.displayed = false;
  5057. this.groupShowing = true;
  5058. this.dirty = true;
  5059. this.top = null;
  5060. this.right = null;
  5061. this.left = null;
  5062. this.width = null;
  5063. this.height = null;
  5064. this.editable = null;
  5065. this._updateEditStatus();
  5066. }
  5067. Item.prototype.stack = true;
  5068. /**
  5069. * Select current item
  5070. */
  5071. Item.prototype.select = function() {
  5072. this.selected = true;
  5073. this.dirty = true;
  5074. if (this.displayed) this.redraw();
  5075. };
  5076. /**
  5077. * Unselect current item
  5078. */
  5079. Item.prototype.unselect = function() {
  5080. this.selected = false;
  5081. this.dirty = true;
  5082. if (this.displayed) this.redraw();
  5083. };
  5084. /**
  5085. * Set data for the item. Existing data will be updated. The id should not
  5086. * be changed. When the item is displayed, it will be redrawn immediately.
  5087. * @param {Object} data
  5088. */
  5089. Item.prototype.setData = function(data) {
  5090. var groupChanged = data.group != undefined && this.data.group != data.group;
  5091. if (groupChanged && this.parent != null) {
  5092. this.parent.itemSet._moveToGroup(this, data.group);
  5093. }
  5094. if (this.parent) {
  5095. this.parent.stackDirty = true;
  5096. }
  5097. var subGroupChanged = data.subgroup != undefined && this.data.subgroup != data.subgroup;
  5098. if (subGroupChanged && this.parent != null) {
  5099. this.parent.changeSubgroup(this, this.data.subgroup, data.subgroup);
  5100. }
  5101. this.data = data;
  5102. this._updateEditStatus();
  5103. this.dirty = true;
  5104. if (this.displayed) this.redraw();
  5105. };
  5106. /**
  5107. * Set a parent for the item
  5108. * @param {Group} parent
  5109. */
  5110. Item.prototype.setParent = function(parent) {
  5111. if (this.displayed) {
  5112. this.hide();
  5113. this.parent = parent;
  5114. if (this.parent) {
  5115. this.show();
  5116. }
  5117. } else {
  5118. this.parent = parent;
  5119. }
  5120. };
  5121. /**
  5122. * Check whether this item is visible inside given range
  5123. * @param {vis.Range} range with a timestamp for start and end
  5124. * @returns {boolean} True if visible
  5125. */
  5126. Item.prototype.isVisible = function(range) {
  5127. // eslint-disable-line no-unused-vars
  5128. return false;
  5129. };
  5130. /**
  5131. * Show the Item in the DOM (when not already visible)
  5132. * @return {Boolean} changed
  5133. */
  5134. Item.prototype.show = function() {
  5135. return false;
  5136. };
  5137. /**
  5138. * Hide the Item from the DOM (when visible)
  5139. * @return {Boolean} changed
  5140. */
  5141. Item.prototype.hide = function() {
  5142. return false;
  5143. };
  5144. /**
  5145. * Repaint the item
  5146. */
  5147. Item.prototype.redraw = function() {
  5148. // should be implemented by the item
  5149. };
  5150. /**
  5151. * Reposition the Item horizontally
  5152. */
  5153. Item.prototype.repositionX = function() {
  5154. // should be implemented by the item
  5155. };
  5156. /**
  5157. * Reposition the Item vertically
  5158. */
  5159. Item.prototype.repositionY = function() {
  5160. // should be implemented by the item
  5161. };
  5162. /**
  5163. * Repaint a drag area on the center of the item when the item is selected
  5164. * @protected
  5165. */
  5166. Item.prototype._repaintDragCenter = function() {
  5167. if (this.selected && this.options.editable.updateTime && !this.dom.dragCenter) {
  5168. var me = this;
  5169. // create and show drag area
  5170. var dragCenter = document.createElement('div');
  5171. dragCenter.className = 'vis-drag-center';
  5172. dragCenter.dragCenterItem = this;
  5173. var hammer = new Hammer(dragCenter);
  5174. hammer.on('tap', function(event) {
  5175. me.parent.itemSet.body.emitter.emit('click', {
  5176. event: event,
  5177. item: me.id
  5178. });
  5179. });
  5180. hammer.on('doubletap', function(event) {
  5181. event.stopPropagation();
  5182. me.parent.itemSet._onUpdateItem(me);
  5183. me.parent.itemSet.body.emitter.emit('doubleClick', {
  5184. event: event,
  5185. item: me.id
  5186. });
  5187. });
  5188. if (this.dom.box) {
  5189. if (this.dom.dragLeft) {
  5190. this.dom.box.insertBefore(dragCenter, this.dom.dragLeft);
  5191. } else {
  5192. this.dom.box.appendChild(dragCenter);
  5193. }
  5194. } else if (this.dom.point) {
  5195. this.dom.point.appendChild(dragCenter);
  5196. }
  5197. this.dom.dragCenter = dragCenter;
  5198. } else if (!this.selected && this.dom.dragCenter) {
  5199. // delete drag area
  5200. if (this.dom.dragCenter.parentNode) {
  5201. this.dom.dragCenter.parentNode.removeChild(this.dom.dragCenter);
  5202. }
  5203. this.dom.dragCenter = null;
  5204. }
  5205. };
  5206. /**
  5207. * Repaint a delete button on the top right of the item when the item is selected
  5208. * @param {HTMLElement} anchor
  5209. * @protected
  5210. */
  5211. Item.prototype._repaintDeleteButton = function(anchor) {
  5212. var editable = (this.options.editable.overrideItems || this.editable == null) && this.options.editable.remove || !this.options.editable.overrideItems && this.editable != null && this.editable.remove;
  5213. if (this.selected && editable && !this.dom.deleteButton) {
  5214. // create and show button
  5215. var me = this;
  5216. var deleteButton = document.createElement('div');
  5217. if (this.options.rtl) {
  5218. deleteButton.className = 'vis-delete-rtl';
  5219. } else {
  5220. deleteButton.className = 'vis-delete';
  5221. }
  5222. deleteButton.title = 'Delete this item';
  5223. // TODO: be able to destroy the delete button
  5224. new Hammer(deleteButton).on('tap', function(event) {
  5225. event.stopPropagation();
  5226. me.parent.removeFromDataSet(me);
  5227. });
  5228. anchor.appendChild(deleteButton);
  5229. this.dom.deleteButton = deleteButton;
  5230. } else if (!this.selected && this.dom.deleteButton) {
  5231. // remove button
  5232. if (this.dom.deleteButton.parentNode) {
  5233. this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton);
  5234. }
  5235. this.dom.deleteButton = null;
  5236. }
  5237. };
  5238. /**
  5239. * Repaint a onChange tooltip on the top right of the item when the item is selected
  5240. * @param {HTMLElement} anchor
  5241. * @protected
  5242. */
  5243. Item.prototype._repaintOnItemUpdateTimeTooltip = function(anchor) {
  5244. if (!this.options.tooltipOnItemUpdateTime) return;
  5245. var editable = (this.options.editable.updateTime || this.data.editable === true) && this.data.editable !== false;
  5246. if (this.selected && editable && !this.dom.onItemUpdateTimeTooltip) {
  5247. var onItemUpdateTimeTooltip = document.createElement('div');
  5248. onItemUpdateTimeTooltip.className = 'vis-onUpdateTime-tooltip';
  5249. anchor.appendChild(onItemUpdateTimeTooltip);
  5250. this.dom.onItemUpdateTimeTooltip = onItemUpdateTimeTooltip;
  5251. } else if (!this.selected && this.dom.onItemUpdateTimeTooltip) {
  5252. // remove button
  5253. if (this.dom.onItemUpdateTimeTooltip.parentNode) {
  5254. this.dom.onItemUpdateTimeTooltip.parentNode.removeChild(this.dom.onItemUpdateTimeTooltip);
  5255. }
  5256. this.dom.onItemUpdateTimeTooltip = null;
  5257. }
  5258. // position onChange tooltip
  5259. if (this.dom.onItemUpdateTimeTooltip) {
  5260. // only show when editing
  5261. this.dom.onItemUpdateTimeTooltip.style.visibility = this.parent.itemSet.touchParams.itemIsDragging ? 'visible' : 'hidden';
  5262. // position relative to item's content
  5263. if (this.options.rtl) {
  5264. this.dom.onItemUpdateTimeTooltip.style.right = this.dom.content.style.right;
  5265. } else {
  5266. this.dom.onItemUpdateTimeTooltip.style.left = this.dom.content.style.left;
  5267. }
  5268. // position above or below the item depending on the item's position in the window
  5269. var tooltipOffset = 50; // TODO: should be tooltip height (depends on template)
  5270. var scrollTop = this.parent.itemSet.body.domProps.scrollTop;
  5271. // TODO: this.top for orientation:true is actually the items distance from the bottom...
  5272. // (should be this.bottom)
  5273. var itemDistanceFromTop;
  5274. if (this.options.orientation.item == 'top') {
  5275. itemDistanceFromTop = this.top;
  5276. } else {
  5277. itemDistanceFromTop = this.parent.height - this.top - this.height;
  5278. }
  5279. var isCloseToTop = itemDistanceFromTop + this.parent.top - tooltipOffset < -scrollTop;
  5280. if (isCloseToTop) {
  5281. this.dom.onItemUpdateTimeTooltip.style.bottom = "";
  5282. this.dom.onItemUpdateTimeTooltip.style.top = this.height + 2 + "px";
  5283. } else {
  5284. this.dom.onItemUpdateTimeTooltip.style.top = "";
  5285. this.dom.onItemUpdateTimeTooltip.style.bottom = this.height + 2 + "px";
  5286. }
  5287. // handle tooltip content
  5288. var content;
  5289. var templateFunction;
  5290. if (this.options.tooltipOnItemUpdateTime && this.options.tooltipOnItemUpdateTime.template) {
  5291. templateFunction = this.options.tooltipOnItemUpdateTime.template.bind(this);
  5292. content = templateFunction(this.data);
  5293. } else {
  5294. content = 'start: ' + moment(this.data.start).format('MM/DD/YYYY hh:mm');
  5295. if (this.data.end) {
  5296. content += '<br> end: ' + moment(this.data.end).format('MM/DD/YYYY hh:mm');
  5297. }
  5298. }
  5299. this.dom.onItemUpdateTimeTooltip.innerHTML = content;
  5300. }
  5301. };
  5302. /**
  5303. * Set HTML contents for the item
  5304. * @param {Element} element HTML element to fill with the contents
  5305. * @private
  5306. */
  5307. Item.prototype._updateContents = function(element) {
  5308. var content;
  5309. var changed;
  5310. var templateFunction;
  5311. var itemVisibleFrameContent;
  5312. var visibleFrameTemplateFunction;
  5313. var itemData = this.parent.itemSet.itemsData.get(this.id); // get a clone of the data from the dataset
  5314. var frameElement = this.dom.box || this.dom.point;
  5315. var itemVisibleFrameContentElement = frameElement.getElementsByClassName('vis-item-visible-frame')[0];
  5316. if (this.options.visibleFrameTemplate) {
  5317. visibleFrameTemplateFunction = this.options.visibleFrameTemplate.bind(this);
  5318. itemVisibleFrameContent = visibleFrameTemplateFunction(itemData, frameElement);
  5319. } else {
  5320. itemVisibleFrameContent = '';
  5321. }
  5322. if (itemVisibleFrameContentElement) {
  5323. if (itemVisibleFrameContent instanceof Object && !(itemVisibleFrameContent instanceof Element)) {
  5324. visibleFrameTemplateFunction(itemData, itemVisibleFrameContentElement);
  5325. } else {
  5326. changed = this._contentToString(this.itemVisibleFrameContent) !== this._contentToString(itemVisibleFrameContent);
  5327. if (changed) {
  5328. // only replace the content when changed
  5329. if (itemVisibleFrameContent instanceof Element) {
  5330. itemVisibleFrameContentElement.innerHTML = '';
  5331. itemVisibleFrameContentElement.appendChild(itemVisibleFrameContent);
  5332. } else if (itemVisibleFrameContent != undefined) {
  5333. itemVisibleFrameContentElement.innerHTML = itemVisibleFrameContent;
  5334. } else {
  5335. if (!(this.data.type == 'background' && this.data.content === undefined)) {
  5336. throw new Error('Property "content" missing in item ' + this.id);
  5337. }
  5338. }
  5339. this.itemVisibleFrameContent = itemVisibleFrameContent;
  5340. }
  5341. }
  5342. }
  5343. if (this.options.template) {
  5344. templateFunction = this.options.template.bind(this);
  5345. content = templateFunction(itemData, element, this.data);
  5346. } else {
  5347. content = this.data.content;
  5348. }
  5349. if (content instanceof Object && !(content instanceof Element)) {
  5350. templateFunction(itemData, element);
  5351. } else {
  5352. changed = this._contentToString(this.content) !== this._contentToString(content);
  5353. if (changed) {
  5354. // only replace the content when changed
  5355. if (content instanceof Element) {
  5356. element.innerHTML = '';
  5357. element.appendChild(content);
  5358. } else if (content != undefined) {
  5359. element.innerHTML = content;
  5360. } else {
  5361. if (!(this.data.type == 'background' && this.data.content === undefined)) {
  5362. throw new Error('Property "content" missing in item ' + this.id);
  5363. }
  5364. }
  5365. this.content = content;
  5366. }
  5367. }
  5368. };
  5369. /**
  5370. * Process dataAttributes timeline option and set as data- attributes on dom.content
  5371. * @param {Element} element HTML element to which the attributes will be attached
  5372. * @private
  5373. */
  5374. Item.prototype._updateDataAttributes = function(element) {
  5375. if (this.options.dataAttributes && this.options.dataAttributes.length > 0) {
  5376. var attributes = [];
  5377. if (Array.isArray(this.options.dataAttributes)) {
  5378. attributes = this.options.dataAttributes;
  5379. } else if (this.options.dataAttributes == 'all') {
  5380. attributes = (0, _keys2['default'])(this.data);
  5381. } else {
  5382. return;
  5383. }
  5384. for (var i = 0; i < attributes.length; i++) {
  5385. var name = attributes[i];
  5386. var value = this.data[name];
  5387. if (value != null) {
  5388. element.setAttribute('data-' + name, value);
  5389. } else {
  5390. element.removeAttribute('data-' + name);
  5391. }
  5392. }
  5393. }
  5394. };
  5395. /**
  5396. * Update custom styles of the element
  5397. * @param {Element} element
  5398. * @private
  5399. */
  5400. Item.prototype._updateStyle = function(element) {
  5401. // remove old styles
  5402. if (this.style) {
  5403. util.removeCssText(element, this.style);
  5404. this.style = null;
  5405. }
  5406. // append new styles
  5407. if (this.data.style) {
  5408. util.addCssText(element, this.data.style);
  5409. this.style = this.data.style;
  5410. }
  5411. };
  5412. /**
  5413. * Stringify the items contents
  5414. * @param {string | Element | undefined} content
  5415. * @returns {string | undefined}
  5416. * @private
  5417. */
  5418. Item.prototype._contentToString = function(content) {
  5419. if (typeof content === 'string') return content;
  5420. if (content && 'outerHTML' in content) return content.outerHTML;
  5421. return content;
  5422. };
  5423. /**
  5424. * Update the editability of this item.
  5425. */
  5426. Item.prototype._updateEditStatus = function() {
  5427. if (this.options) {
  5428. if (typeof this.options.editable === 'boolean') {
  5429. this.editable = {
  5430. updateTime: this.options.editable,
  5431. updateGroup: this.options.editable,
  5432. remove: this.options.editable
  5433. };
  5434. } else if ((0, _typeof3['default'])(this.options.editable) === 'object') {
  5435. this.editable = {};
  5436. util.selectiveExtend(['updateTime', 'updateGroup', 'remove'], this.editable, this.options.editable);
  5437. }
  5438. }
  5439. // Item data overrides, except if options.editable.overrideItems is set.
  5440. if (!this.options || !this.options.editable || this.options.editable.overrideItems !== true) {
  5441. if (this.data) {
  5442. if (typeof this.data.editable === 'boolean') {
  5443. this.editable = {
  5444. updateTime: this.data.editable,
  5445. updateGroup: this.data.editable,
  5446. remove: this.data.editable
  5447. };
  5448. } else if ((0, _typeof3['default'])(this.data.editable) === 'object') {
  5449. // TODO: in vis.js 5.0, we should change this to not reset options from the timeline configuration.
  5450. // Basically just remove the next line...
  5451. this.editable = {};
  5452. util.selectiveExtend(['updateTime', 'updateGroup', 'remove'], this.editable, this.data.editable);
  5453. }
  5454. }
  5455. }
  5456. };
  5457. /**
  5458. * Return the width of the item left from its start date
  5459. * @return {number}
  5460. */
  5461. Item.prototype.getWidthLeft = function() {
  5462. return 0;
  5463. };
  5464. /**
  5465. * Return the width of the item right from the max of its start and end date
  5466. * @return {number}
  5467. */
  5468. Item.prototype.getWidthRight = function() {
  5469. return 0;
  5470. };
  5471. /**
  5472. * Return the title of the item
  5473. * @return {string | undefined}
  5474. */
  5475. Item.prototype.getTitle = function() {
  5476. return this.data.title;
  5477. };
  5478. module.exports = Item;
  5479. /***/
  5480. }),
  5481. /* 39 */
  5482. /***/
  5483. (function(module, exports) {
  5484. module.exports = function(bitmap, value) {
  5485. return {
  5486. enumerable: !(bitmap & 1),
  5487. configurable: !(bitmap & 2),
  5488. writable: !(bitmap & 4),
  5489. value: value
  5490. };
  5491. };
  5492. /***/
  5493. }),
  5494. /* 40 */
  5495. /***/
  5496. (function(module, exports) {
  5497. var id = 0;
  5498. var px = Math.random();
  5499. module.exports = function(key) {
  5500. return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));
  5501. };
  5502. /***/
  5503. }),
  5504. /* 41 */
  5505. /***/
  5506. (function(module, exports, __webpack_require__) {
  5507. // 7.1.13 ToObject(argument)
  5508. var defined = __webpack_require__(51);
  5509. module.exports = function(it) {
  5510. return Object(defined(it));
  5511. };
  5512. /***/
  5513. }),
  5514. /* 42 */
  5515. /***/
  5516. (function(module, exports) {
  5517. exports.f = {}.propertyIsEnumerable;
  5518. /***/
  5519. }),
  5520. /* 43 */
  5521. /***/
  5522. (function(module, exports, __webpack_require__) {
  5523. "use strict";
  5524. /**
  5525. * A queue
  5526. * @param {Object} options
  5527. * Available options:
  5528. * - delay: number When provided, the queue will be flushed
  5529. * automatically after an inactivity of this delay
  5530. * in milliseconds.
  5531. * Default value is null.
  5532. * - max: number When the queue exceeds the given maximum number
  5533. * of entries, the queue is flushed automatically.
  5534. * Default value of max is Infinity.
  5535. * @constructor Queue
  5536. */
  5537. function Queue(options) {
  5538. // options
  5539. this.delay = null;
  5540. this.max = Infinity;
  5541. // properties
  5542. this._queue = [];
  5543. this._timeout = null;
  5544. this._extended = null;
  5545. this.setOptions(options);
  5546. }
  5547. /**
  5548. * Update the configuration of the queue
  5549. * @param {Object} options
  5550. * Available options:
  5551. * - delay: number When provided, the queue will be flushed
  5552. * automatically after an inactivity of this delay
  5553. * in milliseconds.
  5554. * Default value is null.
  5555. * - max: number When the queue exceeds the given maximum number
  5556. * of entries, the queue is flushed automatically.
  5557. * Default value of max is Infinity.
  5558. */
  5559. Queue.prototype.setOptions = function(options) {
  5560. if (options && typeof options.delay !== 'undefined') {
  5561. this.delay = options.delay;
  5562. }
  5563. if (options && typeof options.max !== 'undefined') {
  5564. this.max = options.max;
  5565. }
  5566. this._flushIfNeeded();
  5567. };
  5568. /**
  5569. * Extend an object with queuing functionality.
  5570. * The object will be extended with a function flush, and the methods provided
  5571. * in options.replace will be replaced with queued ones.
  5572. * @param {Object} object
  5573. * @param {Object} options
  5574. * Available options:
  5575. * - replace: Array.<string>
  5576. * A list with method names of the methods
  5577. * on the object to be replaced with queued ones.
  5578. * - delay: number When provided, the queue will be flushed
  5579. * automatically after an inactivity of this delay
  5580. * in milliseconds.
  5581. * Default value is null.
  5582. * - max: number When the queue exceeds the given maximum number
  5583. * of entries, the queue is flushed automatically.
  5584. * Default value of max is Infinity.
  5585. * @return {Queue} Returns the created queue
  5586. */
  5587. Queue.extend = function(object, options) {
  5588. var queue = new Queue(options);
  5589. if (object.flush !== undefined) {
  5590. throw new Error('Target object already has a property flush');
  5591. }
  5592. object.flush = function() {
  5593. queue.flush();
  5594. };
  5595. var methods = [{
  5596. name: 'flush',
  5597. original: undefined
  5598. }];
  5599. if (options && options.replace) {
  5600. for (var i = 0; i < options.replace.length; i++) {
  5601. var name = options.replace[i];
  5602. methods.push({
  5603. name: name,
  5604. original: object[name]
  5605. });
  5606. queue.replace(object, name);
  5607. }
  5608. }
  5609. queue._extended = {
  5610. object: object,
  5611. methods: methods
  5612. };
  5613. return queue;
  5614. };
  5615. /**
  5616. * Destroy the queue. The queue will first flush all queued actions, and in
  5617. * case it has extended an object, will restore the original object.
  5618. */
  5619. Queue.prototype.destroy = function() {
  5620. this.flush();
  5621. if (this._extended) {
  5622. var object = this._extended.object;
  5623. var methods = this._extended.methods;
  5624. for (var i = 0; i < methods.length; i++) {
  5625. var method = methods[i];
  5626. if (method.original) {
  5627. object[method.name] = method.original;
  5628. } else {
  5629. delete object[method.name];
  5630. }
  5631. }
  5632. this._extended = null;
  5633. }
  5634. };
  5635. /**
  5636. * Replace a method on an object with a queued version
  5637. * @param {Object} object Object having the method
  5638. * @param {string} method The method name
  5639. */
  5640. Queue.prototype.replace = function(object, method) {
  5641. var me = this;
  5642. var original = object[method];
  5643. if (!original) {
  5644. throw new Error('Method ' + method + ' undefined');
  5645. }
  5646. object[method] = function() {
  5647. // create an Array with the arguments
  5648. var args = [];
  5649. for (var i = 0; i < arguments.length; i++) {
  5650. args[i] = arguments[i];
  5651. }
  5652. // add this call to the queue
  5653. me.queue({
  5654. args: args,
  5655. fn: original,
  5656. context: this
  5657. });
  5658. };
  5659. };
  5660. /**
  5661. * Queue a call
  5662. * @param {function | {fn: function, args: Array} | {fn: function, args: Array, context: Object}} entry
  5663. */
  5664. Queue.prototype.queue = function(entry) {
  5665. if (typeof entry === 'function') {
  5666. this._queue.push({ fn: entry });
  5667. } else {
  5668. this._queue.push(entry);
  5669. }
  5670. this._flushIfNeeded();
  5671. };
  5672. /**
  5673. * Check whether the queue needs to be flushed
  5674. * @private
  5675. */
  5676. Queue.prototype._flushIfNeeded = function() {
  5677. // flush when the maximum is exceeded.
  5678. if (this._queue.length > this.max) {
  5679. this.flush();
  5680. }
  5681. // flush after a period of inactivity when a delay is configured
  5682. clearTimeout(this._timeout);
  5683. if (this.queue.length > 0 && typeof this.delay === 'number') {
  5684. var me = this;
  5685. this._timeout = setTimeout(function() {
  5686. me.flush();
  5687. }, this.delay);
  5688. }
  5689. };
  5690. /**
  5691. * Flush all queued calls
  5692. */
  5693. Queue.prototype.flush = function() {
  5694. while (this._queue.length > 0) {
  5695. var entry = this._queue.shift();
  5696. entry.fn.apply(entry.context || entry.fn, entry.args || []);
  5697. }
  5698. };
  5699. module.exports = Queue;
  5700. /***/
  5701. }),
  5702. /* 44 */
  5703. /***/
  5704. (function(module, exports) {
  5705. /**
  5706. * Expose `Emitter`.
  5707. */
  5708. module.exports = Emitter;
  5709. /**
  5710. * Initialize a new `Emitter`.
  5711. *
  5712. * @api public
  5713. */
  5714. function Emitter(obj) {
  5715. if (obj) return mixin(obj);
  5716. };
  5717. /**
  5718. * Mixin the emitter properties.
  5719. *
  5720. * @param {Object} obj
  5721. * @return {Object}
  5722. * @api private
  5723. */
  5724. function mixin(obj) {
  5725. for (var key in Emitter.prototype) {
  5726. obj[key] = Emitter.prototype[key];
  5727. }
  5728. return obj;
  5729. }
  5730. /**
  5731. * Listen on the given `event` with `fn`.
  5732. *
  5733. * @param {String} event
  5734. * @param {Function} fn
  5735. * @return {Emitter}
  5736. * @api public
  5737. */
  5738. Emitter.prototype.on =
  5739. Emitter.prototype.addEventListener = function(event, fn) {
  5740. this._callbacks = this._callbacks || {};
  5741. (this._callbacks[event] = this._callbacks[event] || [])
  5742. .push(fn);
  5743. return this;
  5744. };
  5745. /**
  5746. * Adds an `event` listener that will be invoked a single
  5747. * time then automatically removed.
  5748. *
  5749. * @param {String} event
  5750. * @param {Function} fn
  5751. * @return {Emitter}
  5752. * @api public
  5753. */
  5754. Emitter.prototype.once = function(event, fn) {
  5755. var self = this;
  5756. this._callbacks = this._callbacks || {};
  5757. function on() {
  5758. self.off(event, on);
  5759. fn.apply(this, arguments);
  5760. }
  5761. on.fn = fn;
  5762. this.on(event, on);
  5763. return this;
  5764. };
  5765. /**
  5766. * Remove the given callback for `event` or all
  5767. * registered callbacks.
  5768. *
  5769. * @param {String} event
  5770. * @param {Function} fn
  5771. * @return {Emitter}
  5772. * @api public
  5773. */
  5774. Emitter.prototype.off =
  5775. Emitter.prototype.removeListener =
  5776. Emitter.prototype.removeAllListeners =
  5777. Emitter.prototype.removeEventListener = function(event, fn) {
  5778. this._callbacks = this._callbacks || {};
  5779. // all
  5780. if (0 == arguments.length) {
  5781. this._callbacks = {};
  5782. return this;
  5783. }
  5784. // specific event
  5785. var callbacks = this._callbacks[event];
  5786. if (!callbacks) return this;
  5787. // remove all handlers
  5788. if (1 == arguments.length) {
  5789. delete this._callbacks[event];
  5790. return this;
  5791. }
  5792. // remove specific handler
  5793. var cb;
  5794. for (var i = 0; i < callbacks.length; i++) {
  5795. cb = callbacks[i];
  5796. if (cb === fn || cb.fn === fn) {
  5797. callbacks.splice(i, 1);
  5798. break;
  5799. }
  5800. }
  5801. return this;
  5802. };
  5803. /**
  5804. * Emit `event` with the given args.
  5805. *
  5806. * @param {String} event
  5807. * @param {Mixed} ...
  5808. * @return {Emitter}
  5809. */
  5810. Emitter.prototype.emit = function(event) {
  5811. this._callbacks = this._callbacks || {};
  5812. var args = [].slice.call(arguments, 1),
  5813. callbacks = this._callbacks[event];
  5814. if (callbacks) {
  5815. callbacks = callbacks.slice(0);
  5816. for (var i = 0, len = callbacks.length; i < len; ++i) {
  5817. callbacks[i].apply(this, args);
  5818. }
  5819. }
  5820. return this;
  5821. };
  5822. /**
  5823. * Return array of callbacks for `event`.
  5824. *
  5825. * @param {String} event
  5826. * @return {Array}
  5827. * @api public
  5828. */
  5829. Emitter.prototype.listeners = function(event) {
  5830. this._callbacks = this._callbacks || {};
  5831. return this._callbacks[event] || [];
  5832. };
  5833. /**
  5834. * Check if this emitter has `event` handlers.
  5835. *
  5836. * @param {String} event
  5837. * @return {Boolean}
  5838. * @api public
  5839. */
  5840. Emitter.prototype.hasListeners = function(event) {
  5841. return !!this.listeners(event).length;
  5842. };
  5843. /***/
  5844. }),
  5845. /* 45 */
  5846. /***/
  5847. (function(module, exports, __webpack_require__) {
  5848. "use strict";
  5849. var _typeof2 = __webpack_require__(6);
  5850. var _typeof3 = _interopRequireDefault(_typeof2);
  5851. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  5852. var util = __webpack_require__(2);
  5853. var Component = __webpack_require__(16);
  5854. var TimeStep = __webpack_require__(66);
  5855. var DateUtil = __webpack_require__(36);
  5856. var moment = __webpack_require__(9);
  5857. /**
  5858. * A horizontal time axis
  5859. * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body
  5860. * @param {Object} [options] See TimeAxis.setOptions for the available
  5861. * options.
  5862. * @constructor TimeAxis
  5863. * @extends Component
  5864. */
  5865. function TimeAxis(body, options) {
  5866. this.dom = {
  5867. foreground: null,
  5868. lines: [],
  5869. majorTexts: [],
  5870. minorTexts: [],
  5871. redundant: {
  5872. lines: [],
  5873. majorTexts: [],
  5874. minorTexts: []
  5875. }
  5876. };
  5877. this.props = {
  5878. range: {
  5879. start: 0,
  5880. end: 0,
  5881. minimumStep: 0
  5882. },
  5883. lineTop: 0
  5884. };
  5885. this.defaultOptions = {
  5886. orientation: {
  5887. axis: 'bottom'
  5888. }, // axis orientation: 'top' or 'bottom'
  5889. showMinorLabels: true,
  5890. showMajorLabels: true,
  5891. maxMinorChars: 7,
  5892. format: TimeStep.FORMAT,
  5893. moment: moment,
  5894. timeAxis: null
  5895. };
  5896. this.options = util.extend({}, this.defaultOptions);
  5897. this.body = body;
  5898. // create the HTML DOM
  5899. this._create();
  5900. this.setOptions(options);
  5901. }
  5902. TimeAxis.prototype = new Component();
  5903. /**
  5904. * Set options for the TimeAxis.
  5905. * Parameters will be merged in current options.
  5906. * @param {Object} options Available options:
  5907. * {string} [orientation.axis]
  5908. * {boolean} [showMinorLabels]
  5909. * {boolean} [showMajorLabels]
  5910. */
  5911. TimeAxis.prototype.setOptions = function(options) {
  5912. if (options) {
  5913. // copy all options that we know
  5914. util.selectiveExtend(['showMinorLabels', 'showMajorLabels', 'maxMinorChars', 'hiddenDates', 'timeAxis', 'moment', 'rtl'], this.options, options);
  5915. // deep copy the format options
  5916. util.selectiveDeepExtend(['format'], this.options, options);
  5917. if ('orientation' in options) {
  5918. if (typeof options.orientation === 'string') {
  5919. this.options.orientation.axis = options.orientation;
  5920. } else if ((0, _typeof3['default'])(options.orientation) === 'object' && 'axis' in options.orientation) {
  5921. this.options.orientation.axis = options.orientation.axis;
  5922. }
  5923. }
  5924. // apply locale to moment.js
  5925. // TODO: not so nice, this is applied globally to moment.js
  5926. if ('locale' in options) {
  5927. if (typeof moment.locale === 'function') {
  5928. // moment.js 2.8.1+
  5929. moment.locale(options.locale);
  5930. } else {
  5931. moment.lang(options.locale);
  5932. }
  5933. }
  5934. }
  5935. };
  5936. /**
  5937. * Create the HTML DOM for the TimeAxis
  5938. */
  5939. TimeAxis.prototype._create = function() {
  5940. this.dom.foreground = document.createElement('div');
  5941. this.dom.background = document.createElement('div');
  5942. this.dom.foreground.className = 'vis-time-axis vis-foreground';
  5943. this.dom.background.className = 'vis-time-axis vis-background';
  5944. };
  5945. /**
  5946. * Destroy the TimeAxis
  5947. */
  5948. TimeAxis.prototype.destroy = function() {
  5949. // remove from DOM
  5950. if (this.dom.foreground.parentNode) {
  5951. this.dom.foreground.parentNode.removeChild(this.dom.foreground);
  5952. }
  5953. if (this.dom.background.parentNode) {
  5954. this.dom.background.parentNode.removeChild(this.dom.background);
  5955. }
  5956. this.body = null;
  5957. };
  5958. /**
  5959. * Repaint the component
  5960. * @return {boolean} Returns true if the component is resized
  5961. */
  5962. TimeAxis.prototype.redraw = function() {
  5963. var props = this.props;
  5964. var foreground = this.dom.foreground;
  5965. var background = this.dom.background;
  5966. // determine the correct parent DOM element (depending on option orientation)
  5967. var parent = this.options.orientation.axis == 'top' ? this.body.dom.top : this.body.dom.bottom;
  5968. var parentChanged = foreground.parentNode !== parent;
  5969. // calculate character width and height
  5970. this._calculateCharSize();
  5971. // TODO: recalculate sizes only needed when parent is resized or options is changed
  5972. var showMinorLabels = this.options.showMinorLabels && this.options.orientation.axis !== 'none';
  5973. var showMajorLabels = this.options.showMajorLabels && this.options.orientation.axis !== 'none';
  5974. // determine the width and height of the elemens for the axis
  5975. props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0;
  5976. props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0;
  5977. props.height = props.minorLabelHeight + props.majorLabelHeight;
  5978. props.width = foreground.offsetWidth;
  5979. props.minorLineHeight = this.body.domProps.root.height - props.majorLabelHeight - (this.options.orientation.axis == 'top' ? this.body.domProps.bottom.height : this.body.domProps.top.height);
  5980. props.minorLineWidth = 1; // TODO: really calculate width
  5981. props.majorLineHeight = props.minorLineHeight + props.majorLabelHeight;
  5982. props.majorLineWidth = 1; // TODO: really calculate width
  5983. // take foreground and background offline while updating (is almost twice as fast)
  5984. var foregroundNextSibling = foreground.nextSibling;
  5985. var backgroundNextSibling = background.nextSibling;
  5986. foreground.parentNode && foreground.parentNode.removeChild(foreground);
  5987. background.parentNode && background.parentNode.removeChild(background);
  5988. foreground.style.height = this.props.height + 'px';
  5989. this._repaintLabels();
  5990. // put DOM online again (at the same place)
  5991. if (foregroundNextSibling) {
  5992. parent.insertBefore(foreground, foregroundNextSibling);
  5993. } else {
  5994. parent.appendChild(foreground);
  5995. }
  5996. if (backgroundNextSibling) {
  5997. this.body.dom.backgroundVertical.insertBefore(background, backgroundNextSibling);
  5998. } else {
  5999. this.body.dom.backgroundVertical.appendChild(background);
  6000. }
  6001. return this._isResized() || parentChanged;
  6002. };
  6003. /**
  6004. * Repaint major and minor text labels and vertical grid lines
  6005. * @private
  6006. */
  6007. TimeAxis.prototype._repaintLabels = function() {
  6008. var orientation = this.options.orientation.axis;
  6009. // calculate range and step (step such that we have space for 7 characters per label)
  6010. var start = util.convert(this.body.range.start, 'Number');
  6011. var end = util.convert(this.body.range.end, 'Number');
  6012. var timeLabelsize = this.body.util.toTime((this.props.minorCharWidth || 10) * this.options.maxMinorChars).valueOf();
  6013. var minimumStep = timeLabelsize - DateUtil.getHiddenDurationBefore(this.options.moment, this.body.hiddenDates, this.body.range, timeLabelsize);
  6014. minimumStep -= this.body.util.toTime(0).valueOf();
  6015. var step = new TimeStep(new Date(start), new Date(end), minimumStep, this.body.hiddenDates, this.options);
  6016. step.setMoment(this.options.moment);
  6017. if (this.options.format) {
  6018. step.setFormat(this.options.format);
  6019. }
  6020. if (this.options.timeAxis) {
  6021. step.setScale(this.options.timeAxis);
  6022. }
  6023. this.step = step;
  6024. // Move all DOM elements to a "redundant" list, where they
  6025. // can be picked for re-use, and clear the lists with lines and texts.
  6026. // At the end of the function _repaintLabels, left over elements will be cleaned up
  6027. var dom = this.dom;
  6028. dom.redundant.lines = dom.lines;
  6029. dom.redundant.majorTexts = dom.majorTexts;
  6030. dom.redundant.minorTexts = dom.minorTexts;
  6031. dom.lines = [];
  6032. dom.majorTexts = [];
  6033. dom.minorTexts = [];
  6034. var current; // eslint-disable-line no-unused-vars
  6035. var next;
  6036. var x;
  6037. var xNext;
  6038. var isMajor;
  6039. var nextIsMajor; // eslint-disable-line no-unused-vars
  6040. var showMinorGrid;
  6041. var width = 0,
  6042. prevWidth;
  6043. var line;
  6044. var labelMinor;
  6045. var xFirstMajorLabel = undefined;
  6046. var count = 0;
  6047. var MAX = 1000;
  6048. var className;
  6049. step.start();
  6050. next = step.getCurrent();
  6051. xNext = this.body.util.toScreen(next);
  6052. while (step.hasNext() && count < MAX) {
  6053. count++;
  6054. isMajor = step.isMajor();
  6055. className = step.getClassName();
  6056. labelMinor = step.getLabelMinor();
  6057. current = next;
  6058. x = xNext;
  6059. step.next();
  6060. next = step.getCurrent();
  6061. nextIsMajor = step.isMajor();
  6062. xNext = this.body.util.toScreen(next);
  6063. prevWidth = width;
  6064. width = xNext - x;
  6065. switch (step.scale) {
  6066. case 'week':
  6067. showMinorGrid = true;
  6068. break;
  6069. default:
  6070. showMinorGrid = width >= prevWidth * 0.4;
  6071. break; // prevent displaying of the 31th of the month on a scale of 5 days
  6072. }
  6073. if (this.options.showMinorLabels && showMinorGrid) {
  6074. var label = this._repaintMinorText(x, labelMinor, orientation, className);
  6075. label.style.width = width + 'px'; // set width to prevent overflow
  6076. }
  6077. if (isMajor && this.options.showMajorLabels) {
  6078. if (x > 0) {
  6079. if (xFirstMajorLabel == undefined) {
  6080. xFirstMajorLabel = x;
  6081. }
  6082. label = this._repaintMajorText(x, step.getLabelMajor(), orientation, className);
  6083. }
  6084. line = this._repaintMajorLine(x, width, orientation, className);
  6085. } else {
  6086. // minor line
  6087. if (showMinorGrid) {
  6088. line = this._repaintMinorLine(x, width, orientation, className);
  6089. } else {
  6090. if (line) {
  6091. // adjust the width of the previous grid
  6092. line.style.width = parseInt(line.style.width) + width + 'px';
  6093. }
  6094. }
  6095. }
  6096. }
  6097. if (count === MAX && !warnedForOverflow) {
  6098. console.warn('Something is wrong with the Timeline scale. Limited drawing of grid lines to ' + MAX + ' lines.');
  6099. warnedForOverflow = true;
  6100. }
  6101. // create a major label on the left when needed
  6102. if (this.options.showMajorLabels) {
  6103. var leftTime = this.body.util.toTime(0),
  6104. leftText = step.getLabelMajor(leftTime),
  6105. widthText = leftText.length * (this.props.majorCharWidth || 10) + 10; // upper bound estimation
  6106. if (xFirstMajorLabel == undefined || widthText < xFirstMajorLabel) {
  6107. this._repaintMajorText(0, leftText, orientation, className);
  6108. }
  6109. }
  6110. // Cleanup leftover DOM elements from the redundant list
  6111. util.forEach(this.dom.redundant, function(arr) {
  6112. while (arr.length) {
  6113. var elem = arr.pop();
  6114. if (elem && elem.parentNode) {
  6115. elem.parentNode.removeChild(elem);
  6116. }
  6117. }
  6118. });
  6119. };
  6120. /**
  6121. * Create a minor label for the axis at position x
  6122. * @param {number} x
  6123. * @param {string} text
  6124. * @param {string} orientation "top" or "bottom" (default)
  6125. * @param {string} className
  6126. * @return {Element} Returns the HTML element of the created label
  6127. * @private
  6128. */
  6129. TimeAxis.prototype._repaintMinorText = function(x, text, orientation, className) {
  6130. // reuse redundant label
  6131. var label = this.dom.redundant.minorTexts.shift();
  6132. if (!label) {
  6133. // create new label
  6134. var content = document.createTextNode('');
  6135. label = document.createElement('div');
  6136. label.appendChild(content);
  6137. this.dom.foreground.appendChild(label);
  6138. }
  6139. this.dom.minorTexts.push(label);
  6140. label.innerHTML = text;
  6141. label.style.top = orientation == 'top' ? this.props.majorLabelHeight + 'px' : '0';
  6142. if (this.options.rtl) {
  6143. label.style.left = "";
  6144. label.style.right = x + 'px';
  6145. } else {
  6146. label.style.left = x + 'px';
  6147. }
  6148. label.className = 'vis-text vis-minor ' + className;
  6149. //label.title = title; // TODO: this is a heavy operation
  6150. return label;
  6151. };
  6152. /**
  6153. * Create a Major label for the axis at position x
  6154. * @param {number} x
  6155. * @param {string} text
  6156. * @param {string} orientation "top" or "bottom" (default)
  6157. * @param {string} className
  6158. * @return {Element} Returns the HTML element of the created label
  6159. * @private
  6160. */
  6161. TimeAxis.prototype._repaintMajorText = function(x, text, orientation, className) {
  6162. // reuse redundant label
  6163. var label = this.dom.redundant.majorTexts.shift();
  6164. if (!label) {
  6165. // create label
  6166. var content = document.createElement('div');
  6167. label = document.createElement('div');
  6168. label.appendChild(content);
  6169. this.dom.foreground.appendChild(label);
  6170. }
  6171. label.childNodes[0].innerHTML = text;
  6172. label.className = 'vis-text vis-major ' + className;
  6173. //label.title = title; // TODO: this is a heavy operation
  6174. label.style.top = orientation == 'top' ? '0' : this.props.minorLabelHeight + 'px';
  6175. if (this.options.rtl) {
  6176. label.style.left = "";
  6177. label.style.right = x + 'px';
  6178. } else {
  6179. label.style.left = x + 'px';
  6180. }
  6181. this.dom.majorTexts.push(label);
  6182. return label;
  6183. };
  6184. /**
  6185. * Create a minor line for the axis at position x
  6186. * @param {number} x
  6187. * @param {number} width
  6188. * @param {string} orientation "top" or "bottom" (default)
  6189. * @param {string} className
  6190. * @return {Element} Returns the created line
  6191. * @private
  6192. */
  6193. TimeAxis.prototype._repaintMinorLine = function(x, width, orientation, className) {
  6194. // reuse redundant line
  6195. var line = this.dom.redundant.lines.shift();
  6196. if (!line) {
  6197. // create vertical line
  6198. line = document.createElement('div');
  6199. this.dom.background.appendChild(line);
  6200. }
  6201. this.dom.lines.push(line);
  6202. var props = this.props;
  6203. if (orientation == 'top') {
  6204. line.style.top = props.majorLabelHeight + 'px';
  6205. } else {
  6206. line.style.top = this.body.domProps.top.height + 'px';
  6207. }
  6208. line.style.height = props.minorLineHeight + 'px';
  6209. if (this.options.rtl) {
  6210. line.style.left = "";
  6211. line.style.right = x - props.minorLineWidth / 2 + 'px';
  6212. line.className = 'vis-grid vis-vertical-rtl vis-minor ' + className;
  6213. } else {
  6214. line.style.left = x - props.minorLineWidth / 2 + 'px';
  6215. line.className = 'vis-grid vis-vertical vis-minor ' + className;
  6216. }
  6217. line.style.width = width + 'px';
  6218. return line;
  6219. };
  6220. /**
  6221. * Create a Major line for the axis at position x
  6222. * @param {number} x
  6223. * @param {number} width
  6224. * @param {string} orientation "top" or "bottom" (default)
  6225. * @param {string} className
  6226. * @return {Element} Returns the created line
  6227. * @private
  6228. */
  6229. TimeAxis.prototype._repaintMajorLine = function(x, width, orientation, className) {
  6230. // reuse redundant line
  6231. var line = this.dom.redundant.lines.shift();
  6232. if (!line) {
  6233. // create vertical line
  6234. line = document.createElement('div');
  6235. this.dom.background.appendChild(line);
  6236. }
  6237. this.dom.lines.push(line);
  6238. var props = this.props;
  6239. if (orientation == 'top') {
  6240. line.style.top = '0';
  6241. } else {
  6242. line.style.top = this.body.domProps.top.height + 'px';
  6243. }
  6244. if (this.options.rtl) {
  6245. line.style.left = "";
  6246. line.style.right = x - props.majorLineWidth / 2 + 'px';
  6247. line.className = 'vis-grid vis-vertical-rtl vis-major ' + className;
  6248. } else {
  6249. line.style.left = x - props.majorLineWidth / 2 + 'px';
  6250. line.className = 'vis-grid vis-vertical vis-major ' + className;
  6251. }
  6252. line.style.height = props.majorLineHeight + 'px';
  6253. line.style.width = width + 'px';
  6254. return line;
  6255. };
  6256. /**
  6257. * Determine the size of text on the axis (both major and minor axis).
  6258. * The size is calculated only once and then cached in this.props.
  6259. * @private
  6260. */
  6261. TimeAxis.prototype._calculateCharSize = function() {
  6262. // Note: We calculate char size with every redraw. Size may change, for
  6263. // example when any of the timelines parents had display:none for example.
  6264. // determine the char width and height on the minor axis
  6265. if (!this.dom.measureCharMinor) {
  6266. this.dom.measureCharMinor = document.createElement('DIV');
  6267. this.dom.measureCharMinor.className = 'vis-text vis-minor vis-measure';
  6268. this.dom.measureCharMinor.style.position = 'absolute';
  6269. this.dom.measureCharMinor.appendChild(document.createTextNode('0'));
  6270. this.dom.foreground.appendChild(this.dom.measureCharMinor);
  6271. }
  6272. this.props.minorCharHeight = this.dom.measureCharMinor.clientHeight;
  6273. this.props.minorCharWidth = this.dom.measureCharMinor.clientWidth;
  6274. // determine the char width and height on the major axis
  6275. if (!this.dom.measureCharMajor) {
  6276. this.dom.measureCharMajor = document.createElement('DIV');
  6277. this.dom.measureCharMajor.className = 'vis-text vis-major vis-measure';
  6278. this.dom.measureCharMajor.style.position = 'absolute';
  6279. this.dom.measureCharMajor.appendChild(document.createTextNode('0'));
  6280. this.dom.foreground.appendChild(this.dom.measureCharMajor);
  6281. }
  6282. this.props.majorCharHeight = this.dom.measureCharMajor.clientHeight;
  6283. this.props.majorCharWidth = this.dom.measureCharMajor.clientWidth;
  6284. };
  6285. var warnedForOverflow = false;
  6286. module.exports = TimeAxis;
  6287. /***/
  6288. }),
  6289. /* 46 */
  6290. /***/
  6291. (function(module, exports, __webpack_require__) {
  6292. "use strict";
  6293. var Hammer = __webpack_require__(10);
  6294. var util = __webpack_require__(2);
  6295. var Component = __webpack_require__(16);
  6296. var moment = __webpack_require__(9);
  6297. var locales = __webpack_require__(98);
  6298. /**
  6299. * A custom time bar
  6300. * @param {{range: Range, dom: Object}} body
  6301. * @param {Object} [options] Available parameters:
  6302. * {number | string} id
  6303. * {string} locales
  6304. * {string} locale
  6305. * @constructor CustomTime
  6306. * @extends Component
  6307. */
  6308. function CustomTime(body, options) {
  6309. this.body = body;
  6310. // default options
  6311. this.defaultOptions = {
  6312. moment: moment,
  6313. locales: locales,
  6314. locale: 'en',
  6315. id: undefined,
  6316. title: undefined
  6317. };
  6318. this.options = util.extend({}, this.defaultOptions);
  6319. if (options && options.time) {
  6320. this.customTime = options.time;
  6321. } else {
  6322. this.customTime = new Date();
  6323. }
  6324. this.eventParams = {}; // stores state parameters while dragging the bar
  6325. this.setOptions(options);
  6326. // create the DOM
  6327. this._create();
  6328. }
  6329. CustomTime.prototype = new Component();
  6330. /**
  6331. * Set options for the component. Options will be merged in current options.
  6332. * @param {Object} options Available parameters:
  6333. * {number | string} id
  6334. * {string} locales
  6335. * {string} locale
  6336. */
  6337. CustomTime.prototype.setOptions = function(options) {
  6338. if (options) {
  6339. // copy all options that we know
  6340. util.selectiveExtend(['moment', 'locale', 'locales', 'id'], this.options, options);
  6341. }
  6342. };
  6343. /**
  6344. * Create the DOM for the custom time
  6345. * @private
  6346. */
  6347. CustomTime.prototype._create = function() {
  6348. var bar = document.createElement('div');
  6349. bar['custom-time'] = this;
  6350. bar.className = 'vis-custom-time ' + (this.options.id || '');
  6351. bar.style.position = 'absolute';
  6352. bar.style.top = '0px';
  6353. bar.style.height = '100%';
  6354. this.bar = bar;
  6355. var drag = document.createElement('div');
  6356. drag.style.position = 'relative';
  6357. drag.style.top = '0px';
  6358. drag.style.left = '-10px';
  6359. drag.style.height = '100%';
  6360. drag.style.width = '20px';
  6361. /**
  6362. *
  6363. * @param {WheelEvent} e
  6364. */
  6365. function onMouseWheel(e) {
  6366. this.body.range._onMouseWheel(e);
  6367. }
  6368. if (drag.addEventListener) {
  6369. // IE9, Chrome, Safari, Opera
  6370. drag.addEventListener("mousewheel", onMouseWheel.bind(this), false);
  6371. // Firefox
  6372. drag.addEventListener("DOMMouseScroll", onMouseWheel.bind(this), false);
  6373. } else {
  6374. // IE 6/7/8
  6375. drag.attachEvent("onmousewheel", onMouseWheel.bind(this));
  6376. }
  6377. bar.appendChild(drag);
  6378. // attach event listeners
  6379. this.hammer = new Hammer(drag);
  6380. this.hammer.on('panstart', this._onDragStart.bind(this));
  6381. this.hammer.on('panmove', this._onDrag.bind(this));
  6382. this.hammer.on('panend', this._onDragEnd.bind(this));
  6383. this.hammer.get('pan').set({ threshold: 5, direction: Hammer.DIRECTION_HORIZONTAL });
  6384. };
  6385. /**
  6386. * Destroy the CustomTime bar
  6387. */
  6388. CustomTime.prototype.destroy = function() {
  6389. this.hide();
  6390. this.hammer.destroy();
  6391. this.hammer = null;
  6392. this.body = null;
  6393. };
  6394. /**
  6395. * Repaint the component
  6396. * @return {boolean} Returns true if the component is resized
  6397. */
  6398. CustomTime.prototype.redraw = function() {
  6399. var parent = this.body.dom.backgroundVertical;
  6400. if (this.bar.parentNode != parent) {
  6401. // attach to the dom
  6402. if (this.bar.parentNode) {
  6403. this.bar.parentNode.removeChild(this.bar);
  6404. }
  6405. parent.appendChild(this.bar);
  6406. }
  6407. var x = this.body.util.toScreen(this.customTime);
  6408. var locale = this.options.locales[this.options.locale];
  6409. if (!locale) {
  6410. if (!this.warned) {
  6411. console.log('WARNING: options.locales[\'' + this.options.locale + '\'] not found. See http://visjs.org/docs/timeline/#Localization');
  6412. this.warned = true;
  6413. }
  6414. locale = this.options.locales['en']; // fall back on english when not available
  6415. }
  6416. var title = this.options.title;
  6417. // To hide the title completely use empty string ''.
  6418. if (title === undefined) {
  6419. title = locale.time + ': ' + this.options.moment(this.customTime).format('dddd, MMMM Do YYYY, H:mm:ss');
  6420. title = title.charAt(0).toUpperCase() + title.substring(1);
  6421. } else if (typeof title === "function") {
  6422. title = title.call(this.customTime);
  6423. }
  6424. this.bar.style.left = x + 'px';
  6425. this.bar.title = title;
  6426. return false;
  6427. };
  6428. /**
  6429. * Remove the CustomTime from the DOM
  6430. */
  6431. CustomTime.prototype.hide = function() {
  6432. // remove the line from the DOM
  6433. if (this.bar.parentNode) {
  6434. this.bar.parentNode.removeChild(this.bar);
  6435. }
  6436. };
  6437. /**
  6438. * Set custom time.
  6439. * @param {Date | number | string} time
  6440. */
  6441. CustomTime.prototype.setCustomTime = function(time) {
  6442. this.customTime = util.convert(time, 'Date');
  6443. this.redraw();
  6444. };
  6445. /**
  6446. * Retrieve the current custom time.
  6447. * @return {Date} customTime
  6448. */
  6449. CustomTime.prototype.getCustomTime = function() {
  6450. return new Date(this.customTime.valueOf());
  6451. };
  6452. /**
  6453. * Set custom title.
  6454. * @param {Date | number | string} title
  6455. */
  6456. CustomTime.prototype.setCustomTitle = function(title) {
  6457. this.options.title = title;
  6458. };
  6459. /**
  6460. * Start moving horizontally
  6461. * @param {Event} event
  6462. * @private
  6463. */
  6464. CustomTime.prototype._onDragStart = function(event) {
  6465. this.eventParams.dragging = true;
  6466. this.eventParams.customTime = this.customTime;
  6467. event.stopPropagation();
  6468. };
  6469. /**
  6470. * Perform moving operating.
  6471. * @param {Event} event
  6472. * @private
  6473. */
  6474. CustomTime.prototype._onDrag = function(event) {
  6475. if (!this.eventParams.dragging) return;
  6476. var x = this.body.util.toScreen(this.eventParams.customTime) + event.deltaX;
  6477. var time = this.body.util.toTime(x);
  6478. this.setCustomTime(time);
  6479. // fire a timechange event
  6480. this.body.emitter.emit('timechange', {
  6481. id: this.options.id,
  6482. time: new Date(this.customTime.valueOf()),
  6483. event: event
  6484. });
  6485. event.stopPropagation();
  6486. };
  6487. /**
  6488. * Stop moving operating.
  6489. * @param {Event} event
  6490. * @private
  6491. */
  6492. CustomTime.prototype._onDragEnd = function(event) {
  6493. if (!this.eventParams.dragging) return;
  6494. // fire a timechanged event
  6495. this.body.emitter.emit('timechanged', {
  6496. id: this.options.id,
  6497. time: new Date(this.customTime.valueOf()),
  6498. event: event
  6499. });
  6500. event.stopPropagation();
  6501. };
  6502. /**
  6503. * Find a custom time from an event target:
  6504. * searches for the attribute 'custom-time' in the event target's element tree
  6505. * @param {Event} event
  6506. * @return {CustomTime | null} customTime
  6507. */
  6508. CustomTime.customTimeFromTarget = function(event) {
  6509. var target = event.target;
  6510. while (target) {
  6511. if (target.hasOwnProperty('custom-time')) {
  6512. return target['custom-time'];
  6513. }
  6514. target = target.parentNode;
  6515. }
  6516. return null;
  6517. };
  6518. module.exports = CustomTime;
  6519. /***/
  6520. }),
  6521. /* 47 */
  6522. /***/
  6523. (function(module, exports, __webpack_require__) {
  6524. "use strict";
  6525. Object.defineProperty(exports, "__esModule", {
  6526. value: true
  6527. });
  6528. var _classCallCheck2 = __webpack_require__(0);
  6529. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  6530. var _createClass2 = __webpack_require__(1);
  6531. var _createClass3 = _interopRequireDefault(_createClass2);
  6532. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  6533. var util = __webpack_require__(2);
  6534. var Label = __webpack_require__(117)['default'];
  6535. var ComponentUtil = __webpack_require__(48)['default'];
  6536. var Box = __webpack_require__(193)['default'];
  6537. var Circle = __webpack_require__(200)['default'];
  6538. var CircularImage = __webpack_require__(201)['default'];
  6539. var Database = __webpack_require__(202)['default'];
  6540. var Diamond = __webpack_require__(203)['default'];
  6541. var Dot = __webpack_require__(204)['default'];
  6542. var Ellipse = __webpack_require__(205)['default'];
  6543. var Icon = __webpack_require__(206)['default'];
  6544. var Image = __webpack_require__(207)['default'];
  6545. var Square = __webpack_require__(208)['default'];
  6546. var Hexagon = __webpack_require__(209)['default'];
  6547. var Star = __webpack_require__(210)['default'];
  6548. var Text = __webpack_require__(211)['default'];
  6549. var Triangle = __webpack_require__(212)['default'];
  6550. var TriangleDown = __webpack_require__(213)['default'];
  6551. var _require = __webpack_require__(15),
  6552. printStyle = _require.printStyle;
  6553. /**
  6554. * A node. A node can be connected to other nodes via one or multiple edges.
  6555. */
  6556. var Node = function() {
  6557. /**
  6558. *
  6559. * @param {object} options An object containing options for the node. All
  6560. * options are optional, except for the id.
  6561. * {number} id Id of the node. Required
  6562. * {string} label Text label for the node
  6563. * {number} x Horizontal position of the node
  6564. * {number} y Vertical position of the node
  6565. * {string} shape Node shape
  6566. * {string} image An image url
  6567. * {string} title A title text, can be HTML
  6568. * {anytype} group A group name or number
  6569. *
  6570. * @param {Object} body Shared state of current network instance
  6571. * @param {Network.Images} imagelist A list with images. Only needed when the node has an image
  6572. * @param {Groups} grouplist A list with groups. Needed for retrieving group options
  6573. * @param {Object} globalOptions Current global node options; these serve as defaults for the node instance
  6574. * @param {Object} defaultOptions Global default options for nodes; note that this is also the prototype
  6575. * for parameter `globalOptions`.
  6576. */
  6577. function Node(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
  6578. (0, _classCallCheck3['default'])(this, Node);
  6579. this.options = util.bridgeObject(globalOptions);
  6580. this.globalOptions = globalOptions;
  6581. this.defaultOptions = defaultOptions;
  6582. this.body = body;
  6583. this.edges = []; // all edges connected to this node
  6584. // set defaults for the options
  6585. this.id = undefined;
  6586. this.imagelist = imagelist;
  6587. this.grouplist = grouplist;
  6588. // state options
  6589. this.x = undefined;
  6590. this.y = undefined;
  6591. this.baseSize = this.options.size;
  6592. this.baseFontSize = this.options.font.size;
  6593. this.predefinedPosition = false; // used to check if initial fit should just take the range or approximate
  6594. this.selected = false;
  6595. this.hover = false;
  6596. this.labelModule = new Label(this.body, this.options, false /* Not edge label */ );
  6597. this.setOptions(options);
  6598. }
  6599. /**
  6600. * Attach a edge to the node
  6601. * @param {Edge} edge
  6602. */
  6603. (0, _createClass3['default'])(Node, [{
  6604. key: 'attachEdge',
  6605. value: function attachEdge(edge) {
  6606. if (this.edges.indexOf(edge) === -1) {
  6607. this.edges.push(edge);
  6608. }
  6609. }
  6610. /**
  6611. * Detach a edge from the node
  6612. *
  6613. * @param {Edge} edge
  6614. */
  6615. }, {
  6616. key: 'detachEdge',
  6617. value: function detachEdge(edge) {
  6618. var index = this.edges.indexOf(edge);
  6619. if (index != -1) {
  6620. this.edges.splice(index, 1);
  6621. }
  6622. }
  6623. /**
  6624. * Set or overwrite options for the node
  6625. *
  6626. * @param {Object} options an object with options
  6627. * @returns {null|boolean}
  6628. */
  6629. }, {
  6630. key: 'setOptions',
  6631. value: function setOptions(options) {
  6632. var currentShape = this.options.shape;
  6633. if (!options) {
  6634. return; // Note that the return value will be 'undefined'! This is OK.
  6635. }
  6636. // basic options
  6637. if (options.id !== undefined) {
  6638. this.id = options.id;
  6639. }
  6640. if (this.id === undefined) {
  6641. throw new Error("Node must have an id");
  6642. }
  6643. Node.checkMass(options, this.id);
  6644. // set these options locally
  6645. // clear x and y positions
  6646. if (options.x !== undefined) {
  6647. if (options.x === null) {
  6648. this.x = undefined;
  6649. this.predefinedPosition = false;
  6650. } else {
  6651. this.x = parseInt(options.x);
  6652. this.predefinedPosition = true;
  6653. }
  6654. }
  6655. if (options.y !== undefined) {
  6656. if (options.y === null) {
  6657. this.y = undefined;
  6658. this.predefinedPosition = false;
  6659. } else {
  6660. this.y = parseInt(options.y);
  6661. this.predefinedPosition = true;
  6662. }
  6663. }
  6664. if (options.size !== undefined) {
  6665. this.baseSize = options.size;
  6666. }
  6667. if (options.value !== undefined) {
  6668. options.value = parseFloat(options.value);
  6669. }
  6670. // this transforms all shorthands into fully defined options
  6671. Node.parseOptions(this.options, options, true, this.globalOptions, this.grouplist);
  6672. var pile = [options, this.options, this.defaultOptions];
  6673. this.chooser = ComponentUtil.choosify('node', pile);
  6674. this._load_images();
  6675. this.updateLabelModule(options);
  6676. this.updateShape(currentShape);
  6677. return options.hidden !== undefined || options.physics !== undefined;
  6678. }
  6679. /**
  6680. * Load the images from the options, for the nodes that need them.
  6681. *
  6682. * TODO: The imageObj members should be moved to CircularImageBase.
  6683. * It's the only place where they are required.
  6684. *
  6685. * @private
  6686. */
  6687. }, {
  6688. key: '_load_images',
  6689. value: function _load_images() {
  6690. // Don't bother loading for nodes without images
  6691. if (this.options.shape !== 'circularImage' && this.options.shape !== 'image') {
  6692. return;
  6693. }
  6694. if (this.options.image === undefined) {
  6695. throw new Error("Option image must be defined for node type '" + this.options.shape + "'");
  6696. }
  6697. if (this.imagelist === undefined) {
  6698. throw new Error("Internal Error: No images provided");
  6699. }
  6700. if (typeof this.options.image === 'string') {
  6701. this.imageObj = this.imagelist.load(this.options.image, this.options.brokenImage, this.id);
  6702. } else {
  6703. if (this.options.image.unselected === undefined) {
  6704. throw new Error("No unselected image provided");
  6705. }
  6706. this.imageObj = this.imagelist.load(this.options.image.unselected, this.options.brokenImage, this.id);
  6707. if (this.options.image.selected !== undefined) {
  6708. this.imageObjAlt = this.imagelist.load(this.options.image.selected, this.options.brokenImage, this.id);
  6709. } else {
  6710. this.imageObjAlt = undefined;
  6711. }
  6712. }
  6713. }
  6714. /**
  6715. * Copy group option values into the node options.
  6716. *
  6717. * The group options override the global node options, so the copy of group options
  6718. * must happen *after* the global node options have been set.
  6719. *
  6720. * This method must also be called also if the global node options have changed and the group options did not.
  6721. *
  6722. * @param {Object} parentOptions
  6723. * @param {Object} newOptions new values for the options, currently only passed in for check
  6724. * @param {Object} groupList
  6725. */
  6726. }, {
  6727. key: 'getFormattingValues',
  6728. /**
  6729. *
  6730. * @returns {{color: *, borderWidth: *, borderColor: *, size: *, borderDashes: (boolean|Array|allOptions.nodes.shapeProperties.borderDashes|{boolean, array}), borderRadius: (number|allOptions.nodes.shapeProperties.borderRadius|{number}|Array), shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *}}
  6731. */
  6732. value: function getFormattingValues() {
  6733. var values = {
  6734. color: this.options.color.background,
  6735. borderWidth: this.options.borderWidth,
  6736. borderColor: this.options.color.border,
  6737. size: this.options.size,
  6738. borderDashes: this.options.shapeProperties.borderDashes,
  6739. borderRadius: this.options.shapeProperties.borderRadius,
  6740. shadow: this.options.shadow.enabled,
  6741. shadowColor: this.options.shadow.color,
  6742. shadowSize: this.options.shadow.size,
  6743. shadowX: this.options.shadow.x,
  6744. shadowY: this.options.shadow.y
  6745. };
  6746. if (this.selected || this.hover) {
  6747. if (this.chooser === true) {
  6748. if (this.selected) {
  6749. values.borderWidth *= 2;
  6750. values.color = this.options.color.highlight.background;
  6751. values.borderColor = this.options.color.highlight.border;
  6752. values.shadow = this.options.shadow.enabled;
  6753. } else if (this.hover) {
  6754. values.color = this.options.color.hover.background;
  6755. values.borderColor = this.options.color.hover.border;
  6756. values.shadow = this.options.shadow.enabled;
  6757. }
  6758. } else if (typeof this.chooser === 'function') {
  6759. this.chooser(values, this.options.id, this.selected, this.hover);
  6760. if (values.shadow === false) {
  6761. if (values.shadowColor !== this.options.shadow.color || values.shadowSize !== this.options.shadow.size || values.shadowX !== this.options.shadow.x || values.shadowY !== this.options.shadow.y) {
  6762. values.shadow = true;
  6763. }
  6764. }
  6765. }
  6766. } else {
  6767. values.shadow = this.options.shadow.enabled;
  6768. }
  6769. return values;
  6770. }
  6771. /**
  6772. *
  6773. * @param {Object} options
  6774. */
  6775. }, {
  6776. key: 'updateLabelModule',
  6777. value: function updateLabelModule(options) {
  6778. if (this.options.label === undefined || this.options.label === null) {
  6779. this.options.label = '';
  6780. }
  6781. Node.updateGroupOptions(this.options, options, this.grouplist);
  6782. //
  6783. // Note:The prototype chain for this.options is:
  6784. //
  6785. // this.options -> NodesHandler.options -> NodesHandler.defaultOptions
  6786. // (also: this.globalOptions)
  6787. //
  6788. // Note that the prototypes are mentioned explicitly in the pile list below;
  6789. // WE DON'T WANT THE ORDER OF THE PROTOTYPES!!!! At least, not for font handling of labels.
  6790. // This is a good indication that the prototype usage of options is deficient.
  6791. //
  6792. var currentGroup = this.grouplist.get(this.options.group, false);
  6793. var pile = [options, // new options
  6794. this.options, // current node options, see comment above for prototype
  6795. currentGroup, // group options, if any
  6796. this.globalOptions, // Currently set global node options
  6797. this.defaultOptions // Default global node options
  6798. ];
  6799. this.labelModule.update(this.options, pile);
  6800. if (this.labelModule.baseSize !== undefined) {
  6801. this.baseFontSize = this.labelModule.baseSize;
  6802. }
  6803. }
  6804. /**
  6805. *
  6806. * @param {string} currentShape
  6807. */
  6808. }, {
  6809. key: 'updateShape',
  6810. value: function updateShape(currentShape) {
  6811. if (currentShape === this.options.shape && this.shape) {
  6812. this.shape.setOptions(this.options, this.imageObj, this.imageObjAlt);
  6813. } else {
  6814. // choose draw method depending on the shape
  6815. switch (this.options.shape) {
  6816. case 'box':
  6817. this.shape = new Box(this.options, this.body, this.labelModule);
  6818. break;
  6819. case 'circle':
  6820. this.shape = new Circle(this.options, this.body, this.labelModule);
  6821. break;
  6822. case 'circularImage':
  6823. this.shape = new CircularImage(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
  6824. break;
  6825. case 'database':
  6826. this.shape = new Database(this.options, this.body, this.labelModule);
  6827. break;
  6828. case 'diamond':
  6829. this.shape = new Diamond(this.options, this.body, this.labelModule);
  6830. break;
  6831. case 'dot':
  6832. this.shape = new Dot(this.options, this.body, this.labelModule);
  6833. break;
  6834. case 'ellipse':
  6835. this.shape = new Ellipse(this.options, this.body, this.labelModule);
  6836. break;
  6837. case 'icon':
  6838. this.shape = new Icon(this.options, this.body, this.labelModule);
  6839. break;
  6840. case 'image':
  6841. this.shape = new Image(this.options, this.body, this.labelModule, this.imageObj, this.imageObjAlt);
  6842. break;
  6843. case 'square':
  6844. this.shape = new Square(this.options, this.body, this.labelModule);
  6845. break;
  6846. case 'hexagon':
  6847. this.shape = new Hexagon(this.options, this.body, this.labelModule);
  6848. break;
  6849. case 'star':
  6850. this.shape = new Star(this.options, this.body, this.labelModule);
  6851. break;
  6852. case 'text':
  6853. this.shape = new Text(this.options, this.body, this.labelModule);
  6854. break;
  6855. case 'triangle':
  6856. this.shape = new Triangle(this.options, this.body, this.labelModule);
  6857. break;
  6858. case 'triangleDown':
  6859. this.shape = new TriangleDown(this.options, this.body, this.labelModule);
  6860. break;
  6861. default:
  6862. this.shape = new Ellipse(this.options, this.body, this.labelModule);
  6863. break;
  6864. }
  6865. }
  6866. this.needsRefresh();
  6867. }
  6868. /**
  6869. * select this node
  6870. */
  6871. }, {
  6872. key: 'select',
  6873. value: function select() {
  6874. this.selected = true;
  6875. this.needsRefresh();
  6876. }
  6877. /**
  6878. * unselect this node
  6879. */
  6880. }, {
  6881. key: 'unselect',
  6882. value: function unselect() {
  6883. this.selected = false;
  6884. this.needsRefresh();
  6885. }
  6886. /**
  6887. * Reset the calculated size of the node, forces it to recalculate its size
  6888. */
  6889. }, {
  6890. key: 'needsRefresh',
  6891. value: function needsRefresh() {
  6892. this.shape.refreshNeeded = true;
  6893. }
  6894. /**
  6895. * get the title of this node.
  6896. * @return {string} title The title of the node, or undefined when no title
  6897. * has been set.
  6898. */
  6899. }, {
  6900. key: 'getTitle',
  6901. value: function getTitle() {
  6902. return this.options.title;
  6903. }
  6904. /**
  6905. * Calculate the distance to the border of the Node
  6906. * @param {CanvasRenderingContext2D} ctx
  6907. * @param {number} angle Angle in radians
  6908. * @returns {number} distance Distance to the border in pixels
  6909. */
  6910. }, {
  6911. key: 'distanceToBorder',
  6912. value: function distanceToBorder(ctx, angle) {
  6913. return this.shape.distanceToBorder(ctx, angle);
  6914. }
  6915. /**
  6916. * Check if this node has a fixed x and y position
  6917. * @return {boolean} true if fixed, false if not
  6918. */
  6919. }, {
  6920. key: 'isFixed',
  6921. value: function isFixed() {
  6922. return this.options.fixed.x && this.options.fixed.y;
  6923. }
  6924. /**
  6925. * check if this node is selecte
  6926. * @return {boolean} selected True if node is selected, else false
  6927. */
  6928. }, {
  6929. key: 'isSelected',
  6930. value: function isSelected() {
  6931. return this.selected;
  6932. }
  6933. /**
  6934. * Retrieve the value of the node. Can be undefined
  6935. * @return {number} value
  6936. */
  6937. }, {
  6938. key: 'getValue',
  6939. value: function getValue() {
  6940. return this.options.value;
  6941. }
  6942. /**
  6943. * Get the current dimensions of the label
  6944. *
  6945. * @return {rect}
  6946. */
  6947. }, {
  6948. key: 'getLabelSize',
  6949. value: function getLabelSize() {
  6950. return this.labelModule.size();
  6951. }
  6952. /**
  6953. * Adjust the value range of the node. The node will adjust it's size
  6954. * based on its value.
  6955. * @param {number} min
  6956. * @param {number} max
  6957. * @param {number} total
  6958. */
  6959. }, {
  6960. key: 'setValueRange',
  6961. value: function setValueRange(min, max, total) {
  6962. if (this.options.value !== undefined) {
  6963. var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
  6964. var sizeDiff = this.options.scaling.max - this.options.scaling.min;
  6965. if (this.options.scaling.label.enabled === true) {
  6966. var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
  6967. this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
  6968. }
  6969. this.options.size = this.options.scaling.min + scale * sizeDiff;
  6970. } else {
  6971. this.options.size = this.baseSize;
  6972. this.options.font.size = this.baseFontSize;
  6973. }
  6974. this.updateLabelModule();
  6975. }
  6976. /**
  6977. * Draw this node in the given canvas
  6978. * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
  6979. * @param {CanvasRenderingContext2D} ctx
  6980. */
  6981. }, {
  6982. key: 'draw',
  6983. value: function draw(ctx) {
  6984. var values = this.getFormattingValues();
  6985. this.shape.draw(ctx, this.x, this.y, this.selected, this.hover, values);
  6986. }
  6987. /**
  6988. * Update the bounding box of the shape
  6989. * @param {CanvasRenderingContext2D} ctx
  6990. */
  6991. }, {
  6992. key: 'updateBoundingBox',
  6993. value: function updateBoundingBox(ctx) {
  6994. this.shape.updateBoundingBox(this.x, this.y, ctx);
  6995. }
  6996. /**
  6997. * Recalculate the size of this node in the given canvas
  6998. * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
  6999. * @param {CanvasRenderingContext2D} ctx
  7000. */
  7001. }, {
  7002. key: 'resize',
  7003. value: function resize(ctx) {
  7004. var values = this.getFormattingValues();
  7005. this.shape.resize(ctx, this.selected, this.hover, values);
  7006. }
  7007. /**
  7008. * Determine all visual elements of this node instance, in which the given
  7009. * point falls within the bounding shape.
  7010. *
  7011. * @param {point} point
  7012. * @returns {Array.<nodeClickItem|nodeLabelClickItem>} list with the items which are on the point
  7013. */
  7014. }, {
  7015. key: 'getItemsOnPoint',
  7016. value: function getItemsOnPoint(point) {
  7017. var ret = [];
  7018. if (this.labelModule.visible()) {
  7019. if (ComponentUtil.pointInRect(this.labelModule.getSize(), point)) {
  7020. ret.push({ nodeId: this.id, labelId: 0 });
  7021. }
  7022. }
  7023. if (ComponentUtil.pointInRect(this.shape.boundingBox, point)) {
  7024. ret.push({ nodeId: this.id });
  7025. }
  7026. return ret;
  7027. }
  7028. /**
  7029. * Check if this object is overlapping with the provided object
  7030. * @param {Object} obj an object with parameters left, top, right, bottom
  7031. * @return {boolean} True if location is located on node
  7032. */
  7033. }, {
  7034. key: 'isOverlappingWith',
  7035. value: function isOverlappingWith(obj) {
  7036. return this.shape.left < obj.right && this.shape.left + this.shape.width > obj.left && this.shape.top < obj.bottom && this.shape.top + this.shape.height > obj.top;
  7037. }
  7038. /**
  7039. * Check if this object is overlapping with the provided object
  7040. * @param {Object} obj an object with parameters left, top, right, bottom
  7041. * @return {boolean} True if location is located on node
  7042. */
  7043. }, {
  7044. key: 'isBoundingBoxOverlappingWith',
  7045. value: function isBoundingBoxOverlappingWith(obj) {
  7046. return this.shape.boundingBox.left < obj.right && this.shape.boundingBox.right > obj.left && this.shape.boundingBox.top < obj.bottom && this.shape.boundingBox.bottom > obj.top;
  7047. }
  7048. /**
  7049. * Check valid values for mass
  7050. *
  7051. * The mass may not be negative or zero. If it is, reset to 1
  7052. *
  7053. * @param {object} options
  7054. * @param {Node.id} id
  7055. * @static
  7056. */
  7057. }], [{
  7058. key: 'updateGroupOptions',
  7059. value: function updateGroupOptions(parentOptions, newOptions, groupList) {
  7060. if (groupList === undefined) return; // No groups, nothing to do
  7061. var group = parentOptions.group;
  7062. // paranoia: the selected group is already merged into node options, check.
  7063. if (newOptions !== undefined && newOptions.group !== undefined && group !== newOptions.group) {
  7064. throw new Error("updateGroupOptions: group values in options don't match.");
  7065. }
  7066. var hasGroup = typeof group === 'number' || typeof group === 'string' && group != '';
  7067. if (!hasGroup) return; // current node has no group, no need to merge
  7068. var groupObj = groupList.get(group);
  7069. // Skip merging of group font options into parent; these are required to be distinct for labels
  7070. // TODO: It might not be a good idea either to merge the rest of the options, investigate this.
  7071. util.selectiveNotDeepExtend(['font'], parentOptions, groupObj);
  7072. // the color object needs to be completely defined.
  7073. // Since groups can partially overwrite the colors, we parse it again, just in case.
  7074. parentOptions.color = util.parseColor(parentOptions.color);
  7075. }
  7076. /**
  7077. * This process all possible shorthands in the new options and makes sure that the parentOptions are fully defined.
  7078. * Static so it can also be used by the handler.
  7079. *
  7080. * @param {Object} parentOptions
  7081. * @param {Object} newOptions
  7082. * @param {boolean} [allowDeletion=false]
  7083. * @param {Object} [globalOptions={}]
  7084. * @param {Object} [groupList]
  7085. * @static
  7086. */
  7087. }, {
  7088. key: 'parseOptions',
  7089. value: function parseOptions(parentOptions, newOptions) {
  7090. var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  7091. var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
  7092. var groupList = arguments[4];
  7093. var fields = ['color', 'fixed', 'shadow'];
  7094. util.selectiveNotDeepExtend(fields, parentOptions, newOptions, allowDeletion);
  7095. Node.checkMass(newOptions);
  7096. // merge the shadow options into the parent.
  7097. util.mergeOptions(parentOptions, newOptions, 'shadow', globalOptions);
  7098. // individual shape newOptions
  7099. if (newOptions.color !== undefined && newOptions.color !== null) {
  7100. var parsedColor = util.parseColor(newOptions.color);
  7101. util.fillIfDefined(parentOptions.color, parsedColor);
  7102. } else if (allowDeletion === true && newOptions.color === null) {
  7103. parentOptions.color = util.bridgeObject(globalOptions.color); // set the object back to the global options
  7104. }
  7105. // handle the fixed options
  7106. if (newOptions.fixed !== undefined && newOptions.fixed !== null) {
  7107. if (typeof newOptions.fixed === 'boolean') {
  7108. parentOptions.fixed.x = newOptions.fixed;
  7109. parentOptions.fixed.y = newOptions.fixed;
  7110. } else {
  7111. if (newOptions.fixed.x !== undefined && typeof newOptions.fixed.x === 'boolean') {
  7112. parentOptions.fixed.x = newOptions.fixed.x;
  7113. }
  7114. if (newOptions.fixed.y !== undefined && typeof newOptions.fixed.y === 'boolean') {
  7115. parentOptions.fixed.y = newOptions.fixed.y;
  7116. }
  7117. }
  7118. }
  7119. if (allowDeletion === true && newOptions.font === null) {
  7120. parentOptions.font = util.bridgeObject(globalOptions.font); // set the object back to the global options
  7121. }
  7122. Node.updateGroupOptions(parentOptions, newOptions, groupList);
  7123. // handle the scaling options, specifically the label part
  7124. if (newOptions.scaling !== undefined) {
  7125. util.mergeOptions(parentOptions.scaling, newOptions.scaling, 'label', globalOptions.scaling);
  7126. }
  7127. }
  7128. }, {
  7129. key: 'checkMass',
  7130. value: function checkMass(options, id) {
  7131. if (options.mass !== undefined && options.mass <= 0) {
  7132. var strId = '';
  7133. if (id !== undefined) {
  7134. strId = ' in node id: ' + id;
  7135. }
  7136. console.log('%cNegative or zero mass disallowed' + strId + ', setting mass to 1.', printStyle);
  7137. options.mass = 1;
  7138. }
  7139. }
  7140. }]);
  7141. return Node;
  7142. }();
  7143. exports['default'] = Node;
  7144. /***/
  7145. }),
  7146. /* 48 */
  7147. /***/
  7148. (function(module, exports, __webpack_require__) {
  7149. "use strict";
  7150. Object.defineProperty(exports, "__esModule", {
  7151. value: true
  7152. });
  7153. var _typeof2 = __webpack_require__(6);
  7154. var _typeof3 = _interopRequireDefault(_typeof2);
  7155. var _classCallCheck2 = __webpack_require__(0);
  7156. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  7157. var _createClass2 = __webpack_require__(1);
  7158. var _createClass3 = _interopRequireDefault(_createClass2);
  7159. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  7160. /**
  7161. * Definitions for param's in jsdoc.
  7162. * These are more or less global within Network. Putting them here until I can figure out
  7163. * where to really put them
  7164. *
  7165. * @typedef {string|number} Id
  7166. * @typedef {Id} NodeId
  7167. * @typedef {Id} EdgeId
  7168. * @typedef {Id} LabelId
  7169. *
  7170. * @typedef {{x: number, y: number}} point
  7171. * @typedef {{left: number, top: number, width: number, height: number}} rect
  7172. * @typedef {{x: number, y:number, angle: number}} rotationPoint
  7173. * - point to rotate around and the angle in radians to rotate. angle == 0 means no rotation
  7174. * @typedef {{nodeId:NodeId}} nodeClickItem
  7175. * @typedef {{nodeId:NodeId, labelId:LabelId}} nodeLabelClickItem
  7176. * @typedef {{edgeId:EdgeId}} edgeClickItem
  7177. * @typedef {{edgeId:EdgeId, labelId:LabelId}} edgeLabelClickItem
  7178. */
  7179. var util = __webpack_require__(2);
  7180. /**
  7181. * Helper functions for components
  7182. * @class
  7183. */
  7184. var ComponentUtil = function() {
  7185. function ComponentUtil() {
  7186. (0, _classCallCheck3['default'])(this, ComponentUtil);
  7187. }
  7188. (0, _createClass3['default'])(ComponentUtil, null, [{
  7189. key: 'choosify',
  7190. /**
  7191. * Determine values to use for (sub)options of 'chosen'.
  7192. *
  7193. * This option is either a boolean or an object whose values should be examined further.
  7194. * The relevant structures are:
  7195. *
  7196. * - chosen: <boolean value>
  7197. * - chosen: { subOption: <boolean or function> }
  7198. *
  7199. * Where subOption is 'node', 'edge' or 'label'.
  7200. *
  7201. * The intention of this method appears to be to set a specific priority to the options;
  7202. * Since most properties are either bridged or merged into the local options objects, there
  7203. * is not much point in handling them separately.
  7204. * TODO: examine if 'most' in previous sentence can be replaced with 'all'. In that case, we
  7205. * should be able to get rid of this method.
  7206. *
  7207. * @param {string} subOption option within object 'chosen' to consider; either 'node', 'edge' or 'label'
  7208. * @param {Object} pile array of options objects to consider
  7209. *
  7210. * @return {boolean|function} value for passed subOption of 'chosen' to use
  7211. */
  7212. value: function choosify(subOption, pile) {
  7213. // allowed values for subOption
  7214. var allowed = ['node', 'edge', 'label'];
  7215. var value = true;
  7216. var chosen = util.topMost(pile, 'chosen');
  7217. if (typeof chosen === 'boolean') {
  7218. value = chosen;
  7219. } else if ((typeof chosen === 'undefined' ? 'undefined' : (0, _typeof3['default'])(chosen)) === 'object') {
  7220. if (allowed.indexOf(subOption) === -1) {
  7221. throw new Error('choosify: subOption \'' + subOption + '\' should be one of ' + "'" + allowed.join("', '") + "'");
  7222. }
  7223. var chosenEdge = util.topMost(pile, ['chosen', subOption]);
  7224. if (typeof chosenEdge === 'boolean' || typeof chosenEdge === 'function') {
  7225. value = chosenEdge;
  7226. }
  7227. }
  7228. return value;
  7229. }
  7230. /**
  7231. * Check if the point falls within the given rectangle.
  7232. *
  7233. * @param {rect} rect
  7234. * @param {point} point
  7235. * @param {rotationPoint} [rotationPoint] if specified, the rotation that applies to the rectangle.
  7236. * @returns {boolean} true if point within rectangle, false otherwise
  7237. * @static
  7238. */
  7239. }, {
  7240. key: 'pointInRect',
  7241. value: function pointInRect(rect, point, rotationPoint) {
  7242. if (rect.width <= 0 || rect.height <= 0) {
  7243. return false; // early out
  7244. }
  7245. if (rotationPoint !== undefined) {
  7246. // Rotate the point the same amount as the rectangle
  7247. var tmp = {
  7248. x: point.x - rotationPoint.x,
  7249. y: point.y - rotationPoint.y
  7250. };
  7251. if (rotationPoint.angle !== 0) {
  7252. // In order to get the coordinates the same, you need to
  7253. // rotate in the reverse direction
  7254. var angle = -rotationPoint.angle;
  7255. var tmp2 = {
  7256. x: Math.cos(angle) * tmp.x - Math.sin(angle) * tmp.y,
  7257. y: Math.sin(angle) * tmp.x + Math.cos(angle) * tmp.y
  7258. };
  7259. point = tmp2;
  7260. } else {
  7261. point = tmp;
  7262. }
  7263. // Note that if a rotation is specified, the rectangle coordinates
  7264. // are **not* the full canvas coordinates. They are relative to the
  7265. // rotationPoint. Hence, the point coordinates need not be translated
  7266. // back in this case.
  7267. }
  7268. var right = rect.x + rect.width;
  7269. var bottom = rect.y + rect.width;
  7270. return rect.left < point.x && right > point.x && rect.top < point.y && bottom > point.y;
  7271. }
  7272. /**
  7273. * Check if given value is acceptable as a label text.
  7274. *
  7275. * @param {*} text value to check; can be anything at this point
  7276. * @returns {boolean} true if valid label value, false otherwise
  7277. */
  7278. }, {
  7279. key: 'isValidLabel',
  7280. value: function isValidLabel(text) {
  7281. // Note that this is quite strict: types that *might* be converted to string are disallowed
  7282. return typeof text === 'string' && text !== '';
  7283. }
  7284. }]);
  7285. return ComponentUtil;
  7286. }();
  7287. exports['default'] = ComponentUtil;
  7288. /***/
  7289. }),
  7290. /* 49 */
  7291. /***/
  7292. (function(module, exports, __webpack_require__) {
  7293. __webpack_require__(125);
  7294. var global = __webpack_require__(18);
  7295. var hide = __webpack_require__(26);
  7296. var Iterators = __webpack_require__(31);
  7297. var TO_STRING_TAG = __webpack_require__(13)('toStringTag');
  7298. var DOMIterables = ('CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,' +
  7299. 'DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,' +
  7300. 'MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,' +
  7301. 'SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,' +
  7302. 'TextTrackList,TouchList').split(',');
  7303. for (var i = 0; i < DOMIterables.length; i++) {
  7304. var NAME = DOMIterables[i];
  7305. var Collection = global[NAME];
  7306. var proto = Collection && Collection.prototype;
  7307. if (proto && !proto[TO_STRING_TAG]) hide(proto, TO_STRING_TAG, NAME);
  7308. Iterators[NAME] = Iterators.Array;
  7309. }
  7310. /***/
  7311. }),
  7312. /* 50 */
  7313. /***/
  7314. (function(module, exports) {
  7315. var toString = {}.toString;
  7316. module.exports = function(it) {
  7317. return toString.call(it).slice(8, -1);
  7318. };
  7319. /***/
  7320. }),
  7321. /* 51 */
  7322. /***/
  7323. (function(module, exports) {
  7324. // 7.2.1 RequireObjectCoercible(argument)
  7325. module.exports = function(it) {
  7326. if (it == undefined) throw TypeError("Can't call method on " + it);
  7327. return it;
  7328. };
  7329. /***/
  7330. }),
  7331. /* 52 */
  7332. /***/
  7333. (function(module, exports) {
  7334. module.exports = true;
  7335. /***/
  7336. }),
  7337. /* 53 */
  7338. /***/
  7339. (function(module, exports, __webpack_require__) {
  7340. // 7.1.1 ToPrimitive(input [, PreferredType])
  7341. var isObject = __webpack_require__(32);
  7342. // instead of the ES6 spec version, we didn't implement @@toPrimitive case
  7343. // and the second argument - flag - preferred type is a string
  7344. module.exports = function(it, S) {
  7345. if (!isObject(it)) return it;
  7346. var fn, val;
  7347. if (S && typeof(fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;
  7348. if (typeof(fn = it.valueOf) == 'function' && !isObject(val = fn.call(it))) return val;
  7349. if (!S && typeof(fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;
  7350. throw TypeError("Can't convert object to primitive value");
  7351. };
  7352. /***/
  7353. }),
  7354. /* 54 */
  7355. /***/
  7356. (function(module, exports, __webpack_require__) {
  7357. // 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])
  7358. var anObject = __webpack_require__(27);
  7359. var dPs = __webpack_require__(130);
  7360. var enumBugKeys = __webpack_require__(58);
  7361. var IE_PROTO = __webpack_require__(56)('IE_PROTO');
  7362. var Empty = function() { /* empty */ };
  7363. var PROTOTYPE = 'prototype';
  7364. // Create object with fake `null` prototype: use iframe Object with cleared prototype
  7365. var createDict = function() {
  7366. // Thrash, waste and sodomy: IE GC bug
  7367. var iframe = __webpack_require__(82)('iframe');
  7368. var i = enumBugKeys.length;
  7369. var lt = '<';
  7370. var gt = '>';
  7371. var iframeDocument;
  7372. iframe.style.display = 'none';
  7373. __webpack_require__(134).appendChild(iframe);
  7374. iframe.src = 'javascript:'; // eslint-disable-line no-script-url
  7375. // createDict = iframe.contentWindow.Object;
  7376. // html.removeChild(iframe);
  7377. iframeDocument = iframe.contentWindow.document;
  7378. iframeDocument.open();
  7379. iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt);
  7380. iframeDocument.close();
  7381. createDict = iframeDocument.F;
  7382. while (i--) delete createDict[PROTOTYPE][enumBugKeys[i]];
  7383. return createDict();
  7384. };
  7385. module.exports = Object.create || function create(O, Properties) {
  7386. var result;
  7387. if (O !== null) {
  7388. Empty[PROTOTYPE] = anObject(O);
  7389. result = new Empty();
  7390. Empty[PROTOTYPE] = null;
  7391. // add "__proto__" for Object.getPrototypeOf polyfill
  7392. result[IE_PROTO] = O;
  7393. } else result = createDict();
  7394. return Properties === undefined ? result : dPs(result, Properties);
  7395. };
  7396. /***/
  7397. }),
  7398. /* 55 */
  7399. /***/
  7400. (function(module, exports) {
  7401. // 7.1.4 ToInteger
  7402. var ceil = Math.ceil;
  7403. var floor = Math.floor;
  7404. module.exports = function(it) {
  7405. return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);
  7406. };
  7407. /***/
  7408. }),
  7409. /* 56 */
  7410. /***/
  7411. (function(module, exports, __webpack_require__) {
  7412. var shared = __webpack_require__(57)('keys');
  7413. var uid = __webpack_require__(40);
  7414. module.exports = function(key) {
  7415. return shared[key] || (shared[key] = uid(key));
  7416. };
  7417. /***/
  7418. }),
  7419. /* 57 */
  7420. /***/
  7421. (function(module, exports, __webpack_require__) {
  7422. var global = __webpack_require__(18);
  7423. var SHARED = '__core-js_shared__';
  7424. var store = global[SHARED] || (global[SHARED] = {});
  7425. module.exports = function(key) {
  7426. return store[key] || (store[key] = {});
  7427. };
  7428. /***/
  7429. }),
  7430. /* 58 */
  7431. /***/
  7432. (function(module, exports) {
  7433. // IE 8- don't enum bug keys
  7434. module.exports = (
  7435. 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'
  7436. ).split(',');
  7437. /***/
  7438. }),
  7439. /* 59 */
  7440. /***/
  7441. (function(module, exports, __webpack_require__) {
  7442. var def = __webpack_require__(20).f;
  7443. var has = __webpack_require__(22);
  7444. var TAG = __webpack_require__(13)('toStringTag');
  7445. module.exports = function(it, tag, stat) {
  7446. if (it && !has(it = stat ? it : it.prototype, TAG)) def(it, TAG, { configurable: true, value: tag });
  7447. };
  7448. /***/
  7449. }),
  7450. /* 60 */
  7451. /***/
  7452. (function(module, exports, __webpack_require__) {
  7453. "use strict";
  7454. var $at = __webpack_require__(135)(true);
  7455. // 21.1.3.27 String.prototype[@@iterator]()
  7456. __webpack_require__(79)(String, 'String', function(iterated) {
  7457. this._t = String(iterated); // target
  7458. this._i = 0; // next index
  7459. // 21.1.5.2.1 %StringIteratorPrototype%.next()
  7460. }, function() {
  7461. var O = this._t;
  7462. var index = this._i;
  7463. var point;
  7464. if (index >= O.length) return { value: undefined, done: true };
  7465. point = $at(O, index);
  7466. this._i += point.length;
  7467. return { value: point, done: false };
  7468. });
  7469. /***/
  7470. }),
  7471. /* 61 */
  7472. /***/
  7473. (function(module, exports, __webpack_require__) {
  7474. exports.f = __webpack_require__(13);
  7475. /***/
  7476. }),
  7477. /* 62 */
  7478. /***/
  7479. (function(module, exports, __webpack_require__) {
  7480. var global = __webpack_require__(18);
  7481. var core = __webpack_require__(7);
  7482. var LIBRARY = __webpack_require__(52);
  7483. var wksExt = __webpack_require__(61);
  7484. var defineProperty = __webpack_require__(20).f;
  7485. module.exports = function(name) {
  7486. var $Symbol = core.Symbol || (core.Symbol = LIBRARY ? {} : global.Symbol || {});
  7487. if (name.charAt(0) != '_' && !(name in $Symbol)) defineProperty($Symbol, name, { value: wksExt.f(name) });
  7488. };
  7489. /***/
  7490. }),
  7491. /* 63 */
  7492. /***/
  7493. (function(module, exports) {
  7494. exports.f = Object.getOwnPropertySymbols;
  7495. /***/
  7496. }),
  7497. /* 64 */
  7498. /***/
  7499. (function(module, exports, __webpack_require__) {
  7500. "use strict";
  7501. var _keys = __webpack_require__(8);
  7502. var _keys2 = _interopRequireDefault(_keys);
  7503. var _stringify = __webpack_require__(19);
  7504. var _stringify2 = _interopRequireDefault(_stringify);
  7505. var _typeof2 = __webpack_require__(6);
  7506. var _typeof3 = _interopRequireDefault(_typeof2);
  7507. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  7508. var util = __webpack_require__(2);
  7509. var moment = __webpack_require__(9);
  7510. var Component = __webpack_require__(16);
  7511. var DateUtil = __webpack_require__(36);
  7512. /**
  7513. * A Range controls a numeric range with a start and end value.
  7514. * The Range adjusts the range based on mouse events or programmatic changes,
  7515. * and triggers events when the range is changing or has been changed.
  7516. * @param {{dom: Object, domProps: Object, emitter: Emitter}} body
  7517. * @param {Object} [options] See description at Range.setOptions
  7518. * @constructor Range
  7519. * @extends Component
  7520. */
  7521. function Range(body, options) {
  7522. var now = moment().hours(0).minutes(0).seconds(0).milliseconds(0);
  7523. var start = now.clone().add(-3, 'days').valueOf();
  7524. var end = now.clone().add(3, 'days').valueOf();
  7525. this.millisecondsPerPixelCache = undefined;
  7526. if (options === undefined) {
  7527. this.start = start;
  7528. this.end = end;
  7529. } else {
  7530. this.start = options.start || start;
  7531. this.end = options.end || end;
  7532. }
  7533. this.rolling = false;
  7534. this.body = body;
  7535. this.deltaDifference = 0;
  7536. this.scaleOffset = 0;
  7537. this.startToFront = false;
  7538. this.endToFront = true;
  7539. // default options
  7540. this.defaultOptions = {
  7541. rtl: false,
  7542. start: null,
  7543. end: null,
  7544. moment: moment,
  7545. direction: 'horizontal', // 'horizontal' or 'vertical'
  7546. moveable: true,
  7547. zoomable: true,
  7548. min: null,
  7549. max: null,
  7550. zoomMin: 10, // milliseconds
  7551. zoomMax: 1000 * 60 * 60 * 24 * 365 * 10000, // milliseconds
  7552. rollingMode: {
  7553. follow: false,
  7554. offset: 0.5
  7555. }
  7556. };
  7557. this.options = util.extend({}, this.defaultOptions);
  7558. this.props = {
  7559. touch: {}
  7560. };
  7561. this.animationTimer = null;
  7562. // drag listeners for dragging
  7563. this.body.emitter.on('panstart', this._onDragStart.bind(this));
  7564. this.body.emitter.on('panmove', this._onDrag.bind(this));
  7565. this.body.emitter.on('panend', this._onDragEnd.bind(this));
  7566. // mouse wheel for zooming
  7567. this.body.emitter.on('mousewheel', this._onMouseWheel.bind(this));
  7568. // pinch to zoom
  7569. this.body.emitter.on('touch', this._onTouch.bind(this));
  7570. this.body.emitter.on('pinch', this._onPinch.bind(this));
  7571. // on click of rolling mode button
  7572. this.body.dom.rollingModeBtn.addEventListener('click', this.startRolling.bind(this));
  7573. this.setOptions(options);
  7574. }
  7575. Range.prototype = new Component();
  7576. /**
  7577. * Set options for the range controller
  7578. * @param {Object} options Available options:
  7579. * {number | Date | String} start Start date for the range
  7580. * {number | Date | String} end End date for the range
  7581. * {number} min Minimum value for start
  7582. * {number} max Maximum value for end
  7583. * {number} zoomMin Set a minimum value for
  7584. * (end - start).
  7585. * {number} zoomMax Set a maximum value for
  7586. * (end - start).
  7587. * {boolean} moveable Enable moving of the range
  7588. * by dragging. True by default
  7589. * {boolean} zoomable Enable zooming of the range
  7590. * by pinching/scrolling. True by default
  7591. */
  7592. Range.prototype.setOptions = function(options) {
  7593. if (options) {
  7594. // copy the options that we know
  7595. var fields = ['animation', 'direction', 'min', 'max', 'zoomMin', 'zoomMax', 'moveable', 'zoomable', 'moment', 'activate', 'hiddenDates', 'zoomKey', 'rtl', 'showCurrentTime', 'rollingMode', 'horizontalScroll'];
  7596. util.selectiveExtend(fields, this.options, options);
  7597. if (options.rollingMode && options.rollingMode.follow) {
  7598. this.startRolling();
  7599. }
  7600. if ('start' in options || 'end' in options) {
  7601. // apply a new range. both start and end are optional
  7602. this.setRange(options.start, options.end);
  7603. }
  7604. }
  7605. };
  7606. /**
  7607. * Test whether direction has a valid value
  7608. * @param {string} direction 'horizontal' or 'vertical'
  7609. */
  7610. function validateDirection(direction) {
  7611. if (direction != 'horizontal' && direction != 'vertical') {
  7612. throw new TypeError('Unknown direction "' + direction + '". ' + 'Choose "horizontal" or "vertical".');
  7613. }
  7614. }
  7615. /**
  7616. * Start auto refreshing the current time bar
  7617. */
  7618. Range.prototype.startRolling = function() {
  7619. var me = this;
  7620. /**
  7621. * Updates the current time.
  7622. */
  7623. function update() {
  7624. me.stopRolling();
  7625. me.rolling = true;
  7626. var interval = me.end - me.start;
  7627. var t = util.convert(new Date(), 'Date').valueOf();
  7628. var start = t - interval * me.options.rollingMode.offset;
  7629. var end = t + interval * (1 - me.options.rollingMode.offset);
  7630. var options = {
  7631. animation: false
  7632. };
  7633. me.setRange(start, end, options);
  7634. // determine interval to refresh
  7635. var scale = me.conversion(me.body.domProps.center.width).scale;
  7636. interval = 1 / scale / 10;
  7637. if (interval < 30) interval = 30;
  7638. if (interval > 1000) interval = 1000;
  7639. me.body.dom.rollingModeBtn.style.visibility = "hidden";
  7640. // start a renderTimer to adjust for the new time
  7641. me.currentTimeTimer = setTimeout(update, interval);
  7642. }
  7643. update();
  7644. };
  7645. /**
  7646. * Stop auto refreshing the current time bar
  7647. */
  7648. Range.prototype.stopRolling = function() {
  7649. if (this.currentTimeTimer !== undefined) {
  7650. clearTimeout(this.currentTimeTimer);
  7651. this.rolling = false;
  7652. this.body.dom.rollingModeBtn.style.visibility = "visible";
  7653. }
  7654. };
  7655. /**
  7656. * Set a new start and end range
  7657. * @param {Date | number | string} [start]
  7658. * @param {Date | number | string} [end]
  7659. * @param {Object} options Available options:
  7660. * {boolean | {duration: number, easingFunction: string}} [animation=false]
  7661. * If true, the range is animated
  7662. * smoothly to the new window. An object can be
  7663. * provided to specify duration and easing function.
  7664. * Default duration is 500 ms, and default easing
  7665. * function is 'easeInOutQuad'.
  7666. * {boolean} [byUser=false]
  7667. * {Event} event Mouse event
  7668. * @param {Function} callback a callback function to be executed at the end of this function
  7669. * @param {Function} frameCallback a callback function executed each frame of the range animation.
  7670. * The callback will be passed three parameters:
  7671. * {number} easeCoefficient an easing coefficent
  7672. * {boolean} willDraw If true the caller will redraw after the callback completes
  7673. * {boolean} done If true then animation is ending after the current frame
  7674. */
  7675. Range.prototype.setRange = function(start, end, options, callback, frameCallback) {
  7676. if (!options) {
  7677. options = {};
  7678. }
  7679. if (options.byUser !== true) {
  7680. options.byUser = false;
  7681. }
  7682. var me = this;
  7683. var finalStart = start != undefined ? util.convert(start, 'Date').valueOf() : null;
  7684. var finalEnd = end != undefined ? util.convert(end, 'Date').valueOf() : null;
  7685. this._cancelAnimation();
  7686. this.millisecondsPerPixelCache = undefined;
  7687. if (options.animation) {
  7688. // true or an Object
  7689. var initStart = this.start;
  7690. var initEnd = this.end;
  7691. var duration = (0, _typeof3['default'])(options.animation) === 'object' && 'duration' in options.animation ? options.animation.duration : 500;
  7692. var easingName = (0, _typeof3['default'])(options.animation) === 'object' && 'easingFunction' in options.animation ? options.animation.easingFunction : 'easeInOutQuad';
  7693. var easingFunction = util.easingFunctions[easingName];
  7694. if (!easingFunction) {
  7695. throw new Error('Unknown easing function ' + (0, _stringify2['default'])(easingName) + '. ' + 'Choose from: ' + (0, _keys2['default'])(util.easingFunctions).join(', '));
  7696. }
  7697. var initTime = new Date().valueOf();
  7698. var anyChanged = false;
  7699. var next = function next() {
  7700. if (!me.props.touch.dragging) {
  7701. var now = new Date().valueOf();
  7702. var time = now - initTime;
  7703. var ease = easingFunction(time / duration);
  7704. var done = time > duration;
  7705. var s = done || finalStart === null ? finalStart : initStart + (finalStart - initStart) * ease;
  7706. var e = done || finalEnd === null ? finalEnd : initEnd + (finalEnd - initEnd) * ease;
  7707. changed = me._applyRange(s, e);
  7708. DateUtil.updateHiddenDates(me.options.moment, me.body, me.options.hiddenDates);
  7709. anyChanged = anyChanged || changed;
  7710. var params = {
  7711. start: new Date(me.start),
  7712. end: new Date(me.end),
  7713. byUser: options.byUser,
  7714. event: options.event
  7715. };
  7716. if (frameCallback) {
  7717. frameCallback(ease, changed, done);
  7718. }
  7719. if (changed) {
  7720. me.body.emitter.emit('rangechange', params);
  7721. }
  7722. if (done) {
  7723. if (anyChanged) {
  7724. me.body.emitter.emit('rangechanged', params);
  7725. if (callback) {
  7726. return callback();
  7727. }
  7728. }
  7729. } else {
  7730. // animate with as high as possible frame rate, leave 20 ms in between
  7731. // each to prevent the browser from blocking
  7732. me.animationTimer = setTimeout(next, 20);
  7733. }
  7734. }
  7735. };
  7736. return next();
  7737. } else {
  7738. var changed = this._applyRange(finalStart, finalEnd);
  7739. DateUtil.updateHiddenDates(this.options.moment, this.body, this.options.hiddenDates);
  7740. if (changed) {
  7741. var params = {
  7742. start: new Date(this.start),
  7743. end: new Date(this.end),
  7744. byUser: options.byUser,
  7745. event: options.event
  7746. };
  7747. this.body.emitter.emit('rangechange', params);
  7748. clearTimeout(me.timeoutID);
  7749. me.timeoutID = setTimeout(function() {
  7750. me.body.emitter.emit('rangechanged', params);
  7751. }, 200);
  7752. if (callback) {
  7753. return callback();
  7754. }
  7755. }
  7756. }
  7757. };
  7758. /**
  7759. * Get the number of milliseconds per pixel.
  7760. *
  7761. * @returns {undefined|number}
  7762. */
  7763. Range.prototype.getMillisecondsPerPixel = function() {
  7764. if (this.millisecondsPerPixelCache === undefined) {
  7765. this.millisecondsPerPixelCache = (this.end - this.start) / this.body.dom.center.clientWidth;
  7766. }
  7767. return this.millisecondsPerPixelCache;
  7768. };
  7769. /**
  7770. * Stop an animation
  7771. * @private
  7772. */
  7773. Range.prototype._cancelAnimation = function() {
  7774. if (this.animationTimer) {
  7775. clearTimeout(this.animationTimer);
  7776. this.animationTimer = null;
  7777. }
  7778. };
  7779. /**
  7780. * Set a new start and end range. This method is the same as setRange, but
  7781. * does not trigger a range change and range changed event, and it returns
  7782. * true when the range is changed
  7783. * @param {number} [start]
  7784. * @param {number} [end]
  7785. * @return {boolean} changed
  7786. * @private
  7787. */
  7788. Range.prototype._applyRange = function(start, end) {
  7789. var newStart = start != null ? util.convert(start, 'Date').valueOf() : this.start,
  7790. newEnd = end != null ? util.convert(end, 'Date').valueOf() : this.end,
  7791. max = this.options.max != null ? util.convert(this.options.max, 'Date').valueOf() : null,
  7792. min = this.options.min != null ? util.convert(this.options.min, 'Date').valueOf() : null,
  7793. diff;
  7794. // check for valid number
  7795. if (isNaN(newStart) || newStart === null) {
  7796. throw new Error('Invalid start "' + start + '"');
  7797. }
  7798. if (isNaN(newEnd) || newEnd === null) {
  7799. throw new Error('Invalid end "' + end + '"');
  7800. }
  7801. // prevent end < start
  7802. if (newEnd < newStart) {
  7803. newEnd = newStart;
  7804. }
  7805. // prevent start < min
  7806. if (min !== null) {
  7807. if (newStart < min) {
  7808. diff = min - newStart;
  7809. newStart += diff;
  7810. newEnd += diff;
  7811. // prevent end > max
  7812. if (max != null) {
  7813. if (newEnd > max) {
  7814. newEnd = max;
  7815. }
  7816. }
  7817. }
  7818. }
  7819. // prevent end > max
  7820. if (max !== null) {
  7821. if (newEnd > max) {
  7822. diff = newEnd - max;
  7823. newStart -= diff;
  7824. newEnd -= diff;
  7825. // prevent start < min
  7826. if (min != null) {
  7827. if (newStart < min) {
  7828. newStart = min;
  7829. }
  7830. }
  7831. }
  7832. }
  7833. // prevent (end-start) < zoomMin
  7834. if (this.options.zoomMin !== null) {
  7835. var zoomMin = parseFloat(this.options.zoomMin);
  7836. if (zoomMin < 0) {
  7837. zoomMin = 0;
  7838. }
  7839. if (newEnd - newStart < zoomMin) {
  7840. // compensate for a scale of 0.5 ms
  7841. var compensation = 0.5;
  7842. if (this.end - this.start === zoomMin && newStart >= this.start - compensation && newEnd <= this.end) {
  7843. // ignore this action, we are already zoomed to the minimum
  7844. newStart = this.start;
  7845. newEnd = this.end;
  7846. } else {
  7847. // zoom to the minimum
  7848. diff = zoomMin - (newEnd - newStart);
  7849. newStart -= diff / 2;
  7850. newEnd += diff / 2;
  7851. }
  7852. }
  7853. }
  7854. // prevent (end-start) > zoomMax
  7855. if (this.options.zoomMax !== null) {
  7856. var zoomMax = parseFloat(this.options.zoomMax);
  7857. if (zoomMax < 0) {
  7858. zoomMax = 0;
  7859. }
  7860. if (newEnd - newStart > zoomMax) {
  7861. if (this.end - this.start === zoomMax && newStart < this.start && newEnd > this.end) {
  7862. // ignore this action, we are already zoomed to the maximum
  7863. newStart = this.start;
  7864. newEnd = this.end;
  7865. } else {
  7866. // zoom to the maximum
  7867. diff = newEnd - newStart - zoomMax;
  7868. newStart += diff / 2;
  7869. newEnd -= diff / 2;
  7870. }
  7871. }
  7872. }
  7873. var changed = this.start != newStart || this.end != newEnd;
  7874. // if the new range does NOT overlap with the old range, emit checkRangedItems to avoid not showing ranged items (ranged meaning has end time, not necessarily of type Range)
  7875. if (!(newStart >= this.start && newStart <= this.end || newEnd >= this.start && newEnd <= this.end) && !(this.start >= newStart && this.start <= newEnd || this.end >= newStart && this.end <= newEnd)) {
  7876. this.body.emitter.emit('checkRangedItems');
  7877. }
  7878. this.start = newStart;
  7879. this.end = newEnd;
  7880. return changed;
  7881. };
  7882. /**
  7883. * Retrieve the current range.
  7884. * @return {Object} An object with start and end properties
  7885. */
  7886. Range.prototype.getRange = function() {
  7887. return {
  7888. start: this.start,
  7889. end: this.end
  7890. };
  7891. };
  7892. /**
  7893. * Calculate the conversion offset and scale for current range, based on
  7894. * the provided width
  7895. * @param {number} width
  7896. * @param {number} [totalHidden=0]
  7897. * @returns {{offset: number, scale: number}} conversion
  7898. */
  7899. Range.prototype.conversion = function(width, totalHidden) {
  7900. return Range.conversion(this.start, this.end, width, totalHidden);
  7901. };
  7902. /**
  7903. * Static method to calculate the conversion offset and scale for a range,
  7904. * based on the provided start, end, and width
  7905. * @param {number} start
  7906. * @param {number} end
  7907. * @param {number} width
  7908. * @param {number} [totalHidden=0]
  7909. * @returns {{offset: number, scale: number}} conversion
  7910. */
  7911. Range.conversion = function(start, end, width, totalHidden) {
  7912. if (totalHidden === undefined) {
  7913. totalHidden = 0;
  7914. }
  7915. if (width != 0 && end - start != 0) {
  7916. return {
  7917. offset: start,
  7918. scale: width / (end - start - totalHidden)
  7919. };
  7920. } else {
  7921. return {
  7922. offset: 0,
  7923. scale: 1
  7924. };
  7925. }
  7926. };
  7927. /**
  7928. * Start dragging horizontally or vertically
  7929. * @param {Event} event
  7930. * @private
  7931. */
  7932. Range.prototype._onDragStart = function(event) {
  7933. this.deltaDifference = 0;
  7934. this.previousDelta = 0;
  7935. // only allow dragging when configured as movable
  7936. if (!this.options.moveable) return;
  7937. // only start dragging when the mouse is inside the current range
  7938. if (!this._isInsideRange(event)) return;
  7939. // refuse to drag when we where pinching to prevent the timeline make a jump
  7940. // when releasing the fingers in opposite order from the touch screen
  7941. if (!this.props.touch.allowDragging) return;
  7942. this.stopRolling();
  7943. this.props.touch.start = this.start;
  7944. this.props.touch.end = this.end;
  7945. this.props.touch.dragging = true;
  7946. if (this.body.dom.root) {
  7947. this.body.dom.root.style.cursor = 'move';
  7948. }
  7949. };
  7950. /**
  7951. * Perform dragging operation
  7952. * @param {Event} event
  7953. * @private
  7954. */
  7955. Range.prototype._onDrag = function(event) {
  7956. if (!event) return;
  7957. if (!this.props.touch.dragging) return;
  7958. // only allow dragging when configured as movable
  7959. if (!this.options.moveable) return;
  7960. // TODO: this may be redundant in hammerjs2
  7961. // refuse to drag when we where pinching to prevent the timeline make a jump
  7962. // when releasing the fingers in opposite order from the touch screen
  7963. if (!this.props.touch.allowDragging) return;
  7964. var direction = this.options.direction;
  7965. validateDirection(direction);
  7966. var delta = direction == 'horizontal' ? event.deltaX : event.deltaY;
  7967. delta -= this.deltaDifference;
  7968. var interval = this.props.touch.end - this.props.touch.start;
  7969. // normalize dragging speed if cutout is in between.
  7970. var duration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end);
  7971. interval -= duration;
  7972. var width = direction == 'horizontal' ? this.body.domProps.center.width : this.body.domProps.center.height;
  7973. var diffRange;
  7974. if (this.options.rtl) {
  7975. diffRange = delta / width * interval;
  7976. } else {
  7977. diffRange = -delta / width * interval;
  7978. }
  7979. var newStart = this.props.touch.start + diffRange;
  7980. var newEnd = this.props.touch.end + diffRange;
  7981. // snapping times away from hidden zones
  7982. var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, this.previousDelta - delta, true);
  7983. var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, this.previousDelta - delta, true);
  7984. if (safeStart != newStart || safeEnd != newEnd) {
  7985. this.deltaDifference += delta;
  7986. this.props.touch.start = safeStart;
  7987. this.props.touch.end = safeEnd;
  7988. this._onDrag(event);
  7989. return;
  7990. }
  7991. this.previousDelta = delta;
  7992. this._applyRange(newStart, newEnd);
  7993. var startDate = new Date(this.start);
  7994. var endDate = new Date(this.end);
  7995. // fire a rangechange event
  7996. this.body.emitter.emit('rangechange', {
  7997. start: startDate,
  7998. end: endDate,
  7999. byUser: true,
  8000. event: event
  8001. });
  8002. // fire a panmove event
  8003. this.body.emitter.emit('panmove');
  8004. };
  8005. /**
  8006. * Stop dragging operation
  8007. * @param {event} event
  8008. * @private
  8009. */
  8010. Range.prototype._onDragEnd = function(event) {
  8011. if (!this.props.touch.dragging) return;
  8012. // only allow dragging when configured as movable
  8013. if (!this.options.moveable) return;
  8014. // TODO: this may be redundant in hammerjs2
  8015. // refuse to drag when we where pinching to prevent the timeline make a jump
  8016. // when releasing the fingers in opposite order from the touch screen
  8017. if (!this.props.touch.allowDragging) return;
  8018. this.props.touch.dragging = false;
  8019. if (this.body.dom.root) {
  8020. this.body.dom.root.style.cursor = 'auto';
  8021. }
  8022. // fire a rangechanged event
  8023. this.body.emitter.emit('rangechanged', {
  8024. start: new Date(this.start),
  8025. end: new Date(this.end),
  8026. byUser: true,
  8027. event: event
  8028. });
  8029. };
  8030. /**
  8031. * Event handler for mouse wheel event, used to zoom
  8032. * Code from http://adomas.org/javascript-mouse-wheel/
  8033. * @param {Event} event
  8034. * @private
  8035. */
  8036. Range.prototype._onMouseWheel = function(event) {
  8037. // retrieve delta
  8038. var delta = 0;
  8039. if (event.wheelDelta) {
  8040. /* IE/Opera. */
  8041. delta = event.wheelDelta / 120;
  8042. } else if (event.detail) {
  8043. /* Mozilla case. */
  8044. // In Mozilla, sign of delta is different than in IE.
  8045. // Also, delta is multiple of 3.
  8046. delta = -event.detail / 3;
  8047. }
  8048. // don't allow zoom when the according key is pressed and the zoomKey option or not zoomable but movable
  8049. if (this.options.zoomKey && !event[this.options.zoomKey] && this.options.zoomable || !this.options.zoomable && this.options.moveable) {
  8050. return;
  8051. }
  8052. // only allow zooming when configured as zoomable and moveable
  8053. if (!(this.options.zoomable && this.options.moveable)) return;
  8054. // only zoom when the mouse is inside the current range
  8055. if (!this._isInsideRange(event)) return;
  8056. // If delta is nonzero, handle it.
  8057. // Basically, delta is now positive if wheel was scrolled up,
  8058. // and negative, if wheel was scrolled down.
  8059. if (delta) {
  8060. // perform the zoom action. Delta is normally 1 or -1
  8061. // adjust a negative delta such that zooming in with delta 0.1
  8062. // equals zooming out with a delta -0.1
  8063. var scale;
  8064. if (delta < 0) {
  8065. scale = 1 - delta / 5;
  8066. } else {
  8067. scale = 1 / (1 + delta / 5);
  8068. }
  8069. // calculate center, the date to zoom around
  8070. var pointerDate;
  8071. if (this.rolling) {
  8072. pointerDate = this.start + (this.end - this.start) * this.options.rollingMode.offset;
  8073. } else {
  8074. var pointer = this.getPointer({ x: event.clientX, y: event.clientY }, this.body.dom.center);
  8075. pointerDate = this._pointerToDate(pointer);
  8076. }
  8077. this.zoom(scale, pointerDate, delta, event);
  8078. // Prevent default actions caused by mouse wheel
  8079. // (else the page and timeline both scroll)
  8080. event.preventDefault();
  8081. }
  8082. };
  8083. /**
  8084. * Start of a touch gesture
  8085. * @param {Event} event
  8086. * @private
  8087. */
  8088. Range.prototype._onTouch = function(event) {
  8089. // eslint-disable-line no-unused-vars
  8090. this.props.touch.start = this.start;
  8091. this.props.touch.end = this.end;
  8092. this.props.touch.allowDragging = true;
  8093. this.props.touch.center = null;
  8094. this.scaleOffset = 0;
  8095. this.deltaDifference = 0;
  8096. // Disable the browser default handling of this event.
  8097. util.preventDefault(event);
  8098. };
  8099. /**
  8100. * Handle pinch event
  8101. * @param {Event} event
  8102. * @private
  8103. */
  8104. Range.prototype._onPinch = function(event) {
  8105. // only allow zooming when configured as zoomable and moveable
  8106. if (!(this.options.zoomable && this.options.moveable)) return;
  8107. // Disable the browser default handling of this event.
  8108. util.preventDefault(event);
  8109. this.props.touch.allowDragging = false;
  8110. if (!this.props.touch.center) {
  8111. this.props.touch.center = this.getPointer(event.center, this.body.dom.center);
  8112. }
  8113. this.stopRolling();
  8114. var scale = 1 / (event.scale + this.scaleOffset);
  8115. var centerDate = this._pointerToDate(this.props.touch.center);
  8116. var hiddenDuration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end);
  8117. var hiddenDurationBefore = DateUtil.getHiddenDurationBefore(this.options.moment, this.body.hiddenDates, this, centerDate);
  8118. var hiddenDurationAfter = hiddenDuration - hiddenDurationBefore;
  8119. // calculate new start and end
  8120. var newStart = centerDate - hiddenDurationBefore + (this.props.touch.start - (centerDate - hiddenDurationBefore)) * scale;
  8121. var newEnd = centerDate + hiddenDurationAfter + (this.props.touch.end - (centerDate + hiddenDurationAfter)) * scale;
  8122. // snapping times away from hidden zones
  8123. this.startToFront = 1 - scale <= 0; // used to do the right auto correction with periodic hidden times
  8124. this.endToFront = scale - 1 <= 0; // used to do the right auto correction with periodic hidden times
  8125. var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, 1 - scale, true);
  8126. var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, scale - 1, true);
  8127. if (safeStart != newStart || safeEnd != newEnd) {
  8128. this.props.touch.start = safeStart;
  8129. this.props.touch.end = safeEnd;
  8130. this.scaleOffset = 1 - event.scale;
  8131. newStart = safeStart;
  8132. newEnd = safeEnd;
  8133. }
  8134. var options = {
  8135. animation: false,
  8136. byUser: true,
  8137. event: event
  8138. };
  8139. this.setRange(newStart, newEnd, options);
  8140. this.startToFront = false; // revert to default
  8141. this.endToFront = true; // revert to default
  8142. };
  8143. /**
  8144. * Test whether the mouse from a mouse event is inside the visible window,
  8145. * between the current start and end date
  8146. * @param {Object} event
  8147. * @return {boolean} Returns true when inside the visible window
  8148. * @private
  8149. */
  8150. Range.prototype._isInsideRange = function(event) {
  8151. // calculate the time where the mouse is, check whether inside
  8152. // and no scroll action should happen.
  8153. var clientX = event.center ? event.center.x : event.clientX;
  8154. var x;
  8155. if (this.options.rtl) {
  8156. x = clientX - util.getAbsoluteLeft(this.body.dom.centerContainer);
  8157. } else {
  8158. x = util.getAbsoluteRight(this.body.dom.centerContainer) - clientX;
  8159. }
  8160. var time = this.body.util.toTime(x);
  8161. return time >= this.start && time <= this.end;
  8162. };
  8163. /**
  8164. * Helper function to calculate the center date for zooming
  8165. * @param {{x: number, y: number}} pointer
  8166. * @return {number} date
  8167. * @private
  8168. */
  8169. Range.prototype._pointerToDate = function(pointer) {
  8170. var conversion;
  8171. var direction = this.options.direction;
  8172. validateDirection(direction);
  8173. if (direction == 'horizontal') {
  8174. return this.body.util.toTime(pointer.x).valueOf();
  8175. } else {
  8176. var height = this.body.domProps.center.height;
  8177. conversion = this.conversion(height);
  8178. return pointer.y / conversion.scale + conversion.offset;
  8179. }
  8180. };
  8181. /**
  8182. * Get the pointer location relative to the location of the dom element
  8183. * @param {{x: number, y: number}} touch
  8184. * @param {Element} element HTML DOM element
  8185. * @return {{x: number, y: number}} pointer
  8186. * @private
  8187. */
  8188. Range.prototype.getPointer = function(touch, element) {
  8189. if (this.options.rtl) {
  8190. return {
  8191. x: util.getAbsoluteRight(element) - touch.x,
  8192. y: touch.y - util.getAbsoluteTop(element)
  8193. };
  8194. } else {
  8195. return {
  8196. x: touch.x - util.getAbsoluteLeft(element),
  8197. y: touch.y - util.getAbsoluteTop(element)
  8198. };
  8199. }
  8200. };
  8201. /**
  8202. * Zoom the range the given scale in or out. Start and end date will
  8203. * be adjusted, and the timeline will be redrawn. You can optionally give a
  8204. * date around which to zoom.
  8205. * For example, try scale = 0.9 or 1.1
  8206. * @param {number} scale Scaling factor. Values above 1 will zoom out,
  8207. * values below 1 will zoom in.
  8208. * @param {number} [center] Value representing a date around which will
  8209. * be zoomed.
  8210. * @param {number} delta
  8211. * @param {Event} event
  8212. */
  8213. Range.prototype.zoom = function(scale, center, delta, event) {
  8214. // if centerDate is not provided, take it half between start Date and end Date
  8215. if (center == null) {
  8216. center = (this.start + this.end) / 2;
  8217. }
  8218. var hiddenDuration = DateUtil.getHiddenDurationBetween(this.body.hiddenDates, this.start, this.end);
  8219. var hiddenDurationBefore = DateUtil.getHiddenDurationBefore(this.options.moment, this.body.hiddenDates, this, center);
  8220. var hiddenDurationAfter = hiddenDuration - hiddenDurationBefore;
  8221. // calculate new start and end
  8222. var newStart = center - hiddenDurationBefore + (this.start - (center - hiddenDurationBefore)) * scale;
  8223. var newEnd = center + hiddenDurationAfter + (this.end - (center + hiddenDurationAfter)) * scale;
  8224. // snapping times away from hidden zones
  8225. this.startToFront = delta > 0 ? false : true; // used to do the right autocorrection with periodic hidden times
  8226. this.endToFront = -delta > 0 ? false : true; // used to do the right autocorrection with periodic hidden times
  8227. var safeStart = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newStart, delta, true);
  8228. var safeEnd = DateUtil.snapAwayFromHidden(this.body.hiddenDates, newEnd, -delta, true);
  8229. if (safeStart != newStart || safeEnd != newEnd) {
  8230. newStart = safeStart;
  8231. newEnd = safeEnd;
  8232. }
  8233. var options = {
  8234. animation: false,
  8235. byUser: true,
  8236. event: event
  8237. };
  8238. this.setRange(newStart, newEnd, options);
  8239. this.startToFront = false; // revert to default
  8240. this.endToFront = true; // revert to default
  8241. };
  8242. /**
  8243. * Move the range with a given delta to the left or right. Start and end
  8244. * value will be adjusted. For example, try delta = 0.1 or -0.1
  8245. * @param {number} delta Moving amount. Positive value will move right,
  8246. * negative value will move left
  8247. */
  8248. Range.prototype.move = function(delta) {
  8249. // zoom start Date and end Date relative to the centerDate
  8250. var diff = this.end - this.start;
  8251. // apply new values
  8252. var newStart = this.start + diff * delta;
  8253. var newEnd = this.end + diff * delta;
  8254. // TODO: reckon with min and max range
  8255. this.start = newStart;
  8256. this.end = newEnd;
  8257. };
  8258. /**
  8259. * Move the range to a new center point
  8260. * @param {number} moveTo New center point of the range
  8261. */
  8262. Range.prototype.moveTo = function(moveTo) {
  8263. var center = (this.start + this.end) / 2;
  8264. var diff = center - moveTo;
  8265. // calculate new start and end
  8266. var newStart = this.start - diff;
  8267. var newEnd = this.end - diff;
  8268. var options = {
  8269. animation: false,
  8270. byUser: true,
  8271. event: null
  8272. };
  8273. this.setRange(newStart, newEnd, options);
  8274. };
  8275. module.exports = Range;
  8276. /***/
  8277. }),
  8278. /* 65 */
  8279. /***/
  8280. (function(module, exports, __webpack_require__) {
  8281. "use strict";
  8282. var _stringify = __webpack_require__(19);
  8283. var _stringify2 = _interopRequireDefault(_stringify);
  8284. var _typeof2 = __webpack_require__(6);
  8285. var _typeof3 = _interopRequireDefault(_typeof2);
  8286. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  8287. var Emitter = __webpack_require__(44);
  8288. var Hammer = __webpack_require__(10);
  8289. var hammerUtil = __webpack_require__(37);
  8290. var util = __webpack_require__(2);
  8291. var TimeAxis = __webpack_require__(45);
  8292. var Activator = __webpack_require__(97);
  8293. var DateUtil = __webpack_require__(36);
  8294. var CustomTime = __webpack_require__(46);
  8295. /**
  8296. * Create a timeline visualization
  8297. * @constructor Core
  8298. */
  8299. function Core() {}
  8300. // turn Core into an event emitter
  8301. Emitter(Core.prototype);
  8302. /**
  8303. * Create the main DOM for the Core: a root panel containing left, right,
  8304. * top, bottom, content, and background panel.
  8305. * @param {Element} container The container element where the Core will
  8306. * be attached.
  8307. * @protected
  8308. */
  8309. Core.prototype._create = function(container) {
  8310. this.dom = {};
  8311. this.dom.container = container;
  8312. this.dom.root = document.createElement('div');
  8313. this.dom.background = document.createElement('div');
  8314. this.dom.backgroundVertical = document.createElement('div');
  8315. this.dom.backgroundHorizontal = document.createElement('div');
  8316. this.dom.centerContainer = document.createElement('div');
  8317. this.dom.leftContainer = document.createElement('div');
  8318. this.dom.rightContainer = document.createElement('div');
  8319. this.dom.center = document.createElement('div');
  8320. this.dom.left = document.createElement('div');
  8321. this.dom.right = document.createElement('div');
  8322. this.dom.top = document.createElement('div');
  8323. this.dom.bottom = document.createElement('div');
  8324. this.dom.shadowTop = document.createElement('div');
  8325. this.dom.shadowBottom = document.createElement('div');
  8326. this.dom.shadowTopLeft = document.createElement('div');
  8327. this.dom.shadowBottomLeft = document.createElement('div');
  8328. this.dom.shadowTopRight = document.createElement('div');
  8329. this.dom.shadowBottomRight = document.createElement('div');
  8330. this.dom.rollingModeBtn = document.createElement('div');
  8331. this.dom.root.className = 'vis-timeline';
  8332. this.dom.background.className = 'vis-panel vis-background';
  8333. this.dom.backgroundVertical.className = 'vis-panel vis-background vis-vertical';
  8334. this.dom.backgroundHorizontal.className = 'vis-panel vis-background vis-horizontal';
  8335. this.dom.centerContainer.className = 'vis-panel vis-center';
  8336. this.dom.leftContainer.className = 'vis-panel vis-left';
  8337. this.dom.rightContainer.className = 'vis-panel vis-right';
  8338. this.dom.top.className = 'vis-panel vis-top';
  8339. this.dom.bottom.className = 'vis-panel vis-bottom';
  8340. this.dom.left.className = 'vis-content';
  8341. this.dom.center.className = 'vis-content';
  8342. this.dom.right.className = 'vis-content';
  8343. this.dom.shadowTop.className = 'vis-shadow vis-top';
  8344. this.dom.shadowBottom.className = 'vis-shadow vis-bottom';
  8345. this.dom.shadowTopLeft.className = 'vis-shadow vis-top';
  8346. this.dom.shadowBottomLeft.className = 'vis-shadow vis-bottom';
  8347. this.dom.shadowTopRight.className = 'vis-shadow vis-top';
  8348. this.dom.shadowBottomRight.className = 'vis-shadow vis-bottom';
  8349. this.dom.rollingModeBtn.className = 'vis-rolling-mode-btn';
  8350. this.dom.root.appendChild(this.dom.background);
  8351. this.dom.root.appendChild(this.dom.backgroundVertical);
  8352. this.dom.root.appendChild(this.dom.backgroundHorizontal);
  8353. this.dom.root.appendChild(this.dom.centerContainer);
  8354. this.dom.root.appendChild(this.dom.leftContainer);
  8355. this.dom.root.appendChild(this.dom.rightContainer);
  8356. this.dom.root.appendChild(this.dom.top);
  8357. this.dom.root.appendChild(this.dom.bottom);
  8358. this.dom.root.appendChild(this.dom.bottom);
  8359. this.dom.root.appendChild(this.dom.rollingModeBtn);
  8360. this.dom.centerContainer.appendChild(this.dom.center);
  8361. this.dom.leftContainer.appendChild(this.dom.left);
  8362. this.dom.rightContainer.appendChild(this.dom.right);
  8363. this.dom.centerContainer.appendChild(this.dom.shadowTop);
  8364. this.dom.centerContainer.appendChild(this.dom.shadowBottom);
  8365. this.dom.leftContainer.appendChild(this.dom.shadowTopLeft);
  8366. this.dom.leftContainer.appendChild(this.dom.shadowBottomLeft);
  8367. this.dom.rightContainer.appendChild(this.dom.shadowTopRight);
  8368. this.dom.rightContainer.appendChild(this.dom.shadowBottomRight);
  8369. // size properties of each of the panels
  8370. this.props = {
  8371. root: {},
  8372. background: {},
  8373. centerContainer: {},
  8374. leftContainer: {},
  8375. rightContainer: {},
  8376. center: {},
  8377. left: {},
  8378. right: {},
  8379. top: {},
  8380. bottom: {},
  8381. border: {},
  8382. scrollTop: 0,
  8383. scrollTopMin: 0
  8384. };
  8385. this.on('rangechange', function() {
  8386. if (this.initialDrawDone === true) {
  8387. this._redraw();
  8388. }
  8389. }.bind(this));
  8390. this.on('rangechanged', function() {
  8391. if (!this.initialRangeChangeDone) {
  8392. this.initialRangeChangeDone = true;
  8393. }
  8394. }.bind(this));
  8395. this.on('touch', this._onTouch.bind(this));
  8396. this.on('panmove', this._onDrag.bind(this));
  8397. var me = this;
  8398. this._origRedraw = this._redraw.bind(this);
  8399. this._redraw = util.throttle(this._origRedraw);
  8400. this.on('_change', function(properties) {
  8401. if (me.itemSet && me.itemSet.initialItemSetDrawn && properties && properties.queue == true) {
  8402. me._redraw();
  8403. } else {
  8404. me._origRedraw();
  8405. }
  8406. });
  8407. // create event listeners for all interesting events, these events will be
  8408. // emitted via emitter
  8409. this.hammer = new Hammer(this.dom.root);
  8410. var pinchRecognizer = this.hammer.get('pinch').set({ enable: true });
  8411. hammerUtil.disablePreventDefaultVertically(pinchRecognizer);
  8412. this.hammer.get('pan').set({ threshold: 5, direction: Hammer.DIRECTION_HORIZONTAL });
  8413. this.listeners = {};
  8414. var events = ['tap', 'doubletap', 'press', 'pinch', 'pan', 'panstart', 'panmove', 'panend'
  8415. // TODO: cleanup
  8416. //'touch', 'pinch',
  8417. //'tap', 'doubletap', 'hold',
  8418. //'dragstart', 'drag', 'dragend',
  8419. //'mousewheel', 'DOMMouseScroll' // DOMMouseScroll is needed for Firefox
  8420. ];
  8421. events.forEach(function(type) {
  8422. var listener = function listener(event) {
  8423. if (me.isActive()) {
  8424. me.emit(type, event);
  8425. }
  8426. };
  8427. me.hammer.on(type, listener);
  8428. me.listeners[type] = listener;
  8429. });
  8430. // emulate a touch event (emitted before the start of a pan, pinch, tap, or press)
  8431. hammerUtil.onTouch(this.hammer, function(event) {
  8432. me.emit('touch', event);
  8433. }.bind(this));
  8434. // emulate a release event (emitted after a pan, pinch, tap, or press)
  8435. hammerUtil.onRelease(this.hammer, function(event) {
  8436. me.emit('release', event);
  8437. }.bind(this));
  8438. /**
  8439. *
  8440. * @param {WheelEvent} event
  8441. */
  8442. function onMouseWheel(event) {
  8443. if (this.isActive()) {
  8444. this.emit('mousewheel', event);
  8445. }
  8446. // deltaX and deltaY normalization from jquery.mousewheel.js
  8447. var deltaX = 0;
  8448. var deltaY = 0;
  8449. // Old school scrollwheel delta
  8450. if ('detail' in event) {
  8451. deltaY = event.detail * -1;
  8452. }
  8453. if ('wheelDelta' in event) {
  8454. deltaY = event.wheelDelta;
  8455. }
  8456. if ('wheelDeltaY' in event) {
  8457. deltaY = event.wheelDeltaY;
  8458. }
  8459. if ('wheelDeltaX' in event) {
  8460. deltaX = event.wheelDeltaX * -1;
  8461. }
  8462. // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
  8463. if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) {
  8464. deltaX = deltaY * -1;
  8465. deltaY = 0;
  8466. }
  8467. // New school wheel delta (wheel event)
  8468. if ('deltaY' in event) {
  8469. deltaY = event.deltaY * -1;
  8470. }
  8471. if ('deltaX' in event) {
  8472. deltaX = event.deltaX;
  8473. }
  8474. // prevent scrolling when zoomKey defined or activated
  8475. if (!this.options.zoomKey || event[this.options.zoomKey]) return;
  8476. // Prevent default actions caused by mouse wheel
  8477. // (else the page and timeline both scroll)
  8478. event.preventDefault();
  8479. if (this.options.verticalScroll && Math.abs(deltaY) >= Math.abs(deltaX)) {
  8480. var current = this.props.scrollTop;
  8481. var adjusted = current + deltaY;
  8482. if (this.isActive()) {
  8483. this._setScrollTop(adjusted);
  8484. this._redraw();
  8485. this.emit('scroll', event);
  8486. }
  8487. } else if (this.options.horizontalScroll) {
  8488. var delta = Math.abs(deltaX) >= Math.abs(deltaY) ? deltaX : deltaY;
  8489. // calculate a single scroll jump relative to the range scale
  8490. var diff = delta / 120 * (this.range.end - this.range.start) / 20;
  8491. // calculate new start and end
  8492. var newStart = this.range.start + diff;
  8493. var newEnd = this.range.end + diff;
  8494. var options = {
  8495. animation: false,
  8496. byUser: true,
  8497. event: event
  8498. };
  8499. this.range.setRange(newStart, newEnd, options);
  8500. }
  8501. }
  8502. if (this.dom.centerContainer.addEventListener) {
  8503. // IE9, Chrome, Safari, Opera
  8504. this.dom.centerContainer.addEventListener("mousewheel", onMouseWheel.bind(this), false);
  8505. // Firefox
  8506. this.dom.centerContainer.addEventListener("DOMMouseScroll", onMouseWheel.bind(this), false);
  8507. } else {
  8508. // IE 6/7/8
  8509. this.dom.centerContainer.attachEvent("onmousewheel", onMouseWheel.bind(this));
  8510. }
  8511. /**
  8512. *
  8513. * @param {scroll} event
  8514. */
  8515. function onMouseScrollSide(event) {
  8516. if (!me.options.verticalScroll) return;
  8517. event.preventDefault();
  8518. if (me.isActive()) {
  8519. var adjusted = -event.target.scrollTop;
  8520. me._setScrollTop(adjusted);
  8521. me._redraw();
  8522. me.emit('scrollSide', event);
  8523. }
  8524. }
  8525. this.dom.left.parentNode.addEventListener('scroll', onMouseScrollSide.bind(this));
  8526. this.dom.right.parentNode.addEventListener('scroll', onMouseScrollSide.bind(this));
  8527. var itemAddedToTimeline = false;
  8528. /**
  8529. *
  8530. * @param {dragover} event
  8531. * @returns {boolean}
  8532. */
  8533. function handleDragOver(event) {
  8534. if (event.preventDefault) {
  8535. event.preventDefault(); // Necessary. Allows us to drop.
  8536. }
  8537. // make sure your target is a vis element
  8538. if (!event.target.className.indexOf("vis") > -1) return;
  8539. // make sure only one item is added every time you're over the timeline
  8540. if (itemAddedToTimeline) return;
  8541. event.dataTransfer.dropEffect = 'move';
  8542. itemAddedToTimeline = true;
  8543. return false;
  8544. }
  8545. /**
  8546. *
  8547. * @param {drop} event
  8548. * @returns {boolean}
  8549. */
  8550. function handleDrop(event) {
  8551. // prevent redirect to blank page - Firefox
  8552. if (event.preventDefault) {
  8553. event.preventDefault();
  8554. }
  8555. if (event.stopPropagation) {
  8556. event.stopPropagation();
  8557. }
  8558. // return when dropping non-vis items
  8559. try {
  8560. var itemData = JSON.parse(event.dataTransfer.getData("text"));
  8561. if (!itemData || !itemData.content) return;
  8562. } catch (err) {
  8563. return false;
  8564. }
  8565. itemAddedToTimeline = false;
  8566. event.center = {
  8567. x: event.clientX,
  8568. y: event.clientY
  8569. };
  8570. if (itemData.target !== 'item') {
  8571. me.itemSet._onAddItem(event);
  8572. } else {
  8573. me.itemSet._onDropObjectOnItem(event);
  8574. }
  8575. me.emit('drop', me.getEventProperties(event));
  8576. return false;
  8577. }
  8578. this.dom.center.addEventListener('dragover', handleDragOver.bind(this), false);
  8579. this.dom.center.addEventListener('drop', handleDrop.bind(this), false);
  8580. this.customTimes = [];
  8581. // store state information needed for touch events
  8582. this.touch = {};
  8583. this.redrawCount = 0;
  8584. this.initialDrawDone = false;
  8585. this.initialRangeChangeDone = false;
  8586. // attach the root panel to the provided container
  8587. if (!container) throw new Error('No container provided');
  8588. container.appendChild(this.dom.root);
  8589. };
  8590. /**
  8591. * Set options. Options will be passed to all components loaded in the Timeline.
  8592. * @param {Object} [options]
  8593. * {String} orientation
  8594. * Vertical orientation for the Timeline,
  8595. * can be 'bottom' (default) or 'top'.
  8596. * {string | number} width
  8597. * Width for the timeline, a number in pixels or
  8598. * a css string like '1000px' or '75%'. '100%' by default.
  8599. * {string | number} height
  8600. * Fixed height for the Timeline, a number in pixels or
  8601. * a css string like '400px' or '75%'. If undefined,
  8602. * The Timeline will automatically size such that
  8603. * its contents fit.
  8604. * {string | number} minHeight
  8605. * Minimum height for the Timeline, a number in pixels or
  8606. * a css string like '400px' or '75%'.
  8607. * {string | number} maxHeight
  8608. * Maximum height for the Timeline, a number in pixels or
  8609. * a css string like '400px' or '75%'.
  8610. * {number | Date | string} start
  8611. * Start date for the visible window
  8612. * {number | Date | string} end
  8613. * End date for the visible window
  8614. */
  8615. Core.prototype.setOptions = function(options) {
  8616. if (options) {
  8617. // copy the known options
  8618. var fields = ['width', 'height', 'minHeight', 'maxHeight', 'autoResize', 'start', 'end', 'clickToUse', 'dataAttributes', 'hiddenDates', 'locale', 'locales', 'moment', 'rtl', 'zoomKey', 'horizontalScroll', 'verticalScroll'];
  8619. util.selectiveExtend(fields, this.options, options);
  8620. this.dom.rollingModeBtn.style.visibility = 'hidden';
  8621. if (this.options.rtl) {
  8622. this.dom.container.style.direction = "rtl";
  8623. this.dom.backgroundVertical.className = 'vis-panel vis-background vis-vertical-rtl';
  8624. }
  8625. if (this.options.verticalScroll) {
  8626. if (this.options.rtl) {
  8627. this.dom.rightContainer.className = 'vis-panel vis-right vis-vertical-scroll';
  8628. } else {
  8629. this.dom.leftContainer.className = 'vis-panel vis-left vis-vertical-scroll';
  8630. }
  8631. }
  8632. if ((0, _typeof3['default'])(this.options.orientation) !== 'object') {
  8633. this.options.orientation = { item: undefined, axis: undefined };
  8634. }
  8635. if ('orientation' in options) {
  8636. if (typeof options.orientation === 'string') {
  8637. this.options.orientation = {
  8638. item: options.orientation,
  8639. axis: options.orientation
  8640. };
  8641. } else if ((0, _typeof3['default'])(options.orientation) === 'object') {
  8642. if ('item' in options.orientation) {
  8643. this.options.orientation.item = options.orientation.item;
  8644. }
  8645. if ('axis' in options.orientation) {
  8646. this.options.orientation.axis = options.orientation.axis;
  8647. }
  8648. }
  8649. }
  8650. if (this.options.orientation.axis === 'both') {
  8651. if (!this.timeAxis2) {
  8652. var timeAxis2 = this.timeAxis2 = new TimeAxis(this.body);
  8653. timeAxis2.setOptions = function(options) {
  8654. var _options = options ? util.extend({}, options) : {};
  8655. _options.orientation = 'top'; // override the orientation option, always top
  8656. TimeAxis.prototype.setOptions.call(timeAxis2, _options);
  8657. };
  8658. this.components.push(timeAxis2);
  8659. }
  8660. } else {
  8661. if (this.timeAxis2) {
  8662. var index = this.components.indexOf(this.timeAxis2);
  8663. if (index !== -1) {
  8664. this.components.splice(index, 1);
  8665. }
  8666. this.timeAxis2.destroy();
  8667. this.timeAxis2 = null;
  8668. }
  8669. }
  8670. // if the graph2d's drawPoints is a function delegate the callback to the onRender property
  8671. if (typeof options.drawPoints == 'function') {
  8672. options.drawPoints = {
  8673. onRender: options.drawPoints
  8674. };
  8675. }
  8676. if ('hiddenDates' in this.options) {
  8677. DateUtil.convertHiddenOptions(this.options.moment, this.body, this.options.hiddenDates);
  8678. }
  8679. if ('clickToUse' in options) {
  8680. if (options.clickToUse) {
  8681. if (!this.activator) {
  8682. this.activator = new Activator(this.dom.root);
  8683. }
  8684. } else {
  8685. if (this.activator) {
  8686. this.activator.destroy();
  8687. delete this.activator;
  8688. }
  8689. }
  8690. }
  8691. if ('showCustomTime' in options) {
  8692. throw new Error('Option `showCustomTime` is deprecated. Create a custom time bar via timeline.addCustomTime(time [, id])');
  8693. }
  8694. // enable/disable autoResize
  8695. this._initAutoResize();
  8696. }
  8697. // propagate options to all components
  8698. this.components.forEach(function(component) {
  8699. return component.setOptions(options);
  8700. });
  8701. // enable/disable configure
  8702. if ('configure' in options) {
  8703. if (!this.configurator) {
  8704. this.configurator = this._createConfigurator();
  8705. }
  8706. this.configurator.setOptions(options.configure);
  8707. // collect the settings of all components, and pass them to the configuration system
  8708. var appliedOptions = util.deepExtend({}, this.options);
  8709. this.components.forEach(function(component) {
  8710. util.deepExtend(appliedOptions, component.options);
  8711. });
  8712. this.configurator.setModuleOptions({ global: appliedOptions });
  8713. }
  8714. this._redraw();
  8715. };
  8716. /**
  8717. * Returns true when the Timeline is active.
  8718. * @returns {boolean}
  8719. */
  8720. Core.prototype.isActive = function() {
  8721. return !this.activator || this.activator.active;
  8722. };
  8723. /**
  8724. * Destroy the Core, clean up all DOM elements and event listeners.
  8725. */
  8726. Core.prototype.destroy = function() {
  8727. // unbind datasets
  8728. this.setItems(null);
  8729. this.setGroups(null);
  8730. // remove all event listeners
  8731. this.off();
  8732. // stop checking for changed size
  8733. this._stopAutoResize();
  8734. // remove from DOM
  8735. if (this.dom.root.parentNode) {
  8736. this.dom.root.parentNode.removeChild(this.dom.root);
  8737. }
  8738. this.dom = null;
  8739. // remove Activator
  8740. if (this.activator) {
  8741. this.activator.destroy();
  8742. delete this.activator;
  8743. }
  8744. // cleanup hammer touch events
  8745. for (var event in this.listeners) {
  8746. if (this.listeners.hasOwnProperty(event)) {
  8747. delete this.listeners[event];
  8748. }
  8749. }
  8750. this.listeners = null;
  8751. this.hammer = null;
  8752. // give all components the opportunity to cleanup
  8753. this.components.forEach(function(component) {
  8754. return component.destroy();
  8755. });
  8756. this.body = null;
  8757. };
  8758. /**
  8759. * Set a custom time bar
  8760. * @param {Date} time
  8761. * @param {number} [id=undefined] Optional id of the custom time bar to be adjusted.
  8762. */
  8763. Core.prototype.setCustomTime = function(time, id) {
  8764. var customTimes = this.customTimes.filter(function(component) {
  8765. return id === component.options.id;
  8766. });
  8767. if (customTimes.length === 0) {
  8768. throw new Error('No custom time bar found with id ' + (0, _stringify2['default'])(id));
  8769. }
  8770. if (customTimes.length > 0) {
  8771. customTimes[0].setCustomTime(time);
  8772. }
  8773. };
  8774. /**
  8775. * Retrieve the current custom time.
  8776. * @param {number} [id=undefined] Id of the custom time bar.
  8777. * @return {Date | undefined} customTime
  8778. */
  8779. Core.prototype.getCustomTime = function(id) {
  8780. var customTimes = this.customTimes.filter(function(component) {
  8781. return component.options.id === id;
  8782. });
  8783. if (customTimes.length === 0) {
  8784. throw new Error('No custom time bar found with id ' + (0, _stringify2['default'])(id));
  8785. }
  8786. return customTimes[0].getCustomTime();
  8787. };
  8788. /**
  8789. * Set a custom title for the custom time bar.
  8790. * @param {string} [title] Custom title
  8791. * @param {number} [id=undefined] Id of the custom time bar.
  8792. * @returns {*}
  8793. */
  8794. Core.prototype.setCustomTimeTitle = function(title, id) {
  8795. var customTimes = this.customTimes.filter(function(component) {
  8796. return component.options.id === id;
  8797. });
  8798. if (customTimes.length === 0) {
  8799. throw new Error('No custom time bar found with id ' + (0, _stringify2['default'])(id));
  8800. }
  8801. if (customTimes.length > 0) {
  8802. return customTimes[0].setCustomTitle(title);
  8803. }
  8804. };
  8805. /**
  8806. * Retrieve meta information from an event.
  8807. * Should be overridden by classes extending Core
  8808. * @param {Event} event
  8809. * @return {Object} An object with related information.
  8810. */
  8811. Core.prototype.getEventProperties = function(event) {
  8812. return { event: event };
  8813. };
  8814. /**
  8815. * Add custom vertical bar
  8816. * @param {Date | string | number} [time] A Date, unix timestamp, or
  8817. * ISO date string. Time point where
  8818. * the new bar should be placed.
  8819. * If not provided, `new Date()` will
  8820. * be used.
  8821. * @param {number | string} [id=undefined] Id of the new bar. Optional
  8822. * @return {number | string} Returns the id of the new bar
  8823. */
  8824. Core.prototype.addCustomTime = function(time, id) {
  8825. var timestamp = time !== undefined ? util.convert(time, 'Date').valueOf() : new Date();
  8826. var exists = this.customTimes.some(function(customTime) {
  8827. return customTime.options.id === id;
  8828. });
  8829. if (exists) {
  8830. throw new Error('A custom time with id ' + (0, _stringify2['default'])(id) + ' already exists');
  8831. }
  8832. var customTime = new CustomTime(this.body, util.extend({}, this.options, {
  8833. time: timestamp,
  8834. id: id
  8835. }));
  8836. this.customTimes.push(customTime);
  8837. this.components.push(customTime);
  8838. this._redraw();
  8839. return id;
  8840. };
  8841. /**
  8842. * Remove previously added custom bar
  8843. * @param {int} id ID of the custom bar to be removed
  8844. * [at]returns {boolean} True if the bar exists and is removed, false otherwise
  8845. */
  8846. Core.prototype.removeCustomTime = function(id) {
  8847. var customTimes = this.customTimes.filter(function(bar) {
  8848. return bar.options.id === id;
  8849. });
  8850. if (customTimes.length === 0) {
  8851. throw new Error('No custom time bar found with id ' + (0, _stringify2['default'])(id));
  8852. }
  8853. customTimes.forEach(function(customTime) {
  8854. this.customTimes.splice(this.customTimes.indexOf(customTime), 1);
  8855. this.components.splice(this.components.indexOf(customTime), 1);
  8856. customTime.destroy();
  8857. }.bind(this));
  8858. };
  8859. /**
  8860. * Get the id's of the currently visible items.
  8861. * @returns {Array} The ids of the visible items
  8862. */
  8863. Core.prototype.getVisibleItems = function() {
  8864. return this.itemSet && this.itemSet.getVisibleItems() || [];
  8865. };
  8866. /**
  8867. * Set Core window such that it fits all items
  8868. * @param {Object} [options] Available options:
  8869. * `animation: boolean | {duration: number, easingFunction: string}`
  8870. * If true (default), the range is animated
  8871. * smoothly to the new window. An object can be
  8872. * provided to specify duration and easing function.
  8873. * Default duration is 500 ms, and default easing
  8874. * function is 'easeInOutQuad'.
  8875. * @param {function} [callback] a callback funtion to be executed at the end of this function
  8876. */
  8877. Core.prototype.fit = function(options, callback) {
  8878. var range = this.getDataRange();
  8879. // skip range set if there is no min and max date
  8880. if (range.min === null && range.max === null) {
  8881. return;
  8882. }
  8883. // apply a margin of 1% left and right of the data
  8884. var interval = range.max - range.min;
  8885. var min = new Date(range.min.valueOf() - interval * 0.01);
  8886. var max = new Date(range.max.valueOf() + interval * 0.01);
  8887. var animation = options && options.animation !== undefined ? options.animation : true;
  8888. this.range.setRange(min, max, { animation: animation }, callback);
  8889. };
  8890. /**
  8891. * Calculate the data range of the items start and end dates
  8892. * [at]returns {{min: [Date], max: [Date]}}
  8893. * @protected
  8894. */
  8895. Core.prototype.getDataRange = function() {
  8896. // must be implemented by Timeline and Graph2d
  8897. throw new Error('Cannot invoke abstract method getDataRange');
  8898. };
  8899. /**
  8900. * Set the visible window. Both parameters are optional, you can change only
  8901. * start or only end. Syntax:
  8902. *
  8903. * TimeLine.setWindow(start, end)
  8904. * TimeLine.setWindow(start, end, options)
  8905. * TimeLine.setWindow(range)
  8906. *
  8907. * Where start and end can be a Date, number, or string, and range is an
  8908. * object with properties start and end.
  8909. *
  8910. * @param {Date | number | string | Object} [start] Start date of visible window
  8911. * @param {Date | number | string} [end] End date of visible window
  8912. * @param {Object} [options] Available options:
  8913. * `animation: boolean | {duration: number, easingFunction: string}`
  8914. * If true (default), the range is animated
  8915. * smoothly to the new window. An object can be
  8916. * provided to specify duration and easing function.
  8917. * Default duration is 500 ms, and default easing
  8918. * function is 'easeInOutQuad'.
  8919. * @param {function} [callback] a callback funtion to be executed at the end of this function
  8920. */
  8921. Core.prototype.setWindow = function(start, end, options, callback) {
  8922. if (typeof arguments[2] == "function") {
  8923. callback = arguments[2];
  8924. options = {};
  8925. }
  8926. var animation;
  8927. var range;
  8928. if (arguments.length == 1) {
  8929. range = arguments[0];
  8930. animation = range.animation !== undefined ? range.animation : true;
  8931. this.range.setRange(range.start, range.end, { animation: animation });
  8932. } else if (arguments.length == 2 && typeof arguments[1] == "function") {
  8933. range = arguments[0];
  8934. callback = arguments[1];
  8935. animation = range.animation !== undefined ? range.animation : true;
  8936. this.range.setRange(range.start, range.end, { animation: animation }, callback);
  8937. } else {
  8938. animation = options && options.animation !== undefined ? options.animation : true;
  8939. this.range.setRange(start, end, { animation: animation }, callback);
  8940. }
  8941. };
  8942. /**
  8943. * Move the window such that given time is centered on screen.
  8944. * @param {Date | number | string} time
  8945. * @param {Object} [options] Available options:
  8946. * `animation: boolean | {duration: number, easingFunction: string}`
  8947. * If true (default), the range is animated
  8948. * smoothly to the new window. An object can be
  8949. * provided to specify duration and easing function.
  8950. * Default duration is 500 ms, and default easing
  8951. * function is 'easeInOutQuad'.
  8952. * @param {function} [callback] a callback funtion to be executed at the end of this function
  8953. */
  8954. Core.prototype.moveTo = function(time, options, callback) {
  8955. if (typeof arguments[1] == "function") {
  8956. callback = arguments[1];
  8957. options = {};
  8958. }
  8959. var interval = this.range.end - this.range.start;
  8960. var t = util.convert(time, 'Date').valueOf();
  8961. var start = t - interval / 2;
  8962. var end = t + interval / 2;
  8963. var animation = options && options.animation !== undefined ? options.animation : true;
  8964. this.range.setRange(start, end, { animation: animation }, callback);
  8965. };
  8966. /**
  8967. * Get the visible window
  8968. * @return {{start: Date, end: Date}} Visible range
  8969. */
  8970. Core.prototype.getWindow = function() {
  8971. var range = this.range.getRange();
  8972. return {
  8973. start: new Date(range.start),
  8974. end: new Date(range.end)
  8975. };
  8976. };
  8977. /**
  8978. * Zoom in the window such that given time is centered on screen.
  8979. * @param {number} percentage - must be between [0..1]
  8980. * @param {Object} [options] Available options:
  8981. * `animation: boolean | {duration: number, easingFunction: string}`
  8982. * If true (default), the range is animated
  8983. * smoothly to the new window. An object can be
  8984. * provided to specify duration and easing function.
  8985. * Default duration is 500 ms, and default easing
  8986. * function is 'easeInOutQuad'.
  8987. * @param {function} [callback] a callback funtion to be executed at the end of this function
  8988. */
  8989. Core.prototype.zoomIn = function(percentage, options, callback) {
  8990. if (!percentage || percentage < 0 || percentage > 1) return;
  8991. if (typeof arguments[1] == "function") {
  8992. callback = arguments[1];
  8993. options = {};
  8994. }
  8995. var range = this.getWindow();
  8996. var start = range.start.valueOf();
  8997. var end = range.end.valueOf();
  8998. var interval = end - start;
  8999. var newInterval = interval / (1 + percentage);
  9000. var distance = (interval - newInterval) / 2;
  9001. var newStart = start + distance;
  9002. var newEnd = end - distance;
  9003. this.setWindow(newStart, newEnd, options, callback);
  9004. };
  9005. /**
  9006. * Zoom out the window such that given time is centered on screen.
  9007. * @param {number} percentage - must be between [0..1]
  9008. * @param {Object} [options] Available options:
  9009. * `animation: boolean | {duration: number, easingFunction: string}`
  9010. * If true (default), the range is animated
  9011. * smoothly to the new window. An object can be
  9012. * provided to specify duration and easing function.
  9013. * Default duration is 500 ms, and default easing
  9014. * function is 'easeInOutQuad'.
  9015. * @param {function} [callback] a callback funtion to be executed at the end of this function
  9016. */
  9017. Core.prototype.zoomOut = function(percentage, options, callback) {
  9018. if (!percentage || percentage < 0 || percentage > 1) return;
  9019. if (typeof arguments[1] == "function") {
  9020. callback = arguments[1];
  9021. options = {};
  9022. }
  9023. var range = this.getWindow();
  9024. var start = range.start.valueOf();
  9025. var end = range.end.valueOf();
  9026. var interval = end - start;
  9027. var newStart = start - interval * percentage / 2;
  9028. var newEnd = end + interval * percentage / 2;
  9029. this.setWindow(newStart, newEnd, options, callback);
  9030. };
  9031. /**
  9032. * Force a redraw. Can be overridden by implementations of Core
  9033. *
  9034. * Note: this function will be overridden on construction with a trottled version
  9035. */
  9036. Core.prototype.redraw = function() {
  9037. this._redraw();
  9038. };
  9039. /**
  9040. * Redraw for internal use. Redraws all components. See also the public
  9041. * method redraw.
  9042. * @protected
  9043. */
  9044. Core.prototype._redraw = function() {
  9045. this.redrawCount++;
  9046. var resized = false;
  9047. var options = this.options;
  9048. var props = this.props;
  9049. var dom = this.dom;
  9050. if (!dom || !dom.container || dom.root.offsetWidth == 0) return; // when destroyed, or invisible
  9051. DateUtil.updateHiddenDates(this.options.moment, this.body, this.options.hiddenDates);
  9052. // update class names
  9053. if (options.orientation == 'top') {
  9054. util.addClassName(dom.root, 'vis-top');
  9055. util.removeClassName(dom.root, 'vis-bottom');
  9056. } else {
  9057. util.removeClassName(dom.root, 'vis-top');
  9058. util.addClassName(dom.root, 'vis-bottom');
  9059. }
  9060. // update root width and height options
  9061. dom.root.style.maxHeight = util.option.asSize(options.maxHeight, '');
  9062. dom.root.style.minHeight = util.option.asSize(options.minHeight, '');
  9063. dom.root.style.width = util.option.asSize(options.width, '');
  9064. // calculate border widths
  9065. props.border.left = (dom.centerContainer.offsetWidth - dom.centerContainer.clientWidth) / 2;
  9066. props.border.right = props.border.left;
  9067. props.border.top = (dom.centerContainer.offsetHeight - dom.centerContainer.clientHeight) / 2;
  9068. props.border.bottom = props.border.top;
  9069. props.borderRootHeight = dom.root.offsetHeight - dom.root.clientHeight;
  9070. props.borderRootWidth = dom.root.offsetWidth - dom.root.clientWidth;
  9071. // workaround for a bug in IE: the clientWidth of an element with
  9072. // a height:0px and overflow:hidden is not calculated and always has value 0
  9073. if (dom.centerContainer.clientHeight === 0) {
  9074. props.border.left = props.border.top;
  9075. props.border.right = props.border.left;
  9076. }
  9077. if (dom.root.clientHeight === 0) {
  9078. props.borderRootWidth = props.borderRootHeight;
  9079. }
  9080. // calculate the heights. If any of the side panels is empty, we set the height to
  9081. // minus the border width, such that the border will be invisible
  9082. props.center.height = dom.center.offsetHeight;
  9083. props.left.height = dom.left.offsetHeight;
  9084. props.right.height = dom.right.offsetHeight;
  9085. props.top.height = dom.top.clientHeight || -props.border.top;
  9086. props.bottom.height = dom.bottom.clientHeight || -props.border.bottom;
  9087. // TODO: compensate borders when any of the panels is empty.
  9088. // apply auto height
  9089. // TODO: only calculate autoHeight when needed (else we cause an extra reflow/repaint of the DOM)
  9090. var contentHeight = Math.max(props.left.height, props.center.height, props.right.height);
  9091. var autoHeight = props.top.height + contentHeight + props.bottom.height + props.borderRootHeight + props.border.top + props.border.bottom;
  9092. dom.root.style.height = util.option.asSize(options.height, autoHeight + 'px');
  9093. // calculate heights of the content panels
  9094. props.root.height = dom.root.offsetHeight;
  9095. props.background.height = props.root.height - props.borderRootHeight;
  9096. var containerHeight = props.root.height - props.top.height - props.bottom.height - props.borderRootHeight;
  9097. props.centerContainer.height = containerHeight;
  9098. props.leftContainer.height = containerHeight;
  9099. props.rightContainer.height = props.leftContainer.height;
  9100. // calculate the widths of the panels
  9101. props.root.width = dom.root.offsetWidth;
  9102. props.background.width = props.root.width - props.borderRootWidth;
  9103. if (!this.initialDrawDone) {
  9104. props.scrollbarWidth = util.getScrollBarWidth();
  9105. }
  9106. if (options.verticalScroll) {
  9107. if (options.rtl) {
  9108. props.left.width = dom.leftContainer.clientWidth || -props.border.left;
  9109. props.right.width = dom.rightContainer.clientWidth + props.scrollbarWidth || -props.border.right;
  9110. } else {
  9111. props.left.width = dom.leftContainer.clientWidth + props.scrollbarWidth || -props.border.left;
  9112. props.right.width = dom.rightContainer.clientWidth || -props.border.right;
  9113. }
  9114. } else {
  9115. props.left.width = dom.leftContainer.clientWidth || -props.border.left;
  9116. props.right.width = dom.rightContainer.clientWidth || -props.border.right;
  9117. }
  9118. this._setDOM();
  9119. // update the scrollTop, feasible range for the offset can be changed
  9120. // when the height of the Core or of the contents of the center changed
  9121. var offset = this._updateScrollTop();
  9122. // reposition the scrollable contents
  9123. if (options.orientation.item != 'top') {
  9124. offset += Math.max(props.centerContainer.height - props.center.height - props.border.top - props.border.bottom, 0);
  9125. }
  9126. dom.center.style.top = offset + 'px';
  9127. // show shadows when vertical scrolling is available
  9128. var visibilityTop = props.scrollTop == 0 ? 'hidden' : '';
  9129. var visibilityBottom = props.scrollTop == props.scrollTopMin ? 'hidden' : '';
  9130. dom.shadowTop.style.visibility = visibilityTop;
  9131. dom.shadowBottom.style.visibility = visibilityBottom;
  9132. dom.shadowTopLeft.style.visibility = visibilityTop;
  9133. dom.shadowBottomLeft.style.visibility = visibilityBottom;
  9134. dom.shadowTopRight.style.visibility = visibilityTop;
  9135. dom.shadowBottomRight.style.visibility = visibilityBottom;
  9136. if (options.verticalScroll) {
  9137. dom.rightContainer.className = 'vis-panel vis-right vis-vertical-scroll';
  9138. dom.leftContainer.className = 'vis-panel vis-left vis-vertical-scroll';
  9139. dom.shadowTopRight.style.visibility = "hidden";
  9140. dom.shadowBottomRight.style.visibility = "hidden";
  9141. dom.shadowTopLeft.style.visibility = "hidden";
  9142. dom.shadowBottomLeft.style.visibility = "hidden";
  9143. dom.left.style.top = '0px';
  9144. dom.right.style.top = '0px';
  9145. }
  9146. if (!options.verticalScroll || props.center.height < props.centerContainer.height) {
  9147. dom.left.style.top = offset + 'px';
  9148. dom.right.style.top = offset + 'px';
  9149. dom.rightContainer.className = dom.rightContainer.className.replace(new RegExp('(?:^|\\s)' + 'vis-vertical-scroll' + '(?:\\s|$)'), ' ');
  9150. dom.leftContainer.className = dom.leftContainer.className.replace(new RegExp('(?:^|\\s)' + 'vis-vertical-scroll' + '(?:\\s|$)'), ' ');
  9151. props.left.width = dom.leftContainer.clientWidth || -props.border.left;
  9152. props.right.width = dom.rightContainer.clientWidth || -props.border.right;
  9153. this._setDOM();
  9154. }
  9155. // enable/disable vertical panning
  9156. var contentsOverflow = props.center.height > props.centerContainer.height;
  9157. this.hammer.get('pan').set({
  9158. direction: contentsOverflow ? Hammer.DIRECTION_ALL : Hammer.DIRECTION_HORIZONTAL
  9159. });
  9160. // redraw all components
  9161. this.components.forEach(function(component) {
  9162. resized = component.redraw() || resized;
  9163. });
  9164. var MAX_REDRAW = 5;
  9165. if (resized) {
  9166. if (this.redrawCount < MAX_REDRAW) {
  9167. this.body.emitter.emit('_change');
  9168. return;
  9169. } else {
  9170. console.log('WARNING: infinite loop in redraw?');
  9171. }
  9172. } else {
  9173. this.redrawCount = 0;
  9174. }
  9175. //Emit public 'changed' event for UI updates, see issue #1592
  9176. this.body.emitter.emit("changed");
  9177. };
  9178. Core.prototype._setDOM = function() {
  9179. var props = this.props;
  9180. var dom = this.dom;
  9181. props.leftContainer.width = props.left.width;
  9182. props.rightContainer.width = props.right.width;
  9183. var centerWidth = props.root.width - props.left.width - props.right.width - props.borderRootWidth;
  9184. props.center.width = centerWidth;
  9185. props.centerContainer.width = centerWidth;
  9186. props.top.width = centerWidth;
  9187. props.bottom.width = centerWidth;
  9188. // resize the panels
  9189. dom.background.style.height = props.background.height + 'px';
  9190. dom.backgroundVertical.style.height = props.background.height + 'px';
  9191. dom.backgroundHorizontal.style.height = props.centerContainer.height + 'px';
  9192. dom.centerContainer.style.height = props.centerContainer.height + 'px';
  9193. dom.leftContainer.style.height = props.leftContainer.height + 'px';
  9194. dom.rightContainer.style.height = props.rightContainer.height + 'px';
  9195. dom.background.style.width = props.background.width + 'px';
  9196. dom.backgroundVertical.style.width = props.centerContainer.width + 'px';
  9197. dom.backgroundHorizontal.style.width = props.background.width + 'px';
  9198. dom.centerContainer.style.width = props.center.width + 'px';
  9199. dom.top.style.width = props.top.width + 'px';
  9200. dom.bottom.style.width = props.bottom.width + 'px';
  9201. // reposition the panels
  9202. dom.background.style.left = '0';
  9203. dom.background.style.top = '0';
  9204. dom.backgroundVertical.style.left = props.left.width + props.border.left + 'px';
  9205. dom.backgroundVertical.style.top = '0';
  9206. dom.backgroundHorizontal.style.left = '0';
  9207. dom.backgroundHorizontal.style.top = props.top.height + 'px';
  9208. dom.centerContainer.style.left = props.left.width + 'px';
  9209. dom.centerContainer.style.top = props.top.height + 'px';
  9210. dom.leftContainer.style.left = '0';
  9211. dom.leftContainer.style.top = props.top.height + 'px';
  9212. dom.rightContainer.style.left = props.left.width + props.center.width + 'px';
  9213. dom.rightContainer.style.top = props.top.height + 'px';
  9214. dom.top.style.left = props.left.width + 'px';
  9215. dom.top.style.top = '0';
  9216. dom.bottom.style.left = props.left.width + 'px';
  9217. dom.bottom.style.top = props.top.height + props.centerContainer.height + 'px';
  9218. dom.center.style.left = '0';
  9219. dom.left.style.left = '0';
  9220. dom.right.style.left = '0';
  9221. };
  9222. // TODO: deprecated since version 1.1.0, remove some day
  9223. Core.prototype.repaint = function() {
  9224. throw new Error('Function repaint is deprecated. Use redraw instead.');
  9225. };
  9226. /**
  9227. * Set a current time. This can be used for example to ensure that a client's
  9228. * time is synchronized with a shared server time.
  9229. * Only applicable when option `showCurrentTime` is true.
  9230. * @param {Date | string | number} time A Date, unix timestamp, or
  9231. * ISO date string.
  9232. */
  9233. Core.prototype.setCurrentTime = function(time) {
  9234. if (!this.currentTime) {
  9235. throw new Error('Option showCurrentTime must be true');
  9236. }
  9237. this.currentTime.setCurrentTime(time);
  9238. };
  9239. /**
  9240. * Get the current time.
  9241. * Only applicable when option `showCurrentTime` is true.
  9242. * @return {Date} Returns the current time.
  9243. */
  9244. Core.prototype.getCurrentTime = function() {
  9245. if (!this.currentTime) {
  9246. throw new Error('Option showCurrentTime must be true');
  9247. }
  9248. return this.currentTime.getCurrentTime();
  9249. };
  9250. /**
  9251. * Convert a position on screen (pixels) to a datetime
  9252. * @param {int} x Position on the screen in pixels
  9253. * @return {Date} time The datetime the corresponds with given position x
  9254. * @protected
  9255. */
  9256. // TODO: move this function to Range
  9257. Core.prototype._toTime = function(x) {
  9258. return DateUtil.toTime(this, x, this.props.center.width);
  9259. };
  9260. /**
  9261. * Convert a position on the global screen (pixels) to a datetime
  9262. * @param {int} x Position on the screen in pixels
  9263. * @return {Date} time The datetime the corresponds with given position x
  9264. * @protected
  9265. */
  9266. // TODO: move this function to Range
  9267. Core.prototype._toGlobalTime = function(x) {
  9268. return DateUtil.toTime(this, x, this.props.root.width);
  9269. //var conversion = this.range.conversion(this.props.root.width);
  9270. //return new Date(x / conversion.scale + conversion.offset);
  9271. };
  9272. /**
  9273. * Convert a datetime (Date object) into a position on the screen
  9274. * @param {Date} time A date
  9275. * @return {int} x The position on the screen in pixels which corresponds
  9276. * with the given date.
  9277. * @protected
  9278. */
  9279. // TODO: move this function to Range
  9280. Core.prototype._toScreen = function(time) {
  9281. return DateUtil.toScreen(this, time, this.props.center.width);
  9282. };
  9283. /**
  9284. * Convert a datetime (Date object) into a position on the root
  9285. * This is used to get the pixel density estimate for the screen, not the center panel
  9286. * @param {Date} time A date
  9287. * @return {int} x The position on root in pixels which corresponds
  9288. * with the given date.
  9289. * @protected
  9290. */
  9291. // TODO: move this function to Range
  9292. Core.prototype._toGlobalScreen = function(time) {
  9293. return DateUtil.toScreen(this, time, this.props.root.width);
  9294. //var conversion = this.range.conversion(this.props.root.width);
  9295. //return (time.valueOf() - conversion.offset) * conversion.scale;
  9296. };
  9297. /**
  9298. * Initialize watching when option autoResize is true
  9299. * @private
  9300. */
  9301. Core.prototype._initAutoResize = function() {
  9302. if (this.options.autoResize == true) {
  9303. this._startAutoResize();
  9304. } else {
  9305. this._stopAutoResize();
  9306. }
  9307. };
  9308. /**
  9309. * Watch for changes in the size of the container. On resize, the Panel will
  9310. * automatically redraw itself.
  9311. * @private
  9312. */
  9313. Core.prototype._startAutoResize = function() {
  9314. var me = this;
  9315. this._stopAutoResize();
  9316. this._onResize = function() {
  9317. if (me.options.autoResize != true) {
  9318. // stop watching when the option autoResize is changed to false
  9319. me._stopAutoResize();
  9320. return;
  9321. }
  9322. if (me.dom.root) {
  9323. // check whether the frame is resized
  9324. // Note: we compare offsetWidth here, not clientWidth. For some reason,
  9325. // IE does not restore the clientWidth from 0 to the actual width after
  9326. // changing the timeline's container display style from none to visible
  9327. if (me.dom.root.offsetWidth != me.props.lastWidth || me.dom.root.offsetHeight != me.props.lastHeight) {
  9328. me.props.lastWidth = me.dom.root.offsetWidth;
  9329. me.props.lastHeight = me.dom.root.offsetHeight;
  9330. me.props.scrollbarWidth = util.getScrollBarWidth();
  9331. me.body.emitter.emit('_change');
  9332. }
  9333. }
  9334. };
  9335. // add event listener to window resize
  9336. util.addEventListener(window, 'resize', this._onResize);
  9337. //Prevent initial unnecessary redraw
  9338. if (me.dom.root) {
  9339. me.props.lastWidth = me.dom.root.offsetWidth;
  9340. me.props.lastHeight = me.dom.root.offsetHeight;
  9341. }
  9342. this.watchTimer = setInterval(this._onResize, 1000);
  9343. };
  9344. /**
  9345. * Stop watching for a resize of the frame.
  9346. * @private
  9347. */
  9348. Core.prototype._stopAutoResize = function() {
  9349. if (this.watchTimer) {
  9350. clearInterval(this.watchTimer);
  9351. this.watchTimer = undefined;
  9352. }
  9353. // remove event listener on window.resize
  9354. if (this._onResize) {
  9355. util.removeEventListener(window, 'resize', this._onResize);
  9356. this._onResize = null;
  9357. }
  9358. };
  9359. /**
  9360. * Start moving the timeline vertically
  9361. * @param {Event} event
  9362. * @private
  9363. */
  9364. Core.prototype._onTouch = function(event) {
  9365. // eslint-disable-line no-unused-vars
  9366. this.touch.allowDragging = true;
  9367. this.touch.initialScrollTop = this.props.scrollTop;
  9368. };
  9369. /**
  9370. * Start moving the timeline vertically
  9371. * @param {Event} event
  9372. * @private
  9373. */
  9374. Core.prototype._onPinch = function(event) {
  9375. // eslint-disable-line no-unused-vars
  9376. this.touch.allowDragging = false;
  9377. };
  9378. /**
  9379. * Move the timeline vertically
  9380. * @param {Event} event
  9381. * @private
  9382. */
  9383. Core.prototype._onDrag = function(event) {
  9384. if (!event) return;
  9385. // refuse to drag when we where pinching to prevent the timeline make a jump
  9386. // when releasing the fingers in opposite order from the touch screen
  9387. if (!this.touch.allowDragging) return;
  9388. var delta = event.deltaY;
  9389. var oldScrollTop = this._getScrollTop();
  9390. var newScrollTop = this._setScrollTop(this.touch.initialScrollTop + delta);
  9391. if (this.options.verticalScroll) {
  9392. this.dom.left.parentNode.scrollTop = -this.props.scrollTop;
  9393. this.dom.right.parentNode.scrollTop = -this.props.scrollTop;
  9394. }
  9395. if (newScrollTop != oldScrollTop) {
  9396. this.emit("verticalDrag");
  9397. }
  9398. };
  9399. /**
  9400. * Apply a scrollTop
  9401. * @param {number} scrollTop
  9402. * @returns {number} scrollTop Returns the applied scrollTop
  9403. * @private
  9404. */
  9405. Core.prototype._setScrollTop = function(scrollTop) {
  9406. this.props.scrollTop = scrollTop;
  9407. this._updateScrollTop();
  9408. return this.props.scrollTop;
  9409. };
  9410. /**
  9411. * Update the current scrollTop when the height of the containers has been changed
  9412. * @returns {number} scrollTop Returns the applied scrollTop
  9413. * @private
  9414. */
  9415. Core.prototype._updateScrollTop = function() {
  9416. // recalculate the scrollTopMin
  9417. var scrollTopMin = Math.min(this.props.centerContainer.height - this.props.center.height, 0); // is negative or zero
  9418. if (scrollTopMin != this.props.scrollTopMin) {
  9419. // in case of bottom orientation, change the scrollTop such that the contents
  9420. // do not move relative to the time axis at the bottom
  9421. if (this.options.orientation.item != 'top') {
  9422. this.props.scrollTop += scrollTopMin - this.props.scrollTopMin;
  9423. }
  9424. this.props.scrollTopMin = scrollTopMin;
  9425. }
  9426. // limit the scrollTop to the feasible scroll range
  9427. if (this.props.scrollTop > 0) this.props.scrollTop = 0;
  9428. if (this.props.scrollTop < scrollTopMin) this.props.scrollTop = scrollTopMin;
  9429. if (this.options.verticalScroll) {
  9430. this.dom.left.parentNode.scrollTop = -this.props.scrollTop;
  9431. this.dom.right.parentNode.scrollTop = -this.props.scrollTop;
  9432. }
  9433. return this.props.scrollTop;
  9434. };
  9435. /**
  9436. * Get the current scrollTop
  9437. * @returns {number} scrollTop
  9438. * @private
  9439. */
  9440. Core.prototype._getScrollTop = function() {
  9441. return this.props.scrollTop;
  9442. };
  9443. /**
  9444. * Load a configurator
  9445. * [at]returns {Object}
  9446. * @private
  9447. */
  9448. Core.prototype._createConfigurator = function() {
  9449. throw new Error('Cannot invoke abstract method _createConfigurator');
  9450. };
  9451. module.exports = Core;
  9452. /***/
  9453. }),
  9454. /* 66 */
  9455. /***/
  9456. (function(module, exports, __webpack_require__) {
  9457. "use strict";
  9458. var moment = __webpack_require__(9);
  9459. var DateUtil = __webpack_require__(36);
  9460. var util = __webpack_require__(2);
  9461. /**
  9462. * The class TimeStep is an iterator for dates. You provide a start date and an
  9463. * end date. The class itself determines the best scale (step size) based on the
  9464. * provided start Date, end Date, and minimumStep.
  9465. *
  9466. * If minimumStep is provided, the step size is chosen as close as possible
  9467. * to the minimumStep but larger than minimumStep. If minimumStep is not
  9468. * provided, the scale is set to 1 DAY.
  9469. * The minimumStep should correspond with the onscreen size of about 6 characters
  9470. *
  9471. * Alternatively, you can set a scale by hand.
  9472. * After creation, you can initialize the class by executing first(). Then you
  9473. * can iterate from the start date to the end date via next(). You can check if
  9474. * the end date is reached with the function hasNext(). After each step, you can
  9475. * retrieve the current date via getCurrent().
  9476. * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours,
  9477. * days, to years.
  9478. *
  9479. * Version: 1.2
  9480. *
  9481. * @param {Date} [start] The start date, for example new Date(2010, 9, 21)
  9482. * or new Date(2010, 9, 21, 23, 45, 00)
  9483. * @param {Date} [end] The end date
  9484. * @param {number} [minimumStep] Optional. Minimum step size in milliseconds
  9485. * @param {Date|Array.<Date>} [hiddenDates] Optional.
  9486. * @param {{showMajorLabels: boolean}} [options] Optional.
  9487. * @constructor TimeStep
  9488. */
  9489. function TimeStep(start, end, minimumStep, hiddenDates, options) {
  9490. this.moment = moment;
  9491. // variables
  9492. this.current = this.moment();
  9493. this._start = this.moment();
  9494. this._end = this.moment();
  9495. this.autoScale = true;
  9496. this.scale = 'day';
  9497. this.step = 1;
  9498. // initialize the range
  9499. this.setRange(start, end, minimumStep);
  9500. // hidden Dates options
  9501. this.switchedDay = false;
  9502. this.switchedMonth = false;
  9503. this.switchedYear = false;
  9504. if (Array.isArray(hiddenDates)) {
  9505. this.hiddenDates = hiddenDates;
  9506. } else if (hiddenDates != undefined) {
  9507. this.hiddenDates = [hiddenDates];
  9508. } else {
  9509. this.hiddenDates = [];
  9510. }
  9511. this.format = TimeStep.FORMAT; // default formatting
  9512. this.options = options ? options : {};
  9513. }
  9514. // Time formatting
  9515. TimeStep.FORMAT = {
  9516. minorLabels: {
  9517. millisecond: 'SSS',
  9518. second: 's',
  9519. minute: 'HH:mm',
  9520. hour: 'HH:mm',
  9521. weekday: 'ddd D',
  9522. day: 'D',
  9523. week: 'w',
  9524. month: 'MMM',
  9525. year: 'YYYY'
  9526. },
  9527. majorLabels: {
  9528. millisecond: 'HH:mm:ss',
  9529. second: 'D MMMM HH:mm',
  9530. minute: 'ddd D MMMM',
  9531. hour: 'ddd D MMMM',
  9532. weekday: 'MMMM YYYY',
  9533. day: 'MMMM YYYY',
  9534. week: 'MMMM YYYY',
  9535. month: 'YYYY',
  9536. year: ''
  9537. }
  9538. };
  9539. /**
  9540. * Set custom constructor function for moment. Can be used to set dates
  9541. * to UTC or to set a utcOffset.
  9542. * @param {function} moment
  9543. */
  9544. TimeStep.prototype.setMoment = function(moment) {
  9545. this.moment = moment;
  9546. // update the date properties, can have a new utcOffset
  9547. this.current = this.moment(this.current.valueOf());
  9548. this._start = this.moment(this._start.valueOf());
  9549. this._end = this.moment(this._end.valueOf());
  9550. };
  9551. /**
  9552. * Set custom formatting for the minor an major labels of the TimeStep.
  9553. * Both `minorLabels` and `majorLabels` are an Object with properties:
  9554. * 'millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'year'.
  9555. * @param {{minorLabels: Object, majorLabels: Object}} format
  9556. */
  9557. TimeStep.prototype.setFormat = function(format) {
  9558. var defaultFormat = util.deepExtend({}, TimeStep.FORMAT);
  9559. this.format = util.deepExtend(defaultFormat, format);
  9560. };
  9561. /**
  9562. * Set a new range
  9563. * If minimumStep is provided, the step size is chosen as close as possible
  9564. * to the minimumStep but larger than minimumStep. If minimumStep is not
  9565. * provided, the scale is set to 1 DAY.
  9566. * The minimumStep should correspond with the onscreen size of about 6 characters
  9567. * @param {Date} [start] The start date and time.
  9568. * @param {Date} [end] The end date and time.
  9569. * @param {int} [minimumStep] Optional. Minimum step size in milliseconds
  9570. */
  9571. TimeStep.prototype.setRange = function(start, end, minimumStep) {
  9572. if (!(start instanceof Date) || !(end instanceof Date)) {
  9573. throw "No legal start or end date in method setRange";
  9574. }
  9575. this._start = start != undefined ? this.moment(start.valueOf()) : new Date();
  9576. this._end = end != undefined ? this.moment(end.valueOf()) : new Date();
  9577. if (this.autoScale) {
  9578. this.setMinimumStep(minimumStep);
  9579. }
  9580. };
  9581. /**
  9582. * Set the range iterator to the start date.
  9583. */
  9584. TimeStep.prototype.start = function() {
  9585. this.current = this._start.clone();
  9586. this.roundToMinor();
  9587. };
  9588. /**
  9589. * Round the current date to the first minor date value
  9590. * This must be executed once when the current date is set to start Date
  9591. */
  9592. TimeStep.prototype.roundToMinor = function() {
  9593. // round to floor
  9594. // to prevent year & month scales rounding down to the first day of week we perform this separately
  9595. if (this.scale == 'week') {
  9596. this.current.weekday(0);
  9597. }
  9598. // IMPORTANT: we have no breaks in this switch! (this is no bug)
  9599. // noinspection FallThroughInSwitchStatementJS
  9600. switch (this.scale) {
  9601. case 'year':
  9602. this.current.year(this.step * Math.floor(this.current.year() / this.step));
  9603. this.current.month(0);
  9604. case 'month':
  9605. this.current.date(1); // eslint-disable-line no-fallthrough
  9606. case 'week': // eslint-disable-line no-fallthrough
  9607. case 'day': // eslint-disable-line no-fallthrough
  9608. case 'weekday':
  9609. this.current.hours(0); // eslint-disable-line no-fallthrough
  9610. case 'hour':
  9611. this.current.minutes(0); // eslint-disable-line no-fallthrough
  9612. case 'minute':
  9613. this.current.seconds(0); // eslint-disable-line no-fallthrough
  9614. case 'second':
  9615. this.current.milliseconds(0); // eslint-disable-line no-fallthrough
  9616. //case 'millisecond': // nothing to do for milliseconds
  9617. }
  9618. if (this.step != 1) {
  9619. // round down to the first minor value that is a multiple of the current step size
  9620. switch (this.scale) {
  9621. case 'millisecond':
  9622. this.current.subtract(this.current.milliseconds() % this.step, 'milliseconds');
  9623. break;
  9624. case 'second':
  9625. this.current.subtract(this.current.seconds() % this.step, 'seconds');
  9626. break;
  9627. case 'minute':
  9628. this.current.subtract(this.current.minutes() % this.step, 'minutes');
  9629. break;
  9630. case 'hour':
  9631. this.current.subtract(this.current.hours() % this.step, 'hours');
  9632. break;
  9633. case 'weekday': // intentional fall through
  9634. case 'day':
  9635. this.current.subtract((this.current.date() - 1) % this.step, 'day');
  9636. break;
  9637. case 'week':
  9638. this.current.subtract(this.current.week() % this.step, 'week');
  9639. break;
  9640. case 'month':
  9641. this.current.subtract(this.current.month() % this.step, 'month');
  9642. break;
  9643. case 'year':
  9644. this.current.subtract(this.current.year() % this.step, 'year');
  9645. break;
  9646. default:
  9647. break;
  9648. }
  9649. }
  9650. };
  9651. /**
  9652. * Check if the there is a next step
  9653. * @return {boolean} true if the current date has not passed the end date
  9654. */
  9655. TimeStep.prototype.hasNext = function() {
  9656. return this.current.valueOf() <= this._end.valueOf();
  9657. };
  9658. /**
  9659. * Do the next step
  9660. */
  9661. TimeStep.prototype.next = function() {
  9662. var prev = this.current.valueOf();
  9663. // Two cases, needed to prevent issues with switching daylight savings
  9664. // (end of March and end of October)
  9665. switch (this.scale) {
  9666. case 'millisecond':
  9667. this.current.add(this.step, 'millisecond');
  9668. break;
  9669. case 'second':
  9670. this.current.add(this.step, 'second');
  9671. break;
  9672. case 'minute':
  9673. this.current.add(this.step, 'minute');
  9674. break;
  9675. case 'hour':
  9676. this.current.add(this.step, 'hour');
  9677. if (this.current.month() < 6) {
  9678. this.current.subtract(this.current.hours() % this.step, 'hour');
  9679. } else {
  9680. if (this.current.hours() % this.step !== 0) {
  9681. this.current.add(this.step - this.current.hours() % this.step, 'hour');
  9682. }
  9683. }
  9684. break;
  9685. case 'weekday': // intentional fall through
  9686. case 'day':
  9687. this.current.add(this.step, 'day');
  9688. break;
  9689. case 'week':
  9690. if (this.current.weekday() !== 0) {
  9691. // we had a month break not correlating with a week's start before
  9692. this.current.weekday(0); // switch back to week cycles
  9693. this.current.add(this.step, 'week');
  9694. } else if (this.options.showMajorLabels === false) {
  9695. this.current.add(this.step, 'week'); // the default case
  9696. } else {
  9697. // first day of the week
  9698. var nextWeek = this.current.clone();
  9699. nextWeek.add(1, 'week');
  9700. if (nextWeek.isSame(this.current, 'month')) {
  9701. // is the first day of the next week in the same month?
  9702. this.current.add(this.step, 'week'); // the default case
  9703. } else {
  9704. // inject a step at each first day of the month
  9705. this.current.add(this.step, 'week');
  9706. this.current.date(1);
  9707. }
  9708. }
  9709. break;
  9710. case 'month':
  9711. this.current.add(this.step, 'month');
  9712. break;
  9713. case 'year':
  9714. this.current.add(this.step, 'year');
  9715. break;
  9716. default:
  9717. break;
  9718. }
  9719. if (this.step != 1) {
  9720. // round down to the correct major value
  9721. switch (this.scale) {
  9722. case 'millisecond':
  9723. if (this.current.milliseconds() > 0 && this.current.milliseconds() < this.step) this.current.milliseconds(0);
  9724. break;
  9725. case 'second':
  9726. if (this.current.seconds() > 0 && this.current.seconds() < this.step) this.current.seconds(0);
  9727. break;
  9728. case 'minute':
  9729. if (this.current.minutes() > 0 && this.current.minutes() < this.step) this.current.minutes(0);
  9730. break;
  9731. case 'hour':
  9732. if (this.current.hours() > 0 && this.current.hours() < this.step) this.current.hours(0);
  9733. break;
  9734. case 'weekday': // intentional fall through
  9735. case 'day':
  9736. if (this.current.date() < this.step + 1) this.current.date(1);
  9737. break;
  9738. case 'week':
  9739. if (this.current.week() < this.step) this.current.week(1);
  9740. break; // week numbering starts at 1, not 0
  9741. case 'month':
  9742. if (this.current.month() < this.step) this.current.month(0);
  9743. break;
  9744. case 'year':
  9745. break; // nothing to do for year
  9746. default:
  9747. break;
  9748. }
  9749. }
  9750. // safety mechanism: if current time is still unchanged, move to the end
  9751. if (this.current.valueOf() == prev) {
  9752. this.current = this._end.clone();
  9753. }
  9754. // Reset switches for year, month and day. Will get set to true where appropriate in DateUtil.stepOverHiddenDates
  9755. this.switchedDay = false;
  9756. this.switchedMonth = false;
  9757. this.switchedYear = false;
  9758. DateUtil.stepOverHiddenDates(this.moment, this, prev);
  9759. };
  9760. /**
  9761. * Get the current datetime
  9762. * @return {Moment} current The current date
  9763. */
  9764. TimeStep.prototype.getCurrent = function() {
  9765. return this.current;
  9766. };
  9767. /**
  9768. * Set a custom scale. Autoscaling will be disabled.
  9769. * For example setScale('minute', 5) will result
  9770. * in minor steps of 5 minutes, and major steps of an hour.
  9771. *
  9772. * @param {{scale: string, step: number}} params
  9773. * An object containing two properties:
  9774. * - A string 'scale'. Choose from 'millisecond', 'second',
  9775. * 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'year'.
  9776. * - A number 'step'. A step size, by default 1.
  9777. * Choose for example 1, 2, 5, or 10.
  9778. */
  9779. TimeStep.prototype.setScale = function(params) {
  9780. if (params && typeof params.scale == 'string') {
  9781. this.scale = params.scale;
  9782. this.step = params.step > 0 ? params.step : 1;
  9783. this.autoScale = false;
  9784. }
  9785. };
  9786. /**
  9787. * Enable or disable autoscaling
  9788. * @param {boolean} enable If true, autoascaling is set true
  9789. */
  9790. TimeStep.prototype.setAutoScale = function(enable) {
  9791. this.autoScale = enable;
  9792. };
  9793. /**
  9794. * Automatically determine the scale that bests fits the provided minimum step
  9795. * @param {number} [minimumStep] The minimum step size in milliseconds
  9796. */
  9797. TimeStep.prototype.setMinimumStep = function(minimumStep) {
  9798. if (minimumStep == undefined) {
  9799. return;
  9800. }
  9801. //var b = asc + ds;
  9802. var stepYear = 1000 * 60 * 60 * 24 * 30 * 12;
  9803. var stepMonth = 1000 * 60 * 60 * 24 * 30;
  9804. var stepDay = 1000 * 60 * 60 * 24;
  9805. var stepHour = 1000 * 60 * 60;
  9806. var stepMinute = 1000 * 60;
  9807. var stepSecond = 1000;
  9808. var stepMillisecond = 1;
  9809. // find the smallest step that is larger than the provided minimumStep
  9810. if (stepYear * 1000 > minimumStep) {
  9811. this.scale = 'year';
  9812. this.step = 1000;
  9813. }
  9814. if (stepYear * 500 > minimumStep) {
  9815. this.scale = 'year';
  9816. this.step = 500;
  9817. }
  9818. if (stepYear * 100 > minimumStep) {
  9819. this.scale = 'year';
  9820. this.step = 100;
  9821. }
  9822. if (stepYear * 50 > minimumStep) {
  9823. this.scale = 'year';
  9824. this.step = 50;
  9825. }
  9826. if (stepYear * 10 > minimumStep) {
  9827. this.scale = 'year';
  9828. this.step = 10;
  9829. }
  9830. if (stepYear * 5 > minimumStep) {
  9831. this.scale = 'year';
  9832. this.step = 5;
  9833. }
  9834. if (stepYear > minimumStep) {
  9835. this.scale = 'year';
  9836. this.step = 1;
  9837. }
  9838. if (stepMonth * 3 > minimumStep) {
  9839. this.scale = 'month';
  9840. this.step = 3;
  9841. }
  9842. if (stepMonth > minimumStep) {
  9843. this.scale = 'month';
  9844. this.step = 1;
  9845. }
  9846. if (stepDay * 5 > minimumStep) {
  9847. this.scale = 'day';
  9848. this.step = 5;
  9849. }
  9850. if (stepDay * 2 > minimumStep) {
  9851. this.scale = 'day';
  9852. this.step = 2;
  9853. }
  9854. if (stepDay > minimumStep) {
  9855. this.scale = 'day';
  9856. this.step = 1;
  9857. }
  9858. if (stepDay / 2 > minimumStep) {
  9859. this.scale = 'weekday';
  9860. this.step = 1;
  9861. }
  9862. if (stepHour * 4 > minimumStep) {
  9863. this.scale = 'hour';
  9864. this.step = 4;
  9865. }
  9866. if (stepHour > minimumStep) {
  9867. this.scale = 'hour';
  9868. this.step = 1;
  9869. }
  9870. if (stepMinute * 15 > minimumStep) {
  9871. this.scale = 'minute';
  9872. this.step = 15;
  9873. }
  9874. if (stepMinute * 10 > minimumStep) {
  9875. this.scale = 'minute';
  9876. this.step = 10;
  9877. }
  9878. if (stepMinute * 5 > minimumStep) {
  9879. this.scale = 'minute';
  9880. this.step = 5;
  9881. }
  9882. if (stepMinute > minimumStep) {
  9883. this.scale = 'minute';
  9884. this.step = 1;
  9885. }
  9886. if (stepSecond * 15 > minimumStep) {
  9887. this.scale = 'second';
  9888. this.step = 15;
  9889. }
  9890. if (stepSecond * 10 > minimumStep) {
  9891. this.scale = 'second';
  9892. this.step = 10;
  9893. }
  9894. if (stepSecond * 5 > minimumStep) {
  9895. this.scale = 'second';
  9896. this.step = 5;
  9897. }
  9898. if (stepSecond > minimumStep) {
  9899. this.scale = 'second';
  9900. this.step = 1;
  9901. }
  9902. if (stepMillisecond * 200 > minimumStep) {
  9903. this.scale = 'millisecond';
  9904. this.step = 200;
  9905. }
  9906. if (stepMillisecond * 100 > minimumStep) {
  9907. this.scale = 'millisecond';
  9908. this.step = 100;
  9909. }
  9910. if (stepMillisecond * 50 > minimumStep) {
  9911. this.scale = 'millisecond';
  9912. this.step = 50;
  9913. }
  9914. if (stepMillisecond * 10 > minimumStep) {
  9915. this.scale = 'millisecond';
  9916. this.step = 10;
  9917. }
  9918. if (stepMillisecond * 5 > minimumStep) {
  9919. this.scale = 'millisecond';
  9920. this.step = 5;
  9921. }
  9922. if (stepMillisecond > minimumStep) {
  9923. this.scale = 'millisecond';
  9924. this.step = 1;
  9925. }
  9926. };
  9927. /**
  9928. * Snap a date to a rounded value.
  9929. * The snap intervals are dependent on the current scale and step.
  9930. * Static function
  9931. * @param {Date} date the date to be snapped.
  9932. * @param {string} scale Current scale, can be 'millisecond', 'second',
  9933. * 'minute', 'hour', 'weekday, 'day', 'week', 'month', 'year'.
  9934. * @param {number} step Current step (1, 2, 4, 5, ...
  9935. * @return {Date} snappedDate
  9936. */
  9937. TimeStep.snap = function(date, scale, step) {
  9938. var clone = moment(date);
  9939. if (scale == 'year') {
  9940. var year = clone.year() + Math.round(clone.month() / 12);
  9941. clone.year(Math.round(year / step) * step);
  9942. clone.month(0);
  9943. clone.date(0);
  9944. clone.hours(0);
  9945. clone.minutes(0);
  9946. clone.seconds(0);
  9947. clone.milliseconds(0);
  9948. } else if (scale == 'month') {
  9949. if (clone.date() > 15) {
  9950. clone.date(1);
  9951. clone.add(1, 'month');
  9952. // important: first set Date to 1, after that change the month.
  9953. } else {
  9954. clone.date(1);
  9955. }
  9956. clone.hours(0);
  9957. clone.minutes(0);
  9958. clone.seconds(0);
  9959. clone.milliseconds(0);
  9960. } else if (scale == 'week') {
  9961. if (clone.weekday() > 2) {
  9962. // doing it the momentjs locale aware way
  9963. clone.weekday(0);
  9964. clone.add(1, 'week');
  9965. } else {
  9966. clone.weekday(0);
  9967. }
  9968. clone.hours(0);
  9969. clone.minutes(0);
  9970. clone.seconds(0);
  9971. clone.milliseconds(0);
  9972. } else if (scale == 'day') {
  9973. //noinspection FallthroughInSwitchStatementJS
  9974. switch (step) {
  9975. case 5:
  9976. case 2:
  9977. clone.hours(Math.round(clone.hours() / 24) * 24);
  9978. break;
  9979. default:
  9980. clone.hours(Math.round(clone.hours() / 12) * 12);
  9981. break;
  9982. }
  9983. clone.minutes(0);
  9984. clone.seconds(0);
  9985. clone.milliseconds(0);
  9986. } else if (scale == 'weekday') {
  9987. //noinspection FallthroughInSwitchStatementJS
  9988. switch (step) {
  9989. case 5:
  9990. case 2:
  9991. clone.hours(Math.round(clone.hours() / 12) * 12);
  9992. break;
  9993. default:
  9994. clone.hours(Math.round(clone.hours() / 6) * 6);
  9995. break;
  9996. }
  9997. clone.minutes(0);
  9998. clone.seconds(0);
  9999. clone.milliseconds(0);
  10000. } else if (scale == 'hour') {
  10001. switch (step) {
  10002. case 4:
  10003. clone.minutes(Math.round(clone.minutes() / 60) * 60);
  10004. break;
  10005. default:
  10006. clone.minutes(Math.round(clone.minutes() / 30) * 30);
  10007. break;
  10008. }
  10009. clone.seconds(0);
  10010. clone.milliseconds(0);
  10011. } else if (scale == 'minute') {
  10012. //noinspection FallthroughInSwitchStatementJS
  10013. switch (step) {
  10014. case 15:
  10015. case 10:
  10016. clone.minutes(Math.round(clone.minutes() / 5) * 5);
  10017. clone.seconds(0);
  10018. break;
  10019. case 5:
  10020. clone.seconds(Math.round(clone.seconds() / 60) * 60);
  10021. break;
  10022. default:
  10023. clone.seconds(Math.round(clone.seconds() / 30) * 30);
  10024. break;
  10025. }
  10026. clone.milliseconds(0);
  10027. } else if (scale == 'second') {
  10028. //noinspection FallthroughInSwitchStatementJS
  10029. switch (step) {
  10030. case 15:
  10031. case 10:
  10032. clone.seconds(Math.round(clone.seconds() / 5) * 5);
  10033. clone.milliseconds(0);
  10034. break;
  10035. case 5:
  10036. clone.milliseconds(Math.round(clone.milliseconds() / 1000) * 1000);
  10037. break;
  10038. default:
  10039. clone.milliseconds(Math.round(clone.milliseconds() / 500) * 500);
  10040. break;
  10041. }
  10042. } else if (scale == 'millisecond') {
  10043. var _step = step > 5 ? step / 2 : 1;
  10044. clone.milliseconds(Math.round(clone.milliseconds() / _step) * _step);
  10045. }
  10046. return clone;
  10047. };
  10048. /**
  10049. * Check if the current value is a major value (for example when the step
  10050. * is DAY, a major value is each first day of the MONTH)
  10051. * @return {boolean} true if current date is major, else false.
  10052. */
  10053. TimeStep.prototype.isMajor = function() {
  10054. if (this.switchedYear == true) {
  10055. switch (this.scale) {
  10056. case 'year':
  10057. case 'month':
  10058. case 'week':
  10059. case 'weekday':
  10060. case 'day':
  10061. case 'hour':
  10062. case 'minute':
  10063. case 'second':
  10064. case 'millisecond':
  10065. return true;
  10066. default:
  10067. return false;
  10068. }
  10069. } else if (this.switchedMonth == true) {
  10070. switch (this.scale) {
  10071. case 'week':
  10072. case 'weekday':
  10073. case 'day':
  10074. case 'hour':
  10075. case 'minute':
  10076. case 'second':
  10077. case 'millisecond':
  10078. return true;
  10079. default:
  10080. return false;
  10081. }
  10082. } else if (this.switchedDay == true) {
  10083. switch (this.scale) {
  10084. case 'millisecond':
  10085. case 'second':
  10086. case 'minute':
  10087. case 'hour':
  10088. return true;
  10089. default:
  10090. return false;
  10091. }
  10092. }
  10093. var date = this.moment(this.current);
  10094. switch (this.scale) {
  10095. case 'millisecond':
  10096. return date.milliseconds() == 0;
  10097. case 'second':
  10098. return date.seconds() == 0;
  10099. case 'minute':
  10100. return date.hours() == 0 && date.minutes() == 0;
  10101. case 'hour':
  10102. return date.hours() == 0;
  10103. case 'weekday': // intentional fall through
  10104. case 'day':
  10105. return date.date() == 1;
  10106. case 'week':
  10107. return date.date() == 1;
  10108. case 'month':
  10109. return date.month() == 0;
  10110. case 'year':
  10111. return false;
  10112. default:
  10113. return false;
  10114. }
  10115. };
  10116. /**
  10117. * Returns formatted text for the minor axislabel, depending on the current
  10118. * date and the scale. For example when scale is MINUTE, the current time is
  10119. * formatted as "hh:mm".
  10120. * @param {Date} [date=this.current] custom date. if not provided, current date is taken
  10121. * @returns {String}
  10122. */
  10123. TimeStep.prototype.getLabelMinor = function(date) {
  10124. if (date == undefined) {
  10125. date = this.current;
  10126. }
  10127. if (date instanceof Date) {
  10128. date = this.moment(date);
  10129. }
  10130. if (typeof this.format.minorLabels === "function") {
  10131. return this.format.minorLabels(date, this.scale, this.step);
  10132. }
  10133. var format = this.format.minorLabels[this.scale];
  10134. // noinspection FallThroughInSwitchStatementJS
  10135. switch (this.scale) {
  10136. case 'week':
  10137. if (this.isMajor() && date.weekday() !== 0) {
  10138. return "";
  10139. }
  10140. default:
  10141. // eslint-disable-line no-fallthrough
  10142. return format && format.length > 0 ? this.moment(date).format(format) : '';
  10143. }
  10144. };
  10145. /**
  10146. * Returns formatted text for the major axis label, depending on the current
  10147. * date and the scale. For example when scale is MINUTE, the major scale is
  10148. * hours, and the hour will be formatted as "hh".
  10149. * @param {Date} [date=this.current] custom date. if not provided, current date is taken
  10150. * @returns {String}
  10151. */
  10152. TimeStep.prototype.getLabelMajor = function(date) {
  10153. if (date == undefined) {
  10154. date = this.current;
  10155. }
  10156. if (date instanceof Date) {
  10157. date = this.moment(date);
  10158. }
  10159. if (typeof this.format.majorLabels === "function") {
  10160. return this.format.majorLabels(date, this.scale, this.step);
  10161. }
  10162. var format = this.format.majorLabels[this.scale];
  10163. return format && format.length > 0 ? this.moment(date).format(format) : '';
  10164. };
  10165. TimeStep.prototype.getClassName = function() {
  10166. var _moment = this.moment;
  10167. var m = this.moment(this.current);
  10168. var current = m.locale ? m.locale('en') : m.lang('en'); // old versions of moment have .lang() function
  10169. var step = this.step;
  10170. var classNames = [];
  10171. /**
  10172. *
  10173. * @param {number} value
  10174. * @returns {String}
  10175. */
  10176. function even(value) {
  10177. return value / step % 2 == 0 ? ' vis-even' : ' vis-odd';
  10178. }
  10179. /**
  10180. *
  10181. * @param {Date} date
  10182. * @returns {String}
  10183. */
  10184. function today(date) {
  10185. if (date.isSame(new Date(), 'day')) {
  10186. return ' vis-today';
  10187. }
  10188. if (date.isSame(_moment().add(1, 'day'), 'day')) {
  10189. return ' vis-tomorrow';
  10190. }
  10191. if (date.isSame(_moment().add(-1, 'day'), 'day')) {
  10192. return ' vis-yesterday';
  10193. }
  10194. return '';
  10195. }
  10196. /**
  10197. *
  10198. * @param {Date} date
  10199. * @returns {String}
  10200. */
  10201. function currentWeek(date) {
  10202. return date.isSame(new Date(), 'week') ? ' vis-current-week' : '';
  10203. }
  10204. /**
  10205. *
  10206. * @param {Date} date
  10207. * @returns {String}
  10208. */
  10209. function currentMonth(date) {
  10210. return date.isSame(new Date(), 'month') ? ' vis-current-month' : '';
  10211. }
  10212. /**
  10213. *
  10214. * @param {Date} date
  10215. * @returns {String}
  10216. */
  10217. function currentYear(date) {
  10218. return date.isSame(new Date(), 'year') ? ' vis-current-year' : '';
  10219. }
  10220. switch (this.scale) {
  10221. case 'millisecond':
  10222. classNames.push(today(current));
  10223. classNames.push(even(current.milliseconds()));
  10224. break;
  10225. case 'second':
  10226. classNames.push(today(current));
  10227. classNames.push(even(current.seconds()));
  10228. break;
  10229. case 'minute':
  10230. classNames.push(today(current));
  10231. classNames.push(even(current.minutes()));
  10232. break;
  10233. case 'hour':
  10234. classNames.push('vis-h' + current.hours() + (this.step == 4 ? '-h' + (current.hours() + 4) : ''));
  10235. classNames.push(today(current));
  10236. classNames.push(even(current.hours()));
  10237. break;
  10238. case 'weekday':
  10239. classNames.push('vis-' + current.format('dddd').toLowerCase());
  10240. classNames.push(today(current));
  10241. classNames.push(currentWeek(current));
  10242. classNames.push(even(current.date()));
  10243. break;
  10244. case 'day':
  10245. classNames.push('vis-day' + current.date());
  10246. classNames.push('vis-' + current.format('MMMM').toLowerCase());
  10247. classNames.push(today(current));
  10248. classNames.push(currentMonth(current));
  10249. classNames.push(this.step <= 2 ? today(current) : '');
  10250. classNames.push(this.step <= 2 ? 'vis-' + current.format('dddd').toLowerCase() : '');
  10251. classNames.push(even(current.date() - 1));
  10252. break;
  10253. case 'week':
  10254. classNames.push('vis-week' + current.format('w'));
  10255. classNames.push(currentWeek(current));
  10256. classNames.push(even(current.week()));
  10257. break;
  10258. case 'month':
  10259. classNames.push('vis-' + current.format('MMMM').toLowerCase());
  10260. classNames.push(currentMonth(current));
  10261. classNames.push(even(current.month()));
  10262. break;
  10263. case 'year':
  10264. classNames.push('vis-year' + current.year());
  10265. classNames.push(currentYear(current));
  10266. classNames.push(even(current.year()));
  10267. break;
  10268. }
  10269. return classNames.filter(String).join(" ");
  10270. };
  10271. module.exports = TimeStep;
  10272. /***/
  10273. }),
  10274. /* 67 */
  10275. /***/
  10276. (function(module, exports, __webpack_require__) {
  10277. "use strict";
  10278. var util = __webpack_require__(2);
  10279. var Component = __webpack_require__(16);
  10280. var moment = __webpack_require__(9);
  10281. var locales = __webpack_require__(98);
  10282. /**
  10283. * A current time bar
  10284. * @param {{range: Range, dom: Object, domProps: Object}} body
  10285. * @param {Object} [options] Available parameters:
  10286. * {Boolean} [showCurrentTime]
  10287. * @constructor CurrentTime
  10288. * @extends Component
  10289. */
  10290. function CurrentTime(body, options) {
  10291. this.body = body;
  10292. // default options
  10293. this.defaultOptions = {
  10294. rtl: false,
  10295. showCurrentTime: true,
  10296. moment: moment,
  10297. locales: locales,
  10298. locale: 'en'
  10299. };
  10300. this.options = util.extend({}, this.defaultOptions);
  10301. this.offset = 0;
  10302. this._create();
  10303. this.setOptions(options);
  10304. }
  10305. CurrentTime.prototype = new Component();
  10306. /**
  10307. * Create the HTML DOM for the current time bar
  10308. * @private
  10309. */
  10310. CurrentTime.prototype._create = function() {
  10311. var bar = document.createElement('div');
  10312. bar.className = 'vis-current-time';
  10313. bar.style.position = 'absolute';
  10314. bar.style.top = '0px';
  10315. bar.style.height = '100%';
  10316. this.bar = bar;
  10317. };
  10318. /**
  10319. * Destroy the CurrentTime bar
  10320. */
  10321. CurrentTime.prototype.destroy = function() {
  10322. this.options.showCurrentTime = false;
  10323. this.redraw(); // will remove the bar from the DOM and stop refreshing
  10324. this.body = null;
  10325. };
  10326. /**
  10327. * Set options for the component. Options will be merged in current options.
  10328. * @param {Object} options Available parameters:
  10329. * {boolean} [showCurrentTime]
  10330. */
  10331. CurrentTime.prototype.setOptions = function(options) {
  10332. if (options) {
  10333. // copy all options that we know
  10334. util.selectiveExtend(['rtl', 'showCurrentTime', 'moment', 'locale', 'locales'], this.options, options);
  10335. }
  10336. };
  10337. /**
  10338. * Repaint the component
  10339. * @return {boolean} Returns true if the component is resized
  10340. */
  10341. CurrentTime.prototype.redraw = function() {
  10342. if (this.options.showCurrentTime) {
  10343. var parent = this.body.dom.backgroundVertical;
  10344. if (this.bar.parentNode != parent) {
  10345. // attach to the dom
  10346. if (this.bar.parentNode) {
  10347. this.bar.parentNode.removeChild(this.bar);
  10348. }
  10349. parent.appendChild(this.bar);
  10350. this.start();
  10351. }
  10352. var now = this.options.moment(new Date().valueOf() + this.offset);
  10353. var x = this.body.util.toScreen(now);
  10354. var locale = this.options.locales[this.options.locale];
  10355. if (!locale) {
  10356. if (!this.warned) {
  10357. console.log('WARNING: options.locales[\'' + this.options.locale + '\'] not found. See http://visjs.org/docs/timeline/#Localization');
  10358. this.warned = true;
  10359. }
  10360. locale = this.options.locales['en']; // fall back on english when not available
  10361. }
  10362. var title = locale.current + ' ' + locale.time + ': ' + now.format('dddd, MMMM Do YYYY, H:mm:ss');
  10363. title = title.charAt(0).toUpperCase() + title.substring(1);
  10364. if (this.options.rtl) {
  10365. this.bar.style.right = x + 'px';
  10366. } else {
  10367. this.bar.style.left = x + 'px';
  10368. }
  10369. this.bar.title = title;
  10370. } else {
  10371. // remove the line from the DOM
  10372. if (this.bar.parentNode) {
  10373. this.bar.parentNode.removeChild(this.bar);
  10374. }
  10375. this.stop();
  10376. }
  10377. return false;
  10378. };
  10379. /**
  10380. * Start auto refreshing the current time bar
  10381. */
  10382. CurrentTime.prototype.start = function() {
  10383. var me = this;
  10384. /**
  10385. * Updates the current time.
  10386. */
  10387. function update() {
  10388. me.stop();
  10389. // determine interval to refresh
  10390. var scale = me.body.range.conversion(me.body.domProps.center.width).scale;
  10391. var interval = 1 / scale / 10;
  10392. if (interval < 30) interval = 30;
  10393. if (interval > 1000) interval = 1000;
  10394. me.redraw();
  10395. me.body.emitter.emit('currentTimeTick');
  10396. // start a renderTimer to adjust for the new time
  10397. me.currentTimeTimer = setTimeout(update, interval);
  10398. }
  10399. update();
  10400. };
  10401. /**
  10402. * Stop auto refreshing the current time bar
  10403. */
  10404. CurrentTime.prototype.stop = function() {
  10405. if (this.currentTimeTimer !== undefined) {
  10406. clearTimeout(this.currentTimeTimer);
  10407. delete this.currentTimeTimer;
  10408. }
  10409. };
  10410. /**
  10411. * Set a current time. This can be used for example to ensure that a client's
  10412. * time is synchronized with a shared server time.
  10413. * @param {Date | string | number} time A Date, unix timestamp, or
  10414. * ISO date string.
  10415. */
  10416. CurrentTime.prototype.setCurrentTime = function(time) {
  10417. var t = util.convert(time, 'Date').valueOf();
  10418. var now = new Date().valueOf();
  10419. this.offset = t - now;
  10420. this.redraw();
  10421. };
  10422. /**
  10423. * Get the current time.
  10424. * @return {Date} Returns the current time.
  10425. */
  10426. CurrentTime.prototype.getCurrentTime = function() {
  10427. return new Date(new Date().valueOf() + this.offset);
  10428. };
  10429. module.exports = CurrentTime;
  10430. /***/
  10431. }),
  10432. /* 68 */
  10433. /***/
  10434. (function(module, exports, __webpack_require__) {
  10435. "use strict";
  10436. var _keys = __webpack_require__(8);
  10437. var _keys2 = _interopRequireDefault(_keys);
  10438. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  10439. var util = __webpack_require__(2);
  10440. var stack = __webpack_require__(100);
  10441. /**
  10442. * @param {number | string} groupId
  10443. * @param {Object} data
  10444. * @param {ItemSet} itemSet
  10445. * @constructor Group
  10446. */
  10447. function Group(groupId, data, itemSet) {
  10448. this.groupId = groupId;
  10449. this.subgroups = {};
  10450. this.subgroupStack = {};
  10451. this.subgroupStackAll = false;
  10452. this.doInnerStack = false;
  10453. this.subgroupIndex = 0;
  10454. this.subgroupOrderer = data && data.subgroupOrder;
  10455. this.itemSet = itemSet;
  10456. this.isVisible = null;
  10457. this.stackDirty = true; // if true, items will be restacked on next redraw
  10458. if (data && data.nestedGroups) {
  10459. this.nestedGroups = data.nestedGroups;
  10460. if (data.showNested == false) {
  10461. this.showNested = false;
  10462. } else {
  10463. this.showNested = true;
  10464. }
  10465. }
  10466. if (data && data.subgroupStack) {
  10467. if (typeof data.subgroupStack === "boolean") {
  10468. this.doInnerStack = data.subgroupStack;
  10469. this.subgroupStackAll = data.subgroupStack;
  10470. } else {
  10471. // We might be doing stacking on specific sub groups, but only
  10472. // if at least one is set to do stacking
  10473. for (var key in data.subgroupStack) {
  10474. this.subgroupStack[key] = data.subgroupStack[key];
  10475. this.doInnerStack = this.doInnerStack || data.subgroupStack[key];
  10476. }
  10477. }
  10478. }
  10479. this.nestedInGroup = null;
  10480. this.dom = {};
  10481. this.props = {
  10482. label: {
  10483. width: 0,
  10484. height: 0
  10485. }
  10486. };
  10487. this.className = null;
  10488. this.items = {}; // items filtered by groupId of this group
  10489. this.visibleItems = []; // items currently visible in window
  10490. this.itemsInRange = []; // items currently in range
  10491. this.orderedItems = {
  10492. byStart: [],
  10493. byEnd: []
  10494. };
  10495. this.checkRangedItems = false; // needed to refresh the ranged items if the window is programatically changed with NO overlap.
  10496. var me = this;
  10497. this.itemSet.body.emitter.on("checkRangedItems", function() {
  10498. me.checkRangedItems = true;
  10499. });
  10500. this._create();
  10501. this.setData(data);
  10502. }
  10503. /**
  10504. * Create DOM elements for the group
  10505. * @private
  10506. */
  10507. Group.prototype._create = function() {
  10508. var label = document.createElement('div');
  10509. if (this.itemSet.options.groupEditable.order) {
  10510. label.className = 'vis-label draggable';
  10511. } else {
  10512. label.className = 'vis-label';
  10513. }
  10514. this.dom.label = label;
  10515. var inner = document.createElement('div');
  10516. inner.className = 'vis-inner';
  10517. label.appendChild(inner);
  10518. this.dom.inner = inner;
  10519. var foreground = document.createElement('div');
  10520. foreground.className = 'vis-group';
  10521. foreground['timeline-group'] = this;
  10522. this.dom.foreground = foreground;
  10523. this.dom.background = document.createElement('div');
  10524. this.dom.background.className = 'vis-group';
  10525. this.dom.axis = document.createElement('div');
  10526. this.dom.axis.className = 'vis-group';
  10527. // create a hidden marker to detect when the Timelines container is attached
  10528. // to the DOM, or the style of a parent of the Timeline is changed from
  10529. // display:none is changed to visible.
  10530. this.dom.marker = document.createElement('div');
  10531. this.dom.marker.style.visibility = 'hidden';
  10532. this.dom.marker.style.position = 'absolute';
  10533. this.dom.marker.innerHTML = '';
  10534. this.dom.background.appendChild(this.dom.marker);
  10535. };
  10536. /**
  10537. * Set the group data for this group
  10538. * @param {Object} data Group data, can contain properties content and className
  10539. */
  10540. Group.prototype.setData = function(data) {
  10541. // update contents
  10542. var content;
  10543. var templateFunction;
  10544. if (this.itemSet.options && this.itemSet.options.groupTemplate) {
  10545. templateFunction = this.itemSet.options.groupTemplate.bind(this);
  10546. content = templateFunction(data, this.dom.inner);
  10547. } else {
  10548. content = data && data.content;
  10549. }
  10550. if (content instanceof Element) {
  10551. this.dom.inner.appendChild(content);
  10552. while (this.dom.inner.firstChild) {
  10553. this.dom.inner.removeChild(this.dom.inner.firstChild);
  10554. }
  10555. this.dom.inner.appendChild(content);
  10556. } else if (content instanceof Object) {
  10557. templateFunction(data, this.dom.inner);
  10558. } else if (content !== undefined && content !== null) {
  10559. this.dom.inner.innerHTML = content;
  10560. } else {
  10561. this.dom.inner.innerHTML = this.groupId || ''; // groupId can be null
  10562. }
  10563. // update title
  10564. this.dom.label.title = data && data.title || '';
  10565. if (!this.dom.inner.firstChild) {
  10566. util.addClassName(this.dom.inner, 'vis-hidden');
  10567. } else {
  10568. util.removeClassName(this.dom.inner, 'vis-hidden');
  10569. }
  10570. if (data && data.nestedGroups) {
  10571. if (!this.nestedGroups || this.nestedGroups != data.nestedGroups) {
  10572. this.nestedGroups = data.nestedGroups;
  10573. }
  10574. if (data.showNested !== undefined || this.showNested === undefined) {
  10575. if (data.showNested == false) {
  10576. this.showNested = false;
  10577. } else {
  10578. this.showNested = true;
  10579. }
  10580. }
  10581. util.addClassName(this.dom.label, 'vis-nesting-group');
  10582. var collapsedDirClassName = this.itemSet.options.rtl ? 'collapsed-rtl' : 'collapsed';
  10583. if (this.showNested) {
  10584. util.removeClassName(this.dom.label, collapsedDirClassName);
  10585. util.addClassName(this.dom.label, 'expanded');
  10586. } else {
  10587. util.removeClassName(this.dom.label, 'expanded');
  10588. util.addClassName(this.dom.label, collapsedDirClassName);
  10589. }
  10590. } else if (this.nestedGroups) {
  10591. this.nestedGroups = null;
  10592. collapsedDirClassName = this.itemSet.options.rtl ? 'collapsed-rtl' : 'collapsed';
  10593. util.removeClassName(this.dom.label, collapsedDirClassName);
  10594. util.removeClassName(this.dom.label, 'expanded');
  10595. util.removeClassName(this.dom.label, 'vis-nesting-group');
  10596. }
  10597. if (data && data.nestedInGroup) {
  10598. util.addClassName(this.dom.label, 'vis-nested-group');
  10599. if (this.itemSet.options && this.itemSet.options.rtl) {
  10600. this.dom.inner.style.paddingRight = '30px';
  10601. } else {
  10602. this.dom.inner.style.paddingLeft = '30px';
  10603. }
  10604. }
  10605. // update className
  10606. var className = data && data.className || null;
  10607. if (className != this.className) {
  10608. if (this.className) {
  10609. util.removeClassName(this.dom.label, this.className);
  10610. util.removeClassName(this.dom.foreground, this.className);
  10611. util.removeClassName(this.dom.background, this.className);
  10612. util.removeClassName(this.dom.axis, this.className);
  10613. }
  10614. util.addClassName(this.dom.label, className);
  10615. util.addClassName(this.dom.foreground, className);
  10616. util.addClassName(this.dom.background, className);
  10617. util.addClassName(this.dom.axis, className);
  10618. this.className = className;
  10619. }
  10620. // update style
  10621. if (this.style) {
  10622. util.removeCssText(this.dom.label, this.style);
  10623. this.style = null;
  10624. }
  10625. if (data && data.style) {
  10626. util.addCssText(this.dom.label, data.style);
  10627. this.style = data.style;
  10628. }
  10629. };
  10630. /**
  10631. * Get the width of the group label
  10632. * @return {number} width
  10633. */
  10634. Group.prototype.getLabelWidth = function() {
  10635. return this.props.label.width;
  10636. };
  10637. Group.prototype._didMarkerHeightChange = function() {
  10638. var markerHeight = this.dom.marker.clientHeight;
  10639. if (markerHeight != this.lastMarkerHeight) {
  10640. this.lastMarkerHeight = markerHeight;
  10641. var redrawQueue = {};
  10642. var redrawQueueLength = 0;
  10643. util.forEach(this.items, function(item, key) {
  10644. item.dirty = true;
  10645. if (item.displayed) {
  10646. var returnQueue = true;
  10647. redrawQueue[key] = item.redraw(returnQueue);
  10648. redrawQueueLength = redrawQueue[key].length;
  10649. }
  10650. });
  10651. var needRedraw = redrawQueueLength > 0;
  10652. if (needRedraw) {
  10653. // redraw all regular items
  10654. for (var i = 0; i < redrawQueueLength; i++) {
  10655. util.forEach(redrawQueue, function(fns) {
  10656. fns[i]();
  10657. });
  10658. }
  10659. }
  10660. return true;
  10661. }
  10662. };
  10663. Group.prototype._calculateGroupSizeAndPosition = function() {
  10664. var offsetTop = this.dom.foreground.offsetTop;
  10665. var offsetLeft = this.dom.foreground.offsetLeft;
  10666. var offsetWidth = this.dom.foreground.offsetWidth;
  10667. this.top = offsetTop;
  10668. this.right = offsetLeft;
  10669. this.width = offsetWidth;
  10670. };
  10671. Group.prototype._redrawItems = function(forceRestack, lastIsVisible, margin, range) {
  10672. var restack = forceRestack || this.stackDirty || this.isVisible && !lastIsVisible;
  10673. // if restacking, reposition visible items vertically
  10674. if (restack) {
  10675. var visibleSubgroups = {};
  10676. var subgroup = null;
  10677. if (typeof this.itemSet.options.order === 'function') {
  10678. // a custom order function
  10679. // brute force restack of all items
  10680. // show all items
  10681. var me = this;
  10682. var limitSize = false;
  10683. var redrawQueue = {};
  10684. var redrawQueueLength = 0;
  10685. util.forEach(this.items, function(item, key) {
  10686. if (!item.displayed) {
  10687. var returnQueue = true;
  10688. redrawQueue[key] = item.redraw(returnQueue);
  10689. redrawQueueLength = redrawQueue[key].length;
  10690. me.visibleItems.push(item);
  10691. }
  10692. });
  10693. var needRedraw = redrawQueueLength > 0;
  10694. if (needRedraw) {
  10695. // redraw all regular items
  10696. for (var i = 0; i < redrawQueueLength; i++) {
  10697. util.forEach(redrawQueue, function(fns) {
  10698. fns[i]();
  10699. });
  10700. }
  10701. }
  10702. util.forEach(this.items, function(item) {
  10703. item.repositionX(limitSize);
  10704. });
  10705. if (this.doInnerStack && this.itemSet.options.stackSubgroups) {
  10706. // Order the items within each subgroup
  10707. for (subgroup in this.subgroups) {
  10708. visibleSubgroups[subgroup] = this.subgroups[subgroup].items.slice().sort(function(a, b) {
  10709. return me.itemSet.options.order(a.data, b.data);
  10710. });
  10711. }
  10712. stack.stackSubgroupsWithInnerStack(visibleSubgroups, margin, this.subgroups);
  10713. } else {
  10714. // order all items and force a restacking
  10715. var customOrderedItems = this.orderedItems.byStart.slice().sort(function(a, b) {
  10716. return me.itemSet.options.order(a.data, b.data);
  10717. });
  10718. stack.stack(customOrderedItems, margin, true /* restack=true */ );
  10719. }
  10720. this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range);
  10721. } else {
  10722. // no custom order function, lazy stacking
  10723. this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range);
  10724. if (this.itemSet.options.stack) {
  10725. if (this.doInnerStack && this.itemSet.options.stackSubgroups) {
  10726. for (subgroup in this.subgroups) {
  10727. visibleSubgroups[subgroup] = this.subgroups[subgroup].items;
  10728. }
  10729. stack.stackSubgroupsWithInnerStack(visibleSubgroups, margin, this.subgroups);
  10730. } else {
  10731. // TODO: ugly way to access options...
  10732. stack.stack(this.visibleItems, margin, true /* restack=true */ );
  10733. }
  10734. } else {
  10735. // no stacking
  10736. stack.nostack(this.visibleItems, margin, this.subgroups, this.itemSet.options.stackSubgroups);
  10737. }
  10738. }
  10739. this.stackDirty = false;
  10740. }
  10741. };
  10742. Group.prototype._didResize = function(resized, height) {
  10743. resized = util.updateProperty(this, 'height', height) || resized;
  10744. // recalculate size of label
  10745. var labelWidth = this.dom.inner.clientWidth;
  10746. var labelHeight = this.dom.inner.clientHeight;
  10747. resized = util.updateProperty(this.props.label, 'width', labelWidth) || resized;
  10748. resized = util.updateProperty(this.props.label, 'height', labelHeight) || resized;
  10749. return resized;
  10750. };
  10751. Group.prototype._applyGroupHeight = function(height) {
  10752. this.dom.background.style.height = height + 'px';
  10753. this.dom.foreground.style.height = height + 'px';
  10754. this.dom.label.style.height = height + 'px';
  10755. };
  10756. // update vertical position of items after they are re-stacked and the height of the group is calculated
  10757. Group.prototype._updateItemsVerticalPosition = function(margin) {
  10758. for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
  10759. var item = this.visibleItems[i];
  10760. item.repositionY(margin);
  10761. if (!this.isVisible && this.groupId != "__background__") {
  10762. if (item.displayed) item.hide();
  10763. }
  10764. }
  10765. };
  10766. /**
  10767. * Repaint this group
  10768. * @param {{start: number, end: number}} range
  10769. * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
  10770. * @param {boolean} [forceRestack=false] Force restacking of all items
  10771. * @param {boolean} [returnQueue=false] return the queue or if the group resized
  10772. * @return {boolean} Returns true if the group is resized or the redraw queue if returnQueue=true
  10773. */
  10774. Group.prototype.redraw = function(range, margin, forceRestack, returnQueue) {
  10775. var resized = false;
  10776. var lastIsVisible = this.isVisible;
  10777. var height;
  10778. var queue = [
  10779. // force recalculation of the height of the items when the marker height changed
  10780. // (due to the Timeline being attached to the DOM or changed from display:none to visible)
  10781. function() {
  10782. forceRestack = this._didMarkerHeightChange.bind(this);
  10783. }.bind(this),
  10784. // recalculate the height of the subgroups
  10785. this._updateSubGroupHeights.bind(this, margin),
  10786. // calculate actual size and position
  10787. this._calculateGroupSizeAndPosition.bind(this),
  10788. // check if group is visible
  10789. function() {
  10790. this.isVisible = this._isGroupVisible.bind(this)(range, margin);
  10791. }.bind(this),
  10792. // redraw Items if needed
  10793. function() {
  10794. this._redrawItems.bind(this)(forceRestack, lastIsVisible, margin, range);
  10795. }.bind(this),
  10796. // update subgroups
  10797. this._updateSubgroupsSizes.bind(this),
  10798. // recalculate the height of the group
  10799. function() {
  10800. height = this._calculateHeight.bind(this)(margin);
  10801. }.bind(this),
  10802. // calculate actual size and position again
  10803. this._calculateGroupSizeAndPosition.bind(this),
  10804. // check if resized
  10805. function() {
  10806. resized = this._didResize.bind(this)(resized, height);
  10807. }.bind(this),
  10808. // apply group height
  10809. function() {
  10810. this._applyGroupHeight.bind(this)(height);
  10811. }.bind(this),
  10812. // update vertical position of items after they are re-stacked and the height of the group is calculated
  10813. function() {
  10814. this._updateItemsVerticalPosition.bind(this)(margin);
  10815. }.bind(this),
  10816. function() {
  10817. if (!this.isVisible && this.height) {
  10818. resized = false;
  10819. }
  10820. return resized;
  10821. }
  10822. ];
  10823. if (returnQueue) {
  10824. return queue;
  10825. } else {
  10826. var result;
  10827. queue.forEach(function(fn) {
  10828. result = fn();
  10829. });
  10830. return result;
  10831. }
  10832. };
  10833. /**
  10834. * recalculate the height of the subgroups
  10835. *
  10836. * @param {{item: vis.Item}} margin
  10837. * @private
  10838. */
  10839. Group.prototype._updateSubGroupHeights = function(margin) {
  10840. if ((0, _keys2['default'])(this.subgroups).length > 0) {
  10841. var me = this;
  10842. this.resetSubgroups();
  10843. util.forEach(this.visibleItems, function(item) {
  10844. if (item.data.subgroup !== undefined) {
  10845. me.subgroups[item.data.subgroup].height = Math.max(me.subgroups[item.data.subgroup].height, item.height + margin.item.vertical);
  10846. me.subgroups[item.data.subgroup].visible = true;
  10847. }
  10848. });
  10849. }
  10850. };
  10851. /**
  10852. * check if group is visible
  10853. *
  10854. * @param {vis.Range} range
  10855. * @param {{axis: vis.DataAxis}} margin
  10856. * @returns {boolean} is visible
  10857. * @private
  10858. */
  10859. Group.prototype._isGroupVisible = function(range, margin) {
  10860. return this.top <= range.body.domProps.centerContainer.height - range.body.domProps.scrollTop + margin.axis && this.top + this.height + margin.axis >= -range.body.domProps.scrollTop;
  10861. };
  10862. /**
  10863. * recalculate the height of the group
  10864. * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
  10865. * @returns {number} Returns the height
  10866. * @private
  10867. */
  10868. Group.prototype._calculateHeight = function(margin) {
  10869. // recalculate the height of the group
  10870. var height;
  10871. var itemsInRange = this.visibleItems;
  10872. if (itemsInRange.length > 0) {
  10873. var min = itemsInRange[0].top;
  10874. var max = itemsInRange[0].top + itemsInRange[0].height;
  10875. util.forEach(itemsInRange, function(item) {
  10876. min = Math.min(min, item.top);
  10877. max = Math.max(max, item.top + item.height);
  10878. });
  10879. if (min > margin.axis) {
  10880. // there is an empty gap between the lowest item and the axis
  10881. var offset = min - margin.axis;
  10882. max -= offset;
  10883. util.forEach(itemsInRange, function(item) {
  10884. item.top -= offset;
  10885. });
  10886. }
  10887. height = max + margin.item.vertical / 2;
  10888. } else {
  10889. height = 0;
  10890. }
  10891. height = Math.max(height, this.props.label.height);
  10892. return height;
  10893. };
  10894. /**
  10895. * Show this group: attach to the DOM
  10896. */
  10897. Group.prototype.show = function() {
  10898. if (!this.dom.label.parentNode) {
  10899. this.itemSet.dom.labelSet.appendChild(this.dom.label);
  10900. }
  10901. if (!this.dom.foreground.parentNode) {
  10902. this.itemSet.dom.foreground.appendChild(this.dom.foreground);
  10903. }
  10904. if (!this.dom.background.parentNode) {
  10905. this.itemSet.dom.background.appendChild(this.dom.background);
  10906. }
  10907. if (!this.dom.axis.parentNode) {
  10908. this.itemSet.dom.axis.appendChild(this.dom.axis);
  10909. }
  10910. };
  10911. /**
  10912. * Hide this group: remove from the DOM
  10913. */
  10914. Group.prototype.hide = function() {
  10915. var label = this.dom.label;
  10916. if (label.parentNode) {
  10917. label.parentNode.removeChild(label);
  10918. }
  10919. var foreground = this.dom.foreground;
  10920. if (foreground.parentNode) {
  10921. foreground.parentNode.removeChild(foreground);
  10922. }
  10923. var background = this.dom.background;
  10924. if (background.parentNode) {
  10925. background.parentNode.removeChild(background);
  10926. }
  10927. var axis = this.dom.axis;
  10928. if (axis.parentNode) {
  10929. axis.parentNode.removeChild(axis);
  10930. }
  10931. };
  10932. /**
  10933. * Add an item to the group
  10934. * @param {Item} item
  10935. */
  10936. Group.prototype.add = function(item) {
  10937. this.items[item.id] = item;
  10938. item.setParent(this);
  10939. this.stackDirty = true;
  10940. // add to
  10941. if (item.data.subgroup !== undefined) {
  10942. this._addToSubgroup(item);
  10943. this.orderSubgroups();
  10944. }
  10945. if (this.visibleItems.indexOf(item) == -1) {
  10946. var range = this.itemSet.body.range; // TODO: not nice accessing the range like this
  10947. this._checkIfVisible(item, this.visibleItems, range);
  10948. }
  10949. };
  10950. Group.prototype._addToSubgroup = function(item, subgroupId) {
  10951. subgroupId = subgroupId || item.data.subgroup;
  10952. if (subgroupId != undefined && this.subgroups[subgroupId] === undefined) {
  10953. this.subgroups[subgroupId] = {
  10954. height: 0,
  10955. top: 0,
  10956. start: item.data.start,
  10957. end: item.data.end || item.data.start,
  10958. visible: false,
  10959. index: this.subgroupIndex,
  10960. items: [],
  10961. stack: this.subgroupStackAll || this.subgroupStack[subgroupId] || false
  10962. };
  10963. this.subgroupIndex++;
  10964. }
  10965. if (new Date(item.data.start) < new Date(this.subgroups[subgroupId].start)) {
  10966. this.subgroups[subgroupId].start = item.data.start;
  10967. }
  10968. var itemEnd = item.data.end || item.data.start;
  10969. if (new Date(itemEnd) > new Date(this.subgroups[subgroupId].end)) {
  10970. this.subgroups[subgroupId].end = itemEnd;
  10971. }
  10972. this.subgroups[subgroupId].items.push(item);
  10973. };
  10974. Group.prototype._updateSubgroupsSizes = function() {
  10975. var me = this;
  10976. if (me.subgroups) {
  10977. for (var subgroup in me.subgroups) {
  10978. var initialEnd = me.subgroups[subgroup].items[0].data.end || me.subgroups[subgroup].items[0].data.start;
  10979. var newStart = me.subgroups[subgroup].items[0].data.start;
  10980. var newEnd = initialEnd - 1;
  10981. me.subgroups[subgroup].items.forEach(function(item) {
  10982. if (new Date(item.data.start) < new Date(newStart)) {
  10983. newStart = item.data.start;
  10984. }
  10985. var itemEnd = item.data.end || item.data.start;
  10986. if (new Date(itemEnd) > new Date(newEnd)) {
  10987. newEnd = itemEnd;
  10988. }
  10989. });
  10990. me.subgroups[subgroup].start = newStart;
  10991. me.subgroups[subgroup].end = new Date(newEnd - 1); // -1 to compensate for colliding end to start subgroups;
  10992. }
  10993. }
  10994. };
  10995. Group.prototype.orderSubgroups = function() {
  10996. if (this.subgroupOrderer !== undefined) {
  10997. var sortArray = [];
  10998. var subgroup;
  10999. if (typeof this.subgroupOrderer == 'string') {
  11000. for (subgroup in this.subgroups) {
  11001. sortArray.push({ subgroup: subgroup, sortField: this.subgroups[subgroup].items[0].data[this.subgroupOrderer] });
  11002. }
  11003. sortArray.sort(function(a, b) {
  11004. return a.sortField - b.sortField;
  11005. });
  11006. } else if (typeof this.subgroupOrderer == 'function') {
  11007. for (subgroup in this.subgroups) {
  11008. sortArray.push(this.subgroups[subgroup].items[0].data);
  11009. }
  11010. sortArray.sort(this.subgroupOrderer);
  11011. }
  11012. if (sortArray.length > 0) {
  11013. for (var i = 0; i < sortArray.length; i++) {
  11014. this.subgroups[sortArray[i].subgroup].index = i;
  11015. }
  11016. }
  11017. }
  11018. };
  11019. Group.prototype.resetSubgroups = function() {
  11020. for (var subgroup in this.subgroups) {
  11021. if (this.subgroups.hasOwnProperty(subgroup)) {
  11022. this.subgroups[subgroup].visible = false;
  11023. this.subgroups[subgroup].height = 0;
  11024. }
  11025. }
  11026. };
  11027. /**
  11028. * Remove an item from the group
  11029. * @param {Item} item
  11030. */
  11031. Group.prototype.remove = function(item) {
  11032. delete this.items[item.id];
  11033. item.setParent(null);
  11034. this.stackDirty = true;
  11035. // remove from visible items
  11036. var index = this.visibleItems.indexOf(item);
  11037. if (index != -1) this.visibleItems.splice(index, 1);
  11038. if (item.data.subgroup !== undefined) {
  11039. this._removeFromSubgroup(item);
  11040. this.orderSubgroups();
  11041. }
  11042. };
  11043. Group.prototype._removeFromSubgroup = function(item, subgroupId) {
  11044. subgroupId = subgroupId || item.data.subgroup;
  11045. if (subgroupId != undefined) {
  11046. var subgroup = this.subgroups[subgroupId];
  11047. if (subgroup) {
  11048. var itemIndex = subgroup.items.indexOf(item);
  11049. // Check the item is actually in this subgroup. How should items not in the group be handled?
  11050. if (itemIndex >= 0) {
  11051. subgroup.items.splice(itemIndex, 1);
  11052. if (!subgroup.items.length) {
  11053. delete this.subgroups[subgroupId];
  11054. } else {
  11055. this._updateSubgroupsSizes();
  11056. }
  11057. }
  11058. }
  11059. }
  11060. };
  11061. /**
  11062. * Remove an item from the corresponding DataSet
  11063. * @param {Item} item
  11064. */
  11065. Group.prototype.removeFromDataSet = function(item) {
  11066. this.itemSet.removeItem(item.id);
  11067. };
  11068. /**
  11069. * Reorder the items
  11070. */
  11071. Group.prototype.order = function() {
  11072. var array = util.toArray(this.items);
  11073. var startArray = [];
  11074. var endArray = [];
  11075. for (var i = 0; i < array.length; i++) {
  11076. if (array[i].data.end !== undefined) {
  11077. endArray.push(array[i]);
  11078. }
  11079. startArray.push(array[i]);
  11080. }
  11081. this.orderedItems = {
  11082. byStart: startArray,
  11083. byEnd: endArray
  11084. };
  11085. stack.orderByStart(this.orderedItems.byStart);
  11086. stack.orderByEnd(this.orderedItems.byEnd);
  11087. };
  11088. /**
  11089. * Update the visible items
  11090. * @param {{byStart: Item[], byEnd: Item[]}} orderedItems All items ordered by start date and by end date
  11091. * @param {Item[]} oldVisibleItems The previously visible items.
  11092. * @param {{start: number, end: number}} range Visible range
  11093. * @return {Item[]} visibleItems The new visible items.
  11094. * @private
  11095. */
  11096. Group.prototype._updateItemsInRange = function(orderedItems, oldVisibleItems, range) {
  11097. var visibleItems = [];
  11098. var visibleItemsLookup = {}; // we keep this to quickly look up if an item already exists in the list without using indexOf on visibleItems
  11099. var interval = (range.end - range.start) / 4;
  11100. var lowerBound = range.start - interval;
  11101. var upperBound = range.end + interval;
  11102. // this function is used to do the binary search.
  11103. var searchFunction = function searchFunction(value) {
  11104. if (value < lowerBound) {
  11105. return -1;
  11106. } else if (value <= upperBound) {
  11107. return 0;
  11108. } else {
  11109. return 1;
  11110. }
  11111. };
  11112. // first check if the items that were in view previously are still in view.
  11113. // IMPORTANT: this handles the case for the items with startdate before the window and enddate after the window!
  11114. // also cleans up invisible items.
  11115. if (oldVisibleItems.length > 0) {
  11116. for (var i = 0; i < oldVisibleItems.length; i++) {
  11117. this._checkIfVisibleWithReference(oldVisibleItems[i], visibleItems, visibleItemsLookup, range);
  11118. }
  11119. }
  11120. // we do a binary search for the items that have only start values.
  11121. var initialPosByStart = util.binarySearchCustom(orderedItems.byStart, searchFunction, 'data', 'start');
  11122. // trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the start values.
  11123. this._traceVisible(initialPosByStart, orderedItems.byStart, visibleItems, visibleItemsLookup, function(item) {
  11124. return item.data.start < lowerBound || item.data.start > upperBound;
  11125. });
  11126. // if the window has changed programmatically without overlapping the old window, the ranged items with start < lowerBound and end > upperbound are not shown.
  11127. // We therefore have to brute force check all items in the byEnd list
  11128. if (this.checkRangedItems == true) {
  11129. this.checkRangedItems = false;
  11130. for (i = 0; i < orderedItems.byEnd.length; i++) {
  11131. this._checkIfVisibleWithReference(orderedItems.byEnd[i], visibleItems, visibleItemsLookup, range);
  11132. }
  11133. } else {
  11134. // we do a binary search for the items that have defined end times.
  11135. var initialPosByEnd = util.binarySearchCustom(orderedItems.byEnd, searchFunction, 'data', 'end');
  11136. // trace the visible items from the inital start pos both ways until an invisible item is found, we only look at the end values.
  11137. this._traceVisible(initialPosByEnd, orderedItems.byEnd, visibleItems, visibleItemsLookup, function(item) {
  11138. return item.data.end < lowerBound || item.data.end > upperBound;
  11139. });
  11140. }
  11141. var redrawQueue = {};
  11142. var redrawQueueLength = 0;
  11143. for (i = 0; i < visibleItems.length; i++) {
  11144. var item = visibleItems[i];
  11145. if (!item.displayed) {
  11146. var returnQueue = true;
  11147. redrawQueue[i] = item.redraw(returnQueue);
  11148. redrawQueueLength = redrawQueue[i].length;
  11149. }
  11150. }
  11151. var needRedraw = redrawQueueLength > 0;
  11152. if (needRedraw) {
  11153. // redraw all regular items
  11154. for (var j = 0; j < redrawQueueLength; j++) {
  11155. util.forEach(redrawQueue, function(fns) {
  11156. fns[j]();
  11157. });
  11158. }
  11159. }
  11160. for (i = 0; i < visibleItems.length; i++) {
  11161. visibleItems[i].repositionX();
  11162. }
  11163. return visibleItems;
  11164. };
  11165. Group.prototype._traceVisible = function(initialPos, items, visibleItems, visibleItemsLookup, breakCondition) {
  11166. if (initialPos != -1) {
  11167. var i, item;
  11168. for (i = initialPos; i >= 0; i--) {
  11169. item = items[i];
  11170. if (breakCondition(item)) {
  11171. break;
  11172. } else {
  11173. if (visibleItemsLookup[item.id] === undefined) {
  11174. visibleItemsLookup[item.id] = true;
  11175. visibleItems.push(item);
  11176. }
  11177. }
  11178. }
  11179. for (i = initialPos + 1; i < items.length; i++) {
  11180. item = items[i];
  11181. if (breakCondition(item)) {
  11182. break;
  11183. } else {
  11184. if (visibleItemsLookup[item.id] === undefined) {
  11185. visibleItemsLookup[item.id] = true;
  11186. visibleItems.push(item);
  11187. }
  11188. }
  11189. }
  11190. }
  11191. };
  11192. /**
  11193. * this function is very similar to the _checkIfInvisible() but it does not
  11194. * return booleans, hides the item if it should not be seen and always adds to
  11195. * the visibleItems.
  11196. * this one is for brute forcing and hiding.
  11197. *
  11198. * @param {Item} item
  11199. * @param {Array} visibleItems
  11200. * @param {{start:number, end:number}} range
  11201. * @private
  11202. */
  11203. Group.prototype._checkIfVisible = function(item, visibleItems, range) {
  11204. if (item.isVisible(range)) {
  11205. if (!item.displayed) item.show();
  11206. // reposition item horizontally
  11207. item.repositionX();
  11208. visibleItems.push(item);
  11209. } else {
  11210. if (item.displayed) item.hide();
  11211. }
  11212. };
  11213. /**
  11214. * this function is very similar to the _checkIfInvisible() but it does not
  11215. * return booleans, hides the item if it should not be seen and always adds to
  11216. * the visibleItems.
  11217. * this one is for brute forcing and hiding.
  11218. *
  11219. * @param {Item} item
  11220. * @param {Array.<vis.Item>} visibleItems
  11221. * @param {Object<number, boolean>} visibleItemsLookup
  11222. * @param {{start:number, end:number}} range
  11223. * @private
  11224. */
  11225. Group.prototype._checkIfVisibleWithReference = function(item, visibleItems, visibleItemsLookup, range) {
  11226. if (item.isVisible(range)) {
  11227. if (visibleItemsLookup[item.id] === undefined) {
  11228. visibleItemsLookup[item.id] = true;
  11229. visibleItems.push(item);
  11230. }
  11231. } else {
  11232. if (item.displayed) item.hide();
  11233. }
  11234. };
  11235. Group.prototype.changeSubgroup = function(item, oldSubgroup, newSubgroup) {
  11236. this._removeFromSubgroup(item, oldSubgroup);
  11237. this._addToSubgroup(item, newSubgroup);
  11238. this.orderSubgroups();
  11239. };
  11240. module.exports = Group;
  11241. /***/
  11242. }),
  11243. /* 69 */
  11244. /***/
  11245. (function(module, exports, __webpack_require__) {
  11246. "use strict";
  11247. var _create = __webpack_require__(29);
  11248. var _create2 = _interopRequireDefault(_create);
  11249. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  11250. var Group = __webpack_require__(68);
  11251. /**
  11252. * @constructor BackgroundGroup
  11253. * @param {number | string} groupId
  11254. * @param {Object} data
  11255. * @param {ItemSet} itemSet
  11256. * @extends Group
  11257. */
  11258. function BackgroundGroup(groupId, data, itemSet) {
  11259. Group.call(this, groupId, data, itemSet);
  11260. this.width = 0;
  11261. this.height = 0;
  11262. this.top = 0;
  11263. this.left = 0;
  11264. }
  11265. BackgroundGroup.prototype = (0, _create2['default'])(Group.prototype);
  11266. /**
  11267. * Repaint this group
  11268. * @param {{start: number, end: number}} range
  11269. * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
  11270. * @param {boolean} [forceRestack=false] Force restacking of all items
  11271. * @return {boolean} Returns true if the group is resized
  11272. */
  11273. BackgroundGroup.prototype.redraw = function(range, margin, forceRestack) {
  11274. // eslint-disable-line no-unused-vars
  11275. var resized = false;
  11276. this.visibleItems = this._updateItemsInRange(this.orderedItems, this.visibleItems, range);
  11277. // calculate actual size
  11278. this.width = this.dom.background.offsetWidth;
  11279. // apply new height (just always zero for BackgroundGroup
  11280. this.dom.background.style.height = '0';
  11281. // update vertical position of items after they are re-stacked and the height of the group is calculated
  11282. for (var i = 0, ii = this.visibleItems.length; i < ii; i++) {
  11283. var item = this.visibleItems[i];
  11284. item.repositionY(margin);
  11285. }
  11286. return resized;
  11287. };
  11288. /**
  11289. * Show this group: attach to the DOM
  11290. */
  11291. BackgroundGroup.prototype.show = function() {
  11292. if (!this.dom.background.parentNode) {
  11293. this.itemSet.dom.background.appendChild(this.dom.background);
  11294. }
  11295. };
  11296. module.exports = BackgroundGroup;
  11297. /***/
  11298. }),
  11299. /* 70 */
  11300. /***/
  11301. (function(module, exports, __webpack_require__) {
  11302. "use strict";
  11303. var Item = __webpack_require__(38);
  11304. /**
  11305. * @constructor RangeItem
  11306. * @extends Item
  11307. * @param {Object} data Object containing parameters start, end
  11308. * content, className.
  11309. * @param {{toScreen: function, toTime: function}} conversion
  11310. * Conversion functions from time to screen and vice versa
  11311. * @param {Object} [options] Configuration options
  11312. * // TODO: describe options
  11313. */
  11314. function RangeItem(data, conversion, options) {
  11315. this.props = {
  11316. content: {
  11317. width: 0
  11318. }
  11319. };
  11320. this.overflow = false; // if contents can overflow (css styling), this flag is set to true
  11321. this.options = options;
  11322. // validate data
  11323. if (data) {
  11324. if (data.start == undefined) {
  11325. throw new Error('Property "start" missing in item ' + data.id);
  11326. }
  11327. if (data.end == undefined) {
  11328. throw new Error('Property "end" missing in item ' + data.id);
  11329. }
  11330. }
  11331. Item.call(this, data, conversion, options);
  11332. }
  11333. RangeItem.prototype = new Item(null, null, null);
  11334. RangeItem.prototype.baseClassName = 'vis-item vis-range';
  11335. /**
  11336. * Check whether this item is visible inside given range
  11337. *
  11338. * @param {vis.Range} range with a timestamp for start and end
  11339. * @returns {boolean} True if visible
  11340. */
  11341. RangeItem.prototype.isVisible = function(range) {
  11342. // determine visibility
  11343. return this.data.start < range.end && this.data.end > range.start;
  11344. };
  11345. RangeItem.prototype._createDomElement = function() {
  11346. if (!this.dom) {
  11347. // create DOM
  11348. this.dom = {};
  11349. // background box
  11350. this.dom.box = document.createElement('div');
  11351. // className is updated in redraw()
  11352. // frame box (to prevent the item contents from overflowing)
  11353. this.dom.frame = document.createElement('div');
  11354. this.dom.frame.className = 'vis-item-overflow';
  11355. this.dom.box.appendChild(this.dom.frame);
  11356. // visible frame box (showing the frame that is always visible)
  11357. this.dom.visibleFrame = document.createElement('div');
  11358. this.dom.visibleFrame.className = 'vis-item-visible-frame';
  11359. this.dom.box.appendChild(this.dom.visibleFrame);
  11360. // contents box
  11361. this.dom.content = document.createElement('div');
  11362. this.dom.content.className = 'vis-item-content';
  11363. this.dom.frame.appendChild(this.dom.content);
  11364. // attach this item as attribute
  11365. this.dom.box['timeline-item'] = this;
  11366. this.dirty = true;
  11367. }
  11368. };
  11369. RangeItem.prototype._appendDomElement = function() {
  11370. if (!this.parent) {
  11371. throw new Error('Cannot redraw item: no parent attached');
  11372. }
  11373. if (!this.dom.box.parentNode) {
  11374. var foreground = this.parent.dom.foreground;
  11375. if (!foreground) {
  11376. throw new Error('Cannot redraw item: parent has no foreground container element');
  11377. }
  11378. foreground.appendChild(this.dom.box);
  11379. }
  11380. this.displayed = true;
  11381. };
  11382. RangeItem.prototype._updateDirtyDomComponents = function() {
  11383. // update dirty DOM. An item is marked dirty when:
  11384. // - the item is not yet rendered
  11385. // - the item's data is changed
  11386. // - the item is selected/deselected
  11387. if (this.dirty) {
  11388. this._updateContents(this.dom.content);
  11389. this._updateDataAttributes(this.dom.box);
  11390. this._updateStyle(this.dom.box);
  11391. var editable = this.editable.updateTime || this.editable.updateGroup;
  11392. // update class
  11393. var className = (this.data.className ? ' ' + this.data.className : '') + (this.selected ? ' vis-selected' : '') + (editable ? ' vis-editable' : ' vis-readonly');
  11394. this.dom.box.className = this.baseClassName + className;
  11395. // turn off max-width to be able to calculate the real width
  11396. // this causes an extra browser repaint/reflow, but so be it
  11397. this.dom.content.style.maxWidth = 'none';
  11398. }
  11399. };
  11400. RangeItem.prototype._getDomComponentsSizes = function() {
  11401. // determine from css whether this box has overflow
  11402. this.overflow = window.getComputedStyle(this.dom.frame).overflow !== 'hidden';
  11403. return {
  11404. content: {
  11405. width: this.dom.content.offsetWidth
  11406. },
  11407. box: {
  11408. height: this.dom.box.offsetHeight
  11409. }
  11410. };
  11411. };
  11412. RangeItem.prototype._updateDomComponentsSizes = function(sizes) {
  11413. this.props.content.width = sizes.content.width;
  11414. this.height = sizes.box.height;
  11415. this.dom.content.style.maxWidth = '';
  11416. this.dirty = false;
  11417. };
  11418. RangeItem.prototype._repaintDomAdditionals = function() {
  11419. this._repaintOnItemUpdateTimeTooltip(this.dom.box);
  11420. this._repaintDeleteButton(this.dom.box);
  11421. this._repaintDragCenter();
  11422. this._repaintDragLeft();
  11423. this._repaintDragRight();
  11424. };
  11425. /**
  11426. * Repaint the item
  11427. * @param {boolean} [returnQueue=false] return the queue
  11428. * @return {boolean} the redraw queue if returnQueue=true
  11429. */
  11430. RangeItem.prototype.redraw = function(returnQueue) {
  11431. var sizes;
  11432. var queue = [
  11433. // create item DOM
  11434. this._createDomElement.bind(this),
  11435. // append DOM to parent DOM
  11436. this._appendDomElement.bind(this),
  11437. // update dirty DOM
  11438. this._updateDirtyDomComponents.bind(this),
  11439. function() {
  11440. if (this.dirty) {
  11441. sizes = this._getDomComponentsSizes.bind(this)();
  11442. }
  11443. }.bind(this),
  11444. function() {
  11445. if (this.dirty) {
  11446. this._updateDomComponentsSizes.bind(this)(sizes);
  11447. }
  11448. }.bind(this),
  11449. // repaint DOM additionals
  11450. this._repaintDomAdditionals.bind(this)
  11451. ];
  11452. if (returnQueue) {
  11453. return queue;
  11454. } else {
  11455. var result;
  11456. queue.forEach(function(fn) {
  11457. result = fn();
  11458. });
  11459. return result;
  11460. }
  11461. };
  11462. /**
  11463. * Show the item in the DOM (when not already visible). The items DOM will
  11464. * be created when needed.
  11465. */
  11466. RangeItem.prototype.show = function() {
  11467. if (!this.displayed) {
  11468. this.redraw();
  11469. }
  11470. };
  11471. /**
  11472. * Hide the item from the DOM (when visible)
  11473. */
  11474. RangeItem.prototype.hide = function() {
  11475. if (this.displayed) {
  11476. var box = this.dom.box;
  11477. if (box.parentNode) {
  11478. box.parentNode.removeChild(box);
  11479. }
  11480. this.displayed = false;
  11481. }
  11482. };
  11483. /**
  11484. * Reposition the item horizontally
  11485. * @param {boolean} [limitSize=true] If true (default), the width of the range
  11486. * item will be limited, as the browser cannot
  11487. * display very wide divs. This means though
  11488. * that the applied left and width may
  11489. * not correspond to the ranges start and end
  11490. * @Override
  11491. */
  11492. RangeItem.prototype.repositionX = function(limitSize) {
  11493. var parentWidth = this.parent.width;
  11494. var start = this.conversion.toScreen(this.data.start);
  11495. var end = this.conversion.toScreen(this.data.end);
  11496. var align = this.data.align === undefined ? this.options.align : this.data.align;
  11497. var contentStartPosition;
  11498. var contentWidth;
  11499. // limit the width of the range, as browsers cannot draw very wide divs
  11500. // unless limitSize: false is explicitly set in item data
  11501. if (this.data.limitSize !== false && (limitSize === undefined || limitSize === true)) {
  11502. if (start < -parentWidth) {
  11503. start = -parentWidth;
  11504. }
  11505. if (end > 2 * parentWidth) {
  11506. end = 2 * parentWidth;
  11507. }
  11508. }
  11509. // add 0.5 to compensate floating-point values rounding
  11510. var boxWidth = Math.max(end - start + 0.5, 1);
  11511. if (this.overflow) {
  11512. if (this.options.rtl) {
  11513. this.right = start;
  11514. } else {
  11515. this.left = start;
  11516. }
  11517. this.width = boxWidth + this.props.content.width;
  11518. contentWidth = this.props.content.width;
  11519. // Note: The calculation of width is an optimistic calculation, giving
  11520. // a width which will not change when moving the Timeline
  11521. // So no re-stacking needed, which is nicer for the eye;
  11522. } else {
  11523. if (this.options.rtl) {
  11524. this.right = start;
  11525. } else {
  11526. this.left = start;
  11527. }
  11528. this.width = boxWidth;
  11529. contentWidth = Math.min(end - start, this.props.content.width);
  11530. }
  11531. if (this.options.rtl) {
  11532. this.dom.box.style.right = this.right + 'px';
  11533. } else {
  11534. this.dom.box.style.left = this.left + 'px';
  11535. }
  11536. this.dom.box.style.width = boxWidth + 'px';
  11537. switch (align) {
  11538. case 'left':
  11539. if (this.options.rtl) {
  11540. this.dom.content.style.right = '0';
  11541. } else {
  11542. this.dom.content.style.left = '0';
  11543. }
  11544. break;
  11545. case 'right':
  11546. if (this.options.rtl) {
  11547. this.dom.content.style.right = Math.max(boxWidth - contentWidth, 0) + 'px';
  11548. } else {
  11549. this.dom.content.style.left = Math.max(boxWidth - contentWidth, 0) + 'px';
  11550. }
  11551. break;
  11552. case 'center':
  11553. if (this.options.rtl) {
  11554. this.dom.content.style.right = Math.max((boxWidth - contentWidth) / 2, 0) + 'px';
  11555. } else {
  11556. this.dom.content.style.left = Math.max((boxWidth - contentWidth) / 2, 0) + 'px';
  11557. }
  11558. break;
  11559. default:
  11560. // 'auto'
  11561. // when range exceeds left of the window, position the contents at the left of the visible area
  11562. if (this.overflow) {
  11563. if (end > 0) {
  11564. contentStartPosition = Math.max(-start, 0);
  11565. } else {
  11566. contentStartPosition = -contentWidth; // ensure it's not visible anymore
  11567. }
  11568. } else {
  11569. if (start < 0) {
  11570. contentStartPosition = -start;
  11571. } else {
  11572. contentStartPosition = 0;
  11573. }
  11574. }
  11575. if (this.options.rtl) {
  11576. this.dom.content.style.right = contentStartPosition + 'px';
  11577. } else {
  11578. this.dom.content.style.left = contentStartPosition + 'px';
  11579. this.dom.content.style.width = 'calc(100% - ' + contentStartPosition + 'px)';
  11580. }
  11581. }
  11582. };
  11583. /**
  11584. * Reposition the item vertically
  11585. * @Override
  11586. */
  11587. RangeItem.prototype.repositionY = function() {
  11588. var orientation = this.options.orientation.item;
  11589. var box = this.dom.box;
  11590. if (orientation == 'top') {
  11591. box.style.top = this.top + 'px';
  11592. } else {
  11593. box.style.top = this.parent.height - this.top - this.height + 'px';
  11594. }
  11595. };
  11596. /**
  11597. * Repaint a drag area on the left side of the range when the range is selected
  11598. * @protected
  11599. */
  11600. RangeItem.prototype._repaintDragLeft = function() {
  11601. if ((this.selected || this.options.itemsAlwaysDraggable.range) && this.options.editable.updateTime && !this.dom.dragLeft) {
  11602. // create and show drag area
  11603. var dragLeft = document.createElement('div');
  11604. dragLeft.className = 'vis-drag-left';
  11605. dragLeft.dragLeftItem = this;
  11606. this.dom.box.appendChild(dragLeft);
  11607. this.dom.dragLeft = dragLeft;
  11608. } else if (!this.selected && !this.options.itemsAlwaysDraggable.range && this.dom.dragLeft) {
  11609. // delete drag area
  11610. if (this.dom.dragLeft.parentNode) {
  11611. this.dom.dragLeft.parentNode.removeChild(this.dom.dragLeft);
  11612. }
  11613. this.dom.dragLeft = null;
  11614. }
  11615. };
  11616. /**
  11617. * Repaint a drag area on the right side of the range when the range is selected
  11618. * @protected
  11619. */
  11620. RangeItem.prototype._repaintDragRight = function() {
  11621. if ((this.selected || this.options.itemsAlwaysDraggable.range) && this.options.editable.updateTime && !this.dom.dragRight) {
  11622. // create and show drag area
  11623. var dragRight = document.createElement('div');
  11624. dragRight.className = 'vis-drag-right';
  11625. dragRight.dragRightItem = this;
  11626. this.dom.box.appendChild(dragRight);
  11627. this.dom.dragRight = dragRight;
  11628. } else if (!this.selected && !this.options.itemsAlwaysDraggable.range && this.dom.dragRight) {
  11629. // delete drag area
  11630. if (this.dom.dragRight.parentNode) {
  11631. this.dom.dragRight.parentNode.removeChild(this.dom.dragRight);
  11632. }
  11633. this.dom.dragRight = null;
  11634. }
  11635. };
  11636. module.exports = RangeItem;
  11637. /***/
  11638. }),
  11639. /* 71 */
  11640. /***/
  11641. (function(module, exports, __webpack_require__) {
  11642. "use strict";
  11643. Object.defineProperty(exports, "__esModule", {
  11644. value: true
  11645. });
  11646. var _stringify = __webpack_require__(19);
  11647. var _stringify2 = _interopRequireDefault(_stringify);
  11648. var _typeof2 = __webpack_require__(6);
  11649. var _typeof3 = _interopRequireDefault(_typeof2);
  11650. var _classCallCheck2 = __webpack_require__(0);
  11651. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  11652. var _createClass2 = __webpack_require__(1);
  11653. var _createClass3 = _interopRequireDefault(_createClass2);
  11654. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  11655. var util = __webpack_require__(2);
  11656. var ColorPicker = __webpack_require__(179)['default'];
  11657. /**
  11658. * The way this works is for all properties of this.possible options, you can supply the property name in any form to list the options.
  11659. * Boolean options are recognised as Boolean
  11660. * Number options should be written as array: [default value, min value, max value, stepsize]
  11661. * Colors should be written as array: ['color', '#ffffff']
  11662. * Strings with should be written as array: [option1, option2, option3, ..]
  11663. *
  11664. * The options are matched with their counterparts in each of the modules and the values used in the configuration are
  11665. */
  11666. var Configurator = function() {
  11667. /**
  11668. * @param {Object} parentModule | the location where parentModule.setOptions() can be called
  11669. * @param {Object} defaultContainer | the default container of the module
  11670. * @param {Object} configureOptions | the fully configured and predefined options set found in allOptions.js
  11671. * @param {number} pixelRatio | canvas pixel ratio
  11672. */
  11673. function Configurator(parentModule, defaultContainer, configureOptions) {
  11674. var pixelRatio = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
  11675. (0, _classCallCheck3['default'])(this, Configurator);
  11676. this.parent = parentModule;
  11677. this.changedOptions = [];
  11678. this.container = defaultContainer;
  11679. this.allowCreation = false;
  11680. this.options = {};
  11681. this.initialized = false;
  11682. this.popupCounter = 0;
  11683. this.defaultOptions = {
  11684. enabled: false,
  11685. filter: true,
  11686. container: undefined,
  11687. showButton: true
  11688. };
  11689. util.extend(this.options, this.defaultOptions);
  11690. this.configureOptions = configureOptions;
  11691. this.moduleOptions = {};
  11692. this.domElements = [];
  11693. this.popupDiv = {};
  11694. this.popupLimit = 5;
  11695. this.popupHistory = {};
  11696. this.colorPicker = new ColorPicker(pixelRatio);
  11697. this.wrapper = undefined;
  11698. }
  11699. /**
  11700. * refresh all options.
  11701. * Because all modules parse their options by themselves, we just use their options. We copy them here.
  11702. *
  11703. * @param {Object} options
  11704. */
  11705. (0, _createClass3['default'])(Configurator, [{
  11706. key: 'setOptions',
  11707. value: function setOptions(options) {
  11708. if (options !== undefined) {
  11709. // reset the popup history because the indices may have been changed.
  11710. this.popupHistory = {};
  11711. this._removePopup();
  11712. var enabled = true;
  11713. if (typeof options === 'string') {
  11714. this.options.filter = options;
  11715. } else if (options instanceof Array) {
  11716. this.options.filter = options.join();
  11717. } else if ((typeof options === 'undefined' ? 'undefined' : (0, _typeof3['default'])(options)) === 'object') {
  11718. if (options.container !== undefined) {
  11719. this.options.container = options.container;
  11720. }
  11721. if (options.filter !== undefined) {
  11722. this.options.filter = options.filter;
  11723. }
  11724. if (options.showButton !== undefined) {
  11725. this.options.showButton = options.showButton;
  11726. }
  11727. if (options.enabled !== undefined) {
  11728. enabled = options.enabled;
  11729. }
  11730. } else if (typeof options === 'boolean') {
  11731. this.options.filter = true;
  11732. enabled = options;
  11733. } else if (typeof options === 'function') {
  11734. this.options.filter = options;
  11735. enabled = true;
  11736. }
  11737. if (this.options.filter === false) {
  11738. enabled = false;
  11739. }
  11740. this.options.enabled = enabled;
  11741. }
  11742. this._clean();
  11743. }
  11744. /**
  11745. *
  11746. * @param {Object} moduleOptions
  11747. */
  11748. }, {
  11749. key: 'setModuleOptions',
  11750. value: function setModuleOptions(moduleOptions) {
  11751. this.moduleOptions = moduleOptions;
  11752. if (this.options.enabled === true) {
  11753. this._clean();
  11754. if (this.options.container !== undefined) {
  11755. this.container = this.options.container;
  11756. }
  11757. this._create();
  11758. }
  11759. }
  11760. /**
  11761. * Create all DOM elements
  11762. * @private
  11763. */
  11764. }, {
  11765. key: '_create',
  11766. value: function _create() {
  11767. var _this = this;
  11768. this._clean();
  11769. this.changedOptions = [];
  11770. var filter = this.options.filter;
  11771. var counter = 0;
  11772. var show = false;
  11773. for (var option in this.configureOptions) {
  11774. if (this.configureOptions.hasOwnProperty(option)) {
  11775. this.allowCreation = false;
  11776. show = false;
  11777. if (typeof filter === 'function') {
  11778. show = filter(option, []);
  11779. show = show || this._handleObject(this.configureOptions[option], [option], true);
  11780. } else if (filter === true || filter.indexOf(option) !== -1) {
  11781. show = true;
  11782. }
  11783. if (show !== false) {
  11784. this.allowCreation = true;
  11785. // linebreak between categories
  11786. if (counter > 0) {
  11787. this._makeItem([]);
  11788. }
  11789. // a header for the category
  11790. this._makeHeader(option);
  11791. // get the sub options
  11792. this._handleObject(this.configureOptions[option], [option]);
  11793. }
  11794. counter++;
  11795. }
  11796. }
  11797. if (this.options.showButton === true) {
  11798. var generateButton = document.createElement('div');
  11799. generateButton.className = 'vis-configuration vis-config-button';
  11800. generateButton.innerHTML = 'generate options';
  11801. generateButton.onclick = function() {
  11802. _this._printOptions();
  11803. };
  11804. generateButton.onmouseover = function() {
  11805. generateButton.className = 'vis-configuration vis-config-button hover';
  11806. };
  11807. generateButton.onmouseout = function() {
  11808. generateButton.className = 'vis-configuration vis-config-button';
  11809. };
  11810. this.optionsContainer = document.createElement('div');
  11811. this.optionsContainer.className = 'vis-configuration vis-config-option-container';
  11812. this.domElements.push(this.optionsContainer);
  11813. this.domElements.push(generateButton);
  11814. }
  11815. this._push();
  11816. //~ this.colorPicker.insertTo(this.container);
  11817. }
  11818. /**
  11819. * draw all DOM elements on the screen
  11820. * @private
  11821. */
  11822. }, {
  11823. key: '_push',
  11824. value: function _push() {
  11825. this.wrapper = document.createElement('div');
  11826. this.wrapper.className = 'vis-configuration-wrapper';
  11827. this.container.appendChild(this.wrapper);
  11828. for (var i = 0; i < this.domElements.length; i++) {
  11829. this.wrapper.appendChild(this.domElements[i]);
  11830. }
  11831. this._showPopupIfNeeded();
  11832. }
  11833. /**
  11834. * delete all DOM elements
  11835. * @private
  11836. */
  11837. }, {
  11838. key: '_clean',
  11839. value: function _clean() {
  11840. for (var i = 0; i < this.domElements.length; i++) {
  11841. this.wrapper.removeChild(this.domElements[i]);
  11842. }
  11843. if (this.wrapper !== undefined) {
  11844. this.container.removeChild(this.wrapper);
  11845. this.wrapper = undefined;
  11846. }
  11847. this.domElements = [];
  11848. this._removePopup();
  11849. }
  11850. /**
  11851. * get the value from the actualOptions if it exists
  11852. * @param {array} path | where to look for the actual option
  11853. * @returns {*}
  11854. * @private
  11855. */
  11856. }, {
  11857. key: '_getValue',
  11858. value: function _getValue(path) {
  11859. var base = this.moduleOptions;
  11860. for (var i = 0; i < path.length; i++) {
  11861. if (base[path[i]] !== undefined) {
  11862. base = base[path[i]];
  11863. } else {
  11864. base = undefined;
  11865. break;
  11866. }
  11867. }
  11868. return base;
  11869. }
  11870. /**
  11871. * all option elements are wrapped in an item
  11872. * @param {Array} path | where to look for the actual option
  11873. * @param {Array.<Element>} domElements
  11874. * @returns {number}
  11875. * @private
  11876. */
  11877. }, {
  11878. key: '_makeItem',
  11879. value: function _makeItem(path) {
  11880. if (this.allowCreation === true) {
  11881. var item = document.createElement('div');
  11882. item.className = 'vis-configuration vis-config-item vis-config-s' + path.length;
  11883. for (var _len = arguments.length, domElements = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  11884. domElements[_key - 1] = arguments[_key];
  11885. }
  11886. domElements.forEach(function(element) {
  11887. item.appendChild(element);
  11888. });
  11889. this.domElements.push(item);
  11890. return this.domElements.length;
  11891. }
  11892. return 0;
  11893. }
  11894. /**
  11895. * header for major subjects
  11896. * @param {string} name
  11897. * @private
  11898. */
  11899. }, {
  11900. key: '_makeHeader',
  11901. value: function _makeHeader(name) {
  11902. var div = document.createElement('div');
  11903. div.className = 'vis-configuration vis-config-header';
  11904. div.innerHTML = name;
  11905. this._makeItem([], div);
  11906. }
  11907. /**
  11908. * make a label, if it is an object label, it gets different styling.
  11909. * @param {string} name
  11910. * @param {array} path | where to look for the actual option
  11911. * @param {string} objectLabel
  11912. * @returns {HTMLElement}
  11913. * @private
  11914. */
  11915. }, {
  11916. key: '_makeLabel',
  11917. value: function _makeLabel(name, path) {
  11918. var objectLabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  11919. var div = document.createElement('div');
  11920. div.className = 'vis-configuration vis-config-label vis-config-s' + path.length;
  11921. if (objectLabel === true) {
  11922. div.innerHTML = '<i><b>' + name + ':</b></i>';
  11923. } else {
  11924. div.innerHTML = name + ':';
  11925. }
  11926. return div;
  11927. }
  11928. /**
  11929. * make a dropdown list for multiple possible string optoins
  11930. * @param {Array.<number>} arr
  11931. * @param {number} value
  11932. * @param {array} path | where to look for the actual option
  11933. * @private
  11934. */
  11935. }, {
  11936. key: '_makeDropdown',
  11937. value: function _makeDropdown(arr, value, path) {
  11938. var select = document.createElement('select');
  11939. select.className = 'vis-configuration vis-config-select';
  11940. var selectedValue = 0;
  11941. if (value !== undefined) {
  11942. if (arr.indexOf(value) !== -1) {
  11943. selectedValue = arr.indexOf(value);
  11944. }
  11945. }
  11946. for (var i = 0; i < arr.length; i++) {
  11947. var option = document.createElement('option');
  11948. option.value = arr[i];
  11949. if (i === selectedValue) {
  11950. option.selected = 'selected';
  11951. }
  11952. option.innerHTML = arr[i];
  11953. select.appendChild(option);
  11954. }
  11955. var me = this;
  11956. select.onchange = function() {
  11957. me._update(this.value, path);
  11958. };
  11959. var label = this._makeLabel(path[path.length - 1], path);
  11960. this._makeItem(path, label, select);
  11961. }
  11962. /**
  11963. * make a range object for numeric options
  11964. * @param {Array.<number>} arr
  11965. * @param {number} value
  11966. * @param {array} path | where to look for the actual option
  11967. * @private
  11968. */
  11969. }, {
  11970. key: '_makeRange',
  11971. value: function _makeRange(arr, value, path) {
  11972. var defaultValue = arr[0];
  11973. var min = arr[1];
  11974. var max = arr[2];
  11975. var step = arr[3];
  11976. var range = document.createElement('input');
  11977. range.className = 'vis-configuration vis-config-range';
  11978. try {
  11979. range.type = 'range'; // not supported on IE9
  11980. range.min = min;
  11981. range.max = max;
  11982. }
  11983. // TODO: Add some error handling and remove this lint exception
  11984. catch (err) {} // eslint-disable-line no-empty
  11985. range.step = step;
  11986. // set up the popup settings in case they are needed.
  11987. var popupString = '';
  11988. var popupValue = 0;
  11989. if (value !== undefined) {
  11990. var factor = 1.20;
  11991. if (value < 0 && value * factor < min) {
  11992. range.min = Math.ceil(value * factor);
  11993. popupValue = range.min;
  11994. popupString = 'range increased';
  11995. } else if (value / factor < min) {
  11996. range.min = Math.ceil(value / factor);
  11997. popupValue = range.min;
  11998. popupString = 'range increased';
  11999. }
  12000. if (value * factor > max && max !== 1) {
  12001. range.max = Math.ceil(value * factor);
  12002. popupValue = range.max;
  12003. popupString = 'range increased';
  12004. }
  12005. range.value = value;
  12006. } else {
  12007. range.value = defaultValue;
  12008. }
  12009. var input = document.createElement('input');
  12010. input.className = 'vis-configuration vis-config-rangeinput';
  12011. input.value = range.value;
  12012. var me = this;
  12013. range.onchange = function() {
  12014. input.value = this.value;
  12015. me._update(Number(this.value), path);
  12016. };
  12017. range.oninput = function() {
  12018. input.value = this.value;
  12019. };
  12020. var label = this._makeLabel(path[path.length - 1], path);
  12021. var itemIndex = this._makeItem(path, label, range, input);
  12022. // if a popup is needed AND it has not been shown for this value, show it.
  12023. if (popupString !== '' && this.popupHistory[itemIndex] !== popupValue) {
  12024. this.popupHistory[itemIndex] = popupValue;
  12025. this._setupPopup(popupString, itemIndex);
  12026. }
  12027. }
  12028. /**
  12029. * prepare the popup
  12030. * @param {string} string
  12031. * @param {number} index
  12032. * @private
  12033. */
  12034. }, {
  12035. key: '_setupPopup',
  12036. value: function _setupPopup(string, index) {
  12037. var _this2 = this;
  12038. if (this.initialized === true && this.allowCreation === true && this.popupCounter < this.popupLimit) {
  12039. var div = document.createElement("div");
  12040. div.id = "vis-configuration-popup";
  12041. div.className = "vis-configuration-popup";
  12042. div.innerHTML = string;
  12043. div.onclick = function() {
  12044. _this2._removePopup();
  12045. };
  12046. this.popupCounter += 1;
  12047. this.popupDiv = { html: div, index: index };
  12048. }
  12049. }
  12050. /**
  12051. * remove the popup from the dom
  12052. * @private
  12053. */
  12054. }, {
  12055. key: '_removePopup',
  12056. value: function _removePopup() {
  12057. if (this.popupDiv.html !== undefined) {
  12058. this.popupDiv.html.parentNode.removeChild(this.popupDiv.html);
  12059. clearTimeout(this.popupDiv.hideTimeout);
  12060. clearTimeout(this.popupDiv.deleteTimeout);
  12061. this.popupDiv = {};
  12062. }
  12063. }
  12064. /**
  12065. * Show the popup if it is needed.
  12066. * @private
  12067. */
  12068. }, {
  12069. key: '_showPopupIfNeeded',
  12070. value: function _showPopupIfNeeded() {
  12071. var _this3 = this;
  12072. if (this.popupDiv.html !== undefined) {
  12073. var correspondingElement = this.domElements[this.popupDiv.index];
  12074. var rect = correspondingElement.getBoundingClientRect();
  12075. this.popupDiv.html.style.left = rect.left + "px";
  12076. this.popupDiv.html.style.top = rect.top - 30 + "px"; // 30 is the height;
  12077. document.body.appendChild(this.popupDiv.html);
  12078. this.popupDiv.hideTimeout = setTimeout(function() {
  12079. _this3.popupDiv.html.style.opacity = 0;
  12080. }, 1500);
  12081. this.popupDiv.deleteTimeout = setTimeout(function() {
  12082. _this3._removePopup();
  12083. }, 1800);
  12084. }
  12085. }
  12086. /**
  12087. * make a checkbox for boolean options.
  12088. * @param {number} defaultValue
  12089. * @param {number} value
  12090. * @param {array} path | where to look for the actual option
  12091. * @private
  12092. */
  12093. }, {
  12094. key: '_makeCheckbox',
  12095. value: function _makeCheckbox(defaultValue, value, path) {
  12096. var checkbox = document.createElement('input');
  12097. checkbox.type = 'checkbox';
  12098. checkbox.className = 'vis-configuration vis-config-checkbox';
  12099. checkbox.checked = defaultValue;
  12100. if (value !== undefined) {
  12101. checkbox.checked = value;
  12102. if (value !== defaultValue) {
  12103. if ((typeof defaultValue === 'undefined' ? 'undefined' : (0, _typeof3['default'])(defaultValue)) === 'object') {
  12104. if (value !== defaultValue.enabled) {
  12105. this.changedOptions.push({ path: path, value: value });
  12106. }
  12107. } else {
  12108. this.changedOptions.push({ path: path, value: value });
  12109. }
  12110. }
  12111. }
  12112. var me = this;
  12113. checkbox.onchange = function() {
  12114. me._update(this.checked, path);
  12115. };
  12116. var label = this._makeLabel(path[path.length - 1], path);
  12117. this._makeItem(path, label, checkbox);
  12118. }
  12119. /**
  12120. * make a text input field for string options.
  12121. * @param {number} defaultValue
  12122. * @param {number} value
  12123. * @param {array} path | where to look for the actual option
  12124. * @private
  12125. */
  12126. }, {
  12127. key: '_makeTextInput',
  12128. value: function _makeTextInput(defaultValue, value, path) {
  12129. var checkbox = document.createElement('input');
  12130. checkbox.type = 'text';
  12131. checkbox.className = 'vis-configuration vis-config-text';
  12132. checkbox.value = value;
  12133. if (value !== defaultValue) {
  12134. this.changedOptions.push({ path: path, value: value });
  12135. }
  12136. var me = this;
  12137. checkbox.onchange = function() {
  12138. me._update(this.value, path);
  12139. };
  12140. var label = this._makeLabel(path[path.length - 1], path);
  12141. this._makeItem(path, label, checkbox);
  12142. }
  12143. /**
  12144. * make a color field with a color picker for color fields
  12145. * @param {Array.<number>} arr
  12146. * @param {number} value
  12147. * @param {array} path | where to look for the actual option
  12148. * @private
  12149. */
  12150. }, {
  12151. key: '_makeColorField',
  12152. value: function _makeColorField(arr, value, path) {
  12153. var _this4 = this;
  12154. var defaultColor = arr[1];
  12155. var div = document.createElement('div');
  12156. value = value === undefined ? defaultColor : value;
  12157. if (value !== 'none') {
  12158. div.className = 'vis-configuration vis-config-colorBlock';
  12159. div.style.backgroundColor = value;
  12160. } else {
  12161. div.className = 'vis-configuration vis-config-colorBlock none';
  12162. }
  12163. value = value === undefined ? defaultColor : value;
  12164. div.onclick = function() {
  12165. _this4._showColorPicker(value, div, path);
  12166. };
  12167. var label = this._makeLabel(path[path.length - 1], path);
  12168. this._makeItem(path, label, div);
  12169. }
  12170. /**
  12171. * used by the color buttons to call the color picker.
  12172. * @param {number} value
  12173. * @param {HTMLElement} div
  12174. * @param {array} path | where to look for the actual option
  12175. * @private
  12176. */
  12177. }, {
  12178. key: '_showColorPicker',
  12179. value: function _showColorPicker(value, div, path) {
  12180. var _this5 = this;
  12181. // clear the callback from this div
  12182. div.onclick = function() {};
  12183. this.colorPicker.insertTo(div);
  12184. this.colorPicker.show();
  12185. this.colorPicker.setColor(value);
  12186. this.colorPicker.setUpdateCallback(function(color) {
  12187. var colorString = 'rgba(' + color.r + ',' + color.g + ',' + color.b + ',' + color.a + ')';
  12188. div.style.backgroundColor = colorString;
  12189. _this5._update(colorString, path);
  12190. });
  12191. // on close of the colorpicker, restore the callback.
  12192. this.colorPicker.setCloseCallback(function() {
  12193. div.onclick = function() {
  12194. _this5._showColorPicker(value, div, path);
  12195. };
  12196. });
  12197. }
  12198. /**
  12199. * parse an object and draw the correct items
  12200. * @param {Object} obj
  12201. * @param {array} [path=[]] | where to look for the actual option
  12202. * @param {boolean} [checkOnly=false]
  12203. * @returns {boolean}
  12204. * @private
  12205. */
  12206. }, {
  12207. key: '_handleObject',
  12208. value: function _handleObject(obj) {
  12209. var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  12210. var checkOnly = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  12211. var show = false;
  12212. var filter = this.options.filter;
  12213. var visibleInSet = false;
  12214. for (var subObj in obj) {
  12215. if (obj.hasOwnProperty(subObj)) {
  12216. show = true;
  12217. var item = obj[subObj];
  12218. var newPath = util.copyAndExtendArray(path, subObj);
  12219. if (typeof filter === 'function') {
  12220. show = filter(subObj, path);
  12221. // if needed we must go deeper into the object.
  12222. if (show === false) {
  12223. if (!(item instanceof Array) && typeof item !== 'string' && typeof item !== 'boolean' && item instanceof Object) {
  12224. this.allowCreation = false;
  12225. show = this._handleObject(item, newPath, true);
  12226. this.allowCreation = checkOnly === false;
  12227. }
  12228. }
  12229. }
  12230. if (show !== false) {
  12231. visibleInSet = true;
  12232. var value = this._getValue(newPath);
  12233. if (item instanceof Array) {
  12234. this._handleArray(item, value, newPath);
  12235. } else if (typeof item === 'string') {
  12236. this._makeTextInput(item, value, newPath);
  12237. } else if (typeof item === 'boolean') {
  12238. this._makeCheckbox(item, value, newPath);
  12239. } else if (item instanceof Object) {
  12240. // collapse the physics options that are not enabled
  12241. var draw = true;
  12242. if (path.indexOf('physics') !== -1) {
  12243. if (this.moduleOptions.physics.solver !== subObj) {
  12244. draw = false;
  12245. }
  12246. }
  12247. if (draw === true) {
  12248. // initially collapse options with an disabled enabled option.
  12249. if (item.enabled !== undefined) {
  12250. var enabledPath = util.copyAndExtendArray(newPath, 'enabled');
  12251. var enabledValue = this._getValue(enabledPath);
  12252. if (enabledValue === true) {
  12253. var label = this._makeLabel(subObj, newPath, true);
  12254. this._makeItem(newPath, label);
  12255. visibleInSet = this._handleObject(item, newPath) || visibleInSet;
  12256. } else {
  12257. this._makeCheckbox(item, enabledValue, newPath);
  12258. }
  12259. } else {
  12260. var _label = this._makeLabel(subObj, newPath, true);
  12261. this._makeItem(newPath, _label);
  12262. visibleInSet = this._handleObject(item, newPath) || visibleInSet;
  12263. }
  12264. }
  12265. } else {
  12266. console.error('dont know how to handle', item, subObj, newPath);
  12267. }
  12268. }
  12269. }
  12270. }
  12271. return visibleInSet;
  12272. }
  12273. /**
  12274. * handle the array type of option
  12275. * @param {Array.<number>} arr
  12276. * @param {number} value
  12277. * @param {array} path | where to look for the actual option
  12278. * @private
  12279. */
  12280. }, {
  12281. key: '_handleArray',
  12282. value: function _handleArray(arr, value, path) {
  12283. if (typeof arr[0] === 'string' && arr[0] === 'color') {
  12284. this._makeColorField(arr, value, path);
  12285. if (arr[1] !== value) {
  12286. this.changedOptions.push({ path: path, value: value });
  12287. }
  12288. } else if (typeof arr[0] === 'string') {
  12289. this._makeDropdown(arr, value, path);
  12290. if (arr[0] !== value) {
  12291. this.changedOptions.push({ path: path, value: value });
  12292. }
  12293. } else if (typeof arr[0] === 'number') {
  12294. this._makeRange(arr, value, path);
  12295. if (arr[0] !== value) {
  12296. this.changedOptions.push({ path: path, value: Number(value) });
  12297. }
  12298. }
  12299. }
  12300. /**
  12301. * called to update the network with the new settings.
  12302. * @param {number} value
  12303. * @param {array} path | where to look for the actual option
  12304. * @private
  12305. */
  12306. }, {
  12307. key: '_update',
  12308. value: function _update(value, path) {
  12309. var options = this._constructOptions(value, path);
  12310. if (this.parent.body && this.parent.body.emitter && this.parent.body.emitter.emit) {
  12311. this.parent.body.emitter.emit("configChange", options);
  12312. }
  12313. this.initialized = true;
  12314. this.parent.setOptions(options);
  12315. }
  12316. /**
  12317. *
  12318. * @param {string|Boolean} value
  12319. * @param {Array.<string>} path
  12320. * @param {{}} optionsObj
  12321. * @returns {{}}
  12322. * @private
  12323. */
  12324. }, {
  12325. key: '_constructOptions',
  12326. value: function _constructOptions(value, path) {
  12327. var optionsObj = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  12328. var pointer = optionsObj;
  12329. // when dropdown boxes can be string or boolean, we typecast it into correct types
  12330. value = value === 'true' ? true : value;
  12331. value = value === 'false' ? false : value;
  12332. for (var i = 0; i < path.length; i++) {
  12333. if (path[i] !== 'global') {
  12334. if (pointer[path[i]] === undefined) {
  12335. pointer[path[i]] = {};
  12336. }
  12337. if (i !== path.length - 1) {
  12338. pointer = pointer[path[i]];
  12339. } else {
  12340. pointer[path[i]] = value;
  12341. }
  12342. }
  12343. }
  12344. return optionsObj;
  12345. }
  12346. /**
  12347. * @private
  12348. */
  12349. }, {
  12350. key: '_printOptions',
  12351. value: function _printOptions() {
  12352. var options = this.getOptions();
  12353. this.optionsContainer.innerHTML = '<pre>var options = ' + (0, _stringify2['default'])(options, null, 2) + '</pre>';
  12354. }
  12355. /**
  12356. *
  12357. * @returns {{}} options
  12358. */
  12359. }, {
  12360. key: 'getOptions',
  12361. value: function getOptions() {
  12362. var options = {};
  12363. for (var i = 0; i < this.changedOptions.length; i++) {
  12364. this._constructOptions(this.changedOptions[i].value, this.changedOptions[i].path, options);
  12365. }
  12366. return options;
  12367. }
  12368. }]);
  12369. return Configurator;
  12370. }();
  12371. exports['default'] = Configurator;
  12372. /***/
  12373. }),
  12374. /* 72 */
  12375. /***/
  12376. (function(module, exports, __webpack_require__) {
  12377. "use strict";
  12378. var _typeof2 = __webpack_require__(6);
  12379. var _typeof3 = _interopRequireDefault(_typeof2);
  12380. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  12381. var DOMutil = __webpack_require__(14);
  12382. /**
  12383. *
  12384. * @param {number | string} groupId
  12385. * @param {Object} options // TODO: Describe options
  12386. *
  12387. * @constructor Points
  12388. */
  12389. function Points(groupId, options) {} // eslint-disable-line no-unused-vars
  12390. /**
  12391. * draw the data points
  12392. *
  12393. * @param {Array} dataset
  12394. * @param {GraphGroup} group
  12395. * @param {Object} framework | SVG DOM element
  12396. * @param {number} [offset]
  12397. */
  12398. Points.draw = function(dataset, group, framework, offset) {
  12399. offset = offset || 0;
  12400. var callback = getCallback(framework, group);
  12401. for (var i = 0; i < dataset.length; i++) {
  12402. if (!callback) {
  12403. // draw the point the simple way.
  12404. DOMutil.drawPoint(dataset[i].screen_x + offset, dataset[i].screen_y, getGroupTemplate(group), framework.svgElements, framework.svg, dataset[i].label);
  12405. } else {
  12406. var callbackResult = callback(dataset[i], group); // result might be true, false or an object
  12407. if (callbackResult === true || (typeof callbackResult === 'undefined' ? 'undefined' : (0, _typeof3['default'])(callbackResult)) === 'object') {
  12408. DOMutil.drawPoint(dataset[i].screen_x + offset, dataset[i].screen_y, getGroupTemplate(group, callbackResult), framework.svgElements, framework.svg, dataset[i].label);
  12409. }
  12410. }
  12411. }
  12412. };
  12413. Points.drawIcon = function(group, x, y, iconWidth, iconHeight, framework) {
  12414. var fillHeight = iconHeight * 0.5;
  12415. var outline = DOMutil.getSVGElement("rect", framework.svgElements, framework.svg);
  12416. outline.setAttributeNS(null, "x", x);
  12417. outline.setAttributeNS(null, "y", y - fillHeight);
  12418. outline.setAttributeNS(null, "width", iconWidth);
  12419. outline.setAttributeNS(null, "height", 2 * fillHeight);
  12420. outline.setAttributeNS(null, "class", "vis-outline");
  12421. //Don't call callback on icon
  12422. DOMutil.drawPoint(x + 0.5 * iconWidth, y, getGroupTemplate(group), framework.svgElements, framework.svg);
  12423. };
  12424. /**
  12425. *
  12426. * @param {vis.Group} group
  12427. * @param {any} callbackResult
  12428. * @returns {{style: *, styles: (*|string), size: *, className: *}}
  12429. */
  12430. function getGroupTemplate(group, callbackResult) {
  12431. callbackResult = typeof callbackResult === 'undefined' ? {} : callbackResult;
  12432. return {
  12433. style: callbackResult.style || group.options.drawPoints.style,
  12434. styles: callbackResult.styles || group.options.drawPoints.styles,
  12435. size: callbackResult.size || group.options.drawPoints.size,
  12436. className: callbackResult.className || group.className
  12437. };
  12438. }
  12439. /**
  12440. *
  12441. * @param {Object} framework | SVG DOM element
  12442. * @param {vis.Group} group
  12443. * @returns {function}
  12444. */
  12445. function getCallback(framework, group) {
  12446. var callback = undefined;
  12447. // check for the graph2d onRender
  12448. if (framework.options && framework.options.drawPoints && framework.options.drawPoints.onRender && typeof framework.options.drawPoints.onRender == 'function') {
  12449. callback = framework.options.drawPoints.onRender;
  12450. }
  12451. // override it with the group onRender if defined
  12452. if (group.group.options && group.group.options.drawPoints && group.group.options.drawPoints.onRender && typeof group.group.options.drawPoints.onRender == 'function') {
  12453. callback = group.group.options.drawPoints.onRender;
  12454. }
  12455. return callback;
  12456. }
  12457. module.exports = Points;
  12458. /***/
  12459. }),
  12460. /* 73 */
  12461. /***/
  12462. (function(module, exports, __webpack_require__) {
  12463. "use strict";
  12464. Object.defineProperty(exports, "__esModule", {
  12465. value: true
  12466. });
  12467. var _getPrototypeOf = __webpack_require__(3);
  12468. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  12469. var _classCallCheck2 = __webpack_require__(0);
  12470. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  12471. var _createClass2 = __webpack_require__(1);
  12472. var _createClass3 = _interopRequireDefault(_createClass2);
  12473. var _possibleConstructorReturn2 = __webpack_require__(4);
  12474. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  12475. var _inherits2 = __webpack_require__(5);
  12476. var _inherits3 = _interopRequireDefault(_inherits2);
  12477. var _NodeBase2 = __webpack_require__(23);
  12478. var _NodeBase3 = _interopRequireDefault(_NodeBase2);
  12479. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  12480. /**
  12481. * NOTE: This is a bad base class
  12482. *
  12483. * Child classes are:
  12484. *
  12485. * Image - uses *only* image methods
  12486. * Circle - uses *only* _drawRawCircle
  12487. * CircleImage - uses all
  12488. *
  12489. * TODO: Refactor, move _drawRawCircle to different module, derive Circle from NodeBase
  12490. * Rename this to ImageBase
  12491. * Consolidate common code in Image and CircleImage to base class
  12492. *
  12493. * @extends NodeBase
  12494. */
  12495. var CircleImageBase = function(_NodeBase) {
  12496. (0, _inherits3['default'])(CircleImageBase, _NodeBase);
  12497. /**
  12498. * @param {Object} options
  12499. * @param {Object} body
  12500. * @param {Label} labelModule
  12501. */
  12502. function CircleImageBase(options, body, labelModule) {
  12503. (0, _classCallCheck3['default'])(this, CircleImageBase);
  12504. var _this = (0, _possibleConstructorReturn3['default'])(this, (CircleImageBase.__proto__ || (0, _getPrototypeOf2['default'])(CircleImageBase)).call(this, options, body, labelModule));
  12505. _this.labelOffset = 0;
  12506. _this.selected = false;
  12507. return _this;
  12508. }
  12509. /**
  12510. *
  12511. * @param {Object} options
  12512. * @param {Object} [imageObj]
  12513. * @param {Object} [imageObjAlt]
  12514. */
  12515. (0, _createClass3['default'])(CircleImageBase, [{
  12516. key: 'setOptions',
  12517. value: function setOptions(options, imageObj, imageObjAlt) {
  12518. this.options = options;
  12519. if (!(imageObj === undefined && imageObjAlt === undefined)) {
  12520. this.setImages(imageObj, imageObjAlt);
  12521. }
  12522. }
  12523. /**
  12524. * Set the images for this node.
  12525. *
  12526. * The images can be updated after the initial setting of options;
  12527. * therefore, this method needs to be reentrant.
  12528. *
  12529. * For correct working in error cases, it is necessary to properly set
  12530. * field 'nodes.brokenImage' in the options.
  12531. *
  12532. * @param {Image} imageObj required; main image to show for this node
  12533. * @param {Image|undefined} imageObjAlt optional; image to show when node is selected
  12534. */
  12535. }, {
  12536. key: 'setImages',
  12537. value: function setImages(imageObj, imageObjAlt) {
  12538. if (imageObjAlt && this.selected) {
  12539. this.imageObj = imageObjAlt;
  12540. this.imageObjAlt = imageObj;
  12541. } else {
  12542. this.imageObj = imageObj;
  12543. this.imageObjAlt = imageObjAlt;
  12544. }
  12545. }
  12546. /**
  12547. * Set selection and switch between the base and the selected image.
  12548. *
  12549. * Do the switch only if imageObjAlt exists.
  12550. *
  12551. * @param {boolean} selected value of new selected state for current node
  12552. */
  12553. }, {
  12554. key: 'switchImages',
  12555. value: function switchImages(selected) {
  12556. var selection_changed = selected && !this.selected || !selected && this.selected;
  12557. this.selected = selected; // Remember new selection
  12558. if (this.imageObjAlt !== undefined && selection_changed) {
  12559. var imageTmp = this.imageObj;
  12560. this.imageObj = this.imageObjAlt;
  12561. this.imageObjAlt = imageTmp;
  12562. }
  12563. }
  12564. /**
  12565. * Adjust the node dimensions for a loaded image.
  12566. *
  12567. * Pre: this.imageObj is valid
  12568. */
  12569. }, {
  12570. key: '_resizeImage',
  12571. value: function _resizeImage() {
  12572. var width, height;
  12573. if (this.options.shapeProperties.useImageSize === false) {
  12574. // Use the size property
  12575. var ratio_width = 1;
  12576. var ratio_height = 1;
  12577. // Only calculate the proper ratio if both width and height not zero
  12578. if (this.imageObj.width && this.imageObj.height) {
  12579. if (this.imageObj.width > this.imageObj.height) {
  12580. ratio_width = this.imageObj.width / this.imageObj.height;
  12581. } else {
  12582. ratio_height = this.imageObj.height / this.imageObj.width;
  12583. }
  12584. }
  12585. width = this.options.size * 2 * ratio_width;
  12586. height = this.options.size * 2 * ratio_height;
  12587. } else {
  12588. // Use the image size
  12589. width = this.imageObj.width;
  12590. height = this.imageObj.height;
  12591. }
  12592. this.width = width;
  12593. this.height = height;
  12594. this.radius = 0.5 * this.width;
  12595. }
  12596. /**
  12597. *
  12598. * @param {CanvasRenderingContext2D} ctx
  12599. * @param {number} x width
  12600. * @param {number} y height
  12601. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  12602. * @private
  12603. */
  12604. }, {
  12605. key: '_drawRawCircle',
  12606. value: function _drawRawCircle(ctx, x, y, values) {
  12607. this.initContextForDraw(ctx, values);
  12608. ctx.circle(x, y, values.size);
  12609. this.performFill(ctx, values);
  12610. }
  12611. /**
  12612. *
  12613. * @param {CanvasRenderingContext2D} ctx
  12614. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  12615. * @private
  12616. */
  12617. }, {
  12618. key: '_drawImageAtPosition',
  12619. value: function _drawImageAtPosition(ctx, values) {
  12620. if (this.imageObj.width != 0) {
  12621. // draw the image
  12622. ctx.globalAlpha = 1.0;
  12623. // draw shadow if enabled
  12624. this.enableShadow(ctx, values);
  12625. var factor = 1;
  12626. if (this.options.shapeProperties.interpolation === true) {
  12627. factor = this.imageObj.width / this.width / this.body.view.scale;
  12628. }
  12629. this.imageObj.drawImageAtPosition(ctx, factor, this.left, this.top, this.width, this.height);
  12630. // disable shadows for other elements.
  12631. this.disableShadow(ctx, values);
  12632. }
  12633. }
  12634. /**
  12635. *
  12636. * @param {CanvasRenderingContext2D} ctx
  12637. * @param {number} x width
  12638. * @param {number} y height
  12639. * @param {boolean} selected
  12640. * @param {boolean} hover
  12641. * @private
  12642. */
  12643. }, {
  12644. key: '_drawImageLabel',
  12645. value: function _drawImageLabel(ctx, x, y, selected, hover) {
  12646. var yLabel;
  12647. var offset = 0;
  12648. if (this.height !== undefined) {
  12649. offset = this.height * 0.5;
  12650. var labelDimensions = this.labelModule.getTextSize(ctx, selected, hover);
  12651. if (labelDimensions.lineCount >= 1) {
  12652. offset += labelDimensions.height / 2;
  12653. }
  12654. }
  12655. yLabel = y + offset;
  12656. if (this.options.label) {
  12657. this.labelOffset = offset;
  12658. }
  12659. this.labelModule.draw(ctx, x, yLabel, selected, hover, 'hanging');
  12660. }
  12661. }]);
  12662. return CircleImageBase;
  12663. }(_NodeBase3['default']);
  12664. exports['default'] = CircleImageBase;
  12665. /***/
  12666. }),
  12667. /* 74 */
  12668. /***/
  12669. (function(module, exports, __webpack_require__) {
  12670. "use strict";
  12671. Object.defineProperty(exports, "__esModule", {
  12672. value: true
  12673. });
  12674. var _stringify = __webpack_require__(19);
  12675. var _stringify2 = _interopRequireDefault(_stringify);
  12676. var _typeof2 = __webpack_require__(6);
  12677. var _typeof3 = _interopRequireDefault(_typeof2);
  12678. var _create = __webpack_require__(29);
  12679. var _create2 = _interopRequireDefault(_create);
  12680. var _classCallCheck2 = __webpack_require__(0);
  12681. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  12682. var _createClass2 = __webpack_require__(1);
  12683. var _createClass3 = _interopRequireDefault(_createClass2);
  12684. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  12685. var util = __webpack_require__(2);
  12686. var Label = __webpack_require__(117)['default'];
  12687. var ComponentUtil = __webpack_require__(48)['default'];
  12688. var CubicBezierEdge = __webpack_require__(215)['default'];
  12689. var BezierEdgeDynamic = __webpack_require__(217)['default'];
  12690. var BezierEdgeStatic = __webpack_require__(218)['default'];
  12691. var StraightEdge = __webpack_require__(219)['default'];
  12692. /**
  12693. * An edge connects two nodes and has a specific direction.
  12694. */
  12695. var Edge = function() {
  12696. /**
  12697. * @param {Object} options values specific to this edge, must contain at least 'from' and 'to'
  12698. * @param {Object} body shared state from Network instance
  12699. * @param {Object} globalOptions options from the EdgesHandler instance
  12700. * @param {Object} defaultOptions default options from the EdgeHandler instance. Value and reference are constant
  12701. */
  12702. function Edge(options, body, globalOptions, defaultOptions) {
  12703. (0, _classCallCheck3['default'])(this, Edge);
  12704. if (body === undefined) {
  12705. throw new Error("No body provided");
  12706. }
  12707. // Since globalOptions is constant in values as well as reference,
  12708. // Following needs to be done only once.
  12709. this.options = util.bridgeObject(globalOptions);
  12710. this.globalOptions = globalOptions;
  12711. this.defaultOptions = defaultOptions;
  12712. this.body = body;
  12713. // initialize variables
  12714. this.id = undefined;
  12715. this.fromId = undefined;
  12716. this.toId = undefined;
  12717. this.selected = false;
  12718. this.hover = false;
  12719. this.labelDirty = true;
  12720. this.baseWidth = this.options.width;
  12721. this.baseFontSize = this.options.font.size;
  12722. this.from = undefined; // a node
  12723. this.to = undefined; // a node
  12724. this.edgeType = undefined;
  12725. this.connected = false;
  12726. this.labelModule = new Label(this.body, this.options, true /* It's an edge label */ );
  12727. this.setOptions(options);
  12728. }
  12729. /**
  12730. * Set or overwrite options for the edge
  12731. * @param {Object} options an object with options
  12732. * @returns {null|boolean} null if no options, boolean if date changed
  12733. */
  12734. (0, _createClass3['default'])(Edge, [{
  12735. key: 'setOptions',
  12736. value: function setOptions(options) {
  12737. if (!options) {
  12738. return;
  12739. }
  12740. Edge.parseOptions(this.options, options, true, this.globalOptions);
  12741. if (options.id !== undefined) {
  12742. this.id = options.id;
  12743. }
  12744. if (options.from !== undefined) {
  12745. this.fromId = options.from;
  12746. }
  12747. if (options.to !== undefined) {
  12748. this.toId = options.to;
  12749. }
  12750. if (options.title !== undefined) {
  12751. this.title = options.title;
  12752. }
  12753. if (options.value !== undefined) {
  12754. options.value = parseFloat(options.value);
  12755. }
  12756. var pile = [options, this.options, this.defaultOptions];
  12757. this.chooser = ComponentUtil.choosify('edge', pile);
  12758. // update label Module
  12759. this.updateLabelModule(options);
  12760. var dataChanged = this.updateEdgeType();
  12761. // if anything has been updates, reset the selection width and the hover width
  12762. this._setInteractionWidths();
  12763. // A node is connected when it has a from and to node that both exist in the network.body.nodes.
  12764. this.connect();
  12765. if (options.hidden !== undefined || options.physics !== undefined) {
  12766. dataChanged = true;
  12767. }
  12768. return dataChanged;
  12769. }
  12770. /**
  12771. *
  12772. * @param {Object} parentOptions
  12773. * @param {Object} newOptions
  12774. * @param {boolean} [allowDeletion=false]
  12775. * @param {Object} [globalOptions={}]
  12776. * @param {boolean} [copyFromGlobals=false]
  12777. */
  12778. }, {
  12779. key: 'getFormattingValues',
  12780. /**
  12781. *
  12782. * @returns {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}}
  12783. */
  12784. value: function getFormattingValues() {
  12785. var toArrow = this.options.arrows.to === true || this.options.arrows.to.enabled === true;
  12786. var fromArrow = this.options.arrows.from === true || this.options.arrows.from.enabled === true;
  12787. var middleArrow = this.options.arrows.middle === true || this.options.arrows.middle.enabled === true;
  12788. var inheritsColor = this.options.color.inherit;
  12789. var values = {
  12790. toArrow: toArrow,
  12791. toArrowScale: this.options.arrows.to.scaleFactor,
  12792. toArrowType: this.options.arrows.to.type,
  12793. middleArrow: middleArrow,
  12794. middleArrowScale: this.options.arrows.middle.scaleFactor,
  12795. middleArrowType: this.options.arrows.middle.type,
  12796. fromArrow: fromArrow,
  12797. fromArrowScale: this.options.arrows.from.scaleFactor,
  12798. fromArrowType: this.options.arrows.from.type,
  12799. arrowStrikethrough: this.options.arrowStrikethrough,
  12800. color: inheritsColor ? undefined : this.options.color.color,
  12801. inheritsColor: inheritsColor,
  12802. opacity: this.options.color.opacity,
  12803. hidden: this.options.hidden,
  12804. length: this.options.length,
  12805. shadow: this.options.shadow.enabled,
  12806. shadowColor: this.options.shadow.color,
  12807. shadowSize: this.options.shadow.size,
  12808. shadowX: this.options.shadow.x,
  12809. shadowY: this.options.shadow.y,
  12810. dashes: this.options.dashes,
  12811. width: this.options.width
  12812. };
  12813. if (this.selected || this.hover) {
  12814. if (this.chooser === true) {
  12815. if (this.selected) {
  12816. var selectedWidth = this.options.selectionWidth;
  12817. if (typeof selectedWidth === 'function') {
  12818. values.width = selectedWidth(values.width);
  12819. } else if (typeof selectedWidth === 'number') {
  12820. values.width += selectedWidth;
  12821. }
  12822. values.width = Math.max(values.width, 0.3 / this.body.view.scale);
  12823. values.color = this.options.color.highlight;
  12824. values.shadow = this.options.shadow.enabled;
  12825. } else if (this.hover) {
  12826. var hoverWidth = this.options.hoverWidth;
  12827. if (typeof hoverWidth === 'function') {
  12828. values.width = hoverWidth(values.width);
  12829. } else if (typeof hoverWidth === 'number') {
  12830. values.width += hoverWidth;
  12831. }
  12832. values.width = Math.max(values.width, 0.3 / this.body.view.scale);
  12833. values.color = this.options.color.hover;
  12834. values.shadow = this.options.shadow.enabled;
  12835. }
  12836. } else if (typeof this.chooser === 'function') {
  12837. this.chooser(values, this.options.id, this.selected, this.hover);
  12838. if (values.color !== undefined) {
  12839. values.inheritsColor = false;
  12840. }
  12841. if (values.shadow === false) {
  12842. if (values.shadowColor !== this.options.shadow.color || values.shadowSize !== this.options.shadow.size || values.shadowX !== this.options.shadow.x || values.shadowY !== this.options.shadow.y) {
  12843. values.shadow = true;
  12844. }
  12845. }
  12846. }
  12847. } else {
  12848. values.shadow = this.options.shadow.enabled;
  12849. values.width = Math.max(values.width, 0.3 / this.body.view.scale);
  12850. }
  12851. return values;
  12852. }
  12853. /**
  12854. * update the options in the label module
  12855. *
  12856. * @param {Object} options
  12857. */
  12858. }, {
  12859. key: 'updateLabelModule',
  12860. value: function updateLabelModule(options) {
  12861. var pile = [options, this.options, this.globalOptions, // Currently set global edge options
  12862. this.defaultOptions
  12863. ];
  12864. this.labelModule.update(this.options, pile);
  12865. if (this.labelModule.baseSize !== undefined) {
  12866. this.baseFontSize = this.labelModule.baseSize;
  12867. }
  12868. }
  12869. /**
  12870. * update the edge type, set the options
  12871. * @returns {boolean}
  12872. */
  12873. }, {
  12874. key: 'updateEdgeType',
  12875. value: function updateEdgeType() {
  12876. var smooth = this.options.smooth;
  12877. var dataChanged = false;
  12878. var changeInType = true;
  12879. if (this.edgeType !== undefined) {
  12880. if (this.edgeType instanceof BezierEdgeDynamic && smooth.enabled === true && smooth.type === 'dynamic' || this.edgeType instanceof CubicBezierEdge && smooth.enabled === true && smooth.type === 'cubicBezier' || this.edgeType instanceof BezierEdgeStatic && smooth.enabled === true && smooth.type !== 'dynamic' && smooth.type !== 'cubicBezier' || this.edgeType instanceof StraightEdge && smooth.type.enabled === false) {
  12881. changeInType = false;
  12882. }
  12883. if (changeInType === true) {
  12884. dataChanged = this.cleanup();
  12885. }
  12886. }
  12887. if (changeInType === true) {
  12888. if (smooth.enabled === true) {
  12889. if (smooth.type === 'dynamic') {
  12890. dataChanged = true;
  12891. this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
  12892. } else if (smooth.type === 'cubicBezier') {
  12893. this.edgeType = new CubicBezierEdge(this.options, this.body, this.labelModule);
  12894. } else {
  12895. this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
  12896. }
  12897. } else {
  12898. this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
  12899. }
  12900. } else {
  12901. // if nothing changes, we just set the options.
  12902. this.edgeType.setOptions(this.options);
  12903. }
  12904. return dataChanged;
  12905. }
  12906. /**
  12907. * Connect an edge to its nodes
  12908. */
  12909. }, {
  12910. key: 'connect',
  12911. value: function connect() {
  12912. this.disconnect();
  12913. this.from = this.body.nodes[this.fromId] || undefined;
  12914. this.to = this.body.nodes[this.toId] || undefined;
  12915. this.connected = this.from !== undefined && this.to !== undefined;
  12916. if (this.connected === true) {
  12917. this.from.attachEdge(this);
  12918. this.to.attachEdge(this);
  12919. } else {
  12920. if (this.from) {
  12921. this.from.detachEdge(this);
  12922. }
  12923. if (this.to) {
  12924. this.to.detachEdge(this);
  12925. }
  12926. }
  12927. this.edgeType.connect();
  12928. }
  12929. /**
  12930. * Disconnect an edge from its nodes
  12931. */
  12932. }, {
  12933. key: 'disconnect',
  12934. value: function disconnect() {
  12935. if (this.from) {
  12936. this.from.detachEdge(this);
  12937. this.from = undefined;
  12938. }
  12939. if (this.to) {
  12940. this.to.detachEdge(this);
  12941. this.to = undefined;
  12942. }
  12943. this.connected = false;
  12944. }
  12945. /**
  12946. * get the title of this edge.
  12947. * @return {string} title The title of the edge, or undefined when no title
  12948. * has been set.
  12949. */
  12950. }, {
  12951. key: 'getTitle',
  12952. value: function getTitle() {
  12953. return this.title;
  12954. }
  12955. /**
  12956. * check if this node is selecte
  12957. * @return {boolean} selected True if node is selected, else false
  12958. */
  12959. }, {
  12960. key: 'isSelected',
  12961. value: function isSelected() {
  12962. return this.selected;
  12963. }
  12964. /**
  12965. * Retrieve the value of the edge. Can be undefined
  12966. * @return {number} value
  12967. */
  12968. }, {
  12969. key: 'getValue',
  12970. value: function getValue() {
  12971. return this.options.value;
  12972. }
  12973. /**
  12974. * Adjust the value range of the edge. The edge will adjust it's width
  12975. * based on its value.
  12976. * @param {number} min
  12977. * @param {number} max
  12978. * @param {number} total
  12979. */
  12980. }, {
  12981. key: 'setValueRange',
  12982. value: function setValueRange(min, max, total) {
  12983. if (this.options.value !== undefined) {
  12984. var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
  12985. var widthDiff = this.options.scaling.max - this.options.scaling.min;
  12986. if (this.options.scaling.label.enabled === true) {
  12987. var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
  12988. this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
  12989. }
  12990. this.options.width = this.options.scaling.min + scale * widthDiff;
  12991. } else {
  12992. this.options.width = this.baseWidth;
  12993. this.options.font.size = this.baseFontSize;
  12994. }
  12995. this._setInteractionWidths();
  12996. this.updateLabelModule();
  12997. }
  12998. /**
  12999. *
  13000. * @private
  13001. */
  13002. }, {
  13003. key: '_setInteractionWidths',
  13004. value: function _setInteractionWidths() {
  13005. if (typeof this.options.hoverWidth === 'function') {
  13006. this.edgeType.hoverWidth = this.options.hoverWidth(this.options.width);
  13007. } else {
  13008. this.edgeType.hoverWidth = this.options.hoverWidth + this.options.width;
  13009. }
  13010. if (typeof this.options.selectionWidth === 'function') {
  13011. this.edgeType.selectionWidth = this.options.selectionWidth(this.options.width);
  13012. } else {
  13013. this.edgeType.selectionWidth = this.options.selectionWidth + this.options.width;
  13014. }
  13015. }
  13016. /**
  13017. * Redraw a edge
  13018. * Draw this edge in the given canvas
  13019. * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
  13020. * @param {CanvasRenderingContext2D} ctx
  13021. */
  13022. }, {
  13023. key: 'draw',
  13024. value: function draw(ctx) {
  13025. var values = this.getFormattingValues();
  13026. if (values.hidden) {
  13027. return;
  13028. }
  13029. // get the via node from the edge type
  13030. var viaNode = this.edgeType.getViaNode();
  13031. var arrowData = {};
  13032. // restore edge targets to defaults
  13033. this.edgeType.fromPoint = this.edgeType.from;
  13034. this.edgeType.toPoint = this.edgeType.to;
  13035. // from and to arrows give a different end point for edges. we set them here
  13036. if (values.fromArrow) {
  13037. arrowData.from = this.edgeType.getArrowData(ctx, 'from', viaNode, this.selected, this.hover, values);
  13038. if (values.arrowStrikethrough === false) this.edgeType.fromPoint = arrowData.from.core;
  13039. }
  13040. if (values.toArrow) {
  13041. arrowData.to = this.edgeType.getArrowData(ctx, 'to', viaNode, this.selected, this.hover, values);
  13042. if (values.arrowStrikethrough === false) this.edgeType.toPoint = arrowData.to.core;
  13043. }
  13044. // the middle arrow depends on the line, which can depend on the to and from arrows so we do this one lastly.
  13045. if (values.middleArrow) {
  13046. arrowData.middle = this.edgeType.getArrowData(ctx, 'middle', viaNode, this.selected, this.hover, values);
  13047. }
  13048. // draw everything
  13049. this.edgeType.drawLine(ctx, values, this.selected, this.hover, viaNode);
  13050. this.drawArrows(ctx, arrowData, values);
  13051. this.drawLabel(ctx, viaNode);
  13052. }
  13053. /**
  13054. *
  13055. * @param {CanvasRenderingContext2D} ctx
  13056. * @param {Object} arrowData
  13057. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  13058. */
  13059. }, {
  13060. key: 'drawArrows',
  13061. value: function drawArrows(ctx, arrowData, values) {
  13062. if (values.fromArrow) {
  13063. this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.from);
  13064. }
  13065. if (values.middleArrow) {
  13066. this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.middle);
  13067. }
  13068. if (values.toArrow) {
  13069. this.edgeType.drawArrowHead(ctx, values, this.selected, this.hover, arrowData.to);
  13070. }
  13071. }
  13072. /**
  13073. *
  13074. * @param {CanvasRenderingContext2D} ctx
  13075. * @param {Node} viaNode
  13076. */
  13077. }, {
  13078. key: 'drawLabel',
  13079. value: function drawLabel(ctx, viaNode) {
  13080. if (this.options.label !== undefined) {
  13081. // set style
  13082. var node1 = this.from;
  13083. var node2 = this.to;
  13084. if (this.labelModule.differentState(this.selected, this.hover)) {
  13085. this.labelModule.getTextSize(ctx, this.selected, this.hover);
  13086. }
  13087. if (node1.id != node2.id) {
  13088. this.labelModule.pointToSelf = false;
  13089. var point = this.edgeType.getPoint(0.5, viaNode);
  13090. ctx.save();
  13091. var rotationPoint = this._getRotation(ctx);
  13092. if (rotationPoint.angle != 0) {
  13093. ctx.translate(rotationPoint.x, rotationPoint.y);
  13094. ctx.rotate(rotationPoint.angle);
  13095. }
  13096. // draw the label
  13097. this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
  13098. /*
  13099. // Useful debug code: draw a border around the label
  13100. // This should **not** be enabled in production!
  13101. var size = this.labelModule.getSize();; // ;; intentional so lint catches it
  13102. ctx.strokeStyle = "#ff0000";
  13103. ctx.strokeRect(size.left, size.top, size.width, size.height);
  13104. // End debug code
  13105. */
  13106. ctx.restore();
  13107. } else {
  13108. // Ignore the orientations.
  13109. this.labelModule.pointToSelf = true;
  13110. var x, y;
  13111. var radius = this.options.selfReferenceSize;
  13112. if (node1.shape.width > node1.shape.height) {
  13113. x = node1.x + node1.shape.width * 0.5;
  13114. y = node1.y - radius;
  13115. } else {
  13116. x = node1.x + radius;
  13117. y = node1.y - node1.shape.height * 0.5;
  13118. }
  13119. point = this._pointOnCircle(x, y, radius, 0.125);
  13120. this.labelModule.draw(ctx, point.x, point.y, this.selected, this.hover);
  13121. }
  13122. }
  13123. }
  13124. /**
  13125. * Determine all visual elements of this edge instance, in which the given
  13126. * point falls within the bounding shape.
  13127. *
  13128. * @param {point} point
  13129. * @returns {Array.<edgeClickItem|edgeLabelClickItem>} list with the items which are on the point
  13130. */
  13131. }, {
  13132. key: 'getItemsOnPoint',
  13133. value: function getItemsOnPoint(point) {
  13134. var ret = [];
  13135. if (this.labelModule.visible()) {
  13136. var rotationPoint = this._getRotation();
  13137. if (ComponentUtil.pointInRect(this.labelModule.getSize(), point, rotationPoint)) {
  13138. ret.push({ edgeId: this.id, labelId: 0 });
  13139. }
  13140. }
  13141. var obj = {
  13142. left: point.x,
  13143. top: point.y
  13144. };
  13145. if (this.isOverlappingWith(obj)) {
  13146. ret.push({ edgeId: this.id });
  13147. }
  13148. return ret;
  13149. }
  13150. /**
  13151. * Check if this object is overlapping with the provided object
  13152. * @param {Object} obj an object with parameters left, top
  13153. * @return {boolean} True if location is located on the edge
  13154. */
  13155. }, {
  13156. key: 'isOverlappingWith',
  13157. value: function isOverlappingWith(obj) {
  13158. if (this.connected) {
  13159. var distMax = 10;
  13160. var xFrom = this.from.x;
  13161. var yFrom = this.from.y;
  13162. var xTo = this.to.x;
  13163. var yTo = this.to.y;
  13164. var xObj = obj.left;
  13165. var yObj = obj.top;
  13166. var dist = this.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);
  13167. return dist < distMax;
  13168. } else {
  13169. return false;
  13170. }
  13171. }
  13172. /**
  13173. * Determine the rotation point, if any.
  13174. *
  13175. * @param {CanvasRenderingContext2D} [ctx] if passed, do a recalculation of the label size
  13176. * @returns {rotationPoint} the point to rotate around and the angle in radians to rotate
  13177. * @private
  13178. */
  13179. }, {
  13180. key: '_getRotation',
  13181. value: function _getRotation(ctx) {
  13182. var viaNode = this.edgeType.getViaNode();
  13183. var point = this.edgeType.getPoint(0.5, viaNode);
  13184. if (ctx !== undefined) {
  13185. this.labelModule.calculateLabelSize(ctx, this.selected, this.hover, point.x, point.y);
  13186. }
  13187. var ret = {
  13188. x: point.x,
  13189. y: this.labelModule.size.yLine,
  13190. angle: 0
  13191. };
  13192. if (!this.labelModule.visible()) {
  13193. return ret; // Don't even bother doing the atan2, there's nothing to draw
  13194. }
  13195. if (this.options.font.align === "horizontal") {
  13196. return ret; // No need to calculate angle
  13197. }
  13198. var dy = this.from.y - this.to.y;
  13199. var dx = this.from.x - this.to.x;
  13200. var angle = Math.atan2(dy, dx); // radians
  13201. // rotate so that label is readable
  13202. if (angle < -1 && dx < 0 || angle > 0 && dx < 0) {
  13203. angle += Math.PI;
  13204. }
  13205. ret.angle = angle;
  13206. return ret;
  13207. }
  13208. /**
  13209. * Get a point on a circle
  13210. * @param {number} x
  13211. * @param {number} y
  13212. * @param {number} radius
  13213. * @param {number} percentage Value between 0 (line start) and 1 (line end)
  13214. * @return {Object} point
  13215. * @private
  13216. */
  13217. }, {
  13218. key: '_pointOnCircle',
  13219. value: function _pointOnCircle(x, y, radius, percentage) {
  13220. var angle = percentage * 2 * Math.PI;
  13221. return {
  13222. x: x + radius * Math.cos(angle),
  13223. y: y - radius * Math.sin(angle)
  13224. };
  13225. }
  13226. /**
  13227. * Sets selected state to true
  13228. */
  13229. }, {
  13230. key: 'select',
  13231. value: function select() {
  13232. this.selected = true;
  13233. }
  13234. /**
  13235. * Sets selected state to false
  13236. */
  13237. }, {
  13238. key: 'unselect',
  13239. value: function unselect() {
  13240. this.selected = false;
  13241. }
  13242. /**
  13243. * cleans all required things on delete
  13244. * @returns {*}
  13245. */
  13246. }, {
  13247. key: 'cleanup',
  13248. value: function cleanup() {
  13249. return this.edgeType.cleanup();
  13250. }
  13251. /**
  13252. * Remove edge from the list and perform necessary cleanup.
  13253. */
  13254. }, {
  13255. key: 'remove',
  13256. value: function remove() {
  13257. this.cleanup();
  13258. this.disconnect();
  13259. delete this.body.edges[this.id];
  13260. }
  13261. /**
  13262. * Check if both connecting nodes exist
  13263. * @returns {boolean}
  13264. */
  13265. }, {
  13266. key: 'endPointsValid',
  13267. value: function endPointsValid() {
  13268. return this.body.nodes[this.fromId] !== undefined && this.body.nodes[this.toId] !== undefined;
  13269. }
  13270. }], [{
  13271. key: 'parseOptions',
  13272. value: function parseOptions(parentOptions, newOptions) {
  13273. var allowDeletion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  13274. var globalOptions = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
  13275. var copyFromGlobals = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
  13276. var fields = ['arrowStrikethrough', 'id', 'from', 'hidden', 'hoverWidth', 'labelHighlightBold', 'length', 'line', 'opacity', 'physics', 'scaling', 'selectionWidth', 'selfReferenceSize', 'to', 'title', 'value', 'width', 'font', 'chosen', 'widthConstraint'];
  13277. // only deep extend the items in the field array. These do not have shorthand.
  13278. util.selectiveDeepExtend(fields, parentOptions, newOptions, allowDeletion);
  13279. // Only copy label if it's a legal value.
  13280. if (ComponentUtil.isValidLabel(newOptions.label)) {
  13281. parentOptions.label = newOptions.label;
  13282. } else {
  13283. parentOptions.label = undefined;
  13284. }
  13285. util.mergeOptions(parentOptions, newOptions, 'smooth', globalOptions);
  13286. util.mergeOptions(parentOptions, newOptions, 'shadow', globalOptions);
  13287. if (newOptions.dashes !== undefined && newOptions.dashes !== null) {
  13288. parentOptions.dashes = newOptions.dashes;
  13289. } else if (allowDeletion === true && newOptions.dashes === null) {
  13290. parentOptions.dashes = (0, _create2['default'])(globalOptions.dashes); // this sets the pointer of the option back to the global option.
  13291. }
  13292. // set the scaling newOptions
  13293. if (newOptions.scaling !== undefined && newOptions.scaling !== null) {
  13294. if (newOptions.scaling.min !== undefined) {
  13295. parentOptions.scaling.min = newOptions.scaling.min;
  13296. }
  13297. if (newOptions.scaling.max !== undefined) {
  13298. parentOptions.scaling.max = newOptions.scaling.max;
  13299. }
  13300. util.mergeOptions(parentOptions.scaling, newOptions.scaling, 'label', globalOptions.scaling);
  13301. } else if (allowDeletion === true && newOptions.scaling === null) {
  13302. parentOptions.scaling = (0, _create2['default'])(globalOptions.scaling); // this sets the pointer of the option back to the global option.
  13303. }
  13304. // handle multiple input cases for arrows
  13305. if (newOptions.arrows !== undefined && newOptions.arrows !== null) {
  13306. if (typeof newOptions.arrows === 'string') {
  13307. var arrows = newOptions.arrows.toLowerCase();
  13308. parentOptions.arrows.to.enabled = arrows.indexOf("to") != -1;
  13309. parentOptions.arrows.middle.enabled = arrows.indexOf("middle") != -1;
  13310. parentOptions.arrows.from.enabled = arrows.indexOf("from") != -1;
  13311. } else if ((0, _typeof3['default'])(newOptions.arrows) === 'object') {
  13312. util.mergeOptions(parentOptions.arrows, newOptions.arrows, 'to', globalOptions.arrows);
  13313. util.mergeOptions(parentOptions.arrows, newOptions.arrows, 'middle', globalOptions.arrows);
  13314. util.mergeOptions(parentOptions.arrows, newOptions.arrows, 'from', globalOptions.arrows);
  13315. } else {
  13316. throw new Error("The arrow newOptions can only be an object or a string. Refer to the documentation. You used:" + (0, _stringify2['default'])(newOptions.arrows));
  13317. }
  13318. } else if (allowDeletion === true && newOptions.arrows === null) {
  13319. parentOptions.arrows = (0, _create2['default'])(globalOptions.arrows); // this sets the pointer of the option back to the global option.
  13320. }
  13321. // handle multiple input cases for color
  13322. if (newOptions.color !== undefined && newOptions.color !== null) {
  13323. var fromColor = newOptions.color;
  13324. var toColor = parentOptions.color;
  13325. // If passed, fill in values from default options - required in the case of no prototype bridging
  13326. if (copyFromGlobals) {
  13327. util.deepExtend(toColor, globalOptions.color, false, allowDeletion);
  13328. } else {
  13329. // Clear local properties - need to do it like this in order to retain prototype bridges
  13330. for (var i in toColor) {
  13331. if (toColor.hasOwnProperty(i)) {
  13332. delete toColor[i];
  13333. }
  13334. }
  13335. }
  13336. if (util.isString(toColor)) {
  13337. toColor.color = toColor;
  13338. toColor.highlight = toColor;
  13339. toColor.hover = toColor;
  13340. toColor.inherit = false;
  13341. if (fromColor.opacity === undefined) {
  13342. toColor.opacity = 1.0; // set default
  13343. }
  13344. } else {
  13345. var colorsDefined = false;
  13346. if (fromColor.color !== undefined) {
  13347. toColor.color = fromColor.color;
  13348. colorsDefined = true;
  13349. }
  13350. if (fromColor.highlight !== undefined) {
  13351. toColor.highlight = fromColor.highlight;
  13352. colorsDefined = true;
  13353. }
  13354. if (fromColor.hover !== undefined) {
  13355. toColor.hover = fromColor.hover;
  13356. colorsDefined = true;
  13357. }
  13358. if (fromColor.inherit !== undefined) {
  13359. toColor.inherit = fromColor.inherit;
  13360. }
  13361. if (fromColor.opacity !== undefined) {
  13362. toColor.opacity = Math.min(1, Math.max(0, fromColor.opacity));
  13363. }
  13364. if (colorsDefined === true) {
  13365. toColor.inherit = false;
  13366. } else {
  13367. if (toColor.inherit === undefined) {
  13368. toColor.inherit = 'from'; // Set default
  13369. }
  13370. }
  13371. }
  13372. } else if (allowDeletion === true && newOptions.color === null) {
  13373. parentOptions.color = util.bridgeObject(globalOptions.color); // set the object back to the global options
  13374. }
  13375. if (allowDeletion === true && newOptions.font === null) {
  13376. parentOptions.font = util.bridgeObject(globalOptions.font); // set the object back to the global options
  13377. }
  13378. }
  13379. }]);
  13380. return Edge;
  13381. }();
  13382. exports['default'] = Edge;
  13383. /***/
  13384. }),
  13385. /* 75 */
  13386. /***/
  13387. (function(module, exports, __webpack_require__) {
  13388. "use strict";
  13389. Object.defineProperty(exports, "__esModule", {
  13390. value: true
  13391. });
  13392. var _getPrototypeOf = __webpack_require__(3);
  13393. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  13394. var _classCallCheck2 = __webpack_require__(0);
  13395. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  13396. var _createClass2 = __webpack_require__(1);
  13397. var _createClass3 = _interopRequireDefault(_createClass2);
  13398. var _possibleConstructorReturn2 = __webpack_require__(4);
  13399. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  13400. var _inherits2 = __webpack_require__(5);
  13401. var _inherits3 = _interopRequireDefault(_inherits2);
  13402. var _EdgeBase2 = __webpack_require__(118);
  13403. var _EdgeBase3 = _interopRequireDefault(_EdgeBase2);
  13404. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  13405. /**
  13406. * The Base Class for all Bezier edges. Bezier curves are used to model smooth
  13407. * gradual curves in paths between nodes.
  13408. *
  13409. * @extends EdgeBase
  13410. */
  13411. var BezierEdgeBase = function(_EdgeBase) {
  13412. (0, _inherits3['default'])(BezierEdgeBase, _EdgeBase);
  13413. /**
  13414. * @param {Object} options
  13415. * @param {Object} body
  13416. * @param {Label} labelModule
  13417. */
  13418. function BezierEdgeBase(options, body, labelModule) {
  13419. (0, _classCallCheck3['default'])(this, BezierEdgeBase);
  13420. return (0, _possibleConstructorReturn3['default'])(this, (BezierEdgeBase.__proto__ || (0, _getPrototypeOf2['default'])(BezierEdgeBase)).call(this, options, body, labelModule));
  13421. }
  13422. /**
  13423. * This function uses binary search to look for the point where the bezier curve crosses the border of the node.
  13424. *
  13425. * @param {Node} nearNode
  13426. * @param {CanvasRenderingContext2D} ctx
  13427. * @param {Node} viaNode
  13428. * @returns {*}
  13429. * @private
  13430. */
  13431. (0, _createClass3['default'])(BezierEdgeBase, [{
  13432. key: '_findBorderPositionBezier',
  13433. value: function _findBorderPositionBezier(nearNode, ctx) {
  13434. var viaNode = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this._getViaCoordinates();
  13435. var maxIterations = 10;
  13436. var iteration = 0;
  13437. var low = 0;
  13438. var high = 1;
  13439. var pos, angle, distanceToBorder, distanceToPoint, difference;
  13440. var threshold = 0.2;
  13441. var node = this.to;
  13442. var from = false;
  13443. if (nearNode.id === this.from.id) {
  13444. node = this.from;
  13445. from = true;
  13446. }
  13447. while (low <= high && iteration < maxIterations) {
  13448. var middle = (low + high) * 0.5;
  13449. pos = this.getPoint(middle, viaNode);
  13450. angle = Math.atan2(node.y - pos.y, node.x - pos.x);
  13451. distanceToBorder = node.distanceToBorder(ctx, angle);
  13452. distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2));
  13453. difference = distanceToBorder - distanceToPoint;
  13454. if (Math.abs(difference) < threshold) {
  13455. break; // found
  13456. } else if (difference < 0) {
  13457. // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
  13458. if (from === false) {
  13459. low = middle;
  13460. } else {
  13461. high = middle;
  13462. }
  13463. } else {
  13464. if (from === false) {
  13465. high = middle;
  13466. } else {
  13467. low = middle;
  13468. }
  13469. }
  13470. iteration++;
  13471. }
  13472. pos.t = middle;
  13473. return pos;
  13474. }
  13475. /**
  13476. * Calculate the distance between a point (x3,y3) and a line segment from
  13477. * (x1,y1) to (x2,y2).
  13478. * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
  13479. * @param {number} x1 from x
  13480. * @param {number} y1 from y
  13481. * @param {number} x2 to x
  13482. * @param {number} y2 to y
  13483. * @param {number} x3 point to check x
  13484. * @param {number} y3 point to check y
  13485. * @param {Node} via
  13486. * @returns {number}
  13487. * @private
  13488. */
  13489. }, {
  13490. key: '_getDistanceToBezierEdge',
  13491. value: function _getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via) {
  13492. // x3,y3 is the point
  13493. var minDistance = 1e9;
  13494. var distance = void 0;
  13495. var i = void 0,
  13496. t = void 0,
  13497. x = void 0,
  13498. y = void 0;
  13499. var lastX = x1;
  13500. var lastY = y1;
  13501. for (i = 1; i < 10; i++) {
  13502. t = 0.1 * i;
  13503. x = Math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * via.x + Math.pow(t, 2) * x2;
  13504. y = Math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * via.y + Math.pow(t, 2) * y2;
  13505. if (i > 0) {
  13506. distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
  13507. minDistance = distance < minDistance ? distance : minDistance;
  13508. }
  13509. lastX = x;
  13510. lastY = y;
  13511. }
  13512. return minDistance;
  13513. }
  13514. /**
  13515. * Draw a bezier curve between two nodes
  13516. *
  13517. * The method accepts zero, one or two control points.
  13518. * Passing zero control points just draws a straight line
  13519. *
  13520. * @param {CanvasRenderingContext2D} ctx
  13521. * @param {Object} values | options for shadow drawing
  13522. * @param {Object|undefined} viaNode1 | first control point for curve drawing
  13523. * @param {Object|undefined} viaNode2 | second control point for curve drawing
  13524. *
  13525. * @protected
  13526. */
  13527. }, {
  13528. key: '_bezierCurve',
  13529. value: function _bezierCurve(ctx, values, viaNode1, viaNode2) {
  13530. var hasNode1 = viaNode1 !== undefined && viaNode1.x !== undefined;
  13531. var hasNode2 = viaNode2 !== undefined && viaNode2.x !== undefined;
  13532. ctx.beginPath();
  13533. ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
  13534. if (hasNode1 && hasNode2) {
  13535. ctx.bezierCurveTo(viaNode1.x, viaNode1.y, viaNode2.x, viaNode2.y, this.toPoint.x, this.toPoint.y);
  13536. } else if (hasNode1) {
  13537. ctx.quadraticCurveTo(viaNode1.x, viaNode1.y, this.toPoint.x, this.toPoint.y);
  13538. } else {
  13539. // fallback to normal straight edge
  13540. ctx.lineTo(this.toPoint.x, this.toPoint.y);
  13541. }
  13542. // draw shadow if enabled
  13543. this.enableShadow(ctx, values);
  13544. ctx.stroke();
  13545. this.disableShadow(ctx, values);
  13546. }
  13547. /**
  13548. *
  13549. * @returns {*|{x, y}|{x: undefined, y: undefined}}
  13550. */
  13551. }, {
  13552. key: 'getViaNode',
  13553. value: function getViaNode() {
  13554. return this._getViaCoordinates();
  13555. }
  13556. }]);
  13557. return BezierEdgeBase;
  13558. }(_EdgeBase3['default']);
  13559. exports['default'] = BezierEdgeBase;
  13560. /***/
  13561. }),
  13562. /* 76 */
  13563. /***/
  13564. (function(module, exports, __webpack_require__) {
  13565. "use strict";
  13566. Object.defineProperty(exports, "__esModule", {
  13567. value: true
  13568. });
  13569. var _classCallCheck2 = __webpack_require__(0);
  13570. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  13571. var _createClass2 = __webpack_require__(1);
  13572. var _createClass3 = _interopRequireDefault(_createClass2);
  13573. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  13574. var util = __webpack_require__(2);
  13575. /**
  13576. * Utility Class
  13577. */
  13578. var NetworkUtil = function() {
  13579. /**
  13580. * @ignore
  13581. */
  13582. function NetworkUtil() {
  13583. (0, _classCallCheck3["default"])(this, NetworkUtil);
  13584. }
  13585. /**
  13586. * Find the center position of the network considering the bounding boxes
  13587. *
  13588. * @param {Array.<Node>} allNodes
  13589. * @param {Array.<Node>} [specificNodes=[]]
  13590. * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
  13591. * @static
  13592. */
  13593. (0, _createClass3["default"])(NetworkUtil, null, [{
  13594. key: "getRange",
  13595. value: function getRange(allNodes) {
  13596. var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  13597. var minY = 1e9,
  13598. maxY = -1e9,
  13599. minX = 1e9,
  13600. maxX = -1e9,
  13601. node;
  13602. if (specificNodes.length > 0) {
  13603. for (var i = 0; i < specificNodes.length; i++) {
  13604. node = allNodes[specificNodes[i]];
  13605. if (minX > node.shape.boundingBox.left) {
  13606. minX = node.shape.boundingBox.left;
  13607. }
  13608. if (maxX < node.shape.boundingBox.right) {
  13609. maxX = node.shape.boundingBox.right;
  13610. }
  13611. if (minY > node.shape.boundingBox.top) {
  13612. minY = node.shape.boundingBox.top;
  13613. } // top is negative, bottom is positive
  13614. if (maxY < node.shape.boundingBox.bottom) {
  13615. maxY = node.shape.boundingBox.bottom;
  13616. } // top is negative, bottom is positive
  13617. }
  13618. }
  13619. if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
  13620. minY = 0, maxY = 0, minX = 0, maxX = 0;
  13621. }
  13622. return { minX: minX, maxX: maxX, minY: minY, maxY: maxY };
  13623. }
  13624. /**
  13625. * Find the center position of the network
  13626. *
  13627. * @param {Array.<Node>} allNodes
  13628. * @param {Array.<Node>} [specificNodes=[]]
  13629. * @returns {{minX: number, maxX: number, minY: number, maxY: number}}
  13630. * @static
  13631. */
  13632. }, {
  13633. key: "getRangeCore",
  13634. value: function getRangeCore(allNodes) {
  13635. var specificNodes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  13636. var minY = 1e9,
  13637. maxY = -1e9,
  13638. minX = 1e9,
  13639. maxX = -1e9,
  13640. node;
  13641. if (specificNodes.length > 0) {
  13642. for (var i = 0; i < specificNodes.length; i++) {
  13643. node = allNodes[specificNodes[i]];
  13644. if (minX > node.x) {
  13645. minX = node.x;
  13646. }
  13647. if (maxX < node.x) {
  13648. maxX = node.x;
  13649. }
  13650. if (minY > node.y) {
  13651. minY = node.y;
  13652. } // top is negative, bottom is positive
  13653. if (maxY < node.y) {
  13654. maxY = node.y;
  13655. } // top is negative, bottom is positive
  13656. }
  13657. }
  13658. if (minX === 1e9 && maxX === -1e9 && minY === 1e9 && maxY === -1e9) {
  13659. minY = 0, maxY = 0, minX = 0, maxX = 0;
  13660. }
  13661. return { minX: minX, maxX: maxX, minY: minY, maxY: maxY };
  13662. }
  13663. /**
  13664. * @param {object} range = {minX: minX, maxX: maxX, minY: minY, maxY: maxY};
  13665. * @returns {{x: number, y: number}}
  13666. * @static
  13667. */
  13668. }, {
  13669. key: "findCenter",
  13670. value: function findCenter(range) {
  13671. return {
  13672. x: 0.5 * (range.maxX + range.minX),
  13673. y: 0.5 * (range.maxY + range.minY)
  13674. };
  13675. }
  13676. /**
  13677. * This returns a clone of the options or options of the edge or node to be used for construction of new edges or check functions for new nodes.
  13678. * @param {vis.Item} item
  13679. * @param {'node'|undefined} type
  13680. * @returns {{}}
  13681. * @static
  13682. */
  13683. }, {
  13684. key: "cloneOptions",
  13685. value: function cloneOptions(item, type) {
  13686. var clonedOptions = {};
  13687. if (type === undefined || type === 'node') {
  13688. util.deepExtend(clonedOptions, item.options, true);
  13689. clonedOptions.x = item.x;
  13690. clonedOptions.y = item.y;
  13691. clonedOptions.amountOfConnections = item.edges.length;
  13692. } else {
  13693. util.deepExtend(clonedOptions, item.options, true);
  13694. }
  13695. return clonedOptions;
  13696. }
  13697. }]);
  13698. return NetworkUtil;
  13699. }();
  13700. exports["default"] = NetworkUtil;
  13701. /***/
  13702. }),
  13703. /* 77 */
  13704. /***/
  13705. (function(module, exports, __webpack_require__) {
  13706. module.exports = { "default": __webpack_require__(124), __esModule: true };
  13707. /***/
  13708. }),
  13709. /* 78 */
  13710. /***/
  13711. (function(module, exports, __webpack_require__) {
  13712. // fallback for non-array-like ES3 and non-enumerable old V8 strings
  13713. var cof = __webpack_require__(50);
  13714. // eslint-disable-next-line no-prototype-builtins
  13715. module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it) {
  13716. return cof(it) == 'String' ? it.split('') : Object(it);
  13717. };
  13718. /***/
  13719. }),
  13720. /* 79 */
  13721. /***/
  13722. (function(module, exports, __webpack_require__) {
  13723. "use strict";
  13724. var LIBRARY = __webpack_require__(52);
  13725. var $export = __webpack_require__(17);
  13726. var redefine = __webpack_require__(83);
  13727. var hide = __webpack_require__(26);
  13728. var has = __webpack_require__(22);
  13729. var Iterators = __webpack_require__(31);
  13730. var $iterCreate = __webpack_require__(129);
  13731. var setToStringTag = __webpack_require__(59);
  13732. var getPrototypeOf = __webpack_require__(85);
  13733. var ITERATOR = __webpack_require__(13)('iterator');
  13734. var BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next`
  13735. var FF_ITERATOR = '@@iterator';
  13736. var KEYS = 'keys';
  13737. var VALUES = 'values';
  13738. var returnThis = function() { return this; };
  13739. module.exports = function(Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED) {
  13740. $iterCreate(Constructor, NAME, next);
  13741. var getMethod = function(kind) {
  13742. if (!BUGGY && kind in proto) return proto[kind];
  13743. switch (kind) {
  13744. case KEYS:
  13745. return function keys() { return new Constructor(this, kind); };
  13746. case VALUES:
  13747. return function values() { return new Constructor(this, kind); };
  13748. }
  13749. return function entries() { return new Constructor(this, kind); };
  13750. };
  13751. var TAG = NAME + ' Iterator';
  13752. var DEF_VALUES = DEFAULT == VALUES;
  13753. var VALUES_BUG = false;
  13754. var proto = Base.prototype;
  13755. var $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT];
  13756. var $default = $native || getMethod(DEFAULT);
  13757. var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined;
  13758. var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;
  13759. var methods, key, IteratorPrototype;
  13760. // Fix native
  13761. if ($anyNative) {
  13762. IteratorPrototype = getPrototypeOf($anyNative.call(new Base()));
  13763. if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) {
  13764. // Set @@toStringTag to native iterators
  13765. setToStringTag(IteratorPrototype, TAG, true);
  13766. // fix for some old engines
  13767. if (!LIBRARY && !has(IteratorPrototype, ITERATOR)) hide(IteratorPrototype, ITERATOR, returnThis);
  13768. }
  13769. }
  13770. // fix Array#{values, @@iterator}.name in V8 / FF
  13771. if (DEF_VALUES && $native && $native.name !== VALUES) {
  13772. VALUES_BUG = true;
  13773. $default = function values() { return $native.call(this); };
  13774. }
  13775. // Define iterator
  13776. if ((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])) {
  13777. hide(proto, ITERATOR, $default);
  13778. }
  13779. // Plug for library
  13780. Iterators[NAME] = $default;
  13781. Iterators[TAG] = returnThis;
  13782. if (DEFAULT) {
  13783. methods = {
  13784. values: DEF_VALUES ? $default : getMethod(VALUES),
  13785. keys: IS_SET ? $default : getMethod(KEYS),
  13786. entries: $entries
  13787. };
  13788. if (FORCED)
  13789. for (key in methods) {
  13790. if (!(key in proto)) redefine(proto, key, methods[key]);
  13791. } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods);
  13792. }
  13793. return methods;
  13794. };
  13795. /***/
  13796. }),
  13797. /* 80 */
  13798. /***/
  13799. (function(module, exports, __webpack_require__) {
  13800. // optional / simple context binding
  13801. var aFunction = __webpack_require__(128);
  13802. module.exports = function(fn, that, length) {
  13803. aFunction(fn);
  13804. if (that === undefined) return fn;
  13805. switch (length) {
  13806. case 1:
  13807. return function(a) {
  13808. return fn.call(that, a);
  13809. };
  13810. case 2:
  13811. return function(a, b) {
  13812. return fn.call(that, a, b);
  13813. };
  13814. case 3:
  13815. return function(a, b, c) {
  13816. return fn.call(that, a, b, c);
  13817. };
  13818. }
  13819. return function( /* ...args */ ) {
  13820. return fn.apply(that, arguments);
  13821. };
  13822. };
  13823. /***/
  13824. }),
  13825. /* 81 */
  13826. /***/
  13827. (function(module, exports, __webpack_require__) {
  13828. module.exports = !__webpack_require__(21) && !__webpack_require__(28)(function() {
  13829. return Object.defineProperty(__webpack_require__(82)('div'), 'a', { get: function() { return 7; } }).a != 7;
  13830. });
  13831. /***/
  13832. }),
  13833. /* 82 */
  13834. /***/
  13835. (function(module, exports, __webpack_require__) {
  13836. var isObject = __webpack_require__(32);
  13837. var document = __webpack_require__(18).document;
  13838. // typeof document.createElement is 'object' in old IE
  13839. var is = isObject(document) && isObject(document.createElement);
  13840. module.exports = function(it) {
  13841. return is ? document.createElement(it) : {};
  13842. };
  13843. /***/
  13844. }),
  13845. /* 83 */
  13846. /***/
  13847. (function(module, exports, __webpack_require__) {
  13848. module.exports = __webpack_require__(26);
  13849. /***/
  13850. }),
  13851. /* 84 */
  13852. /***/
  13853. (function(module, exports, __webpack_require__) {
  13854. var has = __webpack_require__(22);
  13855. var toIObject = __webpack_require__(25);
  13856. var arrayIndexOf = __webpack_require__(131)(false);
  13857. var IE_PROTO = __webpack_require__(56)('IE_PROTO');
  13858. module.exports = function(object, names) {
  13859. var O = toIObject(object);
  13860. var i = 0;
  13861. var result = [];
  13862. var key;
  13863. for (key in O)
  13864. if (key != IE_PROTO) has(O, key) && result.push(key);
  13865. // Don't enum bug & hidden keys
  13866. while (names.length > i)
  13867. if (has(O, key = names[i++])) {
  13868. ~arrayIndexOf(result, key) || result.push(key);
  13869. }
  13870. return result;
  13871. };
  13872. /***/
  13873. }),
  13874. /* 85 */
  13875. /***/
  13876. (function(module, exports, __webpack_require__) {
  13877. // 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O)
  13878. var has = __webpack_require__(22);
  13879. var toObject = __webpack_require__(41);
  13880. var IE_PROTO = __webpack_require__(56)('IE_PROTO');
  13881. var ObjectProto = Object.prototype;
  13882. module.exports = Object.getPrototypeOf || function(O) {
  13883. O = toObject(O);
  13884. if (has(O, IE_PROTO)) return O[IE_PROTO];
  13885. if (typeof O.constructor == 'function' && O instanceof O.constructor) {
  13886. return O.constructor.prototype;
  13887. }
  13888. return O instanceof Object ? ObjectProto : null;
  13889. };
  13890. /***/
  13891. }),
  13892. /* 86 */
  13893. /***/
  13894. (function(module, exports, __webpack_require__) {
  13895. // getting tag from 19.1.3.6 Object.prototype.toString()
  13896. var cof = __webpack_require__(50);
  13897. var TAG = __webpack_require__(13)('toStringTag');
  13898. // ES3 wrong here
  13899. var ARG = cof(function() { return arguments; }()) == 'Arguments';
  13900. // fallback for IE11 Script Access Denied error
  13901. var tryGet = function(it, key) {
  13902. try {
  13903. return it[key];
  13904. } catch (e) { /* empty */ }
  13905. };
  13906. module.exports = function(it) {
  13907. var O, T, B;
  13908. return it === undefined ? 'Undefined' : it === null ? 'Null'
  13909. // @@toStringTag case
  13910. :
  13911. typeof(T = tryGet(O = Object(it), TAG)) == 'string' ? T
  13912. // builtinTag case
  13913. :
  13914. ARG ? cof(O)
  13915. // ES3 arguments fallback
  13916. :
  13917. (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B;
  13918. };
  13919. /***/
  13920. }),
  13921. /* 87 */
  13922. /***/
  13923. (function(module, exports, __webpack_require__) {
  13924. // most Object methods by ES6 should accept primitives
  13925. var $export = __webpack_require__(17);
  13926. var core = __webpack_require__(7);
  13927. var fails = __webpack_require__(28);
  13928. module.exports = function(KEY, exec) {
  13929. var fn = (core.Object || {})[KEY] || Object[KEY];
  13930. var exp = {};
  13931. exp[KEY] = exec(fn);
  13932. $export($export.S + $export.F * fails(function() { fn(1); }), 'Object', exp);
  13933. };
  13934. /***/
  13935. }),
  13936. /* 88 */
  13937. /***/
  13938. (function(module, exports, __webpack_require__) {
  13939. // 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O)
  13940. var $keys = __webpack_require__(84);
  13941. var hiddenKeys = __webpack_require__(58).concat('length', 'prototype');
  13942. exports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
  13943. return $keys(O, hiddenKeys);
  13944. };
  13945. /***/
  13946. }),
  13947. /* 89 */
  13948. /***/
  13949. (function(module, exports, __webpack_require__) {
  13950. var pIE = __webpack_require__(42);
  13951. var createDesc = __webpack_require__(39);
  13952. var toIObject = __webpack_require__(25);
  13953. var toPrimitive = __webpack_require__(53);
  13954. var has = __webpack_require__(22);
  13955. var IE8_DOM_DEFINE = __webpack_require__(81);
  13956. var gOPD = Object.getOwnPropertyDescriptor;
  13957. exports.f = __webpack_require__(21) ? gOPD : function getOwnPropertyDescriptor(O, P) {
  13958. O = toIObject(O);
  13959. P = toPrimitive(P, true);
  13960. if (IE8_DOM_DEFINE) try {
  13961. return gOPD(O, P);
  13962. } catch (e) { /* empty */ }
  13963. if (has(O, P)) return createDesc(!pIE.f.call(O, P), O[P]);
  13964. };
  13965. /***/
  13966. }),
  13967. /* 90 */
  13968. /***/
  13969. (function(module, exports, __webpack_require__) {
  13970. module.exports = { "default": __webpack_require__(162), __esModule: true };
  13971. /***/
  13972. }),
  13973. /* 91 */
  13974. /***/
  13975. (function(module, exports, __webpack_require__) {
  13976. "use strict";
  13977. /**
  13978. * @prototype Point2d
  13979. * @param {number} [x]
  13980. * @param {number} [y]
  13981. */
  13982. function Point2d(x, y) {
  13983. this.x = x !== undefined ? x : 0;
  13984. this.y = y !== undefined ? y : 0;
  13985. }
  13986. module.exports = Point2d;
  13987. /***/
  13988. }),
  13989. /* 92 */
  13990. /***/
  13991. (function(module, exports, __webpack_require__) {
  13992. "use strict";
  13993. var util = __webpack_require__(2);
  13994. /**
  13995. * An html slider control with start/stop/prev/next buttons
  13996. *
  13997. * @constructor Slider
  13998. * @param {Element} container The element where the slider will be created
  13999. * @param {Object} options Available options:
  14000. * {boolean} visible If true (default) the
  14001. * slider is visible.
  14002. */
  14003. function Slider(container, options) {
  14004. if (container === undefined) {
  14005. throw new Error('No container element defined');
  14006. }
  14007. this.container = container;
  14008. this.visible = options && options.visible != undefined ? options.visible : true;
  14009. if (this.visible) {
  14010. this.frame = document.createElement('DIV');
  14011. //this.frame.style.backgroundColor = '#E5E5E5';
  14012. this.frame.style.width = '100%';
  14013. this.frame.style.position = 'relative';
  14014. this.container.appendChild(this.frame);
  14015. this.frame.prev = document.createElement('INPUT');
  14016. this.frame.prev.type = 'BUTTON';
  14017. this.frame.prev.value = 'Prev';
  14018. this.frame.appendChild(this.frame.prev);
  14019. this.frame.play = document.createElement('INPUT');
  14020. this.frame.play.type = 'BUTTON';
  14021. this.frame.play.value = 'Play';
  14022. this.frame.appendChild(this.frame.play);
  14023. this.frame.next = document.createElement('INPUT');
  14024. this.frame.next.type = 'BUTTON';
  14025. this.frame.next.value = 'Next';
  14026. this.frame.appendChild(this.frame.next);
  14027. this.frame.bar = document.createElement('INPUT');
  14028. this.frame.bar.type = 'BUTTON';
  14029. this.frame.bar.style.position = 'absolute';
  14030. this.frame.bar.style.border = '1px solid red';
  14031. this.frame.bar.style.width = '100px';
  14032. this.frame.bar.style.height = '6px';
  14033. this.frame.bar.style.borderRadius = '2px';
  14034. this.frame.bar.style.MozBorderRadius = '2px';
  14035. this.frame.bar.style.border = '1px solid #7F7F7F';
  14036. this.frame.bar.style.backgroundColor = '#E5E5E5';
  14037. this.frame.appendChild(this.frame.bar);
  14038. this.frame.slide = document.createElement('INPUT');
  14039. this.frame.slide.type = 'BUTTON';
  14040. this.frame.slide.style.margin = '0px';
  14041. this.frame.slide.value = ' ';
  14042. this.frame.slide.style.position = 'relative';
  14043. this.frame.slide.style.left = '-100px';
  14044. this.frame.appendChild(this.frame.slide);
  14045. // create events
  14046. var me = this;
  14047. this.frame.slide.onmousedown = function(event) {
  14048. me._onMouseDown(event);
  14049. };
  14050. this.frame.prev.onclick = function(event) {
  14051. me.prev(event);
  14052. };
  14053. this.frame.play.onclick = function(event) {
  14054. me.togglePlay(event);
  14055. };
  14056. this.frame.next.onclick = function(event) {
  14057. me.next(event);
  14058. };
  14059. }
  14060. this.onChangeCallback = undefined;
  14061. this.values = [];
  14062. this.index = undefined;
  14063. this.playTimeout = undefined;
  14064. this.playInterval = 1000; // milliseconds
  14065. this.playLoop = true;
  14066. }
  14067. /**
  14068. * Select the previous index
  14069. */
  14070. Slider.prototype.prev = function() {
  14071. var index = this.getIndex();
  14072. if (index > 0) {
  14073. index--;
  14074. this.setIndex(index);
  14075. }
  14076. };
  14077. /**
  14078. * Select the next index
  14079. */
  14080. Slider.prototype.next = function() {
  14081. var index = this.getIndex();
  14082. if (index < this.values.length - 1) {
  14083. index++;
  14084. this.setIndex(index);
  14085. }
  14086. };
  14087. /**
  14088. * Select the next index
  14089. */
  14090. Slider.prototype.playNext = function() {
  14091. var start = new Date();
  14092. var index = this.getIndex();
  14093. if (index < this.values.length - 1) {
  14094. index++;
  14095. this.setIndex(index);
  14096. } else if (this.playLoop) {
  14097. // jump to the start
  14098. index = 0;
  14099. this.setIndex(index);
  14100. }
  14101. var end = new Date();
  14102. var diff = end - start;
  14103. // calculate how much time it to to set the index and to execute the callback
  14104. // function.
  14105. var interval = Math.max(this.playInterval - diff, 0);
  14106. // document.title = diff // TODO: cleanup
  14107. var me = this;
  14108. this.playTimeout = setTimeout(function() {
  14109. me.playNext();
  14110. }, interval);
  14111. };
  14112. /**
  14113. * Toggle start or stop playing
  14114. */
  14115. Slider.prototype.togglePlay = function() {
  14116. if (this.playTimeout === undefined) {
  14117. this.play();
  14118. } else {
  14119. this.stop();
  14120. }
  14121. };
  14122. /**
  14123. * Start playing
  14124. */
  14125. Slider.prototype.play = function() {
  14126. // Test whether already playing
  14127. if (this.playTimeout) return;
  14128. this.playNext();
  14129. if (this.frame) {
  14130. this.frame.play.value = 'Stop';
  14131. }
  14132. };
  14133. /**
  14134. * Stop playing
  14135. */
  14136. Slider.prototype.stop = function() {
  14137. clearInterval(this.playTimeout);
  14138. this.playTimeout = undefined;
  14139. if (this.frame) {
  14140. this.frame.play.value = 'Play';
  14141. }
  14142. };
  14143. /**
  14144. * Set a callback function which will be triggered when the value of the
  14145. * slider bar has changed.
  14146. *
  14147. * @param {function} callback
  14148. */
  14149. Slider.prototype.setOnChangeCallback = function(callback) {
  14150. this.onChangeCallback = callback;
  14151. };
  14152. /**
  14153. * Set the interval for playing the list
  14154. * @param {number} interval The interval in milliseconds
  14155. */
  14156. Slider.prototype.setPlayInterval = function(interval) {
  14157. this.playInterval = interval;
  14158. };
  14159. /**
  14160. * Retrieve the current play interval
  14161. * @return {number} interval The interval in milliseconds
  14162. */
  14163. Slider.prototype.getPlayInterval = function() {
  14164. return this.playInterval;
  14165. };
  14166. /**
  14167. * Set looping on or off
  14168. * @param {boolean} doLoop If true, the slider will jump to the start when
  14169. * the end is passed, and will jump to the end
  14170. * when the start is passed.
  14171. *
  14172. */
  14173. Slider.prototype.setPlayLoop = function(doLoop) {
  14174. this.playLoop = doLoop;
  14175. };
  14176. /**
  14177. * Execute the onchange callback function
  14178. */
  14179. Slider.prototype.onChange = function() {
  14180. if (this.onChangeCallback !== undefined) {
  14181. this.onChangeCallback();
  14182. }
  14183. };
  14184. /**
  14185. * redraw the slider on the correct place
  14186. */
  14187. Slider.prototype.redraw = function() {
  14188. if (this.frame) {
  14189. // resize the bar
  14190. this.frame.bar.style.top = this.frame.clientHeight / 2 - this.frame.bar.offsetHeight / 2 + 'px';
  14191. this.frame.bar.style.width = this.frame.clientWidth - this.frame.prev.clientWidth - this.frame.play.clientWidth - this.frame.next.clientWidth - 30 + 'px';
  14192. // position the slider button
  14193. var left = this.indexToLeft(this.index);
  14194. this.frame.slide.style.left = left + 'px';
  14195. }
  14196. };
  14197. /**
  14198. * Set the list with values for the slider
  14199. * @param {Array} values A javascript array with values (any type)
  14200. */
  14201. Slider.prototype.setValues = function(values) {
  14202. this.values = values;
  14203. if (this.values.length > 0) this.setIndex(0);
  14204. else this.index = undefined;
  14205. };
  14206. /**
  14207. * Select a value by its index
  14208. * @param {number} index
  14209. */
  14210. Slider.prototype.setIndex = function(index) {
  14211. if (index < this.values.length) {
  14212. this.index = index;
  14213. this.redraw();
  14214. this.onChange();
  14215. } else {
  14216. throw new Error('Index out of range');
  14217. }
  14218. };
  14219. /**
  14220. * retrieve the index of the currently selected vaue
  14221. * @return {number} index
  14222. */
  14223. Slider.prototype.getIndex = function() {
  14224. return this.index;
  14225. };
  14226. /**
  14227. * retrieve the currently selected value
  14228. * @return {*} value
  14229. */
  14230. Slider.prototype.get = function() {
  14231. return this.values[this.index];
  14232. };
  14233. Slider.prototype._onMouseDown = function(event) {
  14234. // only react on left mouse button down
  14235. var leftButtonDown = event.which ? event.which === 1 : event.button === 1;
  14236. if (!leftButtonDown) return;
  14237. this.startClientX = event.clientX;
  14238. this.startSlideX = parseFloat(this.frame.slide.style.left);
  14239. this.frame.style.cursor = 'move';
  14240. // add event listeners to handle moving the contents
  14241. // we store the function onmousemove and onmouseup in the graph, so we can
  14242. // remove the eventlisteners lateron in the function mouseUp()
  14243. var me = this;
  14244. this.onmousemove = function(event) {
  14245. me._onMouseMove(event);
  14246. };
  14247. this.onmouseup = function(event) {
  14248. me._onMouseUp(event);
  14249. };
  14250. util.addEventListener(document, 'mousemove', this.onmousemove);
  14251. util.addEventListener(document, 'mouseup', this.onmouseup);
  14252. util.preventDefault(event);
  14253. };
  14254. Slider.prototype.leftToIndex = function(left) {
  14255. var width = parseFloat(this.frame.bar.style.width) - this.frame.slide.clientWidth - 10;
  14256. var x = left - 3;
  14257. var index = Math.round(x / width * (this.values.length - 1));
  14258. if (index < 0) index = 0;
  14259. if (index > this.values.length - 1) index = this.values.length - 1;
  14260. return index;
  14261. };
  14262. Slider.prototype.indexToLeft = function(index) {
  14263. var width = parseFloat(this.frame.bar.style.width) - this.frame.slide.clientWidth - 10;
  14264. var x = index / (this.values.length - 1) * width;
  14265. var left = x + 3;
  14266. return left;
  14267. };
  14268. Slider.prototype._onMouseMove = function(event) {
  14269. var diff = event.clientX - this.startClientX;
  14270. var x = this.startSlideX + diff;
  14271. var index = this.leftToIndex(x);
  14272. this.setIndex(index);
  14273. util.preventDefault();
  14274. };
  14275. Slider.prototype._onMouseUp = function(event) {
  14276. // eslint-disable-line no-unused-vars
  14277. this.frame.style.cursor = 'auto';
  14278. // remove event listeners
  14279. util.removeEventListener(document, 'mousemove', this.onmousemove);
  14280. util.removeEventListener(document, 'mouseup', this.onmouseup);
  14281. util.preventDefault();
  14282. };
  14283. module.exports = Slider;
  14284. /***/
  14285. }),
  14286. /* 93 */
  14287. /***/
  14288. (function(module, exports, __webpack_require__) {
  14289. "use strict";
  14290. /**
  14291. * @prototype StepNumber
  14292. * The class StepNumber is an iterator for Numbers. You provide a start and end
  14293. * value, and a best step size. StepNumber itself rounds to fixed values and
  14294. * a finds the step that best fits the provided step.
  14295. *
  14296. * If prettyStep is true, the step size is chosen as close as possible to the
  14297. * provided step, but being a round value like 1, 2, 5, 10, 20, 50, ....
  14298. *
  14299. * Example usage:
  14300. * var step = new StepNumber(0, 10, 2.5, true);
  14301. * step.start();
  14302. * while (!step.end()) {
  14303. * alert(step.getCurrent());
  14304. * step.next();
  14305. * }
  14306. *
  14307. * Version: 1.0
  14308. *
  14309. * @param {number} start The start value
  14310. * @param {number} end The end value
  14311. * @param {number} step Optional. Step size. Must be a positive value.
  14312. * @param {boolean} prettyStep Optional. If true, the step size is rounded
  14313. * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
  14314. */
  14315. function StepNumber(start, end, step, prettyStep) {
  14316. // set default values
  14317. this._start = 0;
  14318. this._end = 0;
  14319. this._step = 1;
  14320. this.prettyStep = true;
  14321. this.precision = 5;
  14322. this._current = 0;
  14323. this.setRange(start, end, step, prettyStep);
  14324. }
  14325. /**
  14326. * Check for input values, to prevent disasters from happening
  14327. *
  14328. * Source: http://stackoverflow.com/a/1830844
  14329. *
  14330. * @param {string} n
  14331. * @returns {boolean}
  14332. */
  14333. StepNumber.prototype.isNumeric = function(n) {
  14334. return !isNaN(parseFloat(n)) && isFinite(n);
  14335. };
  14336. /**
  14337. * Set a new range: start, end and step.
  14338. *
  14339. * @param {number} start The start value
  14340. * @param {number} end The end value
  14341. * @param {number} step Optional. Step size. Must be a positive value.
  14342. * @param {boolean} prettyStep Optional. If true, the step size is rounded
  14343. * To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
  14344. */
  14345. StepNumber.prototype.setRange = function(start, end, step, prettyStep) {
  14346. if (!this.isNumeric(start)) {
  14347. throw new Error('Parameter \'start\' is not numeric; value: ' + start);
  14348. }
  14349. if (!this.isNumeric(end)) {
  14350. throw new Error('Parameter \'end\' is not numeric; value: ' + start);
  14351. }
  14352. if (!this.isNumeric(step)) {
  14353. throw new Error('Parameter \'step\' is not numeric; value: ' + start);
  14354. }
  14355. this._start = start ? start : 0;
  14356. this._end = end ? end : 0;
  14357. this.setStep(step, prettyStep);
  14358. };
  14359. /**
  14360. * Set a new step size
  14361. * @param {number} step New step size. Must be a positive value
  14362. * @param {boolean} prettyStep Optional. If true, the provided step is rounded
  14363. * to a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
  14364. */
  14365. StepNumber.prototype.setStep = function(step, prettyStep) {
  14366. if (step === undefined || step <= 0) return;
  14367. if (prettyStep !== undefined) this.prettyStep = prettyStep;
  14368. if (this.prettyStep === true) this._step = StepNumber.calculatePrettyStep(step);
  14369. else this._step = step;
  14370. };
  14371. /**
  14372. * Calculate a nice step size, closest to the desired step size.
  14373. * Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an
  14374. * integer Number. For example 1, 2, 5, 10, 20, 50, etc...
  14375. * @param {number} step Desired step size
  14376. * @return {number} Nice step size
  14377. */
  14378. StepNumber.calculatePrettyStep = function(step) {
  14379. var log10 = function log10(x) {
  14380. return Math.log(x) / Math.LN10;
  14381. };
  14382. // try three steps (multiple of 1, 2, or 5
  14383. var step1 = Math.pow(10, Math.round(log10(step))),
  14384. step2 = 2 * Math.pow(10, Math.round(log10(step / 2))),
  14385. step5 = 5 * Math.pow(10, Math.round(log10(step / 5)));
  14386. // choose the best step (closest to minimum step)
  14387. var prettyStep = step1;
  14388. if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2;
  14389. if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5;
  14390. // for safety
  14391. if (prettyStep <= 0) {
  14392. prettyStep = 1;
  14393. }
  14394. return prettyStep;
  14395. };
  14396. /**
  14397. * returns the current value of the step
  14398. * @return {number} current value
  14399. */
  14400. StepNumber.prototype.getCurrent = function() {
  14401. return parseFloat(this._current.toPrecision(this.precision));
  14402. };
  14403. /**
  14404. * returns the current step size
  14405. * @return {number} current step size
  14406. */
  14407. StepNumber.prototype.getStep = function() {
  14408. return this._step;
  14409. };
  14410. /**
  14411. * Set the current to its starting value.
  14412. *
  14413. * By default, this will be the largest value smaller than start, which
  14414. * is a multiple of the step size.
  14415. *
  14416. * Parameters checkFirst is optional, default false.
  14417. * If set to true, move the current value one step if smaller than start.
  14418. *
  14419. * @param {boolean} [checkFirst=false]
  14420. */
  14421. StepNumber.prototype.start = function(checkFirst) {
  14422. if (checkFirst === undefined) {
  14423. checkFirst = false;
  14424. }
  14425. this._current = this._start - this._start % this._step;
  14426. if (checkFirst) {
  14427. if (this.getCurrent() < this._start) {
  14428. this.next();
  14429. }
  14430. }
  14431. };
  14432. /**
  14433. * Do a step, add the step size to the current value
  14434. */
  14435. StepNumber.prototype.next = function() {
  14436. this._current += this._step;
  14437. };
  14438. /**
  14439. * Returns true whether the end is reached
  14440. * @return {boolean} True if the current value has passed the end value.
  14441. */
  14442. StepNumber.prototype.end = function() {
  14443. return this._current > this._end;
  14444. };
  14445. module.exports = StepNumber;
  14446. /***/
  14447. }),
  14448. /* 94 */
  14449. /***/
  14450. (function(module, exports, __webpack_require__) {
  14451. "use strict";
  14452. var _typeof2 = __webpack_require__(6);
  14453. var _typeof3 = _interopRequireDefault(_typeof2);
  14454. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  14455. ////////////////////////////////////////////////////////////////////////////////
  14456. // This modules handles the options for Graph3d.
  14457. //
  14458. ////////////////////////////////////////////////////////////////////////////////
  14459. var util = __webpack_require__(2);
  14460. var Camera = __webpack_require__(95);
  14461. var Point3d = __webpack_require__(34);
  14462. // enumerate the available styles
  14463. var STYLE = {
  14464. BAR: 0,
  14465. BARCOLOR: 1,
  14466. BARSIZE: 2,
  14467. DOT: 3,
  14468. DOTLINE: 4,
  14469. DOTCOLOR: 5,
  14470. DOTSIZE: 6,
  14471. GRID: 7,
  14472. LINE: 8,
  14473. SURFACE: 9
  14474. };
  14475. // The string representations of the styles
  14476. var STYLENAME = {
  14477. 'dot': STYLE.DOT,
  14478. 'dot-line': STYLE.DOTLINE,
  14479. 'dot-color': STYLE.DOTCOLOR,
  14480. 'dot-size': STYLE.DOTSIZE,
  14481. 'line': STYLE.LINE,
  14482. 'grid': STYLE.GRID,
  14483. 'surface': STYLE.SURFACE,
  14484. 'bar': STYLE.BAR,
  14485. 'bar-color': STYLE.BARCOLOR,
  14486. 'bar-size': STYLE.BARSIZE
  14487. };
  14488. /**
  14489. * Field names in the options hash which are of relevance to the user.
  14490. *
  14491. * Specifically, these are the fields which require no special handling,
  14492. * and can be directly copied over.
  14493. */
  14494. var OPTIONKEYS = ['width', 'height', 'filterLabel', 'legendLabel', 'xLabel', 'yLabel', 'zLabel', 'xValueLabel', 'yValueLabel', 'zValueLabel', 'showXAxis', 'showYAxis', 'showZAxis', 'showGrid', 'showPerspective', 'showShadow', 'keepAspectRatio', 'verticalRatio', 'dotSizeRatio', 'dotSizeMinFraction', 'dotSizeMaxFraction', 'showAnimationControls', 'animationInterval', 'animationPreload', 'animationAutoStart', 'axisColor', 'gridColor', 'xCenter', 'yCenter'];
  14495. /**
  14496. * Field names in the options hash which are of relevance to the user.
  14497. *
  14498. * Same as OPTIONKEYS, but internally these fields are stored with
  14499. * prefix 'default' in the name.
  14500. */
  14501. var PREFIXEDOPTIONKEYS = ['xBarWidth', 'yBarWidth', 'valueMin', 'valueMax', 'xMin', 'xMax', 'xStep', 'yMin', 'yMax', 'yStep', 'zMin', 'zMax', 'zStep'];
  14502. // Placeholder for DEFAULTS reference
  14503. var DEFAULTS = undefined;
  14504. /**
  14505. * Check if given hash is empty.
  14506. *
  14507. * Source: http://stackoverflow.com/a/679937
  14508. *
  14509. * @param {object} obj
  14510. * @returns {boolean}
  14511. */
  14512. function isEmpty(obj) {
  14513. for (var prop in obj) {
  14514. if (obj.hasOwnProperty(prop)) return false;
  14515. }
  14516. return true;
  14517. }
  14518. /**
  14519. * Make first letter of parameter upper case.
  14520. *
  14521. * Source: http://stackoverflow.com/a/1026087
  14522. *
  14523. * @param {string} str
  14524. * @returns {string}
  14525. */
  14526. function capitalize(str) {
  14527. if (str === undefined || str === "" || typeof str != "string") {
  14528. return str;
  14529. }
  14530. return str.charAt(0).toUpperCase() + str.slice(1);
  14531. }
  14532. /**
  14533. * Add a prefix to a field name, taking style guide into account
  14534. *
  14535. * @param {string} prefix
  14536. * @param {string} fieldName
  14537. * @returns {string}
  14538. */
  14539. function prefixFieldName(prefix, fieldName) {
  14540. if (prefix === undefined || prefix === "") {
  14541. return fieldName;
  14542. }
  14543. return prefix + capitalize(fieldName);
  14544. }
  14545. /**
  14546. * Forcibly copy fields from src to dst in a controlled manner.
  14547. *
  14548. * A given field in dst will always be overwitten. If this field
  14549. * is undefined or not present in src, the field in dst will
  14550. * be explicitly set to undefined.
  14551. *
  14552. * The intention here is to be able to reset all option fields.
  14553. *
  14554. * Only the fields mentioned in array 'fields' will be handled.
  14555. *
  14556. * @param {object} src
  14557. * @param {object} dst
  14558. * @param {array<string>} fields array with names of fields to copy
  14559. * @param {string} [prefix] prefix to use for the target fields.
  14560. */
  14561. function forceCopy(src, dst, fields, prefix) {
  14562. var srcKey;
  14563. var dstKey;
  14564. for (var i = 0; i < fields.length; ++i) {
  14565. srcKey = fields[i];
  14566. dstKey = prefixFieldName(prefix, srcKey);
  14567. dst[dstKey] = src[srcKey];
  14568. }
  14569. }
  14570. /**
  14571. * Copy fields from src to dst in a safe and controlled manner.
  14572. *
  14573. * Only the fields mentioned in array 'fields' will be copied over,
  14574. * and only if these are actually defined.
  14575. *
  14576. * @param {object} src
  14577. * @param {object} dst
  14578. * @param {array<string>} fields array with names of fields to copy
  14579. * @param {string} [prefix] prefix to use for the target fields.
  14580. */
  14581. function safeCopy(src, dst, fields, prefix) {
  14582. var srcKey;
  14583. var dstKey;
  14584. for (var i = 0; i < fields.length; ++i) {
  14585. srcKey = fields[i];
  14586. if (src[srcKey] === undefined) continue;
  14587. dstKey = prefixFieldName(prefix, srcKey);
  14588. dst[dstKey] = src[srcKey];
  14589. }
  14590. }
  14591. /**
  14592. * Initialize dst with the values in src.
  14593. *
  14594. * src is the hash with the default values.
  14595. * A reference DEFAULTS to this hash is stored locally for
  14596. * further handling.
  14597. *
  14598. * For now, dst is assumed to be a Graph3d instance.
  14599. * @param {object} src
  14600. * @param {object} dst
  14601. */
  14602. function setDefaults(src, dst) {
  14603. if (src === undefined || isEmpty(src)) {
  14604. throw new Error('No DEFAULTS passed');
  14605. }
  14606. if (dst === undefined) {
  14607. throw new Error('No dst passed');
  14608. }
  14609. // Remember defaults for future reference
  14610. DEFAULTS = src;
  14611. // Handle the defaults which can be simply copied over
  14612. forceCopy(src, dst, OPTIONKEYS);
  14613. forceCopy(src, dst, PREFIXEDOPTIONKEYS, 'default');
  14614. // Handle the more complex ('special') fields
  14615. setSpecialSettings(src, dst);
  14616. // Following are internal fields, not part of the user settings
  14617. dst.margin = 10; // px
  14618. dst.showGrayBottom = false; // TODO: this does not work correctly
  14619. dst.showTooltip = false;
  14620. dst.onclick_callback = null;
  14621. dst.eye = new Point3d(0, 0, -1); // TODO: set eye.z about 3/4 of the width of the window?
  14622. }
  14623. /**
  14624. *
  14625. * @param {object} options
  14626. * @param {object} dst
  14627. */
  14628. function setOptions(options, dst) {
  14629. if (options === undefined) {
  14630. return;
  14631. }
  14632. if (dst === undefined) {
  14633. throw new Error('No dst passed');
  14634. }
  14635. if (DEFAULTS === undefined || isEmpty(DEFAULTS)) {
  14636. throw new Error('DEFAULTS not set for module Settings');
  14637. }
  14638. // Handle the parameters which can be simply copied over
  14639. safeCopy(options, dst, OPTIONKEYS);
  14640. safeCopy(options, dst, PREFIXEDOPTIONKEYS, 'default');
  14641. // Handle the more complex ('special') fields
  14642. setSpecialSettings(options, dst);
  14643. }
  14644. /**
  14645. * Special handling for certain parameters
  14646. *
  14647. * 'Special' here means: setting requires more than a simple copy
  14648. *
  14649. * @param {object} src
  14650. * @param {object} dst
  14651. */
  14652. function setSpecialSettings(src, dst) {
  14653. if (src.backgroundColor !== undefined) {
  14654. setBackgroundColor(src.backgroundColor, dst);
  14655. }
  14656. setDataColor(src.dataColor, dst);
  14657. setStyle(src.style, dst);
  14658. setShowLegend(src.showLegend, dst);
  14659. setCameraPosition(src.cameraPosition, dst);
  14660. // As special fields go, this is an easy one; just a translation of the name.
  14661. // Can't use this.tooltip directly, because that field exists internally
  14662. if (src.tooltip !== undefined) {
  14663. dst.showTooltip = src.tooltip;
  14664. }
  14665. if (src.onclick != undefined) {
  14666. dst.onclick_callback = src.onclick;
  14667. }
  14668. if (src.tooltipStyle !== undefined) {
  14669. util.selectiveDeepExtend(['tooltipStyle'], dst, src);
  14670. }
  14671. }
  14672. /**
  14673. * Set the value of setting 'showLegend'
  14674. *
  14675. * This depends on the value of the style fields, so it must be called
  14676. * after the style field has been initialized.
  14677. *
  14678. * @param {boolean} showLegend
  14679. * @param {object} dst
  14680. */
  14681. function setShowLegend(showLegend, dst) {
  14682. if (showLegend === undefined) {
  14683. // If the default was auto, make a choice for this field
  14684. var isAutoByDefault = DEFAULTS.showLegend === undefined;
  14685. if (isAutoByDefault) {
  14686. // these styles default to having legends
  14687. var isLegendGraphStyle = dst.style === STYLE.DOTCOLOR || dst.style === STYLE.DOTSIZE;
  14688. dst.showLegend = isLegendGraphStyle;
  14689. } else {
  14690. // Leave current value as is
  14691. }
  14692. } else {
  14693. dst.showLegend = showLegend;
  14694. }
  14695. }
  14696. /**
  14697. * Retrieve the style index from given styleName
  14698. * @param {string} styleName Style name such as 'dot', 'grid', 'dot-line'
  14699. * @return {number} styleNumber Enumeration value representing the style, or -1
  14700. * when not found
  14701. */
  14702. function getStyleNumberByName(styleName) {
  14703. var number = STYLENAME[styleName];
  14704. if (number === undefined) {
  14705. return -1;
  14706. }
  14707. return number;
  14708. }
  14709. /**
  14710. * Check if given number is a valid style number.
  14711. *
  14712. * @param {string | number} style
  14713. * @return {boolean} true if valid, false otherwise
  14714. */
  14715. function checkStyleNumber(style) {
  14716. var valid = false;
  14717. for (var n in STYLE) {
  14718. if (STYLE[n] === style) {
  14719. valid = true;
  14720. break;
  14721. }
  14722. }
  14723. return valid;
  14724. }
  14725. /**
  14726. *
  14727. * @param {string | number} style
  14728. * @param {Object} dst
  14729. */
  14730. function setStyle(style, dst) {
  14731. if (style === undefined) {
  14732. return; // Nothing to do
  14733. }
  14734. var styleNumber;
  14735. if (typeof style === 'string') {
  14736. styleNumber = getStyleNumberByName(style);
  14737. if (styleNumber === -1) {
  14738. throw new Error('Style \'' + style + '\' is invalid');
  14739. }
  14740. } else {
  14741. // Do a pedantic check on style number value
  14742. if (!checkStyleNumber(style)) {
  14743. throw new Error('Style \'' + style + '\' is invalid');
  14744. }
  14745. styleNumber = style;
  14746. }
  14747. dst.style = styleNumber;
  14748. }
  14749. /**
  14750. * Set the background styling for the graph
  14751. * @param {string | {fill: string, stroke: string, strokeWidth: string}} backgroundColor
  14752. * @param {Object} dst
  14753. */
  14754. function setBackgroundColor(backgroundColor, dst) {
  14755. var fill = 'white';
  14756. var stroke = 'gray';
  14757. var strokeWidth = 1;
  14758. if (typeof backgroundColor === 'string') {
  14759. fill = backgroundColor;
  14760. stroke = 'none';
  14761. strokeWidth = 0;
  14762. } else if ((typeof backgroundColor === 'undefined' ? 'undefined' : (0, _typeof3['default'])(backgroundColor)) === 'object') {
  14763. if (backgroundColor.fill !== undefined) fill = backgroundColor.fill;
  14764. if (backgroundColor.stroke !== undefined) stroke = backgroundColor.stroke;
  14765. if (backgroundColor.strokeWidth !== undefined) strokeWidth = backgroundColor.strokeWidth;
  14766. } else {
  14767. throw new Error('Unsupported type of backgroundColor');
  14768. }
  14769. dst.frame.style.backgroundColor = fill;
  14770. dst.frame.style.borderColor = stroke;
  14771. dst.frame.style.borderWidth = strokeWidth + 'px';
  14772. dst.frame.style.borderStyle = 'solid';
  14773. }
  14774. /**
  14775. *
  14776. * @param {string | Object} dataColor
  14777. * @param {Object} dst
  14778. */
  14779. function setDataColor(dataColor, dst) {
  14780. if (dataColor === undefined) {
  14781. return; // Nothing to do
  14782. }
  14783. if (dst.dataColor === undefined) {
  14784. dst.dataColor = {};
  14785. }
  14786. if (typeof dataColor === 'string') {
  14787. dst.dataColor.fill = dataColor;
  14788. dst.dataColor.stroke = dataColor;
  14789. } else {
  14790. if (dataColor.fill) {
  14791. dst.dataColor.fill = dataColor.fill;
  14792. }
  14793. if (dataColor.stroke) {
  14794. dst.dataColor.stroke = dataColor.stroke;
  14795. }
  14796. if (dataColor.strokeWidth !== undefined) {
  14797. dst.dataColor.strokeWidth = dataColor.strokeWidth;
  14798. }
  14799. }
  14800. }
  14801. /**
  14802. *
  14803. * @param {Object} cameraPosition
  14804. * @param {Object} dst
  14805. */
  14806. function setCameraPosition(cameraPosition, dst) {
  14807. var camPos = cameraPosition;
  14808. if (camPos === undefined) {
  14809. return;
  14810. }
  14811. if (dst.camera === undefined) {
  14812. dst.camera = new Camera();
  14813. }
  14814. dst.camera.setArmRotation(camPos.horizontal, camPos.vertical);
  14815. dst.camera.setArmLength(camPos.distance);
  14816. }
  14817. module.exports.STYLE = STYLE;
  14818. module.exports.setDefaults = setDefaults;
  14819. module.exports.setOptions = setOptions;
  14820. module.exports.setCameraPosition = setCameraPosition;
  14821. /***/
  14822. }),
  14823. /* 95 */
  14824. /***/
  14825. (function(module, exports, __webpack_require__) {
  14826. "use strict";
  14827. var _sign = __webpack_require__(165);
  14828. var _sign2 = _interopRequireDefault(_sign);
  14829. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  14830. var Point3d = __webpack_require__(34);
  14831. /**
  14832. * The camera is mounted on a (virtual) camera arm. The camera arm can rotate
  14833. * The camera is always looking in the direction of the origin of the arm.
  14834. * This way, the camera always rotates around one fixed point, the location
  14835. * of the camera arm.
  14836. *
  14837. * Documentation:
  14838. * http://en.wikipedia.org/wiki/3D_projection
  14839. * @class Camera
  14840. */
  14841. function Camera() {
  14842. this.armLocation = new Point3d();
  14843. this.armRotation = {};
  14844. this.armRotation.horizontal = 0;
  14845. this.armRotation.vertical = 0;
  14846. this.armLength = 1.7;
  14847. this.cameraOffset = new Point3d();
  14848. this.offsetMultiplier = 0.6;
  14849. this.cameraLocation = new Point3d();
  14850. this.cameraRotation = new Point3d(0.5 * Math.PI, 0, 0);
  14851. this.calculateCameraOrientation();
  14852. }
  14853. /**
  14854. * Set offset camera in camera coordinates
  14855. * @param {number} x offset by camera horisontal
  14856. * @param {number} y offset by camera vertical
  14857. */
  14858. Camera.prototype.setOffset = function(x, y) {
  14859. var abs = Math.abs,
  14860. sign = _sign2['default'],
  14861. mul = this.offsetMultiplier,
  14862. border = this.armLength * mul;
  14863. if (abs(x) > border) {
  14864. x = sign(x) * border;
  14865. }
  14866. if (abs(y) > border) {
  14867. y = sign(y) * border;
  14868. }
  14869. this.cameraOffset.x = x;
  14870. this.cameraOffset.y = y;
  14871. this.calculateCameraOrientation();
  14872. };
  14873. /**
  14874. * Get camera offset by horizontal and vertical
  14875. * @returns {number}
  14876. */
  14877. Camera.prototype.getOffset = function() {
  14878. return this.cameraOffset;
  14879. };
  14880. /**
  14881. * Set the location (origin) of the arm
  14882. * @param {number} x Normalized value of x
  14883. * @param {number} y Normalized value of y
  14884. * @param {number} z Normalized value of z
  14885. */
  14886. Camera.prototype.setArmLocation = function(x, y, z) {
  14887. this.armLocation.x = x;
  14888. this.armLocation.y = y;
  14889. this.armLocation.z = z;
  14890. this.calculateCameraOrientation();
  14891. };
  14892. /**
  14893. * Set the rotation of the camera arm
  14894. * @param {number} horizontal The horizontal rotation, between 0 and 2*PI.
  14895. * Optional, can be left undefined.
  14896. * @param {number} vertical The vertical rotation, between 0 and 0.5*PI
  14897. * if vertical=0.5*PI, the graph is shown from the
  14898. * top. Optional, can be left undefined.
  14899. */
  14900. Camera.prototype.setArmRotation = function(horizontal, vertical) {
  14901. if (horizontal !== undefined) {
  14902. this.armRotation.horizontal = horizontal;
  14903. }
  14904. if (vertical !== undefined) {
  14905. this.armRotation.vertical = vertical;
  14906. if (this.armRotation.vertical < 0) this.armRotation.vertical = 0;
  14907. if (this.armRotation.vertical > 0.5 * Math.PI) this.armRotation.vertical = 0.5 * Math.PI;
  14908. }
  14909. if (horizontal !== undefined || vertical !== undefined) {
  14910. this.calculateCameraOrientation();
  14911. }
  14912. };
  14913. /**
  14914. * Retrieve the current arm rotation
  14915. * @return {object} An object with parameters horizontal and vertical
  14916. */
  14917. Camera.prototype.getArmRotation = function() {
  14918. var rot = {};
  14919. rot.horizontal = this.armRotation.horizontal;
  14920. rot.vertical = this.armRotation.vertical;
  14921. return rot;
  14922. };
  14923. /**
  14924. * Set the (normalized) length of the camera arm.
  14925. * @param {number} length A length between 0.71 and 5.0
  14926. */
  14927. Camera.prototype.setArmLength = function(length) {
  14928. if (length === undefined) return;
  14929. this.armLength = length;
  14930. // Radius must be larger than the corner of the graph,
  14931. // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the
  14932. // graph
  14933. if (this.armLength < 0.71) this.armLength = 0.71;
  14934. if (this.armLength > 5.0) this.armLength = 5.0;
  14935. this.setOffset(this.cameraOffset.x, this.cameraOffset.y);
  14936. this.calculateCameraOrientation();
  14937. };
  14938. /**
  14939. * Retrieve the arm length
  14940. * @return {number} length
  14941. */
  14942. Camera.prototype.getArmLength = function() {
  14943. return this.armLength;
  14944. };
  14945. /**
  14946. * Retrieve the camera location
  14947. * @return {Point3d} cameraLocation
  14948. */
  14949. Camera.prototype.getCameraLocation = function() {
  14950. return this.cameraLocation;
  14951. };
  14952. /**
  14953. * Retrieve the camera rotation
  14954. * @return {Point3d} cameraRotation
  14955. */
  14956. Camera.prototype.getCameraRotation = function() {
  14957. return this.cameraRotation;
  14958. };
  14959. /**
  14960. * Calculate the location and rotation of the camera based on the
  14961. * position and orientation of the camera arm
  14962. */
  14963. Camera.prototype.calculateCameraOrientation = function() {
  14964. // calculate location of the camera
  14965. this.cameraLocation.x = this.armLocation.x - this.armLength * Math.sin(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical);
  14966. this.cameraLocation.y = this.armLocation.y - this.armLength * Math.cos(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical);
  14967. this.cameraLocation.z = this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical);
  14968. // calculate rotation of the camera
  14969. this.cameraRotation.x = Math.PI / 2 - this.armRotation.vertical;
  14970. this.cameraRotation.y = 0;
  14971. this.cameraRotation.z = -this.armRotation.horizontal;
  14972. var xa = this.cameraRotation.x;
  14973. var za = this.cameraRotation.z;
  14974. var dx = this.cameraOffset.x;
  14975. var dy = this.cameraOffset.y;
  14976. var sin = Math.sin,
  14977. cos = Math.cos;
  14978. this.cameraLocation.x = this.cameraLocation.x + dx * cos(za) + dy * -sin(za) * cos(xa);
  14979. this.cameraLocation.y = this.cameraLocation.y + dx * sin(za) + dy * cos(za) * cos(xa);
  14980. this.cameraLocation.z = this.cameraLocation.z + dy * sin(xa);
  14981. };
  14982. module.exports = Camera;
  14983. /***/
  14984. }),
  14985. /* 96 */
  14986. /***/
  14987. (function(module, exports, __webpack_require__) {
  14988. "use strict";
  14989. var DataView = __webpack_require__(12);
  14990. /**
  14991. * @class Filter
  14992. *
  14993. * @param {DataGroup} dataGroup the data group
  14994. * @param {number} column The index of the column to be filtered
  14995. * @param {Graph3d} graph The graph
  14996. */
  14997. function Filter(dataGroup, column, graph) {
  14998. this.dataGroup = dataGroup;
  14999. this.column = column;
  15000. this.graph = graph; // the parent graph
  15001. this.index = undefined;
  15002. this.value = undefined;
  15003. // read all distinct values and select the first one
  15004. this.values = dataGroup.getDistinctValues(this.column);
  15005. if (this.values.length > 0) {
  15006. this.selectValue(0);
  15007. }
  15008. // create an array with the filtered datapoints. this will be loaded afterwards
  15009. this.dataPoints = [];
  15010. this.loaded = false;
  15011. this.onLoadCallback = undefined;
  15012. if (graph.animationPreload) {
  15013. this.loaded = false;
  15014. this.loadInBackground();
  15015. } else {
  15016. this.loaded = true;
  15017. }
  15018. }
  15019. /**
  15020. * Return the label
  15021. * @return {string} label
  15022. */
  15023. Filter.prototype.isLoaded = function() {
  15024. return this.loaded;
  15025. };
  15026. /**
  15027. * Return the loaded progress
  15028. * @return {number} percentage between 0 and 100
  15029. */
  15030. Filter.prototype.getLoadedProgress = function() {
  15031. var len = this.values.length;
  15032. var i = 0;
  15033. while (this.dataPoints[i]) {
  15034. i++;
  15035. }
  15036. return Math.round(i / len * 100);
  15037. };
  15038. /**
  15039. * Return the label
  15040. * @return {string} label
  15041. */
  15042. Filter.prototype.getLabel = function() {
  15043. return this.graph.filterLabel;
  15044. };
  15045. /**
  15046. * Return the columnIndex of the filter
  15047. * @return {number} columnIndex
  15048. */
  15049. Filter.prototype.getColumn = function() {
  15050. return this.column;
  15051. };
  15052. /**
  15053. * Return the currently selected value. Returns undefined if there is no selection
  15054. * @return {*} value
  15055. */
  15056. Filter.prototype.getSelectedValue = function() {
  15057. if (this.index === undefined) return undefined;
  15058. return this.values[this.index];
  15059. };
  15060. /**
  15061. * Retrieve all values of the filter
  15062. * @return {Array} values
  15063. */
  15064. Filter.prototype.getValues = function() {
  15065. return this.values;
  15066. };
  15067. /**
  15068. * Retrieve one value of the filter
  15069. * @param {number} index
  15070. * @return {*} value
  15071. */
  15072. Filter.prototype.getValue = function(index) {
  15073. if (index >= this.values.length) throw new Error('Index out of range');
  15074. return this.values[index];
  15075. };
  15076. /**
  15077. * Retrieve the (filtered) dataPoints for the currently selected filter index
  15078. * @param {number} [index] (optional)
  15079. * @return {Array} dataPoints
  15080. */
  15081. Filter.prototype._getDataPoints = function(index) {
  15082. if (index === undefined) index = this.index;
  15083. if (index === undefined) return [];
  15084. var dataPoints;
  15085. if (this.dataPoints[index]) {
  15086. dataPoints = this.dataPoints[index];
  15087. } else {
  15088. var f = {};
  15089. f.column = this.column;
  15090. f.value = this.values[index];
  15091. var dataView = new DataView(this.dataGroup.getDataSet(), {
  15092. filter: function filter(item) {
  15093. return item[f.column] == f.value;
  15094. }
  15095. }).get();
  15096. dataPoints = this.dataGroup._getDataPoints(dataView);
  15097. this.dataPoints[index] = dataPoints;
  15098. }
  15099. return dataPoints;
  15100. };
  15101. /**
  15102. * Set a callback function when the filter is fully loaded.
  15103. *
  15104. * @param {function} callback
  15105. */
  15106. Filter.prototype.setOnLoadCallback = function(callback) {
  15107. this.onLoadCallback = callback;
  15108. };
  15109. /**
  15110. * Add a value to the list with available values for this filter
  15111. * No double entries will be created.
  15112. * @param {number} index
  15113. */
  15114. Filter.prototype.selectValue = function(index) {
  15115. if (index >= this.values.length) throw new Error('Index out of range');
  15116. this.index = index;
  15117. this.value = this.values[index];
  15118. };
  15119. /**
  15120. * Load all filtered rows in the background one by one
  15121. * Start this method without providing an index!
  15122. *
  15123. * @param {number} [index=0]
  15124. */
  15125. Filter.prototype.loadInBackground = function(index) {
  15126. if (index === undefined) index = 0;
  15127. var frame = this.graph.frame;
  15128. if (index < this.values.length) {
  15129. // create a progress box
  15130. if (frame.progress === undefined) {
  15131. frame.progress = document.createElement('DIV');
  15132. frame.progress.style.position = 'absolute';
  15133. frame.progress.style.color = 'gray';
  15134. frame.appendChild(frame.progress);
  15135. }
  15136. var progress = this.getLoadedProgress();
  15137. frame.progress.innerHTML = 'Loading animation... ' + progress + '%';
  15138. // TODO: this is no nice solution...
  15139. frame.progress.style.bottom = 60 + 'px'; // TODO: use height of slider
  15140. frame.progress.style.left = 10 + 'px';
  15141. var me = this;
  15142. setTimeout(function() {
  15143. me.loadInBackground(index + 1);
  15144. }, 10);
  15145. this.loaded = false;
  15146. } else {
  15147. this.loaded = true;
  15148. // remove the progress box
  15149. if (frame.progress !== undefined) {
  15150. frame.removeChild(frame.progress);
  15151. frame.progress = undefined;
  15152. }
  15153. if (this.onLoadCallback) this.onLoadCallback();
  15154. }
  15155. };
  15156. module.exports = Filter;
  15157. /***/
  15158. }),
  15159. /* 97 */
  15160. /***/
  15161. (function(module, exports, __webpack_require__) {
  15162. "use strict";
  15163. var keycharm = __webpack_require__(35);
  15164. var Emitter = __webpack_require__(44);
  15165. var Hammer = __webpack_require__(10);
  15166. var util = __webpack_require__(2);
  15167. /**
  15168. * Turn an element into an clickToUse element.
  15169. * When not active, the element has a transparent overlay. When the overlay is
  15170. * clicked, the mode is changed to active.
  15171. * When active, the element is displayed with a blue border around it, and
  15172. * the interactive contents of the element can be used. When clicked outside
  15173. * the element, the elements mode is changed to inactive.
  15174. * @param {Element} container
  15175. * @constructor Activator
  15176. */
  15177. function Activator(container) {
  15178. this.active = false;
  15179. this.dom = {
  15180. container: container
  15181. };
  15182. this.dom.overlay = document.createElement('div');
  15183. this.dom.overlay.className = 'vis-overlay';
  15184. this.dom.container.appendChild(this.dom.overlay);
  15185. this.hammer = Hammer(this.dom.overlay);
  15186. this.hammer.on('tap', this._onTapOverlay.bind(this));
  15187. // block all touch events (except tap)
  15188. var me = this;
  15189. var events = ['tap', 'doubletap', 'press', 'pinch', 'pan', 'panstart', 'panmove', 'panend'];
  15190. events.forEach(function(event) {
  15191. me.hammer.on(event, function(event) {
  15192. event.stopPropagation();
  15193. });
  15194. });
  15195. // attach a click event to the window, in order to deactivate when clicking outside the timeline
  15196. if (document && document.body) {
  15197. this.onClick = function(event) {
  15198. if (!_hasParent(event.target, container)) {
  15199. me.deactivate();
  15200. }
  15201. };
  15202. document.body.addEventListener('click', this.onClick);
  15203. }
  15204. if (this.keycharm !== undefined) {
  15205. this.keycharm.destroy();
  15206. }
  15207. this.keycharm = keycharm();
  15208. // keycharm listener only bounded when active)
  15209. this.escListener = this.deactivate.bind(this);
  15210. }
  15211. // turn into an event emitter
  15212. Emitter(Activator.prototype);
  15213. // The currently active activator
  15214. Activator.current = null;
  15215. /**
  15216. * Destroy the activator. Cleans up all created DOM and event listeners
  15217. */
  15218. Activator.prototype.destroy = function() {
  15219. this.deactivate();
  15220. // remove dom
  15221. this.dom.overlay.parentNode.removeChild(this.dom.overlay);
  15222. // remove global event listener
  15223. if (this.onClick) {
  15224. document.body.removeEventListener('click', this.onClick);
  15225. }
  15226. // cleanup hammer instances
  15227. this.hammer.destroy();
  15228. this.hammer = null;
  15229. // FIXME: cleaning up hammer instances doesn't work (Timeline not removed from memory)
  15230. };
  15231. /**
  15232. * Activate the element
  15233. * Overlay is hidden, element is decorated with a blue shadow border
  15234. */
  15235. Activator.prototype.activate = function() {
  15236. // we allow only one active activator at a time
  15237. if (Activator.current) {
  15238. Activator.current.deactivate();
  15239. }
  15240. Activator.current = this;
  15241. this.active = true;
  15242. this.dom.overlay.style.display = 'none';
  15243. util.addClassName(this.dom.container, 'vis-active');
  15244. this.emit('change');
  15245. this.emit('activate');
  15246. // ugly hack: bind ESC after emitting the events, as the Network rebinds all
  15247. // keyboard events on a 'change' event
  15248. this.keycharm.bind('esc', this.escListener);
  15249. };
  15250. /**
  15251. * Deactivate the element
  15252. * Overlay is displayed on top of the element
  15253. */
  15254. Activator.prototype.deactivate = function() {
  15255. this.active = false;
  15256. this.dom.overlay.style.display = '';
  15257. util.removeClassName(this.dom.container, 'vis-active');
  15258. this.keycharm.unbind('esc', this.escListener);
  15259. this.emit('change');
  15260. this.emit('deactivate');
  15261. };
  15262. /**
  15263. * Handle a tap event: activate the container
  15264. * @param {Event} event The event
  15265. * @private
  15266. */
  15267. Activator.prototype._onTapOverlay = function(event) {
  15268. // activate the container
  15269. this.activate();
  15270. event.stopPropagation();
  15271. };
  15272. /**
  15273. * Test whether the element has the requested parent element somewhere in
  15274. * its chain of parent nodes.
  15275. * @param {HTMLElement} element
  15276. * @param {HTMLElement} parent
  15277. * @returns {boolean} Returns true when the parent is found somewhere in the
  15278. * chain of parent nodes.
  15279. * @private
  15280. */
  15281. function _hasParent(element, parent) {
  15282. while (element) {
  15283. if (element === parent) {
  15284. return true;
  15285. }
  15286. element = element.parentNode;
  15287. }
  15288. return false;
  15289. }
  15290. module.exports = Activator;
  15291. /***/
  15292. }),
  15293. /* 98 */
  15294. /***/
  15295. (function(module, exports, __webpack_require__) {
  15296. "use strict";
  15297. // English
  15298. exports['en'] = {
  15299. current: 'current',
  15300. time: 'time'
  15301. };
  15302. exports['en_EN'] = exports['en'];
  15303. exports['en_US'] = exports['en'];
  15304. // Italiano
  15305. exports['it'] = {
  15306. current: 'attuale',
  15307. time: 'tempo'
  15308. };
  15309. exports['it_IT'] = exports['it'];
  15310. exports['it_CH'] = exports['it'];
  15311. // Dutch
  15312. exports['nl'] = {
  15313. current: 'huidige',
  15314. time: 'tijd'
  15315. };
  15316. exports['nl_NL'] = exports['nl'];
  15317. exports['nl_BE'] = exports['nl'];
  15318. // German
  15319. exports['de'] = {
  15320. current: 'Aktuelle',
  15321. time: 'Zeit'
  15322. };
  15323. exports['de_DE'] = exports['de'];
  15324. // French
  15325. exports['fr'] = {
  15326. current: 'actuel',
  15327. time: 'heure'
  15328. };
  15329. exports['fr_FR'] = exports['fr'];
  15330. exports['fr_CA'] = exports['fr'];
  15331. exports['fr_BE'] = exports['fr'];
  15332. // Espanol
  15333. exports['es'] = {
  15334. current: 'corriente',
  15335. time: 'hora'
  15336. };
  15337. exports['es_ES'] = exports['es'];
  15338. /***/
  15339. }),
  15340. /* 99 */
  15341. /***/
  15342. (function(module, exports, __webpack_require__) {
  15343. "use strict";
  15344. var _create = __webpack_require__(29);
  15345. var _create2 = _interopRequireDefault(_create);
  15346. var _typeof2 = __webpack_require__(6);
  15347. var _typeof3 = _interopRequireDefault(_typeof2);
  15348. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  15349. var Hammer = __webpack_require__(10);
  15350. var util = __webpack_require__(2);
  15351. var DataSet = __webpack_require__(11);
  15352. var DataView = __webpack_require__(12);
  15353. var TimeStep = __webpack_require__(66);
  15354. var Component = __webpack_require__(16);
  15355. var Group = __webpack_require__(68);
  15356. var BackgroundGroup = __webpack_require__(69);
  15357. var BoxItem = __webpack_require__(101);
  15358. var PointItem = __webpack_require__(102);
  15359. var RangeItem = __webpack_require__(70);
  15360. var BackgroundItem = __webpack_require__(103);
  15361. var Popup = __webpack_require__(104)['default'];
  15362. var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items
  15363. var BACKGROUND = '__background__'; // reserved group id for background items without group
  15364. /**
  15365. * An ItemSet holds a set of items and ranges which can be displayed in a
  15366. * range. The width is determined by the parent of the ItemSet, and the height
  15367. * is determined by the size of the items.
  15368. * @param {{dom: Object, domProps: Object, emitter: Emitter, range: Range}} body
  15369. * @param {Object} [options] See ItemSet.setOptions for the available options.
  15370. * @constructor ItemSet
  15371. * @extends Component
  15372. */
  15373. function ItemSet(body, options) {
  15374. this.body = body;
  15375. this.defaultOptions = {
  15376. type: null, // 'box', 'point', 'range', 'background'
  15377. orientation: {
  15378. item: 'bottom' // item orientation: 'top' or 'bottom'
  15379. },
  15380. align: 'auto', // alignment of box items
  15381. stack: true,
  15382. stackSubgroups: true,
  15383. groupOrderSwap: function groupOrderSwap(fromGroup, toGroup, groups) {
  15384. // eslint-disable-line no-unused-vars
  15385. var targetOrder = toGroup.order;
  15386. toGroup.order = fromGroup.order;
  15387. fromGroup.order = targetOrder;
  15388. },
  15389. groupOrder: 'order',
  15390. selectable: true,
  15391. multiselect: false,
  15392. itemsAlwaysDraggable: {
  15393. item: false,
  15394. range: false
  15395. },
  15396. editable: {
  15397. updateTime: false,
  15398. updateGroup: false,
  15399. add: false,
  15400. remove: false,
  15401. overrideItems: false
  15402. },
  15403. groupEditable: {
  15404. order: false,
  15405. add: false,
  15406. remove: false
  15407. },
  15408. snap: TimeStep.snap,
  15409. // Only called when `objectData.target === 'item'.
  15410. onDropObjectOnItem: function onDropObjectOnItem(objectData, item, callback) {
  15411. callback(item);
  15412. },
  15413. onAdd: function onAdd(item, callback) {
  15414. callback(item);
  15415. },
  15416. onUpdate: function onUpdate(item, callback) {
  15417. callback(item);
  15418. },
  15419. onMove: function onMove(item, callback) {
  15420. callback(item);
  15421. },
  15422. onRemove: function onRemove(item, callback) {
  15423. callback(item);
  15424. },
  15425. onMoving: function onMoving(item, callback) {
  15426. callback(item);
  15427. },
  15428. onAddGroup: function onAddGroup(item, callback) {
  15429. callback(item);
  15430. },
  15431. onMoveGroup: function onMoveGroup(item, callback) {
  15432. callback(item);
  15433. },
  15434. onRemoveGroup: function onRemoveGroup(item, callback) {
  15435. callback(item);
  15436. },
  15437. margin: {
  15438. item: {
  15439. horizontal: 10,
  15440. vertical: 10
  15441. },
  15442. axis: 20
  15443. },
  15444. showTooltips: true,
  15445. tooltip: {
  15446. followMouse: false,
  15447. overflowMethod: 'flip'
  15448. },
  15449. tooltipOnItemUpdateTime: false
  15450. };
  15451. // options is shared by this ItemSet and all its items
  15452. this.options = util.extend({}, this.defaultOptions);
  15453. this.options.rtl = options.rtl;
  15454. // options for getting items from the DataSet with the correct type
  15455. this.itemOptions = {
  15456. type: { start: 'Date', end: 'Date' }
  15457. };
  15458. this.conversion = {
  15459. toScreen: body.util.toScreen,
  15460. toTime: body.util.toTime
  15461. };
  15462. this.dom = {};
  15463. this.props = {};
  15464. this.hammer = null;
  15465. var me = this;
  15466. this.itemsData = null; // DataSet
  15467. this.groupsData = null; // DataSet
  15468. // listeners for the DataSet of the items
  15469. this.itemListeners = {
  15470. 'add': function add(event, params, senderId) {
  15471. // eslint-disable-line no-unused-vars
  15472. me._onAdd(params.items);
  15473. },
  15474. 'update': function update(event, params, senderId) {
  15475. // eslint-disable-line no-unused-vars
  15476. me._onUpdate(params.items);
  15477. },
  15478. 'remove': function remove(event, params, senderId) {
  15479. // eslint-disable-line no-unused-vars
  15480. me._onRemove(params.items);
  15481. }
  15482. };
  15483. // listeners for the DataSet of the groups
  15484. this.groupListeners = {
  15485. 'add': function add(event, params, senderId) {
  15486. // eslint-disable-line no-unused-vars
  15487. me._onAddGroups(params.items);
  15488. if (me.groupsData && me.groupsData.length > 0) {
  15489. var groupsData = me.groupsData.getDataSet();
  15490. groupsData.get().forEach(function(groupData) {
  15491. if (groupData.nestedGroups) {
  15492. if (groupData.showNested != false) {
  15493. groupData.showNested = true;
  15494. }
  15495. var updatedGroups = [];
  15496. groupData.nestedGroups.forEach(function(nestedGroupId) {
  15497. var updatedNestedGroup = groupsData.get(nestedGroupId);
  15498. if (!updatedNestedGroup) {
  15499. return;
  15500. }
  15501. updatedNestedGroup.nestedInGroup = groupData.id;
  15502. if (groupData.showNested == false) {
  15503. updatedNestedGroup.visible = false;
  15504. }
  15505. updatedGroups = updatedGroups.concat(updatedNestedGroup);
  15506. });
  15507. groupsData.update(updatedGroups, senderId);
  15508. }
  15509. });
  15510. }
  15511. },
  15512. 'update': function update(event, params, senderId) {
  15513. // eslint-disable-line no-unused-vars
  15514. me._onUpdateGroups(params.items);
  15515. },
  15516. 'remove': function remove(event, params, senderId) {
  15517. // eslint-disable-line no-unused-vars
  15518. me._onRemoveGroups(params.items);
  15519. }
  15520. };
  15521. this.items = {}; // object with an Item for every data item
  15522. this.groups = {}; // Group object for every group
  15523. this.groupIds = [];
  15524. this.selection = []; // list with the ids of all selected nodes
  15525. this.popup = null;
  15526. this.touchParams = {}; // stores properties while dragging
  15527. this.groupTouchParams = {};
  15528. // create the HTML DOM
  15529. this._create();
  15530. this.setOptions(options);
  15531. }
  15532. ItemSet.prototype = new Component();
  15533. // available item types will be registered here
  15534. ItemSet.types = {
  15535. background: BackgroundItem,
  15536. box: BoxItem,
  15537. range: RangeItem,
  15538. point: PointItem
  15539. };
  15540. /**
  15541. * Create the HTML DOM for the ItemSet
  15542. */
  15543. ItemSet.prototype._create = function() {
  15544. var frame = document.createElement('div');
  15545. frame.className = 'vis-itemset';
  15546. frame['timeline-itemset'] = this;
  15547. this.dom.frame = frame;
  15548. // create background panel
  15549. var background = document.createElement('div');
  15550. background.className = 'vis-background';
  15551. frame.appendChild(background);
  15552. this.dom.background = background;
  15553. // create foreground panel
  15554. var foreground = document.createElement('div');
  15555. foreground.className = 'vis-foreground';
  15556. frame.appendChild(foreground);
  15557. this.dom.foreground = foreground;
  15558. // create axis panel
  15559. var axis = document.createElement('div');
  15560. axis.className = 'vis-axis';
  15561. this.dom.axis = axis;
  15562. // create labelset
  15563. var labelSet = document.createElement('div');
  15564. labelSet.className = 'vis-labelset';
  15565. this.dom.labelSet = labelSet;
  15566. // create ungrouped Group
  15567. this._updateUngrouped();
  15568. // create background Group
  15569. var backgroundGroup = new BackgroundGroup(BACKGROUND, null, this);
  15570. backgroundGroup.show();
  15571. this.groups[BACKGROUND] = backgroundGroup;
  15572. // attach event listeners
  15573. // Note: we bind to the centerContainer for the case where the height
  15574. // of the center container is larger than of the ItemSet, so we
  15575. // can click in the empty area to create a new item or deselect an item.
  15576. this.hammer = new Hammer(this.body.dom.centerContainer);
  15577. // drag items when selected
  15578. this.hammer.on('hammer.input', function(event) {
  15579. if (event.isFirst) {
  15580. this._onTouch(event);
  15581. }
  15582. }.bind(this));
  15583. this.hammer.on('panstart', this._onDragStart.bind(this));
  15584. this.hammer.on('panmove', this._onDrag.bind(this));
  15585. this.hammer.on('panend', this._onDragEnd.bind(this));
  15586. this.hammer.get('pan').set({ threshold: 5, direction: Hammer.DIRECTION_HORIZONTAL });
  15587. // single select (or unselect) when tapping an item
  15588. this.hammer.on('tap', this._onSelectItem.bind(this));
  15589. // multi select when holding mouse/touch, or on ctrl+click
  15590. this.hammer.on('press', this._onMultiSelectItem.bind(this));
  15591. // add item on doubletap
  15592. this.hammer.on('doubletap', this._onAddItem.bind(this));
  15593. if (this.options.rtl) {
  15594. this.groupHammer = new Hammer(this.body.dom.rightContainer);
  15595. } else {
  15596. this.groupHammer = new Hammer(this.body.dom.leftContainer);
  15597. }
  15598. this.groupHammer.on('tap', this._onGroupClick.bind(this));
  15599. this.groupHammer.on('panstart', this._onGroupDragStart.bind(this));
  15600. this.groupHammer.on('panmove', this._onGroupDrag.bind(this));
  15601. this.groupHammer.on('panend', this._onGroupDragEnd.bind(this));
  15602. this.groupHammer.get('pan').set({ threshold: 5, direction: Hammer.DIRECTION_VERTICAL });
  15603. this.body.dom.centerContainer.addEventListener('mouseover', this._onMouseOver.bind(this));
  15604. this.body.dom.centerContainer.addEventListener('mouseout', this._onMouseOut.bind(this));
  15605. this.body.dom.centerContainer.addEventListener('mousemove', this._onMouseMove.bind(this));
  15606. // right-click on timeline
  15607. this.body.dom.centerContainer.addEventListener('contextmenu', this._onDragEnd.bind(this));
  15608. this.body.dom.centerContainer.addEventListener('mousewheel', this._onMouseWheel.bind(this));
  15609. // attach to the DOM
  15610. this.show();
  15611. };
  15612. /**
  15613. * Set options for the ItemSet. Existing options will be extended/overwritten.
  15614. * @param {Object} [options] The following options are available:
  15615. * {string} type
  15616. * Default type for the items. Choose from 'box'
  15617. * (default), 'point', 'range', or 'background'.
  15618. * The default style can be overwritten by
  15619. * individual items.
  15620. * {string} align
  15621. * Alignment for the items, only applicable for
  15622. * BoxItem. Choose 'center' (default), 'left', or
  15623. * 'right'.
  15624. * {string} orientation.item
  15625. * Orientation of the item set. Choose 'top' or
  15626. * 'bottom' (default).
  15627. * {Function} groupOrder
  15628. * A sorting function for ordering groups
  15629. * {boolean} stack
  15630. * If true (default), items will be stacked on
  15631. * top of each other.
  15632. * {number} margin.axis
  15633. * Margin between the axis and the items in pixels.
  15634. * Default is 20.
  15635. * {number} margin.item.horizontal
  15636. * Horizontal margin between items in pixels.
  15637. * Default is 10.
  15638. * {number} margin.item.vertical
  15639. * Vertical Margin between items in pixels.
  15640. * Default is 10.
  15641. * {number} margin.item
  15642. * Margin between items in pixels in both horizontal
  15643. * and vertical direction. Default is 10.
  15644. * {number} margin
  15645. * Set margin for both axis and items in pixels.
  15646. * {boolean} selectable
  15647. * If true (default), items can be selected.
  15648. * {boolean} multiselect
  15649. * If true, multiple items can be selected.
  15650. * False by default.
  15651. * {boolean} editable
  15652. * Set all editable options to true or false
  15653. * {boolean} editable.updateTime
  15654. * Allow dragging an item to an other moment in time
  15655. * {boolean} editable.updateGroup
  15656. * Allow dragging an item to an other group
  15657. * {boolean} editable.add
  15658. * Allow creating new items on double tap
  15659. * {boolean} editable.remove
  15660. * Allow removing items by clicking the delete button
  15661. * top right of a selected item.
  15662. * {Function(item: Item, callback: Function)} onAdd
  15663. * Callback function triggered when an item is about to be added:
  15664. * when the user double taps an empty space in the Timeline.
  15665. * {Function(item: Item, callback: Function)} onUpdate
  15666. * Callback function fired when an item is about to be updated.
  15667. * This function typically has to show a dialog where the user
  15668. * change the item. If not implemented, nothing happens.
  15669. * {Function(item: Item, callback: Function)} onMove
  15670. * Fired when an item has been moved. If not implemented,
  15671. * the move action will be accepted.
  15672. * {Function(item: Item, callback: Function)} onRemove
  15673. * Fired when an item is about to be deleted.
  15674. * If not implemented, the item will be always removed.
  15675. */
  15676. ItemSet.prototype.setOptions = function(options) {
  15677. if (options) {
  15678. // copy all options that we know
  15679. var fields = ['type', 'rtl', 'align', 'order', 'stack', 'stackSubgroups', 'selectable', 'multiselect', 'multiselectPerGroup', 'groupOrder', 'dataAttributes', 'template', 'groupTemplate', 'visibleFrameTemplate', 'hide', 'snap', 'groupOrderSwap', 'showTooltips', 'tooltip', 'tooltipOnItemUpdateTime'];
  15680. util.selectiveExtend(fields, this.options, options);
  15681. if ('itemsAlwaysDraggable' in options) {
  15682. if (typeof options.itemsAlwaysDraggable === 'boolean') {
  15683. this.options.itemsAlwaysDraggable.item = options.itemsAlwaysDraggable;
  15684. this.options.itemsAlwaysDraggable.range = false;
  15685. } else if ((0, _typeof3['default'])(options.itemsAlwaysDraggable) === 'object') {
  15686. util.selectiveExtend(['item', 'range'], this.options.itemsAlwaysDraggable, options.itemsAlwaysDraggable);
  15687. // only allow range always draggable when item is always draggable as well
  15688. if (!this.options.itemsAlwaysDraggable.item) {
  15689. this.options.itemsAlwaysDraggable.range = false;
  15690. }
  15691. }
  15692. }
  15693. if ('orientation' in options) {
  15694. if (typeof options.orientation === 'string') {
  15695. this.options.orientation.item = options.orientation === 'top' ? 'top' : 'bottom';
  15696. } else if ((0, _typeof3['default'])(options.orientation) === 'object' && 'item' in options.orientation) {
  15697. this.options.orientation.item = options.orientation.item;
  15698. }
  15699. }
  15700. if ('margin' in options) {
  15701. if (typeof options.margin === 'number') {
  15702. this.options.margin.axis = options.margin;
  15703. this.options.margin.item.horizontal = options.margin;
  15704. this.options.margin.item.vertical = options.margin;
  15705. } else if ((0, _typeof3['default'])(options.margin) === 'object') {
  15706. util.selectiveExtend(['axis'], this.options.margin, options.margin);
  15707. if ('item' in options.margin) {
  15708. if (typeof options.margin.item === 'number') {
  15709. this.options.margin.item.horizontal = options.margin.item;
  15710. this.options.margin.item.vertical = options.margin.item;
  15711. } else if ((0, _typeof3['default'])(options.margin.item) === 'object') {
  15712. util.selectiveExtend(['horizontal', 'vertical'], this.options.margin.item, options.margin.item);
  15713. }
  15714. }
  15715. }
  15716. }
  15717. if ('editable' in options) {
  15718. if (typeof options.editable === 'boolean') {
  15719. this.options.editable.updateTime = options.editable;
  15720. this.options.editable.updateGroup = options.editable;
  15721. this.options.editable.add = options.editable;
  15722. this.options.editable.remove = options.editable;
  15723. this.options.editable.overrideItems = false;
  15724. } else if ((0, _typeof3['default'])(options.editable) === 'object') {
  15725. util.selectiveExtend(['updateTime', 'updateGroup', 'add', 'remove', 'overrideItems'], this.options.editable, options.editable);
  15726. }
  15727. }
  15728. if ('groupEditable' in options) {
  15729. if (typeof options.groupEditable === 'boolean') {
  15730. this.options.groupEditable.order = options.groupEditable;
  15731. this.options.groupEditable.add = options.groupEditable;
  15732. this.options.groupEditable.remove = options.groupEditable;
  15733. } else if ((0, _typeof3['default'])(options.groupEditable) === 'object') {
  15734. util.selectiveExtend(['order', 'add', 'remove'], this.options.groupEditable, options.groupEditable);
  15735. }
  15736. }
  15737. // callback functions
  15738. var addCallback = function(name) {
  15739. var fn = options[name];
  15740. if (fn) {
  15741. if (!(fn instanceof Function)) {
  15742. throw new Error('option ' + name + ' must be a function ' + name + '(item, callback)');
  15743. }
  15744. this.options[name] = fn;
  15745. }
  15746. }.bind(this);
  15747. ['onDropObjectOnItem', 'onAdd', 'onUpdate', 'onRemove', 'onMove', 'onMoving', 'onAddGroup', 'onMoveGroup', 'onRemoveGroup'].forEach(addCallback);
  15748. // force the itemSet to refresh: options like orientation and margins may be changed
  15749. this.markDirty();
  15750. }
  15751. };
  15752. /**
  15753. * Mark the ItemSet dirty so it will refresh everything with next redraw.
  15754. * Optionally, all items can be marked as dirty and be refreshed.
  15755. * @param {{refreshItems: boolean}} [options]
  15756. */
  15757. ItemSet.prototype.markDirty = function(options) {
  15758. this.groupIds = [];
  15759. if (options && options.refreshItems) {
  15760. util.forEach(this.items, function(item) {
  15761. item.dirty = true;
  15762. if (item.displayed) item.redraw();
  15763. });
  15764. }
  15765. };
  15766. /**
  15767. * Destroy the ItemSet
  15768. */
  15769. ItemSet.prototype.destroy = function() {
  15770. this.hide();
  15771. this.setItems(null);
  15772. this.setGroups(null);
  15773. this.hammer = null;
  15774. this.body = null;
  15775. this.conversion = null;
  15776. };
  15777. /**
  15778. * Hide the component from the DOM
  15779. */
  15780. ItemSet.prototype.hide = function() {
  15781. // remove the frame containing the items
  15782. if (this.dom.frame.parentNode) {
  15783. this.dom.frame.parentNode.removeChild(this.dom.frame);
  15784. }
  15785. // remove the axis with dots
  15786. if (this.dom.axis.parentNode) {
  15787. this.dom.axis.parentNode.removeChild(this.dom.axis);
  15788. }
  15789. // remove the labelset containing all group labels
  15790. if (this.dom.labelSet.parentNode) {
  15791. this.dom.labelSet.parentNode.removeChild(this.dom.labelSet);
  15792. }
  15793. };
  15794. /**
  15795. * Show the component in the DOM (when not already visible).
  15796. */
  15797. ItemSet.prototype.show = function() {
  15798. // show frame containing the items
  15799. if (!this.dom.frame.parentNode) {
  15800. this.body.dom.center.appendChild(this.dom.frame);
  15801. }
  15802. // show axis with dots
  15803. if (!this.dom.axis.parentNode) {
  15804. this.body.dom.backgroundVertical.appendChild(this.dom.axis);
  15805. }
  15806. // show labelset containing labels
  15807. if (!this.dom.labelSet.parentNode) {
  15808. if (this.options.rtl) {
  15809. this.body.dom.right.appendChild(this.dom.labelSet);
  15810. } else {
  15811. this.body.dom.left.appendChild(this.dom.labelSet);
  15812. }
  15813. }
  15814. };
  15815. /**
  15816. * Set selected items by their id. Replaces the current selection
  15817. * Unknown id's are silently ignored.
  15818. * @param {string[] | string} [ids] An array with zero or more id's of the items to be
  15819. * selected, or a single item id. If ids is undefined
  15820. * or an empty array, all items will be unselected.
  15821. */
  15822. ItemSet.prototype.setSelection = function(ids) {
  15823. var i, ii, id, item;
  15824. if (ids == undefined) ids = [];
  15825. if (!Array.isArray(ids)) ids = [ids];
  15826. // unselect currently selected items
  15827. for (i = 0, ii = this.selection.length; i < ii; i++) {
  15828. id = this.selection[i];
  15829. item = this.items[id];
  15830. if (item) item.unselect();
  15831. }
  15832. // select items
  15833. this.selection = [];
  15834. for (i = 0, ii = ids.length; i < ii; i++) {
  15835. id = ids[i];
  15836. item = this.items[id];
  15837. if (item) {
  15838. this.selection.push(id);
  15839. item.select();
  15840. }
  15841. }
  15842. };
  15843. /**
  15844. * Get the selected items by their id
  15845. * @return {Array} ids The ids of the selected items
  15846. */
  15847. ItemSet.prototype.getSelection = function() {
  15848. return this.selection.concat([]);
  15849. };
  15850. /**
  15851. * Get the id's of the currently visible items.
  15852. * @returns {Array} The ids of the visible items
  15853. */
  15854. ItemSet.prototype.getVisibleItems = function() {
  15855. var range = this.body.range.getRange();
  15856. var right, left;
  15857. if (this.options.rtl) {
  15858. right = this.body.util.toScreen(range.start);
  15859. left = this.body.util.toScreen(range.end);
  15860. } else {
  15861. left = this.body.util.toScreen(range.start);
  15862. right = this.body.util.toScreen(range.end);
  15863. }
  15864. var ids = [];
  15865. for (var groupId in this.groups) {
  15866. if (this.groups.hasOwnProperty(groupId)) {
  15867. var group = this.groups[groupId];
  15868. var rawVisibleItems = group.isVisible ? group.visibleItems : [];
  15869. // filter the "raw" set with visibleItems into a set which is really
  15870. // visible by pixels
  15871. for (var i = 0; i < rawVisibleItems.length; i++) {
  15872. var item = rawVisibleItems[i];
  15873. // TODO: also check whether visible vertically
  15874. if (this.options.rtl) {
  15875. if (item.right < left && item.right + item.width > right) {
  15876. ids.push(item.id);
  15877. }
  15878. } else {
  15879. if (item.left < right && item.left + item.width > left) {
  15880. ids.push(item.id);
  15881. }
  15882. }
  15883. }
  15884. }
  15885. }
  15886. return ids;
  15887. };
  15888. /**
  15889. * Deselect a selected item
  15890. * @param {string | number} id
  15891. * @private
  15892. */
  15893. ItemSet.prototype._deselect = function(id) {
  15894. var selection = this.selection;
  15895. for (var i = 0, ii = selection.length; i < ii; i++) {
  15896. if (selection[i] == id) {
  15897. // non-strict comparison!
  15898. selection.splice(i, 1);
  15899. break;
  15900. }
  15901. }
  15902. };
  15903. /**
  15904. * Repaint the component
  15905. * @return {boolean} Returns true if the component is resized
  15906. */
  15907. ItemSet.prototype.redraw = function() {
  15908. var margin = this.options.margin,
  15909. range = this.body.range,
  15910. asSize = util.option.asSize,
  15911. options = this.options,
  15912. orientation = options.orientation.item,
  15913. resized = false,
  15914. frame = this.dom.frame;
  15915. // recalculate absolute position (before redrawing groups)
  15916. this.props.top = this.body.domProps.top.height + this.body.domProps.border.top;
  15917. if (this.options.rtl) {
  15918. this.props.right = this.body.domProps.right.width + this.body.domProps.border.right;
  15919. } else {
  15920. this.props.left = this.body.domProps.left.width + this.body.domProps.border.left;
  15921. }
  15922. // update class name
  15923. frame.className = 'vis-itemset';
  15924. // reorder the groups (if needed)
  15925. resized = this._orderGroups() || resized;
  15926. // check whether zoomed (in that case we need to re-stack everything)
  15927. // TODO: would be nicer to get this as a trigger from Range
  15928. var visibleInterval = range.end - range.start;
  15929. var zoomed = visibleInterval != this.lastVisibleInterval || this.props.width != this.props.lastWidth;
  15930. var scrolled = range.start != this.lastRangeStart;
  15931. var changedStackOption = options.stack != this.lastStack;
  15932. var changedStackSubgroupsOption = options.stackSubgroups != this.lastStackSubgroups;
  15933. var forceRestack = zoomed || scrolled || changedStackOption || changedStackSubgroupsOption;
  15934. this.lastVisibleInterval = visibleInterval;
  15935. this.lastRangeStart = range.start;
  15936. this.lastStack = options.stack;
  15937. this.lastStackSubgroups = options.stackSubgroups;
  15938. this.props.lastWidth = this.props.width;
  15939. var firstGroup = this._firstGroup();
  15940. var firstMargin = {
  15941. item: margin.item,
  15942. axis: margin.axis
  15943. };
  15944. var nonFirstMargin = {
  15945. item: margin.item,
  15946. axis: margin.item.vertical / 2
  15947. };
  15948. var height = 0;
  15949. var minHeight = margin.axis + margin.item.vertical;
  15950. // redraw the background group
  15951. this.groups[BACKGROUND].redraw(range, nonFirstMargin, forceRestack);
  15952. var redrawQueue = {};
  15953. var redrawQueueLength = 0;
  15954. // collect redraw functions
  15955. util.forEach(this.groups, function(group, key) {
  15956. if (key === BACKGROUND) return;
  15957. var groupMargin = group == firstGroup ? firstMargin : nonFirstMargin;
  15958. var returnQueue = true;
  15959. redrawQueue[key] = group.redraw(range, groupMargin, forceRestack, returnQueue);
  15960. redrawQueueLength = redrawQueue[key].length;
  15961. });
  15962. var needRedraw = redrawQueueLength > 0;
  15963. if (needRedraw) {
  15964. var redrawResults = {};
  15965. for (var i = 0; i < redrawQueueLength; i++) {
  15966. util.forEach(redrawQueue, function(fns, key) {
  15967. redrawResults[key] = fns[i]();
  15968. });
  15969. }
  15970. // redraw all regular groups
  15971. util.forEach(this.groups, function(group, key) {
  15972. if (key === BACKGROUND) return;
  15973. var groupResized = redrawResults[key];
  15974. resized = groupResized || resized;
  15975. height += group.height;
  15976. });
  15977. height = Math.max(height, minHeight);
  15978. }
  15979. height = Math.max(height, minHeight);
  15980. // update frame height
  15981. frame.style.height = asSize(height);
  15982. // calculate actual size
  15983. this.props.width = frame.offsetWidth;
  15984. this.props.height = height;
  15985. // reposition axis
  15986. this.dom.axis.style.top = asSize(orientation == 'top' ? this.body.domProps.top.height + this.body.domProps.border.top : this.body.domProps.top.height + this.body.domProps.centerContainer.height);
  15987. if (this.options.rtl) {
  15988. this.dom.axis.style.right = '0';
  15989. } else {
  15990. this.dom.axis.style.left = '0';
  15991. }
  15992. this.initialItemSetDrawn = true;
  15993. // check if this component is resized
  15994. resized = this._isResized() || resized;
  15995. return resized;
  15996. };
  15997. /**
  15998. * Get the first group, aligned with the axis
  15999. * @return {Group | null} firstGroup
  16000. * @private
  16001. */
  16002. ItemSet.prototype._firstGroup = function() {
  16003. var firstGroupIndex = this.options.orientation.item == 'top' ? 0 : this.groupIds.length - 1;
  16004. var firstGroupId = this.groupIds[firstGroupIndex];
  16005. var firstGroup = this.groups[firstGroupId] || this.groups[UNGROUPED];
  16006. return firstGroup || null;
  16007. };
  16008. /**
  16009. * Create or delete the group holding all ungrouped items. This group is used when
  16010. * there are no groups specified.
  16011. * @protected
  16012. */
  16013. ItemSet.prototype._updateUngrouped = function() {
  16014. var ungrouped = this.groups[UNGROUPED];
  16015. var item, itemId;
  16016. if (this.groupsData) {
  16017. // remove the group holding all ungrouped items
  16018. if (ungrouped) {
  16019. ungrouped.hide();
  16020. delete this.groups[UNGROUPED];
  16021. for (itemId in this.items) {
  16022. if (this.items.hasOwnProperty(itemId)) {
  16023. item = this.items[itemId];
  16024. item.parent && item.parent.remove(item);
  16025. var groupId = this._getGroupId(item.data);
  16026. var group = this.groups[groupId];
  16027. group && group.add(item) || item.hide();
  16028. }
  16029. }
  16030. }
  16031. } else {
  16032. // create a group holding all (unfiltered) items
  16033. if (!ungrouped) {
  16034. var id = null;
  16035. var data = null;
  16036. ungrouped = new Group(id, data, this);
  16037. this.groups[UNGROUPED] = ungrouped;
  16038. for (itemId in this.items) {
  16039. if (this.items.hasOwnProperty(itemId)) {
  16040. item = this.items[itemId];
  16041. ungrouped.add(item);
  16042. }
  16043. }
  16044. ungrouped.show();
  16045. }
  16046. }
  16047. };
  16048. /**
  16049. * Get the element for the labelset
  16050. * @return {HTMLElement} labelSet
  16051. */
  16052. ItemSet.prototype.getLabelSet = function() {
  16053. return this.dom.labelSet;
  16054. };
  16055. /**
  16056. * Set items
  16057. * @param {vis.DataSet | null} items
  16058. */
  16059. ItemSet.prototype.setItems = function(items) {
  16060. var me = this,
  16061. ids,
  16062. oldItemsData = this.itemsData;
  16063. // replace the dataset
  16064. if (!items) {
  16065. this.itemsData = null;
  16066. } else if (items instanceof DataSet || items instanceof DataView) {
  16067. this.itemsData = items;
  16068. } else {
  16069. throw new TypeError('Data must be an instance of DataSet or DataView');
  16070. }
  16071. if (oldItemsData) {
  16072. // unsubscribe from old dataset
  16073. util.forEach(this.itemListeners, function(callback, event) {
  16074. oldItemsData.off(event, callback);
  16075. });
  16076. // remove all drawn items
  16077. ids = oldItemsData.getIds();
  16078. this._onRemove(ids);
  16079. }
  16080. if (this.itemsData) {
  16081. // subscribe to new dataset
  16082. var id = this.id;
  16083. util.forEach(this.itemListeners, function(callback, event) {
  16084. me.itemsData.on(event, callback, id);
  16085. });
  16086. // add all new items
  16087. ids = this.itemsData.getIds();
  16088. this._onAdd(ids);
  16089. // update the group holding all ungrouped items
  16090. this._updateUngrouped();
  16091. }
  16092. this.body.emitter.emit('_change', { queue: true });
  16093. };
  16094. /**
  16095. * Get the current items
  16096. * @returns {vis.DataSet | null}
  16097. */
  16098. ItemSet.prototype.getItems = function() {
  16099. return this.itemsData;
  16100. };
  16101. /**
  16102. * Set groups
  16103. * @param {vis.DataSet} groups
  16104. */
  16105. ItemSet.prototype.setGroups = function(groups) {
  16106. var me = this,
  16107. ids;
  16108. // unsubscribe from current dataset
  16109. if (this.groupsData) {
  16110. util.forEach(this.groupListeners, function(callback, event) {
  16111. me.groupsData.off(event, callback);
  16112. });
  16113. // remove all drawn groups
  16114. ids = this.groupsData.getIds();
  16115. this.groupsData = null;
  16116. this._onRemoveGroups(ids); // note: this will cause a redraw
  16117. }
  16118. // replace the dataset
  16119. if (!groups) {
  16120. this.groupsData = null;
  16121. } else if (groups instanceof DataSet || groups instanceof DataView) {
  16122. this.groupsData = groups;
  16123. } else {
  16124. throw new TypeError('Data must be an instance of DataSet or DataView');
  16125. }
  16126. if (this.groupsData) {
  16127. // go over all groups nesting
  16128. var groupsData = this.groupsData;
  16129. if (this.groupsData instanceof DataView) {
  16130. groupsData = this.groupsData.getDataSet();
  16131. }
  16132. groupsData.get().forEach(function(group) {
  16133. if (group.nestedGroups) {
  16134. group.nestedGroups.forEach(function(nestedGroupId) {
  16135. var updatedNestedGroup = groupsData.get(nestedGroupId);
  16136. updatedNestedGroup.nestedInGroup = group.id;
  16137. if (group.showNested == false) {
  16138. updatedNestedGroup.visible = false;
  16139. }
  16140. groupsData.update(updatedNestedGroup);
  16141. });
  16142. }
  16143. });
  16144. // subscribe to new dataset
  16145. var id = this.id;
  16146. util.forEach(this.groupListeners, function(callback, event) {
  16147. me.groupsData.on(event, callback, id);
  16148. });
  16149. // draw all ms
  16150. ids = this.groupsData.getIds();
  16151. this._onAddGroups(ids);
  16152. }
  16153. // update the group holding all ungrouped items
  16154. this._updateUngrouped();
  16155. // update the order of all items in each group
  16156. this._order();
  16157. this.body.emitter.emit('_change', { queue: true });
  16158. };
  16159. /**
  16160. * Get the current groups
  16161. * @returns {vis.DataSet | null} groups
  16162. */
  16163. ItemSet.prototype.getGroups = function() {
  16164. return this.groupsData;
  16165. };
  16166. /**
  16167. * Remove an item by its id
  16168. * @param {string | number} id
  16169. */
  16170. ItemSet.prototype.removeItem = function(id) {
  16171. var item = this.itemsData.get(id),
  16172. dataset = this.itemsData.getDataSet();
  16173. if (item) {
  16174. // confirm deletion
  16175. this.options.onRemove(item, function(item) {
  16176. if (item) {
  16177. // remove by id here, it is possible that an item has no id defined
  16178. // itself, so better not delete by the item itself
  16179. dataset.remove(id);
  16180. }
  16181. });
  16182. }
  16183. };
  16184. /**
  16185. * Get the time of an item based on it's data and options.type
  16186. * @param {Object} itemData
  16187. * @returns {string} Returns the type
  16188. * @private
  16189. */
  16190. ItemSet.prototype._getType = function(itemData) {
  16191. return itemData.type || this.options.type || (itemData.end ? 'range' : 'box');
  16192. };
  16193. /**
  16194. * Get the group id for an item
  16195. * @param {Object} itemData
  16196. * @returns {string} Returns the groupId
  16197. * @private
  16198. */
  16199. ItemSet.prototype._getGroupId = function(itemData) {
  16200. var type = this._getType(itemData);
  16201. if (type == 'background' && itemData.group == undefined) {
  16202. return BACKGROUND;
  16203. } else {
  16204. return this.groupsData ? itemData.group : UNGROUPED;
  16205. }
  16206. };
  16207. /**
  16208. * Handle updated items
  16209. * @param {number[]} ids
  16210. * @protected
  16211. */
  16212. ItemSet.prototype._onUpdate = function(ids) {
  16213. var me = this;
  16214. ids.forEach(function(id) {
  16215. var itemData = me.itemsData.get(id, me.itemOptions);
  16216. var item = me.items[id];
  16217. var type = itemData ? me._getType(itemData) : null;
  16218. var constructor = ItemSet.types[type];
  16219. var selected;
  16220. if (item) {
  16221. // update item
  16222. if (!constructor || !(item instanceof constructor)) {
  16223. // item type has changed, delete the item and recreate it
  16224. selected = item.selected; // preserve selection of this item
  16225. me._removeItem(item);
  16226. item = null;
  16227. } else {
  16228. me._updateItem(item, itemData);
  16229. }
  16230. }
  16231. if (!item && itemData) {
  16232. // create item
  16233. if (constructor) {
  16234. item = new constructor(itemData, me.conversion, me.options);
  16235. item.id = id; // TODO: not so nice setting id afterwards
  16236. me._addItem(item);
  16237. if (selected) {
  16238. this.selection.push(id);
  16239. item.select();
  16240. }
  16241. } else if (type == 'rangeoverflow') {
  16242. // TODO: deprecated since version 2.1.0 (or 3.0.0?). cleanup some day
  16243. throw new TypeError('Item type "rangeoverflow" is deprecated. Use css styling instead: ' + '.vis-item.vis-range .vis-item-content {overflow: visible;}');
  16244. } else {
  16245. throw new TypeError('Unknown item type "' + type + '"');
  16246. }
  16247. }
  16248. }.bind(this));
  16249. this._order();
  16250. this.body.emitter.emit('_change', { queue: true });
  16251. };
  16252. /**
  16253. * Handle added items
  16254. * @param {number[]} ids
  16255. * @protected
  16256. */
  16257. ItemSet.prototype._onAdd = ItemSet.prototype._onUpdate;
  16258. /**
  16259. * Handle removed items
  16260. * @param {number[]} ids
  16261. * @protected
  16262. */
  16263. ItemSet.prototype._onRemove = function(ids) {
  16264. var count = 0;
  16265. var me = this;
  16266. ids.forEach(function(id) {
  16267. var item = me.items[id];
  16268. if (item) {
  16269. count++;
  16270. me._removeItem(item);
  16271. }
  16272. });
  16273. if (count) {
  16274. // update order
  16275. this._order();
  16276. this.body.emitter.emit('_change', { queue: true });
  16277. }
  16278. };
  16279. /**
  16280. * Update the order of item in all groups
  16281. * @private
  16282. */
  16283. ItemSet.prototype._order = function() {
  16284. // reorder the items in all groups
  16285. // TODO: optimization: only reorder groups affected by the changed items
  16286. util.forEach(this.groups, function(group) {
  16287. group.order();
  16288. });
  16289. };
  16290. /**
  16291. * Handle updated groups
  16292. * @param {number[]} ids
  16293. * @private
  16294. */
  16295. ItemSet.prototype._onUpdateGroups = function(ids) {
  16296. this._onAddGroups(ids);
  16297. };
  16298. /**
  16299. * Handle changed groups (added or updated)
  16300. * @param {number[]} ids
  16301. * @private
  16302. */
  16303. ItemSet.prototype._onAddGroups = function(ids) {
  16304. var me = this;
  16305. ids.forEach(function(id) {
  16306. var groupData = me.groupsData.get(id);
  16307. var group = me.groups[id];
  16308. if (!group) {
  16309. // check for reserved ids
  16310. if (id == UNGROUPED || id == BACKGROUND) {
  16311. throw new Error('Illegal group id. ' + id + ' is a reserved id.');
  16312. }
  16313. var groupOptions = (0, _create2['default'])(me.options);
  16314. util.extend(groupOptions, {
  16315. height: null
  16316. });
  16317. group = new Group(id, groupData, me);
  16318. me.groups[id] = group;
  16319. // add items with this groupId to the new group
  16320. for (var itemId in me.items) {
  16321. if (me.items.hasOwnProperty(itemId)) {
  16322. var item = me.items[itemId];
  16323. if (item.data.group == id) {
  16324. group.add(item);
  16325. }
  16326. }
  16327. }
  16328. group.order();
  16329. group.show();
  16330. } else {
  16331. // update group
  16332. group.setData(groupData);
  16333. }
  16334. });
  16335. this.body.emitter.emit('_change', { queue: true });
  16336. };
  16337. /**
  16338. * Handle removed groups
  16339. * @param {number[]} ids
  16340. * @private
  16341. */
  16342. ItemSet.prototype._onRemoveGroups = function(ids) {
  16343. var groups = this.groups;
  16344. ids.forEach(function(id) {
  16345. var group = groups[id];
  16346. if (group) {
  16347. group.hide();
  16348. delete groups[id];
  16349. }
  16350. });
  16351. this.markDirty();
  16352. this.body.emitter.emit('_change', { queue: true });
  16353. };
  16354. /**
  16355. * Reorder the groups if needed
  16356. * @return {boolean} changed
  16357. * @private
  16358. */
  16359. ItemSet.prototype._orderGroups = function() {
  16360. if (this.groupsData) {
  16361. // reorder the groups
  16362. var groupIds = this.groupsData.getIds({
  16363. order: this.options.groupOrder
  16364. });
  16365. groupIds = this._orderNestedGroups(groupIds);
  16366. var changed = !util.equalArray(groupIds, this.groupIds);
  16367. if (changed) {
  16368. // hide all groups, removes them from the DOM
  16369. var groups = this.groups;
  16370. groupIds.forEach(function(groupId) {
  16371. groups[groupId].hide();
  16372. });
  16373. // show the groups again, attach them to the DOM in correct order
  16374. groupIds.forEach(function(groupId) {
  16375. groups[groupId].show();
  16376. });
  16377. this.groupIds = groupIds;
  16378. }
  16379. return changed;
  16380. } else {
  16381. return false;
  16382. }
  16383. };
  16384. /**
  16385. * Reorder the nested groups
  16386. *
  16387. * @param {Array.<number>} groupIds
  16388. * @returns {Array.<number>}
  16389. * @private
  16390. */
  16391. ItemSet.prototype._orderNestedGroups = function(groupIds) {
  16392. var newGroupIdsOrder = [];
  16393. groupIds.forEach(function(groupId) {
  16394. var groupData = this.groupsData.get(groupId);
  16395. if (!groupData.nestedInGroup) {
  16396. newGroupIdsOrder.push(groupId);
  16397. }
  16398. if (groupData.nestedGroups) {
  16399. var nestedGroups = this.groupsData.get({
  16400. filter: function filter(nestedGroup) {
  16401. return nestedGroup.nestedInGroup == groupId;
  16402. },
  16403. order: this.options.groupOrder
  16404. });
  16405. var nestedGroupIds = nestedGroups.map(function(nestedGroup) {
  16406. return nestedGroup.id;
  16407. });
  16408. newGroupIdsOrder = newGroupIdsOrder.concat(nestedGroupIds);
  16409. }
  16410. }, this);
  16411. return newGroupIdsOrder;
  16412. };
  16413. /**
  16414. * Add a new item
  16415. * @param {Item} item
  16416. * @private
  16417. */
  16418. ItemSet.prototype._addItem = function(item) {
  16419. this.items[item.id] = item;
  16420. // add to group
  16421. var groupId = this._getGroupId(item.data);
  16422. var group = this.groups[groupId];
  16423. if (!group) {
  16424. item.groupShowing = false;
  16425. } else if (group && group.data && group.data.showNested) {
  16426. item.groupShowing = true;
  16427. }
  16428. if (group) group.add(item);
  16429. };
  16430. /**
  16431. * Update an existing item
  16432. * @param {Item} item
  16433. * @param {Object} itemData
  16434. * @private
  16435. */
  16436. ItemSet.prototype._updateItem = function(item, itemData) {
  16437. // update the items data (will redraw the item when displayed)
  16438. item.setData(itemData);
  16439. var groupId = this._getGroupId(item.data);
  16440. var group = this.groups[groupId];
  16441. if (!group) {
  16442. item.groupShowing = false;
  16443. } else if (group && group.data && group.data.showNested) {
  16444. item.groupShowing = true;
  16445. }
  16446. };
  16447. /**
  16448. * Delete an item from the ItemSet: remove it from the DOM, from the map
  16449. * with items, and from the map with visible items, and from the selection
  16450. * @param {Item} item
  16451. * @private
  16452. */
  16453. ItemSet.prototype._removeItem = function(item) {
  16454. // remove from DOM
  16455. item.hide();
  16456. // remove from items
  16457. delete this.items[item.id];
  16458. // remove from selection
  16459. var index = this.selection.indexOf(item.id);
  16460. if (index != -1) this.selection.splice(index, 1);
  16461. // remove from group
  16462. item.parent && item.parent.remove(item);
  16463. };
  16464. /**
  16465. * Create an array containing all items being a range (having an end date)
  16466. * @param {Array.<Object>} array
  16467. * @returns {Array}
  16468. * @private
  16469. */
  16470. ItemSet.prototype._constructByEndArray = function(array) {
  16471. var endArray = [];
  16472. for (var i = 0; i < array.length; i++) {
  16473. if (array[i] instanceof RangeItem) {
  16474. endArray.push(array[i]);
  16475. }
  16476. }
  16477. return endArray;
  16478. };
  16479. /**
  16480. * Register the clicked item on touch, before dragStart is initiated.
  16481. *
  16482. * dragStart is initiated from a mousemove event, AFTER the mouse/touch is
  16483. * already moving. Therefore, the mouse/touch can sometimes be above an other
  16484. * DOM element than the item itself.
  16485. *
  16486. * @param {Event} event
  16487. * @private
  16488. */
  16489. ItemSet.prototype._onTouch = function(event) {
  16490. // store the touched item, used in _onDragStart
  16491. this.touchParams.item = this.itemFromTarget(event);
  16492. this.touchParams.dragLeftItem = event.target.dragLeftItem || false;
  16493. this.touchParams.dragRightItem = event.target.dragRightItem || false;
  16494. this.touchParams.itemProps = null;
  16495. };
  16496. /**
  16497. * Given an group id, returns the index it has.
  16498. *
  16499. * @param {number} groupId
  16500. * @returns {number} index / groupId
  16501. * @private
  16502. */
  16503. ItemSet.prototype._getGroupIndex = function(groupId) {
  16504. for (var i = 0; i < this.groupIds.length; i++) {
  16505. if (groupId == this.groupIds[i]) return i;
  16506. }
  16507. };
  16508. /**
  16509. * Start dragging the selected events
  16510. * @param {Event} event
  16511. * @private
  16512. */
  16513. ItemSet.prototype._onDragStart = function(event) {
  16514. if (this.touchParams.itemIsDragging) {
  16515. return;
  16516. }
  16517. var item = this.touchParams.item || null;
  16518. var me = this;
  16519. var props;
  16520. if (item && (item.selected || this.options.itemsAlwaysDraggable.item)) {
  16521. if (this.options.editable.overrideItems && !this.options.editable.updateTime && !this.options.editable.updateGroup) {
  16522. return;
  16523. }
  16524. // override options.editable
  16525. if (item.editable != null && !item.editable.updateTime && !item.editable.updateGroup && !this.options.editable.overrideItems) {
  16526. return;
  16527. }
  16528. var dragLeftItem = this.touchParams.dragLeftItem;
  16529. var dragRightItem = this.touchParams.dragRightItem;
  16530. this.touchParams.itemIsDragging = true;
  16531. this.touchParams.selectedItem = item;
  16532. if (dragLeftItem) {
  16533. props = {
  16534. item: dragLeftItem,
  16535. initialX: event.center.x,
  16536. dragLeft: true,
  16537. data: this._cloneItemData(item.data)
  16538. };
  16539. this.touchParams.itemProps = [props];
  16540. } else if (dragRightItem) {
  16541. props = {
  16542. item: dragRightItem,
  16543. initialX: event.center.x,
  16544. dragRight: true,
  16545. data: this._cloneItemData(item.data)
  16546. };
  16547. this.touchParams.itemProps = [props];
  16548. } else if (this.options.editable.add && (event.srcEvent.ctrlKey || event.srcEvent.metaKey)) {
  16549. // create a new range item when dragging with ctrl key down
  16550. this._onDragStartAddItem(event);
  16551. } else {
  16552. if (this.groupIds.length < 1) {
  16553. // Mitigates a race condition if _onDragStart() is
  16554. // called after markDirty() without redraw() being called between.
  16555. this.redraw();
  16556. }
  16557. var baseGroupIndex = this._getGroupIndex(item.data.group);
  16558. var itemsToDrag = this.options.itemsAlwaysDraggable.item && !item.selected ? [item.id] : this.getSelection();
  16559. this.touchParams.itemProps = itemsToDrag.map(function(id) {
  16560. var item = me.items[id];
  16561. var groupIndex = me._getGroupIndex(item.data.group);
  16562. return {
  16563. item: item,
  16564. initialX: event.center.x,
  16565. groupOffset: baseGroupIndex - groupIndex,
  16566. data: this._cloneItemData(item.data)
  16567. };
  16568. }.bind(this));
  16569. }
  16570. event.stopPropagation();
  16571. } else if (this.options.editable.add && (event.srcEvent.ctrlKey || event.srcEvent.metaKey)) {
  16572. // create a new range item when dragging with ctrl key down
  16573. this._onDragStartAddItem(event);
  16574. }
  16575. };
  16576. /**
  16577. * Start creating a new range item by dragging.
  16578. * @param {Event} event
  16579. * @private
  16580. */
  16581. ItemSet.prototype._onDragStartAddItem = function(event) {
  16582. var xAbs;
  16583. var x;
  16584. var snap = this.options.snap || null;
  16585. if (this.options.rtl) {
  16586. xAbs = util.getAbsoluteRight(this.dom.frame);
  16587. x = xAbs - event.center.x + 10; // plus 10 to compensate for the drag starting as soon as you've moved 10px
  16588. } else {
  16589. xAbs = util.getAbsoluteLeft(this.dom.frame);
  16590. x = event.center.x - xAbs - 10; // minus 10 to compensate for the drag starting as soon as you've moved 10px
  16591. }
  16592. var time = this.body.util.toTime(x);
  16593. var scale = this.body.util.getScale();
  16594. var step = this.body.util.getStep();
  16595. var start = snap ? snap(time, scale, step) : time;
  16596. var end = start;
  16597. var itemData = {
  16598. type: 'range',
  16599. start: start,
  16600. end: end,
  16601. content: 'new item'
  16602. };
  16603. var id = util.randomUUID();
  16604. itemData[this.itemsData._fieldId] = id;
  16605. var group = this.groupFromTarget(event);
  16606. if (group) {
  16607. itemData.group = group.groupId;
  16608. }
  16609. var newItem = new RangeItem(itemData, this.conversion, this.options);
  16610. newItem.id = id; // TODO: not so nice setting id afterwards
  16611. newItem.data = this._cloneItemData(itemData);
  16612. this._addItem(newItem);
  16613. this.touchParams.selectedItem = newItem;
  16614. var props = {
  16615. item: newItem,
  16616. initialX: event.center.x,
  16617. data: newItem.data
  16618. };
  16619. if (this.options.rtl) {
  16620. props.dragLeft = true;
  16621. } else {
  16622. props.dragRight = true;
  16623. }
  16624. this.touchParams.itemProps = [props];
  16625. event.stopPropagation();
  16626. };
  16627. /**
  16628. * Drag selected items
  16629. * @param {Event} event
  16630. * @private
  16631. */
  16632. ItemSet.prototype._onDrag = function(event) {
  16633. if (this.touchParams.itemProps) {
  16634. event.stopPropagation();
  16635. var me = this;
  16636. var snap = this.options.snap || null;
  16637. var xOffset;
  16638. if (this.options.rtl) {
  16639. xOffset = this.body.dom.root.offsetLeft + this.body.domProps.right.width;
  16640. } else {
  16641. xOffset = this.body.dom.root.offsetLeft + this.body.domProps.left.width;
  16642. }
  16643. var scale = this.body.util.getScale();
  16644. var step = this.body.util.getStep();
  16645. //only calculate the new group for the item that's actually dragged
  16646. var selectedItem = this.touchParams.selectedItem;
  16647. var updateGroupAllowed = (this.options.editable.overrideItems || selectedItem.editable == null) && this.options.editable.updateGroup || !this.options.editable.overrideItems && selectedItem.editable != null && selectedItem.editable.updateGroup;
  16648. var newGroupBase = null;
  16649. if (updateGroupAllowed && selectedItem) {
  16650. if (selectedItem.data.group != undefined) {
  16651. // drag from one group to another
  16652. var group = me.groupFromTarget(event);
  16653. if (group) {
  16654. //we know the offset for all items, so the new group for all items
  16655. //will be relative to this one.
  16656. newGroupBase = this._getGroupIndex(group.groupId);
  16657. }
  16658. }
  16659. }
  16660. // move
  16661. this.touchParams.itemProps.forEach(function(props) {
  16662. var current = me.body.util.toTime(event.center.x - xOffset);
  16663. var initial = me.body.util.toTime(props.initialX - xOffset);
  16664. var offset;
  16665. var initialStart;
  16666. var initialEnd;
  16667. var start;
  16668. var end;
  16669. if (this.options.rtl) {
  16670. offset = -(current - initial); // ms
  16671. } else {
  16672. offset = current - initial; // ms
  16673. }
  16674. var itemData = this._cloneItemData(props.item.data); // clone the data
  16675. if (props.item.editable != null && !props.item.editable.updateTime && !props.item.editable.updateGroup && !me.options.editable.overrideItems) {
  16676. return;
  16677. }
  16678. var updateTimeAllowed = (this.options.editable.overrideItems || selectedItem.editable == null) && this.options.editable.updateTime || !this.options.editable.overrideItems && selectedItem.editable != null && selectedItem.editable.updateTime;
  16679. if (updateTimeAllowed) {
  16680. if (props.dragLeft) {
  16681. // drag left side of a range item
  16682. if (this.options.rtl) {
  16683. if (itemData.end != undefined) {
  16684. initialEnd = util.convert(props.data.end, 'Date');
  16685. end = new Date(initialEnd.valueOf() + offset);
  16686. // TODO: pass a Moment instead of a Date to snap(). (Breaking change)
  16687. itemData.end = snap ? snap(end, scale, step) : end;
  16688. }
  16689. } else {
  16690. if (itemData.start != undefined) {
  16691. initialStart = util.convert(props.data.start, 'Date');
  16692. start = new Date(initialStart.valueOf() + offset);
  16693. // TODO: pass a Moment instead of a Date to snap(). (Breaking change)
  16694. itemData.start = snap ? snap(start, scale, step) : start;
  16695. }
  16696. }
  16697. } else if (props.dragRight) {
  16698. // drag right side of a range item
  16699. if (this.options.rtl) {
  16700. if (itemData.start != undefined) {
  16701. initialStart = util.convert(props.data.start, 'Date');
  16702. start = new Date(initialStart.valueOf() + offset);
  16703. // TODO: pass a Moment instead of a Date to snap(). (Breaking change)
  16704. itemData.start = snap ? snap(start, scale, step) : start;
  16705. }
  16706. } else {
  16707. if (itemData.end != undefined) {
  16708. initialEnd = util.convert(props.data.end, 'Date');
  16709. end = new Date(initialEnd.valueOf() + offset);
  16710. // TODO: pass a Moment instead of a Date to snap(). (Breaking change)
  16711. itemData.end = snap ? snap(end, scale, step) : end;
  16712. }
  16713. }
  16714. } else {
  16715. // drag both start and end
  16716. if (itemData.start != undefined) {
  16717. initialStart = util.convert(props.data.start, 'Date').valueOf();
  16718. start = new Date(initialStart + offset);
  16719. if (itemData.end != undefined) {
  16720. initialEnd = util.convert(props.data.end, 'Date');
  16721. var duration = initialEnd.valueOf() - initialStart.valueOf();
  16722. // TODO: pass a Moment instead of a Date to snap(). (Breaking change)
  16723. itemData.start = snap ? snap(start, scale, step) : start;
  16724. itemData.end = new Date(itemData.start.valueOf() + duration);
  16725. } else {
  16726. // TODO: pass a Moment instead of a Date to snap(). (Breaking change)
  16727. itemData.start = snap ? snap(start, scale, step) : start;
  16728. }
  16729. }
  16730. }
  16731. }
  16732. if (updateGroupAllowed && !props.dragLeft && !props.dragRight && newGroupBase != null) {
  16733. if (itemData.group != undefined) {
  16734. var newOffset = newGroupBase - props.groupOffset;
  16735. //make sure we stay in bounds
  16736. newOffset = Math.max(0, newOffset);
  16737. newOffset = Math.min(me.groupIds.length - 1, newOffset);
  16738. itemData.group = me.groupIds[newOffset];
  16739. }
  16740. }
  16741. // confirm moving the item
  16742. itemData = this._cloneItemData(itemData); // convert start and end to the correct type
  16743. me.options.onMoving(itemData, function(itemData) {
  16744. if (itemData) {
  16745. props.item.setData(this._cloneItemData(itemData, 'Date'));
  16746. }
  16747. }.bind(this));
  16748. }.bind(this));
  16749. this.body.emitter.emit('_change');
  16750. }
  16751. };
  16752. /**
  16753. * Move an item to another group
  16754. * @param {Item} item
  16755. * @param {string | number} groupId
  16756. * @private
  16757. */
  16758. ItemSet.prototype._moveToGroup = function(item, groupId) {
  16759. var group = this.groups[groupId];
  16760. if (group && group.groupId != item.data.group) {
  16761. var oldGroup = item.parent;
  16762. oldGroup.remove(item);
  16763. oldGroup.order();
  16764. item.data.group = group.groupId;
  16765. group.add(item);
  16766. group.order();
  16767. }
  16768. };
  16769. /**
  16770. * End of dragging selected items
  16771. * @param {Event} event
  16772. * @private
  16773. */
  16774. ItemSet.prototype._onDragEnd = function(event) {
  16775. this.touchParams.itemIsDragging = false;
  16776. if (this.touchParams.itemProps) {
  16777. event.stopPropagation();
  16778. var me = this;
  16779. var dataset = this.itemsData.getDataSet();
  16780. var itemProps = this.touchParams.itemProps;
  16781. this.touchParams.itemProps = null;
  16782. itemProps.forEach(function(props) {
  16783. var id = props.item.id;
  16784. var exists = me.itemsData.get(id, me.itemOptions) != null;
  16785. if (!exists) {
  16786. // add a new item
  16787. me.options.onAdd(props.item.data, function(itemData) {
  16788. me._removeItem(props.item); // remove temporary item
  16789. if (itemData) {
  16790. me.itemsData.getDataSet().add(itemData);
  16791. }
  16792. // force re-stacking of all items next redraw
  16793. me.body.emitter.emit('_change');
  16794. });
  16795. } else {
  16796. // update existing item
  16797. var itemData = this._cloneItemData(props.item.data); // convert start and end to the correct type
  16798. me.options.onMove(itemData, function(itemData) {
  16799. if (itemData) {
  16800. // apply changes
  16801. itemData[dataset._fieldId] = id; // ensure the item contains its id (can be undefined)
  16802. dataset.update(itemData);
  16803. } else {
  16804. // restore original values
  16805. props.item.setData(props.data);
  16806. me.body.emitter.emit('_change');
  16807. }
  16808. });
  16809. }
  16810. }.bind(this));
  16811. }
  16812. };
  16813. ItemSet.prototype._onGroupClick = function(event) {
  16814. var group = this.groupFromTarget(event);
  16815. if (!group || !group.nestedGroups) return;
  16816. var groupsData = this.groupsData.getDataSet();
  16817. var nestingGroup = groupsData.get(group.groupId);
  16818. if (nestingGroup.showNested == undefined) {
  16819. nestingGroup.showNested = true;
  16820. }
  16821. nestingGroup.showNested = !nestingGroup.showNested;
  16822. var nestedGroups = groupsData.get(group.nestedGroups).map(function(nestedGroup) {
  16823. nestedGroup.visible = nestingGroup.showNested;
  16824. return nestedGroup;
  16825. });
  16826. groupsData.update(nestedGroups.concat(nestingGroup));
  16827. if (nestingGroup.showNested) {
  16828. util.removeClassName(group.dom.label, 'collapsed');
  16829. util.addClassName(group.dom.label, 'expanded');
  16830. } else {
  16831. util.removeClassName(group.dom.label, 'expanded');
  16832. var collapsedDirClassName = this.options.rtl ? 'collapsed-rtl' : 'collapsed';
  16833. util.addClassName(group.dom.label, collapsedDirClassName);
  16834. }
  16835. };
  16836. ItemSet.prototype._onGroupDragStart = function(event) {
  16837. if (this.options.groupEditable.order) {
  16838. this.groupTouchParams.group = this.groupFromTarget(event);
  16839. if (this.groupTouchParams.group) {
  16840. event.stopPropagation();
  16841. this.groupTouchParams.originalOrder = this.groupsData.getIds({
  16842. order: this.options.groupOrder
  16843. });
  16844. }
  16845. }
  16846. };
  16847. ItemSet.prototype._onGroupDrag = function(event) {
  16848. if (this.options.groupEditable.order && this.groupTouchParams.group) {
  16849. event.stopPropagation();
  16850. var groupsData = this.groupsData;
  16851. if (this.groupsData instanceof DataView) {
  16852. groupsData = this.groupsData.getDataSet();
  16853. }
  16854. // drag from one group to another
  16855. var group = this.groupFromTarget(event);
  16856. // try to avoid toggling when groups differ in height
  16857. if (group && group.height != this.groupTouchParams.group.height) {
  16858. var movingUp = group.top < this.groupTouchParams.group.top;
  16859. var clientY = event.center ? event.center.y : event.clientY;
  16860. var targetGroupTop = util.getAbsoluteTop(group.dom.foreground);
  16861. var draggedGroupHeight = this.groupTouchParams.group.height;
  16862. if (movingUp) {
  16863. // skip swapping the groups when the dragged group is not below clientY afterwards
  16864. if (targetGroupTop + draggedGroupHeight < clientY) {
  16865. return;
  16866. }
  16867. } else {
  16868. var targetGroupHeight = group.height;
  16869. // skip swapping the groups when the dragged group is not below clientY afterwards
  16870. if (targetGroupTop + targetGroupHeight - draggedGroupHeight > clientY) {
  16871. return;
  16872. }
  16873. }
  16874. }
  16875. if (group && group != this.groupTouchParams.group) {
  16876. var targetGroup = groupsData.get(group.groupId);
  16877. var draggedGroup = groupsData.get(this.groupTouchParams.group.groupId);
  16878. // switch groups
  16879. if (draggedGroup && targetGroup) {
  16880. this.options.groupOrderSwap(draggedGroup, targetGroup, groupsData);
  16881. groupsData.update(draggedGroup);
  16882. groupsData.update(targetGroup);
  16883. }
  16884. // fetch current order of groups
  16885. var newOrder = groupsData.getIds({
  16886. order: this.options.groupOrder
  16887. });
  16888. // in case of changes since _onGroupDragStart
  16889. if (!util.equalArray(newOrder, this.groupTouchParams.originalOrder)) {
  16890. var origOrder = this.groupTouchParams.originalOrder;
  16891. var draggedId = this.groupTouchParams.group.groupId;
  16892. var numGroups = Math.min(origOrder.length, newOrder.length);
  16893. var curPos = 0;
  16894. var newOffset = 0;
  16895. var orgOffset = 0;
  16896. while (curPos < numGroups) {
  16897. // as long as the groups are where they should be step down along the groups order
  16898. while (curPos + newOffset < numGroups && curPos + orgOffset < numGroups && newOrder[curPos + newOffset] == origOrder[curPos + orgOffset]) {
  16899. curPos++;
  16900. }
  16901. // all ok
  16902. if (curPos + newOffset >= numGroups) {
  16903. break;
  16904. }
  16905. // not all ok
  16906. // if dragged group was move upwards everything below should have an offset
  16907. if (newOrder[curPos + newOffset] == draggedId) {
  16908. newOffset = 1;
  16909. }
  16910. // if dragged group was move downwards everything above should have an offset
  16911. else if (origOrder[curPos + orgOffset] == draggedId) {
  16912. orgOffset = 1;
  16913. }
  16914. // found a group (apart from dragged group) that has the wrong position -> switch with the
  16915. // group at the position where other one should be, fix index arrays and continue
  16916. else {
  16917. var slippedPosition = newOrder.indexOf(origOrder[curPos + orgOffset]);
  16918. var switchGroup = groupsData.get(newOrder[curPos + newOffset]);
  16919. var shouldBeGroup = groupsData.get(origOrder[curPos + orgOffset]);
  16920. this.options.groupOrderSwap(switchGroup, shouldBeGroup, groupsData);
  16921. groupsData.update(switchGroup);
  16922. groupsData.update(shouldBeGroup);
  16923. var switchGroupId = newOrder[curPos + newOffset];
  16924. newOrder[curPos + newOffset] = origOrder[curPos + orgOffset];
  16925. newOrder[slippedPosition] = switchGroupId;
  16926. curPos++;
  16927. }
  16928. }
  16929. }
  16930. }
  16931. }
  16932. };
  16933. ItemSet.prototype._onGroupDragEnd = function(event) {
  16934. if (this.options.groupEditable.order && this.groupTouchParams.group) {
  16935. event.stopPropagation();
  16936. // update existing group
  16937. var me = this;
  16938. var id = me.groupTouchParams.group.groupId;
  16939. var dataset = me.groupsData.getDataSet();
  16940. var groupData = util.extend({}, dataset.get(id)); // clone the data
  16941. me.options.onMoveGroup(groupData, function(groupData) {
  16942. if (groupData) {
  16943. // apply changes
  16944. groupData[dataset._fieldId] = id; // ensure the group contains its id (can be undefined)
  16945. dataset.update(groupData);
  16946. } else {
  16947. // fetch current order of groups
  16948. var newOrder = dataset.getIds({
  16949. order: me.options.groupOrder
  16950. });
  16951. // restore original order
  16952. if (!util.equalArray(newOrder, me.groupTouchParams.originalOrder)) {
  16953. var origOrder = me.groupTouchParams.originalOrder;
  16954. var numGroups = Math.min(origOrder.length, newOrder.length);
  16955. var curPos = 0;
  16956. while (curPos < numGroups) {
  16957. // as long as the groups are where they should be step down along the groups order
  16958. while (curPos < numGroups && newOrder[curPos] == origOrder[curPos]) {
  16959. curPos++;
  16960. }
  16961. // all ok
  16962. if (curPos >= numGroups) {
  16963. break;
  16964. }
  16965. // found a group that has the wrong position -> switch with the
  16966. // group at the position where other one should be, fix index arrays and continue
  16967. var slippedPosition = newOrder.indexOf(origOrder[curPos]);
  16968. var switchGroup = dataset.get(newOrder[curPos]);
  16969. var shouldBeGroup = dataset.get(origOrder[curPos]);
  16970. me.options.groupOrderSwap(switchGroup, shouldBeGroup, dataset);
  16971. dataset.update(switchGroup);
  16972. dataset.update(shouldBeGroup);
  16973. var switchGroupId = newOrder[curPos];
  16974. newOrder[curPos] = origOrder[curPos];
  16975. newOrder[slippedPosition] = switchGroupId;
  16976. curPos++;
  16977. }
  16978. }
  16979. }
  16980. });
  16981. me.body.emitter.emit('groupDragged', { groupId: id });
  16982. }
  16983. };
  16984. /**
  16985. * Handle selecting/deselecting an item when tapping it
  16986. * @param {Event} event
  16987. * @private
  16988. */
  16989. ItemSet.prototype._onSelectItem = function(event) {
  16990. if (!this.options.selectable) return;
  16991. var ctrlKey = event.srcEvent && (event.srcEvent.ctrlKey || event.srcEvent.metaKey);
  16992. var shiftKey = event.srcEvent && event.srcEvent.shiftKey;
  16993. if (ctrlKey || shiftKey) {
  16994. this._onMultiSelectItem(event);
  16995. return;
  16996. }
  16997. var oldSelection = this.getSelection();
  16998. var item = this.itemFromTarget(event);
  16999. var selection = item ? [item.id] : [];
  17000. this.setSelection(selection);
  17001. var newSelection = this.getSelection();
  17002. // emit a select event,
  17003. // except when old selection is empty and new selection is still empty
  17004. if (newSelection.length > 0 || oldSelection.length > 0) {
  17005. this.body.emitter.emit('select', {
  17006. items: newSelection,
  17007. event: event
  17008. });
  17009. }
  17010. };
  17011. /**
  17012. * Handle hovering an item
  17013. * @param {Event} event
  17014. * @private
  17015. */
  17016. ItemSet.prototype._onMouseOver = function(event) {
  17017. var item = this.itemFromTarget(event);
  17018. if (!item) return;
  17019. // Item we just left
  17020. var related = this.itemFromRelatedTarget(event);
  17021. if (item === related) {
  17022. // We haven't changed item, just element in the item
  17023. return;
  17024. }
  17025. var title = item.getTitle();
  17026. if (this.options.showTooltips && title) {
  17027. if (this.popup == null) {
  17028. this.popup = new Popup(this.body.dom.root, this.options.tooltip.overflowMethod || 'flip');
  17029. }
  17030. this.popup.setText(title);
  17031. var container = this.body.dom.centerContainer;
  17032. this.popup.setPosition(event.clientX - util.getAbsoluteLeft(container) + container.offsetLeft, event.clientY - util.getAbsoluteTop(container) + container.offsetTop);
  17033. this.popup.show();
  17034. } else {
  17035. // Hovering over item without a title, hide popup
  17036. // Needed instead of _just_ in _onMouseOut due to #2572
  17037. if (this.popup != null) {
  17038. this.popup.hide();
  17039. }
  17040. }
  17041. this.body.emitter.emit('itemover', {
  17042. item: item.id,
  17043. event: event
  17044. });
  17045. };
  17046. ItemSet.prototype._onMouseOut = function(event) {
  17047. var item = this.itemFromTarget(event);
  17048. if (!item) return;
  17049. // Item we are going to
  17050. var related = this.itemFromRelatedTarget(event);
  17051. if (item === related) {
  17052. // We aren't changing item, just element in the item
  17053. return;
  17054. }
  17055. if (this.popup != null) {
  17056. this.popup.hide();
  17057. }
  17058. this.body.emitter.emit('itemout', {
  17059. item: item.id,
  17060. event: event
  17061. });
  17062. };
  17063. ItemSet.prototype._onMouseMove = function(event) {
  17064. var item = this.itemFromTarget(event);
  17065. if (!item) return;
  17066. if (this.options.showTooltips && this.options.tooltip.followMouse) {
  17067. if (this.popup) {
  17068. if (!this.popup.hidden) {
  17069. var container = this.body.dom.centerContainer;
  17070. this.popup.setPosition(event.clientX - util.getAbsoluteLeft(container) + container.offsetLeft, event.clientY - util.getAbsoluteTop(container) + container.offsetTop);
  17071. this.popup.show(); // Redraw
  17072. }
  17073. }
  17074. }
  17075. };
  17076. /**
  17077. * Handle mousewheel
  17078. * @param {Event} event The event
  17079. * @private
  17080. */
  17081. ItemSet.prototype._onMouseWheel = function(event) {
  17082. if (this.touchParams.itemIsDragging) {
  17083. this._onDragEnd(event);
  17084. }
  17085. };
  17086. /**
  17087. * Handle updates of an item on double tap
  17088. * @param {vis.Item} item The item
  17089. * @private
  17090. */
  17091. ItemSet.prototype._onUpdateItem = function(item) {
  17092. if (!this.options.selectable) return;
  17093. if (!this.options.editable.add) return;
  17094. var me = this;
  17095. if (item) {
  17096. // execute async handler to update the item (or cancel it)
  17097. var itemData = me.itemsData.get(item.id); // get a clone of the data from the dataset
  17098. this.options.onUpdate(itemData, function(itemData) {
  17099. if (itemData) {
  17100. me.itemsData.getDataSet().update(itemData);
  17101. }
  17102. });
  17103. }
  17104. };
  17105. /**
  17106. * Handle drop event of data on item
  17107. * Only called when `objectData.target === 'item'.
  17108. * @param {Event} event The event
  17109. * @private
  17110. */
  17111. ItemSet.prototype._onDropObjectOnItem = function(event) {
  17112. var item = this.itemFromTarget(event);
  17113. var objectData = JSON.parse(event.dataTransfer.getData("text"));
  17114. this.options.onDropObjectOnItem(objectData, item);
  17115. };
  17116. /**
  17117. * Handle creation of an item on double tap or drop of a drag event
  17118. * @param {Event} event The event
  17119. * @private
  17120. */
  17121. ItemSet.prototype._onAddItem = function(event) {
  17122. if (!this.options.selectable) return;
  17123. if (!this.options.editable.add) return;
  17124. var me = this;
  17125. var snap = this.options.snap || null;
  17126. var xAbs;
  17127. var x;
  17128. // add item
  17129. if (this.options.rtl) {
  17130. xAbs = util.getAbsoluteRight(this.dom.frame);
  17131. x = xAbs - event.center.x;
  17132. } else {
  17133. xAbs = util.getAbsoluteLeft(this.dom.frame);
  17134. x = event.center.x - xAbs;
  17135. }
  17136. // var xAbs = util.getAbsoluteLeft(this.dom.frame);
  17137. // var x = event.center.x - xAbs;
  17138. var start = this.body.util.toTime(x);
  17139. var scale = this.body.util.getScale();
  17140. var step = this.body.util.getStep();
  17141. var end;
  17142. var newItemData;
  17143. if (event.type == 'drop') {
  17144. newItemData = JSON.parse(event.dataTransfer.getData("text"));
  17145. newItemData.content = newItemData.content ? newItemData.content : 'new item';
  17146. newItemData.start = newItemData.start ? newItemData.start : snap ? snap(start, scale, step) : start;
  17147. newItemData.type = newItemData.type || 'box';
  17148. newItemData[this.itemsData._fieldId] = newItemData.id || util.randomUUID();
  17149. if (newItemData.type == 'range' && !newItemData.end) {
  17150. end = this.body.util.toTime(x + this.props.width / 5);
  17151. newItemData.end = snap ? snap(end, scale, step) : end;
  17152. }
  17153. } else {
  17154. newItemData = {
  17155. start: snap ? snap(start, scale, step) : start,
  17156. content: 'new item'
  17157. };
  17158. newItemData[this.itemsData._fieldId] = util.randomUUID();
  17159. // when default type is a range, add a default end date to the new item
  17160. if (this.options.type === 'range') {
  17161. end = this.body.util.toTime(x + this.props.width / 5);
  17162. newItemData.end = snap ? snap(end, scale, step) : end;
  17163. }
  17164. }
  17165. var group = this.groupFromTarget(event);
  17166. if (group) {
  17167. newItemData.group = group.groupId;
  17168. }
  17169. // execute async handler to customize (or cancel) adding an item
  17170. newItemData = this._cloneItemData(newItemData); // convert start and end to the correct type
  17171. this.options.onAdd(newItemData, function(item) {
  17172. if (item) {
  17173. me.itemsData.getDataSet().add(item);
  17174. if (event.type == 'drop') {
  17175. me.setSelection([item.id]);
  17176. }
  17177. // TODO: need to trigger a redraw?
  17178. }
  17179. });
  17180. };
  17181. /**
  17182. * Handle selecting/deselecting multiple items when holding an item
  17183. * @param {Event} event
  17184. * @private
  17185. */
  17186. ItemSet.prototype._onMultiSelectItem = function(event) {
  17187. if (!this.options.selectable) return;
  17188. var item = this.itemFromTarget(event);
  17189. if (item) {
  17190. // multi select items (if allowed)
  17191. var selection = this.options.multiselect ? this.getSelection() // take current selection
  17192. :
  17193. []; // deselect current selection
  17194. var shiftKey = event.srcEvent && event.srcEvent.shiftKey || false;
  17195. if (shiftKey && this.options.multiselect) {
  17196. // select all items between the old selection and the tapped item
  17197. var itemGroup = this.itemsData.get(item.id).group;
  17198. // when filtering get the group of the last selected item
  17199. var lastSelectedGroup = undefined;
  17200. if (this.options.multiselectPerGroup) {
  17201. if (selection.length > 0) {
  17202. lastSelectedGroup = this.itemsData.get(selection[0]).group;
  17203. }
  17204. }
  17205. // determine the selection range
  17206. if (!this.options.multiselectPerGroup || lastSelectedGroup == undefined || lastSelectedGroup == itemGroup) {
  17207. selection.push(item.id);
  17208. }
  17209. var range = ItemSet._getItemRange(this.itemsData.get(selection, this.itemOptions));
  17210. if (!this.options.multiselectPerGroup || lastSelectedGroup == itemGroup) {
  17211. // select all items within the selection range
  17212. selection = [];
  17213. for (var id in this.items) {
  17214. if (this.items.hasOwnProperty(id)) {
  17215. var _item = this.items[id];
  17216. var start = _item.data.start;
  17217. var end = _item.data.end !== undefined ? _item.data.end : start;
  17218. if (start >= range.min && end <= range.max && (!this.options.multiselectPerGroup || lastSelectedGroup == this.itemsData.get(_item.id).group) && !(_item instanceof BackgroundItem)) {
  17219. selection.push(_item.id); // do not use id but item.id, id itself is stringified
  17220. }
  17221. }
  17222. }
  17223. }
  17224. } else {
  17225. // add/remove this item from the current selection
  17226. var index = selection.indexOf(item.id);
  17227. if (index == -1) {
  17228. // item is not yet selected -> select it
  17229. selection.push(item.id);
  17230. } else {
  17231. // item is already selected -> deselect it
  17232. selection.splice(index, 1);
  17233. }
  17234. }
  17235. this.setSelection(selection);
  17236. this.body.emitter.emit('select', {
  17237. items: this.getSelection(),
  17238. event: event
  17239. });
  17240. }
  17241. };
  17242. /**
  17243. * Calculate the time range of a list of items
  17244. * @param {Array.<Object>} itemsData
  17245. * @return {{min: Date, max: Date}} Returns the range of the provided items
  17246. * @private
  17247. */
  17248. ItemSet._getItemRange = function(itemsData) {
  17249. var max = null;
  17250. var min = null;
  17251. itemsData.forEach(function(data) {
  17252. if (min == null || data.start < min) {
  17253. min = data.start;
  17254. }
  17255. if (data.end != undefined) {
  17256. if (max == null || data.end > max) {
  17257. max = data.end;
  17258. }
  17259. } else {
  17260. if (max == null || data.start > max) {
  17261. max = data.start;
  17262. }
  17263. }
  17264. });
  17265. return {
  17266. min: min,
  17267. max: max
  17268. };
  17269. };
  17270. /**
  17271. * Find an item from an element:
  17272. * searches for the attribute 'timeline-item' in the element's tree
  17273. * @param {HTMLElement} element
  17274. * @return {Item | null} item
  17275. */
  17276. ItemSet.prototype.itemFromElement = function(element) {
  17277. var cur = element;
  17278. while (cur) {
  17279. if (cur.hasOwnProperty('timeline-item')) {
  17280. return cur['timeline-item'];
  17281. }
  17282. cur = cur.parentNode;
  17283. }
  17284. return null;
  17285. };
  17286. /**
  17287. * Find an item from an event target:
  17288. * searches for the attribute 'timeline-item' in the event target's element tree
  17289. * @param {Event} event
  17290. * @return {Item | null} item
  17291. */
  17292. ItemSet.prototype.itemFromTarget = function(event) {
  17293. return this.itemFromElement(event.target);
  17294. };
  17295. /**
  17296. * Find an item from an event's related target:
  17297. * searches for the attribute 'timeline-item' in the related target's element tree
  17298. * @param {Event} event
  17299. * @return {Item | null} item
  17300. */
  17301. ItemSet.prototype.itemFromRelatedTarget = function(event) {
  17302. return this.itemFromElement(event.relatedTarget);
  17303. };
  17304. /**
  17305. * Find the Group from an event target:
  17306. * searches for the attribute 'timeline-group' in the event target's element tree
  17307. * @param {Event} event
  17308. * @return {Group | null} group
  17309. */
  17310. ItemSet.prototype.groupFromTarget = function(event) {
  17311. var clientY = event.center ? event.center.y : event.clientY;
  17312. var groupIds = this.groupIds;
  17313. if (groupIds.length <= 0 && this.groupsData) {
  17314. groupIds = this.groupsData.getIds({
  17315. order: this.options.groupOrder
  17316. });
  17317. }
  17318. for (var i = 0; i < groupIds.length; i++) {
  17319. var groupId = groupIds[i];
  17320. var group = this.groups[groupId];
  17321. var foreground = group.dom.foreground;
  17322. var top = util.getAbsoluteTop(foreground);
  17323. if (clientY > top && clientY < top + foreground.offsetHeight) {
  17324. return group;
  17325. }
  17326. if (this.options.orientation.item === 'top') {
  17327. if (i === this.groupIds.length - 1 && clientY > top) {
  17328. return group;
  17329. }
  17330. } else {
  17331. if (i === 0 && clientY < top + foreground.offset) {
  17332. return group;
  17333. }
  17334. }
  17335. }
  17336. return null;
  17337. };
  17338. /**
  17339. * Find the ItemSet from an event target:
  17340. * searches for the attribute 'timeline-itemset' in the event target's element tree
  17341. * @param {Event} event
  17342. * @return {ItemSet | null} item
  17343. */
  17344. ItemSet.itemSetFromTarget = function(event) {
  17345. var target = event.target;
  17346. while (target) {
  17347. if (target.hasOwnProperty('timeline-itemset')) {
  17348. return target['timeline-itemset'];
  17349. }
  17350. target = target.parentNode;
  17351. }
  17352. return null;
  17353. };
  17354. /**
  17355. * Clone the data of an item, and "normalize" it: convert the start and end date
  17356. * to the type (Date, Moment, ...) configured in the DataSet. If not configured,
  17357. * start and end are converted to Date.
  17358. * @param {Object} itemData, typically `item.data`
  17359. * @param {string} [type] Optional Date type. If not provided, the type from the DataSet is taken
  17360. * @return {Object} The cloned object
  17361. * @private
  17362. */
  17363. ItemSet.prototype._cloneItemData = function(itemData, type) {
  17364. var clone = util.extend({}, itemData);
  17365. if (!type) {
  17366. // convert start and end date to the type (Date, Moment, ...) configured in the DataSet
  17367. type = this.itemsData.getDataSet()._options.type;
  17368. }
  17369. if (clone.start != undefined) {
  17370. clone.start = util.convert(clone.start, type && type.start || 'Date');
  17371. }
  17372. if (clone.end != undefined) {
  17373. clone.end = util.convert(clone.end, type && type.end || 'Date');
  17374. }
  17375. return clone;
  17376. };
  17377. module.exports = ItemSet;
  17378. /***/
  17379. }),
  17380. /* 100 */
  17381. /***/
  17382. (function(module, exports, __webpack_require__) {
  17383. "use strict";
  17384. // Utility functions for ordering and stacking of items
  17385. var EPSILON = 0.001; // used when checking collisions, to prevent round-off errors
  17386. /**
  17387. * Order items by their start data
  17388. * @param {Item[]} items
  17389. */
  17390. exports.orderByStart = function(items) {
  17391. items.sort(function(a, b) {
  17392. return a.data.start - b.data.start;
  17393. });
  17394. };
  17395. /**
  17396. * Order items by their end date. If they have no end date, their start date
  17397. * is used.
  17398. * @param {Item[]} items
  17399. */
  17400. exports.orderByEnd = function(items) {
  17401. items.sort(function(a, b) {
  17402. var aTime = 'end' in a.data ? a.data.end : a.data.start,
  17403. bTime = 'end' in b.data ? b.data.end : b.data.start;
  17404. return aTime - bTime;
  17405. });
  17406. };
  17407. /**
  17408. * Adjust vertical positions of the items such that they don't overlap each
  17409. * other.
  17410. * @param {Item[]} items
  17411. * All visible items
  17412. * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
  17413. * Margins between items and between items and the axis.
  17414. * @param {boolean} [force=false]
  17415. * If true, all items will be repositioned. If false (default), only
  17416. * items having a top===null will be re-stacked
  17417. */
  17418. exports.stack = function(items, margin, force) {
  17419. if (force) {
  17420. // reset top position of all items
  17421. for (var i = 0; i < items.length; i++) {
  17422. items[i].top = null;
  17423. }
  17424. }
  17425. // calculate new, non-overlapping positions
  17426. for (var i = 0; i < items.length; i++) {
  17427. // eslint-disable-line no-redeclare
  17428. var item = items[i];
  17429. if (item.stack && item.top === null) {
  17430. // initialize top position
  17431. item.top = margin.axis;
  17432. do {
  17433. // TODO: optimize checking for overlap. when there is a gap without items,
  17434. // you only need to check for items from the next item on, not from zero
  17435. var collidingItem = null;
  17436. for (var j = 0, jj = items.length; j < jj; j++) {
  17437. var other = items[j];
  17438. if (other.top !== null && other !== item && other.stack && exports.collision(item, other, margin.item, other.options.rtl)) {
  17439. collidingItem = other;
  17440. break;
  17441. }
  17442. }
  17443. if (collidingItem != null) {
  17444. // There is a collision. Reposition the items above the colliding element
  17445. item.top = collidingItem.top + collidingItem.height + margin.item.vertical;
  17446. }
  17447. } while (collidingItem);
  17448. }
  17449. }
  17450. };
  17451. /**
  17452. * Adjust vertical positions of the items within a single subgroup such that they
  17453. * don't overlap each other.
  17454. * @param {Item[]} items
  17455. * All items withina subgroup
  17456. * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
  17457. * Margins between items and between items and the axis.
  17458. * @param {subgroup} subgroup
  17459. * The subgroup that is being stacked
  17460. */
  17461. exports.substack = function(items, margin, subgroup) {
  17462. for (var i = 0; i < items.length; i++) {
  17463. items[i].top = null;
  17464. }
  17465. // Set the initial height
  17466. var subgroupHeight = subgroup.height;
  17467. // calculate new, non-overlapping positions
  17468. for (i = 0; i < items.length; i++) {
  17469. var item = items[i];
  17470. if (item.stack && item.top === null) {
  17471. // initialize top position
  17472. item.top = item.baseTop; //margin.axis + item.baseTop;
  17473. do {
  17474. // TODO: optimize checking for overlap. when there is a gap without items,
  17475. // you only need to check for items from the next item on, not from zero
  17476. var collidingItem = null;
  17477. for (var j = 0, jj = items.length; j < jj; j++) {
  17478. var other = items[j];
  17479. if (other.top !== null && other !== item /*&& other.stack*/ && exports.collision(item, other, margin.item, other.options.rtl)) {
  17480. collidingItem = other;
  17481. break;
  17482. }
  17483. }
  17484. if (collidingItem != null) {
  17485. // There is a collision. Reposition the items above the colliding element
  17486. item.top = collidingItem.top + collidingItem.height + margin.item.vertical; // + item.baseTop;
  17487. }
  17488. if (item.top + item.height > subgroupHeight) {
  17489. subgroupHeight = item.top + item.height;
  17490. }
  17491. } while (collidingItem);
  17492. }
  17493. }
  17494. // Set the new height
  17495. subgroup.height = subgroupHeight - subgroup.top + 0.5 * margin.item.vertical;
  17496. };
  17497. /**
  17498. * Adjust vertical positions of the items without stacking them
  17499. * @param {Item[]} items
  17500. * All visible items
  17501. * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
  17502. * Margins between items and between items and the axis.
  17503. * @param {subgroups[]} subgroups
  17504. * All subgroups
  17505. * @param {boolean} stackSubgroups
  17506. */
  17507. exports.nostack = function(items, margin, subgroups, stackSubgroups) {
  17508. for (var i = 0; i < items.length; i++) {
  17509. if (items[i].data.subgroup == undefined) {
  17510. items[i].top = margin.item.vertical;
  17511. } else if (items[i].data.subgroup !== undefined && stackSubgroups) {
  17512. var newTop = 0;
  17513. for (var subgroup in subgroups) {
  17514. if (subgroups.hasOwnProperty(subgroup)) {
  17515. if (subgroups[subgroup].visible == true && subgroups[subgroup].index < subgroups[items[i].data.subgroup].index) {
  17516. newTop += subgroups[subgroup].height;
  17517. subgroups[items[i].data.subgroup].top = newTop;
  17518. }
  17519. }
  17520. }
  17521. items[i].top = newTop + 0.5 * margin.item.vertical;
  17522. }
  17523. }
  17524. if (!stackSubgroups) {
  17525. exports.stackSubgroups(items, margin, subgroups);
  17526. }
  17527. };
  17528. /**
  17529. * Adjust vertical positions of the subgroups such that they don't overlap each
  17530. * other.
  17531. * @param {Array.<vis.Item>} items
  17532. * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin Margins between items and between items and the axis.
  17533. * @param {subgroups[]} subgroups
  17534. * All subgroups
  17535. */
  17536. exports.stackSubgroups = function(items, margin, subgroups) {
  17537. for (var subgroup in subgroups) {
  17538. if (subgroups.hasOwnProperty(subgroup)) {
  17539. subgroups[subgroup].top = 0;
  17540. do {
  17541. // TODO: optimize checking for overlap. when there is a gap without items,
  17542. // you only need to check for items from the next item on, not from zero
  17543. var collidingItem = null;
  17544. for (var otherSubgroup in subgroups) {
  17545. if (subgroups[otherSubgroup].top !== null && otherSubgroup !== subgroup && subgroups[subgroup].index > subgroups[otherSubgroup].index && exports.collisionByTimes(subgroups[subgroup], subgroups[otherSubgroup])) {
  17546. collidingItem = subgroups[otherSubgroup];
  17547. break;
  17548. }
  17549. }
  17550. if (collidingItem != null) {
  17551. // There is a collision. Reposition the subgroups above the colliding element
  17552. subgroups[subgroup].top = collidingItem.top + collidingItem.height;
  17553. }
  17554. } while (collidingItem);
  17555. }
  17556. }
  17557. for (var i = 0; i < items.length; i++) {
  17558. if (items[i].data.subgroup !== undefined) {
  17559. items[i].top = subgroups[items[i].data.subgroup].top + 0.5 * margin.item.vertical;
  17560. }
  17561. }
  17562. };
  17563. /**
  17564. * Adjust vertical positions of the subgroups such that they don't overlap each
  17565. * other, then stacks the contents of each subgroup individually.
  17566. * @param {Item[]} subgroupItems
  17567. * All the items in a subgroup
  17568. * @param {{item: {horizontal: number, vertical: number}, axis: number}} margin
  17569. * Margins between items and between items and the axis.
  17570. * @param {subgroups[]} subgroups
  17571. * All subgroups
  17572. */
  17573. exports.stackSubgroupsWithInnerStack = function(subgroupItems, margin, subgroups) {
  17574. var doSubStack = false;
  17575. // Run subgroups in their order (if any)
  17576. var subgroupOrder = [];
  17577. for (var subgroup in subgroups) {
  17578. if (subgroups[subgroup].hasOwnProperty("index")) {
  17579. subgroupOrder[subgroups[subgroup].index] = subgroup;
  17580. } else {
  17581. subgroupOrder.push(subgroup);
  17582. }
  17583. }
  17584. for (var j = 0; j < subgroupOrder.length; j++) {
  17585. subgroup = subgroupOrder[j];
  17586. if (subgroups.hasOwnProperty(subgroup)) {
  17587. doSubStack = doSubStack || subgroups[subgroup].stack;
  17588. subgroups[subgroup].top = 0;
  17589. for (var otherSubgroup in subgroups) {
  17590. if (subgroups[otherSubgroup].visible && subgroups[subgroup].index > subgroups[otherSubgroup].index) {
  17591. subgroups[subgroup].top += subgroups[otherSubgroup].height;
  17592. }
  17593. }
  17594. var items = subgroupItems[subgroup];
  17595. for (var i = 0; i < items.length; i++) {
  17596. if (items[i].data.subgroup !== undefined) {
  17597. items[i].top = subgroups[items[i].data.subgroup].top + 0.5 * margin.item.vertical;
  17598. if (subgroups[subgroup].stack) {
  17599. items[i].baseTop = items[i].top;
  17600. }
  17601. }
  17602. }
  17603. if (doSubStack && subgroups[subgroup].stack) {
  17604. exports.substack(subgroupItems[subgroup], margin, subgroups[subgroup]);
  17605. }
  17606. }
  17607. }
  17608. };
  17609. /**
  17610. * Test if the two provided items collide
  17611. * The items must have parameters left, width, top, and height.
  17612. * @param {Item} a The first item
  17613. * @param {Item} b The second item
  17614. * @param {{horizontal: number, vertical: number}} margin
  17615. * An object containing a horizontal and vertical
  17616. * minimum required margin.
  17617. * @param {boolean} rtl
  17618. * @return {boolean} true if a and b collide, else false
  17619. */
  17620. exports.collision = function(a, b, margin, rtl) {
  17621. if (rtl) {
  17622. return a.right - margin.horizontal + EPSILON < b.right + b.width && a.right + a.width + margin.horizontal - EPSILON > b.right && a.top - margin.vertical + EPSILON < b.top + b.height && a.top + a.height + margin.vertical - EPSILON > b.top;
  17623. } else {
  17624. return a.left - margin.horizontal + EPSILON < b.left + b.width && a.left + a.width + margin.horizontal - EPSILON > b.left && a.top - margin.vertical + EPSILON < b.top + b.height && a.top + a.height + margin.vertical - EPSILON > b.top;
  17625. }
  17626. };
  17627. /**
  17628. * Test if the two provided objects collide
  17629. * The objects must have parameters start, end, top, and height.
  17630. * @param {Object} a The first Object
  17631. * @param {Object} b The second Object
  17632. * @return {boolean} true if a and b collide, else false
  17633. */
  17634. exports.collisionByTimes = function(a, b) {
  17635. return a.start <= b.start && a.end >= b.start && a.top < b.top + b.height && a.top + a.height > b.top || b.start <= a.start && b.end >= a.start && b.top < a.top + a.height && b.top + b.height > a.top;
  17636. };
  17637. /***/
  17638. }),
  17639. /* 101 */
  17640. /***/
  17641. (function(module, exports, __webpack_require__) {
  17642. "use strict";
  17643. var Item = __webpack_require__(38);
  17644. /**
  17645. * @constructor BoxItem
  17646. * @extends Item
  17647. * @param {Object} data Object containing parameters start
  17648. * content, className.
  17649. * @param {{toScreen: function, toTime: function}} conversion
  17650. * Conversion functions from time to screen and vice versa
  17651. * @param {Object} [options] Configuration options
  17652. * // TODO: describe available options
  17653. */
  17654. function BoxItem(data, conversion, options) {
  17655. this.props = {
  17656. dot: {
  17657. width: 0,
  17658. height: 0
  17659. },
  17660. line: {
  17661. width: 0,
  17662. height: 0
  17663. }
  17664. };
  17665. this.options = options;
  17666. // validate data
  17667. if (data) {
  17668. if (data.start == undefined) {
  17669. throw new Error('Property "start" missing in item ' + data);
  17670. }
  17671. }
  17672. Item.call(this, data, conversion, options);
  17673. }
  17674. BoxItem.prototype = new Item(null, null, null);
  17675. /**
  17676. * Check whether this item is visible inside given range
  17677. * @param {{start: number, end: number}} range with a timestamp for start and end
  17678. * @returns {boolean} True if visible
  17679. */
  17680. BoxItem.prototype.isVisible = function(range) {
  17681. // determine visibility
  17682. var isVisible;
  17683. var align = this.options.align;
  17684. var widthInMs = this.width * range.getMillisecondsPerPixel();
  17685. if (align == 'right') {
  17686. isVisible = this.data.start.getTime() > range.start && this.data.start.getTime() - widthInMs < range.end;
  17687. } else if (align == 'left') {
  17688. isVisible = this.data.start.getTime() + widthInMs > range.start && this.data.start.getTime() < range.end;
  17689. } else {
  17690. // default or 'center'
  17691. isVisible = this.data.start.getTime() + widthInMs / 2 > range.start && this.data.start.getTime() - widthInMs / 2 < range.end;
  17692. }
  17693. return isVisible;
  17694. };
  17695. BoxItem.prototype._createDomElement = function() {
  17696. if (!this.dom) {
  17697. // create DOM
  17698. this.dom = {};
  17699. // create main box
  17700. this.dom.box = document.createElement('DIV');
  17701. // contents box (inside the background box). used for making margins
  17702. this.dom.content = document.createElement('DIV');
  17703. this.dom.content.className = 'vis-item-content';
  17704. this.dom.box.appendChild(this.dom.content);
  17705. // line to axis
  17706. this.dom.line = document.createElement('DIV');
  17707. this.dom.line.className = 'vis-line';
  17708. // dot on axis
  17709. this.dom.dot = document.createElement('DIV');
  17710. this.dom.dot.className = 'vis-dot';
  17711. // attach this item as attribute
  17712. this.dom.box['timeline-item'] = this;
  17713. this.dirty = true;
  17714. }
  17715. };
  17716. BoxItem.prototype._appendDomElement = function() {
  17717. if (!this.parent) {
  17718. throw new Error('Cannot redraw item: no parent attached');
  17719. }
  17720. if (!this.dom.box.parentNode) {
  17721. var foreground = this.parent.dom.foreground;
  17722. if (!foreground) throw new Error('Cannot redraw item: parent has no foreground container element');
  17723. foreground.appendChild(this.dom.box);
  17724. }
  17725. if (!this.dom.line.parentNode) {
  17726. var background = this.parent.dom.background;
  17727. if (!background) throw new Error('Cannot redraw item: parent has no background container element');
  17728. background.appendChild(this.dom.line);
  17729. }
  17730. if (!this.dom.dot.parentNode) {
  17731. var axis = this.parent.dom.axis;
  17732. if (!background) throw new Error('Cannot redraw item: parent has no axis container element');
  17733. axis.appendChild(this.dom.dot);
  17734. }
  17735. this.displayed = true;
  17736. };
  17737. BoxItem.prototype._updateDirtyDomComponents = function() {
  17738. // An item is marked dirty when:
  17739. // - the item is not yet rendered
  17740. // - the item's data is changed
  17741. // - the item is selected/deselected
  17742. if (this.dirty) {
  17743. this._updateContents(this.dom.content);
  17744. this._updateDataAttributes(this.dom.box);
  17745. this._updateStyle(this.dom.box);
  17746. var editable = this.editable.updateTime || this.editable.updateGroup;
  17747. // update class
  17748. var className = (this.data.className ? ' ' + this.data.className : '') + (this.selected ? ' vis-selected' : '') + (editable ? ' vis-editable' : ' vis-readonly');
  17749. this.dom.box.className = 'vis-item vis-box' + className;
  17750. this.dom.line.className = 'vis-item vis-line' + className;
  17751. this.dom.dot.className = 'vis-item vis-dot' + className;
  17752. }
  17753. };
  17754. BoxItem.prototype._getDomComponentsSizes = function() {
  17755. return {
  17756. previous: {
  17757. right: this.dom.box.style.right,
  17758. left: this.dom.box.style.left
  17759. },
  17760. dot: {
  17761. height: this.dom.dot.offsetHeight,
  17762. width: this.dom.dot.offsetWidth
  17763. },
  17764. line: {
  17765. width: this.dom.line.offsetWidth
  17766. },
  17767. box: {
  17768. width: this.dom.box.offsetWidth,
  17769. height: this.dom.box.offsetHeight
  17770. }
  17771. };
  17772. };
  17773. BoxItem.prototype._updateDomComponentsSizes = function(sizes) {
  17774. if (this.options.rtl) {
  17775. this.dom.box.style.right = "0px";
  17776. } else {
  17777. this.dom.box.style.left = "0px";
  17778. }
  17779. // recalculate size
  17780. this.props.dot.height = sizes.dot.height;
  17781. this.props.dot.width = sizes.dot.width;
  17782. this.props.line.width = sizes.line.width;
  17783. this.width = sizes.box.width;
  17784. this.height = sizes.box.height;
  17785. // restore previous position
  17786. if (this.options.rtl) {
  17787. this.dom.box.style.right = sizes.previous.right;
  17788. } else {
  17789. this.dom.box.style.left = sizes.previous.left;
  17790. }
  17791. this.dirty = false;
  17792. };
  17793. BoxItem.prototype._repaintDomAdditionals = function() {
  17794. this._repaintOnItemUpdateTimeTooltip(this.dom.box);
  17795. this._repaintDragCenter();
  17796. this._repaintDeleteButton(this.dom.box);
  17797. };
  17798. /**
  17799. * Repaint the item
  17800. * @param {boolean} [returnQueue=false] return the queue
  17801. * @return {boolean} the redraw queue if returnQueue=true
  17802. */
  17803. BoxItem.prototype.redraw = function(returnQueue) {
  17804. var sizes;
  17805. var queue = [
  17806. // create item DOM
  17807. this._createDomElement.bind(this),
  17808. // append DOM to parent DOM
  17809. this._appendDomElement.bind(this),
  17810. // update dirty DOM
  17811. this._updateDirtyDomComponents.bind(this),
  17812. function() {
  17813. if (this.dirty) {
  17814. sizes = this._getDomComponentsSizes();
  17815. }
  17816. }.bind(this),
  17817. function() {
  17818. if (this.dirty) {
  17819. this._updateDomComponentsSizes.bind(this)(sizes);
  17820. }
  17821. }.bind(this),
  17822. // repaint DOM additionals
  17823. this._repaintDomAdditionals.bind(this)
  17824. ];
  17825. if (returnQueue) {
  17826. return queue;
  17827. } else {
  17828. var result;
  17829. queue.forEach(function(fn) {
  17830. result = fn();
  17831. });
  17832. return result;
  17833. }
  17834. };
  17835. /**
  17836. * Show the item in the DOM (when not already displayed). The items DOM will
  17837. * be created when needed.
  17838. */
  17839. BoxItem.prototype.show = function() {
  17840. if (!this.displayed) {
  17841. this.redraw();
  17842. }
  17843. };
  17844. /**
  17845. * Hide the item from the DOM (when visible)
  17846. */
  17847. BoxItem.prototype.hide = function() {
  17848. if (this.displayed) {
  17849. var dom = this.dom;
  17850. if (dom.box.parentNode) dom.box.parentNode.removeChild(dom.box);
  17851. if (dom.line.parentNode) dom.line.parentNode.removeChild(dom.line);
  17852. if (dom.dot.parentNode) dom.dot.parentNode.removeChild(dom.dot);
  17853. this.displayed = false;
  17854. }
  17855. };
  17856. /**
  17857. * Reposition the item horizontally
  17858. * @Override
  17859. */
  17860. BoxItem.prototype.repositionX = function() {
  17861. var start = this.conversion.toScreen(this.data.start);
  17862. var align = this.options.align;
  17863. // calculate left position of the box
  17864. if (align == 'right') {
  17865. if (this.options.rtl) {
  17866. this.right = start - this.width;
  17867. // reposition box, line, and dot
  17868. this.dom.box.style.right = this.right + 'px';
  17869. this.dom.line.style.right = start - this.props.line.width + 'px';
  17870. this.dom.dot.style.right = start - this.props.line.width / 2 - this.props.dot.width / 2 + 'px';
  17871. } else {
  17872. this.left = start - this.width;
  17873. // reposition box, line, and dot
  17874. this.dom.box.style.left = this.left + 'px';
  17875. this.dom.line.style.left = start - this.props.line.width + 'px';
  17876. this.dom.dot.style.left = start - this.props.line.width / 2 - this.props.dot.width / 2 + 'px';
  17877. }
  17878. } else if (align == 'left') {
  17879. if (this.options.rtl) {
  17880. this.right = start;
  17881. // reposition box, line, and dot
  17882. this.dom.box.style.right = this.right + 'px';
  17883. this.dom.line.style.right = start + 'px';
  17884. this.dom.dot.style.right = start + this.props.line.width / 2 - this.props.dot.width / 2 + 'px';
  17885. } else {
  17886. this.left = start;
  17887. // reposition box, line, and dot
  17888. this.dom.box.style.left = this.left + 'px';
  17889. this.dom.line.style.left = start + 'px';
  17890. this.dom.dot.style.left = start + this.props.line.width / 2 - this.props.dot.width / 2 + 'px';
  17891. }
  17892. } else {
  17893. // default or 'center'
  17894. if (this.options.rtl) {
  17895. this.right = start - this.width / 2;
  17896. // reposition box, line, and dot
  17897. this.dom.box.style.right = this.right + 'px';
  17898. this.dom.line.style.right = start - this.props.line.width + 'px';
  17899. this.dom.dot.style.right = start - this.props.dot.width / 2 + 'px';
  17900. } else {
  17901. this.left = start - this.width / 2;
  17902. // reposition box, line, and dot
  17903. this.dom.box.style.left = this.left + 'px';
  17904. this.dom.line.style.left = start - this.props.line.width / 2 + 'px';
  17905. this.dom.dot.style.left = start - this.props.dot.width / 2 + 'px';
  17906. }
  17907. }
  17908. };
  17909. /**
  17910. * Reposition the item vertically
  17911. * @Override
  17912. */
  17913. BoxItem.prototype.repositionY = function() {
  17914. var orientation = this.options.orientation.item;
  17915. var box = this.dom.box;
  17916. var line = this.dom.line;
  17917. var dot = this.dom.dot;
  17918. if (orientation == 'top') {
  17919. box.style.top = (this.top || 0) + 'px';
  17920. line.style.top = '0';
  17921. line.style.height = this.parent.top + this.top + 1 + 'px';
  17922. line.style.bottom = '';
  17923. } else {
  17924. // orientation 'bottom'
  17925. var itemSetHeight = this.parent.itemSet.props.height; // TODO: this is nasty
  17926. var lineHeight = itemSetHeight - this.parent.top - this.parent.height + this.top;
  17927. box.style.top = (this.parent.height - this.top - this.height || 0) + 'px';
  17928. line.style.top = itemSetHeight - lineHeight + 'px';
  17929. line.style.bottom = '0';
  17930. }
  17931. dot.style.top = -this.props.dot.height / 2 + 'px';
  17932. };
  17933. /**
  17934. * Return the width of the item left from its start date
  17935. * @return {number}
  17936. */
  17937. BoxItem.prototype.getWidthLeft = function() {
  17938. return this.width / 2;
  17939. };
  17940. /**
  17941. * Return the width of the item right from its start date
  17942. * @return {number}
  17943. */
  17944. BoxItem.prototype.getWidthRight = function() {
  17945. return this.width / 2;
  17946. };
  17947. module.exports = BoxItem;
  17948. /***/
  17949. }),
  17950. /* 102 */
  17951. /***/
  17952. (function(module, exports, __webpack_require__) {
  17953. "use strict";
  17954. var Item = __webpack_require__(38);
  17955. /**
  17956. * @constructor PointItem
  17957. * @extends Item
  17958. * @param {Object} data Object containing parameters start
  17959. * content, className.
  17960. * @param {{toScreen: function, toTime: function}} conversion
  17961. * Conversion functions from time to screen and vice versa
  17962. * @param {Object} [options] Configuration options
  17963. * // TODO: describe available options
  17964. */
  17965. function PointItem(data, conversion, options) {
  17966. this.props = {
  17967. dot: {
  17968. top: 0,
  17969. width: 0,
  17970. height: 0
  17971. },
  17972. content: {
  17973. height: 0,
  17974. marginLeft: 0,
  17975. marginRight: 0
  17976. }
  17977. };
  17978. this.options = options;
  17979. // validate data
  17980. if (data) {
  17981. if (data.start == undefined) {
  17982. throw new Error('Property "start" missing in item ' + data);
  17983. }
  17984. }
  17985. Item.call(this, data, conversion, options);
  17986. }
  17987. PointItem.prototype = new Item(null, null, null);
  17988. /**
  17989. * Check whether this item is visible inside given range
  17990. * @param {{start: number, end: number}} range with a timestamp for start and end
  17991. * @returns {boolean} True if visible
  17992. */
  17993. PointItem.prototype.isVisible = function(range) {
  17994. // determine visibility
  17995. var widthInMs = this.width * range.getMillisecondsPerPixel();
  17996. return this.data.start.getTime() + widthInMs > range.start && this.data.start < range.end;
  17997. };
  17998. PointItem.prototype._createDomElement = function() {
  17999. if (!this.dom) {
  18000. // create DOM
  18001. this.dom = {};
  18002. // background box
  18003. this.dom.point = document.createElement('div');
  18004. // className is updated in redraw()
  18005. // contents box, right from the dot
  18006. this.dom.content = document.createElement('div');
  18007. this.dom.content.className = 'vis-item-content';
  18008. this.dom.point.appendChild(this.dom.content);
  18009. // dot at start
  18010. this.dom.dot = document.createElement('div');
  18011. this.dom.point.appendChild(this.dom.dot);
  18012. // attach this item as attribute
  18013. this.dom.point['timeline-item'] = this;
  18014. this.dirty = true;
  18015. }
  18016. };
  18017. PointItem.prototype._appendDomElement = function() {
  18018. if (!this.parent) {
  18019. throw new Error('Cannot redraw item: no parent attached');
  18020. }
  18021. if (!this.dom.point.parentNode) {
  18022. var foreground = this.parent.dom.foreground;
  18023. if (!foreground) {
  18024. throw new Error('Cannot redraw item: parent has no foreground container element');
  18025. }
  18026. foreground.appendChild(this.dom.point);
  18027. }
  18028. this.displayed = true;
  18029. };
  18030. PointItem.prototype._updateDirtyDomComponents = function() {
  18031. // An item is marked dirty when:
  18032. // - the item is not yet rendered
  18033. // - the item's data is changed
  18034. // - the item is selected/deselected
  18035. if (this.dirty) {
  18036. this._updateContents(this.dom.content);
  18037. this._updateDataAttributes(this.dom.point);
  18038. this._updateStyle(this.dom.point);
  18039. var editable = this.editable.updateTime || this.editable.updateGroup;
  18040. // update class
  18041. var className = (this.data.className ? ' ' + this.data.className : '') + (this.selected ? ' vis-selected' : '') + (editable ? ' vis-editable' : ' vis-readonly');
  18042. this.dom.point.className = 'vis-item vis-point' + className;
  18043. this.dom.dot.className = 'vis-item vis-dot' + className;
  18044. }
  18045. };
  18046. PointItem.prototype._getDomComponentsSizes = function() {
  18047. return {
  18048. dot: {
  18049. width: this.dom.dot.offsetWidth,
  18050. height: this.dom.dot.offsetHeight
  18051. },
  18052. content: {
  18053. width: this.dom.content.offsetWidth,
  18054. height: this.dom.content.offsetHeight
  18055. },
  18056. point: {
  18057. width: this.dom.point.offsetWidth,
  18058. height: this.dom.point.offsetHeight
  18059. }
  18060. };
  18061. };
  18062. PointItem.prototype._updateDomComponentsSizes = function(sizes) {
  18063. // recalculate size of dot and contents
  18064. this.props.dot.width = sizes.dot.width;
  18065. this.props.dot.height = sizes.dot.height;
  18066. this.props.content.height = sizes.content.height;
  18067. // resize contents
  18068. if (this.options.rtl) {
  18069. this.dom.content.style.marginRight = 2 * this.props.dot.width + 'px';
  18070. } else {
  18071. this.dom.content.style.marginLeft = 2 * this.props.dot.width + 'px';
  18072. }
  18073. //this.dom.content.style.marginRight = ... + 'px'; // TODO: margin right
  18074. // recalculate size
  18075. this.width = sizes.point.width;
  18076. this.height = sizes.point.height;
  18077. // reposition the dot
  18078. this.dom.dot.style.top = (this.height - this.props.dot.height) / 2 + 'px';
  18079. if (this.options.rtl) {
  18080. this.dom.dot.style.right = this.props.dot.width / 2 + 'px';
  18081. } else {
  18082. this.dom.dot.style.left = this.props.dot.width / 2 + 'px';
  18083. }
  18084. this.dirty = false;
  18085. };
  18086. PointItem.prototype._repaintDomAdditionals = function() {
  18087. this._repaintOnItemUpdateTimeTooltip(this.dom.point);
  18088. this._repaintDragCenter();
  18089. this._repaintDeleteButton(this.dom.point);
  18090. };
  18091. /**
  18092. * Repaint the item
  18093. * @param {boolean} [returnQueue=false] return the queue
  18094. * @return {boolean} the redraw queue if returnQueue=true
  18095. */
  18096. PointItem.prototype.redraw = function(returnQueue) {
  18097. var sizes;
  18098. var queue = [
  18099. // create item DOM
  18100. this._createDomElement.bind(this),
  18101. // append DOM to parent DOM
  18102. this._appendDomElement.bind(this),
  18103. // update dirty DOM
  18104. this._updateDirtyDomComponents.bind(this),
  18105. function() {
  18106. if (this.dirty) {
  18107. sizes = this._getDomComponentsSizes();
  18108. }
  18109. }.bind(this),
  18110. function() {
  18111. if (this.dirty) {
  18112. this._updateDomComponentsSizes.bind(this)(sizes);
  18113. }
  18114. }.bind(this),
  18115. // repaint DOM additionals
  18116. this._repaintDomAdditionals.bind(this)
  18117. ];
  18118. if (returnQueue) {
  18119. return queue;
  18120. } else {
  18121. var result;
  18122. queue.forEach(function(fn) {
  18123. result = fn();
  18124. });
  18125. return result;
  18126. }
  18127. };
  18128. /**
  18129. * Show the item in the DOM (when not already visible). The items DOM will
  18130. * be created when needed.
  18131. */
  18132. PointItem.prototype.show = function() {
  18133. if (!this.displayed) {
  18134. this.redraw();
  18135. }
  18136. };
  18137. /**
  18138. * Hide the item from the DOM (when visible)
  18139. */
  18140. PointItem.prototype.hide = function() {
  18141. if (this.displayed) {
  18142. if (this.dom.point.parentNode) {
  18143. this.dom.point.parentNode.removeChild(this.dom.point);
  18144. }
  18145. this.displayed = false;
  18146. }
  18147. };
  18148. /**
  18149. * Reposition the item horizontally
  18150. * @Override
  18151. */
  18152. PointItem.prototype.repositionX = function() {
  18153. var start = this.conversion.toScreen(this.data.start);
  18154. if (this.options.rtl) {
  18155. this.right = start - this.props.dot.width;
  18156. // reposition point
  18157. this.dom.point.style.right = this.right + 'px';
  18158. } else {
  18159. this.left = start - this.props.dot.width;
  18160. // reposition point
  18161. this.dom.point.style.left = this.left + 'px';
  18162. }
  18163. };
  18164. /**
  18165. * Reposition the item vertically
  18166. * @Override
  18167. */
  18168. PointItem.prototype.repositionY = function() {
  18169. var orientation = this.options.orientation.item;
  18170. var point = this.dom.point;
  18171. if (orientation == 'top') {
  18172. point.style.top = this.top + 'px';
  18173. } else {
  18174. point.style.top = this.parent.height - this.top - this.height + 'px';
  18175. }
  18176. };
  18177. /**
  18178. * Return the width of the item left from its start date
  18179. * @return {number}
  18180. */
  18181. PointItem.prototype.getWidthLeft = function() {
  18182. return this.props.dot.width;
  18183. };
  18184. /**
  18185. * Return the width of the item right from its start date
  18186. * @return {number}
  18187. */
  18188. PointItem.prototype.getWidthRight = function() {
  18189. return this.props.dot.width;
  18190. };
  18191. module.exports = PointItem;
  18192. /***/
  18193. }),
  18194. /* 103 */
  18195. /***/
  18196. (function(module, exports, __webpack_require__) {
  18197. "use strict";
  18198. var Item = __webpack_require__(38);
  18199. var BackgroundGroup = __webpack_require__(69);
  18200. var RangeItem = __webpack_require__(70);
  18201. /**
  18202. * @constructor BackgroundItem
  18203. * @extends Item
  18204. * @param {Object} data Object containing parameters start, end
  18205. * content, className.
  18206. * @param {{toScreen: function, toTime: function}} conversion
  18207. * Conversion functions from time to screen and vice versa
  18208. * @param {Object} [options] Configuration options
  18209. * // TODO: describe options
  18210. * // TODO: implement support for the BackgroundItem just having a start, then being displayed as a sort of an annotation
  18211. */
  18212. function BackgroundItem(data, conversion, options) {
  18213. this.props = {
  18214. content: {
  18215. width: 0
  18216. }
  18217. };
  18218. this.overflow = false; // if contents can overflow (css styling), this flag is set to true
  18219. // validate data
  18220. if (data) {
  18221. if (data.start == undefined) {
  18222. throw new Error('Property "start" missing in item ' + data.id);
  18223. }
  18224. if (data.end == undefined) {
  18225. throw new Error('Property "end" missing in item ' + data.id);
  18226. }
  18227. }
  18228. Item.call(this, data, conversion, options);
  18229. }
  18230. BackgroundItem.prototype = new Item(null, null, null);
  18231. BackgroundItem.prototype.baseClassName = 'vis-item vis-background';
  18232. BackgroundItem.prototype.stack = false;
  18233. /**
  18234. * Check whether this item is visible inside given range
  18235. * @param {vis.Range} range with a timestamp for start and end
  18236. * @returns {boolean} True if visible
  18237. */
  18238. BackgroundItem.prototype.isVisible = function(range) {
  18239. // determine visibility
  18240. return this.data.start < range.end && this.data.end > range.start;
  18241. };
  18242. BackgroundItem.prototype._createDomElement = function() {
  18243. if (!this.dom) {
  18244. // create DOM
  18245. this.dom = {};
  18246. // background box
  18247. this.dom.box = document.createElement('div');
  18248. // className is updated in redraw()
  18249. // frame box (to prevent the item contents from overflowing
  18250. this.dom.frame = document.createElement('div');
  18251. this.dom.frame.className = 'vis-item-overflow';
  18252. this.dom.box.appendChild(this.dom.frame);
  18253. // contents box
  18254. this.dom.content = document.createElement('div');
  18255. this.dom.content.className = 'vis-item-content';
  18256. this.dom.frame.appendChild(this.dom.content);
  18257. // Note: we do NOT attach this item as attribute to the DOM,
  18258. // such that background items cannot be selected
  18259. //this.dom.box['timeline-item'] = this;
  18260. this.dirty = true;
  18261. }
  18262. };
  18263. BackgroundItem.prototype._appendDomElement = function() {
  18264. if (!this.parent) {
  18265. throw new Error('Cannot redraw item: no parent attached');
  18266. }
  18267. if (!this.dom.box.parentNode) {
  18268. var background = this.parent.dom.background;
  18269. if (!background) {
  18270. throw new Error('Cannot redraw item: parent has no background container element');
  18271. }
  18272. background.appendChild(this.dom.box);
  18273. }
  18274. this.displayed = true;
  18275. };
  18276. BackgroundItem.prototype._updateDirtyDomComponents = function() {
  18277. // update dirty DOM. An item is marked dirty when:
  18278. // - the item is not yet rendered
  18279. // - the item's data is changed
  18280. // - the item is selected/deselected
  18281. if (this.dirty) {
  18282. this._updateContents(this.dom.content);
  18283. this._updateDataAttributes(this.dom.content);
  18284. this._updateStyle(this.dom.box);
  18285. // update class
  18286. var className = (this.data.className ? ' ' + this.data.className : '') + (this.selected ? ' vis-selected' : '');
  18287. this.dom.box.className = this.baseClassName + className;
  18288. }
  18289. };
  18290. BackgroundItem.prototype._getDomComponentsSizes = function() {
  18291. // determine from css whether this box has overflow
  18292. this.overflow = window.getComputedStyle(this.dom.content).overflow !== 'hidden';
  18293. return {
  18294. content: {
  18295. width: this.dom.content.offsetWidth
  18296. }
  18297. };
  18298. };
  18299. BackgroundItem.prototype._updateDomComponentsSizes = function(sizes) {
  18300. // recalculate size
  18301. this.props.content.width = sizes.content.width;
  18302. this.height = 0; // set height zero, so this item will be ignored when stacking items
  18303. this.dirty = false;
  18304. };
  18305. BackgroundItem.prototype._repaintDomAdditionals = function() {};
  18306. /**
  18307. * Repaint the item
  18308. * @param {boolean} [returnQueue=false] return the queue
  18309. * @return {boolean} the redraw result or the redraw queue if returnQueue=true
  18310. */
  18311. BackgroundItem.prototype.redraw = function(returnQueue) {
  18312. var sizes;
  18313. var queue = [
  18314. // create item DOM
  18315. this._createDomElement.bind(this),
  18316. // append DOM to parent DOM
  18317. this._appendDomElement.bind(this), this._updateDirtyDomComponents.bind(this),
  18318. function() {
  18319. if (this.dirty) {
  18320. sizes = this._getDomComponentsSizes.bind(this)();
  18321. }
  18322. }.bind(this),
  18323. function() {
  18324. if (this.dirty) {
  18325. this._updateDomComponentsSizes.bind(this)(sizes);
  18326. }
  18327. }.bind(this),
  18328. // repaint DOM additionals
  18329. this._repaintDomAdditionals.bind(this)
  18330. ];
  18331. if (returnQueue) {
  18332. return queue;
  18333. } else {
  18334. var result;
  18335. queue.forEach(function(fn) {
  18336. result = fn();
  18337. });
  18338. return result;
  18339. }
  18340. };
  18341. /**
  18342. * Show the item in the DOM (when not already visible). The items DOM will
  18343. * be created when needed.
  18344. */
  18345. BackgroundItem.prototype.show = RangeItem.prototype.show;
  18346. /**
  18347. * Hide the item from the DOM (when visible)
  18348. * @return {Boolean} changed
  18349. */
  18350. BackgroundItem.prototype.hide = RangeItem.prototype.hide;
  18351. /**
  18352. * Reposition the item horizontally
  18353. * @Override
  18354. */
  18355. BackgroundItem.prototype.repositionX = RangeItem.prototype.repositionX;
  18356. /**
  18357. * Reposition the item vertically
  18358. * @Override
  18359. */
  18360. BackgroundItem.prototype.repositionY = function(margin) {
  18361. // eslint-disable-line no-unused-vars
  18362. var height;
  18363. var orientation = this.options.orientation.item;
  18364. // special positioning for subgroups
  18365. if (this.data.subgroup !== undefined) {
  18366. // TODO: instead of calculating the top position of the subgroups here for every BackgroundItem, calculate the top of the subgroup once in Itemset
  18367. var itemSubgroup = this.data.subgroup;
  18368. this.dom.box.style.height = this.parent.subgroups[itemSubgroup].height + 'px';
  18369. if (orientation == 'top') {
  18370. this.dom.box.style.top = this.parent.top + this.parent.subgroups[itemSubgroup].top + 'px';
  18371. } else {
  18372. this.dom.box.style.top = this.parent.top + this.parent.height - this.parent.subgroups[itemSubgroup].top - this.parent.subgroups[itemSubgroup].height + 'px';
  18373. }
  18374. this.dom.box.style.bottom = '';
  18375. }
  18376. // and in the case of no subgroups:
  18377. else {
  18378. // we want backgrounds with groups to only show in groups.
  18379. if (this.parent instanceof BackgroundGroup) {
  18380. // if the item is not in a group:
  18381. height = Math.max(this.parent.height, this.parent.itemSet.body.domProps.center.height, this.parent.itemSet.body.domProps.centerContainer.height);
  18382. this.dom.box.style.bottom = orientation == 'bottom' ? '0' : '';
  18383. this.dom.box.style.top = orientation == 'top' ? '0' : '';
  18384. } else {
  18385. height = this.parent.height;
  18386. // same alignment for items when orientation is top or bottom
  18387. this.dom.box.style.top = this.parent.top + 'px';
  18388. this.dom.box.style.bottom = '';
  18389. }
  18390. }
  18391. this.dom.box.style.height = height + 'px';
  18392. };
  18393. module.exports = BackgroundItem;
  18394. /***/
  18395. }),
  18396. /* 104 */
  18397. /***/
  18398. (function(module, exports, __webpack_require__) {
  18399. "use strict";
  18400. Object.defineProperty(exports, "__esModule", {
  18401. value: true
  18402. });
  18403. var _classCallCheck2 = __webpack_require__(0);
  18404. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  18405. var _createClass2 = __webpack_require__(1);
  18406. var _createClass3 = _interopRequireDefault(_createClass2);
  18407. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  18408. /**
  18409. * Popup is a class to create a popup window with some text
  18410. */
  18411. var Popup = function() {
  18412. /**
  18413. * @param {Element} container The container object.
  18414. * @param {string} overflowMethod How the popup should act to overflowing ('flip' or 'cap')
  18415. */
  18416. function Popup(container, overflowMethod) {
  18417. (0, _classCallCheck3['default'])(this, Popup);
  18418. this.container = container;
  18419. this.overflowMethod = overflowMethod || 'cap';
  18420. this.x = 0;
  18421. this.y = 0;
  18422. this.padding = 5;
  18423. this.hidden = false;
  18424. // create the frame
  18425. this.frame = document.createElement('div');
  18426. this.frame.className = 'vis-tooltip';
  18427. this.container.appendChild(this.frame);
  18428. }
  18429. /**
  18430. * @param {number} x Horizontal position of the popup window
  18431. * @param {number} y Vertical position of the popup window
  18432. */
  18433. (0, _createClass3['default'])(Popup, [{
  18434. key: 'setPosition',
  18435. value: function setPosition(x, y) {
  18436. this.x = parseInt(x);
  18437. this.y = parseInt(y);
  18438. }
  18439. /**
  18440. * Set the content for the popup window. This can be HTML code or text.
  18441. * @param {string | Element} content
  18442. */
  18443. }, {
  18444. key: 'setText',
  18445. value: function setText(content) {
  18446. if (content instanceof Element) {
  18447. this.frame.innerHTML = '';
  18448. this.frame.appendChild(content);
  18449. } else {
  18450. this.frame.innerHTML = content; // string containing text or HTML
  18451. }
  18452. }
  18453. /**
  18454. * Show the popup window
  18455. * @param {boolean} [doShow] Show or hide the window
  18456. */
  18457. }, {
  18458. key: 'show',
  18459. value: function show(doShow) {
  18460. if (doShow === undefined) {
  18461. doShow = true;
  18462. }
  18463. if (doShow === true) {
  18464. var height = this.frame.clientHeight;
  18465. var width = this.frame.clientWidth;
  18466. var maxHeight = this.frame.parentNode.clientHeight;
  18467. var maxWidth = this.frame.parentNode.clientWidth;
  18468. var left = 0,
  18469. top = 0;
  18470. if (this.overflowMethod == 'flip') {
  18471. var isLeft = false,
  18472. isTop = true; // Where around the position it's located
  18473. if (this.y - height < this.padding) {
  18474. isTop = false;
  18475. }
  18476. if (this.x + width > maxWidth - this.padding) {
  18477. isLeft = true;
  18478. }
  18479. if (isLeft) {
  18480. left = this.x - width;
  18481. } else {
  18482. left = this.x;
  18483. }
  18484. if (isTop) {
  18485. top = this.y - height;
  18486. } else {
  18487. top = this.y;
  18488. }
  18489. } else {
  18490. top = this.y - height;
  18491. if (top + height + this.padding > maxHeight) {
  18492. top = maxHeight - height - this.padding;
  18493. }
  18494. if (top < this.padding) {
  18495. top = this.padding;
  18496. }
  18497. left = this.x;
  18498. if (left + width + this.padding > maxWidth) {
  18499. left = maxWidth - width - this.padding;
  18500. }
  18501. if (left < this.padding) {
  18502. left = this.padding;
  18503. }
  18504. }
  18505. this.frame.style.left = left + "px";
  18506. this.frame.style.top = top + "px";
  18507. this.frame.style.visibility = "visible";
  18508. this.hidden = false;
  18509. } else {
  18510. this.hide();
  18511. }
  18512. }
  18513. /**
  18514. * Hide the popup window
  18515. */
  18516. }, {
  18517. key: 'hide',
  18518. value: function hide() {
  18519. this.hidden = true;
  18520. this.frame.style.left = "0";
  18521. this.frame.style.top = "0";
  18522. this.frame.style.visibility = "hidden";
  18523. }
  18524. /**
  18525. * Remove the popup window
  18526. */
  18527. }, {
  18528. key: 'destroy',
  18529. value: function destroy() {
  18530. this.frame.parentNode.removeChild(this.frame); // Remove element from DOM
  18531. }
  18532. }]);
  18533. return Popup;
  18534. }();
  18535. exports['default'] = Popup;
  18536. /***/
  18537. }),
  18538. /* 105 */
  18539. /***/
  18540. (function(module, exports, __webpack_require__) {
  18541. "use strict";
  18542. Object.defineProperty(exports, "__esModule", {
  18543. value: true
  18544. });
  18545. /**
  18546. * This object contains all possible options. It will check if the types are correct, if required if the option is one
  18547. * of the allowed values.
  18548. *
  18549. * __any__ means that the name of the property does not matter.
  18550. * __type__ is a required field for all objects and contains the allowed types of all objects
  18551. */
  18552. var string = 'string';
  18553. var bool = 'boolean';
  18554. var number = 'number';
  18555. var array = 'array';
  18556. var date = 'date';
  18557. var object = 'object'; // should only be in a __type__ property
  18558. var dom = 'dom';
  18559. var moment = 'moment';
  18560. var any = 'any';
  18561. var allOptions = {
  18562. configure: {
  18563. enabled: { 'boolean': bool },
  18564. filter: { 'boolean': bool, 'function': 'function' },
  18565. container: { dom: dom },
  18566. __type__: { object: object, 'boolean': bool, 'function': 'function' }
  18567. },
  18568. //globals :
  18569. align: { string: string },
  18570. rtl: { 'boolean': bool, 'undefined': 'undefined' },
  18571. rollingMode: {
  18572. follow: { 'boolean': bool },
  18573. offset: { number: number, 'undefined': 'undefined' },
  18574. __type__: { object: object }
  18575. },
  18576. verticalScroll: { 'boolean': bool, 'undefined': 'undefined' },
  18577. horizontalScroll: { 'boolean': bool, 'undefined': 'undefined' },
  18578. autoResize: { 'boolean': bool },
  18579. throttleRedraw: { number: number }, // TODO: DEPRICATED see https://github.com/almende/vis/issues/2511
  18580. clickToUse: { 'boolean': bool },
  18581. dataAttributes: { string: string, array: array },
  18582. editable: {
  18583. add: { 'boolean': bool, 'undefined': 'undefined' },
  18584. remove: { 'boolean': bool, 'undefined': 'undefined' },
  18585. updateGroup: { 'boolean': bool, 'undefined': 'undefined' },
  18586. updateTime: { 'boolean': bool, 'undefined': 'undefined' },
  18587. overrideItems: { 'boolean': bool, 'undefined': 'undefined' },
  18588. __type__: { 'boolean': bool, object: object }
  18589. },
  18590. end: { number: number, date: date, string: string, moment: moment },
  18591. format: {
  18592. minorLabels: {
  18593. millisecond: { string: string, 'undefined': 'undefined' },
  18594. second: { string: string, 'undefined': 'undefined' },
  18595. minute: { string: string, 'undefined': 'undefined' },
  18596. hour: { string: string, 'undefined': 'undefined' },
  18597. weekday: { string: string, 'undefined': 'undefined' },
  18598. day: { string: string, 'undefined': 'undefined' },
  18599. week: { string: string, 'undefined': 'undefined' },
  18600. month: { string: string, 'undefined': 'undefined' },
  18601. year: { string: string, 'undefined': 'undefined' },
  18602. __type__: { object: object, 'function': 'function' }
  18603. },
  18604. majorLabels: {
  18605. millisecond: { string: string, 'undefined': 'undefined' },
  18606. second: { string: string, 'undefined': 'undefined' },
  18607. minute: { string: string, 'undefined': 'undefined' },
  18608. hour: { string: string, 'undefined': 'undefined' },
  18609. weekday: { string: string, 'undefined': 'undefined' },
  18610. day: { string: string, 'undefined': 'undefined' },
  18611. week: { string: string, 'undefined': 'undefined' },
  18612. month: { string: string, 'undefined': 'undefined' },
  18613. year: { string: string, 'undefined': 'undefined' },
  18614. __type__: { object: object, 'function': 'function' }
  18615. },
  18616. __type__: { object: object }
  18617. },
  18618. moment: { 'function': 'function' },
  18619. groupOrder: { string: string, 'function': 'function' },
  18620. groupEditable: {
  18621. add: { 'boolean': bool, 'undefined': 'undefined' },
  18622. remove: { 'boolean': bool, 'undefined': 'undefined' },
  18623. order: { 'boolean': bool, 'undefined': 'undefined' },
  18624. __type__: { 'boolean': bool, object: object }
  18625. },
  18626. groupOrderSwap: { 'function': 'function' },
  18627. height: { string: string, number: number },
  18628. hiddenDates: {
  18629. start: { date: date, number: number, string: string, moment: moment },
  18630. end: { date: date, number: number, string: string, moment: moment },
  18631. repeat: { string: string },
  18632. __type__: { object: object, array: array }
  18633. },
  18634. itemsAlwaysDraggable: {
  18635. item: { 'boolean': bool, 'undefined': 'undefined' },
  18636. range: { 'boolean': bool, 'undefined': 'undefined' },
  18637. __type__: { 'boolean': bool, object: object }
  18638. },
  18639. limitSize: { 'boolean': bool },
  18640. locale: { string: string },
  18641. locales: {
  18642. __any__: { any: any },
  18643. __type__: { object: object }
  18644. },
  18645. margin: {
  18646. axis: { number: number },
  18647. item: {
  18648. horizontal: { number: number, 'undefined': 'undefined' },
  18649. vertical: { number: number, 'undefined': 'undefined' },
  18650. __type__: { object: object, number: number }
  18651. },
  18652. __type__: { object: object, number: number }
  18653. },
  18654. max: { date: date, number: number, string: string, moment: moment },
  18655. maxHeight: { number: number, string: string },
  18656. maxMinorChars: { number: number },
  18657. min: { date: date, number: number, string: string, moment: moment },
  18658. minHeight: { number: number, string: string },
  18659. moveable: { 'boolean': bool },
  18660. multiselect: { 'boolean': bool },
  18661. multiselectPerGroup: { 'boolean': bool },
  18662. onAdd: { 'function': 'function' },
  18663. onDropObjectOnItem: { 'function': 'function' },
  18664. onUpdate: { 'function': 'function' },
  18665. onMove: { 'function': 'function' },
  18666. onMoving: { 'function': 'function' },
  18667. onRemove: { 'function': 'function' },
  18668. onAddGroup: { 'function': 'function' },
  18669. onMoveGroup: { 'function': 'function' },
  18670. onRemoveGroup: { 'function': 'function' },
  18671. onInitialDrawComplete: { 'function': 'function' },
  18672. order: { 'function': 'function' },
  18673. orientation: {
  18674. axis: { string: string, 'undefined': 'undefined' },
  18675. item: { string: string, 'undefined': 'undefined' },
  18676. __type__: { string: string, object: object }
  18677. },
  18678. selectable: { 'boolean': bool },
  18679. showCurrentTime: { 'boolean': bool },
  18680. showMajorLabels: { 'boolean': bool },
  18681. showMinorLabels: { 'boolean': bool },
  18682. stack: { 'boolean': bool },
  18683. stackSubgroups: { 'boolean': bool },
  18684. snap: { 'function': 'function', 'null': 'null' },
  18685. start: { date: date, number: number, string: string, moment: moment },
  18686. template: { 'function': 'function' },
  18687. groupTemplate: { 'function': 'function' },
  18688. visibleFrameTemplate: { string: string, 'function': 'function' },
  18689. showTooltips: { 'boolean': bool },
  18690. tooltip: {
  18691. followMouse: { 'boolean': bool },
  18692. overflowMethod: { 'string': ['cap', 'flip'] },
  18693. __type__: { object: object }
  18694. },
  18695. tooltipOnItemUpdateTime: {
  18696. template: { 'function': 'function' },
  18697. __type__: { 'boolean': bool, object: object }
  18698. },
  18699. timeAxis: {
  18700. scale: { string: string, 'undefined': 'undefined' },
  18701. step: { number: number, 'undefined': 'undefined' },
  18702. __type__: { object: object }
  18703. },
  18704. type: { string: string },
  18705. width: { string: string, number: number },
  18706. zoomable: { 'boolean': bool },
  18707. zoomKey: { string: ['ctrlKey', 'altKey', 'metaKey', ''] },
  18708. zoomMax: { number: number },
  18709. zoomMin: { number: number },
  18710. __type__: { object: object }
  18711. };
  18712. var configureOptions = {
  18713. global: {
  18714. align: ['center', 'left', 'right'],
  18715. direction: false,
  18716. autoResize: true,
  18717. clickToUse: false,
  18718. // dataAttributes: ['all'], // FIXME: can be 'all' or string[]
  18719. editable: {
  18720. add: false,
  18721. remove: false,
  18722. updateGroup: false,
  18723. updateTime: false
  18724. },
  18725. end: '',
  18726. format: {
  18727. minorLabels: {
  18728. millisecond: 'SSS',
  18729. second: 's',
  18730. minute: 'HH:mm',
  18731. hour: 'HH:mm',
  18732. weekday: 'ddd D',
  18733. day: 'D',
  18734. week: 'w',
  18735. month: 'MMM',
  18736. year: 'YYYY'
  18737. },
  18738. majorLabels: {
  18739. millisecond: 'HH:mm:ss',
  18740. second: 'D MMMM HH:mm',
  18741. minute: 'ddd D MMMM',
  18742. hour: 'ddd D MMMM',
  18743. weekday: 'MMMM YYYY',
  18744. day: 'MMMM YYYY',
  18745. week: 'MMMM YYYY',
  18746. month: 'YYYY',
  18747. year: ''
  18748. }
  18749. },
  18750. //groupOrder: {string, 'function': 'function'},
  18751. groupsDraggable: false,
  18752. height: '',
  18753. //hiddenDates: {object, array},
  18754. locale: '',
  18755. margin: {
  18756. axis: [20, 0, 100, 1],
  18757. item: {
  18758. horizontal: [10, 0, 100, 1],
  18759. vertical: [10, 0, 100, 1]
  18760. }
  18761. },
  18762. max: '',
  18763. maxHeight: '',
  18764. maxMinorChars: [7, 0, 20, 1],
  18765. min: '',
  18766. minHeight: '',
  18767. moveable: false,
  18768. multiselect: false,
  18769. multiselectPerGroup: false,
  18770. //onAdd: {'function': 'function'},
  18771. //onUpdate: {'function': 'function'},
  18772. //onMove: {'function': 'function'},
  18773. //onMoving: {'function': 'function'},
  18774. //onRename: {'function': 'function'},
  18775. //order: {'function': 'function'},
  18776. orientation: {
  18777. axis: ['both', 'bottom', 'top'],
  18778. item: ['bottom', 'top']
  18779. },
  18780. selectable: true,
  18781. showCurrentTime: false,
  18782. showMajorLabels: true,
  18783. showMinorLabels: true,
  18784. stack: true,
  18785. stackSubgroups: true,
  18786. //snap: {'function': 'function', nada},
  18787. start: '',
  18788. //template: {'function': 'function'},
  18789. //timeAxis: {
  18790. // scale: ['millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'year'],
  18791. // step: [1, 1, 10, 1]
  18792. //},
  18793. showTooltips: true,
  18794. tooltip: {
  18795. followMouse: false,
  18796. overflowMethod: 'flip'
  18797. },
  18798. tooltipOnItemUpdateTime: false,
  18799. type: ['box', 'point', 'range', 'background'],
  18800. width: '100%',
  18801. zoomable: true,
  18802. zoomKey: ['ctrlKey', 'altKey', 'metaKey', ''],
  18803. zoomMax: [315360000000000, 10, 315360000000000, 1],
  18804. zoomMin: [10, 10, 315360000000000, 1]
  18805. }
  18806. };
  18807. exports.allOptions = allOptions;
  18808. exports.configureOptions = configureOptions;
  18809. /***/
  18810. }),
  18811. /* 106 */
  18812. /***/
  18813. (function(module, exports, __webpack_require__) {
  18814. "use strict";
  18815. var _typeof2 = __webpack_require__(6);
  18816. var _typeof3 = _interopRequireDefault(_typeof2);
  18817. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  18818. var util = __webpack_require__(2);
  18819. var DOMutil = __webpack_require__(14);
  18820. var DataSet = __webpack_require__(11);
  18821. var DataView = __webpack_require__(12);
  18822. var Component = __webpack_require__(16);
  18823. var DataAxis = __webpack_require__(107);
  18824. var GraphGroup = __webpack_require__(109);
  18825. var Legend = __webpack_require__(112);
  18826. var Bars = __webpack_require__(110);
  18827. var Lines = __webpack_require__(111);
  18828. var Points = __webpack_require__(72);
  18829. var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items
  18830. /**
  18831. * This is the constructor of the LineGraph. It requires a Timeline body and options.
  18832. *
  18833. * @param {vis.Timeline.body} body
  18834. * @param {Object} options
  18835. * @constructor LineGraph
  18836. * @extends Component
  18837. */
  18838. function LineGraph(body, options) {
  18839. this.id = util.randomUUID();
  18840. this.body = body;
  18841. this.defaultOptions = {
  18842. yAxisOrientation: 'left',
  18843. defaultGroup: 'default',
  18844. sort: true,
  18845. sampling: true,
  18846. stack: false,
  18847. graphHeight: '400px',
  18848. shaded: {
  18849. enabled: false,
  18850. orientation: 'bottom' // top, bottom, zero
  18851. },
  18852. style: 'line', // line, bar
  18853. barChart: {
  18854. width: 50,
  18855. sideBySide: false,
  18856. align: 'center' // left, center, right
  18857. },
  18858. interpolation: {
  18859. enabled: true,
  18860. parametrization: 'centripetal', // uniform (alpha = 0.0), chordal (alpha = 1.0), centripetal (alpha = 0.5)
  18861. alpha: 0.5
  18862. },
  18863. drawPoints: {
  18864. enabled: true,
  18865. size: 6,
  18866. style: 'square' // square, circle
  18867. },
  18868. dataAxis: {}, //Defaults are done on DataAxis level
  18869. legend: {}, //Defaults are done on Legend level
  18870. groups: {
  18871. visibility: {}
  18872. }
  18873. };
  18874. // options is shared by this lineGraph and all its items
  18875. this.options = util.extend({}, this.defaultOptions);
  18876. this.dom = {};
  18877. this.props = {};
  18878. this.hammer = null;
  18879. this.groups = {};
  18880. this.abortedGraphUpdate = false;
  18881. this.updateSVGheight = false;
  18882. this.updateSVGheightOnResize = false;
  18883. this.forceGraphUpdate = true;
  18884. var me = this;
  18885. this.itemsData = null; // DataSet
  18886. this.groupsData = null; // DataSet
  18887. // listeners for the DataSet of the items
  18888. this.itemListeners = {
  18889. 'add': function add(event, params, senderId) {
  18890. // eslint-disable-line no-unused-vars
  18891. me._onAdd(params.items);
  18892. },
  18893. 'update': function update(event, params, senderId) {
  18894. // eslint-disable-line no-unused-vars
  18895. me._onUpdate(params.items);
  18896. },
  18897. 'remove': function remove(event, params, senderId) {
  18898. // eslint-disable-line no-unused-vars
  18899. me._onRemove(params.items);
  18900. }
  18901. };
  18902. // listeners for the DataSet of the groups
  18903. this.groupListeners = {
  18904. 'add': function add(event, params, senderId) {
  18905. // eslint-disable-line no-unused-vars
  18906. me._onAddGroups(params.items);
  18907. },
  18908. 'update': function update(event, params, senderId) {
  18909. // eslint-disable-line no-unused-vars
  18910. me._onUpdateGroups(params.items);
  18911. },
  18912. 'remove': function remove(event, params, senderId) {
  18913. // eslint-disable-line no-unused-vars
  18914. me._onRemoveGroups(params.items);
  18915. }
  18916. };
  18917. this.items = {}; // object with an Item for every data item
  18918. this.selection = []; // list with the ids of all selected nodes
  18919. this.lastStart = this.body.range.start;
  18920. this.touchParams = {}; // stores properties while dragging
  18921. this.svgElements = {};
  18922. this.setOptions(options);
  18923. this.groupsUsingDefaultStyles = [0];
  18924. this.body.emitter.on('rangechanged', function() {
  18925. me.lastStart = me.body.range.start;
  18926. me.svg.style.left = util.option.asSize(-me.props.width);
  18927. me.forceGraphUpdate = true;
  18928. //Is this local redraw necessary? (Core also does a change event!)
  18929. me.redraw.call(me);
  18930. });
  18931. // create the HTML DOM
  18932. this._create();
  18933. this.framework = { svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups };
  18934. }
  18935. LineGraph.prototype = new Component();
  18936. /**
  18937. * Create the HTML DOM for the ItemSet
  18938. */
  18939. LineGraph.prototype._create = function() {
  18940. var frame = document.createElement('div');
  18941. frame.className = 'vis-line-graph';
  18942. this.dom.frame = frame;
  18943. // create svg element for graph drawing.
  18944. this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  18945. this.svg.style.position = 'relative';
  18946. this.svg.style.height = ('' + this.options.graphHeight).replace('px', '') + 'px';
  18947. this.svg.style.display = 'block';
  18948. frame.appendChild(this.svg);
  18949. // data axis
  18950. this.options.dataAxis.orientation = 'left';
  18951. this.yAxisLeft = new DataAxis(this.body, this.options.dataAxis, this.svg, this.options.groups);
  18952. this.options.dataAxis.orientation = 'right';
  18953. this.yAxisRight = new DataAxis(this.body, this.options.dataAxis, this.svg, this.options.groups);
  18954. delete this.options.dataAxis.orientation;
  18955. // legends
  18956. this.legendLeft = new Legend(this.body, this.options.legend, 'left', this.options.groups);
  18957. this.legendRight = new Legend(this.body, this.options.legend, 'right', this.options.groups);
  18958. this.show();
  18959. };
  18960. /**
  18961. * set the options of the LineGraph. the mergeOptions is used for subObjects that have an enabled element.
  18962. * @param {object} options
  18963. */
  18964. LineGraph.prototype.setOptions = function(options) {
  18965. if (options) {
  18966. var fields = ['sampling', 'defaultGroup', 'stack', 'height', 'graphHeight', 'yAxisOrientation', 'style', 'barChart', 'dataAxis', 'sort', 'groups'];
  18967. if (options.graphHeight === undefined && options.height !== undefined) {
  18968. this.updateSVGheight = true;
  18969. this.updateSVGheightOnResize = true;
  18970. } else if (this.body.domProps.centerContainer.height !== undefined && options.graphHeight !== undefined) {
  18971. if (parseInt((options.graphHeight + '').replace("px", '')) < this.body.domProps.centerContainer.height) {
  18972. this.updateSVGheight = true;
  18973. }
  18974. }
  18975. util.selectiveDeepExtend(fields, this.options, options);
  18976. util.mergeOptions(this.options, options, 'interpolation');
  18977. util.mergeOptions(this.options, options, 'drawPoints');
  18978. util.mergeOptions(this.options, options, 'shaded');
  18979. util.mergeOptions(this.options, options, 'legend');
  18980. if (options.interpolation) {
  18981. if ((0, _typeof3['default'])(options.interpolation) == 'object') {
  18982. if (options.interpolation.parametrization) {
  18983. if (options.interpolation.parametrization == 'uniform') {
  18984. this.options.interpolation.alpha = 0;
  18985. } else if (options.interpolation.parametrization == 'chordal') {
  18986. this.options.interpolation.alpha = 1.0;
  18987. } else {
  18988. this.options.interpolation.parametrization = 'centripetal';
  18989. this.options.interpolation.alpha = 0.5;
  18990. }
  18991. }
  18992. }
  18993. }
  18994. if (this.yAxisLeft) {
  18995. if (options.dataAxis !== undefined) {
  18996. this.yAxisLeft.setOptions(this.options.dataAxis);
  18997. this.yAxisRight.setOptions(this.options.dataAxis);
  18998. }
  18999. }
  19000. if (this.legendLeft) {
  19001. if (options.legend !== undefined) {
  19002. this.legendLeft.setOptions(this.options.legend);
  19003. this.legendRight.setOptions(this.options.legend);
  19004. }
  19005. }
  19006. if (this.groups.hasOwnProperty(UNGROUPED)) {
  19007. this.groups[UNGROUPED].setOptions(options);
  19008. }
  19009. }
  19010. // this is used to redraw the graph if the visibility of the groups is changed.
  19011. if (this.dom.frame) {
  19012. //not on initial run?
  19013. this.forceGraphUpdate = true;
  19014. this.body.emitter.emit("_change", { queue: true });
  19015. }
  19016. };
  19017. /**
  19018. * Hide the component from the DOM
  19019. */
  19020. LineGraph.prototype.hide = function() {
  19021. // remove the frame containing the items
  19022. if (this.dom.frame.parentNode) {
  19023. this.dom.frame.parentNode.removeChild(this.dom.frame);
  19024. }
  19025. };
  19026. /**
  19027. * Show the component in the DOM (when not already visible).
  19028. */
  19029. LineGraph.prototype.show = function() {
  19030. // show frame containing the items
  19031. if (!this.dom.frame.parentNode) {
  19032. this.body.dom.center.appendChild(this.dom.frame);
  19033. }
  19034. };
  19035. /**
  19036. * Set items
  19037. * @param {vis.DataSet | null} items
  19038. */
  19039. LineGraph.prototype.setItems = function(items) {
  19040. var me = this,
  19041. ids,
  19042. oldItemsData = this.itemsData;
  19043. // replace the dataset
  19044. if (!items) {
  19045. this.itemsData = null;
  19046. } else if (items instanceof DataSet || items instanceof DataView) {
  19047. this.itemsData = items;
  19048. } else {
  19049. throw new TypeError('Data must be an instance of DataSet or DataView');
  19050. }
  19051. if (oldItemsData) {
  19052. // unsubscribe from old dataset
  19053. util.forEach(this.itemListeners, function(callback, event) {
  19054. oldItemsData.off(event, callback);
  19055. });
  19056. // remove all drawn items
  19057. ids = oldItemsData.getIds();
  19058. this._onRemove(ids);
  19059. }
  19060. if (this.itemsData) {
  19061. // subscribe to new dataset
  19062. var id = this.id;
  19063. util.forEach(this.itemListeners, function(callback, event) {
  19064. me.itemsData.on(event, callback, id);
  19065. });
  19066. // add all new items
  19067. ids = this.itemsData.getIds();
  19068. this._onAdd(ids);
  19069. }
  19070. };
  19071. /**
  19072. * Set groups
  19073. * @param {vis.DataSet} groups
  19074. */
  19075. LineGraph.prototype.setGroups = function(groups) {
  19076. var me = this;
  19077. var ids;
  19078. // unsubscribe from current dataset
  19079. if (this.groupsData) {
  19080. util.forEach(this.groupListeners, function(callback, event) {
  19081. me.groupsData.off(event, callback);
  19082. });
  19083. // remove all drawn groups
  19084. ids = this.groupsData.getIds();
  19085. this.groupsData = null;
  19086. for (var i = 0; i < ids.length; i++) {
  19087. this._removeGroup(ids[i]);
  19088. }
  19089. }
  19090. // replace the dataset
  19091. if (!groups) {
  19092. this.groupsData = null;
  19093. } else if (groups instanceof DataSet || groups instanceof DataView) {
  19094. this.groupsData = groups;
  19095. } else {
  19096. throw new TypeError('Data must be an instance of DataSet or DataView');
  19097. }
  19098. if (this.groupsData) {
  19099. // subscribe to new dataset
  19100. var id = this.id;
  19101. util.forEach(this.groupListeners, function(callback, event) {
  19102. me.groupsData.on(event, callback, id);
  19103. });
  19104. // draw all ms
  19105. ids = this.groupsData.getIds();
  19106. this._onAddGroups(ids);
  19107. }
  19108. };
  19109. LineGraph.prototype._onUpdate = function(ids) {
  19110. this._updateAllGroupData(ids);
  19111. };
  19112. LineGraph.prototype._onAdd = function(ids) {
  19113. this._onUpdate(ids);
  19114. };
  19115. LineGraph.prototype._onRemove = function(ids) {
  19116. this._onUpdate(ids);
  19117. };
  19118. LineGraph.prototype._onUpdateGroups = function(groupIds) {
  19119. this._updateAllGroupData(null, groupIds);
  19120. };
  19121. LineGraph.prototype._onAddGroups = function(groupIds) {
  19122. this._onUpdateGroups(groupIds);
  19123. };
  19124. /**
  19125. * this cleans the group out off the legends and the dataaxis, updates the ungrouped and updates the graph
  19126. * @param {Array} groupIds
  19127. * @private
  19128. */
  19129. LineGraph.prototype._onRemoveGroups = function(groupIds) {
  19130. for (var i = 0; i < groupIds.length; i++) {
  19131. this._removeGroup(groupIds[i]);
  19132. }
  19133. this.forceGraphUpdate = true;
  19134. this.body.emitter.emit("_change", { queue: true });
  19135. };
  19136. /**
  19137. * this cleans the group out off the legends and the dataaxis
  19138. * @param {vis.GraphGroup.id} groupId
  19139. * @private
  19140. */
  19141. LineGraph.prototype._removeGroup = function(groupId) {
  19142. if (this.groups.hasOwnProperty(groupId)) {
  19143. if (this.groups[groupId].options.yAxisOrientation == 'right') {
  19144. this.yAxisRight.removeGroup(groupId);
  19145. this.legendRight.removeGroup(groupId);
  19146. this.legendRight.redraw();
  19147. } else {
  19148. this.yAxisLeft.removeGroup(groupId);
  19149. this.legendLeft.removeGroup(groupId);
  19150. this.legendLeft.redraw();
  19151. }
  19152. delete this.groups[groupId];
  19153. }
  19154. };
  19155. /**
  19156. * update a group object with the group dataset entree
  19157. *
  19158. * @param {vis.GraphGroup} group
  19159. * @param {vis.GraphGroup.id} groupId
  19160. * @private
  19161. */
  19162. LineGraph.prototype._updateGroup = function(group, groupId) {
  19163. if (!this.groups.hasOwnProperty(groupId)) {
  19164. this.groups[groupId] = new GraphGroup(group, groupId, this.options, this.groupsUsingDefaultStyles);
  19165. if (this.groups[groupId].options.yAxisOrientation == 'right') {
  19166. this.yAxisRight.addGroup(groupId, this.groups[groupId]);
  19167. this.legendRight.addGroup(groupId, this.groups[groupId]);
  19168. } else {
  19169. this.yAxisLeft.addGroup(groupId, this.groups[groupId]);
  19170. this.legendLeft.addGroup(groupId, this.groups[groupId]);
  19171. }
  19172. } else {
  19173. this.groups[groupId].update(group);
  19174. if (this.groups[groupId].options.yAxisOrientation == 'right') {
  19175. this.yAxisRight.updateGroup(groupId, this.groups[groupId]);
  19176. this.legendRight.updateGroup(groupId, this.groups[groupId]);
  19177. //If yAxisOrientation changed, clean out the group from the other axis.
  19178. this.yAxisLeft.removeGroup(groupId);
  19179. this.legendLeft.removeGroup(groupId);
  19180. } else {
  19181. this.yAxisLeft.updateGroup(groupId, this.groups[groupId]);
  19182. this.legendLeft.updateGroup(groupId, this.groups[groupId]);
  19183. //If yAxisOrientation changed, clean out the group from the other axis.
  19184. this.yAxisRight.removeGroup(groupId);
  19185. this.legendRight.removeGroup(groupId);
  19186. }
  19187. }
  19188. this.legendLeft.redraw();
  19189. this.legendRight.redraw();
  19190. };
  19191. /**
  19192. * this updates all groups, it is used when there is an update the the itemset.
  19193. *
  19194. * @param {Array} ids
  19195. * @param {Array} groupIds
  19196. * @private
  19197. */
  19198. LineGraph.prototype._updateAllGroupData = function(ids, groupIds) {
  19199. if (this.itemsData != null) {
  19200. var groupsContent = {};
  19201. var items = this.itemsData.get();
  19202. var fieldId = this.itemsData._fieldId;
  19203. var idMap = {};
  19204. if (ids) {
  19205. ids.map(function(id) {
  19206. idMap[id] = id;
  19207. });
  19208. }
  19209. //pre-Determine array sizes, for more efficient memory claim
  19210. var groupCounts = {};
  19211. for (var i = 0; i < items.length; i++) {
  19212. var item = items[i];
  19213. var groupId = item.group;
  19214. if (groupId === null || groupId === undefined) {
  19215. groupId = UNGROUPED;
  19216. }
  19217. groupCounts.hasOwnProperty(groupId) ? groupCounts[groupId]++ : groupCounts[groupId] = 1;
  19218. }
  19219. //Pre-load arrays from existing groups if items are not changed (not in ids)
  19220. var existingItemsMap = {};
  19221. if (!groupIds && ids) {
  19222. for (groupId in this.groups) {
  19223. if (this.groups.hasOwnProperty(groupId)) {
  19224. group = this.groups[groupId];
  19225. var existing_items = group.getItems();
  19226. groupsContent[groupId] = existing_items.filter(function(item) {
  19227. existingItemsMap[item[fieldId]] = item[fieldId];
  19228. return item[fieldId] !== idMap[item[fieldId]];
  19229. });
  19230. var newLength = groupCounts[groupId];
  19231. groupCounts[groupId] -= groupsContent[groupId].length;
  19232. if (groupsContent[groupId].length < newLength) {
  19233. groupsContent[groupId][newLength - 1] = {};
  19234. }
  19235. }
  19236. }
  19237. }
  19238. //Now insert data into the arrays.
  19239. for (i = 0; i < items.length; i++) {
  19240. item = items[i];
  19241. groupId = item.group;
  19242. if (groupId === null || groupId === undefined) {
  19243. groupId = UNGROUPED;
  19244. }
  19245. if (!groupIds && ids && item[fieldId] !== idMap[item[fieldId]] && existingItemsMap.hasOwnProperty(item[fieldId])) {
  19246. continue;
  19247. }
  19248. if (!groupsContent.hasOwnProperty(groupId)) {
  19249. groupsContent[groupId] = new Array(groupCounts[groupId]);
  19250. }
  19251. //Copy data (because of unmodifiable DataView input.
  19252. var extended = util.bridgeObject(item);
  19253. extended.x = util.convert(item.x, 'Date');
  19254. extended.end = util.convert(item.end, 'Date');
  19255. extended.orginalY = item.y; //real Y
  19256. extended.y = Number(item.y);
  19257. extended[fieldId] = item[fieldId];
  19258. var index = groupsContent[groupId].length - groupCounts[groupId]--;
  19259. groupsContent[groupId][index] = extended;
  19260. }
  19261. //Make sure all groups are present, to allow removal of old groups
  19262. for (groupId in this.groups) {
  19263. if (this.groups.hasOwnProperty(groupId)) {
  19264. if (!groupsContent.hasOwnProperty(groupId)) {
  19265. groupsContent[groupId] = new Array(0);
  19266. }
  19267. }
  19268. }
  19269. //Update legendas, style and axis
  19270. for (groupId in groupsContent) {
  19271. if (groupsContent.hasOwnProperty(groupId)) {
  19272. if (groupsContent[groupId].length == 0) {
  19273. if (this.groups.hasOwnProperty(groupId)) {
  19274. this._removeGroup(groupId);
  19275. }
  19276. } else {
  19277. var group = undefined;
  19278. if (this.groupsData != undefined) {
  19279. group = this.groupsData.get(groupId);
  19280. }
  19281. if (group == undefined) {
  19282. group = { id: groupId, content: this.options.defaultGroup + groupId };
  19283. }
  19284. this._updateGroup(group, groupId);
  19285. this.groups[groupId].setItems(groupsContent[groupId]);
  19286. }
  19287. }
  19288. }
  19289. this.forceGraphUpdate = true;
  19290. this.body.emitter.emit("_change", { queue: true });
  19291. }
  19292. };
  19293. /**
  19294. * Redraw the component, mandatory function
  19295. * @return {boolean} Returns true if the component is resized
  19296. */
  19297. LineGraph.prototype.redraw = function() {
  19298. var resized = false;
  19299. // calculate actual size and position
  19300. this.props.width = this.dom.frame.offsetWidth;
  19301. this.props.height = this.body.domProps.centerContainer.height - this.body.domProps.border.top - this.body.domProps.border.bottom;
  19302. // check if this component is resized
  19303. resized = this._isResized() || resized;
  19304. // check whether zoomed (in that case we need to re-stack everything)
  19305. var visibleInterval = this.body.range.end - this.body.range.start;
  19306. var zoomed = visibleInterval != this.lastVisibleInterval;
  19307. this.lastVisibleInterval = visibleInterval;
  19308. // the svg element is three times as big as the width, this allows for fully dragging left and right
  19309. // without reloading the graph. the controls for this are bound to events in the constructor
  19310. if (resized == true) {
  19311. this.svg.style.width = util.option.asSize(3 * this.props.width);
  19312. this.svg.style.left = util.option.asSize(-this.props.width);
  19313. // if the height of the graph is set as proportional, change the height of the svg
  19314. if ((this.options.height + '').indexOf("%") != -1 || this.updateSVGheightOnResize == true) {
  19315. this.updateSVGheight = true;
  19316. }
  19317. }
  19318. // update the height of the graph on each redraw of the graph.
  19319. if (this.updateSVGheight == true) {
  19320. if (this.options.graphHeight != this.props.height + 'px') {
  19321. this.options.graphHeight = this.props.height + 'px';
  19322. this.svg.style.height = this.props.height + 'px';
  19323. }
  19324. this.updateSVGheight = false;
  19325. } else {
  19326. this.svg.style.height = ('' + this.options.graphHeight).replace('px', '') + 'px';
  19327. }
  19328. // zoomed is here to ensure that animations are shown correctly.
  19329. if (resized == true || zoomed == true || this.abortedGraphUpdate == true || this.forceGraphUpdate == true) {
  19330. resized = this._updateGraph() || resized;
  19331. this.forceGraphUpdate = false;
  19332. } else {
  19333. // move the whole svg while dragging
  19334. if (this.lastStart != 0) {
  19335. var offset = this.body.range.start - this.lastStart;
  19336. var range = this.body.range.end - this.body.range.start;
  19337. if (this.props.width != 0) {
  19338. var rangePerPixelInv = this.props.width / range;
  19339. var xOffset = offset * rangePerPixelInv;
  19340. this.svg.style.left = -this.props.width - xOffset + 'px';
  19341. }
  19342. }
  19343. }
  19344. this.legendLeft.redraw();
  19345. this.legendRight.redraw();
  19346. return resized;
  19347. };
  19348. LineGraph.prototype._getSortedGroupIds = function() {
  19349. // getting group Ids
  19350. var grouplist = [];
  19351. for (var groupId in this.groups) {
  19352. if (this.groups.hasOwnProperty(groupId)) {
  19353. var group = this.groups[groupId];
  19354. if (group.visible == true && (this.options.groups.visibility[groupId] === undefined || this.options.groups.visibility[groupId] == true)) {
  19355. grouplist.push({ id: groupId, zIndex: group.options.zIndex });
  19356. }
  19357. }
  19358. }
  19359. util.insertSort(grouplist, function(a, b) {
  19360. var az = a.zIndex;
  19361. var bz = b.zIndex;
  19362. if (az === undefined) az = 0;
  19363. if (bz === undefined) bz = 0;
  19364. return az == bz ? 0 : az < bz ? -1 : 1;
  19365. });
  19366. var groupIds = new Array(grouplist.length);
  19367. for (var i = 0; i < grouplist.length; i++) {
  19368. groupIds[i] = grouplist[i].id;
  19369. }
  19370. return groupIds;
  19371. };
  19372. /**
  19373. * Update and redraw the graph.
  19374. *
  19375. * @returns {boolean}
  19376. * @private
  19377. */
  19378. LineGraph.prototype._updateGraph = function() {
  19379. // reset the svg elements
  19380. DOMutil.prepareElements(this.svgElements);
  19381. if (this.props.width != 0 && this.itemsData != null) {
  19382. var group, i;
  19383. var groupRanges = {};
  19384. var changeCalled = false;
  19385. // this is the range of the SVG canvas
  19386. var minDate = this.body.util.toGlobalTime(-this.body.domProps.root.width);
  19387. var maxDate = this.body.util.toGlobalTime(2 * this.body.domProps.root.width);
  19388. // getting group Ids
  19389. var groupIds = this._getSortedGroupIds();
  19390. if (groupIds.length > 0) {
  19391. var groupsData = {};
  19392. // fill groups data, this only loads the data we require based on the timewindow
  19393. this._getRelevantData(groupIds, groupsData, minDate, maxDate);
  19394. // apply sampling, if disabled, it will pass through this function.
  19395. this._applySampling(groupIds, groupsData);
  19396. // we transform the X coordinates to detect collisions
  19397. for (i = 0; i < groupIds.length; i++) {
  19398. this._convertXcoordinates(groupsData[groupIds[i]]);
  19399. }
  19400. // now all needed data has been collected we start the processing.
  19401. this._getYRanges(groupIds, groupsData, groupRanges);
  19402. // update the Y axis first, we use this data to draw at the correct Y points
  19403. changeCalled = this._updateYAxis(groupIds, groupRanges);
  19404. // at changeCalled, abort this update cycle as the graph needs another update with new Width input from the Redraw container.
  19405. // Cleanup SVG elements on abort.
  19406. if (changeCalled == true) {
  19407. DOMutil.cleanupElements(this.svgElements);
  19408. this.abortedGraphUpdate = true;
  19409. return true;
  19410. }
  19411. this.abortedGraphUpdate = false;
  19412. // With the yAxis scaled correctly, use this to get the Y values of the points.
  19413. var below = undefined;
  19414. for (i = 0; i < groupIds.length; i++) {
  19415. group = this.groups[groupIds[i]];
  19416. if (this.options.stack === true && this.options.style === 'line') {
  19417. if (group.options.excludeFromStacking == undefined || !group.options.excludeFromStacking) {
  19418. if (below != undefined) {
  19419. this._stack(groupsData[group.id], groupsData[below.id]);
  19420. if (group.options.shaded.enabled == true && group.options.shaded.orientation !== "group") {
  19421. if (group.options.shaded.orientation == "top" && below.options.shaded.orientation !== "group") {
  19422. below.options.shaded.orientation = "group";
  19423. below.options.shaded.groupId = group.id;
  19424. } else {
  19425. group.options.shaded.orientation = "group";
  19426. group.options.shaded.groupId = below.id;
  19427. }
  19428. }
  19429. }
  19430. below = group;
  19431. }
  19432. }
  19433. this._convertYcoordinates(groupsData[groupIds[i]], group);
  19434. }
  19435. //Precalculate paths and draw shading if appropriate. This will make sure the shading is always behind any lines.
  19436. var paths = {};
  19437. for (i = 0; i < groupIds.length; i++) {
  19438. group = this.groups[groupIds[i]];
  19439. if (group.options.style === 'line' && group.options.shaded.enabled == true) {
  19440. var dataset = groupsData[groupIds[i]];
  19441. if (dataset == null || dataset.length == 0) {
  19442. continue;
  19443. }
  19444. if (!paths.hasOwnProperty(groupIds[i])) {
  19445. paths[groupIds[i]] = Lines.calcPath(dataset, group);
  19446. }
  19447. if (group.options.shaded.orientation === "group") {
  19448. var subGroupId = group.options.shaded.groupId;
  19449. if (groupIds.indexOf(subGroupId) === -1) {
  19450. console.log(group.id + ": Unknown shading group target given:" + subGroupId);
  19451. continue;
  19452. }
  19453. if (!paths.hasOwnProperty(subGroupId)) {
  19454. paths[subGroupId] = Lines.calcPath(groupsData[subGroupId], this.groups[subGroupId]);
  19455. }
  19456. Lines.drawShading(paths[groupIds[i]], group, paths[subGroupId], this.framework);
  19457. } else {
  19458. Lines.drawShading(paths[groupIds[i]], group, undefined, this.framework);
  19459. }
  19460. }
  19461. }
  19462. // draw the groups, calculating paths if still necessary.
  19463. Bars.draw(groupIds, groupsData, this.framework);
  19464. for (i = 0; i < groupIds.length; i++) {
  19465. group = this.groups[groupIds[i]];
  19466. if (groupsData[groupIds[i]].length > 0) {
  19467. switch (group.options.style) {
  19468. case "line":
  19469. if (!paths.hasOwnProperty(groupIds[i])) {
  19470. paths[groupIds[i]] = Lines.calcPath(groupsData[groupIds[i]], group);
  19471. }
  19472. Lines.draw(paths[groupIds[i]], group, this.framework);
  19473. // eslint-disable-line no-fallthrough
  19474. case "point":
  19475. // eslint-disable-line no-fallthrough
  19476. case "points":
  19477. if (group.options.style == "point" || group.options.style == "points" || group.options.drawPoints.enabled == true) {
  19478. Points.draw(groupsData[groupIds[i]], group, this.framework);
  19479. }
  19480. break;
  19481. case "bar":
  19482. // bar needs to be drawn enmasse
  19483. // eslint-disable-line no-fallthrough
  19484. default:
  19485. //do nothing...
  19486. }
  19487. }
  19488. }
  19489. }
  19490. }
  19491. // cleanup unused svg elements
  19492. DOMutil.cleanupElements(this.svgElements);
  19493. return false;
  19494. };
  19495. LineGraph.prototype._stack = function(data, subData) {
  19496. var index, dx, dy, subPrevPoint, subNextPoint;
  19497. index = 0;
  19498. // for each data point we look for a matching on in the set below
  19499. for (var j = 0; j < data.length; j++) {
  19500. subPrevPoint = undefined;
  19501. subNextPoint = undefined;
  19502. // we look for time matches or a before-after point
  19503. for (var k = index; k < subData.length; k++) {
  19504. // if times match exactly
  19505. if (subData[k].x === data[j].x) {
  19506. subPrevPoint = subData[k];
  19507. subNextPoint = subData[k];
  19508. index = k;
  19509. break;
  19510. } else if (subData[k].x > data[j].x) {
  19511. // overshoot
  19512. subNextPoint = subData[k];
  19513. if (k == 0) {
  19514. subPrevPoint = subNextPoint;
  19515. } else {
  19516. subPrevPoint = subData[k - 1];
  19517. }
  19518. index = k;
  19519. break;
  19520. }
  19521. }
  19522. // in case the last data point has been used, we assume it stays like this.
  19523. if (subNextPoint === undefined) {
  19524. subPrevPoint = subData[subData.length - 1];
  19525. subNextPoint = subData[subData.length - 1];
  19526. }
  19527. // linear interpolation
  19528. dx = subNextPoint.x - subPrevPoint.x;
  19529. dy = subNextPoint.y - subPrevPoint.y;
  19530. if (dx == 0) {
  19531. data[j].y = data[j].orginalY + subNextPoint.y;
  19532. } else {
  19533. data[j].y = data[j].orginalY + dy / dx * (data[j].x - subPrevPoint.x) + subPrevPoint.y; // ax + b where b is data[j].y
  19534. }
  19535. }
  19536. };
  19537. /**
  19538. * first select and preprocess the data from the datasets.
  19539. * the groups have their preselection of data, we now loop over this data to see
  19540. * what data we need to draw. Sorted data is much faster.
  19541. * more optimization is possible by doing the sampling before and using the binary search
  19542. * to find the end date to determine the increment.
  19543. *
  19544. * @param {array} groupIds
  19545. * @param {object} groupsData
  19546. * @param {date} minDate
  19547. * @param {date} maxDate
  19548. * @private
  19549. */
  19550. LineGraph.prototype._getRelevantData = function(groupIds, groupsData, minDate, maxDate) {
  19551. var group, i, j, item;
  19552. if (groupIds.length > 0) {
  19553. for (i = 0; i < groupIds.length; i++) {
  19554. group = this.groups[groupIds[i]];
  19555. var itemsData = group.getItems();
  19556. // optimization for sorted data
  19557. if (group.options.sort == true) {
  19558. var dateComparator = function dateComparator(a, b) {
  19559. return a.getTime() == b.getTime() ? 0 : a < b ? -1 : 1;
  19560. };
  19561. var first = Math.max(0, util.binarySearchValue(itemsData, minDate, 'x', 'before', dateComparator));
  19562. var last = Math.min(itemsData.length, util.binarySearchValue(itemsData, maxDate, 'x', 'after', dateComparator) + 1);
  19563. if (last <= 0) {
  19564. last = itemsData.length;
  19565. }
  19566. var dataContainer = new Array(last - first);
  19567. for (j = first; j < last; j++) {
  19568. item = group.itemsData[j];
  19569. dataContainer[j - first] = item;
  19570. }
  19571. groupsData[groupIds[i]] = dataContainer;
  19572. } else {
  19573. // If unsorted data, all data is relevant, just returning entire structure
  19574. groupsData[groupIds[i]] = group.itemsData;
  19575. }
  19576. }
  19577. }
  19578. };
  19579. /**
  19580. *
  19581. * @param {Array.<vis.GraphGroup.id>} groupIds
  19582. * @param {vis.DataSet} groupsData
  19583. * @private
  19584. */
  19585. LineGraph.prototype._applySampling = function(groupIds, groupsData) {
  19586. var group;
  19587. if (groupIds.length > 0) {
  19588. for (var i = 0; i < groupIds.length; i++) {
  19589. group = this.groups[groupIds[i]];
  19590. if (group.options.sampling == true) {
  19591. var dataContainer = groupsData[groupIds[i]];
  19592. if (dataContainer.length > 0) {
  19593. var increment = 1;
  19594. var amountOfPoints = dataContainer.length;
  19595. // the global screen is used because changing the width of the yAxis may affect the increment, resulting in an endless loop
  19596. // of width changing of the yAxis.
  19597. //TODO: This assumes sorted data, but that's not guaranteed!
  19598. var xDistance = this.body.util.toGlobalScreen(dataContainer[dataContainer.length - 1].x) - this.body.util.toGlobalScreen(dataContainer[0].x);
  19599. var pointsPerPixel = amountOfPoints / xDistance;
  19600. increment = Math.min(Math.ceil(0.2 * amountOfPoints), Math.max(1, Math.round(pointsPerPixel)));
  19601. var sampledData = new Array(amountOfPoints);
  19602. for (var j = 0; j < amountOfPoints; j += increment) {
  19603. var idx = Math.round(j / increment);
  19604. sampledData[idx] = dataContainer[j];
  19605. }
  19606. groupsData[groupIds[i]] = sampledData.splice(0, Math.round(amountOfPoints / increment));
  19607. }
  19608. }
  19609. }
  19610. }
  19611. };
  19612. /**
  19613. *
  19614. * @param {Array.<vis.GraphGroup.id>} groupIds
  19615. * @param {vis.DataSet} groupsData
  19616. * @param {object} groupRanges | this is being filled here
  19617. * @private
  19618. */
  19619. LineGraph.prototype._getYRanges = function(groupIds, groupsData, groupRanges) {
  19620. var groupData, group, i;
  19621. var combinedDataLeft = [];
  19622. var combinedDataRight = [];
  19623. var options;
  19624. if (groupIds.length > 0) {
  19625. for (i = 0; i < groupIds.length; i++) {
  19626. groupData = groupsData[groupIds[i]];
  19627. options = this.groups[groupIds[i]].options;
  19628. if (groupData.length > 0) {
  19629. group = this.groups[groupIds[i]];
  19630. // if bar graphs are stacked, their range need to be handled differently and accumulated over all groups.
  19631. if (options.stack === true && options.style === 'bar') {
  19632. if (options.yAxisOrientation === 'left') {
  19633. combinedDataLeft = combinedDataLeft.concat(groupData);
  19634. } else {
  19635. combinedDataRight = combinedDataRight.concat(groupData);
  19636. }
  19637. } else {
  19638. groupRanges[groupIds[i]] = group.getYRange(groupData, groupIds[i]);
  19639. }
  19640. }
  19641. }
  19642. // if bar graphs are stacked, their range need to be handled differently and accumulated over all groups.
  19643. Bars.getStackedYRange(combinedDataLeft, groupRanges, groupIds, '__barStackLeft', 'left');
  19644. Bars.getStackedYRange(combinedDataRight, groupRanges, groupIds, '__barStackRight', 'right');
  19645. }
  19646. };
  19647. /**
  19648. * this sets the Y ranges for the Y axis. It also determines which of the axis should be shown or hidden.
  19649. * @param {Array.<vis.GraphGroup.id>} groupIds
  19650. * @param {Object} groupRanges
  19651. * @returns {boolean} resized
  19652. * @private
  19653. */
  19654. LineGraph.prototype._updateYAxis = function(groupIds, groupRanges) {
  19655. var resized = false;
  19656. var yAxisLeftUsed = false;
  19657. var yAxisRightUsed = false;
  19658. var minLeft = 1e9,
  19659. minRight = 1e9,
  19660. maxLeft = -1e9,
  19661. maxRight = -1e9,
  19662. minVal,
  19663. maxVal;
  19664. // if groups are present
  19665. if (groupIds.length > 0) {
  19666. // this is here to make sure that if there are no items in the axis but there are groups, that there is no infinite draw/redraw loop.
  19667. for (var i = 0; i < groupIds.length; i++) {
  19668. var group = this.groups[groupIds[i]];
  19669. if (group && group.options.yAxisOrientation != 'right') {
  19670. yAxisLeftUsed = true;
  19671. minLeft = 1e9;
  19672. maxLeft = -1e9;
  19673. } else if (group && group.options.yAxisOrientation) {
  19674. yAxisRightUsed = true;
  19675. minRight = 1e9;
  19676. maxRight = -1e9;
  19677. }
  19678. }
  19679. // if there are items:
  19680. for (i = 0; i < groupIds.length; i++) {
  19681. if (groupRanges.hasOwnProperty(groupIds[i])) {
  19682. if (groupRanges[groupIds[i]].ignore !== true) {
  19683. minVal = groupRanges[groupIds[i]].min;
  19684. maxVal = groupRanges[groupIds[i]].max;
  19685. if (groupRanges[groupIds[i]].yAxisOrientation != 'right') {
  19686. yAxisLeftUsed = true;
  19687. minLeft = minLeft > minVal ? minVal : minLeft;
  19688. maxLeft = maxLeft < maxVal ? maxVal : maxLeft;
  19689. } else {
  19690. yAxisRightUsed = true;
  19691. minRight = minRight > minVal ? minVal : minRight;
  19692. maxRight = maxRight < maxVal ? maxVal : maxRight;
  19693. }
  19694. }
  19695. }
  19696. }
  19697. if (yAxisLeftUsed == true) {
  19698. this.yAxisLeft.setRange(minLeft, maxLeft);
  19699. }
  19700. if (yAxisRightUsed == true) {
  19701. this.yAxisRight.setRange(minRight, maxRight);
  19702. }
  19703. }
  19704. resized = this._toggleAxisVisiblity(yAxisLeftUsed, this.yAxisLeft) || resized;
  19705. resized = this._toggleAxisVisiblity(yAxisRightUsed, this.yAxisRight) || resized;
  19706. if (yAxisRightUsed == true && yAxisLeftUsed == true) {
  19707. this.yAxisLeft.drawIcons = true;
  19708. this.yAxisRight.drawIcons = true;
  19709. } else {
  19710. this.yAxisLeft.drawIcons = false;
  19711. this.yAxisRight.drawIcons = false;
  19712. }
  19713. this.yAxisRight.master = !yAxisLeftUsed;
  19714. this.yAxisRight.masterAxis = this.yAxisLeft;
  19715. if (this.yAxisRight.master == false) {
  19716. if (yAxisRightUsed == true) {
  19717. this.yAxisLeft.lineOffset = this.yAxisRight.width;
  19718. } else {
  19719. this.yAxisLeft.lineOffset = 0;
  19720. }
  19721. resized = this.yAxisLeft.redraw() || resized;
  19722. resized = this.yAxisRight.redraw() || resized;
  19723. } else {
  19724. resized = this.yAxisRight.redraw() || resized;
  19725. }
  19726. // clean the accumulated lists
  19727. var tempGroups = ['__barStackLeft', '__barStackRight', '__lineStackLeft', '__lineStackRight'];
  19728. for (i = 0; i < tempGroups.length; i++) {
  19729. if (groupIds.indexOf(tempGroups[i]) != -1) {
  19730. groupIds.splice(groupIds.indexOf(tempGroups[i]), 1);
  19731. }
  19732. }
  19733. return resized;
  19734. };
  19735. /**
  19736. * This shows or hides the Y axis if needed. If there is a change, the changed event is emitted by the updateYAxis function
  19737. *
  19738. * @param {boolean} axisUsed
  19739. * @param {vis.DataAxis} axis
  19740. * @returns {boolean}
  19741. * @private
  19742. */
  19743. LineGraph.prototype._toggleAxisVisiblity = function(axisUsed, axis) {
  19744. var changed = false;
  19745. if (axisUsed == false) {
  19746. if (axis.dom.frame.parentNode && axis.hidden == false) {
  19747. axis.hide();
  19748. changed = true;
  19749. }
  19750. } else {
  19751. if (!axis.dom.frame.parentNode && axis.hidden == true) {
  19752. axis.show();
  19753. changed = true;
  19754. }
  19755. }
  19756. return changed;
  19757. };
  19758. /**
  19759. * This uses the DataAxis object to generate the correct X coordinate on the SVG window. It uses the
  19760. * util function toScreen to get the x coordinate from the timestamp. It also pre-filters the data and get the minMax ranges for
  19761. * the yAxis.
  19762. *
  19763. * @param {Array.<Object>} datapoints
  19764. * @private
  19765. */
  19766. LineGraph.prototype._convertXcoordinates = function(datapoints) {
  19767. var toScreen = this.body.util.toScreen;
  19768. for (var i = 0; i < datapoints.length; i++) {
  19769. datapoints[i].screen_x = toScreen(datapoints[i].x) + this.props.width;
  19770. datapoints[i].screen_y = datapoints[i].y; //starting point for range calculations
  19771. if (datapoints[i].end != undefined) {
  19772. datapoints[i].screen_end = toScreen(datapoints[i].end) + this.props.width;
  19773. } else {
  19774. datapoints[i].screen_end = undefined;
  19775. }
  19776. }
  19777. };
  19778. /**
  19779. * This uses the DataAxis object to generate the correct X coordinate on the SVG window. It uses the
  19780. * util function toScreen to get the x coordinate from the timestamp. It also pre-filters the data and get the minMax ranges for
  19781. * the yAxis.
  19782. *
  19783. * @param {Array.<Object>} datapoints
  19784. * @param {vis.GraphGroup} group
  19785. * @private
  19786. */
  19787. LineGraph.prototype._convertYcoordinates = function(datapoints, group) {
  19788. var axis = this.yAxisLeft;
  19789. var svgHeight = Number(this.svg.style.height.replace('px', ''));
  19790. if (group.options.yAxisOrientation == 'right') {
  19791. axis = this.yAxisRight;
  19792. }
  19793. for (var i = 0; i < datapoints.length; i++) {
  19794. datapoints[i].screen_y = Math.round(axis.convertValue(datapoints[i].y));
  19795. }
  19796. group.setZeroPosition(Math.min(svgHeight, axis.convertValue(0)));
  19797. };
  19798. module.exports = LineGraph;
  19799. /***/
  19800. }),
  19801. /* 107 */
  19802. /***/
  19803. (function(module, exports, __webpack_require__) {
  19804. "use strict";
  19805. var _keys = __webpack_require__(8);
  19806. var _keys2 = _interopRequireDefault(_keys);
  19807. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  19808. var util = __webpack_require__(2);
  19809. var DOMutil = __webpack_require__(14);
  19810. var Component = __webpack_require__(16);
  19811. var DataScale = __webpack_require__(108);
  19812. /**
  19813. * A horizontal time axis
  19814. * @param {Object} body
  19815. * @param {Object} [options] See DataAxis.setOptions for the available
  19816. * options.
  19817. * @param {SVGElement} svg
  19818. * @param {vis.LineGraph.options} linegraphOptions
  19819. * @constructor DataAxis
  19820. * @extends Component
  19821. */
  19822. function DataAxis(body, options, svg, linegraphOptions) {
  19823. this.id = util.randomUUID();
  19824. this.body = body;
  19825. this.defaultOptions = {
  19826. orientation: 'left', // supported: 'left', 'right'
  19827. showMinorLabels: true,
  19828. showMajorLabels: true,
  19829. icons: false,
  19830. majorLinesOffset: 7,
  19831. minorLinesOffset: 4,
  19832. labelOffsetX: 10,
  19833. labelOffsetY: 2,
  19834. iconWidth: 20,
  19835. width: '40px',
  19836. visible: true,
  19837. alignZeros: true,
  19838. left: {
  19839. range: { min: undefined, max: undefined },
  19840. format: function format(value) {
  19841. return '' + parseFloat(value.toPrecision(3));
  19842. },
  19843. title: { text: undefined, style: undefined }
  19844. },
  19845. right: {
  19846. range: { min: undefined, max: undefined },
  19847. format: function format(value) {
  19848. return '' + parseFloat(value.toPrecision(3));
  19849. },
  19850. title: { text: undefined, style: undefined }
  19851. }
  19852. };
  19853. this.linegraphOptions = linegraphOptions;
  19854. this.linegraphSVG = svg;
  19855. this.props = {};
  19856. this.DOMelements = { // dynamic elements
  19857. lines: {},
  19858. labels: {},
  19859. title: {}
  19860. };
  19861. this.dom = {};
  19862. this.scale = undefined;
  19863. this.range = { start: 0, end: 0 };
  19864. this.options = util.extend({}, this.defaultOptions);
  19865. this.conversionFactor = 1;
  19866. this.setOptions(options);
  19867. this.width = Number(('' + this.options.width).replace("px", ""));
  19868. this.minWidth = this.width;
  19869. this.height = this.linegraphSVG.getBoundingClientRect().height;
  19870. this.hidden = false;
  19871. this.stepPixels = 25;
  19872. this.zeroCrossing = -1;
  19873. this.amountOfSteps = -1;
  19874. this.lineOffset = 0;
  19875. this.master = true;
  19876. this.masterAxis = null;
  19877. this.svgElements = {};
  19878. this.iconsRemoved = false;
  19879. this.groups = {};
  19880. this.amountOfGroups = 0;
  19881. // create the HTML DOM
  19882. this._create();
  19883. this.framework = { svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups };
  19884. var me = this;
  19885. this.body.emitter.on("verticalDrag", function() {
  19886. me.dom.lineContainer.style.top = me.body.domProps.scrollTop + 'px';
  19887. });
  19888. }
  19889. DataAxis.prototype = new Component();
  19890. DataAxis.prototype.addGroup = function(label, graphOptions) {
  19891. if (!this.groups.hasOwnProperty(label)) {
  19892. this.groups[label] = graphOptions;
  19893. }
  19894. this.amountOfGroups += 1;
  19895. };
  19896. DataAxis.prototype.updateGroup = function(label, graphOptions) {
  19897. if (!this.groups.hasOwnProperty(label)) {
  19898. this.amountOfGroups += 1;
  19899. }
  19900. this.groups[label] = graphOptions;
  19901. };
  19902. DataAxis.prototype.removeGroup = function(label) {
  19903. if (this.groups.hasOwnProperty(label)) {
  19904. delete this.groups[label];
  19905. this.amountOfGroups -= 1;
  19906. }
  19907. };
  19908. DataAxis.prototype.setOptions = function(options) {
  19909. if (options) {
  19910. var redraw = false;
  19911. if (this.options.orientation != options.orientation && options.orientation !== undefined) {
  19912. redraw = true;
  19913. }
  19914. var fields = ['orientation', 'showMinorLabels', 'showMajorLabels', 'icons', 'majorLinesOffset', 'minorLinesOffset', 'labelOffsetX', 'labelOffsetY', 'iconWidth', 'width', 'visible', 'left', 'right', 'alignZeros'];
  19915. util.selectiveDeepExtend(fields, this.options, options);
  19916. this.minWidth = Number(('' + this.options.width).replace("px", ""));
  19917. if (redraw === true && this.dom.frame) {
  19918. this.hide();
  19919. this.show();
  19920. }
  19921. }
  19922. };
  19923. /**
  19924. * Create the HTML DOM for the DataAxis
  19925. */
  19926. DataAxis.prototype._create = function() {
  19927. this.dom.frame = document.createElement('div');
  19928. this.dom.frame.style.width = this.options.width;
  19929. this.dom.frame.style.height = this.height;
  19930. this.dom.lineContainer = document.createElement('div');
  19931. this.dom.lineContainer.style.width = '100%';
  19932. this.dom.lineContainer.style.height = this.height;
  19933. this.dom.lineContainer.style.position = 'relative';
  19934. // create svg element for graph drawing.
  19935. this.svg = document.createElementNS('http://www.w3.org/2000/svg', "svg");
  19936. this.svg.style.position = "absolute";
  19937. this.svg.style.top = '0px';
  19938. this.svg.style.height = '100%';
  19939. this.svg.style.width = '100%';
  19940. this.svg.style.display = "block";
  19941. this.dom.frame.appendChild(this.svg);
  19942. };
  19943. DataAxis.prototype._redrawGroupIcons = function() {
  19944. DOMutil.prepareElements(this.svgElements);
  19945. var x;
  19946. var iconWidth = this.options.iconWidth;
  19947. var iconHeight = 15;
  19948. var iconOffset = 4;
  19949. var y = iconOffset + 0.5 * iconHeight;
  19950. if (this.options.orientation === 'left') {
  19951. x = iconOffset;
  19952. } else {
  19953. x = this.width - iconWidth - iconOffset;
  19954. }
  19955. var groupArray = (0, _keys2['default'])(this.groups);
  19956. groupArray.sort(function(a, b) {
  19957. return a < b ? -1 : 1;
  19958. });
  19959. for (var i = 0; i < groupArray.length; i++) {
  19960. var groupId = groupArray[i];
  19961. if (this.groups[groupId].visible === true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] === true)) {
  19962. this.groups[groupId].getLegend(iconWidth, iconHeight, this.framework, x, y);
  19963. y += iconHeight + iconOffset;
  19964. }
  19965. }
  19966. DOMutil.cleanupElements(this.svgElements);
  19967. this.iconsRemoved = false;
  19968. };
  19969. DataAxis.prototype._cleanupIcons = function() {
  19970. if (this.iconsRemoved === false) {
  19971. DOMutil.prepareElements(this.svgElements);
  19972. DOMutil.cleanupElements(this.svgElements);
  19973. this.iconsRemoved = true;
  19974. }
  19975. };
  19976. /**
  19977. * Create the HTML DOM for the DataAxis
  19978. */
  19979. DataAxis.prototype.show = function() {
  19980. this.hidden = false;
  19981. if (!this.dom.frame.parentNode) {
  19982. if (this.options.orientation === 'left') {
  19983. this.body.dom.left.appendChild(this.dom.frame);
  19984. } else {
  19985. this.body.dom.right.appendChild(this.dom.frame);
  19986. }
  19987. }
  19988. if (!this.dom.lineContainer.parentNode) {
  19989. this.body.dom.backgroundHorizontal.appendChild(this.dom.lineContainer);
  19990. }
  19991. };
  19992. /**
  19993. * Create the HTML DOM for the DataAxis
  19994. */
  19995. DataAxis.prototype.hide = function() {
  19996. this.hidden = true;
  19997. if (this.dom.frame.parentNode) {
  19998. this.dom.frame.parentNode.removeChild(this.dom.frame);
  19999. }
  20000. if (this.dom.lineContainer.parentNode) {
  20001. this.dom.lineContainer.parentNode.removeChild(this.dom.lineContainer);
  20002. }
  20003. };
  20004. /**
  20005. * Set a range (start and end)
  20006. * @param {number} start
  20007. * @param {number} end
  20008. */
  20009. DataAxis.prototype.setRange = function(start, end) {
  20010. this.range.start = start;
  20011. this.range.end = end;
  20012. };
  20013. /**
  20014. * Repaint the component
  20015. * @return {boolean} Returns true if the component is resized
  20016. */
  20017. DataAxis.prototype.redraw = function() {
  20018. var resized = false;
  20019. var activeGroups = 0;
  20020. // Make sure the line container adheres to the vertical scrolling.
  20021. this.dom.lineContainer.style.top = this.body.domProps.scrollTop + 'px';
  20022. for (var groupId in this.groups) {
  20023. if (this.groups.hasOwnProperty(groupId)) {
  20024. if (this.groups[groupId].visible === true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] === true)) {
  20025. activeGroups++;
  20026. }
  20027. }
  20028. }
  20029. if (this.amountOfGroups === 0 || activeGroups === 0) {
  20030. this.hide();
  20031. } else {
  20032. this.show();
  20033. this.height = Number(this.linegraphSVG.style.height.replace("px", ""));
  20034. // svg offsetheight did not work in firefox and explorer...
  20035. this.dom.lineContainer.style.height = this.height + 'px';
  20036. this.width = this.options.visible === true ? Number(('' + this.options.width).replace("px", "")) : 0;
  20037. var props = this.props;
  20038. var frame = this.dom.frame;
  20039. // update classname
  20040. frame.className = 'vis-data-axis';
  20041. // calculate character width and height
  20042. this._calculateCharSize();
  20043. var orientation = this.options.orientation;
  20044. var showMinorLabels = this.options.showMinorLabels;
  20045. var showMajorLabels = this.options.showMajorLabels;
  20046. // determine the width and height of the elements for the axis
  20047. props.minorLabelHeight = showMinorLabels ? props.minorCharHeight : 0;
  20048. props.majorLabelHeight = showMajorLabels ? props.majorCharHeight : 0;
  20049. props.minorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.minorLinesOffset;
  20050. props.minorLineHeight = 1;
  20051. props.majorLineWidth = this.body.dom.backgroundHorizontal.offsetWidth - this.lineOffset - this.width + 2 * this.options.majorLinesOffset;
  20052. props.majorLineHeight = 1;
  20053. // take frame offline while updating (is almost twice as fast)
  20054. if (orientation === 'left') {
  20055. frame.style.top = '0';
  20056. frame.style.left = '0';
  20057. frame.style.bottom = '';
  20058. frame.style.width = this.width + 'px';
  20059. frame.style.height = this.height + "px";
  20060. this.props.width = this.body.domProps.left.width;
  20061. this.props.height = this.body.domProps.left.height;
  20062. } else {
  20063. // right
  20064. frame.style.top = '';
  20065. frame.style.bottom = '0';
  20066. frame.style.left = '0';
  20067. frame.style.width = this.width + 'px';
  20068. frame.style.height = this.height + "px";
  20069. this.props.width = this.body.domProps.right.width;
  20070. this.props.height = this.body.domProps.right.height;
  20071. }
  20072. resized = this._redrawLabels();
  20073. resized = this._isResized() || resized;
  20074. if (this.options.icons === true) {
  20075. this._redrawGroupIcons();
  20076. } else {
  20077. this._cleanupIcons();
  20078. }
  20079. this._redrawTitle(orientation);
  20080. }
  20081. return resized;
  20082. };
  20083. /**
  20084. * Repaint major and minor text labels and vertical grid lines
  20085. *
  20086. * @returns {boolean}
  20087. * @private
  20088. */
  20089. DataAxis.prototype._redrawLabels = function() {
  20090. var _this = this;
  20091. var resized = false;
  20092. DOMutil.prepareElements(this.DOMelements.lines);
  20093. DOMutil.prepareElements(this.DOMelements.labels);
  20094. var orientation = this.options['orientation'];
  20095. var customRange = this.options[orientation].range != undefined ? this.options[orientation].range : {};
  20096. //Override range with manual options:
  20097. var autoScaleEnd = true;
  20098. if (customRange.max != undefined) {
  20099. this.range.end = customRange.max;
  20100. autoScaleEnd = false;
  20101. }
  20102. var autoScaleStart = true;
  20103. if (customRange.min != undefined) {
  20104. this.range.start = customRange.min;
  20105. autoScaleStart = false;
  20106. }
  20107. this.scale = new DataScale(this.range.start, this.range.end, autoScaleStart, autoScaleEnd, this.dom.frame.offsetHeight, this.props.majorCharHeight, this.options.alignZeros, this.options[orientation].format);
  20108. if (this.master === false && this.masterAxis != undefined) {
  20109. this.scale.followScale(this.masterAxis.scale);
  20110. }
  20111. //Is updated in side-effect of _redrawLabel():
  20112. this.maxLabelSize = 0;
  20113. var lines = this.scale.getLines();
  20114. lines.forEach(function(line) {
  20115. var y = line.y;
  20116. var isMajor = line.major;
  20117. if (_this.options['showMinorLabels'] && isMajor === false) {
  20118. _this._redrawLabel(y - 2, line.val, orientation, 'vis-y-axis vis-minor', _this.props.minorCharHeight);
  20119. }
  20120. if (isMajor) {
  20121. if (y >= 0) {
  20122. _this._redrawLabel(y - 2, line.val, orientation, 'vis-y-axis vis-major', _this.props.majorCharHeight);
  20123. }
  20124. }
  20125. if (_this.master === true) {
  20126. if (isMajor) {
  20127. _this._redrawLine(y, orientation, 'vis-grid vis-horizontal vis-major', _this.options.majorLinesOffset, _this.props.majorLineWidth);
  20128. } else {
  20129. _this._redrawLine(y, orientation, 'vis-grid vis-horizontal vis-minor', _this.options.minorLinesOffset, _this.props.minorLineWidth);
  20130. }
  20131. }
  20132. });
  20133. // Note that title is rotated, so we're using the height, not width!
  20134. var titleWidth = 0;
  20135. if (this.options[orientation].title !== undefined && this.options[orientation].title.text !== undefined) {
  20136. titleWidth = this.props.titleCharHeight;
  20137. }
  20138. var offset = this.options.icons === true ? Math.max(this.options.iconWidth, titleWidth) + this.options.labelOffsetX + 15 : titleWidth + this.options.labelOffsetX + 15;
  20139. // this will resize the yAxis to accommodate the labels.
  20140. if (this.maxLabelSize > this.width - offset && this.options.visible === true) {
  20141. this.width = this.maxLabelSize + offset;
  20142. this.options.width = this.width + "px";
  20143. DOMutil.cleanupElements(this.DOMelements.lines);
  20144. DOMutil.cleanupElements(this.DOMelements.labels);
  20145. this.redraw();
  20146. resized = true;
  20147. }
  20148. // this will resize the yAxis if it is too big for the labels.
  20149. else if (this.maxLabelSize < this.width - offset && this.options.visible === true && this.width > this.minWidth) {
  20150. this.width = Math.max(this.minWidth, this.maxLabelSize + offset);
  20151. this.options.width = this.width + "px";
  20152. DOMutil.cleanupElements(this.DOMelements.lines);
  20153. DOMutil.cleanupElements(this.DOMelements.labels);
  20154. this.redraw();
  20155. resized = true;
  20156. } else {
  20157. DOMutil.cleanupElements(this.DOMelements.lines);
  20158. DOMutil.cleanupElements(this.DOMelements.labels);
  20159. resized = false;
  20160. }
  20161. return resized;
  20162. };
  20163. DataAxis.prototype.convertValue = function(value) {
  20164. return this.scale.convertValue(value);
  20165. };
  20166. DataAxis.prototype.screenToValue = function(x) {
  20167. return this.scale.screenToValue(x);
  20168. };
  20169. /**
  20170. * Create a label for the axis at position x
  20171. *
  20172. * @param {number} y
  20173. * @param {string} text
  20174. * @param {'top'|'right'|'bottom'|'left'} orientation
  20175. * @param {string} className
  20176. * @param {number} characterHeight
  20177. * @private
  20178. */
  20179. DataAxis.prototype._redrawLabel = function(y, text, orientation, className, characterHeight) {
  20180. // reuse redundant label
  20181. var label = DOMutil.getDOMElement('div', this.DOMelements.labels, this.dom.frame); //this.dom.redundant.labels.shift();
  20182. label.className = className;
  20183. label.innerHTML = text;
  20184. if (orientation === 'left') {
  20185. label.style.left = '-' + this.options.labelOffsetX + 'px';
  20186. label.style.textAlign = "right";
  20187. } else {
  20188. label.style.right = '-' + this.options.labelOffsetX + 'px';
  20189. label.style.textAlign = "left";
  20190. }
  20191. label.style.top = y - 0.5 * characterHeight + this.options.labelOffsetY + 'px';
  20192. text += '';
  20193. var largestWidth = Math.max(this.props.majorCharWidth, this.props.minorCharWidth);
  20194. if (this.maxLabelSize < text.length * largestWidth) {
  20195. this.maxLabelSize = text.length * largestWidth;
  20196. }
  20197. };
  20198. /**
  20199. * Create a minor line for the axis at position y
  20200. * @param {number} y
  20201. * @param {'top'|'right'|'bottom'|'left'} orientation
  20202. * @param {string} className
  20203. * @param {number} offset
  20204. * @param {number} width
  20205. */
  20206. DataAxis.prototype._redrawLine = function(y, orientation, className, offset, width) {
  20207. if (this.master === true) {
  20208. var line = DOMutil.getDOMElement('div', this.DOMelements.lines, this.dom.lineContainer); //this.dom.redundant.lines.shift();
  20209. line.className = className;
  20210. line.innerHTML = '';
  20211. if (orientation === 'left') {
  20212. line.style.left = this.width - offset + 'px';
  20213. } else {
  20214. line.style.right = this.width - offset + 'px';
  20215. }
  20216. line.style.width = width + 'px';
  20217. line.style.top = y + 'px';
  20218. }
  20219. };
  20220. /**
  20221. * Create a title for the axis
  20222. * @private
  20223. * @param {'top'|'right'|'bottom'|'left'} orientation
  20224. */
  20225. DataAxis.prototype._redrawTitle = function(orientation) {
  20226. DOMutil.prepareElements(this.DOMelements.title);
  20227. // Check if the title is defined for this axes
  20228. if (this.options[orientation].title !== undefined && this.options[orientation].title.text !== undefined) {
  20229. var title = DOMutil.getDOMElement('div', this.DOMelements.title, this.dom.frame);
  20230. title.className = 'vis-y-axis vis-title vis-' + orientation;
  20231. title.innerHTML = this.options[orientation].title.text;
  20232. // Add style - if provided
  20233. if (this.options[orientation].title.style !== undefined) {
  20234. util.addCssText(title, this.options[orientation].title.style);
  20235. }
  20236. if (orientation === 'left') {
  20237. title.style.left = this.props.titleCharHeight + 'px';
  20238. } else {
  20239. title.style.right = this.props.titleCharHeight + 'px';
  20240. }
  20241. title.style.width = this.height + 'px';
  20242. }
  20243. // we need to clean up in case we did not use all elements.
  20244. DOMutil.cleanupElements(this.DOMelements.title);
  20245. };
  20246. /**
  20247. * Determine the size of text on the axis (both major and minor axis).
  20248. * The size is calculated only once and then cached in this.props.
  20249. * @private
  20250. */
  20251. DataAxis.prototype._calculateCharSize = function() {
  20252. // determine the char width and height on the minor axis
  20253. if (!('minorCharHeight' in this.props)) {
  20254. var textMinor = document.createTextNode('0');
  20255. var measureCharMinor = document.createElement('div');
  20256. measureCharMinor.className = 'vis-y-axis vis-minor vis-measure';
  20257. measureCharMinor.appendChild(textMinor);
  20258. this.dom.frame.appendChild(measureCharMinor);
  20259. this.props.minorCharHeight = measureCharMinor.clientHeight;
  20260. this.props.minorCharWidth = measureCharMinor.clientWidth;
  20261. this.dom.frame.removeChild(measureCharMinor);
  20262. }
  20263. if (!('majorCharHeight' in this.props)) {
  20264. var textMajor = document.createTextNode('0');
  20265. var measureCharMajor = document.createElement('div');
  20266. measureCharMajor.className = 'vis-y-axis vis-major vis-measure';
  20267. measureCharMajor.appendChild(textMajor);
  20268. this.dom.frame.appendChild(measureCharMajor);
  20269. this.props.majorCharHeight = measureCharMajor.clientHeight;
  20270. this.props.majorCharWidth = measureCharMajor.clientWidth;
  20271. this.dom.frame.removeChild(measureCharMajor);
  20272. }
  20273. if (!('titleCharHeight' in this.props)) {
  20274. var textTitle = document.createTextNode('0');
  20275. var measureCharTitle = document.createElement('div');
  20276. measureCharTitle.className = 'vis-y-axis vis-title vis-measure';
  20277. measureCharTitle.appendChild(textTitle);
  20278. this.dom.frame.appendChild(measureCharTitle);
  20279. this.props.titleCharHeight = measureCharTitle.clientHeight;
  20280. this.props.titleCharWidth = measureCharTitle.clientWidth;
  20281. this.dom.frame.removeChild(measureCharTitle);
  20282. }
  20283. };
  20284. module.exports = DataAxis;
  20285. /***/
  20286. }),
  20287. /* 108 */
  20288. /***/
  20289. (function(module, exports, __webpack_require__) {
  20290. "use strict";
  20291. /**
  20292. *
  20293. * @param {number} start
  20294. * @param {number} end
  20295. * @param {boolean} autoScaleStart
  20296. * @param {boolean} autoScaleEnd
  20297. * @param {number} containerHeight
  20298. * @param {number} majorCharHeight
  20299. * @param {boolean} zeroAlign
  20300. * @param {function} formattingFunction
  20301. * @constructor DataScale
  20302. */
  20303. function DataScale(start, end, autoScaleStart, autoScaleEnd, containerHeight, majorCharHeight) {
  20304. var zeroAlign = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false;
  20305. var formattingFunction = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;
  20306. this.majorSteps = [1, 2, 5, 10];
  20307. this.minorSteps = [0.25, 0.5, 1, 2];
  20308. this.customLines = null;
  20309. this.containerHeight = containerHeight;
  20310. this.majorCharHeight = majorCharHeight;
  20311. this._start = start;
  20312. this._end = end;
  20313. this.scale = 1;
  20314. this.minorStepIdx = -1;
  20315. this.magnitudefactor = 1;
  20316. this.determineScale();
  20317. this.zeroAlign = zeroAlign;
  20318. this.autoScaleStart = autoScaleStart;
  20319. this.autoScaleEnd = autoScaleEnd;
  20320. this.formattingFunction = formattingFunction;
  20321. if (autoScaleStart || autoScaleEnd) {
  20322. var me = this;
  20323. var roundToMinor = function roundToMinor(value) {
  20324. var rounded = value - value % (me.magnitudefactor * me.minorSteps[me.minorStepIdx]);
  20325. if (value % (me.magnitudefactor * me.minorSteps[me.minorStepIdx]) > 0.5 * (me.magnitudefactor * me.minorSteps[me.minorStepIdx])) {
  20326. return rounded + me.magnitudefactor * me.minorSteps[me.minorStepIdx];
  20327. } else {
  20328. return rounded;
  20329. }
  20330. };
  20331. if (autoScaleStart) {
  20332. this._start -= this.magnitudefactor * 2 * this.minorSteps[this.minorStepIdx];
  20333. this._start = roundToMinor(this._start);
  20334. }
  20335. if (autoScaleEnd) {
  20336. this._end += this.magnitudefactor * this.minorSteps[this.minorStepIdx];
  20337. this._end = roundToMinor(this._end);
  20338. }
  20339. this.determineScale();
  20340. }
  20341. }
  20342. DataScale.prototype.setCharHeight = function(majorCharHeight) {
  20343. this.majorCharHeight = majorCharHeight;
  20344. };
  20345. DataScale.prototype.setHeight = function(containerHeight) {
  20346. this.containerHeight = containerHeight;
  20347. };
  20348. DataScale.prototype.determineScale = function() {
  20349. var range = this._end - this._start;
  20350. this.scale = this.containerHeight / range;
  20351. var minimumStepValue = this.majorCharHeight / this.scale;
  20352. var orderOfMagnitude = range > 0 ? Math.round(Math.log(range) / Math.LN10) : 0;
  20353. this.minorStepIdx = -1;
  20354. this.magnitudefactor = Math.pow(10, orderOfMagnitude);
  20355. var start = 0;
  20356. if (orderOfMagnitude < 0) {
  20357. start = orderOfMagnitude;
  20358. }
  20359. var solutionFound = false;
  20360. for (var l = start; Math.abs(l) <= Math.abs(orderOfMagnitude); l++) {
  20361. this.magnitudefactor = Math.pow(10, l);
  20362. for (var j = 0; j < this.minorSteps.length; j++) {
  20363. var stepSize = this.magnitudefactor * this.minorSteps[j];
  20364. if (stepSize >= minimumStepValue) {
  20365. solutionFound = true;
  20366. this.minorStepIdx = j;
  20367. break;
  20368. }
  20369. }
  20370. if (solutionFound === true) {
  20371. break;
  20372. }
  20373. }
  20374. };
  20375. DataScale.prototype.is_major = function(value) {
  20376. return value % (this.magnitudefactor * this.majorSteps[this.minorStepIdx]) === 0;
  20377. };
  20378. DataScale.prototype.getStep = function() {
  20379. return this.magnitudefactor * this.minorSteps[this.minorStepIdx];
  20380. };
  20381. DataScale.prototype.getFirstMajor = function() {
  20382. var majorStep = this.magnitudefactor * this.majorSteps[this.minorStepIdx];
  20383. return this.convertValue(this._start + (majorStep - this._start % majorStep) % majorStep);
  20384. };
  20385. DataScale.prototype.formatValue = function(current) {
  20386. var returnValue = current.toPrecision(5);
  20387. if (typeof this.formattingFunction === 'function') {
  20388. returnValue = this.formattingFunction(current);
  20389. }
  20390. if (typeof returnValue === 'number') {
  20391. return '' + returnValue;
  20392. } else if (typeof returnValue === 'string') {
  20393. return returnValue;
  20394. } else {
  20395. return current.toPrecision(5);
  20396. }
  20397. };
  20398. DataScale.prototype.getLines = function() {
  20399. var lines = [];
  20400. var step = this.getStep();
  20401. var bottomOffset = (step - this._start % step) % step;
  20402. for (var i = this._start + bottomOffset; this._end - i > 0.00001; i += step) {
  20403. if (i != this._start) {
  20404. //Skip the bottom line
  20405. lines.push({ major: this.is_major(i), y: this.convertValue(i), val: this.formatValue(i) });
  20406. }
  20407. }
  20408. return lines;
  20409. };
  20410. DataScale.prototype.followScale = function(other) {
  20411. var oldStepIdx = this.minorStepIdx;
  20412. var oldStart = this._start;
  20413. var oldEnd = this._end;
  20414. var me = this;
  20415. var increaseMagnitude = function increaseMagnitude() {
  20416. me.magnitudefactor *= 2;
  20417. };
  20418. var decreaseMagnitude = function decreaseMagnitude() {
  20419. me.magnitudefactor /= 2;
  20420. };
  20421. if (other.minorStepIdx <= 1 && this.minorStepIdx <= 1 || other.minorStepIdx > 1 && this.minorStepIdx > 1) {
  20422. //easy, no need to change stepIdx nor multiplication factor
  20423. } else if (other.minorStepIdx < this.minorStepIdx) {
  20424. //I'm 5, they are 4 per major.
  20425. this.minorStepIdx = 1;
  20426. if (oldStepIdx == 2) {
  20427. increaseMagnitude();
  20428. } else {
  20429. increaseMagnitude();
  20430. increaseMagnitude();
  20431. }
  20432. } else {
  20433. //I'm 4, they are 5 per major
  20434. this.minorStepIdx = 2;
  20435. if (oldStepIdx == 1) {
  20436. decreaseMagnitude();
  20437. } else {
  20438. decreaseMagnitude();
  20439. decreaseMagnitude();
  20440. }
  20441. }
  20442. //Get masters stats:
  20443. var otherZero = other.convertValue(0);
  20444. var otherStep = other.getStep() * other.scale;
  20445. var done = false;
  20446. var count = 0;
  20447. //Loop until magnitude is correct for given constrains.
  20448. while (!done && count++ < 5) {
  20449. //Get my stats:
  20450. this.scale = otherStep / (this.minorSteps[this.minorStepIdx] * this.magnitudefactor);
  20451. var newRange = this.containerHeight / this.scale;
  20452. //For the case the magnitudefactor has changed:
  20453. this._start = oldStart;
  20454. this._end = this._start + newRange;
  20455. var myOriginalZero = this._end * this.scale;
  20456. var majorStep = this.magnitudefactor * this.majorSteps[this.minorStepIdx];
  20457. var majorOffset = this.getFirstMajor() - other.getFirstMajor();
  20458. if (this.zeroAlign) {
  20459. var zeroOffset = otherZero - myOriginalZero;
  20460. this._end += zeroOffset / this.scale;
  20461. this._start = this._end - newRange;
  20462. } else {
  20463. if (!this.autoScaleStart) {
  20464. this._start += majorStep - majorOffset / this.scale;
  20465. this._end = this._start + newRange;
  20466. } else {
  20467. this._start -= majorOffset / this.scale;
  20468. this._end = this._start + newRange;
  20469. }
  20470. }
  20471. if (!this.autoScaleEnd && this._end > oldEnd + 0.00001) {
  20472. //Need to decrease magnitude to prevent scale overshoot! (end)
  20473. decreaseMagnitude();
  20474. done = false;
  20475. continue;
  20476. }
  20477. if (!this.autoScaleStart && this._start < oldStart - 0.00001) {
  20478. if (this.zeroAlign && oldStart >= 0) {
  20479. console.warn("Can't adhere to given 'min' range, due to zeroalign");
  20480. } else {
  20481. //Need to decrease magnitude to prevent scale overshoot! (start)
  20482. decreaseMagnitude();
  20483. done = false;
  20484. continue;
  20485. }
  20486. }
  20487. if (this.autoScaleStart && this.autoScaleEnd && newRange < oldEnd - oldStart) {
  20488. increaseMagnitude();
  20489. done = false;
  20490. continue;
  20491. }
  20492. done = true;
  20493. }
  20494. };
  20495. DataScale.prototype.convertValue = function(value) {
  20496. return this.containerHeight - (value - this._start) * this.scale;
  20497. };
  20498. DataScale.prototype.screenToValue = function(pixels) {
  20499. return (this.containerHeight - pixels) / this.scale + this._start;
  20500. };
  20501. module.exports = DataScale;
  20502. /***/
  20503. }),
  20504. /* 109 */
  20505. /***/
  20506. (function(module, exports, __webpack_require__) {
  20507. "use strict";
  20508. var _typeof2 = __webpack_require__(6);
  20509. var _typeof3 = _interopRequireDefault(_typeof2);
  20510. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  20511. var util = __webpack_require__(2);
  20512. var Bars = __webpack_require__(110);
  20513. var Lines = __webpack_require__(111);
  20514. var Points = __webpack_require__(72);
  20515. /**
  20516. * /**
  20517. * @param {object} group | the object of the group from the dataset
  20518. * @param {string} groupId | ID of the group
  20519. * @param {object} options | the default options
  20520. * @param {array} groupsUsingDefaultStyles | this array has one entree.
  20521. * It is passed as an array so it is passed by reference.
  20522. * It enumerates through the default styles
  20523. * @constructor GraphGroup
  20524. */
  20525. function GraphGroup(group, groupId, options, groupsUsingDefaultStyles) {
  20526. this.id = groupId;
  20527. var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'drawPoints', 'shaded', 'interpolation', 'zIndex', 'excludeFromStacking', 'excludeFromLegend'];
  20528. this.options = util.selectiveBridgeObject(fields, options);
  20529. this.usingDefaultStyle = group.className === undefined;
  20530. this.groupsUsingDefaultStyles = groupsUsingDefaultStyles;
  20531. this.zeroPosition = 0;
  20532. this.update(group);
  20533. if (this.usingDefaultStyle == true) {
  20534. this.groupsUsingDefaultStyles[0] += 1;
  20535. }
  20536. this.itemsData = [];
  20537. this.visible = group.visible === undefined ? true : group.visible;
  20538. }
  20539. /**
  20540. * this loads a reference to all items in this group into this group.
  20541. * @param {array} items
  20542. */
  20543. GraphGroup.prototype.setItems = function(items) {
  20544. if (items != null) {
  20545. this.itemsData = items;
  20546. if (this.options.sort == true) {
  20547. util.insertSort(this.itemsData, function(a, b) {
  20548. return a.x > b.x ? 1 : -1;
  20549. });
  20550. }
  20551. } else {
  20552. this.itemsData = [];
  20553. }
  20554. };
  20555. GraphGroup.prototype.getItems = function() {
  20556. return this.itemsData;
  20557. };
  20558. /**
  20559. * this is used for barcharts and shading, this way, we only have to calculate it once.
  20560. * @param {number} pos
  20561. */
  20562. GraphGroup.prototype.setZeroPosition = function(pos) {
  20563. this.zeroPosition = pos;
  20564. };
  20565. /**
  20566. * set the options of the graph group over the default options.
  20567. * @param {Object} options
  20568. */
  20569. GraphGroup.prototype.setOptions = function(options) {
  20570. if (options !== undefined) {
  20571. var fields = ['sampling', 'style', 'sort', 'yAxisOrientation', 'barChart', 'zIndex', 'excludeFromStacking', 'excludeFromLegend'];
  20572. util.selectiveDeepExtend(fields, this.options, options);
  20573. // if the group's drawPoints is a function delegate the callback to the onRender property
  20574. if (typeof options.drawPoints == 'function') {
  20575. options.drawPoints = {
  20576. onRender: options.drawPoints
  20577. };
  20578. }
  20579. util.mergeOptions(this.options, options, 'interpolation');
  20580. util.mergeOptions(this.options, options, 'drawPoints');
  20581. util.mergeOptions(this.options, options, 'shaded');
  20582. if (options.interpolation) {
  20583. if ((0, _typeof3['default'])(options.interpolation) == 'object') {
  20584. if (options.interpolation.parametrization) {
  20585. if (options.interpolation.parametrization == 'uniform') {
  20586. this.options.interpolation.alpha = 0;
  20587. } else if (options.interpolation.parametrization == 'chordal') {
  20588. this.options.interpolation.alpha = 1.0;
  20589. } else {
  20590. this.options.interpolation.parametrization = 'centripetal';
  20591. this.options.interpolation.alpha = 0.5;
  20592. }
  20593. }
  20594. }
  20595. }
  20596. }
  20597. };
  20598. /**
  20599. * this updates the current group class with the latest group dataset entree, used in _updateGroup in linegraph
  20600. * @param {vis.Group} group
  20601. */
  20602. GraphGroup.prototype.update = function(group) {
  20603. this.group = group;
  20604. this.content = group.content || 'graph';
  20605. this.className = group.className || this.className || 'vis-graph-group' + this.groupsUsingDefaultStyles[0] % 10;
  20606. this.visible = group.visible === undefined ? true : group.visible;
  20607. this.style = group.style;
  20608. this.setOptions(group.options);
  20609. };
  20610. /**
  20611. * return the legend entree for this group.
  20612. *
  20613. * @param {number} iconWidth
  20614. * @param {number} iconHeight
  20615. * @param {{svg: (*|Element), svgElements: Object, options: Object, groups: Array.<Object>}} framework
  20616. * @param {number} x
  20617. * @param {number} y
  20618. * @returns {{icon: (*|Element), label: (*|string), orientation: *}}
  20619. */
  20620. GraphGroup.prototype.getLegend = function(iconWidth, iconHeight, framework, x, y) {
  20621. if (framework == undefined || framework == null) {
  20622. var svg = document.createElementNS('http://www.w3.org/2000/svg', "svg");
  20623. framework = { svg: svg, svgElements: {}, options: this.options, groups: [this] };
  20624. }
  20625. if (x == undefined || x == null) {
  20626. x = 0;
  20627. }
  20628. if (y == undefined || y == null) {
  20629. y = 0.5 * iconHeight;
  20630. }
  20631. switch (this.options.style) {
  20632. case "line":
  20633. Lines.drawIcon(this, x, y, iconWidth, iconHeight, framework);
  20634. break;
  20635. case "points": //explicit no break
  20636. case "point":
  20637. Points.drawIcon(this, x, y, iconWidth, iconHeight, framework);
  20638. break;
  20639. case "bar":
  20640. Bars.drawIcon(this, x, y, iconWidth, iconHeight, framework);
  20641. break;
  20642. }
  20643. return { icon: framework.svg, label: this.content, orientation: this.options.yAxisOrientation };
  20644. };
  20645. GraphGroup.prototype.getYRange = function(groupData) {
  20646. var yMin = groupData[0].y;
  20647. var yMax = groupData[0].y;
  20648. for (var j = 0; j < groupData.length; j++) {
  20649. yMin = yMin > groupData[j].y ? groupData[j].y : yMin;
  20650. yMax = yMax < groupData[j].y ? groupData[j].y : yMax;
  20651. }
  20652. return { min: yMin, max: yMax, yAxisOrientation: this.options.yAxisOrientation };
  20653. };
  20654. module.exports = GraphGroup;
  20655. /***/
  20656. }),
  20657. /* 110 */
  20658. /***/
  20659. (function(module, exports, __webpack_require__) {
  20660. "use strict";
  20661. var DOMutil = __webpack_require__(14);
  20662. var Points = __webpack_require__(72);
  20663. /**
  20664. *
  20665. * @param {vis.GraphGroup.id} groupId
  20666. * @param {Object} options // TODO: Describe options
  20667. * @constructor Bargraph
  20668. */
  20669. function Bargraph(groupId, options) { // eslint-disable-line no-unused-vars
  20670. }
  20671. Bargraph.drawIcon = function(group, x, y, iconWidth, iconHeight, framework) {
  20672. var fillHeight = iconHeight * 0.5;
  20673. var outline = DOMutil.getSVGElement("rect", framework.svgElements, framework.svg);
  20674. outline.setAttributeNS(null, "x", x);
  20675. outline.setAttributeNS(null, "y", y - fillHeight);
  20676. outline.setAttributeNS(null, "width", iconWidth);
  20677. outline.setAttributeNS(null, "height", 2 * fillHeight);
  20678. outline.setAttributeNS(null, "class", "vis-outline");
  20679. var barWidth = Math.round(0.3 * iconWidth);
  20680. var originalWidth = group.options.barChart.width;
  20681. var scale = originalWidth / barWidth;
  20682. var bar1Height = Math.round(0.4 * iconHeight);
  20683. var bar2Height = Math.round(0.75 * iconHeight);
  20684. var offset = Math.round((iconWidth - 2 * barWidth) / 3);
  20685. DOMutil.drawBar(x + 0.5 * barWidth + offset, y + fillHeight - bar1Height - 1, barWidth, bar1Height, group.className + ' vis-bar', framework.svgElements, framework.svg, group.style);
  20686. DOMutil.drawBar(x + 1.5 * barWidth + offset + 2, y + fillHeight - bar2Height - 1, barWidth, bar2Height, group.className + ' vis-bar', framework.svgElements, framework.svg, group.style);
  20687. if (group.options.drawPoints.enabled == true) {
  20688. var groupTemplate = {
  20689. style: group.options.drawPoints.style,
  20690. styles: group.options.drawPoints.styles,
  20691. size: group.options.drawPoints.size / scale,
  20692. className: group.className
  20693. };
  20694. DOMutil.drawPoint(x + 0.5 * barWidth + offset, y + fillHeight - bar1Height - 1, groupTemplate, framework.svgElements, framework.svg);
  20695. DOMutil.drawPoint(x + 1.5 * barWidth + offset + 2, y + fillHeight - bar2Height - 1, groupTemplate, framework.svgElements, framework.svg);
  20696. }
  20697. };
  20698. /**
  20699. * draw a bar graph
  20700. *
  20701. * @param {Array.<vis.GraphGroup.id>} groupIds
  20702. * @param {Object} processedGroupData
  20703. * @param {{svg: Object, svgElements: Array.<Object>, options: Object, groups: Array.<vis.Group>}} framework
  20704. */
  20705. Bargraph.draw = function(groupIds, processedGroupData, framework) {
  20706. var combinedData = [];
  20707. var intersections = {};
  20708. var coreDistance;
  20709. var key, drawData;
  20710. var group;
  20711. var i, j;
  20712. var barPoints = 0;
  20713. // combine all barchart data
  20714. for (i = 0; i < groupIds.length; i++) {
  20715. group = framework.groups[groupIds[i]];
  20716. if (group.options.style === 'bar') {
  20717. if (group.visible === true && (framework.options.groups.visibility[groupIds[i]] === undefined || framework.options.groups.visibility[groupIds[i]] === true)) {
  20718. for (j = 0; j < processedGroupData[groupIds[i]].length; j++) {
  20719. combinedData.push({
  20720. screen_x: processedGroupData[groupIds[i]][j].screen_x,
  20721. screen_end: processedGroupData[groupIds[i]][j].screen_end,
  20722. screen_y: processedGroupData[groupIds[i]][j].screen_y,
  20723. x: processedGroupData[groupIds[i]][j].x,
  20724. end: processedGroupData[groupIds[i]][j].end,
  20725. y: processedGroupData[groupIds[i]][j].y,
  20726. groupId: groupIds[i],
  20727. label: processedGroupData[groupIds[i]][j].label
  20728. });
  20729. barPoints += 1;
  20730. }
  20731. }
  20732. }
  20733. }
  20734. if (barPoints === 0) {
  20735. return;
  20736. }
  20737. // sort by time and by group
  20738. combinedData.sort(function(a, b) {
  20739. if (a.screen_x === b.screen_x) {
  20740. return a.groupId < b.groupId ? -1 : 1;
  20741. } else {
  20742. return a.screen_x - b.screen_x;
  20743. }
  20744. });
  20745. // get intersections
  20746. Bargraph._getDataIntersections(intersections, combinedData);
  20747. // plot barchart
  20748. for (i = 0; i < combinedData.length; i++) {
  20749. group = framework.groups[combinedData[i].groupId];
  20750. var minWidth = group.options.barChart.minWidth != undefined ? group.options.barChart.minWidth : 0.1 * group.options.barChart.width;
  20751. key = combinedData[i].screen_x;
  20752. var heightOffset = 0;
  20753. if (intersections[key] === undefined) {
  20754. if (i + 1 < combinedData.length) {
  20755. coreDistance = Math.abs(combinedData[i + 1].screen_x - key);
  20756. }
  20757. drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth);
  20758. } else {
  20759. var nextKey = i + (intersections[key].amount - intersections[key].resolved);
  20760. if (nextKey < combinedData.length) {
  20761. coreDistance = Math.abs(combinedData[nextKey].screen_x - key);
  20762. }
  20763. drawData = Bargraph._getSafeDrawData(coreDistance, group, minWidth);
  20764. intersections[key].resolved += 1;
  20765. if (group.options.stack === true && group.options.excludeFromStacking !== true) {
  20766. if (combinedData[i].screen_y < group.zeroPosition) {
  20767. heightOffset = intersections[key].accumulatedNegative;
  20768. intersections[key].accumulatedNegative += group.zeroPosition - combinedData[i].screen_y;
  20769. } else {
  20770. heightOffset = intersections[key].accumulatedPositive;
  20771. intersections[key].accumulatedPositive += group.zeroPosition - combinedData[i].screen_y;
  20772. }
  20773. } else if (group.options.barChart.sideBySide === true) {
  20774. drawData.width = drawData.width / intersections[key].amount;
  20775. drawData.offset += intersections[key].resolved * drawData.width - 0.5 * drawData.width * (intersections[key].amount + 1);
  20776. }
  20777. }
  20778. var dataWidth = drawData.width;
  20779. var start = combinedData[i].screen_x;
  20780. // are we drawing explicit boxes? (we supplied an end value)
  20781. if (combinedData[i].screen_end != undefined) {
  20782. dataWidth = combinedData[i].screen_end - combinedData[i].screen_x;
  20783. start += dataWidth * 0.5;
  20784. } else {
  20785. start += drawData.offset;
  20786. }
  20787. DOMutil.drawBar(start, combinedData[i].screen_y - heightOffset, dataWidth, group.zeroPosition - combinedData[i].screen_y, group.className + ' vis-bar', framework.svgElements, framework.svg, group.style);
  20788. // draw points
  20789. if (group.options.drawPoints.enabled === true) {
  20790. var pointData = {
  20791. screen_x: combinedData[i].screen_x,
  20792. screen_y: combinedData[i].screen_y - heightOffset,
  20793. x: combinedData[i].x,
  20794. y: combinedData[i].y,
  20795. groupId: combinedData[i].groupId,
  20796. label: combinedData[i].label
  20797. };
  20798. Points.draw([pointData], group, framework, drawData.offset);
  20799. //DOMutil.drawPoint(combinedData[i].x + drawData.offset, combinedData[i].y, group, framework.svgElements, framework.svg);
  20800. }
  20801. }
  20802. };
  20803. /**
  20804. * Fill the intersections object with counters of how many datapoints share the same x coordinates
  20805. * @param {Object} intersections
  20806. * @param {Array.<Object>} combinedData
  20807. * @private
  20808. */
  20809. Bargraph._getDataIntersections = function(intersections, combinedData) {
  20810. // get intersections
  20811. var coreDistance;
  20812. for (var i = 0; i < combinedData.length; i++) {
  20813. if (i + 1 < combinedData.length) {
  20814. coreDistance = Math.abs(combinedData[i + 1].screen_x - combinedData[i].screen_x);
  20815. }
  20816. if (i > 0) {
  20817. coreDistance = Math.min(coreDistance, Math.abs(combinedData[i - 1].screen_x - combinedData[i].screen_x));
  20818. }
  20819. if (coreDistance === 0) {
  20820. if (intersections[combinedData[i].screen_x] === undefined) {
  20821. intersections[combinedData[i].screen_x] = {
  20822. amount: 0,
  20823. resolved: 0,
  20824. accumulatedPositive: 0,
  20825. accumulatedNegative: 0
  20826. };
  20827. }
  20828. intersections[combinedData[i].screen_x].amount += 1;
  20829. }
  20830. }
  20831. };
  20832. /**
  20833. * Get the width and offset for bargraphs based on the coredistance between datapoints
  20834. *
  20835. * @param {number} coreDistance
  20836. * @param {vis.Group} group
  20837. * @param {number} minWidth
  20838. * @returns {{width: number, offset: number}}
  20839. * @private
  20840. */
  20841. Bargraph._getSafeDrawData = function(coreDistance, group, minWidth) {
  20842. var width, offset;
  20843. if (coreDistance < group.options.barChart.width && coreDistance > 0) {
  20844. width = coreDistance < minWidth ? minWidth : coreDistance;
  20845. offset = 0; // recalculate offset with the new width;
  20846. if (group.options.barChart.align === 'left') {
  20847. offset -= 0.5 * coreDistance;
  20848. } else if (group.options.barChart.align === 'right') {
  20849. offset += 0.5 * coreDistance;
  20850. }
  20851. } else {
  20852. // default settings
  20853. width = group.options.barChart.width;
  20854. offset = 0;
  20855. if (group.options.barChart.align === 'left') {
  20856. offset -= 0.5 * group.options.barChart.width;
  20857. } else if (group.options.barChart.align === 'right') {
  20858. offset += 0.5 * group.options.barChart.width;
  20859. }
  20860. }
  20861. return { width: width, offset: offset };
  20862. };
  20863. Bargraph.getStackedYRange = function(combinedData, groupRanges, groupIds, groupLabel, orientation) {
  20864. if (combinedData.length > 0) {
  20865. // sort by time and by group
  20866. combinedData.sort(function(a, b) {
  20867. if (a.screen_x === b.screen_x) {
  20868. return a.groupId < b.groupId ? -1 : 1;
  20869. } else {
  20870. return a.screen_x - b.screen_x;
  20871. }
  20872. });
  20873. var intersections = {};
  20874. Bargraph._getDataIntersections(intersections, combinedData);
  20875. groupRanges[groupLabel] = Bargraph._getStackedYRange(intersections, combinedData);
  20876. groupRanges[groupLabel].yAxisOrientation = orientation;
  20877. groupIds.push(groupLabel);
  20878. }
  20879. };
  20880. Bargraph._getStackedYRange = function(intersections, combinedData) {
  20881. var key;
  20882. var yMin = combinedData[0].screen_y;
  20883. var yMax = combinedData[0].screen_y;
  20884. for (var i = 0; i < combinedData.length; i++) {
  20885. key = combinedData[i].screen_x;
  20886. if (intersections[key] === undefined) {
  20887. yMin = yMin > combinedData[i].screen_y ? combinedData[i].screen_y : yMin;
  20888. yMax = yMax < combinedData[i].screen_y ? combinedData[i].screen_y : yMax;
  20889. } else {
  20890. if (combinedData[i].screen_y < 0) {
  20891. intersections[key].accumulatedNegative += combinedData[i].screen_y;
  20892. } else {
  20893. intersections[key].accumulatedPositive += combinedData[i].screen_y;
  20894. }
  20895. }
  20896. }
  20897. for (var xpos in intersections) {
  20898. if (intersections.hasOwnProperty(xpos)) {
  20899. yMin = yMin > intersections[xpos].accumulatedNegative ? intersections[xpos].accumulatedNegative : yMin;
  20900. yMin = yMin > intersections[xpos].accumulatedPositive ? intersections[xpos].accumulatedPositive : yMin;
  20901. yMax = yMax < intersections[xpos].accumulatedNegative ? intersections[xpos].accumulatedNegative : yMax;
  20902. yMax = yMax < intersections[xpos].accumulatedPositive ? intersections[xpos].accumulatedPositive : yMax;
  20903. }
  20904. }
  20905. return { min: yMin, max: yMax };
  20906. };
  20907. module.exports = Bargraph;
  20908. /***/
  20909. }),
  20910. /* 111 */
  20911. /***/
  20912. (function(module, exports, __webpack_require__) {
  20913. "use strict";
  20914. var DOMutil = __webpack_require__(14);
  20915. /**
  20916. *
  20917. * @param {vis.GraphGroup.id} groupId
  20918. * @param {Object} options // TODO: Describe options
  20919. * @constructor Line
  20920. */
  20921. function Line(groupId, options) { // eslint-disable-line no-unused-vars
  20922. }
  20923. Line.calcPath = function(dataset, group) {
  20924. if (dataset != null) {
  20925. if (dataset.length > 0) {
  20926. var d = [];
  20927. // construct path from dataset
  20928. if (group.options.interpolation.enabled == true) {
  20929. d = Line._catmullRom(dataset, group);
  20930. } else {
  20931. d = Line._linear(dataset);
  20932. }
  20933. return d;
  20934. }
  20935. }
  20936. };
  20937. Line.drawIcon = function(group, x, y, iconWidth, iconHeight, framework) {
  20938. var fillHeight = iconHeight * 0.5;
  20939. var path, fillPath;
  20940. var outline = DOMutil.getSVGElement("rect", framework.svgElements, framework.svg);
  20941. outline.setAttributeNS(null, "x", x);
  20942. outline.setAttributeNS(null, "y", y - fillHeight);
  20943. outline.setAttributeNS(null, "width", iconWidth);
  20944. outline.setAttributeNS(null, "height", 2 * fillHeight);
  20945. outline.setAttributeNS(null, "class", "vis-outline");
  20946. path = DOMutil.getSVGElement("path", framework.svgElements, framework.svg);
  20947. path.setAttributeNS(null, "class", group.className);
  20948. if (group.style !== undefined) {
  20949. path.setAttributeNS(null, "style", group.style);
  20950. }
  20951. path.setAttributeNS(null, "d", "M" + x + "," + y + " L" + (x + iconWidth) + "," + y + "");
  20952. if (group.options.shaded.enabled == true) {
  20953. fillPath = DOMutil.getSVGElement("path", framework.svgElements, framework.svg);
  20954. if (group.options.shaded.orientation == 'top') {
  20955. fillPath.setAttributeNS(null, "d", "M" + x + ", " + (y - fillHeight) + "L" + x + "," + y + " L" + (x + iconWidth) + "," + y + " L" + (x + iconWidth) + "," + (y - fillHeight));
  20956. } else {
  20957. fillPath.setAttributeNS(null, "d", "M" + x + "," + y + " " + "L" + x + "," + (y + fillHeight) + " " + "L" + (x + iconWidth) + "," + (y + fillHeight) + "L" + (x + iconWidth) + "," + y);
  20958. }
  20959. fillPath.setAttributeNS(null, "class", group.className + " vis-icon-fill");
  20960. if (group.options.shaded.style !== undefined && group.options.shaded.style !== "") {
  20961. fillPath.setAttributeNS(null, "style", group.options.shaded.style);
  20962. }
  20963. }
  20964. if (group.options.drawPoints.enabled == true) {
  20965. var groupTemplate = {
  20966. style: group.options.drawPoints.style,
  20967. styles: group.options.drawPoints.styles,
  20968. size: group.options.drawPoints.size,
  20969. className: group.className
  20970. };
  20971. DOMutil.drawPoint(x + 0.5 * iconWidth, y, groupTemplate, framework.svgElements, framework.svg);
  20972. }
  20973. };
  20974. Line.drawShading = function(pathArray, group, subPathArray, framework) {
  20975. // append shading to the path
  20976. if (group.options.shaded.enabled == true) {
  20977. var svgHeight = Number(framework.svg.style.height.replace('px', ''));
  20978. var fillPath = DOMutil.getSVGElement('path', framework.svgElements, framework.svg);
  20979. var type = "L";
  20980. if (group.options.interpolation.enabled == true) {
  20981. type = "C";
  20982. }
  20983. var dFill;
  20984. var zero = 0;
  20985. if (group.options.shaded.orientation == 'top') {
  20986. zero = 0;
  20987. } else if (group.options.shaded.orientation == 'bottom') {
  20988. zero = svgHeight;
  20989. } else {
  20990. zero = Math.min(Math.max(0, group.zeroPosition), svgHeight);
  20991. }
  20992. if (group.options.shaded.orientation == 'group' && subPathArray != null && subPathArray != undefined) {
  20993. dFill = 'M' + pathArray[0][0] + "," + pathArray[0][1] + " " + this.serializePath(pathArray, type, false) + ' L' + subPathArray[subPathArray.length - 1][0] + "," + subPathArray[subPathArray.length - 1][1] + " " + this.serializePath(subPathArray, type, true) + subPathArray[0][0] + "," + subPathArray[0][1] + " Z";
  20994. } else {
  20995. dFill = 'M' + pathArray[0][0] + "," + pathArray[0][1] + " " + this.serializePath(pathArray, type, false) + ' V' + zero + ' H' + pathArray[0][0] + " Z";
  20996. }
  20997. fillPath.setAttributeNS(null, 'class', group.className + ' vis-fill');
  20998. if (group.options.shaded.style !== undefined) {
  20999. fillPath.setAttributeNS(null, 'style', group.options.shaded.style);
  21000. }
  21001. fillPath.setAttributeNS(null, 'd', dFill);
  21002. }
  21003. };
  21004. /**
  21005. * draw a line graph
  21006. *
  21007. * @param {Array.<Object>} pathArray
  21008. * @param {vis.Group} group
  21009. * @param {{svg: Object, svgElements: Array.<Object>, options: Object, groups: Array.<vis.Group>}} framework
  21010. */
  21011. Line.draw = function(pathArray, group, framework) {
  21012. if (pathArray != null && pathArray != undefined) {
  21013. var path = DOMutil.getSVGElement('path', framework.svgElements, framework.svg);
  21014. path.setAttributeNS(null, "class", group.className);
  21015. if (group.style !== undefined) {
  21016. path.setAttributeNS(null, "style", group.style);
  21017. }
  21018. var type = "L";
  21019. if (group.options.interpolation.enabled == true) {
  21020. type = "C";
  21021. }
  21022. // copy properties to path for drawing.
  21023. path.setAttributeNS(null, 'd', 'M' + pathArray[0][0] + "," + pathArray[0][1] + " " + this.serializePath(pathArray, type, false));
  21024. }
  21025. };
  21026. Line.serializePath = function(pathArray, type, inverse) {
  21027. if (pathArray.length < 2) {
  21028. //Too little data to create a path.
  21029. return "";
  21030. }
  21031. var d = type;
  21032. var i;
  21033. if (inverse) {
  21034. for (i = pathArray.length - 2; i > 0; i--) {
  21035. d += pathArray[i][0] + "," + pathArray[i][1] + " ";
  21036. }
  21037. } else {
  21038. for (i = 1; i < pathArray.length; i++) {
  21039. d += pathArray[i][0] + "," + pathArray[i][1] + " ";
  21040. }
  21041. }
  21042. return d;
  21043. };
  21044. /**
  21045. * This uses an uniform parametrization of the interpolation algorithm:
  21046. * 'On the Parameterization of Catmull-Rom Curves' by Cem Yuksel et al.
  21047. * @param {Array.<Object>} data
  21048. * @returns {string}
  21049. * @private
  21050. */
  21051. Line._catmullRomUniform = function(data) {
  21052. // catmull rom
  21053. var p0, p1, p2, p3, bp1, bp2;
  21054. var d = [];
  21055. d.push([Math.round(data[0].screen_x), Math.round(data[0].screen_y)]);
  21056. var normalization = 1 / 6;
  21057. var length = data.length;
  21058. for (var i = 0; i < length - 1; i++) {
  21059. p0 = i == 0 ? data[0] : data[i - 1];
  21060. p1 = data[i];
  21061. p2 = data[i + 1];
  21062. p3 = i + 2 < length ? data[i + 2] : p2;
  21063. // Catmull-Rom to Cubic Bezier conversion matrix
  21064. // 0 1 0 0
  21065. // -1/6 1 1/6 0
  21066. // 0 1/6 1 -1/6
  21067. // 0 0 1 0
  21068. // bp0 = { x: p1.x, y: p1.y };
  21069. bp1 = {
  21070. screen_x: (-p0.screen_x + 6 * p1.screen_x + p2.screen_x) * normalization,
  21071. screen_y: (-p0.screen_y + 6 * p1.screen_y + p2.screen_y) * normalization
  21072. };
  21073. bp2 = {
  21074. screen_x: (p1.screen_x + 6 * p2.screen_x - p3.screen_x) * normalization,
  21075. screen_y: (p1.screen_y + 6 * p2.screen_y - p3.screen_y) * normalization
  21076. };
  21077. // bp0 = { x: p2.x, y: p2.y };
  21078. d.push([bp1.screen_x, bp1.screen_y]);
  21079. d.push([bp2.screen_x, bp2.screen_y]);
  21080. d.push([p2.screen_x, p2.screen_y]);
  21081. }
  21082. return d;
  21083. };
  21084. /**
  21085. * This uses either the chordal or centripetal parameterization of the catmull-rom algorithm.
  21086. * By default, the centripetal parameterization is used because this gives the nicest results.
  21087. * These parameterizations are relatively heavy because the distance between 4 points have to be calculated.
  21088. *
  21089. * One optimization can be used to reuse distances since this is a sliding window approach.
  21090. * @param {Array.<Object>} data
  21091. * @param {vis.GraphGroup} group
  21092. * @returns {string}
  21093. * @private
  21094. */
  21095. Line._catmullRom = function(data, group) {
  21096. var alpha = group.options.interpolation.alpha;
  21097. if (alpha == 0 || alpha === undefined) {
  21098. return this._catmullRomUniform(data);
  21099. } else {
  21100. var p0, p1, p2, p3, bp1, bp2, d1, d2, d3, A, B, N, M;
  21101. var d3powA, d2powA, d3pow2A, d2pow2A, d1pow2A, d1powA;
  21102. var d = [];
  21103. d.push([Math.round(data[0].screen_x), Math.round(data[0].screen_y)]);
  21104. var length = data.length;
  21105. for (var i = 0; i < length - 1; i++) {
  21106. p0 = i == 0 ? data[0] : data[i - 1];
  21107. p1 = data[i];
  21108. p2 = data[i + 1];
  21109. p3 = i + 2 < length ? data[i + 2] : p2;
  21110. d1 = Math.sqrt(Math.pow(p0.screen_x - p1.screen_x, 2) + Math.pow(p0.screen_y - p1.screen_y, 2));
  21111. d2 = Math.sqrt(Math.pow(p1.screen_x - p2.screen_x, 2) + Math.pow(p1.screen_y - p2.screen_y, 2));
  21112. d3 = Math.sqrt(Math.pow(p2.screen_x - p3.screen_x, 2) + Math.pow(p2.screen_y - p3.screen_y, 2));
  21113. // Catmull-Rom to Cubic Bezier conversion matrix
  21114. // A = 2d1^2a + 3d1^a * d2^a + d3^2a
  21115. // B = 2d3^2a + 3d3^a * d2^a + d2^2a
  21116. // [ 0 1 0 0 ]
  21117. // [ -d2^2a /N A/N d1^2a /N 0 ]
  21118. // [ 0 d3^2a /M B/M -d2^2a /M ]
  21119. // [ 0 0 1 0 ]
  21120. d3powA = Math.pow(d3, alpha);
  21121. d3pow2A = Math.pow(d3, 2 * alpha);
  21122. d2powA = Math.pow(d2, alpha);
  21123. d2pow2A = Math.pow(d2, 2 * alpha);
  21124. d1powA = Math.pow(d1, alpha);
  21125. d1pow2A = Math.pow(d1, 2 * alpha);
  21126. A = 2 * d1pow2A + 3 * d1powA * d2powA + d2pow2A;
  21127. B = 2 * d3pow2A + 3 * d3powA * d2powA + d2pow2A;
  21128. N = 3 * d1powA * (d1powA + d2powA);
  21129. if (N > 0) {
  21130. N = 1 / N;
  21131. }
  21132. M = 3 * d3powA * (d3powA + d2powA);
  21133. if (M > 0) {
  21134. M = 1 / M;
  21135. }
  21136. bp1 = {
  21137. screen_x: (-d2pow2A * p0.screen_x + A * p1.screen_x + d1pow2A * p2.screen_x) * N,
  21138. screen_y: (-d2pow2A * p0.screen_y + A * p1.screen_y + d1pow2A * p2.screen_y) * N
  21139. };
  21140. bp2 = {
  21141. screen_x: (d3pow2A * p1.screen_x + B * p2.screen_x - d2pow2A * p3.screen_x) * M,
  21142. screen_y: (d3pow2A * p1.screen_y + B * p2.screen_y - d2pow2A * p3.screen_y) * M
  21143. };
  21144. if (bp1.screen_x == 0 && bp1.screen_y == 0) {
  21145. bp1 = p1;
  21146. }
  21147. if (bp2.screen_x == 0 && bp2.screen_y == 0) {
  21148. bp2 = p2;
  21149. }
  21150. d.push([bp1.screen_x, bp1.screen_y]);
  21151. d.push([bp2.screen_x, bp2.screen_y]);
  21152. d.push([p2.screen_x, p2.screen_y]);
  21153. }
  21154. return d;
  21155. }
  21156. };
  21157. /**
  21158. * this generates the SVG path for a linear drawing between datapoints.
  21159. * @param {Array.<Object>} data
  21160. * @returns {string}
  21161. * @private
  21162. */
  21163. Line._linear = function(data) {
  21164. // linear
  21165. var d = [];
  21166. for (var i = 0; i < data.length; i++) {
  21167. d.push([data[i].screen_x, data[i].screen_y]);
  21168. }
  21169. return d;
  21170. };
  21171. module.exports = Line;
  21172. /***/
  21173. }),
  21174. /* 112 */
  21175. /***/
  21176. (function(module, exports, __webpack_require__) {
  21177. "use strict";
  21178. var _keys = __webpack_require__(8);
  21179. var _keys2 = _interopRequireDefault(_keys);
  21180. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  21181. var util = __webpack_require__(2);
  21182. var DOMutil = __webpack_require__(14);
  21183. var Component = __webpack_require__(16);
  21184. /**
  21185. * Legend for Graph2d
  21186. *
  21187. * @param {vis.Graph2d.body} body
  21188. * @param {vis.Graph2d.options} options
  21189. * @param {number} side
  21190. * @param {vis.LineGraph.options} linegraphOptions
  21191. * @constructor Legend
  21192. * @extends Component
  21193. */
  21194. function Legend(body, options, side, linegraphOptions) {
  21195. this.body = body;
  21196. this.defaultOptions = {
  21197. enabled: false,
  21198. icons: true,
  21199. iconSize: 20,
  21200. iconSpacing: 6,
  21201. left: {
  21202. visible: true,
  21203. position: 'top-left' // top/bottom - left,center,right
  21204. },
  21205. right: {
  21206. visible: true,
  21207. position: 'top-right' // top/bottom - left,center,right
  21208. }
  21209. };
  21210. this.side = side;
  21211. this.options = util.extend({}, this.defaultOptions);
  21212. this.linegraphOptions = linegraphOptions;
  21213. this.svgElements = {};
  21214. this.dom = {};
  21215. this.groups = {};
  21216. this.amountOfGroups = 0;
  21217. this._create();
  21218. this.framework = { svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups };
  21219. this.setOptions(options);
  21220. }
  21221. Legend.prototype = new Component();
  21222. Legend.prototype.clear = function() {
  21223. this.groups = {};
  21224. this.amountOfGroups = 0;
  21225. };
  21226. Legend.prototype.addGroup = function(label, graphOptions) {
  21227. // Include a group only if the group option 'excludeFromLegend: false' is not set.
  21228. if (graphOptions.options.excludeFromLegend != true) {
  21229. if (!this.groups.hasOwnProperty(label)) {
  21230. this.groups[label] = graphOptions;
  21231. }
  21232. this.amountOfGroups += 1;
  21233. }
  21234. };
  21235. Legend.prototype.updateGroup = function(label, graphOptions) {
  21236. this.groups[label] = graphOptions;
  21237. };
  21238. Legend.prototype.removeGroup = function(label) {
  21239. if (this.groups.hasOwnProperty(label)) {
  21240. delete this.groups[label];
  21241. this.amountOfGroups -= 1;
  21242. }
  21243. };
  21244. Legend.prototype._create = function() {
  21245. this.dom.frame = document.createElement('div');
  21246. this.dom.frame.className = 'vis-legend';
  21247. this.dom.frame.style.position = "absolute";
  21248. this.dom.frame.style.top = "10px";
  21249. this.dom.frame.style.display = "block";
  21250. this.dom.textArea = document.createElement('div');
  21251. this.dom.textArea.className = 'vis-legend-text';
  21252. this.dom.textArea.style.position = "relative";
  21253. this.dom.textArea.style.top = "0px";
  21254. this.svg = document.createElementNS('http://www.w3.org/2000/svg', "svg");
  21255. this.svg.style.position = 'absolute';
  21256. this.svg.style.top = 0 + 'px';
  21257. this.svg.style.width = this.options.iconSize + 5 + 'px';
  21258. this.svg.style.height = '100%';
  21259. this.dom.frame.appendChild(this.svg);
  21260. this.dom.frame.appendChild(this.dom.textArea);
  21261. };
  21262. /**
  21263. * Hide the component from the DOM
  21264. */
  21265. Legend.prototype.hide = function() {
  21266. // remove the frame containing the items
  21267. if (this.dom.frame.parentNode) {
  21268. this.dom.frame.parentNode.removeChild(this.dom.frame);
  21269. }
  21270. };
  21271. /**
  21272. * Show the component in the DOM (when not already visible).
  21273. */
  21274. Legend.prototype.show = function() {
  21275. // show frame containing the items
  21276. if (!this.dom.frame.parentNode) {
  21277. this.body.dom.center.appendChild(this.dom.frame);
  21278. }
  21279. };
  21280. Legend.prototype.setOptions = function(options) {
  21281. var fields = ['enabled', 'orientation', 'icons', 'left', 'right'];
  21282. util.selectiveDeepExtend(fields, this.options, options);
  21283. };
  21284. Legend.prototype.redraw = function() {
  21285. var activeGroups = 0;
  21286. var groupArray = (0, _keys2['default'])(this.groups);
  21287. groupArray.sort(function(a, b) {
  21288. return a < b ? -1 : 1;
  21289. });
  21290. for (var i = 0; i < groupArray.length; i++) {
  21291. var groupId = groupArray[i];
  21292. if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) {
  21293. activeGroups++;
  21294. }
  21295. }
  21296. if (this.options[this.side].visible == false || this.amountOfGroups == 0 || this.options.enabled == false || activeGroups == 0) {
  21297. this.hide();
  21298. } else {
  21299. this.show();
  21300. if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'bottom-left') {
  21301. this.dom.frame.style.left = '4px';
  21302. this.dom.frame.style.textAlign = "left";
  21303. this.dom.textArea.style.textAlign = "left";
  21304. this.dom.textArea.style.left = this.options.iconSize + 15 + 'px';
  21305. this.dom.textArea.style.right = '';
  21306. this.svg.style.left = 0 + 'px';
  21307. this.svg.style.right = '';
  21308. } else {
  21309. this.dom.frame.style.right = '4px';
  21310. this.dom.frame.style.textAlign = "right";
  21311. this.dom.textArea.style.textAlign = "right";
  21312. this.dom.textArea.style.right = this.options.iconSize + 15 + 'px';
  21313. this.dom.textArea.style.left = '';
  21314. this.svg.style.right = 0 + 'px';
  21315. this.svg.style.left = '';
  21316. }
  21317. if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'top-right') {
  21318. this.dom.frame.style.top = 4 - Number(this.body.dom.center.style.top.replace("px", "")) + 'px';
  21319. this.dom.frame.style.bottom = '';
  21320. } else {
  21321. var scrollableHeight = this.body.domProps.center.height - this.body.domProps.centerContainer.height;
  21322. this.dom.frame.style.bottom = 4 + scrollableHeight + Number(this.body.dom.center.style.top.replace("px", "")) + 'px';
  21323. this.dom.frame.style.top = '';
  21324. }
  21325. if (this.options.icons == false) {
  21326. this.dom.frame.style.width = this.dom.textArea.offsetWidth + 10 + 'px';
  21327. this.dom.textArea.style.right = '';
  21328. this.dom.textArea.style.left = '';
  21329. this.svg.style.width = '0px';
  21330. } else {
  21331. this.dom.frame.style.width = this.options.iconSize + 15 + this.dom.textArea.offsetWidth + 10 + 'px';
  21332. this.drawLegendIcons();
  21333. }
  21334. var content = '';
  21335. for (i = 0; i < groupArray.length; i++) {
  21336. groupId = groupArray[i];
  21337. if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) {
  21338. content += this.groups[groupId].content + '<br />';
  21339. }
  21340. }
  21341. this.dom.textArea.innerHTML = content;
  21342. this.dom.textArea.style.lineHeight = 0.75 * this.options.iconSize + this.options.iconSpacing + 'px';
  21343. }
  21344. };
  21345. Legend.prototype.drawLegendIcons = function() {
  21346. if (this.dom.frame.parentNode) {
  21347. var groupArray = (0, _keys2['default'])(this.groups);
  21348. groupArray.sort(function(a, b) {
  21349. return a < b ? -1 : 1;
  21350. });
  21351. // this resets the elements so the order is maintained
  21352. DOMutil.resetElements(this.svgElements);
  21353. var padding = window.getComputedStyle(this.dom.frame).paddingTop;
  21354. var iconOffset = Number(padding.replace('px', ''));
  21355. var x = iconOffset;
  21356. var iconWidth = this.options.iconSize;
  21357. var iconHeight = 0.75 * this.options.iconSize;
  21358. var y = iconOffset + 0.5 * iconHeight + 3;
  21359. this.svg.style.width = iconWidth + 5 + iconOffset + 'px';
  21360. for (var i = 0; i < groupArray.length; i++) {
  21361. var groupId = groupArray[i];
  21362. if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) {
  21363. this.groups[groupId].getLegend(iconWidth, iconHeight, this.framework, x, y);
  21364. y += iconHeight + this.options.iconSpacing;
  21365. }
  21366. }
  21367. }
  21368. };
  21369. module.exports = Legend;
  21370. /***/
  21371. }),
  21372. /* 113 */
  21373. /***/
  21374. (function(module, exports, __webpack_require__) {
  21375. "use strict";
  21376. Object.defineProperty(exports, "__esModule", {
  21377. value: true
  21378. });
  21379. /**
  21380. * This object contains all possible options. It will check if the types are correct, if required if the option is one
  21381. * of the allowed values.
  21382. *
  21383. * __any__ means that the name of the property does not matter.
  21384. * __type__ is a required field for all objects and contains the allowed types of all objects
  21385. */
  21386. var string = 'string';
  21387. var bool = 'boolean';
  21388. var number = 'number';
  21389. var array = 'array';
  21390. var date = 'date';
  21391. var object = 'object'; // should only be in a __type__ property
  21392. var dom = 'dom';
  21393. var moment = 'moment';
  21394. var any = 'any';
  21395. var allOptions = {
  21396. configure: {
  21397. enabled: { 'boolean': bool },
  21398. filter: { 'boolean': bool, 'function': 'function' },
  21399. container: { dom: dom },
  21400. __type__: { object: object, 'boolean': bool, 'function': 'function' }
  21401. },
  21402. //globals :
  21403. yAxisOrientation: { string: ['left', 'right'] },
  21404. defaultGroup: { string: string },
  21405. sort: { 'boolean': bool },
  21406. sampling: { 'boolean': bool },
  21407. stack: { 'boolean': bool },
  21408. graphHeight: { string: string, number: number },
  21409. shaded: {
  21410. enabled: { 'boolean': bool },
  21411. orientation: { string: ['bottom', 'top', 'zero', 'group'] }, // top, bottom, zero, group
  21412. groupId: { object: object },
  21413. __type__: { 'boolean': bool, object: object }
  21414. },
  21415. style: { string: ['line', 'bar', 'points'] }, // line, bar
  21416. barChart: {
  21417. width: { number: number },
  21418. minWidth: { number: number },
  21419. sideBySide: { 'boolean': bool },
  21420. align: { string: ['left', 'center', 'right'] },
  21421. __type__: { object: object }
  21422. },
  21423. interpolation: {
  21424. enabled: { 'boolean': bool },
  21425. parametrization: { string: ['centripetal', 'chordal', 'uniform'] }, // uniform (alpha = 0.0), chordal (alpha = 1.0), centripetal (alpha = 0.5)
  21426. alpha: { number: number },
  21427. __type__: { object: object, 'boolean': bool }
  21428. },
  21429. drawPoints: {
  21430. enabled: { 'boolean': bool },
  21431. onRender: { 'function': 'function' },
  21432. size: { number: number },
  21433. style: { string: ['square', 'circle'] }, // square, circle
  21434. __type__: { object: object, 'boolean': bool, 'function': 'function' }
  21435. },
  21436. dataAxis: {
  21437. showMinorLabels: { 'boolean': bool },
  21438. showMajorLabels: { 'boolean': bool },
  21439. icons: { 'boolean': bool },
  21440. width: { string: string, number: number },
  21441. visible: { 'boolean': bool },
  21442. alignZeros: { 'boolean': bool },
  21443. left: {
  21444. range: { min: { number: number, 'undefined': 'undefined' }, max: { number: number, 'undefined': 'undefined' }, __type__: { object: object } },
  21445. format: { 'function': 'function' },
  21446. title: { text: { string: string, number: number, 'undefined': 'undefined' }, style: { string: string, 'undefined': 'undefined' }, __type__: { object: object } },
  21447. __type__: { object: object }
  21448. },
  21449. right: {
  21450. range: { min: { number: number, 'undefined': 'undefined' }, max: { number: number, 'undefined': 'undefined' }, __type__: { object: object } },
  21451. format: { 'function': 'function' },
  21452. title: { text: { string: string, number: number, 'undefined': 'undefined' }, style: { string: string, 'undefined': 'undefined' }, __type__: { object: object } },
  21453. __type__: { object: object }
  21454. },
  21455. __type__: { object: object }
  21456. },
  21457. legend: {
  21458. enabled: { 'boolean': bool },
  21459. icons: { 'boolean': bool },
  21460. left: {
  21461. visible: { 'boolean': bool },
  21462. position: { string: ['top-right', 'bottom-right', 'top-left', 'bottom-left'] },
  21463. __type__: { object: object }
  21464. },
  21465. right: {
  21466. visible: { 'boolean': bool },
  21467. position: { string: ['top-right', 'bottom-right', 'top-left', 'bottom-left'] },
  21468. __type__: { object: object }
  21469. },
  21470. __type__: { object: object, 'boolean': bool }
  21471. },
  21472. groups: {
  21473. visibility: { any: any },
  21474. __type__: { object: object }
  21475. },
  21476. autoResize: { 'boolean': bool },
  21477. throttleRedraw: { number: number }, // TODO: DEPRICATED see https://github.com/almende/vis/issues/2511
  21478. clickToUse: { 'boolean': bool },
  21479. end: { number: number, date: date, string: string, moment: moment },
  21480. format: {
  21481. minorLabels: {
  21482. millisecond: { string: string, 'undefined': 'undefined' },
  21483. second: { string: string, 'undefined': 'undefined' },
  21484. minute: { string: string, 'undefined': 'undefined' },
  21485. hour: { string: string, 'undefined': 'undefined' },
  21486. weekday: { string: string, 'undefined': 'undefined' },
  21487. day: { string: string, 'undefined': 'undefined' },
  21488. month: { string: string, 'undefined': 'undefined' },
  21489. year: { string: string, 'undefined': 'undefined' },
  21490. __type__: { object: object }
  21491. },
  21492. majorLabels: {
  21493. millisecond: { string: string, 'undefined': 'undefined' },
  21494. second: { string: string, 'undefined': 'undefined' },
  21495. minute: { string: string, 'undefined': 'undefined' },
  21496. hour: { string: string, 'undefined': 'undefined' },
  21497. weekday: { string: string, 'undefined': 'undefined' },
  21498. day: { string: string, 'undefined': 'undefined' },
  21499. month: { string: string, 'undefined': 'undefined' },
  21500. year: { string: string, 'undefined': 'undefined' },
  21501. __type__: { object: object }
  21502. },
  21503. __type__: { object: object }
  21504. },
  21505. moment: { 'function': 'function' },
  21506. height: { string: string, number: number },
  21507. hiddenDates: {
  21508. start: { date: date, number: number, string: string, moment: moment },
  21509. end: { date: date, number: number, string: string, moment: moment },
  21510. repeat: { string: string },
  21511. __type__: { object: object, array: array }
  21512. },
  21513. locale: { string: string },
  21514. locales: {
  21515. __any__: { any: any },
  21516. __type__: { object: object }
  21517. },
  21518. max: { date: date, number: number, string: string, moment: moment },
  21519. maxHeight: { number: number, string: string },
  21520. maxMinorChars: { number: number },
  21521. min: { date: date, number: number, string: string, moment: moment },
  21522. minHeight: { number: number, string: string },
  21523. moveable: { 'boolean': bool },
  21524. multiselect: { 'boolean': bool },
  21525. orientation: { string: string },
  21526. showCurrentTime: { 'boolean': bool },
  21527. showMajorLabels: { 'boolean': bool },
  21528. showMinorLabels: { 'boolean': bool },
  21529. start: { date: date, number: number, string: string, moment: moment },
  21530. timeAxis: {
  21531. scale: { string: string, 'undefined': 'undefined' },
  21532. step: { number: number, 'undefined': 'undefined' },
  21533. __type__: { object: object }
  21534. },
  21535. width: { string: string, number: number },
  21536. zoomable: { 'boolean': bool },
  21537. zoomKey: { string: ['ctrlKey', 'altKey', 'metaKey', ''] },
  21538. zoomMax: { number: number },
  21539. zoomMin: { number: number },
  21540. zIndex: { number: number },
  21541. __type__: { object: object }
  21542. };
  21543. var configureOptions = {
  21544. global: {
  21545. //yAxisOrientation: ['left','right'], // TDOO: enable as soon as Grahp2d doesn't crash when changing this on the fly
  21546. sort: true,
  21547. sampling: true,
  21548. stack: false,
  21549. shaded: {
  21550. enabled: false,
  21551. orientation: ['zero', 'top', 'bottom', 'group'] // zero, top, bottom
  21552. },
  21553. style: ['line', 'bar', 'points'], // line, bar
  21554. barChart: {
  21555. width: [50, 5, 100, 5],
  21556. minWidth: [50, 5, 100, 5],
  21557. sideBySide: false,
  21558. align: ['left', 'center', 'right'] // left, center, right
  21559. },
  21560. interpolation: {
  21561. enabled: true,
  21562. parametrization: ['centripetal', 'chordal', 'uniform'] // uniform (alpha = 0.0), chordal (alpha = 1.0), centripetal (alpha = 0.5)
  21563. },
  21564. drawPoints: {
  21565. enabled: true,
  21566. size: [6, 2, 30, 1],
  21567. style: ['square', 'circle'] // square, circle
  21568. },
  21569. dataAxis: {
  21570. showMinorLabels: true,
  21571. showMajorLabels: true,
  21572. icons: false,
  21573. width: [40, 0, 200, 1],
  21574. visible: true,
  21575. alignZeros: true,
  21576. left: {
  21577. //range: {min:'undefined': 'undefined'ined,max:'undefined': 'undefined'ined},
  21578. //format: function (value) {return value;},
  21579. title: { text: '', style: '' }
  21580. },
  21581. right: {
  21582. //range: {min:'undefined': 'undefined'ined,max:'undefined': 'undefined'ined},
  21583. //format: function (value) {return value;},
  21584. title: { text: '', style: '' }
  21585. }
  21586. },
  21587. legend: {
  21588. enabled: false,
  21589. icons: true,
  21590. left: {
  21591. visible: true,
  21592. position: ['top-right', 'bottom-right', 'top-left', 'bottom-left'] // top/bottom - left,right
  21593. },
  21594. right: {
  21595. visible: true,
  21596. position: ['top-right', 'bottom-right', 'top-left', 'bottom-left'] // top/bottom - left,right
  21597. }
  21598. },
  21599. autoResize: true,
  21600. clickToUse: false,
  21601. end: '',
  21602. format: {
  21603. minorLabels: {
  21604. millisecond: 'SSS',
  21605. second: 's',
  21606. minute: 'HH:mm',
  21607. hour: 'HH:mm',
  21608. weekday: 'ddd D',
  21609. day: 'D',
  21610. month: 'MMM',
  21611. year: 'YYYY'
  21612. },
  21613. majorLabels: {
  21614. millisecond: 'HH:mm:ss',
  21615. second: 'D MMMM HH:mm',
  21616. minute: 'ddd D MMMM',
  21617. hour: 'ddd D MMMM',
  21618. weekday: 'MMMM YYYY',
  21619. day: 'MMMM YYYY',
  21620. month: 'YYYY',
  21621. year: ''
  21622. }
  21623. },
  21624. height: '',
  21625. locale: '',
  21626. max: '',
  21627. maxHeight: '',
  21628. maxMinorChars: [7, 0, 20, 1],
  21629. min: '',
  21630. minHeight: '',
  21631. moveable: true,
  21632. orientation: ['both', 'bottom', 'top'],
  21633. showCurrentTime: false,
  21634. showMajorLabels: true,
  21635. showMinorLabels: true,
  21636. start: '',
  21637. width: '100%',
  21638. zoomable: true,
  21639. zoomKey: ['ctrlKey', 'altKey', 'metaKey', ''],
  21640. zoomMax: [315360000000000, 10, 315360000000000, 1],
  21641. zoomMin: [10, 10, 315360000000000, 1],
  21642. zIndex: 0
  21643. }
  21644. };
  21645. exports.allOptions = allOptions;
  21646. exports.configureOptions = configureOptions;
  21647. /***/
  21648. }),
  21649. /* 114 */
  21650. /***/
  21651. (function(module, exports, __webpack_require__) {
  21652. "use strict";
  21653. var _create = __webpack_require__(29);
  21654. var _create2 = _interopRequireDefault(_create);
  21655. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  21656. /**
  21657. * Parse a text source containing data in DOT language into a JSON object.
  21658. * The object contains two lists: one with nodes and one with edges.
  21659. *
  21660. * DOT language reference: http://www.graphviz.org/doc/info/lang.html
  21661. *
  21662. * DOT language attributes: http://graphviz.org/content/attrs
  21663. *
  21664. * @param {string} data Text containing a graph in DOT-notation
  21665. * @return {Object} graph An object containing two parameters:
  21666. * {Object[]} nodes
  21667. * {Object[]} edges
  21668. *
  21669. * -------------------------------------------
  21670. * TODO
  21671. * ====
  21672. *
  21673. * For label handling, this is an incomplete implementation. From docs (quote #3015):
  21674. *
  21675. * > the escape sequences "\n", "\l" and "\r" divide the label into lines, centered,
  21676. * > left-justified, and right-justified, respectively.
  21677. *
  21678. * Source: http://www.graphviz.org/content/attrs#kescString
  21679. *
  21680. * > As another aid for readability, dot allows double-quoted strings to span multiple physical
  21681. * > lines using the standard C convention of a backslash immediately preceding a newline
  21682. * > character
  21683. * > In addition, double-quoted strings can be concatenated using a '+' operator.
  21684. * > As HTML strings can contain newline characters, which are used solely for formatting,
  21685. * > the language does not allow escaped newlines or concatenation operators to be used
  21686. * > within them.
  21687. *
  21688. * - Currently, only '\\n' is handled
  21689. * - Note that text explicitly says 'labels'; the dot parser currently handles escape
  21690. * sequences in **all** strings.
  21691. */
  21692. function parseDOT(data) {
  21693. dot = data;
  21694. return parseGraph();
  21695. }
  21696. // mapping of attributes from DOT (the keys) to vis.js (the values)
  21697. var NODE_ATTR_MAPPING = {
  21698. 'fontsize': 'font.size',
  21699. 'fontcolor': 'font.color',
  21700. 'labelfontcolor': 'font.color',
  21701. 'fontname': 'font.face',
  21702. 'color': ['color.border', 'color.background'],
  21703. 'fillcolor': 'color.background',
  21704. 'tooltip': 'title',
  21705. 'labeltooltip': 'title'
  21706. };
  21707. var EDGE_ATTR_MAPPING = (0, _create2['default'])(NODE_ATTR_MAPPING);
  21708. EDGE_ATTR_MAPPING.color = 'color.color';
  21709. EDGE_ATTR_MAPPING.style = 'dashes';
  21710. // token types enumeration
  21711. var TOKENTYPE = {
  21712. NULL: 0,
  21713. DELIMITER: 1,
  21714. IDENTIFIER: 2,
  21715. UNKNOWN: 3
  21716. };
  21717. // map with all delimiters
  21718. var DELIMITERS = {
  21719. '{': true,
  21720. '}': true,
  21721. '[': true,
  21722. ']': true,
  21723. ';': true,
  21724. '=': true,
  21725. ',': true,
  21726. '->': true,
  21727. '--': true
  21728. };
  21729. var dot = ''; // current dot file
  21730. var index = 0; // current index in dot file
  21731. var c = ''; // current token character in expr
  21732. var token = ''; // current token
  21733. var tokenType = TOKENTYPE.NULL; // type of the token
  21734. /**
  21735. * Get the first character from the dot file.
  21736. * The character is stored into the char c. If the end of the dot file is
  21737. * reached, the function puts an empty string in c.
  21738. */
  21739. function first() {
  21740. index = 0;
  21741. c = dot.charAt(0);
  21742. }
  21743. /**
  21744. * Get the next character from the dot file.
  21745. * The character is stored into the char c. If the end of the dot file is
  21746. * reached, the function puts an empty string in c.
  21747. */
  21748. function next() {
  21749. index++;
  21750. c = dot.charAt(index);
  21751. }
  21752. /**
  21753. * Preview the next character from the dot file.
  21754. * @return {string} cNext
  21755. */
  21756. function nextPreview() {
  21757. return dot.charAt(index + 1);
  21758. }
  21759. var regexAlphaNumeric = /[a-zA-Z_0-9.:#]/;
  21760. /**
  21761. * Test whether given character is alphabetic or numeric
  21762. * @param {string} c
  21763. * @return {Boolean} isAlphaNumeric
  21764. */
  21765. function isAlphaNumeric(c) {
  21766. return regexAlphaNumeric.test(c);
  21767. }
  21768. /**
  21769. * Merge all options of object b into object b
  21770. * @param {Object} a
  21771. * @param {Object} b
  21772. * @return {Object} a
  21773. */
  21774. function merge(a, b) {
  21775. if (!a) {
  21776. a = {};
  21777. }
  21778. if (b) {
  21779. for (var name in b) {
  21780. if (b.hasOwnProperty(name)) {
  21781. a[name] = b[name];
  21782. }
  21783. }
  21784. }
  21785. return a;
  21786. }
  21787. /**
  21788. * Set a value in an object, where the provided parameter name can be a
  21789. * path with nested parameters. For example:
  21790. *
  21791. * var obj = {a: 2};
  21792. * setValue(obj, 'b.c', 3); // obj = {a: 2, b: {c: 3}}
  21793. *
  21794. * @param {Object} obj
  21795. * @param {string} path A parameter name or dot-separated parameter path,
  21796. * like "color.highlight.border".
  21797. * @param {*} value
  21798. */
  21799. function setValue(obj, path, value) {
  21800. var keys = path.split('.');
  21801. var o = obj;
  21802. while (keys.length) {
  21803. var key = keys.shift();
  21804. if (keys.length) {
  21805. // this isn't the end point
  21806. if (!o[key]) {
  21807. o[key] = {};
  21808. }
  21809. o = o[key];
  21810. } else {
  21811. // this is the end point
  21812. o[key] = value;
  21813. }
  21814. }
  21815. }
  21816. /**
  21817. * Add a node to a graph object. If there is already a node with
  21818. * the same id, their attributes will be merged.
  21819. * @param {Object} graph
  21820. * @param {Object} node
  21821. */
  21822. function addNode(graph, node) {
  21823. var i, len;
  21824. var current = null;
  21825. // find root graph (in case of subgraph)
  21826. var graphs = [graph]; // list with all graphs from current graph to root graph
  21827. var root = graph;
  21828. while (root.parent) {
  21829. graphs.push(root.parent);
  21830. root = root.parent;
  21831. }
  21832. // find existing node (at root level) by its id
  21833. if (root.nodes) {
  21834. for (i = 0, len = root.nodes.length; i < len; i++) {
  21835. if (node.id === root.nodes[i].id) {
  21836. current = root.nodes[i];
  21837. break;
  21838. }
  21839. }
  21840. }
  21841. if (!current) {
  21842. // this is a new node
  21843. current = {
  21844. id: node.id
  21845. };
  21846. if (graph.node) {
  21847. // clone default attributes
  21848. current.attr = merge(current.attr, graph.node);
  21849. }
  21850. }
  21851. // add node to this (sub)graph and all its parent graphs
  21852. for (i = graphs.length - 1; i >= 0; i--) {
  21853. var g = graphs[i];
  21854. if (!g.nodes) {
  21855. g.nodes = [];
  21856. }
  21857. if (g.nodes.indexOf(current) === -1) {
  21858. g.nodes.push(current);
  21859. }
  21860. }
  21861. // merge attributes
  21862. if (node.attr) {
  21863. current.attr = merge(current.attr, node.attr);
  21864. }
  21865. }
  21866. /**
  21867. * Add an edge to a graph object
  21868. * @param {Object} graph
  21869. * @param {Object} edge
  21870. */
  21871. function addEdge(graph, edge) {
  21872. if (!graph.edges) {
  21873. graph.edges = [];
  21874. }
  21875. graph.edges.push(edge);
  21876. if (graph.edge) {
  21877. var attr = merge({}, graph.edge); // clone default attributes
  21878. edge.attr = merge(attr, edge.attr); // merge attributes
  21879. }
  21880. }
  21881. /**
  21882. * Create an edge to a graph object
  21883. * @param {Object} graph
  21884. * @param {string | number | Object} from
  21885. * @param {string | number | Object} to
  21886. * @param {string} type
  21887. * @param {Object | null} attr
  21888. * @return {Object} edge
  21889. */
  21890. function createEdge(graph, from, to, type, attr) {
  21891. var edge = {
  21892. from: from,
  21893. to: to,
  21894. type: type
  21895. };
  21896. if (graph.edge) {
  21897. edge.attr = merge({}, graph.edge); // clone default attributes
  21898. }
  21899. edge.attr = merge(edge.attr || {}, attr); // merge attributes
  21900. return edge;
  21901. }
  21902. /**
  21903. * Get next token in the current dot file.
  21904. * The token and token type are available as token and tokenType
  21905. */
  21906. function getToken() {
  21907. tokenType = TOKENTYPE.NULL;
  21908. token = '';
  21909. // skip over whitespaces
  21910. while (c === ' ' || c === '\t' || c === '\n' || c === '\r') {
  21911. // space, tab, enter
  21912. next();
  21913. }
  21914. do {
  21915. var isComment = false;
  21916. // skip comment
  21917. if (c === '#') {
  21918. // find the previous non-space character
  21919. var i = index - 1;
  21920. while (dot.charAt(i) === ' ' || dot.charAt(i) === '\t') {
  21921. i--;
  21922. }
  21923. if (dot.charAt(i) === '\n' || dot.charAt(i) === '') {
  21924. // the # is at the start of a line, this is indeed a line comment
  21925. while (c != '' && c != '\n') {
  21926. next();
  21927. }
  21928. isComment = true;
  21929. }
  21930. }
  21931. if (c === '/' && nextPreview() === '/') {
  21932. // skip line comment
  21933. while (c != '' && c != '\n') {
  21934. next();
  21935. }
  21936. isComment = true;
  21937. }
  21938. if (c === '/' && nextPreview() === '*') {
  21939. // skip block comment
  21940. while (c != '') {
  21941. if (c === '*' && nextPreview() === '/') {
  21942. // end of block comment found. skip these last two characters
  21943. next();
  21944. next();
  21945. break;
  21946. } else {
  21947. next();
  21948. }
  21949. }
  21950. isComment = true;
  21951. }
  21952. // skip over whitespaces
  21953. while (c === ' ' || c === '\t' || c === '\n' || c === '\r') {
  21954. // space, tab, enter
  21955. next();
  21956. }
  21957. } while (isComment);
  21958. // check for end of dot file
  21959. if (c === '') {
  21960. // token is still empty
  21961. tokenType = TOKENTYPE.DELIMITER;
  21962. return;
  21963. }
  21964. // check for delimiters consisting of 2 characters
  21965. var c2 = c + nextPreview();
  21966. if (DELIMITERS[c2]) {
  21967. tokenType = TOKENTYPE.DELIMITER;
  21968. token = c2;
  21969. next();
  21970. next();
  21971. return;
  21972. }
  21973. // check for delimiters consisting of 1 character
  21974. if (DELIMITERS[c]) {
  21975. tokenType = TOKENTYPE.DELIMITER;
  21976. token = c;
  21977. next();
  21978. return;
  21979. }
  21980. // check for an identifier (number or string)
  21981. // TODO: more precise parsing of numbers/strings (and the port separator ':')
  21982. if (isAlphaNumeric(c) || c === '-') {
  21983. token += c;
  21984. next();
  21985. while (isAlphaNumeric(c)) {
  21986. token += c;
  21987. next();
  21988. }
  21989. if (token === 'false') {
  21990. token = false; // convert to boolean
  21991. } else if (token === 'true') {
  21992. token = true; // convert to boolean
  21993. } else if (!isNaN(Number(token))) {
  21994. token = Number(token); // convert to number
  21995. }
  21996. tokenType = TOKENTYPE.IDENTIFIER;
  21997. return;
  21998. }
  21999. // check for a string enclosed by double quotes
  22000. if (c === '"') {
  22001. next();
  22002. while (c != '' && (c != '"' || c === '"' && nextPreview() === '"')) {
  22003. if (c === '"') {
  22004. // skip the escape character
  22005. token += c;
  22006. next();
  22007. } else if (c === '\\' && nextPreview() === 'n') {
  22008. // Honor a newline escape sequence
  22009. token += '\n';
  22010. next();
  22011. } else {
  22012. token += c;
  22013. }
  22014. next();
  22015. }
  22016. if (c != '"') {
  22017. throw newSyntaxError('End of string " expected');
  22018. }
  22019. next();
  22020. tokenType = TOKENTYPE.IDENTIFIER;
  22021. return;
  22022. }
  22023. // something unknown is found, wrong characters, a syntax error
  22024. tokenType = TOKENTYPE.UNKNOWN;
  22025. while (c != '') {
  22026. token += c;
  22027. next();
  22028. }
  22029. throw new SyntaxError('Syntax error in part "' + chop(token, 30) + '"');
  22030. }
  22031. /**
  22032. * Parse a graph.
  22033. * @returns {Object} graph
  22034. */
  22035. function parseGraph() {
  22036. var graph = {};
  22037. first();
  22038. getToken();
  22039. // optional strict keyword
  22040. if (token === 'strict') {
  22041. graph.strict = true;
  22042. getToken();
  22043. }
  22044. // graph or digraph keyword
  22045. if (token === 'graph' || token === 'digraph') {
  22046. graph.type = token;
  22047. getToken();
  22048. }
  22049. // optional graph id
  22050. if (tokenType === TOKENTYPE.IDENTIFIER) {
  22051. graph.id = token;
  22052. getToken();
  22053. }
  22054. // open angle bracket
  22055. if (token != '{') {
  22056. throw newSyntaxError('Angle bracket { expected');
  22057. }
  22058. getToken();
  22059. // statements
  22060. parseStatements(graph);
  22061. // close angle bracket
  22062. if (token != '}') {
  22063. throw newSyntaxError('Angle bracket } expected');
  22064. }
  22065. getToken();
  22066. // end of file
  22067. if (token !== '') {
  22068. throw newSyntaxError('End of file expected');
  22069. }
  22070. getToken();
  22071. // remove temporary default options
  22072. delete graph.node;
  22073. delete graph.edge;
  22074. delete graph.graph;
  22075. return graph;
  22076. }
  22077. /**
  22078. * Parse a list with statements.
  22079. * @param {Object} graph
  22080. */
  22081. function parseStatements(graph) {
  22082. while (token !== '' && token != '}') {
  22083. parseStatement(graph);
  22084. if (token === ';') {
  22085. getToken();
  22086. }
  22087. }
  22088. }
  22089. /**
  22090. * Parse a single statement. Can be a an attribute statement, node
  22091. * statement, a series of node statements and edge statements, or a
  22092. * parameter.
  22093. * @param {Object} graph
  22094. */
  22095. function parseStatement(graph) {
  22096. // parse subgraph
  22097. var subgraph = parseSubgraph(graph);
  22098. if (subgraph) {
  22099. // edge statements
  22100. parseEdge(graph, subgraph);
  22101. return;
  22102. }
  22103. // parse an attribute statement
  22104. var attr = parseAttributeStatement(graph);
  22105. if (attr) {
  22106. return;
  22107. }
  22108. // parse node
  22109. if (tokenType != TOKENTYPE.IDENTIFIER) {
  22110. throw newSyntaxError('Identifier expected');
  22111. }
  22112. var id = token; // id can be a string or a number
  22113. getToken();
  22114. if (token === '=') {
  22115. // id statement
  22116. getToken();
  22117. if (tokenType != TOKENTYPE.IDENTIFIER) {
  22118. throw newSyntaxError('Identifier expected');
  22119. }
  22120. graph[id] = token;
  22121. getToken();
  22122. // TODO: implement comma separated list with "a_list: ID=ID [','] [a_list] "
  22123. } else {
  22124. parseNodeStatement(graph, id);
  22125. }
  22126. }
  22127. /**
  22128. * Parse a subgraph
  22129. * @param {Object} graph parent graph object
  22130. * @return {Object | null} subgraph
  22131. */
  22132. function parseSubgraph(graph) {
  22133. var subgraph = null;
  22134. // optional subgraph keyword
  22135. if (token === 'subgraph') {
  22136. subgraph = {};
  22137. subgraph.type = 'subgraph';
  22138. getToken();
  22139. // optional graph id
  22140. if (tokenType === TOKENTYPE.IDENTIFIER) {
  22141. subgraph.id = token;
  22142. getToken();
  22143. }
  22144. }
  22145. // open angle bracket
  22146. if (token === '{') {
  22147. getToken();
  22148. if (!subgraph) {
  22149. subgraph = {};
  22150. }
  22151. subgraph.parent = graph;
  22152. subgraph.node = graph.node;
  22153. subgraph.edge = graph.edge;
  22154. subgraph.graph = graph.graph;
  22155. // statements
  22156. parseStatements(subgraph);
  22157. // close angle bracket
  22158. if (token != '}') {
  22159. throw newSyntaxError('Angle bracket } expected');
  22160. }
  22161. getToken();
  22162. // remove temporary default options
  22163. delete subgraph.node;
  22164. delete subgraph.edge;
  22165. delete subgraph.graph;
  22166. delete subgraph.parent;
  22167. // register at the parent graph
  22168. if (!graph.subgraphs) {
  22169. graph.subgraphs = [];
  22170. }
  22171. graph.subgraphs.push(subgraph);
  22172. }
  22173. return subgraph;
  22174. }
  22175. /**
  22176. * parse an attribute statement like "node [shape=circle fontSize=16]".
  22177. * Available keywords are 'node', 'edge', 'graph'.
  22178. * The previous list with default attributes will be replaced
  22179. * @param {Object} graph
  22180. * @returns {String | null} keyword Returns the name of the parsed attribute
  22181. * (node, edge, graph), or null if nothing
  22182. * is parsed.
  22183. */
  22184. function parseAttributeStatement(graph) {
  22185. // attribute statements
  22186. if (token === 'node') {
  22187. getToken();
  22188. // node attributes
  22189. graph.node = parseAttributeList();
  22190. return 'node';
  22191. } else if (token === 'edge') {
  22192. getToken();
  22193. // edge attributes
  22194. graph.edge = parseAttributeList();
  22195. return 'edge';
  22196. } else if (token === 'graph') {
  22197. getToken();
  22198. // graph attributes
  22199. graph.graph = parseAttributeList();
  22200. return 'graph';
  22201. }
  22202. return null;
  22203. }
  22204. /**
  22205. * parse a node statement
  22206. * @param {Object} graph
  22207. * @param {string | number} id
  22208. */
  22209. function parseNodeStatement(graph, id) {
  22210. // node statement
  22211. var node = {
  22212. id: id
  22213. };
  22214. var attr = parseAttributeList();
  22215. if (attr) {
  22216. node.attr = attr;
  22217. }
  22218. addNode(graph, node);
  22219. // edge statements
  22220. parseEdge(graph, id);
  22221. }
  22222. /**
  22223. * Parse an edge or a series of edges
  22224. * @param {Object} graph
  22225. * @param {string | number} from Id of the from node
  22226. */
  22227. function parseEdge(graph, from) {
  22228. while (token === '->' || token === '--') {
  22229. var to;
  22230. var type = token;
  22231. getToken();
  22232. var subgraph = parseSubgraph(graph);
  22233. if (subgraph) {
  22234. to = subgraph;
  22235. } else {
  22236. if (tokenType != TOKENTYPE.IDENTIFIER) {
  22237. throw newSyntaxError('Identifier or subgraph expected');
  22238. }
  22239. to = token;
  22240. addNode(graph, {
  22241. id: to
  22242. });
  22243. getToken();
  22244. }
  22245. // parse edge attributes
  22246. var attr = parseAttributeList();
  22247. // create edge
  22248. var edge = createEdge(graph, from, to, type, attr);
  22249. addEdge(graph, edge);
  22250. from = to;
  22251. }
  22252. }
  22253. /**
  22254. * Parse a set with attributes,
  22255. * for example [label="1.000", shape=solid]
  22256. * @return {Object | null} attr
  22257. */
  22258. function parseAttributeList() {
  22259. var attr = null;
  22260. // edge styles of dot and vis
  22261. var edgeStyles = {
  22262. 'dashed': true,
  22263. 'solid': false,
  22264. 'dotted': [1, 5]
  22265. };
  22266. while (token === '[') {
  22267. getToken();
  22268. attr = {};
  22269. while (token !== '' && token != ']') {
  22270. if (tokenType != TOKENTYPE.IDENTIFIER) {
  22271. throw newSyntaxError('Attribute name expected');
  22272. }
  22273. var name = token;
  22274. getToken();
  22275. if (token != '=') {
  22276. throw newSyntaxError('Equal sign = expected');
  22277. }
  22278. getToken();
  22279. if (tokenType != TOKENTYPE.IDENTIFIER) {
  22280. throw newSyntaxError('Attribute value expected');
  22281. }
  22282. var value = token;
  22283. // convert from dot style to vis
  22284. if (name === 'style') {
  22285. value = edgeStyles[value];
  22286. }
  22287. setValue(attr, name, value); // name can be a path
  22288. getToken();
  22289. if (token == ',') {
  22290. getToken();
  22291. }
  22292. }
  22293. if (token != ']') {
  22294. throw newSyntaxError('Bracket ] expected');
  22295. }
  22296. getToken();
  22297. }
  22298. return attr;
  22299. }
  22300. /**
  22301. * Create a syntax error with extra information on current token and index.
  22302. * @param {string} message
  22303. * @returns {SyntaxError} err
  22304. */
  22305. function newSyntaxError(message) {
  22306. return new SyntaxError(message + ', got "' + chop(token, 30) + '" (char ' + index + ')');
  22307. }
  22308. /**
  22309. * Chop off text after a maximum length
  22310. * @param {string} text
  22311. * @param {number} maxLength
  22312. * @returns {String}
  22313. */
  22314. function chop(text, maxLength) {
  22315. return text.length <= maxLength ? text : text.substr(0, 27) + '...';
  22316. }
  22317. /**
  22318. * Execute a function fn for each pair of elements in two arrays
  22319. * @param {Array | *} array1
  22320. * @param {Array | *} array2
  22321. * @param {function} fn
  22322. */
  22323. function forEach2(array1, array2, fn) {
  22324. if (Array.isArray(array1)) {
  22325. array1.forEach(function(elem1) {
  22326. if (Array.isArray(array2)) {
  22327. array2.forEach(function(elem2) {
  22328. fn(elem1, elem2);
  22329. });
  22330. } else {
  22331. fn(elem1, array2);
  22332. }
  22333. });
  22334. } else {
  22335. if (Array.isArray(array2)) {
  22336. array2.forEach(function(elem2) {
  22337. fn(array1, elem2);
  22338. });
  22339. } else {
  22340. fn(array1, array2);
  22341. }
  22342. }
  22343. }
  22344. /**
  22345. * Set a nested property on an object
  22346. * When nested objects are missing, they will be created.
  22347. * For example setProp({}, 'font.color', 'red') will return {font: {color: 'red'}}
  22348. * @param {Object} object
  22349. * @param {string} path A dot separated string like 'font.color'
  22350. * @param {*} value Value for the property
  22351. * @return {Object} Returns the original object, allows for chaining.
  22352. */
  22353. function setProp(object, path, value) {
  22354. var names = path.split('.');
  22355. var prop = names.pop();
  22356. // traverse over the nested objects
  22357. var obj = object;
  22358. for (var i = 0; i < names.length; i++) {
  22359. var name = names[i];
  22360. if (!(name in obj)) {
  22361. obj[name] = {};
  22362. }
  22363. obj = obj[name];
  22364. }
  22365. // set the property value
  22366. obj[prop] = value;
  22367. return object;
  22368. }
  22369. /**
  22370. * Convert an object with DOT attributes to their vis.js equivalents.
  22371. * @param {Object} attr Object with DOT attributes
  22372. * @param {Object} mapping
  22373. * @return {Object} Returns an object with vis.js attributes
  22374. */
  22375. function convertAttr(attr, mapping) {
  22376. var converted = {};
  22377. for (var prop in attr) {
  22378. if (attr.hasOwnProperty(prop)) {
  22379. var visProp = mapping[prop];
  22380. if (Array.isArray(visProp)) {
  22381. visProp.forEach(function(visPropI) {
  22382. setProp(converted, visPropI, attr[prop]);
  22383. });
  22384. } else if (typeof visProp === 'string') {
  22385. setProp(converted, visProp, attr[prop]);
  22386. } else {
  22387. setProp(converted, prop, attr[prop]);
  22388. }
  22389. }
  22390. }
  22391. return converted;
  22392. }
  22393. /**
  22394. * Convert a string containing a graph in DOT language into a map containing
  22395. * with nodes and edges in the format of graph.
  22396. * @param {string} data Text containing a graph in DOT-notation
  22397. * @return {Object} graphData
  22398. */
  22399. function DOTToGraph(data) {
  22400. // parse the DOT file
  22401. var dotData = parseDOT(data);
  22402. var graphData = {
  22403. nodes: [],
  22404. edges: [],
  22405. options: {}
  22406. };
  22407. // copy the nodes
  22408. if (dotData.nodes) {
  22409. dotData.nodes.forEach(function(dotNode) {
  22410. var graphNode = {
  22411. id: dotNode.id,
  22412. label: String(dotNode.label || dotNode.id)
  22413. };
  22414. merge(graphNode, convertAttr(dotNode.attr, NODE_ATTR_MAPPING));
  22415. if (graphNode.image) {
  22416. graphNode.shape = 'image';
  22417. }
  22418. graphData.nodes.push(graphNode);
  22419. });
  22420. }
  22421. // copy the edges
  22422. if (dotData.edges) {
  22423. /**
  22424. * Convert an edge in DOT format to an edge with VisGraph format
  22425. * @param {Object} dotEdge
  22426. * @returns {Object} graphEdge
  22427. */
  22428. var convertEdge = function convertEdge(dotEdge) {
  22429. var graphEdge = {
  22430. from: dotEdge.from,
  22431. to: dotEdge.to
  22432. };
  22433. merge(graphEdge, convertAttr(dotEdge.attr, EDGE_ATTR_MAPPING));
  22434. graphEdge.arrows = dotEdge.type === '->' ? 'to' : undefined;
  22435. return graphEdge;
  22436. };
  22437. dotData.edges.forEach(function(dotEdge) {
  22438. var from, to;
  22439. if (dotEdge.from instanceof Object) {
  22440. from = dotEdge.from.nodes;
  22441. } else {
  22442. from = {
  22443. id: dotEdge.from
  22444. };
  22445. }
  22446. // TODO: support for attributes 'dir' and 'arrowhead' (edge arrows)
  22447. if (dotEdge.to instanceof Object) {
  22448. to = dotEdge.to.nodes;
  22449. } else {
  22450. to = {
  22451. id: dotEdge.to
  22452. };
  22453. }
  22454. if (dotEdge.from instanceof Object && dotEdge.from.edges) {
  22455. dotEdge.from.edges.forEach(function(subEdge) {
  22456. var graphEdge = convertEdge(subEdge);
  22457. graphData.edges.push(graphEdge);
  22458. });
  22459. }
  22460. forEach2(from, to, function(from, to) {
  22461. var subEdge = createEdge(graphData, from.id, to.id, dotEdge.type, dotEdge.attr);
  22462. var graphEdge = convertEdge(subEdge);
  22463. graphData.edges.push(graphEdge);
  22464. });
  22465. if (dotEdge.to instanceof Object && dotEdge.to.edges) {
  22466. dotEdge.to.edges.forEach(function(subEdge) {
  22467. var graphEdge = convertEdge(subEdge);
  22468. graphData.edges.push(graphEdge);
  22469. });
  22470. }
  22471. });
  22472. }
  22473. // copy the options
  22474. if (dotData.attr) {
  22475. graphData.options = dotData.attr;
  22476. }
  22477. return graphData;
  22478. }
  22479. // exports
  22480. exports.parseDOT = parseDOT;
  22481. exports.DOTToGraph = DOTToGraph;
  22482. /***/
  22483. }),
  22484. /* 115 */
  22485. /***/
  22486. (function(module, exports, __webpack_require__) {
  22487. "use strict";
  22488. /**
  22489. *
  22490. * @param {json} gephiJSON
  22491. * @param {obj} optionsObj
  22492. * @returns {{nodes: Array, edges: Array}}
  22493. */
  22494. function parseGephi(gephiJSON, optionsObj) {
  22495. var edges = [];
  22496. var nodes = [];
  22497. var options = {
  22498. edges: {
  22499. inheritColor: false
  22500. },
  22501. nodes: {
  22502. fixed: false,
  22503. parseColor: false
  22504. }
  22505. };
  22506. if (optionsObj !== undefined) {
  22507. if (optionsObj.fixed !== undefined) {
  22508. options.nodes.fixed = optionsObj.fixed;
  22509. }
  22510. if (optionsObj.parseColor !== undefined) {
  22511. options.nodes.parseColor = optionsObj.parseColor;
  22512. }
  22513. if (optionsObj.inheritColor !== undefined) {
  22514. options.edges.inheritColor = optionsObj.inheritColor;
  22515. }
  22516. }
  22517. var gEdges = gephiJSON.edges;
  22518. var gNodes = gephiJSON.nodes;
  22519. for (var i = 0; i < gEdges.length; i++) {
  22520. var edge = {};
  22521. var gEdge = gEdges[i];
  22522. edge['id'] = gEdge.id;
  22523. edge['from'] = gEdge.source;
  22524. edge['to'] = gEdge.target;
  22525. edge['attributes'] = gEdge.attributes;
  22526. edge['label'] = gEdge.label;
  22527. edge['title'] = gEdge.attributes !== undefined ? gEdge.attributes.title : undefined;
  22528. if (gEdge['type'] === 'Directed') {
  22529. edge['arrows'] = 'to';
  22530. }
  22531. // edge['value'] = gEdge.attributes !== undefined ? gEdge.attributes.Weight : undefined;
  22532. // edge['width'] = edge['value'] !== undefined ? undefined : edgegEdge.size;
  22533. if (gEdge.color && options.inheritColor === false) {
  22534. edge['color'] = gEdge.color;
  22535. }
  22536. edges.push(edge);
  22537. }
  22538. for (var j = 0; j < gNodes.length; j++) {
  22539. var node = {};
  22540. var gNode = gNodes[j];
  22541. node['id'] = gNode.id;
  22542. node['attributes'] = gNode.attributes;
  22543. node['x'] = gNode.x;
  22544. node['y'] = gNode.y;
  22545. node['label'] = gNode.label;
  22546. node['title'] = gNode.attributes !== undefined ? gNode.attributes.title : gNode.title;
  22547. if (options.nodes.parseColor === true) {
  22548. node['color'] = gNode.color;
  22549. } else {
  22550. node['color'] = gNode.color !== undefined ? { background: gNode.color, border: gNode.color, highlight: { background: gNode.color, border: gNode.color }, hover: { background: gNode.color, border: gNode.color } } : undefined;
  22551. }
  22552. node['size'] = gNode.size;
  22553. node['fixed'] = options.nodes.fixed && gNode.x !== undefined && gNode.y !== undefined;
  22554. nodes.push(node);
  22555. }
  22556. return { nodes: nodes, edges: edges };
  22557. }
  22558. exports.parseGephi = parseGephi;
  22559. /***/
  22560. }),
  22561. /* 116 */
  22562. /***/
  22563. (function(module, exports, __webpack_require__) {
  22564. "use strict";
  22565. Object.defineProperty(exports, "__esModule", {
  22566. value: true
  22567. });
  22568. var _classCallCheck2 = __webpack_require__(0);
  22569. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  22570. var _createClass2 = __webpack_require__(1);
  22571. var _createClass3 = _interopRequireDefault(_createClass2);
  22572. var _CachedImage = __webpack_require__(185);
  22573. var _CachedImage2 = _interopRequireDefault(_CachedImage);
  22574. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  22575. /**
  22576. * This callback is a callback that accepts an Image.
  22577. * @callback ImageCallback
  22578. * @param {Image} image
  22579. */
  22580. /**
  22581. * This class loads images and keeps them stored.
  22582. *
  22583. * @param {ImageCallback} callback
  22584. */
  22585. var Images = function() {
  22586. /**
  22587. * @param {ImageCallback} callback
  22588. */
  22589. function Images(callback) {
  22590. (0, _classCallCheck3["default"])(this, Images);
  22591. this.images = {};
  22592. this.imageBroken = {};
  22593. this.callback = callback;
  22594. }
  22595. /**
  22596. * @param {string} url The original Url that failed to load, if the broken image is successfully loaded it will be added to the cache using this Url as the key so that subsequent requests for this Url will return the broken image
  22597. * @param {string} brokenUrl Url the broken image to try and load
  22598. * @param {Image} imageToLoadBrokenUrlOn The image object
  22599. */
  22600. (0, _createClass3["default"])(Images, [{
  22601. key: "_tryloadBrokenUrl",
  22602. value: function _tryloadBrokenUrl(url, brokenUrl, imageToLoadBrokenUrlOn) {
  22603. //If these parameters aren't specified then exit the function because nothing constructive can be done
  22604. if (url === undefined || imageToLoadBrokenUrlOn === undefined) return;
  22605. if (brokenUrl === undefined) {
  22606. console.warn("No broken url image defined");
  22607. return;
  22608. }
  22609. //Clear the old subscription to the error event and put a new in place that only handle errors in loading the brokenImageUrl
  22610. imageToLoadBrokenUrlOn.onerror = function() {
  22611. console.error("Could not load brokenImage:", brokenUrl);
  22612. // cache item will contain empty image, this should be OK for default
  22613. };
  22614. //Set the source of the image to the brokenUrl, this is actually what kicks off the loading of the broken image
  22615. imageToLoadBrokenUrlOn.image.src = brokenUrl;
  22616. }
  22617. /**
  22618. *
  22619. * @param {vis.Image} imageToRedrawWith
  22620. * @private
  22621. */
  22622. }, {
  22623. key: "_redrawWithImage",
  22624. value: function _redrawWithImage(imageToRedrawWith) {
  22625. if (this.callback) {
  22626. this.callback(imageToRedrawWith);
  22627. }
  22628. }
  22629. /**
  22630. * @param {string} url Url of the image
  22631. * @param {string} brokenUrl Url of an image to use if the url image is not found
  22632. * @return {Image} img The image object
  22633. */
  22634. }, {
  22635. key: "load",
  22636. value: function load(url, brokenUrl) {
  22637. var _this = this;
  22638. //Try and get the image from the cache, if successful then return the cached image
  22639. var cachedImage = this.images[url];
  22640. if (cachedImage) return cachedImage;
  22641. //Create a new image
  22642. var img = new _CachedImage2["default"]();
  22643. // Need to add to cache here, otherwise final return will spawn different copies of the same image,
  22644. // Also, there will be multiple loads of the same image.
  22645. this.images[url] = img;
  22646. //Subscribe to the event that is raised if the image loads successfully
  22647. img.image.onload = function() {
  22648. // Properly init the cached item and then request a redraw
  22649. _this._fixImageCoordinates(img.image);
  22650. img.init();
  22651. _this._redrawWithImage(img);
  22652. };
  22653. //Subscribe to the event that is raised if the image fails to load
  22654. img.image.onerror = function() {
  22655. console.error("Could not load image:", url);
  22656. //Try and load the image specified by the brokenUrl using
  22657. _this._tryloadBrokenUrl(url, brokenUrl, img);
  22658. };
  22659. //Set the source of the image to the url, this is what actually kicks off the loading of the image
  22660. img.image.src = url;
  22661. //Return the new image
  22662. return img;
  22663. }
  22664. /**
  22665. * IE11 fix -- thanks dponch!
  22666. *
  22667. * Local helper function
  22668. * @param {vis.Image} imageToCache
  22669. * @private
  22670. */
  22671. }, {
  22672. key: "_fixImageCoordinates",
  22673. value: function _fixImageCoordinates(imageToCache) {
  22674. if (imageToCache.width === 0) {
  22675. document.body.appendChild(imageToCache);
  22676. imageToCache.width = imageToCache.offsetWidth;
  22677. imageToCache.height = imageToCache.offsetHeight;
  22678. document.body.removeChild(imageToCache);
  22679. }
  22680. }
  22681. }]);
  22682. return Images;
  22683. }();
  22684. exports["default"] = Images;
  22685. /***/
  22686. }),
  22687. /* 117 */
  22688. /***/
  22689. (function(module, exports, __webpack_require__) {
  22690. "use strict";
  22691. Object.defineProperty(exports, "__esModule", {
  22692. value: true
  22693. });
  22694. var _slicedToArray2 = __webpack_require__(30);
  22695. var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
  22696. var _typeof2 = __webpack_require__(6);
  22697. var _typeof3 = _interopRequireDefault(_typeof2);
  22698. var _classCallCheck2 = __webpack_require__(0);
  22699. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  22700. var _createClass2 = __webpack_require__(1);
  22701. var _createClass3 = _interopRequireDefault(_createClass2);
  22702. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  22703. var util = __webpack_require__(2);
  22704. var ComponentUtil = __webpack_require__(48)['default'];
  22705. var LabelSplitter = __webpack_require__(191)['default'];
  22706. /**
  22707. * @typedef {'bold'|'ital'|'boldital'|'mono'|'normal'} MultiFontStyle
  22708. *
  22709. * The allowed specifiers of multi-fonts.
  22710. */
  22711. /**
  22712. * @typedef {{color:string, size:number, face:string, mod:string, vadjust:number}} MultiFontOptions
  22713. *
  22714. * The full set of options of a given multi-font.
  22715. */
  22716. /**
  22717. * @typedef {Array.<object>} Pile
  22718. *
  22719. * Sequence of option objects, the order is significant.
  22720. * The sequence is used to determine the value of a given option.
  22721. *
  22722. * Usage principles:
  22723. *
  22724. * - All search is done in the sequence of the pile.
  22725. * - As soon as a value is found, the searching stops.
  22726. * - prototypes are totally ignored. The idea is to add option objects used as prototypes
  22727. * to the pile, in the correct order.
  22728. */
  22729. /**
  22730. * List of special styles for multi-fonts
  22731. * @private
  22732. */
  22733. var multiFontStyle = ['bold', 'ital', 'boldital', 'mono'];
  22734. /**
  22735. * A Label to be used for Nodes or Edges.
  22736. */
  22737. var Label = function() {
  22738. /**
  22739. * @param {Object} body
  22740. * @param {Object} options
  22741. * @param {boolean} [edgelabel=false]
  22742. */
  22743. function Label(body, options) {
  22744. var edgelabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  22745. (0, _classCallCheck3['default'])(this, Label);
  22746. this.body = body;
  22747. this.pointToSelf = false;
  22748. this.baseSize = undefined;
  22749. this.fontOptions = {}; // instance variable containing the *instance-local* font options
  22750. this.setOptions(options);
  22751. this.size = { top: 0, left: 0, width: 0, height: 0, yLine: 0 };
  22752. this.isEdgeLabel = edgelabel;
  22753. }
  22754. /**
  22755. * @param {Object} options the options of the parent Node-instance
  22756. */
  22757. (0, _createClass3['default'])(Label, [{
  22758. key: 'setOptions',
  22759. value: function setOptions(options) {
  22760. this.elementOptions = options; // Reference to the options of the parent Node-instance
  22761. this.initFontOptions(options.font);
  22762. if (ComponentUtil.isValidLabel(options.label)) {
  22763. this.labelDirty = true;
  22764. } else {
  22765. // Bad label! Change the option value to prevent bad stuff happening
  22766. options.label = '';
  22767. }
  22768. if (options.font !== undefined && options.font !== null) {
  22769. // font options can be deleted at various levels
  22770. if (typeof options.font === 'string') {
  22771. this.baseSize = this.fontOptions.size;
  22772. } else if ((0, _typeof3['default'])(options.font) === 'object') {
  22773. var size = options.font.size;
  22774. if (size !== undefined) {
  22775. this.baseSize = size;
  22776. }
  22777. }
  22778. }
  22779. }
  22780. /**
  22781. * Init the font Options structure.
  22782. *
  22783. * Member fontOptions serves as an accumulator for the current font options.
  22784. * As such, it needs to be completely separated from the node options.
  22785. *
  22786. * @param {Object} newFontOptions the new font options to process
  22787. * @private
  22788. */
  22789. }, {
  22790. key: 'initFontOptions',
  22791. value: function initFontOptions(newFontOptions) {
  22792. var _this = this;
  22793. // Prepare the multi-font option objects.
  22794. // These will be filled in propagateFonts(), if required
  22795. util.forEach(multiFontStyle, function(style) {
  22796. _this.fontOptions[style] = {};
  22797. });
  22798. // Handle shorthand option, if present
  22799. if (Label.parseFontString(this.fontOptions, newFontOptions)) {
  22800. this.fontOptions.vadjust = 0;
  22801. return;
  22802. }
  22803. // Copy over the non-multifont options, if specified
  22804. util.forEach(newFontOptions, function(prop, n) {
  22805. if (prop !== undefined && prop !== null && (typeof prop === 'undefined' ? 'undefined' : (0, _typeof3['default'])(prop)) !== 'object') {
  22806. _this.fontOptions[n] = prop;
  22807. }
  22808. });
  22809. }
  22810. /**
  22811. * If in-variable is a string, parse it as a font specifier.
  22812. *
  22813. * Note that following is not done here and have to be done after the call:
  22814. * - No number conversion (size)
  22815. * - Not all font options are set (vadjust, mod)
  22816. *
  22817. * @param {Object} outOptions out-parameter, object in which to store the parse results (if any)
  22818. * @param {Object} inOptions font options to parse
  22819. * @return {boolean} true if font parsed as string, false otherwise
  22820. * @static
  22821. */
  22822. }, {
  22823. key: 'constrain',
  22824. /**
  22825. * Set the width and height constraints based on 'nearest' value
  22826. *
  22827. * @param {Array} pile array of option objects to consider
  22828. * @returns {object} the actual constraint values to use
  22829. * @private
  22830. */
  22831. value: function constrain(pile) {
  22832. // NOTE: constrainWidth and constrainHeight never set!
  22833. // NOTE: for edge labels, only 'maxWdt' set
  22834. // Node labels can set all the fields
  22835. var fontOptions = {
  22836. constrainWidth: false,
  22837. maxWdt: -1,
  22838. minWdt: -1,
  22839. constrainHeight: false,
  22840. minHgt: -1,
  22841. valign: 'middle'
  22842. };
  22843. var widthConstraint = util.topMost(pile, 'widthConstraint');
  22844. if (typeof widthConstraint === 'number') {
  22845. fontOptions.maxWdt = Number(widthConstraint);
  22846. fontOptions.minWdt = Number(widthConstraint);
  22847. } else if ((typeof widthConstraint === 'undefined' ? 'undefined' : (0, _typeof3['default'])(widthConstraint)) === 'object') {
  22848. var widthConstraintMaximum = util.topMost(pile, ['widthConstraint', 'maximum']);
  22849. if (typeof widthConstraintMaximum === 'number') {
  22850. fontOptions.maxWdt = Number(widthConstraintMaximum);
  22851. }
  22852. var widthConstraintMinimum = util.topMost(pile, ['widthConstraint', 'minimum']);
  22853. if (typeof widthConstraintMinimum === 'number') {
  22854. fontOptions.minWdt = Number(widthConstraintMinimum);
  22855. }
  22856. }
  22857. var heightConstraint = util.topMost(pile, 'heightConstraint');
  22858. if (typeof heightConstraint === 'number') {
  22859. fontOptions.minHgt = Number(heightConstraint);
  22860. } else if ((typeof heightConstraint === 'undefined' ? 'undefined' : (0, _typeof3['default'])(heightConstraint)) === 'object') {
  22861. var heightConstraintMinimum = util.topMost(pile, ['heightConstraint', 'minimum']);
  22862. if (typeof heightConstraintMinimum === 'number') {
  22863. fontOptions.minHgt = Number(heightConstraintMinimum);
  22864. }
  22865. var heightConstraintValign = util.topMost(pile, ['heightConstraint', 'valign']);
  22866. if (typeof heightConstraintValign === 'string') {
  22867. if (heightConstraintValign === 'top' || heightConstraintValign === 'bottom') {
  22868. fontOptions.valign = heightConstraintValign;
  22869. }
  22870. }
  22871. }
  22872. return fontOptions;
  22873. }
  22874. /**
  22875. * Set options and update internal state
  22876. *
  22877. * @param {Object} options options to set
  22878. * @param {Array} pile array of option objects to consider for option 'chosen'
  22879. */
  22880. }, {
  22881. key: 'update',
  22882. value: function update(options, pile) {
  22883. this.setOptions(options, true);
  22884. this.propagateFonts(pile);
  22885. util.deepExtend(this.fontOptions, this.constrain(pile));
  22886. this.fontOptions.chooser = ComponentUtil.choosify('label', pile);
  22887. }
  22888. /**
  22889. * When margins are set in an element, adjust sizes is called to remove them
  22890. * from the width/height constraints. This must be done prior to label sizing.
  22891. *
  22892. * @param {{top: number, right: number, bottom: number, left: number}} margins
  22893. */
  22894. }, {
  22895. key: 'adjustSizes',
  22896. value: function adjustSizes(margins) {
  22897. var widthBias = margins ? margins.right + margins.left : 0;
  22898. if (this.fontOptions.constrainWidth) {
  22899. this.fontOptions.maxWdt -= widthBias;
  22900. this.fontOptions.minWdt -= widthBias;
  22901. }
  22902. var heightBias = margins ? margins.top + margins.bottom : 0;
  22903. if (this.fontOptions.constrainHeight) {
  22904. this.fontOptions.minHgt -= heightBias;
  22905. }
  22906. }
  22907. /////////////////////////////////////////////////////////
  22908. // Methods for handling options piles
  22909. // Eventually, these will be moved to a separate class
  22910. /////////////////////////////////////////////////////////
  22911. /**
  22912. * Add the font members of the passed list of option objects to the pile.
  22913. *
  22914. * @param {Pile} dstPile pile of option objects add to
  22915. * @param {Pile} srcPile pile of option objects to take font options from
  22916. * @private
  22917. */
  22918. }, {
  22919. key: 'addFontOptionsToPile',
  22920. value: function addFontOptionsToPile(dstPile, srcPile) {
  22921. for (var i = 0; i < srcPile.length; ++i) {
  22922. this.addFontToPile(dstPile, srcPile[i]);
  22923. }
  22924. }
  22925. /**
  22926. * Add given font option object to the list of objects (the 'pile') to consider for determining
  22927. * multi-font option values.
  22928. *
  22929. * @param {Pile} pile pile of option objects to use
  22930. * @param {object} options instance to add to pile
  22931. * @private
  22932. */
  22933. }, {
  22934. key: 'addFontToPile',
  22935. value: function addFontToPile(pile, options) {
  22936. if (options === undefined) return;
  22937. if (options.font === undefined || options.font === null) return;
  22938. var item = options.font;
  22939. pile.push(item);
  22940. }
  22941. /**
  22942. * Collect all own-property values from the font pile that aren't multi-font option objectss.
  22943. *
  22944. * @param {Pile} pile pile of option objects to use
  22945. * @returns {object} object with all current own basic font properties
  22946. * @private
  22947. */
  22948. }, {
  22949. key: 'getBasicOptions',
  22950. value: function getBasicOptions(pile) {
  22951. var ret = {};
  22952. // Scans the whole pile to get all options present
  22953. for (var n = 0; n < pile.length; ++n) {
  22954. var fontOptions = pile[n];
  22955. // Convert shorthand if necessary
  22956. var tmpShorthand = {};
  22957. if (Label.parseFontString(tmpShorthand, fontOptions)) {
  22958. fontOptions = tmpShorthand;
  22959. }
  22960. util.forEach(fontOptions, function(opt, name) {
  22961. if (opt === undefined) return; // multi-font option need not be present
  22962. if (ret.hasOwnProperty(name)) return; // Keep first value we encounter
  22963. if (multiFontStyle.indexOf(name) !== -1) {
  22964. // Skip multi-font properties but we do need the structure
  22965. ret[name] = {};
  22966. } else {
  22967. ret[name] = opt;
  22968. }
  22969. });
  22970. }
  22971. return ret;
  22972. }
  22973. /**
  22974. * Return the value for given option for the given multi-font.
  22975. *
  22976. * All available option objects are trawled in the set order to construct the option values.
  22977. *
  22978. * ---------------------------------------------------------------------
  22979. * ## Traversal of pile for multi-fonts
  22980. *
  22981. * The determination of multi-font option values is a special case, because any values not
  22982. * present in the multi-font options should by definition be taken from the main font options,
  22983. * i.e. from the current 'parent' object of the multi-font option.
  22984. *
  22985. * ### Search order for multi-fonts
  22986. *
  22987. * 'bold' used as example:
  22988. *
  22989. * - search in option group 'bold' in local properties
  22990. * - search in main font option group in local properties
  22991. *
  22992. * ---------------------------------------------------------------------
  22993. *
  22994. * @param {Pile} pile pile of option objects to use
  22995. * @param {MultiFontStyle} multiName sub path for the multi-font
  22996. * @param {string} option the option to search for, for the given multi-font
  22997. * @returns {string|number} the value for the given option
  22998. * @private
  22999. */
  23000. }, {
  23001. key: 'getFontOption',
  23002. value: function getFontOption(pile, multiName, option) {
  23003. var multiFont = void 0;
  23004. // Search multi font in local properties
  23005. for (var n = 0; n < pile.length; ++n) {
  23006. var fontOptions = pile[n];
  23007. if (fontOptions.hasOwnProperty(multiName)) {
  23008. multiFont = fontOptions[multiName];
  23009. if (multiFont === undefined || multiFont === null) continue;
  23010. // Convert shorthand if necessary
  23011. // TODO: inefficient to do this conversion every time; find a better way.
  23012. var tmpShorthand = {};
  23013. if (Label.parseFontString(tmpShorthand, multiFont)) {
  23014. multiFont = tmpShorthand;
  23015. }
  23016. if (multiFont.hasOwnProperty(option)) {
  23017. return multiFont[option];
  23018. }
  23019. }
  23020. }
  23021. // Option is not mentioned in the multi font options; take it from the parent font options.
  23022. // These have already been converted with getBasicOptions(), so use the converted values.
  23023. if (this.fontOptions.hasOwnProperty(option)) {
  23024. return this.fontOptions[option];
  23025. }
  23026. // A value **must** be found; you should never get here.
  23027. throw new Error("Did not find value for multi-font for property: '" + option + "'");
  23028. }
  23029. /**
  23030. * Return all options values for the given multi-font.
  23031. *
  23032. * All available option objects are trawled in the set order to construct the option values.
  23033. *
  23034. * @param {Pile} pile pile of option objects to use
  23035. * @param {MultiFontStyle} multiName sub path for the mod-font
  23036. * @returns {MultiFontOptions}
  23037. * @private
  23038. */
  23039. }, {
  23040. key: 'getFontOptions',
  23041. value: function getFontOptions(pile, multiName) {
  23042. var result = {};
  23043. var optionNames = ['color', 'size', 'face', 'mod', 'vadjust']; // List of allowed options per multi-font
  23044. for (var i = 0; i < optionNames.length; ++i) {
  23045. var mod = optionNames[i];
  23046. result[mod] = this.getFontOption(pile, multiName, mod);
  23047. }
  23048. return result;
  23049. }
  23050. /////////////////////////////////////////////////////////
  23051. // End methods for handling options piles
  23052. /////////////////////////////////////////////////////////
  23053. /**
  23054. * Collapse the font options for the multi-font to single objects, from
  23055. * the chain of option objects passed (the 'pile').
  23056. *
  23057. * @param {Pile} pile sequence of option objects to consider.
  23058. * First item in list assumed to be the newly set options.
  23059. */
  23060. }, {
  23061. key: 'propagateFonts',
  23062. value: function propagateFonts(pile) {
  23063. var _this2 = this;
  23064. var fontPile = []; // sequence of font objects to consider, order important
  23065. // Note that this.elementOptions is not used here.
  23066. this.addFontOptionsToPile(fontPile, pile);
  23067. this.fontOptions = this.getBasicOptions(fontPile);
  23068. // We set multifont values even if multi === false, for consistency (things break otherwise)
  23069. var _loop = function _loop(i) {
  23070. var mod = multiFontStyle[i];
  23071. var modOptions = _this2.fontOptions[mod];
  23072. var tmpMultiFontOptions = _this2.getFontOptions(fontPile, mod);
  23073. // Copy over found values
  23074. util.forEach(tmpMultiFontOptions, function(option, n) {
  23075. modOptions[n] = option;
  23076. });
  23077. modOptions.size = Number(modOptions.size);
  23078. modOptions.vadjust = Number(modOptions.vadjust);
  23079. };
  23080. for (var i = 0; i < multiFontStyle.length; ++i) {
  23081. _loop(i);
  23082. }
  23083. }
  23084. /**
  23085. * Main function. This is called from anything that wants to draw a label.
  23086. * @param {CanvasRenderingContext2D} ctx
  23087. * @param {number} x
  23088. * @param {number} y
  23089. * @param {boolean} selected
  23090. * @param {boolean} hover
  23091. * @param {string} [baseline='middle']
  23092. */
  23093. }, {
  23094. key: 'draw',
  23095. value: function draw(ctx, x, y, selected, hover) {
  23096. var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 'middle';
  23097. // if no label, return
  23098. if (this.elementOptions.label === undefined) return;
  23099. // check if we have to render the label
  23100. var viewFontSize = this.fontOptions.size * this.body.view.scale;
  23101. if (this.elementOptions.label && viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) return;
  23102. // This ensures that there will not be HUGE letters on screen
  23103. // by setting an upper limit on the visible text size (regardless of zoomLevel)
  23104. if (viewFontSize >= this.elementOptions.scaling.label.maxVisible) {
  23105. viewFontSize = Number(this.elementOptions.scaling.label.maxVisible) / this.body.view.scale;
  23106. }
  23107. // update the size cache if required
  23108. this.calculateLabelSize(ctx, selected, hover, x, y, baseline);
  23109. this._drawBackground(ctx);
  23110. this._drawText(ctx, x, this.size.yLine, baseline, viewFontSize);
  23111. }
  23112. /**
  23113. * Draws the label background
  23114. * @param {CanvasRenderingContext2D} ctx
  23115. * @private
  23116. */
  23117. }, {
  23118. key: '_drawBackground',
  23119. value: function _drawBackground(ctx) {
  23120. if (this.fontOptions.background !== undefined && this.fontOptions.background !== "none") {
  23121. ctx.fillStyle = this.fontOptions.background;
  23122. var size = this.getSize();
  23123. ctx.fillRect(size.left, size.top, size.width, size.height);
  23124. }
  23125. }
  23126. /**
  23127. *
  23128. * @param {CanvasRenderingContext2D} ctx
  23129. * @param {number} x
  23130. * @param {number} y
  23131. * @param {string} [baseline='middle']
  23132. * @param {number} viewFontSize
  23133. * @private
  23134. */
  23135. }, {
  23136. key: '_drawText',
  23137. value: function _drawText(ctx, x, y) {
  23138. var baseline = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'middle';
  23139. var viewFontSize = arguments[4];
  23140. var _setAlignment2 = this._setAlignment(ctx, x, y, baseline);
  23141. var _setAlignment3 = (0, _slicedToArray3['default'])(_setAlignment2, 2);
  23142. x = _setAlignment3[0];
  23143. y = _setAlignment3[1];
  23144. ctx.textAlign = 'left';
  23145. x = x - this.size.width / 2; // Shift label 1/2-distance to the left
  23146. if (this.fontOptions.valign && this.size.height > this.size.labelHeight) {
  23147. if (this.fontOptions.valign === 'top') {
  23148. y -= (this.size.height - this.size.labelHeight) / 2;
  23149. }
  23150. if (this.fontOptions.valign === 'bottom') {
  23151. y += (this.size.height - this.size.labelHeight) / 2;
  23152. }
  23153. }
  23154. // draw the text
  23155. for (var i = 0; i < this.lineCount; i++) {
  23156. var line = this.lines[i];
  23157. if (line && line.blocks) {
  23158. var width = 0;
  23159. if (this.isEdgeLabel || this.fontOptions.align === 'center') {
  23160. width += (this.size.width - line.width) / 2;
  23161. } else if (this.fontOptions.align === 'right') {
  23162. width += this.size.width - line.width;
  23163. }
  23164. for (var j = 0; j < line.blocks.length; j++) {
  23165. var block = line.blocks[j];
  23166. ctx.font = block.font;
  23167. var _getColor2 = this._getColor(block.color, viewFontSize, block.strokeColor),
  23168. _getColor3 = (0, _slicedToArray3['default'])(_getColor2, 2),
  23169. fontColor = _getColor3[0],
  23170. strokeColor = _getColor3[1];
  23171. if (block.strokeWidth > 0) {
  23172. ctx.lineWidth = block.strokeWidth;
  23173. ctx.strokeStyle = strokeColor;
  23174. ctx.lineJoin = 'round';
  23175. }
  23176. ctx.fillStyle = fontColor;
  23177. if (block.strokeWidth > 0) {
  23178. ctx.strokeText(block.text, x + width, y + block.vadjust);
  23179. }
  23180. ctx.fillText(block.text, x + width, y + block.vadjust);
  23181. width += block.width;
  23182. }
  23183. y += line.height;
  23184. }
  23185. }
  23186. }
  23187. /**
  23188. *
  23189. * @param {CanvasRenderingContext2D} ctx
  23190. * @param {number} x
  23191. * @param {number} y
  23192. * @param {string} baseline
  23193. * @returns {Array.<number>}
  23194. * @private
  23195. */
  23196. }, {
  23197. key: '_setAlignment',
  23198. value: function _setAlignment(ctx, x, y, baseline) {
  23199. // check for label alignment (for edges)
  23200. // TODO: make alignment for nodes
  23201. if (this.isEdgeLabel && this.fontOptions.align !== 'horizontal' && this.pointToSelf === false) {
  23202. x = 0;
  23203. y = 0;
  23204. var lineMargin = 2;
  23205. if (this.fontOptions.align === 'top') {
  23206. ctx.textBaseline = 'alphabetic';
  23207. y -= 2 * lineMargin; // distance from edge, required because we use alphabetic. Alphabetic has less difference between browsers
  23208. } else if (this.fontOptions.align === 'bottom') {
  23209. ctx.textBaseline = 'hanging';
  23210. y += 2 * lineMargin; // distance from edge, required because we use hanging. Hanging has less difference between browsers
  23211. } else {
  23212. ctx.textBaseline = 'middle';
  23213. }
  23214. } else {
  23215. ctx.textBaseline = baseline;
  23216. }
  23217. return [x, y];
  23218. }
  23219. /**
  23220. * fade in when relative scale is between threshold and threshold - 1.
  23221. * If the relative scale would be smaller than threshold -1 the draw function would have returned before coming here.
  23222. *
  23223. * @param {string} color The font color to use
  23224. * @param {number} viewFontSize
  23225. * @param {string} initialStrokeColor
  23226. * @returns {Array.<string>} An array containing the font color and stroke color
  23227. * @private
  23228. */
  23229. }, {
  23230. key: '_getColor',
  23231. value: function _getColor(color, viewFontSize, initialStrokeColor) {
  23232. var fontColor = color || '#000000';
  23233. var strokeColor = initialStrokeColor || '#ffffff';
  23234. if (viewFontSize <= this.elementOptions.scaling.label.drawThreshold) {
  23235. var opacity = Math.max(0, Math.min(1, 1 - (this.elementOptions.scaling.label.drawThreshold - viewFontSize)));
  23236. fontColor = util.overrideOpacity(fontColor, opacity);
  23237. strokeColor = util.overrideOpacity(strokeColor, opacity);
  23238. }
  23239. return [fontColor, strokeColor];
  23240. }
  23241. /**
  23242. *
  23243. * @param {CanvasRenderingContext2D} ctx
  23244. * @param {boolean} selected
  23245. * @param {boolean} hover
  23246. * @returns {{width: number, height: number}}
  23247. */
  23248. }, {
  23249. key: 'getTextSize',
  23250. value: function getTextSize(ctx) {
  23251. var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  23252. var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  23253. this._processLabel(ctx, selected, hover);
  23254. return {
  23255. width: this.size.width,
  23256. height: this.size.height,
  23257. lineCount: this.lineCount
  23258. };
  23259. }
  23260. /**
  23261. * Get the current dimensions of the label
  23262. *
  23263. * @return {rect}
  23264. */
  23265. }, {
  23266. key: 'getSize',
  23267. value: function getSize() {
  23268. var lineMargin = 2;
  23269. var x = this.size.left; // default values which might be overridden below
  23270. var y = this.size.top - 0.5 * lineMargin; // idem
  23271. if (this.isEdgeLabel) {
  23272. var x2 = -this.size.width * 0.5;
  23273. switch (this.fontOptions.align) {
  23274. case 'middle':
  23275. x = x2;
  23276. y = -this.size.height * 0.5;
  23277. break;
  23278. case 'top':
  23279. x = x2;
  23280. y = -(this.size.height + lineMargin);
  23281. break;
  23282. case 'bottom':
  23283. x = x2;
  23284. y = lineMargin;
  23285. break;
  23286. }
  23287. }
  23288. var ret = {
  23289. left: x,
  23290. top: y,
  23291. width: this.size.width,
  23292. height: this.size.height
  23293. };
  23294. return ret;
  23295. }
  23296. /**
  23297. *
  23298. * @param {CanvasRenderingContext2D} ctx
  23299. * @param {boolean} selected
  23300. * @param {boolean} hover
  23301. * @param {number} [x=0]
  23302. * @param {number} [y=0]
  23303. * @param {'middle'|'hanging'} [baseline='middle']
  23304. */
  23305. }, {
  23306. key: 'calculateLabelSize',
  23307. value: function calculateLabelSize(ctx, selected, hover) {
  23308. var x = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
  23309. var y = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
  23310. var baseline = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 'middle';
  23311. this._processLabel(ctx, selected, hover);
  23312. this.size.left = x - this.size.width * 0.5;
  23313. this.size.top = y - this.size.height * 0.5;
  23314. this.size.yLine = y + (1 - this.lineCount) * 0.5 * this.fontOptions.size;
  23315. if (baseline === "hanging") {
  23316. this.size.top += 0.5 * this.fontOptions.size;
  23317. this.size.top += 4; // distance from node, required because we use hanging. Hanging has less difference between browsers
  23318. this.size.yLine += 4; // distance from node
  23319. }
  23320. }
  23321. /**
  23322. *
  23323. * @param {CanvasRenderingContext2D} ctx
  23324. * @param {boolean} selected
  23325. * @param {boolean} hover
  23326. * @param {string} mod
  23327. * @returns {{color, size, face, mod, vadjust, strokeWidth: *, strokeColor: (*|string|allOptions.edges.font.strokeColor|{string}|allOptions.nodes.font.strokeColor|Array)}}
  23328. */
  23329. }, {
  23330. key: 'getFormattingValues',
  23331. value: function getFormattingValues(ctx, selected, hover, mod) {
  23332. var getValue = function getValue(fontOptions, mod, option) {
  23333. if (mod === "normal") {
  23334. if (option === 'mod') return "";
  23335. return fontOptions[option];
  23336. }
  23337. if (fontOptions[mod][option] !== undefined) {
  23338. // Grumbl leaving out test on undefined equals false for ""
  23339. return fontOptions[mod][option];
  23340. } else {
  23341. // Take from parent font option
  23342. return fontOptions[option];
  23343. }
  23344. };
  23345. var values = {
  23346. color: getValue(this.fontOptions, mod, 'color'),
  23347. size: getValue(this.fontOptions, mod, 'size'),
  23348. face: getValue(this.fontOptions, mod, 'face'),
  23349. mod: getValue(this.fontOptions, mod, 'mod'),
  23350. vadjust: getValue(this.fontOptions, mod, 'vadjust'),
  23351. strokeWidth: this.fontOptions.strokeWidth,
  23352. strokeColor: this.fontOptions.strokeColor
  23353. };
  23354. if (selected || hover) {
  23355. if (mod === "normal" && this.fontOptions.chooser === true && this.elementOptions.labelHighlightBold) {
  23356. values.mod = 'bold';
  23357. } else {
  23358. if (typeof this.fontOptions.chooser === 'function') {
  23359. this.fontOptions.chooser(values, this.elementOptions.id, selected, hover);
  23360. }
  23361. }
  23362. }
  23363. var fontString = "";
  23364. if (values.mod !== undefined && values.mod !== "") {
  23365. // safeguard for undefined - this happened
  23366. fontString += values.mod + " ";
  23367. }
  23368. fontString += values.size + "px " + values.face;
  23369. ctx.font = fontString.replace(/"/g, "");
  23370. values.font = ctx.font;
  23371. values.height = values.size;
  23372. return values;
  23373. }
  23374. /**
  23375. *
  23376. * @param {boolean} selected
  23377. * @param {boolean} hover
  23378. * @returns {boolean}
  23379. */
  23380. }, {
  23381. key: 'differentState',
  23382. value: function differentState(selected, hover) {
  23383. return selected !== this.selectedState || hover !== this.hoverState;
  23384. }
  23385. /**
  23386. * This explodes the passed text into lines and determines the width, height and number of lines.
  23387. *
  23388. * @param {CanvasRenderingContext2D} ctx
  23389. * @param {boolean} selected
  23390. * @param {boolean} hover
  23391. * @param {string} inText the text to explode
  23392. * @returns {{width, height, lines}|*}
  23393. * @private
  23394. */
  23395. }, {
  23396. key: '_processLabelText',
  23397. value: function _processLabelText(ctx, selected, hover, inText) {
  23398. var splitter = new LabelSplitter(ctx, this, selected, hover);
  23399. return splitter.process(inText);
  23400. }
  23401. /**
  23402. * This explodes the label string into lines and sets the width, height and number of lines.
  23403. * @param {CanvasRenderingContext2D} ctx
  23404. * @param {boolean} selected
  23405. * @param {boolean} hover
  23406. * @private
  23407. */
  23408. }, {
  23409. key: '_processLabel',
  23410. value: function _processLabel(ctx, selected, hover) {
  23411. if (this.labelDirty === false && !this.differentState(selected, hover)) return;
  23412. var state = this._processLabelText(ctx, selected, hover, this.elementOptions.label);
  23413. if (this.fontOptions.minWdt > 0 && state.width < this.fontOptions.minWdt) {
  23414. state.width = this.fontOptions.minWdt;
  23415. }
  23416. this.size.labelHeight = state.height;
  23417. if (this.fontOptions.minHgt > 0 && state.height < this.fontOptions.minHgt) {
  23418. state.height = this.fontOptions.minHgt;
  23419. }
  23420. this.lines = state.lines;
  23421. this.lineCount = state.lines.length;
  23422. this.size.width = state.width;
  23423. this.size.height = state.height;
  23424. this.selectedState = selected;
  23425. this.hoverState = hover;
  23426. this.labelDirty = false;
  23427. }
  23428. /**
  23429. * Check if this label is visible
  23430. *
  23431. * @return {boolean} true if this label will be show, false otherwise
  23432. */
  23433. }, {
  23434. key: 'visible',
  23435. value: function visible() {
  23436. if (this.size.width === 0 || this.size.height === 0 || this.elementOptions.label === undefined) {
  23437. return false; // nothing to display
  23438. }
  23439. var viewFontSize = this.fontOptions.size * this.body.view.scale;
  23440. if (viewFontSize < this.elementOptions.scaling.label.drawThreshold - 1) {
  23441. return false; // Too small or too far away to show
  23442. }
  23443. return true;
  23444. }
  23445. }], [{
  23446. key: 'parseFontString',
  23447. value: function parseFontString(outOptions, inOptions) {
  23448. if (!inOptions || typeof inOptions !== 'string') return false;
  23449. var newOptionsArray = inOptions.split(" ");
  23450. outOptions.size = newOptionsArray[0].replace("px", '');
  23451. outOptions.face = newOptionsArray[1];
  23452. outOptions.color = newOptionsArray[2];
  23453. return true;
  23454. }
  23455. }]);
  23456. return Label;
  23457. }();
  23458. exports['default'] = Label;
  23459. /***/
  23460. }),
  23461. /* 118 */
  23462. /***/
  23463. (function(module, exports, __webpack_require__) {
  23464. "use strict";
  23465. Object.defineProperty(exports, "__esModule", {
  23466. value: true
  23467. });
  23468. var _slicedToArray2 = __webpack_require__(30);
  23469. var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
  23470. var _classCallCheck2 = __webpack_require__(0);
  23471. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  23472. var _createClass2 = __webpack_require__(1);
  23473. var _createClass3 = _interopRequireDefault(_createClass2);
  23474. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  23475. var util = __webpack_require__(2);
  23476. var EndPoints = __webpack_require__(119)["default"];
  23477. /**
  23478. * The Base Class for all edges.
  23479. *
  23480. */
  23481. var EdgeBase = function() {
  23482. /**
  23483. * @param {Object} options
  23484. * @param {Object} body
  23485. * @param {Label} labelModule
  23486. */
  23487. function EdgeBase(options, body, labelModule) {
  23488. (0, _classCallCheck3["default"])(this, EdgeBase);
  23489. this.body = body;
  23490. this.labelModule = labelModule;
  23491. this.options = {};
  23492. this.setOptions(options);
  23493. this.colorDirty = true;
  23494. this.color = {};
  23495. this.selectionWidth = 2;
  23496. this.hoverWidth = 1.5;
  23497. this.fromPoint = this.from;
  23498. this.toPoint = this.to;
  23499. }
  23500. /**
  23501. * Connects a node to itself
  23502. */
  23503. (0, _createClass3["default"])(EdgeBase, [{
  23504. key: "connect",
  23505. value: function connect() {
  23506. this.from = this.body.nodes[this.options.from];
  23507. this.to = this.body.nodes[this.options.to];
  23508. }
  23509. /**
  23510. *
  23511. * @returns {boolean} always false
  23512. */
  23513. }, {
  23514. key: "cleanup",
  23515. value: function cleanup() {
  23516. return false;
  23517. }
  23518. /**
  23519. *
  23520. * @param {Object} options
  23521. */
  23522. }, {
  23523. key: "setOptions",
  23524. value: function setOptions(options) {
  23525. this.options = options;
  23526. this.from = this.body.nodes[this.options.from];
  23527. this.to = this.body.nodes[this.options.to];
  23528. this.id = this.options.id;
  23529. }
  23530. /**
  23531. * Redraw a edge as a line
  23532. * Draw this edge in the given canvas
  23533. * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
  23534. *
  23535. * @param {CanvasRenderingContext2D} ctx
  23536. * @param {Array} values
  23537. * @param {boolean} selected
  23538. * @param {boolean} hover
  23539. * @param {Node} viaNode
  23540. * @private
  23541. */
  23542. }, {
  23543. key: "drawLine",
  23544. value: function drawLine(ctx, values, selected, hover, viaNode) {
  23545. // set style
  23546. ctx.strokeStyle = this.getColor(ctx, values, selected, hover);
  23547. ctx.lineWidth = values.width;
  23548. if (values.dashes !== false) {
  23549. this._drawDashedLine(ctx, values, viaNode);
  23550. } else {
  23551. this._drawLine(ctx, values, viaNode);
  23552. }
  23553. }
  23554. /**
  23555. *
  23556. * @param {CanvasRenderingContext2D} ctx
  23557. * @param {Array} values
  23558. * @param {Node} viaNode
  23559. * @param {{x: number, y: number}} [fromPoint]
  23560. * @param {{x: number, y: number}} [toPoint]
  23561. * @private
  23562. */
  23563. }, {
  23564. key: "_drawLine",
  23565. value: function _drawLine(ctx, values, viaNode, fromPoint, toPoint) {
  23566. if (this.from != this.to) {
  23567. // draw line
  23568. this._line(ctx, values, viaNode, fromPoint, toPoint);
  23569. } else {
  23570. var _getCircleData2 = this._getCircleData(ctx),
  23571. _getCircleData3 = (0, _slicedToArray3["default"])(_getCircleData2, 3),
  23572. x = _getCircleData3[0],
  23573. y = _getCircleData3[1],
  23574. radius = _getCircleData3[2];
  23575. this._circle(ctx, values, x, y, radius);
  23576. }
  23577. }
  23578. /**
  23579. *
  23580. * @param {CanvasRenderingContext2D} ctx
  23581. * @param {Array} values
  23582. * @param {Node} viaNode
  23583. * @param {{x: number, y: number}} [fromPoint] TODO: Remove in next major release
  23584. * @param {{x: number, y: number}} [toPoint] TODO: Remove in next major release
  23585. * @private
  23586. */
  23587. }, {
  23588. key: "_drawDashedLine",
  23589. value: function _drawDashedLine(ctx, values, viaNode, fromPoint, toPoint) {
  23590. // eslint-disable-line no-unused-vars
  23591. ctx.lineCap = 'round';
  23592. var pattern = [5, 5];
  23593. if (Array.isArray(values.dashes) === true) {
  23594. pattern = values.dashes;
  23595. }
  23596. // only firefox and chrome support this method, else we use the legacy one.
  23597. if (ctx.setLineDash !== undefined) {
  23598. ctx.save();
  23599. // set dash settings for chrome or firefox
  23600. ctx.setLineDash(pattern);
  23601. ctx.lineDashOffset = 0;
  23602. // draw the line
  23603. if (this.from != this.to) {
  23604. // draw line
  23605. this._line(ctx, values, viaNode);
  23606. } else {
  23607. var _getCircleData4 = this._getCircleData(ctx),
  23608. _getCircleData5 = (0, _slicedToArray3["default"])(_getCircleData4, 3),
  23609. x = _getCircleData5[0],
  23610. y = _getCircleData5[1],
  23611. radius = _getCircleData5[2];
  23612. this._circle(ctx, values, x, y, radius);
  23613. }
  23614. // restore the dash settings.
  23615. ctx.setLineDash([0]);
  23616. ctx.lineDashOffset = 0;
  23617. ctx.restore();
  23618. } else {
  23619. // unsupporting smooth lines
  23620. if (this.from != this.to) {
  23621. // draw line
  23622. ctx.dashedLine(this.from.x, this.from.y, this.to.x, this.to.y, pattern);
  23623. } else {
  23624. var _getCircleData6 = this._getCircleData(ctx),
  23625. _getCircleData7 = (0, _slicedToArray3["default"])(_getCircleData6, 3),
  23626. _x = _getCircleData7[0],
  23627. _y = _getCircleData7[1],
  23628. _radius = _getCircleData7[2];
  23629. this._circle(ctx, values, _x, _y, _radius);
  23630. }
  23631. // draw shadow if enabled
  23632. this.enableShadow(ctx, values);
  23633. ctx.stroke();
  23634. // disable shadows for other elements.
  23635. this.disableShadow(ctx, values);
  23636. }
  23637. }
  23638. /**
  23639. *
  23640. * @param {Node} nearNode
  23641. * @param {CanvasRenderingContext2D} ctx
  23642. * @param {Object} options
  23643. * @returns {{x: number, y: number}}
  23644. */
  23645. }, {
  23646. key: "findBorderPosition",
  23647. value: function findBorderPosition(nearNode, ctx, options) {
  23648. if (this.from != this.to) {
  23649. return this._findBorderPosition(nearNode, ctx, options);
  23650. } else {
  23651. return this._findBorderPositionCircle(nearNode, ctx, options);
  23652. }
  23653. }
  23654. /**
  23655. *
  23656. * @param {CanvasRenderingContext2D} ctx
  23657. * @returns {{from: ({x: number, y: number, t: number}|*), to: ({x: number, y: number, t: number}|*)}}
  23658. */
  23659. }, {
  23660. key: "findBorderPositions",
  23661. value: function findBorderPositions(ctx) {
  23662. var from = {};
  23663. var to = {};
  23664. if (this.from != this.to) {
  23665. from = this._findBorderPosition(this.from, ctx);
  23666. to = this._findBorderPosition(this.to, ctx);
  23667. } else {
  23668. var _getCircleData$slice = this._getCircleData(ctx).slice(0, 2),
  23669. _getCircleData$slice2 = (0, _slicedToArray3["default"])(_getCircleData$slice, 2),
  23670. x = _getCircleData$slice2[0],
  23671. y = _getCircleData$slice2[1];
  23672. from = this._findBorderPositionCircle(this.from, ctx, { x: x, y: y, low: 0.25, high: 0.6, direction: -1 });
  23673. to = this._findBorderPositionCircle(this.from, ctx, { x: x, y: y, low: 0.6, high: 0.8, direction: 1 });
  23674. }
  23675. return { from: from, to: to };
  23676. }
  23677. /**
  23678. *
  23679. * @param {CanvasRenderingContext2D} ctx
  23680. * @returns {Array.<number>} x, y, radius
  23681. * @private
  23682. */
  23683. }, {
  23684. key: "_getCircleData",
  23685. value: function _getCircleData(ctx) {
  23686. var x = void 0,
  23687. y = void 0;
  23688. var node = this.from;
  23689. var radius = this.options.selfReferenceSize;
  23690. if (ctx !== undefined) {
  23691. if (node.shape.width === undefined) {
  23692. node.shape.resize(ctx);
  23693. }
  23694. }
  23695. // get circle coordinates
  23696. if (node.shape.width > node.shape.height) {
  23697. x = node.x + node.shape.width * 0.5;
  23698. y = node.y - radius;
  23699. } else {
  23700. x = node.x + radius;
  23701. y = node.y - node.shape.height * 0.5;
  23702. }
  23703. return [x, y, radius];
  23704. }
  23705. /**
  23706. * Get a point on a circle
  23707. * @param {number} x
  23708. * @param {number} y
  23709. * @param {number} radius
  23710. * @param {number} percentage - Value between 0 (line start) and 1 (line end)
  23711. * @return {Object} point
  23712. * @private
  23713. */
  23714. }, {
  23715. key: "_pointOnCircle",
  23716. value: function _pointOnCircle(x, y, radius, percentage) {
  23717. var angle = percentage * 2 * Math.PI;
  23718. return {
  23719. x: x + radius * Math.cos(angle),
  23720. y: y - radius * Math.sin(angle)
  23721. };
  23722. }
  23723. /**
  23724. * This function uses binary search to look for the point where the circle crosses the border of the node.
  23725. * @param {Node} node
  23726. * @param {CanvasRenderingContext2D} ctx
  23727. * @param {Object} options
  23728. * @returns {*}
  23729. * @private
  23730. */
  23731. }, {
  23732. key: "_findBorderPositionCircle",
  23733. value: function _findBorderPositionCircle(node, ctx, options) {
  23734. var x = options.x;
  23735. var y = options.y;
  23736. var low = options.low;
  23737. var high = options.high;
  23738. var direction = options.direction;
  23739. var maxIterations = 10;
  23740. var iteration = 0;
  23741. var radius = this.options.selfReferenceSize;
  23742. var pos = void 0,
  23743. angle = void 0,
  23744. distanceToBorder = void 0,
  23745. distanceToPoint = void 0,
  23746. difference = void 0;
  23747. var threshold = 0.05;
  23748. var middle = (low + high) * 0.5;
  23749. while (low <= high && iteration < maxIterations) {
  23750. middle = (low + high) * 0.5;
  23751. pos = this._pointOnCircle(x, y, radius, middle);
  23752. angle = Math.atan2(node.y - pos.y, node.x - pos.x);
  23753. distanceToBorder = node.distanceToBorder(ctx, angle);
  23754. distanceToPoint = Math.sqrt(Math.pow(pos.x - node.x, 2) + Math.pow(pos.y - node.y, 2));
  23755. difference = distanceToBorder - distanceToPoint;
  23756. if (Math.abs(difference) < threshold) {
  23757. break; // found
  23758. } else if (difference > 0) {
  23759. // distance to nodes is larger than distance to border --> t needs to be bigger if we're looking at the to node.
  23760. if (direction > 0) {
  23761. low = middle;
  23762. } else {
  23763. high = middle;
  23764. }
  23765. } else {
  23766. if (direction > 0) {
  23767. high = middle;
  23768. } else {
  23769. low = middle;
  23770. }
  23771. }
  23772. iteration++;
  23773. }
  23774. pos.t = middle;
  23775. return pos;
  23776. }
  23777. /**
  23778. * Get the line width of the edge. Depends on width and whether one of the
  23779. * connected nodes is selected.
  23780. * @param {boolean} selected
  23781. * @param {boolean} hover
  23782. * @returns {number} width
  23783. * @private
  23784. */
  23785. }, {
  23786. key: "getLineWidth",
  23787. value: function getLineWidth(selected, hover) {
  23788. if (selected === true) {
  23789. return Math.max(this.selectionWidth, 0.3 / this.body.view.scale);
  23790. } else {
  23791. if (hover === true) {
  23792. return Math.max(this.hoverWidth, 0.3 / this.body.view.scale);
  23793. } else {
  23794. return Math.max(this.options.width, 0.3 / this.body.view.scale);
  23795. }
  23796. }
  23797. }
  23798. /**
  23799. *
  23800. * @param {CanvasRenderingContext2D} ctx
  23801. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  23802. * @param {boolean} selected - Unused
  23803. * @param {boolean} hover - Unused
  23804. * @returns {string}
  23805. */
  23806. }, {
  23807. key: "getColor",
  23808. value: function getColor(ctx, values, selected, hover) {
  23809. // eslint-disable-line no-unused-vars
  23810. if (values.inheritsColor !== false) {
  23811. // when this is a loop edge, just use the 'from' method
  23812. if (values.inheritsColor === 'both' && this.from.id !== this.to.id) {
  23813. var grd = ctx.createLinearGradient(this.from.x, this.from.y, this.to.x, this.to.y);
  23814. var fromColor = void 0,
  23815. toColor = void 0;
  23816. fromColor = this.from.options.color.highlight.border;
  23817. toColor = this.to.options.color.highlight.border;
  23818. if (this.from.selected === false && this.to.selected === false) {
  23819. fromColor = util.overrideOpacity(this.from.options.color.border, values.opacity);
  23820. toColor = util.overrideOpacity(this.to.options.color.border, values.opacity);
  23821. } else if (this.from.selected === true && this.to.selected === false) {
  23822. toColor = this.to.options.color.border;
  23823. } else if (this.from.selected === false && this.to.selected === true) {
  23824. fromColor = this.from.options.color.border;
  23825. }
  23826. grd.addColorStop(0, fromColor);
  23827. grd.addColorStop(1, toColor);
  23828. // -------------------- this returns -------------------- //
  23829. return grd;
  23830. }
  23831. if (values.inheritsColor === "to") {
  23832. return util.overrideOpacity(this.to.options.color.border, values.opacity);
  23833. } else {
  23834. // "from"
  23835. return util.overrideOpacity(this.from.options.color.border, values.opacity);
  23836. }
  23837. } else {
  23838. return util.overrideOpacity(values.color, values.opacity);
  23839. }
  23840. }
  23841. /**
  23842. * Draw a line from a node to itself, a circle
  23843. *
  23844. * @param {CanvasRenderingContext2D} ctx
  23845. * @param {Array} values
  23846. * @param {number} x
  23847. * @param {number} y
  23848. * @param {number} radius
  23849. * @private
  23850. */
  23851. }, {
  23852. key: "_circle",
  23853. value: function _circle(ctx, values, x, y, radius) {
  23854. // draw shadow if enabled
  23855. this.enableShadow(ctx, values);
  23856. // draw a circle
  23857. ctx.beginPath();
  23858. ctx.arc(x, y, radius, 0, 2 * Math.PI, false);
  23859. ctx.stroke();
  23860. // disable shadows for other elements.
  23861. this.disableShadow(ctx, values);
  23862. }
  23863. /**
  23864. * Calculate the distance between a point (x3,y3) and a line segment from (x1,y1) to (x2,y2).
  23865. * (x3,y3) is the point.
  23866. *
  23867. * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
  23868. *
  23869. * @param {number} x1
  23870. * @param {number} y1
  23871. * @param {number} x2
  23872. * @param {number} y2
  23873. * @param {number} x3
  23874. * @param {number} y3
  23875. * @param {Node} via
  23876. * @param {Array} values
  23877. * @returns {number}
  23878. */
  23879. }, {
  23880. key: "getDistanceToEdge",
  23881. value: function getDistanceToEdge(x1, y1, x2, y2, x3, y3, via, values) {
  23882. // eslint-disable-line no-unused-vars
  23883. var returnValue = 0;
  23884. if (this.from != this.to) {
  23885. returnValue = this._getDistanceToEdge(x1, y1, x2, y2, x3, y3, via);
  23886. } else {
  23887. var _getCircleData8 = this._getCircleData(undefined),
  23888. _getCircleData9 = (0, _slicedToArray3["default"])(_getCircleData8, 3),
  23889. x = _getCircleData9[0],
  23890. y = _getCircleData9[1],
  23891. radius = _getCircleData9[2];
  23892. var dx = x - x3;
  23893. var dy = y - y3;
  23894. returnValue = Math.abs(Math.sqrt(dx * dx + dy * dy) - radius);
  23895. }
  23896. return returnValue;
  23897. }
  23898. /**
  23899. *
  23900. * @param {number} x1
  23901. * @param {number} y1
  23902. * @param {number} x2
  23903. * @param {number} y2
  23904. * @param {number} x3
  23905. * @param {number} y3
  23906. * @returns {number}
  23907. * @private
  23908. */
  23909. }, {
  23910. key: "_getDistanceToLine",
  23911. value: function _getDistanceToLine(x1, y1, x2, y2, x3, y3) {
  23912. var px = x2 - x1;
  23913. var py = y2 - y1;
  23914. var something = px * px + py * py;
  23915. var u = ((x3 - x1) * px + (y3 - y1) * py) / something;
  23916. if (u > 1) {
  23917. u = 1;
  23918. } else if (u < 0) {
  23919. u = 0;
  23920. }
  23921. var x = x1 + u * px;
  23922. var y = y1 + u * py;
  23923. var dx = x - x3;
  23924. var dy = y - y3;
  23925. //# Note: If the actual distance does not matter,
  23926. //# if you only want to compare what this function
  23927. //# returns to other results of this function, you
  23928. //# can just return the squared distance instead
  23929. //# (i.e. remove the sqrt) to gain a little performance
  23930. return Math.sqrt(dx * dx + dy * dy);
  23931. }
  23932. /**
  23933. * @param {CanvasRenderingContext2D} ctx
  23934. * @param {string} position
  23935. * @param {Node} viaNode
  23936. * @param {boolean} selected
  23937. * @param {boolean} hover
  23938. * @param {Array} values
  23939. * @returns {{point: *, core: {x: number, y: number}, angle: *, length: number, type: *}}
  23940. */
  23941. }, {
  23942. key: "getArrowData",
  23943. value: function getArrowData(ctx, position, viaNode, selected, hover, values) {
  23944. // set lets
  23945. var angle = void 0;
  23946. var arrowPoint = void 0;
  23947. var node1 = void 0;
  23948. var node2 = void 0;
  23949. var guideOffset = void 0;
  23950. var scaleFactor = void 0;
  23951. var type = void 0;
  23952. var lineWidth = values.width;
  23953. if (position === 'from') {
  23954. node1 = this.from;
  23955. node2 = this.to;
  23956. guideOffset = 0.1;
  23957. scaleFactor = values.fromArrowScale;
  23958. type = values.fromArrowType;
  23959. } else if (position === 'to') {
  23960. node1 = this.to;
  23961. node2 = this.from;
  23962. guideOffset = -0.1;
  23963. scaleFactor = values.toArrowScale;
  23964. type = values.toArrowType;
  23965. } else {
  23966. node1 = this.to;
  23967. node2 = this.from;
  23968. scaleFactor = values.middleArrowScale;
  23969. type = values.middleArrowType;
  23970. }
  23971. // if not connected to itself
  23972. if (node1 != node2) {
  23973. if (position !== 'middle') {
  23974. // draw arrow head
  23975. if (this.options.smooth.enabled === true) {
  23976. arrowPoint = this.findBorderPosition(node1, ctx, { via: viaNode });
  23977. var guidePos = this.getPoint(Math.max(0.0, Math.min(1.0, arrowPoint.t + guideOffset)), viaNode);
  23978. angle = Math.atan2(arrowPoint.y - guidePos.y, arrowPoint.x - guidePos.x);
  23979. } else {
  23980. angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
  23981. arrowPoint = this.findBorderPosition(node1, ctx);
  23982. }
  23983. } else {
  23984. angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
  23985. arrowPoint = this.getPoint(0.5, viaNode); // this is 0.6 to account for the size of the arrow.
  23986. }
  23987. } else {
  23988. // draw circle
  23989. var _getCircleData10 = this._getCircleData(ctx),
  23990. _getCircleData11 = (0, _slicedToArray3["default"])(_getCircleData10, 3),
  23991. x = _getCircleData11[0],
  23992. y = _getCircleData11[1],
  23993. radius = _getCircleData11[2];
  23994. if (position === 'from') {
  23995. arrowPoint = this.findBorderPosition(this.from, ctx, { x: x, y: y, low: 0.25, high: 0.6, direction: -1 });
  23996. angle = arrowPoint.t * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
  23997. } else if (position === 'to') {
  23998. arrowPoint = this.findBorderPosition(this.from, ctx, { x: x, y: y, low: 0.6, high: 1.0, direction: 1 });
  23999. angle = arrowPoint.t * -2 * Math.PI + 1.5 * Math.PI - 1.1 * Math.PI;
  24000. } else {
  24001. arrowPoint = this._pointOnCircle(x, y, radius, 0.175);
  24002. angle = 3.9269908169872414; // === 0.175 * -2 * Math.PI + 1.5 * Math.PI + 0.1 * Math.PI;
  24003. }
  24004. }
  24005. if (position === 'middle' && scaleFactor < 0) lineWidth *= -1; // reversed middle arrow
  24006. var length = 15 * scaleFactor + 3 * lineWidth; // 3* lineWidth is the width of the edge.
  24007. var xi = arrowPoint.x - length * 0.9 * Math.cos(angle);
  24008. var yi = arrowPoint.y - length * 0.9 * Math.sin(angle);
  24009. var arrowCore = { x: xi, y: yi };
  24010. return { point: arrowPoint, core: arrowCore, angle: angle, length: length, type: type };
  24011. }
  24012. /**
  24013. *
  24014. * @param {CanvasRenderingContext2D} ctx
  24015. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  24016. * @param {boolean} selected
  24017. * @param {boolean} hover
  24018. * @param {Object} arrowData
  24019. */
  24020. }, {
  24021. key: "drawArrowHead",
  24022. value: function drawArrowHead(ctx, values, selected, hover, arrowData) {
  24023. // set style
  24024. ctx.strokeStyle = this.getColor(ctx, values, selected, hover);
  24025. ctx.fillStyle = ctx.strokeStyle;
  24026. ctx.lineWidth = values.width;
  24027. EndPoints.draw(ctx, arrowData);
  24028. // draw shadow if enabled
  24029. this.enableShadow(ctx, values);
  24030. ctx.fill();
  24031. // disable shadows for other elements.
  24032. this.disableShadow(ctx, values);
  24033. }
  24034. /**
  24035. *
  24036. * @param {CanvasRenderingContext2D} ctx
  24037. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  24038. */
  24039. }, {
  24040. key: "enableShadow",
  24041. value: function enableShadow(ctx, values) {
  24042. if (values.shadow === true) {
  24043. ctx.shadowColor = values.shadowColor;
  24044. ctx.shadowBlur = values.shadowSize;
  24045. ctx.shadowOffsetX = values.shadowX;
  24046. ctx.shadowOffsetY = values.shadowY;
  24047. }
  24048. }
  24049. /**
  24050. *
  24051. * @param {CanvasRenderingContext2D} ctx
  24052. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  24053. */
  24054. }, {
  24055. key: "disableShadow",
  24056. value: function disableShadow(ctx, values) {
  24057. if (values.shadow === true) {
  24058. ctx.shadowColor = 'rgba(0,0,0,0)';
  24059. ctx.shadowBlur = 0;
  24060. ctx.shadowOffsetX = 0;
  24061. ctx.shadowOffsetY = 0;
  24062. }
  24063. }
  24064. }]);
  24065. return EdgeBase;
  24066. }();
  24067. exports["default"] = EdgeBase;
  24068. /***/
  24069. }),
  24070. /* 119 */
  24071. /***/
  24072. (function(module, exports, __webpack_require__) {
  24073. "use strict";
  24074. Object.defineProperty(exports, "__esModule", {
  24075. value: true
  24076. });
  24077. var _getPrototypeOf = __webpack_require__(3);
  24078. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  24079. var _possibleConstructorReturn2 = __webpack_require__(4);
  24080. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  24081. var _inherits2 = __webpack_require__(5);
  24082. var _inherits3 = _interopRequireDefault(_inherits2);
  24083. var _classCallCheck2 = __webpack_require__(0);
  24084. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  24085. var _createClass2 = __webpack_require__(1);
  24086. var _createClass3 = _interopRequireDefault(_createClass2);
  24087. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  24088. /** ============================================================================
  24089. * Location of all the endpoint drawing routines.
  24090. *
  24091. * Every endpoint has its own drawing routine, which contains an endpoint definition.
  24092. *
  24093. * The endpoint definitions must have the following properies:
  24094. *
  24095. * - (0,0) is the connection point to the node it attaches to
  24096. * - The endpoints are orientated to the positive x-direction
  24097. * - The length of the endpoint is at most 1
  24098. *
  24099. * As long as the endpoint classes remain simple and not too numerous, they will
  24100. * be contained within this module.
  24101. * All classes here except `EndPoints` should be considered as private to this module.
  24102. *
  24103. * -----------------------------------------------------------------------------
  24104. * ### Further Actions
  24105. *
  24106. * After adding a new endpoint here, you also need to do the following things:
  24107. *
  24108. * - Add the new endpoint name to `network/options.js` in array `endPoints`.
  24109. * - Add the new endpoint name to the documentation.
  24110. * Scan for 'arrows.to.type` and add it to the description.
  24111. * - Add the endpoint to the examples. At the very least, add it to example
  24112. * `edgeStyles/arrowTypes`.
  24113. * ============================================================================= */
  24114. // NOTE: When a typedef is isolated in a separate comment block, an actual description is generated for it,
  24115. // using the rest of the commenting in the code block. Usage of typedef in other comments then
  24116. // link to there. TIL.
  24117. //
  24118. // Also noteworthy, all typedef's set up in this manner are collected in a single, global page 'global.html'.
  24119. // In other words, it doesn't matter *where* the typedef's are defined in the code.
  24120. //
  24121. //
  24122. // TODO: add descriptive commenting to given typedef's
  24123. /**
  24124. * @typedef {{type:string, point:Point, angle:number, length:number}} ArrowData
  24125. *
  24126. * Object containing instantiation data for a given endpoint.
  24127. */
  24128. /**
  24129. * @typedef {{x:number, y:number}} Point
  24130. *
  24131. * A point in view-coordinates.
  24132. */
  24133. /**
  24134. * Common methods for endpoints
  24135. *
  24136. * @class
  24137. */
  24138. var EndPoint = function() {
  24139. function EndPoint() {
  24140. (0, _classCallCheck3['default'])(this, EndPoint);
  24141. }
  24142. (0, _createClass3['default'])(EndPoint, null, [{
  24143. key: 'transform',
  24144. /**
  24145. * Apply transformation on points for display.
  24146. *
  24147. * The following is done:
  24148. * - rotate by the specified angle
  24149. * - multiply the (normalized) coordinates by the passed length
  24150. * - offset by the target coordinates
  24151. *
  24152. * @param {Array<Point>} points
  24153. * @param {ArrowData} arrowData
  24154. * @static
  24155. */
  24156. value: function transform(points, arrowData) {
  24157. if (!(points instanceof Array)) {
  24158. points = [points];
  24159. }
  24160. var x = arrowData.point.x;
  24161. var y = arrowData.point.y;
  24162. var angle = arrowData.angle;
  24163. var length = arrowData.length;
  24164. for (var i = 0; i < points.length; ++i) {
  24165. var p = points[i];
  24166. var xt = p.x * Math.cos(angle) - p.y * Math.sin(angle);
  24167. var yt = p.x * Math.sin(angle) + p.y * Math.cos(angle);
  24168. p.x = x + length * xt;
  24169. p.y = y + length * yt;
  24170. }
  24171. }
  24172. /**
  24173. * Draw a closed path using the given real coordinates.
  24174. *
  24175. * @param {CanvasRenderingContext2D} ctx
  24176. * @param {Array.<Point>} points
  24177. * @static
  24178. */
  24179. }, {
  24180. key: 'drawPath',
  24181. value: function drawPath(ctx, points) {
  24182. ctx.beginPath();
  24183. ctx.moveTo(points[0].x, points[0].y);
  24184. for (var i = 1; i < points.length; ++i) {
  24185. ctx.lineTo(points[i].x, points[i].y);
  24186. }
  24187. ctx.closePath();
  24188. }
  24189. }]);
  24190. return EndPoint;
  24191. }();
  24192. /**
  24193. * Drawing methods for the arrow endpoint.
  24194. * @extends EndPoint
  24195. */
  24196. var Arrow = function(_EndPoint) {
  24197. (0, _inherits3['default'])(Arrow, _EndPoint);
  24198. function Arrow() {
  24199. (0, _classCallCheck3['default'])(this, Arrow);
  24200. return (0, _possibleConstructorReturn3['default'])(this, (Arrow.__proto__ || (0, _getPrototypeOf2['default'])(Arrow)).apply(this, arguments));
  24201. }
  24202. (0, _createClass3['default'])(Arrow, null, [{
  24203. key: 'draw',
  24204. /**
  24205. * Draw this shape at the end of a line.
  24206. *
  24207. * @param {CanvasRenderingContext2D} ctx
  24208. * @param {ArrowData} arrowData
  24209. * @static
  24210. */
  24211. value: function draw(ctx, arrowData) {
  24212. // Normalized points of closed path, in the order that they should be drawn.
  24213. // (0, 0) is the attachment point, and the point around which should be rotated
  24214. var points = [{ x: 0, y: 0 }, { x: -1, y: 0.3 }, { x: -0.9, y: 0 }, { x: -1, y: -0.3 }];
  24215. EndPoint.transform(points, arrowData);
  24216. EndPoint.drawPath(ctx, points);
  24217. }
  24218. }]);
  24219. return Arrow;
  24220. }(EndPoint);
  24221. /**
  24222. * Drawing methods for the circle endpoint.
  24223. */
  24224. var Circle = function() {
  24225. function Circle() {
  24226. (0, _classCallCheck3['default'])(this, Circle);
  24227. }
  24228. (0, _createClass3['default'])(Circle, null, [{
  24229. key: 'draw',
  24230. /**
  24231. * Draw this shape at the end of a line.
  24232. *
  24233. * @param {CanvasRenderingContext2D} ctx
  24234. * @param {ArrowData} arrowData
  24235. * @static
  24236. */
  24237. value: function draw(ctx, arrowData) {
  24238. var point = { x: -0.4, y: 0 };
  24239. EndPoint.transform(point, arrowData);
  24240. ctx.circle(point.x, point.y, arrowData.length * 0.4);
  24241. }
  24242. }]);
  24243. return Circle;
  24244. }();
  24245. /**
  24246. * Drawing methods for the bar endpoint.
  24247. */
  24248. var Bar = function() {
  24249. function Bar() {
  24250. (0, _classCallCheck3['default'])(this, Bar);
  24251. }
  24252. (0, _createClass3['default'])(Bar, null, [{
  24253. key: 'draw',
  24254. /**
  24255. * Draw this shape at the end of a line.
  24256. *
  24257. * @param {CanvasRenderingContext2D} ctx
  24258. * @param {ArrowData} arrowData
  24259. * @static
  24260. */
  24261. value: function draw(ctx, arrowData) {
  24262. /*
  24263. var points = [
  24264. {x:0, y:0.5},
  24265. {x:0, y:-0.5}
  24266. ];
  24267. EndPoint.transform(points, arrowData);
  24268. ctx.beginPath();
  24269. ctx.moveTo(points[0].x, points[0].y);
  24270. ctx.lineTo(points[1].x, points[1].y);
  24271. ctx.stroke();
  24272. */
  24273. var points = [{ x: 0, y: 0.5 }, { x: 0, y: -0.5 }, { x: -0.15, y: -0.5 }, { x: -0.15, y: 0.5 }];
  24274. EndPoint.transform(points, arrowData);
  24275. EndPoint.drawPath(ctx, points);
  24276. }
  24277. }]);
  24278. return Bar;
  24279. }();
  24280. /**
  24281. * Drawing methods for the endpoints.
  24282. */
  24283. var EndPoints = function() {
  24284. function EndPoints() {
  24285. (0, _classCallCheck3['default'])(this, EndPoints);
  24286. }
  24287. (0, _createClass3['default'])(EndPoints, null, [{
  24288. key: 'draw',
  24289. /**
  24290. * Draw an endpoint
  24291. *
  24292. * @param {CanvasRenderingContext2D} ctx
  24293. * @param {ArrowData} arrowData
  24294. * @static
  24295. */
  24296. value: function draw(ctx, arrowData) {
  24297. var type;
  24298. if (arrowData.type) {
  24299. type = arrowData.type.toLowerCase();
  24300. }
  24301. switch (type) {
  24302. case 'circle':
  24303. Circle.draw(ctx, arrowData);
  24304. break;
  24305. case 'bar':
  24306. Bar.draw(ctx, arrowData);
  24307. break;
  24308. case 'arrow': // fall-through
  24309. default:
  24310. Arrow.draw(ctx, arrowData);
  24311. }
  24312. }
  24313. }]);
  24314. return EndPoints;
  24315. }();
  24316. exports['default'] = EndPoints;
  24317. /***/
  24318. }),
  24319. /* 120 */
  24320. /***/
  24321. (function(module, exports, __webpack_require__) {
  24322. "use strict";
  24323. Object.defineProperty(exports, "__esModule", {
  24324. value: true
  24325. });
  24326. var _classCallCheck2 = __webpack_require__(0);
  24327. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  24328. var _createClass2 = __webpack_require__(1);
  24329. var _createClass3 = _interopRequireDefault(_createClass2);
  24330. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  24331. /**
  24332. * Barnes Hut Solver
  24333. */
  24334. var BarnesHutSolver = function() {
  24335. /**
  24336. * @param {Object} body
  24337. * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
  24338. * @param {Object} options
  24339. */
  24340. function BarnesHutSolver(body, physicsBody, options) {
  24341. (0, _classCallCheck3["default"])(this, BarnesHutSolver);
  24342. this.body = body;
  24343. this.physicsBody = physicsBody;
  24344. this.barnesHutTree;
  24345. this.setOptions(options);
  24346. this.randomSeed = 5;
  24347. // debug: show grid
  24348. // this.body.emitter.on("afterDrawing", (ctx) => {this._debug(ctx,'#ff0000')})
  24349. }
  24350. /**
  24351. *
  24352. * @param {Object} options
  24353. */
  24354. (0, _createClass3["default"])(BarnesHutSolver, [{
  24355. key: "setOptions",
  24356. value: function setOptions(options) {
  24357. this.options = options;
  24358. this.thetaInversed = 1 / this.options.theta;
  24359. // if 1 then min distance = 0.5, if 0.5 then min distance = 0.5 + 0.5*node.shape.radius
  24360. this.overlapAvoidanceFactor = 1 - Math.max(0, Math.min(1, this.options.avoidOverlap));
  24361. }
  24362. /**
  24363. *
  24364. * @returns {number} random integer
  24365. */
  24366. }, {
  24367. key: "seededRandom",
  24368. value: function seededRandom() {
  24369. var x = Math.sin(this.randomSeed++) * 10000;
  24370. return x - Math.floor(x);
  24371. }
  24372. /**
  24373. * This function calculates the forces the nodes apply on each other based on a gravitational model.
  24374. * The Barnes Hut method is used to speed up this N-body simulation.
  24375. *
  24376. * @private
  24377. */
  24378. }, {
  24379. key: "solve",
  24380. value: function solve() {
  24381. if (this.options.gravitationalConstant !== 0 && this.physicsBody.physicsNodeIndices.length > 0) {
  24382. var node = void 0;
  24383. var nodes = this.body.nodes;
  24384. var nodeIndices = this.physicsBody.physicsNodeIndices;
  24385. var nodeCount = nodeIndices.length;
  24386. // create the tree
  24387. var barnesHutTree = this._formBarnesHutTree(nodes, nodeIndices);
  24388. // for debugging
  24389. this.barnesHutTree = barnesHutTree;
  24390. // place the nodes one by one recursively
  24391. for (var i = 0; i < nodeCount; i++) {
  24392. node = nodes[nodeIndices[i]];
  24393. if (node.options.mass > 0) {
  24394. // starting with root is irrelevant, it never passes the BarnesHutSolver condition
  24395. this._getForceContributions(barnesHutTree.root, node);
  24396. }
  24397. }
  24398. }
  24399. }
  24400. /**
  24401. * @param {Object} parentBranch
  24402. * @param {Node} node
  24403. * @private
  24404. */
  24405. }, {
  24406. key: "_getForceContributions",
  24407. value: function _getForceContributions(parentBranch, node) {
  24408. this._getForceContribution(parentBranch.children.NW, node);
  24409. this._getForceContribution(parentBranch.children.NE, node);
  24410. this._getForceContribution(parentBranch.children.SW, node);
  24411. this._getForceContribution(parentBranch.children.SE, node);
  24412. }
  24413. /**
  24414. * This function traverses the barnesHutTree. It checks when it can approximate distant nodes with their center of mass.
  24415. * If a region contains a single node, we check if it is not itself, then we apply the force.
  24416. *
  24417. * @param {Object} parentBranch
  24418. * @param {Node} node
  24419. * @private
  24420. */
  24421. }, {
  24422. key: "_getForceContribution",
  24423. value: function _getForceContribution(parentBranch, node) {
  24424. // we get no force contribution from an empty region
  24425. if (parentBranch.childrenCount > 0) {
  24426. var dx = void 0,
  24427. dy = void 0,
  24428. distance = void 0;
  24429. // get the distance from the center of mass to the node.
  24430. dx = parentBranch.centerOfMass.x - node.x;
  24431. dy = parentBranch.centerOfMass.y - node.y;
  24432. distance = Math.sqrt(dx * dx + dy * dy);
  24433. // BarnesHutSolver condition
  24434. // original condition : s/d < theta = passed === d/s > 1/theta = passed
  24435. // calcSize = 1/s --> d * 1/s > 1/theta = passed
  24436. if (distance * parentBranch.calcSize > this.thetaInversed) {
  24437. this._calculateForces(distance, dx, dy, node, parentBranch);
  24438. } else {
  24439. // Did not pass the condition, go into children if available
  24440. if (parentBranch.childrenCount === 4) {
  24441. this._getForceContributions(parentBranch, node);
  24442. } else {
  24443. // parentBranch must have only one node, if it was empty we wouldnt be here
  24444. if (parentBranch.children.data.id != node.id) {
  24445. // if it is not self
  24446. this._calculateForces(distance, dx, dy, node, parentBranch);
  24447. }
  24448. }
  24449. }
  24450. }
  24451. }
  24452. /**
  24453. * Calculate the forces based on the distance.
  24454. *
  24455. * @param {number} distance
  24456. * @param {number} dx
  24457. * @param {number} dy
  24458. * @param {Node} node
  24459. * @param {Object} parentBranch
  24460. * @private
  24461. */
  24462. }, {
  24463. key: "_calculateForces",
  24464. value: function _calculateForces(distance, dx, dy, node, parentBranch) {
  24465. if (distance === 0) {
  24466. distance = 0.1;
  24467. dx = distance;
  24468. }
  24469. if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
  24470. distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
  24471. }
  24472. // the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
  24473. // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
  24474. var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass / Math.pow(distance, 3);
  24475. var fx = dx * gravityForce;
  24476. var fy = dy * gravityForce;
  24477. this.physicsBody.forces[node.id].x += fx;
  24478. this.physicsBody.forces[node.id].y += fy;
  24479. }
  24480. /**
  24481. * This function constructs the barnesHut tree recursively. It creates the root, splits it and starts placing the nodes.
  24482. *
  24483. * @param {Array.<Node>} nodes
  24484. * @param {Array.<number>} nodeIndices
  24485. * @returns {{root: {centerOfMass: {x: number, y: number}, mass: number, range: {minX: number, maxX: number, minY: number, maxY: number}, size: number, calcSize: number, children: {data: null}, maxWidth: number, level: number, childrenCount: number}}} BarnesHutTree
  24486. * @private
  24487. */
  24488. }, {
  24489. key: "_formBarnesHutTree",
  24490. value: function _formBarnesHutTree(nodes, nodeIndices) {
  24491. var node = void 0;
  24492. var nodeCount = nodeIndices.length;
  24493. var minX = nodes[nodeIndices[0]].x;
  24494. var minY = nodes[nodeIndices[0]].y;
  24495. var maxX = nodes[nodeIndices[0]].x;
  24496. var maxY = nodes[nodeIndices[0]].y;
  24497. // get the range of the nodes
  24498. for (var i = 1; i < nodeCount; i++) {
  24499. var _node = nodes[nodeIndices[i]];
  24500. var x = _node.x;
  24501. var y = _node.y;
  24502. if (_node.options.mass > 0) {
  24503. if (x < minX) {
  24504. minX = x;
  24505. }
  24506. if (x > maxX) {
  24507. maxX = x;
  24508. }
  24509. if (y < minY) {
  24510. minY = y;
  24511. }
  24512. if (y > maxY) {
  24513. maxY = y;
  24514. }
  24515. }
  24516. }
  24517. // make the range a square
  24518. var sizeDiff = Math.abs(maxX - minX) - Math.abs(maxY - minY); // difference between X and Y
  24519. if (sizeDiff > 0) {
  24520. minY -= 0.5 * sizeDiff;
  24521. maxY += 0.5 * sizeDiff;
  24522. } // xSize > ySize
  24523. else {
  24524. minX += 0.5 * sizeDiff;
  24525. maxX -= 0.5 * sizeDiff;
  24526. } // xSize < ySize
  24527. var minimumTreeSize = 1e-5;
  24528. var rootSize = Math.max(minimumTreeSize, Math.abs(maxX - minX));
  24529. var halfRootSize = 0.5 * rootSize;
  24530. var centerX = 0.5 * (minX + maxX),
  24531. centerY = 0.5 * (minY + maxY);
  24532. // construct the barnesHutTree
  24533. var barnesHutTree = {
  24534. root: {
  24535. centerOfMass: { x: 0, y: 0 },
  24536. mass: 0,
  24537. range: {
  24538. minX: centerX - halfRootSize,
  24539. maxX: centerX + halfRootSize,
  24540. minY: centerY - halfRootSize,
  24541. maxY: centerY + halfRootSize
  24542. },
  24543. size: rootSize,
  24544. calcSize: 1 / rootSize,
  24545. children: { data: null },
  24546. maxWidth: 0,
  24547. level: 0,
  24548. childrenCount: 4
  24549. }
  24550. };
  24551. this._splitBranch(barnesHutTree.root);
  24552. // place the nodes one by one recursively
  24553. for (var _i = 0; _i < nodeCount; _i++) {
  24554. node = nodes[nodeIndices[_i]];
  24555. if (node.options.mass > 0) {
  24556. this._placeInTree(barnesHutTree.root, node);
  24557. }
  24558. }
  24559. // make global
  24560. return barnesHutTree;
  24561. }
  24562. /**
  24563. * this updates the mass of a branch. this is increased by adding a node.
  24564. *
  24565. * @param {Object} parentBranch
  24566. * @param {Node} node
  24567. * @private
  24568. */
  24569. }, {
  24570. key: "_updateBranchMass",
  24571. value: function _updateBranchMass(parentBranch, node) {
  24572. var centerOfMass = parentBranch.centerOfMass;
  24573. var totalMass = parentBranch.mass + node.options.mass;
  24574. var totalMassInv = 1 / totalMass;
  24575. centerOfMass.x = centerOfMass.x * parentBranch.mass + node.x * node.options.mass;
  24576. centerOfMass.x *= totalMassInv;
  24577. centerOfMass.y = centerOfMass.y * parentBranch.mass + node.y * node.options.mass;
  24578. centerOfMass.y *= totalMassInv;
  24579. parentBranch.mass = totalMass;
  24580. var biggestSize = Math.max(Math.max(node.height, node.radius), node.width);
  24581. parentBranch.maxWidth = parentBranch.maxWidth < biggestSize ? biggestSize : parentBranch.maxWidth;
  24582. }
  24583. /**
  24584. * determine in which branch the node will be placed.
  24585. *
  24586. * @param {Object} parentBranch
  24587. * @param {Node} node
  24588. * @param {boolean} skipMassUpdate
  24589. * @private
  24590. */
  24591. }, {
  24592. key: "_placeInTree",
  24593. value: function _placeInTree(parentBranch, node, skipMassUpdate) {
  24594. if (skipMassUpdate != true || skipMassUpdate === undefined) {
  24595. // update the mass of the branch.
  24596. this._updateBranchMass(parentBranch, node);
  24597. }
  24598. var range = parentBranch.children.NW.range;
  24599. var region = void 0;
  24600. if (range.maxX > node.x) {
  24601. // in NW or SW
  24602. if (range.maxY > node.y) {
  24603. region = "NW";
  24604. } else {
  24605. region = "SW";
  24606. }
  24607. } else {
  24608. // in NE or SE
  24609. if (range.maxY > node.y) {
  24610. region = "NE";
  24611. } else {
  24612. region = "SE";
  24613. }
  24614. }
  24615. this._placeInRegion(parentBranch, node, region);
  24616. }
  24617. /**
  24618. * actually place the node in a region (or branch)
  24619. *
  24620. * @param {Object} parentBranch
  24621. * @param {Node} node
  24622. * @param {'NW'| 'NE' | 'SW' | 'SE'} region
  24623. * @private
  24624. */
  24625. }, {
  24626. key: "_placeInRegion",
  24627. value: function _placeInRegion(parentBranch, node, region) {
  24628. var children = parentBranch.children[region];
  24629. switch (children.childrenCount) {
  24630. case 0:
  24631. // place node here
  24632. children.children.data = node;
  24633. children.childrenCount = 1;
  24634. this._updateBranchMass(children, node);
  24635. break;
  24636. case 1:
  24637. // convert into children
  24638. // if there are two nodes exactly overlapping (on init, on opening of cluster etc.)
  24639. // we move one node a little bit and we do not put it in the tree.
  24640. if (children.children.data.x === node.x && children.children.data.y === node.y) {
  24641. node.x += this.seededRandom();
  24642. node.y += this.seededRandom();
  24643. } else {
  24644. this._splitBranch(children);
  24645. this._placeInTree(children, node);
  24646. }
  24647. break;
  24648. case 4:
  24649. // place in branch
  24650. this._placeInTree(children, node);
  24651. break;
  24652. }
  24653. }
  24654. /**
  24655. * this function splits a branch into 4 sub branches. If the branch contained a node, we place it in the subbranch
  24656. * after the split is complete.
  24657. *
  24658. * @param {Object} parentBranch
  24659. * @private
  24660. */
  24661. }, {
  24662. key: "_splitBranch",
  24663. value: function _splitBranch(parentBranch) {
  24664. // if the branch is shaded with a node, replace the node in the new subset.
  24665. var containedNode = null;
  24666. if (parentBranch.childrenCount === 1) {
  24667. containedNode = parentBranch.children.data;
  24668. parentBranch.mass = 0;
  24669. parentBranch.centerOfMass.x = 0;
  24670. parentBranch.centerOfMass.y = 0;
  24671. }
  24672. parentBranch.childrenCount = 4;
  24673. parentBranch.children.data = null;
  24674. this._insertRegion(parentBranch, "NW");
  24675. this._insertRegion(parentBranch, "NE");
  24676. this._insertRegion(parentBranch, "SW");
  24677. this._insertRegion(parentBranch, "SE");
  24678. if (containedNode != null) {
  24679. this._placeInTree(parentBranch, containedNode);
  24680. }
  24681. }
  24682. /**
  24683. * This function subdivides the region into four new segments.
  24684. * Specifically, this inserts a single new segment.
  24685. * It fills the children section of the parentBranch
  24686. *
  24687. * @param {Object} parentBranch
  24688. * @param {'NW'| 'NE' | 'SW' | 'SE'} region
  24689. * @private
  24690. */
  24691. }, {
  24692. key: "_insertRegion",
  24693. value: function _insertRegion(parentBranch, region) {
  24694. var minX = void 0,
  24695. maxX = void 0,
  24696. minY = void 0,
  24697. maxY = void 0;
  24698. var childSize = 0.5 * parentBranch.size;
  24699. switch (region) {
  24700. case "NW":
  24701. minX = parentBranch.range.minX;
  24702. maxX = parentBranch.range.minX + childSize;
  24703. minY = parentBranch.range.minY;
  24704. maxY = parentBranch.range.minY + childSize;
  24705. break;
  24706. case "NE":
  24707. minX = parentBranch.range.minX + childSize;
  24708. maxX = parentBranch.range.maxX;
  24709. minY = parentBranch.range.minY;
  24710. maxY = parentBranch.range.minY + childSize;
  24711. break;
  24712. case "SW":
  24713. minX = parentBranch.range.minX;
  24714. maxX = parentBranch.range.minX + childSize;
  24715. minY = parentBranch.range.minY + childSize;
  24716. maxY = parentBranch.range.maxY;
  24717. break;
  24718. case "SE":
  24719. minX = parentBranch.range.minX + childSize;
  24720. maxX = parentBranch.range.maxX;
  24721. minY = parentBranch.range.minY + childSize;
  24722. maxY = parentBranch.range.maxY;
  24723. break;
  24724. }
  24725. parentBranch.children[region] = {
  24726. centerOfMass: { x: 0, y: 0 },
  24727. mass: 0,
  24728. range: { minX: minX, maxX: maxX, minY: minY, maxY: maxY },
  24729. size: 0.5 * parentBranch.size,
  24730. calcSize: 2 * parentBranch.calcSize,
  24731. children: { data: null },
  24732. maxWidth: 0,
  24733. level: parentBranch.level + 1,
  24734. childrenCount: 0
  24735. };
  24736. }
  24737. //--------------------------- DEBUGGING BELOW ---------------------------//
  24738. /**
  24739. * This function is for debugging purposed, it draws the tree.
  24740. *
  24741. * @param {CanvasRenderingContext2D} ctx
  24742. * @param {string} color
  24743. * @private
  24744. */
  24745. }, {
  24746. key: "_debug",
  24747. value: function _debug(ctx, color) {
  24748. if (this.barnesHutTree !== undefined) {
  24749. ctx.lineWidth = 1;
  24750. this._drawBranch(this.barnesHutTree.root, ctx, color);
  24751. }
  24752. }
  24753. /**
  24754. * This function is for debugging purposes. It draws the branches recursively.
  24755. *
  24756. * @param {Object} branch
  24757. * @param {CanvasRenderingContext2D} ctx
  24758. * @param {string} color
  24759. * @private
  24760. */
  24761. }, {
  24762. key: "_drawBranch",
  24763. value: function _drawBranch(branch, ctx, color) {
  24764. if (color === undefined) {
  24765. color = "#FF0000";
  24766. }
  24767. if (branch.childrenCount === 4) {
  24768. this._drawBranch(branch.children.NW, ctx);
  24769. this._drawBranch(branch.children.NE, ctx);
  24770. this._drawBranch(branch.children.SE, ctx);
  24771. this._drawBranch(branch.children.SW, ctx);
  24772. }
  24773. ctx.strokeStyle = color;
  24774. ctx.beginPath();
  24775. ctx.moveTo(branch.range.minX, branch.range.minY);
  24776. ctx.lineTo(branch.range.maxX, branch.range.minY);
  24777. ctx.stroke();
  24778. ctx.beginPath();
  24779. ctx.moveTo(branch.range.maxX, branch.range.minY);
  24780. ctx.lineTo(branch.range.maxX, branch.range.maxY);
  24781. ctx.stroke();
  24782. ctx.beginPath();
  24783. ctx.moveTo(branch.range.maxX, branch.range.maxY);
  24784. ctx.lineTo(branch.range.minX, branch.range.maxY);
  24785. ctx.stroke();
  24786. ctx.beginPath();
  24787. ctx.moveTo(branch.range.minX, branch.range.maxY);
  24788. ctx.lineTo(branch.range.minX, branch.range.minY);
  24789. ctx.stroke();
  24790. /*
  24791. if (branch.mass > 0) {
  24792. ctx.circle(branch.centerOfMass.x, branch.centerOfMass.y, 3*branch.mass);
  24793. ctx.stroke();
  24794. }
  24795. */
  24796. }
  24797. }]);
  24798. return BarnesHutSolver;
  24799. }();
  24800. exports["default"] = BarnesHutSolver;
  24801. /***/
  24802. }),
  24803. /* 121 */
  24804. /***/
  24805. (function(module, exports, __webpack_require__) {
  24806. "use strict";
  24807. Object.defineProperty(exports, "__esModule", {
  24808. value: true
  24809. });
  24810. var _classCallCheck2 = __webpack_require__(0);
  24811. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  24812. var _createClass2 = __webpack_require__(1);
  24813. var _createClass3 = _interopRequireDefault(_createClass2);
  24814. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  24815. /**
  24816. * Central Gravity Solver
  24817. */
  24818. var CentralGravitySolver = function() {
  24819. /**
  24820. * @param {Object} body
  24821. * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
  24822. * @param {Object} options
  24823. */
  24824. function CentralGravitySolver(body, physicsBody, options) {
  24825. (0, _classCallCheck3["default"])(this, CentralGravitySolver);
  24826. this.body = body;
  24827. this.physicsBody = physicsBody;
  24828. this.setOptions(options);
  24829. }
  24830. /**
  24831. *
  24832. * @param {Object} options
  24833. */
  24834. (0, _createClass3["default"])(CentralGravitySolver, [{
  24835. key: "setOptions",
  24836. value: function setOptions(options) {
  24837. this.options = options;
  24838. }
  24839. /**
  24840. * Calculates forces for each node
  24841. */
  24842. }, {
  24843. key: "solve",
  24844. value: function solve() {
  24845. var dx = void 0,
  24846. dy = void 0,
  24847. distance = void 0,
  24848. node = void 0;
  24849. var nodes = this.body.nodes;
  24850. var nodeIndices = this.physicsBody.physicsNodeIndices;
  24851. var forces = this.physicsBody.forces;
  24852. for (var i = 0; i < nodeIndices.length; i++) {
  24853. var nodeId = nodeIndices[i];
  24854. node = nodes[nodeId];
  24855. dx = -node.x;
  24856. dy = -node.y;
  24857. distance = Math.sqrt(dx * dx + dy * dy);
  24858. this._calculateForces(distance, dx, dy, forces, node);
  24859. }
  24860. }
  24861. /**
  24862. * Calculate the forces based on the distance.
  24863. * @param {number} distance
  24864. * @param {number} dx
  24865. * @param {number} dy
  24866. * @param {Object<Node.id, vis.Node>} forces
  24867. * @param {Node} node
  24868. * @private
  24869. */
  24870. }, {
  24871. key: "_calculateForces",
  24872. value: function _calculateForces(distance, dx, dy, forces, node) {
  24873. var gravityForce = distance === 0 ? 0 : this.options.centralGravity / distance;
  24874. forces[node.id].x = dx * gravityForce;
  24875. forces[node.id].y = dy * gravityForce;
  24876. }
  24877. }]);
  24878. return CentralGravitySolver;
  24879. }();
  24880. exports["default"] = CentralGravitySolver;
  24881. /***/
  24882. }),
  24883. /* 122 */
  24884. /***/
  24885. (function(module, exports, __webpack_require__) {
  24886. "use strict";
  24887. Object.defineProperty(exports, "__esModule", {
  24888. value: true
  24889. });
  24890. /**
  24891. * This object contains all possible options. It will check if the types are correct, if required if the option is one
  24892. * of the allowed values.
  24893. *
  24894. * __any__ means that the name of the property does not matter.
  24895. * __type__ is a required field for all objects and contains the allowed types of all objects
  24896. */
  24897. var string = 'string';
  24898. var bool = 'boolean';
  24899. var number = 'number';
  24900. var array = 'array';
  24901. var object = 'object'; // should only be in a __type__ property
  24902. var dom = 'dom';
  24903. var any = 'any';
  24904. // List of endpoints
  24905. var endPoints = ['arrow', 'circle', 'bar'];
  24906. var allOptions = {
  24907. configure: {
  24908. enabled: { boolean: bool },
  24909. filter: { boolean: bool, string: string, array: array, 'function': 'function' },
  24910. container: { dom: dom },
  24911. showButton: { boolean: bool },
  24912. __type__: { object: object, boolean: bool, string: string, array: array, 'function': 'function' }
  24913. },
  24914. edges: {
  24915. arrows: {
  24916. to: { enabled: { boolean: bool }, scaleFactor: { number: number }, type: { string: endPoints }, __type__: { object: object, boolean: bool } },
  24917. middle: { enabled: { boolean: bool }, scaleFactor: { number: number }, type: { string: endPoints }, __type__: { object: object, boolean: bool } },
  24918. from: { enabled: { boolean: bool }, scaleFactor: { number: number }, type: { string: endPoints }, __type__: { object: object, boolean: bool } },
  24919. __type__: { string: ['from', 'to', 'middle'], object: object }
  24920. },
  24921. arrowStrikethrough: { boolean: bool },
  24922. chosen: {
  24923. label: { boolean: bool, 'function': 'function' },
  24924. edge: { boolean: bool, 'function': 'function' },
  24925. __type__: { object: object, boolean: bool }
  24926. },
  24927. color: {
  24928. color: { string: string },
  24929. highlight: { string: string },
  24930. hover: { string: string },
  24931. inherit: { string: ['from', 'to', 'both'], boolean: bool },
  24932. opacity: { number: number },
  24933. __type__: { object: object, string: string }
  24934. },
  24935. dashes: { boolean: bool, array: array },
  24936. font: {
  24937. color: { string: string },
  24938. size: { number: number }, // px
  24939. face: { string: string },
  24940. background: { string: string },
  24941. strokeWidth: { number: number }, // px
  24942. strokeColor: { string: string },
  24943. align: { string: ['horizontal', 'top', 'middle', 'bottom'] },
  24944. vadjust: { number: number },
  24945. multi: { boolean: bool, string: string },
  24946. bold: {
  24947. color: { string: string },
  24948. size: { number: number }, // px
  24949. face: { string: string },
  24950. mod: { string: string },
  24951. vadjust: { number: number },
  24952. __type__: { object: object, string: string }
  24953. },
  24954. boldital: {
  24955. color: { string: string },
  24956. size: { number: number }, // px
  24957. face: { string: string },
  24958. mod: { string: string },
  24959. vadjust: { number: number },
  24960. __type__: { object: object, string: string }
  24961. },
  24962. ital: {
  24963. color: { string: string },
  24964. size: { number: number }, // px
  24965. face: { string: string },
  24966. mod: { string: string },
  24967. vadjust: { number: number },
  24968. __type__: { object: object, string: string }
  24969. },
  24970. mono: {
  24971. color: { string: string },
  24972. size: { number: number }, // px
  24973. face: { string: string },
  24974. mod: { string: string },
  24975. vadjust: { number: number },
  24976. __type__: { object: object, string: string }
  24977. },
  24978. __type__: { object: object, string: string }
  24979. },
  24980. hidden: { boolean: bool },
  24981. hoverWidth: { 'function': 'function', number: number },
  24982. label: { string: string, 'undefined': 'undefined' },
  24983. labelHighlightBold: { boolean: bool },
  24984. length: { number: number, 'undefined': 'undefined' },
  24985. physics: { boolean: bool },
  24986. scaling: {
  24987. min: { number: number },
  24988. max: { number: number },
  24989. label: {
  24990. enabled: { boolean: bool },
  24991. min: { number: number },
  24992. max: { number: number },
  24993. maxVisible: { number: number },
  24994. drawThreshold: { number: number },
  24995. __type__: { object: object, boolean: bool }
  24996. },
  24997. customScalingFunction: { 'function': 'function' },
  24998. __type__: { object: object }
  24999. },
  25000. selectionWidth: { 'function': 'function', number: number },
  25001. selfReferenceSize: { number: number },
  25002. shadow: {
  25003. enabled: { boolean: bool },
  25004. color: { string: string },
  25005. size: { number: number },
  25006. x: { number: number },
  25007. y: { number: number },
  25008. __type__: { object: object, boolean: bool }
  25009. },
  25010. smooth: {
  25011. enabled: { boolean: bool },
  25012. type: { string: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW', 'cubicBezier'] },
  25013. roundness: { number: number },
  25014. forceDirection: { string: ['horizontal', 'vertical', 'none'], boolean: bool },
  25015. __type__: { object: object, boolean: bool }
  25016. },
  25017. title: { string: string, 'undefined': 'undefined' },
  25018. width: { number: number },
  25019. widthConstraint: {
  25020. maximum: { number: number },
  25021. __type__: { object: object, boolean: bool, number: number }
  25022. },
  25023. value: { number: number, 'undefined': 'undefined' },
  25024. __type__: { object: object }
  25025. },
  25026. groups: {
  25027. useDefaultGroups: { boolean: bool },
  25028. __any__: 'get from nodes, will be overwritten below',
  25029. __type__: { object: object }
  25030. },
  25031. interaction: {
  25032. dragNodes: { boolean: bool },
  25033. dragView: { boolean: bool },
  25034. hideEdgesOnDrag: { boolean: bool },
  25035. hideNodesOnDrag: { boolean: bool },
  25036. hover: { boolean: bool },
  25037. keyboard: {
  25038. enabled: { boolean: bool },
  25039. speed: { x: { number: number }, y: { number: number }, zoom: { number: number }, __type__: { object: object } },
  25040. bindToWindow: { boolean: bool },
  25041. __type__: { object: object, boolean: bool }
  25042. },
  25043. multiselect: { boolean: bool },
  25044. navigationButtons: { boolean: bool },
  25045. selectable: { boolean: bool },
  25046. selectConnectedEdges: { boolean: bool },
  25047. hoverConnectedEdges: { boolean: bool },
  25048. tooltipDelay: { number: number },
  25049. zoomView: { boolean: bool },
  25050. __type__: { object: object }
  25051. },
  25052. layout: {
  25053. randomSeed: { 'undefined': 'undefined', number: number },
  25054. improvedLayout: { boolean: bool },
  25055. hierarchical: {
  25056. enabled: { boolean: bool },
  25057. levelSeparation: { number: number },
  25058. nodeSpacing: { number: number },
  25059. treeSpacing: { number: number },
  25060. blockShifting: { boolean: bool },
  25061. edgeMinimization: { boolean: bool },
  25062. parentCentralization: { boolean: bool },
  25063. direction: { string: ['UD', 'DU', 'LR', 'RL'] }, // UD, DU, LR, RL
  25064. sortMethod: { string: ['hubsize', 'directed'] }, // hubsize, directed
  25065. __type__: { object: object, boolean: bool }
  25066. },
  25067. __type__: { object: object }
  25068. },
  25069. manipulation: {
  25070. enabled: { boolean: bool },
  25071. initiallyActive: { boolean: bool },
  25072. addNode: { boolean: bool, 'function': 'function' },
  25073. addEdge: { boolean: bool, 'function': 'function' },
  25074. editNode: { 'function': 'function' },
  25075. editEdge: {
  25076. editWithoutDrag: { 'function': 'function' },
  25077. __type__: { object: object, boolean: bool, 'function': 'function' }
  25078. },
  25079. deleteNode: { boolean: bool, 'function': 'function' },
  25080. deleteEdge: { boolean: bool, 'function': 'function' },
  25081. controlNodeStyle: 'get from nodes, will be overwritten below',
  25082. __type__: { object: object, boolean: bool }
  25083. },
  25084. nodes: {
  25085. borderWidth: { number: number },
  25086. borderWidthSelected: { number: number, 'undefined': 'undefined' },
  25087. brokenImage: { string: string, 'undefined': 'undefined' },
  25088. chosen: {
  25089. label: { boolean: bool, 'function': 'function' },
  25090. node: { boolean: bool, 'function': 'function' },
  25091. __type__: { object: object, boolean: bool }
  25092. },
  25093. color: {
  25094. border: { string: string },
  25095. background: { string: string },
  25096. highlight: {
  25097. border: { string: string },
  25098. background: { string: string },
  25099. __type__: { object: object, string: string }
  25100. },
  25101. hover: {
  25102. border: { string: string },
  25103. background: { string: string },
  25104. __type__: { object: object, string: string }
  25105. },
  25106. __type__: { object: object, string: string }
  25107. },
  25108. fixed: {
  25109. x: { boolean: bool },
  25110. y: { boolean: bool },
  25111. __type__: { object: object, boolean: bool }
  25112. },
  25113. font: {
  25114. align: { string: string },
  25115. color: { string: string },
  25116. size: { number: number }, // px
  25117. face: { string: string },
  25118. background: { string: string },
  25119. strokeWidth: { number: number }, // px
  25120. strokeColor: { string: string },
  25121. vadjust: { number: number },
  25122. multi: { boolean: bool, string: string },
  25123. bold: {
  25124. color: { string: string },
  25125. size: { number: number }, // px
  25126. face: { string: string },
  25127. mod: { string: string },
  25128. vadjust: { number: number },
  25129. __type__: { object: object, string: string }
  25130. },
  25131. boldital: {
  25132. color: { string: string },
  25133. size: { number: number }, // px
  25134. face: { string: string },
  25135. mod: { string: string },
  25136. vadjust: { number: number },
  25137. __type__: { object: object, string: string }
  25138. },
  25139. ital: {
  25140. color: { string: string },
  25141. size: { number: number }, // px
  25142. face: { string: string },
  25143. mod: { string: string },
  25144. vadjust: { number: number },
  25145. __type__: { object: object, string: string }
  25146. },
  25147. mono: {
  25148. color: { string: string },
  25149. size: { number: number }, // px
  25150. face: { string: string },
  25151. mod: { string: string },
  25152. vadjust: { number: number },
  25153. __type__: { object: object, string: string }
  25154. },
  25155. __type__: { object: object, string: string }
  25156. },
  25157. group: { string: string, number: number, 'undefined': 'undefined' },
  25158. heightConstraint: {
  25159. minimum: { number: number },
  25160. valign: { string: string },
  25161. __type__: { object: object, boolean: bool, number: number }
  25162. },
  25163. hidden: { boolean: bool },
  25164. icon: {
  25165. face: { string: string },
  25166. code: { string: string }, //'\uf007',
  25167. size: { number: number }, //50,
  25168. color: { string: string },
  25169. __type__: { object: object }
  25170. },
  25171. id: { string: string, number: number },
  25172. image: {
  25173. selected: { string: string, 'undefined': 'undefined' }, // --> URL
  25174. unselected: { string: string, 'undefined': 'undefined' }, // --> URL
  25175. __type__: { object: object, string: string }
  25176. },
  25177. label: { string: string, 'undefined': 'undefined' },
  25178. labelHighlightBold: { boolean: bool },
  25179. level: { number: number, 'undefined': 'undefined' },
  25180. margin: {
  25181. top: { number: number },
  25182. right: { number: number },
  25183. bottom: { number: number },
  25184. left: { number: number },
  25185. __type__: { object: object, number: number }
  25186. },
  25187. mass: { number: number },
  25188. physics: { boolean: bool },
  25189. scaling: {
  25190. min: { number: number },
  25191. max: { number: number },
  25192. label: {
  25193. enabled: { boolean: bool },
  25194. min: { number: number },
  25195. max: { number: number },
  25196. maxVisible: { number: number },
  25197. drawThreshold: { number: number },
  25198. __type__: { object: object, boolean: bool }
  25199. },
  25200. customScalingFunction: { 'function': 'function' },
  25201. __type__: { object: object }
  25202. },
  25203. shadow: {
  25204. enabled: { boolean: bool },
  25205. color: { string: string },
  25206. size: { number: number },
  25207. x: { number: number },
  25208. y: { number: number },
  25209. __type__: { object: object, boolean: bool }
  25210. },
  25211. shape: { string: ['ellipse', 'circle', 'database', 'box', 'text', 'image', 'circularImage', 'diamond', 'dot', 'star', 'triangle', 'triangleDown', 'square', 'icon', 'hexagon'] },
  25212. shapeProperties: {
  25213. borderDashes: { boolean: bool, array: array },
  25214. borderRadius: { number: number },
  25215. interpolation: { boolean: bool },
  25216. useImageSize: { boolean: bool },
  25217. useBorderWithImage: { boolean: bool },
  25218. __type__: { object: object }
  25219. },
  25220. size: { number: number },
  25221. title: { string: string, dom: dom, 'undefined': 'undefined' },
  25222. value: { number: number, 'undefined': 'undefined' },
  25223. widthConstraint: {
  25224. minimum: { number: number },
  25225. maximum: { number: number },
  25226. __type__: { object: object, boolean: bool, number: number }
  25227. },
  25228. x: { number: number },
  25229. y: { number: number },
  25230. __type__: { object: object }
  25231. },
  25232. physics: {
  25233. enabled: { boolean: bool },
  25234. barnesHut: {
  25235. gravitationalConstant: { number: number },
  25236. centralGravity: { number: number },
  25237. springLength: { number: number },
  25238. springConstant: { number: number },
  25239. damping: { number: number },
  25240. avoidOverlap: { number: number },
  25241. __type__: { object: object }
  25242. },
  25243. forceAtlas2Based: {
  25244. gravitationalConstant: { number: number },
  25245. centralGravity: { number: number },
  25246. springLength: { number: number },
  25247. springConstant: { number: number },
  25248. damping: { number: number },
  25249. avoidOverlap: { number: number },
  25250. __type__: { object: object }
  25251. },
  25252. repulsion: {
  25253. centralGravity: { number: number },
  25254. springLength: { number: number },
  25255. springConstant: { number: number },
  25256. nodeDistance: { number: number },
  25257. damping: { number: number },
  25258. __type__: { object: object }
  25259. },
  25260. hierarchicalRepulsion: {
  25261. centralGravity: { number: number },
  25262. springLength: { number: number },
  25263. springConstant: { number: number },
  25264. nodeDistance: { number: number },
  25265. damping: { number: number },
  25266. __type__: { object: object }
  25267. },
  25268. maxVelocity: { number: number },
  25269. minVelocity: { number: number }, // px/s
  25270. solver: { string: ['barnesHut', 'repulsion', 'hierarchicalRepulsion', 'forceAtlas2Based'] },
  25271. stabilization: {
  25272. enabled: { boolean: bool },
  25273. iterations: { number: number }, // maximum number of iteration to stabilize
  25274. updateInterval: { number: number },
  25275. onlyDynamicEdges: { boolean: bool },
  25276. fit: { boolean: bool },
  25277. __type__: { object: object, boolean: bool }
  25278. },
  25279. timestep: { number: number },
  25280. adaptiveTimestep: { boolean: bool },
  25281. __type__: { object: object, boolean: bool }
  25282. },
  25283. //globals :
  25284. autoResize: { boolean: bool },
  25285. clickToUse: { boolean: bool },
  25286. locale: { string: string },
  25287. locales: {
  25288. __any__: { any: any },
  25289. __type__: { object: object }
  25290. },
  25291. height: { string: string },
  25292. width: { string: string },
  25293. __type__: { object: object }
  25294. };
  25295. allOptions.groups.__any__ = allOptions.nodes;
  25296. allOptions.manipulation.controlNodeStyle = allOptions.nodes;
  25297. var configureOptions = {
  25298. nodes: {
  25299. borderWidth: [1, 0, 10, 1],
  25300. borderWidthSelected: [2, 0, 10, 1],
  25301. color: {
  25302. border: ['color', '#2B7CE9'],
  25303. background: ['color', '#97C2FC'],
  25304. highlight: {
  25305. border: ['color', '#2B7CE9'],
  25306. background: ['color', '#D2E5FF']
  25307. },
  25308. hover: {
  25309. border: ['color', '#2B7CE9'],
  25310. background: ['color', '#D2E5FF']
  25311. }
  25312. },
  25313. fixed: {
  25314. x: false,
  25315. y: false
  25316. },
  25317. font: {
  25318. color: ['color', '#343434'],
  25319. size: [14, 0, 100, 1], // px
  25320. face: ['arial', 'verdana', 'tahoma'],
  25321. background: ['color', 'none'],
  25322. strokeWidth: [0, 0, 50, 1], // px
  25323. strokeColor: ['color', '#ffffff']
  25324. },
  25325. //group: 'string',
  25326. hidden: false,
  25327. labelHighlightBold: true,
  25328. //icon: {
  25329. // face: 'string', //'FontAwesome',
  25330. // code: 'string', //'\uf007',
  25331. // size: [50, 0, 200, 1], //50,
  25332. // color: ['color','#2B7CE9'] //'#aa00ff'
  25333. //},
  25334. //image: 'string', // --> URL
  25335. physics: true,
  25336. scaling: {
  25337. min: [10, 0, 200, 1],
  25338. max: [30, 0, 200, 1],
  25339. label: {
  25340. enabled: false,
  25341. min: [14, 0, 200, 1],
  25342. max: [30, 0, 200, 1],
  25343. maxVisible: [30, 0, 200, 1],
  25344. drawThreshold: [5, 0, 20, 1]
  25345. }
  25346. },
  25347. shadow: {
  25348. enabled: false,
  25349. color: 'rgba(0,0,0,0.5)',
  25350. size: [10, 0, 20, 1],
  25351. x: [5, -30, 30, 1],
  25352. y: [5, -30, 30, 1]
  25353. },
  25354. shape: ['ellipse', 'box', 'circle', 'database', 'diamond', 'dot', 'square', 'star', 'text', 'triangle', 'triangleDown', 'hexagon'],
  25355. shapeProperties: {
  25356. borderDashes: false,
  25357. borderRadius: [6, 0, 20, 1],
  25358. interpolation: true,
  25359. useImageSize: false
  25360. },
  25361. size: [25, 0, 200, 1]
  25362. },
  25363. edges: {
  25364. arrows: {
  25365. to: { enabled: false, scaleFactor: [1, 0, 3, 0.05], type: 'arrow' },
  25366. middle: { enabled: false, scaleFactor: [1, 0, 3, 0.05], type: 'arrow' },
  25367. from: { enabled: false, scaleFactor: [1, 0, 3, 0.05], type: 'arrow' }
  25368. },
  25369. arrowStrikethrough: true,
  25370. color: {
  25371. color: ['color', '#848484'],
  25372. highlight: ['color', '#848484'],
  25373. hover: ['color', '#848484'],
  25374. inherit: ['from', 'to', 'both', true, false],
  25375. opacity: [1, 0, 1, 0.05]
  25376. },
  25377. dashes: false,
  25378. font: {
  25379. color: ['color', '#343434'],
  25380. size: [14, 0, 100, 1], // px
  25381. face: ['arial', 'verdana', 'tahoma'],
  25382. background: ['color', 'none'],
  25383. strokeWidth: [2, 0, 50, 1], // px
  25384. strokeColor: ['color', '#ffffff'],
  25385. align: ['horizontal', 'top', 'middle', 'bottom']
  25386. },
  25387. hidden: false,
  25388. hoverWidth: [1.5, 0, 5, 0.1],
  25389. labelHighlightBold: true,
  25390. physics: true,
  25391. scaling: {
  25392. min: [1, 0, 100, 1],
  25393. max: [15, 0, 100, 1],
  25394. label: {
  25395. enabled: true,
  25396. min: [14, 0, 200, 1],
  25397. max: [30, 0, 200, 1],
  25398. maxVisible: [30, 0, 200, 1],
  25399. drawThreshold: [5, 0, 20, 1]
  25400. }
  25401. },
  25402. selectionWidth: [1.5, 0, 5, 0.1],
  25403. selfReferenceSize: [20, 0, 200, 1],
  25404. shadow: {
  25405. enabled: false,
  25406. color: 'rgba(0,0,0,0.5)',
  25407. size: [10, 0, 20, 1],
  25408. x: [5, -30, 30, 1],
  25409. y: [5, -30, 30, 1]
  25410. },
  25411. smooth: {
  25412. enabled: true,
  25413. type: ['dynamic', 'continuous', 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW', 'cubicBezier'],
  25414. forceDirection: ['horizontal', 'vertical', 'none'],
  25415. roundness: [0.5, 0, 1, 0.05]
  25416. },
  25417. width: [1, 0, 30, 1]
  25418. },
  25419. layout: {
  25420. //randomSeed: [0, 0, 500, 1],
  25421. //improvedLayout: true,
  25422. hierarchical: {
  25423. enabled: false,
  25424. levelSeparation: [150, 20, 500, 5],
  25425. nodeSpacing: [100, 20, 500, 5],
  25426. treeSpacing: [200, 20, 500, 5],
  25427. blockShifting: true,
  25428. edgeMinimization: true,
  25429. parentCentralization: true,
  25430. direction: ['UD', 'DU', 'LR', 'RL'], // UD, DU, LR, RL
  25431. sortMethod: ['hubsize', 'directed'] // hubsize, directed
  25432. }
  25433. },
  25434. interaction: {
  25435. dragNodes: true,
  25436. dragView: true,
  25437. hideEdgesOnDrag: false,
  25438. hideNodesOnDrag: false,
  25439. hover: false,
  25440. keyboard: {
  25441. enabled: false,
  25442. speed: { x: [10, 0, 40, 1], y: [10, 0, 40, 1], zoom: [0.02, 0, 0.1, 0.005] },
  25443. bindToWindow: true
  25444. },
  25445. multiselect: false,
  25446. navigationButtons: false,
  25447. selectable: true,
  25448. selectConnectedEdges: true,
  25449. hoverConnectedEdges: true,
  25450. tooltipDelay: [300, 0, 1000, 25],
  25451. zoomView: true
  25452. },
  25453. manipulation: {
  25454. enabled: false,
  25455. initiallyActive: false
  25456. },
  25457. physics: {
  25458. enabled: true,
  25459. barnesHut: {
  25460. //theta: [0.5, 0.1, 1, 0.05],
  25461. gravitationalConstant: [-2000, -30000, 0, 50],
  25462. centralGravity: [0.3, 0, 10, 0.05],
  25463. springLength: [95, 0, 500, 5],
  25464. springConstant: [0.04, 0, 1.2, 0.005],
  25465. damping: [0.09, 0, 1, 0.01],
  25466. avoidOverlap: [0, 0, 1, 0.01]
  25467. },
  25468. forceAtlas2Based: {
  25469. //theta: [0.5, 0.1, 1, 0.05],
  25470. gravitationalConstant: [-50, -500, 0, 1],
  25471. centralGravity: [0.01, 0, 1, 0.005],
  25472. springLength: [95, 0, 500, 5],
  25473. springConstant: [0.08, 0, 1.2, 0.005],
  25474. damping: [0.4, 0, 1, 0.01],
  25475. avoidOverlap: [0, 0, 1, 0.01]
  25476. },
  25477. repulsion: {
  25478. centralGravity: [0.2, 0, 10, 0.05],
  25479. springLength: [200, 0, 500, 5],
  25480. springConstant: [0.05, 0, 1.2, 0.005],
  25481. nodeDistance: [100, 0, 500, 5],
  25482. damping: [0.09, 0, 1, 0.01]
  25483. },
  25484. hierarchicalRepulsion: {
  25485. centralGravity: [0.2, 0, 10, 0.05],
  25486. springLength: [100, 0, 500, 5],
  25487. springConstant: [0.01, 0, 1.2, 0.005],
  25488. nodeDistance: [120, 0, 500, 5],
  25489. damping: [0.09, 0, 1, 0.01]
  25490. },
  25491. maxVelocity: [50, 0, 150, 1],
  25492. minVelocity: [0.1, 0.01, 0.5, 0.01],
  25493. solver: ['barnesHut', 'forceAtlas2Based', 'repulsion', 'hierarchicalRepulsion'],
  25494. timestep: [0.5, 0.01, 1, 0.01]
  25495. //adaptiveTimestep: true
  25496. }
  25497. };
  25498. exports.allOptions = allOptions;
  25499. exports.configureOptions = configureOptions;
  25500. /***/
  25501. }),
  25502. /* 123 */
  25503. /***/
  25504. (function(module, exports, __webpack_require__) {
  25505. "use strict";
  25506. var util = __webpack_require__(2);
  25507. // Graph3d
  25508. util.extend(exports, __webpack_require__(159));
  25509. // Timeline & Graph2d
  25510. util.extend(exports, __webpack_require__(177));
  25511. // Network
  25512. util.extend(exports, __webpack_require__(181));
  25513. /***/
  25514. }),
  25515. /* 124 */
  25516. /***/
  25517. (function(module, exports, __webpack_require__) {
  25518. __webpack_require__(49);
  25519. __webpack_require__(60);
  25520. module.exports = __webpack_require__(136);
  25521. /***/
  25522. }),
  25523. /* 125 */
  25524. /***/
  25525. (function(module, exports, __webpack_require__) {
  25526. "use strict";
  25527. var addToUnscopables = __webpack_require__(126);
  25528. var step = __webpack_require__(127);
  25529. var Iterators = __webpack_require__(31);
  25530. var toIObject = __webpack_require__(25);
  25531. // 22.1.3.4 Array.prototype.entries()
  25532. // 22.1.3.13 Array.prototype.keys()
  25533. // 22.1.3.29 Array.prototype.values()
  25534. // 22.1.3.30 Array.prototype[@@iterator]()
  25535. module.exports = __webpack_require__(79)(Array, 'Array', function(iterated, kind) {
  25536. this._t = toIObject(iterated); // target
  25537. this._i = 0; // next index
  25538. this._k = kind; // kind
  25539. // 22.1.5.2.1 %ArrayIteratorPrototype%.next()
  25540. }, function() {
  25541. var O = this._t;
  25542. var kind = this._k;
  25543. var index = this._i++;
  25544. if (!O || index >= O.length) {
  25545. this._t = undefined;
  25546. return step(1);
  25547. }
  25548. if (kind == 'keys') return step(0, index);
  25549. if (kind == 'values') return step(0, O[index]);
  25550. return step(0, [index, O[index]]);
  25551. }, 'values');
  25552. // argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7)
  25553. Iterators.Arguments = Iterators.Array;
  25554. addToUnscopables('keys');
  25555. addToUnscopables('values');
  25556. addToUnscopables('entries');
  25557. /***/
  25558. }),
  25559. /* 126 */
  25560. /***/
  25561. (function(module, exports) {
  25562. module.exports = function() { /* empty */ };
  25563. /***/
  25564. }),
  25565. /* 127 */
  25566. /***/
  25567. (function(module, exports) {
  25568. module.exports = function(done, value) {
  25569. return { value: value, done: !!done };
  25570. };
  25571. /***/
  25572. }),
  25573. /* 128 */
  25574. /***/
  25575. (function(module, exports) {
  25576. module.exports = function(it) {
  25577. if (typeof it != 'function') throw TypeError(it + ' is not a function!');
  25578. return it;
  25579. };
  25580. /***/
  25581. }),
  25582. /* 129 */
  25583. /***/
  25584. (function(module, exports, __webpack_require__) {
  25585. "use strict";
  25586. var create = __webpack_require__(54);
  25587. var descriptor = __webpack_require__(39);
  25588. var setToStringTag = __webpack_require__(59);
  25589. var IteratorPrototype = {};
  25590. // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
  25591. __webpack_require__(26)(IteratorPrototype, __webpack_require__(13)('iterator'), function() { return this; });
  25592. module.exports = function(Constructor, NAME, next) {
  25593. Constructor.prototype = create(IteratorPrototype, { next: descriptor(1, next) });
  25594. setToStringTag(Constructor, NAME + ' Iterator');
  25595. };
  25596. /***/
  25597. }),
  25598. /* 130 */
  25599. /***/
  25600. (function(module, exports, __webpack_require__) {
  25601. var dP = __webpack_require__(20);
  25602. var anObject = __webpack_require__(27);
  25603. var getKeys = __webpack_require__(33);
  25604. module.exports = __webpack_require__(21) ? Object.defineProperties : function defineProperties(O, Properties) {
  25605. anObject(O);
  25606. var keys = getKeys(Properties);
  25607. var length = keys.length;
  25608. var i = 0;
  25609. var P;
  25610. while (length > i) dP.f(O, P = keys[i++], Properties[P]);
  25611. return O;
  25612. };
  25613. /***/
  25614. }),
  25615. /* 131 */
  25616. /***/
  25617. (function(module, exports, __webpack_require__) {
  25618. // false -> Array#indexOf
  25619. // true -> Array#includes
  25620. var toIObject = __webpack_require__(25);
  25621. var toLength = __webpack_require__(132);
  25622. var toAbsoluteIndex = __webpack_require__(133);
  25623. module.exports = function(IS_INCLUDES) {
  25624. return function($this, el, fromIndex) {
  25625. var O = toIObject($this);
  25626. var length = toLength(O.length);
  25627. var index = toAbsoluteIndex(fromIndex, length);
  25628. var value;
  25629. // Array#includes uses SameValueZero equality algorithm
  25630. // eslint-disable-next-line no-self-compare
  25631. if (IS_INCLUDES && el != el)
  25632. while (length > index) {
  25633. value = O[index++];
  25634. // eslint-disable-next-line no-self-compare
  25635. if (value != value) return true;
  25636. // Array#indexOf ignores holes, Array#includes - not
  25637. } else
  25638. for (; length > index; index++)
  25639. if (IS_INCLUDES || index in O) {
  25640. if (O[index] === el) return IS_INCLUDES || index || 0;
  25641. }
  25642. return !IS_INCLUDES && -1;
  25643. };
  25644. };
  25645. /***/
  25646. }),
  25647. /* 132 */
  25648. /***/
  25649. (function(module, exports, __webpack_require__) {
  25650. // 7.1.15 ToLength
  25651. var toInteger = __webpack_require__(55);
  25652. var min = Math.min;
  25653. module.exports = function(it) {
  25654. return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991
  25655. };
  25656. /***/
  25657. }),
  25658. /* 133 */
  25659. /***/
  25660. (function(module, exports, __webpack_require__) {
  25661. var toInteger = __webpack_require__(55);
  25662. var max = Math.max;
  25663. var min = Math.min;
  25664. module.exports = function(index, length) {
  25665. index = toInteger(index);
  25666. return index < 0 ? max(index + length, 0) : min(index, length);
  25667. };
  25668. /***/
  25669. }),
  25670. /* 134 */
  25671. /***/
  25672. (function(module, exports, __webpack_require__) {
  25673. var document = __webpack_require__(18).document;
  25674. module.exports = document && document.documentElement;
  25675. /***/
  25676. }),
  25677. /* 135 */
  25678. /***/
  25679. (function(module, exports, __webpack_require__) {
  25680. var toInteger = __webpack_require__(55);
  25681. var defined = __webpack_require__(51);
  25682. // true -> String#at
  25683. // false -> String#codePointAt
  25684. module.exports = function(TO_STRING) {
  25685. return function(that, pos) {
  25686. var s = String(defined(that));
  25687. var i = toInteger(pos);
  25688. var l = s.length;
  25689. var a, b;
  25690. if (i < 0 || i >= l) return TO_STRING ? '' : undefined;
  25691. a = s.charCodeAt(i);
  25692. return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff ?
  25693. TO_STRING ? s.charAt(i) : a :
  25694. TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000;
  25695. };
  25696. };
  25697. /***/
  25698. }),
  25699. /* 136 */
  25700. /***/
  25701. (function(module, exports, __webpack_require__) {
  25702. var anObject = __webpack_require__(27);
  25703. var get = __webpack_require__(137);
  25704. module.exports = __webpack_require__(7).getIterator = function(it) {
  25705. var iterFn = get(it);
  25706. if (typeof iterFn != 'function') throw TypeError(it + ' is not iterable!');
  25707. return anObject(iterFn.call(it));
  25708. };
  25709. /***/
  25710. }),
  25711. /* 137 */
  25712. /***/
  25713. (function(module, exports, __webpack_require__) {
  25714. var classof = __webpack_require__(86);
  25715. var ITERATOR = __webpack_require__(13)('iterator');
  25716. var Iterators = __webpack_require__(31);
  25717. module.exports = __webpack_require__(7).getIteratorMethod = function(it) {
  25718. if (it != undefined) return it[ITERATOR] ||
  25719. it['@@iterator'] ||
  25720. Iterators[classof(it)];
  25721. };
  25722. /***/
  25723. }),
  25724. /* 138 */
  25725. /***/
  25726. (function(module, exports, __webpack_require__) {
  25727. __webpack_require__(139);
  25728. var $Object = __webpack_require__(7).Object;
  25729. module.exports = function create(P, D) {
  25730. return $Object.create(P, D);
  25731. };
  25732. /***/
  25733. }),
  25734. /* 139 */
  25735. /***/
  25736. (function(module, exports, __webpack_require__) {
  25737. var $export = __webpack_require__(17);
  25738. // 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])
  25739. $export($export.S, 'Object', { create: __webpack_require__(54) });
  25740. /***/
  25741. }),
  25742. /* 140 */
  25743. /***/
  25744. (function(module, exports, __webpack_require__) {
  25745. __webpack_require__(141);
  25746. module.exports = __webpack_require__(7).Object.keys;
  25747. /***/
  25748. }),
  25749. /* 141 */
  25750. /***/
  25751. (function(module, exports, __webpack_require__) {
  25752. // 19.1.2.14 Object.keys(O)
  25753. var toObject = __webpack_require__(41);
  25754. var $keys = __webpack_require__(33);
  25755. __webpack_require__(87)('keys', function() {
  25756. return function keys(it) {
  25757. return $keys(toObject(it));
  25758. };
  25759. });
  25760. /***/
  25761. }),
  25762. /* 142 */
  25763. /***/
  25764. (function(module, exports, __webpack_require__) {
  25765. module.exports = { "default": __webpack_require__(143), __esModule: true };
  25766. /***/
  25767. }),
  25768. /* 143 */
  25769. /***/
  25770. (function(module, exports, __webpack_require__) {
  25771. __webpack_require__(60);
  25772. __webpack_require__(49);
  25773. module.exports = __webpack_require__(61).f('iterator');
  25774. /***/
  25775. }),
  25776. /* 144 */
  25777. /***/
  25778. (function(module, exports, __webpack_require__) {
  25779. module.exports = { "default": __webpack_require__(145), __esModule: true };
  25780. /***/
  25781. }),
  25782. /* 145 */
  25783. /***/
  25784. (function(module, exports, __webpack_require__) {
  25785. __webpack_require__(146);
  25786. __webpack_require__(151);
  25787. __webpack_require__(152);
  25788. __webpack_require__(153);
  25789. module.exports = __webpack_require__(7).Symbol;
  25790. /***/
  25791. }),
  25792. /* 146 */
  25793. /***/
  25794. (function(module, exports, __webpack_require__) {
  25795. "use strict";
  25796. // ECMAScript 6 symbols shim
  25797. var global = __webpack_require__(18);
  25798. var has = __webpack_require__(22);
  25799. var DESCRIPTORS = __webpack_require__(21);
  25800. var $export = __webpack_require__(17);
  25801. var redefine = __webpack_require__(83);
  25802. var META = __webpack_require__(147).KEY;
  25803. var $fails = __webpack_require__(28);
  25804. var shared = __webpack_require__(57);
  25805. var setToStringTag = __webpack_require__(59);
  25806. var uid = __webpack_require__(40);
  25807. var wks = __webpack_require__(13);
  25808. var wksExt = __webpack_require__(61);
  25809. var wksDefine = __webpack_require__(62);
  25810. var enumKeys = __webpack_require__(148);
  25811. var isArray = __webpack_require__(149);
  25812. var anObject = __webpack_require__(27);
  25813. var toIObject = __webpack_require__(25);
  25814. var toPrimitive = __webpack_require__(53);
  25815. var createDesc = __webpack_require__(39);
  25816. var _create = __webpack_require__(54);
  25817. var gOPNExt = __webpack_require__(150);
  25818. var $GOPD = __webpack_require__(89);
  25819. var $DP = __webpack_require__(20);
  25820. var $keys = __webpack_require__(33);
  25821. var gOPD = $GOPD.f;
  25822. var dP = $DP.f;
  25823. var gOPN = gOPNExt.f;
  25824. var $Symbol = global.Symbol;
  25825. var $JSON = global.JSON;
  25826. var _stringify = $JSON && $JSON.stringify;
  25827. var PROTOTYPE = 'prototype';
  25828. var HIDDEN = wks('_hidden');
  25829. var TO_PRIMITIVE = wks('toPrimitive');
  25830. var isEnum = {}.propertyIsEnumerable;
  25831. var SymbolRegistry = shared('symbol-registry');
  25832. var AllSymbols = shared('symbols');
  25833. var OPSymbols = shared('op-symbols');
  25834. var ObjectProto = Object[PROTOTYPE];
  25835. var USE_NATIVE = typeof $Symbol == 'function';
  25836. var QObject = global.QObject;
  25837. // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
  25838. var setter = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild;
  25839. // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
  25840. var setSymbolDesc = DESCRIPTORS && $fails(function() {
  25841. return _create(dP({}, 'a', {
  25842. get: function() { return dP(this, 'a', { value: 7 }).a; }
  25843. })).a != 7;
  25844. }) ? function(it, key, D) {
  25845. var protoDesc = gOPD(ObjectProto, key);
  25846. if (protoDesc) delete ObjectProto[key];
  25847. dP(it, key, D);
  25848. if (protoDesc && it !== ObjectProto) dP(ObjectProto, key, protoDesc);
  25849. } : dP;
  25850. var wrap = function(tag) {
  25851. var sym = AllSymbols[tag] = _create($Symbol[PROTOTYPE]);
  25852. sym._k = tag;
  25853. return sym;
  25854. };
  25855. var isSymbol = USE_NATIVE && typeof $Symbol.iterator == 'symbol' ? function(it) {
  25856. return typeof it == 'symbol';
  25857. } : function(it) {
  25858. return it instanceof $Symbol;
  25859. };
  25860. var $defineProperty = function defineProperty(it, key, D) {
  25861. if (it === ObjectProto) $defineProperty(OPSymbols, key, D);
  25862. anObject(it);
  25863. key = toPrimitive(key, true);
  25864. anObject(D);
  25865. if (has(AllSymbols, key)) {
  25866. if (!D.enumerable) {
  25867. if (!has(it, HIDDEN)) dP(it, HIDDEN, createDesc(1, {}));
  25868. it[HIDDEN][key] = true;
  25869. } else {
  25870. if (has(it, HIDDEN) && it[HIDDEN][key]) it[HIDDEN][key] = false;
  25871. D = _create(D, { enumerable: createDesc(0, false) });
  25872. }
  25873. return setSymbolDesc(it, key, D);
  25874. }
  25875. return dP(it, key, D);
  25876. };
  25877. var $defineProperties = function defineProperties(it, P) {
  25878. anObject(it);
  25879. var keys = enumKeys(P = toIObject(P));
  25880. var i = 0;
  25881. var l = keys.length;
  25882. var key;
  25883. while (l > i) $defineProperty(it, key = keys[i++], P[key]);
  25884. return it;
  25885. };
  25886. var $create = function create(it, P) {
  25887. return P === undefined ? _create(it) : $defineProperties(_create(it), P);
  25888. };
  25889. var $propertyIsEnumerable = function propertyIsEnumerable(key) {
  25890. var E = isEnum.call(this, key = toPrimitive(key, true));
  25891. if (this === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key)) return false;
  25892. return E || !has(this, key) || !has(AllSymbols, key) || has(this, HIDDEN) && this[HIDDEN][key] ? E : true;
  25893. };
  25894. var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key) {
  25895. it = toIObject(it);
  25896. key = toPrimitive(key, true);
  25897. if (it === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key)) return;
  25898. var D = gOPD(it, key);
  25899. if (D && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key])) D.enumerable = true;
  25900. return D;
  25901. };
  25902. var $getOwnPropertyNames = function getOwnPropertyNames(it) {
  25903. var names = gOPN(toIObject(it));
  25904. var result = [];
  25905. var i = 0;
  25906. var key;
  25907. while (names.length > i) {
  25908. if (!has(AllSymbols, key = names[i++]) && key != HIDDEN && key != META) result.push(key);
  25909. }
  25910. return result;
  25911. };
  25912. var $getOwnPropertySymbols = function getOwnPropertySymbols(it) {
  25913. var IS_OP = it === ObjectProto;
  25914. var names = gOPN(IS_OP ? OPSymbols : toIObject(it));
  25915. var result = [];
  25916. var i = 0;
  25917. var key;
  25918. while (names.length > i) {
  25919. if (has(AllSymbols, key = names[i++]) && (IS_OP ? has(ObjectProto, key) : true)) result.push(AllSymbols[key]);
  25920. }
  25921. return result;
  25922. };
  25923. // 19.4.1.1 Symbol([description])
  25924. if (!USE_NATIVE) {
  25925. $Symbol = function Symbol() {
  25926. if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor!');
  25927. var tag = uid(arguments.length > 0 ? arguments[0] : undefined);
  25928. var $set = function(value) {
  25929. if (this === ObjectProto) $set.call(OPSymbols, value);
  25930. if (has(this, HIDDEN) && has(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
  25931. setSymbolDesc(this, tag, createDesc(1, value));
  25932. };
  25933. if (DESCRIPTORS && setter) setSymbolDesc(ObjectProto, tag, { configurable: true, set: $set });
  25934. return wrap(tag);
  25935. };
  25936. redefine($Symbol[PROTOTYPE], 'toString', function toString() {
  25937. return this._k;
  25938. });
  25939. $GOPD.f = $getOwnPropertyDescriptor;
  25940. $DP.f = $defineProperty;
  25941. __webpack_require__(88).f = gOPNExt.f = $getOwnPropertyNames;
  25942. __webpack_require__(42).f = $propertyIsEnumerable;
  25943. __webpack_require__(63).f = $getOwnPropertySymbols;
  25944. if (DESCRIPTORS && !__webpack_require__(52)) {
  25945. redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true);
  25946. }
  25947. wksExt.f = function(name) {
  25948. return wrap(wks(name));
  25949. };
  25950. }
  25951. $export($export.G + $export.W + $export.F * !USE_NATIVE, { Symbol: $Symbol });
  25952. for (var es6Symbols = (
  25953. // 19.4.2.2, 19.4.2.3, 19.4.2.4, 19.4.2.6, 19.4.2.8, 19.4.2.9, 19.4.2.10, 19.4.2.11, 19.4.2.12, 19.4.2.13, 19.4.2.14
  25954. 'hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables'
  25955. ).split(','), j = 0; es6Symbols.length > j;) wks(es6Symbols[j++]);
  25956. for (var wellKnownSymbols = $keys(wks.store), k = 0; wellKnownSymbols.length > k;) wksDefine(wellKnownSymbols[k++]);
  25957. $export($export.S + $export.F * !USE_NATIVE, 'Symbol', {
  25958. // 19.4.2.1 Symbol.for(key)
  25959. 'for': function(key) {
  25960. return has(SymbolRegistry, key += '') ?
  25961. SymbolRegistry[key] :
  25962. SymbolRegistry[key] = $Symbol(key);
  25963. },
  25964. // 19.4.2.5 Symbol.keyFor(sym)
  25965. keyFor: function keyFor(sym) {
  25966. if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol!');
  25967. for (var key in SymbolRegistry)
  25968. if (SymbolRegistry[key] === sym) return key;
  25969. },
  25970. useSetter: function() { setter = true; },
  25971. useSimple: function() { setter = false; }
  25972. });
  25973. $export($export.S + $export.F * !USE_NATIVE, 'Object', {
  25974. // 19.1.2.2 Object.create(O [, Properties])
  25975. create: $create,
  25976. // 19.1.2.4 Object.defineProperty(O, P, Attributes)
  25977. defineProperty: $defineProperty,
  25978. // 19.1.2.3 Object.defineProperties(O, Properties)
  25979. defineProperties: $defineProperties,
  25980. // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)
  25981. getOwnPropertyDescriptor: $getOwnPropertyDescriptor,
  25982. // 19.1.2.7 Object.getOwnPropertyNames(O)
  25983. getOwnPropertyNames: $getOwnPropertyNames,
  25984. // 19.1.2.8 Object.getOwnPropertySymbols(O)
  25985. getOwnPropertySymbols: $getOwnPropertySymbols
  25986. });
  25987. // 24.3.2 JSON.stringify(value [, replacer [, space]])
  25988. $JSON && $export($export.S + $export.F * (!USE_NATIVE || $fails(function() {
  25989. var S = $Symbol();
  25990. // MS Edge converts symbol values to JSON as {}
  25991. // WebKit converts symbol values to JSON as null
  25992. // V8 throws on boxed symbols
  25993. return _stringify([S]) != '[null]' || _stringify({ a: S }) != '{}' || _stringify(Object(S)) != '{}';
  25994. })), 'JSON', {
  25995. stringify: function stringify(it) {
  25996. if (it === undefined || isSymbol(it)) return; // IE8 returns string on undefined
  25997. var args = [it];
  25998. var i = 1;
  25999. var replacer, $replacer;
  26000. while (arguments.length > i) args.push(arguments[i++]);
  26001. replacer = args[1];
  26002. if (typeof replacer == 'function') $replacer = replacer;
  26003. if ($replacer || !isArray(replacer)) replacer = function(key, value) {
  26004. if ($replacer) value = $replacer.call(this, key, value);
  26005. if (!isSymbol(value)) return value;
  26006. };
  26007. args[1] = replacer;
  26008. return _stringify.apply($JSON, args);
  26009. }
  26010. });
  26011. // 19.4.3.4 Symbol.prototype[@@toPrimitive](hint)
  26012. $Symbol[PROTOTYPE][TO_PRIMITIVE] || __webpack_require__(26)($Symbol[PROTOTYPE], TO_PRIMITIVE, $Symbol[PROTOTYPE].valueOf);
  26013. // 19.4.3.5 Symbol.prototype[@@toStringTag]
  26014. setToStringTag($Symbol, 'Symbol');
  26015. // 20.2.1.9 Math[@@toStringTag]
  26016. setToStringTag(Math, 'Math', true);
  26017. // 24.3.3 JSON[@@toStringTag]
  26018. setToStringTag(global.JSON, 'JSON', true);
  26019. /***/
  26020. }),
  26021. /* 147 */
  26022. /***/
  26023. (function(module, exports, __webpack_require__) {
  26024. var META = __webpack_require__(40)('meta');
  26025. var isObject = __webpack_require__(32);
  26026. var has = __webpack_require__(22);
  26027. var setDesc = __webpack_require__(20).f;
  26028. var id = 0;
  26029. var isExtensible = Object.isExtensible || function() {
  26030. return true;
  26031. };
  26032. var FREEZE = !__webpack_require__(28)(function() {
  26033. return isExtensible(Object.preventExtensions({}));
  26034. });
  26035. var setMeta = function(it) {
  26036. setDesc(it, META, {
  26037. value: {
  26038. i: 'O' + ++id, // object ID
  26039. w: {} // weak collections IDs
  26040. }
  26041. });
  26042. };
  26043. var fastKey = function(it, create) {
  26044. // return primitive with prefix
  26045. if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
  26046. if (!has(it, META)) {
  26047. // can't set metadata to uncaught frozen object
  26048. if (!isExtensible(it)) return 'F';
  26049. // not necessary to add metadata
  26050. if (!create) return 'E';
  26051. // add missing metadata
  26052. setMeta(it);
  26053. // return object ID
  26054. }
  26055. return it[META].i;
  26056. };
  26057. var getWeak = function(it, create) {
  26058. if (!has(it, META)) {
  26059. // can't set metadata to uncaught frozen object
  26060. if (!isExtensible(it)) return true;
  26061. // not necessary to add metadata
  26062. if (!create) return false;
  26063. // add missing metadata
  26064. setMeta(it);
  26065. // return hash weak collections IDs
  26066. }
  26067. return it[META].w;
  26068. };
  26069. // add metadata on freeze-family methods calling
  26070. var onFreeze = function(it) {
  26071. if (FREEZE && meta.NEED && isExtensible(it) && !has(it, META)) setMeta(it);
  26072. return it;
  26073. };
  26074. var meta = module.exports = {
  26075. KEY: META,
  26076. NEED: false,
  26077. fastKey: fastKey,
  26078. getWeak: getWeak,
  26079. onFreeze: onFreeze
  26080. };
  26081. /***/
  26082. }),
  26083. /* 148 */
  26084. /***/
  26085. (function(module, exports, __webpack_require__) {
  26086. // all enumerable object keys, includes symbols
  26087. var getKeys = __webpack_require__(33);
  26088. var gOPS = __webpack_require__(63);
  26089. var pIE = __webpack_require__(42);
  26090. module.exports = function(it) {
  26091. var result = getKeys(it);
  26092. var getSymbols = gOPS.f;
  26093. if (getSymbols) {
  26094. var symbols = getSymbols(it);
  26095. var isEnum = pIE.f;
  26096. var i = 0;
  26097. var key;
  26098. while (symbols.length > i)
  26099. if (isEnum.call(it, key = symbols[i++])) result.push(key);
  26100. }
  26101. return result;
  26102. };
  26103. /***/
  26104. }),
  26105. /* 149 */
  26106. /***/
  26107. (function(module, exports, __webpack_require__) {
  26108. // 7.2.2 IsArray(argument)
  26109. var cof = __webpack_require__(50);
  26110. module.exports = Array.isArray || function isArray(arg) {
  26111. return cof(arg) == 'Array';
  26112. };
  26113. /***/
  26114. }),
  26115. /* 150 */
  26116. /***/
  26117. (function(module, exports, __webpack_require__) {
  26118. // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
  26119. var toIObject = __webpack_require__(25);
  26120. var gOPN = __webpack_require__(88).f;
  26121. var toString = {}.toString;
  26122. var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames ?
  26123. Object.getOwnPropertyNames(window) : [];
  26124. var getWindowNames = function(it) {
  26125. try {
  26126. return gOPN(it);
  26127. } catch (e) {
  26128. return windowNames.slice();
  26129. }
  26130. };
  26131. module.exports.f = function getOwnPropertyNames(it) {
  26132. return windowNames && toString.call(it) == '[object Window]' ? getWindowNames(it) : gOPN(toIObject(it));
  26133. };
  26134. /***/
  26135. }),
  26136. /* 151 */
  26137. /***/
  26138. (function(module, exports) {
  26139. /***/
  26140. }),
  26141. /* 152 */
  26142. /***/
  26143. (function(module, exports, __webpack_require__) {
  26144. __webpack_require__(62)('asyncIterator');
  26145. /***/
  26146. }),
  26147. /* 153 */
  26148. /***/
  26149. (function(module, exports, __webpack_require__) {
  26150. __webpack_require__(62)('observable');
  26151. /***/
  26152. }),
  26153. /* 154 */
  26154. /***/
  26155. (function(module, exports, __webpack_require__) {
  26156. /* WEBPACK VAR INJECTION */
  26157. (function(module) {
  26158. var require; //! moment.js
  26159. //! version : 2.19.1
  26160. //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
  26161. //! license : MIT
  26162. //! momentjs.com
  26163. ;
  26164. (function(global, factory) {
  26165. true ? module.exports = factory() :
  26166. typeof define === 'function' && define.amd ? define(factory) :
  26167. global.moment = factory()
  26168. }(this, (function() {
  26169. 'use strict';
  26170. var hookCallback;
  26171. function hooks() {
  26172. return hookCallback.apply(null, arguments);
  26173. }
  26174. // This is done to register the method called with moment()
  26175. // without creating circular dependencies.
  26176. function setHookCallback(callback) {
  26177. hookCallback = callback;
  26178. }
  26179. function isArray(input) {
  26180. return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
  26181. }
  26182. function isObject(input) {
  26183. // IE8 will treat undefined and null as object if it wasn't for
  26184. // input != null
  26185. return input != null && Object.prototype.toString.call(input) === '[object Object]';
  26186. }
  26187. function isObjectEmpty(obj) {
  26188. if (Object.getOwnPropertyNames) {
  26189. return (Object.getOwnPropertyNames(obj).length === 0);
  26190. } else {
  26191. var k;
  26192. for (k in obj) {
  26193. if (obj.hasOwnProperty(k)) {
  26194. return false;
  26195. }
  26196. }
  26197. return true;
  26198. }
  26199. }
  26200. function isUndefined(input) {
  26201. return input === void 0;
  26202. }
  26203. function isNumber(input) {
  26204. return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
  26205. }
  26206. function isDate(input) {
  26207. return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
  26208. }
  26209. function map(arr, fn) {
  26210. var res = [],
  26211. i;
  26212. for (i = 0; i < arr.length; ++i) {
  26213. res.push(fn(arr[i], i));
  26214. }
  26215. return res;
  26216. }
  26217. function hasOwnProp(a, b) {
  26218. return Object.prototype.hasOwnProperty.call(a, b);
  26219. }
  26220. function extend(a, b) {
  26221. for (var i in b) {
  26222. if (hasOwnProp(b, i)) {
  26223. a[i] = b[i];
  26224. }
  26225. }
  26226. if (hasOwnProp(b, 'toString')) {
  26227. a.toString = b.toString;
  26228. }
  26229. if (hasOwnProp(b, 'valueOf')) {
  26230. a.valueOf = b.valueOf;
  26231. }
  26232. return a;
  26233. }
  26234. function createUTC(input, format, locale, strict) {
  26235. return createLocalOrUTC(input, format, locale, strict, true).utc();
  26236. }
  26237. function defaultParsingFlags() {
  26238. // We need to deep clone this object.
  26239. return {
  26240. empty: false,
  26241. unusedTokens: [],
  26242. unusedInput: [],
  26243. overflow: -2,
  26244. charsLeftOver: 0,
  26245. nullInput: false,
  26246. invalidMonth: null,
  26247. invalidFormat: false,
  26248. userInvalidated: false,
  26249. iso: false,
  26250. parsedDateParts: [],
  26251. meridiem: null,
  26252. rfc2822: false,
  26253. weekdayMismatch: false
  26254. };
  26255. }
  26256. function getParsingFlags(m) {
  26257. if (m._pf == null) {
  26258. m._pf = defaultParsingFlags();
  26259. }
  26260. return m._pf;
  26261. }
  26262. var some;
  26263. if (Array.prototype.some) {
  26264. some = Array.prototype.some;
  26265. } else {
  26266. some = function(fun) {
  26267. var t = Object(this);
  26268. var len = t.length >>> 0;
  26269. for (var i = 0; i < len; i++) {
  26270. if (i in t && fun.call(this, t[i], i, t)) {
  26271. return true;
  26272. }
  26273. }
  26274. return false;
  26275. };
  26276. }
  26277. function isValid(m) {
  26278. if (m._isValid == null) {
  26279. var flags = getParsingFlags(m);
  26280. var parsedParts = some.call(flags.parsedDateParts, function(i) {
  26281. return i != null;
  26282. });
  26283. var isNowValid = !isNaN(m._d.getTime()) &&
  26284. flags.overflow < 0 &&
  26285. !flags.empty &&
  26286. !flags.invalidMonth &&
  26287. !flags.invalidWeekday &&
  26288. !flags.weekdayMismatch &&
  26289. !flags.nullInput &&
  26290. !flags.invalidFormat &&
  26291. !flags.userInvalidated &&
  26292. (!flags.meridiem || (flags.meridiem && parsedParts));
  26293. if (m._strict) {
  26294. isNowValid = isNowValid &&
  26295. flags.charsLeftOver === 0 &&
  26296. flags.unusedTokens.length === 0 &&
  26297. flags.bigHour === undefined;
  26298. }
  26299. if (Object.isFrozen == null || !Object.isFrozen(m)) {
  26300. m._isValid = isNowValid;
  26301. } else {
  26302. return isNowValid;
  26303. }
  26304. }
  26305. return m._isValid;
  26306. }
  26307. function createInvalid(flags) {
  26308. var m = createUTC(NaN);
  26309. if (flags != null) {
  26310. extend(getParsingFlags(m), flags);
  26311. } else {
  26312. getParsingFlags(m).userInvalidated = true;
  26313. }
  26314. return m;
  26315. }
  26316. // Plugins that add properties should also add the key here (null value),
  26317. // so we can properly clone ourselves.
  26318. var momentProperties = hooks.momentProperties = [];
  26319. function copyConfig(to, from) {
  26320. var i, prop, val;
  26321. if (!isUndefined(from._isAMomentObject)) {
  26322. to._isAMomentObject = from._isAMomentObject;
  26323. }
  26324. if (!isUndefined(from._i)) {
  26325. to._i = from._i;
  26326. }
  26327. if (!isUndefined(from._f)) {
  26328. to._f = from._f;
  26329. }
  26330. if (!isUndefined(from._l)) {
  26331. to._l = from._l;
  26332. }
  26333. if (!isUndefined(from._strict)) {
  26334. to._strict = from._strict;
  26335. }
  26336. if (!isUndefined(from._tzm)) {
  26337. to._tzm = from._tzm;
  26338. }
  26339. if (!isUndefined(from._isUTC)) {
  26340. to._isUTC = from._isUTC;
  26341. }
  26342. if (!isUndefined(from._offset)) {
  26343. to._offset = from._offset;
  26344. }
  26345. if (!isUndefined(from._pf)) {
  26346. to._pf = getParsingFlags(from);
  26347. }
  26348. if (!isUndefined(from._locale)) {
  26349. to._locale = from._locale;
  26350. }
  26351. if (momentProperties.length > 0) {
  26352. for (i = 0; i < momentProperties.length; i++) {
  26353. prop = momentProperties[i];
  26354. val = from[prop];
  26355. if (!isUndefined(val)) {
  26356. to[prop] = val;
  26357. }
  26358. }
  26359. }
  26360. return to;
  26361. }
  26362. var updateInProgress = false;
  26363. // Moment prototype object
  26364. function Moment(config) {
  26365. copyConfig(this, config);
  26366. this._d = new Date(config._d != null ? config._d.getTime() : NaN);
  26367. if (!this.isValid()) {
  26368. this._d = new Date(NaN);
  26369. }
  26370. // Prevent infinite loop in case updateOffset creates new moment
  26371. // objects.
  26372. if (updateInProgress === false) {
  26373. updateInProgress = true;
  26374. hooks.updateOffset(this);
  26375. updateInProgress = false;
  26376. }
  26377. }
  26378. function isMoment(obj) {
  26379. return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
  26380. }
  26381. function absFloor(number) {
  26382. if (number < 0) {
  26383. // -0 -> 0
  26384. return Math.ceil(number) || 0;
  26385. } else {
  26386. return Math.floor(number);
  26387. }
  26388. }
  26389. function toInt(argumentForCoercion) {
  26390. var coercedNumber = +argumentForCoercion,
  26391. value = 0;
  26392. if (coercedNumber !== 0 && isFinite(coercedNumber)) {
  26393. value = absFloor(coercedNumber);
  26394. }
  26395. return value;
  26396. }
  26397. // compare two arrays, return the number of differences
  26398. function compareArrays(array1, array2, dontConvert) {
  26399. var len = Math.min(array1.length, array2.length),
  26400. lengthDiff = Math.abs(array1.length - array2.length),
  26401. diffs = 0,
  26402. i;
  26403. for (i = 0; i < len; i++) {
  26404. if ((dontConvert && array1[i] !== array2[i]) ||
  26405. (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
  26406. diffs++;
  26407. }
  26408. }
  26409. return diffs + lengthDiff;
  26410. }
  26411. function warn(msg) {
  26412. if (hooks.suppressDeprecationWarnings === false &&
  26413. (typeof console !== 'undefined') && console.warn) {
  26414. console.warn('Deprecation warning: ' + msg);
  26415. }
  26416. }
  26417. function deprecate(msg, fn) {
  26418. var firstTime = true;
  26419. return extend(function() {
  26420. if (hooks.deprecationHandler != null) {
  26421. hooks.deprecationHandler(null, msg);
  26422. }
  26423. if (firstTime) {
  26424. var args = [];
  26425. var arg;
  26426. for (var i = 0; i < arguments.length; i++) {
  26427. arg = '';
  26428. if (typeof arguments[i] === 'object') {
  26429. arg += '\n[' + i + '] ';
  26430. for (var key in arguments[0]) {
  26431. arg += key + ': ' + arguments[0][key] + ', ';
  26432. }
  26433. arg = arg.slice(0, -2); // Remove trailing comma and space
  26434. } else {
  26435. arg = arguments[i];
  26436. }
  26437. args.push(arg);
  26438. }
  26439. warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
  26440. firstTime = false;
  26441. }
  26442. return fn.apply(this, arguments);
  26443. }, fn);
  26444. }
  26445. var deprecations = {};
  26446. function deprecateSimple(name, msg) {
  26447. if (hooks.deprecationHandler != null) {
  26448. hooks.deprecationHandler(name, msg);
  26449. }
  26450. if (!deprecations[name]) {
  26451. warn(msg);
  26452. deprecations[name] = true;
  26453. }
  26454. }
  26455. hooks.suppressDeprecationWarnings = false;
  26456. hooks.deprecationHandler = null;
  26457. function isFunction(input) {
  26458. return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
  26459. }
  26460. function set(config) {
  26461. var prop, i;
  26462. for (i in config) {
  26463. prop = config[i];
  26464. if (isFunction(prop)) {
  26465. this[i] = prop;
  26466. } else {
  26467. this['_' + i] = prop;
  26468. }
  26469. }
  26470. this._config = config;
  26471. // Lenient ordinal parsing accepts just a number in addition to
  26472. // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
  26473. // TODO: Remove "ordinalParse" fallback in next major release.
  26474. this._dayOfMonthOrdinalParseLenient = new RegExp(
  26475. (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
  26476. '|' + (/\d{1,2}/).source);
  26477. }
  26478. function mergeConfigs(parentConfig, childConfig) {
  26479. var res = extend({}, parentConfig),
  26480. prop;
  26481. for (prop in childConfig) {
  26482. if (hasOwnProp(childConfig, prop)) {
  26483. if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
  26484. res[prop] = {};
  26485. extend(res[prop], parentConfig[prop]);
  26486. extend(res[prop], childConfig[prop]);
  26487. } else if (childConfig[prop] != null) {
  26488. res[prop] = childConfig[prop];
  26489. } else {
  26490. delete res[prop];
  26491. }
  26492. }
  26493. }
  26494. for (prop in parentConfig) {
  26495. if (hasOwnProp(parentConfig, prop) &&
  26496. !hasOwnProp(childConfig, prop) &&
  26497. isObject(parentConfig[prop])) {
  26498. // make sure changes to properties don't modify parent config
  26499. res[prop] = extend({}, res[prop]);
  26500. }
  26501. }
  26502. return res;
  26503. }
  26504. function Locale(config) {
  26505. if (config != null) {
  26506. this.set(config);
  26507. }
  26508. }
  26509. var keys;
  26510. if (Object.keys) {
  26511. keys = Object.keys;
  26512. } else {
  26513. keys = function(obj) {
  26514. var i, res = [];
  26515. for (i in obj) {
  26516. if (hasOwnProp(obj, i)) {
  26517. res.push(i);
  26518. }
  26519. }
  26520. return res;
  26521. };
  26522. }
  26523. var defaultCalendar = {
  26524. sameDay: '[Today at] LT',
  26525. nextDay: '[Tomorrow at] LT',
  26526. nextWeek: 'dddd [at] LT',
  26527. lastDay: '[Yesterday at] LT',
  26528. lastWeek: '[Last] dddd [at] LT',
  26529. sameElse: 'L'
  26530. };
  26531. function calendar(key, mom, now) {
  26532. var output = this._calendar[key] || this._calendar['sameElse'];
  26533. return isFunction(output) ? output.call(mom, now) : output;
  26534. }
  26535. var defaultLongDateFormat = {
  26536. LTS: 'h:mm:ss A',
  26537. LT: 'h:mm A',
  26538. L: 'MM/DD/YYYY',
  26539. LL: 'MMMM D, YYYY',
  26540. LLL: 'MMMM D, YYYY h:mm A',
  26541. LLLL: 'dddd, MMMM D, YYYY h:mm A'
  26542. };
  26543. function longDateFormat(key) {
  26544. var format = this._longDateFormat[key],
  26545. formatUpper = this._longDateFormat[key.toUpperCase()];
  26546. if (format || !formatUpper) {
  26547. return format;
  26548. }
  26549. this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function(val) {
  26550. return val.slice(1);
  26551. });
  26552. return this._longDateFormat[key];
  26553. }
  26554. var defaultInvalidDate = 'Invalid date';
  26555. function invalidDate() {
  26556. return this._invalidDate;
  26557. }
  26558. var defaultOrdinal = '%d';
  26559. var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
  26560. function ordinal(number) {
  26561. return this._ordinal.replace('%d', number);
  26562. }
  26563. var defaultRelativeTime = {
  26564. future: 'in %s',
  26565. past: '%s ago',
  26566. s: 'a few seconds',
  26567. ss: '%d seconds',
  26568. m: 'a minute',
  26569. mm: '%d minutes',
  26570. h: 'an hour',
  26571. hh: '%d hours',
  26572. d: 'a day',
  26573. dd: '%d days',
  26574. M: 'a month',
  26575. MM: '%d months',
  26576. y: 'a year',
  26577. yy: '%d years'
  26578. };
  26579. function relativeTime(number, withoutSuffix, string, isFuture) {
  26580. var output = this._relativeTime[string];
  26581. return (isFunction(output)) ?
  26582. output(number, withoutSuffix, string, isFuture) :
  26583. output.replace(/%d/i, number);
  26584. }
  26585. function pastFuture(diff, output) {
  26586. var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
  26587. return isFunction(format) ? format(output) : format.replace(/%s/i, output);
  26588. }
  26589. var aliases = {};
  26590. function addUnitAlias(unit, shorthand) {
  26591. var lowerCase = unit.toLowerCase();
  26592. aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
  26593. }
  26594. function normalizeUnits(units) {
  26595. return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
  26596. }
  26597. function normalizeObjectUnits(inputObject) {
  26598. var normalizedInput = {},
  26599. normalizedProp,
  26600. prop;
  26601. for (prop in inputObject) {
  26602. if (hasOwnProp(inputObject, prop)) {
  26603. normalizedProp = normalizeUnits(prop);
  26604. if (normalizedProp) {
  26605. normalizedInput[normalizedProp] = inputObject[prop];
  26606. }
  26607. }
  26608. }
  26609. return normalizedInput;
  26610. }
  26611. var priorities = {};
  26612. function addUnitPriority(unit, priority) {
  26613. priorities[unit] = priority;
  26614. }
  26615. function getPrioritizedUnits(unitsObj) {
  26616. var units = [];
  26617. for (var u in unitsObj) {
  26618. units.push({ unit: u, priority: priorities[u] });
  26619. }
  26620. units.sort(function(a, b) {
  26621. return a.priority - b.priority;
  26622. });
  26623. return units;
  26624. }
  26625. function zeroFill(number, targetLength, forceSign) {
  26626. var absNumber = '' + Math.abs(number),
  26627. zerosToFill = targetLength - absNumber.length,
  26628. sign = number >= 0;
  26629. return (sign ? (forceSign ? '+' : '') : '-') +
  26630. Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
  26631. }
  26632. var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
  26633. var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
  26634. var formatFunctions = {};
  26635. var formatTokenFunctions = {};
  26636. // token: 'M'
  26637. // padded: ['MM', 2]
  26638. // ordinal: 'Mo'
  26639. // callback: function () { this.month() + 1 }
  26640. function addFormatToken(token, padded, ordinal, callback) {
  26641. var func = callback;
  26642. if (typeof callback === 'string') {
  26643. func = function() {
  26644. return this[callback]();
  26645. };
  26646. }
  26647. if (token) {
  26648. formatTokenFunctions[token] = func;
  26649. }
  26650. if (padded) {
  26651. formatTokenFunctions[padded[0]] = function() {
  26652. return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
  26653. };
  26654. }
  26655. if (ordinal) {
  26656. formatTokenFunctions[ordinal] = function() {
  26657. return this.localeData().ordinal(func.apply(this, arguments), token);
  26658. };
  26659. }
  26660. }
  26661. function removeFormattingTokens(input) {
  26662. if (input.match(/\[[\s\S]/)) {
  26663. return input.replace(/^\[|\]$/g, '');
  26664. }
  26665. return input.replace(/\\/g, '');
  26666. }
  26667. function makeFormatFunction(format) {
  26668. var array = format.match(formattingTokens),
  26669. i, length;
  26670. for (i = 0, length = array.length; i < length; i++) {
  26671. if (formatTokenFunctions[array[i]]) {
  26672. array[i] = formatTokenFunctions[array[i]];
  26673. } else {
  26674. array[i] = removeFormattingTokens(array[i]);
  26675. }
  26676. }
  26677. return function(mom) {
  26678. var output = '',
  26679. i;
  26680. for (i = 0; i < length; i++) {
  26681. output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
  26682. }
  26683. return output;
  26684. };
  26685. }
  26686. // format date using native date object
  26687. function formatMoment(m, format) {
  26688. if (!m.isValid()) {
  26689. return m.localeData().invalidDate();
  26690. }
  26691. format = expandFormat(format, m.localeData());
  26692. formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
  26693. return formatFunctions[format](m);
  26694. }
  26695. function expandFormat(format, locale) {
  26696. var i = 5;
  26697. function replaceLongDateFormatTokens(input) {
  26698. return locale.longDateFormat(input) || input;
  26699. }
  26700. localFormattingTokens.lastIndex = 0;
  26701. while (i >= 0 && localFormattingTokens.test(format)) {
  26702. format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
  26703. localFormattingTokens.lastIndex = 0;
  26704. i -= 1;
  26705. }
  26706. return format;
  26707. }
  26708. var match1 = /\d/; // 0 - 9
  26709. var match2 = /\d\d/; // 00 - 99
  26710. var match3 = /\d{3}/; // 000 - 999
  26711. var match4 = /\d{4}/; // 0000 - 9999
  26712. var match6 = /[+-]?\d{6}/; // -999999 - 999999
  26713. var match1to2 = /\d\d?/; // 0 - 99
  26714. var match3to4 = /\d\d\d\d?/; // 999 - 9999
  26715. var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
  26716. var match1to3 = /\d{1,3}/; // 0 - 999
  26717. var match1to4 = /\d{1,4}/; // 0 - 9999
  26718. var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
  26719. var matchUnsigned = /\d+/; // 0 - inf
  26720. var matchSigned = /[+-]?\d+/; // -inf - inf
  26721. var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
  26722. var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
  26723. var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
  26724. // any word (or two) characters or numbers including two/three word month in arabic.
  26725. // includes scottish gaelic two word and hyphenated months
  26726. var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;
  26727. var regexes = {};
  26728. function addRegexToken(token, regex, strictRegex) {
  26729. regexes[token] = isFunction(regex) ? regex : function(isStrict, localeData) {
  26730. return (isStrict && strictRegex) ? strictRegex : regex;
  26731. };
  26732. }
  26733. function getParseRegexForToken(token, config) {
  26734. if (!hasOwnProp(regexes, token)) {
  26735. return new RegExp(unescapeFormat(token));
  26736. }
  26737. return regexes[token](config._strict, config._locale);
  26738. }
  26739. // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
  26740. function unescapeFormat(s) {
  26741. return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function(matched, p1, p2, p3, p4) {
  26742. return p1 || p2 || p3 || p4;
  26743. }));
  26744. }
  26745. function regexEscape(s) {
  26746. return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
  26747. }
  26748. var tokens = {};
  26749. function addParseToken(token, callback) {
  26750. var i, func = callback;
  26751. if (typeof token === 'string') {
  26752. token = [token];
  26753. }
  26754. if (isNumber(callback)) {
  26755. func = function(input, array) {
  26756. array[callback] = toInt(input);
  26757. };
  26758. }
  26759. for (i = 0; i < token.length; i++) {
  26760. tokens[token[i]] = func;
  26761. }
  26762. }
  26763. function addWeekParseToken(token, callback) {
  26764. addParseToken(token, function(input, array, config, token) {
  26765. config._w = config._w || {};
  26766. callback(input, config._w, config, token);
  26767. });
  26768. }
  26769. function addTimeToArrayFromToken(token, input, config) {
  26770. if (input != null && hasOwnProp(tokens, token)) {
  26771. tokens[token](input, config._a, config, token);
  26772. }
  26773. }
  26774. var YEAR = 0;
  26775. var MONTH = 1;
  26776. var DATE = 2;
  26777. var HOUR = 3;
  26778. var MINUTE = 4;
  26779. var SECOND = 5;
  26780. var MILLISECOND = 6;
  26781. var WEEK = 7;
  26782. var WEEKDAY = 8;
  26783. // FORMATTING
  26784. addFormatToken('Y', 0, 0, function() {
  26785. var y = this.year();
  26786. return y <= 9999 ? '' + y : '+' + y;
  26787. });
  26788. addFormatToken(0, ['YY', 2], 0, function() {
  26789. return this.year() % 100;
  26790. });
  26791. addFormatToken(0, ['YYYY', 4], 0, 'year');
  26792. addFormatToken(0, ['YYYYY', 5], 0, 'year');
  26793. addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
  26794. // ALIASES
  26795. addUnitAlias('year', 'y');
  26796. // PRIORITIES
  26797. addUnitPriority('year', 1);
  26798. // PARSING
  26799. addRegexToken('Y', matchSigned);
  26800. addRegexToken('YY', match1to2, match2);
  26801. addRegexToken('YYYY', match1to4, match4);
  26802. addRegexToken('YYYYY', match1to6, match6);
  26803. addRegexToken('YYYYYY', match1to6, match6);
  26804. addParseToken(['YYYYY', 'YYYYYY'], YEAR);
  26805. addParseToken('YYYY', function(input, array) {
  26806. array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
  26807. });
  26808. addParseToken('YY', function(input, array) {
  26809. array[YEAR] = hooks.parseTwoDigitYear(input);
  26810. });
  26811. addParseToken('Y', function(input, array) {
  26812. array[YEAR] = parseInt(input, 10);
  26813. });
  26814. // HELPERS
  26815. function daysInYear(year) {
  26816. return isLeapYear(year) ? 366 : 365;
  26817. }
  26818. function isLeapYear(year) {
  26819. return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
  26820. }
  26821. // HOOKS
  26822. hooks.parseTwoDigitYear = function(input) {
  26823. return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
  26824. };
  26825. // MOMENTS
  26826. var getSetYear = makeGetSet('FullYear', true);
  26827. function getIsLeapYear() {
  26828. return isLeapYear(this.year());
  26829. }
  26830. function makeGetSet(unit, keepTime) {
  26831. return function(value) {
  26832. if (value != null) {
  26833. set$1(this, unit, value);
  26834. hooks.updateOffset(this, keepTime);
  26835. return this;
  26836. } else {
  26837. return get(this, unit);
  26838. }
  26839. };
  26840. }
  26841. function get(mom, unit) {
  26842. return mom.isValid() ?
  26843. mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
  26844. }
  26845. function set$1(mom, unit, value) {
  26846. if (mom.isValid() && !isNaN(value)) {
  26847. if (unit === 'FullYear' && isLeapYear(mom.year())) {
  26848. mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
  26849. } else {
  26850. mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
  26851. }
  26852. }
  26853. }
  26854. // MOMENTS
  26855. function stringGet(units) {
  26856. units = normalizeUnits(units);
  26857. if (isFunction(this[units])) {
  26858. return this[units]();
  26859. }
  26860. return this;
  26861. }
  26862. function stringSet(units, value) {
  26863. if (typeof units === 'object') {
  26864. units = normalizeObjectUnits(units);
  26865. var prioritized = getPrioritizedUnits(units);
  26866. for (var i = 0; i < prioritized.length; i++) {
  26867. this[prioritized[i].unit](units[prioritized[i].unit]);
  26868. }
  26869. } else {
  26870. units = normalizeUnits(units);
  26871. if (isFunction(this[units])) {
  26872. return this[units](value);
  26873. }
  26874. }
  26875. return this;
  26876. }
  26877. function mod(n, x) {
  26878. return ((n % x) + x) % x;
  26879. }
  26880. var indexOf;
  26881. if (Array.prototype.indexOf) {
  26882. indexOf = Array.prototype.indexOf;
  26883. } else {
  26884. indexOf = function(o) {
  26885. // I know
  26886. var i;
  26887. for (i = 0; i < this.length; ++i) {
  26888. if (this[i] === o) {
  26889. return i;
  26890. }
  26891. }
  26892. return -1;
  26893. };
  26894. }
  26895. function daysInMonth(year, month) {
  26896. if (isNaN(year) || isNaN(month)) {
  26897. return NaN;
  26898. }
  26899. var modMonth = mod(month, 12);
  26900. year += (month - modMonth) / 12;
  26901. return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2);
  26902. }
  26903. // FORMATTING
  26904. addFormatToken('M', ['MM', 2], 'Mo', function() {
  26905. return this.month() + 1;
  26906. });
  26907. addFormatToken('MMM', 0, 0, function(format) {
  26908. return this.localeData().monthsShort(this, format);
  26909. });
  26910. addFormatToken('MMMM', 0, 0, function(format) {
  26911. return this.localeData().months(this, format);
  26912. });
  26913. // ALIASES
  26914. addUnitAlias('month', 'M');
  26915. // PRIORITY
  26916. addUnitPriority('month', 8);
  26917. // PARSING
  26918. addRegexToken('M', match1to2);
  26919. addRegexToken('MM', match1to2, match2);
  26920. addRegexToken('MMM', function(isStrict, locale) {
  26921. return locale.monthsShortRegex(isStrict);
  26922. });
  26923. addRegexToken('MMMM', function(isStrict, locale) {
  26924. return locale.monthsRegex(isStrict);
  26925. });
  26926. addParseToken(['M', 'MM'], function(input, array) {
  26927. array[MONTH] = toInt(input) - 1;
  26928. });
  26929. addParseToken(['MMM', 'MMMM'], function(input, array, config, token) {
  26930. var month = config._locale.monthsParse(input, token, config._strict);
  26931. // if we didn't find a month name, mark the date as invalid.
  26932. if (month != null) {
  26933. array[MONTH] = month;
  26934. } else {
  26935. getParsingFlags(config).invalidMonth = input;
  26936. }
  26937. });
  26938. // LOCALES
  26939. var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
  26940. var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
  26941. function localeMonths(m, format) {
  26942. if (!m) {
  26943. return isArray(this._months) ? this._months :
  26944. this._months['standalone'];
  26945. }
  26946. return isArray(this._months) ? this._months[m.month()] :
  26947. this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
  26948. }
  26949. var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
  26950. function localeMonthsShort(m, format) {
  26951. if (!m) {
  26952. return isArray(this._monthsShort) ? this._monthsShort :
  26953. this._monthsShort['standalone'];
  26954. }
  26955. return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
  26956. this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
  26957. }
  26958. function handleStrictParse(monthName, format, strict) {
  26959. var i, ii, mom, llc = monthName.toLocaleLowerCase();
  26960. if (!this._monthsParse) {
  26961. // this is not used
  26962. this._monthsParse = [];
  26963. this._longMonthsParse = [];
  26964. this._shortMonthsParse = [];
  26965. for (i = 0; i < 12; ++i) {
  26966. mom = createUTC([2000, i]);
  26967. this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
  26968. this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
  26969. }
  26970. }
  26971. if (strict) {
  26972. if (format === 'MMM') {
  26973. ii = indexOf.call(this._shortMonthsParse, llc);
  26974. return ii !== -1 ? ii : null;
  26975. } else {
  26976. ii = indexOf.call(this._longMonthsParse, llc);
  26977. return ii !== -1 ? ii : null;
  26978. }
  26979. } else {
  26980. if (format === 'MMM') {
  26981. ii = indexOf.call(this._shortMonthsParse, llc);
  26982. if (ii !== -1) {
  26983. return ii;
  26984. }
  26985. ii = indexOf.call(this._longMonthsParse, llc);
  26986. return ii !== -1 ? ii : null;
  26987. } else {
  26988. ii = indexOf.call(this._longMonthsParse, llc);
  26989. if (ii !== -1) {
  26990. return ii;
  26991. }
  26992. ii = indexOf.call(this._shortMonthsParse, llc);
  26993. return ii !== -1 ? ii : null;
  26994. }
  26995. }
  26996. }
  26997. function localeMonthsParse(monthName, format, strict) {
  26998. var i, mom, regex;
  26999. if (this._monthsParseExact) {
  27000. return handleStrictParse.call(this, monthName, format, strict);
  27001. }
  27002. if (!this._monthsParse) {
  27003. this._monthsParse = [];
  27004. this._longMonthsParse = [];
  27005. this._shortMonthsParse = [];
  27006. }
  27007. // TODO: add sorting
  27008. // Sorting makes sure if one month (or abbr) is a prefix of another
  27009. // see sorting in computeMonthsParse
  27010. for (i = 0; i < 12; i++) {
  27011. // make the regex if we don't have it already
  27012. mom = createUTC([2000, i]);
  27013. if (strict && !this._longMonthsParse[i]) {
  27014. this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
  27015. this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
  27016. }
  27017. if (!strict && !this._monthsParse[i]) {
  27018. regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
  27019. this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
  27020. }
  27021. // test the regex
  27022. if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
  27023. return i;
  27024. } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
  27025. return i;
  27026. } else if (!strict && this._monthsParse[i].test(monthName)) {
  27027. return i;
  27028. }
  27029. }
  27030. }
  27031. // MOMENTS
  27032. function setMonth(mom, value) {
  27033. var dayOfMonth;
  27034. if (!mom.isValid()) {
  27035. // No op
  27036. return mom;
  27037. }
  27038. if (typeof value === 'string') {
  27039. if (/^\d+$/.test(value)) {
  27040. value = toInt(value);
  27041. } else {
  27042. value = mom.localeData().monthsParse(value);
  27043. // TODO: Another silent failure?
  27044. if (!isNumber(value)) {
  27045. return mom;
  27046. }
  27047. }
  27048. }
  27049. dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
  27050. mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
  27051. return mom;
  27052. }
  27053. function getSetMonth(value) {
  27054. if (value != null) {
  27055. setMonth(this, value);
  27056. hooks.updateOffset(this, true);
  27057. return this;
  27058. } else {
  27059. return get(this, 'Month');
  27060. }
  27061. }
  27062. function getDaysInMonth() {
  27063. return daysInMonth(this.year(), this.month());
  27064. }
  27065. var defaultMonthsShortRegex = matchWord;
  27066. function monthsShortRegex(isStrict) {
  27067. if (this._monthsParseExact) {
  27068. if (!hasOwnProp(this, '_monthsRegex')) {
  27069. computeMonthsParse.call(this);
  27070. }
  27071. if (isStrict) {
  27072. return this._monthsShortStrictRegex;
  27073. } else {
  27074. return this._monthsShortRegex;
  27075. }
  27076. } else {
  27077. if (!hasOwnProp(this, '_monthsShortRegex')) {
  27078. this._monthsShortRegex = defaultMonthsShortRegex;
  27079. }
  27080. return this._monthsShortStrictRegex && isStrict ?
  27081. this._monthsShortStrictRegex : this._monthsShortRegex;
  27082. }
  27083. }
  27084. var defaultMonthsRegex = matchWord;
  27085. function monthsRegex(isStrict) {
  27086. if (this._monthsParseExact) {
  27087. if (!hasOwnProp(this, '_monthsRegex')) {
  27088. computeMonthsParse.call(this);
  27089. }
  27090. if (isStrict) {
  27091. return this._monthsStrictRegex;
  27092. } else {
  27093. return this._monthsRegex;
  27094. }
  27095. } else {
  27096. if (!hasOwnProp(this, '_monthsRegex')) {
  27097. this._monthsRegex = defaultMonthsRegex;
  27098. }
  27099. return this._monthsStrictRegex && isStrict ?
  27100. this._monthsStrictRegex : this._monthsRegex;
  27101. }
  27102. }
  27103. function computeMonthsParse() {
  27104. function cmpLenRev(a, b) {
  27105. return b.length - a.length;
  27106. }
  27107. var shortPieces = [],
  27108. longPieces = [],
  27109. mixedPieces = [],
  27110. i, mom;
  27111. for (i = 0; i < 12; i++) {
  27112. // make the regex if we don't have it already
  27113. mom = createUTC([2000, i]);
  27114. shortPieces.push(this.monthsShort(mom, ''));
  27115. longPieces.push(this.months(mom, ''));
  27116. mixedPieces.push(this.months(mom, ''));
  27117. mixedPieces.push(this.monthsShort(mom, ''));
  27118. }
  27119. // Sorting makes sure if one month (or abbr) is a prefix of another it
  27120. // will match the longer piece.
  27121. shortPieces.sort(cmpLenRev);
  27122. longPieces.sort(cmpLenRev);
  27123. mixedPieces.sort(cmpLenRev);
  27124. for (i = 0; i < 12; i++) {
  27125. shortPieces[i] = regexEscape(shortPieces[i]);
  27126. longPieces[i] = regexEscape(longPieces[i]);
  27127. }
  27128. for (i = 0; i < 24; i++) {
  27129. mixedPieces[i] = regexEscape(mixedPieces[i]);
  27130. }
  27131. this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
  27132. this._monthsShortRegex = this._monthsRegex;
  27133. this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
  27134. this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
  27135. }
  27136. function createDate(y, m, d, h, M, s, ms) {
  27137. // can't just apply() to create a date:
  27138. // https://stackoverflow.com/q/181348
  27139. var date = new Date(y, m, d, h, M, s, ms);
  27140. // the date constructor remaps years 0-99 to 1900-1999
  27141. if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
  27142. date.setFullYear(y);
  27143. }
  27144. return date;
  27145. }
  27146. function createUTCDate(y) {
  27147. var date = new Date(Date.UTC.apply(null, arguments));
  27148. // the Date.UTC function remaps years 0-99 to 1900-1999
  27149. if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
  27150. date.setUTCFullYear(y);
  27151. }
  27152. return date;
  27153. }
  27154. // start-of-first-week - start-of-year
  27155. function firstWeekOffset(year, dow, doy) {
  27156. var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
  27157. fwd = 7 + dow - doy,
  27158. // first-week day local weekday -- which local weekday is fwd
  27159. fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
  27160. return -fwdlw + fwd - 1;
  27161. }
  27162. // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
  27163. function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
  27164. var localWeekday = (7 + weekday - dow) % 7,
  27165. weekOffset = firstWeekOffset(year, dow, doy),
  27166. dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
  27167. resYear, resDayOfYear;
  27168. if (dayOfYear <= 0) {
  27169. resYear = year - 1;
  27170. resDayOfYear = daysInYear(resYear) + dayOfYear;
  27171. } else if (dayOfYear > daysInYear(year)) {
  27172. resYear = year + 1;
  27173. resDayOfYear = dayOfYear - daysInYear(year);
  27174. } else {
  27175. resYear = year;
  27176. resDayOfYear = dayOfYear;
  27177. }
  27178. return {
  27179. year: resYear,
  27180. dayOfYear: resDayOfYear
  27181. };
  27182. }
  27183. function weekOfYear(mom, dow, doy) {
  27184. var weekOffset = firstWeekOffset(mom.year(), dow, doy),
  27185. week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
  27186. resWeek, resYear;
  27187. if (week < 1) {
  27188. resYear = mom.year() - 1;
  27189. resWeek = week + weeksInYear(resYear, dow, doy);
  27190. } else if (week > weeksInYear(mom.year(), dow, doy)) {
  27191. resWeek = week - weeksInYear(mom.year(), dow, doy);
  27192. resYear = mom.year() + 1;
  27193. } else {
  27194. resYear = mom.year();
  27195. resWeek = week;
  27196. }
  27197. return {
  27198. week: resWeek,
  27199. year: resYear
  27200. };
  27201. }
  27202. function weeksInYear(year, dow, doy) {
  27203. var weekOffset = firstWeekOffset(year, dow, doy),
  27204. weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
  27205. return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
  27206. }
  27207. // FORMATTING
  27208. addFormatToken('w', ['ww', 2], 'wo', 'week');
  27209. addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
  27210. // ALIASES
  27211. addUnitAlias('week', 'w');
  27212. addUnitAlias('isoWeek', 'W');
  27213. // PRIORITIES
  27214. addUnitPriority('week', 5);
  27215. addUnitPriority('isoWeek', 5);
  27216. // PARSING
  27217. addRegexToken('w', match1to2);
  27218. addRegexToken('ww', match1to2, match2);
  27219. addRegexToken('W', match1to2);
  27220. addRegexToken('WW', match1to2, match2);
  27221. addWeekParseToken(['w', 'ww', 'W', 'WW'], function(input, week, config, token) {
  27222. week[token.substr(0, 1)] = toInt(input);
  27223. });
  27224. // HELPERS
  27225. // LOCALES
  27226. function localeWeek(mom) {
  27227. return weekOfYear(mom, this._week.dow, this._week.doy).week;
  27228. }
  27229. var defaultLocaleWeek = {
  27230. dow: 0, // Sunday is the first day of the week.
  27231. doy: 6 // The week that contains Jan 1st is the first week of the year.
  27232. };
  27233. function localeFirstDayOfWeek() {
  27234. return this._week.dow;
  27235. }
  27236. function localeFirstDayOfYear() {
  27237. return this._week.doy;
  27238. }
  27239. // MOMENTS
  27240. function getSetWeek(input) {
  27241. var week = this.localeData().week(this);
  27242. return input == null ? week : this.add((input - week) * 7, 'd');
  27243. }
  27244. function getSetISOWeek(input) {
  27245. var week = weekOfYear(this, 1, 4).week;
  27246. return input == null ? week : this.add((input - week) * 7, 'd');
  27247. }
  27248. // FORMATTING
  27249. addFormatToken('d', 0, 'do', 'day');
  27250. addFormatToken('dd', 0, 0, function(format) {
  27251. return this.localeData().weekdaysMin(this, format);
  27252. });
  27253. addFormatToken('ddd', 0, 0, function(format) {
  27254. return this.localeData().weekdaysShort(this, format);
  27255. });
  27256. addFormatToken('dddd', 0, 0, function(format) {
  27257. return this.localeData().weekdays(this, format);
  27258. });
  27259. addFormatToken('e', 0, 0, 'weekday');
  27260. addFormatToken('E', 0, 0, 'isoWeekday');
  27261. // ALIASES
  27262. addUnitAlias('day', 'd');
  27263. addUnitAlias('weekday', 'e');
  27264. addUnitAlias('isoWeekday', 'E');
  27265. // PRIORITY
  27266. addUnitPriority('day', 11);
  27267. addUnitPriority('weekday', 11);
  27268. addUnitPriority('isoWeekday', 11);
  27269. // PARSING
  27270. addRegexToken('d', match1to2);
  27271. addRegexToken('e', match1to2);
  27272. addRegexToken('E', match1to2);
  27273. addRegexToken('dd', function(isStrict, locale) {
  27274. return locale.weekdaysMinRegex(isStrict);
  27275. });
  27276. addRegexToken('ddd', function(isStrict, locale) {
  27277. return locale.weekdaysShortRegex(isStrict);
  27278. });
  27279. addRegexToken('dddd', function(isStrict, locale) {
  27280. return locale.weekdaysRegex(isStrict);
  27281. });
  27282. addWeekParseToken(['dd', 'ddd', 'dddd'], function(input, week, config, token) {
  27283. var weekday = config._locale.weekdaysParse(input, token, config._strict);
  27284. // if we didn't get a weekday name, mark the date as invalid
  27285. if (weekday != null) {
  27286. week.d = weekday;
  27287. } else {
  27288. getParsingFlags(config).invalidWeekday = input;
  27289. }
  27290. });
  27291. addWeekParseToken(['d', 'e', 'E'], function(input, week, config, token) {
  27292. week[token] = toInt(input);
  27293. });
  27294. // HELPERS
  27295. function parseWeekday(input, locale) {
  27296. if (typeof input !== 'string') {
  27297. return input;
  27298. }
  27299. if (!isNaN(input)) {
  27300. return parseInt(input, 10);
  27301. }
  27302. input = locale.weekdaysParse(input);
  27303. if (typeof input === 'number') {
  27304. return input;
  27305. }
  27306. return null;
  27307. }
  27308. function parseIsoWeekday(input, locale) {
  27309. if (typeof input === 'string') {
  27310. return locale.weekdaysParse(input) % 7 || 7;
  27311. }
  27312. return isNaN(input) ? null : input;
  27313. }
  27314. // LOCALES
  27315. var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
  27316. function localeWeekdays(m, format) {
  27317. if (!m) {
  27318. return isArray(this._weekdays) ? this._weekdays :
  27319. this._weekdays['standalone'];
  27320. }
  27321. return isArray(this._weekdays) ? this._weekdays[m.day()] :
  27322. this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
  27323. }
  27324. var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
  27325. function localeWeekdaysShort(m) {
  27326. return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
  27327. }
  27328. var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
  27329. function localeWeekdaysMin(m) {
  27330. return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
  27331. }
  27332. function handleStrictParse$1(weekdayName, format, strict) {
  27333. var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
  27334. if (!this._weekdaysParse) {
  27335. this._weekdaysParse = [];
  27336. this._shortWeekdaysParse = [];
  27337. this._minWeekdaysParse = [];
  27338. for (i = 0; i < 7; ++i) {
  27339. mom = createUTC([2000, 1]).day(i);
  27340. this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
  27341. this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
  27342. this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
  27343. }
  27344. }
  27345. if (strict) {
  27346. if (format === 'dddd') {
  27347. ii = indexOf.call(this._weekdaysParse, llc);
  27348. return ii !== -1 ? ii : null;
  27349. } else if (format === 'ddd') {
  27350. ii = indexOf.call(this._shortWeekdaysParse, llc);
  27351. return ii !== -1 ? ii : null;
  27352. } else {
  27353. ii = indexOf.call(this._minWeekdaysParse, llc);
  27354. return ii !== -1 ? ii : null;
  27355. }
  27356. } else {
  27357. if (format === 'dddd') {
  27358. ii = indexOf.call(this._weekdaysParse, llc);
  27359. if (ii !== -1) {
  27360. return ii;
  27361. }
  27362. ii = indexOf.call(this._shortWeekdaysParse, llc);
  27363. if (ii !== -1) {
  27364. return ii;
  27365. }
  27366. ii = indexOf.call(this._minWeekdaysParse, llc);
  27367. return ii !== -1 ? ii : null;
  27368. } else if (format === 'ddd') {
  27369. ii = indexOf.call(this._shortWeekdaysParse, llc);
  27370. if (ii !== -1) {
  27371. return ii;
  27372. }
  27373. ii = indexOf.call(this._weekdaysParse, llc);
  27374. if (ii !== -1) {
  27375. return ii;
  27376. }
  27377. ii = indexOf.call(this._minWeekdaysParse, llc);
  27378. return ii !== -1 ? ii : null;
  27379. } else {
  27380. ii = indexOf.call(this._minWeekdaysParse, llc);
  27381. if (ii !== -1) {
  27382. return ii;
  27383. }
  27384. ii = indexOf.call(this._weekdaysParse, llc);
  27385. if (ii !== -1) {
  27386. return ii;
  27387. }
  27388. ii = indexOf.call(this._shortWeekdaysParse, llc);
  27389. return ii !== -1 ? ii : null;
  27390. }
  27391. }
  27392. }
  27393. function localeWeekdaysParse(weekdayName, format, strict) {
  27394. var i, mom, regex;
  27395. if (this._weekdaysParseExact) {
  27396. return handleStrictParse$1.call(this, weekdayName, format, strict);
  27397. }
  27398. if (!this._weekdaysParse) {
  27399. this._weekdaysParse = [];
  27400. this._minWeekdaysParse = [];
  27401. this._shortWeekdaysParse = [];
  27402. this._fullWeekdaysParse = [];
  27403. }
  27404. for (i = 0; i < 7; i++) {
  27405. // make the regex if we don't have it already
  27406. mom = createUTC([2000, 1]).day(i);
  27407. if (strict && !this._fullWeekdaysParse[i]) {
  27408. this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
  27409. this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
  27410. this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
  27411. }
  27412. if (!this._weekdaysParse[i]) {
  27413. regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
  27414. this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
  27415. }
  27416. // test the regex
  27417. if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
  27418. return i;
  27419. } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
  27420. return i;
  27421. } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
  27422. return i;
  27423. } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
  27424. return i;
  27425. }
  27426. }
  27427. }
  27428. // MOMENTS
  27429. function getSetDayOfWeek(input) {
  27430. if (!this.isValid()) {
  27431. return input != null ? this : NaN;
  27432. }
  27433. var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
  27434. if (input != null) {
  27435. input = parseWeekday(input, this.localeData());
  27436. return this.add(input - day, 'd');
  27437. } else {
  27438. return day;
  27439. }
  27440. }
  27441. function getSetLocaleDayOfWeek(input) {
  27442. if (!this.isValid()) {
  27443. return input != null ? this : NaN;
  27444. }
  27445. var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
  27446. return input == null ? weekday : this.add(input - weekday, 'd');
  27447. }
  27448. function getSetISODayOfWeek(input) {
  27449. if (!this.isValid()) {
  27450. return input != null ? this : NaN;
  27451. }
  27452. // behaves the same as moment#day except
  27453. // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
  27454. // as a setter, sunday should belong to the previous week.
  27455. if (input != null) {
  27456. var weekday = parseIsoWeekday(input, this.localeData());
  27457. return this.day(this.day() % 7 ? weekday : weekday - 7);
  27458. } else {
  27459. return this.day() || 7;
  27460. }
  27461. }
  27462. var defaultWeekdaysRegex = matchWord;
  27463. function weekdaysRegex(isStrict) {
  27464. if (this._weekdaysParseExact) {
  27465. if (!hasOwnProp(this, '_weekdaysRegex')) {
  27466. computeWeekdaysParse.call(this);
  27467. }
  27468. if (isStrict) {
  27469. return this._weekdaysStrictRegex;
  27470. } else {
  27471. return this._weekdaysRegex;
  27472. }
  27473. } else {
  27474. if (!hasOwnProp(this, '_weekdaysRegex')) {
  27475. this._weekdaysRegex = defaultWeekdaysRegex;
  27476. }
  27477. return this._weekdaysStrictRegex && isStrict ?
  27478. this._weekdaysStrictRegex : this._weekdaysRegex;
  27479. }
  27480. }
  27481. var defaultWeekdaysShortRegex = matchWord;
  27482. function weekdaysShortRegex(isStrict) {
  27483. if (this._weekdaysParseExact) {
  27484. if (!hasOwnProp(this, '_weekdaysRegex')) {
  27485. computeWeekdaysParse.call(this);
  27486. }
  27487. if (isStrict) {
  27488. return this._weekdaysShortStrictRegex;
  27489. } else {
  27490. return this._weekdaysShortRegex;
  27491. }
  27492. } else {
  27493. if (!hasOwnProp(this, '_weekdaysShortRegex')) {
  27494. this._weekdaysShortRegex = defaultWeekdaysShortRegex;
  27495. }
  27496. return this._weekdaysShortStrictRegex && isStrict ?
  27497. this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
  27498. }
  27499. }
  27500. var defaultWeekdaysMinRegex = matchWord;
  27501. function weekdaysMinRegex(isStrict) {
  27502. if (this._weekdaysParseExact) {
  27503. if (!hasOwnProp(this, '_weekdaysRegex')) {
  27504. computeWeekdaysParse.call(this);
  27505. }
  27506. if (isStrict) {
  27507. return this._weekdaysMinStrictRegex;
  27508. } else {
  27509. return this._weekdaysMinRegex;
  27510. }
  27511. } else {
  27512. if (!hasOwnProp(this, '_weekdaysMinRegex')) {
  27513. this._weekdaysMinRegex = defaultWeekdaysMinRegex;
  27514. }
  27515. return this._weekdaysMinStrictRegex && isStrict ?
  27516. this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
  27517. }
  27518. }
  27519. function computeWeekdaysParse() {
  27520. function cmpLenRev(a, b) {
  27521. return b.length - a.length;
  27522. }
  27523. var minPieces = [],
  27524. shortPieces = [],
  27525. longPieces = [],
  27526. mixedPieces = [],
  27527. i, mom, minp, shortp, longp;
  27528. for (i = 0; i < 7; i++) {
  27529. // make the regex if we don't have it already
  27530. mom = createUTC([2000, 1]).day(i);
  27531. minp = this.weekdaysMin(mom, '');
  27532. shortp = this.weekdaysShort(mom, '');
  27533. longp = this.weekdays(mom, '');
  27534. minPieces.push(minp);
  27535. shortPieces.push(shortp);
  27536. longPieces.push(longp);
  27537. mixedPieces.push(minp);
  27538. mixedPieces.push(shortp);
  27539. mixedPieces.push(longp);
  27540. }
  27541. // Sorting makes sure if one weekday (or abbr) is a prefix of another it
  27542. // will match the longer piece.
  27543. minPieces.sort(cmpLenRev);
  27544. shortPieces.sort(cmpLenRev);
  27545. longPieces.sort(cmpLenRev);
  27546. mixedPieces.sort(cmpLenRev);
  27547. for (i = 0; i < 7; i++) {
  27548. shortPieces[i] = regexEscape(shortPieces[i]);
  27549. longPieces[i] = regexEscape(longPieces[i]);
  27550. mixedPieces[i] = regexEscape(mixedPieces[i]);
  27551. }
  27552. this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
  27553. this._weekdaysShortRegex = this._weekdaysRegex;
  27554. this._weekdaysMinRegex = this._weekdaysRegex;
  27555. this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
  27556. this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
  27557. this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
  27558. }
  27559. // FORMATTING
  27560. function hFormat() {
  27561. return this.hours() % 12 || 12;
  27562. }
  27563. function kFormat() {
  27564. return this.hours() || 24;
  27565. }
  27566. addFormatToken('H', ['HH', 2], 0, 'hour');
  27567. addFormatToken('h', ['hh', 2], 0, hFormat);
  27568. addFormatToken('k', ['kk', 2], 0, kFormat);
  27569. addFormatToken('hmm', 0, 0, function() {
  27570. return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
  27571. });
  27572. addFormatToken('hmmss', 0, 0, function() {
  27573. return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
  27574. zeroFill(this.seconds(), 2);
  27575. });
  27576. addFormatToken('Hmm', 0, 0, function() {
  27577. return '' + this.hours() + zeroFill(this.minutes(), 2);
  27578. });
  27579. addFormatToken('Hmmss', 0, 0, function() {
  27580. return '' + this.hours() + zeroFill(this.minutes(), 2) +
  27581. zeroFill(this.seconds(), 2);
  27582. });
  27583. function meridiem(token, lowercase) {
  27584. addFormatToken(token, 0, 0, function() {
  27585. return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
  27586. });
  27587. }
  27588. meridiem('a', true);
  27589. meridiem('A', false);
  27590. // ALIASES
  27591. addUnitAlias('hour', 'h');
  27592. // PRIORITY
  27593. addUnitPriority('hour', 13);
  27594. // PARSING
  27595. function matchMeridiem(isStrict, locale) {
  27596. return locale._meridiemParse;
  27597. }
  27598. addRegexToken('a', matchMeridiem);
  27599. addRegexToken('A', matchMeridiem);
  27600. addRegexToken('H', match1to2);
  27601. addRegexToken('h', match1to2);
  27602. addRegexToken('k', match1to2);
  27603. addRegexToken('HH', match1to2, match2);
  27604. addRegexToken('hh', match1to2, match2);
  27605. addRegexToken('kk', match1to2, match2);
  27606. addRegexToken('hmm', match3to4);
  27607. addRegexToken('hmmss', match5to6);
  27608. addRegexToken('Hmm', match3to4);
  27609. addRegexToken('Hmmss', match5to6);
  27610. addParseToken(['H', 'HH'], HOUR);
  27611. addParseToken(['k', 'kk'], function(input, array, config) {
  27612. var kInput = toInt(input);
  27613. array[HOUR] = kInput === 24 ? 0 : kInput;
  27614. });
  27615. addParseToken(['a', 'A'], function(input, array, config) {
  27616. config._isPm = config._locale.isPM(input);
  27617. config._meridiem = input;
  27618. });
  27619. addParseToken(['h', 'hh'], function(input, array, config) {
  27620. array[HOUR] = toInt(input);
  27621. getParsingFlags(config).bigHour = true;
  27622. });
  27623. addParseToken('hmm', function(input, array, config) {
  27624. var pos = input.length - 2;
  27625. array[HOUR] = toInt(input.substr(0, pos));
  27626. array[MINUTE] = toInt(input.substr(pos));
  27627. getParsingFlags(config).bigHour = true;
  27628. });
  27629. addParseToken('hmmss', function(input, array, config) {
  27630. var pos1 = input.length - 4;
  27631. var pos2 = input.length - 2;
  27632. array[HOUR] = toInt(input.substr(0, pos1));
  27633. array[MINUTE] = toInt(input.substr(pos1, 2));
  27634. array[SECOND] = toInt(input.substr(pos2));
  27635. getParsingFlags(config).bigHour = true;
  27636. });
  27637. addParseToken('Hmm', function(input, array, config) {
  27638. var pos = input.length - 2;
  27639. array[HOUR] = toInt(input.substr(0, pos));
  27640. array[MINUTE] = toInt(input.substr(pos));
  27641. });
  27642. addParseToken('Hmmss', function(input, array, config) {
  27643. var pos1 = input.length - 4;
  27644. var pos2 = input.length - 2;
  27645. array[HOUR] = toInt(input.substr(0, pos1));
  27646. array[MINUTE] = toInt(input.substr(pos1, 2));
  27647. array[SECOND] = toInt(input.substr(pos2));
  27648. });
  27649. // LOCALES
  27650. function localeIsPM(input) {
  27651. // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
  27652. // Using charAt should be more compatible.
  27653. return ((input + '').toLowerCase().charAt(0) === 'p');
  27654. }
  27655. var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
  27656. function localeMeridiem(hours, minutes, isLower) {
  27657. if (hours > 11) {
  27658. return isLower ? 'pm' : 'PM';
  27659. } else {
  27660. return isLower ? 'am' : 'AM';
  27661. }
  27662. }
  27663. // MOMENTS
  27664. // Setting the hour should keep the time, because the user explicitly
  27665. // specified which hour he wants. So trying to maintain the same hour (in
  27666. // a new timezone) makes sense. Adding/subtracting hours does not follow
  27667. // this rule.
  27668. var getSetHour = makeGetSet('Hours', true);
  27669. // months
  27670. // week
  27671. // weekdays
  27672. // meridiem
  27673. var baseConfig = {
  27674. calendar: defaultCalendar,
  27675. longDateFormat: defaultLongDateFormat,
  27676. invalidDate: defaultInvalidDate,
  27677. ordinal: defaultOrdinal,
  27678. dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
  27679. relativeTime: defaultRelativeTime,
  27680. months: defaultLocaleMonths,
  27681. monthsShort: defaultLocaleMonthsShort,
  27682. week: defaultLocaleWeek,
  27683. weekdays: defaultLocaleWeekdays,
  27684. weekdaysMin: defaultLocaleWeekdaysMin,
  27685. weekdaysShort: defaultLocaleWeekdaysShort,
  27686. meridiemParse: defaultLocaleMeridiemParse
  27687. };
  27688. // internal storage for locale config files
  27689. var locales = {};
  27690. var localeFamilies = {};
  27691. var globalLocale;
  27692. function normalizeLocale(key) {
  27693. return key ? key.toLowerCase().replace('_', '-') : key;
  27694. }
  27695. // pick the locale from the array
  27696. // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
  27697. // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
  27698. function chooseLocale(names) {
  27699. var i = 0,
  27700. j, next, locale, split;
  27701. while (i < names.length) {
  27702. split = normalizeLocale(names[i]).split('-');
  27703. j = split.length;
  27704. next = normalizeLocale(names[i + 1]);
  27705. next = next ? next.split('-') : null;
  27706. while (j > 0) {
  27707. locale = loadLocale(split.slice(0, j).join('-'));
  27708. if (locale) {
  27709. return locale;
  27710. }
  27711. if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
  27712. //the next array item is better than a shallower substring of this one
  27713. break;
  27714. }
  27715. j--;
  27716. }
  27717. i++;
  27718. }
  27719. return null;
  27720. }
  27721. function loadLocale(name) {
  27722. var oldLocale = null;
  27723. // TODO: Find a better way to register and load all the locales in Node
  27724. if (!locales[name] && (typeof module !== 'undefined') &&
  27725. module && module.exports) {
  27726. try {
  27727. oldLocale = globalLocale._abbr;
  27728. var aliasedRequire = require;
  27729. !(function webpackMissingModule() {
  27730. var e = new Error("Cannot find module \"./locale\"");
  27731. e.code = 'MODULE_NOT_FOUND';
  27732. throw e;
  27733. }());
  27734. getSetGlobalLocale(oldLocale);
  27735. } catch (e) {}
  27736. }
  27737. return locales[name];
  27738. }
  27739. // This function will load locale and then set the global locale. If
  27740. // no arguments are passed in, it will simply return the current global
  27741. // locale key.
  27742. function getSetGlobalLocale(key, values) {
  27743. var data;
  27744. if (key) {
  27745. if (isUndefined(values)) {
  27746. data = getLocale(key);
  27747. } else {
  27748. data = defineLocale(key, values);
  27749. }
  27750. if (data) {
  27751. // moment.duration._locale = moment._locale = data;
  27752. globalLocale = data;
  27753. }
  27754. }
  27755. return globalLocale._abbr;
  27756. }
  27757. function defineLocale(name, config) {
  27758. if (config !== null) {
  27759. var parentConfig = baseConfig;
  27760. config.abbr = name;
  27761. if (locales[name] != null) {
  27762. deprecateSimple('defineLocaleOverride',
  27763. 'use moment.updateLocale(localeName, config) to change ' +
  27764. 'an existing locale. moment.defineLocale(localeName, ' +
  27765. 'config) should only be used for creating a new locale ' +
  27766. 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
  27767. parentConfig = locales[name]._config;
  27768. } else if (config.parentLocale != null) {
  27769. if (locales[config.parentLocale] != null) {
  27770. parentConfig = locales[config.parentLocale]._config;
  27771. } else {
  27772. if (!localeFamilies[config.parentLocale]) {
  27773. localeFamilies[config.parentLocale] = [];
  27774. }
  27775. localeFamilies[config.parentLocale].push({
  27776. name: name,
  27777. config: config
  27778. });
  27779. return null;
  27780. }
  27781. }
  27782. locales[name] = new Locale(mergeConfigs(parentConfig, config));
  27783. if (localeFamilies[name]) {
  27784. localeFamilies[name].forEach(function(x) {
  27785. defineLocale(x.name, x.config);
  27786. });
  27787. }
  27788. // backwards compat for now: also set the locale
  27789. // make sure we set the locale AFTER all child locales have been
  27790. // created, so we won't end up with the child locale set.
  27791. getSetGlobalLocale(name);
  27792. return locales[name];
  27793. } else {
  27794. // useful for testing
  27795. delete locales[name];
  27796. return null;
  27797. }
  27798. }
  27799. function updateLocale(name, config) {
  27800. if (config != null) {
  27801. var locale, parentConfig = baseConfig;
  27802. // MERGE
  27803. if (locales[name] != null) {
  27804. parentConfig = locales[name]._config;
  27805. }
  27806. config = mergeConfigs(parentConfig, config);
  27807. locale = new Locale(config);
  27808. locale.parentLocale = locales[name];
  27809. locales[name] = locale;
  27810. // backwards compat for now: also set the locale
  27811. getSetGlobalLocale(name);
  27812. } else {
  27813. // pass null for config to unupdate, useful for tests
  27814. if (locales[name] != null) {
  27815. if (locales[name].parentLocale != null) {
  27816. locales[name] = locales[name].parentLocale;
  27817. } else if (locales[name] != null) {
  27818. delete locales[name];
  27819. }
  27820. }
  27821. }
  27822. return locales[name];
  27823. }
  27824. // returns locale data
  27825. function getLocale(key) {
  27826. var locale;
  27827. if (key && key._locale && key._locale._abbr) {
  27828. key = key._locale._abbr;
  27829. }
  27830. if (!key) {
  27831. return globalLocale;
  27832. }
  27833. if (!isArray(key)) {
  27834. //short-circuit everything else
  27835. locale = loadLocale(key);
  27836. if (locale) {
  27837. return locale;
  27838. }
  27839. key = [key];
  27840. }
  27841. return chooseLocale(key);
  27842. }
  27843. function listLocales() {
  27844. return keys(locales);
  27845. }
  27846. function checkOverflow(m) {
  27847. var overflow;
  27848. var a = m._a;
  27849. if (a && getParsingFlags(m).overflow === -2) {
  27850. overflow =
  27851. a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :
  27852. a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
  27853. a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
  27854. a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :
  27855. a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :
  27856. a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
  27857. -1;
  27858. if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
  27859. overflow = DATE;
  27860. }
  27861. if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
  27862. overflow = WEEK;
  27863. }
  27864. if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
  27865. overflow = WEEKDAY;
  27866. }
  27867. getParsingFlags(m).overflow = overflow;
  27868. }
  27869. return m;
  27870. }
  27871. // Pick the first defined of two or three arguments.
  27872. function defaults(a, b, c) {
  27873. if (a != null) {
  27874. return a;
  27875. }
  27876. if (b != null) {
  27877. return b;
  27878. }
  27879. return c;
  27880. }
  27881. function currentDateArray(config) {
  27882. // hooks is actually the exported moment object
  27883. var nowValue = new Date(hooks.now());
  27884. if (config._useUTC) {
  27885. return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
  27886. }
  27887. return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
  27888. }
  27889. // convert an array to a date.
  27890. // the array should mirror the parameters below
  27891. // note: all values past the year are optional and will default to the lowest possible value.
  27892. // [year, month, day , hour, minute, second, millisecond]
  27893. function configFromArray(config) {
  27894. var i, date, input = [],
  27895. currentDate, yearToUse;
  27896. if (config._d) {
  27897. return;
  27898. }
  27899. currentDate = currentDateArray(config);
  27900. //compute day of the year from weeks and weekdays
  27901. if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
  27902. dayOfYearFromWeekInfo(config);
  27903. }
  27904. //if the day of the year is set, figure out what it is
  27905. if (config._dayOfYear != null) {
  27906. yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
  27907. if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
  27908. getParsingFlags(config)._overflowDayOfYear = true;
  27909. }
  27910. date = createUTCDate(yearToUse, 0, config._dayOfYear);
  27911. config._a[MONTH] = date.getUTCMonth();
  27912. config._a[DATE] = date.getUTCDate();
  27913. }
  27914. // Default to current date.
  27915. // * if no year, month, day of month are given, default to today
  27916. // * if day of month is given, default month and year
  27917. // * if month is given, default only year
  27918. // * if year is given, don't default anything
  27919. for (i = 0; i < 3 && config._a[i] == null; ++i) {
  27920. config._a[i] = input[i] = currentDate[i];
  27921. }
  27922. // Zero out whatever was not defaulted, including time
  27923. for (; i < 7; i++) {
  27924. config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
  27925. }
  27926. // Check for 24:00:00.000
  27927. if (config._a[HOUR] === 24 &&
  27928. config._a[MINUTE] === 0 &&
  27929. config._a[SECOND] === 0 &&
  27930. config._a[MILLISECOND] === 0) {
  27931. config._nextDay = true;
  27932. config._a[HOUR] = 0;
  27933. }
  27934. config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
  27935. // Apply timezone offset from input. The actual utcOffset can be changed
  27936. // with parseZone.
  27937. if (config._tzm != null) {
  27938. config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
  27939. }
  27940. if (config._nextDay) {
  27941. config._a[HOUR] = 24;
  27942. }
  27943. // check for mismatching day of week
  27944. if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== config._d.getDay()) {
  27945. getParsingFlags(config).weekdayMismatch = true;
  27946. }
  27947. }
  27948. function dayOfYearFromWeekInfo(config) {
  27949. var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
  27950. w = config._w;
  27951. if (w.GG != null || w.W != null || w.E != null) {
  27952. dow = 1;
  27953. doy = 4;
  27954. // TODO: We need to take the current isoWeekYear, but that depends on
  27955. // how we interpret now (local, utc, fixed offset). So create
  27956. // a now version of current config (take local/utc/offset flags, and
  27957. // create now).
  27958. weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
  27959. week = defaults(w.W, 1);
  27960. weekday = defaults(w.E, 1);
  27961. if (weekday < 1 || weekday > 7) {
  27962. weekdayOverflow = true;
  27963. }
  27964. } else {
  27965. dow = config._locale._week.dow;
  27966. doy = config._locale._week.doy;
  27967. var curWeek = weekOfYear(createLocal(), dow, doy);
  27968. weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
  27969. // Default to current week.
  27970. week = defaults(w.w, curWeek.week);
  27971. if (w.d != null) {
  27972. // weekday -- low day numbers are considered next week
  27973. weekday = w.d;
  27974. if (weekday < 0 || weekday > 6) {
  27975. weekdayOverflow = true;
  27976. }
  27977. } else if (w.e != null) {
  27978. // local weekday -- counting starts from begining of week
  27979. weekday = w.e + dow;
  27980. if (w.e < 0 || w.e > 6) {
  27981. weekdayOverflow = true;
  27982. }
  27983. } else {
  27984. // default to begining of week
  27985. weekday = dow;
  27986. }
  27987. }
  27988. if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
  27989. getParsingFlags(config)._overflowWeeks = true;
  27990. } else if (weekdayOverflow != null) {
  27991. getParsingFlags(config)._overflowWeekday = true;
  27992. } else {
  27993. temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
  27994. config._a[YEAR] = temp.year;
  27995. config._dayOfYear = temp.dayOfYear;
  27996. }
  27997. }
  27998. // iso 8601 regex
  27999. // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
  28000. var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
  28001. var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
  28002. var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
  28003. var isoDates = [
  28004. ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
  28005. ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
  28006. ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
  28007. ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
  28008. ['YYYY-DDD', /\d{4}-\d{3}/],
  28009. ['YYYY-MM', /\d{4}-\d\d/, false],
  28010. ['YYYYYYMMDD', /[+-]\d{10}/],
  28011. ['YYYYMMDD', /\d{8}/],
  28012. // YYYYMM is NOT allowed by the standard
  28013. ['GGGG[W]WWE', /\d{4}W\d{3}/],
  28014. ['GGGG[W]WW', /\d{4}W\d{2}/, false],
  28015. ['YYYYDDD', /\d{7}/]
  28016. ];
  28017. // iso time formats and regexes
  28018. var isoTimes = [
  28019. ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
  28020. ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
  28021. ['HH:mm:ss', /\d\d:\d\d:\d\d/],
  28022. ['HH:mm', /\d\d:\d\d/],
  28023. ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
  28024. ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
  28025. ['HHmmss', /\d\d\d\d\d\d/],
  28026. ['HHmm', /\d\d\d\d/],
  28027. ['HH', /\d\d/]
  28028. ];
  28029. var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
  28030. // date from iso format
  28031. function configFromISO(config) {
  28032. var i, l,
  28033. string = config._i,
  28034. match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
  28035. allowTime, dateFormat, timeFormat, tzFormat;
  28036. if (match) {
  28037. getParsingFlags(config).iso = true;
  28038. for (i = 0, l = isoDates.length; i < l; i++) {
  28039. if (isoDates[i][1].exec(match[1])) {
  28040. dateFormat = isoDates[i][0];
  28041. allowTime = isoDates[i][2] !== false;
  28042. break;
  28043. }
  28044. }
  28045. if (dateFormat == null) {
  28046. config._isValid = false;
  28047. return;
  28048. }
  28049. if (match[3]) {
  28050. for (i = 0, l = isoTimes.length; i < l; i++) {
  28051. if (isoTimes[i][1].exec(match[3])) {
  28052. // match[2] should be 'T' or space
  28053. timeFormat = (match[2] || ' ') + isoTimes[i][0];
  28054. break;
  28055. }
  28056. }
  28057. if (timeFormat == null) {
  28058. config._isValid = false;
  28059. return;
  28060. }
  28061. }
  28062. if (!allowTime && timeFormat != null) {
  28063. config._isValid = false;
  28064. return;
  28065. }
  28066. if (match[4]) {
  28067. if (tzRegex.exec(match[4])) {
  28068. tzFormat = 'Z';
  28069. } else {
  28070. config._isValid = false;
  28071. return;
  28072. }
  28073. }
  28074. config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
  28075. configFromStringAndFormat(config);
  28076. } else {
  28077. config._isValid = false;
  28078. }
  28079. }
  28080. // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
  28081. var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
  28082. function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
  28083. var result = [
  28084. untruncateYear(yearStr),
  28085. defaultLocaleMonthsShort.indexOf(monthStr),
  28086. parseInt(dayStr, 10),
  28087. parseInt(hourStr, 10),
  28088. parseInt(minuteStr, 10)
  28089. ];
  28090. if (secondStr) {
  28091. result.push(parseInt(secondStr, 10));
  28092. }
  28093. return result;
  28094. }
  28095. function untruncateYear(yearStr) {
  28096. var year = parseInt(yearStr, 10);
  28097. if (year <= 49) {
  28098. return 2000 + year;
  28099. } else if (year <= 999) {
  28100. return 1900 + year;
  28101. }
  28102. return year;
  28103. }
  28104. function preprocessRFC2822(s) {
  28105. // Remove comments and folding whitespace and replace multiple-spaces with a single space
  28106. return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').trim();
  28107. }
  28108. function checkWeekday(weekdayStr, parsedInput, config) {
  28109. if (weekdayStr) {
  28110. // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
  28111. var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
  28112. weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
  28113. if (weekdayProvided !== weekdayActual) {
  28114. getParsingFlags(config).weekdayMismatch = true;
  28115. config._isValid = false;
  28116. return false;
  28117. }
  28118. }
  28119. return true;
  28120. }
  28121. var obsOffsets = {
  28122. UT: 0,
  28123. GMT: 0,
  28124. EDT: -4 * 60,
  28125. EST: -5 * 60,
  28126. CDT: -5 * 60,
  28127. CST: -6 * 60,
  28128. MDT: -6 * 60,
  28129. MST: -7 * 60,
  28130. PDT: -7 * 60,
  28131. PST: -8 * 60
  28132. };
  28133. function calculateOffset(obsOffset, militaryOffset, numOffset) {
  28134. if (obsOffset) {
  28135. return obsOffsets[obsOffset];
  28136. } else if (militaryOffset) {
  28137. // the only allowed military tz is Z
  28138. return 0;
  28139. } else {
  28140. var hm = parseInt(numOffset, 10);
  28141. var m = hm % 100,
  28142. h = (hm - m) / 100;
  28143. return h * 60 + m;
  28144. }
  28145. }
  28146. // date and time from ref 2822 format
  28147. function configFromRFC2822(config) {
  28148. var match = rfc2822.exec(preprocessRFC2822(config._i));
  28149. if (match) {
  28150. var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
  28151. if (!checkWeekday(match[1], parsedArray, config)) {
  28152. return;
  28153. }
  28154. config._a = parsedArray;
  28155. config._tzm = calculateOffset(match[8], match[9], match[10]);
  28156. config._d = createUTCDate.apply(null, config._a);
  28157. config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
  28158. getParsingFlags(config).rfc2822 = true;
  28159. } else {
  28160. config._isValid = false;
  28161. }
  28162. }
  28163. // date from iso format or fallback
  28164. function configFromString(config) {
  28165. var matched = aspNetJsonRegex.exec(config._i);
  28166. if (matched !== null) {
  28167. config._d = new Date(+matched[1]);
  28168. return;
  28169. }
  28170. configFromISO(config);
  28171. if (config._isValid === false) {
  28172. delete config._isValid;
  28173. } else {
  28174. return;
  28175. }
  28176. configFromRFC2822(config);
  28177. if (config._isValid === false) {
  28178. delete config._isValid;
  28179. } else {
  28180. return;
  28181. }
  28182. // Final attempt, use Input Fallback
  28183. hooks.createFromInputFallback(config);
  28184. }
  28185. hooks.createFromInputFallback = deprecate(
  28186. 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
  28187. 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
  28188. 'discouraged and will be removed in an upcoming major release. Please refer to ' +
  28189. 'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
  28190. function(config) {
  28191. config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
  28192. }
  28193. );
  28194. // constant that refers to the ISO standard
  28195. hooks.ISO_8601 = function() {};
  28196. // constant that refers to the RFC 2822 form
  28197. hooks.RFC_2822 = function() {};
  28198. // date from string and format string
  28199. function configFromStringAndFormat(config) {
  28200. // TODO: Move this to another part of the creation flow to prevent circular deps
  28201. if (config._f === hooks.ISO_8601) {
  28202. configFromISO(config);
  28203. return;
  28204. }
  28205. if (config._f === hooks.RFC_2822) {
  28206. configFromRFC2822(config);
  28207. return;
  28208. }
  28209. config._a = [];
  28210. getParsingFlags(config).empty = true;
  28211. // This array is used to make a Date, either with `new Date` or `Date.UTC`
  28212. var string = '' + config._i,
  28213. i, parsedInput, tokens, token, skipped,
  28214. stringLength = string.length,
  28215. totalParsedInputLength = 0;
  28216. tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
  28217. for (i = 0; i < tokens.length; i++) {
  28218. token = tokens[i];
  28219. parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
  28220. // console.log('token', token, 'parsedInput', parsedInput,
  28221. // 'regex', getParseRegexForToken(token, config));
  28222. if (parsedInput) {
  28223. skipped = string.substr(0, string.indexOf(parsedInput));
  28224. if (skipped.length > 0) {
  28225. getParsingFlags(config).unusedInput.push(skipped);
  28226. }
  28227. string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
  28228. totalParsedInputLength += parsedInput.length;
  28229. }
  28230. // don't parse if it's not a known token
  28231. if (formatTokenFunctions[token]) {
  28232. if (parsedInput) {
  28233. getParsingFlags(config).empty = false;
  28234. } else {
  28235. getParsingFlags(config).unusedTokens.push(token);
  28236. }
  28237. addTimeToArrayFromToken(token, parsedInput, config);
  28238. } else if (config._strict && !parsedInput) {
  28239. getParsingFlags(config).unusedTokens.push(token);
  28240. }
  28241. }
  28242. // add remaining unparsed input length to the string
  28243. getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
  28244. if (string.length > 0) {
  28245. getParsingFlags(config).unusedInput.push(string);
  28246. }
  28247. // clear _12h flag if hour is <= 12
  28248. if (config._a[HOUR] <= 12 &&
  28249. getParsingFlags(config).bigHour === true &&
  28250. config._a[HOUR] > 0) {
  28251. getParsingFlags(config).bigHour = undefined;
  28252. }
  28253. getParsingFlags(config).parsedDateParts = config._a.slice(0);
  28254. getParsingFlags(config).meridiem = config._meridiem;
  28255. // handle meridiem
  28256. config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
  28257. configFromArray(config);
  28258. checkOverflow(config);
  28259. }
  28260. function meridiemFixWrap(locale, hour, meridiem) {
  28261. var isPm;
  28262. if (meridiem == null) {
  28263. // nothing to do
  28264. return hour;
  28265. }
  28266. if (locale.meridiemHour != null) {
  28267. return locale.meridiemHour(hour, meridiem);
  28268. } else if (locale.isPM != null) {
  28269. // Fallback
  28270. isPm = locale.isPM(meridiem);
  28271. if (isPm && hour < 12) {
  28272. hour += 12;
  28273. }
  28274. if (!isPm && hour === 12) {
  28275. hour = 0;
  28276. }
  28277. return hour;
  28278. } else {
  28279. // this is not supposed to happen
  28280. return hour;
  28281. }
  28282. }
  28283. // date from string and array of format strings
  28284. function configFromStringAndArray(config) {
  28285. var tempConfig,
  28286. bestMoment,
  28287. scoreToBeat,
  28288. i,
  28289. currentScore;
  28290. if (config._f.length === 0) {
  28291. getParsingFlags(config).invalidFormat = true;
  28292. config._d = new Date(NaN);
  28293. return;
  28294. }
  28295. for (i = 0; i < config._f.length; i++) {
  28296. currentScore = 0;
  28297. tempConfig = copyConfig({}, config);
  28298. if (config._useUTC != null) {
  28299. tempConfig._useUTC = config._useUTC;
  28300. }
  28301. tempConfig._f = config._f[i];
  28302. configFromStringAndFormat(tempConfig);
  28303. if (!isValid(tempConfig)) {
  28304. continue;
  28305. }
  28306. // if there is any input that was not parsed add a penalty for that format
  28307. currentScore += getParsingFlags(tempConfig).charsLeftOver;
  28308. //or tokens
  28309. currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
  28310. getParsingFlags(tempConfig).score = currentScore;
  28311. if (scoreToBeat == null || currentScore < scoreToBeat) {
  28312. scoreToBeat = currentScore;
  28313. bestMoment = tempConfig;
  28314. }
  28315. }
  28316. extend(config, bestMoment || tempConfig);
  28317. }
  28318. function configFromObject(config) {
  28319. if (config._d) {
  28320. return;
  28321. }
  28322. var i = normalizeObjectUnits(config._i);
  28323. config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function(obj) {
  28324. return obj && parseInt(obj, 10);
  28325. });
  28326. configFromArray(config);
  28327. }
  28328. function createFromConfig(config) {
  28329. var res = new Moment(checkOverflow(prepareConfig(config)));
  28330. if (res._nextDay) {
  28331. // Adding is smart enough around DST
  28332. res.add(1, 'd');
  28333. res._nextDay = undefined;
  28334. }
  28335. return res;
  28336. }
  28337. function prepareConfig(config) {
  28338. var input = config._i,
  28339. format = config._f;
  28340. config._locale = config._locale || getLocale(config._l);
  28341. if (input === null || (format === undefined && input === '')) {
  28342. return createInvalid({ nullInput: true });
  28343. }
  28344. if (typeof input === 'string') {
  28345. config._i = input = config._locale.preparse(input);
  28346. }
  28347. if (isMoment(input)) {
  28348. return new Moment(checkOverflow(input));
  28349. } else if (isDate(input)) {
  28350. config._d = input;
  28351. } else if (isArray(format)) {
  28352. configFromStringAndArray(config);
  28353. } else if (format) {
  28354. configFromStringAndFormat(config);
  28355. } else {
  28356. configFromInput(config);
  28357. }
  28358. if (!isValid(config)) {
  28359. config._d = null;
  28360. }
  28361. return config;
  28362. }
  28363. function configFromInput(config) {
  28364. var input = config._i;
  28365. if (isUndefined(input)) {
  28366. config._d = new Date(hooks.now());
  28367. } else if (isDate(input)) {
  28368. config._d = new Date(input.valueOf());
  28369. } else if (typeof input === 'string') {
  28370. configFromString(config);
  28371. } else if (isArray(input)) {
  28372. config._a = map(input.slice(0), function(obj) {
  28373. return parseInt(obj, 10);
  28374. });
  28375. configFromArray(config);
  28376. } else if (isObject(input)) {
  28377. configFromObject(config);
  28378. } else if (isNumber(input)) {
  28379. // from milliseconds
  28380. config._d = new Date(input);
  28381. } else {
  28382. hooks.createFromInputFallback(config);
  28383. }
  28384. }
  28385. function createLocalOrUTC(input, format, locale, strict, isUTC) {
  28386. var c = {};
  28387. if (locale === true || locale === false) {
  28388. strict = locale;
  28389. locale = undefined;
  28390. }
  28391. if ((isObject(input) && isObjectEmpty(input)) ||
  28392. (isArray(input) && input.length === 0)) {
  28393. input = undefined;
  28394. }
  28395. // object construction must be done this way.
  28396. // https://github.com/moment/moment/issues/1423
  28397. c._isAMomentObject = true;
  28398. c._useUTC = c._isUTC = isUTC;
  28399. c._l = locale;
  28400. c._i = input;
  28401. c._f = format;
  28402. c._strict = strict;
  28403. return createFromConfig(c);
  28404. }
  28405. function createLocal(input, format, locale, strict) {
  28406. return createLocalOrUTC(input, format, locale, strict, false);
  28407. }
  28408. var prototypeMin = deprecate(
  28409. 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
  28410. function() {
  28411. var other = createLocal.apply(null, arguments);
  28412. if (this.isValid() && other.isValid()) {
  28413. return other < this ? this : other;
  28414. } else {
  28415. return createInvalid();
  28416. }
  28417. }
  28418. );
  28419. var prototypeMax = deprecate(
  28420. 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
  28421. function() {
  28422. var other = createLocal.apply(null, arguments);
  28423. if (this.isValid() && other.isValid()) {
  28424. return other > this ? this : other;
  28425. } else {
  28426. return createInvalid();
  28427. }
  28428. }
  28429. );
  28430. // Pick a moment m from moments so that m[fn](other) is true for all
  28431. // other. This relies on the function fn to be transitive.
  28432. //
  28433. // moments should either be an array of moment objects or an array, whose
  28434. // first element is an array of moment objects.
  28435. function pickBy(fn, moments) {
  28436. var res, i;
  28437. if (moments.length === 1 && isArray(moments[0])) {
  28438. moments = moments[0];
  28439. }
  28440. if (!moments.length) {
  28441. return createLocal();
  28442. }
  28443. res = moments[0];
  28444. for (i = 1; i < moments.length; ++i) {
  28445. if (!moments[i].isValid() || moments[i][fn](res)) {
  28446. res = moments[i];
  28447. }
  28448. }
  28449. return res;
  28450. }
  28451. // TODO: Use [].sort instead?
  28452. function min() {
  28453. var args = [].slice.call(arguments, 0);
  28454. return pickBy('isBefore', args);
  28455. }
  28456. function max() {
  28457. var args = [].slice.call(arguments, 0);
  28458. return pickBy('isAfter', args);
  28459. }
  28460. var now = function() {
  28461. return Date.now ? Date.now() : +(new Date());
  28462. };
  28463. var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
  28464. function isDurationValid(m) {
  28465. for (var key in m) {
  28466. if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
  28467. return false;
  28468. }
  28469. }
  28470. var unitHasDecimal = false;
  28471. for (var i = 0; i < ordering.length; ++i) {
  28472. if (m[ordering[i]]) {
  28473. if (unitHasDecimal) {
  28474. return false; // only allow non-integers for smallest unit
  28475. }
  28476. if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
  28477. unitHasDecimal = true;
  28478. }
  28479. }
  28480. }
  28481. return true;
  28482. }
  28483. function isValid$1() {
  28484. return this._isValid;
  28485. }
  28486. function createInvalid$1() {
  28487. return createDuration(NaN);
  28488. }
  28489. function Duration(duration) {
  28490. var normalizedInput = normalizeObjectUnits(duration),
  28491. years = normalizedInput.year || 0,
  28492. quarters = normalizedInput.quarter || 0,
  28493. months = normalizedInput.month || 0,
  28494. weeks = normalizedInput.week || 0,
  28495. days = normalizedInput.day || 0,
  28496. hours = normalizedInput.hour || 0,
  28497. minutes = normalizedInput.minute || 0,
  28498. seconds = normalizedInput.second || 0,
  28499. milliseconds = normalizedInput.millisecond || 0;
  28500. this._isValid = isDurationValid(normalizedInput);
  28501. // representation for dateAddRemove
  28502. this._milliseconds = +milliseconds +
  28503. seconds * 1e3 + // 1000
  28504. minutes * 6e4 + // 1000 * 60
  28505. hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
  28506. // Because of dateAddRemove treats 24 hours as different from a
  28507. // day when working around DST, we need to store them separately
  28508. this._days = +days +
  28509. weeks * 7;
  28510. // It is impossible to translate months into days without knowing
  28511. // which months you are are talking about, so we have to store
  28512. // it separately.
  28513. this._months = +months +
  28514. quarters * 3 +
  28515. years * 12;
  28516. this._data = {};
  28517. this._locale = getLocale();
  28518. this._bubble();
  28519. }
  28520. function isDuration(obj) {
  28521. return obj instanceof Duration;
  28522. }
  28523. function absRound(number) {
  28524. if (number < 0) {
  28525. return Math.round(-1 * number) * -1;
  28526. } else {
  28527. return Math.round(number);
  28528. }
  28529. }
  28530. // FORMATTING
  28531. function offset(token, separator) {
  28532. addFormatToken(token, 0, 0, function() {
  28533. var offset = this.utcOffset();
  28534. var sign = '+';
  28535. if (offset < 0) {
  28536. offset = -offset;
  28537. sign = '-';
  28538. }
  28539. return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
  28540. });
  28541. }
  28542. offset('Z', ':');
  28543. offset('ZZ', '');
  28544. // PARSING
  28545. addRegexToken('Z', matchShortOffset);
  28546. addRegexToken('ZZ', matchShortOffset);
  28547. addParseToken(['Z', 'ZZ'], function(input, array, config) {
  28548. config._useUTC = true;
  28549. config._tzm = offsetFromString(matchShortOffset, input);
  28550. });
  28551. // HELPERS
  28552. // timezone chunker
  28553. // '+10:00' > ['10', '00']
  28554. // '-1530' > ['-15', '30']
  28555. var chunkOffset = /([\+\-]|\d\d)/gi;
  28556. function offsetFromString(matcher, string) {
  28557. var matches = (string || '').match(matcher);
  28558. if (matches === null) {
  28559. return null;
  28560. }
  28561. var chunk = matches[matches.length - 1] || [];
  28562. var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
  28563. var minutes = +(parts[1] * 60) + toInt(parts[2]);
  28564. return minutes === 0 ?
  28565. 0 :
  28566. parts[0] === '+' ? minutes : -minutes;
  28567. }
  28568. // Return a moment from input, that is local/utc/zone equivalent to model.
  28569. function cloneWithOffset(input, model) {
  28570. var res, diff;
  28571. if (model._isUTC) {
  28572. res = model.clone();
  28573. diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
  28574. // Use low-level api, because this fn is low-level api.
  28575. res._d.setTime(res._d.valueOf() + diff);
  28576. hooks.updateOffset(res, false);
  28577. return res;
  28578. } else {
  28579. return createLocal(input).local();
  28580. }
  28581. }
  28582. function getDateOffset(m) {
  28583. // On Firefox.24 Date#getTimezoneOffset returns a floating point.
  28584. // https://github.com/moment/moment/pull/1871
  28585. return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
  28586. }
  28587. // HOOKS
  28588. // This function will be called whenever a moment is mutated.
  28589. // It is intended to keep the offset in sync with the timezone.
  28590. hooks.updateOffset = function() {};
  28591. // MOMENTS
  28592. // keepLocalTime = true means only change the timezone, without
  28593. // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
  28594. // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
  28595. // +0200, so we adjust the time as needed, to be valid.
  28596. //
  28597. // Keeping the time actually adds/subtracts (one hour)
  28598. // from the actual represented time. That is why we call updateOffset
  28599. // a second time. In case it wants us to change the offset again
  28600. // _changeInProgress == true case, then we have to adjust, because
  28601. // there is no such time in the given timezone.
  28602. function getSetOffset(input, keepLocalTime, keepMinutes) {
  28603. var offset = this._offset || 0,
  28604. localAdjust;
  28605. if (!this.isValid()) {
  28606. return input != null ? this : NaN;
  28607. }
  28608. if (input != null) {
  28609. if (typeof input === 'string') {
  28610. input = offsetFromString(matchShortOffset, input);
  28611. if (input === null) {
  28612. return this;
  28613. }
  28614. } else if (Math.abs(input) < 16 && !keepMinutes) {
  28615. input = input * 60;
  28616. }
  28617. if (!this._isUTC && keepLocalTime) {
  28618. localAdjust = getDateOffset(this);
  28619. }
  28620. this._offset = input;
  28621. this._isUTC = true;
  28622. if (localAdjust != null) {
  28623. this.add(localAdjust, 'm');
  28624. }
  28625. if (offset !== input) {
  28626. if (!keepLocalTime || this._changeInProgress) {
  28627. addSubtract(this, createDuration(input - offset, 'm'), 1, false);
  28628. } else if (!this._changeInProgress) {
  28629. this._changeInProgress = true;
  28630. hooks.updateOffset(this, true);
  28631. this._changeInProgress = null;
  28632. }
  28633. }
  28634. return this;
  28635. } else {
  28636. return this._isUTC ? offset : getDateOffset(this);
  28637. }
  28638. }
  28639. function getSetZone(input, keepLocalTime) {
  28640. if (input != null) {
  28641. if (typeof input !== 'string') {
  28642. input = -input;
  28643. }
  28644. this.utcOffset(input, keepLocalTime);
  28645. return this;
  28646. } else {
  28647. return -this.utcOffset();
  28648. }
  28649. }
  28650. function setOffsetToUTC(keepLocalTime) {
  28651. return this.utcOffset(0, keepLocalTime);
  28652. }
  28653. function setOffsetToLocal(keepLocalTime) {
  28654. if (this._isUTC) {
  28655. this.utcOffset(0, keepLocalTime);
  28656. this._isUTC = false;
  28657. if (keepLocalTime) {
  28658. this.subtract(getDateOffset(this), 'm');
  28659. }
  28660. }
  28661. return this;
  28662. }
  28663. function setOffsetToParsedOffset() {
  28664. if (this._tzm != null) {
  28665. this.utcOffset(this._tzm, false, true);
  28666. } else if (typeof this._i === 'string') {
  28667. var tZone = offsetFromString(matchOffset, this._i);
  28668. if (tZone != null) {
  28669. this.utcOffset(tZone);
  28670. } else {
  28671. this.utcOffset(0, true);
  28672. }
  28673. }
  28674. return this;
  28675. }
  28676. function hasAlignedHourOffset(input) {
  28677. if (!this.isValid()) {
  28678. return false;
  28679. }
  28680. input = input ? createLocal(input).utcOffset() : 0;
  28681. return (this.utcOffset() - input) % 60 === 0;
  28682. }
  28683. function isDaylightSavingTime() {
  28684. return (
  28685. this.utcOffset() > this.clone().month(0).utcOffset() ||
  28686. this.utcOffset() > this.clone().month(5).utcOffset()
  28687. );
  28688. }
  28689. function isDaylightSavingTimeShifted() {
  28690. if (!isUndefined(this._isDSTShifted)) {
  28691. return this._isDSTShifted;
  28692. }
  28693. var c = {};
  28694. copyConfig(c, this);
  28695. c = prepareConfig(c);
  28696. if (c._a) {
  28697. var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
  28698. this._isDSTShifted = this.isValid() &&
  28699. compareArrays(c._a, other.toArray()) > 0;
  28700. } else {
  28701. this._isDSTShifted = false;
  28702. }
  28703. return this._isDSTShifted;
  28704. }
  28705. function isLocal() {
  28706. return this.isValid() ? !this._isUTC : false;
  28707. }
  28708. function isUtcOffset() {
  28709. return this.isValid() ? this._isUTC : false;
  28710. }
  28711. function isUtc() {
  28712. return this.isValid() ? this._isUTC && this._offset === 0 : false;
  28713. }
  28714. // ASP.NET json date format regex
  28715. var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
  28716. // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
  28717. // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
  28718. // and further modified to allow for strings containing both week and day
  28719. var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
  28720. function createDuration(input, key) {
  28721. var duration = input,
  28722. // matching against regexp is expensive, do it on demand
  28723. match = null,
  28724. sign,
  28725. ret,
  28726. diffRes;
  28727. if (isDuration(input)) {
  28728. duration = {
  28729. ms: input._milliseconds,
  28730. d: input._days,
  28731. M: input._months
  28732. };
  28733. } else if (isNumber(input)) {
  28734. duration = {};
  28735. if (key) {
  28736. duration[key] = input;
  28737. } else {
  28738. duration.milliseconds = input;
  28739. }
  28740. } else if (!!(match = aspNetRegex.exec(input))) {
  28741. sign = (match[1] === '-') ? -1 : 1;
  28742. duration = {
  28743. y: 0,
  28744. d: toInt(match[DATE]) * sign,
  28745. h: toInt(match[HOUR]) * sign,
  28746. m: toInt(match[MINUTE]) * sign,
  28747. s: toInt(match[SECOND]) * sign,
  28748. ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
  28749. };
  28750. } else if (!!(match = isoRegex.exec(input))) {
  28751. sign = (match[1] === '-') ? -1 : (match[1] === '+') ? 1 : 1;
  28752. duration = {
  28753. y: parseIso(match[2], sign),
  28754. M: parseIso(match[3], sign),
  28755. w: parseIso(match[4], sign),
  28756. d: parseIso(match[5], sign),
  28757. h: parseIso(match[6], sign),
  28758. m: parseIso(match[7], sign),
  28759. s: parseIso(match[8], sign)
  28760. };
  28761. } else if (duration == null) { // checks for null or undefined
  28762. duration = {};
  28763. } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
  28764. diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
  28765. duration = {};
  28766. duration.ms = diffRes.milliseconds;
  28767. duration.M = diffRes.months;
  28768. }
  28769. ret = new Duration(duration);
  28770. if (isDuration(input) && hasOwnProp(input, '_locale')) {
  28771. ret._locale = input._locale;
  28772. }
  28773. return ret;
  28774. }
  28775. createDuration.fn = Duration.prototype;
  28776. createDuration.invalid = createInvalid$1;
  28777. function parseIso(inp, sign) {
  28778. // We'd normally use ~~inp for this, but unfortunately it also
  28779. // converts floats to ints.
  28780. // inp may be undefined, so careful calling replace on it.
  28781. var res = inp && parseFloat(inp.replace(',', '.'));
  28782. // apply sign while we're at it
  28783. return (isNaN(res) ? 0 : res) * sign;
  28784. }
  28785. function positiveMomentsDifference(base, other) {
  28786. var res = { milliseconds: 0, months: 0 };
  28787. res.months = other.month() - base.month() +
  28788. (other.year() - base.year()) * 12;
  28789. if (base.clone().add(res.months, 'M').isAfter(other)) {
  28790. --res.months;
  28791. }
  28792. res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
  28793. return res;
  28794. }
  28795. function momentsDifference(base, other) {
  28796. var res;
  28797. if (!(base.isValid() && other.isValid())) {
  28798. return { milliseconds: 0, months: 0 };
  28799. }
  28800. other = cloneWithOffset(other, base);
  28801. if (base.isBefore(other)) {
  28802. res = positiveMomentsDifference(base, other);
  28803. } else {
  28804. res = positiveMomentsDifference(other, base);
  28805. res.milliseconds = -res.milliseconds;
  28806. res.months = -res.months;
  28807. }
  28808. return res;
  28809. }
  28810. // TODO: remove 'name' arg after deprecation is removed
  28811. function createAdder(direction, name) {
  28812. return function(val, period) {
  28813. var dur, tmp;
  28814. //invert the arguments, but complain about it
  28815. if (period !== null && !isNaN(+period)) {
  28816. deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
  28817. 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
  28818. tmp = val;
  28819. val = period;
  28820. period = tmp;
  28821. }
  28822. val = typeof val === 'string' ? +val : val;
  28823. dur = createDuration(val, period);
  28824. addSubtract(this, dur, direction);
  28825. return this;
  28826. };
  28827. }
  28828. function addSubtract(mom, duration, isAdding, updateOffset) {
  28829. var milliseconds = duration._milliseconds,
  28830. days = absRound(duration._days),
  28831. months = absRound(duration._months);
  28832. if (!mom.isValid()) {
  28833. // No op
  28834. return;
  28835. }
  28836. updateOffset = updateOffset == null ? true : updateOffset;
  28837. if (months) {
  28838. setMonth(mom, get(mom, 'Month') + months * isAdding);
  28839. }
  28840. if (days) {
  28841. set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
  28842. }
  28843. if (milliseconds) {
  28844. mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
  28845. }
  28846. if (updateOffset) {
  28847. hooks.updateOffset(mom, days || months);
  28848. }
  28849. }
  28850. var add = createAdder(1, 'add');
  28851. var subtract = createAdder(-1, 'subtract');
  28852. function getCalendarFormat(myMoment, now) {
  28853. var diff = myMoment.diff(now, 'days', true);
  28854. return diff < -6 ? 'sameElse' :
  28855. diff < -1 ? 'lastWeek' :
  28856. diff < 0 ? 'lastDay' :
  28857. diff < 1 ? 'sameDay' :
  28858. diff < 2 ? 'nextDay' :
  28859. diff < 7 ? 'nextWeek' : 'sameElse';
  28860. }
  28861. function calendar$1(time, formats) {
  28862. // We want to compare the start of today, vs this.
  28863. // Getting start-of-today depends on whether we're local/utc/offset or not.
  28864. var now = time || createLocal(),
  28865. sod = cloneWithOffset(now, this).startOf('day'),
  28866. format = hooks.calendarFormat(this, sod) || 'sameElse';
  28867. var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
  28868. return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
  28869. }
  28870. function clone() {
  28871. return new Moment(this);
  28872. }
  28873. function isAfter(input, units) {
  28874. var localInput = isMoment(input) ? input : createLocal(input);
  28875. if (!(this.isValid() && localInput.isValid())) {
  28876. return false;
  28877. }
  28878. units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
  28879. if (units === 'millisecond') {
  28880. return this.valueOf() > localInput.valueOf();
  28881. } else {
  28882. return localInput.valueOf() < this.clone().startOf(units).valueOf();
  28883. }
  28884. }
  28885. function isBefore(input, units) {
  28886. var localInput = isMoment(input) ? input : createLocal(input);
  28887. if (!(this.isValid() && localInput.isValid())) {
  28888. return false;
  28889. }
  28890. units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
  28891. if (units === 'millisecond') {
  28892. return this.valueOf() < localInput.valueOf();
  28893. } else {
  28894. return this.clone().endOf(units).valueOf() < localInput.valueOf();
  28895. }
  28896. }
  28897. function isBetween(from, to, units, inclusivity) {
  28898. inclusivity = inclusivity || '()';
  28899. return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
  28900. (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
  28901. }
  28902. function isSame(input, units) {
  28903. var localInput = isMoment(input) ? input : createLocal(input),
  28904. inputMs;
  28905. if (!(this.isValid() && localInput.isValid())) {
  28906. return false;
  28907. }
  28908. units = normalizeUnits(units || 'millisecond');
  28909. if (units === 'millisecond') {
  28910. return this.valueOf() === localInput.valueOf();
  28911. } else {
  28912. inputMs = localInput.valueOf();
  28913. return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
  28914. }
  28915. }
  28916. function isSameOrAfter(input, units) {
  28917. return this.isSame(input, units) || this.isAfter(input, units);
  28918. }
  28919. function isSameOrBefore(input, units) {
  28920. return this.isSame(input, units) || this.isBefore(input, units);
  28921. }
  28922. function diff(input, units, asFloat) {
  28923. var that,
  28924. zoneDelta,
  28925. delta, output;
  28926. if (!this.isValid()) {
  28927. return NaN;
  28928. }
  28929. that = cloneWithOffset(input, this);
  28930. if (!that.isValid()) {
  28931. return NaN;
  28932. }
  28933. zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
  28934. units = normalizeUnits(units);
  28935. switch (units) {
  28936. case 'year':
  28937. output = monthDiff(this, that) / 12;
  28938. break;
  28939. case 'month':
  28940. output = monthDiff(this, that);
  28941. break;
  28942. case 'quarter':
  28943. output = monthDiff(this, that) / 3;
  28944. break;
  28945. case 'second':
  28946. output = (this - that) / 1e3;
  28947. break; // 1000
  28948. case 'minute':
  28949. output = (this - that) / 6e4;
  28950. break; // 1000 * 60
  28951. case 'hour':
  28952. output = (this - that) / 36e5;
  28953. break; // 1000 * 60 * 60
  28954. case 'day':
  28955. output = (this - that - zoneDelta) / 864e5;
  28956. break; // 1000 * 60 * 60 * 24, negate dst
  28957. case 'week':
  28958. output = (this - that - zoneDelta) / 6048e5;
  28959. break; // 1000 * 60 * 60 * 24 * 7, negate dst
  28960. default:
  28961. output = this - that;
  28962. }
  28963. return asFloat ? output : absFloor(output);
  28964. }
  28965. function monthDiff(a, b) {
  28966. // difference in months
  28967. var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
  28968. // b is in (anchor - 1 month, anchor + 1 month)
  28969. anchor = a.clone().add(wholeMonthDiff, 'months'),
  28970. anchor2, adjust;
  28971. if (b - anchor < 0) {
  28972. anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
  28973. // linear across the month
  28974. adjust = (b - anchor) / (anchor - anchor2);
  28975. } else {
  28976. anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
  28977. // linear across the month
  28978. adjust = (b - anchor) / (anchor2 - anchor);
  28979. }
  28980. //check for negative zero, return zero if negative zero
  28981. return -(wholeMonthDiff + adjust) || 0;
  28982. }
  28983. hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
  28984. hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
  28985. function toString() {
  28986. return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
  28987. }
  28988. function toISOString() {
  28989. if (!this.isValid()) {
  28990. return null;
  28991. }
  28992. var m = this.clone().utc();
  28993. if (m.year() < 0 || m.year() > 9999) {
  28994. return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
  28995. }
  28996. if (isFunction(Date.prototype.toISOString)) {
  28997. // native implementation is ~50x faster, use it when we can
  28998. return this.toDate().toISOString();
  28999. }
  29000. return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
  29001. }
  29002. /**
  29003. * Return a human readable representation of a moment that can
  29004. * also be evaluated to get a new moment which is the same
  29005. *
  29006. * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
  29007. */
  29008. function inspect() {
  29009. if (!this.isValid()) {
  29010. return 'moment.invalid(/* ' + this._i + ' */)';
  29011. }
  29012. var func = 'moment';
  29013. var zone = '';
  29014. if (!this.isLocal()) {
  29015. func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
  29016. zone = 'Z';
  29017. }
  29018. var prefix = '[' + func + '("]';
  29019. var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
  29020. var datetime = '-MM-DD[T]HH:mm:ss.SSS';
  29021. var suffix = zone + '[")]';
  29022. return this.format(prefix + year + datetime + suffix);
  29023. }
  29024. function format(inputString) {
  29025. if (!inputString) {
  29026. inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
  29027. }
  29028. var output = formatMoment(this, inputString);
  29029. return this.localeData().postformat(output);
  29030. }
  29031. function from(time, withoutSuffix) {
  29032. if (this.isValid() &&
  29033. ((isMoment(time) && time.isValid()) ||
  29034. createLocal(time).isValid())) {
  29035. return createDuration({ to: this, from: time }).locale(this.locale()).humanize(!withoutSuffix);
  29036. } else {
  29037. return this.localeData().invalidDate();
  29038. }
  29039. }
  29040. function fromNow(withoutSuffix) {
  29041. return this.from(createLocal(), withoutSuffix);
  29042. }
  29043. function to(time, withoutSuffix) {
  29044. if (this.isValid() &&
  29045. ((isMoment(time) && time.isValid()) ||
  29046. createLocal(time).isValid())) {
  29047. return createDuration({ from: this, to: time }).locale(this.locale()).humanize(!withoutSuffix);
  29048. } else {
  29049. return this.localeData().invalidDate();
  29050. }
  29051. }
  29052. function toNow(withoutSuffix) {
  29053. return this.to(createLocal(), withoutSuffix);
  29054. }
  29055. // If passed a locale key, it will set the locale for this
  29056. // instance. Otherwise, it will return the locale configuration
  29057. // variables for this instance.
  29058. function locale(key) {
  29059. var newLocaleData;
  29060. if (key === undefined) {
  29061. return this._locale._abbr;
  29062. } else {
  29063. newLocaleData = getLocale(key);
  29064. if (newLocaleData != null) {
  29065. this._locale = newLocaleData;
  29066. }
  29067. return this;
  29068. }
  29069. }
  29070. var lang = deprecate(
  29071. 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
  29072. function(key) {
  29073. if (key === undefined) {
  29074. return this.localeData();
  29075. } else {
  29076. return this.locale(key);
  29077. }
  29078. }
  29079. );
  29080. function localeData() {
  29081. return this._locale;
  29082. }
  29083. function startOf(units) {
  29084. units = normalizeUnits(units);
  29085. // the following switch intentionally omits break keywords
  29086. // to utilize falling through the cases.
  29087. switch (units) {
  29088. case 'year':
  29089. this.month(0);
  29090. /* falls through */
  29091. case 'quarter':
  29092. case 'month':
  29093. this.date(1);
  29094. /* falls through */
  29095. case 'week':
  29096. case 'isoWeek':
  29097. case 'day':
  29098. case 'date':
  29099. this.hours(0);
  29100. /* falls through */
  29101. case 'hour':
  29102. this.minutes(0);
  29103. /* falls through */
  29104. case 'minute':
  29105. this.seconds(0);
  29106. /* falls through */
  29107. case 'second':
  29108. this.milliseconds(0);
  29109. }
  29110. // weeks are a special case
  29111. if (units === 'week') {
  29112. this.weekday(0);
  29113. }
  29114. if (units === 'isoWeek') {
  29115. this.isoWeekday(1);
  29116. }
  29117. // quarters are also special
  29118. if (units === 'quarter') {
  29119. this.month(Math.floor(this.month() / 3) * 3);
  29120. }
  29121. return this;
  29122. }
  29123. function endOf(units) {
  29124. units = normalizeUnits(units);
  29125. if (units === undefined || units === 'millisecond') {
  29126. return this;
  29127. }
  29128. // 'date' is an alias for 'day', so it should be considered as such.
  29129. if (units === 'date') {
  29130. units = 'day';
  29131. }
  29132. return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
  29133. }
  29134. function valueOf() {
  29135. return this._d.valueOf() - ((this._offset || 0) * 60000);
  29136. }
  29137. function unix() {
  29138. return Math.floor(this.valueOf() / 1000);
  29139. }
  29140. function toDate() {
  29141. return new Date(this.valueOf());
  29142. }
  29143. function toArray() {
  29144. var m = this;
  29145. return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
  29146. }
  29147. function toObject() {
  29148. var m = this;
  29149. return {
  29150. years: m.year(),
  29151. months: m.month(),
  29152. date: m.date(),
  29153. hours: m.hours(),
  29154. minutes: m.minutes(),
  29155. seconds: m.seconds(),
  29156. milliseconds: m.milliseconds()
  29157. };
  29158. }
  29159. function toJSON() {
  29160. // new Date(NaN).toJSON() === null
  29161. return this.isValid() ? this.toISOString() : null;
  29162. }
  29163. function isValid$2() {
  29164. return isValid(this);
  29165. }
  29166. function parsingFlags() {
  29167. return extend({}, getParsingFlags(this));
  29168. }
  29169. function invalidAt() {
  29170. return getParsingFlags(this).overflow;
  29171. }
  29172. function creationData() {
  29173. return {
  29174. input: this._i,
  29175. format: this._f,
  29176. locale: this._locale,
  29177. isUTC: this._isUTC,
  29178. strict: this._strict
  29179. };
  29180. }
  29181. // FORMATTING
  29182. addFormatToken(0, ['gg', 2], 0, function() {
  29183. return this.weekYear() % 100;
  29184. });
  29185. addFormatToken(0, ['GG', 2], 0, function() {
  29186. return this.isoWeekYear() % 100;
  29187. });
  29188. function addWeekYearFormatToken(token, getter) {
  29189. addFormatToken(0, [token, token.length], 0, getter);
  29190. }
  29191. addWeekYearFormatToken('gggg', 'weekYear');
  29192. addWeekYearFormatToken('ggggg', 'weekYear');
  29193. addWeekYearFormatToken('GGGG', 'isoWeekYear');
  29194. addWeekYearFormatToken('GGGGG', 'isoWeekYear');
  29195. // ALIASES
  29196. addUnitAlias('weekYear', 'gg');
  29197. addUnitAlias('isoWeekYear', 'GG');
  29198. // PRIORITY
  29199. addUnitPriority('weekYear', 1);
  29200. addUnitPriority('isoWeekYear', 1);
  29201. // PARSING
  29202. addRegexToken('G', matchSigned);
  29203. addRegexToken('g', matchSigned);
  29204. addRegexToken('GG', match1to2, match2);
  29205. addRegexToken('gg', match1to2, match2);
  29206. addRegexToken('GGGG', match1to4, match4);
  29207. addRegexToken('gggg', match1to4, match4);
  29208. addRegexToken('GGGGG', match1to6, match6);
  29209. addRegexToken('ggggg', match1to6, match6);
  29210. addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function(input, week, config, token) {
  29211. week[token.substr(0, 2)] = toInt(input);
  29212. });
  29213. addWeekParseToken(['gg', 'GG'], function(input, week, config, token) {
  29214. week[token] = hooks.parseTwoDigitYear(input);
  29215. });
  29216. // MOMENTS
  29217. function getSetWeekYear(input) {
  29218. return getSetWeekYearHelper.call(this,
  29219. input,
  29220. this.week(),
  29221. this.weekday(),
  29222. this.localeData()._week.dow,
  29223. this.localeData()._week.doy);
  29224. }
  29225. function getSetISOWeekYear(input) {
  29226. return getSetWeekYearHelper.call(this,
  29227. input, this.isoWeek(), this.isoWeekday(), 1, 4);
  29228. }
  29229. function getISOWeeksInYear() {
  29230. return weeksInYear(this.year(), 1, 4);
  29231. }
  29232. function getWeeksInYear() {
  29233. var weekInfo = this.localeData()._week;
  29234. return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
  29235. }
  29236. function getSetWeekYearHelper(input, week, weekday, dow, doy) {
  29237. var weeksTarget;
  29238. if (input == null) {
  29239. return weekOfYear(this, dow, doy).year;
  29240. } else {
  29241. weeksTarget = weeksInYear(input, dow, doy);
  29242. if (week > weeksTarget) {
  29243. week = weeksTarget;
  29244. }
  29245. return setWeekAll.call(this, input, week, weekday, dow, doy);
  29246. }
  29247. }
  29248. function setWeekAll(weekYear, week, weekday, dow, doy) {
  29249. var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
  29250. date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
  29251. this.year(date.getUTCFullYear());
  29252. this.month(date.getUTCMonth());
  29253. this.date(date.getUTCDate());
  29254. return this;
  29255. }
  29256. // FORMATTING
  29257. addFormatToken('Q', 0, 'Qo', 'quarter');
  29258. // ALIASES
  29259. addUnitAlias('quarter', 'Q');
  29260. // PRIORITY
  29261. addUnitPriority('quarter', 7);
  29262. // PARSING
  29263. addRegexToken('Q', match1);
  29264. addParseToken('Q', function(input, array) {
  29265. array[MONTH] = (toInt(input) - 1) * 3;
  29266. });
  29267. // MOMENTS
  29268. function getSetQuarter(input) {
  29269. return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
  29270. }
  29271. // FORMATTING
  29272. addFormatToken('D', ['DD', 2], 'Do', 'date');
  29273. // ALIASES
  29274. addUnitAlias('date', 'D');
  29275. // PRIOROITY
  29276. addUnitPriority('date', 9);
  29277. // PARSING
  29278. addRegexToken('D', match1to2);
  29279. addRegexToken('DD', match1to2, match2);
  29280. addRegexToken('Do', function(isStrict, locale) {
  29281. // TODO: Remove "ordinalParse" fallback in next major release.
  29282. return isStrict ?
  29283. (locale._dayOfMonthOrdinalParse || locale._ordinalParse) :
  29284. locale._dayOfMonthOrdinalParseLenient;
  29285. });
  29286. addParseToken(['D', 'DD'], DATE);
  29287. addParseToken('Do', function(input, array) {
  29288. array[DATE] = toInt(input.match(match1to2)[0], 10);
  29289. });
  29290. // MOMENTS
  29291. var getSetDayOfMonth = makeGetSet('Date', true);
  29292. // FORMATTING
  29293. addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
  29294. // ALIASES
  29295. addUnitAlias('dayOfYear', 'DDD');
  29296. // PRIORITY
  29297. addUnitPriority('dayOfYear', 4);
  29298. // PARSING
  29299. addRegexToken('DDD', match1to3);
  29300. addRegexToken('DDDD', match3);
  29301. addParseToken(['DDD', 'DDDD'], function(input, array, config) {
  29302. config._dayOfYear = toInt(input);
  29303. });
  29304. // HELPERS
  29305. // MOMENTS
  29306. function getSetDayOfYear(input) {
  29307. var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
  29308. return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
  29309. }
  29310. // FORMATTING
  29311. addFormatToken('m', ['mm', 2], 0, 'minute');
  29312. // ALIASES
  29313. addUnitAlias('minute', 'm');
  29314. // PRIORITY
  29315. addUnitPriority('minute', 14);
  29316. // PARSING
  29317. addRegexToken('m', match1to2);
  29318. addRegexToken('mm', match1to2, match2);
  29319. addParseToken(['m', 'mm'], MINUTE);
  29320. // MOMENTS
  29321. var getSetMinute = makeGetSet('Minutes', false);
  29322. // FORMATTING
  29323. addFormatToken('s', ['ss', 2], 0, 'second');
  29324. // ALIASES
  29325. addUnitAlias('second', 's');
  29326. // PRIORITY
  29327. addUnitPriority('second', 15);
  29328. // PARSING
  29329. addRegexToken('s', match1to2);
  29330. addRegexToken('ss', match1to2, match2);
  29331. addParseToken(['s', 'ss'], SECOND);
  29332. // MOMENTS
  29333. var getSetSecond = makeGetSet('Seconds', false);
  29334. // FORMATTING
  29335. addFormatToken('S', 0, 0, function() {
  29336. return ~~(this.millisecond() / 100);
  29337. });
  29338. addFormatToken(0, ['SS', 2], 0, function() {
  29339. return ~~(this.millisecond() / 10);
  29340. });
  29341. addFormatToken(0, ['SSS', 3], 0, 'millisecond');
  29342. addFormatToken(0, ['SSSS', 4], 0, function() {
  29343. return this.millisecond() * 10;
  29344. });
  29345. addFormatToken(0, ['SSSSS', 5], 0, function() {
  29346. return this.millisecond() * 100;
  29347. });
  29348. addFormatToken(0, ['SSSSSS', 6], 0, function() {
  29349. return this.millisecond() * 1000;
  29350. });
  29351. addFormatToken(0, ['SSSSSSS', 7], 0, function() {
  29352. return this.millisecond() * 10000;
  29353. });
  29354. addFormatToken(0, ['SSSSSSSS', 8], 0, function() {
  29355. return this.millisecond() * 100000;
  29356. });
  29357. addFormatToken(0, ['SSSSSSSSS', 9], 0, function() {
  29358. return this.millisecond() * 1000000;
  29359. });
  29360. // ALIASES
  29361. addUnitAlias('millisecond', 'ms');
  29362. // PRIORITY
  29363. addUnitPriority('millisecond', 16);
  29364. // PARSING
  29365. addRegexToken('S', match1to3, match1);
  29366. addRegexToken('SS', match1to3, match2);
  29367. addRegexToken('SSS', match1to3, match3);
  29368. var token;
  29369. for (token = 'SSSS'; token.length <= 9; token += 'S') {
  29370. addRegexToken(token, matchUnsigned);
  29371. }
  29372. function parseMs(input, array) {
  29373. array[MILLISECOND] = toInt(('0.' + input) * 1000);
  29374. }
  29375. for (token = 'S'; token.length <= 9; token += 'S') {
  29376. addParseToken(token, parseMs);
  29377. }
  29378. // MOMENTS
  29379. var getSetMillisecond = makeGetSet('Milliseconds', false);
  29380. // FORMATTING
  29381. addFormatToken('z', 0, 0, 'zoneAbbr');
  29382. addFormatToken('zz', 0, 0, 'zoneName');
  29383. // MOMENTS
  29384. function getZoneAbbr() {
  29385. return this._isUTC ? 'UTC' : '';
  29386. }
  29387. function getZoneName() {
  29388. return this._isUTC ? 'Coordinated Universal Time' : '';
  29389. }
  29390. var proto = Moment.prototype;
  29391. proto.add = add;
  29392. proto.calendar = calendar$1;
  29393. proto.clone = clone;
  29394. proto.diff = diff;
  29395. proto.endOf = endOf;
  29396. proto.format = format;
  29397. proto.from = from;
  29398. proto.fromNow = fromNow;
  29399. proto.to = to;
  29400. proto.toNow = toNow;
  29401. proto.get = stringGet;
  29402. proto.invalidAt = invalidAt;
  29403. proto.isAfter = isAfter;
  29404. proto.isBefore = isBefore;
  29405. proto.isBetween = isBetween;
  29406. proto.isSame = isSame;
  29407. proto.isSameOrAfter = isSameOrAfter;
  29408. proto.isSameOrBefore = isSameOrBefore;
  29409. proto.isValid = isValid$2;
  29410. proto.lang = lang;
  29411. proto.locale = locale;
  29412. proto.localeData = localeData;
  29413. proto.max = prototypeMax;
  29414. proto.min = prototypeMin;
  29415. proto.parsingFlags = parsingFlags;
  29416. proto.set = stringSet;
  29417. proto.startOf = startOf;
  29418. proto.subtract = subtract;
  29419. proto.toArray = toArray;
  29420. proto.toObject = toObject;
  29421. proto.toDate = toDate;
  29422. proto.toISOString = toISOString;
  29423. proto.inspect = inspect;
  29424. proto.toJSON = toJSON;
  29425. proto.toString = toString;
  29426. proto.unix = unix;
  29427. proto.valueOf = valueOf;
  29428. proto.creationData = creationData;
  29429. // Year
  29430. proto.year = getSetYear;
  29431. proto.isLeapYear = getIsLeapYear;
  29432. // Week Year
  29433. proto.weekYear = getSetWeekYear;
  29434. proto.isoWeekYear = getSetISOWeekYear;
  29435. // Quarter
  29436. proto.quarter = proto.quarters = getSetQuarter;
  29437. // Month
  29438. proto.month = getSetMonth;
  29439. proto.daysInMonth = getDaysInMonth;
  29440. // Week
  29441. proto.week = proto.weeks = getSetWeek;
  29442. proto.isoWeek = proto.isoWeeks = getSetISOWeek;
  29443. proto.weeksInYear = getWeeksInYear;
  29444. proto.isoWeeksInYear = getISOWeeksInYear;
  29445. // Day
  29446. proto.date = getSetDayOfMonth;
  29447. proto.day = proto.days = getSetDayOfWeek;
  29448. proto.weekday = getSetLocaleDayOfWeek;
  29449. proto.isoWeekday = getSetISODayOfWeek;
  29450. proto.dayOfYear = getSetDayOfYear;
  29451. // Hour
  29452. proto.hour = proto.hours = getSetHour;
  29453. // Minute
  29454. proto.minute = proto.minutes = getSetMinute;
  29455. // Second
  29456. proto.second = proto.seconds = getSetSecond;
  29457. // Millisecond
  29458. proto.millisecond = proto.milliseconds = getSetMillisecond;
  29459. // Offset
  29460. proto.utcOffset = getSetOffset;
  29461. proto.utc = setOffsetToUTC;
  29462. proto.local = setOffsetToLocal;
  29463. proto.parseZone = setOffsetToParsedOffset;
  29464. proto.hasAlignedHourOffset = hasAlignedHourOffset;
  29465. proto.isDST = isDaylightSavingTime;
  29466. proto.isLocal = isLocal;
  29467. proto.isUtcOffset = isUtcOffset;
  29468. proto.isUtc = isUtc;
  29469. proto.isUTC = isUtc;
  29470. // Timezone
  29471. proto.zoneAbbr = getZoneAbbr;
  29472. proto.zoneName = getZoneName;
  29473. // Deprecations
  29474. proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
  29475. proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
  29476. proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
  29477. proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
  29478. proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
  29479. function createUnix(input) {
  29480. return createLocal(input * 1000);
  29481. }
  29482. function createInZone() {
  29483. return createLocal.apply(null, arguments).parseZone();
  29484. }
  29485. function preParsePostFormat(string) {
  29486. return string;
  29487. }
  29488. var proto$1 = Locale.prototype;
  29489. proto$1.calendar = calendar;
  29490. proto$1.longDateFormat = longDateFormat;
  29491. proto$1.invalidDate = invalidDate;
  29492. proto$1.ordinal = ordinal;
  29493. proto$1.preparse = preParsePostFormat;
  29494. proto$1.postformat = preParsePostFormat;
  29495. proto$1.relativeTime = relativeTime;
  29496. proto$1.pastFuture = pastFuture;
  29497. proto$1.set = set;
  29498. // Month
  29499. proto$1.months = localeMonths;
  29500. proto$1.monthsShort = localeMonthsShort;
  29501. proto$1.monthsParse = localeMonthsParse;
  29502. proto$1.monthsRegex = monthsRegex;
  29503. proto$1.monthsShortRegex = monthsShortRegex;
  29504. // Week
  29505. proto$1.week = localeWeek;
  29506. proto$1.firstDayOfYear = localeFirstDayOfYear;
  29507. proto$1.firstDayOfWeek = localeFirstDayOfWeek;
  29508. // Day of Week
  29509. proto$1.weekdays = localeWeekdays;
  29510. proto$1.weekdaysMin = localeWeekdaysMin;
  29511. proto$1.weekdaysShort = localeWeekdaysShort;
  29512. proto$1.weekdaysParse = localeWeekdaysParse;
  29513. proto$1.weekdaysRegex = weekdaysRegex;
  29514. proto$1.weekdaysShortRegex = weekdaysShortRegex;
  29515. proto$1.weekdaysMinRegex = weekdaysMinRegex;
  29516. // Hours
  29517. proto$1.isPM = localeIsPM;
  29518. proto$1.meridiem = localeMeridiem;
  29519. function get$1(format, index, field, setter) {
  29520. var locale = getLocale();
  29521. var utc = createUTC().set(setter, index);
  29522. return locale[field](utc, format);
  29523. }
  29524. function listMonthsImpl(format, index, field) {
  29525. if (isNumber(format)) {
  29526. index = format;
  29527. format = undefined;
  29528. }
  29529. format = format || '';
  29530. if (index != null) {
  29531. return get$1(format, index, field, 'month');
  29532. }
  29533. var i;
  29534. var out = [];
  29535. for (i = 0; i < 12; i++) {
  29536. out[i] = get$1(format, i, field, 'month');
  29537. }
  29538. return out;
  29539. }
  29540. // ()
  29541. // (5)
  29542. // (fmt, 5)
  29543. // (fmt)
  29544. // (true)
  29545. // (true, 5)
  29546. // (true, fmt, 5)
  29547. // (true, fmt)
  29548. function listWeekdaysImpl(localeSorted, format, index, field) {
  29549. if (typeof localeSorted === 'boolean') {
  29550. if (isNumber(format)) {
  29551. index = format;
  29552. format = undefined;
  29553. }
  29554. format = format || '';
  29555. } else {
  29556. format = localeSorted;
  29557. index = format;
  29558. localeSorted = false;
  29559. if (isNumber(format)) {
  29560. index = format;
  29561. format = undefined;
  29562. }
  29563. format = format || '';
  29564. }
  29565. var locale = getLocale(),
  29566. shift = localeSorted ? locale._week.dow : 0;
  29567. if (index != null) {
  29568. return get$1(format, (index + shift) % 7, field, 'day');
  29569. }
  29570. var i;
  29571. var out = [];
  29572. for (i = 0; i < 7; i++) {
  29573. out[i] = get$1(format, (i + shift) % 7, field, 'day');
  29574. }
  29575. return out;
  29576. }
  29577. function listMonths(format, index) {
  29578. return listMonthsImpl(format, index, 'months');
  29579. }
  29580. function listMonthsShort(format, index) {
  29581. return listMonthsImpl(format, index, 'monthsShort');
  29582. }
  29583. function listWeekdays(localeSorted, format, index) {
  29584. return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
  29585. }
  29586. function listWeekdaysShort(localeSorted, format, index) {
  29587. return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
  29588. }
  29589. function listWeekdaysMin(localeSorted, format, index) {
  29590. return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
  29591. }
  29592. getSetGlobalLocale('en', {
  29593. dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
  29594. ordinal: function(number) {
  29595. var b = number % 10,
  29596. output = (toInt(number % 100 / 10) === 1) ? 'th' :
  29597. (b === 1) ? 'st' :
  29598. (b === 2) ? 'nd' :
  29599. (b === 3) ? 'rd' : 'th';
  29600. return number + output;
  29601. }
  29602. });
  29603. // Side effect imports
  29604. hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
  29605. hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
  29606. var mathAbs = Math.abs;
  29607. function abs() {
  29608. var data = this._data;
  29609. this._milliseconds = mathAbs(this._milliseconds);
  29610. this._days = mathAbs(this._days);
  29611. this._months = mathAbs(this._months);
  29612. data.milliseconds = mathAbs(data.milliseconds);
  29613. data.seconds = mathAbs(data.seconds);
  29614. data.minutes = mathAbs(data.minutes);
  29615. data.hours = mathAbs(data.hours);
  29616. data.months = mathAbs(data.months);
  29617. data.years = mathAbs(data.years);
  29618. return this;
  29619. }
  29620. function addSubtract$1(duration, input, value, direction) {
  29621. var other = createDuration(input, value);
  29622. duration._milliseconds += direction * other._milliseconds;
  29623. duration._days += direction * other._days;
  29624. duration._months += direction * other._months;
  29625. return duration._bubble();
  29626. }
  29627. // supports only 2.0-style add(1, 's') or add(duration)
  29628. function add$1(input, value) {
  29629. return addSubtract$1(this, input, value, 1);
  29630. }
  29631. // supports only 2.0-style subtract(1, 's') or subtract(duration)
  29632. function subtract$1(input, value) {
  29633. return addSubtract$1(this, input, value, -1);
  29634. }
  29635. function absCeil(number) {
  29636. if (number < 0) {
  29637. return Math.floor(number);
  29638. } else {
  29639. return Math.ceil(number);
  29640. }
  29641. }
  29642. function bubble() {
  29643. var milliseconds = this._milliseconds;
  29644. var days = this._days;
  29645. var months = this._months;
  29646. var data = this._data;
  29647. var seconds, minutes, hours, years, monthsFromDays;
  29648. // if we have a mix of positive and negative values, bubble down first
  29649. // check: https://github.com/moment/moment/issues/2166
  29650. if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
  29651. (milliseconds <= 0 && days <= 0 && months <= 0))) {
  29652. milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
  29653. days = 0;
  29654. months = 0;
  29655. }
  29656. // The following code bubbles up values, see the tests for
  29657. // examples of what that means.
  29658. data.milliseconds = milliseconds % 1000;
  29659. seconds = absFloor(milliseconds / 1000);
  29660. data.seconds = seconds % 60;
  29661. minutes = absFloor(seconds / 60);
  29662. data.minutes = minutes % 60;
  29663. hours = absFloor(minutes / 60);
  29664. data.hours = hours % 24;
  29665. days += absFloor(hours / 24);
  29666. // convert days to months
  29667. monthsFromDays = absFloor(daysToMonths(days));
  29668. months += monthsFromDays;
  29669. days -= absCeil(monthsToDays(monthsFromDays));
  29670. // 12 months -> 1 year
  29671. years = absFloor(months / 12);
  29672. months %= 12;
  29673. data.days = days;
  29674. data.months = months;
  29675. data.years = years;
  29676. return this;
  29677. }
  29678. function daysToMonths(days) {
  29679. // 400 years have 146097 days (taking into account leap year rules)
  29680. // 400 years have 12 months === 4800
  29681. return days * 4800 / 146097;
  29682. }
  29683. function monthsToDays(months) {
  29684. // the reverse of daysToMonths
  29685. return months * 146097 / 4800;
  29686. }
  29687. function as(units) {
  29688. if (!this.isValid()) {
  29689. return NaN;
  29690. }
  29691. var days;
  29692. var months;
  29693. var milliseconds = this._milliseconds;
  29694. units = normalizeUnits(units);
  29695. if (units === 'month' || units === 'year') {
  29696. days = this._days + milliseconds / 864e5;
  29697. months = this._months + daysToMonths(days);
  29698. return units === 'month' ? months : months / 12;
  29699. } else {
  29700. // handle milliseconds separately because of floating point math errors (issue #1867)
  29701. days = this._days + Math.round(monthsToDays(this._months));
  29702. switch (units) {
  29703. case 'week':
  29704. return days / 7 + milliseconds / 6048e5;
  29705. case 'day':
  29706. return days + milliseconds / 864e5;
  29707. case 'hour':
  29708. return days * 24 + milliseconds / 36e5;
  29709. case 'minute':
  29710. return days * 1440 + milliseconds / 6e4;
  29711. case 'second':
  29712. return days * 86400 + milliseconds / 1000;
  29713. // Math.floor prevents floating point math errors here
  29714. case 'millisecond':
  29715. return Math.floor(days * 864e5) + milliseconds;
  29716. default:
  29717. throw new Error('Unknown unit ' + units);
  29718. }
  29719. }
  29720. }
  29721. // TODO: Use this.as('ms')?
  29722. function valueOf$1() {
  29723. if (!this.isValid()) {
  29724. return NaN;
  29725. }
  29726. return (
  29727. this._milliseconds +
  29728. this._days * 864e5 +
  29729. (this._months % 12) * 2592e6 +
  29730. toInt(this._months / 12) * 31536e6
  29731. );
  29732. }
  29733. function makeAs(alias) {
  29734. return function() {
  29735. return this.as(alias);
  29736. };
  29737. }
  29738. var asMilliseconds = makeAs('ms');
  29739. var asSeconds = makeAs('s');
  29740. var asMinutes = makeAs('m');
  29741. var asHours = makeAs('h');
  29742. var asDays = makeAs('d');
  29743. var asWeeks = makeAs('w');
  29744. var asMonths = makeAs('M');
  29745. var asYears = makeAs('y');
  29746. function clone$1() {
  29747. return createDuration(this);
  29748. }
  29749. function get$2(units) {
  29750. units = normalizeUnits(units);
  29751. return this.isValid() ? this[units + 's']() : NaN;
  29752. }
  29753. function makeGetter(name) {
  29754. return function() {
  29755. return this.isValid() ? this._data[name] : NaN;
  29756. };
  29757. }
  29758. var milliseconds = makeGetter('milliseconds');
  29759. var seconds = makeGetter('seconds');
  29760. var minutes = makeGetter('minutes');
  29761. var hours = makeGetter('hours');
  29762. var days = makeGetter('days');
  29763. var months = makeGetter('months');
  29764. var years = makeGetter('years');
  29765. function weeks() {
  29766. return absFloor(this.days() / 7);
  29767. }
  29768. var round = Math.round;
  29769. var thresholds = {
  29770. ss: 44, // a few seconds to seconds
  29771. s: 45, // seconds to minute
  29772. m: 45, // minutes to hour
  29773. h: 22, // hours to day
  29774. d: 26, // days to month
  29775. M: 11 // months to year
  29776. };
  29777. // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
  29778. function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
  29779. return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
  29780. }
  29781. function relativeTime$1(posNegDuration, withoutSuffix, locale) {
  29782. var duration = createDuration(posNegDuration).abs();
  29783. var seconds = round(duration.as('s'));
  29784. var minutes = round(duration.as('m'));
  29785. var hours = round(duration.as('h'));
  29786. var days = round(duration.as('d'));
  29787. var months = round(duration.as('M'));
  29788. var years = round(duration.as('y'));
  29789. var a = seconds <= thresholds.ss && ['s', seconds] ||
  29790. seconds < thresholds.s && ['ss', seconds] ||
  29791. minutes <= 1 && ['m'] ||
  29792. minutes < thresholds.m && ['mm', minutes] ||
  29793. hours <= 1 && ['h'] ||
  29794. hours < thresholds.h && ['hh', hours] ||
  29795. days <= 1 && ['d'] ||
  29796. days < thresholds.d && ['dd', days] ||
  29797. months <= 1 && ['M'] ||
  29798. months < thresholds.M && ['MM', months] ||
  29799. years <= 1 && ['y'] || ['yy', years];
  29800. a[2] = withoutSuffix;
  29801. a[3] = +posNegDuration > 0;
  29802. a[4] = locale;
  29803. return substituteTimeAgo.apply(null, a);
  29804. }
  29805. // This function allows you to set the rounding function for relative time strings
  29806. function getSetRelativeTimeRounding(roundingFunction) {
  29807. if (roundingFunction === undefined) {
  29808. return round;
  29809. }
  29810. if (typeof(roundingFunction) === 'function') {
  29811. round = roundingFunction;
  29812. return true;
  29813. }
  29814. return false;
  29815. }
  29816. // This function allows you to set a threshold for relative time strings
  29817. function getSetRelativeTimeThreshold(threshold, limit) {
  29818. if (thresholds[threshold] === undefined) {
  29819. return false;
  29820. }
  29821. if (limit === undefined) {
  29822. return thresholds[threshold];
  29823. }
  29824. thresholds[threshold] = limit;
  29825. if (threshold === 's') {
  29826. thresholds.ss = limit - 1;
  29827. }
  29828. return true;
  29829. }
  29830. function humanize(withSuffix) {
  29831. if (!this.isValid()) {
  29832. return this.localeData().invalidDate();
  29833. }
  29834. var locale = this.localeData();
  29835. var output = relativeTime$1(this, !withSuffix, locale);
  29836. if (withSuffix) {
  29837. output = locale.pastFuture(+this, output);
  29838. }
  29839. return locale.postformat(output);
  29840. }
  29841. var abs$1 = Math.abs;
  29842. function sign(x) {
  29843. return ((x > 0) - (x < 0)) || +x;
  29844. }
  29845. function toISOString$1() {
  29846. // for ISO strings we do not use the normal bubbling rules:
  29847. // * milliseconds bubble up until they become hours
  29848. // * days do not bubble at all
  29849. // * months bubble up until they become years
  29850. // This is because there is no context-free conversion between hours and days
  29851. // (think of clock changes)
  29852. // and also not between days and months (28-31 days per month)
  29853. if (!this.isValid()) {
  29854. return this.localeData().invalidDate();
  29855. }
  29856. var seconds = abs$1(this._milliseconds) / 1000;
  29857. var days = abs$1(this._days);
  29858. var months = abs$1(this._months);
  29859. var minutes, hours, years;
  29860. // 3600 seconds -> 60 minutes -> 1 hour
  29861. minutes = absFloor(seconds / 60);
  29862. hours = absFloor(minutes / 60);
  29863. seconds %= 60;
  29864. minutes %= 60;
  29865. // 12 months -> 1 year
  29866. years = absFloor(months / 12);
  29867. months %= 12;
  29868. // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
  29869. var Y = years;
  29870. var M = months;
  29871. var D = days;
  29872. var h = hours;
  29873. var m = minutes;
  29874. var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
  29875. var total = this.asSeconds();
  29876. if (!total) {
  29877. // this is the same as C#'s (Noda) and python (isodate)...
  29878. // but not other JS (goog.date)
  29879. return 'P0D';
  29880. }
  29881. var totalSign = total < 0 ? '-' : '';
  29882. var ymSign = sign(this._months) !== sign(total) ? '-' : '';
  29883. var daysSign = sign(this._days) !== sign(total) ? '-' : '';
  29884. var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
  29885. return totalSign + 'P' +
  29886. (Y ? ymSign + Y + 'Y' : '') +
  29887. (M ? ymSign + M + 'M' : '') +
  29888. (D ? daysSign + D + 'D' : '') +
  29889. ((h || m || s) ? 'T' : '') +
  29890. (h ? hmsSign + h + 'H' : '') +
  29891. (m ? hmsSign + m + 'M' : '') +
  29892. (s ? hmsSign + s + 'S' : '');
  29893. }
  29894. var proto$2 = Duration.prototype;
  29895. proto$2.isValid = isValid$1;
  29896. proto$2.abs = abs;
  29897. proto$2.add = add$1;
  29898. proto$2.subtract = subtract$1;
  29899. proto$2.as = as;
  29900. proto$2.asMilliseconds = asMilliseconds;
  29901. proto$2.asSeconds = asSeconds;
  29902. proto$2.asMinutes = asMinutes;
  29903. proto$2.asHours = asHours;
  29904. proto$2.asDays = asDays;
  29905. proto$2.asWeeks = asWeeks;
  29906. proto$2.asMonths = asMonths;
  29907. proto$2.asYears = asYears;
  29908. proto$2.valueOf = valueOf$1;
  29909. proto$2._bubble = bubble;
  29910. proto$2.clone = clone$1;
  29911. proto$2.get = get$2;
  29912. proto$2.milliseconds = milliseconds;
  29913. proto$2.seconds = seconds;
  29914. proto$2.minutes = minutes;
  29915. proto$2.hours = hours;
  29916. proto$2.days = days;
  29917. proto$2.weeks = weeks;
  29918. proto$2.months = months;
  29919. proto$2.years = years;
  29920. proto$2.humanize = humanize;
  29921. proto$2.toISOString = toISOString$1;
  29922. proto$2.toString = toISOString$1;
  29923. proto$2.toJSON = toISOString$1;
  29924. proto$2.locale = locale;
  29925. proto$2.localeData = localeData;
  29926. // Deprecations
  29927. proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
  29928. proto$2.lang = lang;
  29929. // Side effect imports
  29930. // FORMATTING
  29931. addFormatToken('X', 0, 0, 'unix');
  29932. addFormatToken('x', 0, 0, 'valueOf');
  29933. // PARSING
  29934. addRegexToken('x', matchSigned);
  29935. addRegexToken('X', matchTimestamp);
  29936. addParseToken('X', function(input, array, config) {
  29937. config._d = new Date(parseFloat(input, 10) * 1000);
  29938. });
  29939. addParseToken('x', function(input, array, config) {
  29940. config._d = new Date(toInt(input));
  29941. });
  29942. // Side effect imports
  29943. hooks.version = '2.19.1';
  29944. setHookCallback(createLocal);
  29945. hooks.fn = proto;
  29946. hooks.min = min;
  29947. hooks.max = max;
  29948. hooks.now = now;
  29949. hooks.utc = createUTC;
  29950. hooks.unix = createUnix;
  29951. hooks.months = listMonths;
  29952. hooks.isDate = isDate;
  29953. hooks.locale = getSetGlobalLocale;
  29954. hooks.invalid = createInvalid;
  29955. hooks.duration = createDuration;
  29956. hooks.isMoment = isMoment;
  29957. hooks.weekdays = listWeekdays;
  29958. hooks.parseZone = createInZone;
  29959. hooks.localeData = getLocale;
  29960. hooks.isDuration = isDuration;
  29961. hooks.monthsShort = listMonthsShort;
  29962. hooks.weekdaysMin = listWeekdaysMin;
  29963. hooks.defineLocale = defineLocale;
  29964. hooks.updateLocale = updateLocale;
  29965. hooks.locales = listLocales;
  29966. hooks.weekdaysShort = listWeekdaysShort;
  29967. hooks.normalizeUnits = normalizeUnits;
  29968. hooks.relativeTimeRounding = getSetRelativeTimeRounding;
  29969. hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
  29970. hooks.calendarFormat = getCalendarFormat;
  29971. hooks.prototype = proto;
  29972. return hooks;
  29973. })));
  29974. /* WEBPACK VAR INJECTION */
  29975. }.call(exports, __webpack_require__(155)(module)))
  29976. /***/
  29977. }),
  29978. /* 155 */
  29979. /***/
  29980. (function(module, exports) {
  29981. module.exports = function(module) {
  29982. if (!module.webpackPolyfill) {
  29983. module.deprecate = function() {};
  29984. module.paths = [];
  29985. // module.parent = undefined by default
  29986. if (!module.children) module.children = [];
  29987. Object.defineProperty(module, "loaded", {
  29988. enumerable: true,
  29989. get: function() {
  29990. return module.l;
  29991. }
  29992. });
  29993. Object.defineProperty(module, "id", {
  29994. enumerable: true,
  29995. get: function() {
  29996. return module.i;
  29997. }
  29998. });
  29999. module.webpackPolyfill = 1;
  30000. }
  30001. return module;
  30002. };
  30003. /***/
  30004. }),
  30005. /* 156 */
  30006. /***/
  30007. (function(module, exports) {
  30008. function webpackEmptyContext(req) {
  30009. throw new Error("Cannot find module '" + req + "'.");
  30010. }
  30011. webpackEmptyContext.keys = function() { return []; };
  30012. webpackEmptyContext.resolve = webpackEmptyContext;
  30013. module.exports = webpackEmptyContext;
  30014. webpackEmptyContext.id = 156;
  30015. /***/
  30016. }),
  30017. /* 157 */
  30018. /***/
  30019. (function(module, exports, __webpack_require__) {
  30020. "use strict";
  30021. /* WEBPACK VAR INJECTION */
  30022. (function(global) {
  30023. /* eslint-disable require-jsdoc */
  30024. var _rng;
  30025. var globalVar = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : null;
  30026. if (globalVar && globalVar.crypto && crypto.getRandomValues) {
  30027. // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
  30028. // Moderately fast, high quality
  30029. var _rnds8 = new Uint8Array(16);
  30030. _rng = function whatwgRNG() {
  30031. crypto.getRandomValues(_rnds8);
  30032. return _rnds8;
  30033. };
  30034. }
  30035. if (!_rng) {
  30036. // Math.random()-based (RNG)
  30037. //
  30038. // If all else fails, use Math.random(). It's fast, but is of unspecified
  30039. // quality.
  30040. var _rnds = new Array(16);
  30041. _rng = function _rng() {
  30042. for (var i = 0, r; i < 16; i++) {
  30043. if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
  30044. _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
  30045. }
  30046. return _rnds;
  30047. };
  30048. }
  30049. // uuid.js
  30050. //
  30051. // Copyright (c) 2010-2012 Robert Kieffer
  30052. // MIT License - http://opensource.org/licenses/mit-license.php
  30053. // Unique ID creation requires a high quality random # generator. We feature
  30054. // detect to determine the best RNG source, normalizing to a function that
  30055. // returns 128-bits of randomness, since that's what's usually required
  30056. //var _rng = require('./rng');
  30057. // Maps for number <-> hex string conversion
  30058. var _byteToHex = [];
  30059. var _hexToByte = {};
  30060. for (var i = 0; i < 256; i++) {
  30061. _byteToHex[i] = (i + 0x100).toString(16).substr(1);
  30062. _hexToByte[_byteToHex[i]] = i;
  30063. }
  30064. // **`parse()` - Parse a UUID into it's component bytes**
  30065. function parse(s, buf, offset) {
  30066. var i = buf && offset || 0,
  30067. ii = 0;
  30068. buf = buf || [];
  30069. s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
  30070. if (ii < 16) {
  30071. // Don't overflow!
  30072. buf[i + ii++] = _hexToByte[oct];
  30073. }
  30074. });
  30075. // Zero out remaining bytes if string was short
  30076. while (ii < 16) {
  30077. buf[i + ii++] = 0;
  30078. }
  30079. return buf;
  30080. }
  30081. // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
  30082. function unparse(buf, offset) {
  30083. var i = offset || 0,
  30084. bth = _byteToHex;
  30085. return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]];
  30086. }
  30087. // **`v1()` - Generate time-based UUID**
  30088. //
  30089. // Inspired by https://github.com/LiosK/UUID.js
  30090. // and http://docs.python.org/library/uuid.html
  30091. // random #'s we need to init node and clockseq
  30092. var _seedBytes = _rng();
  30093. // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
  30094. var _nodeId = [_seedBytes[0] | 0x01, _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]];
  30095. // Per 4.2.2, randomize (14 bit) clockseq
  30096. var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
  30097. // Previous uuid creation time
  30098. var _lastMSecs = 0,
  30099. _lastNSecs = 0;
  30100. // See https://github.com/broofa/node-uuid for API details
  30101. function v1(options, buf, offset) {
  30102. var i = buf && offset || 0;
  30103. var b = buf || [];
  30104. options = options || {};
  30105. var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq;
  30106. // UUID timestamps are 100 nano-second units since the Gregorian epoch,
  30107. // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
  30108. // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
  30109. // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
  30110. var msecs = options.msecs !== undefined ? options.msecs : new Date().getTime();
  30111. // Per 4.2.1.2, use count of uuid's generated during the current clock
  30112. // cycle to simulate higher resolution clock
  30113. var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1;
  30114. // Time since last uuid creation (in msecs)
  30115. var dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000;
  30116. // Per 4.2.1.2, Bump clockseq on clock regression
  30117. if (dt < 0 && options.clockseq === undefined) {
  30118. clockseq = clockseq + 1 & 0x3fff;
  30119. }
  30120. // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
  30121. // time interval
  30122. if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
  30123. nsecs = 0;
  30124. }
  30125. // Per 4.2.1.2 Throw error if too many uuids are requested
  30126. if (nsecs >= 10000) {
  30127. throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
  30128. }
  30129. _lastMSecs = msecs;
  30130. _lastNSecs = nsecs;
  30131. _clockseq = clockseq;
  30132. // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
  30133. msecs += 12219292800000;
  30134. // `time_low`
  30135. var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
  30136. b[i++] = tl >>> 24 & 0xff;
  30137. b[i++] = tl >>> 16 & 0xff;
  30138. b[i++] = tl >>> 8 & 0xff;
  30139. b[i++] = tl & 0xff;
  30140. // `time_mid`
  30141. var tmh = msecs / 0x100000000 * 10000 & 0xfffffff;
  30142. b[i++] = tmh >>> 8 & 0xff;
  30143. b[i++] = tmh & 0xff;
  30144. // `time_high_and_version`
  30145. b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
  30146. b[i++] = tmh >>> 16 & 0xff;
  30147. // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
  30148. b[i++] = clockseq >>> 8 | 0x80;
  30149. // `clock_seq_low`
  30150. b[i++] = clockseq & 0xff;
  30151. // `node`
  30152. var node = options.node || _nodeId;
  30153. for (var n = 0; n < 6; n++) {
  30154. b[i + n] = node[n];
  30155. }
  30156. return buf ? buf : unparse(b);
  30157. }
  30158. // **`v4()` - Generate random UUID**
  30159. // See https://github.com/broofa/node-uuid for API details
  30160. function v4(options, buf, offset) {
  30161. // Deprecated - 'format' argument, as supported in v1.2
  30162. var i = buf && offset || 0;
  30163. if (typeof options == 'string') {
  30164. buf = options == 'binary' ? new Array(16) : null;
  30165. options = null;
  30166. }
  30167. options = options || {};
  30168. var rnds = options.random || (options.rng || _rng)();
  30169. // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
  30170. rnds[6] = rnds[6] & 0x0f | 0x40;
  30171. rnds[8] = rnds[8] & 0x3f | 0x80;
  30172. // Copy bytes to buffer, if provided
  30173. if (buf) {
  30174. for (var ii = 0; ii < 16; ii++) {
  30175. buf[i + ii] = rnds[ii];
  30176. }
  30177. }
  30178. return buf || unparse(rnds);
  30179. }
  30180. // Export public API
  30181. var uuid = v4;
  30182. uuid.v1 = v1;
  30183. uuid.v4 = v4;
  30184. uuid.parse = parse;
  30185. uuid.unparse = unparse;
  30186. module.exports = uuid;
  30187. /* WEBPACK VAR INJECTION */
  30188. }.call(exports, __webpack_require__(158)))
  30189. /***/
  30190. }),
  30191. /* 158 */
  30192. /***/
  30193. (function(module, exports) {
  30194. var g;
  30195. // This works in non-strict mode
  30196. g = (function() {
  30197. return this;
  30198. })();
  30199. try {
  30200. // This works if eval is allowed (see CSP)
  30201. g = g || Function("return this")() || (1, eval)("this");
  30202. } catch (e) {
  30203. // This works if the window reference is available
  30204. if (typeof window === "object")
  30205. g = window;
  30206. }
  30207. // g can still be undefined, but nothing to do about it...
  30208. // We return undefined, instead of nothing here, so it's
  30209. // easier to handle this case. if(!global) { ...}
  30210. module.exports = g;
  30211. /***/
  30212. }),
  30213. /* 159 */
  30214. /***/
  30215. (function(module, exports, __webpack_require__) {
  30216. "use strict";
  30217. // utils
  30218. exports.util = __webpack_require__(2);
  30219. exports.DOMutil = __webpack_require__(14);
  30220. // data
  30221. exports.DataSet = __webpack_require__(11);
  30222. exports.DataView = __webpack_require__(12);
  30223. exports.Queue = __webpack_require__(43);
  30224. // Graph3d
  30225. exports.Graph3d = __webpack_require__(161);
  30226. exports.graph3d = {
  30227. Camera: __webpack_require__(95),
  30228. Filter: __webpack_require__(96),
  30229. Point2d: __webpack_require__(91),
  30230. Point3d: __webpack_require__(34),
  30231. Slider: __webpack_require__(92),
  30232. StepNumber: __webpack_require__(93)
  30233. };
  30234. // bundled external libraries
  30235. exports.moment = __webpack_require__(9);
  30236. exports.Hammer = __webpack_require__(10);
  30237. exports.keycharm = __webpack_require__(35);
  30238. /***/
  30239. }),
  30240. /* 160 */
  30241. /***/
  30242. (function(module, exports, __webpack_require__) {
  30243. var core = __webpack_require__(7);
  30244. var $JSON = core.JSON || (core.JSON = { stringify: JSON.stringify });
  30245. module.exports = function stringify(it) { // eslint-disable-line no-unused-vars
  30246. return $JSON.stringify.apply($JSON, arguments);
  30247. };
  30248. /***/
  30249. }),
  30250. /* 161 */
  30251. /***/
  30252. (function(module, exports, __webpack_require__) {
  30253. "use strict";
  30254. var _assign = __webpack_require__(90);
  30255. var _assign2 = _interopRequireDefault(_assign);
  30256. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  30257. var Emitter = __webpack_require__(44);
  30258. var util = __webpack_require__(2);
  30259. var Point3d = __webpack_require__(34);
  30260. var Point2d = __webpack_require__(91);
  30261. var Slider = __webpack_require__(92);
  30262. var StepNumber = __webpack_require__(93);
  30263. var Settings = __webpack_require__(94);
  30264. var Validator = __webpack_require__(15)['default'];
  30265. var _require = __webpack_require__(15),
  30266. printStyle = _require.printStyle;
  30267. var _require2 = __webpack_require__(172),
  30268. allOptions = _require2.allOptions;
  30269. var DataGroup = __webpack_require__(173);
  30270. /// enumerate the available styles
  30271. Graph3d.STYLE = Settings.STYLE;
  30272. /**
  30273. * Following label is used in the settings to describe values which should be
  30274. * determined by the code while running, from the current data and graph style.
  30275. *
  30276. * Using 'undefined' directly achieves the same thing, but this is more
  30277. * descriptive by describing the intent.
  30278. */
  30279. var autoByDefault = undefined;
  30280. /**
  30281. * Default values for option settings.
  30282. *
  30283. * These are the values used when a Graph3d instance is initialized without
  30284. * custom settings.
  30285. *
  30286. * If a field is not in this list, a default value of 'autoByDefault' is assumed,
  30287. * which is just an alias for 'undefined'.
  30288. */
  30289. Graph3d.DEFAULTS = {
  30290. width: '400px',
  30291. height: '400px',
  30292. filterLabel: 'time',
  30293. legendLabel: 'value',
  30294. xLabel: 'x',
  30295. yLabel: 'y',
  30296. zLabel: 'z',
  30297. xValueLabel: function xValueLabel(v) {
  30298. return v;
  30299. },
  30300. yValueLabel: function yValueLabel(v) {
  30301. return v;
  30302. },
  30303. zValueLabel: function zValueLabel(v) {
  30304. return v;
  30305. },
  30306. showXAxis: true,
  30307. showYAxis: true,
  30308. showZAxis: true,
  30309. showGrid: true,
  30310. showPerspective: true,
  30311. showShadow: false,
  30312. keepAspectRatio: true,
  30313. verticalRatio: 0.5, // 0.1 to 1.0, where 1.0 results in a 'cube'
  30314. dotSizeRatio: 0.02, // size of the dots as a fraction of the graph width
  30315. dotSizeMinFraction: 0.5, // size of min-value dot as a fraction of dotSizeRatio
  30316. dotSizeMaxFraction: 2.5, // size of max-value dot as a fraction of dotSizeRatio
  30317. showAnimationControls: autoByDefault,
  30318. animationInterval: 1000, // milliseconds
  30319. animationPreload: false,
  30320. animationAutoStart: autoByDefault,
  30321. axisColor: '#4D4D4D',
  30322. gridColor: '#D3D3D3',
  30323. xCenter: '55%',
  30324. yCenter: '50%',
  30325. style: Graph3d.STYLE.DOT,
  30326. tooltip: false,
  30327. tooltipStyle: {
  30328. content: {
  30329. padding: '10px',
  30330. border: '1px solid #4d4d4d',
  30331. color: '#1a1a1a',
  30332. background: 'rgba(255,255,255,0.7)',
  30333. borderRadius: '2px',
  30334. boxShadow: '5px 5px 10px rgba(128,128,128,0.5)'
  30335. },
  30336. line: {
  30337. height: '40px',
  30338. width: '0',
  30339. borderLeft: '1px solid #4d4d4d'
  30340. },
  30341. dot: {
  30342. height: '0',
  30343. width: '0',
  30344. border: '5px solid #4d4d4d',
  30345. borderRadius: '5px'
  30346. }
  30347. },
  30348. dataColor: {
  30349. fill: '#7DC1FF',
  30350. stroke: '#3267D2',
  30351. strokeWidth: 1 // px
  30352. },
  30353. cameraPosition: {
  30354. horizontal: 1.0,
  30355. vertical: 0.5,
  30356. distance: 1.7
  30357. },
  30358. /*
  30359. The following fields are 'auto by default', see above.
  30360. */
  30361. showLegend: autoByDefault, // determined by graph style
  30362. backgroundColor: autoByDefault,
  30363. xBarWidth: autoByDefault,
  30364. yBarWidth: autoByDefault,
  30365. valueMin: autoByDefault,
  30366. valueMax: autoByDefault,
  30367. xMin: autoByDefault,
  30368. xMax: autoByDefault,
  30369. xStep: autoByDefault,
  30370. yMin: autoByDefault,
  30371. yMax: autoByDefault,
  30372. yStep: autoByDefault,
  30373. zMin: autoByDefault,
  30374. zMax: autoByDefault,
  30375. zStep: autoByDefault
  30376. };
  30377. // -----------------------------------------------------------------------------
  30378. // Class Graph3d
  30379. // -----------------------------------------------------------------------------
  30380. /**
  30381. * Graph3d displays data in 3d.
  30382. *
  30383. * Graph3d is developed in javascript as a Google Visualization Chart.
  30384. *
  30385. * @constructor Graph3d
  30386. * @param {Element} container The DOM element in which the Graph3d will
  30387. * be created. Normally a div element.
  30388. * @param {DataSet | DataView | Array} [data]
  30389. * @param {Object} [options]
  30390. */
  30391. function Graph3d(container, data, options) {
  30392. if (!(this instanceof Graph3d)) {
  30393. throw new SyntaxError('Constructor must be called with the new operator');
  30394. }
  30395. // create variables and set default values
  30396. this.containerElement = container;
  30397. this.dataGroup = new DataGroup();
  30398. this.dataPoints = null; // The table with point objects
  30399. // create a frame and canvas
  30400. this.create();
  30401. Settings.setDefaults(Graph3d.DEFAULTS, this);
  30402. // the column indexes
  30403. this.colX = undefined;
  30404. this.colY = undefined;
  30405. this.colZ = undefined;
  30406. this.colValue = undefined;
  30407. // TODO: customize axis range
  30408. // apply options (also when undefined)
  30409. this.setOptions(options);
  30410. // apply data
  30411. this.setData(data);
  30412. }
  30413. // Extend Graph3d with an Emitter mixin
  30414. Emitter(Graph3d.prototype);
  30415. /**
  30416. * Calculate the scaling values, dependent on the range in x, y, and z direction
  30417. */
  30418. Graph3d.prototype._setScale = function() {
  30419. this.scale = new Point3d(1 / this.xRange.range(), 1 / this.yRange.range(), 1 / this.zRange.range());
  30420. // keep aspect ration between x and y scale if desired
  30421. if (this.keepAspectRatio) {
  30422. if (this.scale.x < this.scale.y) {
  30423. //noinspection JSSuspiciousNameCombination
  30424. this.scale.y = this.scale.x;
  30425. } else {
  30426. //noinspection JSSuspiciousNameCombination
  30427. this.scale.x = this.scale.y;
  30428. }
  30429. }
  30430. // scale the vertical axis
  30431. this.scale.z *= this.verticalRatio;
  30432. // TODO: can this be automated? verticalRatio?
  30433. // determine scale for (optional) value
  30434. if (this.valueRange !== undefined) {
  30435. this.scale.value = 1 / this.valueRange.range();
  30436. }
  30437. // position the camera arm
  30438. var xCenter = this.xRange.center() * this.scale.x;
  30439. var yCenter = this.yRange.center() * this.scale.y;
  30440. var zCenter = this.zRange.center() * this.scale.z;
  30441. this.camera.setArmLocation(xCenter, yCenter, zCenter);
  30442. };
  30443. /**
  30444. * Convert a 3D location to a 2D location on screen
  30445. * Source: ttp://en.wikipedia.org/wiki/3D_projection
  30446. *
  30447. * @param {Point3d} point3d A 3D point with parameters x, y, z
  30448. * @returns {Point2d} point2d A 2D point with parameters x, y
  30449. */
  30450. Graph3d.prototype._convert3Dto2D = function(point3d) {
  30451. var translation = this._convertPointToTranslation(point3d);
  30452. return this._convertTranslationToScreen(translation);
  30453. };
  30454. /**
  30455. * Convert a 3D location its translation seen from the camera
  30456. * Source: http://en.wikipedia.org/wiki/3D_projection
  30457. *
  30458. * @param {Point3d} point3d A 3D point with parameters x, y, z
  30459. * @returns {Point3d} translation A 3D point with parameters x, y, z This is
  30460. * the translation of the point, seen from the
  30461. * camera.
  30462. */
  30463. Graph3d.prototype._convertPointToTranslation = function(point3d) {
  30464. var cameraLocation = this.camera.getCameraLocation(),
  30465. cameraRotation = this.camera.getCameraRotation(),
  30466. ax = point3d.x * this.scale.x,
  30467. ay = point3d.y * this.scale.y,
  30468. az = point3d.z * this.scale.z,
  30469. cx = cameraLocation.x,
  30470. cy = cameraLocation.y,
  30471. cz = cameraLocation.z,
  30472. // calculate angles
  30473. sinTx = Math.sin(cameraRotation.x),
  30474. cosTx = Math.cos(cameraRotation.x),
  30475. sinTy = Math.sin(cameraRotation.y),
  30476. cosTy = Math.cos(cameraRotation.y),
  30477. sinTz = Math.sin(cameraRotation.z),
  30478. cosTz = Math.cos(cameraRotation.z),
  30479. // calculate translation
  30480. dx = cosTy * (sinTz * (ay - cy) + cosTz * (ax - cx)) - sinTy * (az - cz),
  30481. dy = sinTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) + cosTx * (cosTz * (ay - cy) - sinTz * (ax - cx)),
  30482. dz = cosTx * (cosTy * (az - cz) + sinTy * (sinTz * (ay - cy) + cosTz * (ax - cx))) - sinTx * (cosTz * (ay - cy) - sinTz * (ax - cx));
  30483. return new Point3d(dx, dy, dz);
  30484. };
  30485. /**
  30486. * Convert a translation point to a point on the screen
  30487. *
  30488. * @param {Point3d} translation A 3D point with parameters x, y, z This is
  30489. * the translation of the point, seen from the
  30490. * camera.
  30491. * @returns {Point2d} point2d A 2D point with parameters x, y
  30492. */
  30493. Graph3d.prototype._convertTranslationToScreen = function(translation) {
  30494. var ex = this.eye.x,
  30495. ey = this.eye.y,
  30496. ez = this.eye.z,
  30497. dx = translation.x,
  30498. dy = translation.y,
  30499. dz = translation.z;
  30500. // calculate position on screen from translation
  30501. var bx;
  30502. var by;
  30503. if (this.showPerspective) {
  30504. bx = (dx - ex) * (ez / dz);
  30505. by = (dy - ey) * (ez / dz);
  30506. } else {
  30507. bx = dx * -(ez / this.camera.getArmLength());
  30508. by = dy * -(ez / this.camera.getArmLength());
  30509. }
  30510. // shift and scale the point to the center of the screen
  30511. // use the width of the graph to scale both horizontally and vertically.
  30512. return new Point2d(this.currentXCenter + bx * this.frame.canvas.clientWidth, this.currentYCenter - by * this.frame.canvas.clientWidth);
  30513. };
  30514. /**
  30515. * Calculate the translations and screen positions of all points
  30516. *
  30517. * @param {Array.<Point3d>} points
  30518. * @private
  30519. */
  30520. Graph3d.prototype._calcTranslations = function(points) {
  30521. for (var i = 0; i < points.length; i++) {
  30522. var point = points[i];
  30523. point.trans = this._convertPointToTranslation(point.point);
  30524. point.screen = this._convertTranslationToScreen(point.trans);
  30525. // calculate the translation of the point at the bottom (needed for sorting)
  30526. var transBottom = this._convertPointToTranslation(point.bottom);
  30527. point.dist = this.showPerspective ? transBottom.length() : -transBottom.z;
  30528. }
  30529. // sort the points on depth of their (x,y) position (not on z)
  30530. var sortDepth = function sortDepth(a, b) {
  30531. return b.dist - a.dist;
  30532. };
  30533. points.sort(sortDepth);
  30534. };
  30535. /**
  30536. * Transfer min/max values to the Graph3d instance.
  30537. */
  30538. Graph3d.prototype._initializeRanges = function() {
  30539. // TODO: later on, all min/maxes of all datagroups will be combined here
  30540. var dg = this.dataGroup;
  30541. this.xRange = dg.xRange;
  30542. this.yRange = dg.yRange;
  30543. this.zRange = dg.zRange;
  30544. this.valueRange = dg.valueRange;
  30545. // Values currently needed but which need to be sorted out for
  30546. // the multiple graph case.
  30547. this.xStep = dg.xStep;
  30548. this.yStep = dg.yStep;
  30549. this.zStep = dg.zStep;
  30550. this.xBarWidth = dg.xBarWidth;
  30551. this.yBarWidth = dg.yBarWidth;
  30552. this.colX = dg.colX;
  30553. this.colY = dg.colY;
  30554. this.colZ = dg.colZ;
  30555. this.colValue = dg.colValue;
  30556. // set the scale dependent on the ranges.
  30557. this._setScale();
  30558. };
  30559. /**
  30560. * Return all data values as a list of Point3d objects
  30561. *
  30562. * @param {vis.DataSet} data
  30563. * @returns {Array.<Object>}
  30564. */
  30565. Graph3d.prototype.getDataPoints = function(data) {
  30566. var dataPoints = [];
  30567. for (var i = 0; i < data.length; i++) {
  30568. var point = new Point3d();
  30569. point.x = data[i][this.colX] || 0;
  30570. point.y = data[i][this.colY] || 0;
  30571. point.z = data[i][this.colZ] || 0;
  30572. point.data = data[i];
  30573. if (this.colValue !== undefined) {
  30574. point.value = data[i][this.colValue] || 0;
  30575. }
  30576. var obj = {};
  30577. obj.point = point;
  30578. obj.bottom = new Point3d(point.x, point.y, this.zRange.min);
  30579. obj.trans = undefined;
  30580. obj.screen = undefined;
  30581. dataPoints.push(obj);
  30582. }
  30583. return dataPoints;
  30584. };
  30585. /**
  30586. * Filter the data based on the current filter
  30587. *
  30588. * @param {Array} data
  30589. * @returns {Array} dataPoints Array with point objects which can be drawn on
  30590. * screen
  30591. */
  30592. Graph3d.prototype._getDataPoints = function(data) {
  30593. // TODO: store the created matrix dataPoints in the filters instead of
  30594. // reloading each time.
  30595. var x, y, i, obj;
  30596. var dataPoints = [];
  30597. if (this.style === Graph3d.STYLE.GRID || this.style === Graph3d.STYLE.SURFACE) {
  30598. // copy all values from the data table to a matrix
  30599. // the provided values are supposed to form a grid of (x,y) positions
  30600. // create two lists with all present x and y values
  30601. var dataX = this.dataGroup.getDistinctValues(this.colX, data);
  30602. var dataY = this.dataGroup.getDistinctValues(this.colY, data);
  30603. dataPoints = this.getDataPoints(data);
  30604. // create a grid, a 2d matrix, with all values.
  30605. var dataMatrix = []; // temporary data matrix
  30606. for (i = 0; i < dataPoints.length; i++) {
  30607. obj = dataPoints[i];
  30608. // TODO: implement Array().indexOf() for Internet Explorer
  30609. var xIndex = dataX.indexOf(obj.point.x);
  30610. var yIndex = dataY.indexOf(obj.point.y);
  30611. if (dataMatrix[xIndex] === undefined) {
  30612. dataMatrix[xIndex] = [];
  30613. }
  30614. dataMatrix[xIndex][yIndex] = obj;
  30615. }
  30616. // fill in the pointers to the neighbors.
  30617. for (x = 0; x < dataMatrix.length; x++) {
  30618. for (y = 0; y < dataMatrix[x].length; y++) {
  30619. if (dataMatrix[x][y]) {
  30620. dataMatrix[x][y].pointRight = x < dataMatrix.length - 1 ? dataMatrix[x + 1][y] : undefined;
  30621. dataMatrix[x][y].pointTop = y < dataMatrix[x].length - 1 ? dataMatrix[x][y + 1] : undefined;
  30622. dataMatrix[x][y].pointCross = x < dataMatrix.length - 1 && y < dataMatrix[x].length - 1 ? dataMatrix[x + 1][y + 1] : undefined;
  30623. }
  30624. }
  30625. }
  30626. } else {
  30627. // 'dot', 'dot-line', etc.
  30628. this._checkValueField(data);
  30629. dataPoints = this.getDataPoints(data);
  30630. if (this.style === Graph3d.STYLE.LINE) {
  30631. // Add next member points for line drawing
  30632. for (i = 0; i < dataPoints.length; i++) {
  30633. if (i > 0) {
  30634. dataPoints[i - 1].pointNext = dataPoints[i];
  30635. }
  30636. }
  30637. }
  30638. }
  30639. return dataPoints;
  30640. };
  30641. /**
  30642. * Create the main frame for the Graph3d.
  30643. *
  30644. * This function is executed once when a Graph3d object is created. The frame
  30645. * contains a canvas, and this canvas contains all objects like the axis and
  30646. * nodes.
  30647. */
  30648. Graph3d.prototype.create = function() {
  30649. // remove all elements from the container element.
  30650. while (this.containerElement.hasChildNodes()) {
  30651. this.containerElement.removeChild(this.containerElement.firstChild);
  30652. }
  30653. this.frame = document.createElement('div');
  30654. this.frame.style.position = 'relative';
  30655. this.frame.style.overflow = 'hidden';
  30656. // create the graph canvas (HTML canvas element)
  30657. this.frame.canvas = document.createElement('canvas');
  30658. this.frame.canvas.style.position = 'relative';
  30659. this.frame.appendChild(this.frame.canvas);
  30660. //if (!this.frame.canvas.getContext) {
  30661. {
  30662. var noCanvas = document.createElement('DIV');
  30663. noCanvas.style.color = 'red';
  30664. noCanvas.style.fontWeight = 'bold';
  30665. noCanvas.style.padding = '10px';
  30666. noCanvas.innerHTML = 'Error: your browser does not support HTML canvas';
  30667. this.frame.canvas.appendChild(noCanvas);
  30668. }
  30669. this.frame.filter = document.createElement('div');
  30670. this.frame.filter.style.position = 'absolute';
  30671. this.frame.filter.style.bottom = '0px';
  30672. this.frame.filter.style.left = '0px';
  30673. this.frame.filter.style.width = '100%';
  30674. this.frame.appendChild(this.frame.filter);
  30675. // add event listeners to handle moving and zooming the contents
  30676. var me = this;
  30677. var onmousedown = function onmousedown(event) {
  30678. me._onMouseDown(event);
  30679. };
  30680. var ontouchstart = function ontouchstart(event) {
  30681. me._onTouchStart(event);
  30682. };
  30683. var onmousewheel = function onmousewheel(event) {
  30684. me._onWheel(event);
  30685. };
  30686. var ontooltip = function ontooltip(event) {
  30687. me._onTooltip(event);
  30688. };
  30689. var onclick = function onclick(event) {
  30690. me._onClick(event);
  30691. };
  30692. // TODO: these events are never cleaned up... can give a 'memory leakage'
  30693. util.addEventListener(this.frame.canvas, 'mousedown', onmousedown);
  30694. util.addEventListener(this.frame.canvas, 'touchstart', ontouchstart);
  30695. util.addEventListener(this.frame.canvas, 'mousewheel', onmousewheel);
  30696. util.addEventListener(this.frame.canvas, 'mousemove', ontooltip);
  30697. util.addEventListener(this.frame.canvas, 'click', onclick);
  30698. // add the new graph to the container element
  30699. this.containerElement.appendChild(this.frame);
  30700. };
  30701. /**
  30702. * Set a new size for the graph
  30703. *
  30704. * @param {number} width
  30705. * @param {number} height
  30706. * @private
  30707. */
  30708. Graph3d.prototype._setSize = function(width, height) {
  30709. this.frame.style.width = width;
  30710. this.frame.style.height = height;
  30711. this._resizeCanvas();
  30712. };
  30713. /**
  30714. * Resize the canvas to the current size of the frame
  30715. */
  30716. Graph3d.prototype._resizeCanvas = function() {
  30717. this.frame.canvas.style.width = '100%';
  30718. this.frame.canvas.style.height = '100%';
  30719. this.frame.canvas.width = this.frame.canvas.clientWidth;
  30720. this.frame.canvas.height = this.frame.canvas.clientHeight;
  30721. // adjust with for margin
  30722. this.frame.filter.style.width = this.frame.canvas.clientWidth - 2 * 10 + 'px';
  30723. };
  30724. /**
  30725. * Start playing the animation, if requested and filter present. Only applicable
  30726. * when animation data is available.
  30727. */
  30728. Graph3d.prototype.animationStart = function() {
  30729. // start animation when option is true
  30730. if (!this.animationAutoStart || !this.dataGroup.dataFilter) return;
  30731. if (!this.frame.filter || !this.frame.filter.slider) throw new Error('No animation available');
  30732. this.frame.filter.slider.play();
  30733. };
  30734. /**
  30735. * Stop animation
  30736. */
  30737. Graph3d.prototype.animationStop = function() {
  30738. if (!this.frame.filter || !this.frame.filter.slider) return;
  30739. this.frame.filter.slider.stop();
  30740. };
  30741. /**
  30742. * Resize the center position based on the current values in this.xCenter
  30743. * and this.yCenter (which are strings with a percentage or a value
  30744. * in pixels). The center positions are the variables this.currentXCenter
  30745. * and this.currentYCenter
  30746. */
  30747. Graph3d.prototype._resizeCenter = function() {
  30748. // calculate the horizontal center position
  30749. if (this.xCenter.charAt(this.xCenter.length - 1) === '%') {
  30750. this.currentXCenter = parseFloat(this.xCenter) / 100 * this.frame.canvas.clientWidth;
  30751. } else {
  30752. this.currentXCenter = parseFloat(this.xCenter); // supposed to be in px
  30753. }
  30754. // calculate the vertical center position
  30755. if (this.yCenter.charAt(this.yCenter.length - 1) === '%') {
  30756. this.currentYCenter = parseFloat(this.yCenter) / 100 * (this.frame.canvas.clientHeight - this.frame.filter.clientHeight);
  30757. } else {
  30758. this.currentYCenter = parseFloat(this.yCenter); // supposed to be in px
  30759. }
  30760. };
  30761. /**
  30762. * Retrieve the current camera rotation
  30763. *
  30764. * @returns {object} An object with parameters horizontal, vertical, and
  30765. * distance
  30766. */
  30767. Graph3d.prototype.getCameraPosition = function() {
  30768. var pos = this.camera.getArmRotation();
  30769. pos.distance = this.camera.getArmLength();
  30770. return pos;
  30771. };
  30772. /**
  30773. * Load data into the 3D Graph
  30774. *
  30775. * @param {vis.DataSet} data
  30776. * @private
  30777. */
  30778. Graph3d.prototype._readData = function(data) {
  30779. // read the data
  30780. this.dataPoints = this.dataGroup.initializeData(this, data, this.style);
  30781. this._initializeRanges();
  30782. this._redrawFilter();
  30783. };
  30784. /**
  30785. * Replace the dataset of the Graph3d
  30786. *
  30787. * @param {Array | DataSet | DataView} data
  30788. */
  30789. Graph3d.prototype.setData = function(data) {
  30790. if (data === undefined || data === null) return;
  30791. this._readData(data);
  30792. this.redraw();
  30793. this.animationStart();
  30794. };
  30795. /**
  30796. * Update the options. Options will be merged with current options
  30797. *
  30798. * @param {Object} options
  30799. */
  30800. Graph3d.prototype.setOptions = function(options) {
  30801. if (options === undefined) return;
  30802. var errorFound = Validator.validate(options, allOptions);
  30803. if (errorFound === true) {
  30804. console.log('%cErrors have been found in the supplied options object.', printStyle);
  30805. }
  30806. this.animationStop();
  30807. Settings.setOptions(options, this);
  30808. this.setPointDrawingMethod();
  30809. this._setSize(this.width, this.height);
  30810. this.setData(this.dataGroup.getDataTable());
  30811. this.animationStart();
  30812. };
  30813. /**
  30814. * Determine which point drawing method to use for the current graph style.
  30815. */
  30816. Graph3d.prototype.setPointDrawingMethod = function() {
  30817. var method = undefined;
  30818. switch (this.style) {
  30819. case Graph3d.STYLE.BAR:
  30820. method = Graph3d.prototype._redrawBarGraphPoint;
  30821. break;
  30822. case Graph3d.STYLE.BARCOLOR:
  30823. method = Graph3d.prototype._redrawBarColorGraphPoint;
  30824. break;
  30825. case Graph3d.STYLE.BARSIZE:
  30826. method = Graph3d.prototype._redrawBarSizeGraphPoint;
  30827. break;
  30828. case Graph3d.STYLE.DOT:
  30829. method = Graph3d.prototype._redrawDotGraphPoint;
  30830. break;
  30831. case Graph3d.STYLE.DOTLINE:
  30832. method = Graph3d.prototype._redrawDotLineGraphPoint;
  30833. break;
  30834. case Graph3d.STYLE.DOTCOLOR:
  30835. method = Graph3d.prototype._redrawDotColorGraphPoint;
  30836. break;
  30837. case Graph3d.STYLE.DOTSIZE:
  30838. method = Graph3d.prototype._redrawDotSizeGraphPoint;
  30839. break;
  30840. case Graph3d.STYLE.SURFACE:
  30841. method = Graph3d.prototype._redrawSurfaceGraphPoint;
  30842. break;
  30843. case Graph3d.STYLE.GRID:
  30844. method = Graph3d.prototype._redrawGridGraphPoint;
  30845. break;
  30846. case Graph3d.STYLE.LINE:
  30847. method = Graph3d.prototype._redrawLineGraphPoint;
  30848. break;
  30849. default:
  30850. throw new Error('Can not determine point drawing method ' + 'for graph style \'' + this.style + '\'');
  30851. }
  30852. this._pointDrawingMethod = method;
  30853. };
  30854. /**
  30855. * Redraw the Graph.
  30856. */
  30857. Graph3d.prototype.redraw = function() {
  30858. if (this.dataPoints === undefined) {
  30859. throw new Error('Graph data not initialized');
  30860. }
  30861. this._resizeCanvas();
  30862. this._resizeCenter();
  30863. this._redrawSlider();
  30864. this._redrawClear();
  30865. this._redrawAxis();
  30866. this._redrawDataGraph();
  30867. this._redrawInfo();
  30868. this._redrawLegend();
  30869. };
  30870. /**
  30871. * Get drawing context without exposing canvas
  30872. *
  30873. * @returns {CanvasRenderingContext2D}
  30874. * @private
  30875. */
  30876. Graph3d.prototype._getContext = function() {
  30877. var canvas = this.frame.canvas;
  30878. var ctx = canvas.getContext('2d');
  30879. ctx.lineJoin = 'round';
  30880. ctx.lineCap = 'round';
  30881. return ctx;
  30882. };
  30883. /**
  30884. * Clear the canvas before redrawing
  30885. */
  30886. Graph3d.prototype._redrawClear = function() {
  30887. var canvas = this.frame.canvas;
  30888. var ctx = canvas.getContext('2d');
  30889. ctx.clearRect(0, 0, canvas.width, canvas.height);
  30890. };
  30891. Graph3d.prototype._dotSize = function() {
  30892. return this.frame.clientWidth * this.dotSizeRatio;
  30893. };
  30894. /**
  30895. * Get legend width
  30896. *
  30897. * @returns {*}
  30898. * @private
  30899. */
  30900. Graph3d.prototype._getLegendWidth = function() {
  30901. var width;
  30902. if (this.style === Graph3d.STYLE.DOTSIZE) {
  30903. var dotSize = this._dotSize();
  30904. //width = dotSize / 2 + dotSize * 2;
  30905. width = dotSize * this.dotSizeMaxFraction;
  30906. } else if (this.style === Graph3d.STYLE.BARSIZE) {
  30907. width = this.xBarWidth;
  30908. } else {
  30909. width = 20;
  30910. }
  30911. return width;
  30912. };
  30913. /**
  30914. * Redraw the legend based on size, dot color, or surface height
  30915. */
  30916. Graph3d.prototype._redrawLegend = function() {
  30917. //Return without drawing anything, if no legend is specified
  30918. if (this.showLegend !== true) {
  30919. return;
  30920. }
  30921. // Do not draw legend when graph style does not support
  30922. if (this.style === Graph3d.STYLE.LINE || this.style === Graph3d.STYLE.BARSIZE //TODO add legend support for BARSIZE
  30923. ) {
  30924. return;
  30925. }
  30926. // Legend types - size and color. Determine if size legend.
  30927. var isSizeLegend = this.style === Graph3d.STYLE.BARSIZE || this.style === Graph3d.STYLE.DOTSIZE;
  30928. // Legend is either tracking z values or style values. This flag if false means use z values.
  30929. var isValueLegend = this.style === Graph3d.STYLE.DOTSIZE || this.style === Graph3d.STYLE.DOTCOLOR || this.style === Graph3d.STYLE.BARCOLOR;
  30930. var height = Math.max(this.frame.clientHeight * 0.25, 100);
  30931. var top = this.margin;
  30932. var width = this._getLegendWidth(); // px - overwritten by size legend
  30933. var right = this.frame.clientWidth - this.margin;
  30934. var left = right - width;
  30935. var bottom = top + height;
  30936. var ctx = this._getContext();
  30937. ctx.lineWidth = 1;
  30938. ctx.font = '14px arial'; // TODO: put in options
  30939. if (isSizeLegend === false) {
  30940. // draw the color bar
  30941. var ymin = 0;
  30942. var ymax = height; // Todo: make height customizable
  30943. var y;
  30944. for (y = ymin; y < ymax; y++) {
  30945. var f = (y - ymin) / (ymax - ymin);
  30946. var hue = f * 240;
  30947. var color = this._hsv2rgb(hue, 1, 1);
  30948. ctx.strokeStyle = color;
  30949. ctx.beginPath();
  30950. ctx.moveTo(left, top + y);
  30951. ctx.lineTo(right, top + y);
  30952. ctx.stroke();
  30953. }
  30954. ctx.strokeStyle = this.axisColor;
  30955. ctx.strokeRect(left, top, width, height);
  30956. } else {
  30957. // draw the size legend box
  30958. var widthMin;
  30959. if (this.style === Graph3d.STYLE.DOTSIZE) {
  30960. // Get the proportion to max and min right
  30961. widthMin = width * (this.dotSizeMinFraction / this.dotSizeMaxFraction);
  30962. } else if (this.style === Graph3d.STYLE.BARSIZE) {
  30963. //widthMin = this.xBarWidth * 0.2 this is wrong - barwidth measures in terms of xvalues
  30964. }
  30965. ctx.strokeStyle = this.axisColor;
  30966. ctx.fillStyle = this.dataColor.fill;
  30967. ctx.beginPath();
  30968. ctx.moveTo(left, top);
  30969. ctx.lineTo(right, top);
  30970. ctx.lineTo(left + widthMin, bottom);
  30971. ctx.lineTo(left, bottom);
  30972. ctx.closePath();
  30973. ctx.fill();
  30974. ctx.stroke();
  30975. }
  30976. // print value text along the legend edge
  30977. var gridLineLen = 5; // px
  30978. var legendMin = isValueLegend ? this.valueRange.min : this.zRange.min;
  30979. var legendMax = isValueLegend ? this.valueRange.max : this.zRange.max;
  30980. var step = new StepNumber(legendMin, legendMax, (legendMax - legendMin) / 5, true);
  30981. step.start(true);
  30982. var from;
  30983. var to;
  30984. while (!step.end()) {
  30985. y = bottom - (step.getCurrent() - legendMin) / (legendMax - legendMin) * height;
  30986. from = new Point2d(left - gridLineLen, y);
  30987. to = new Point2d(left, y);
  30988. this._line(ctx, from, to);
  30989. ctx.textAlign = 'right';
  30990. ctx.textBaseline = 'middle';
  30991. ctx.fillStyle = this.axisColor;
  30992. ctx.fillText(step.getCurrent(), left - 2 * gridLineLen, y);
  30993. step.next();
  30994. }
  30995. ctx.textAlign = 'right';
  30996. ctx.textBaseline = 'top';
  30997. var label = this.legendLabel;
  30998. ctx.fillText(label, right, bottom + this.margin);
  30999. };
  31000. /**
  31001. * Redraw the filter
  31002. */
  31003. Graph3d.prototype._redrawFilter = function() {
  31004. var dataFilter = this.dataGroup.dataFilter;
  31005. var filter = this.frame.filter;
  31006. filter.innerHTML = '';
  31007. if (!dataFilter) {
  31008. filter.slider = undefined;
  31009. return;
  31010. }
  31011. var options = {
  31012. 'visible': this.showAnimationControls
  31013. };
  31014. var slider = new Slider(filter, options);
  31015. filter.slider = slider;
  31016. // TODO: css here is not nice here...
  31017. filter.style.padding = '10px';
  31018. //this.frame.filter.style.backgroundColor = '#EFEFEF';
  31019. slider.setValues(dataFilter.values);
  31020. slider.setPlayInterval(this.animationInterval);
  31021. // create an event handler
  31022. var me = this;
  31023. var onchange = function onchange() {
  31024. var dataFilter = me.dataGroup.dataFilter;
  31025. var index = slider.getIndex();
  31026. dataFilter.selectValue(index);
  31027. me.dataPoints = dataFilter._getDataPoints();
  31028. me.redraw();
  31029. };
  31030. slider.setOnChangeCallback(onchange);
  31031. };
  31032. /**
  31033. * Redraw the slider
  31034. */
  31035. Graph3d.prototype._redrawSlider = function() {
  31036. if (this.frame.filter.slider !== undefined) {
  31037. this.frame.filter.slider.redraw();
  31038. }
  31039. };
  31040. /**
  31041. * Redraw common information
  31042. */
  31043. Graph3d.prototype._redrawInfo = function() {
  31044. var info = this.dataGroup.getInfo();
  31045. if (info === undefined) return;
  31046. var ctx = this._getContext();
  31047. ctx.font = '14px arial'; // TODO: put in options
  31048. ctx.lineStyle = 'gray';
  31049. ctx.fillStyle = 'gray';
  31050. ctx.textAlign = 'left';
  31051. ctx.textBaseline = 'top';
  31052. var x = this.margin;
  31053. var y = this.margin;
  31054. ctx.fillText(info, x, y);
  31055. };
  31056. /**
  31057. * Draw a line between 2d points 'from' and 'to'.
  31058. *
  31059. * If stroke style specified, set that as well.
  31060. *
  31061. * @param {CanvasRenderingContext2D} ctx
  31062. * @param {vis.Point2d} from
  31063. * @param {vis.Point2d} to
  31064. * @param {string} [strokeStyle]
  31065. * @private
  31066. */
  31067. Graph3d.prototype._line = function(ctx, from, to, strokeStyle) {
  31068. if (strokeStyle !== undefined) {
  31069. ctx.strokeStyle = strokeStyle;
  31070. }
  31071. ctx.beginPath();
  31072. ctx.moveTo(from.x, from.y);
  31073. ctx.lineTo(to.x, to.y);
  31074. ctx.stroke();
  31075. };
  31076. /**
  31077. *
  31078. * @param {CanvasRenderingContext2D} ctx
  31079. * @param {vis.Point3d} point3d
  31080. * @param {string} text
  31081. * @param {number} armAngle
  31082. * @param {number} [yMargin=0]
  31083. */
  31084. Graph3d.prototype.drawAxisLabelX = function(ctx, point3d, text, armAngle, yMargin) {
  31085. if (yMargin === undefined) {
  31086. yMargin = 0;
  31087. }
  31088. var point2d = this._convert3Dto2D(point3d);
  31089. if (Math.cos(armAngle * 2) > 0) {
  31090. ctx.textAlign = 'center';
  31091. ctx.textBaseline = 'top';
  31092. point2d.y += yMargin;
  31093. } else if (Math.sin(armAngle * 2) < 0) {
  31094. ctx.textAlign = 'right';
  31095. ctx.textBaseline = 'middle';
  31096. } else {
  31097. ctx.textAlign = 'left';
  31098. ctx.textBaseline = 'middle';
  31099. }
  31100. ctx.fillStyle = this.axisColor;
  31101. ctx.fillText(text, point2d.x, point2d.y);
  31102. };
  31103. /**
  31104. *
  31105. * @param {CanvasRenderingContext2D} ctx
  31106. * @param {vis.Point3d} point3d
  31107. * @param {string} text
  31108. * @param {number} armAngle
  31109. * @param {number} [yMargin=0]
  31110. */
  31111. Graph3d.prototype.drawAxisLabelY = function(ctx, point3d, text, armAngle, yMargin) {
  31112. if (yMargin === undefined) {
  31113. yMargin = 0;
  31114. }
  31115. var point2d = this._convert3Dto2D(point3d);
  31116. if (Math.cos(armAngle * 2) < 0) {
  31117. ctx.textAlign = 'center';
  31118. ctx.textBaseline = 'top';
  31119. point2d.y += yMargin;
  31120. } else if (Math.sin(armAngle * 2) > 0) {
  31121. ctx.textAlign = 'right';
  31122. ctx.textBaseline = 'middle';
  31123. } else {
  31124. ctx.textAlign = 'left';
  31125. ctx.textBaseline = 'middle';
  31126. }
  31127. ctx.fillStyle = this.axisColor;
  31128. ctx.fillText(text, point2d.x, point2d.y);
  31129. };
  31130. /**
  31131. *
  31132. * @param {CanvasRenderingContext2D} ctx
  31133. * @param {vis.Point3d} point3d
  31134. * @param {string} text
  31135. * @param {number} [offset=0]
  31136. */
  31137. Graph3d.prototype.drawAxisLabelZ = function(ctx, point3d, text, offset) {
  31138. if (offset === undefined) {
  31139. offset = 0;
  31140. }
  31141. var point2d = this._convert3Dto2D(point3d);
  31142. ctx.textAlign = 'right';
  31143. ctx.textBaseline = 'middle';
  31144. ctx.fillStyle = this.axisColor;
  31145. ctx.fillText(text, point2d.x - offset, point2d.y);
  31146. };
  31147. /**
  31148. /**
  31149. * Draw a line between 2d points 'from' and 'to'.
  31150. *
  31151. * If stroke style specified, set that as well.
  31152. *
  31153. * @param {CanvasRenderingContext2D} ctx
  31154. * @param {vis.Point2d} from
  31155. * @param {vis.Point2d} to
  31156. * @param {string} [strokeStyle]
  31157. * @private
  31158. */
  31159. Graph3d.prototype._line3d = function(ctx, from, to, strokeStyle) {
  31160. var from2d = this._convert3Dto2D(from);
  31161. var to2d = this._convert3Dto2D(to);
  31162. this._line(ctx, from2d, to2d, strokeStyle);
  31163. };
  31164. /**
  31165. * Redraw the axis
  31166. */
  31167. Graph3d.prototype._redrawAxis = function() {
  31168. var ctx = this._getContext(),
  31169. from,
  31170. to,
  31171. step,
  31172. prettyStep,
  31173. text,
  31174. xText,
  31175. yText,
  31176. zText,
  31177. offset,
  31178. xOffset,
  31179. yOffset;
  31180. // TODO: get the actual rendered style of the containerElement
  31181. //ctx.font = this.containerElement.style.font;
  31182. ctx.font = 24 / this.camera.getArmLength() + 'px arial';
  31183. // calculate the length for the short grid lines
  31184. var gridLenX = 0.025 / this.scale.x;
  31185. var gridLenY = 0.025 / this.scale.y;
  31186. var textMargin = 5 / this.camera.getArmLength(); // px
  31187. var armAngle = this.camera.getArmRotation().horizontal;
  31188. var armVector = new Point2d(Math.cos(armAngle), Math.sin(armAngle));
  31189. var xRange = this.xRange;
  31190. var yRange = this.yRange;
  31191. var zRange = this.zRange;
  31192. var point3d;
  31193. // draw x-grid lines
  31194. ctx.lineWidth = 1;
  31195. prettyStep = this.defaultXStep === undefined;
  31196. step = new StepNumber(xRange.min, xRange.max, this.xStep, prettyStep);
  31197. step.start(true);
  31198. while (!step.end()) {
  31199. var x = step.getCurrent();
  31200. if (this.showGrid) {
  31201. from = new Point3d(x, yRange.min, zRange.min);
  31202. to = new Point3d(x, yRange.max, zRange.min);
  31203. this._line3d(ctx, from, to, this.gridColor);
  31204. } else if (this.showXAxis) {
  31205. from = new Point3d(x, yRange.min, zRange.min);
  31206. to = new Point3d(x, yRange.min + gridLenX, zRange.min);
  31207. this._line3d(ctx, from, to, this.axisColor);
  31208. from = new Point3d(x, yRange.max, zRange.min);
  31209. to = new Point3d(x, yRange.max - gridLenX, zRange.min);
  31210. this._line3d(ctx, from, to, this.axisColor);
  31211. }
  31212. if (this.showXAxis) {
  31213. yText = armVector.x > 0 ? yRange.min : yRange.max;
  31214. point3d = new Point3d(x, yText, zRange.min);
  31215. var msg = ' ' + this.xValueLabel(x) + ' ';
  31216. this.drawAxisLabelX(ctx, point3d, msg, armAngle, textMargin);
  31217. }
  31218. step.next();
  31219. }
  31220. // draw y-grid lines
  31221. ctx.lineWidth = 1;
  31222. prettyStep = this.defaultYStep === undefined;
  31223. step = new StepNumber(yRange.min, yRange.max, this.yStep, prettyStep);
  31224. step.start(true);
  31225. while (!step.end()) {
  31226. var y = step.getCurrent();
  31227. if (this.showGrid) {
  31228. from = new Point3d(xRange.min, y, zRange.min);
  31229. to = new Point3d(xRange.max, y, zRange.min);
  31230. this._line3d(ctx, from, to, this.gridColor);
  31231. } else if (this.showYAxis) {
  31232. from = new Point3d(xRange.min, y, zRange.min);
  31233. to = new Point3d(xRange.min + gridLenY, y, zRange.min);
  31234. this._line3d(ctx, from, to, this.axisColor);
  31235. from = new Point3d(xRange.max, y, zRange.min);
  31236. to = new Point3d(xRange.max - gridLenY, y, zRange.min);
  31237. this._line3d(ctx, from, to, this.axisColor);
  31238. }
  31239. if (this.showYAxis) {
  31240. xText = armVector.y > 0 ? xRange.min : xRange.max;
  31241. point3d = new Point3d(xText, y, zRange.min);
  31242. var _msg = ' ' + this.yValueLabel(y) + ' ';
  31243. this.drawAxisLabelY(ctx, point3d, _msg, armAngle, textMargin);
  31244. }
  31245. step.next();
  31246. }
  31247. // draw z-grid lines and axis
  31248. if (this.showZAxis) {
  31249. ctx.lineWidth = 1;
  31250. prettyStep = this.defaultZStep === undefined;
  31251. step = new StepNumber(zRange.min, zRange.max, this.zStep, prettyStep);
  31252. step.start(true);
  31253. xText = armVector.x > 0 ? xRange.min : xRange.max;
  31254. yText = armVector.y < 0 ? yRange.min : yRange.max;
  31255. while (!step.end()) {
  31256. var z = step.getCurrent();
  31257. // TODO: make z-grid lines really 3d?
  31258. var from3d = new Point3d(xText, yText, z);
  31259. var from2d = this._convert3Dto2D(from3d);
  31260. to = new Point2d(from2d.x - textMargin, from2d.y);
  31261. this._line(ctx, from2d, to, this.axisColor);
  31262. var _msg2 = this.zValueLabel(z) + ' ';
  31263. this.drawAxisLabelZ(ctx, from3d, _msg2, 5);
  31264. step.next();
  31265. }
  31266. ctx.lineWidth = 1;
  31267. from = new Point3d(xText, yText, zRange.min);
  31268. to = new Point3d(xText, yText, zRange.max);
  31269. this._line3d(ctx, from, to, this.axisColor);
  31270. }
  31271. // draw x-axis
  31272. if (this.showXAxis) {
  31273. var xMin2d;
  31274. var xMax2d;
  31275. ctx.lineWidth = 1;
  31276. // line at yMin
  31277. xMin2d = new Point3d(xRange.min, yRange.min, zRange.min);
  31278. xMax2d = new Point3d(xRange.max, yRange.min, zRange.min);
  31279. this._line3d(ctx, xMin2d, xMax2d, this.axisColor);
  31280. // line at ymax
  31281. xMin2d = new Point3d(xRange.min, yRange.max, zRange.min);
  31282. xMax2d = new Point3d(xRange.max, yRange.max, zRange.min);
  31283. this._line3d(ctx, xMin2d, xMax2d, this.axisColor);
  31284. }
  31285. // draw y-axis
  31286. if (this.showYAxis) {
  31287. ctx.lineWidth = 1;
  31288. // line at xMin
  31289. from = new Point3d(xRange.min, yRange.min, zRange.min);
  31290. to = new Point3d(xRange.min, yRange.max, zRange.min);
  31291. this._line3d(ctx, from, to, this.axisColor);
  31292. // line at xMax
  31293. from = new Point3d(xRange.max, yRange.min, zRange.min);
  31294. to = new Point3d(xRange.max, yRange.max, zRange.min);
  31295. this._line3d(ctx, from, to, this.axisColor);
  31296. }
  31297. // draw x-label
  31298. var xLabel = this.xLabel;
  31299. if (xLabel.length > 0 && this.showXAxis) {
  31300. yOffset = 0.1 / this.scale.y;
  31301. xText = (xRange.max + 3 * xRange.min) / 4;
  31302. yText = armVector.x > 0 ? yRange.min - yOffset : yRange.max + yOffset;
  31303. text = new Point3d(xText, yText, zRange.min);
  31304. this.drawAxisLabelX(ctx, text, xLabel, armAngle);
  31305. }
  31306. // draw y-label
  31307. var yLabel = this.yLabel;
  31308. if (yLabel.length > 0 && this.showYAxis) {
  31309. xOffset = 0.1 / this.scale.x;
  31310. xText = armVector.y > 0 ? xRange.min - xOffset : xRange.max + xOffset;
  31311. yText = (yRange.max + 3 * yRange.min) / 4;
  31312. text = new Point3d(xText, yText, zRange.min);
  31313. this.drawAxisLabelY(ctx, text, yLabel, armAngle);
  31314. }
  31315. // draw z-label
  31316. var zLabel = this.zLabel;
  31317. if (zLabel.length > 0 && this.showZAxis) {
  31318. offset = 30; // pixels. // TODO: relate to the max width of the values on the z axis?
  31319. xText = armVector.x > 0 ? xRange.min : xRange.max;
  31320. yText = armVector.y < 0 ? yRange.min : yRange.max;
  31321. zText = (zRange.max + 3 * zRange.min) / 4;
  31322. text = new Point3d(xText, yText, zText);
  31323. this.drawAxisLabelZ(ctx, text, zLabel, offset);
  31324. }
  31325. };
  31326. /**
  31327. * Calculate the color based on the given value.
  31328. * @param {number} H Hue, a value be between 0 and 360
  31329. * @param {number} S Saturation, a value between 0 and 1
  31330. * @param {number} V Value, a value between 0 and 1
  31331. * @returns {string}
  31332. * @private
  31333. */
  31334. Graph3d.prototype._hsv2rgb = function(H, S, V) {
  31335. var R, G, B, C, Hi, X;
  31336. C = V * S;
  31337. Hi = Math.floor(H / 60); // hi = 0,1,2,3,4,5
  31338. X = C * (1 - Math.abs(H / 60 % 2 - 1));
  31339. switch (Hi) {
  31340. case 0:
  31341. R = C;
  31342. G = X;
  31343. B = 0;
  31344. break;
  31345. case 1:
  31346. R = X;
  31347. G = C;
  31348. B = 0;
  31349. break;
  31350. case 2:
  31351. R = 0;
  31352. G = C;
  31353. B = X;
  31354. break;
  31355. case 3:
  31356. R = 0;
  31357. G = X;
  31358. B = C;
  31359. break;
  31360. case 4:
  31361. R = X;
  31362. G = 0;
  31363. B = C;
  31364. break;
  31365. case 5:
  31366. R = C;
  31367. G = 0;
  31368. B = X;
  31369. break;
  31370. default:
  31371. R = 0;
  31372. G = 0;
  31373. B = 0;
  31374. break;
  31375. }
  31376. return 'RGB(' + parseInt(R * 255) + ',' + parseInt(G * 255) + ',' + parseInt(B * 255) + ')';
  31377. };
  31378. /**
  31379. *
  31380. * @param {vis.Point3d} point
  31381. * @returns {*}
  31382. * @private
  31383. */
  31384. Graph3d.prototype._getStrokeWidth = function(point) {
  31385. if (point !== undefined) {
  31386. if (this.showPerspective) {
  31387. return 1 / -point.trans.z * this.dataColor.strokeWidth;
  31388. } else {
  31389. return -(this.eye.z / this.camera.getArmLength()) * this.dataColor.strokeWidth;
  31390. }
  31391. }
  31392. return this.dataColor.strokeWidth;
  31393. };
  31394. // -----------------------------------------------------------------------------
  31395. // Drawing primitives for the graphs
  31396. // -----------------------------------------------------------------------------
  31397. /**
  31398. * Draw a bar element in the view with the given properties.
  31399. *
  31400. * @param {CanvasRenderingContext2D} ctx
  31401. * @param {Object} point
  31402. * @param {number} xWidth
  31403. * @param {number} yWidth
  31404. * @param {string} color
  31405. * @param {string} borderColor
  31406. * @private
  31407. */
  31408. Graph3d.prototype._redrawBar = function(ctx, point, xWidth, yWidth, color, borderColor) {
  31409. var surface;
  31410. // calculate all corner points
  31411. var me = this;
  31412. var point3d = point.point;
  31413. var zMin = this.zRange.min;
  31414. var top = [{ point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, point3d.z) }, { point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, point3d.z) }, { point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, point3d.z) }, { point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, point3d.z) }];
  31415. var bottom = [{ point: new Point3d(point3d.x - xWidth, point3d.y - yWidth, zMin) }, { point: new Point3d(point3d.x + xWidth, point3d.y - yWidth, zMin) }, { point: new Point3d(point3d.x + xWidth, point3d.y + yWidth, zMin) }, { point: new Point3d(point3d.x - xWidth, point3d.y + yWidth, zMin) }];
  31416. // calculate screen location of the points
  31417. top.forEach(function(obj) {
  31418. obj.screen = me._convert3Dto2D(obj.point);
  31419. });
  31420. bottom.forEach(function(obj) {
  31421. obj.screen = me._convert3Dto2D(obj.point);
  31422. });
  31423. // create five sides, calculate both corner points and center points
  31424. var surfaces = [{ corners: top, center: Point3d.avg(bottom[0].point, bottom[2].point) }, { corners: [top[0], top[1], bottom[1], bottom[0]], center: Point3d.avg(bottom[1].point, bottom[0].point) }, { corners: [top[1], top[2], bottom[2], bottom[1]], center: Point3d.avg(bottom[2].point, bottom[1].point) }, { corners: [top[2], top[3], bottom[3], bottom[2]], center: Point3d.avg(bottom[3].point, bottom[2].point) }, { corners: [top[3], top[0], bottom[0], bottom[3]], center: Point3d.avg(bottom[0].point, bottom[3].point) }];
  31425. point.surfaces = surfaces;
  31426. // calculate the distance of each of the surface centers to the camera
  31427. for (var j = 0; j < surfaces.length; j++) {
  31428. surface = surfaces[j];
  31429. var transCenter = this._convertPointToTranslation(surface.center);
  31430. surface.dist = this.showPerspective ? transCenter.length() : -transCenter.z;
  31431. // TODO: this dept calculation doesn't work 100% of the cases due to perspective,
  31432. // but the current solution is fast/simple and works in 99.9% of all cases
  31433. // the issue is visible in example 14, with graph.setCameraPosition({horizontal: 2.97, vertical: 0.5, distance: 0.9})
  31434. }
  31435. // order the surfaces by their (translated) depth
  31436. surfaces.sort(function(a, b) {
  31437. var diff = b.dist - a.dist;
  31438. if (diff) return diff;
  31439. // if equal depth, sort the top surface last
  31440. if (a.corners === top) return 1;
  31441. if (b.corners === top) return -1;
  31442. // both are equal
  31443. return 0;
  31444. });
  31445. // draw the ordered surfaces
  31446. ctx.lineWidth = this._getStrokeWidth(point);
  31447. ctx.strokeStyle = borderColor;
  31448. ctx.fillStyle = color;
  31449. // NOTE: we start at j=2 instead of j=0 as we don't need to draw the two surfaces at the backside
  31450. for (var _j = 2; _j < surfaces.length; _j++) {
  31451. surface = surfaces[_j];
  31452. this._polygon(ctx, surface.corners);
  31453. }
  31454. };
  31455. /**
  31456. * Draw a polygon using the passed points and fill it with the passed style and stroke.
  31457. *
  31458. * @param {CanvasRenderingContext2D} ctx
  31459. * @param {Array.<vis.Point3d>} points an array of points.
  31460. * @param {string} [fillStyle] the fill style to set
  31461. * @param {string} [strokeStyle] the stroke style to set
  31462. */
  31463. Graph3d.prototype._polygon = function(ctx, points, fillStyle, strokeStyle) {
  31464. if (points.length < 2) {
  31465. return;
  31466. }
  31467. if (fillStyle !== undefined) {
  31468. ctx.fillStyle = fillStyle;
  31469. }
  31470. if (strokeStyle !== undefined) {
  31471. ctx.strokeStyle = strokeStyle;
  31472. }
  31473. ctx.beginPath();
  31474. ctx.moveTo(points[0].screen.x, points[0].screen.y);
  31475. for (var i = 1; i < points.length; ++i) {
  31476. var point = points[i];
  31477. ctx.lineTo(point.screen.x, point.screen.y);
  31478. }
  31479. ctx.closePath();
  31480. ctx.fill();
  31481. ctx.stroke(); // TODO: only draw stroke when strokeWidth > 0
  31482. };
  31483. /**
  31484. * @param {CanvasRenderingContext2D} ctx
  31485. * @param {object} point
  31486. * @param {string} color
  31487. * @param {string} borderColor
  31488. * @param {number} [size=this._dotSize()]
  31489. * @private
  31490. */
  31491. Graph3d.prototype._drawCircle = function(ctx, point, color, borderColor, size) {
  31492. var radius = this._calcRadius(point, size);
  31493. ctx.lineWidth = this._getStrokeWidth(point);
  31494. ctx.strokeStyle = borderColor;
  31495. ctx.fillStyle = color;
  31496. ctx.beginPath();
  31497. ctx.arc(point.screen.x, point.screen.y, radius, 0, Math.PI * 2, true);
  31498. ctx.fill();
  31499. ctx.stroke();
  31500. };
  31501. /**
  31502. * Determine the colors for the 'regular' graph styles.
  31503. *
  31504. * @param {object} point
  31505. * @returns {{fill, border}}
  31506. * @private
  31507. */
  31508. Graph3d.prototype._getColorsRegular = function(point) {
  31509. // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
  31510. var hue = (1 - (point.point.z - this.zRange.min) * this.scale.z / this.verticalRatio) * 240;
  31511. var color = this._hsv2rgb(hue, 1, 1);
  31512. var borderColor = this._hsv2rgb(hue, 1, 0.8);
  31513. return {
  31514. fill: color,
  31515. border: borderColor
  31516. };
  31517. };
  31518. /**
  31519. * Get the colors for the 'color' graph styles.
  31520. * These styles are currently: 'bar-color' and 'dot-color'
  31521. * Color may be set as a string representation of HTML color, like #ff00ff,
  31522. * or calculated from a number, for example, distance from this point
  31523. * The first option is useful when we have some pre-given legend, to which we have to adjust ourselves
  31524. * The second option is useful when we are interested in automatically setting the color, from some value,
  31525. * using some color scale
  31526. * @param {object} point
  31527. * @returns {{fill: *, border: *}}
  31528. * @private
  31529. */
  31530. Graph3d.prototype._getColorsColor = function(point) {
  31531. // calculate the color based on the value
  31532. var color, borderColor;
  31533. if (typeof point.point.value === "string") {
  31534. color = point.point.value;
  31535. borderColor = point.point.value;
  31536. } else {
  31537. var hue = (1 - (point.point.value - this.valueRange.min) * this.scale.value) * 240;
  31538. color = this._hsv2rgb(hue, 1, 1);
  31539. borderColor = this._hsv2rgb(hue, 1, 0.8);
  31540. }
  31541. return {
  31542. fill: color,
  31543. border: borderColor
  31544. };
  31545. };
  31546. /**
  31547. * Get the colors for the 'size' graph styles.
  31548. * These styles are currently: 'bar-size' and 'dot-size'
  31549. *
  31550. * @returns {{fill: *, border: (string|colorOptions.stroke|{string, undefined}|string|colorOptions.stroke|{string}|*)}}
  31551. * @private
  31552. */
  31553. Graph3d.prototype._getColorsSize = function() {
  31554. return {
  31555. fill: this.dataColor.fill,
  31556. border: this.dataColor.stroke
  31557. };
  31558. };
  31559. /**
  31560. * Determine the size of a point on-screen, as determined by the
  31561. * distance to the camera.
  31562. *
  31563. * @param {Object} point
  31564. * @param {number} [size=this._dotSize()] the size that needs to be translated to screen coordinates.
  31565. * optional; if not passed, use the default point size.
  31566. * @returns {number}
  31567. * @private
  31568. */
  31569. Graph3d.prototype._calcRadius = function(point, size) {
  31570. if (size === undefined) {
  31571. size = this._dotSize();
  31572. }
  31573. var radius;
  31574. if (this.showPerspective) {
  31575. radius = size / -point.trans.z;
  31576. } else {
  31577. radius = size * -(this.eye.z / this.camera.getArmLength());
  31578. }
  31579. if (radius < 0) {
  31580. radius = 0;
  31581. }
  31582. return radius;
  31583. };
  31584. // -----------------------------------------------------------------------------
  31585. // Methods for drawing points per graph style.
  31586. // -----------------------------------------------------------------------------
  31587. /**
  31588. * Draw single datapoint for graph style 'bar'.
  31589. *
  31590. * @param {CanvasRenderingContext2D} ctx
  31591. * @param {Object} point
  31592. * @private
  31593. */
  31594. Graph3d.prototype._redrawBarGraphPoint = function(ctx, point) {
  31595. var xWidth = this.xBarWidth / 2;
  31596. var yWidth = this.yBarWidth / 2;
  31597. var colors = this._getColorsRegular(point);
  31598. this._redrawBar(ctx, point, xWidth, yWidth, colors.fill, colors.border);
  31599. };
  31600. /**
  31601. * Draw single datapoint for graph style 'bar-color'.
  31602. *
  31603. * @param {CanvasRenderingContext2D} ctx
  31604. * @param {Object} point
  31605. * @private
  31606. */
  31607. Graph3d.prototype._redrawBarColorGraphPoint = function(ctx, point) {
  31608. var xWidth = this.xBarWidth / 2;
  31609. var yWidth = this.yBarWidth / 2;
  31610. var colors = this._getColorsColor(point);
  31611. this._redrawBar(ctx, point, xWidth, yWidth, colors.fill, colors.border);
  31612. };
  31613. /**
  31614. * Draw single datapoint for graph style 'bar-size'.
  31615. *
  31616. * @param {CanvasRenderingContext2D} ctx
  31617. * @param {Object} point
  31618. * @private
  31619. */
  31620. Graph3d.prototype._redrawBarSizeGraphPoint = function(ctx, point) {
  31621. // calculate size for the bar
  31622. var fraction = (point.point.value - this.valueRange.min) / this.valueRange.range();
  31623. var xWidth = this.xBarWidth / 2 * (fraction * 0.8 + 0.2);
  31624. var yWidth = this.yBarWidth / 2 * (fraction * 0.8 + 0.2);
  31625. var colors = this._getColorsSize();
  31626. this._redrawBar(ctx, point, xWidth, yWidth, colors.fill, colors.border);
  31627. };
  31628. /**
  31629. * Draw single datapoint for graph style 'dot'.
  31630. *
  31631. * @param {CanvasRenderingContext2D} ctx
  31632. * @param {Object} point
  31633. * @private
  31634. */
  31635. Graph3d.prototype._redrawDotGraphPoint = function(ctx, point) {
  31636. var colors = this._getColorsRegular(point);
  31637. this._drawCircle(ctx, point, colors.fill, colors.border);
  31638. };
  31639. /**
  31640. * Draw single datapoint for graph style 'dot-line'.
  31641. *
  31642. * @param {CanvasRenderingContext2D} ctx
  31643. * @param {Object} point
  31644. * @private
  31645. */
  31646. Graph3d.prototype._redrawDotLineGraphPoint = function(ctx, point) {
  31647. // draw a vertical line from the XY-plane to the graph value
  31648. var from = this._convert3Dto2D(point.bottom);
  31649. ctx.lineWidth = 1;
  31650. this._line(ctx, from, point.screen, this.gridColor);
  31651. this._redrawDotGraphPoint(ctx, point);
  31652. };
  31653. /**
  31654. * Draw single datapoint for graph style 'dot-color'.
  31655. *
  31656. * @param {CanvasRenderingContext2D} ctx
  31657. * @param {Object} point
  31658. * @private
  31659. */
  31660. Graph3d.prototype._redrawDotColorGraphPoint = function(ctx, point) {
  31661. var colors = this._getColorsColor(point);
  31662. this._drawCircle(ctx, point, colors.fill, colors.border);
  31663. };
  31664. /**
  31665. * Draw single datapoint for graph style 'dot-size'.
  31666. *
  31667. * @param {CanvasRenderingContext2D} ctx
  31668. * @param {Object} point
  31669. * @private
  31670. */
  31671. Graph3d.prototype._redrawDotSizeGraphPoint = function(ctx, point) {
  31672. var dotSize = this._dotSize();
  31673. var fraction = (point.point.value - this.valueRange.min) / this.valueRange.range();
  31674. var sizeMin = dotSize * this.dotSizeMinFraction;
  31675. var sizeRange = dotSize * this.dotSizeMaxFraction - sizeMin;
  31676. var size = sizeMin + sizeRange * fraction;
  31677. var colors = this._getColorsSize();
  31678. this._drawCircle(ctx, point, colors.fill, colors.border, size);
  31679. };
  31680. /**
  31681. * Draw single datapoint for graph style 'surface'.
  31682. *
  31683. * @param {CanvasRenderingContext2D} ctx
  31684. * @param {Object} point
  31685. * @private
  31686. */
  31687. Graph3d.prototype._redrawSurfaceGraphPoint = function(ctx, point) {
  31688. var right = point.pointRight;
  31689. var top = point.pointTop;
  31690. var cross = point.pointCross;
  31691. if (point === undefined || right === undefined || top === undefined || cross === undefined) {
  31692. return;
  31693. }
  31694. var topSideVisible = true;
  31695. var fillStyle;
  31696. var strokeStyle;
  31697. if (this.showGrayBottom || this.showShadow) {
  31698. // calculate the cross product of the two vectors from center
  31699. // to left and right, in order to know whether we are looking at the
  31700. // bottom or at the top side. We can also use the cross product
  31701. // for calculating light intensity
  31702. var aDiff = Point3d.subtract(cross.trans, point.trans);
  31703. var bDiff = Point3d.subtract(top.trans, right.trans);
  31704. var crossproduct = Point3d.crossProduct(aDiff, bDiff);
  31705. var len = crossproduct.length();
  31706. // FIXME: there is a bug with determining the surface side (shadow or colored)
  31707. topSideVisible = crossproduct.z > 0;
  31708. }
  31709. if (topSideVisible) {
  31710. // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
  31711. var zAvg = (point.point.z + right.point.z + top.point.z + cross.point.z) / 4;
  31712. var h = (1 - (zAvg - this.zRange.min) * this.scale.z / this.verticalRatio) * 240;
  31713. var s = 1; // saturation
  31714. var v;
  31715. if (this.showShadow) {
  31716. v = Math.min(1 + crossproduct.x / len / 2, 1); // value. TODO: scale
  31717. fillStyle = this._hsv2rgb(h, s, v);
  31718. strokeStyle = fillStyle;
  31719. } else {
  31720. v = 1;
  31721. fillStyle = this._hsv2rgb(h, s, v);
  31722. strokeStyle = this.axisColor; // TODO: should be customizable
  31723. }
  31724. } else {
  31725. fillStyle = 'gray';
  31726. strokeStyle = this.axisColor;
  31727. }
  31728. ctx.lineWidth = this._getStrokeWidth(point);
  31729. // TODO: only draw stroke when strokeWidth > 0
  31730. var points = [point, right, cross, top];
  31731. this._polygon(ctx, points, fillStyle, strokeStyle);
  31732. };
  31733. /**
  31734. * Helper method for _redrawGridGraphPoint()
  31735. *
  31736. * @param {CanvasRenderingContext2D} ctx
  31737. * @param {Object} from
  31738. * @param {Object} to
  31739. * @private
  31740. */
  31741. Graph3d.prototype._drawGridLine = function(ctx, from, to) {
  31742. if (from === undefined || to === undefined) {
  31743. return;
  31744. }
  31745. // calculate Hue from the current value. At zMin the hue is 240, at zMax the hue is 0
  31746. var zAvg = (from.point.z + to.point.z) / 2;
  31747. var h = (1 - (zAvg - this.zRange.min) * this.scale.z / this.verticalRatio) * 240;
  31748. ctx.lineWidth = this._getStrokeWidth(from) * 2;
  31749. ctx.strokeStyle = this._hsv2rgb(h, 1, 1);
  31750. this._line(ctx, from.screen, to.screen);
  31751. };
  31752. /**
  31753. * Draw single datapoint for graph style 'Grid'.
  31754. *
  31755. * @param {CanvasRenderingContext2D} ctx
  31756. * @param {Object} point
  31757. * @private
  31758. */
  31759. Graph3d.prototype._redrawGridGraphPoint = function(ctx, point) {
  31760. this._drawGridLine(ctx, point, point.pointRight);
  31761. this._drawGridLine(ctx, point, point.pointTop);
  31762. };
  31763. /**
  31764. * Draw single datapoint for graph style 'line'.
  31765. *
  31766. * @param {CanvasRenderingContext2D} ctx
  31767. * @param {Object} point
  31768. * @private
  31769. */
  31770. Graph3d.prototype._redrawLineGraphPoint = function(ctx, point) {
  31771. if (point.pointNext === undefined) {
  31772. return;
  31773. }
  31774. ctx.lineWidth = this._getStrokeWidth(point);
  31775. ctx.strokeStyle = this.dataColor.stroke;
  31776. this._line(ctx, point.screen, point.pointNext.screen);
  31777. };
  31778. /**
  31779. * Draw all datapoints for currently selected graph style.
  31780. *
  31781. */
  31782. Graph3d.prototype._redrawDataGraph = function() {
  31783. var ctx = this._getContext();
  31784. var i;
  31785. if (this.dataPoints === undefined || this.dataPoints.length <= 0) return; // TODO: throw exception?
  31786. this._calcTranslations(this.dataPoints);
  31787. for (i = 0; i < this.dataPoints.length; i++) {
  31788. var point = this.dataPoints[i];
  31789. // Using call() ensures that the correct context is used
  31790. this._pointDrawingMethod.call(this, ctx, point);
  31791. }
  31792. };
  31793. // -----------------------------------------------------------------------------
  31794. // End methods for drawing points per graph style.
  31795. // -----------------------------------------------------------------------------
  31796. /**
  31797. * Store startX, startY and startOffset for mouse operations
  31798. *
  31799. * @param {Event} event The event that occurred
  31800. */
  31801. Graph3d.prototype._storeMousePosition = function(event) {
  31802. // get mouse position (different code for IE and all other browsers)
  31803. this.startMouseX = getMouseX(event);
  31804. this.startMouseY = getMouseY(event);
  31805. this._startCameraOffset = this.camera.getOffset();
  31806. };
  31807. /**
  31808. * Start a moving operation inside the provided parent element
  31809. * @param {Event} event The event that occurred (required for
  31810. * retrieving the mouse position)
  31811. */
  31812. Graph3d.prototype._onMouseDown = function(event) {
  31813. event = event || window.event;
  31814. // check if mouse is still down (may be up when focus is lost for example
  31815. // in an iframe)
  31816. if (this.leftButtonDown) {
  31817. this._onMouseUp(event);
  31818. }
  31819. // only react on left mouse button down
  31820. this.leftButtonDown = event.which ? event.which === 1 : event.button === 1;
  31821. if (!this.leftButtonDown && !this.touchDown) return;
  31822. this._storeMousePosition(event);
  31823. this.startStart = new Date(this.start);
  31824. this.startEnd = new Date(this.end);
  31825. this.startArmRotation = this.camera.getArmRotation();
  31826. this.frame.style.cursor = 'move';
  31827. // add event listeners to handle moving the contents
  31828. // we store the function onmousemove and onmouseup in the graph, so we can
  31829. // remove the eventlisteners lateron in the function mouseUp()
  31830. var me = this;
  31831. this.onmousemove = function(event) {
  31832. me._onMouseMove(event);
  31833. };
  31834. this.onmouseup = function(event) {
  31835. me._onMouseUp(event);
  31836. };
  31837. util.addEventListener(document, 'mousemove', me.onmousemove);
  31838. util.addEventListener(document, 'mouseup', me.onmouseup);
  31839. util.preventDefault(event);
  31840. };
  31841. /**
  31842. * Perform moving operating.
  31843. * This function activated from within the funcion Graph.mouseDown().
  31844. * @param {Event} event Well, eehh, the event
  31845. */
  31846. Graph3d.prototype._onMouseMove = function(event) {
  31847. this.moving = true;
  31848. event = event || window.event;
  31849. // calculate change in mouse position
  31850. var diffX = parseFloat(getMouseX(event)) - this.startMouseX;
  31851. var diffY = parseFloat(getMouseY(event)) - this.startMouseY;
  31852. // move with ctrl or rotate by other
  31853. if (event && event.ctrlKey === true) {
  31854. // calculate change in mouse position
  31855. var scaleX = this.frame.clientWidth * 0.5;
  31856. var scaleY = this.frame.clientHeight * 0.5;
  31857. var offXNew = (this._startCameraOffset.x || 0) - diffX / scaleX * this.camera.armLength * 0.8;
  31858. var offYNew = (this._startCameraOffset.y || 0) + diffY / scaleY * this.camera.armLength * 0.8;
  31859. this.camera.setOffset(offXNew, offYNew);
  31860. this._storeMousePosition(event);
  31861. } else {
  31862. var horizontalNew = this.startArmRotation.horizontal + diffX / 200;
  31863. var verticalNew = this.startArmRotation.vertical + diffY / 200;
  31864. var snapAngle = 4; // degrees
  31865. var snapValue = Math.sin(snapAngle / 360 * 2 * Math.PI);
  31866. // snap horizontally to nice angles at 0pi, 0.5pi, 1pi, 1.5pi, etc...
  31867. // the -0.001 is to take care that the vertical axis is always drawn at the left front corner
  31868. if (Math.abs(Math.sin(horizontalNew)) < snapValue) {
  31869. horizontalNew = Math.round(horizontalNew / Math.PI) * Math.PI - 0.001;
  31870. }
  31871. if (Math.abs(Math.cos(horizontalNew)) < snapValue) {
  31872. horizontalNew = (Math.round(horizontalNew / Math.PI - 0.5) + 0.5) * Math.PI - 0.001;
  31873. }
  31874. // snap vertically to nice angles
  31875. if (Math.abs(Math.sin(verticalNew)) < snapValue) {
  31876. verticalNew = Math.round(verticalNew / Math.PI) * Math.PI;
  31877. }
  31878. if (Math.abs(Math.cos(verticalNew)) < snapValue) {
  31879. verticalNew = (Math.round(verticalNew / Math.PI - 0.5) + 0.5) * Math.PI;
  31880. }
  31881. this.camera.setArmRotation(horizontalNew, verticalNew);
  31882. }
  31883. this.redraw();
  31884. // fire a cameraPositionChange event
  31885. var parameters = this.getCameraPosition();
  31886. this.emit('cameraPositionChange', parameters);
  31887. util.preventDefault(event);
  31888. };
  31889. /**
  31890. * Stop moving operating.
  31891. * This function activated from within the funcion Graph.mouseDown().
  31892. * @param {Event} event The event
  31893. */
  31894. Graph3d.prototype._onMouseUp = function(event) {
  31895. this.frame.style.cursor = 'auto';
  31896. this.leftButtonDown = false;
  31897. // remove event listeners here
  31898. util.removeEventListener(document, 'mousemove', this.onmousemove);
  31899. util.removeEventListener(document, 'mouseup', this.onmouseup);
  31900. util.preventDefault(event);
  31901. };
  31902. /**
  31903. * @param {Event} event The event
  31904. */
  31905. Graph3d.prototype._onClick = function(event) {
  31906. if (!this.onclick_callback) return;
  31907. if (!this.moving) {
  31908. var boundingRect = this.frame.getBoundingClientRect();
  31909. var mouseX = getMouseX(event) - boundingRect.left;
  31910. var mouseY = getMouseY(event) - boundingRect.top;
  31911. var dataPoint = this._dataPointFromXY(mouseX, mouseY);
  31912. if (dataPoint) this.onclick_callback(dataPoint.point.data);
  31913. } else {
  31914. // disable onclick callback, if it came immediately after rotate/pan
  31915. this.moving = false;
  31916. }
  31917. util.preventDefault(event);
  31918. };
  31919. /**
  31920. * After having moved the mouse, a tooltip should pop up when the mouse is resting on a data point
  31921. * @param {Event} event A mouse move event
  31922. */
  31923. Graph3d.prototype._onTooltip = function(event) {
  31924. var delay = 300; // ms
  31925. var boundingRect = this.frame.getBoundingClientRect();
  31926. var mouseX = getMouseX(event) - boundingRect.left;
  31927. var mouseY = getMouseY(event) - boundingRect.top;
  31928. if (!this.showTooltip) {
  31929. return;
  31930. }
  31931. if (this.tooltipTimeout) {
  31932. clearTimeout(this.tooltipTimeout);
  31933. }
  31934. // (delayed) display of a tooltip only if no mouse button is down
  31935. if (this.leftButtonDown) {
  31936. this._hideTooltip();
  31937. return;
  31938. }
  31939. if (this.tooltip && this.tooltip.dataPoint) {
  31940. // tooltip is currently visible
  31941. var dataPoint = this._dataPointFromXY(mouseX, mouseY);
  31942. if (dataPoint !== this.tooltip.dataPoint) {
  31943. // datapoint changed
  31944. if (dataPoint) {
  31945. this._showTooltip(dataPoint);
  31946. } else {
  31947. this._hideTooltip();
  31948. }
  31949. }
  31950. } else {
  31951. // tooltip is currently not visible
  31952. var me = this;
  31953. this.tooltipTimeout = setTimeout(function() {
  31954. me.tooltipTimeout = null;
  31955. // show a tooltip if we have a data point
  31956. var dataPoint = me._dataPointFromXY(mouseX, mouseY);
  31957. if (dataPoint) {
  31958. me._showTooltip(dataPoint);
  31959. }
  31960. }, delay);
  31961. }
  31962. };
  31963. /**
  31964. * Event handler for touchstart event on mobile devices
  31965. * @param {Event} event The event
  31966. */
  31967. Graph3d.prototype._onTouchStart = function(event) {
  31968. this.touchDown = true;
  31969. var me = this;
  31970. this.ontouchmove = function(event) {
  31971. me._onTouchMove(event);
  31972. };
  31973. this.ontouchend = function(event) {
  31974. me._onTouchEnd(event);
  31975. };
  31976. util.addEventListener(document, 'touchmove', me.ontouchmove);
  31977. util.addEventListener(document, 'touchend', me.ontouchend);
  31978. this._onMouseDown(event);
  31979. };
  31980. /**
  31981. * Event handler for touchmove event on mobile devices
  31982. * @param {Event} event The event
  31983. */
  31984. Graph3d.prototype._onTouchMove = function(event) {
  31985. this._onMouseMove(event);
  31986. };
  31987. /**
  31988. * Event handler for touchend event on mobile devices
  31989. * @param {Event} event The event
  31990. */
  31991. Graph3d.prototype._onTouchEnd = function(event) {
  31992. this.touchDown = false;
  31993. util.removeEventListener(document, 'touchmove', this.ontouchmove);
  31994. util.removeEventListener(document, 'touchend', this.ontouchend);
  31995. this._onMouseUp(event);
  31996. };
  31997. /**
  31998. * Event handler for mouse wheel event, used to zoom the graph
  31999. * Code from http://adomas.org/javascript-mouse-wheel/
  32000. * @param {Event} event The event
  32001. */
  32002. Graph3d.prototype._onWheel = function(event) {
  32003. if (!event) /* For IE. */
  32004. event = window.event;
  32005. // retrieve delta
  32006. var delta = 0;
  32007. if (event.wheelDelta) {
  32008. /* IE/Opera. */
  32009. delta = event.wheelDelta / 120;
  32010. } else if (event.detail) {
  32011. /* Mozilla case. */
  32012. // In Mozilla, sign of delta is different than in IE.
  32013. // Also, delta is multiple of 3.
  32014. delta = -event.detail / 3;
  32015. }
  32016. // If delta is nonzero, handle it.
  32017. // Basically, delta is now positive if wheel was scrolled up,
  32018. // and negative, if wheel was scrolled down.
  32019. if (delta) {
  32020. var oldLength = this.camera.getArmLength();
  32021. var newLength = oldLength * (1 - delta / 10);
  32022. this.camera.setArmLength(newLength);
  32023. this.redraw();
  32024. this._hideTooltip();
  32025. }
  32026. // fire a cameraPositionChange event
  32027. var parameters = this.getCameraPosition();
  32028. this.emit('cameraPositionChange', parameters);
  32029. // Prevent default actions caused by mouse wheel.
  32030. // That might be ugly, but we handle scrolls somehow
  32031. // anyway, so don't bother here..
  32032. util.preventDefault(event);
  32033. };
  32034. /**
  32035. * Test whether a point lies inside given 2D triangle
  32036. *
  32037. * @param {vis.Point2d} point
  32038. * @param {vis.Point2d[]} triangle
  32039. * @returns {boolean} true if given point lies inside or on the edge of the
  32040. * triangle, false otherwise
  32041. * @private
  32042. */
  32043. Graph3d.prototype._insideTriangle = function(point, triangle) {
  32044. var a = triangle[0],
  32045. b = triangle[1],
  32046. c = triangle[2];
  32047. /**
  32048. *
  32049. * @param {number} x
  32050. * @returns {number}
  32051. */
  32052. function sign(x) {
  32053. return x > 0 ? 1 : x < 0 ? -1 : 0;
  32054. }
  32055. var as = sign((b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x));
  32056. var bs = sign((c.x - b.x) * (point.y - b.y) - (c.y - b.y) * (point.x - b.x));
  32057. var cs = sign((a.x - c.x) * (point.y - c.y) - (a.y - c.y) * (point.x - c.x));
  32058. // each of the three signs must be either equal to each other or zero
  32059. return (as == 0 || bs == 0 || as == bs) && (bs == 0 || cs == 0 || bs == cs) && (as == 0 || cs == 0 || as == cs);
  32060. };
  32061. /**
  32062. * Find a data point close to given screen position (x, y)
  32063. *
  32064. * @param {number} x
  32065. * @param {number} y
  32066. * @returns {Object | null} The closest data point or null if not close to any
  32067. * data point
  32068. * @private
  32069. */
  32070. Graph3d.prototype._dataPointFromXY = function(x, y) {
  32071. var i,
  32072. distMax = 100,
  32073. // px
  32074. dataPoint = null,
  32075. closestDataPoint = null,
  32076. closestDist = null,
  32077. center = new Point2d(x, y);
  32078. if (this.style === Graph3d.STYLE.BAR || this.style === Graph3d.STYLE.BARCOLOR || this.style === Graph3d.STYLE.BARSIZE) {
  32079. // the data points are ordered from far away to closest
  32080. for (i = this.dataPoints.length - 1; i >= 0; i--) {
  32081. dataPoint = this.dataPoints[i];
  32082. var surfaces = dataPoint.surfaces;
  32083. if (surfaces) {
  32084. for (var s = surfaces.length - 1; s >= 0; s--) {
  32085. // split each surface in two triangles, and see if the center point is inside one of these
  32086. var surface = surfaces[s];
  32087. var corners = surface.corners;
  32088. var triangle1 = [corners[0].screen, corners[1].screen, corners[2].screen];
  32089. var triangle2 = [corners[2].screen, corners[3].screen, corners[0].screen];
  32090. if (this._insideTriangle(center, triangle1) || this._insideTriangle(center, triangle2)) {
  32091. // return immediately at the first hit
  32092. return dataPoint;
  32093. }
  32094. }
  32095. }
  32096. }
  32097. } else {
  32098. // find the closest data point, using distance to the center of the point on 2d screen
  32099. for (i = 0; i < this.dataPoints.length; i++) {
  32100. dataPoint = this.dataPoints[i];
  32101. var point = dataPoint.screen;
  32102. if (point) {
  32103. var distX = Math.abs(x - point.x);
  32104. var distY = Math.abs(y - point.y);
  32105. var dist = Math.sqrt(distX * distX + distY * distY);
  32106. if ((closestDist === null || dist < closestDist) && dist < distMax) {
  32107. closestDist = dist;
  32108. closestDataPoint = dataPoint;
  32109. }
  32110. }
  32111. }
  32112. }
  32113. return closestDataPoint;
  32114. };
  32115. /**
  32116. * Determine if the given style has bars
  32117. *
  32118. * @param {number} style the style to check
  32119. * @returns {boolean} true if bar style, false otherwise
  32120. */
  32121. Graph3d.prototype.hasBars = function(style) {
  32122. return style == Graph3d.STYLE.BAR || style == Graph3d.STYLE.BARCOLOR || style == Graph3d.STYLE.BARSIZE;
  32123. };
  32124. /**
  32125. * Display a tooltip for given data point
  32126. * @param {Object} dataPoint
  32127. * @private
  32128. */
  32129. Graph3d.prototype._showTooltip = function(dataPoint) {
  32130. var content, line, dot;
  32131. if (!this.tooltip) {
  32132. content = document.createElement('div');
  32133. (0, _assign2['default'])(content.style, {}, this.tooltipStyle.content);
  32134. content.style.position = 'absolute';
  32135. line = document.createElement('div');
  32136. (0, _assign2['default'])(line.style, {}, this.tooltipStyle.line);
  32137. line.style.position = 'absolute';
  32138. dot = document.createElement('div');
  32139. (0, _assign2['default'])(dot.style, {}, this.tooltipStyle.dot);
  32140. dot.style.position = 'absolute';
  32141. this.tooltip = {
  32142. dataPoint: null,
  32143. dom: {
  32144. content: content,
  32145. line: line,
  32146. dot: dot
  32147. }
  32148. };
  32149. } else {
  32150. content = this.tooltip.dom.content;
  32151. line = this.tooltip.dom.line;
  32152. dot = this.tooltip.dom.dot;
  32153. }
  32154. this._hideTooltip();
  32155. this.tooltip.dataPoint = dataPoint;
  32156. if (typeof this.showTooltip === 'function') {
  32157. content.innerHTML = this.showTooltip(dataPoint.point);
  32158. } else {
  32159. content.innerHTML = '<table>' + '<tr><td>' + this.xLabel + ':</td><td>' + dataPoint.point.x + '</td></tr>' + '<tr><td>' + this.yLabel + ':</td><td>' + dataPoint.point.y + '</td></tr>' + '<tr><td>' + this.zLabel + ':</td><td>' + dataPoint.point.z + '</td></tr>' + '</table>';
  32160. }
  32161. content.style.left = '0';
  32162. content.style.top = '0';
  32163. this.frame.appendChild(content);
  32164. this.frame.appendChild(line);
  32165. this.frame.appendChild(dot);
  32166. // calculate sizes
  32167. var contentWidth = content.offsetWidth;
  32168. var contentHeight = content.offsetHeight;
  32169. var lineHeight = line.offsetHeight;
  32170. var dotWidth = dot.offsetWidth;
  32171. var dotHeight = dot.offsetHeight;
  32172. var left = dataPoint.screen.x - contentWidth / 2;
  32173. left = Math.min(Math.max(left, 10), this.frame.clientWidth - 10 - contentWidth);
  32174. line.style.left = dataPoint.screen.x + 'px';
  32175. line.style.top = dataPoint.screen.y - lineHeight + 'px';
  32176. content.style.left = left + 'px';
  32177. content.style.top = dataPoint.screen.y - lineHeight - contentHeight + 'px';
  32178. dot.style.left = dataPoint.screen.x - dotWidth / 2 + 'px';
  32179. dot.style.top = dataPoint.screen.y - dotHeight / 2 + 'px';
  32180. };
  32181. /**
  32182. * Hide the tooltip when displayed
  32183. * @private
  32184. */
  32185. Graph3d.prototype._hideTooltip = function() {
  32186. if (this.tooltip) {
  32187. this.tooltip.dataPoint = null;
  32188. for (var prop in this.tooltip.dom) {
  32189. if (this.tooltip.dom.hasOwnProperty(prop)) {
  32190. var elem = this.tooltip.dom[prop];
  32191. if (elem && elem.parentNode) {
  32192. elem.parentNode.removeChild(elem);
  32193. }
  32194. }
  32195. }
  32196. }
  32197. };
  32198. /**--------------------------------------------------------------------------**/
  32199. /**
  32200. * Get the horizontal mouse position from a mouse event
  32201. *
  32202. * @param {Event} event
  32203. * @returns {number} mouse x
  32204. */
  32205. function getMouseX(event) {
  32206. if ('clientX' in event) return event.clientX;
  32207. return event.targetTouches[0] && event.targetTouches[0].clientX || 0;
  32208. }
  32209. /**
  32210. * Get the vertical mouse position from a mouse event
  32211. *
  32212. * @param {Event} event
  32213. * @returns {number} mouse y
  32214. */
  32215. function getMouseY(event) {
  32216. if ('clientY' in event) return event.clientY;
  32217. return event.targetTouches[0] && event.targetTouches[0].clientY || 0;
  32218. }
  32219. // -----------------------------------------------------------------------------
  32220. // Public methods for specific settings
  32221. // -----------------------------------------------------------------------------
  32222. /**
  32223. * Set the rotation and distance of the camera
  32224. *
  32225. * @param {Object} pos An object with the camera position
  32226. * @param {number} [pos.horizontal] The horizontal rotation, between 0 and 2*PI.
  32227. * Optional, can be left undefined.
  32228. * @param {number} [pos.vertical] The vertical rotation, between 0 and 0.5*PI.
  32229. * if vertical=0.5*PI, the graph is shown from
  32230. * the top. Optional, can be left undefined.
  32231. * @param {number} [pos.distance] The (normalized) distance of the camera to the
  32232. * center of the graph, a value between 0.71 and
  32233. * 5.0. Optional, can be left undefined.
  32234. */
  32235. Graph3d.prototype.setCameraPosition = function(pos) {
  32236. Settings.setCameraPosition(pos, this);
  32237. this.redraw();
  32238. };
  32239. /**
  32240. * Set a new size for the graph
  32241. *
  32242. * @param {string} width Width in pixels or percentage (for example '800px'
  32243. * or '50%')
  32244. * @param {string} height Height in pixels or percentage (for example '400px'
  32245. * or '30%')
  32246. */
  32247. Graph3d.prototype.setSize = function(width, height) {
  32248. this._setSize(width, height);
  32249. this.redraw();
  32250. };
  32251. // -----------------------------------------------------------------------------
  32252. // End public methods for specific settings
  32253. // -----------------------------------------------------------------------------
  32254. module.exports = Graph3d;
  32255. /***/
  32256. }),
  32257. /* 162 */
  32258. /***/
  32259. (function(module, exports, __webpack_require__) {
  32260. __webpack_require__(163);
  32261. module.exports = __webpack_require__(7).Object.assign;
  32262. /***/
  32263. }),
  32264. /* 163 */
  32265. /***/
  32266. (function(module, exports, __webpack_require__) {
  32267. // 19.1.3.1 Object.assign(target, source)
  32268. var $export = __webpack_require__(17);
  32269. $export($export.S + $export.F, 'Object', { assign: __webpack_require__(164) });
  32270. /***/
  32271. }),
  32272. /* 164 */
  32273. /***/
  32274. (function(module, exports, __webpack_require__) {
  32275. "use strict";
  32276. // 19.1.2.1 Object.assign(target, source, ...)
  32277. var getKeys = __webpack_require__(33);
  32278. var gOPS = __webpack_require__(63);
  32279. var pIE = __webpack_require__(42);
  32280. var toObject = __webpack_require__(41);
  32281. var IObject = __webpack_require__(78);
  32282. var $assign = Object.assign;
  32283. // should work with symbols and should have deterministic property order (V8 bug)
  32284. module.exports = !$assign || __webpack_require__(28)(function() {
  32285. var A = {};
  32286. var B = {};
  32287. // eslint-disable-next-line no-undef
  32288. var S = Symbol();
  32289. var K = 'abcdefghijklmnopqrst';
  32290. A[S] = 7;
  32291. K.split('').forEach(function(k) { B[k] = k; });
  32292. return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K;
  32293. }) ? function assign(target, source) { // eslint-disable-line no-unused-vars
  32294. var T = toObject(target);
  32295. var aLen = arguments.length;
  32296. var index = 1;
  32297. var getSymbols = gOPS.f;
  32298. var isEnum = pIE.f;
  32299. while (aLen > index) {
  32300. var S = IObject(arguments[index++]);
  32301. var keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S);
  32302. var length = keys.length;
  32303. var j = 0;
  32304. var key;
  32305. while (length > j)
  32306. if (isEnum.call(S, key = keys[j++])) T[key] = S[key];
  32307. }
  32308. return T;
  32309. } : $assign;
  32310. /***/
  32311. }),
  32312. /* 165 */
  32313. /***/
  32314. (function(module, exports, __webpack_require__) {
  32315. module.exports = { "default": __webpack_require__(166), __esModule: true };
  32316. /***/
  32317. }),
  32318. /* 166 */
  32319. /***/
  32320. (function(module, exports, __webpack_require__) {
  32321. __webpack_require__(167);
  32322. module.exports = __webpack_require__(7).Math.sign;
  32323. /***/
  32324. }),
  32325. /* 167 */
  32326. /***/
  32327. (function(module, exports, __webpack_require__) {
  32328. // 20.2.2.28 Math.sign(x)
  32329. var $export = __webpack_require__(17);
  32330. $export($export.S, 'Math', { sign: __webpack_require__(168) });
  32331. /***/
  32332. }),
  32333. /* 168 */
  32334. /***/
  32335. (function(module, exports) {
  32336. // 20.2.2.28 Math.sign(x)
  32337. module.exports = Math.sign || function sign(x) {
  32338. // eslint-disable-next-line no-self-compare
  32339. return (x = +x) == 0 || x != x ? x : x < 0 ? -1 : 1;
  32340. };
  32341. /***/
  32342. }),
  32343. /* 169 */
  32344. /***/
  32345. (function(module, exports, __webpack_require__) {
  32346. module.exports = { "default": __webpack_require__(170), __esModule: true };
  32347. /***/
  32348. }),
  32349. /* 170 */
  32350. /***/
  32351. (function(module, exports, __webpack_require__) {
  32352. __webpack_require__(171);
  32353. var $Object = __webpack_require__(7).Object;
  32354. module.exports = function defineProperty(it, key, desc) {
  32355. return $Object.defineProperty(it, key, desc);
  32356. };
  32357. /***/
  32358. }),
  32359. /* 171 */
  32360. /***/
  32361. (function(module, exports, __webpack_require__) {
  32362. var $export = __webpack_require__(17);
  32363. // 19.1.2.4 / 15.2.3.6 Object.defineProperty(O, P, Attributes)
  32364. $export($export.S + $export.F * !__webpack_require__(21), 'Object', { defineProperty: __webpack_require__(20).f });
  32365. /***/
  32366. }),
  32367. /* 172 */
  32368. /***/
  32369. (function(module, exports, __webpack_require__) {
  32370. "use strict";
  32371. Object.defineProperty(exports, "__esModule", {
  32372. value: true
  32373. });
  32374. /**
  32375. * This object contains all possible options. It will check if the types are correct, if required if the option is one
  32376. * of the allowed values.
  32377. *
  32378. * __any__ means that the name of the property does not matter.
  32379. * __type__ is a required field for all objects and contains the allowed types of all objects
  32380. */
  32381. var string = 'string';
  32382. var bool = 'boolean';
  32383. var number = 'number';
  32384. var object = 'object'; // should only be in a __type__ property
  32385. // Following not used here, but useful for reference
  32386. //let array = 'array';
  32387. //let dom = 'dom';
  32388. //let any = 'any';
  32389. var colorOptions = {
  32390. fill: { string: string },
  32391. stroke: { string: string },
  32392. strokeWidth: { number: number },
  32393. __type__: { string: string, object: object, 'undefined': 'undefined' }
  32394. };
  32395. /**
  32396. * Order attempted to be alphabetical.
  32397. * - x/y/z-prefixes ignored in sorting
  32398. * - __type__ always at end
  32399. * - globals at end
  32400. */
  32401. var allOptions = {
  32402. animationAutoStart: { boolean: bool, 'undefined': 'undefined' },
  32403. animationInterval: { number: number },
  32404. animationPreload: { boolean: bool },
  32405. axisColor: { string: string },
  32406. backgroundColor: colorOptions,
  32407. xBarWidth: { number: number, 'undefined': 'undefined' },
  32408. yBarWidth: { number: number, 'undefined': 'undefined' },
  32409. cameraPosition: {
  32410. distance: { number: number },
  32411. horizontal: { number: number },
  32412. vertical: { number: number },
  32413. __type__: { object: object }
  32414. },
  32415. xCenter: { string: string },
  32416. yCenter: { string: string },
  32417. dataColor: colorOptions,
  32418. dotSizeMinFraction: { number: number },
  32419. dotSizeMaxFraction: { number: number },
  32420. dotSizeRatio: { number: number },
  32421. filterLabel: { string: string },
  32422. gridColor: { string: string },
  32423. onclick: { 'function': 'function' },
  32424. keepAspectRatio: { boolean: bool },
  32425. xLabel: { string: string },
  32426. yLabel: { string: string },
  32427. zLabel: { string: string },
  32428. legendLabel: { string: string },
  32429. xMin: { number: number, 'undefined': 'undefined' },
  32430. yMin: { number: number, 'undefined': 'undefined' },
  32431. zMin: { number: number, 'undefined': 'undefined' },
  32432. xMax: { number: number, 'undefined': 'undefined' },
  32433. yMax: { number: number, 'undefined': 'undefined' },
  32434. zMax: { number: number, 'undefined': 'undefined' },
  32435. showAnimationControls: { boolean: bool, 'undefined': 'undefined' },
  32436. showGrid: { boolean: bool },
  32437. showLegend: { boolean: bool, 'undefined': 'undefined' },
  32438. showPerspective: { boolean: bool },
  32439. showShadow: { boolean: bool },
  32440. showXAxis: { boolean: bool },
  32441. showYAxis: { boolean: bool },
  32442. showZAxis: { boolean: bool },
  32443. xStep: { number: number, 'undefined': 'undefined' },
  32444. yStep: { number: number, 'undefined': 'undefined' },
  32445. zStep: { number: number, 'undefined': 'undefined' },
  32446. style: {
  32447. number: number, // TODO: either Graph3d.DEFAULT has string, or number allowed in documentation
  32448. string: ['bar', 'bar-color', 'bar-size', 'dot', 'dot-line', 'dot-color', 'dot-size', 'line', 'grid', 'surface']
  32449. },
  32450. tooltip: { boolean: bool, 'function': 'function' },
  32451. tooltipStyle: {
  32452. content: {
  32453. color: { string: string },
  32454. background: { string: string },
  32455. border: { string: string },
  32456. borderRadius: { string: string },
  32457. boxShadow: { string: string },
  32458. padding: { string: string },
  32459. __type__: { object: object }
  32460. },
  32461. line: {
  32462. borderLeft: { string: string },
  32463. height: { string: string },
  32464. width: { string: string },
  32465. __type__: { object: object }
  32466. },
  32467. dot: {
  32468. border: { string: string },
  32469. borderRadius: { string: string },
  32470. height: { string: string },
  32471. width: { string: string },
  32472. __type__: { object: object }
  32473. },
  32474. __type__: { object: object }
  32475. },
  32476. xValueLabel: { 'function': 'function' },
  32477. yValueLabel: { 'function': 'function' },
  32478. zValueLabel: { 'function': 'function' },
  32479. valueMax: { number: number, 'undefined': 'undefined' },
  32480. valueMin: { number: number, 'undefined': 'undefined' },
  32481. verticalRatio: { number: number },
  32482. //globals :
  32483. height: { string: string },
  32484. width: { string: string },
  32485. __type__: { object: object }
  32486. };
  32487. exports.allOptions = allOptions;
  32488. /***/
  32489. }),
  32490. /* 173 */
  32491. /***/
  32492. (function(module, exports, __webpack_require__) {
  32493. "use strict";
  32494. var DataSet = __webpack_require__(11);
  32495. var DataView = __webpack_require__(12);
  32496. var Range = __webpack_require__(174);
  32497. var Filter = __webpack_require__(96);
  32498. var Settings = __webpack_require__(94);
  32499. var Point3d = __webpack_require__(34);
  32500. /**
  32501. * Creates a container for all data of one specific 3D-graph.
  32502. *
  32503. * On construction, the container is totally empty; the data
  32504. * needs to be initialized with method initializeData().
  32505. * Failure to do so will result in the following exception begin thrown
  32506. * on instantiation of Graph3D:
  32507. *
  32508. * Error: Array, DataSet, or DataView expected
  32509. *
  32510. * @constructor DataGroup
  32511. */
  32512. function DataGroup() {
  32513. this.dataTable = null; // The original data table
  32514. }
  32515. /**
  32516. * Initializes the instance from the passed data.
  32517. *
  32518. * Calculates minimum and maximum values and column index values.
  32519. *
  32520. * The graph3d instance is used internally to access the settings for
  32521. * the given instance.
  32522. * TODO: Pass settings only instead.
  32523. *
  32524. * @param {vis.Graph3d} graph3d Reference to the calling Graph3D instance.
  32525. * @param {Array | DataSet | DataView} rawData The data containing the items for
  32526. * the Graph.
  32527. * @param {number} style Style Number
  32528. * @returns {Array.<Object>}
  32529. */
  32530. DataGroup.prototype.initializeData = function(graph3d, rawData, style) {
  32531. if (rawData === undefined) return;
  32532. if (Array.isArray(rawData)) {
  32533. rawData = new DataSet(rawData);
  32534. }
  32535. var data;
  32536. if (rawData instanceof DataSet || rawData instanceof DataView) {
  32537. data = rawData.get();
  32538. } else {
  32539. throw new Error('Array, DataSet, or DataView expected');
  32540. }
  32541. if (data.length == 0) return;
  32542. this.style = style;
  32543. // unsubscribe from the dataTable
  32544. if (this.dataSet) {
  32545. this.dataSet.off('*', this._onChange);
  32546. }
  32547. this.dataSet = rawData;
  32548. this.dataTable = data;
  32549. // subscribe to changes in the dataset
  32550. var me = this;
  32551. this._onChange = function() {
  32552. graph3d.setData(me.dataSet);
  32553. };
  32554. this.dataSet.on('*', this._onChange);
  32555. // determine the location of x,y,z,value,filter columns
  32556. this.colX = 'x';
  32557. this.colY = 'y';
  32558. this.colZ = 'z';
  32559. var withBars = graph3d.hasBars(style);
  32560. // determine barWidth from data
  32561. if (withBars) {
  32562. if (graph3d.defaultXBarWidth !== undefined) {
  32563. this.xBarWidth = graph3d.defaultXBarWidth;
  32564. } else {
  32565. this.xBarWidth = this.getSmallestDifference(data, this.colX) || 1;
  32566. }
  32567. if (graph3d.defaultYBarWidth !== undefined) {
  32568. this.yBarWidth = graph3d.defaultYBarWidth;
  32569. } else {
  32570. this.yBarWidth = this.getSmallestDifference(data, this.colY) || 1;
  32571. }
  32572. }
  32573. // calculate minima and maxima
  32574. this._initializeRange(data, this.colX, graph3d, withBars);
  32575. this._initializeRange(data, this.colY, graph3d, withBars);
  32576. this._initializeRange(data, this.colZ, graph3d, false);
  32577. if (data[0].hasOwnProperty('style')) {
  32578. this.colValue = 'style';
  32579. var valueRange = this.getColumnRange(data, this.colValue);
  32580. this._setRangeDefaults(valueRange, graph3d.defaultValueMin, graph3d.defaultValueMax);
  32581. this.valueRange = valueRange;
  32582. }
  32583. // Initialize data filter if a filter column is provided
  32584. var table = this.getDataTable();
  32585. if (table[0].hasOwnProperty('filter')) {
  32586. if (this.dataFilter === undefined) {
  32587. this.dataFilter = new Filter(this, 'filter', graph3d);
  32588. this.dataFilter.setOnLoadCallback(function() {
  32589. graph3d.redraw();
  32590. });
  32591. }
  32592. }
  32593. var dataPoints;
  32594. if (this.dataFilter) {
  32595. // apply filtering
  32596. dataPoints = this.dataFilter._getDataPoints();
  32597. } else {
  32598. // no filtering. load all data
  32599. dataPoints = this._getDataPoints(this.getDataTable());
  32600. }
  32601. return dataPoints;
  32602. };
  32603. /**
  32604. * Collect the range settings for the given data column.
  32605. *
  32606. * This internal method is intended to make the range
  32607. * initalization more generic.
  32608. *
  32609. * TODO: if/when combined settings per axis defined, get rid of this.
  32610. *
  32611. * @private
  32612. *
  32613. * @param {'x'|'y'|'z'} column The data column to process
  32614. * @param {vis.Graph3d} graph3d Reference to the calling Graph3D instance;
  32615. * required for access to settings
  32616. * @returns {Object}
  32617. */
  32618. DataGroup.prototype._collectRangeSettings = function(column, graph3d) {
  32619. var index = ['x', 'y', 'z'].indexOf(column);
  32620. if (index == -1) {
  32621. throw new Error('Column \'' + column + '\' invalid');
  32622. }
  32623. var upper = column.toUpperCase();
  32624. return {
  32625. barWidth: this[column + 'BarWidth'],
  32626. min: graph3d['default' + upper + 'Min'],
  32627. max: graph3d['default' + upper + 'Max'],
  32628. step: graph3d['default' + upper + 'Step'],
  32629. range_label: column + 'Range', // Name of instance field to write to
  32630. step_label: column + 'Step' // Name of instance field to write to
  32631. };
  32632. };
  32633. /**
  32634. * Initializes the settings per given column.
  32635. *
  32636. * TODO: if/when combined settings per axis defined, rewrite this.
  32637. *
  32638. * @private
  32639. *
  32640. * @param {DataSet | DataView} data The data containing the items for the Graph
  32641. * @param {'x'|'y'|'z'} column The data column to process
  32642. * @param {vis.Graph3d} graph3d Reference to the calling Graph3D instance;
  32643. * required for access to settings
  32644. * @param {boolean} withBars True if initializing for bar graph
  32645. */
  32646. DataGroup.prototype._initializeRange = function(data, column, graph3d, withBars) {
  32647. var NUMSTEPS = 5;
  32648. var settings = this._collectRangeSettings(column, graph3d);
  32649. var range = this.getColumnRange(data, column);
  32650. if (withBars && column != 'z') {
  32651. // Safeguard for 'z'; it doesn't have a bar width
  32652. range.expand(settings.barWidth / 2);
  32653. }
  32654. this._setRangeDefaults(range, settings.min, settings.max);
  32655. this[settings.range_label] = range;
  32656. this[settings.step_label] = settings.step !== undefined ? settings.step : range.range() / NUMSTEPS;
  32657. };
  32658. /**
  32659. * Creates a list with all the different values in the data for the given column.
  32660. *
  32661. * If no data passed, use the internal data of this instance.
  32662. *
  32663. * @param {'x'|'y'|'z'} column The data column to process
  32664. * @param {DataSet|DataView|undefined} data The data containing the items for the Graph
  32665. *
  32666. * @returns {Array} All distinct values in the given column data, sorted ascending.
  32667. */
  32668. DataGroup.prototype.getDistinctValues = function(column, data) {
  32669. if (data === undefined) {
  32670. data = this.dataTable;
  32671. }
  32672. var values = [];
  32673. for (var i = 0; i < data.length; i++) {
  32674. var value = data[i][column] || 0;
  32675. if (values.indexOf(value) === -1) {
  32676. values.push(value);
  32677. }
  32678. }
  32679. return values.sort(function(a, b) {
  32680. return a - b;
  32681. });
  32682. };
  32683. /**
  32684. * Determine the smallest difference between the values for given
  32685. * column in the passed data set.
  32686. *
  32687. * @param {DataSet|DataView|undefined} data The data containing the items for the Graph
  32688. * @param {'x'|'y'|'z'} column The data column to process
  32689. *
  32690. * @returns {number|null} Smallest difference value or
  32691. * null, if it can't be determined.
  32692. */
  32693. DataGroup.prototype.getSmallestDifference = function(data, column) {
  32694. var values = this.getDistinctValues(data, column);
  32695. // Get all the distinct diffs
  32696. // Array values is assumed to be sorted here
  32697. var smallest_diff = null;
  32698. for (var i = 1; i < values.length; i++) {
  32699. var diff = values[i] - values[i - 1];
  32700. if (smallest_diff == null || smallest_diff > diff) {
  32701. smallest_diff = diff;
  32702. }
  32703. }
  32704. return smallest_diff;
  32705. };
  32706. /**
  32707. * Get the absolute min/max values for the passed data column.
  32708. *
  32709. * @param {DataSet|DataView|undefined} data The data containing the items for the Graph
  32710. * @param {'x'|'y'|'z'} column The data column to process
  32711. *
  32712. * @returns {Range} A Range instance with min/max members properly set.
  32713. */
  32714. DataGroup.prototype.getColumnRange = function(data, column) {
  32715. var range = new Range();
  32716. // Adjust the range so that it covers all values in the passed data elements.
  32717. for (var i = 0; i < data.length; i++) {
  32718. var item = data[i][column];
  32719. range.adjust(item);
  32720. }
  32721. return range;
  32722. };
  32723. /**
  32724. * Determines the number of rows in the current data.
  32725. *
  32726. * @returns {number}
  32727. */
  32728. DataGroup.prototype.getNumberOfRows = function() {
  32729. return this.dataTable.length;
  32730. };
  32731. /**
  32732. * Set default values for range
  32733. *
  32734. * The default values override the range values, if defined.
  32735. *
  32736. * Because it's possible that only defaultMin or defaultMax is set, it's better
  32737. * to pass in a range already set with the min/max set from the data. Otherwise,
  32738. * it's quite hard to process the min/max properly.
  32739. *
  32740. * @param {vis.Range} range
  32741. * @param {number} [defaultMin=range.min]
  32742. * @param {number} [defaultMax=range.max]
  32743. * @private
  32744. */
  32745. DataGroup.prototype._setRangeDefaults = function(range, defaultMin, defaultMax) {
  32746. if (defaultMin !== undefined) {
  32747. range.min = defaultMin;
  32748. }
  32749. if (defaultMax !== undefined) {
  32750. range.max = defaultMax;
  32751. }
  32752. // This is the original way that the default min/max values were adjusted.
  32753. // TODO: Perhaps it's better if an error is thrown if the values do not agree.
  32754. // But this will change the behaviour.
  32755. if (range.max <= range.min) range.max = range.min + 1;
  32756. };
  32757. DataGroup.prototype.getDataTable = function() {
  32758. return this.dataTable;
  32759. };
  32760. DataGroup.prototype.getDataSet = function() {
  32761. return this.dataSet;
  32762. };
  32763. /**
  32764. * Return all data values as a list of Point3d objects
  32765. * @param {Array.<Object>} data
  32766. * @returns {Array.<Object>}
  32767. */
  32768. DataGroup.prototype.getDataPoints = function(data) {
  32769. var dataPoints = [];
  32770. for (var i = 0; i < data.length; i++) {
  32771. var point = new Point3d();
  32772. point.x = data[i][this.colX] || 0;
  32773. point.y = data[i][this.colY] || 0;
  32774. point.z = data[i][this.colZ] || 0;
  32775. point.data = data[i];
  32776. if (this.colValue !== undefined) {
  32777. point.value = data[i][this.colValue] || 0;
  32778. }
  32779. var obj = {};
  32780. obj.point = point;
  32781. obj.bottom = new Point3d(point.x, point.y, this.zRange.min);
  32782. obj.trans = undefined;
  32783. obj.screen = undefined;
  32784. dataPoints.push(obj);
  32785. }
  32786. return dataPoints;
  32787. };
  32788. /**
  32789. * Copy all values from the data table to a matrix.
  32790. *
  32791. * The provided values are supposed to form a grid of (x,y) positions.
  32792. * @param {Array.<Object>} data
  32793. * @returns {Array.<Object>}
  32794. * @private
  32795. */
  32796. DataGroup.prototype.initDataAsMatrix = function(data) {
  32797. // TODO: store the created matrix dataPoints in the filters instead of
  32798. // reloading each time.
  32799. var x, y, i, obj;
  32800. // create two lists with all present x and y values
  32801. var dataX = this.getDistinctValues(this.colX, data);
  32802. var dataY = this.getDistinctValues(this.colY, data);
  32803. var dataPoints = this.getDataPoints(data);
  32804. // create a grid, a 2d matrix, with all values.
  32805. var dataMatrix = []; // temporary data matrix
  32806. for (i = 0; i < dataPoints.length; i++) {
  32807. obj = dataPoints[i];
  32808. // TODO: implement Array().indexOf() for Internet Explorer
  32809. var xIndex = dataX.indexOf(obj.point.x);
  32810. var yIndex = dataY.indexOf(obj.point.y);
  32811. if (dataMatrix[xIndex] === undefined) {
  32812. dataMatrix[xIndex] = [];
  32813. }
  32814. dataMatrix[xIndex][yIndex] = obj;
  32815. }
  32816. // fill in the pointers to the neighbors.
  32817. for (x = 0; x < dataMatrix.length; x++) {
  32818. for (y = 0; y < dataMatrix[x].length; y++) {
  32819. if (dataMatrix[x][y]) {
  32820. dataMatrix[x][y].pointRight = x < dataMatrix.length - 1 ? dataMatrix[x + 1][y] : undefined;
  32821. dataMatrix[x][y].pointTop = y < dataMatrix[x].length - 1 ? dataMatrix[x][y + 1] : undefined;
  32822. dataMatrix[x][y].pointCross = x < dataMatrix.length - 1 && y < dataMatrix[x].length - 1 ? dataMatrix[x + 1][y + 1] : undefined;
  32823. }
  32824. }
  32825. }
  32826. return dataPoints;
  32827. };
  32828. /**
  32829. * Return common information, if present
  32830. *
  32831. * @returns {string}
  32832. */
  32833. DataGroup.prototype.getInfo = function() {
  32834. var dataFilter = this.dataFilter;
  32835. if (!dataFilter) return undefined;
  32836. return dataFilter.getLabel() + ': ' + dataFilter.getSelectedValue();
  32837. };
  32838. /**
  32839. * Reload the data
  32840. */
  32841. DataGroup.prototype.reload = function() {
  32842. if (this.dataTable) {
  32843. this.setData(this.dataTable);
  32844. }
  32845. };
  32846. /**
  32847. * Filter the data based on the current filter
  32848. *
  32849. * @param {Array} data
  32850. * @returns {Array} dataPoints Array with point objects which can be drawn on
  32851. * screen
  32852. */
  32853. DataGroup.prototype._getDataPoints = function(data) {
  32854. var dataPoints = [];
  32855. if (this.style === Settings.STYLE.GRID || this.style === Settings.STYLE.SURFACE) {
  32856. dataPoints = this.initDataAsMatrix(data);
  32857. } else {
  32858. // 'dot', 'dot-line', etc.
  32859. this._checkValueField(data);
  32860. dataPoints = this.getDataPoints(data);
  32861. if (this.style === Settings.STYLE.LINE) {
  32862. // Add next member points for line drawing
  32863. for (var i = 0; i < dataPoints.length; i++) {
  32864. if (i > 0) {
  32865. dataPoints[i - 1].pointNext = dataPoints[i];
  32866. }
  32867. }
  32868. }
  32869. }
  32870. return dataPoints;
  32871. };
  32872. /**
  32873. * Check if the state is consistent for the use of the value field.
  32874. *
  32875. * Throws if a problem is detected.
  32876. *
  32877. * @param {Array.<Object>} data
  32878. * @private
  32879. */
  32880. DataGroup.prototype._checkValueField = function(data) {
  32881. var hasValueField = this.style === Settings.STYLE.BARCOLOR || this.style === Settings.STYLE.BARSIZE || this.style === Settings.STYLE.DOTCOLOR || this.style === Settings.STYLE.DOTSIZE;
  32882. if (!hasValueField) {
  32883. return; // No need to check further
  32884. }
  32885. // Following field must be present for the current graph style
  32886. if (this.colValue === undefined) {
  32887. throw new Error('Expected data to have ' + ' field \'style\' ' + ' for graph style \'' + this.style + '\'');
  32888. }
  32889. // The data must also contain this field.
  32890. // Note that only first data element is checked.
  32891. if (data[0][this.colValue] === undefined) {
  32892. throw new Error('Expected data to have ' + ' field \'' + this.colValue + '\' ' + ' for graph style \'' + this.style + '\'');
  32893. }
  32894. };
  32895. module.exports = DataGroup;
  32896. /***/
  32897. }),
  32898. /* 174 */
  32899. /***/
  32900. (function(module, exports, __webpack_require__) {
  32901. "use strict";
  32902. /**
  32903. * @prototype Range
  32904. *
  32905. * Helper class to make working with related min and max values easier.
  32906. *
  32907. * The range is inclusive; a given value is considered part of the range if:
  32908. *
  32909. * this.min <= value <= this.max
  32910. */
  32911. function Range() {
  32912. this.min = undefined;
  32913. this.max = undefined;
  32914. }
  32915. /**
  32916. * Adjust the range so that the passed value fits in it.
  32917. *
  32918. * If the value is outside of the current extremes, adjust
  32919. * the min or max so that the value is within the range.
  32920. *
  32921. * @param {number} value Numeric value to fit in range
  32922. */
  32923. Range.prototype.adjust = function(value) {
  32924. if (value === undefined) return;
  32925. if (this.min === undefined || this.min > value) {
  32926. this.min = value;
  32927. }
  32928. if (this.max === undefined || this.max < value) {
  32929. this.max = value;
  32930. }
  32931. };
  32932. /**
  32933. * Adjust the current range so that the passed range fits in it.
  32934. *
  32935. * @param {Range} range Range instance to fit in current instance
  32936. */
  32937. Range.prototype.combine = function(range) {
  32938. this.add(range.min);
  32939. this.add(range.max);
  32940. };
  32941. /**
  32942. * Expand the range by the given value
  32943. *
  32944. * min will be lowered by given value;
  32945. * max will be raised by given value
  32946. *
  32947. * Shrinking by passing a negative value is allowed.
  32948. *
  32949. * @param {number} val Amount by which to expand or shrink current range with
  32950. */
  32951. Range.prototype.expand = function(val) {
  32952. if (val === undefined) {
  32953. return;
  32954. }
  32955. var newMin = this.min - val;
  32956. var newMax = this.max + val;
  32957. // Note that following allows newMin === newMax.
  32958. // This should be OK, since method expand() allows this also.
  32959. if (newMin > newMax) {
  32960. throw new Error('Passed expansion value makes range invalid');
  32961. }
  32962. this.min = newMin;
  32963. this.max = newMax;
  32964. };
  32965. /**
  32966. * Determine the full range width of current instance.
  32967. *
  32968. * @returns {num} The calculated width of this range
  32969. */
  32970. Range.prototype.range = function() {
  32971. return this.max - this.min;
  32972. };
  32973. /**
  32974. * Determine the central point of current instance.
  32975. *
  32976. * @returns {number} the value in the middle of min and max
  32977. */
  32978. Range.prototype.center = function() {
  32979. return (this.min + this.max) / 2;
  32980. };
  32981. module.exports = Range;
  32982. /***/
  32983. }),
  32984. /* 175 */
  32985. /***/
  32986. (function(module, exports, __webpack_require__) {
  32987. "use strict";
  32988. var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;
  32989. (function(factory) {
  32990. if (true) {
  32991. // AMD. Register as an anonymous module.
  32992. !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
  32993. __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
  32994. (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
  32995. __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  32996. } else if (typeof exports === 'object') {
  32997. // Node. Does not work with strict CommonJS, but
  32998. // only CommonJS-like environments that support module.exports,
  32999. // like Node.
  33000. module.exports = factory();
  33001. } else {
  33002. // Browser globals (root is window)
  33003. window.propagating = factory();
  33004. }
  33005. }(function() {
  33006. var _firstTarget = null; // singleton, will contain the target element where the touch event started
  33007. /**
  33008. * Extend an Hammer.js instance with event propagation.
  33009. *
  33010. * Features:
  33011. * - Events emitted by hammer will propagate in order from child to parent
  33012. * elements.
  33013. * - Events are extended with a function `event.stopPropagation()` to stop
  33014. * propagation to parent elements.
  33015. * - An option `preventDefault` to stop all default browser behavior.
  33016. *
  33017. * Usage:
  33018. * var hammer = propagatingHammer(new Hammer(element));
  33019. * var hammer = propagatingHammer(new Hammer(element), {preventDefault: true});
  33020. *
  33021. * @param {Hammer.Manager} hammer An hammer instance.
  33022. * @param {Object} [options] Available options:
  33023. * - `preventDefault: true | false | 'mouse' | 'touch' | 'pen'`.
  33024. * Enforce preventing the default browser behavior.
  33025. * Cannot be set to `false`.
  33026. * @return {Hammer.Manager} Returns the same hammer instance with extended
  33027. * functionality
  33028. */
  33029. return function propagating(hammer, options) {
  33030. var _options = options || {
  33031. preventDefault: false
  33032. };
  33033. if (hammer.Manager) {
  33034. // This looks like the Hammer constructor.
  33035. // Overload the constructors with our own.
  33036. var Hammer = hammer;
  33037. var PropagatingHammer = function(element, options) {
  33038. var o = Object.create(_options);
  33039. if (options) Hammer.assign(o, options);
  33040. return propagating(new Hammer(element, o), o);
  33041. };
  33042. Hammer.assign(PropagatingHammer, Hammer);
  33043. PropagatingHammer.Manager = function(element, options) {
  33044. var o = Object.create(_options);
  33045. if (options) Hammer.assign(o, options);
  33046. return propagating(new Hammer.Manager(element, o), o);
  33047. };
  33048. return PropagatingHammer;
  33049. }
  33050. // create a wrapper object which will override the functions
  33051. // `on`, `off`, `destroy`, and `emit` of the hammer instance
  33052. var wrapper = Object.create(hammer);
  33053. // attach to DOM element
  33054. var element = hammer.element;
  33055. if (!element.hammer) element.hammer = [];
  33056. element.hammer.push(wrapper);
  33057. // register an event to catch the start of a gesture and store the
  33058. // target in a singleton
  33059. hammer.on('hammer.input', function(event) {
  33060. if (_options.preventDefault === true || (_options.preventDefault === event.pointerType)) {
  33061. event.preventDefault();
  33062. }
  33063. if (event.isFirst) {
  33064. _firstTarget = event.target;
  33065. }
  33066. });
  33067. /** @type {Object.<String, Array.<function>>} */
  33068. wrapper._handlers = {};
  33069. /**
  33070. * Register a handler for one or multiple events
  33071. * @param {String} events A space separated string with events
  33072. * @param {function} handler A callback function, called as handler(event)
  33073. * @returns {Hammer.Manager} Returns the hammer instance
  33074. */
  33075. wrapper.on = function(events, handler) {
  33076. // register the handler
  33077. split(events).forEach(function(event) {
  33078. var _handlers = wrapper._handlers[event];
  33079. if (!_handlers) {
  33080. wrapper._handlers[event] = _handlers = [];
  33081. // register the static, propagated handler
  33082. hammer.on(event, propagatedHandler);
  33083. }
  33084. _handlers.push(handler);
  33085. });
  33086. return wrapper;
  33087. };
  33088. /**
  33089. * Unregister a handler for one or multiple events
  33090. * @param {String} events A space separated string with events
  33091. * @param {function} [handler] Optional. The registered handler. If not
  33092. * provided, all handlers for given events
  33093. * are removed.
  33094. * @returns {Hammer.Manager} Returns the hammer instance
  33095. */
  33096. wrapper.off = function(events, handler) {
  33097. // unregister the handler
  33098. split(events).forEach(function(event) {
  33099. var _handlers = wrapper._handlers[event];
  33100. if (_handlers) {
  33101. _handlers = handler ? _handlers.filter(function(h) {
  33102. return h !== handler;
  33103. }) : [];
  33104. if (_handlers.length > 0) {
  33105. wrapper._handlers[event] = _handlers;
  33106. } else {
  33107. // remove static, propagated handler
  33108. hammer.off(event, propagatedHandler);
  33109. delete wrapper._handlers[event];
  33110. }
  33111. }
  33112. });
  33113. return wrapper;
  33114. };
  33115. /**
  33116. * Emit to the event listeners
  33117. * @param {string} eventType
  33118. * @param {Event} event
  33119. */
  33120. wrapper.emit = function(eventType, event) {
  33121. _firstTarget = event.target;
  33122. hammer.emit(eventType, event);
  33123. };
  33124. wrapper.destroy = function() {
  33125. // Detach from DOM element
  33126. var hammers = hammer.element.hammer;
  33127. var idx = hammers.indexOf(wrapper);
  33128. if (idx !== -1) hammers.splice(idx, 1);
  33129. if (!hammers.length) delete hammer.element.hammer;
  33130. // clear all handlers
  33131. wrapper._handlers = {};
  33132. // call original hammer destroy
  33133. hammer.destroy();
  33134. };
  33135. // split a string with space separated words
  33136. function split(events) {
  33137. return events.match(/[^ ]+/g);
  33138. }
  33139. /**
  33140. * A static event handler, applying event propagation.
  33141. * @param {Object} event
  33142. */
  33143. function propagatedHandler(event) {
  33144. // let only a single hammer instance handle this event
  33145. if (event.type !== 'hammer.input') {
  33146. // it is possible that the same srcEvent is used with multiple hammer events,
  33147. // we keep track on which events are handled in an object _handled
  33148. if (!event.srcEvent._handled) {
  33149. event.srcEvent._handled = {};
  33150. }
  33151. if (event.srcEvent._handled[event.type]) {
  33152. return;
  33153. } else {
  33154. event.srcEvent._handled[event.type] = true;
  33155. }
  33156. }
  33157. // attach a stopPropagation function to the event
  33158. var stopped = false;
  33159. event.stopPropagation = function() {
  33160. stopped = true;
  33161. };
  33162. //wrap the srcEvent's stopPropagation to also stop hammer propagation:
  33163. var srcStop = event.srcEvent.stopPropagation.bind(event.srcEvent);
  33164. if (typeof srcStop == "function") {
  33165. event.srcEvent.stopPropagation = function() {
  33166. srcStop();
  33167. event.stopPropagation();
  33168. }
  33169. }
  33170. // attach firstTarget property to the event
  33171. event.firstTarget = _firstTarget;
  33172. // propagate over all elements (until stopped)
  33173. var elem = _firstTarget;
  33174. while (elem && !stopped) {
  33175. var elemHammer = elem.hammer;
  33176. if (elemHammer) {
  33177. var _handlers;
  33178. for (var k = 0; k < elemHammer.length; k++) {
  33179. _handlers = elemHammer[k]._handlers[event.type];
  33180. if (_handlers)
  33181. for (var i = 0; i < _handlers.length && !stopped; i++) {
  33182. _handlers[i](event);
  33183. }
  33184. }
  33185. }
  33186. elem = elem.parentNode;
  33187. }
  33188. }
  33189. return wrapper;
  33190. };
  33191. }));
  33192. /***/
  33193. }),
  33194. /* 176 */
  33195. /***/
  33196. (function(module, exports, __webpack_require__) {
  33197. var __WEBPACK_AMD_DEFINE_RESULT__;
  33198. /*! Hammer.JS - v2.0.7 - 2016-04-22
  33199. * http://hammerjs.github.io/
  33200. *
  33201. * Copyright (c) 2016 Jorik Tangelder;
  33202. * Licensed under the MIT license */
  33203. (function(window, document, exportName, undefined) {
  33204. 'use strict';
  33205. var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
  33206. var TEST_ELEMENT = document.createElement('div');
  33207. var TYPE_FUNCTION = 'function';
  33208. var round = Math.round;
  33209. var abs = Math.abs;
  33210. var now = Date.now;
  33211. /**
  33212. * set a timeout with a given scope
  33213. * @param {Function} fn
  33214. * @param {Number} timeout
  33215. * @param {Object} context
  33216. * @returns {number}
  33217. */
  33218. function setTimeoutContext(fn, timeout, context) {
  33219. return setTimeout(bindFn(fn, context), timeout);
  33220. }
  33221. /**
  33222. * if the argument is an array, we want to execute the fn on each entry
  33223. * if it aint an array we don't want to do a thing.
  33224. * this is used by all the methods that accept a single and array argument.
  33225. * @param {*|Array} arg
  33226. * @param {String} fn
  33227. * @param {Object} [context]
  33228. * @returns {Boolean}
  33229. */
  33230. function invokeArrayArg(arg, fn, context) {
  33231. if (Array.isArray(arg)) {
  33232. each(arg, context[fn], context);
  33233. return true;
  33234. }
  33235. return false;
  33236. }
  33237. /**
  33238. * walk objects and arrays
  33239. * @param {Object} obj
  33240. * @param {Function} iterator
  33241. * @param {Object} context
  33242. */
  33243. function each(obj, iterator, context) {
  33244. var i;
  33245. if (!obj) {
  33246. return;
  33247. }
  33248. if (obj.forEach) {
  33249. obj.forEach(iterator, context);
  33250. } else if (obj.length !== undefined) {
  33251. i = 0;
  33252. while (i < obj.length) {
  33253. iterator.call(context, obj[i], i, obj);
  33254. i++;
  33255. }
  33256. } else {
  33257. for (i in obj) {
  33258. obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
  33259. }
  33260. }
  33261. }
  33262. /**
  33263. * wrap a method with a deprecation warning and stack trace
  33264. * @param {Function} method
  33265. * @param {String} name
  33266. * @param {String} message
  33267. * @returns {Function} A new function wrapping the supplied method.
  33268. */
  33269. function deprecate(method, name, message) {
  33270. var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n';
  33271. return function() {
  33272. var e = new Error('get-stack-trace');
  33273. var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '')
  33274. .replace(/^\s+at\s+/gm, '')
  33275. .replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
  33276. var log = window.console && (window.console.warn || window.console.log);
  33277. if (log) {
  33278. log.call(window.console, deprecationMessage, stack);
  33279. }
  33280. return method.apply(this, arguments);
  33281. };
  33282. }
  33283. /**
  33284. * extend object.
  33285. * means that properties in dest will be overwritten by the ones in src.
  33286. * @param {Object} target
  33287. * @param {...Object} objects_to_assign
  33288. * @returns {Object} target
  33289. */
  33290. var assign;
  33291. if (typeof Object.assign !== 'function') {
  33292. assign = function assign(target) {
  33293. if (target === undefined || target === null) {
  33294. throw new TypeError('Cannot convert undefined or null to object');
  33295. }
  33296. var output = Object(target);
  33297. for (var index = 1; index < arguments.length; index++) {
  33298. var source = arguments[index];
  33299. if (source !== undefined && source !== null) {
  33300. for (var nextKey in source) {
  33301. if (source.hasOwnProperty(nextKey)) {
  33302. output[nextKey] = source[nextKey];
  33303. }
  33304. }
  33305. }
  33306. }
  33307. return output;
  33308. };
  33309. } else {
  33310. assign = Object.assign;
  33311. }
  33312. /**
  33313. * extend object.
  33314. * means that properties in dest will be overwritten by the ones in src.
  33315. * @param {Object} dest
  33316. * @param {Object} src
  33317. * @param {Boolean} [merge=false]
  33318. * @returns {Object} dest
  33319. */
  33320. var extend = deprecate(function extend(dest, src, merge) {
  33321. var keys = Object.keys(src);
  33322. var i = 0;
  33323. while (i < keys.length) {
  33324. if (!merge || (merge && dest[keys[i]] === undefined)) {
  33325. dest[keys[i]] = src[keys[i]];
  33326. }
  33327. i++;
  33328. }
  33329. return dest;
  33330. }, 'extend', 'Use `assign`.');
  33331. /**
  33332. * merge the values from src in the dest.
  33333. * means that properties that exist in dest will not be overwritten by src
  33334. * @param {Object} dest
  33335. * @param {Object} src
  33336. * @returns {Object} dest
  33337. */
  33338. var merge = deprecate(function merge(dest, src) {
  33339. return extend(dest, src, true);
  33340. }, 'merge', 'Use `assign`.');
  33341. /**
  33342. * simple class inheritance
  33343. * @param {Function} child
  33344. * @param {Function} base
  33345. * @param {Object} [properties]
  33346. */
  33347. function inherit(child, base, properties) {
  33348. var baseP = base.prototype,
  33349. childP;
  33350. childP = child.prototype = Object.create(baseP);
  33351. childP.constructor = child;
  33352. childP._super = baseP;
  33353. if (properties) {
  33354. assign(childP, properties);
  33355. }
  33356. }
  33357. /**
  33358. * simple function bind
  33359. * @param {Function} fn
  33360. * @param {Object} context
  33361. * @returns {Function}
  33362. */
  33363. function bindFn(fn, context) {
  33364. return function boundFn() {
  33365. return fn.apply(context, arguments);
  33366. };
  33367. }
  33368. /**
  33369. * let a boolean value also be a function that must return a boolean
  33370. * this first item in args will be used as the context
  33371. * @param {Boolean|Function} val
  33372. * @param {Array} [args]
  33373. * @returns {Boolean}
  33374. */
  33375. function boolOrFn(val, args) {
  33376. if (typeof val == TYPE_FUNCTION) {
  33377. return val.apply(args ? args[0] || undefined : undefined, args);
  33378. }
  33379. return val;
  33380. }
  33381. /**
  33382. * use the val2 when val1 is undefined
  33383. * @param {*} val1
  33384. * @param {*} val2
  33385. * @returns {*}
  33386. */
  33387. function ifUndefined(val1, val2) {
  33388. return (val1 === undefined) ? val2 : val1;
  33389. }
  33390. /**
  33391. * addEventListener with multiple events at once
  33392. * @param {EventTarget} target
  33393. * @param {String} types
  33394. * @param {Function} handler
  33395. */
  33396. function addEventListeners(target, types, handler) {
  33397. each(splitStr(types), function(type) {
  33398. target.addEventListener(type, handler, false);
  33399. });
  33400. }
  33401. /**
  33402. * removeEventListener with multiple events at once
  33403. * @param {EventTarget} target
  33404. * @param {String} types
  33405. * @param {Function} handler
  33406. */
  33407. function removeEventListeners(target, types, handler) {
  33408. each(splitStr(types), function(type) {
  33409. target.removeEventListener(type, handler, false);
  33410. });
  33411. }
  33412. /**
  33413. * find if a node is in the given parent
  33414. * @method hasParent
  33415. * @param {HTMLElement} node
  33416. * @param {HTMLElement} parent
  33417. * @return {Boolean} found
  33418. */
  33419. function hasParent(node, parent) {
  33420. while (node) {
  33421. if (node == parent) {
  33422. return true;
  33423. }
  33424. node = node.parentNode;
  33425. }
  33426. return false;
  33427. }
  33428. /**
  33429. * small indexOf wrapper
  33430. * @param {String} str
  33431. * @param {String} find
  33432. * @returns {Boolean} found
  33433. */
  33434. function inStr(str, find) {
  33435. return str.indexOf(find) > -1;
  33436. }
  33437. /**
  33438. * split string on whitespace
  33439. * @param {String} str
  33440. * @returns {Array} words
  33441. */
  33442. function splitStr(str) {
  33443. return str.trim().split(/\s+/g);
  33444. }
  33445. /**
  33446. * find if a array contains the object using indexOf or a simple polyFill
  33447. * @param {Array} src
  33448. * @param {String} find
  33449. * @param {String} [findByKey]
  33450. * @return {Boolean|Number} false when not found, or the index
  33451. */
  33452. function inArray(src, find, findByKey) {
  33453. if (src.indexOf && !findByKey) {
  33454. return src.indexOf(find);
  33455. } else {
  33456. var i = 0;
  33457. while (i < src.length) {
  33458. if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
  33459. return i;
  33460. }
  33461. i++;
  33462. }
  33463. return -1;
  33464. }
  33465. }
  33466. /**
  33467. * convert array-like objects to real arrays
  33468. * @param {Object} obj
  33469. * @returns {Array}
  33470. */
  33471. function toArray(obj) {
  33472. return Array.prototype.slice.call(obj, 0);
  33473. }
  33474. /**
  33475. * unique array with objects based on a key (like 'id') or just by the array's value
  33476. * @param {Array} src [{id:1},{id:2},{id:1}]
  33477. * @param {String} [key]
  33478. * @param {Boolean} [sort=False]
  33479. * @returns {Array} [{id:1},{id:2}]
  33480. */
  33481. function uniqueArray(src, key, sort) {
  33482. var results = [];
  33483. var values = [];
  33484. var i = 0;
  33485. while (i < src.length) {
  33486. var val = key ? src[i][key] : src[i];
  33487. if (inArray(values, val) < 0) {
  33488. results.push(src[i]);
  33489. }
  33490. values[i] = val;
  33491. i++;
  33492. }
  33493. if (sort) {
  33494. if (!key) {
  33495. results = results.sort();
  33496. } else {
  33497. results = results.sort(function sortUniqueArray(a, b) {
  33498. return a[key] > b[key];
  33499. });
  33500. }
  33501. }
  33502. return results;
  33503. }
  33504. /**
  33505. * get the prefixed property
  33506. * @param {Object} obj
  33507. * @param {String} property
  33508. * @returns {String|Undefined} prefixed
  33509. */
  33510. function prefixed(obj, property) {
  33511. var prefix, prop;
  33512. var camelProp = property[0].toUpperCase() + property.slice(1);
  33513. var i = 0;
  33514. while (i < VENDOR_PREFIXES.length) {
  33515. prefix = VENDOR_PREFIXES[i];
  33516. prop = (prefix) ? prefix + camelProp : property;
  33517. if (prop in obj) {
  33518. return prop;
  33519. }
  33520. i++;
  33521. }
  33522. return undefined;
  33523. }
  33524. /**
  33525. * get a unique id
  33526. * @returns {number} uniqueId
  33527. */
  33528. var _uniqueId = 1;
  33529. function uniqueId() {
  33530. return _uniqueId++;
  33531. }
  33532. /**
  33533. * get the window object of an element
  33534. * @param {HTMLElement} element
  33535. * @returns {DocumentView|Window}
  33536. */
  33537. function getWindowForElement(element) {
  33538. var doc = element.ownerDocument || element;
  33539. return (doc.defaultView || doc.parentWindow || window);
  33540. }
  33541. var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
  33542. var SUPPORT_TOUCH = ('ontouchstart' in window);
  33543. var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined;
  33544. var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
  33545. var INPUT_TYPE_TOUCH = 'touch';
  33546. var INPUT_TYPE_PEN = 'pen';
  33547. var INPUT_TYPE_MOUSE = 'mouse';
  33548. var INPUT_TYPE_KINECT = 'kinect';
  33549. var COMPUTE_INTERVAL = 25;
  33550. var INPUT_START = 1;
  33551. var INPUT_MOVE = 2;
  33552. var INPUT_END = 4;
  33553. var INPUT_CANCEL = 8;
  33554. var DIRECTION_NONE = 1;
  33555. var DIRECTION_LEFT = 2;
  33556. var DIRECTION_RIGHT = 4;
  33557. var DIRECTION_UP = 8;
  33558. var DIRECTION_DOWN = 16;
  33559. var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
  33560. var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
  33561. var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
  33562. var PROPS_XY = ['x', 'y'];
  33563. var PROPS_CLIENT_XY = ['clientX', 'clientY'];
  33564. /**
  33565. * create new input type manager
  33566. * @param {Manager} manager
  33567. * @param {Function} callback
  33568. * @returns {Input}
  33569. * @constructor
  33570. */
  33571. function Input(manager, callback) {
  33572. var self = this;
  33573. this.manager = manager;
  33574. this.callback = callback;
  33575. this.element = manager.element;
  33576. this.target = manager.options.inputTarget;
  33577. // smaller wrapper around the handler, for the scope and the enabled state of the manager,
  33578. // so when disabled the input events are completely bypassed.
  33579. this.domHandler = function(ev) {
  33580. if (boolOrFn(manager.options.enable, [manager])) {
  33581. self.handler(ev);
  33582. }
  33583. };
  33584. this.init();
  33585. }
  33586. Input.prototype = {
  33587. /**
  33588. * should handle the inputEvent data and trigger the callback
  33589. * @virtual
  33590. */
  33591. handler: function() {},
  33592. /**
  33593. * bind the events
  33594. */
  33595. init: function() {
  33596. this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
  33597. this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
  33598. this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
  33599. },
  33600. /**
  33601. * unbind the events
  33602. */
  33603. destroy: function() {
  33604. this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
  33605. this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
  33606. this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
  33607. }
  33608. };
  33609. /**
  33610. * create new input type manager
  33611. * called by the Manager constructor
  33612. * @param {Hammer} manager
  33613. * @returns {Input}
  33614. */
  33615. function createInputInstance(manager) {
  33616. var Type;
  33617. var inputClass = manager.options.inputClass;
  33618. if (inputClass) {
  33619. Type = inputClass;
  33620. } else if (SUPPORT_POINTER_EVENTS) {
  33621. Type = PointerEventInput;
  33622. } else if (SUPPORT_ONLY_TOUCH) {
  33623. Type = TouchInput;
  33624. } else if (!SUPPORT_TOUCH) {
  33625. Type = MouseInput;
  33626. } else {
  33627. Type = TouchMouseInput;
  33628. }
  33629. return new(Type)(manager, inputHandler);
  33630. }
  33631. /**
  33632. * handle input events
  33633. * @param {Manager} manager
  33634. * @param {String} eventType
  33635. * @param {Object} input
  33636. */
  33637. function inputHandler(manager, eventType, input) {
  33638. var pointersLen = input.pointers.length;
  33639. var changedPointersLen = input.changedPointers.length;
  33640. var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
  33641. var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));
  33642. input.isFirst = !!isFirst;
  33643. input.isFinal = !!isFinal;
  33644. if (isFirst) {
  33645. manager.session = {};
  33646. }
  33647. // source event is the normalized value of the domEvents
  33648. // like 'touchstart, mouseup, pointerdown'
  33649. input.eventType = eventType;
  33650. // compute scale, rotation etc
  33651. computeInputData(manager, input);
  33652. // emit secret event
  33653. manager.emit('hammer.input', input);
  33654. manager.recognize(input);
  33655. manager.session.prevInput = input;
  33656. }
  33657. /**
  33658. * extend the data with some usable properties like scale, rotate, velocity etc
  33659. * @param {Object} manager
  33660. * @param {Object} input
  33661. */
  33662. function computeInputData(manager, input) {
  33663. var session = manager.session;
  33664. var pointers = input.pointers;
  33665. var pointersLength = pointers.length;
  33666. // store the first input to calculate the distance and direction
  33667. if (!session.firstInput) {
  33668. session.firstInput = simpleCloneInputData(input);
  33669. }
  33670. // to compute scale and rotation we need to store the multiple touches
  33671. if (pointersLength > 1 && !session.firstMultiple) {
  33672. session.firstMultiple = simpleCloneInputData(input);
  33673. } else if (pointersLength === 1) {
  33674. session.firstMultiple = false;
  33675. }
  33676. var firstInput = session.firstInput;
  33677. var firstMultiple = session.firstMultiple;
  33678. var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
  33679. var center = input.center = getCenter(pointers);
  33680. input.timeStamp = now();
  33681. input.deltaTime = input.timeStamp - firstInput.timeStamp;
  33682. input.angle = getAngle(offsetCenter, center);
  33683. input.distance = getDistance(offsetCenter, center);
  33684. computeDeltaXY(session, input);
  33685. input.offsetDirection = getDirection(input.deltaX, input.deltaY);
  33686. var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
  33687. input.overallVelocityX = overallVelocity.x;
  33688. input.overallVelocityY = overallVelocity.y;
  33689. input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y;
  33690. input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
  33691. input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
  33692. input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length >
  33693. session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers);
  33694. computeIntervalInputData(session, input);
  33695. // find the correct target
  33696. var target = manager.element;
  33697. if (hasParent(input.srcEvent.target, target)) {
  33698. target = input.srcEvent.target;
  33699. }
  33700. input.target = target;
  33701. }
  33702. function computeDeltaXY(session, input) {
  33703. var center = input.center;
  33704. var offset = session.offsetDelta || {};
  33705. var prevDelta = session.prevDelta || {};
  33706. var prevInput = session.prevInput || {};
  33707. if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
  33708. prevDelta = session.prevDelta = {
  33709. x: prevInput.deltaX || 0,
  33710. y: prevInput.deltaY || 0
  33711. };
  33712. offset = session.offsetDelta = {
  33713. x: center.x,
  33714. y: center.y
  33715. };
  33716. }
  33717. input.deltaX = prevDelta.x + (center.x - offset.x);
  33718. input.deltaY = prevDelta.y + (center.y - offset.y);
  33719. }
  33720. /**
  33721. * velocity is calculated every x ms
  33722. * @param {Object} session
  33723. * @param {Object} input
  33724. */
  33725. function computeIntervalInputData(session, input) {
  33726. var last = session.lastInterval || input,
  33727. deltaTime = input.timeStamp - last.timeStamp,
  33728. velocity, velocityX, velocityY, direction;
  33729. if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
  33730. var deltaX = input.deltaX - last.deltaX;
  33731. var deltaY = input.deltaY - last.deltaY;
  33732. var v = getVelocity(deltaTime, deltaX, deltaY);
  33733. velocityX = v.x;
  33734. velocityY = v.y;
  33735. velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
  33736. direction = getDirection(deltaX, deltaY);
  33737. session.lastInterval = input;
  33738. } else {
  33739. // use latest velocity info if it doesn't overtake a minimum period
  33740. velocity = last.velocity;
  33741. velocityX = last.velocityX;
  33742. velocityY = last.velocityY;
  33743. direction = last.direction;
  33744. }
  33745. input.velocity = velocity;
  33746. input.velocityX = velocityX;
  33747. input.velocityY = velocityY;
  33748. input.direction = direction;
  33749. }
  33750. /**
  33751. * create a simple clone from the input used for storage of firstInput and firstMultiple
  33752. * @param {Object} input
  33753. * @returns {Object} clonedInputData
  33754. */
  33755. function simpleCloneInputData(input) {
  33756. // make a simple copy of the pointers because we will get a reference if we don't
  33757. // we only need clientXY for the calculations
  33758. var pointers = [];
  33759. var i = 0;
  33760. while (i < input.pointers.length) {
  33761. pointers[i] = {
  33762. clientX: round(input.pointers[i].clientX),
  33763. clientY: round(input.pointers[i].clientY)
  33764. };
  33765. i++;
  33766. }
  33767. return {
  33768. timeStamp: now(),
  33769. pointers: pointers,
  33770. center: getCenter(pointers),
  33771. deltaX: input.deltaX,
  33772. deltaY: input.deltaY
  33773. };
  33774. }
  33775. /**
  33776. * get the center of all the pointers
  33777. * @param {Array} pointers
  33778. * @return {Object} center contains `x` and `y` properties
  33779. */
  33780. function getCenter(pointers) {
  33781. var pointersLength = pointers.length;
  33782. // no need to loop when only one touch
  33783. if (pointersLength === 1) {
  33784. return {
  33785. x: round(pointers[0].clientX),
  33786. y: round(pointers[0].clientY)
  33787. };
  33788. }
  33789. var x = 0,
  33790. y = 0,
  33791. i = 0;
  33792. while (i < pointersLength) {
  33793. x += pointers[i].clientX;
  33794. y += pointers[i].clientY;
  33795. i++;
  33796. }
  33797. return {
  33798. x: round(x / pointersLength),
  33799. y: round(y / pointersLength)
  33800. };
  33801. }
  33802. /**
  33803. * calculate the velocity between two points. unit is in px per ms.
  33804. * @param {Number} deltaTime
  33805. * @param {Number} x
  33806. * @param {Number} y
  33807. * @return {Object} velocity `x` and `y`
  33808. */
  33809. function getVelocity(deltaTime, x, y) {
  33810. return {
  33811. x: x / deltaTime || 0,
  33812. y: y / deltaTime || 0
  33813. };
  33814. }
  33815. /**
  33816. * get the direction between two points
  33817. * @param {Number} x
  33818. * @param {Number} y
  33819. * @return {Number} direction
  33820. */
  33821. function getDirection(x, y) {
  33822. if (x === y) {
  33823. return DIRECTION_NONE;
  33824. }
  33825. if (abs(x) >= abs(y)) {
  33826. return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
  33827. }
  33828. return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
  33829. }
  33830. /**
  33831. * calculate the absolute distance between two points
  33832. * @param {Object} p1 {x, y}
  33833. * @param {Object} p2 {x, y}
  33834. * @param {Array} [props] containing x and y keys
  33835. * @return {Number} distance
  33836. */
  33837. function getDistance(p1, p2, props) {
  33838. if (!props) {
  33839. props = PROPS_XY;
  33840. }
  33841. var x = p2[props[0]] - p1[props[0]],
  33842. y = p2[props[1]] - p1[props[1]];
  33843. return Math.sqrt((x * x) + (y * y));
  33844. }
  33845. /**
  33846. * calculate the angle between two coordinates
  33847. * @param {Object} p1
  33848. * @param {Object} p2
  33849. * @param {Array} [props] containing x and y keys
  33850. * @return {Number} angle
  33851. */
  33852. function getAngle(p1, p2, props) {
  33853. if (!props) {
  33854. props = PROPS_XY;
  33855. }
  33856. var x = p2[props[0]] - p1[props[0]],
  33857. y = p2[props[1]] - p1[props[1]];
  33858. return Math.atan2(y, x) * 180 / Math.PI;
  33859. }
  33860. /**
  33861. * calculate the rotation degrees between two pointersets
  33862. * @param {Array} start array of pointers
  33863. * @param {Array} end array of pointers
  33864. * @return {Number} rotation
  33865. */
  33866. function getRotation(start, end) {
  33867. return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
  33868. }
  33869. /**
  33870. * calculate the scale factor between two pointersets
  33871. * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
  33872. * @param {Array} start array of pointers
  33873. * @param {Array} end array of pointers
  33874. * @return {Number} scale
  33875. */
  33876. function getScale(start, end) {
  33877. return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
  33878. }
  33879. var MOUSE_INPUT_MAP = {
  33880. mousedown: INPUT_START,
  33881. mousemove: INPUT_MOVE,
  33882. mouseup: INPUT_END
  33883. };
  33884. var MOUSE_ELEMENT_EVENTS = 'mousedown';
  33885. var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
  33886. /**
  33887. * Mouse events input
  33888. * @constructor
  33889. * @extends Input
  33890. */
  33891. function MouseInput() {
  33892. this.evEl = MOUSE_ELEMENT_EVENTS;
  33893. this.evWin = MOUSE_WINDOW_EVENTS;
  33894. this.pressed = false; // mousedown state
  33895. Input.apply(this, arguments);
  33896. }
  33897. inherit(MouseInput, Input, {
  33898. /**
  33899. * handle mouse events
  33900. * @param {Object} ev
  33901. */
  33902. handler: function MEhandler(ev) {
  33903. var eventType = MOUSE_INPUT_MAP[ev.type];
  33904. // on start we want to have the left mouse button down
  33905. if (eventType & INPUT_START && ev.button === 0) {
  33906. this.pressed = true;
  33907. }
  33908. if (eventType & INPUT_MOVE && ev.which !== 1) {
  33909. eventType = INPUT_END;
  33910. }
  33911. // mouse must be down
  33912. if (!this.pressed) {
  33913. return;
  33914. }
  33915. if (eventType & INPUT_END) {
  33916. this.pressed = false;
  33917. }
  33918. this.callback(this.manager, eventType, {
  33919. pointers: [ev],
  33920. changedPointers: [ev],
  33921. pointerType: INPUT_TYPE_MOUSE,
  33922. srcEvent: ev
  33923. });
  33924. }
  33925. });
  33926. var POINTER_INPUT_MAP = {
  33927. pointerdown: INPUT_START,
  33928. pointermove: INPUT_MOVE,
  33929. pointerup: INPUT_END,
  33930. pointercancel: INPUT_CANCEL,
  33931. pointerout: INPUT_CANCEL
  33932. };
  33933. // in IE10 the pointer types is defined as an enum
  33934. var IE10_POINTER_TYPE_ENUM = {
  33935. 2: INPUT_TYPE_TOUCH,
  33936. 3: INPUT_TYPE_PEN,
  33937. 4: INPUT_TYPE_MOUSE,
  33938. 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
  33939. };
  33940. var POINTER_ELEMENT_EVENTS = 'pointerdown';
  33941. var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
  33942. // IE10 has prefixed support, and case-sensitive
  33943. if (window.MSPointerEvent && !window.PointerEvent) {
  33944. POINTER_ELEMENT_EVENTS = 'MSPointerDown';
  33945. POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
  33946. }
  33947. /**
  33948. * Pointer events input
  33949. * @constructor
  33950. * @extends Input
  33951. */
  33952. function PointerEventInput() {
  33953. this.evEl = POINTER_ELEMENT_EVENTS;
  33954. this.evWin = POINTER_WINDOW_EVENTS;
  33955. Input.apply(this, arguments);
  33956. this.store = (this.manager.session.pointerEvents = []);
  33957. }
  33958. inherit(PointerEventInput, Input, {
  33959. /**
  33960. * handle mouse events
  33961. * @param {Object} ev
  33962. */
  33963. handler: function PEhandler(ev) {
  33964. var store = this.store;
  33965. var removePointer = false;
  33966. var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
  33967. var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
  33968. var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
  33969. var isTouch = (pointerType == INPUT_TYPE_TOUCH);
  33970. // get index of the event in the store
  33971. var storeIndex = inArray(store, ev.pointerId, 'pointerId');
  33972. // start and mouse must be down
  33973. if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
  33974. if (storeIndex < 0) {
  33975. store.push(ev);
  33976. storeIndex = store.length - 1;
  33977. }
  33978. } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
  33979. removePointer = true;
  33980. }
  33981. // it not found, so the pointer hasn't been down (so it's probably a hover)
  33982. if (storeIndex < 0) {
  33983. return;
  33984. }
  33985. // update the event in the store
  33986. store[storeIndex] = ev;
  33987. this.callback(this.manager, eventType, {
  33988. pointers: store,
  33989. changedPointers: [ev],
  33990. pointerType: pointerType,
  33991. srcEvent: ev
  33992. });
  33993. if (removePointer) {
  33994. // remove from the store
  33995. store.splice(storeIndex, 1);
  33996. }
  33997. }
  33998. });
  33999. var SINGLE_TOUCH_INPUT_MAP = {
  34000. touchstart: INPUT_START,
  34001. touchmove: INPUT_MOVE,
  34002. touchend: INPUT_END,
  34003. touchcancel: INPUT_CANCEL
  34004. };
  34005. var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
  34006. var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
  34007. /**
  34008. * Touch events input
  34009. * @constructor
  34010. * @extends Input
  34011. */
  34012. function SingleTouchInput() {
  34013. this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
  34014. this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
  34015. this.started = false;
  34016. Input.apply(this, arguments);
  34017. }
  34018. inherit(SingleTouchInput, Input, {
  34019. handler: function TEhandler(ev) {
  34020. var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
  34021. // should we handle the touch events?
  34022. if (type === INPUT_START) {
  34023. this.started = true;
  34024. }
  34025. if (!this.started) {
  34026. return;
  34027. }
  34028. var touches = normalizeSingleTouches.call(this, ev, type);
  34029. // when done, reset the started state
  34030. if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
  34031. this.started = false;
  34032. }
  34033. this.callback(this.manager, type, {
  34034. pointers: touches[0],
  34035. changedPointers: touches[1],
  34036. pointerType: INPUT_TYPE_TOUCH,
  34037. srcEvent: ev
  34038. });
  34039. }
  34040. });
  34041. /**
  34042. * @this {TouchInput}
  34043. * @param {Object} ev
  34044. * @param {Number} type flag
  34045. * @returns {undefined|Array} [all, changed]
  34046. */
  34047. function normalizeSingleTouches(ev, type) {
  34048. var all = toArray(ev.touches);
  34049. var changed = toArray(ev.changedTouches);
  34050. if (type & (INPUT_END | INPUT_CANCEL)) {
  34051. all = uniqueArray(all.concat(changed), 'identifier', true);
  34052. }
  34053. return [all, changed];
  34054. }
  34055. var TOUCH_INPUT_MAP = {
  34056. touchstart: INPUT_START,
  34057. touchmove: INPUT_MOVE,
  34058. touchend: INPUT_END,
  34059. touchcancel: INPUT_CANCEL
  34060. };
  34061. var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
  34062. /**
  34063. * Multi-user touch events input
  34064. * @constructor
  34065. * @extends Input
  34066. */
  34067. function TouchInput() {
  34068. this.evTarget = TOUCH_TARGET_EVENTS;
  34069. this.targetIds = {};
  34070. Input.apply(this, arguments);
  34071. }
  34072. inherit(TouchInput, Input, {
  34073. handler: function MTEhandler(ev) {
  34074. var type = TOUCH_INPUT_MAP[ev.type];
  34075. var touches = getTouches.call(this, ev, type);
  34076. if (!touches) {
  34077. return;
  34078. }
  34079. this.callback(this.manager, type, {
  34080. pointers: touches[0],
  34081. changedPointers: touches[1],
  34082. pointerType: INPUT_TYPE_TOUCH,
  34083. srcEvent: ev
  34084. });
  34085. }
  34086. });
  34087. /**
  34088. * @this {TouchInput}
  34089. * @param {Object} ev
  34090. * @param {Number} type flag
  34091. * @returns {undefined|Array} [all, changed]
  34092. */
  34093. function getTouches(ev, type) {
  34094. var allTouches = toArray(ev.touches);
  34095. var targetIds = this.targetIds;
  34096. // when there is only one touch, the process can be simplified
  34097. if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
  34098. targetIds[allTouches[0].identifier] = true;
  34099. return [allTouches, allTouches];
  34100. }
  34101. var i,
  34102. targetTouches,
  34103. changedTouches = toArray(ev.changedTouches),
  34104. changedTargetTouches = [],
  34105. target = this.target;
  34106. // get target touches from touches
  34107. targetTouches = allTouches.filter(function(touch) {
  34108. return hasParent(touch.target, target);
  34109. });
  34110. // collect touches
  34111. if (type === INPUT_START) {
  34112. i = 0;
  34113. while (i < targetTouches.length) {
  34114. targetIds[targetTouches[i].identifier] = true;
  34115. i++;
  34116. }
  34117. }
  34118. // filter changed touches to only contain touches that exist in the collected target ids
  34119. i = 0;
  34120. while (i < changedTouches.length) {
  34121. if (targetIds[changedTouches[i].identifier]) {
  34122. changedTargetTouches.push(changedTouches[i]);
  34123. }
  34124. // cleanup removed touches
  34125. if (type & (INPUT_END | INPUT_CANCEL)) {
  34126. delete targetIds[changedTouches[i].identifier];
  34127. }
  34128. i++;
  34129. }
  34130. if (!changedTargetTouches.length) {
  34131. return;
  34132. }
  34133. return [
  34134. // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
  34135. uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
  34136. changedTargetTouches
  34137. ];
  34138. }
  34139. /**
  34140. * Combined touch and mouse input
  34141. *
  34142. * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
  34143. * This because touch devices also emit mouse events while doing a touch.
  34144. *
  34145. * @constructor
  34146. * @extends Input
  34147. */
  34148. var DEDUP_TIMEOUT = 2500;
  34149. var DEDUP_DISTANCE = 25;
  34150. function TouchMouseInput() {
  34151. Input.apply(this, arguments);
  34152. var handler = bindFn(this.handler, this);
  34153. this.touch = new TouchInput(this.manager, handler);
  34154. this.mouse = new MouseInput(this.manager, handler);
  34155. this.primaryTouch = null;
  34156. this.lastTouches = [];
  34157. }
  34158. inherit(TouchMouseInput, Input, {
  34159. /**
  34160. * handle mouse and touch events
  34161. * @param {Hammer} manager
  34162. * @param {String} inputEvent
  34163. * @param {Object} inputData
  34164. */
  34165. handler: function TMEhandler(manager, inputEvent, inputData) {
  34166. var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
  34167. isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
  34168. if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
  34169. return;
  34170. }
  34171. // when we're in a touch event, record touches to de-dupe synthetic mouse event
  34172. if (isTouch) {
  34173. recordTouches.call(this, inputEvent, inputData);
  34174. } else if (isMouse && isSyntheticEvent.call(this, inputData)) {
  34175. return;
  34176. }
  34177. this.callback(manager, inputEvent, inputData);
  34178. },
  34179. /**
  34180. * remove the event listeners
  34181. */
  34182. destroy: function destroy() {
  34183. this.touch.destroy();
  34184. this.mouse.destroy();
  34185. }
  34186. });
  34187. function recordTouches(eventType, eventData) {
  34188. if (eventType & INPUT_START) {
  34189. this.primaryTouch = eventData.changedPointers[0].identifier;
  34190. setLastTouch.call(this, eventData);
  34191. } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
  34192. setLastTouch.call(this, eventData);
  34193. }
  34194. }
  34195. function setLastTouch(eventData) {
  34196. var touch = eventData.changedPointers[0];
  34197. if (touch.identifier === this.primaryTouch) {
  34198. var lastTouch = { x: touch.clientX, y: touch.clientY };
  34199. this.lastTouches.push(lastTouch);
  34200. var lts = this.lastTouches;
  34201. var removeLastTouch = function() {
  34202. var i = lts.indexOf(lastTouch);
  34203. if (i > -1) {
  34204. lts.splice(i, 1);
  34205. }
  34206. };
  34207. setTimeout(removeLastTouch, DEDUP_TIMEOUT);
  34208. }
  34209. }
  34210. function isSyntheticEvent(eventData) {
  34211. var x = eventData.srcEvent.clientX,
  34212. y = eventData.srcEvent.clientY;
  34213. for (var i = 0; i < this.lastTouches.length; i++) {
  34214. var t = this.lastTouches[i];
  34215. var dx = Math.abs(x - t.x),
  34216. dy = Math.abs(y - t.y);
  34217. if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
  34218. return true;
  34219. }
  34220. }
  34221. return false;
  34222. }
  34223. var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
  34224. var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
  34225. // magical touchAction value
  34226. var TOUCH_ACTION_COMPUTE = 'compute';
  34227. var TOUCH_ACTION_AUTO = 'auto';
  34228. var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
  34229. var TOUCH_ACTION_NONE = 'none';
  34230. var TOUCH_ACTION_PAN_X = 'pan-x';
  34231. var TOUCH_ACTION_PAN_Y = 'pan-y';
  34232. var TOUCH_ACTION_MAP = getTouchActionProps();
  34233. /**
  34234. * Touch Action
  34235. * sets the touchAction property or uses the js alternative
  34236. * @param {Manager} manager
  34237. * @param {String} value
  34238. * @constructor
  34239. */
  34240. function TouchAction(manager, value) {
  34241. this.manager = manager;
  34242. this.set(value);
  34243. }
  34244. TouchAction.prototype = {
  34245. /**
  34246. * set the touchAction value on the element or enable the polyfill
  34247. * @param {String} value
  34248. */
  34249. set: function(value) {
  34250. // find out the touch-action by the event handlers
  34251. if (value == TOUCH_ACTION_COMPUTE) {
  34252. value = this.compute();
  34253. }
  34254. if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
  34255. this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
  34256. }
  34257. this.actions = value.toLowerCase().trim();
  34258. },
  34259. /**
  34260. * just re-set the touchAction value
  34261. */
  34262. update: function() {
  34263. this.set(this.manager.options.touchAction);
  34264. },
  34265. /**
  34266. * compute the value for the touchAction property based on the recognizer's settings
  34267. * @returns {String} value
  34268. */
  34269. compute: function() {
  34270. var actions = [];
  34271. each(this.manager.recognizers, function(recognizer) {
  34272. if (boolOrFn(recognizer.options.enable, [recognizer])) {
  34273. actions = actions.concat(recognizer.getTouchAction());
  34274. }
  34275. });
  34276. return cleanTouchActions(actions.join(' '));
  34277. },
  34278. /**
  34279. * this method is called on each input cycle and provides the preventing of the browser behavior
  34280. * @param {Object} input
  34281. */
  34282. preventDefaults: function(input) {
  34283. var srcEvent = input.srcEvent;
  34284. var direction = input.offsetDirection;
  34285. // if the touch action did prevented once this session
  34286. if (this.manager.session.prevented) {
  34287. srcEvent.preventDefault();
  34288. return;
  34289. }
  34290. var actions = this.actions;
  34291. var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
  34292. var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
  34293. var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
  34294. if (hasNone) {
  34295. //do not prevent defaults if this is a tap gesture
  34296. var isTapPointer = input.pointers.length === 1;
  34297. var isTapMovement = input.distance < 2;
  34298. var isTapTouchTime = input.deltaTime < 250;
  34299. if (isTapPointer && isTapMovement && isTapTouchTime) {
  34300. return;
  34301. }
  34302. }
  34303. if (hasPanX && hasPanY) {
  34304. // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
  34305. return;
  34306. }
  34307. if (hasNone ||
  34308. (hasPanY && direction & DIRECTION_HORIZONTAL) ||
  34309. (hasPanX && direction & DIRECTION_VERTICAL)) {
  34310. return this.preventSrc(srcEvent);
  34311. }
  34312. },
  34313. /**
  34314. * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
  34315. * @param {Object} srcEvent
  34316. */
  34317. preventSrc: function(srcEvent) {
  34318. this.manager.session.prevented = true;
  34319. srcEvent.preventDefault();
  34320. }
  34321. };
  34322. /**
  34323. * when the touchActions are collected they are not a valid value, so we need to clean things up. *
  34324. * @param {String} actions
  34325. * @returns {*}
  34326. */
  34327. function cleanTouchActions(actions) {
  34328. // none
  34329. if (inStr(actions, TOUCH_ACTION_NONE)) {
  34330. return TOUCH_ACTION_NONE;
  34331. }
  34332. var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
  34333. var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
  34334. // if both pan-x and pan-y are set (different recognizers
  34335. // for different directions, e.g. horizontal pan but vertical swipe?)
  34336. // we need none (as otherwise with pan-x pan-y combined none of these
  34337. // recognizers will work, since the browser would handle all panning
  34338. if (hasPanX && hasPanY) {
  34339. return TOUCH_ACTION_NONE;
  34340. }
  34341. // pan-x OR pan-y
  34342. if (hasPanX || hasPanY) {
  34343. return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
  34344. }
  34345. // manipulation
  34346. if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
  34347. return TOUCH_ACTION_MANIPULATION;
  34348. }
  34349. return TOUCH_ACTION_AUTO;
  34350. }
  34351. function getTouchActionProps() {
  34352. if (!NATIVE_TOUCH_ACTION) {
  34353. return false;
  34354. }
  34355. var touchMap = {};
  34356. var cssSupports = window.CSS && window.CSS.supports;
  34357. ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) {
  34358. // If css.supports is not supported but there is native touch-action assume it supports
  34359. // all values. This is the case for IE 10 and 11.
  34360. touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true;
  34361. });
  34362. return touchMap;
  34363. }
  34364. /**
  34365. * Recognizer flow explained; *
  34366. * All recognizers have the initial state of POSSIBLE when a input session starts.
  34367. * The definition of a input session is from the first input until the last input, with all it's movement in it. *
  34368. * Example session for mouse-input: mousedown -> mousemove -> mouseup
  34369. *
  34370. * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
  34371. * which determines with state it should be.
  34372. *
  34373. * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
  34374. * POSSIBLE to give it another change on the next cycle.
  34375. *
  34376. * Possible
  34377. * |
  34378. * +-----+---------------+
  34379. * | |
  34380. * +-----+-----+ |
  34381. * | | |
  34382. * Failed Cancelled |
  34383. * +-------+------+
  34384. * | |
  34385. * Recognized Began
  34386. * |
  34387. * Changed
  34388. * |
  34389. * Ended/Recognized
  34390. */
  34391. var STATE_POSSIBLE = 1;
  34392. var STATE_BEGAN = 2;
  34393. var STATE_CHANGED = 4;
  34394. var STATE_ENDED = 8;
  34395. var STATE_RECOGNIZED = STATE_ENDED;
  34396. var STATE_CANCELLED = 16;
  34397. var STATE_FAILED = 32;
  34398. /**
  34399. * Recognizer
  34400. * Every recognizer needs to extend from this class.
  34401. * @constructor
  34402. * @param {Object} options
  34403. */
  34404. function Recognizer(options) {
  34405. this.options = assign({}, this.defaults, options || {});
  34406. this.id = uniqueId();
  34407. this.manager = null;
  34408. // default is enable true
  34409. this.options.enable = ifUndefined(this.options.enable, true);
  34410. this.state = STATE_POSSIBLE;
  34411. this.simultaneous = {};
  34412. this.requireFail = [];
  34413. }
  34414. Recognizer.prototype = {
  34415. /**
  34416. * @virtual
  34417. * @type {Object}
  34418. */
  34419. defaults: {},
  34420. /**
  34421. * set options
  34422. * @param {Object} options
  34423. * @return {Recognizer}
  34424. */
  34425. set: function(options) {
  34426. assign(this.options, options);
  34427. // also update the touchAction, in case something changed about the directions/enabled state
  34428. this.manager && this.manager.touchAction.update();
  34429. return this;
  34430. },
  34431. /**
  34432. * recognize simultaneous with an other recognizer.
  34433. * @param {Recognizer} otherRecognizer
  34434. * @returns {Recognizer} this
  34435. */
  34436. recognizeWith: function(otherRecognizer) {
  34437. if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
  34438. return this;
  34439. }
  34440. var simultaneous = this.simultaneous;
  34441. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
  34442. if (!simultaneous[otherRecognizer.id]) {
  34443. simultaneous[otherRecognizer.id] = otherRecognizer;
  34444. otherRecognizer.recognizeWith(this);
  34445. }
  34446. return this;
  34447. },
  34448. /**
  34449. * drop the simultaneous link. it doesnt remove the link on the other recognizer.
  34450. * @param {Recognizer} otherRecognizer
  34451. * @returns {Recognizer} this
  34452. */
  34453. dropRecognizeWith: function(otherRecognizer) {
  34454. if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
  34455. return this;
  34456. }
  34457. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
  34458. delete this.simultaneous[otherRecognizer.id];
  34459. return this;
  34460. },
  34461. /**
  34462. * recognizer can only run when an other is failing
  34463. * @param {Recognizer} otherRecognizer
  34464. * @returns {Recognizer} this
  34465. */
  34466. requireFailure: function(otherRecognizer) {
  34467. if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
  34468. return this;
  34469. }
  34470. var requireFail = this.requireFail;
  34471. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
  34472. if (inArray(requireFail, otherRecognizer) === -1) {
  34473. requireFail.push(otherRecognizer);
  34474. otherRecognizer.requireFailure(this);
  34475. }
  34476. return this;
  34477. },
  34478. /**
  34479. * drop the requireFailure link. it does not remove the link on the other recognizer.
  34480. * @param {Recognizer} otherRecognizer
  34481. * @returns {Recognizer} this
  34482. */
  34483. dropRequireFailure: function(otherRecognizer) {
  34484. if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
  34485. return this;
  34486. }
  34487. otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
  34488. var index = inArray(this.requireFail, otherRecognizer);
  34489. if (index > -1) {
  34490. this.requireFail.splice(index, 1);
  34491. }
  34492. return this;
  34493. },
  34494. /**
  34495. * has require failures boolean
  34496. * @returns {boolean}
  34497. */
  34498. hasRequireFailures: function() {
  34499. return this.requireFail.length > 0;
  34500. },
  34501. /**
  34502. * if the recognizer can recognize simultaneous with an other recognizer
  34503. * @param {Recognizer} otherRecognizer
  34504. * @returns {Boolean}
  34505. */
  34506. canRecognizeWith: function(otherRecognizer) {
  34507. return !!this.simultaneous[otherRecognizer.id];
  34508. },
  34509. /**
  34510. * You should use `tryEmit` instead of `emit` directly to check
  34511. * that all the needed recognizers has failed before emitting.
  34512. * @param {Object} input
  34513. */
  34514. emit: function(input) {
  34515. var self = this;
  34516. var state = this.state;
  34517. function emit(event) {
  34518. self.manager.emit(event, input);
  34519. }
  34520. // 'panstart' and 'panmove'
  34521. if (state < STATE_ENDED) {
  34522. emit(self.options.event + stateStr(state));
  34523. }
  34524. emit(self.options.event); // simple 'eventName' events
  34525. if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...)
  34526. emit(input.additionalEvent);
  34527. }
  34528. // panend and pancancel
  34529. if (state >= STATE_ENDED) {
  34530. emit(self.options.event + stateStr(state));
  34531. }
  34532. },
  34533. /**
  34534. * Check that all the require failure recognizers has failed,
  34535. * if true, it emits a gesture event,
  34536. * otherwise, setup the state to FAILED.
  34537. * @param {Object} input
  34538. */
  34539. tryEmit: function(input) {
  34540. if (this.canEmit()) {
  34541. return this.emit(input);
  34542. }
  34543. // it's failing anyway
  34544. this.state = STATE_FAILED;
  34545. },
  34546. /**
  34547. * can we emit?
  34548. * @returns {boolean}
  34549. */
  34550. canEmit: function() {
  34551. var i = 0;
  34552. while (i < this.requireFail.length) {
  34553. if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
  34554. return false;
  34555. }
  34556. i++;
  34557. }
  34558. return true;
  34559. },
  34560. /**
  34561. * update the recognizer
  34562. * @param {Object} inputData
  34563. */
  34564. recognize: function(inputData) {
  34565. // make a new copy of the inputData
  34566. // so we can change the inputData without messing up the other recognizers
  34567. var inputDataClone = assign({}, inputData);
  34568. // is is enabled and allow recognizing?
  34569. if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
  34570. this.reset();
  34571. this.state = STATE_FAILED;
  34572. return;
  34573. }
  34574. // reset when we've reached the end
  34575. if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
  34576. this.state = STATE_POSSIBLE;
  34577. }
  34578. this.state = this.process(inputDataClone);
  34579. // the recognizer has recognized a gesture
  34580. // so trigger an event
  34581. if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
  34582. this.tryEmit(inputDataClone);
  34583. }
  34584. },
  34585. /**
  34586. * return the state of the recognizer
  34587. * the actual recognizing happens in this method
  34588. * @virtual
  34589. * @param {Object} inputData
  34590. * @returns {Const} STATE
  34591. */
  34592. process: function(inputData) {}, // jshint ignore:line
  34593. /**
  34594. * return the preferred touch-action
  34595. * @virtual
  34596. * @returns {Array}
  34597. */
  34598. getTouchAction: function() {},
  34599. /**
  34600. * called when the gesture isn't allowed to recognize
  34601. * like when another is being recognized or it is disabled
  34602. * @virtual
  34603. */
  34604. reset: function() {}
  34605. };
  34606. /**
  34607. * get a usable string, used as event postfix
  34608. * @param {Const} state
  34609. * @returns {String} state
  34610. */
  34611. function stateStr(state) {
  34612. if (state & STATE_CANCELLED) {
  34613. return 'cancel';
  34614. } else if (state & STATE_ENDED) {
  34615. return 'end';
  34616. } else if (state & STATE_CHANGED) {
  34617. return 'move';
  34618. } else if (state & STATE_BEGAN) {
  34619. return 'start';
  34620. }
  34621. return '';
  34622. }
  34623. /**
  34624. * direction cons to string
  34625. * @param {Const} direction
  34626. * @returns {String}
  34627. */
  34628. function directionStr(direction) {
  34629. if (direction == DIRECTION_DOWN) {
  34630. return 'down';
  34631. } else if (direction == DIRECTION_UP) {
  34632. return 'up';
  34633. } else if (direction == DIRECTION_LEFT) {
  34634. return 'left';
  34635. } else if (direction == DIRECTION_RIGHT) {
  34636. return 'right';
  34637. }
  34638. return '';
  34639. }
  34640. /**
  34641. * get a recognizer by name if it is bound to a manager
  34642. * @param {Recognizer|String} otherRecognizer
  34643. * @param {Recognizer} recognizer
  34644. * @returns {Recognizer}
  34645. */
  34646. function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
  34647. var manager = recognizer.manager;
  34648. if (manager) {
  34649. return manager.get(otherRecognizer);
  34650. }
  34651. return otherRecognizer;
  34652. }
  34653. /**
  34654. * This recognizer is just used as a base for the simple attribute recognizers.
  34655. * @constructor
  34656. * @extends Recognizer
  34657. */
  34658. function AttrRecognizer() {
  34659. Recognizer.apply(this, arguments);
  34660. }
  34661. inherit(AttrRecognizer, Recognizer, {
  34662. /**
  34663. * @namespace
  34664. * @memberof AttrRecognizer
  34665. */
  34666. defaults: {
  34667. /**
  34668. * @type {Number}
  34669. * @default 1
  34670. */
  34671. pointers: 1
  34672. },
  34673. /**
  34674. * Used to check if it the recognizer receives valid input, like input.distance > 10.
  34675. * @memberof AttrRecognizer
  34676. * @param {Object} input
  34677. * @returns {Boolean} recognized
  34678. */
  34679. attrTest: function(input) {
  34680. var optionPointers = this.options.pointers;
  34681. return optionPointers === 0 || input.pointers.length === optionPointers;
  34682. },
  34683. /**
  34684. * Process the input and return the state for the recognizer
  34685. * @memberof AttrRecognizer
  34686. * @param {Object} input
  34687. * @returns {*} State
  34688. */
  34689. process: function(input) {
  34690. var state = this.state;
  34691. var eventType = input.eventType;
  34692. var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
  34693. var isValid = this.attrTest(input);
  34694. // on cancel input and we've recognized before, return STATE_CANCELLED
  34695. if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
  34696. return state | STATE_CANCELLED;
  34697. } else if (isRecognized || isValid) {
  34698. if (eventType & INPUT_END) {
  34699. return state | STATE_ENDED;
  34700. } else if (!(state & STATE_BEGAN)) {
  34701. return STATE_BEGAN;
  34702. }
  34703. return state | STATE_CHANGED;
  34704. }
  34705. return STATE_FAILED;
  34706. }
  34707. });
  34708. /**
  34709. * Pan
  34710. * Recognized when the pointer is down and moved in the allowed direction.
  34711. * @constructor
  34712. * @extends AttrRecognizer
  34713. */
  34714. function PanRecognizer() {
  34715. AttrRecognizer.apply(this, arguments);
  34716. this.pX = null;
  34717. this.pY = null;
  34718. }
  34719. inherit(PanRecognizer, AttrRecognizer, {
  34720. /**
  34721. * @namespace
  34722. * @memberof PanRecognizer
  34723. */
  34724. defaults: {
  34725. event: 'pan',
  34726. threshold: 10,
  34727. pointers: 1,
  34728. direction: DIRECTION_ALL
  34729. },
  34730. getTouchAction: function() {
  34731. var direction = this.options.direction;
  34732. var actions = [];
  34733. if (direction & DIRECTION_HORIZONTAL) {
  34734. actions.push(TOUCH_ACTION_PAN_Y);
  34735. }
  34736. if (direction & DIRECTION_VERTICAL) {
  34737. actions.push(TOUCH_ACTION_PAN_X);
  34738. }
  34739. return actions;
  34740. },
  34741. directionTest: function(input) {
  34742. var options = this.options;
  34743. var hasMoved = true;
  34744. var distance = input.distance;
  34745. var direction = input.direction;
  34746. var x = input.deltaX;
  34747. var y = input.deltaY;
  34748. // lock to axis?
  34749. if (!(direction & options.direction)) {
  34750. if (options.direction & DIRECTION_HORIZONTAL) {
  34751. direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
  34752. hasMoved = x != this.pX;
  34753. distance = Math.abs(input.deltaX);
  34754. } else {
  34755. direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
  34756. hasMoved = y != this.pY;
  34757. distance = Math.abs(input.deltaY);
  34758. }
  34759. }
  34760. input.direction = direction;
  34761. return hasMoved && distance > options.threshold && direction & options.direction;
  34762. },
  34763. attrTest: function(input) {
  34764. return AttrRecognizer.prototype.attrTest.call(this, input) &&
  34765. (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
  34766. },
  34767. emit: function(input) {
  34768. this.pX = input.deltaX;
  34769. this.pY = input.deltaY;
  34770. var direction = directionStr(input.direction);
  34771. if (direction) {
  34772. input.additionalEvent = this.options.event + direction;
  34773. }
  34774. this._super.emit.call(this, input);
  34775. }
  34776. });
  34777. /**
  34778. * Pinch
  34779. * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
  34780. * @constructor
  34781. * @extends AttrRecognizer
  34782. */
  34783. function PinchRecognizer() {
  34784. AttrRecognizer.apply(this, arguments);
  34785. }
  34786. inherit(PinchRecognizer, AttrRecognizer, {
  34787. /**
  34788. * @namespace
  34789. * @memberof PinchRecognizer
  34790. */
  34791. defaults: {
  34792. event: 'pinch',
  34793. threshold: 0,
  34794. pointers: 2
  34795. },
  34796. getTouchAction: function() {
  34797. return [TOUCH_ACTION_NONE];
  34798. },
  34799. attrTest: function(input) {
  34800. return this._super.attrTest.call(this, input) &&
  34801. (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
  34802. },
  34803. emit: function(input) {
  34804. if (input.scale !== 1) {
  34805. var inOut = input.scale < 1 ? 'in' : 'out';
  34806. input.additionalEvent = this.options.event + inOut;
  34807. }
  34808. this._super.emit.call(this, input);
  34809. }
  34810. });
  34811. /**
  34812. * Press
  34813. * Recognized when the pointer is down for x ms without any movement.
  34814. * @constructor
  34815. * @extends Recognizer
  34816. */
  34817. function PressRecognizer() {
  34818. Recognizer.apply(this, arguments);
  34819. this._timer = null;
  34820. this._input = null;
  34821. }
  34822. inherit(PressRecognizer, Recognizer, {
  34823. /**
  34824. * @namespace
  34825. * @memberof PressRecognizer
  34826. */
  34827. defaults: {
  34828. event: 'press',
  34829. pointers: 1,
  34830. time: 251, // minimal time of the pointer to be pressed
  34831. threshold: 9 // a minimal movement is ok, but keep it low
  34832. },
  34833. getTouchAction: function() {
  34834. return [TOUCH_ACTION_AUTO];
  34835. },
  34836. process: function(input) {
  34837. var options = this.options;
  34838. var validPointers = input.pointers.length === options.pointers;
  34839. var validMovement = input.distance < options.threshold;
  34840. var validTime = input.deltaTime > options.time;
  34841. this._input = input;
  34842. // we only allow little movement
  34843. // and we've reached an end event, so a tap is possible
  34844. if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
  34845. this.reset();
  34846. } else if (input.eventType & INPUT_START) {
  34847. this.reset();
  34848. this._timer = setTimeoutContext(function() {
  34849. this.state = STATE_RECOGNIZED;
  34850. this.tryEmit();
  34851. }, options.time, this);
  34852. } else if (input.eventType & INPUT_END) {
  34853. return STATE_RECOGNIZED;
  34854. }
  34855. return STATE_FAILED;
  34856. },
  34857. reset: function() {
  34858. clearTimeout(this._timer);
  34859. },
  34860. emit: function(input) {
  34861. if (this.state !== STATE_RECOGNIZED) {
  34862. return;
  34863. }
  34864. if (input && (input.eventType & INPUT_END)) {
  34865. this.manager.emit(this.options.event + 'up', input);
  34866. } else {
  34867. this._input.timeStamp = now();
  34868. this.manager.emit(this.options.event, this._input);
  34869. }
  34870. }
  34871. });
  34872. /**
  34873. * Rotate
  34874. * Recognized when two or more pointer are moving in a circular motion.
  34875. * @constructor
  34876. * @extends AttrRecognizer
  34877. */
  34878. function RotateRecognizer() {
  34879. AttrRecognizer.apply(this, arguments);
  34880. }
  34881. inherit(RotateRecognizer, AttrRecognizer, {
  34882. /**
  34883. * @namespace
  34884. * @memberof RotateRecognizer
  34885. */
  34886. defaults: {
  34887. event: 'rotate',
  34888. threshold: 0,
  34889. pointers: 2
  34890. },
  34891. getTouchAction: function() {
  34892. return [TOUCH_ACTION_NONE];
  34893. },
  34894. attrTest: function(input) {
  34895. return this._super.attrTest.call(this, input) &&
  34896. (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
  34897. }
  34898. });
  34899. /**
  34900. * Swipe
  34901. * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
  34902. * @constructor
  34903. * @extends AttrRecognizer
  34904. */
  34905. function SwipeRecognizer() {
  34906. AttrRecognizer.apply(this, arguments);
  34907. }
  34908. inherit(SwipeRecognizer, AttrRecognizer, {
  34909. /**
  34910. * @namespace
  34911. * @memberof SwipeRecognizer
  34912. */
  34913. defaults: {
  34914. event: 'swipe',
  34915. threshold: 10,
  34916. velocity: 0.3,
  34917. direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
  34918. pointers: 1
  34919. },
  34920. getTouchAction: function() {
  34921. return PanRecognizer.prototype.getTouchAction.call(this);
  34922. },
  34923. attrTest: function(input) {
  34924. var direction = this.options.direction;
  34925. var velocity;
  34926. if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
  34927. velocity = input.overallVelocity;
  34928. } else if (direction & DIRECTION_HORIZONTAL) {
  34929. velocity = input.overallVelocityX;
  34930. } else if (direction & DIRECTION_VERTICAL) {
  34931. velocity = input.overallVelocityY;
  34932. }
  34933. return this._super.attrTest.call(this, input) &&
  34934. direction & input.offsetDirection &&
  34935. input.distance > this.options.threshold &&
  34936. input.maxPointers == this.options.pointers &&
  34937. abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
  34938. },
  34939. emit: function(input) {
  34940. var direction = directionStr(input.offsetDirection);
  34941. if (direction) {
  34942. this.manager.emit(this.options.event + direction, input);
  34943. }
  34944. this.manager.emit(this.options.event, input);
  34945. }
  34946. });
  34947. /**
  34948. * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
  34949. * between the given interval and position. The delay option can be used to recognize multi-taps without firing
  34950. * a single tap.
  34951. *
  34952. * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
  34953. * multi-taps being recognized.
  34954. * @constructor
  34955. * @extends Recognizer
  34956. */
  34957. function TapRecognizer() {
  34958. Recognizer.apply(this, arguments);
  34959. // previous time and center,
  34960. // used for tap counting
  34961. this.pTime = false;
  34962. this.pCenter = false;
  34963. this._timer = null;
  34964. this._input = null;
  34965. this.count = 0;
  34966. }
  34967. inherit(TapRecognizer, Recognizer, {
  34968. /**
  34969. * @namespace
  34970. * @memberof PinchRecognizer
  34971. */
  34972. defaults: {
  34973. event: 'tap',
  34974. pointers: 1,
  34975. taps: 1,
  34976. interval: 300, // max time between the multi-tap taps
  34977. time: 250, // max time of the pointer to be down (like finger on the screen)
  34978. threshold: 9, // a minimal movement is ok, but keep it low
  34979. posThreshold: 10 // a multi-tap can be a bit off the initial position
  34980. },
  34981. getTouchAction: function() {
  34982. return [TOUCH_ACTION_MANIPULATION];
  34983. },
  34984. process: function(input) {
  34985. var options = this.options;
  34986. var validPointers = input.pointers.length === options.pointers;
  34987. var validMovement = input.distance < options.threshold;
  34988. var validTouchTime = input.deltaTime < options.time;
  34989. this.reset();
  34990. if ((input.eventType & INPUT_START) && (this.count === 0)) {
  34991. return this.failTimeout();
  34992. }
  34993. // we only allow little movement
  34994. // and we've reached an end event, so a tap is possible
  34995. if (validMovement && validTouchTime && validPointers) {
  34996. if (input.eventType != INPUT_END) {
  34997. return this.failTimeout();
  34998. }
  34999. var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
  35000. var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
  35001. this.pTime = input.timeStamp;
  35002. this.pCenter = input.center;
  35003. if (!validMultiTap || !validInterval) {
  35004. this.count = 1;
  35005. } else {
  35006. this.count += 1;
  35007. }
  35008. this._input = input;
  35009. // if tap count matches we have recognized it,
  35010. // else it has began recognizing...
  35011. var tapCount = this.count % options.taps;
  35012. if (tapCount === 0) {
  35013. // no failing requirements, immediately trigger the tap event
  35014. // or wait as long as the multitap interval to trigger
  35015. if (!this.hasRequireFailures()) {
  35016. return STATE_RECOGNIZED;
  35017. } else {
  35018. this._timer = setTimeoutContext(function() {
  35019. this.state = STATE_RECOGNIZED;
  35020. this.tryEmit();
  35021. }, options.interval, this);
  35022. return STATE_BEGAN;
  35023. }
  35024. }
  35025. }
  35026. return STATE_FAILED;
  35027. },
  35028. failTimeout: function() {
  35029. this._timer = setTimeoutContext(function() {
  35030. this.state = STATE_FAILED;
  35031. }, this.options.interval, this);
  35032. return STATE_FAILED;
  35033. },
  35034. reset: function() {
  35035. clearTimeout(this._timer);
  35036. },
  35037. emit: function() {
  35038. if (this.state == STATE_RECOGNIZED) {
  35039. this._input.tapCount = this.count;
  35040. this.manager.emit(this.options.event, this._input);
  35041. }
  35042. }
  35043. });
  35044. /**
  35045. * Simple way to create a manager with a default set of recognizers.
  35046. * @param {HTMLElement} element
  35047. * @param {Object} [options]
  35048. * @constructor
  35049. */
  35050. function Hammer(element, options) {
  35051. options = options || {};
  35052. options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
  35053. return new Manager(element, options);
  35054. }
  35055. /**
  35056. * @const {string}
  35057. */
  35058. Hammer.VERSION = '2.0.7';
  35059. /**
  35060. * default settings
  35061. * @namespace
  35062. */
  35063. Hammer.defaults = {
  35064. /**
  35065. * set if DOM events are being triggered.
  35066. * But this is slower and unused by simple implementations, so disabled by default.
  35067. * @type {Boolean}
  35068. * @default false
  35069. */
  35070. domEvents: false,
  35071. /**
  35072. * The value for the touchAction property/fallback.
  35073. * When set to `compute` it will magically set the correct value based on the added recognizers.
  35074. * @type {String}
  35075. * @default compute
  35076. */
  35077. touchAction: TOUCH_ACTION_COMPUTE,
  35078. /**
  35079. * @type {Boolean}
  35080. * @default true
  35081. */
  35082. enable: true,
  35083. /**
  35084. * EXPERIMENTAL FEATURE -- can be removed/changed
  35085. * Change the parent input target element.
  35086. * If Null, then it is being set the to main element.
  35087. * @type {Null|EventTarget}
  35088. * @default null
  35089. */
  35090. inputTarget: null,
  35091. /**
  35092. * force an input class
  35093. * @type {Null|Function}
  35094. * @default null
  35095. */
  35096. inputClass: null,
  35097. /**
  35098. * Default recognizer setup when calling `Hammer()`
  35099. * When creating a new Manager these will be skipped.
  35100. * @type {Array}
  35101. */
  35102. preset: [
  35103. // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
  35104. [RotateRecognizer, { enable: false }],
  35105. [PinchRecognizer, { enable: false },
  35106. ['rotate']
  35107. ],
  35108. [SwipeRecognizer, { direction: DIRECTION_HORIZONTAL }],
  35109. [PanRecognizer, { direction: DIRECTION_HORIZONTAL },
  35110. ['swipe']
  35111. ],
  35112. [TapRecognizer],
  35113. [TapRecognizer, { event: 'doubletap', taps: 2 },
  35114. ['tap']
  35115. ],
  35116. [PressRecognizer]
  35117. ],
  35118. /**
  35119. * Some CSS properties can be used to improve the working of Hammer.
  35120. * Add them to this method and they will be set when creating a new Manager.
  35121. * @namespace
  35122. */
  35123. cssProps: {
  35124. /**
  35125. * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
  35126. * @type {String}
  35127. * @default 'none'
  35128. */
  35129. userSelect: 'none',
  35130. /**
  35131. * Disable the Windows Phone grippers when pressing an element.
  35132. * @type {String}
  35133. * @default 'none'
  35134. */
  35135. touchSelect: 'none',
  35136. /**
  35137. * Disables the default callout shown when you touch and hold a touch target.
  35138. * On iOS, when you touch and hold a touch target such as a link, Safari displays
  35139. * a callout containing information about the link. This property allows you to disable that callout.
  35140. * @type {String}
  35141. * @default 'none'
  35142. */
  35143. touchCallout: 'none',
  35144. /**
  35145. * Specifies whether zooming is enabled. Used by IE10>
  35146. * @type {String}
  35147. * @default 'none'
  35148. */
  35149. contentZooming: 'none',
  35150. /**
  35151. * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
  35152. * @type {String}
  35153. * @default 'none'
  35154. */
  35155. userDrag: 'none',
  35156. /**
  35157. * Overrides the highlight color shown when the user taps a link or a JavaScript
  35158. * clickable element in iOS. This property obeys the alpha value, if specified.
  35159. * @type {String}
  35160. * @default 'rgba(0,0,0,0)'
  35161. */
  35162. tapHighlightColor: 'rgba(0,0,0,0)'
  35163. }
  35164. };
  35165. var STOP = 1;
  35166. var FORCED_STOP = 2;
  35167. /**
  35168. * Manager
  35169. * @param {HTMLElement} element
  35170. * @param {Object} [options]
  35171. * @constructor
  35172. */
  35173. function Manager(element, options) {
  35174. this.options = assign({}, Hammer.defaults, options || {});
  35175. this.options.inputTarget = this.options.inputTarget || element;
  35176. this.handlers = {};
  35177. this.session = {};
  35178. this.recognizers = [];
  35179. this.oldCssProps = {};
  35180. this.element = element;
  35181. this.input = createInputInstance(this);
  35182. this.touchAction = new TouchAction(this, this.options.touchAction);
  35183. toggleCssProps(this, true);
  35184. each(this.options.recognizers, function(item) {
  35185. var recognizer = this.add(new(item[0])(item[1]));
  35186. item[2] && recognizer.recognizeWith(item[2]);
  35187. item[3] && recognizer.requireFailure(item[3]);
  35188. }, this);
  35189. }
  35190. Manager.prototype = {
  35191. /**
  35192. * set options
  35193. * @param {Object} options
  35194. * @returns {Manager}
  35195. */
  35196. set: function(options) {
  35197. assign(this.options, options);
  35198. // Options that need a little more setup
  35199. if (options.touchAction) {
  35200. this.touchAction.update();
  35201. }
  35202. if (options.inputTarget) {
  35203. // Clean up existing event listeners and reinitialize
  35204. this.input.destroy();
  35205. this.input.target = options.inputTarget;
  35206. this.input.init();
  35207. }
  35208. return this;
  35209. },
  35210. /**
  35211. * stop recognizing for this session.
  35212. * This session will be discarded, when a new [input]start event is fired.
  35213. * When forced, the recognizer cycle is stopped immediately.
  35214. * @param {Boolean} [force]
  35215. */
  35216. stop: function(force) {
  35217. this.session.stopped = force ? FORCED_STOP : STOP;
  35218. },
  35219. /**
  35220. * run the recognizers!
  35221. * called by the inputHandler function on every movement of the pointers (touches)
  35222. * it walks through all the recognizers and tries to detect the gesture that is being made
  35223. * @param {Object} inputData
  35224. */
  35225. recognize: function(inputData) {
  35226. var session = this.session;
  35227. if (session.stopped) {
  35228. return;
  35229. }
  35230. // run the touch-action polyfill
  35231. this.touchAction.preventDefaults(inputData);
  35232. var recognizer;
  35233. var recognizers = this.recognizers;
  35234. // this holds the recognizer that is being recognized.
  35235. // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
  35236. // if no recognizer is detecting a thing, it is set to `null`
  35237. var curRecognizer = session.curRecognizer;
  35238. // reset when the last recognizer is recognized
  35239. // or when we're in a new session
  35240. if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
  35241. curRecognizer = session.curRecognizer = null;
  35242. }
  35243. var i = 0;
  35244. while (i < recognizers.length) {
  35245. recognizer = recognizers[i];
  35246. // find out if we are allowed try to recognize the input for this one.
  35247. // 1. allow if the session is NOT forced stopped (see the .stop() method)
  35248. // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
  35249. // that is being recognized.
  35250. // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
  35251. // this can be setup with the `recognizeWith()` method on the recognizer.
  35252. if (session.stopped !== FORCED_STOP && ( // 1
  35253. !curRecognizer || recognizer == curRecognizer || // 2
  35254. recognizer.canRecognizeWith(curRecognizer))) { // 3
  35255. recognizer.recognize(inputData);
  35256. } else {
  35257. recognizer.reset();
  35258. }
  35259. // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
  35260. // current active recognizer. but only if we don't already have an active recognizer
  35261. if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
  35262. curRecognizer = session.curRecognizer = recognizer;
  35263. }
  35264. i++;
  35265. }
  35266. },
  35267. /**
  35268. * get a recognizer by its event name.
  35269. * @param {Recognizer|String} recognizer
  35270. * @returns {Recognizer|Null}
  35271. */
  35272. get: function(recognizer) {
  35273. if (recognizer instanceof Recognizer) {
  35274. return recognizer;
  35275. }
  35276. var recognizers = this.recognizers;
  35277. for (var i = 0; i < recognizers.length; i++) {
  35278. if (recognizers[i].options.event == recognizer) {
  35279. return recognizers[i];
  35280. }
  35281. }
  35282. return null;
  35283. },
  35284. /**
  35285. * add a recognizer to the manager
  35286. * existing recognizers with the same event name will be removed
  35287. * @param {Recognizer} recognizer
  35288. * @returns {Recognizer|Manager}
  35289. */
  35290. add: function(recognizer) {
  35291. if (invokeArrayArg(recognizer, 'add', this)) {
  35292. return this;
  35293. }
  35294. // remove existing
  35295. var existing = this.get(recognizer.options.event);
  35296. if (existing) {
  35297. this.remove(existing);
  35298. }
  35299. this.recognizers.push(recognizer);
  35300. recognizer.manager = this;
  35301. this.touchAction.update();
  35302. return recognizer;
  35303. },
  35304. /**
  35305. * remove a recognizer by name or instance
  35306. * @param {Recognizer|String} recognizer
  35307. * @returns {Manager}
  35308. */
  35309. remove: function(recognizer) {
  35310. if (invokeArrayArg(recognizer, 'remove', this)) {
  35311. return this;
  35312. }
  35313. recognizer = this.get(recognizer);
  35314. // let's make sure this recognizer exists
  35315. if (recognizer) {
  35316. var recognizers = this.recognizers;
  35317. var index = inArray(recognizers, recognizer);
  35318. if (index !== -1) {
  35319. recognizers.splice(index, 1);
  35320. this.touchAction.update();
  35321. }
  35322. }
  35323. return this;
  35324. },
  35325. /**
  35326. * bind event
  35327. * @param {String} events
  35328. * @param {Function} handler
  35329. * @returns {EventEmitter} this
  35330. */
  35331. on: function(events, handler) {
  35332. if (events === undefined) {
  35333. return;
  35334. }
  35335. if (handler === undefined) {
  35336. return;
  35337. }
  35338. var handlers = this.handlers;
  35339. each(splitStr(events), function(event) {
  35340. handlers[event] = handlers[event] || [];
  35341. handlers[event].push(handler);
  35342. });
  35343. return this;
  35344. },
  35345. /**
  35346. * unbind event, leave emit blank to remove all handlers
  35347. * @param {String} events
  35348. * @param {Function} [handler]
  35349. * @returns {EventEmitter} this
  35350. */
  35351. off: function(events, handler) {
  35352. if (events === undefined) {
  35353. return;
  35354. }
  35355. var handlers = this.handlers;
  35356. each(splitStr(events), function(event) {
  35357. if (!handler) {
  35358. delete handlers[event];
  35359. } else {
  35360. handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
  35361. }
  35362. });
  35363. return this;
  35364. },
  35365. /**
  35366. * emit event to the listeners
  35367. * @param {String} event
  35368. * @param {Object} data
  35369. */
  35370. emit: function(event, data) {
  35371. // we also want to trigger dom events
  35372. if (this.options.domEvents) {
  35373. triggerDomEvent(event, data);
  35374. }
  35375. // no handlers, so skip it all
  35376. var handlers = this.handlers[event] && this.handlers[event].slice();
  35377. if (!handlers || !handlers.length) {
  35378. return;
  35379. }
  35380. data.type = event;
  35381. data.preventDefault = function() {
  35382. data.srcEvent.preventDefault();
  35383. };
  35384. var i = 0;
  35385. while (i < handlers.length) {
  35386. handlers[i](data);
  35387. i++;
  35388. }
  35389. },
  35390. /**
  35391. * destroy the manager and unbinds all events
  35392. * it doesn't unbind dom events, that is the user own responsibility
  35393. */
  35394. destroy: function() {
  35395. this.element && toggleCssProps(this, false);
  35396. this.handlers = {};
  35397. this.session = {};
  35398. this.input.destroy();
  35399. this.element = null;
  35400. }
  35401. };
  35402. /**
  35403. * add/remove the css properties as defined in manager.options.cssProps
  35404. * @param {Manager} manager
  35405. * @param {Boolean} add
  35406. */
  35407. function toggleCssProps(manager, add) {
  35408. var element = manager.element;
  35409. if (!element.style) {
  35410. return;
  35411. }
  35412. var prop;
  35413. each(manager.options.cssProps, function(value, name) {
  35414. prop = prefixed(element.style, name);
  35415. if (add) {
  35416. manager.oldCssProps[prop] = element.style[prop];
  35417. element.style[prop] = value;
  35418. } else {
  35419. element.style[prop] = manager.oldCssProps[prop] || '';
  35420. }
  35421. });
  35422. if (!add) {
  35423. manager.oldCssProps = {};
  35424. }
  35425. }
  35426. /**
  35427. * trigger dom event
  35428. * @param {String} event
  35429. * @param {Object} data
  35430. */
  35431. function triggerDomEvent(event, data) {
  35432. var gestureEvent = document.createEvent('Event');
  35433. gestureEvent.initEvent(event, true, true);
  35434. gestureEvent.gesture = data;
  35435. data.target.dispatchEvent(gestureEvent);
  35436. }
  35437. assign(Hammer, {
  35438. INPUT_START: INPUT_START,
  35439. INPUT_MOVE: INPUT_MOVE,
  35440. INPUT_END: INPUT_END,
  35441. INPUT_CANCEL: INPUT_CANCEL,
  35442. STATE_POSSIBLE: STATE_POSSIBLE,
  35443. STATE_BEGAN: STATE_BEGAN,
  35444. STATE_CHANGED: STATE_CHANGED,
  35445. STATE_ENDED: STATE_ENDED,
  35446. STATE_RECOGNIZED: STATE_RECOGNIZED,
  35447. STATE_CANCELLED: STATE_CANCELLED,
  35448. STATE_FAILED: STATE_FAILED,
  35449. DIRECTION_NONE: DIRECTION_NONE,
  35450. DIRECTION_LEFT: DIRECTION_LEFT,
  35451. DIRECTION_RIGHT: DIRECTION_RIGHT,
  35452. DIRECTION_UP: DIRECTION_UP,
  35453. DIRECTION_DOWN: DIRECTION_DOWN,
  35454. DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
  35455. DIRECTION_VERTICAL: DIRECTION_VERTICAL,
  35456. DIRECTION_ALL: DIRECTION_ALL,
  35457. Manager: Manager,
  35458. Input: Input,
  35459. TouchAction: TouchAction,
  35460. TouchInput: TouchInput,
  35461. MouseInput: MouseInput,
  35462. PointerEventInput: PointerEventInput,
  35463. TouchMouseInput: TouchMouseInput,
  35464. SingleTouchInput: SingleTouchInput,
  35465. Recognizer: Recognizer,
  35466. AttrRecognizer: AttrRecognizer,
  35467. Tap: TapRecognizer,
  35468. Pan: PanRecognizer,
  35469. Swipe: SwipeRecognizer,
  35470. Pinch: PinchRecognizer,
  35471. Rotate: RotateRecognizer,
  35472. Press: PressRecognizer,
  35473. on: addEventListeners,
  35474. off: removeEventListeners,
  35475. each: each,
  35476. merge: merge,
  35477. extend: extend,
  35478. assign: assign,
  35479. inherit: inherit,
  35480. bindFn: bindFn,
  35481. prefixed: prefixed
  35482. });
  35483. // this prevents errors when Hammer is loaded in the presence of an AMD
  35484. // style loader but by script tag, not by the loader.
  35485. var freeGlobal = (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); // jshint ignore:line
  35486. freeGlobal.Hammer = Hammer;
  35487. if (true) {
  35488. !(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
  35489. return Hammer;
  35490. }.call(exports, __webpack_require__, exports, module),
  35491. __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  35492. } else if (typeof module != 'undefined' && module.exports) {
  35493. module.exports = Hammer;
  35494. } else {
  35495. window[exportName] = Hammer;
  35496. }
  35497. })(window, document, 'Hammer');
  35498. /***/
  35499. }),
  35500. /* 177 */
  35501. /***/
  35502. (function(module, exports, __webpack_require__) {
  35503. "use strict";
  35504. // utils
  35505. exports.util = __webpack_require__(2);
  35506. exports.DOMutil = __webpack_require__(14);
  35507. // data
  35508. exports.DataSet = __webpack_require__(11);
  35509. exports.DataView = __webpack_require__(12);
  35510. exports.Queue = __webpack_require__(43);
  35511. // Timeline
  35512. exports.Timeline = __webpack_require__(178);
  35513. exports.Graph2d = __webpack_require__(180);
  35514. exports.timeline = {
  35515. Core: __webpack_require__(65),
  35516. DateUtil: __webpack_require__(36),
  35517. Range: __webpack_require__(64),
  35518. stack: __webpack_require__(100),
  35519. TimeStep: __webpack_require__(66),
  35520. components: {
  35521. items: {
  35522. Item: __webpack_require__(38),
  35523. BackgroundItem: __webpack_require__(103),
  35524. BoxItem: __webpack_require__(101),
  35525. PointItem: __webpack_require__(102),
  35526. RangeItem: __webpack_require__(70)
  35527. },
  35528. BackgroundGroup: __webpack_require__(69),
  35529. Component: __webpack_require__(16),
  35530. CurrentTime: __webpack_require__(67),
  35531. CustomTime: __webpack_require__(46),
  35532. DataAxis: __webpack_require__(107),
  35533. DataScale: __webpack_require__(108),
  35534. GraphGroup: __webpack_require__(109),
  35535. Group: __webpack_require__(68),
  35536. ItemSet: __webpack_require__(99),
  35537. Legend: __webpack_require__(112),
  35538. LineGraph: __webpack_require__(106),
  35539. TimeAxis: __webpack_require__(45)
  35540. }
  35541. };
  35542. // bundled external libraries
  35543. exports.moment = __webpack_require__(9);
  35544. exports.Hammer = __webpack_require__(10);
  35545. exports.keycharm = __webpack_require__(35);
  35546. /***/
  35547. }),
  35548. /* 178 */
  35549. /***/
  35550. (function(module, exports, __webpack_require__) {
  35551. "use strict";
  35552. var moment = __webpack_require__(9);
  35553. var util = __webpack_require__(2);
  35554. var DataSet = __webpack_require__(11);
  35555. var DataView = __webpack_require__(12);
  35556. var Range = __webpack_require__(64);
  35557. var Core = __webpack_require__(65);
  35558. var TimeAxis = __webpack_require__(45);
  35559. var CurrentTime = __webpack_require__(67);
  35560. var CustomTime = __webpack_require__(46);
  35561. var ItemSet = __webpack_require__(99);
  35562. var printStyle = __webpack_require__(15).printStyle;
  35563. var allOptions = __webpack_require__(105).allOptions;
  35564. var configureOptions = __webpack_require__(105).configureOptions;
  35565. var Configurator = __webpack_require__(71)['default'];
  35566. var Validator = __webpack_require__(15)['default'];
  35567. /**
  35568. * Create a timeline visualization
  35569. * @param {HTMLElement} container
  35570. * @param {vis.DataSet | vis.DataView | Array} [items]
  35571. * @param {vis.DataSet | vis.DataView | Array} [groups]
  35572. * @param {Object} [options] See Timeline.setOptions for the available options.
  35573. * @constructor Timeline
  35574. * @extends Core
  35575. */
  35576. function Timeline(container, items, groups, options) {
  35577. if (!(this instanceof Timeline)) {
  35578. throw new SyntaxError('Constructor must be called with the new operator');
  35579. }
  35580. // if the third element is options, the forth is groups (optionally);
  35581. if (!(Array.isArray(groups) || groups instanceof DataSet || groups instanceof DataView) && groups instanceof Object) {
  35582. var forthArgument = options;
  35583. options = groups;
  35584. groups = forthArgument;
  35585. }
  35586. // TODO: REMOVE THIS in the next MAJOR release
  35587. // see https://github.com/almende/vis/issues/2511
  35588. if (options && options.throttleRedraw) {
  35589. console.warn("Timeline option \"throttleRedraw\" is DEPRICATED and no longer supported. It will be removed in the next MAJOR release.");
  35590. }
  35591. var me = this;
  35592. this.defaultOptions = {
  35593. start: null,
  35594. end: null,
  35595. autoResize: true,
  35596. orientation: {
  35597. axis: 'bottom', // axis orientation: 'bottom', 'top', or 'both'
  35598. item: 'bottom' // not relevant
  35599. },
  35600. moment: moment,
  35601. width: null,
  35602. height: null,
  35603. maxHeight: null,
  35604. minHeight: null
  35605. };
  35606. this.options = util.deepExtend({}, this.defaultOptions);
  35607. // Create the DOM, props, and emitter
  35608. this._create(container);
  35609. if (!options || options && typeof options.rtl == "undefined") {
  35610. this.dom.root.style.visibility = 'hidden';
  35611. var directionFromDom,
  35612. domNode = this.dom.root;
  35613. while (!directionFromDom && domNode) {
  35614. directionFromDom = window.getComputedStyle(domNode, null).direction;
  35615. domNode = domNode.parentElement;
  35616. }
  35617. this.options.rtl = directionFromDom && directionFromDom.toLowerCase() == "rtl";
  35618. } else {
  35619. this.options.rtl = options.rtl;
  35620. }
  35621. this.options.rollingMode = options && options.rollingMode;
  35622. this.options.onInitialDrawComplete = options && options.onInitialDrawComplete;
  35623. // all components listed here will be repainted automatically
  35624. this.components = [];
  35625. this.body = {
  35626. dom: this.dom,
  35627. domProps: this.props,
  35628. emitter: {
  35629. on: this.on.bind(this),
  35630. off: this.off.bind(this),
  35631. emit: this.emit.bind(this)
  35632. },
  35633. hiddenDates: [],
  35634. util: {
  35635. getScale: function getScale() {
  35636. return me.timeAxis.step.scale;
  35637. },
  35638. getStep: function getStep() {
  35639. return me.timeAxis.step.step;
  35640. },
  35641. toScreen: me._toScreen.bind(me),
  35642. toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width
  35643. toTime: me._toTime.bind(me),
  35644. toGlobalTime: me._toGlobalTime.bind(me)
  35645. }
  35646. };
  35647. // range
  35648. this.range = new Range(this.body, this.options);
  35649. this.components.push(this.range);
  35650. this.body.range = this.range;
  35651. // time axis
  35652. this.timeAxis = new TimeAxis(this.body, this.options);
  35653. this.timeAxis2 = null; // used in case of orientation option 'both'
  35654. this.components.push(this.timeAxis);
  35655. // current time bar
  35656. this.currentTime = new CurrentTime(this.body, this.options);
  35657. this.components.push(this.currentTime);
  35658. // item set
  35659. this.itemSet = new ItemSet(this.body, this.options);
  35660. this.components.push(this.itemSet);
  35661. this.itemsData = null; // DataSet
  35662. this.groupsData = null; // DataSet
  35663. this.dom.root.onclick = function(event) {
  35664. me.emit('click', me.getEventProperties(event));
  35665. };
  35666. this.dom.root.ondblclick = function(event) {
  35667. me.emit('doubleClick', me.getEventProperties(event));
  35668. };
  35669. this.dom.root.oncontextmenu = function(event) {
  35670. me.emit('contextmenu', me.getEventProperties(event));
  35671. };
  35672. this.dom.root.onmouseover = function(event) {
  35673. me.emit('mouseOver', me.getEventProperties(event));
  35674. };
  35675. if (window.PointerEvent) {
  35676. this.dom.root.onpointerdown = function(event) {
  35677. me.emit('mouseDown', me.getEventProperties(event));
  35678. };
  35679. this.dom.root.onpointermove = function(event) {
  35680. me.emit('mouseMove', me.getEventProperties(event));
  35681. };
  35682. this.dom.root.onpointerup = function(event) {
  35683. me.emit('mouseUp', me.getEventProperties(event));
  35684. };
  35685. } else {
  35686. this.dom.root.onmousemove = function(event) {
  35687. me.emit('mouseMove', me.getEventProperties(event));
  35688. };
  35689. this.dom.root.onmousedown = function(event) {
  35690. me.emit('mouseDown', me.getEventProperties(event));
  35691. };
  35692. this.dom.root.onmouseup = function(event) {
  35693. me.emit('mouseUp', me.getEventProperties(event));
  35694. };
  35695. }
  35696. //Single time autoscale/fit
  35697. this.initialFitDone = false;
  35698. this.on('changed', function() {
  35699. if (this.itemsData == null || this.options.rollingMode) return;
  35700. if (!me.initialFitDone) {
  35701. me.initialFitDone = true;
  35702. if (me.options.start != undefined || me.options.end != undefined) {
  35703. if (me.options.start == undefined || me.options.end == undefined) {
  35704. var range = me.getItemRange();
  35705. }
  35706. var start = me.options.start != undefined ? me.options.start : range.min;
  35707. var end = me.options.end != undefined ? me.options.end : range.max;
  35708. me.setWindow(start, end, { animation: false });
  35709. } else {
  35710. me.fit({ animation: false });
  35711. }
  35712. }
  35713. if (!me.initialDrawDone && me.initialRangeChangeDone) {
  35714. me.initialDrawDone = true;
  35715. me.dom.root.style.visibility = 'visible';
  35716. if (me.options.onInitialDrawComplete) {
  35717. setTimeout(function() {
  35718. return me.options.onInitialDrawComplete();
  35719. }, 0);
  35720. }
  35721. }
  35722. });
  35723. // apply options
  35724. if (options) {
  35725. this.setOptions(options);
  35726. }
  35727. // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS!
  35728. if (groups) {
  35729. this.setGroups(groups);
  35730. }
  35731. // create itemset
  35732. if (items) {
  35733. this.setItems(items);
  35734. }
  35735. // draw for the first time
  35736. this._redraw();
  35737. }
  35738. // Extend the functionality from Core
  35739. Timeline.prototype = new Core();
  35740. /**
  35741. * Load a configurator
  35742. * @return {Object}
  35743. * @private
  35744. */
  35745. Timeline.prototype._createConfigurator = function() {
  35746. return new Configurator(this, this.dom.container, configureOptions);
  35747. };
  35748. /**
  35749. * Force a redraw. The size of all items will be recalculated.
  35750. * Can be useful to manually redraw when option autoResize=false and the window
  35751. * has been resized, or when the items CSS has been changed.
  35752. *
  35753. * Note: this function will be overridden on construction with a trottled version
  35754. */
  35755. Timeline.prototype.redraw = function() {
  35756. this.itemSet && this.itemSet.markDirty({ refreshItems: true });
  35757. this._redraw();
  35758. };
  35759. Timeline.prototype.setOptions = function(options) {
  35760. // validate options
  35761. var errorFound = Validator.validate(options, allOptions);
  35762. if (errorFound === true) {
  35763. console.log('%cErrors have been found in the supplied options object.', printStyle);
  35764. }
  35765. Core.prototype.setOptions.call(this, options);
  35766. if ('type' in options) {
  35767. if (options.type !== this.options.type) {
  35768. this.options.type = options.type;
  35769. // force recreation of all items
  35770. var itemsData = this.itemsData;
  35771. if (itemsData) {
  35772. var selection = this.getSelection();
  35773. this.setItems(null); // remove all
  35774. this.setItems(itemsData); // add all
  35775. this.setSelection(selection); // restore selection
  35776. }
  35777. }
  35778. }
  35779. };
  35780. /**
  35781. * Set items
  35782. * @param {vis.DataSet | Array | null} items
  35783. */
  35784. Timeline.prototype.setItems = function(items) {
  35785. // convert to type DataSet when needed
  35786. var newDataSet;
  35787. if (!items) {
  35788. newDataSet = null;
  35789. } else if (items instanceof DataSet || items instanceof DataView) {
  35790. newDataSet = items;
  35791. } else {
  35792. // turn an array into a dataset
  35793. newDataSet = new DataSet(items, {
  35794. type: {
  35795. start: 'Date',
  35796. end: 'Date'
  35797. }
  35798. });
  35799. }
  35800. // set items
  35801. this.itemsData = newDataSet;
  35802. this.itemSet && this.itemSet.setItems(newDataSet);
  35803. };
  35804. /**
  35805. * Set groups
  35806. * @param {vis.DataSet | Array} groups
  35807. */
  35808. Timeline.prototype.setGroups = function(groups) {
  35809. // convert to type DataSet when needed
  35810. var newDataSet;
  35811. if (!groups) {
  35812. newDataSet = null;
  35813. } else {
  35814. var filter = function filter(group) {
  35815. return group.visible !== false;
  35816. };
  35817. if (groups instanceof DataSet || groups instanceof DataView) {
  35818. newDataSet = new DataView(groups, { filter: filter });
  35819. } else {
  35820. // turn an array into a dataset
  35821. newDataSet = new DataSet(groups.filter(filter));
  35822. }
  35823. }
  35824. this.groupsData = newDataSet;
  35825. this.itemSet.setGroups(newDataSet);
  35826. };
  35827. /**
  35828. * Set both items and groups in one go
  35829. * @param {{items: (Array | vis.DataSet), groups: (Array | vis.DataSet)}} data
  35830. */
  35831. Timeline.prototype.setData = function(data) {
  35832. if (data && data.groups) {
  35833. this.setGroups(data.groups);
  35834. }
  35835. if (data && data.items) {
  35836. this.setItems(data.items);
  35837. }
  35838. };
  35839. /**
  35840. * Set selected items by their id. Replaces the current selection
  35841. * Unknown id's are silently ignored.
  35842. * @param {string[] | string} [ids] An array with zero or more id's of the items to be
  35843. * selected. If ids is an empty array, all items will be
  35844. * unselected.
  35845. * @param {Object} [options] Available options:
  35846. * `focus: boolean`
  35847. * If true, focus will be set to the selected item(s)
  35848. * `animation: boolean | {duration: number, easingFunction: string}`
  35849. * If true (default), the range is animated
  35850. * smoothly to the new window. An object can be
  35851. * provided to specify duration and easing function.
  35852. * Default duration is 500 ms, and default easing
  35853. * function is 'easeInOutQuad'.
  35854. * Only applicable when option focus is true.
  35855. */
  35856. Timeline.prototype.setSelection = function(ids, options) {
  35857. this.itemSet && this.itemSet.setSelection(ids);
  35858. if (options && options.focus) {
  35859. this.focus(ids, options);
  35860. }
  35861. };
  35862. /**
  35863. * Get the selected items by their id
  35864. * @return {Array} ids The ids of the selected items
  35865. */
  35866. Timeline.prototype.getSelection = function() {
  35867. return this.itemSet && this.itemSet.getSelection() || [];
  35868. };
  35869. /**
  35870. * Adjust the visible window such that the selected item (or multiple items)
  35871. * are centered on screen.
  35872. * @param {string | String[]} id An item id or array with item ids
  35873. * @param {Object} [options] Available options:
  35874. * `animation: boolean | {duration: number, easingFunction: string}`
  35875. * If true (default), the range is animated
  35876. * smoothly to the new window. An object can be
  35877. * provided to specify duration and easing function.
  35878. * Default duration is 500 ms, and default easing
  35879. * function is 'easeInOutQuad'.
  35880. */
  35881. Timeline.prototype.focus = function(id, options) {
  35882. if (!this.itemsData || id == undefined) return;
  35883. var ids = Array.isArray(id) ? id : [id];
  35884. // get the specified item(s)
  35885. var itemsData = this.itemsData.getDataSet().get(ids, {
  35886. type: {
  35887. start: 'Date',
  35888. end: 'Date'
  35889. }
  35890. });
  35891. // calculate minimum start and maximum end of specified items
  35892. var start = null;
  35893. var end = null;
  35894. itemsData.forEach(function(itemData) {
  35895. var s = itemData.start.valueOf();
  35896. var e = 'end' in itemData ? itemData.end.valueOf() : itemData.start.valueOf();
  35897. if (start === null || s < start) {
  35898. start = s;
  35899. }
  35900. if (end === null || e > end) {
  35901. end = e;
  35902. }
  35903. });
  35904. if (start !== null && end !== null) {
  35905. var me = this;
  35906. // Use the first item for the vertical focus
  35907. var item = this.itemSet.items[ids[0]];
  35908. var startPos = this._getScrollTop() * -1;
  35909. var initialVerticalScroll = null;
  35910. // Setup a handler for each frame of the vertical scroll
  35911. var verticalAnimationFrame = function verticalAnimationFrame(ease, willDraw, done) {
  35912. var verticalScroll = getItemVerticalScroll(me, item);
  35913. if (!initialVerticalScroll) {
  35914. initialVerticalScroll = verticalScroll;
  35915. }
  35916. if (initialVerticalScroll.itemTop == verticalScroll.itemTop && !initialVerticalScroll.shouldScroll) {
  35917. return; // We don't need to scroll, so do nothing
  35918. } else if (initialVerticalScroll.itemTop != verticalScroll.itemTop && verticalScroll.shouldScroll) {
  35919. // The redraw shifted elements, so reset the animation to correct
  35920. initialVerticalScroll = verticalScroll;
  35921. startPos = me._getScrollTop() * -1;
  35922. }
  35923. var from = startPos;
  35924. var to = initialVerticalScroll.scrollOffset;
  35925. var scrollTop = done ? to : from + (to - from) * ease;
  35926. me._setScrollTop(-scrollTop);
  35927. if (!willDraw) {
  35928. me._redraw();
  35929. }
  35930. };
  35931. // Enforces the final vertical scroll position
  35932. var setFinalVerticalPosition = function setFinalVerticalPosition() {
  35933. var finalVerticalScroll = getItemVerticalScroll(me, item);
  35934. if (finalVerticalScroll.shouldScroll && finalVerticalScroll.itemTop != initialVerticalScroll.itemTop) {
  35935. me._setScrollTop(-finalVerticalScroll.scrollOffset);
  35936. me._redraw();
  35937. }
  35938. };
  35939. // Perform one last check at the end to make sure the final vertical
  35940. // position is correct
  35941. var finalVerticalCallback = function finalVerticalCallback() {
  35942. // Double check we ended at the proper scroll position
  35943. setFinalVerticalPosition();
  35944. // Let the redraw settle and finalize the position.
  35945. setTimeout(setFinalVerticalPosition, 100);
  35946. };
  35947. // calculate the new middle and interval for the window
  35948. var middle = (start + end) / 2;
  35949. var interval = Math.max(this.range.end - this.range.start, (end - start) * 1.1);
  35950. var animation = options && options.animation !== undefined ? options.animation : true;
  35951. if (!animation) {
  35952. // We aren't animating so set a default so that the final callback forces the vertical location
  35953. initialVerticalScroll = { shouldScroll: false, scrollOffset: -1, itemTop: -1 };
  35954. }
  35955. this.range.setRange(middle - interval / 2, middle + interval / 2, { animation: animation }, finalVerticalCallback, verticalAnimationFrame);
  35956. }
  35957. };
  35958. /**
  35959. * Set Timeline window such that it fits all items
  35960. * @param {Object} [options] Available options:
  35961. * `animation: boolean | {duration: number, easingFunction: string}`
  35962. * If true (default), the range is animated
  35963. * smoothly to the new window. An object can be
  35964. * provided to specify duration and easing function.
  35965. * Default duration is 500 ms, and default easing
  35966. * function is 'easeInOutQuad'.
  35967. * @param {function} [callback]
  35968. */
  35969. Timeline.prototype.fit = function(options, callback) {
  35970. var animation = options && options.animation !== undefined ? options.animation : true;
  35971. var range;
  35972. var dataset = this.itemsData && this.itemsData.getDataSet();
  35973. if (dataset.length === 1 && dataset.get()[0].end === undefined) {
  35974. // a single item -> don't fit, just show a range around the item from -4 to +3 days
  35975. range = this.getDataRange();
  35976. this.moveTo(range.min.valueOf(), { animation: animation }, callback);
  35977. } else {
  35978. // exactly fit the items (plus a small margin)
  35979. range = this.getItemRange();
  35980. this.range.setRange(range.min, range.max, { animation: animation }, callback);
  35981. }
  35982. };
  35983. /**
  35984. *
  35985. * @param {vis.Item} item
  35986. * @returns {number}
  35987. */
  35988. function getStart(item) {
  35989. return util.convert(item.data.start, 'Date').valueOf();
  35990. }
  35991. /**
  35992. *
  35993. * @param {vis.Item} item
  35994. * @returns {number}
  35995. */
  35996. function getEnd(item) {
  35997. var end = item.data.end != undefined ? item.data.end : item.data.start;
  35998. return util.convert(end, 'Date').valueOf();
  35999. }
  36000. /**
  36001. * @param {vis.Timeline} timeline
  36002. * @param {vis.Item} item
  36003. * @return {{shouldScroll: bool, scrollOffset: number, itemTop: number}}
  36004. */
  36005. function getItemVerticalScroll(timeline, item) {
  36006. var leftHeight = timeline.props.leftContainer.height;
  36007. var contentHeight = timeline.props.left.height;
  36008. var group = item.parent;
  36009. var offset = group.top;
  36010. var shouldScroll = true;
  36011. var orientation = timeline.timeAxis.options.orientation.axis;
  36012. var itemTop = function itemTop() {
  36013. if (orientation == "bottom") {
  36014. return group.height - item.top - item.height;
  36015. } else {
  36016. return item.top;
  36017. }
  36018. };
  36019. var currentScrollHeight = timeline._getScrollTop() * -1;
  36020. var targetOffset = offset + itemTop();
  36021. var height = item.height;
  36022. if (targetOffset < currentScrollHeight) {
  36023. if (offset + leftHeight <= offset + itemTop() + height) {
  36024. offset += itemTop() - timeline.itemSet.options.margin.item.vertical;
  36025. }
  36026. } else if (targetOffset + height > currentScrollHeight + leftHeight) {
  36027. offset += itemTop() + height - leftHeight + timeline.itemSet.options.margin.item.vertical;
  36028. } else {
  36029. shouldScroll = false;
  36030. }
  36031. offset = Math.min(offset, contentHeight - leftHeight);
  36032. return { shouldScroll: shouldScroll, scrollOffset: offset, itemTop: targetOffset };
  36033. }
  36034. /**
  36035. * Determine the range of the items, taking into account their actual width
  36036. * and a margin of 10 pixels on both sides.
  36037. *
  36038. * @returns {{min: Date, max: Date}}
  36039. */
  36040. Timeline.prototype.getItemRange = function() {
  36041. // get a rough approximation for the range based on the items start and end dates
  36042. var range = this.getDataRange();
  36043. var min = range.min !== null ? range.min.valueOf() : null;
  36044. var max = range.max !== null ? range.max.valueOf() : null;
  36045. var minItem = null;
  36046. var maxItem = null;
  36047. if (min != null && max != null) {
  36048. var interval = max - min; // ms
  36049. if (interval <= 0) {
  36050. interval = 10;
  36051. }
  36052. var factor = interval / this.props.center.width;
  36053. var redrawQueue = {};
  36054. var redrawQueueLength = 0;
  36055. // collect redraw functions
  36056. util.forEach(this.itemSet.items, function(item, key) {
  36057. if (item.groupShowing) {
  36058. var returnQueue = true;
  36059. redrawQueue[key] = item.redraw(returnQueue);
  36060. redrawQueueLength = redrawQueue[key].length;
  36061. }
  36062. });
  36063. var needRedraw = redrawQueueLength > 0;
  36064. if (needRedraw) {
  36065. // redraw all regular items
  36066. for (var i = 0; i < redrawQueueLength; i++) {
  36067. util.forEach(redrawQueue, function(fns) {
  36068. fns[i]();
  36069. });
  36070. }
  36071. }
  36072. // calculate the date of the left side and right side of the items given
  36073. util.forEach(this.itemSet.items, function(item) {
  36074. var start = getStart(item);
  36075. var end = getEnd(item);
  36076. var startSide;
  36077. var endSide;
  36078. if (this.options.rtl) {
  36079. startSide = start - (item.getWidthRight() + 10) * factor;
  36080. endSide = end + (item.getWidthLeft() + 10) * factor;
  36081. } else {
  36082. startSide = start - (item.getWidthLeft() + 10) * factor;
  36083. endSide = end + (item.getWidthRight() + 10) * factor;
  36084. }
  36085. if (startSide < min) {
  36086. min = startSide;
  36087. minItem = item;
  36088. }
  36089. if (endSide > max) {
  36090. max = endSide;
  36091. maxItem = item;
  36092. }
  36093. }.bind(this));
  36094. if (minItem && maxItem) {
  36095. var lhs = minItem.getWidthLeft() + 10;
  36096. var rhs = maxItem.getWidthRight() + 10;
  36097. var delta = this.props.center.width - lhs - rhs; // px
  36098. if (delta > 0) {
  36099. if (this.options.rtl) {
  36100. min = getStart(minItem) - rhs * interval / delta; // ms
  36101. max = getEnd(maxItem) + lhs * interval / delta; // ms
  36102. } else {
  36103. min = getStart(minItem) - lhs * interval / delta; // ms
  36104. max = getEnd(maxItem) + rhs * interval / delta; // ms
  36105. }
  36106. }
  36107. }
  36108. }
  36109. return {
  36110. min: min != null ? new Date(min) : null,
  36111. max: max != null ? new Date(max) : null
  36112. };
  36113. };
  36114. /**
  36115. * Calculate the data range of the items start and end dates
  36116. * @returns {{min: Date, max: Date}}
  36117. */
  36118. Timeline.prototype.getDataRange = function() {
  36119. var min = null;
  36120. var max = null;
  36121. var dataset = this.itemsData && this.itemsData.getDataSet();
  36122. if (dataset) {
  36123. dataset.forEach(function(item) {
  36124. var start = util.convert(item.start, 'Date').valueOf();
  36125. var end = util.convert(item.end != undefined ? item.end : item.start, 'Date').valueOf();
  36126. if (min === null || start < min) {
  36127. min = start;
  36128. }
  36129. if (max === null || end > max) {
  36130. max = end;
  36131. }
  36132. });
  36133. }
  36134. return {
  36135. min: min != null ? new Date(min) : null,
  36136. max: max != null ? new Date(max) : null
  36137. };
  36138. };
  36139. /**
  36140. * Generate Timeline related information from an event
  36141. * @param {Event} event
  36142. * @return {Object} An object with related information, like on which area
  36143. * The event happened, whether clicked on an item, etc.
  36144. */
  36145. Timeline.prototype.getEventProperties = function(event) {
  36146. var clientX = event.center ? event.center.x : event.clientX;
  36147. var clientY = event.center ? event.center.y : event.clientY;
  36148. var x;
  36149. if (this.options.rtl) {
  36150. x = util.getAbsoluteRight(this.dom.centerContainer) - clientX;
  36151. } else {
  36152. x = clientX - util.getAbsoluteLeft(this.dom.centerContainer);
  36153. }
  36154. var y = clientY - util.getAbsoluteTop(this.dom.centerContainer);
  36155. var item = this.itemSet.itemFromTarget(event);
  36156. var group = this.itemSet.groupFromTarget(event);
  36157. var customTime = CustomTime.customTimeFromTarget(event);
  36158. var snap = this.itemSet.options.snap || null;
  36159. var scale = this.body.util.getScale();
  36160. var step = this.body.util.getStep();
  36161. var time = this._toTime(x);
  36162. var snappedTime = snap ? snap(time, scale, step) : time;
  36163. var element = util.getTarget(event);
  36164. var what = null;
  36165. if (item != null) {
  36166. what = 'item';
  36167. } else if (customTime != null) {
  36168. what = 'custom-time';
  36169. } else if (util.hasParent(element, this.timeAxis.dom.foreground)) {
  36170. what = 'axis';
  36171. } else if (this.timeAxis2 && util.hasParent(element, this.timeAxis2.dom.foreground)) {
  36172. what = 'axis';
  36173. } else if (util.hasParent(element, this.itemSet.dom.labelSet)) {
  36174. what = 'group-label';
  36175. } else if (util.hasParent(element, this.currentTime.bar)) {
  36176. what = 'current-time';
  36177. } else if (util.hasParent(element, this.dom.center)) {
  36178. what = 'background';
  36179. }
  36180. return {
  36181. event: event,
  36182. item: item ? item.id : null,
  36183. group: group ? group.groupId : null,
  36184. what: what,
  36185. pageX: event.srcEvent ? event.srcEvent.pageX : event.pageX,
  36186. pageY: event.srcEvent ? event.srcEvent.pageY : event.pageY,
  36187. x: x,
  36188. y: y,
  36189. time: time,
  36190. snappedTime: snappedTime
  36191. };
  36192. };
  36193. /**
  36194. * Toggle Timeline rolling mode
  36195. */
  36196. Timeline.prototype.toggleRollingMode = function() {
  36197. if (this.range.rolling) {
  36198. this.range.stopRolling();
  36199. } else {
  36200. if (this.options.rollingMode == undefined) {
  36201. this.setOptions(this.options);
  36202. }
  36203. this.range.startRolling();
  36204. }
  36205. };
  36206. module.exports = Timeline;
  36207. /***/
  36208. }),
  36209. /* 179 */
  36210. /***/
  36211. (function(module, exports, __webpack_require__) {
  36212. "use strict";
  36213. Object.defineProperty(exports, "__esModule", {
  36214. value: true
  36215. });
  36216. var _stringify = __webpack_require__(19);
  36217. var _stringify2 = _interopRequireDefault(_stringify);
  36218. var _classCallCheck2 = __webpack_require__(0);
  36219. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  36220. var _createClass2 = __webpack_require__(1);
  36221. var _createClass3 = _interopRequireDefault(_createClass2);
  36222. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  36223. var Hammer = __webpack_require__(10);
  36224. var hammerUtil = __webpack_require__(37);
  36225. var util = __webpack_require__(2);
  36226. /**
  36227. * @param {number} [pixelRatio=1]
  36228. */
  36229. var ColorPicker = function() {
  36230. /**
  36231. * @param {number} [pixelRatio=1]
  36232. */
  36233. function ColorPicker() {
  36234. var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
  36235. (0, _classCallCheck3['default'])(this, ColorPicker);
  36236. this.pixelRatio = pixelRatio;
  36237. this.generated = false;
  36238. this.centerCoordinates = { x: 289 / 2, y: 289 / 2 };
  36239. this.r = 289 * 0.49;
  36240. this.color = { r: 255, g: 255, b: 255, a: 1.0 };
  36241. this.hueCircle = undefined;
  36242. this.initialColor = { r: 255, g: 255, b: 255, a: 1.0 };
  36243. this.previousColor = undefined;
  36244. this.applied = false;
  36245. // bound by
  36246. this.updateCallback = function() {};
  36247. this.closeCallback = function() {};
  36248. // create all DOM elements
  36249. this._create();
  36250. }
  36251. /**
  36252. * this inserts the colorPicker into a div from the DOM
  36253. * @param {Element} container
  36254. */
  36255. (0, _createClass3['default'])(ColorPicker, [{
  36256. key: 'insertTo',
  36257. value: function insertTo(container) {
  36258. if (this.hammer !== undefined) {
  36259. this.hammer.destroy();
  36260. this.hammer = undefined;
  36261. }
  36262. this.container = container;
  36263. this.container.appendChild(this.frame);
  36264. this._bindHammer();
  36265. this._setSize();
  36266. }
  36267. /**
  36268. * the callback is executed on apply and save. Bind it to the application
  36269. * @param {function} callback
  36270. */
  36271. }, {
  36272. key: 'setUpdateCallback',
  36273. value: function setUpdateCallback(callback) {
  36274. if (typeof callback === 'function') {
  36275. this.updateCallback = callback;
  36276. } else {
  36277. throw new Error("Function attempted to set as colorPicker update callback is not a function.");
  36278. }
  36279. }
  36280. /**
  36281. * the callback is executed on apply and save. Bind it to the application
  36282. * @param {function} callback
  36283. */
  36284. }, {
  36285. key: 'setCloseCallback',
  36286. value: function setCloseCallback(callback) {
  36287. if (typeof callback === 'function') {
  36288. this.closeCallback = callback;
  36289. } else {
  36290. throw new Error("Function attempted to set as colorPicker closing callback is not a function.");
  36291. }
  36292. }
  36293. /**
  36294. *
  36295. * @param {string} color
  36296. * @returns {String}
  36297. * @private
  36298. */
  36299. }, {
  36300. key: '_isColorString',
  36301. value: function _isColorString(color) {
  36302. var htmlColors = { black: '#000000', navy: '#000080', darkblue: '#00008B', mediumblue: '#0000CD', blue: '#0000FF', darkgreen: '#006400', green: '#008000', teal: '#008080', darkcyan: '#008B8B', deepskyblue: '#00BFFF', darkturquoise: '#00CED1', mediumspringgreen: '#00FA9A', lime: '#00FF00', springgreen: '#00FF7F', aqua: '#00FFFF', cyan: '#00FFFF', midnightblue: '#191970', dodgerblue: '#1E90FF', lightseagreen: '#20B2AA', forestgreen: '#228B22', seagreen: '#2E8B57', darkslategray: '#2F4F4F', limegreen: '#32CD32', mediumseagreen: '#3CB371', turquoise: '#40E0D0', royalblue: '#4169E1', steelblue: '#4682B4', darkslateblue: '#483D8B', mediumturquoise: '#48D1CC', indigo: '#4B0082', darkolivegreen: '#556B2F', cadetblue: '#5F9EA0', cornflowerblue: '#6495ED', mediumaquamarine: '#66CDAA', dimgray: '#696969', slateblue: '#6A5ACD', olivedrab: '#6B8E23', slategray: '#708090', lightslategray: '#778899', mediumslateblue: '#7B68EE', lawngreen: '#7CFC00', chartreuse: '#7FFF00', aquamarine: '#7FFFD4', maroon: '#800000', purple: '#800080', olive: '#808000', gray: '#808080', skyblue: '#87CEEB', lightskyblue: '#87CEFA', blueviolet: '#8A2BE2', darkred: '#8B0000', darkmagenta: '#8B008B', saddlebrown: '#8B4513', darkseagreen: '#8FBC8F', lightgreen: '#90EE90', mediumpurple: '#9370D8', darkviolet: '#9400D3', palegreen: '#98FB98', darkorchid: '#9932CC', yellowgreen: '#9ACD32', sienna: '#A0522D', brown: '#A52A2A', darkgray: '#A9A9A9', lightblue: '#ADD8E6', greenyellow: '#ADFF2F', paleturquoise: '#AFEEEE', lightsteelblue: '#B0C4DE', powderblue: '#B0E0E6', firebrick: '#B22222', darkgoldenrod: '#B8860B', mediumorchid: '#BA55D3', rosybrown: '#BC8F8F', darkkhaki: '#BDB76B', silver: '#C0C0C0', mediumvioletred: '#C71585', indianred: '#CD5C5C', peru: '#CD853F', chocolate: '#D2691E', tan: '#D2B48C', lightgrey: '#D3D3D3', palevioletred: '#D87093', thistle: '#D8BFD8', orchid: '#DA70D6', goldenrod: '#DAA520', crimson: '#DC143C', gainsboro: '#DCDCDC', plum: '#DDA0DD', burlywood: '#DEB887', lightcyan: '#E0FFFF', lavender: '#E6E6FA', darksalmon: '#E9967A', violet: '#EE82EE', palegoldenrod: '#EEE8AA', lightcoral: '#F08080', khaki: '#F0E68C', aliceblue: '#F0F8FF', honeydew: '#F0FFF0', azure: '#F0FFFF', sandybrown: '#F4A460', wheat: '#F5DEB3', beige: '#F5F5DC', whitesmoke: '#F5F5F5', mintcream: '#F5FFFA', ghostwhite: '#F8F8FF', salmon: '#FA8072', antiquewhite: '#FAEBD7', linen: '#FAF0E6', lightgoldenrodyellow: '#FAFAD2', oldlace: '#FDF5E6', red: '#FF0000', fuchsia: '#FF00FF', magenta: '#FF00FF', deeppink: '#FF1493', orangered: '#FF4500', tomato: '#FF6347', hotpink: '#FF69B4', coral: '#FF7F50', darkorange: '#FF8C00', lightsalmon: '#FFA07A', orange: '#FFA500', lightpink: '#FFB6C1', pink: '#FFC0CB', gold: '#FFD700', peachpuff: '#FFDAB9', navajowhite: '#FFDEAD', moccasin: '#FFE4B5', bisque: '#FFE4C4', mistyrose: '#FFE4E1', blanchedalmond: '#FFEBCD', papayawhip: '#FFEFD5', lavenderblush: '#FFF0F5', seashell: '#FFF5EE', cornsilk: '#FFF8DC', lemonchiffon: '#FFFACD', floralwhite: '#FFFAF0', snow: '#FFFAFA', yellow: '#FFFF00', lightyellow: '#FFFFE0', ivory: '#FFFFF0', white: '#FFFFFF' };
  36303. if (typeof color === 'string') {
  36304. return htmlColors[color];
  36305. }
  36306. }
  36307. /**
  36308. * Set the color of the colorPicker
  36309. * Supported formats:
  36310. * 'red' --> HTML color string
  36311. * '#ffffff' --> hex string
  36312. * 'rbg(255,255,255)' --> rgb string
  36313. * 'rgba(255,255,255,1.0)' --> rgba string
  36314. * {r:255,g:255,b:255} --> rgb object
  36315. * {r:255,g:255,b:255,a:1.0} --> rgba object
  36316. * @param {string|Object} color
  36317. * @param {boolean} [setInitial=true]
  36318. */
  36319. }, {
  36320. key: 'setColor',
  36321. value: function setColor(color) {
  36322. var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  36323. if (color === 'none') {
  36324. return;
  36325. }
  36326. var rgba = void 0;
  36327. // if a html color shorthand is used, convert to hex
  36328. var htmlColor = this._isColorString(color);
  36329. if (htmlColor !== undefined) {
  36330. color = htmlColor;
  36331. }
  36332. // check format
  36333. if (util.isString(color) === true) {
  36334. if (util.isValidRGB(color) === true) {
  36335. var rgbaArray = color.substr(4).substr(0, color.length - 5).split(',');
  36336. rgba = { r: rgbaArray[0], g: rgbaArray[1], b: rgbaArray[2], a: 1.0 };
  36337. } else if (util.isValidRGBA(color) === true) {
  36338. var _rgbaArray = color.substr(5).substr(0, color.length - 6).split(',');
  36339. rgba = { r: _rgbaArray[0], g: _rgbaArray[1], b: _rgbaArray[2], a: _rgbaArray[3] };
  36340. } else if (util.isValidHex(color) === true) {
  36341. var rgbObj = util.hexToRGB(color);
  36342. rgba = { r: rgbObj.r, g: rgbObj.g, b: rgbObj.b, a: 1.0 };
  36343. }
  36344. } else {
  36345. if (color instanceof Object) {
  36346. if (color.r !== undefined && color.g !== undefined && color.b !== undefined) {
  36347. var alpha = color.a !== undefined ? color.a : '1.0';
  36348. rgba = { r: color.r, g: color.g, b: color.b, a: alpha };
  36349. }
  36350. }
  36351. }
  36352. // set color
  36353. if (rgba === undefined) {
  36354. throw new Error("Unknown color passed to the colorPicker. Supported are strings: rgb, hex, rgba. Object: rgb ({r:r,g:g,b:b,[a:a]}). Supplied: " + (0, _stringify2['default'])(color));
  36355. } else {
  36356. this._setColor(rgba, setInitial);
  36357. }
  36358. }
  36359. /**
  36360. * this shows the color picker.
  36361. * The hue circle is constructed once and stored.
  36362. */
  36363. }, {
  36364. key: 'show',
  36365. value: function show() {
  36366. if (this.closeCallback !== undefined) {
  36367. this.closeCallback();
  36368. this.closeCallback = undefined;
  36369. }
  36370. this.applied = false;
  36371. this.frame.style.display = 'block';
  36372. this._generateHueCircle();
  36373. }
  36374. // ------------------------------------------ PRIVATE ----------------------------- //
  36375. /**
  36376. * Hide the picker. Is called by the cancel button.
  36377. * Optional boolean to store the previous color for easy access later on.
  36378. * @param {boolean} [storePrevious=true]
  36379. * @private
  36380. */
  36381. }, {
  36382. key: '_hide',
  36383. value: function _hide() {
  36384. var _this = this;
  36385. var storePrevious = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
  36386. // store the previous color for next time;
  36387. if (storePrevious === true) {
  36388. this.previousColor = util.extend({}, this.color);
  36389. }
  36390. if (this.applied === true) {
  36391. this.updateCallback(this.initialColor);
  36392. }
  36393. this.frame.style.display = 'none';
  36394. // call the closing callback, restoring the onclick method.
  36395. // this is in a setTimeout because it will trigger the show again before the click is done.
  36396. setTimeout(function() {
  36397. if (_this.closeCallback !== undefined) {
  36398. _this.closeCallback();
  36399. _this.closeCallback = undefined;
  36400. }
  36401. }, 0);
  36402. }
  36403. /**
  36404. * bound to the save button. Saves and hides.
  36405. * @private
  36406. */
  36407. }, {
  36408. key: '_save',
  36409. value: function _save() {
  36410. this.updateCallback(this.color);
  36411. this.applied = false;
  36412. this._hide();
  36413. }
  36414. /**
  36415. * Bound to apply button. Saves but does not close. Is undone by the cancel button.
  36416. * @private
  36417. */
  36418. }, {
  36419. key: '_apply',
  36420. value: function _apply() {
  36421. this.applied = true;
  36422. this.updateCallback(this.color);
  36423. this._updatePicker(this.color);
  36424. }
  36425. /**
  36426. * load the color from the previous session.
  36427. * @private
  36428. */
  36429. }, {
  36430. key: '_loadLast',
  36431. value: function _loadLast() {
  36432. if (this.previousColor !== undefined) {
  36433. this.setColor(this.previousColor, false);
  36434. } else {
  36435. alert("There is no last color to load...");
  36436. }
  36437. }
  36438. /**
  36439. * set the color, place the picker
  36440. * @param {Object} rgba
  36441. * @param {boolean} [setInitial=true]
  36442. * @private
  36443. */
  36444. }, {
  36445. key: '_setColor',
  36446. value: function _setColor(rgba) {
  36447. var setInitial = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  36448. // store the initial color
  36449. if (setInitial === true) {
  36450. this.initialColor = util.extend({}, rgba);
  36451. }
  36452. this.color = rgba;
  36453. var hsv = util.RGBToHSV(rgba.r, rgba.g, rgba.b);
  36454. var angleConvert = 2 * Math.PI;
  36455. var radius = this.r * hsv.s;
  36456. var x = this.centerCoordinates.x + radius * Math.sin(angleConvert * hsv.h);
  36457. var y = this.centerCoordinates.y + radius * Math.cos(angleConvert * hsv.h);
  36458. this.colorPickerSelector.style.left = x - 0.5 * this.colorPickerSelector.clientWidth + 'px';
  36459. this.colorPickerSelector.style.top = y - 0.5 * this.colorPickerSelector.clientHeight + 'px';
  36460. this._updatePicker(rgba);
  36461. }
  36462. /**
  36463. * bound to opacity control
  36464. * @param {number} value
  36465. * @private
  36466. */
  36467. }, {
  36468. key: '_setOpacity',
  36469. value: function _setOpacity(value) {
  36470. this.color.a = value / 100;
  36471. this._updatePicker(this.color);
  36472. }
  36473. /**
  36474. * bound to brightness control
  36475. * @param {number} value
  36476. * @private
  36477. */
  36478. }, {
  36479. key: '_setBrightness',
  36480. value: function _setBrightness(value) {
  36481. var hsv = util.RGBToHSV(this.color.r, this.color.g, this.color.b);
  36482. hsv.v = value / 100;
  36483. var rgba = util.HSVToRGB(hsv.h, hsv.s, hsv.v);
  36484. rgba['a'] = this.color.a;
  36485. this.color = rgba;
  36486. this._updatePicker();
  36487. }
  36488. /**
  36489. * update the color picker. A black circle overlays the hue circle to mimic the brightness decreasing.
  36490. * @param {Object} rgba
  36491. * @private
  36492. */
  36493. }, {
  36494. key: '_updatePicker',
  36495. value: function _updatePicker() {
  36496. var rgba = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.color;
  36497. var hsv = util.RGBToHSV(rgba.r, rgba.g, rgba.b);
  36498. var ctx = this.colorPickerCanvas.getContext('2d');
  36499. if (this.pixelRation === undefined) {
  36500. this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
  36501. }
  36502. ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
  36503. // clear the canvas
  36504. var w = this.colorPickerCanvas.clientWidth;
  36505. var h = this.colorPickerCanvas.clientHeight;
  36506. ctx.clearRect(0, 0, w, h);
  36507. ctx.putImageData(this.hueCircle, 0, 0);
  36508. ctx.fillStyle = 'rgba(0,0,0,' + (1 - hsv.v) + ')';
  36509. ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
  36510. ctx.fill();
  36511. this.brightnessRange.value = 100 * hsv.v;
  36512. this.opacityRange.value = 100 * rgba.a;
  36513. this.initialColorDiv.style.backgroundColor = 'rgba(' + this.initialColor.r + ',' + this.initialColor.g + ',' + this.initialColor.b + ',' + this.initialColor.a + ')';
  36514. this.newColorDiv.style.backgroundColor = 'rgba(' + this.color.r + ',' + this.color.g + ',' + this.color.b + ',' + this.color.a + ')';
  36515. }
  36516. /**
  36517. * used by create to set the size of the canvas.
  36518. * @private
  36519. */
  36520. }, {
  36521. key: '_setSize',
  36522. value: function _setSize() {
  36523. this.colorPickerCanvas.style.width = '100%';
  36524. this.colorPickerCanvas.style.height = '100%';
  36525. this.colorPickerCanvas.width = 289 * this.pixelRatio;
  36526. this.colorPickerCanvas.height = 289 * this.pixelRatio;
  36527. }
  36528. /**
  36529. * create all dom elements
  36530. * TODO: cleanup, lots of similar dom elements
  36531. * @private
  36532. */
  36533. }, {
  36534. key: '_create',
  36535. value: function _create() {
  36536. this.frame = document.createElement('div');
  36537. this.frame.className = 'vis-color-picker';
  36538. this.colorPickerDiv = document.createElement('div');
  36539. this.colorPickerSelector = document.createElement('div');
  36540. this.colorPickerSelector.className = 'vis-selector';
  36541. this.colorPickerDiv.appendChild(this.colorPickerSelector);
  36542. this.colorPickerCanvas = document.createElement('canvas');
  36543. this.colorPickerDiv.appendChild(this.colorPickerCanvas);
  36544. if (!this.colorPickerCanvas.getContext) {
  36545. var noCanvas = document.createElement('DIV');
  36546. noCanvas.style.color = 'red';
  36547. noCanvas.style.fontWeight = 'bold';
  36548. noCanvas.style.padding = '10px';
  36549. noCanvas.innerHTML = 'Error: your browser does not support HTML canvas';
  36550. this.colorPickerCanvas.appendChild(noCanvas);
  36551. } else {
  36552. var ctx = this.colorPickerCanvas.getContext("2d");
  36553. this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
  36554. this.colorPickerCanvas.getContext("2d").setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
  36555. }
  36556. this.colorPickerDiv.className = 'vis-color';
  36557. this.opacityDiv = document.createElement('div');
  36558. this.opacityDiv.className = 'vis-opacity';
  36559. this.brightnessDiv = document.createElement('div');
  36560. this.brightnessDiv.className = 'vis-brightness';
  36561. this.arrowDiv = document.createElement('div');
  36562. this.arrowDiv.className = 'vis-arrow';
  36563. this.opacityRange = document.createElement('input');
  36564. try {
  36565. this.opacityRange.type = 'range'; // Not supported on IE9
  36566. this.opacityRange.min = '0';
  36567. this.opacityRange.max = '100';
  36568. }
  36569. // TODO: Add some error handling and remove this lint exception
  36570. catch (err) {} // eslint-disable-line no-empty
  36571. this.opacityRange.value = '100';
  36572. this.opacityRange.className = 'vis-range';
  36573. this.brightnessRange = document.createElement('input');
  36574. try {
  36575. this.brightnessRange.type = 'range'; // Not supported on IE9
  36576. this.brightnessRange.min = '0';
  36577. this.brightnessRange.max = '100';
  36578. }
  36579. // TODO: Add some error handling and remove this lint exception
  36580. catch (err) {} // eslint-disable-line no-empty
  36581. this.brightnessRange.value = '100';
  36582. this.brightnessRange.className = 'vis-range';
  36583. this.opacityDiv.appendChild(this.opacityRange);
  36584. this.brightnessDiv.appendChild(this.brightnessRange);
  36585. var me = this;
  36586. this.opacityRange.onchange = function() {
  36587. me._setOpacity(this.value);
  36588. };
  36589. this.opacityRange.oninput = function() {
  36590. me._setOpacity(this.value);
  36591. };
  36592. this.brightnessRange.onchange = function() {
  36593. me._setBrightness(this.value);
  36594. };
  36595. this.brightnessRange.oninput = function() {
  36596. me._setBrightness(this.value);
  36597. };
  36598. this.brightnessLabel = document.createElement("div");
  36599. this.brightnessLabel.className = "vis-label vis-brightness";
  36600. this.brightnessLabel.innerHTML = 'brightness:';
  36601. this.opacityLabel = document.createElement("div");
  36602. this.opacityLabel.className = "vis-label vis-opacity";
  36603. this.opacityLabel.innerHTML = 'opacity:';
  36604. this.newColorDiv = document.createElement("div");
  36605. this.newColorDiv.className = "vis-new-color";
  36606. this.newColorDiv.innerHTML = 'new';
  36607. this.initialColorDiv = document.createElement("div");
  36608. this.initialColorDiv.className = "vis-initial-color";
  36609. this.initialColorDiv.innerHTML = 'initial';
  36610. this.cancelButton = document.createElement("div");
  36611. this.cancelButton.className = "vis-button vis-cancel";
  36612. this.cancelButton.innerHTML = 'cancel';
  36613. this.cancelButton.onclick = this._hide.bind(this, false);
  36614. this.applyButton = document.createElement("div");
  36615. this.applyButton.className = "vis-button vis-apply";
  36616. this.applyButton.innerHTML = 'apply';
  36617. this.applyButton.onclick = this._apply.bind(this);
  36618. this.saveButton = document.createElement("div");
  36619. this.saveButton.className = "vis-button vis-save";
  36620. this.saveButton.innerHTML = 'save';
  36621. this.saveButton.onclick = this._save.bind(this);
  36622. this.loadButton = document.createElement("div");
  36623. this.loadButton.className = "vis-button vis-load";
  36624. this.loadButton.innerHTML = 'load last';
  36625. this.loadButton.onclick = this._loadLast.bind(this);
  36626. this.frame.appendChild(this.colorPickerDiv);
  36627. this.frame.appendChild(this.arrowDiv);
  36628. this.frame.appendChild(this.brightnessLabel);
  36629. this.frame.appendChild(this.brightnessDiv);
  36630. this.frame.appendChild(this.opacityLabel);
  36631. this.frame.appendChild(this.opacityDiv);
  36632. this.frame.appendChild(this.newColorDiv);
  36633. this.frame.appendChild(this.initialColorDiv);
  36634. this.frame.appendChild(this.cancelButton);
  36635. this.frame.appendChild(this.applyButton);
  36636. this.frame.appendChild(this.saveButton);
  36637. this.frame.appendChild(this.loadButton);
  36638. }
  36639. /**
  36640. * bind hammer to the color picker
  36641. * @private
  36642. */
  36643. }, {
  36644. key: '_bindHammer',
  36645. value: function _bindHammer() {
  36646. var _this2 = this;
  36647. this.drag = {};
  36648. this.pinch = {};
  36649. this.hammer = new Hammer(this.colorPickerCanvas);
  36650. this.hammer.get('pinch').set({ enable: true });
  36651. hammerUtil.onTouch(this.hammer, function(event) {
  36652. _this2._moveSelector(event);
  36653. });
  36654. this.hammer.on('tap', function(event) {
  36655. _this2._moveSelector(event);
  36656. });
  36657. this.hammer.on('panstart', function(event) {
  36658. _this2._moveSelector(event);
  36659. });
  36660. this.hammer.on('panmove', function(event) {
  36661. _this2._moveSelector(event);
  36662. });
  36663. this.hammer.on('panend', function(event) {
  36664. _this2._moveSelector(event);
  36665. });
  36666. }
  36667. /**
  36668. * generate the hue circle. This is relatively heavy (200ms) and is done only once on the first time it is shown.
  36669. * @private
  36670. */
  36671. }, {
  36672. key: '_generateHueCircle',
  36673. value: function _generateHueCircle() {
  36674. if (this.generated === false) {
  36675. var ctx = this.colorPickerCanvas.getContext('2d');
  36676. if (this.pixelRation === undefined) {
  36677. this.pixelRatio = (window.devicePixelRatio || 1) / (ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1);
  36678. }
  36679. ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
  36680. // clear the canvas
  36681. var w = this.colorPickerCanvas.clientWidth;
  36682. var h = this.colorPickerCanvas.clientHeight;
  36683. ctx.clearRect(0, 0, w, h);
  36684. // draw hue circle
  36685. var x = void 0,
  36686. y = void 0,
  36687. hue = void 0,
  36688. sat = void 0;
  36689. this.centerCoordinates = { x: w * 0.5, y: h * 0.5 };
  36690. this.r = 0.49 * w;
  36691. var angleConvert = 2 * Math.PI / 360;
  36692. var hfac = 1 / 360;
  36693. var sfac = 1 / this.r;
  36694. var rgb = void 0;
  36695. for (hue = 0; hue < 360; hue++) {
  36696. for (sat = 0; sat < this.r; sat++) {
  36697. x = this.centerCoordinates.x + sat * Math.sin(angleConvert * hue);
  36698. y = this.centerCoordinates.y + sat * Math.cos(angleConvert * hue);
  36699. rgb = util.HSVToRGB(hue * hfac, sat * sfac, 1);
  36700. ctx.fillStyle = 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
  36701. ctx.fillRect(x - 0.5, y - 0.5, 2, 2);
  36702. }
  36703. }
  36704. ctx.strokeStyle = 'rgba(0,0,0,1)';
  36705. ctx.circle(this.centerCoordinates.x, this.centerCoordinates.y, this.r);
  36706. ctx.stroke();
  36707. this.hueCircle = ctx.getImageData(0, 0, w, h);
  36708. }
  36709. this.generated = true;
  36710. }
  36711. /**
  36712. * move the selector. This is called by hammer functions.
  36713. *
  36714. * @param {Event} event The event
  36715. * @private
  36716. */
  36717. }, {
  36718. key: '_moveSelector',
  36719. value: function _moveSelector(event) {
  36720. var rect = this.colorPickerDiv.getBoundingClientRect();
  36721. var left = event.center.x - rect.left;
  36722. var top = event.center.y - rect.top;
  36723. var centerY = 0.5 * this.colorPickerDiv.clientHeight;
  36724. var centerX = 0.5 * this.colorPickerDiv.clientWidth;
  36725. var x = left - centerX;
  36726. var y = top - centerY;
  36727. var angle = Math.atan2(x, y);
  36728. var radius = 0.98 * Math.min(Math.sqrt(x * x + y * y), centerX);
  36729. var newTop = Math.cos(angle) * radius + centerY;
  36730. var newLeft = Math.sin(angle) * radius + centerX;
  36731. this.colorPickerSelector.style.top = newTop - 0.5 * this.colorPickerSelector.clientHeight + 'px';
  36732. this.colorPickerSelector.style.left = newLeft - 0.5 * this.colorPickerSelector.clientWidth + 'px';
  36733. // set color
  36734. var h = angle / (2 * Math.PI);
  36735. h = h < 0 ? h + 1 : h;
  36736. var s = radius / this.r;
  36737. var hsv = util.RGBToHSV(this.color.r, this.color.g, this.color.b);
  36738. hsv.h = h;
  36739. hsv.s = s;
  36740. var rgba = util.HSVToRGB(hsv.h, hsv.s, hsv.v);
  36741. rgba['a'] = this.color.a;
  36742. this.color = rgba;
  36743. // update previews
  36744. this.initialColorDiv.style.backgroundColor = 'rgba(' + this.initialColor.r + ',' + this.initialColor.g + ',' + this.initialColor.b + ',' + this.initialColor.a + ')';
  36745. this.newColorDiv.style.backgroundColor = 'rgba(' + this.color.r + ',' + this.color.g + ',' + this.color.b + ',' + this.color.a + ')';
  36746. }
  36747. }]);
  36748. return ColorPicker;
  36749. }();
  36750. exports['default'] = ColorPicker;
  36751. /***/
  36752. }),
  36753. /* 180 */
  36754. /***/
  36755. (function(module, exports, __webpack_require__) {
  36756. "use strict";
  36757. var moment = __webpack_require__(9);
  36758. var util = __webpack_require__(2);
  36759. var DataSet = __webpack_require__(11);
  36760. var DataView = __webpack_require__(12);
  36761. var Range = __webpack_require__(64);
  36762. var Core = __webpack_require__(65);
  36763. var TimeAxis = __webpack_require__(45);
  36764. var CurrentTime = __webpack_require__(67);
  36765. var CustomTime = __webpack_require__(46);
  36766. var LineGraph = __webpack_require__(106);
  36767. var printStyle = __webpack_require__(15).printStyle;
  36768. var allOptions = __webpack_require__(113).allOptions;
  36769. var configureOptions = __webpack_require__(113).configureOptions;
  36770. var Configurator = __webpack_require__(71)['default'];
  36771. var Validator = __webpack_require__(15)['default'];
  36772. /**
  36773. * Create a timeline visualization
  36774. * @param {HTMLElement} container
  36775. * @param {vis.DataSet | Array} [items]
  36776. * @param {vis.DataSet | Array | vis.DataView | Object} [groups]
  36777. * @param {Object} [options] See Graph2d.setOptions for the available options.
  36778. * @constructor Graph2d
  36779. * @extends Core
  36780. */
  36781. function Graph2d(container, items, groups, options) {
  36782. // if the third element is options, the forth is groups (optionally);
  36783. if (!(Array.isArray(groups) || groups instanceof DataSet || groups instanceof DataView) && groups instanceof Object) {
  36784. var forthArgument = options;
  36785. options = groups;
  36786. groups = forthArgument;
  36787. }
  36788. // TODO: REMOVE THIS in the next MAJOR release
  36789. // see https://github.com/almende/vis/issues/2511
  36790. if (options && options.throttleRedraw) {
  36791. console.warn("Graph2d option \"throttleRedraw\" is DEPRICATED and no longer supported. It will be removed in the next MAJOR release.");
  36792. }
  36793. var me = this;
  36794. this.defaultOptions = {
  36795. start: null,
  36796. end: null,
  36797. autoResize: true,
  36798. orientation: {
  36799. axis: 'bottom', // axis orientation: 'bottom', 'top', or 'both'
  36800. item: 'bottom' // not relevant for Graph2d
  36801. },
  36802. moment: moment,
  36803. width: null,
  36804. height: null,
  36805. maxHeight: null,
  36806. minHeight: null
  36807. };
  36808. this.options = util.deepExtend({}, this.defaultOptions);
  36809. // Create the DOM, props, and emitter
  36810. this._create(container);
  36811. // all components listed here will be repainted automatically
  36812. this.components = [];
  36813. this.body = {
  36814. dom: this.dom,
  36815. domProps: this.props,
  36816. emitter: {
  36817. on: this.on.bind(this),
  36818. off: this.off.bind(this),
  36819. emit: this.emit.bind(this)
  36820. },
  36821. hiddenDates: [],
  36822. util: {
  36823. toScreen: me._toScreen.bind(me),
  36824. toGlobalScreen: me._toGlobalScreen.bind(me), // this refers to the root.width
  36825. toTime: me._toTime.bind(me),
  36826. toGlobalTime: me._toGlobalTime.bind(me)
  36827. }
  36828. };
  36829. // range
  36830. this.range = new Range(this.body);
  36831. this.components.push(this.range);
  36832. this.body.range = this.range;
  36833. // time axis
  36834. this.timeAxis = new TimeAxis(this.body);
  36835. this.components.push(this.timeAxis);
  36836. //this.body.util.snap = this.timeAxis.snap.bind(this.timeAxis);
  36837. // current time bar
  36838. this.currentTime = new CurrentTime(this.body);
  36839. this.components.push(this.currentTime);
  36840. // item set
  36841. this.linegraph = new LineGraph(this.body);
  36842. this.components.push(this.linegraph);
  36843. this.itemsData = null; // DataSet
  36844. this.groupsData = null; // DataSet
  36845. this.on('tap', function(event) {
  36846. me.emit('click', me.getEventProperties(event));
  36847. });
  36848. this.on('doubletap', function(event) {
  36849. me.emit('doubleClick', me.getEventProperties(event));
  36850. });
  36851. this.dom.root.oncontextmenu = function(event) {
  36852. me.emit('contextmenu', me.getEventProperties(event));
  36853. };
  36854. // apply options
  36855. if (options) {
  36856. this.setOptions(options);
  36857. }
  36858. // IMPORTANT: THIS HAPPENS BEFORE SET ITEMS!
  36859. if (groups) {
  36860. this.setGroups(groups);
  36861. }
  36862. // create itemset
  36863. if (items) {
  36864. this.setItems(items);
  36865. }
  36866. // draw for the first time
  36867. this._redraw();
  36868. }
  36869. // Extend the functionality from Core
  36870. Graph2d.prototype = new Core();
  36871. Graph2d.prototype.setOptions = function(options) {
  36872. // validate options
  36873. var errorFound = Validator.validate(options, allOptions);
  36874. if (errorFound === true) {
  36875. console.log('%cErrors have been found in the supplied options object.', printStyle);
  36876. }
  36877. Core.prototype.setOptions.call(this, options);
  36878. };
  36879. /**
  36880. * Set items
  36881. * @param {vis.DataSet | Array | null} items
  36882. */
  36883. Graph2d.prototype.setItems = function(items) {
  36884. var initialLoad = this.itemsData == null;
  36885. // convert to type DataSet when needed
  36886. var newDataSet;
  36887. if (!items) {
  36888. newDataSet = null;
  36889. } else if (items instanceof DataSet || items instanceof DataView) {
  36890. newDataSet = items;
  36891. } else {
  36892. // turn an array into a dataset
  36893. newDataSet = new DataSet(items, {
  36894. type: {
  36895. start: 'Date',
  36896. end: 'Date'
  36897. }
  36898. });
  36899. }
  36900. // set items
  36901. this.itemsData = newDataSet;
  36902. this.linegraph && this.linegraph.setItems(newDataSet);
  36903. if (initialLoad) {
  36904. if (this.options.start != undefined || this.options.end != undefined) {
  36905. var start = this.options.start != undefined ? this.options.start : null;
  36906. var end = this.options.end != undefined ? this.options.end : null;
  36907. this.setWindow(start, end, { animation: false });
  36908. } else {
  36909. this.fit({ animation: false });
  36910. }
  36911. }
  36912. };
  36913. /**
  36914. * Set groups
  36915. * @param {vis.DataSet | Array} groups
  36916. */
  36917. Graph2d.prototype.setGroups = function(groups) {
  36918. // convert to type DataSet when needed
  36919. var newDataSet;
  36920. if (!groups) {
  36921. newDataSet = null;
  36922. } else if (groups instanceof DataSet || groups instanceof DataView) {
  36923. newDataSet = groups;
  36924. } else {
  36925. // turn an array into a dataset
  36926. newDataSet = new DataSet(groups);
  36927. }
  36928. this.groupsData = newDataSet;
  36929. this.linegraph.setGroups(newDataSet);
  36930. };
  36931. /**
  36932. * Returns an object containing an SVG element with the icon of the group (size determined by iconWidth and iconHeight), the label of the group (content) and the yAxisOrientation of the group (left or right).
  36933. * @param {vis.GraphGroup.id} groupId
  36934. * @param {number} width
  36935. * @param {number} height
  36936. * @returns {{icon: SVGElement, label: string, orientation: string}|string}
  36937. */
  36938. Graph2d.prototype.getLegend = function(groupId, width, height) {
  36939. if (width === undefined) {
  36940. width = 15;
  36941. }
  36942. if (height === undefined) {
  36943. height = 15;
  36944. }
  36945. if (this.linegraph.groups[groupId] !== undefined) {
  36946. return this.linegraph.groups[groupId].getLegend(width, height);
  36947. } else {
  36948. return "cannot find group:'" + groupId + "'";
  36949. }
  36950. };
  36951. /**
  36952. * This checks if the visible option of the supplied group (by ID) is true or false.
  36953. * @param {vis.GraphGroup.id} groupId
  36954. * @returns {boolean}
  36955. */
  36956. Graph2d.prototype.isGroupVisible = function(groupId) {
  36957. if (this.linegraph.groups[groupId] !== undefined) {
  36958. return this.linegraph.groups[groupId].visible && (this.linegraph.options.groups.visibility[groupId] === undefined || this.linegraph.options.groups.visibility[groupId] == true);
  36959. } else {
  36960. return false;
  36961. }
  36962. };
  36963. /**
  36964. * Get the data range of the item set.
  36965. * @returns {{min: Date, max: Date}} range A range with a start and end Date.
  36966. * When no minimum is found, min==null
  36967. * When no maximum is found, max==null
  36968. */
  36969. Graph2d.prototype.getDataRange = function() {
  36970. var min = null;
  36971. var max = null;
  36972. // calculate min from start filed
  36973. for (var groupId in this.linegraph.groups) {
  36974. if (this.linegraph.groups.hasOwnProperty(groupId)) {
  36975. if (this.linegraph.groups[groupId].visible == true) {
  36976. for (var i = 0; i < this.linegraph.groups[groupId].itemsData.length; i++) {
  36977. var item = this.linegraph.groups[groupId].itemsData[i];
  36978. var value = util.convert(item.x, 'Date').valueOf();
  36979. min = min == null ? value : min > value ? value : min;
  36980. max = max == null ? value : max < value ? value : max;
  36981. }
  36982. }
  36983. }
  36984. }
  36985. return {
  36986. min: min != null ? new Date(min) : null,
  36987. max: max != null ? new Date(max) : null
  36988. };
  36989. };
  36990. /**
  36991. * Generate Timeline related information from an event
  36992. * @param {Event} event
  36993. * @return {Object} An object with related information, like on which area
  36994. * The event happened, whether clicked on an item, etc.
  36995. */
  36996. Graph2d.prototype.getEventProperties = function(event) {
  36997. var clientX = event.center ? event.center.x : event.clientX;
  36998. var clientY = event.center ? event.center.y : event.clientY;
  36999. var x = clientX - util.getAbsoluteLeft(this.dom.centerContainer);
  37000. var y = clientY - util.getAbsoluteTop(this.dom.centerContainer);
  37001. var time = this._toTime(x);
  37002. var customTime = CustomTime.customTimeFromTarget(event);
  37003. var element = util.getTarget(event);
  37004. var what = null;
  37005. if (util.hasParent(element, this.timeAxis.dom.foreground)) {
  37006. what = 'axis';
  37007. } else if (this.timeAxis2 && util.hasParent(element, this.timeAxis2.dom.foreground)) {
  37008. what = 'axis';
  37009. } else if (util.hasParent(element, this.linegraph.yAxisLeft.dom.frame)) {
  37010. what = 'data-axis';
  37011. } else if (util.hasParent(element, this.linegraph.yAxisRight.dom.frame)) {
  37012. what = 'data-axis';
  37013. } else if (util.hasParent(element, this.linegraph.legendLeft.dom.frame)) {
  37014. what = 'legend';
  37015. } else if (util.hasParent(element, this.linegraph.legendRight.dom.frame)) {
  37016. what = 'legend';
  37017. } else if (customTime != null) {
  37018. what = 'custom-time';
  37019. } else if (util.hasParent(element, this.currentTime.bar)) {
  37020. what = 'current-time';
  37021. } else if (util.hasParent(element, this.dom.center)) {
  37022. what = 'background';
  37023. }
  37024. var value = [];
  37025. var yAxisLeft = this.linegraph.yAxisLeft;
  37026. var yAxisRight = this.linegraph.yAxisRight;
  37027. if (!yAxisLeft.hidden && this.itemsData.length > 0) {
  37028. value.push(yAxisLeft.screenToValue(y));
  37029. }
  37030. if (!yAxisRight.hidden && this.itemsData.length > 0) {
  37031. value.push(yAxisRight.screenToValue(y));
  37032. }
  37033. return {
  37034. event: event,
  37035. what: what,
  37036. pageX: event.srcEvent ? event.srcEvent.pageX : event.pageX,
  37037. pageY: event.srcEvent ? event.srcEvent.pageY : event.pageY,
  37038. x: x,
  37039. y: y,
  37040. time: time,
  37041. value: value
  37042. };
  37043. };
  37044. /**
  37045. * Load a configurator
  37046. * @return {Object}
  37047. * @private
  37048. */
  37049. Graph2d.prototype._createConfigurator = function() {
  37050. return new Configurator(this, this.dom.container, configureOptions);
  37051. };
  37052. module.exports = Graph2d;
  37053. /***/
  37054. }),
  37055. /* 181 */
  37056. /***/
  37057. (function(module, exports, __webpack_require__) {
  37058. "use strict";
  37059. // utils
  37060. exports.util = __webpack_require__(2);
  37061. exports.DOMutil = __webpack_require__(14);
  37062. // data
  37063. exports.DataSet = __webpack_require__(11);
  37064. exports.DataView = __webpack_require__(12);
  37065. exports.Queue = __webpack_require__(43);
  37066. // Network
  37067. exports.Network = __webpack_require__(182);
  37068. exports.network = {
  37069. Images: __webpack_require__(116),
  37070. dotparser: __webpack_require__(114),
  37071. gephiParser: __webpack_require__(115),
  37072. allOptions: __webpack_require__(122)
  37073. };
  37074. exports.network.convertDot = function(input) {
  37075. return exports.network.dotparser.DOTToGraph(input);
  37076. };
  37077. exports.network.convertGephi = function(input, options) {
  37078. return exports.network.gephiParser.parseGephi(input, options);
  37079. };
  37080. // bundled external libraries
  37081. exports.moment = __webpack_require__(9);
  37082. exports.Hammer = __webpack_require__(10);
  37083. exports.keycharm = __webpack_require__(35);
  37084. /***/
  37085. }),
  37086. /* 182 */
  37087. /***/
  37088. (function(module, exports, __webpack_require__) {
  37089. "use strict";
  37090. // Load custom shapes into CanvasRenderingContext2D
  37091. __webpack_require__(183);
  37092. var Emitter = __webpack_require__(44);
  37093. var util = __webpack_require__(2);
  37094. var dotparser = __webpack_require__(114);
  37095. var gephiParser = __webpack_require__(115);
  37096. var Activator = __webpack_require__(97);
  37097. var locales = __webpack_require__(184);
  37098. var Images = __webpack_require__(116)['default'];
  37099. var Groups = __webpack_require__(186)['default'];
  37100. var NodesHandler = __webpack_require__(187)['default'];
  37101. var EdgesHandler = __webpack_require__(214)['default'];
  37102. var PhysicsEngine = __webpack_require__(220)['default'];
  37103. var ClusterEngine = __webpack_require__(227)['default'];
  37104. var CanvasRenderer = __webpack_require__(229)['default'];
  37105. var Canvas = __webpack_require__(230)['default'];
  37106. var View = __webpack_require__(231)['default'];
  37107. var InteractionHandler = __webpack_require__(232)['default'];
  37108. var SelectionHandler = __webpack_require__(234)['default'];
  37109. var LayoutEngine = __webpack_require__(235)['default'];
  37110. var ManipulationSystem = __webpack_require__(237)['default'];
  37111. var Configurator = __webpack_require__(71)['default'];
  37112. var Validator = __webpack_require__(15)['default'];
  37113. var _require = __webpack_require__(15),
  37114. printStyle = _require.printStyle;
  37115. var _require2 = __webpack_require__(122),
  37116. allOptions = _require2.allOptions,
  37117. configureOptions = _require2.configureOptions;
  37118. var KamadaKawai = __webpack_require__(238)['default'];
  37119. /**
  37120. * Create a network visualization, displaying nodes and edges.
  37121. *
  37122. * @param {Element} container The DOM element in which the Network will
  37123. * be created. Normally a div element.
  37124. * @param {Object} data An object containing parameters
  37125. * {Array} nodes
  37126. * {Array} edges
  37127. * @param {Object} options Options
  37128. * @constructor Network
  37129. */
  37130. function Network(container, data, options) {
  37131. var _this = this;
  37132. if (!(this instanceof Network)) {
  37133. throw new SyntaxError('Constructor must be called with the new operator');
  37134. }
  37135. // set constant values
  37136. this.options = {};
  37137. this.defaultOptions = {
  37138. locale: 'en',
  37139. locales: locales,
  37140. clickToUse: false
  37141. };
  37142. util.extend(this.options, this.defaultOptions);
  37143. /**
  37144. * Containers for nodes and edges.
  37145. *
  37146. * 'edges' and 'nodes' contain the full definitions of all the network elements.
  37147. * 'nodeIndices' and 'edgeIndices' contain the id's of the active elements.
  37148. *
  37149. * The distinction is important, because a defined node need not be active, i.e.
  37150. * visible on the canvas. This happens in particular when clusters are defined, in
  37151. * that case there will be nodes and edges not displayed.
  37152. * The bottom line is that all code with actions related to visibility, *must* use
  37153. * 'nodeIndices' and 'edgeIndices', not 'nodes' and 'edges' directly.
  37154. */
  37155. this.body = {
  37156. container: container,
  37157. // See comment above for following fields
  37158. nodes: {},
  37159. nodeIndices: [],
  37160. edges: {},
  37161. edgeIndices: [],
  37162. emitter: {
  37163. on: this.on.bind(this),
  37164. off: this.off.bind(this),
  37165. emit: this.emit.bind(this),
  37166. once: this.once.bind(this)
  37167. },
  37168. eventListeners: {
  37169. onTap: function onTap() {},
  37170. onTouch: function onTouch() {},
  37171. onDoubleTap: function onDoubleTap() {},
  37172. onHold: function onHold() {},
  37173. onDragStart: function onDragStart() {},
  37174. onDrag: function onDrag() {},
  37175. onDragEnd: function onDragEnd() {},
  37176. onMouseWheel: function onMouseWheel() {},
  37177. onPinch: function onPinch() {},
  37178. onMouseMove: function onMouseMove() {},
  37179. onRelease: function onRelease() {},
  37180. onContext: function onContext() {}
  37181. },
  37182. data: {
  37183. nodes: null, // A DataSet or DataView
  37184. edges: null // A DataSet or DataView
  37185. },
  37186. functions: {
  37187. createNode: function createNode() {},
  37188. createEdge: function createEdge() {},
  37189. getPointer: function getPointer() {}
  37190. },
  37191. modules: {},
  37192. view: {
  37193. scale: 1,
  37194. translation: { x: 0, y: 0 }
  37195. }
  37196. };
  37197. // bind the event listeners
  37198. this.bindEventListeners();
  37199. // setting up all modules
  37200. this.images = new Images(function() {
  37201. return _this.body.emitter.emit("_requestRedraw");
  37202. }); // object with images
  37203. this.groups = new Groups(); // object with groups
  37204. this.canvas = new Canvas(this.body); // DOM handler
  37205. this.selectionHandler = new SelectionHandler(this.body, this.canvas); // Selection handler
  37206. this.interactionHandler = new InteractionHandler(this.body, this.canvas, this.selectionHandler); // Interaction handler handles all the hammer bindings (that are bound by canvas), key
  37207. this.view = new View(this.body, this.canvas); // camera handler, does animations and zooms
  37208. this.renderer = new CanvasRenderer(this.body, this.canvas); // renderer, starts renderloop, has events that modules can hook into
  37209. this.physics = new PhysicsEngine(this.body); // physics engine, does all the simulations
  37210. this.layoutEngine = new LayoutEngine(this.body); // layout engine for inital layout and hierarchical layout
  37211. this.clustering = new ClusterEngine(this.body); // clustering api
  37212. this.manipulation = new ManipulationSystem(this.body, this.canvas, this.selectionHandler); // data manipulation system
  37213. this.nodesHandler = new NodesHandler(this.body, this.images, this.groups, this.layoutEngine); // Handle adding, deleting and updating of nodes as well as global options
  37214. this.edgesHandler = new EdgesHandler(this.body, this.images, this.groups); // Handle adding, deleting and updating of edges as well as global options
  37215. this.body.modules["kamadaKawai"] = new KamadaKawai(this.body, 150, 0.05); // Layouting algorithm.
  37216. this.body.modules["clustering"] = this.clustering;
  37217. // create the DOM elements
  37218. this.canvas._create();
  37219. // apply options
  37220. this.setOptions(options);
  37221. // load data (the disable start variable will be the same as the enabled clustering)
  37222. this.setData(data);
  37223. }
  37224. // Extend Network with an Emitter mixin
  37225. Emitter(Network.prototype);
  37226. /**
  37227. * Set options
  37228. * @param {Object} options
  37229. */
  37230. Network.prototype.setOptions = function(options) {
  37231. var _this2 = this;
  37232. if (options !== undefined) {
  37233. var errorFound = Validator.validate(options, allOptions);
  37234. if (errorFound === true) {
  37235. console.log('%cErrors have been found in the supplied options object.', printStyle);
  37236. }
  37237. // copy the global fields over
  37238. var fields = ['locale', 'locales', 'clickToUse'];
  37239. util.selectiveDeepExtend(fields, this.options, options);
  37240. // the hierarchical system can adapt the edges and the physics to it's own options because not all combinations work with the hierarichical system.
  37241. options = this.layoutEngine.setOptions(options.layout, options);
  37242. this.canvas.setOptions(options); // options for canvas are in globals
  37243. // pass the options to the modules
  37244. this.groups.setOptions(options.groups);
  37245. this.nodesHandler.setOptions(options.nodes);
  37246. this.edgesHandler.setOptions(options.edges);
  37247. this.physics.setOptions(options.physics);
  37248. this.manipulation.setOptions(options.manipulation, options, this.options); // manipulation uses the locales in the globals
  37249. this.interactionHandler.setOptions(options.interaction);
  37250. this.renderer.setOptions(options.interaction); // options for rendering are in interaction
  37251. this.selectionHandler.setOptions(options.interaction); // options for selection are in interaction
  37252. // reload the settings of the nodes to apply changes in groups that are not referenced by pointer.
  37253. if (options.groups !== undefined) {
  37254. this.body.emitter.emit("refreshNodes");
  37255. }
  37256. // these two do not have options at the moment, here for completeness
  37257. //this.view.setOptions(options.view);
  37258. //this.clustering.setOptions(options.clustering);
  37259. if ('configure' in options) {
  37260. if (!this.configurator) {
  37261. this.configurator = new Configurator(this, this.body.container, configureOptions, this.canvas.pixelRatio);
  37262. }
  37263. this.configurator.setOptions(options.configure);
  37264. }
  37265. // if the configuration system is enabled, copy all options and put them into the config system
  37266. if (this.configurator && this.configurator.options.enabled === true) {
  37267. var networkOptions = { nodes: {}, edges: {}, layout: {}, interaction: {}, manipulation: {}, physics: {}, global: {} };
  37268. util.deepExtend(networkOptions.nodes, this.nodesHandler.options);
  37269. util.deepExtend(networkOptions.edges, this.edgesHandler.options);
  37270. util.deepExtend(networkOptions.layout, this.layoutEngine.options);
  37271. // load the selectionHandler and render default options in to the interaction group
  37272. util.deepExtend(networkOptions.interaction, this.selectionHandler.options);
  37273. util.deepExtend(networkOptions.interaction, this.renderer.options);
  37274. util.deepExtend(networkOptions.interaction, this.interactionHandler.options);
  37275. util.deepExtend(networkOptions.manipulation, this.manipulation.options);
  37276. util.deepExtend(networkOptions.physics, this.physics.options);
  37277. // load globals into the global object
  37278. util.deepExtend(networkOptions.global, this.canvas.options);
  37279. util.deepExtend(networkOptions.global, this.options);
  37280. this.configurator.setModuleOptions(networkOptions);
  37281. }
  37282. // handle network global options
  37283. if (options.clickToUse !== undefined) {
  37284. if (options.clickToUse === true) {
  37285. if (this.activator === undefined) {
  37286. this.activator = new Activator(this.canvas.frame);
  37287. this.activator.on('change', function() {
  37288. _this2.body.emitter.emit("activate");
  37289. });
  37290. }
  37291. } else {
  37292. if (this.activator !== undefined) {
  37293. this.activator.destroy();
  37294. delete this.activator;
  37295. }
  37296. this.body.emitter.emit("activate");
  37297. }
  37298. } else {
  37299. this.body.emitter.emit("activate");
  37300. }
  37301. this.canvas.setSize();
  37302. // start the physics simulation. Can be safely called multiple times.
  37303. this.body.emitter.emit("startSimulation");
  37304. }
  37305. };
  37306. /**
  37307. * Update the visible nodes and edges list with the most recent node state.
  37308. *
  37309. * Visible nodes are stored in this.body.nodeIndices.
  37310. * Visible edges are stored in this.body.edgeIndices.
  37311. * A node or edges is visible if it is not hidden or clustered.
  37312. *
  37313. * @private
  37314. */
  37315. Network.prototype._updateVisibleIndices = function() {
  37316. var nodes = this.body.nodes;
  37317. var edges = this.body.edges;
  37318. this.body.nodeIndices = [];
  37319. this.body.edgeIndices = [];
  37320. for (var nodeId in nodes) {
  37321. if (nodes.hasOwnProperty(nodeId)) {
  37322. if (!this.clustering._isClusteredNode(nodeId) && nodes[nodeId].options.hidden === false) {
  37323. this.body.nodeIndices.push(nodes[nodeId].id);
  37324. }
  37325. }
  37326. }
  37327. for (var edgeId in edges) {
  37328. if (edges.hasOwnProperty(edgeId)) {
  37329. var edge = edges[edgeId];
  37330. // It can happen that this is executed *after* a node edge has been removed,
  37331. // but *before* the edge itself has been removed. Taking this into account.
  37332. var fromNode = nodes[edge.fromId];
  37333. var toNode = nodes[edge.toId];
  37334. var edgeNodesPresent = fromNode !== undefined && toNode !== undefined;
  37335. var isVisible = !this.clustering._isClusteredEdge(edgeId) && edge.options.hidden === false && edgeNodesPresent && fromNode.options.hidden === false // Also hidden if any of its connecting nodes are hidden
  37336. &&
  37337. toNode.options.hidden === false; // idem
  37338. if (isVisible) {
  37339. this.body.edgeIndices.push(edge.id);
  37340. }
  37341. }
  37342. }
  37343. };
  37344. /**
  37345. * Bind all events
  37346. */
  37347. Network.prototype.bindEventListeners = function() {
  37348. var _this3 = this;
  37349. // This event will trigger a rebuilding of the cache everything.
  37350. // Used when nodes or edges have been added or removed.
  37351. this.body.emitter.on("_dataChanged", function() {
  37352. _this3.edgesHandler._updateState();
  37353. _this3.body.emitter.emit("_dataUpdated");
  37354. });
  37355. // this is called when options of EXISTING nodes or edges have changed.
  37356. this.body.emitter.on("_dataUpdated", function() {
  37357. // Order important in following block
  37358. _this3.clustering._updateState();
  37359. _this3._updateVisibleIndices();
  37360. _this3._updateValueRange(_this3.body.nodes);
  37361. _this3._updateValueRange(_this3.body.edges);
  37362. // start simulation (can be called safely, even if already running)
  37363. _this3.body.emitter.emit("startSimulation");
  37364. _this3.body.emitter.emit("_requestRedraw");
  37365. });
  37366. };
  37367. /**
  37368. * Set nodes and edges, and optionally options as well.
  37369. *
  37370. * @param {Object} data Object containing parameters:
  37371. * {Array | DataSet | DataView} [nodes] Array with nodes
  37372. * {Array | DataSet | DataView} [edges] Array with edges
  37373. * {String} [dot] String containing data in DOT format
  37374. * {String} [gephi] String containing data in gephi JSON format
  37375. * {Options} [options] Object with options
  37376. */
  37377. Network.prototype.setData = function(data) {
  37378. // reset the physics engine.
  37379. this.body.emitter.emit("resetPhysics");
  37380. this.body.emitter.emit("_resetData");
  37381. // unselect all to ensure no selections from old data are carried over.
  37382. this.selectionHandler.unselectAll();
  37383. if (data && data.dot && (data.nodes || data.edges)) {
  37384. throw new SyntaxError('Data must contain either parameter "dot" or ' + ' parameter pair "nodes" and "edges", but not both.');
  37385. }
  37386. // set options
  37387. this.setOptions(data && data.options);
  37388. // set all data
  37389. if (data && data.dot) {
  37390. console.log('The dot property has been deprecated. Please use the static convertDot method to convert DOT into vis.network format and use the normal data format with nodes and edges. This converter is used like this: var data = vis.network.convertDot(dotString);');
  37391. // parse DOT file
  37392. var dotData = dotparser.DOTToGraph(data.dot);
  37393. this.setData(dotData);
  37394. return;
  37395. } else if (data && data.gephi) {
  37396. // parse DOT file
  37397. console.log('The gephi property has been deprecated. Please use the static convertGephi method to convert gephi into vis.network format and use the normal data format with nodes and edges. This converter is used like this: var data = vis.network.convertGephi(gephiJson);');
  37398. var gephiData = gephiParser.parseGephi(data.gephi);
  37399. this.setData(gephiData);
  37400. return;
  37401. } else {
  37402. this.nodesHandler.setData(data && data.nodes, true);
  37403. this.edgesHandler.setData(data && data.edges, true);
  37404. }
  37405. // emit change in data
  37406. this.body.emitter.emit("_dataChanged");
  37407. // emit data loaded
  37408. this.body.emitter.emit("_dataLoaded");
  37409. // find a stable position or start animating to a stable position
  37410. this.body.emitter.emit("initPhysics");
  37411. };
  37412. /**
  37413. * Cleans up all bindings of the network, removing it fully from the memory IF the variable is set to null after calling this function.
  37414. * var network = new vis.Network(..);
  37415. * network.destroy();
  37416. * network = null;
  37417. */
  37418. Network.prototype.destroy = function() {
  37419. this.body.emitter.emit("destroy");
  37420. // clear events
  37421. this.body.emitter.off();
  37422. this.off();
  37423. // delete modules
  37424. delete this.groups;
  37425. delete this.canvas;
  37426. delete this.selectionHandler;
  37427. delete this.interactionHandler;
  37428. delete this.view;
  37429. delete this.renderer;
  37430. delete this.physics;
  37431. delete this.layoutEngine;
  37432. delete this.clustering;
  37433. delete this.manipulation;
  37434. delete this.nodesHandler;
  37435. delete this.edgesHandler;
  37436. delete this.configurator;
  37437. delete this.images;
  37438. for (var nodeId in this.body.nodes) {
  37439. if (!this.body.nodes.hasOwnProperty(nodeId)) continue;
  37440. delete this.body.nodes[nodeId];
  37441. }
  37442. for (var edgeId in this.body.edges) {
  37443. if (!this.body.edges.hasOwnProperty(edgeId)) continue;
  37444. delete this.body.edges[edgeId];
  37445. }
  37446. // remove the container and everything inside it recursively
  37447. util.recursiveDOMDelete(this.body.container);
  37448. };
  37449. /**
  37450. * Update the values of all object in the given array according to the current
  37451. * value range of the objects in the array.
  37452. * @param {Object} obj An object containing a set of Edges or Nodes
  37453. * The objects must have a method getValue() and
  37454. * setValueRange(min, max).
  37455. * @private
  37456. */
  37457. Network.prototype._updateValueRange = function(obj) {
  37458. var id;
  37459. // determine the range of the objects
  37460. var valueMin = undefined;
  37461. var valueMax = undefined;
  37462. var valueTotal = 0;
  37463. for (id in obj) {
  37464. if (obj.hasOwnProperty(id)) {
  37465. var value = obj[id].getValue();
  37466. if (value !== undefined) {
  37467. valueMin = valueMin === undefined ? value : Math.min(value, valueMin);
  37468. valueMax = valueMax === undefined ? value : Math.max(value, valueMax);
  37469. valueTotal += value;
  37470. }
  37471. }
  37472. }
  37473. // adjust the range of all objects
  37474. if (valueMin !== undefined && valueMax !== undefined) {
  37475. for (id in obj) {
  37476. if (obj.hasOwnProperty(id)) {
  37477. obj[id].setValueRange(valueMin, valueMax, valueTotal);
  37478. }
  37479. }
  37480. }
  37481. };
  37482. /**
  37483. * Returns true when the Network is active.
  37484. * @returns {boolean}
  37485. */
  37486. Network.prototype.isActive = function() {
  37487. return !this.activator || this.activator.active;
  37488. };
  37489. Network.prototype.setSize = function() {
  37490. return this.canvas.setSize.apply(this.canvas, arguments);
  37491. };
  37492. Network.prototype.canvasToDOM = function() {
  37493. return this.canvas.canvasToDOM.apply(this.canvas, arguments);
  37494. };
  37495. Network.prototype.DOMtoCanvas = function() {
  37496. return this.canvas.DOMtoCanvas.apply(this.canvas, arguments);
  37497. };
  37498. Network.prototype.findNode = function() {
  37499. return this.clustering.findNode.apply(this.clustering, arguments);
  37500. };
  37501. Network.prototype.isCluster = function() {
  37502. return this.clustering.isCluster.apply(this.clustering, arguments);
  37503. };
  37504. Network.prototype.openCluster = function() {
  37505. return this.clustering.openCluster.apply(this.clustering, arguments);
  37506. };
  37507. Network.prototype.cluster = function() {
  37508. return this.clustering.cluster.apply(this.clustering, arguments);
  37509. };
  37510. Network.prototype.getNodesInCluster = function() {
  37511. return this.clustering.getNodesInCluster.apply(this.clustering, arguments);
  37512. };
  37513. Network.prototype.clusterByConnection = function() {
  37514. return this.clustering.clusterByConnection.apply(this.clustering, arguments);
  37515. };
  37516. Network.prototype.clusterByHubsize = function() {
  37517. return this.clustering.clusterByHubsize.apply(this.clustering, arguments);
  37518. };
  37519. Network.prototype.clusterOutliers = function() {
  37520. return this.clustering.clusterOutliers.apply(this.clustering, arguments);
  37521. };
  37522. Network.prototype.getSeed = function() {
  37523. return this.layoutEngine.getSeed.apply(this.layoutEngine, arguments);
  37524. };
  37525. Network.prototype.enableEditMode = function() {
  37526. return this.manipulation.enableEditMode.apply(this.manipulation, arguments);
  37527. };
  37528. Network.prototype.disableEditMode = function() {
  37529. return this.manipulation.disableEditMode.apply(this.manipulation, arguments);
  37530. };
  37531. Network.prototype.addNodeMode = function() {
  37532. return this.manipulation.addNodeMode.apply(this.manipulation, arguments);
  37533. };
  37534. Network.prototype.editNode = function() {
  37535. return this.manipulation.editNode.apply(this.manipulation, arguments);
  37536. };
  37537. Network.prototype.editNodeMode = function() {
  37538. console.log("Deprecated: Please use editNode instead of editNodeMode.");
  37539. return this.manipulation.editNode.apply(this.manipulation, arguments);
  37540. };
  37541. Network.prototype.addEdgeMode = function() {
  37542. return this.manipulation.addEdgeMode.apply(this.manipulation, arguments);
  37543. };
  37544. Network.prototype.editEdgeMode = function() {
  37545. return this.manipulation.editEdgeMode.apply(this.manipulation, arguments);
  37546. };
  37547. Network.prototype.deleteSelected = function() {
  37548. return this.manipulation.deleteSelected.apply(this.manipulation, arguments);
  37549. };
  37550. Network.prototype.getPositions = function() {
  37551. return this.nodesHandler.getPositions.apply(this.nodesHandler, arguments);
  37552. };
  37553. Network.prototype.storePositions = function() {
  37554. return this.nodesHandler.storePositions.apply(this.nodesHandler, arguments);
  37555. };
  37556. Network.prototype.moveNode = function() {
  37557. return this.nodesHandler.moveNode.apply(this.nodesHandler, arguments);
  37558. };
  37559. Network.prototype.getBoundingBox = function() {
  37560. return this.nodesHandler.getBoundingBox.apply(this.nodesHandler, arguments);
  37561. };
  37562. Network.prototype.getConnectedNodes = function(objectId) {
  37563. if (this.body.nodes[objectId] !== undefined) {
  37564. return this.nodesHandler.getConnectedNodes.apply(this.nodesHandler, arguments);
  37565. } else {
  37566. return this.edgesHandler.getConnectedNodes.apply(this.edgesHandler, arguments);
  37567. }
  37568. };
  37569. Network.prototype.getConnectedEdges = function() {
  37570. return this.nodesHandler.getConnectedEdges.apply(this.nodesHandler, arguments);
  37571. };
  37572. Network.prototype.startSimulation = function() {
  37573. return this.physics.startSimulation.apply(this.physics, arguments);
  37574. };
  37575. Network.prototype.stopSimulation = function() {
  37576. return this.physics.stopSimulation.apply(this.physics, arguments);
  37577. };
  37578. Network.prototype.stabilize = function() {
  37579. return this.physics.stabilize.apply(this.physics, arguments);
  37580. };
  37581. Network.prototype.getSelection = function() {
  37582. return this.selectionHandler.getSelection.apply(this.selectionHandler, arguments);
  37583. };
  37584. Network.prototype.setSelection = function() {
  37585. return this.selectionHandler.setSelection.apply(this.selectionHandler, arguments);
  37586. };
  37587. Network.prototype.getSelectedNodes = function() {
  37588. return this.selectionHandler.getSelectedNodes.apply(this.selectionHandler, arguments);
  37589. };
  37590. Network.prototype.getSelectedEdges = function() {
  37591. return this.selectionHandler.getSelectedEdges.apply(this.selectionHandler, arguments);
  37592. };
  37593. Network.prototype.getNodeAt = function() {
  37594. var node = this.selectionHandler.getNodeAt.apply(this.selectionHandler, arguments);
  37595. if (node !== undefined && node.id !== undefined) {
  37596. return node.id;
  37597. }
  37598. return node;
  37599. };
  37600. Network.prototype.getEdgeAt = function() {
  37601. var edge = this.selectionHandler.getEdgeAt.apply(this.selectionHandler, arguments);
  37602. if (edge !== undefined && edge.id !== undefined) {
  37603. return edge.id;
  37604. }
  37605. return edge;
  37606. };
  37607. Network.prototype.selectNodes = function() {
  37608. return this.selectionHandler.selectNodes.apply(this.selectionHandler, arguments);
  37609. };
  37610. Network.prototype.selectEdges = function() {
  37611. return this.selectionHandler.selectEdges.apply(this.selectionHandler, arguments);
  37612. };
  37613. Network.prototype.unselectAll = function() {
  37614. this.selectionHandler.unselectAll.apply(this.selectionHandler, arguments);
  37615. this.redraw();
  37616. };
  37617. Network.prototype.redraw = function() {
  37618. return this.renderer.redraw.apply(this.renderer, arguments);
  37619. };
  37620. Network.prototype.getScale = function() {
  37621. return this.view.getScale.apply(this.view, arguments);
  37622. };
  37623. Network.prototype.getViewPosition = function() {
  37624. return this.view.getViewPosition.apply(this.view, arguments);
  37625. };
  37626. Network.prototype.fit = function() {
  37627. return this.view.fit.apply(this.view, arguments);
  37628. };
  37629. Network.prototype.moveTo = function() {
  37630. return this.view.moveTo.apply(this.view, arguments);
  37631. };
  37632. Network.prototype.focus = function() {
  37633. return this.view.focus.apply(this.view, arguments);
  37634. };
  37635. Network.prototype.releaseNode = function() {
  37636. return this.view.releaseNode.apply(this.view, arguments);
  37637. };
  37638. Network.prototype.getOptionsFromConfigurator = function() {
  37639. var options = {};
  37640. if (this.configurator) {
  37641. options = this.configurator.getOptions.apply(this.configurator);
  37642. }
  37643. return options;
  37644. };
  37645. module.exports = Network;
  37646. /***/
  37647. }),
  37648. /* 183 */
  37649. /***/
  37650. (function(module, exports, __webpack_require__) {
  37651. "use strict";
  37652. /**
  37653. * Canvas shapes used by Network
  37654. */
  37655. if (typeof CanvasRenderingContext2D !== 'undefined') {
  37656. /**
  37657. * Draw a circle shape
  37658. *
  37659. * @param {number} x
  37660. * @param {number} y
  37661. * @param {number} r
  37662. */
  37663. CanvasRenderingContext2D.prototype.circle = function(x, y, r) {
  37664. this.beginPath();
  37665. this.arc(x, y, r, 0, 2 * Math.PI, false);
  37666. this.closePath();
  37667. };
  37668. /**
  37669. * Draw a square shape
  37670. * @param {number} x horizontal center
  37671. * @param {number} y vertical center
  37672. * @param {number} r size, width and height of the square
  37673. */
  37674. CanvasRenderingContext2D.prototype.square = function(x, y, r) {
  37675. this.beginPath();
  37676. this.rect(x - r, y - r, r * 2, r * 2);
  37677. this.closePath();
  37678. };
  37679. /**
  37680. * Draw a triangle shape
  37681. * @param {number} x horizontal center
  37682. * @param {number} y vertical center
  37683. * @param {number} r radius, half the length of the sides of the triangle
  37684. */
  37685. CanvasRenderingContext2D.prototype.triangle = function(x, y, r) {
  37686. // http://en.wikipedia.org/wiki/Equilateral_triangle
  37687. this.beginPath();
  37688. // the change in radius and the offset is here to center the shape
  37689. r *= 1.15;
  37690. y += 0.275 * r;
  37691. var s = r * 2;
  37692. var s2 = s / 2;
  37693. var ir = Math.sqrt(3) / 6 * s; // radius of inner circle
  37694. var h = Math.sqrt(s * s - s2 * s2); // height
  37695. this.moveTo(x, y - (h - ir));
  37696. this.lineTo(x + s2, y + ir);
  37697. this.lineTo(x - s2, y + ir);
  37698. this.lineTo(x, y - (h - ir));
  37699. this.closePath();
  37700. };
  37701. /**
  37702. * Draw a triangle shape in downward orientation
  37703. * @param {number} x horizontal center
  37704. * @param {number} y vertical center
  37705. * @param {number} r radius
  37706. */
  37707. CanvasRenderingContext2D.prototype.triangleDown = function(x, y, r) {
  37708. // http://en.wikipedia.org/wiki/Equilateral_triangle
  37709. this.beginPath();
  37710. // the change in radius and the offset is here to center the shape
  37711. r *= 1.15;
  37712. y -= 0.275 * r;
  37713. var s = r * 2;
  37714. var s2 = s / 2;
  37715. var ir = Math.sqrt(3) / 6 * s; // radius of inner circle
  37716. var h = Math.sqrt(s * s - s2 * s2); // height
  37717. this.moveTo(x, y + (h - ir));
  37718. this.lineTo(x + s2, y - ir);
  37719. this.lineTo(x - s2, y - ir);
  37720. this.lineTo(x, y + (h - ir));
  37721. this.closePath();
  37722. };
  37723. /**
  37724. * Draw a star shape, a star with 5 points
  37725. * @param {number} x horizontal center
  37726. * @param {number} y vertical center
  37727. * @param {number} r radius, half the length of the sides of the triangle
  37728. */
  37729. CanvasRenderingContext2D.prototype.star = function(x, y, r) {
  37730. // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/
  37731. this.beginPath();
  37732. // the change in radius and the offset is here to center the shape
  37733. r *= 0.82;
  37734. y += 0.1 * r;
  37735. for (var n = 0; n < 10; n++) {
  37736. var radius = n % 2 === 0 ? r * 1.3 : r * 0.5;
  37737. this.lineTo(x + radius * Math.sin(n * 2 * Math.PI / 10), y - radius * Math.cos(n * 2 * Math.PI / 10));
  37738. }
  37739. this.closePath();
  37740. };
  37741. /**
  37742. * Draw a Diamond shape
  37743. * @param {number} x horizontal center
  37744. * @param {number} y vertical center
  37745. * @param {number} r radius, half the length of the sides of the triangle
  37746. */
  37747. CanvasRenderingContext2D.prototype.diamond = function(x, y, r) {
  37748. // http://www.html5canvastutorials.com/labs/html5-canvas-star-spinner/
  37749. this.beginPath();
  37750. this.lineTo(x, y + r);
  37751. this.lineTo(x + r, y);
  37752. this.lineTo(x, y - r);
  37753. this.lineTo(x - r, y);
  37754. this.closePath();
  37755. };
  37756. /**
  37757. * http://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas
  37758. *
  37759. * @param {number} x
  37760. * @param {number} y
  37761. * @param {number} w
  37762. * @param {number} h
  37763. * @param {number} r
  37764. */
  37765. CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {
  37766. var r2d = Math.PI / 180;
  37767. if (w - 2 * r < 0) {
  37768. r = w / 2;
  37769. } //ensure that the radius isn't too large for x
  37770. if (h - 2 * r < 0) {
  37771. r = h / 2;
  37772. } //ensure that the radius isn't too large for y
  37773. this.beginPath();
  37774. this.moveTo(x + r, y);
  37775. this.lineTo(x + w - r, y);
  37776. this.arc(x + w - r, y + r, r, r2d * 270, r2d * 360, false);
  37777. this.lineTo(x + w, y + h - r);
  37778. this.arc(x + w - r, y + h - r, r, 0, r2d * 90, false);
  37779. this.lineTo(x + r, y + h);
  37780. this.arc(x + r, y + h - r, r, r2d * 90, r2d * 180, false);
  37781. this.lineTo(x, y + r);
  37782. this.arc(x + r, y + r, r, r2d * 180, r2d * 270, false);
  37783. this.closePath();
  37784. };
  37785. /**
  37786. * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
  37787. *
  37788. * Postfix '_vis' added to discern it from standard method ellipse().
  37789. *
  37790. * @param {number} x
  37791. * @param {number} y
  37792. * @param {number} w
  37793. * @param {number} h
  37794. */
  37795. CanvasRenderingContext2D.prototype.ellipse_vis = function(x, y, w, h) {
  37796. var kappa = .5522848,
  37797. ox = w / 2 * kappa,
  37798. // control point offset horizontal
  37799. oy = h / 2 * kappa,
  37800. // control point offset vertical
  37801. xe = x + w,
  37802. // x-end
  37803. ye = y + h,
  37804. // y-end
  37805. xm = x + w / 2,
  37806. // x-middle
  37807. ym = y + h / 2; // y-middle
  37808. this.beginPath();
  37809. this.moveTo(x, ym);
  37810. this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
  37811. this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
  37812. this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
  37813. this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
  37814. this.closePath();
  37815. };
  37816. /**
  37817. * http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
  37818. *
  37819. * @param {number} x
  37820. * @param {number} y
  37821. * @param {number} w
  37822. * @param {number} h
  37823. */
  37824. CanvasRenderingContext2D.prototype.database = function(x, y, w, h) {
  37825. var f = 1 / 3;
  37826. var wEllipse = w;
  37827. var hEllipse = h * f;
  37828. var kappa = .5522848,
  37829. ox = wEllipse / 2 * kappa,
  37830. // control point offset horizontal
  37831. oy = hEllipse / 2 * kappa,
  37832. // control point offset vertical
  37833. xe = x + wEllipse,
  37834. // x-end
  37835. ye = y + hEllipse,
  37836. // y-end
  37837. xm = x + wEllipse / 2,
  37838. // x-middle
  37839. ym = y + hEllipse / 2,
  37840. // y-middle
  37841. ymb = y + (h - hEllipse / 2),
  37842. // y-midlle, bottom ellipse
  37843. yeb = y + h; // y-end, bottom ellipse
  37844. this.beginPath();
  37845. this.moveTo(xe, ym);
  37846. this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
  37847. this.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
  37848. this.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
  37849. this.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
  37850. this.lineTo(xe, ymb);
  37851. this.bezierCurveTo(xe, ymb + oy, xm + ox, yeb, xm, yeb);
  37852. this.bezierCurveTo(xm - ox, yeb, x, ymb + oy, x, ymb);
  37853. this.lineTo(x, ym);
  37854. };
  37855. /**
  37856. * Sets up the dashedLine functionality for drawing
  37857. * Original code came from http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas
  37858. * @author David Jordan
  37859. * @date 2012-08-08
  37860. *
  37861. * @param {number} x
  37862. * @param {number} y
  37863. * @param {number} x2
  37864. * @param {number} y2
  37865. * @param {string} pattern
  37866. */
  37867. CanvasRenderingContext2D.prototype.dashedLine = function(x, y, x2, y2, pattern) {
  37868. this.beginPath();
  37869. this.moveTo(x, y);
  37870. var patternLength = pattern.length;
  37871. var dx = x2 - x;
  37872. var dy = y2 - y;
  37873. var slope = dy / dx;
  37874. var distRemaining = Math.sqrt(dx * dx + dy * dy);
  37875. var patternIndex = 0;
  37876. var draw = true;
  37877. var xStep = 0;
  37878. var dashLength = pattern[0];
  37879. while (distRemaining >= 0.1) {
  37880. dashLength = pattern[patternIndex++ % patternLength];
  37881. if (dashLength > distRemaining) {
  37882. dashLength = distRemaining;
  37883. }
  37884. xStep = Math.sqrt(dashLength * dashLength / (1 + slope * slope));
  37885. xStep = dx < 0 ? -xStep : xStep;
  37886. x += xStep;
  37887. y += slope * xStep;
  37888. if (draw === true) {
  37889. this.lineTo(x, y);
  37890. } else {
  37891. this.moveTo(x, y);
  37892. }
  37893. distRemaining -= dashLength;
  37894. draw = !draw;
  37895. }
  37896. };
  37897. /**
  37898. * Draw a Hexagon shape with 6 sides
  37899. * @param {Number} x horizontal center
  37900. * @param {Number} y vertical center
  37901. * @param {Number} r radius
  37902. */
  37903. CanvasRenderingContext2D.prototype.hexagon = function(x, y, r) {
  37904. this.beginPath();
  37905. var sides = 6;
  37906. var a = Math.PI * 2 / sides;
  37907. this.moveTo(x + r, y);
  37908. for (var i = 1; i < sides; i++) {
  37909. this.lineTo(x + r * Math.cos(a * i), y + r * Math.sin(a * i));
  37910. }
  37911. this.closePath();
  37912. };
  37913. }
  37914. /***/
  37915. }),
  37916. /* 184 */
  37917. /***/
  37918. (function(module, exports, __webpack_require__) {
  37919. "use strict";
  37920. // English
  37921. exports['en'] = {
  37922. edit: 'Edit',
  37923. del: 'Delete selected',
  37924. back: 'Back',
  37925. addNode: 'Add Node',
  37926. addEdge: 'Add Edge',
  37927. editNode: 'Edit Node',
  37928. editEdge: 'Edit Edge',
  37929. addDescription: 'Click in an empty space to place a new node.',
  37930. edgeDescription: 'Click on a node and drag the edge to another node to connect them.',
  37931. editEdgeDescription: 'Click on the control points and drag them to a node to connect to it.',
  37932. createEdgeError: 'Cannot link edges to a cluster.',
  37933. deleteClusterError: 'Clusters cannot be deleted.',
  37934. editClusterError: 'Clusters cannot be edited.'
  37935. };
  37936. exports['en_EN'] = exports['en'];
  37937. exports['en_US'] = exports['en'];
  37938. // German
  37939. exports['de'] = {
  37940. edit: 'Editieren',
  37941. del: 'L\xF6sche Auswahl',
  37942. back: 'Zur\xFCck',
  37943. addNode: 'Knoten hinzuf\xFCgen',
  37944. addEdge: 'Kante hinzuf\xFCgen',
  37945. editNode: 'Knoten editieren',
  37946. editEdge: 'Kante editieren',
  37947. addDescription: 'Klicke auf eine freie Stelle, um einen neuen Knoten zu plazieren.',
  37948. edgeDescription: 'Klicke auf einen Knoten und ziehe die Kante zu einem anderen Knoten, um diese zu verbinden.',
  37949. editEdgeDescription: 'Klicke auf die Verbindungspunkte und ziehe diese auf einen Knoten, um sie zu verbinden.',
  37950. createEdgeError: 'Es ist nicht m\xF6glich, Kanten mit Clustern zu verbinden.',
  37951. deleteClusterError: 'Cluster k\xF6nnen nicht gel\xF6scht werden.',
  37952. editClusterError: 'Cluster k\xF6nnen nicht editiert werden.'
  37953. };
  37954. exports['de_DE'] = exports['de'];
  37955. // Spanish
  37956. exports['es'] = {
  37957. edit: 'Editar',
  37958. del: 'Eliminar selecci\xF3n',
  37959. back: '\xC1tras',
  37960. addNode: 'A\xF1adir nodo',
  37961. addEdge: 'A\xF1adir arista',
  37962. editNode: 'Editar nodo',
  37963. editEdge: 'Editar arista',
  37964. addDescription: 'Haga clic en un lugar vac\xEDo para colocar un nuevo nodo.',
  37965. edgeDescription: 'Haga clic en un nodo y arrastre la arista hacia otro nodo para conectarlos.',
  37966. editEdgeDescription: 'Haga clic en un punto de control y arrastrelo a un nodo para conectarlo.',
  37967. createEdgeError: 'No se puede conectar una arista a un grupo.',
  37968. deleteClusterError: 'No es posible eliminar grupos.',
  37969. editClusterError: 'No es posible editar grupos.'
  37970. };
  37971. exports['es_ES'] = exports['es'];
  37972. //Italiano
  37973. exports['it'] = {
  37974. edit: 'Modifica',
  37975. del: 'Cancella la selezione',
  37976. back: 'Indietro',
  37977. addNode: 'Aggiungi un nodo',
  37978. addEdge: 'Aggiungi un vertice',
  37979. editNode: 'Modifica il nodo',
  37980. editEdge: 'Modifica il vertice',
  37981. addDescription: 'Clicca per aggiungere un nuovo nodo',
  37982. edgeDescription: 'Clicca su un nodo e trascinalo ad un altro nodo per connetterli.',
  37983. editEdgeDescription: 'Clicca sui Punti di controllo e trascinali ad un nodo per connetterli.',
  37984. createEdgeError: 'Non si possono collegare vertici ad un cluster',
  37985. deleteClusterError: 'I cluster non possono essere cancellati',
  37986. editClusterError: 'I clusters non possono essere modificati.'
  37987. };
  37988. exports['it_IT'] = exports['it'];
  37989. // Dutch
  37990. exports['nl'] = {
  37991. edit: 'Wijzigen',
  37992. del: 'Selectie verwijderen',
  37993. back: 'Terug',
  37994. addNode: 'Node toevoegen',
  37995. addEdge: 'Link toevoegen',
  37996. editNode: 'Node wijzigen',
  37997. editEdge: 'Link wijzigen',
  37998. addDescription: 'Klik op een leeg gebied om een nieuwe node te maken.',
  37999. edgeDescription: 'Klik op een node en sleep de link naar een andere node om ze te verbinden.',
  38000. editEdgeDescription: 'Klik op de verbindingspunten en sleep ze naar een node om daarmee te verbinden.',
  38001. createEdgeError: 'Kan geen link maken naar een cluster.',
  38002. deleteClusterError: 'Clusters kunnen niet worden verwijderd.',
  38003. editClusterError: 'Clusters kunnen niet worden aangepast.'
  38004. };
  38005. exports['nl_NL'] = exports['nl'];
  38006. exports['nl_BE'] = exports['nl'];
  38007. // Portuguese Brazil
  38008. exports['pt-br'] = {
  38009. edit: 'Editar',
  38010. del: 'Remover selecionado',
  38011. back: 'Voltar',
  38012. addNode: 'Adicionar nó',
  38013. addEdge: 'Adicionar aresta',
  38014. editNode: 'Editar nó',
  38015. editEdge: 'Editar aresta',
  38016. addDescription: 'Clique em um espaço em branco para adicionar um novo nó',
  38017. edgeDescription: 'Clique em um nó e arraste a aresta até outro nó para conectá-los',
  38018. editEdgeDescription: 'Clique nos pontos de controle e os arraste para um nó para conectá-los',
  38019. createEdgeError: 'Não foi possível linkar arestas a um cluster.',
  38020. deleteClusterError: 'Clusters não puderam ser removidos.',
  38021. editClusterError: 'Clusters não puderam ser editados.'
  38022. };
  38023. exports['pt-BR'] = exports['pt-br'];
  38024. exports['pt_BR'] = exports['pt-br'];
  38025. exports['pt_br'] = exports['pt-br'];
  38026. // Russian
  38027. exports['ru'] = {
  38028. edit: 'Редактировать',
  38029. del: 'Удалить выбранное',
  38030. back: 'Назад',
  38031. addNode: 'Добавить узел',
  38032. addEdge: 'Добавить ребро',
  38033. editNode: 'Редактировать узел',
  38034. editEdge: 'Редактировать ребро',
  38035. addDescription: 'Кликните в свободное место, чтобы добавить новый узел.',
  38036. edgeDescription: 'Кликните на узел и протяните ребро к другому узлу, чтобы соединить их.',
  38037. editEdgeDescription: 'Кликните на контрольные точки и перетащите их в узел, чтобы подключиться к нему.',
  38038. createEdgeError: 'Невозможно соединить ребра в кластер.',
  38039. deleteClusterError: 'Кластеры не могут быть удалены',
  38040. editClusterError: 'Кластеры недоступны для редактирования.'
  38041. };
  38042. exports['ru_RU'] = exports['ru'];
  38043. // Chinese
  38044. exports['cn'] = {
  38045. edit: '编辑',
  38046. del: '删除选定',
  38047. back: '返回',
  38048. addNode: '添加节点',
  38049. addEdge: '添加连接线',
  38050. editNode: '编辑节点',
  38051. editEdge: '编辑连接线',
  38052. addDescription: '单击空白处放置新节点。',
  38053. edgeDescription: '单击某个节点并将该连接线拖动到另一个节点以连接它们。',
  38054. editEdgeDescription: '单击控制节点并将它们拖到节点上连接。',
  38055. createEdgeError: '无法将连接线连接到群集。',
  38056. deleteClusterError: '无法删除群集。',
  38057. editClusterError: '无法编辑群集。'
  38058. };
  38059. exports['zh_CN'] = exports['cn'];
  38060. /***/
  38061. }),
  38062. /* 185 */
  38063. /***/
  38064. (function(module, exports, __webpack_require__) {
  38065. "use strict";
  38066. Object.defineProperty(exports, "__esModule", {
  38067. value: true
  38068. });
  38069. var _classCallCheck2 = __webpack_require__(0);
  38070. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  38071. var _createClass2 = __webpack_require__(1);
  38072. var _createClass3 = _interopRequireDefault(_createClass2);
  38073. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  38074. /**
  38075. * Associates a canvas to a given image, containing a number of renderings
  38076. * of the image at various sizes.
  38077. *
  38078. * This technique is known as 'mipmapping'.
  38079. *
  38080. * NOTE: Images can also be of type 'data:svg+xml`. This code also works
  38081. * for svg, but the mipmapping may not be necessary.
  38082. *
  38083. * @param {Image} image
  38084. */
  38085. var CachedImage = function() {
  38086. /**
  38087. * @ignore
  38088. */
  38089. function CachedImage() {
  38090. (0, _classCallCheck3['default'])(this, CachedImage);
  38091. // eslint-disable-line no-unused-vars
  38092. this.NUM_ITERATIONS = 4; // Number of items in the coordinates array
  38093. this.image = new Image();
  38094. this.canvas = document.createElement('canvas');
  38095. }
  38096. /**
  38097. * Called when the image has been successfully loaded.
  38098. */
  38099. (0, _createClass3['default'])(CachedImage, [{
  38100. key: 'init',
  38101. value: function init() {
  38102. if (this.initialized()) return;
  38103. this.src = this.image.src; // For same interface with Image
  38104. var w = this.image.width;
  38105. var h = this.image.height;
  38106. // Ease external access
  38107. this.width = w;
  38108. this.height = h;
  38109. var h2 = Math.floor(h / 2);
  38110. var h4 = Math.floor(h / 4);
  38111. var h8 = Math.floor(h / 8);
  38112. var h16 = Math.floor(h / 16);
  38113. var w2 = Math.floor(w / 2);
  38114. var w4 = Math.floor(w / 4);
  38115. var w8 = Math.floor(w / 8);
  38116. var w16 = Math.floor(w / 16);
  38117. // Make canvas as small as possible
  38118. this.canvas.width = 3 * w4;
  38119. this.canvas.height = h2;
  38120. // Coordinates and sizes of images contained in the canvas
  38121. // Values per row: [top x, left y, width, height]
  38122. this.coordinates = [
  38123. [0, 0, w2, h2],
  38124. [w2, 0, w4, h4],
  38125. [w2, h4, w8, h8],
  38126. [5 * w8, h4, w16, h16]
  38127. ];
  38128. this._fillMipMap();
  38129. }
  38130. /**
  38131. * @return {Boolean} true if init() has been called, false otherwise.
  38132. */
  38133. }, {
  38134. key: 'initialized',
  38135. value: function initialized() {
  38136. return this.coordinates !== undefined;
  38137. }
  38138. /**
  38139. * Redraw main image in various sizes to the context.
  38140. *
  38141. * The rationale behind this is to reduce artefacts due to interpolation
  38142. * at differing zoom levels.
  38143. *
  38144. * Source: http://stackoverflow.com/q/18761404/1223531
  38145. *
  38146. * This methods takes the resizing out of the drawing loop, in order to
  38147. * reduce performance overhead.
  38148. *
  38149. * TODO: The code assumes that a 2D context can always be gotten. This is
  38150. * not necessarily true! OTOH, if not true then usage of this class
  38151. * is senseless.
  38152. *
  38153. * @private
  38154. */
  38155. }, {
  38156. key: '_fillMipMap',
  38157. value: function _fillMipMap() {
  38158. var ctx = this.canvas.getContext('2d');
  38159. // First zoom-level comes from the image
  38160. var to = this.coordinates[0];
  38161. ctx.drawImage(this.image, to[0], to[1], to[2], to[3]);
  38162. // The rest are copy actions internal to the canvas/context
  38163. for (var iterations = 1; iterations < this.NUM_ITERATIONS; iterations++) {
  38164. var from = this.coordinates[iterations - 1];
  38165. var _to = this.coordinates[iterations];
  38166. ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], _to[0], _to[1], _to[2], _to[3]);
  38167. }
  38168. }
  38169. /**
  38170. * Draw the image, using the mipmap if necessary.
  38171. *
  38172. * MipMap is only used if param factor > 2; otherwise, original bitmap
  38173. * is resized. This is also used to skip mipmap usage, e.g. by setting factor = 1
  38174. *
  38175. * Credits to 'Alex de Mulder' for original implementation.
  38176. *
  38177. * @param {CanvasRenderingContext2D} ctx context on which to draw zoomed image
  38178. * @param {Float} factor scale factor at which to draw
  38179. * @param {number} left
  38180. * @param {number} top
  38181. * @param {number} width
  38182. * @param {number} height
  38183. */
  38184. }, {
  38185. key: 'drawImageAtPosition',
  38186. value: function drawImageAtPosition(ctx, factor, left, top, width, height) {
  38187. if (!this.initialized()) return; //can't draw image yet not intialized
  38188. if (factor > 2) {
  38189. // Determine which zoomed image to use
  38190. factor *= 0.5;
  38191. var iterations = 0;
  38192. while (factor > 2 && iterations < this.NUM_ITERATIONS) {
  38193. factor *= 0.5;
  38194. iterations += 1;
  38195. }
  38196. if (iterations >= this.NUM_ITERATIONS) {
  38197. iterations = this.NUM_ITERATIONS - 1;
  38198. }
  38199. //console.log("iterations: " + iterations);
  38200. var from = this.coordinates[iterations];
  38201. ctx.drawImage(this.canvas, from[0], from[1], from[2], from[3], left, top, width, height);
  38202. } else {
  38203. // Draw image directly
  38204. ctx.drawImage(this.image, left, top, width, height);
  38205. }
  38206. }
  38207. }]);
  38208. return CachedImage;
  38209. }();
  38210. exports['default'] = CachedImage;
  38211. /***/
  38212. }),
  38213. /* 186 */
  38214. /***/
  38215. (function(module, exports, __webpack_require__) {
  38216. "use strict";
  38217. Object.defineProperty(exports, "__esModule", {
  38218. value: true
  38219. });
  38220. var _classCallCheck2 = __webpack_require__(0);
  38221. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  38222. var _createClass2 = __webpack_require__(1);
  38223. var _createClass3 = _interopRequireDefault(_createClass2);
  38224. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  38225. var util = __webpack_require__(2);
  38226. /**
  38227. * This class can store groups and options specific for groups.
  38228. */
  38229. var Groups = function() {
  38230. /**
  38231. * @ignore
  38232. */
  38233. function Groups() {
  38234. (0, _classCallCheck3["default"])(this, Groups);
  38235. this.clear();
  38236. this.defaultIndex = 0;
  38237. this.groupsArray = [];
  38238. this.groupIndex = 0;
  38239. this.defaultGroups = [{ border: "#2B7CE9", background: "#97C2FC", highlight: { border: "#2B7CE9", background: "#D2E5FF" }, hover: { border: "#2B7CE9", background: "#D2E5FF" } }, // 0: blue
  38240. { border: "#FFA500", background: "#FFFF00", highlight: { border: "#FFA500", background: "#FFFFA3" }, hover: { border: "#FFA500", background: "#FFFFA3" } }, // 1: yellow
  38241. { border: "#FA0A10", background: "#FB7E81", highlight: { border: "#FA0A10", background: "#FFAFB1" }, hover: { border: "#FA0A10", background: "#FFAFB1" } }, // 2: red
  38242. { border: "#41A906", background: "#7BE141", highlight: { border: "#41A906", background: "#A1EC76" }, hover: { border: "#41A906", background: "#A1EC76" } }, // 3: green
  38243. { border: "#E129F0", background: "#EB7DF4", highlight: { border: "#E129F0", background: "#F0B3F5" }, hover: { border: "#E129F0", background: "#F0B3F5" } }, // 4: magenta
  38244. { border: "#7C29F0", background: "#AD85E4", highlight: { border: "#7C29F0", background: "#D3BDF0" }, hover: { border: "#7C29F0", background: "#D3BDF0" } }, // 5: purple
  38245. { border: "#C37F00", background: "#FFA807", highlight: { border: "#C37F00", background: "#FFCA66" }, hover: { border: "#C37F00", background: "#FFCA66" } }, // 6: orange
  38246. { border: "#4220FB", background: "#6E6EFD", highlight: { border: "#4220FB", background: "#9B9BFD" }, hover: { border: "#4220FB", background: "#9B9BFD" } }, // 7: darkblue
  38247. { border: "#FD5A77", background: "#FFC0CB", highlight: { border: "#FD5A77", background: "#FFD1D9" }, hover: { border: "#FD5A77", background: "#FFD1D9" } }, // 8: pink
  38248. { border: "#4AD63A", background: "#C2FABC", highlight: { border: "#4AD63A", background: "#E6FFE3" }, hover: { border: "#4AD63A", background: "#E6FFE3" } }, // 9: mint
  38249. { border: "#990000", background: "#EE0000", highlight: { border: "#BB0000", background: "#FF3333" }, hover: { border: "#BB0000", background: "#FF3333" } }, // 10:bright red
  38250. { border: "#FF6000", background: "#FF6000", highlight: { border: "#FF6000", background: "#FF6000" }, hover: { border: "#FF6000", background: "#FF6000" } }, // 12: real orange
  38251. { border: "#97C2FC", background: "#2B7CE9", highlight: { border: "#D2E5FF", background: "#2B7CE9" }, hover: { border: "#D2E5FF", background: "#2B7CE9" } }, // 13: blue
  38252. { border: "#399605", background: "#255C03", highlight: { border: "#399605", background: "#255C03" }, hover: { border: "#399605", background: "#255C03" } }, // 14: green
  38253. { border: "#B70054", background: "#FF007E", highlight: { border: "#B70054", background: "#FF007E" }, hover: { border: "#B70054", background: "#FF007E" } }, // 15: magenta
  38254. { border: "#AD85E4", background: "#7C29F0", highlight: { border: "#D3BDF0", background: "#7C29F0" }, hover: { border: "#D3BDF0", background: "#7C29F0" } }, // 16: purple
  38255. { border: "#4557FA", background: "#000EA1", highlight: { border: "#6E6EFD", background: "#000EA1" }, hover: { border: "#6E6EFD", background: "#000EA1" } }, // 17: darkblue
  38256. { border: "#FFC0CB", background: "#FD5A77", highlight: { border: "#FFD1D9", background: "#FD5A77" }, hover: { border: "#FFD1D9", background: "#FD5A77" } }, // 18: pink
  38257. { border: "#C2FABC", background: "#74D66A", highlight: { border: "#E6FFE3", background: "#74D66A" }, hover: { border: "#E6FFE3", background: "#74D66A" } }, // 19: mint
  38258. {
  38259. border: "#EE0000",
  38260. background: "#990000",
  38261. highlight: { border: "#FF3333", background: "#BB0000" },
  38262. hover: { border: "#FF3333", background: "#BB0000" } // 20:bright red
  38263. }
  38264. ];
  38265. this.options = {};
  38266. this.defaultOptions = {
  38267. useDefaultGroups: true
  38268. };
  38269. util.extend(this.options, this.defaultOptions);
  38270. }
  38271. /**
  38272. *
  38273. * @param {Object} options
  38274. */
  38275. (0, _createClass3["default"])(Groups, [{
  38276. key: "setOptions",
  38277. value: function setOptions(options) {
  38278. var optionFields = ['useDefaultGroups'];
  38279. if (options !== undefined) {
  38280. for (var groupName in options) {
  38281. if (options.hasOwnProperty(groupName)) {
  38282. if (optionFields.indexOf(groupName) === -1) {
  38283. var group = options[groupName];
  38284. this.add(groupName, group);
  38285. }
  38286. }
  38287. }
  38288. }
  38289. }
  38290. /**
  38291. * Clear all groups
  38292. */
  38293. }, {
  38294. key: "clear",
  38295. value: function clear() {
  38296. this.groups = {};
  38297. this.groupsArray = [];
  38298. }
  38299. /**
  38300. * Get group options of a groupname.
  38301. * If groupname is not found, a new group may be created.
  38302. *
  38303. * @param {*} groupname Can be a number, string, Date, etc.
  38304. * @param {boolean} [shouldCreate=true] If true, create a new group
  38305. * @return {Object} The found or created group
  38306. */
  38307. }, {
  38308. key: "get",
  38309. value: function get(groupname) {
  38310. var shouldCreate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  38311. var group = this.groups[groupname];
  38312. if (group === undefined && shouldCreate) {
  38313. if (this.options.useDefaultGroups === false && this.groupsArray.length > 0) {
  38314. // create new group
  38315. var index = this.groupIndex % this.groupsArray.length;
  38316. this.groupIndex++;
  38317. group = {};
  38318. group.color = this.groups[this.groupsArray[index]];
  38319. this.groups[groupname] = group;
  38320. } else {
  38321. // create new group
  38322. var _index = this.defaultIndex % this.defaultGroups.length;
  38323. this.defaultIndex++;
  38324. group = {};
  38325. group.color = this.defaultGroups[_index];
  38326. this.groups[groupname] = group;
  38327. }
  38328. }
  38329. return group;
  38330. }
  38331. /**
  38332. * Add a custom group style
  38333. * @param {string} groupName
  38334. * @param {Object} style An object containing borderColor,
  38335. * backgroundColor, etc.
  38336. * @return {Object} group The created group object
  38337. */
  38338. }, {
  38339. key: "add",
  38340. value: function add(groupName, style) {
  38341. this.groups[groupName] = style;
  38342. this.groupsArray.push(groupName);
  38343. return style;
  38344. }
  38345. }]);
  38346. return Groups;
  38347. }();
  38348. exports["default"] = Groups;
  38349. /***/
  38350. }),
  38351. /* 187 */
  38352. /***/
  38353. (function(module, exports, __webpack_require__) {
  38354. "use strict";
  38355. Object.defineProperty(exports, "__esModule", {
  38356. value: true
  38357. });
  38358. var _classCallCheck2 = __webpack_require__(0);
  38359. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  38360. var _createClass2 = __webpack_require__(1);
  38361. var _createClass3 = _interopRequireDefault(_createClass2);
  38362. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  38363. var util = __webpack_require__(2);
  38364. var DataSet = __webpack_require__(11);
  38365. var DataView = __webpack_require__(12);
  38366. var Node = __webpack_require__(47)['default'];
  38367. /**
  38368. * Handler for Nodes
  38369. */
  38370. var NodesHandler = function() {
  38371. /**
  38372. * @param {Object} body
  38373. * @param {Images} images
  38374. * @param {Array.<Group>} groups
  38375. * @param {LayoutEngine} layoutEngine
  38376. */
  38377. function NodesHandler(body, images, groups, layoutEngine) {
  38378. var _this = this;
  38379. (0, _classCallCheck3['default'])(this, NodesHandler);
  38380. this.body = body;
  38381. this.images = images;
  38382. this.groups = groups;
  38383. this.layoutEngine = layoutEngine;
  38384. // create the node API in the body container
  38385. this.body.functions.createNode = this.create.bind(this);
  38386. this.nodesListeners = {
  38387. add: function add(event, params) {
  38388. _this.add(params.items);
  38389. },
  38390. update: function update(event, params) {
  38391. _this.update(params.items, params.data, params.oldData);
  38392. },
  38393. remove: function remove(event, params) {
  38394. _this.remove(params.items);
  38395. }
  38396. };
  38397. this.defaultOptions = {
  38398. borderWidth: 1,
  38399. borderWidthSelected: 2,
  38400. brokenImage: undefined,
  38401. color: {
  38402. border: '#2B7CE9',
  38403. background: '#97C2FC',
  38404. highlight: {
  38405. border: '#2B7CE9',
  38406. background: '#D2E5FF'
  38407. },
  38408. hover: {
  38409. border: '#2B7CE9',
  38410. background: '#D2E5FF'
  38411. }
  38412. },
  38413. fixed: {
  38414. x: false,
  38415. y: false
  38416. },
  38417. font: {
  38418. color: '#343434',
  38419. size: 14, // px
  38420. face: 'arial',
  38421. background: 'none',
  38422. strokeWidth: 0, // px
  38423. strokeColor: '#ffffff',
  38424. align: 'center',
  38425. vadjust: 0,
  38426. multi: false,
  38427. bold: {
  38428. mod: 'bold'
  38429. },
  38430. boldital: {
  38431. mod: 'bold italic'
  38432. },
  38433. ital: {
  38434. mod: 'italic'
  38435. },
  38436. mono: {
  38437. mod: '',
  38438. size: 15, // px
  38439. face: 'monospace',
  38440. vadjust: 2
  38441. }
  38442. },
  38443. group: undefined,
  38444. hidden: false,
  38445. icon: {
  38446. face: 'FontAwesome', //'FontAwesome',
  38447. code: undefined, //'\uf007',
  38448. size: 50, //50,
  38449. color: '#2B7CE9' //'#aa00ff'
  38450. },
  38451. image: undefined, // --> URL
  38452. label: undefined,
  38453. labelHighlightBold: true,
  38454. level: undefined,
  38455. margin: {
  38456. top: 5,
  38457. right: 5,
  38458. bottom: 5,
  38459. left: 5
  38460. },
  38461. mass: 1,
  38462. physics: true,
  38463. scaling: {
  38464. min: 10,
  38465. max: 30,
  38466. label: {
  38467. enabled: false,
  38468. min: 14,
  38469. max: 30,
  38470. maxVisible: 30,
  38471. drawThreshold: 5
  38472. },
  38473. customScalingFunction: function customScalingFunction(min, max, total, value) {
  38474. if (max === min) {
  38475. return 0.5;
  38476. } else {
  38477. var scale = 1 / (max - min);
  38478. return Math.max(0, (value - min) * scale);
  38479. }
  38480. }
  38481. },
  38482. shadow: {
  38483. enabled: false,
  38484. color: 'rgba(0,0,0,0.5)',
  38485. size: 10,
  38486. x: 5,
  38487. y: 5
  38488. },
  38489. shape: 'ellipse',
  38490. shapeProperties: {
  38491. borderDashes: false, // only for borders
  38492. borderRadius: 6, // only for box shape
  38493. interpolation: true, // only for image and circularImage shapes
  38494. useImageSize: false, // only for image and circularImage shapes
  38495. useBorderWithImage: false // only for image shape
  38496. },
  38497. size: 25,
  38498. title: undefined,
  38499. value: undefined,
  38500. x: undefined,
  38501. y: undefined
  38502. };
  38503. // Protect from idiocy
  38504. if (this.defaultOptions.mass <= 0) {
  38505. throw 'Internal error: mass in defaultOptions of NodesHandler may not be zero or negative';
  38506. }
  38507. this.options = util.bridgeObject(this.defaultOptions);
  38508. this.bindEventListeners();
  38509. }
  38510. /**
  38511. * Binds event listeners
  38512. */
  38513. (0, _createClass3['default'])(NodesHandler, [{
  38514. key: 'bindEventListeners',
  38515. value: function bindEventListeners() {
  38516. var _this2 = this;
  38517. // refresh the nodes. Used when reverting from hierarchical layout
  38518. this.body.emitter.on('refreshNodes', this.refresh.bind(this));
  38519. this.body.emitter.on('refresh', this.refresh.bind(this));
  38520. this.body.emitter.on('destroy', function() {
  38521. util.forEach(_this2.nodesListeners, function(callback, event) {
  38522. if (_this2.body.data.nodes) _this2.body.data.nodes.off(event, callback);
  38523. });
  38524. delete _this2.body.functions.createNode;
  38525. delete _this2.nodesListeners.add;
  38526. delete _this2.nodesListeners.update;
  38527. delete _this2.nodesListeners.remove;
  38528. delete _this2.nodesListeners;
  38529. });
  38530. }
  38531. /**
  38532. *
  38533. * @param {Object} options
  38534. */
  38535. }, {
  38536. key: 'setOptions',
  38537. value: function setOptions(options) {
  38538. if (options !== undefined) {
  38539. Node.parseOptions(this.options, options);
  38540. // update the shape in all nodes
  38541. if (options.shape !== undefined) {
  38542. for (var nodeId in this.body.nodes) {
  38543. if (this.body.nodes.hasOwnProperty(nodeId)) {
  38544. this.body.nodes[nodeId].updateShape();
  38545. }
  38546. }
  38547. }
  38548. // update the font in all nodes
  38549. if (options.font !== undefined) {
  38550. for (var _nodeId in this.body.nodes) {
  38551. if (this.body.nodes.hasOwnProperty(_nodeId)) {
  38552. this.body.nodes[_nodeId].updateLabelModule();
  38553. this.body.nodes[_nodeId].needsRefresh();
  38554. }
  38555. }
  38556. }
  38557. // update the shape size in all nodes
  38558. if (options.size !== undefined) {
  38559. for (var _nodeId2 in this.body.nodes) {
  38560. if (this.body.nodes.hasOwnProperty(_nodeId2)) {
  38561. this.body.nodes[_nodeId2].needsRefresh();
  38562. }
  38563. }
  38564. }
  38565. // update the state of the variables if needed
  38566. if (options.hidden !== undefined || options.physics !== undefined) {
  38567. this.body.emitter.emit('_dataChanged');
  38568. }
  38569. }
  38570. }
  38571. /**
  38572. * Set a data set with nodes for the network
  38573. * @param {Array | DataSet | DataView} nodes The data containing the nodes.
  38574. * @param {boolean} [doNotEmit=false]
  38575. * @private
  38576. */
  38577. }, {
  38578. key: 'setData',
  38579. value: function setData(nodes) {
  38580. var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  38581. var oldNodesData = this.body.data.nodes;
  38582. if (nodes instanceof DataSet || nodes instanceof DataView) {
  38583. this.body.data.nodes = nodes;
  38584. } else if (Array.isArray(nodes)) {
  38585. this.body.data.nodes = new DataSet();
  38586. this.body.data.nodes.add(nodes);
  38587. } else if (!nodes) {
  38588. this.body.data.nodes = new DataSet();
  38589. } else {
  38590. throw new TypeError('Array or DataSet expected');
  38591. }
  38592. if (oldNodesData) {
  38593. // unsubscribe from old dataset
  38594. util.forEach(this.nodesListeners, function(callback, event) {
  38595. oldNodesData.off(event, callback);
  38596. });
  38597. }
  38598. // remove drawn nodes
  38599. this.body.nodes = {};
  38600. if (this.body.data.nodes) {
  38601. // subscribe to new dataset
  38602. var me = this;
  38603. util.forEach(this.nodesListeners, function(callback, event) {
  38604. me.body.data.nodes.on(event, callback);
  38605. });
  38606. // draw all new nodes
  38607. var ids = this.body.data.nodes.getIds();
  38608. this.add(ids, true);
  38609. }
  38610. if (doNotEmit === false) {
  38611. this.body.emitter.emit("_dataChanged");
  38612. }
  38613. }
  38614. /**
  38615. * Add nodes
  38616. * @param {number[] | string[]} ids
  38617. * @param {boolean} [doNotEmit=false]
  38618. * @private
  38619. */
  38620. }, {
  38621. key: 'add',
  38622. value: function add(ids) {
  38623. var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  38624. var id = void 0;
  38625. var newNodes = [];
  38626. for (var i = 0; i < ids.length; i++) {
  38627. id = ids[i];
  38628. var properties = this.body.data.nodes.get(id);
  38629. var node = this.create(properties);
  38630. newNodes.push(node);
  38631. this.body.nodes[id] = node; // note: this may replace an existing node
  38632. }
  38633. this.layoutEngine.positionInitially(newNodes);
  38634. if (doNotEmit === false) {
  38635. this.body.emitter.emit("_dataChanged");
  38636. }
  38637. }
  38638. /**
  38639. * Update existing nodes, or create them when not yet existing
  38640. * @param {number[] | string[]} ids id's of changed nodes
  38641. * @param {Array} changedData array with changed data
  38642. * @param {Array|undefined} oldData optional; array with previous data
  38643. * @private
  38644. */
  38645. }, {
  38646. key: 'update',
  38647. value: function update(ids, changedData, oldData) {
  38648. var nodes = this.body.nodes;
  38649. var dataChanged = false;
  38650. for (var i = 0; i < ids.length; i++) {
  38651. var id = ids[i];
  38652. var node = nodes[id];
  38653. var data = changedData[i];
  38654. if (node !== undefined) {
  38655. // update node
  38656. if (node.setOptions(data)) {
  38657. dataChanged = true;
  38658. }
  38659. } else {
  38660. dataChanged = true;
  38661. // create node
  38662. node = this.create(data);
  38663. nodes[id] = node;
  38664. }
  38665. }
  38666. if (!dataChanged && oldData !== undefined) {
  38667. // Check for any changes which should trigger a layout recalculation
  38668. // For now, this is just 'level' for hierarchical layout
  38669. // Assumption: old and new data arranged in same order; at time of writing, this holds.
  38670. dataChanged = changedData.some(function(newValue, index) {
  38671. var oldValue = oldData[index];
  38672. return oldValue && oldValue.level !== newValue.level;
  38673. });
  38674. }
  38675. if (dataChanged === true) {
  38676. this.body.emitter.emit("_dataChanged");
  38677. } else {
  38678. this.body.emitter.emit("_dataUpdated");
  38679. }
  38680. }
  38681. /**
  38682. * Remove existing nodes. If nodes do not exist, the method will just ignore it.
  38683. * @param {number[] | string[]} ids
  38684. * @private
  38685. */
  38686. }, {
  38687. key: 'remove',
  38688. value: function remove(ids) {
  38689. var nodes = this.body.nodes;
  38690. for (var i = 0; i < ids.length; i++) {
  38691. var id = ids[i];
  38692. delete nodes[id];
  38693. }
  38694. this.body.emitter.emit("_dataChanged");
  38695. }
  38696. /**
  38697. * create a node
  38698. * @param {Object} properties
  38699. * @param {class} [constructorClass=Node.default]
  38700. * @returns {*}
  38701. */
  38702. }, {
  38703. key: 'create',
  38704. value: function create(properties) {
  38705. var constructorClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Node;
  38706. return new constructorClass(properties, this.body, this.images, this.groups, this.options, this.defaultOptions);
  38707. }
  38708. /**
  38709. *
  38710. * @param {boolean} [clearPositions=false]
  38711. */
  38712. }, {
  38713. key: 'refresh',
  38714. value: function refresh() {
  38715. var _this3 = this;
  38716. var clearPositions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  38717. util.forEach(this.body.nodes, function(node, nodeId) {
  38718. var data = _this3.body.data.nodes.get(nodeId);
  38719. if (data !== undefined) {
  38720. if (clearPositions === true) {
  38721. node.setOptions({ x: null, y: null });
  38722. }
  38723. node.setOptions({ fixed: false });
  38724. node.setOptions(data);
  38725. }
  38726. });
  38727. }
  38728. /**
  38729. * Returns the positions of the nodes.
  38730. * @param {Array.<Node.id>|String} [ids] --> optional, can be array of nodeIds, can be string
  38731. * @returns {{}}
  38732. */
  38733. }, {
  38734. key: 'getPositions',
  38735. value: function getPositions(ids) {
  38736. var dataArray = {};
  38737. if (ids !== undefined) {
  38738. if (Array.isArray(ids) === true) {
  38739. for (var i = 0; i < ids.length; i++) {
  38740. if (this.body.nodes[ids[i]] !== undefined) {
  38741. var node = this.body.nodes[ids[i]];
  38742. dataArray[ids[i]] = { x: Math.round(node.x), y: Math.round(node.y) };
  38743. }
  38744. }
  38745. } else {
  38746. if (this.body.nodes[ids] !== undefined) {
  38747. var _node = this.body.nodes[ids];
  38748. dataArray[ids] = { x: Math.round(_node.x), y: Math.round(_node.y) };
  38749. }
  38750. }
  38751. } else {
  38752. for (var _i = 0; _i < this.body.nodeIndices.length; _i++) {
  38753. var _node2 = this.body.nodes[this.body.nodeIndices[_i]];
  38754. dataArray[this.body.nodeIndices[_i]] = { x: Math.round(_node2.x), y: Math.round(_node2.y) };
  38755. }
  38756. }
  38757. return dataArray;
  38758. }
  38759. /**
  38760. * Load the XY positions of the nodes into the dataset.
  38761. */
  38762. }, {
  38763. key: 'storePositions',
  38764. value: function storePositions() {
  38765. // todo: add support for clusters and hierarchical.
  38766. var dataArray = [];
  38767. var dataset = this.body.data.nodes.getDataSet();
  38768. for (var nodeId in dataset._data) {
  38769. if (dataset._data.hasOwnProperty(nodeId)) {
  38770. var node = this.body.nodes[nodeId];
  38771. if (dataset._data[nodeId].x != Math.round(node.x) || dataset._data[nodeId].y != Math.round(node.y)) {
  38772. dataArray.push({ id: node.id, x: Math.round(node.x), y: Math.round(node.y) });
  38773. }
  38774. }
  38775. }
  38776. dataset.update(dataArray);
  38777. }
  38778. /**
  38779. * get the bounding box of a node.
  38780. * @param {Node.id} nodeId
  38781. * @returns {j|*}
  38782. */
  38783. }, {
  38784. key: 'getBoundingBox',
  38785. value: function getBoundingBox(nodeId) {
  38786. if (this.body.nodes[nodeId] !== undefined) {
  38787. return this.body.nodes[nodeId].shape.boundingBox;
  38788. }
  38789. }
  38790. /**
  38791. * Get the Ids of nodes connected to this node.
  38792. * @param {Node.id} nodeId
  38793. * @param {'to'|'from'|undefined} direction values 'from' and 'to' select respectively parent and child nodes only.
  38794. * Any other value returns both parent and child nodes.
  38795. * @returns {Array}
  38796. */
  38797. }, {
  38798. key: 'getConnectedNodes',
  38799. value: function getConnectedNodes(nodeId, direction) {
  38800. var nodeList = [];
  38801. if (this.body.nodes[nodeId] !== undefined) {
  38802. var node = this.body.nodes[nodeId];
  38803. var nodeObj = {}; // used to quickly check if node already exists
  38804. for (var i = 0; i < node.edges.length; i++) {
  38805. var edge = node.edges[i];
  38806. if (direction !== 'to' && edge.toId == node.id) {
  38807. // these are double equals since ids can be numeric or string
  38808. if (nodeObj[edge.fromId] === undefined) {
  38809. nodeList.push(edge.fromId);
  38810. nodeObj[edge.fromId] = true;
  38811. }
  38812. } else if (direction !== 'from' && edge.fromId == node.id) {
  38813. // these are double equals since ids can be numeric or string
  38814. if (nodeObj[edge.toId] === undefined) {
  38815. nodeList.push(edge.toId);
  38816. nodeObj[edge.toId] = true;
  38817. }
  38818. }
  38819. }
  38820. }
  38821. return nodeList;
  38822. }
  38823. /**
  38824. * Get the ids of the edges connected to this node.
  38825. * @param {Node.id} nodeId
  38826. * @returns {*}
  38827. */
  38828. }, {
  38829. key: 'getConnectedEdges',
  38830. value: function getConnectedEdges(nodeId) {
  38831. var edgeList = [];
  38832. if (this.body.nodes[nodeId] !== undefined) {
  38833. var node = this.body.nodes[nodeId];
  38834. for (var i = 0; i < node.edges.length; i++) {
  38835. edgeList.push(node.edges[i].id);
  38836. }
  38837. } else {
  38838. console.log("NodeId provided for getConnectedEdges does not exist. Provided: ", nodeId);
  38839. }
  38840. return edgeList;
  38841. }
  38842. /**
  38843. * Move a node.
  38844. *
  38845. * @param {Node.id} nodeId
  38846. * @param {number} x
  38847. * @param {number} y
  38848. */
  38849. }, {
  38850. key: 'moveNode',
  38851. value: function moveNode(nodeId, x, y) {
  38852. var _this4 = this;
  38853. if (this.body.nodes[nodeId] !== undefined) {
  38854. this.body.nodes[nodeId].x = Number(x);
  38855. this.body.nodes[nodeId].y = Number(y);
  38856. setTimeout(function() {
  38857. _this4.body.emitter.emit("startSimulation");
  38858. }, 0);
  38859. } else {
  38860. console.log("Node id supplied to moveNode does not exist. Provided: ", nodeId);
  38861. }
  38862. }
  38863. }]);
  38864. return NodesHandler;
  38865. }();
  38866. exports['default'] = NodesHandler;
  38867. /***/
  38868. }),
  38869. /* 188 */
  38870. /***/
  38871. (function(module, exports, __webpack_require__) {
  38872. module.exports = { "default": __webpack_require__(189), __esModule: true };
  38873. /***/
  38874. }),
  38875. /* 189 */
  38876. /***/
  38877. (function(module, exports, __webpack_require__) {
  38878. __webpack_require__(49);
  38879. __webpack_require__(60);
  38880. module.exports = __webpack_require__(190);
  38881. /***/
  38882. }),
  38883. /* 190 */
  38884. /***/
  38885. (function(module, exports, __webpack_require__) {
  38886. var classof = __webpack_require__(86);
  38887. var ITERATOR = __webpack_require__(13)('iterator');
  38888. var Iterators = __webpack_require__(31);
  38889. module.exports = __webpack_require__(7).isIterable = function(it) {
  38890. var O = Object(it);
  38891. return O[ITERATOR] !== undefined ||
  38892. '@@iterator' in O
  38893. // eslint-disable-next-line no-prototype-builtins
  38894. ||
  38895. Iterators.hasOwnProperty(classof(O));
  38896. };
  38897. /***/
  38898. }),
  38899. /* 191 */
  38900. /***/
  38901. (function(module, exports, __webpack_require__) {
  38902. "use strict";
  38903. Object.defineProperty(exports, "__esModule", {
  38904. value: true
  38905. });
  38906. var _classCallCheck2 = __webpack_require__(0);
  38907. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  38908. var _createClass2 = __webpack_require__(1);
  38909. var _createClass3 = _interopRequireDefault(_createClass2);
  38910. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  38911. var LabelAccumulator = __webpack_require__(192)['default'];
  38912. var ComponentUtil = __webpack_require__(48)['default'];
  38913. /**
  38914. * Helper class for Label which explodes the label text into lines and blocks within lines
  38915. *
  38916. * @private
  38917. */
  38918. var LabelSplitter = function() {
  38919. /**
  38920. * @param {CanvasRenderingContext2D} ctx Canvas rendering context
  38921. * @param {Label} parent reference to the Label instance using current instance
  38922. * @param {boolean} selected
  38923. * @param {boolean} hover
  38924. */
  38925. function LabelSplitter(ctx, parent, selected, hover) {
  38926. var _this = this;
  38927. (0, _classCallCheck3['default'])(this, LabelSplitter);
  38928. this.ctx = ctx;
  38929. this.parent = parent;
  38930. /**
  38931. * Callback to determine text width; passed to LabelAccumulator instance
  38932. *
  38933. * @param {String} text string to determine width of
  38934. * @param {String} mod font type to use for this text
  38935. * @return {Object} { width, values} width in pixels and font attributes
  38936. */
  38937. var textWidth = function textWidth(text, mod) {
  38938. if (text === undefined) return 0;
  38939. // TODO: This can be done more efficiently with caching
  38940. var values = _this.parent.getFormattingValues(ctx, selected, hover, mod);
  38941. var width = 0;
  38942. if (text !== '') {
  38943. // NOTE: The following may actually be *incorrect* for the mod fonts!
  38944. // This returns the size with a regular font, bold etc. may
  38945. // have different sizes.
  38946. var measure = _this.ctx.measureText(text);
  38947. width = measure.width;
  38948. }
  38949. return { width: width, values: values };
  38950. };
  38951. this.lines = new LabelAccumulator(textWidth);
  38952. }
  38953. /**
  38954. * Split passed text of a label into lines and blocks.
  38955. *
  38956. * # NOTE
  38957. *
  38958. * The handling of spacing is option dependent:
  38959. *
  38960. * - if `font.multi : false`, all spaces are retained
  38961. * - if `font.multi : true`, every sequence of spaces is compressed to a single space
  38962. *
  38963. * This might not be the best way to do it, but this is as it has been working till now.
  38964. * In order not to break existing functionality, for the time being this behaviour will
  38965. * be retained in any code changes.
  38966. *
  38967. * @param {string} text text to split
  38968. * @returns {Array<line>}
  38969. */
  38970. (0, _createClass3['default'])(LabelSplitter, [{
  38971. key: 'process',
  38972. value: function process(text) {
  38973. if (!ComponentUtil.isValidLabel(text)) {
  38974. return this.lines.finalize();
  38975. }
  38976. var font = this.parent.fontOptions;
  38977. // Normalize the end-of-line's to a single representation - order important
  38978. text = text.replace(/\r\n/g, '\n'); // Dos EOL's
  38979. text = text.replace(/\r/g, '\n'); // Mac EOL's
  38980. // Note that at this point, there can be no \r's in the text.
  38981. // This is used later on splitStringIntoLines() to split multifont texts.
  38982. var nlLines = String(text).split('\n');
  38983. var lineCount = nlLines.length;
  38984. if (font.multi) {
  38985. // Multi-font case: styling tags active
  38986. for (var i = 0; i < lineCount; i++) {
  38987. var blocks = this.splitBlocks(nlLines[i], font.multi);
  38988. // Post: Sequences of tabs and spaces are reduced to single space
  38989. if (blocks === undefined) continue;
  38990. if (blocks.length === 0) {
  38991. this.lines.newLine("");
  38992. continue;
  38993. }
  38994. if (font.maxWdt > 0) {
  38995. // widthConstraint.maximum defined
  38996. //console.log('Running widthConstraint multi, max: ' + this.fontOptions.maxWdt);
  38997. for (var j = 0; j < blocks.length; j++) {
  38998. var mod = blocks[j].mod;
  38999. var _text = blocks[j].text;
  39000. this.splitStringIntoLines(_text, mod, true);
  39001. }
  39002. } else {
  39003. // widthConstraint.maximum NOT defined
  39004. for (var _j = 0; _j < blocks.length; _j++) {
  39005. var _mod = blocks[_j].mod;
  39006. var _text2 = blocks[_j].text;
  39007. this.lines.append(_text2, _mod);
  39008. }
  39009. }
  39010. this.lines.newLine();
  39011. }
  39012. } else {
  39013. // Single-font case
  39014. if (font.maxWdt > 0) {
  39015. // widthConstraint.maximum defined
  39016. // console.log('Running widthConstraint normal, max: ' + this.fontOptions.maxWdt);
  39017. for (var _i = 0; _i < lineCount; _i++) {
  39018. this.splitStringIntoLines(nlLines[_i]);
  39019. }
  39020. } else {
  39021. // widthConstraint.maximum NOT defined
  39022. for (var _i2 = 0; _i2 < lineCount; _i2++) {
  39023. this.lines.newLine(nlLines[_i2]);
  39024. }
  39025. }
  39026. }
  39027. return this.lines.finalize();
  39028. }
  39029. /**
  39030. * normalize the markup system
  39031. *
  39032. * @param {boolean|'md'|'markdown'|'html'} markupSystem
  39033. * @returns {string}
  39034. */
  39035. }, {
  39036. key: 'decodeMarkupSystem',
  39037. value: function decodeMarkupSystem(markupSystem) {
  39038. var system = 'none';
  39039. if (markupSystem === 'markdown' || markupSystem === 'md') {
  39040. system = 'markdown';
  39041. } else if (markupSystem === true || markupSystem === 'html') {
  39042. system = 'html';
  39043. }
  39044. return system;
  39045. }
  39046. /**
  39047. *
  39048. * @param {string} text
  39049. * @returns {Array}
  39050. */
  39051. }, {
  39052. key: 'splitHtmlBlocks',
  39053. value: function splitHtmlBlocks(text) {
  39054. var blocks = [];
  39055. // TODO: consolidate following + methods/closures with splitMarkdownBlocks()
  39056. // NOTE: sequences of tabs and spaces are reduced to single space; scan usage of `this.spacing` within method
  39057. var s = {
  39058. bold: false,
  39059. ital: false,
  39060. mono: false,
  39061. spacing: false,
  39062. position: 0,
  39063. buffer: "",
  39064. modStack: []
  39065. };
  39066. s.mod = function() {
  39067. return this.modStack.length === 0 ? 'normal' : this.modStack[0];
  39068. };
  39069. s.modName = function() {
  39070. if (this.modStack.length === 0) return 'normal';
  39071. else if (this.modStack[0] === 'mono') return 'mono';
  39072. else {
  39073. if (s.bold && s.ital) {
  39074. return 'boldital';
  39075. } else if (s.bold) {
  39076. return 'bold';
  39077. } else if (s.ital) {
  39078. return 'ital';
  39079. }
  39080. }
  39081. };
  39082. s.emitBlock = function() {
  39083. var override = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  39084. // eslint-disable-line no-unused-vars
  39085. if (this.spacing) {
  39086. this.add(" ");
  39087. this.spacing = false;
  39088. }
  39089. if (this.buffer.length > 0) {
  39090. blocks.push({ text: this.buffer, mod: this.modName() });
  39091. this.buffer = "";
  39092. }
  39093. };
  39094. s.add = function(text) {
  39095. if (text === " ") {
  39096. s.spacing = true;
  39097. }
  39098. if (s.spacing) {
  39099. this.buffer += " ";
  39100. this.spacing = false;
  39101. }
  39102. if (text != " ") {
  39103. this.buffer += text;
  39104. }
  39105. };
  39106. while (s.position < text.length) {
  39107. var ch = text.charAt(s.position);
  39108. if (/[ \t]/.test(ch)) {
  39109. if (!s.mono) {
  39110. s.spacing = true;
  39111. } else {
  39112. s.add(ch);
  39113. }
  39114. } else if (/</.test(ch)) {
  39115. if (!s.mono && !s.bold && /<b>/.test(text.substr(s.position, 3))) {
  39116. s.emitBlock();
  39117. s.bold = true;
  39118. s.modStack.unshift("bold");
  39119. s.position += 2;
  39120. } else if (!s.mono && !s.ital && /<i>/.test(text.substr(s.position, 3))) {
  39121. s.emitBlock();
  39122. s.ital = true;
  39123. s.modStack.unshift("ital");
  39124. s.position += 2;
  39125. } else if (!s.mono && /<code>/.test(text.substr(s.position, 6))) {
  39126. s.emitBlock();
  39127. s.mono = true;
  39128. s.modStack.unshift("mono");
  39129. s.position += 5;
  39130. } else if (!s.mono && s.mod() === 'bold' && /<\/b>/.test(text.substr(s.position, 4))) {
  39131. s.emitBlock();
  39132. s.bold = false;
  39133. s.modStack.shift();
  39134. s.position += 3;
  39135. } else if (!s.mono && s.mod() === 'ital' && /<\/i>/.test(text.substr(s.position, 4))) {
  39136. s.emitBlock();
  39137. s.ital = false;
  39138. s.modStack.shift();
  39139. s.position += 3;
  39140. } else if (s.mod() === 'mono' && /<\/code>/.test(text.substr(s.position, 7))) {
  39141. s.emitBlock();
  39142. s.mono = false;
  39143. s.modStack.shift();
  39144. s.position += 6;
  39145. } else {
  39146. s.add(ch);
  39147. }
  39148. } else if (/&/.test(ch)) {
  39149. if (/&lt;/.test(text.substr(s.position, 4))) {
  39150. s.add("<");
  39151. s.position += 3;
  39152. } else if (/&amp;/.test(text.substr(s.position, 5))) {
  39153. s.add("&");
  39154. s.position += 4;
  39155. } else {
  39156. s.add("&");
  39157. }
  39158. } else {
  39159. s.add(ch);
  39160. }
  39161. s.position++;
  39162. }
  39163. s.emitBlock();
  39164. return blocks;
  39165. }
  39166. /**
  39167. *
  39168. * @param {string} text
  39169. * @returns {Array}
  39170. */
  39171. }, {
  39172. key: 'splitMarkdownBlocks',
  39173. value: function splitMarkdownBlocks(text) {
  39174. var blocks = [];
  39175. // TODO: consolidate following + methods/closures with splitHtmlBlocks()
  39176. // NOTE: sequences of tabs and spaces are reduced to single space; scan usage of `this.spacing` within method
  39177. var s = {
  39178. bold: false,
  39179. ital: false,
  39180. mono: false,
  39181. beginable: true,
  39182. spacing: false,
  39183. position: 0,
  39184. buffer: "",
  39185. modStack: []
  39186. };
  39187. s.mod = function() {
  39188. return this.modStack.length === 0 ? 'normal' : this.modStack[0];
  39189. };
  39190. s.modName = function() {
  39191. if (this.modStack.length === 0) return 'normal';
  39192. else if (this.modStack[0] === 'mono') return 'mono';
  39193. else {
  39194. if (s.bold && s.ital) {
  39195. return 'boldital';
  39196. } else if (s.bold) {
  39197. return 'bold';
  39198. } else if (s.ital) {
  39199. return 'ital';
  39200. }
  39201. }
  39202. };
  39203. s.emitBlock = function() {
  39204. var override = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  39205. // eslint-disable-line no-unused-vars
  39206. if (this.spacing) {
  39207. this.add(" ");
  39208. this.spacing = false;
  39209. }
  39210. if (this.buffer.length > 0) {
  39211. blocks.push({ text: this.buffer, mod: this.modName() });
  39212. this.buffer = "";
  39213. }
  39214. };
  39215. s.add = function(text) {
  39216. if (text === " ") {
  39217. s.spacing = true;
  39218. }
  39219. if (s.spacing) {
  39220. this.buffer += " ";
  39221. this.spacing = false;
  39222. }
  39223. if (text != " ") {
  39224. this.buffer += text;
  39225. }
  39226. };
  39227. while (s.position < text.length) {
  39228. var ch = text.charAt(s.position);
  39229. if (/[ \t]/.test(ch)) {
  39230. if (!s.mono) {
  39231. s.spacing = true;
  39232. } else {
  39233. s.add(ch);
  39234. }
  39235. s.beginable = true;
  39236. } else if (/\\/.test(ch)) {
  39237. if (s.position < text.length + 1) {
  39238. s.position++;
  39239. ch = text.charAt(s.position);
  39240. if (/ \t/.test(ch)) {
  39241. s.spacing = true;
  39242. } else {
  39243. s.add(ch);
  39244. s.beginable = false;
  39245. }
  39246. }
  39247. } else if (!s.mono && !s.bold && (s.beginable || s.spacing) && /\*/.test(ch)) {
  39248. s.emitBlock();
  39249. s.bold = true;
  39250. s.modStack.unshift("bold");
  39251. } else if (!s.mono && !s.ital && (s.beginable || s.spacing) && /\_/.test(ch)) {
  39252. s.emitBlock();
  39253. s.ital = true;
  39254. s.modStack.unshift("ital");
  39255. } else if (!s.mono && (s.beginable || s.spacing) && /`/.test(ch)) {
  39256. s.emitBlock();
  39257. s.mono = true;
  39258. s.modStack.unshift("mono");
  39259. } else if (!s.mono && s.mod() === "bold" && /\*/.test(ch)) {
  39260. if (s.position === text.length - 1 || /[.,_` \t\n]/.test(text.charAt(s.position + 1))) {
  39261. s.emitBlock();
  39262. s.bold = false;
  39263. s.modStack.shift();
  39264. } else {
  39265. s.add(ch);
  39266. }
  39267. } else if (!s.mono && s.mod() === "ital" && /\_/.test(ch)) {
  39268. if (s.position === text.length - 1 || /[.,*` \t\n]/.test(text.charAt(s.position + 1))) {
  39269. s.emitBlock();
  39270. s.ital = false;
  39271. s.modStack.shift();
  39272. } else {
  39273. s.add(ch);
  39274. }
  39275. } else if (s.mono && s.mod() === "mono" && /`/.test(ch)) {
  39276. if (s.position === text.length - 1 || /[.,*_ \t\n]/.test(text.charAt(s.position + 1))) {
  39277. s.emitBlock();
  39278. s.mono = false;
  39279. s.modStack.shift();
  39280. } else {
  39281. s.add(ch);
  39282. }
  39283. } else {
  39284. s.add(ch);
  39285. s.beginable = false;
  39286. }
  39287. s.position++;
  39288. }
  39289. s.emitBlock();
  39290. return blocks;
  39291. }
  39292. /**
  39293. * Explodes a piece of text into single-font blocks using a given markup
  39294. *
  39295. * @param {string} text
  39296. * @param {boolean|'md'|'markdown'|'html'} markupSystem
  39297. * @returns {Array.<{text: string, mod: string}>}
  39298. * @private
  39299. */
  39300. }, {
  39301. key: 'splitBlocks',
  39302. value: function splitBlocks(text, markupSystem) {
  39303. var system = this.decodeMarkupSystem(markupSystem);
  39304. if (system === 'none') {
  39305. return [{
  39306. text: text,
  39307. mod: 'normal'
  39308. }];
  39309. } else if (system === 'markdown') {
  39310. return this.splitMarkdownBlocks(text);
  39311. } else if (system === 'html') {
  39312. return this.splitHtmlBlocks(text);
  39313. }
  39314. }
  39315. /**
  39316. * @param {string} text
  39317. * @returns {boolean} true if text length over the current max with
  39318. * @private
  39319. */
  39320. }, {
  39321. key: 'overMaxWidth',
  39322. value: function overMaxWidth(text) {
  39323. var width = this.ctx.measureText(text).width;
  39324. return this.lines.curWidth() + width > this.parent.fontOptions.maxWdt;
  39325. }
  39326. /**
  39327. * Determine the longest part of the sentence which still fits in the
  39328. * current max width.
  39329. *
  39330. * @param {Array} words Array of strings signifying a text lines
  39331. * @return {number} index of first item in string making string go over max
  39332. * @private
  39333. */
  39334. }, {
  39335. key: 'getLongestFit',
  39336. value: function getLongestFit(words) {
  39337. var text = '';
  39338. var w = 0;
  39339. while (w < words.length) {
  39340. var pre = text === '' ? '' : ' ';
  39341. var newText = text + pre + words[w];
  39342. if (this.overMaxWidth(newText)) break;
  39343. text = newText;
  39344. w++;
  39345. }
  39346. return w;
  39347. }
  39348. /**
  39349. * Determine the longest part of the string which still fits in the
  39350. * current max width.
  39351. *
  39352. * @param {Array} words Array of strings signifying a text lines
  39353. * @return {number} index of first item in string making string go over max
  39354. */
  39355. }, {
  39356. key: 'getLongestFitWord',
  39357. value: function getLongestFitWord(words) {
  39358. var w = 0;
  39359. while (w < words.length) {
  39360. if (this.overMaxWidth(words.slice(0, w))) break;
  39361. w++;
  39362. }
  39363. return w;
  39364. }
  39365. /**
  39366. * Split the passed text into lines, according to width constraint (if any).
  39367. *
  39368. * The method assumes that the input string is a single line, i.e. without lines break.
  39369. *
  39370. * This method retains spaces, if still present (case `font.multi: false`).
  39371. * A space which falls on an internal line break, will be replaced by a newline.
  39372. * There is no special handling of tabs; these go along with the flow.
  39373. *
  39374. * @param {string} str
  39375. * @param {string} [mod='normal']
  39376. * @param {boolean} [appendLast=false]
  39377. * @private
  39378. */
  39379. }, {
  39380. key: 'splitStringIntoLines',
  39381. value: function splitStringIntoLines(str) {
  39382. var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'normal';
  39383. var appendLast = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  39384. // Still-present spaces are relevant, retain them
  39385. str = str.replace(/^( +)/g, '$1\r');
  39386. str = str.replace(/([^\r][^ ]*)( +)/g, '$1\r$2\r');
  39387. var words = str.split('\r');
  39388. while (words.length > 0) {
  39389. var w = this.getLongestFit(words);
  39390. if (w === 0) {
  39391. // Special case: the first word is already larger than the max width.
  39392. var word = words[0];
  39393. // Break the word to the largest part that fits the line
  39394. var x = this.getLongestFitWord(word);
  39395. this.lines.newLine(word.slice(0, x), mod);
  39396. // Adjust the word, so that the rest will be done next iteration
  39397. words[0] = word.slice(x);
  39398. } else {
  39399. // skip any space that is replaced by a newline
  39400. var newW = w;
  39401. if (words[w - 1] === ' ') {
  39402. w--;
  39403. } else if (words[newW] === ' ') {
  39404. newW++;
  39405. }
  39406. var text = words.slice(0, w).join("");
  39407. if (w == words.length && appendLast) {
  39408. this.lines.append(text, mod);
  39409. } else {
  39410. this.lines.newLine(text, mod);
  39411. }
  39412. // Adjust the word, so that the rest will be done next iteration
  39413. words = words.slice(newW);
  39414. }
  39415. }
  39416. }
  39417. }]);
  39418. return LabelSplitter;
  39419. }();
  39420. exports['default'] = LabelSplitter;
  39421. /***/
  39422. }),
  39423. /* 192 */
  39424. /***/
  39425. (function(module, exports, __webpack_require__) {
  39426. "use strict";
  39427. Object.defineProperty(exports, "__esModule", {
  39428. value: true
  39429. });
  39430. var _assign = __webpack_require__(90);
  39431. var _assign2 = _interopRequireDefault(_assign);
  39432. var _classCallCheck2 = __webpack_require__(0);
  39433. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  39434. var _createClass2 = __webpack_require__(1);
  39435. var _createClass3 = _interopRequireDefault(_createClass2);
  39436. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  39437. /**
  39438. * Callback to determine text dimensions, using the parent label settings.
  39439. * @callback MeasureText
  39440. * @param {text} text
  39441. * @param {text} mod
  39442. * @return {Object} { width, values} width in pixels and font attributes
  39443. */
  39444. /**
  39445. * Helper class for Label which collects results of splitting labels into lines and blocks.
  39446. *
  39447. * @private
  39448. */
  39449. var LabelAccumulator = function() {
  39450. /**
  39451. * @param {MeasureText} measureText
  39452. */
  39453. function LabelAccumulator(measureText) {
  39454. (0, _classCallCheck3["default"])(this, LabelAccumulator);
  39455. this.measureText = measureText;
  39456. this.current = 0;
  39457. this.width = 0;
  39458. this.height = 0;
  39459. this.lines = [];
  39460. }
  39461. /**
  39462. * Append given text to the given line.
  39463. *
  39464. * @param {number} l index of line to add to
  39465. * @param {string} text string to append to line
  39466. * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
  39467. * @private
  39468. */
  39469. (0, _createClass3["default"])(LabelAccumulator, [{
  39470. key: "_add",
  39471. value: function _add(l, text) {
  39472. var mod = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'normal';
  39473. if (this.lines[l] === undefined) {
  39474. this.lines[l] = {
  39475. width: 0,
  39476. height: 0,
  39477. blocks: []
  39478. };
  39479. }
  39480. // We still need to set a block for undefined and empty texts, hence return at this point
  39481. // This is necessary because we don't know at this point if we're at the
  39482. // start of an empty line or not.
  39483. // To compensate, empty blocks are removed in `finalize()`.
  39484. //
  39485. // Empty strings should still have a height
  39486. var tmpText = text;
  39487. if (text === undefined || text === "") tmpText = " ";
  39488. // Determine width and get the font properties
  39489. var result = this.measureText(tmpText, mod);
  39490. var block = (0, _assign2["default"])({}, result.values);
  39491. block.text = text;
  39492. block.width = result.width;
  39493. block.mod = mod;
  39494. if (text === undefined || text === "") {
  39495. block.width = 0;
  39496. }
  39497. this.lines[l].blocks.push(block);
  39498. // Update the line width. We need this for determining if a string goes over max width
  39499. this.lines[l].width += block.width;
  39500. }
  39501. /**
  39502. * Returns the width in pixels of the current line.
  39503. *
  39504. * @returns {number}
  39505. */
  39506. }, {
  39507. key: "curWidth",
  39508. value: function curWidth() {
  39509. var line = this.lines[this.current];
  39510. if (line === undefined) return 0;
  39511. return line.width;
  39512. }
  39513. /**
  39514. * Add text in block to current line
  39515. *
  39516. * @param {string} text
  39517. * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
  39518. */
  39519. }, {
  39520. key: "append",
  39521. value: function append(text) {
  39522. var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'normal';
  39523. this._add(this.current, text, mod);
  39524. }
  39525. /**
  39526. * Add text in block to current line and start a new line
  39527. *
  39528. * @param {string} text
  39529. * @param {'bold'|'ital'|'boldital'|'mono'|'normal'} [mod='normal']
  39530. */
  39531. }, {
  39532. key: "newLine",
  39533. value: function newLine(text) {
  39534. var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'normal';
  39535. this._add(this.current, text, mod);
  39536. this.current++;
  39537. }
  39538. /**
  39539. * Determine and set the heights of all the lines currently contained in this instance
  39540. *
  39541. * Note that width has already been set.
  39542. *
  39543. * @private
  39544. */
  39545. }, {
  39546. key: "determineLineHeights",
  39547. value: function determineLineHeights() {
  39548. for (var k = 0; k < this.lines.length; k++) {
  39549. var line = this.lines[k];
  39550. // Looking for max height of blocks in line
  39551. var height = 0;
  39552. if (line.blocks !== undefined) {
  39553. // Can happen if text contains e.g. '\n '
  39554. for (var l = 0; l < line.blocks.length; l++) {
  39555. var block = line.blocks[l];
  39556. if (height < block.height) {
  39557. height = block.height;
  39558. }
  39559. }
  39560. }
  39561. line.height = height;
  39562. }
  39563. }
  39564. /**
  39565. * Determine the full size of the label text, as determined by current lines and blocks
  39566. *
  39567. * @private
  39568. */
  39569. }, {
  39570. key: "determineLabelSize",
  39571. value: function determineLabelSize() {
  39572. var width = 0;
  39573. var height = 0;
  39574. for (var k = 0; k < this.lines.length; k++) {
  39575. var line = this.lines[k];
  39576. if (line.width > width) {
  39577. width = line.width;
  39578. }
  39579. height += line.height;
  39580. }
  39581. this.width = width;
  39582. this.height = height;
  39583. }
  39584. /**
  39585. * Remove all empty blocks and empty lines we don't need
  39586. *
  39587. * This must be done after the width/height determination,
  39588. * so that these are set properly for processing here.
  39589. *
  39590. * @returns {Array<Line>} Lines with empty blocks (and some empty lines) removed
  39591. * @private
  39592. */
  39593. }, {
  39594. key: "removeEmptyBlocks",
  39595. value: function removeEmptyBlocks() {
  39596. var tmpLines = [];
  39597. for (var k = 0; k < this.lines.length; k++) {
  39598. var line = this.lines[k];
  39599. // Note: an empty line in between text has width zero but is still relevant to layout.
  39600. // So we can't use width for testing empty line here
  39601. if (line.blocks.length === 0) continue;
  39602. // Discard final empty line always
  39603. if (k === this.lines.length - 1) {
  39604. if (line.width === 0) continue;
  39605. }
  39606. var tmpLine = {};
  39607. (0, _assign2["default"])(tmpLine, line);
  39608. tmpLine.blocks = [];
  39609. var firstEmptyBlock = void 0;
  39610. var tmpBlocks = [];
  39611. for (var l = 0; l < line.blocks.length; l++) {
  39612. var block = line.blocks[l];
  39613. if (block.width !== 0) {
  39614. tmpBlocks.push(block);
  39615. } else {
  39616. if (firstEmptyBlock === undefined) {
  39617. firstEmptyBlock = block;
  39618. }
  39619. }
  39620. }
  39621. // Ensure that there is *some* text present
  39622. if (tmpBlocks.length === 0 && firstEmptyBlock !== undefined) {
  39623. tmpBlocks.push(firstEmptyBlock);
  39624. }
  39625. tmpLine.blocks = tmpBlocks;
  39626. tmpLines.push(tmpLine);
  39627. }
  39628. return tmpLines;
  39629. }
  39630. /**
  39631. * Set the sizes for all lines and the whole thing.
  39632. *
  39633. * @returns {{width: (number|*), height: (number|*), lines: Array}}
  39634. */
  39635. }, {
  39636. key: "finalize",
  39637. value: function finalize() {
  39638. //console.log(JSON.stringify(this.lines, null, 2));
  39639. this.determineLineHeights();
  39640. this.determineLabelSize();
  39641. var tmpLines = this.removeEmptyBlocks();
  39642. // Return a simple hash object for further processing.
  39643. return {
  39644. width: this.width,
  39645. height: this.height,
  39646. lines: tmpLines
  39647. };
  39648. }
  39649. }]);
  39650. return LabelAccumulator;
  39651. }();
  39652. exports["default"] = LabelAccumulator;
  39653. /***/
  39654. }),
  39655. /* 193 */
  39656. /***/
  39657. (function(module, exports, __webpack_require__) {
  39658. "use strict";
  39659. Object.defineProperty(exports, "__esModule", {
  39660. value: true
  39661. });
  39662. var _getPrototypeOf = __webpack_require__(3);
  39663. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  39664. var _classCallCheck2 = __webpack_require__(0);
  39665. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  39666. var _createClass2 = __webpack_require__(1);
  39667. var _createClass3 = _interopRequireDefault(_createClass2);
  39668. var _possibleConstructorReturn2 = __webpack_require__(4);
  39669. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  39670. var _inherits2 = __webpack_require__(5);
  39671. var _inherits3 = _interopRequireDefault(_inherits2);
  39672. var _NodeBase2 = __webpack_require__(23);
  39673. var _NodeBase3 = _interopRequireDefault(_NodeBase2);
  39674. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  39675. /**
  39676. * A Box Node/Cluster shape.
  39677. *
  39678. * @extends NodeBase
  39679. */
  39680. var Box = function(_NodeBase) {
  39681. (0, _inherits3['default'])(Box, _NodeBase);
  39682. /**
  39683. * @param {Object} options
  39684. * @param {Object} body
  39685. * @param {Label} labelModule
  39686. */
  39687. function Box(options, body, labelModule) {
  39688. (0, _classCallCheck3['default'])(this, Box);
  39689. var _this = (0, _possibleConstructorReturn3['default'])(this, (Box.__proto__ || (0, _getPrototypeOf2['default'])(Box)).call(this, options, body, labelModule));
  39690. _this._setMargins(labelModule);
  39691. return _this;
  39692. }
  39693. /**
  39694. *
  39695. * @param {CanvasRenderingContext2D} ctx
  39696. * @param {boolean} [selected]
  39697. * @param {boolean} [hover]
  39698. */
  39699. (0, _createClass3['default'])(Box, [{
  39700. key: 'resize',
  39701. value: function resize(ctx) {
  39702. var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
  39703. var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
  39704. if (this.needsRefresh(selected, hover)) {
  39705. var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
  39706. this.width = dimensions.width + this.margin.right + this.margin.left;
  39707. this.height = dimensions.height + this.margin.top + this.margin.bottom;
  39708. this.radius = this.width / 2;
  39709. }
  39710. }
  39711. /**
  39712. *
  39713. * @param {CanvasRenderingContext2D} ctx
  39714. * @param {number} x width
  39715. * @param {number} y height
  39716. * @param {boolean} selected
  39717. * @param {boolean} hover
  39718. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  39719. */
  39720. }, {
  39721. key: 'draw',
  39722. value: function draw(ctx, x, y, selected, hover, values) {
  39723. this.resize(ctx, selected, hover);
  39724. this.left = x - this.width / 2;
  39725. this.top = y - this.height / 2;
  39726. this.initContextForDraw(ctx, values);
  39727. ctx.roundRect(this.left, this.top, this.width, this.height, values.borderRadius);
  39728. this.performFill(ctx, values);
  39729. this.updateBoundingBox(x, y, ctx, selected, hover);
  39730. this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
  39731. }
  39732. /**
  39733. *
  39734. * @param {number} x width
  39735. * @param {number} y height
  39736. * @param {CanvasRenderingContext2D} ctx
  39737. * @param {boolean} selected
  39738. * @param {boolean} hover
  39739. */
  39740. }, {
  39741. key: 'updateBoundingBox',
  39742. value: function updateBoundingBox(x, y, ctx, selected, hover) {
  39743. this._updateBoundingBox(x, y, ctx, selected, hover);
  39744. var borderRadius = this.options.shapeProperties.borderRadius; // only effective for box
  39745. this._addBoundingBoxMargin(borderRadius);
  39746. }
  39747. /**
  39748. *
  39749. * @param {CanvasRenderingContext2D} ctx
  39750. * @param {number} angle
  39751. * @returns {number}
  39752. */
  39753. }, {
  39754. key: 'distanceToBorder',
  39755. value: function distanceToBorder(ctx, angle) {
  39756. this.resize(ctx);
  39757. var borderWidth = this.options.borderWidth;
  39758. return Math.min(Math.abs(this.width / 2 / Math.cos(angle)), Math.abs(this.height / 2 / Math.sin(angle))) + borderWidth;
  39759. }
  39760. }]);
  39761. return Box;
  39762. }(_NodeBase3['default']);
  39763. exports['default'] = Box;
  39764. /***/
  39765. }),
  39766. /* 194 */
  39767. /***/
  39768. (function(module, exports, __webpack_require__) {
  39769. __webpack_require__(195);
  39770. module.exports = __webpack_require__(7).Object.getPrototypeOf;
  39771. /***/
  39772. }),
  39773. /* 195 */
  39774. /***/
  39775. (function(module, exports, __webpack_require__) {
  39776. // 19.1.2.9 Object.getPrototypeOf(O)
  39777. var toObject = __webpack_require__(41);
  39778. var $getPrototypeOf = __webpack_require__(85);
  39779. __webpack_require__(87)('getPrototypeOf', function() {
  39780. return function getPrototypeOf(it) {
  39781. return $getPrototypeOf(toObject(it));
  39782. };
  39783. });
  39784. /***/
  39785. }),
  39786. /* 196 */
  39787. /***/
  39788. (function(module, exports, __webpack_require__) {
  39789. module.exports = { "default": __webpack_require__(197), __esModule: true };
  39790. /***/
  39791. }),
  39792. /* 197 */
  39793. /***/
  39794. (function(module, exports, __webpack_require__) {
  39795. __webpack_require__(198);
  39796. module.exports = __webpack_require__(7).Object.setPrototypeOf;
  39797. /***/
  39798. }),
  39799. /* 198 */
  39800. /***/
  39801. (function(module, exports, __webpack_require__) {
  39802. // 19.1.3.19 Object.setPrototypeOf(O, proto)
  39803. var $export = __webpack_require__(17);
  39804. $export($export.S, 'Object', { setPrototypeOf: __webpack_require__(199).set });
  39805. /***/
  39806. }),
  39807. /* 199 */
  39808. /***/
  39809. (function(module, exports, __webpack_require__) {
  39810. // Works with __proto__ only. Old v8 can't work with null proto objects.
  39811. /* eslint-disable no-proto */
  39812. var isObject = __webpack_require__(32);
  39813. var anObject = __webpack_require__(27);
  39814. var check = function(O, proto) {
  39815. anObject(O);
  39816. if (!isObject(proto) && proto !== null) throw TypeError(proto + ": can't set as prototype!");
  39817. };
  39818. module.exports = {
  39819. set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line
  39820. function(test, buggy, set) {
  39821. try {
  39822. set = __webpack_require__(80)(Function.call, __webpack_require__(89).f(Object.prototype, '__proto__').set, 2);
  39823. set(test, []);
  39824. buggy = !(test instanceof Array);
  39825. } catch (e) { buggy = true; }
  39826. return function setPrototypeOf(O, proto) {
  39827. check(O, proto);
  39828. if (buggy) O.__proto__ = proto;
  39829. else set(O, proto);
  39830. return O;
  39831. };
  39832. }({}, false) : undefined),
  39833. check: check
  39834. };
  39835. /***/
  39836. }),
  39837. /* 200 */
  39838. /***/
  39839. (function(module, exports, __webpack_require__) {
  39840. "use strict";
  39841. Object.defineProperty(exports, "__esModule", {
  39842. value: true
  39843. });
  39844. var _getPrototypeOf = __webpack_require__(3);
  39845. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  39846. var _classCallCheck2 = __webpack_require__(0);
  39847. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  39848. var _createClass2 = __webpack_require__(1);
  39849. var _createClass3 = _interopRequireDefault(_createClass2);
  39850. var _possibleConstructorReturn2 = __webpack_require__(4);
  39851. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  39852. var _inherits2 = __webpack_require__(5);
  39853. var _inherits3 = _interopRequireDefault(_inherits2);
  39854. var _CircleImageBase2 = __webpack_require__(73);
  39855. var _CircleImageBase3 = _interopRequireDefault(_CircleImageBase2);
  39856. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  39857. /**
  39858. * A Circle Node/Cluster shape.
  39859. *
  39860. * @extends CircleImageBase
  39861. */
  39862. var Circle = function(_CircleImageBase) {
  39863. (0, _inherits3['default'])(Circle, _CircleImageBase);
  39864. /**
  39865. * @param {Object} options
  39866. * @param {Object} body
  39867. * @param {Label} labelModule
  39868. */
  39869. function Circle(options, body, labelModule) {
  39870. (0, _classCallCheck3['default'])(this, Circle);
  39871. var _this = (0, _possibleConstructorReturn3['default'])(this, (Circle.__proto__ || (0, _getPrototypeOf2['default'])(Circle)).call(this, options, body, labelModule));
  39872. _this._setMargins(labelModule);
  39873. return _this;
  39874. }
  39875. /**
  39876. *
  39877. * @param {CanvasRenderingContext2D} ctx
  39878. * @param {boolean} [selected]
  39879. * @param {boolean} [hover]
  39880. */
  39881. (0, _createClass3['default'])(Circle, [{
  39882. key: 'resize',
  39883. value: function resize(ctx) {
  39884. var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
  39885. var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
  39886. if (this.needsRefresh(selected, hover)) {
  39887. var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
  39888. var diameter = Math.max(dimensions.width + this.margin.right + this.margin.left, dimensions.height + this.margin.top + this.margin.bottom);
  39889. this.options.size = diameter / 2; // NOTE: this size field only set here, not in Ellipse, Database, Box
  39890. this.width = diameter;
  39891. this.height = diameter;
  39892. this.radius = this.width / 2;
  39893. }
  39894. }
  39895. /**
  39896. *
  39897. * @param {CanvasRenderingContext2D} ctx
  39898. * @param {number} x width
  39899. * @param {number} y height
  39900. * @param {boolean} selected
  39901. * @param {boolean} hover
  39902. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  39903. */
  39904. }, {
  39905. key: 'draw',
  39906. value: function draw(ctx, x, y, selected, hover, values) {
  39907. this.resize(ctx, selected, hover);
  39908. this.left = x - this.width / 2;
  39909. this.top = y - this.height / 2;
  39910. this._drawRawCircle(ctx, x, y, values);
  39911. this.updateBoundingBox(x, y);
  39912. this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, y, selected, hover);
  39913. }
  39914. /**
  39915. *
  39916. * @param {number} x width
  39917. * @param {number} y height
  39918. */
  39919. }, {
  39920. key: 'updateBoundingBox',
  39921. value: function updateBoundingBox(x, y) {
  39922. this.boundingBox.top = y - this.options.size;
  39923. this.boundingBox.left = x - this.options.size;
  39924. this.boundingBox.right = x + this.options.size;
  39925. this.boundingBox.bottom = y + this.options.size;
  39926. }
  39927. /**
  39928. *
  39929. * @param {CanvasRenderingContext2D} ctx
  39930. * @param {number} angle - Unused
  39931. * @returns {number}
  39932. */
  39933. }, {
  39934. key: 'distanceToBorder',
  39935. value: function distanceToBorder(ctx, angle) {
  39936. // eslint-disable-line no-unused-vars
  39937. this.resize(ctx);
  39938. return this.width * 0.5;
  39939. }
  39940. }]);
  39941. return Circle;
  39942. }(_CircleImageBase3['default']);
  39943. exports['default'] = Circle;
  39944. /***/
  39945. }),
  39946. /* 201 */
  39947. /***/
  39948. (function(module, exports, __webpack_require__) {
  39949. "use strict";
  39950. Object.defineProperty(exports, "__esModule", {
  39951. value: true
  39952. });
  39953. var _getPrototypeOf = __webpack_require__(3);
  39954. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  39955. var _classCallCheck2 = __webpack_require__(0);
  39956. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  39957. var _createClass2 = __webpack_require__(1);
  39958. var _createClass3 = _interopRequireDefault(_createClass2);
  39959. var _possibleConstructorReturn2 = __webpack_require__(4);
  39960. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  39961. var _inherits2 = __webpack_require__(5);
  39962. var _inherits3 = _interopRequireDefault(_inherits2);
  39963. var _CircleImageBase2 = __webpack_require__(73);
  39964. var _CircleImageBase3 = _interopRequireDefault(_CircleImageBase2);
  39965. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  39966. /**
  39967. * A CircularImage Node/Cluster shape.
  39968. *
  39969. * @extends CircleImageBase
  39970. */
  39971. var CircularImage = function(_CircleImageBase) {
  39972. (0, _inherits3['default'])(CircularImage, _CircleImageBase);
  39973. /**
  39974. * @param {Object} options
  39975. * @param {Object} body
  39976. * @param {Label} labelModule
  39977. * @param {Image} imageObj
  39978. * @param {Image} imageObjAlt
  39979. */
  39980. function CircularImage(options, body, labelModule, imageObj, imageObjAlt) {
  39981. (0, _classCallCheck3['default'])(this, CircularImage);
  39982. var _this = (0, _possibleConstructorReturn3['default'])(this, (CircularImage.__proto__ || (0, _getPrototypeOf2['default'])(CircularImage)).call(this, options, body, labelModule));
  39983. _this.setImages(imageObj, imageObjAlt);
  39984. return _this;
  39985. }
  39986. /**
  39987. *
  39988. * @param {CanvasRenderingContext2D} ctx
  39989. * @param {boolean} [selected]
  39990. * @param {boolean} [hover]
  39991. */
  39992. (0, _createClass3['default'])(CircularImage, [{
  39993. key: 'resize',
  39994. value: function resize(ctx) {
  39995. var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
  39996. var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
  39997. var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
  39998. if (imageAbsent) {
  39999. var diameter = this.options.size * 2;
  40000. this.width = diameter;
  40001. this.height = diameter;
  40002. this.radius = 0.5 * this.width;
  40003. return;
  40004. }
  40005. // At this point, an image is present, i.e. this.imageObj is valid.
  40006. if (this.needsRefresh(selected, hover)) {
  40007. this._resizeImage();
  40008. }
  40009. }
  40010. /**
  40011. *
  40012. * @param {CanvasRenderingContext2D} ctx
  40013. * @param {number} x width
  40014. * @param {number} y height
  40015. * @param {boolean} selected
  40016. * @param {boolean} hover
  40017. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40018. */
  40019. }, {
  40020. key: 'draw',
  40021. value: function draw(ctx, x, y, selected, hover, values) {
  40022. this.switchImages(selected);
  40023. this.resize();
  40024. this.left = x - this.width / 2;
  40025. this.top = y - this.height / 2;
  40026. // draw the background circle. IMPORTANT: the stroke in this method is used by the clip method below.
  40027. this._drawRawCircle(ctx, x, y, values);
  40028. // now we draw in the circle, we save so we can revert the clip operation after drawing.
  40029. ctx.save();
  40030. // clip is used to use the stroke in drawRawCircle as an area that we can draw in.
  40031. ctx.clip();
  40032. // draw the image
  40033. this._drawImageAtPosition(ctx, values);
  40034. // restore so we can again draw on the full canvas
  40035. ctx.restore();
  40036. this._drawImageLabel(ctx, x, y, selected, hover);
  40037. this.updateBoundingBox(x, y);
  40038. }
  40039. // TODO: compare with Circle.updateBoundingBox(), consolidate? More stuff is happening here
  40040. /**
  40041. *
  40042. * @param {number} x width
  40043. * @param {number} y height
  40044. */
  40045. }, {
  40046. key: 'updateBoundingBox',
  40047. value: function updateBoundingBox(x, y) {
  40048. this.boundingBox.top = y - this.options.size;
  40049. this.boundingBox.left = x - this.options.size;
  40050. this.boundingBox.right = x + this.options.size;
  40051. this.boundingBox.bottom = y + this.options.size;
  40052. // TODO: compare with Image.updateBoundingBox(), consolidate?
  40053. this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
  40054. this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
  40055. this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
  40056. }
  40057. /**
  40058. *
  40059. * @param {CanvasRenderingContext2D} ctx
  40060. * @param {number} angle - Unused
  40061. * @returns {number}
  40062. */
  40063. }, {
  40064. key: 'distanceToBorder',
  40065. value: function distanceToBorder(ctx, angle) {
  40066. // eslint-disable-line no-unused-vars
  40067. this.resize(ctx);
  40068. return this.width * 0.5;
  40069. }
  40070. }]);
  40071. return CircularImage;
  40072. }(_CircleImageBase3['default']);
  40073. exports['default'] = CircularImage;
  40074. /***/
  40075. }),
  40076. /* 202 */
  40077. /***/
  40078. (function(module, exports, __webpack_require__) {
  40079. "use strict";
  40080. Object.defineProperty(exports, "__esModule", {
  40081. value: true
  40082. });
  40083. var _getPrototypeOf = __webpack_require__(3);
  40084. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40085. var _classCallCheck2 = __webpack_require__(0);
  40086. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40087. var _createClass2 = __webpack_require__(1);
  40088. var _createClass3 = _interopRequireDefault(_createClass2);
  40089. var _possibleConstructorReturn2 = __webpack_require__(4);
  40090. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40091. var _inherits2 = __webpack_require__(5);
  40092. var _inherits3 = _interopRequireDefault(_inherits2);
  40093. var _NodeBase2 = __webpack_require__(23);
  40094. var _NodeBase3 = _interopRequireDefault(_NodeBase2);
  40095. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40096. /**
  40097. * A Database Node/Cluster shape.
  40098. *
  40099. * @extends NodeBase
  40100. */
  40101. var Database = function(_NodeBase) {
  40102. (0, _inherits3['default'])(Database, _NodeBase);
  40103. /**
  40104. * @param {Object} options
  40105. * @param {Object} body
  40106. * @param {Label} labelModule
  40107. */
  40108. function Database(options, body, labelModule) {
  40109. (0, _classCallCheck3['default'])(this, Database);
  40110. var _this = (0, _possibleConstructorReturn3['default'])(this, (Database.__proto__ || (0, _getPrototypeOf2['default'])(Database)).call(this, options, body, labelModule));
  40111. _this._setMargins(labelModule);
  40112. return _this;
  40113. }
  40114. /**
  40115. *
  40116. * @param {CanvasRenderingContext2D} ctx
  40117. * @param {boolean} selected
  40118. * @param {boolean} hover
  40119. */
  40120. (0, _createClass3['default'])(Database, [{
  40121. key: 'resize',
  40122. value: function resize(ctx, selected, hover) {
  40123. if (this.needsRefresh(selected, hover)) {
  40124. var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
  40125. var size = dimensions.width + this.margin.right + this.margin.left;
  40126. this.width = size;
  40127. this.height = size;
  40128. this.radius = this.width / 2;
  40129. }
  40130. }
  40131. /**
  40132. *
  40133. * @param {CanvasRenderingContext2D} ctx
  40134. * @param {number} x width
  40135. * @param {number} y height
  40136. * @param {boolean} selected
  40137. * @param {boolean} hover
  40138. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40139. */
  40140. }, {
  40141. key: 'draw',
  40142. value: function draw(ctx, x, y, selected, hover, values) {
  40143. this.resize(ctx, selected, hover);
  40144. this.left = x - this.width / 2;
  40145. this.top = y - this.height / 2;
  40146. this.initContextForDraw(ctx, values);
  40147. ctx.database(x - this.width / 2, y - this.height / 2, this.width, this.height);
  40148. this.performFill(ctx, values);
  40149. this.updateBoundingBox(x, y, ctx, selected, hover);
  40150. this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
  40151. }
  40152. /**
  40153. *
  40154. * @param {CanvasRenderingContext2D} ctx
  40155. * @param {number} angle
  40156. * @returns {number}
  40157. */
  40158. }, {
  40159. key: 'distanceToBorder',
  40160. value: function distanceToBorder(ctx, angle) {
  40161. return this._distanceToBorder(ctx, angle);
  40162. }
  40163. }]);
  40164. return Database;
  40165. }(_NodeBase3['default']);
  40166. exports['default'] = Database;
  40167. /***/
  40168. }),
  40169. /* 203 */
  40170. /***/
  40171. (function(module, exports, __webpack_require__) {
  40172. "use strict";
  40173. Object.defineProperty(exports, "__esModule", {
  40174. value: true
  40175. });
  40176. var _getPrototypeOf = __webpack_require__(3);
  40177. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40178. var _classCallCheck2 = __webpack_require__(0);
  40179. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40180. var _createClass2 = __webpack_require__(1);
  40181. var _createClass3 = _interopRequireDefault(_createClass2);
  40182. var _possibleConstructorReturn2 = __webpack_require__(4);
  40183. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40184. var _inherits2 = __webpack_require__(5);
  40185. var _inherits3 = _interopRequireDefault(_inherits2);
  40186. var _ShapeBase2 = __webpack_require__(24);
  40187. var _ShapeBase3 = _interopRequireDefault(_ShapeBase2);
  40188. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40189. /**
  40190. * A Diamond Node/Cluster shape.
  40191. *
  40192. * @extends ShapeBase
  40193. */
  40194. var Diamond = function(_ShapeBase) {
  40195. (0, _inherits3['default'])(Diamond, _ShapeBase);
  40196. /**
  40197. * @param {Object} options
  40198. * @param {Object} body
  40199. * @param {Label} labelModule
  40200. */
  40201. function Diamond(options, body, labelModule) {
  40202. (0, _classCallCheck3['default'])(this, Diamond);
  40203. return (0, _possibleConstructorReturn3['default'])(this, (Diamond.__proto__ || (0, _getPrototypeOf2['default'])(Diamond)).call(this, options, body, labelModule));
  40204. }
  40205. /**
  40206. *
  40207. * @param {CanvasRenderingContext2D} ctx
  40208. * @param {number} x width
  40209. * @param {number} y height
  40210. * @param {boolean} selected
  40211. * @param {boolean} hover
  40212. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40213. */
  40214. (0, _createClass3['default'])(Diamond, [{
  40215. key: 'draw',
  40216. value: function draw(ctx, x, y, selected, hover, values) {
  40217. this._drawShape(ctx, 'diamond', 4, x, y, selected, hover, values);
  40218. }
  40219. /**
  40220. *
  40221. * @param {CanvasRenderingContext2D} ctx
  40222. * @param {number} angle
  40223. * @returns {number}
  40224. */
  40225. }, {
  40226. key: 'distanceToBorder',
  40227. value: function distanceToBorder(ctx, angle) {
  40228. return this._distanceToBorder(ctx, angle);
  40229. }
  40230. }]);
  40231. return Diamond;
  40232. }(_ShapeBase3['default']);
  40233. exports['default'] = Diamond;
  40234. /***/
  40235. }),
  40236. /* 204 */
  40237. /***/
  40238. (function(module, exports, __webpack_require__) {
  40239. "use strict";
  40240. Object.defineProperty(exports, "__esModule", {
  40241. value: true
  40242. });
  40243. var _getPrototypeOf = __webpack_require__(3);
  40244. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40245. var _classCallCheck2 = __webpack_require__(0);
  40246. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40247. var _createClass2 = __webpack_require__(1);
  40248. var _createClass3 = _interopRequireDefault(_createClass2);
  40249. var _possibleConstructorReturn2 = __webpack_require__(4);
  40250. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40251. var _inherits2 = __webpack_require__(5);
  40252. var _inherits3 = _interopRequireDefault(_inherits2);
  40253. var _ShapeBase2 = __webpack_require__(24);
  40254. var _ShapeBase3 = _interopRequireDefault(_ShapeBase2);
  40255. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40256. /**
  40257. * A Dot Node/Cluster shape.
  40258. *
  40259. * @extends ShapeBase
  40260. */
  40261. var Dot = function(_ShapeBase) {
  40262. (0, _inherits3['default'])(Dot, _ShapeBase);
  40263. /**
  40264. * @param {Object} options
  40265. * @param {Object} body
  40266. * @param {Label} labelModule
  40267. */
  40268. function Dot(options, body, labelModule) {
  40269. (0, _classCallCheck3['default'])(this, Dot);
  40270. return (0, _possibleConstructorReturn3['default'])(this, (Dot.__proto__ || (0, _getPrototypeOf2['default'])(Dot)).call(this, options, body, labelModule));
  40271. }
  40272. /**
  40273. *
  40274. * @param {CanvasRenderingContext2D} ctx
  40275. * @param {number} x width
  40276. * @param {number} y height
  40277. * @param {boolean} selected
  40278. * @param {boolean} hover
  40279. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40280. */
  40281. (0, _createClass3['default'])(Dot, [{
  40282. key: 'draw',
  40283. value: function draw(ctx, x, y, selected, hover, values) {
  40284. this._drawShape(ctx, 'circle', 2, x, y, selected, hover, values);
  40285. }
  40286. /**
  40287. *
  40288. * @param {CanvasRenderingContext2D} ctx
  40289. * @param {number} angle
  40290. * @returns {number}
  40291. */
  40292. }, {
  40293. key: 'distanceToBorder',
  40294. value: function distanceToBorder(ctx, angle) {
  40295. // eslint-disable-line no-unused-vars
  40296. this.resize(ctx);
  40297. return this.options.size;
  40298. }
  40299. }]);
  40300. return Dot;
  40301. }(_ShapeBase3['default']);
  40302. exports['default'] = Dot;
  40303. /***/
  40304. }),
  40305. /* 205 */
  40306. /***/
  40307. (function(module, exports, __webpack_require__) {
  40308. "use strict";
  40309. Object.defineProperty(exports, "__esModule", {
  40310. value: true
  40311. });
  40312. var _getPrototypeOf = __webpack_require__(3);
  40313. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40314. var _classCallCheck2 = __webpack_require__(0);
  40315. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40316. var _createClass2 = __webpack_require__(1);
  40317. var _createClass3 = _interopRequireDefault(_createClass2);
  40318. var _possibleConstructorReturn2 = __webpack_require__(4);
  40319. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40320. var _inherits2 = __webpack_require__(5);
  40321. var _inherits3 = _interopRequireDefault(_inherits2);
  40322. var _NodeBase2 = __webpack_require__(23);
  40323. var _NodeBase3 = _interopRequireDefault(_NodeBase2);
  40324. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40325. /**
  40326. * Am Ellipse Node/Cluster shape.
  40327. *
  40328. * @extends NodeBase
  40329. */
  40330. var Ellipse = function(_NodeBase) {
  40331. (0, _inherits3['default'])(Ellipse, _NodeBase);
  40332. /**
  40333. * @param {Object} options
  40334. * @param {Object} body
  40335. * @param {Label} labelModule
  40336. */
  40337. function Ellipse(options, body, labelModule) {
  40338. (0, _classCallCheck3['default'])(this, Ellipse);
  40339. return (0, _possibleConstructorReturn3['default'])(this, (Ellipse.__proto__ || (0, _getPrototypeOf2['default'])(Ellipse)).call(this, options, body, labelModule));
  40340. }
  40341. /**
  40342. *
  40343. * @param {CanvasRenderingContext2D} ctx
  40344. * @param {boolean} [selected]
  40345. * @param {boolean} [hover]
  40346. */
  40347. (0, _createClass3['default'])(Ellipse, [{
  40348. key: 'resize',
  40349. value: function resize(ctx) {
  40350. var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
  40351. var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
  40352. if (this.needsRefresh(selected, hover)) {
  40353. var dimensions = this.getDimensionsFromLabel(ctx, selected, hover);
  40354. this.height = dimensions.height * 2;
  40355. this.width = dimensions.width + dimensions.height;
  40356. this.radius = 0.5 * this.width;
  40357. }
  40358. }
  40359. /**
  40360. *
  40361. * @param {CanvasRenderingContext2D} ctx
  40362. * @param {number} x width
  40363. * @param {number} y height
  40364. * @param {boolean} selected
  40365. * @param {boolean} hover
  40366. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40367. */
  40368. }, {
  40369. key: 'draw',
  40370. value: function draw(ctx, x, y, selected, hover, values) {
  40371. this.resize(ctx, selected, hover);
  40372. this.left = x - this.width * 0.5;
  40373. this.top = y - this.height * 0.5;
  40374. this.initContextForDraw(ctx, values);
  40375. ctx.ellipse_vis(this.left, this.top, this.width, this.height);
  40376. this.performFill(ctx, values);
  40377. this.updateBoundingBox(x, y, ctx, selected, hover);
  40378. this.labelModule.draw(ctx, x, y, selected, hover);
  40379. }
  40380. /**
  40381. *
  40382. * @param {CanvasRenderingContext2D} ctx
  40383. * @param {number} angle
  40384. * @returns {number}
  40385. */
  40386. }, {
  40387. key: 'distanceToBorder',
  40388. value: function distanceToBorder(ctx, angle) {
  40389. this.resize(ctx);
  40390. var a = this.width * 0.5;
  40391. var b = this.height * 0.5;
  40392. var w = Math.sin(angle) * a;
  40393. var h = Math.cos(angle) * b;
  40394. return a * b / Math.sqrt(w * w + h * h);
  40395. }
  40396. }]);
  40397. return Ellipse;
  40398. }(_NodeBase3['default']);
  40399. exports['default'] = Ellipse;
  40400. /***/
  40401. }),
  40402. /* 206 */
  40403. /***/
  40404. (function(module, exports, __webpack_require__) {
  40405. "use strict";
  40406. Object.defineProperty(exports, "__esModule", {
  40407. value: true
  40408. });
  40409. var _getPrototypeOf = __webpack_require__(3);
  40410. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40411. var _classCallCheck2 = __webpack_require__(0);
  40412. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40413. var _createClass2 = __webpack_require__(1);
  40414. var _createClass3 = _interopRequireDefault(_createClass2);
  40415. var _possibleConstructorReturn2 = __webpack_require__(4);
  40416. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40417. var _inherits2 = __webpack_require__(5);
  40418. var _inherits3 = _interopRequireDefault(_inherits2);
  40419. var _NodeBase2 = __webpack_require__(23);
  40420. var _NodeBase3 = _interopRequireDefault(_NodeBase2);
  40421. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40422. /**
  40423. * An icon replacement for the default Node shape.
  40424. *
  40425. * @extends NodeBase
  40426. */
  40427. var Icon = function(_NodeBase) {
  40428. (0, _inherits3['default'])(Icon, _NodeBase);
  40429. /**
  40430. * @param {Object} options
  40431. * @param {Object} body
  40432. * @param {Label} labelModule
  40433. */
  40434. function Icon(options, body, labelModule) {
  40435. (0, _classCallCheck3['default'])(this, Icon);
  40436. var _this = (0, _possibleConstructorReturn3['default'])(this, (Icon.__proto__ || (0, _getPrototypeOf2['default'])(Icon)).call(this, options, body, labelModule));
  40437. _this._setMargins(labelModule);
  40438. return _this;
  40439. }
  40440. /**
  40441. *
  40442. * @param {CanvasRenderingContext2D} ctx - Unused.
  40443. * @param {boolean} [selected]
  40444. * @param {boolean} [hover]
  40445. */
  40446. (0, _createClass3['default'])(Icon, [{
  40447. key: 'resize',
  40448. value: function resize(ctx, selected, hover) {
  40449. if (this.needsRefresh(selected, hover)) {
  40450. this.iconSize = {
  40451. width: Number(this.options.icon.size),
  40452. height: Number(this.options.icon.size)
  40453. };
  40454. this.width = this.iconSize.width + this.margin.right + this.margin.left;
  40455. this.height = this.iconSize.height + this.margin.top + this.margin.bottom;
  40456. this.radius = 0.5 * this.width;
  40457. }
  40458. }
  40459. /**
  40460. *
  40461. * @param {CanvasRenderingContext2D} ctx
  40462. * @param {number} x width
  40463. * @param {number} y height
  40464. * @param {boolean} selected
  40465. * @param {boolean} hover
  40466. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40467. */
  40468. }, {
  40469. key: 'draw',
  40470. value: function draw(ctx, x, y, selected, hover, values) {
  40471. this.resize(ctx, selected, hover);
  40472. this.options.icon.size = this.options.icon.size || 50;
  40473. this.left = x - this.width / 2;
  40474. this.top = y - this.height / 2;
  40475. this._icon(ctx, x, y, selected, hover, values);
  40476. if (this.options.label !== undefined) {
  40477. var iconTextSpacing = 5;
  40478. this.labelModule.draw(ctx, this.left + this.iconSize.width / 2 + this.margin.left, y + this.height / 2 + iconTextSpacing, selected);
  40479. }
  40480. this.updateBoundingBox(x, y);
  40481. }
  40482. /**
  40483. *
  40484. * @param {number} x
  40485. * @param {number} y
  40486. */
  40487. }, {
  40488. key: 'updateBoundingBox',
  40489. value: function updateBoundingBox(x, y) {
  40490. this.boundingBox.top = y - this.options.icon.size * 0.5;
  40491. this.boundingBox.left = x - this.options.icon.size * 0.5;
  40492. this.boundingBox.right = x + this.options.icon.size * 0.5;
  40493. this.boundingBox.bottom = y + this.options.icon.size * 0.5;
  40494. if (this.options.label !== undefined && this.labelModule.size.width > 0) {
  40495. var iconTextSpacing = 5;
  40496. this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
  40497. this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
  40498. this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelModule.size.height + iconTextSpacing);
  40499. }
  40500. }
  40501. /**
  40502. *
  40503. * @param {CanvasRenderingContext2D} ctx
  40504. * @param {number} x width
  40505. * @param {number} y height
  40506. * @param {boolean} selected
  40507. * @param {boolean} hover - Unused
  40508. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40509. */
  40510. }, {
  40511. key: '_icon',
  40512. value: function _icon(ctx, x, y, selected, hover, values) {
  40513. var iconSize = Number(this.options.icon.size);
  40514. if (this.options.icon.code !== undefined) {
  40515. ctx.font = (selected ? "bold " : "") + iconSize + "px " + this.options.icon.face;
  40516. // draw icon
  40517. ctx.fillStyle = this.options.icon.color || "black";
  40518. ctx.textAlign = "center";
  40519. ctx.textBaseline = "middle";
  40520. // draw shadow if enabled
  40521. this.enableShadow(ctx, values);
  40522. ctx.fillText(this.options.icon.code, x, y);
  40523. // disable shadows for other elements.
  40524. this.disableShadow(ctx, values);
  40525. } else {
  40526. console.error('When using the icon shape, you need to define the code in the icon options object. This can be done per node or globally.');
  40527. }
  40528. }
  40529. /**
  40530. *
  40531. * @param {CanvasRenderingContext2D} ctx
  40532. * @param {number} angle
  40533. * @returns {number}
  40534. */
  40535. }, {
  40536. key: 'distanceToBorder',
  40537. value: function distanceToBorder(ctx, angle) {
  40538. return this._distanceToBorder(ctx, angle);
  40539. }
  40540. }]);
  40541. return Icon;
  40542. }(_NodeBase3['default']);
  40543. exports['default'] = Icon;
  40544. /***/
  40545. }),
  40546. /* 207 */
  40547. /***/
  40548. (function(module, exports, __webpack_require__) {
  40549. "use strict";
  40550. Object.defineProperty(exports, "__esModule", {
  40551. value: true
  40552. });
  40553. var _getPrototypeOf = __webpack_require__(3);
  40554. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40555. var _classCallCheck2 = __webpack_require__(0);
  40556. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40557. var _createClass2 = __webpack_require__(1);
  40558. var _createClass3 = _interopRequireDefault(_createClass2);
  40559. var _possibleConstructorReturn2 = __webpack_require__(4);
  40560. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40561. var _inherits2 = __webpack_require__(5);
  40562. var _inherits3 = _interopRequireDefault(_inherits2);
  40563. var _CircleImageBase2 = __webpack_require__(73);
  40564. var _CircleImageBase3 = _interopRequireDefault(_CircleImageBase2);
  40565. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40566. /**
  40567. * An image-based replacement for the default Node shape.
  40568. *
  40569. * @extends CircleImageBase
  40570. */
  40571. var Image = function(_CircleImageBase) {
  40572. (0, _inherits3['default'])(Image, _CircleImageBase);
  40573. /**
  40574. * @param {Object} options
  40575. * @param {Object} body
  40576. * @param {Label} labelModule
  40577. * @param {Image} imageObj
  40578. * @param {Image} imageObjAlt
  40579. */
  40580. function Image(options, body, labelModule, imageObj, imageObjAlt) {
  40581. (0, _classCallCheck3['default'])(this, Image);
  40582. var _this = (0, _possibleConstructorReturn3['default'])(this, (Image.__proto__ || (0, _getPrototypeOf2['default'])(Image)).call(this, options, body, labelModule));
  40583. _this.setImages(imageObj, imageObjAlt);
  40584. return _this;
  40585. }
  40586. /**
  40587. *
  40588. * @param {CanvasRenderingContext2D} ctx - Unused.
  40589. * @param {boolean} [selected]
  40590. * @param {boolean} [hover]
  40591. */
  40592. (0, _createClass3['default'])(Image, [{
  40593. key: 'resize',
  40594. value: function resize(ctx) {
  40595. var selected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.selected;
  40596. var hover = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hover;
  40597. var imageAbsent = this.imageObj.src === undefined || this.imageObj.width === undefined || this.imageObj.height === undefined;
  40598. if (imageAbsent) {
  40599. var side = this.options.size * 2;
  40600. this.width = side;
  40601. this.height = side;
  40602. return;
  40603. }
  40604. if (this.needsRefresh(selected, hover)) {
  40605. this._resizeImage();
  40606. }
  40607. }
  40608. /**
  40609. *
  40610. * @param {CanvasRenderingContext2D} ctx
  40611. * @param {number} x width
  40612. * @param {number} y height
  40613. * @param {boolean} selected
  40614. * @param {boolean} hover
  40615. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40616. */
  40617. }, {
  40618. key: 'draw',
  40619. value: function draw(ctx, x, y, selected, hover, values) {
  40620. this.switchImages(selected);
  40621. this.resize();
  40622. this.left = x - this.width / 2;
  40623. this.top = y - this.height / 2;
  40624. if (this.options.shapeProperties.useBorderWithImage === true) {
  40625. var neutralborderWidth = this.options.borderWidth;
  40626. var selectionLineWidth = this.options.borderWidthSelected || 2 * this.options.borderWidth;
  40627. var borderWidth = (selected ? selectionLineWidth : neutralborderWidth) / this.body.view.scale;
  40628. ctx.lineWidth = Math.min(this.width, borderWidth);
  40629. ctx.beginPath();
  40630. // setup the line properties.
  40631. ctx.strokeStyle = selected ? this.options.color.highlight.border : hover ? this.options.color.hover.border : this.options.color.border;
  40632. // set a fillstyle
  40633. ctx.fillStyle = selected ? this.options.color.highlight.background : hover ? this.options.color.hover.background : this.options.color.background;
  40634. // draw a rectangle to form the border around. This rectangle is filled so the opacity of a picture (in future vis releases?) can be used to tint the image
  40635. ctx.rect(this.left - 0.5 * ctx.lineWidth, this.top - 0.5 * ctx.lineWidth, this.width + ctx.lineWidth, this.height + ctx.lineWidth);
  40636. ctx.fill();
  40637. this.performStroke(ctx, values);
  40638. ctx.closePath();
  40639. }
  40640. this._drawImageAtPosition(ctx, values);
  40641. this._drawImageLabel(ctx, x, y, selected, hover);
  40642. this.updateBoundingBox(x, y);
  40643. }
  40644. /**
  40645. *
  40646. * @param {number} x
  40647. * @param {number} y
  40648. */
  40649. }, {
  40650. key: 'updateBoundingBox',
  40651. value: function updateBoundingBox(x, y) {
  40652. this.resize();
  40653. this._updateBoundingBox(x, y);
  40654. if (this.options.label !== undefined && this.labelModule.size.width > 0) {
  40655. this.boundingBox.left = Math.min(this.boundingBox.left, this.labelModule.size.left);
  40656. this.boundingBox.right = Math.max(this.boundingBox.right, this.labelModule.size.left + this.labelModule.size.width);
  40657. this.boundingBox.bottom = Math.max(this.boundingBox.bottom, this.boundingBox.bottom + this.labelOffset);
  40658. }
  40659. }
  40660. /**
  40661. *
  40662. * @param {CanvasRenderingContext2D} ctx
  40663. * @param {number} angle
  40664. * @returns {number}
  40665. */
  40666. }, {
  40667. key: 'distanceToBorder',
  40668. value: function distanceToBorder(ctx, angle) {
  40669. return this._distanceToBorder(ctx, angle);
  40670. }
  40671. }]);
  40672. return Image;
  40673. }(_CircleImageBase3['default']);
  40674. exports['default'] = Image;
  40675. /***/
  40676. }),
  40677. /* 208 */
  40678. /***/
  40679. (function(module, exports, __webpack_require__) {
  40680. "use strict";
  40681. Object.defineProperty(exports, "__esModule", {
  40682. value: true
  40683. });
  40684. var _getPrototypeOf = __webpack_require__(3);
  40685. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40686. var _classCallCheck2 = __webpack_require__(0);
  40687. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40688. var _createClass2 = __webpack_require__(1);
  40689. var _createClass3 = _interopRequireDefault(_createClass2);
  40690. var _possibleConstructorReturn2 = __webpack_require__(4);
  40691. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40692. var _inherits2 = __webpack_require__(5);
  40693. var _inherits3 = _interopRequireDefault(_inherits2);
  40694. var _ShapeBase2 = __webpack_require__(24);
  40695. var _ShapeBase3 = _interopRequireDefault(_ShapeBase2);
  40696. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40697. /**
  40698. * A Square Node/Cluster shape.
  40699. *
  40700. * @extends ShapeBase
  40701. */
  40702. var Square = function(_ShapeBase) {
  40703. (0, _inherits3['default'])(Square, _ShapeBase);
  40704. /**
  40705. * @param {Object} options
  40706. * @param {Object} body
  40707. * @param {Label} labelModule
  40708. */
  40709. function Square(options, body, labelModule) {
  40710. (0, _classCallCheck3['default'])(this, Square);
  40711. return (0, _possibleConstructorReturn3['default'])(this, (Square.__proto__ || (0, _getPrototypeOf2['default'])(Square)).call(this, options, body, labelModule));
  40712. }
  40713. /**
  40714. *
  40715. * @param {CanvasRenderingContext2D} ctx
  40716. * @param {number} x width
  40717. * @param {number} y height
  40718. * @param {boolean} selected
  40719. * @param {boolean} hover
  40720. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40721. */
  40722. (0, _createClass3['default'])(Square, [{
  40723. key: 'draw',
  40724. value: function draw(ctx, x, y, selected, hover, values) {
  40725. this._drawShape(ctx, 'square', 2, x, y, selected, hover, values);
  40726. }
  40727. /**
  40728. *
  40729. * @param {CanvasRenderingContext2D} ctx
  40730. * @param {number} angle
  40731. * @returns {number}
  40732. */
  40733. }, {
  40734. key: 'distanceToBorder',
  40735. value: function distanceToBorder(ctx, angle) {
  40736. return this._distanceToBorder(ctx, angle);
  40737. }
  40738. }]);
  40739. return Square;
  40740. }(_ShapeBase3['default']);
  40741. exports['default'] = Square;
  40742. /***/
  40743. }),
  40744. /* 209 */
  40745. /***/
  40746. (function(module, exports, __webpack_require__) {
  40747. "use strict";
  40748. Object.defineProperty(exports, "__esModule", {
  40749. value: true
  40750. });
  40751. var _getPrototypeOf = __webpack_require__(3);
  40752. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40753. var _classCallCheck2 = __webpack_require__(0);
  40754. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40755. var _createClass2 = __webpack_require__(1);
  40756. var _createClass3 = _interopRequireDefault(_createClass2);
  40757. var _possibleConstructorReturn2 = __webpack_require__(4);
  40758. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40759. var _inherits2 = __webpack_require__(5);
  40760. var _inherits3 = _interopRequireDefault(_inherits2);
  40761. var _ShapeBase2 = __webpack_require__(24);
  40762. var _ShapeBase3 = _interopRequireDefault(_ShapeBase2);
  40763. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40764. /**
  40765. * A Hexagon Node/Cluster shape.
  40766. *
  40767. * @extends ShapeBase
  40768. */
  40769. var Hexagon = function(_ShapeBase) {
  40770. (0, _inherits3['default'])(Hexagon, _ShapeBase);
  40771. /**
  40772. * @param {Object} options
  40773. * @param {Object} body
  40774. * @param {Label} labelModule
  40775. */
  40776. function Hexagon(options, body, labelModule) {
  40777. (0, _classCallCheck3['default'])(this, Hexagon);
  40778. return (0, _possibleConstructorReturn3['default'])(this, (Hexagon.__proto__ || (0, _getPrototypeOf2['default'])(Hexagon)).call(this, options, body, labelModule));
  40779. }
  40780. /**
  40781. *
  40782. * @param {CanvasRenderingContext2D} ctx
  40783. * @param {number} x width
  40784. * @param {number} y height
  40785. * @param {boolean} selected
  40786. * @param {boolean} hover
  40787. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40788. */
  40789. (0, _createClass3['default'])(Hexagon, [{
  40790. key: 'draw',
  40791. value: function draw(ctx, x, y, selected, hover, values) {
  40792. this._drawShape(ctx, 'hexagon', 4, x, y, selected, hover, values);
  40793. }
  40794. /**
  40795. *
  40796. * @param {CanvasRenderingContext2D} ctx
  40797. * @param {number} angle
  40798. * @returns {number}
  40799. */
  40800. }, {
  40801. key: 'distanceToBorder',
  40802. value: function distanceToBorder(ctx, angle) {
  40803. return this._distanceToBorder(ctx, angle);
  40804. }
  40805. }]);
  40806. return Hexagon;
  40807. }(_ShapeBase3['default']);
  40808. exports['default'] = Hexagon;
  40809. /***/
  40810. }),
  40811. /* 210 */
  40812. /***/
  40813. (function(module, exports, __webpack_require__) {
  40814. "use strict";
  40815. Object.defineProperty(exports, "__esModule", {
  40816. value: true
  40817. });
  40818. var _getPrototypeOf = __webpack_require__(3);
  40819. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40820. var _classCallCheck2 = __webpack_require__(0);
  40821. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40822. var _createClass2 = __webpack_require__(1);
  40823. var _createClass3 = _interopRequireDefault(_createClass2);
  40824. var _possibleConstructorReturn2 = __webpack_require__(4);
  40825. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40826. var _inherits2 = __webpack_require__(5);
  40827. var _inherits3 = _interopRequireDefault(_inherits2);
  40828. var _ShapeBase2 = __webpack_require__(24);
  40829. var _ShapeBase3 = _interopRequireDefault(_ShapeBase2);
  40830. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40831. /**
  40832. * A Star Node/Cluster shape.
  40833. *
  40834. * @extends ShapeBase
  40835. */
  40836. var Star = function(_ShapeBase) {
  40837. (0, _inherits3['default'])(Star, _ShapeBase);
  40838. /**
  40839. * @param {Object} options
  40840. * @param {Object} body
  40841. * @param {Label} labelModule
  40842. */
  40843. function Star(options, body, labelModule) {
  40844. (0, _classCallCheck3['default'])(this, Star);
  40845. return (0, _possibleConstructorReturn3['default'])(this, (Star.__proto__ || (0, _getPrototypeOf2['default'])(Star)).call(this, options, body, labelModule));
  40846. }
  40847. /**
  40848. *
  40849. * @param {CanvasRenderingContext2D} ctx
  40850. * @param {number} x width
  40851. * @param {number} y height
  40852. * @param {boolean} selected
  40853. * @param {boolean} hover
  40854. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40855. */
  40856. (0, _createClass3['default'])(Star, [{
  40857. key: 'draw',
  40858. value: function draw(ctx, x, y, selected, hover, values) {
  40859. this._drawShape(ctx, 'star', 4, x, y, selected, hover, values);
  40860. }
  40861. /**
  40862. *
  40863. * @param {CanvasRenderingContext2D} ctx
  40864. * @param {number} angle
  40865. * @returns {number}
  40866. */
  40867. }, {
  40868. key: 'distanceToBorder',
  40869. value: function distanceToBorder(ctx, angle) {
  40870. return this._distanceToBorder(ctx, angle);
  40871. }
  40872. }]);
  40873. return Star;
  40874. }(_ShapeBase3['default']);
  40875. exports['default'] = Star;
  40876. /***/
  40877. }),
  40878. /* 211 */
  40879. /***/
  40880. (function(module, exports, __webpack_require__) {
  40881. "use strict";
  40882. Object.defineProperty(exports, "__esModule", {
  40883. value: true
  40884. });
  40885. var _getPrototypeOf = __webpack_require__(3);
  40886. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40887. var _classCallCheck2 = __webpack_require__(0);
  40888. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40889. var _createClass2 = __webpack_require__(1);
  40890. var _createClass3 = _interopRequireDefault(_createClass2);
  40891. var _possibleConstructorReturn2 = __webpack_require__(4);
  40892. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40893. var _inherits2 = __webpack_require__(5);
  40894. var _inherits3 = _interopRequireDefault(_inherits2);
  40895. var _NodeBase2 = __webpack_require__(23);
  40896. var _NodeBase3 = _interopRequireDefault(_NodeBase2);
  40897. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40898. /**
  40899. * A text-based replacement for the default Node shape.
  40900. *
  40901. * @extends NodeBase
  40902. */
  40903. var Text = function(_NodeBase) {
  40904. (0, _inherits3['default'])(Text, _NodeBase);
  40905. /**
  40906. * @param {Object} options
  40907. * @param {Object} body
  40908. * @param {Label} labelModule
  40909. */
  40910. function Text(options, body, labelModule) {
  40911. (0, _classCallCheck3['default'])(this, Text);
  40912. var _this = (0, _possibleConstructorReturn3['default'])(this, (Text.__proto__ || (0, _getPrototypeOf2['default'])(Text)).call(this, options, body, labelModule));
  40913. _this._setMargins(labelModule);
  40914. return _this;
  40915. }
  40916. /**
  40917. *
  40918. * @param {CanvasRenderingContext2D} ctx
  40919. * @param {boolean} selected
  40920. * @param {boolean} hover
  40921. */
  40922. (0, _createClass3['default'])(Text, [{
  40923. key: 'resize',
  40924. value: function resize(ctx, selected, hover) {
  40925. if (this.needsRefresh(selected, hover)) {
  40926. this.textSize = this.labelModule.getTextSize(ctx, selected, hover);
  40927. this.width = this.textSize.width + this.margin.right + this.margin.left;
  40928. this.height = this.textSize.height + this.margin.top + this.margin.bottom;
  40929. this.radius = 0.5 * this.width;
  40930. }
  40931. }
  40932. /**
  40933. *
  40934. * @param {CanvasRenderingContext2D} ctx
  40935. * @param {number} x width
  40936. * @param {number} y height
  40937. * @param {boolean} selected
  40938. * @param {boolean} hover
  40939. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  40940. */
  40941. }, {
  40942. key: 'draw',
  40943. value: function draw(ctx, x, y, selected, hover, values) {
  40944. this.resize(ctx, selected, hover);
  40945. this.left = x - this.width / 2;
  40946. this.top = y - this.height / 2;
  40947. // draw shadow if enabled
  40948. this.enableShadow(ctx, values);
  40949. this.labelModule.draw(ctx, this.left + this.textSize.width / 2 + this.margin.left, this.top + this.textSize.height / 2 + this.margin.top, selected, hover);
  40950. // disable shadows for other elements.
  40951. this.disableShadow(ctx, values);
  40952. this.updateBoundingBox(x, y, ctx, selected, hover);
  40953. }
  40954. /**
  40955. *
  40956. * @param {CanvasRenderingContext2D} ctx
  40957. * @param {number} angle
  40958. * @returns {number}
  40959. */
  40960. }, {
  40961. key: 'distanceToBorder',
  40962. value: function distanceToBorder(ctx, angle) {
  40963. return this._distanceToBorder(ctx, angle);
  40964. }
  40965. }]);
  40966. return Text;
  40967. }(_NodeBase3['default']);
  40968. exports['default'] = Text;
  40969. /***/
  40970. }),
  40971. /* 212 */
  40972. /***/
  40973. (function(module, exports, __webpack_require__) {
  40974. "use strict";
  40975. Object.defineProperty(exports, "__esModule", {
  40976. value: true
  40977. });
  40978. var _getPrototypeOf = __webpack_require__(3);
  40979. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  40980. var _classCallCheck2 = __webpack_require__(0);
  40981. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  40982. var _createClass2 = __webpack_require__(1);
  40983. var _createClass3 = _interopRequireDefault(_createClass2);
  40984. var _possibleConstructorReturn2 = __webpack_require__(4);
  40985. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  40986. var _inherits2 = __webpack_require__(5);
  40987. var _inherits3 = _interopRequireDefault(_inherits2);
  40988. var _ShapeBase2 = __webpack_require__(24);
  40989. var _ShapeBase3 = _interopRequireDefault(_ShapeBase2);
  40990. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  40991. /**
  40992. * A Triangle Node/Cluster shape.
  40993. *
  40994. * @extends ShapeBase
  40995. */
  40996. var Triangle = function(_ShapeBase) {
  40997. (0, _inherits3['default'])(Triangle, _ShapeBase);
  40998. /**
  40999. * @param {Object} options
  41000. * @param {Object} body
  41001. * @param {Label} labelModule
  41002. */
  41003. function Triangle(options, body, labelModule) {
  41004. (0, _classCallCheck3['default'])(this, Triangle);
  41005. return (0, _possibleConstructorReturn3['default'])(this, (Triangle.__proto__ || (0, _getPrototypeOf2['default'])(Triangle)).call(this, options, body, labelModule));
  41006. }
  41007. /**
  41008. *
  41009. * @param {CanvasRenderingContext2D} ctx
  41010. * @param {number} x
  41011. * @param {number} y
  41012. * @param {boolean} selected
  41013. * @param {boolean} hover
  41014. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  41015. */
  41016. (0, _createClass3['default'])(Triangle, [{
  41017. key: 'draw',
  41018. value: function draw(ctx, x, y, selected, hover, values) {
  41019. this._drawShape(ctx, 'triangle', 3, x, y, selected, hover, values);
  41020. }
  41021. /**
  41022. *
  41023. * @param {CanvasRenderingContext2D} ctx
  41024. * @param {number} angle
  41025. * @returns {number}
  41026. */
  41027. }, {
  41028. key: 'distanceToBorder',
  41029. value: function distanceToBorder(ctx, angle) {
  41030. return this._distanceToBorder(ctx, angle);
  41031. }
  41032. }]);
  41033. return Triangle;
  41034. }(_ShapeBase3['default']);
  41035. exports['default'] = Triangle;
  41036. /***/
  41037. }),
  41038. /* 213 */
  41039. /***/
  41040. (function(module, exports, __webpack_require__) {
  41041. "use strict";
  41042. Object.defineProperty(exports, "__esModule", {
  41043. value: true
  41044. });
  41045. var _getPrototypeOf = __webpack_require__(3);
  41046. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  41047. var _classCallCheck2 = __webpack_require__(0);
  41048. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  41049. var _createClass2 = __webpack_require__(1);
  41050. var _createClass3 = _interopRequireDefault(_createClass2);
  41051. var _possibleConstructorReturn2 = __webpack_require__(4);
  41052. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  41053. var _inherits2 = __webpack_require__(5);
  41054. var _inherits3 = _interopRequireDefault(_inherits2);
  41055. var _ShapeBase2 = __webpack_require__(24);
  41056. var _ShapeBase3 = _interopRequireDefault(_ShapeBase2);
  41057. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  41058. /**
  41059. * A downward facing Triangle Node/Cluster shape.
  41060. *
  41061. * @extends ShapeBase
  41062. */
  41063. var TriangleDown = function(_ShapeBase) {
  41064. (0, _inherits3['default'])(TriangleDown, _ShapeBase);
  41065. /**
  41066. * @param {Object} options
  41067. * @param {Object} body
  41068. * @param {Label} labelModule
  41069. */
  41070. function TriangleDown(options, body, labelModule) {
  41071. (0, _classCallCheck3['default'])(this, TriangleDown);
  41072. return (0, _possibleConstructorReturn3['default'])(this, (TriangleDown.__proto__ || (0, _getPrototypeOf2['default'])(TriangleDown)).call(this, options, body, labelModule));
  41073. }
  41074. /**
  41075. *
  41076. * @param {CanvasRenderingContext2D} ctx
  41077. * @param {number} x
  41078. * @param {number} y
  41079. * @param {boolean} selected
  41080. * @param {boolean} hover
  41081. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  41082. */
  41083. (0, _createClass3['default'])(TriangleDown, [{
  41084. key: 'draw',
  41085. value: function draw(ctx, x, y, selected, hover, values) {
  41086. this._drawShape(ctx, 'triangleDown', 3, x, y, selected, hover, values);
  41087. }
  41088. /**
  41089. *
  41090. * @param {CanvasRenderingContext2D} ctx
  41091. * @param {number} angle
  41092. * @returns {number}
  41093. */
  41094. }, {
  41095. key: 'distanceToBorder',
  41096. value: function distanceToBorder(ctx, angle) {
  41097. return this._distanceToBorder(ctx, angle);
  41098. }
  41099. }]);
  41100. return TriangleDown;
  41101. }(_ShapeBase3['default']);
  41102. exports['default'] = TriangleDown;
  41103. /***/
  41104. }),
  41105. /* 214 */
  41106. /***/
  41107. (function(module, exports, __webpack_require__) {
  41108. "use strict";
  41109. Object.defineProperty(exports, "__esModule", {
  41110. value: true
  41111. });
  41112. var _classCallCheck2 = __webpack_require__(0);
  41113. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  41114. var _createClass2 = __webpack_require__(1);
  41115. var _createClass3 = _interopRequireDefault(_createClass2);
  41116. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  41117. var util = __webpack_require__(2);
  41118. var DataSet = __webpack_require__(11);
  41119. var DataView = __webpack_require__(12);
  41120. var Edge = __webpack_require__(74)['default'];
  41121. /**
  41122. * Handler for Edges
  41123. */
  41124. var EdgesHandler = function() {
  41125. /**
  41126. * @param {Object} body
  41127. * @param {Array.<Image>} images
  41128. * @param {Array.<Group>} groups
  41129. */
  41130. function EdgesHandler(body, images, groups) {
  41131. var _this = this;
  41132. (0, _classCallCheck3['default'])(this, EdgesHandler);
  41133. this.body = body;
  41134. this.images = images;
  41135. this.groups = groups;
  41136. // create the edge API in the body container
  41137. this.body.functions.createEdge = this.create.bind(this);
  41138. this.edgesListeners = {
  41139. add: function add(event, params) {
  41140. _this.add(params.items);
  41141. },
  41142. update: function update(event, params) {
  41143. _this.update(params.items);
  41144. },
  41145. remove: function remove(event, params) {
  41146. _this.remove(params.items);
  41147. }
  41148. };
  41149. this.options = {};
  41150. this.defaultOptions = {
  41151. arrows: {
  41152. to: { enabled: false, scaleFactor: 1, type: 'arrow' }, // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
  41153. middle: { enabled: false, scaleFactor: 1, type: 'arrow' },
  41154. from: { enabled: false, scaleFactor: 1, type: 'arrow' }
  41155. },
  41156. arrowStrikethrough: true,
  41157. color: {
  41158. color: '#848484',
  41159. highlight: '#848484',
  41160. hover: '#848484',
  41161. inherit: 'from',
  41162. opacity: 1.0
  41163. },
  41164. dashes: false,
  41165. font: {
  41166. color: '#343434',
  41167. size: 14, // px
  41168. face: 'arial',
  41169. background: 'none',
  41170. strokeWidth: 2, // px
  41171. strokeColor: '#ffffff',
  41172. align: 'horizontal',
  41173. multi: false,
  41174. vadjust: 0,
  41175. bold: {
  41176. mod: 'bold'
  41177. },
  41178. boldital: {
  41179. mod: 'bold italic'
  41180. },
  41181. ital: {
  41182. mod: 'italic'
  41183. },
  41184. mono: {
  41185. mod: '',
  41186. size: 15, // px
  41187. face: 'courier new',
  41188. vadjust: 2
  41189. }
  41190. },
  41191. hidden: false,
  41192. hoverWidth: 1.5,
  41193. label: undefined,
  41194. labelHighlightBold: true,
  41195. length: undefined,
  41196. physics: true,
  41197. scaling: {
  41198. min: 1,
  41199. max: 15,
  41200. label: {
  41201. enabled: true,
  41202. min: 14,
  41203. max: 30,
  41204. maxVisible: 30,
  41205. drawThreshold: 5
  41206. },
  41207. customScalingFunction: function customScalingFunction(min, max, total, value) {
  41208. if (max === min) {
  41209. return 0.5;
  41210. } else {
  41211. var scale = 1 / (max - min);
  41212. return Math.max(0, (value - min) * scale);
  41213. }
  41214. }
  41215. },
  41216. selectionWidth: 1.5,
  41217. selfReferenceSize: 20,
  41218. shadow: {
  41219. enabled: false,
  41220. color: 'rgba(0,0,0,0.5)',
  41221. size: 10,
  41222. x: 5,
  41223. y: 5
  41224. },
  41225. smooth: {
  41226. enabled: true,
  41227. type: "dynamic",
  41228. forceDirection: 'none',
  41229. roundness: 0.5
  41230. },
  41231. title: undefined,
  41232. width: 1,
  41233. value: undefined
  41234. };
  41235. util.deepExtend(this.options, this.defaultOptions);
  41236. this.bindEventListeners();
  41237. }
  41238. /**
  41239. * Binds event listeners
  41240. */
  41241. (0, _createClass3['default'])(EdgesHandler, [{
  41242. key: 'bindEventListeners',
  41243. value: function bindEventListeners() {
  41244. var _this2 = this;
  41245. // this allows external modules to force all dynamic curves to turn static.
  41246. this.body.emitter.on("_forceDisableDynamicCurves", function(type) {
  41247. var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  41248. if (type === 'dynamic') {
  41249. type = 'continuous';
  41250. }
  41251. var dataChanged = false;
  41252. for (var edgeId in _this2.body.edges) {
  41253. if (_this2.body.edges.hasOwnProperty(edgeId)) {
  41254. var edge = _this2.body.edges[edgeId];
  41255. var edgeData = _this2.body.data.edges._data[edgeId];
  41256. // only forcibly remove the smooth curve if the data has been set of the edge has the smooth curves defined.
  41257. // this is because a change in the global would not affect these curves.
  41258. if (edgeData !== undefined) {
  41259. var smoothOptions = edgeData.smooth;
  41260. if (smoothOptions !== undefined) {
  41261. if (smoothOptions.enabled === true && smoothOptions.type === 'dynamic') {
  41262. if (type === undefined) {
  41263. edge.setOptions({ smooth: false });
  41264. } else {
  41265. edge.setOptions({ smooth: { type: type } });
  41266. }
  41267. dataChanged = true;
  41268. }
  41269. }
  41270. }
  41271. }
  41272. }
  41273. if (emit === true && dataChanged === true) {
  41274. _this2.body.emitter.emit("_dataChanged");
  41275. }
  41276. });
  41277. // this is called when options of EXISTING nodes or edges have changed.
  41278. //
  41279. // NOTE: Not true, called when options have NOT changed, for both existing as well as new nodes.
  41280. // See update() for logic.
  41281. // TODO: Verify and examine the consequences of this. It might still trigger when
  41282. // non-option fields have changed, but then reconnecting edges is still useless.
  41283. // Alternatively, it might also be called when edges are removed.
  41284. //
  41285. this.body.emitter.on("_dataUpdated", function() {
  41286. _this2.reconnectEdges();
  41287. });
  41288. // refresh the edges. Used when reverting from hierarchical layout
  41289. this.body.emitter.on("refreshEdges", this.refresh.bind(this));
  41290. this.body.emitter.on("refresh", this.refresh.bind(this));
  41291. this.body.emitter.on("destroy", function() {
  41292. util.forEach(_this2.edgesListeners, function(callback, event) {
  41293. if (_this2.body.data.edges) _this2.body.data.edges.off(event, callback);
  41294. });
  41295. delete _this2.body.functions.createEdge;
  41296. delete _this2.edgesListeners.add;
  41297. delete _this2.edgesListeners.update;
  41298. delete _this2.edgesListeners.remove;
  41299. delete _this2.edgesListeners;
  41300. });
  41301. }
  41302. /**
  41303. *
  41304. * @param {Object} options
  41305. */
  41306. }, {
  41307. key: 'setOptions',
  41308. value: function setOptions(options) {
  41309. if (options !== undefined) {
  41310. // use the parser from the Edge class to fill in all shorthand notations
  41311. Edge.parseOptions(this.options, options, true, this.defaultOptions, true);
  41312. // update smooth settings in all edges
  41313. var dataChanged = false;
  41314. if (options.smooth !== undefined) {
  41315. for (var edgeId in this.body.edges) {
  41316. if (this.body.edges.hasOwnProperty(edgeId)) {
  41317. dataChanged = this.body.edges[edgeId].updateEdgeType() || dataChanged;
  41318. }
  41319. }
  41320. }
  41321. // update fonts in all edges
  41322. if (options.font !== undefined) {
  41323. for (var _edgeId in this.body.edges) {
  41324. if (this.body.edges.hasOwnProperty(_edgeId)) {
  41325. this.body.edges[_edgeId].updateLabelModule();
  41326. }
  41327. }
  41328. }
  41329. // update the state of the variables if needed
  41330. if (options.hidden !== undefined || options.physics !== undefined || dataChanged === true) {
  41331. this.body.emitter.emit('_dataChanged');
  41332. }
  41333. }
  41334. }
  41335. /**
  41336. * Load edges by reading the data table
  41337. * @param {Array | DataSet | DataView} edges The data containing the edges.
  41338. * @param {boolean} [doNotEmit=false]
  41339. * @private
  41340. */
  41341. }, {
  41342. key: 'setData',
  41343. value: function setData(edges) {
  41344. var _this3 = this;
  41345. var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  41346. var oldEdgesData = this.body.data.edges;
  41347. if (edges instanceof DataSet || edges instanceof DataView) {
  41348. this.body.data.edges = edges;
  41349. } else if (Array.isArray(edges)) {
  41350. this.body.data.edges = new DataSet();
  41351. this.body.data.edges.add(edges);
  41352. } else if (!edges) {
  41353. this.body.data.edges = new DataSet();
  41354. } else {
  41355. throw new TypeError('Array or DataSet expected');
  41356. }
  41357. // TODO: is this null or undefined or false?
  41358. if (oldEdgesData) {
  41359. // unsubscribe from old dataset
  41360. util.forEach(this.edgesListeners, function(callback, event) {
  41361. oldEdgesData.off(event, callback);
  41362. });
  41363. }
  41364. // remove drawn edges
  41365. this.body.edges = {};
  41366. // TODO: is this null or undefined or false?
  41367. if (this.body.data.edges) {
  41368. // subscribe to new dataset
  41369. util.forEach(this.edgesListeners, function(callback, event) {
  41370. _this3.body.data.edges.on(event, callback);
  41371. });
  41372. // draw all new nodes
  41373. var ids = this.body.data.edges.getIds();
  41374. this.add(ids, true);
  41375. }
  41376. this.body.emitter.emit('_adjustEdgesForHierarchicalLayout');
  41377. if (doNotEmit === false) {
  41378. this.body.emitter.emit("_dataChanged");
  41379. }
  41380. }
  41381. /**
  41382. * Add edges
  41383. * @param {number[] | string[]} ids
  41384. * @param {boolean} [doNotEmit=false]
  41385. * @private
  41386. */
  41387. }, {
  41388. key: 'add',
  41389. value: function add(ids) {
  41390. var doNotEmit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  41391. var edges = this.body.edges;
  41392. var edgesData = this.body.data.edges;
  41393. for (var i = 0; i < ids.length; i++) {
  41394. var id = ids[i];
  41395. var oldEdge = edges[id];
  41396. if (oldEdge) {
  41397. oldEdge.disconnect();
  41398. }
  41399. var data = edgesData.get(id, { "showInternalIds": true });
  41400. edges[id] = this.create(data);
  41401. }
  41402. this.body.emitter.emit('_adjustEdgesForHierarchicalLayout');
  41403. if (doNotEmit === false) {
  41404. this.body.emitter.emit("_dataChanged");
  41405. }
  41406. }
  41407. /**
  41408. * Update existing edges, or create them when not yet existing
  41409. * @param {number[] | string[]} ids
  41410. * @private
  41411. */
  41412. }, {
  41413. key: 'update',
  41414. value: function update(ids) {
  41415. var edges = this.body.edges;
  41416. var edgesData = this.body.data.edges;
  41417. var dataChanged = false;
  41418. for (var i = 0; i < ids.length; i++) {
  41419. var id = ids[i];
  41420. var data = edgesData.get(id);
  41421. var edge = edges[id];
  41422. if (edge !== undefined) {
  41423. // update edge
  41424. edge.disconnect();
  41425. dataChanged = edge.setOptions(data) || dataChanged; // if a support node is added, data can be changed.
  41426. edge.connect();
  41427. } else {
  41428. // create edge
  41429. this.body.edges[id] = this.create(data);
  41430. dataChanged = true;
  41431. }
  41432. }
  41433. if (dataChanged === true) {
  41434. this.body.emitter.emit('_adjustEdgesForHierarchicalLayout');
  41435. this.body.emitter.emit("_dataChanged");
  41436. } else {
  41437. this.body.emitter.emit("_dataUpdated");
  41438. }
  41439. }
  41440. /**
  41441. * Remove existing edges. Non existing ids will be ignored
  41442. * @param {number[] | string[]} ids
  41443. * @param {boolean} [emit=true]
  41444. * @private
  41445. */
  41446. }, {
  41447. key: 'remove',
  41448. value: function remove(ids) {
  41449. var emit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  41450. if (ids.length === 0) return; // early out
  41451. var edges = this.body.edges;
  41452. util.forEach(ids, function(id) {
  41453. var edge = edges[id];
  41454. if (edge !== undefined) {
  41455. edge.remove();
  41456. }
  41457. });
  41458. if (emit) {
  41459. this.body.emitter.emit("_dataChanged");
  41460. }
  41461. }
  41462. /**
  41463. * Refreshes Edge Handler
  41464. */
  41465. }, {
  41466. key: 'refresh',
  41467. value: function refresh() {
  41468. var _this4 = this;
  41469. util.forEach(this.body.edges, function(edge, edgeId) {
  41470. var data = _this4.body.data.edges._data[edgeId];
  41471. if (data !== undefined) {
  41472. edge.setOptions(data);
  41473. }
  41474. });
  41475. }
  41476. /**
  41477. *
  41478. * @param {Object} properties
  41479. * @returns {Edge}
  41480. */
  41481. }, {
  41482. key: 'create',
  41483. value: function create(properties) {
  41484. return new Edge(properties, this.body, this.options, this.defaultOptions);
  41485. }
  41486. /**
  41487. * Reconnect all edges
  41488. * @private
  41489. */
  41490. }, {
  41491. key: 'reconnectEdges',
  41492. value: function reconnectEdges() {
  41493. var id;
  41494. var nodes = this.body.nodes;
  41495. var edges = this.body.edges;
  41496. for (id in nodes) {
  41497. if (nodes.hasOwnProperty(id)) {
  41498. nodes[id].edges = [];
  41499. }
  41500. }
  41501. for (id in edges) {
  41502. if (edges.hasOwnProperty(id)) {
  41503. var edge = edges[id];
  41504. edge.from = null;
  41505. edge.to = null;
  41506. edge.connect();
  41507. }
  41508. }
  41509. }
  41510. /**
  41511. *
  41512. * @param {Edge.id} edgeId
  41513. * @returns {Array}
  41514. */
  41515. }, {
  41516. key: 'getConnectedNodes',
  41517. value: function getConnectedNodes(edgeId) {
  41518. var nodeList = [];
  41519. if (this.body.edges[edgeId] !== undefined) {
  41520. var edge = this.body.edges[edgeId];
  41521. if (edge.fromId !== undefined) {
  41522. nodeList.push(edge.fromId);
  41523. }
  41524. if (edge.toId !== undefined) {
  41525. nodeList.push(edge.toId);
  41526. }
  41527. }
  41528. return nodeList;
  41529. }
  41530. /**
  41531. * There is no direct relation between the nodes and the edges DataSet,
  41532. * so the right place to do call this is in the handler for event `_dataUpdated`.
  41533. */
  41534. }, {
  41535. key: '_updateState',
  41536. value: function _updateState() {
  41537. this._addMissingEdges();
  41538. this._removeInvalidEdges();
  41539. }
  41540. /**
  41541. * Scan for missing nodes and remove corresponding edges, if any.
  41542. * @private
  41543. */
  41544. }, {
  41545. key: '_removeInvalidEdges',
  41546. value: function _removeInvalidEdges() {
  41547. var _this5 = this;
  41548. var edgesToDelete = [];
  41549. util.forEach(this.body.edges, function(edge, id) {
  41550. var toNode = _this5.body.nodes[edge.toId];
  41551. var fromNode = _this5.body.nodes[edge.fromId];
  41552. // Skip clustering edges here, let the Clustering module handle those
  41553. if (toNode !== undefined && toNode.isCluster === true || fromNode !== undefined && fromNode.isCluster === true) {
  41554. return;
  41555. }
  41556. if (toNode === undefined || fromNode === undefined) {
  41557. edgesToDelete.push(id);
  41558. }
  41559. });
  41560. this.remove(edgesToDelete, false);
  41561. }
  41562. /**
  41563. * add all edges from dataset that are not in the cached state
  41564. * @private
  41565. */
  41566. }, {
  41567. key: '_addMissingEdges',
  41568. value: function _addMissingEdges() {
  41569. var edges = this.body.edges;
  41570. var edgesData = this.body.data.edges;
  41571. var addIds = [];
  41572. edgesData.forEach(function(edgeData, edgeId) {
  41573. var edge = edges[edgeId];
  41574. if (edge === undefined) {
  41575. addIds.push(edgeId);
  41576. }
  41577. });
  41578. this.add(addIds, true);
  41579. }
  41580. }]);
  41581. return EdgesHandler;
  41582. }();
  41583. exports['default'] = EdgesHandler;
  41584. /***/
  41585. }),
  41586. /* 215 */
  41587. /***/
  41588. (function(module, exports, __webpack_require__) {
  41589. "use strict";
  41590. Object.defineProperty(exports, "__esModule", {
  41591. value: true
  41592. });
  41593. var _slicedToArray2 = __webpack_require__(30);
  41594. var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
  41595. var _getPrototypeOf = __webpack_require__(3);
  41596. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  41597. var _classCallCheck2 = __webpack_require__(0);
  41598. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  41599. var _createClass2 = __webpack_require__(1);
  41600. var _createClass3 = _interopRequireDefault(_createClass2);
  41601. var _possibleConstructorReturn2 = __webpack_require__(4);
  41602. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  41603. var _inherits2 = __webpack_require__(5);
  41604. var _inherits3 = _interopRequireDefault(_inherits2);
  41605. var _CubicBezierEdgeBase2 = __webpack_require__(216);
  41606. var _CubicBezierEdgeBase3 = _interopRequireDefault(_CubicBezierEdgeBase2);
  41607. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  41608. /**
  41609. * A Cubic Bezier Edge. Bezier curves are used to model smooth gradual
  41610. * curves in paths between nodes.
  41611. *
  41612. * @extends CubicBezierEdgeBase
  41613. */
  41614. var CubicBezierEdge = function(_CubicBezierEdgeBase) {
  41615. (0, _inherits3['default'])(CubicBezierEdge, _CubicBezierEdgeBase);
  41616. /**
  41617. * @param {Object} options
  41618. * @param {Object} body
  41619. * @param {Label} labelModule
  41620. */
  41621. function CubicBezierEdge(options, body, labelModule) {
  41622. (0, _classCallCheck3['default'])(this, CubicBezierEdge);
  41623. return (0, _possibleConstructorReturn3['default'])(this, (CubicBezierEdge.__proto__ || (0, _getPrototypeOf2['default'])(CubicBezierEdge)).call(this, options, body, labelModule));
  41624. }
  41625. /**
  41626. * Draw a line between two nodes
  41627. * @param {CanvasRenderingContext2D} ctx
  41628. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  41629. * @param {Array.<Node>} viaNodes
  41630. * @private
  41631. */
  41632. (0, _createClass3['default'])(CubicBezierEdge, [{
  41633. key: '_line',
  41634. value: function _line(ctx, values, viaNodes) {
  41635. // get the coordinates of the support points.
  41636. var via1 = viaNodes[0];
  41637. var via2 = viaNodes[1];
  41638. this._bezierCurve(ctx, values, via1, via2);
  41639. }
  41640. /**
  41641. *
  41642. * @returns {Array.<{x: number, y: number}>}
  41643. * @private
  41644. */
  41645. }, {
  41646. key: '_getViaCoordinates',
  41647. value: function _getViaCoordinates() {
  41648. var dx = this.from.x - this.to.x;
  41649. var dy = this.from.y - this.to.y;
  41650. var x1 = void 0,
  41651. y1 = void 0,
  41652. x2 = void 0,
  41653. y2 = void 0;
  41654. var roundness = this.options.smooth.roundness;
  41655. // horizontal if x > y or if direction is forced or if direction is horizontal
  41656. if ((Math.abs(dx) > Math.abs(dy) || this.options.smooth.forceDirection === true || this.options.smooth.forceDirection === 'horizontal') && this.options.smooth.forceDirection !== 'vertical') {
  41657. y1 = this.from.y;
  41658. y2 = this.to.y;
  41659. x1 = this.from.x - roundness * dx;
  41660. x2 = this.to.x + roundness * dx;
  41661. } else {
  41662. y1 = this.from.y - roundness * dy;
  41663. y2 = this.to.y + roundness * dy;
  41664. x1 = this.from.x;
  41665. x2 = this.to.x;
  41666. }
  41667. return [{ x: x1, y: y1 }, { x: x2, y: y2 }];
  41668. }
  41669. /**
  41670. *
  41671. * @returns {Array.<{x: number, y: number}>}
  41672. */
  41673. }, {
  41674. key: 'getViaNode',
  41675. value: function getViaNode() {
  41676. return this._getViaCoordinates();
  41677. }
  41678. /**
  41679. *
  41680. * @param {Node} nearNode
  41681. * @param {CanvasRenderingContext2D} ctx
  41682. * @returns {{x: number, y: number, t: number}}
  41683. * @private
  41684. */
  41685. }, {
  41686. key: '_findBorderPosition',
  41687. value: function _findBorderPosition(nearNode, ctx) {
  41688. return this._findBorderPositionBezier(nearNode, ctx);
  41689. }
  41690. /**
  41691. *
  41692. * @param {number} x1
  41693. * @param {number} y1
  41694. * @param {number} x2
  41695. * @param {number} y2
  41696. * @param {number} x3
  41697. * @param {number} y3
  41698. * @param {Node} via1
  41699. * @param {Node} via2
  41700. * @returns {number}
  41701. * @private
  41702. */
  41703. }, {
  41704. key: '_getDistanceToEdge',
  41705. value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
  41706. var _ref = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates(),
  41707. _ref2 = (0, _slicedToArray3['default'])(_ref, 2),
  41708. via1 = _ref2[0],
  41709. via2 = _ref2[1];
  41710. // x3,y3 is the point
  41711. return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via1, via2);
  41712. }
  41713. /**
  41714. * Combined function of pointOnLine and pointOnBezier. This gives the coordinates of a point on the line at a certain percentage of the way
  41715. * @param {number} percentage
  41716. * @param {{x: number, y: number}} [via1=this._getViaCoordinates()[0]]
  41717. * @param {{x: number, y: number}} [via2=this._getViaCoordinates()[1]]
  41718. * @returns {{x: number, y: number}}
  41719. * @private
  41720. */
  41721. }, {
  41722. key: 'getPoint',
  41723. value: function getPoint(percentage) {
  41724. var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates(),
  41725. _ref4 = (0, _slicedToArray3['default'])(_ref3, 2),
  41726. via1 = _ref4[0],
  41727. via2 = _ref4[1];
  41728. var t = percentage;
  41729. var vec = [];
  41730. vec[0] = Math.pow(1 - t, 3);
  41731. vec[1] = 3 * t * Math.pow(1 - t, 2);
  41732. vec[2] = 3 * Math.pow(t, 2) * (1 - t);
  41733. vec[3] = Math.pow(t, 3);
  41734. var x = vec[0] * this.fromPoint.x + vec[1] * via1.x + vec[2] * via2.x + vec[3] * this.toPoint.x;
  41735. var y = vec[0] * this.fromPoint.y + vec[1] * via1.y + vec[2] * via2.y + vec[3] * this.toPoint.y;
  41736. return { x: x, y: y };
  41737. }
  41738. }]);
  41739. return CubicBezierEdge;
  41740. }(_CubicBezierEdgeBase3['default']);
  41741. exports['default'] = CubicBezierEdge;
  41742. /***/
  41743. }),
  41744. /* 216 */
  41745. /***/
  41746. (function(module, exports, __webpack_require__) {
  41747. "use strict";
  41748. Object.defineProperty(exports, "__esModule", {
  41749. value: true
  41750. });
  41751. var _getPrototypeOf = __webpack_require__(3);
  41752. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  41753. var _classCallCheck2 = __webpack_require__(0);
  41754. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  41755. var _createClass2 = __webpack_require__(1);
  41756. var _createClass3 = _interopRequireDefault(_createClass2);
  41757. var _possibleConstructorReturn2 = __webpack_require__(4);
  41758. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  41759. var _inherits2 = __webpack_require__(5);
  41760. var _inherits3 = _interopRequireDefault(_inherits2);
  41761. var _BezierEdgeBase2 = __webpack_require__(75);
  41762. var _BezierEdgeBase3 = _interopRequireDefault(_BezierEdgeBase2);
  41763. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  41764. /**
  41765. * A Base Class for all Cubic Bezier Edges. Bezier curves are used to model
  41766. * smooth gradual curves in paths between nodes.
  41767. *
  41768. * @extends BezierEdgeBase
  41769. */
  41770. var CubicBezierEdgeBase = function(_BezierEdgeBase) {
  41771. (0, _inherits3['default'])(CubicBezierEdgeBase, _BezierEdgeBase);
  41772. /**
  41773. * @param {Object} options
  41774. * @param {Object} body
  41775. * @param {Label} labelModule
  41776. */
  41777. function CubicBezierEdgeBase(options, body, labelModule) {
  41778. (0, _classCallCheck3['default'])(this, CubicBezierEdgeBase);
  41779. return (0, _possibleConstructorReturn3['default'])(this, (CubicBezierEdgeBase.__proto__ || (0, _getPrototypeOf2['default'])(CubicBezierEdgeBase)).call(this, options, body, labelModule));
  41780. }
  41781. /**
  41782. * Calculate the distance between a point (x3,y3) and a line segment from
  41783. * (x1,y1) to (x2,y2).
  41784. * http://stackoverflow.com/questions/849211/shortest-distancae-between-a-point-and-a-line-segment
  41785. * https://en.wikipedia.org/wiki/B%C3%A9zier_curve
  41786. * @param {number} x1 from x
  41787. * @param {number} y1 from y
  41788. * @param {number} x2 to x
  41789. * @param {number} y2 to y
  41790. * @param {number} x3 point to check x
  41791. * @param {number} y3 point to check y
  41792. * @param {Node} via1
  41793. * @param {Node} via2
  41794. * @returns {number}
  41795. * @private
  41796. */
  41797. (0, _createClass3['default'])(CubicBezierEdgeBase, [{
  41798. key: '_getDistanceToBezierEdge',
  41799. value: function _getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, via1, via2) {
  41800. // x3,y3 is the point
  41801. var minDistance = 1e9;
  41802. var distance = void 0;
  41803. var i = void 0,
  41804. t = void 0,
  41805. x = void 0,
  41806. y = void 0;
  41807. var lastX = x1;
  41808. var lastY = y1;
  41809. var vec = [0, 0, 0, 0];
  41810. for (i = 1; i < 10; i++) {
  41811. t = 0.1 * i;
  41812. vec[0] = Math.pow(1 - t, 3);
  41813. vec[1] = 3 * t * Math.pow(1 - t, 2);
  41814. vec[2] = 3 * Math.pow(t, 2) * (1 - t);
  41815. vec[3] = Math.pow(t, 3);
  41816. x = vec[0] * x1 + vec[1] * via1.x + vec[2] * via2.x + vec[3] * x2;
  41817. y = vec[0] * y1 + vec[1] * via1.y + vec[2] * via2.y + vec[3] * y2;
  41818. if (i > 0) {
  41819. distance = this._getDistanceToLine(lastX, lastY, x, y, x3, y3);
  41820. minDistance = distance < minDistance ? distance : minDistance;
  41821. }
  41822. lastX = x;
  41823. lastY = y;
  41824. }
  41825. return minDistance;
  41826. }
  41827. }]);
  41828. return CubicBezierEdgeBase;
  41829. }(_BezierEdgeBase3['default']);
  41830. exports['default'] = CubicBezierEdgeBase;
  41831. /***/
  41832. }),
  41833. /* 217 */
  41834. /***/
  41835. (function(module, exports, __webpack_require__) {
  41836. "use strict";
  41837. Object.defineProperty(exports, "__esModule", {
  41838. value: true
  41839. });
  41840. var _slicedToArray2 = __webpack_require__(30);
  41841. var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
  41842. var _getPrototypeOf = __webpack_require__(3);
  41843. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  41844. var _classCallCheck2 = __webpack_require__(0);
  41845. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  41846. var _createClass2 = __webpack_require__(1);
  41847. var _createClass3 = _interopRequireDefault(_createClass2);
  41848. var _possibleConstructorReturn2 = __webpack_require__(4);
  41849. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  41850. var _inherits2 = __webpack_require__(5);
  41851. var _inherits3 = _interopRequireDefault(_inherits2);
  41852. var _BezierEdgeBase2 = __webpack_require__(75);
  41853. var _BezierEdgeBase3 = _interopRequireDefault(_BezierEdgeBase2);
  41854. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  41855. /**
  41856. * A Dynamic Bezier Edge. Bezier curves are used to model smooth gradual
  41857. * curves in paths between nodes. The Dynamic piece refers to how the curve
  41858. * reacts to physics changes.
  41859. *
  41860. * @extends BezierEdgeBase
  41861. */
  41862. var BezierEdgeDynamic = function(_BezierEdgeBase) {
  41863. (0, _inherits3["default"])(BezierEdgeDynamic, _BezierEdgeBase);
  41864. /**
  41865. * @param {Object} options
  41866. * @param {Object} body
  41867. * @param {Label} labelModule
  41868. */
  41869. function BezierEdgeDynamic(options, body, labelModule) {
  41870. (0, _classCallCheck3["default"])(this, BezierEdgeDynamic);
  41871. // --> this calls the setOptions below
  41872. var _this = (0, _possibleConstructorReturn3["default"])(this, (BezierEdgeDynamic.__proto__ || (0, _getPrototypeOf2["default"])(BezierEdgeDynamic)).call(this, options, body, labelModule));
  41873. //this.via = undefined; // Here for completeness but not allowed to defined before super() is invoked.
  41874. _this._boundFunction = function() {
  41875. _this.positionBezierNode();
  41876. };
  41877. _this.body.emitter.on("_repositionBezierNodes", _this._boundFunction);
  41878. return _this;
  41879. }
  41880. /**
  41881. *
  41882. * @param {Object} options
  41883. */
  41884. (0, _createClass3["default"])(BezierEdgeDynamic, [{
  41885. key: "setOptions",
  41886. value: function setOptions(options) {
  41887. // check if the physics has changed.
  41888. var physicsChange = false;
  41889. if (this.options.physics !== options.physics) {
  41890. physicsChange = true;
  41891. }
  41892. // set the options and the to and from nodes
  41893. this.options = options;
  41894. this.id = this.options.id;
  41895. this.from = this.body.nodes[this.options.from];
  41896. this.to = this.body.nodes[this.options.to];
  41897. // setup the support node and connect
  41898. this.setupSupportNode();
  41899. this.connect();
  41900. // when we change the physics state of the edge, we reposition the support node.
  41901. if (physicsChange === true) {
  41902. this.via.setOptions({ physics: this.options.physics });
  41903. this.positionBezierNode();
  41904. }
  41905. }
  41906. /**
  41907. * Connects an edge to node(s)
  41908. */
  41909. }, {
  41910. key: "connect",
  41911. value: function connect() {
  41912. this.from = this.body.nodes[this.options.from];
  41913. this.to = this.body.nodes[this.options.to];
  41914. if (this.from === undefined || this.to === undefined || this.options.physics === false) {
  41915. this.via.setOptions({ physics: false });
  41916. } else {
  41917. // fix weird behaviour where a self referencing node has physics enabled
  41918. if (this.from.id === this.to.id) {
  41919. this.via.setOptions({ physics: false });
  41920. } else {
  41921. this.via.setOptions({ physics: true });
  41922. }
  41923. }
  41924. }
  41925. /**
  41926. * remove the support nodes
  41927. * @returns {boolean}
  41928. */
  41929. }, {
  41930. key: "cleanup",
  41931. value: function cleanup() {
  41932. this.body.emitter.off("_repositionBezierNodes", this._boundFunction);
  41933. if (this.via !== undefined) {
  41934. delete this.body.nodes[this.via.id];
  41935. this.via = undefined;
  41936. return true;
  41937. }
  41938. return false;
  41939. }
  41940. /**
  41941. * Bezier curves require an anchor point to calculate the smooth flow. These points are nodes. These nodes are invisible but
  41942. * are used for the force calculation.
  41943. *
  41944. * The changed data is not called, if needed, it is returned by the main edge constructor.
  41945. * @private
  41946. */
  41947. }, {
  41948. key: "setupSupportNode",
  41949. value: function setupSupportNode() {
  41950. if (this.via === undefined) {
  41951. var nodeId = "edgeId:" + this.id;
  41952. var node = this.body.functions.createNode({
  41953. id: nodeId,
  41954. shape: 'circle',
  41955. physics: true,
  41956. hidden: true
  41957. });
  41958. this.body.nodes[nodeId] = node;
  41959. this.via = node;
  41960. this.via.parentEdgeId = this.id;
  41961. this.positionBezierNode();
  41962. }
  41963. }
  41964. /**
  41965. * Positions bezier node
  41966. */
  41967. }, {
  41968. key: "positionBezierNode",
  41969. value: function positionBezierNode() {
  41970. if (this.via !== undefined && this.from !== undefined && this.to !== undefined) {
  41971. this.via.x = 0.5 * (this.from.x + this.to.x);
  41972. this.via.y = 0.5 * (this.from.y + this.to.y);
  41973. } else if (this.via !== undefined) {
  41974. this.via.x = 0;
  41975. this.via.y = 0;
  41976. }
  41977. }
  41978. /**
  41979. * Draw a line between two nodes
  41980. * @param {CanvasRenderingContext2D} ctx
  41981. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  41982. * @param {Node} viaNode
  41983. * @private
  41984. */
  41985. }, {
  41986. key: "_line",
  41987. value: function _line(ctx, values, viaNode) {
  41988. this._bezierCurve(ctx, values, viaNode);
  41989. }
  41990. /**
  41991. *
  41992. * @returns {Node|undefined|*|{index, line, column}}
  41993. */
  41994. }, {
  41995. key: "getViaNode",
  41996. value: function getViaNode() {
  41997. return this.via;
  41998. }
  41999. /**
  42000. * Combined function of pointOnLine and pointOnBezier. This gives the coordinates of a point on the line at a certain percentage of the way
  42001. *
  42002. * @param {number} percentage
  42003. * @param {Node} viaNode
  42004. * @returns {{x: number, y: number}}
  42005. * @private
  42006. */
  42007. }, {
  42008. key: "getPoint",
  42009. value: function getPoint(percentage) {
  42010. var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.via;
  42011. var t = percentage;
  42012. var x = void 0,
  42013. y = void 0;
  42014. if (this.from === this.to) {
  42015. var _getCircleData = this._getCircleData(this.from),
  42016. _getCircleData2 = (0, _slicedToArray3["default"])(_getCircleData, 3),
  42017. cx = _getCircleData2[0],
  42018. cy = _getCircleData2[1],
  42019. cr = _getCircleData2[2];
  42020. var a = 2 * Math.PI * (1 - t);
  42021. x = cx + cr * Math.sin(a);
  42022. y = cy + cr - cr * (1 - Math.cos(a));
  42023. } else {
  42024. x = Math.pow(1 - t, 2) * this.fromPoint.x + 2 * t * (1 - t) * viaNode.x + Math.pow(t, 2) * this.toPoint.x;
  42025. y = Math.pow(1 - t, 2) * this.fromPoint.y + 2 * t * (1 - t) * viaNode.y + Math.pow(t, 2) * this.toPoint.y;
  42026. }
  42027. return { x: x, y: y };
  42028. }
  42029. /**
  42030. *
  42031. * @param {Node} nearNode
  42032. * @param {CanvasRenderingContext2D} ctx
  42033. * @returns {*}
  42034. * @private
  42035. */
  42036. }, {
  42037. key: "_findBorderPosition",
  42038. value: function _findBorderPosition(nearNode, ctx) {
  42039. return this._findBorderPositionBezier(nearNode, ctx, this.via);
  42040. }
  42041. /**
  42042. *
  42043. * @param {number} x1
  42044. * @param {number} y1
  42045. * @param {number} x2
  42046. * @param {number} y2
  42047. * @param {number} x3
  42048. * @param {number} y3
  42049. * @returns {number}
  42050. * @private
  42051. */
  42052. }, {
  42053. key: "_getDistanceToEdge",
  42054. value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
  42055. // x3,y3 is the point
  42056. return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, this.via);
  42057. }
  42058. }]);
  42059. return BezierEdgeDynamic;
  42060. }(_BezierEdgeBase3["default"]);
  42061. exports["default"] = BezierEdgeDynamic;
  42062. /***/
  42063. }),
  42064. /* 218 */
  42065. /***/
  42066. (function(module, exports, __webpack_require__) {
  42067. "use strict";
  42068. Object.defineProperty(exports, "__esModule", {
  42069. value: true
  42070. });
  42071. var _getPrototypeOf = __webpack_require__(3);
  42072. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  42073. var _classCallCheck2 = __webpack_require__(0);
  42074. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  42075. var _createClass2 = __webpack_require__(1);
  42076. var _createClass3 = _interopRequireDefault(_createClass2);
  42077. var _possibleConstructorReturn2 = __webpack_require__(4);
  42078. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  42079. var _inherits2 = __webpack_require__(5);
  42080. var _inherits3 = _interopRequireDefault(_inherits2);
  42081. var _BezierEdgeBase2 = __webpack_require__(75);
  42082. var _BezierEdgeBase3 = _interopRequireDefault(_BezierEdgeBase2);
  42083. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  42084. /**
  42085. * A Static Bezier Edge. Bezier curves are used to model smooth gradual
  42086. * curves in paths between nodes.
  42087. *
  42088. * @extends BezierEdgeBase
  42089. */
  42090. var BezierEdgeStatic = function(_BezierEdgeBase) {
  42091. (0, _inherits3['default'])(BezierEdgeStatic, _BezierEdgeBase);
  42092. /**
  42093. * @param {Object} options
  42094. * @param {Object} body
  42095. * @param {Label} labelModule
  42096. */
  42097. function BezierEdgeStatic(options, body, labelModule) {
  42098. (0, _classCallCheck3['default'])(this, BezierEdgeStatic);
  42099. return (0, _possibleConstructorReturn3['default'])(this, (BezierEdgeStatic.__proto__ || (0, _getPrototypeOf2['default'])(BezierEdgeStatic)).call(this, options, body, labelModule));
  42100. }
  42101. /**
  42102. * Draw a line between two nodes
  42103. * @param {CanvasRenderingContext2D} ctx
  42104. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  42105. * @param {Node} viaNode
  42106. * @private
  42107. */
  42108. (0, _createClass3['default'])(BezierEdgeStatic, [{
  42109. key: '_line',
  42110. value: function _line(ctx, values, viaNode) {
  42111. this._bezierCurve(ctx, values, viaNode);
  42112. }
  42113. /**
  42114. *
  42115. * @returns {Array.<{x: number, y: number}>}
  42116. */
  42117. }, {
  42118. key: 'getViaNode',
  42119. value: function getViaNode() {
  42120. return this._getViaCoordinates();
  42121. }
  42122. /**
  42123. * We do not use the to and fromPoints here to make the via nodes the same as edges without arrows.
  42124. * @returns {{x: undefined, y: undefined}}
  42125. * @private
  42126. */
  42127. }, {
  42128. key: '_getViaCoordinates',
  42129. value: function _getViaCoordinates() {
  42130. // Assumption: x/y coordinates in from/to always defined
  42131. var xVia = undefined;
  42132. var yVia = undefined;
  42133. var factor = this.options.smooth.roundness;
  42134. var type = this.options.smooth.type;
  42135. var dx = Math.abs(this.from.x - this.to.x);
  42136. var dy = Math.abs(this.from.y - this.to.y);
  42137. if (type === 'discrete' || type === 'diagonalCross') {
  42138. var stepX = void 0;
  42139. var stepY = void 0;
  42140. if (dx <= dy) {
  42141. stepX = stepY = factor * dy;
  42142. } else {
  42143. stepX = stepY = factor * dx;
  42144. }
  42145. if (this.from.x > this.to.x) stepX = -stepX;
  42146. if (this.from.y >= this.to.y) stepY = -stepY;
  42147. xVia = this.from.x + stepX;
  42148. yVia = this.from.y + stepY;
  42149. if (type === "discrete") {
  42150. if (dx <= dy) {
  42151. xVia = dx < factor * dy ? this.from.x : xVia;
  42152. } else {
  42153. yVia = dy < factor * dx ? this.from.y : yVia;
  42154. }
  42155. }
  42156. } else if (type === "straightCross") {
  42157. var _stepX = (1 - factor) * dx;
  42158. var _stepY = (1 - factor) * dy;
  42159. if (dx <= dy) {
  42160. // up - down
  42161. _stepX = 0;
  42162. if (this.from.y < this.to.y) _stepY = -_stepY;
  42163. } else {
  42164. // left - right
  42165. if (this.from.x < this.to.x) _stepX = -_stepX;
  42166. _stepY = 0;
  42167. }
  42168. xVia = this.to.x + _stepX;
  42169. yVia = this.to.y + _stepY;
  42170. } else if (type === 'horizontal') {
  42171. var _stepX2 = (1 - factor) * dx;
  42172. if (this.from.x < this.to.x) _stepX2 = -_stepX2;
  42173. xVia = this.to.x + _stepX2;
  42174. yVia = this.from.y;
  42175. } else if (type === 'vertical') {
  42176. var _stepY2 = (1 - factor) * dy;
  42177. if (this.from.y < this.to.y) _stepY2 = -_stepY2;
  42178. xVia = this.from.x;
  42179. yVia = this.to.y + _stepY2;
  42180. } else if (type === 'curvedCW') {
  42181. dx = this.to.x - this.from.x;
  42182. dy = this.from.y - this.to.y;
  42183. var radius = Math.sqrt(dx * dx + dy * dy);
  42184. var pi = Math.PI;
  42185. var originalAngle = Math.atan2(dy, dx);
  42186. var myAngle = (originalAngle + (factor * 0.5 + 0.5) * pi) % (2 * pi);
  42187. xVia = this.from.x + (factor * 0.5 + 0.5) * radius * Math.sin(myAngle);
  42188. yVia = this.from.y + (factor * 0.5 + 0.5) * radius * Math.cos(myAngle);
  42189. } else if (type === 'curvedCCW') {
  42190. dx = this.to.x - this.from.x;
  42191. dy = this.from.y - this.to.y;
  42192. var _radius = Math.sqrt(dx * dx + dy * dy);
  42193. var _pi = Math.PI;
  42194. var _originalAngle = Math.atan2(dy, dx);
  42195. var _myAngle = (_originalAngle + (-factor * 0.5 + 0.5) * _pi) % (2 * _pi);
  42196. xVia = this.from.x + (factor * 0.5 + 0.5) * _radius * Math.sin(_myAngle);
  42197. yVia = this.from.y + (factor * 0.5 + 0.5) * _radius * Math.cos(_myAngle);
  42198. } else {
  42199. // continuous
  42200. var _stepX3 = void 0;
  42201. var _stepY3 = void 0;
  42202. if (dx <= dy) {
  42203. _stepX3 = _stepY3 = factor * dy;
  42204. } else {
  42205. _stepX3 = _stepY3 = factor * dx;
  42206. }
  42207. if (this.from.x > this.to.x) _stepX3 = -_stepX3;
  42208. if (this.from.y >= this.to.y) _stepY3 = -_stepY3;
  42209. xVia = this.from.x + _stepX3;
  42210. yVia = this.from.y + _stepY3;
  42211. if (dx <= dy) {
  42212. if (this.from.x <= this.to.x) {
  42213. xVia = this.to.x < xVia ? this.to.x : xVia;
  42214. } else {
  42215. xVia = this.to.x > xVia ? this.to.x : xVia;
  42216. }
  42217. } else {
  42218. if (this.from.y >= this.to.y) {
  42219. yVia = this.to.y > yVia ? this.to.y : yVia;
  42220. } else {
  42221. yVia = this.to.y < yVia ? this.to.y : yVia;
  42222. }
  42223. }
  42224. }
  42225. return { x: xVia, y: yVia };
  42226. }
  42227. /**
  42228. *
  42229. * @param {Node} nearNode
  42230. * @param {CanvasRenderingContext2D} ctx
  42231. * @param {Object} options
  42232. * @returns {*}
  42233. * @private
  42234. */
  42235. }, {
  42236. key: '_findBorderPosition',
  42237. value: function _findBorderPosition(nearNode, ctx) {
  42238. var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  42239. return this._findBorderPositionBezier(nearNode, ctx, options.via);
  42240. }
  42241. /**
  42242. *
  42243. * @param {number} x1
  42244. * @param {number} y1
  42245. * @param {number} x2
  42246. * @param {number} y2
  42247. * @param {number} x3
  42248. * @param {number} y3
  42249. * @param {Node} viaNode
  42250. * @returns {number}
  42251. * @private
  42252. */
  42253. }, {
  42254. key: '_getDistanceToEdge',
  42255. value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
  42256. var viaNode = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : this._getViaCoordinates();
  42257. // x3,y3 is the point
  42258. return this._getDistanceToBezierEdge(x1, y1, x2, y2, x3, y3, viaNode);
  42259. }
  42260. /**
  42261. * Combined function of pointOnLine and pointOnBezier. This gives the coordinates of a point on the line at a certain percentage of the way
  42262. * @param {number} percentage
  42263. * @param {Node} viaNode
  42264. * @returns {{x: number, y: number}}
  42265. * @private
  42266. */
  42267. }, {
  42268. key: 'getPoint',
  42269. value: function getPoint(percentage) {
  42270. var viaNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this._getViaCoordinates();
  42271. var t = percentage;
  42272. var x = Math.pow(1 - t, 2) * this.fromPoint.x + 2 * t * (1 - t) * viaNode.x + Math.pow(t, 2) * this.toPoint.x;
  42273. var y = Math.pow(1 - t, 2) * this.fromPoint.y + 2 * t * (1 - t) * viaNode.y + Math.pow(t, 2) * this.toPoint.y;
  42274. return { x: x, y: y };
  42275. }
  42276. }]);
  42277. return BezierEdgeStatic;
  42278. }(_BezierEdgeBase3['default']);
  42279. exports['default'] = BezierEdgeStatic;
  42280. /***/
  42281. }),
  42282. /* 219 */
  42283. /***/
  42284. (function(module, exports, __webpack_require__) {
  42285. "use strict";
  42286. Object.defineProperty(exports, "__esModule", {
  42287. value: true
  42288. });
  42289. var _getPrototypeOf = __webpack_require__(3);
  42290. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  42291. var _classCallCheck2 = __webpack_require__(0);
  42292. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  42293. var _createClass2 = __webpack_require__(1);
  42294. var _createClass3 = _interopRequireDefault(_createClass2);
  42295. var _possibleConstructorReturn2 = __webpack_require__(4);
  42296. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  42297. var _inherits2 = __webpack_require__(5);
  42298. var _inherits3 = _interopRequireDefault(_inherits2);
  42299. var _EdgeBase2 = __webpack_require__(118);
  42300. var _EdgeBase3 = _interopRequireDefault(_EdgeBase2);
  42301. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  42302. /**
  42303. * A Straight Edge.
  42304. *
  42305. * @extends EdgeBase
  42306. */
  42307. var StraightEdge = function(_EdgeBase) {
  42308. (0, _inherits3['default'])(StraightEdge, _EdgeBase);
  42309. /**
  42310. * @param {Object} options
  42311. * @param {Object} body
  42312. * @param {Label} labelModule
  42313. */
  42314. function StraightEdge(options, body, labelModule) {
  42315. (0, _classCallCheck3['default'])(this, StraightEdge);
  42316. return (0, _possibleConstructorReturn3['default'])(this, (StraightEdge.__proto__ || (0, _getPrototypeOf2['default'])(StraightEdge)).call(this, options, body, labelModule));
  42317. }
  42318. /**
  42319. * Draw a line between two nodes
  42320. * @param {CanvasRenderingContext2D} ctx
  42321. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  42322. * @private
  42323. */
  42324. (0, _createClass3['default'])(StraightEdge, [{
  42325. key: '_line',
  42326. value: function _line(ctx, values) {
  42327. // draw a straight line
  42328. ctx.beginPath();
  42329. ctx.moveTo(this.fromPoint.x, this.fromPoint.y);
  42330. ctx.lineTo(this.toPoint.x, this.toPoint.y);
  42331. // draw shadow if enabled
  42332. this.enableShadow(ctx, values);
  42333. ctx.stroke();
  42334. this.disableShadow(ctx, values);
  42335. }
  42336. /**
  42337. *
  42338. * @returns {undefined}
  42339. */
  42340. }, {
  42341. key: 'getViaNode',
  42342. value: function getViaNode() {
  42343. return undefined;
  42344. }
  42345. /**
  42346. * Combined function of pointOnLine and pointOnBezier. This gives the coordinates of a point on the line at a certain percentage of the way
  42347. *
  42348. * @param {number} percentage
  42349. * @returns {{x: number, y: number}}
  42350. * @private
  42351. */
  42352. }, {
  42353. key: 'getPoint',
  42354. value: function getPoint(percentage) {
  42355. return {
  42356. x: (1 - percentage) * this.fromPoint.x + percentage * this.toPoint.x,
  42357. y: (1 - percentage) * this.fromPoint.y + percentage * this.toPoint.y
  42358. };
  42359. }
  42360. /**
  42361. *
  42362. * @param {Node} nearNode
  42363. * @param {CanvasRenderingContext2D} ctx
  42364. * @returns {{x: number, y: number}}
  42365. * @private
  42366. */
  42367. }, {
  42368. key: '_findBorderPosition',
  42369. value: function _findBorderPosition(nearNode, ctx) {
  42370. var node1 = this.to;
  42371. var node2 = this.from;
  42372. if (nearNode.id === this.from.id) {
  42373. node1 = this.from;
  42374. node2 = this.to;
  42375. }
  42376. var angle = Math.atan2(node1.y - node2.y, node1.x - node2.x);
  42377. var dx = node1.x - node2.x;
  42378. var dy = node1.y - node2.y;
  42379. var edgeSegmentLength = Math.sqrt(dx * dx + dy * dy);
  42380. var toBorderDist = nearNode.distanceToBorder(ctx, angle);
  42381. var toBorderPoint = (edgeSegmentLength - toBorderDist) / edgeSegmentLength;
  42382. var borderPos = {};
  42383. borderPos.x = (1 - toBorderPoint) * node2.x + toBorderPoint * node1.x;
  42384. borderPos.y = (1 - toBorderPoint) * node2.y + toBorderPoint * node1.y;
  42385. return borderPos;
  42386. }
  42387. /**
  42388. *
  42389. * @param {number} x1
  42390. * @param {number} y1
  42391. * @param {number} x2
  42392. * @param {number} y2
  42393. * @param {number} x3
  42394. * @param {number} y3
  42395. * @returns {number}
  42396. * @private
  42397. */
  42398. }, {
  42399. key: '_getDistanceToEdge',
  42400. value: function _getDistanceToEdge(x1, y1, x2, y2, x3, y3) {
  42401. // x3,y3 is the point
  42402. return this._getDistanceToLine(x1, y1, x2, y2, x3, y3);
  42403. }
  42404. }]);
  42405. return StraightEdge;
  42406. }(_EdgeBase3['default']);
  42407. exports['default'] = StraightEdge;
  42408. /***/
  42409. }),
  42410. /* 220 */
  42411. /***/
  42412. (function(module, exports, __webpack_require__) {
  42413. "use strict";
  42414. Object.defineProperty(exports, "__esModule", {
  42415. value: true
  42416. });
  42417. var _keys = __webpack_require__(8);
  42418. var _keys2 = _interopRequireDefault(_keys);
  42419. var _classCallCheck2 = __webpack_require__(0);
  42420. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  42421. var _createClass2 = __webpack_require__(1);
  42422. var _createClass3 = _interopRequireDefault(_createClass2);
  42423. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  42424. var BarnesHutSolver = __webpack_require__(120)['default'];
  42425. var Repulsion = __webpack_require__(221)['default'];
  42426. var HierarchicalRepulsion = __webpack_require__(222)['default'];
  42427. var SpringSolver = __webpack_require__(223)['default'];
  42428. var HierarchicalSpringSolver = __webpack_require__(224)['default'];
  42429. var CentralGravitySolver = __webpack_require__(121)['default'];
  42430. var ForceAtlas2BasedRepulsionSolver = __webpack_require__(225)['default'];
  42431. var ForceAtlas2BasedCentralGravitySolver = __webpack_require__(226)['default'];
  42432. var util = __webpack_require__(2);
  42433. var EndPoints = __webpack_require__(119)['default']; // for debugging with _drawForces()
  42434. /**
  42435. * The physics engine
  42436. */
  42437. var PhysicsEngine = function() {
  42438. /**
  42439. * @param {Object} body
  42440. */
  42441. function PhysicsEngine(body) {
  42442. (0, _classCallCheck3['default'])(this, PhysicsEngine);
  42443. this.body = body;
  42444. this.physicsBody = { physicsNodeIndices: [], physicsEdgeIndices: [], forces: {}, velocities: {} };
  42445. this.physicsEnabled = true;
  42446. this.simulationInterval = 1000 / 60;
  42447. this.requiresTimeout = true;
  42448. this.previousStates = {};
  42449. this.referenceState = {};
  42450. this.freezeCache = {};
  42451. this.renderTimer = undefined;
  42452. // parameters for the adaptive timestep
  42453. this.adaptiveTimestep = false;
  42454. this.adaptiveTimestepEnabled = false;
  42455. this.adaptiveCounter = 0;
  42456. this.adaptiveInterval = 3;
  42457. this.stabilized = false;
  42458. this.startedStabilization = false;
  42459. this.stabilizationIterations = 0;
  42460. this.ready = false; // will be set to true if the stabilize
  42461. // default options
  42462. this.options = {};
  42463. this.defaultOptions = {
  42464. enabled: true,
  42465. barnesHut: {
  42466. theta: 0.5,
  42467. gravitationalConstant: -2000,
  42468. centralGravity: 0.3,
  42469. springLength: 95,
  42470. springConstant: 0.04,
  42471. damping: 0.09,
  42472. avoidOverlap: 0
  42473. },
  42474. forceAtlas2Based: {
  42475. theta: 0.5,
  42476. gravitationalConstant: -50,
  42477. centralGravity: 0.01,
  42478. springConstant: 0.08,
  42479. springLength: 100,
  42480. damping: 0.4,
  42481. avoidOverlap: 0
  42482. },
  42483. repulsion: {
  42484. centralGravity: 0.2,
  42485. springLength: 200,
  42486. springConstant: 0.05,
  42487. nodeDistance: 100,
  42488. damping: 0.09,
  42489. avoidOverlap: 0
  42490. },
  42491. hierarchicalRepulsion: {
  42492. centralGravity: 0.0,
  42493. springLength: 100,
  42494. springConstant: 0.01,
  42495. nodeDistance: 120,
  42496. damping: 0.09
  42497. },
  42498. maxVelocity: 50,
  42499. minVelocity: 0.75, // px/s
  42500. solver: 'barnesHut',
  42501. stabilization: {
  42502. enabled: true,
  42503. iterations: 1000, // maximum number of iteration to stabilize
  42504. updateInterval: 50,
  42505. onlyDynamicEdges: false,
  42506. fit: true
  42507. },
  42508. timestep: 0.5,
  42509. adaptiveTimestep: true
  42510. };
  42511. util.extend(this.options, this.defaultOptions);
  42512. this.timestep = 0.5;
  42513. this.layoutFailed = false;
  42514. this.bindEventListeners();
  42515. }
  42516. /**
  42517. * Binds event listeners
  42518. */
  42519. (0, _createClass3['default'])(PhysicsEngine, [{
  42520. key: 'bindEventListeners',
  42521. value: function bindEventListeners() {
  42522. var _this = this;
  42523. this.body.emitter.on('initPhysics', function() {
  42524. _this.initPhysics();
  42525. });
  42526. this.body.emitter.on('_layoutFailed', function() {
  42527. _this.layoutFailed = true;
  42528. });
  42529. this.body.emitter.on('resetPhysics', function() {
  42530. _this.stopSimulation();
  42531. _this.ready = false;
  42532. });
  42533. this.body.emitter.on('disablePhysics', function() {
  42534. _this.physicsEnabled = false;
  42535. _this.stopSimulation();
  42536. });
  42537. this.body.emitter.on('restorePhysics', function() {
  42538. _this.setOptions(_this.options);
  42539. if (_this.ready === true) {
  42540. _this.startSimulation();
  42541. }
  42542. });
  42543. this.body.emitter.on('startSimulation', function() {
  42544. if (_this.ready === true) {
  42545. _this.startSimulation();
  42546. }
  42547. });
  42548. this.body.emitter.on('stopSimulation', function() {
  42549. _this.stopSimulation();
  42550. });
  42551. this.body.emitter.on('destroy', function() {
  42552. _this.stopSimulation(false);
  42553. _this.body.emitter.off();
  42554. });
  42555. this.body.emitter.on("_dataChanged", function() {
  42556. // Nodes and/or edges have been added or removed, update shortcut lists.
  42557. _this.updatePhysicsData();
  42558. });
  42559. // debug: show forces
  42560. // this.body.emitter.on("afterDrawing", (ctx) => {this._drawForces(ctx);});
  42561. }
  42562. /**
  42563. * set the physics options
  42564. * @param {Object} options
  42565. */
  42566. }, {
  42567. key: 'setOptions',
  42568. value: function setOptions(options) {
  42569. if (options !== undefined) {
  42570. if (options === false) {
  42571. this.options.enabled = false;
  42572. this.physicsEnabled = false;
  42573. this.stopSimulation();
  42574. } else if (options === true) {
  42575. this.options.enabled = true;
  42576. this.physicsEnabled = true;
  42577. this.startSimulation();
  42578. } else {
  42579. this.physicsEnabled = true;
  42580. util.selectiveNotDeepExtend(['stabilization'], this.options, options);
  42581. util.mergeOptions(this.options, options, 'stabilization');
  42582. if (options.enabled === undefined) {
  42583. this.options.enabled = true;
  42584. }
  42585. if (this.options.enabled === false) {
  42586. this.physicsEnabled = false;
  42587. this.stopSimulation();
  42588. }
  42589. // set the timestep
  42590. this.timestep = this.options.timestep;
  42591. }
  42592. }
  42593. this.init();
  42594. }
  42595. /**
  42596. * configure the engine.
  42597. */
  42598. }, {
  42599. key: 'init',
  42600. value: function init() {
  42601. var options;
  42602. if (this.options.solver === 'forceAtlas2Based') {
  42603. options = this.options.forceAtlas2Based;
  42604. this.nodesSolver = new ForceAtlas2BasedRepulsionSolver(this.body, this.physicsBody, options);
  42605. this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
  42606. this.gravitySolver = new ForceAtlas2BasedCentralGravitySolver(this.body, this.physicsBody, options);
  42607. } else if (this.options.solver === 'repulsion') {
  42608. options = this.options.repulsion;
  42609. this.nodesSolver = new Repulsion(this.body, this.physicsBody, options);
  42610. this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
  42611. this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
  42612. } else if (this.options.solver === 'hierarchicalRepulsion') {
  42613. options = this.options.hierarchicalRepulsion;
  42614. this.nodesSolver = new HierarchicalRepulsion(this.body, this.physicsBody, options);
  42615. this.edgesSolver = new HierarchicalSpringSolver(this.body, this.physicsBody, options);
  42616. this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
  42617. } else {
  42618. // barnesHut
  42619. options = this.options.barnesHut;
  42620. this.nodesSolver = new BarnesHutSolver(this.body, this.physicsBody, options);
  42621. this.edgesSolver = new SpringSolver(this.body, this.physicsBody, options);
  42622. this.gravitySolver = new CentralGravitySolver(this.body, this.physicsBody, options);
  42623. }
  42624. this.modelOptions = options;
  42625. }
  42626. /**
  42627. * initialize the engine
  42628. */
  42629. }, {
  42630. key: 'initPhysics',
  42631. value: function initPhysics() {
  42632. if (this.physicsEnabled === true && this.options.enabled === true) {
  42633. if (this.options.stabilization.enabled === true) {
  42634. this.stabilize();
  42635. } else {
  42636. this.stabilized = false;
  42637. this.ready = true;
  42638. this.body.emitter.emit('fit', {}, this.layoutFailed); // if the layout failed, we use the approximation for the zoom
  42639. this.startSimulation();
  42640. }
  42641. } else {
  42642. this.ready = true;
  42643. this.body.emitter.emit('fit');
  42644. }
  42645. }
  42646. /**
  42647. * Start the simulation
  42648. */
  42649. }, {
  42650. key: 'startSimulation',
  42651. value: function startSimulation() {
  42652. if (this.physicsEnabled === true && this.options.enabled === true) {
  42653. this.stabilized = false;
  42654. // when visible, adaptivity is disabled.
  42655. this.adaptiveTimestep = false;
  42656. // this sets the width of all nodes initially which could be required for the avoidOverlap
  42657. this.body.emitter.emit("_resizeNodes");
  42658. if (this.viewFunction === undefined) {
  42659. this.viewFunction = this.simulationStep.bind(this);
  42660. this.body.emitter.on('initRedraw', this.viewFunction);
  42661. this.body.emitter.emit('_startRendering');
  42662. }
  42663. } else {
  42664. this.body.emitter.emit('_redraw');
  42665. }
  42666. }
  42667. /**
  42668. * Stop the simulation, force stabilization.
  42669. * @param {boolean} [emit=true]
  42670. */
  42671. }, {
  42672. key: 'stopSimulation',
  42673. value: function stopSimulation() {
  42674. var emit = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
  42675. this.stabilized = true;
  42676. if (emit === true) {
  42677. this._emitStabilized();
  42678. }
  42679. if (this.viewFunction !== undefined) {
  42680. this.body.emitter.off('initRedraw', this.viewFunction);
  42681. this.viewFunction = undefined;
  42682. if (emit === true) {
  42683. this.body.emitter.emit('_stopRendering');
  42684. }
  42685. }
  42686. }
  42687. /**
  42688. * The viewFunction inserts this step into each render loop. It calls the physics tick and handles the cleanup at stabilized.
  42689. *
  42690. */
  42691. }, {
  42692. key: 'simulationStep',
  42693. value: function simulationStep() {
  42694. // check if the physics have settled
  42695. var startTime = Date.now();
  42696. this.physicsTick();
  42697. var physicsTime = Date.now() - startTime;
  42698. // run double speed if it is a little graph
  42699. if ((physicsTime < 0.4 * this.simulationInterval || this.runDoubleSpeed === true) && this.stabilized === false) {
  42700. this.physicsTick();
  42701. // this makes sure there is no jitter. The decision is taken once to run it at double speed.
  42702. this.runDoubleSpeed = true;
  42703. }
  42704. if (this.stabilized === true) {
  42705. this.stopSimulation();
  42706. }
  42707. }
  42708. /**
  42709. * trigger the stabilized event.
  42710. *
  42711. * @param {number} [amountOfIterations=this.stabilizationIterations]
  42712. * @private
  42713. */
  42714. }, {
  42715. key: '_emitStabilized',
  42716. value: function _emitStabilized() {
  42717. var _this2 = this;
  42718. var amountOfIterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.stabilizationIterations;
  42719. if (this.stabilizationIterations > 1 || this.startedStabilization === true) {
  42720. setTimeout(function() {
  42721. _this2.body.emitter.emit('stabilized', { iterations: amountOfIterations });
  42722. _this2.startedStabilization = false;
  42723. _this2.stabilizationIterations = 0;
  42724. }, 0);
  42725. }
  42726. }
  42727. /**
  42728. * Calculate the forces for one physics iteration and move the nodes.
  42729. * @private
  42730. */
  42731. }, {
  42732. key: 'physicsStep',
  42733. value: function physicsStep() {
  42734. this.gravitySolver.solve();
  42735. this.nodesSolver.solve();
  42736. this.edgesSolver.solve();
  42737. this.moveNodes();
  42738. }
  42739. /**
  42740. * Make dynamic adjustments to the timestep, based on current state.
  42741. *
  42742. * Helper function for physicsTick().
  42743. * @private
  42744. */
  42745. }, {
  42746. key: 'adjustTimeStep',
  42747. value: function adjustTimeStep() {
  42748. var factor = 1.2; // Factor for increasing the timestep on success.
  42749. // we compare the two steps. if it is acceptable we double the step.
  42750. if (this._evaluateStepQuality() === true) {
  42751. this.timestep = factor * this.timestep;
  42752. } else {
  42753. // if not, we decrease the step to a minimum of the options timestep.
  42754. // if the decreased timestep is smaller than the options step, we do not reset the counter
  42755. // we assume that the options timestep is stable enough.
  42756. if (this.timestep / factor < this.options.timestep) {
  42757. this.timestep = this.options.timestep;
  42758. } else {
  42759. // if the timestep was larger than 2 times the option one we check the adaptivity again to ensure
  42760. // that large instabilities do not form.
  42761. this.adaptiveCounter = -1; // check again next iteration
  42762. this.timestep = Math.max(this.options.timestep, this.timestep / factor);
  42763. }
  42764. }
  42765. }
  42766. /**
  42767. * A single simulation step (or 'tick') in the physics simulation
  42768. *
  42769. * @private
  42770. */
  42771. }, {
  42772. key: 'physicsTick',
  42773. value: function physicsTick() {
  42774. this._startStabilizing(); // this ensures that there is no start event when the network is already stable.
  42775. if (this.stabilized === true) return;
  42776. // adaptivity means the timestep adapts to the situation, only applicable for stabilization
  42777. if (this.adaptiveTimestep === true && this.adaptiveTimestepEnabled === true) {
  42778. // timestep remains stable for "interval" iterations.
  42779. var doAdaptive = this.adaptiveCounter % this.adaptiveInterval === 0;
  42780. if (doAdaptive) {
  42781. // first the big step and revert.
  42782. this.timestep = 2 * this.timestep;
  42783. this.physicsStep();
  42784. this.revert(); // saves the reference state
  42785. // now the normal step. Since this is the last step, it is the more stable one and we will take this.
  42786. this.timestep = 0.5 * this.timestep;
  42787. // since it's half the step, we do it twice.
  42788. this.physicsStep();
  42789. this.physicsStep();
  42790. this.adjustTimeStep();
  42791. } else {
  42792. this.physicsStep(); // normal step, keeping timestep constant
  42793. }
  42794. this.adaptiveCounter += 1;
  42795. } else {
  42796. // case for the static timestep, we reset it to the one in options and take a normal step.
  42797. this.timestep = this.options.timestep;
  42798. this.physicsStep();
  42799. }
  42800. if (this.stabilized === true) this.revert();
  42801. this.stabilizationIterations++;
  42802. }
  42803. /**
  42804. * Nodes and edges can have the physics toggles on or off. A collection of indices is created here so we can skip the check all the time.
  42805. *
  42806. * @private
  42807. */
  42808. }, {
  42809. key: 'updatePhysicsData',
  42810. value: function updatePhysicsData() {
  42811. this.physicsBody.forces = {};
  42812. this.physicsBody.physicsNodeIndices = [];
  42813. this.physicsBody.physicsEdgeIndices = [];
  42814. var nodes = this.body.nodes;
  42815. var edges = this.body.edges;
  42816. // get node indices for physics
  42817. for (var nodeId in nodes) {
  42818. if (nodes.hasOwnProperty(nodeId)) {
  42819. if (nodes[nodeId].options.physics === true) {
  42820. this.physicsBody.physicsNodeIndices.push(nodes[nodeId].id);
  42821. }
  42822. }
  42823. }
  42824. // get edge indices for physics
  42825. for (var edgeId in edges) {
  42826. if (edges.hasOwnProperty(edgeId)) {
  42827. if (edges[edgeId].options.physics === true) {
  42828. this.physicsBody.physicsEdgeIndices.push(edges[edgeId].id);
  42829. }
  42830. }
  42831. }
  42832. // get the velocity and the forces vector
  42833. for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
  42834. var _nodeId = this.physicsBody.physicsNodeIndices[i];
  42835. this.physicsBody.forces[_nodeId] = { x: 0, y: 0 };
  42836. // forces can be reset because they are recalculated. Velocities have to persist.
  42837. if (this.physicsBody.velocities[_nodeId] === undefined) {
  42838. this.physicsBody.velocities[_nodeId] = { x: 0, y: 0 };
  42839. }
  42840. }
  42841. // clean deleted nodes from the velocity vector
  42842. for (var _nodeId2 in this.physicsBody.velocities) {
  42843. if (nodes[_nodeId2] === undefined) {
  42844. delete this.physicsBody.velocities[_nodeId2];
  42845. }
  42846. }
  42847. }
  42848. /**
  42849. * Revert the simulation one step. This is done so after stabilization, every new start of the simulation will also say stabilized.
  42850. */
  42851. }, {
  42852. key: 'revert',
  42853. value: function revert() {
  42854. var nodeIds = (0, _keys2['default'])(this.previousStates);
  42855. var nodes = this.body.nodes;
  42856. var velocities = this.physicsBody.velocities;
  42857. this.referenceState = {};
  42858. for (var i = 0; i < nodeIds.length; i++) {
  42859. var nodeId = nodeIds[i];
  42860. if (nodes[nodeId] !== undefined) {
  42861. if (nodes[nodeId].options.physics === true) {
  42862. this.referenceState[nodeId] = {
  42863. positions: { x: nodes[nodeId].x, y: nodes[nodeId].y }
  42864. };
  42865. velocities[nodeId].x = this.previousStates[nodeId].vx;
  42866. velocities[nodeId].y = this.previousStates[nodeId].vy;
  42867. nodes[nodeId].x = this.previousStates[nodeId].x;
  42868. nodes[nodeId].y = this.previousStates[nodeId].y;
  42869. }
  42870. } else {
  42871. delete this.previousStates[nodeId];
  42872. }
  42873. }
  42874. }
  42875. /**
  42876. * This compares the reference state to the current state
  42877. *
  42878. * @returns {boolean}
  42879. * @private
  42880. */
  42881. }, {
  42882. key: '_evaluateStepQuality',
  42883. value: function _evaluateStepQuality() {
  42884. var dx = void 0,
  42885. dy = void 0,
  42886. dpos = void 0;
  42887. var nodes = this.body.nodes;
  42888. var reference = this.referenceState;
  42889. var posThreshold = 0.3;
  42890. for (var nodeId in this.referenceState) {
  42891. if (this.referenceState.hasOwnProperty(nodeId) && nodes[nodeId] !== undefined) {
  42892. dx = nodes[nodeId].x - reference[nodeId].positions.x;
  42893. dy = nodes[nodeId].y - reference[nodeId].positions.y;
  42894. dpos = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
  42895. if (dpos > posThreshold) {
  42896. return false;
  42897. }
  42898. }
  42899. }
  42900. return true;
  42901. }
  42902. /**
  42903. * move the nodes one timestep and check if they are stabilized
  42904. */
  42905. }, {
  42906. key: 'moveNodes',
  42907. value: function moveNodes() {
  42908. var nodeIndices = this.physicsBody.physicsNodeIndices;
  42909. var maxNodeVelocity = 0;
  42910. var averageNodeVelocity = 0;
  42911. // the velocity threshold (energy in the system) for the adaptivity toggle
  42912. var velocityAdaptiveThreshold = 5;
  42913. for (var i = 0; i < nodeIndices.length; i++) {
  42914. var nodeId = nodeIndices[i];
  42915. var nodeVelocity = this._performStep(nodeId);
  42916. // stabilized is true if stabilized is true and velocity is smaller than vmin --> all nodes must be stabilized
  42917. maxNodeVelocity = Math.max(maxNodeVelocity, nodeVelocity);
  42918. averageNodeVelocity += nodeVelocity;
  42919. }
  42920. // evaluating the stabilized and adaptiveTimestepEnabled conditions
  42921. this.adaptiveTimestepEnabled = averageNodeVelocity / nodeIndices.length < velocityAdaptiveThreshold;
  42922. this.stabilized = maxNodeVelocity < this.options.minVelocity;
  42923. }
  42924. /**
  42925. * Calculate new velocity for a coordinate direction
  42926. *
  42927. * @param {number} v velocity for current coordinate
  42928. * @param {number} f regular force for current coordinate
  42929. * @param {number} m mass of current node
  42930. * @returns {number} new velocity for current coordinate
  42931. * @private
  42932. */
  42933. }, {
  42934. key: 'calculateComponentVelocity',
  42935. value: function calculateComponentVelocity(v, f, m) {
  42936. var df = this.modelOptions.damping * v; // damping force
  42937. var a = (f - df) / m; // acceleration
  42938. v += a * this.timestep;
  42939. // Put a limit on the velocities if it is really high
  42940. var maxV = this.options.maxVelocity || 1e9;
  42941. if (Math.abs(v) > maxV) {
  42942. v = v > 0 ? maxV : -maxV;
  42943. }
  42944. return v;
  42945. }
  42946. /**
  42947. * Perform the actual step
  42948. *
  42949. * @param {Node.id} nodeId
  42950. * @returns {number} the new velocity of given node
  42951. * @private
  42952. */
  42953. }, {
  42954. key: '_performStep',
  42955. value: function _performStep(nodeId) {
  42956. var node = this.body.nodes[nodeId];
  42957. var force = this.physicsBody.forces[nodeId];
  42958. var velocity = this.physicsBody.velocities[nodeId];
  42959. // store the state so we can revert
  42960. this.previousStates[nodeId] = { x: node.x, y: node.y, vx: velocity.x, vy: velocity.y };
  42961. if (node.options.fixed.x === false) {
  42962. velocity.x = this.calculateComponentVelocity(velocity.x, force.x, node.options.mass);
  42963. node.x += velocity.x * this.timestep;
  42964. } else {
  42965. force.x = 0;
  42966. velocity.x = 0;
  42967. }
  42968. if (node.options.fixed.y === false) {
  42969. velocity.y = this.calculateComponentVelocity(velocity.y, force.y, node.options.mass);
  42970. node.y += velocity.y * this.timestep;
  42971. } else {
  42972. force.y = 0;
  42973. velocity.y = 0;
  42974. }
  42975. var totalVelocity = Math.sqrt(Math.pow(velocity.x, 2) + Math.pow(velocity.y, 2));
  42976. return totalVelocity;
  42977. }
  42978. /**
  42979. * When initializing and stabilizing, we can freeze nodes with a predefined position.
  42980. * This greatly speeds up stabilization because only the supportnodes for the smoothCurves have to settle.
  42981. *
  42982. * @private
  42983. */
  42984. }, {
  42985. key: '_freezeNodes',
  42986. value: function _freezeNodes() {
  42987. var nodes = this.body.nodes;
  42988. for (var id in nodes) {
  42989. if (nodes.hasOwnProperty(id)) {
  42990. if (nodes[id].x && nodes[id].y) {
  42991. var fixed = nodes[id].options.fixed;
  42992. this.freezeCache[id] = { x: fixed.x, y: fixed.y };
  42993. fixed.x = true;
  42994. fixed.y = true;
  42995. }
  42996. }
  42997. }
  42998. }
  42999. /**
  43000. * Unfreezes the nodes that have been frozen by _freezeDefinedNodes.
  43001. *
  43002. * @private
  43003. */
  43004. }, {
  43005. key: '_restoreFrozenNodes',
  43006. value: function _restoreFrozenNodes() {
  43007. var nodes = this.body.nodes;
  43008. for (var id in nodes) {
  43009. if (nodes.hasOwnProperty(id)) {
  43010. if (this.freezeCache[id] !== undefined) {
  43011. nodes[id].options.fixed.x = this.freezeCache[id].x;
  43012. nodes[id].options.fixed.y = this.freezeCache[id].y;
  43013. }
  43014. }
  43015. }
  43016. this.freezeCache = {};
  43017. }
  43018. /**
  43019. * Find a stable position for all nodes
  43020. *
  43021. * @param {number} [iterations=this.options.stabilization.iterations]
  43022. */
  43023. }, {
  43024. key: 'stabilize',
  43025. value: function stabilize() {
  43026. var _this3 = this;
  43027. var iterations = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.stabilization.iterations;
  43028. if (typeof iterations !== 'number') {
  43029. iterations = this.options.stabilization.iterations;
  43030. console.log('The stabilize method needs a numeric amount of iterations. Switching to default: ', iterations);
  43031. }
  43032. if (this.physicsBody.physicsNodeIndices.length === 0) {
  43033. this.ready = true;
  43034. return;
  43035. }
  43036. // enable adaptive timesteps
  43037. this.adaptiveTimestep = true && this.options.adaptiveTimestep;
  43038. // this sets the width of all nodes initially which could be required for the avoidOverlap
  43039. this.body.emitter.emit("_resizeNodes");
  43040. this.stopSimulation(); // stop the render loop
  43041. this.stabilized = false;
  43042. // block redraw requests
  43043. this.body.emitter.emit('_blockRedraw');
  43044. this.targetIterations = iterations;
  43045. // start the stabilization
  43046. if (this.options.stabilization.onlyDynamicEdges === true) {
  43047. this._freezeNodes();
  43048. }
  43049. this.stabilizationIterations = 0;
  43050. setTimeout(function() {
  43051. return _this3._stabilizationBatch();
  43052. }, 0);
  43053. }
  43054. /**
  43055. * If not already stabilizing, start it and emit a start event.
  43056. *
  43057. * @returns {boolean} true if stabilization started with this call
  43058. * @private
  43059. */
  43060. }, {
  43061. key: '_startStabilizing',
  43062. value: function _startStabilizing() {
  43063. if (this.startedStabilization === true) return false;
  43064. this.body.emitter.emit('startStabilizing');
  43065. this.startedStabilization = true;
  43066. return true;
  43067. }
  43068. /**
  43069. * One batch of stabilization
  43070. * @private
  43071. */
  43072. }, {
  43073. key: '_stabilizationBatch',
  43074. value: function _stabilizationBatch() {
  43075. var _this4 = this;
  43076. var running = function running() {
  43077. return _this4.stabilized === false && _this4.stabilizationIterations < _this4.targetIterations;
  43078. };
  43079. var sendProgress = function sendProgress() {
  43080. _this4.body.emitter.emit('stabilizationProgress', {
  43081. iterations: _this4.stabilizationIterations,
  43082. total: _this4.targetIterations
  43083. });
  43084. };
  43085. if (this._startStabilizing()) {
  43086. sendProgress(); // Ensure that there is at least one start event.
  43087. }
  43088. var count = 0;
  43089. while (running() && count < this.options.stabilization.updateInterval) {
  43090. this.physicsTick();
  43091. count++;
  43092. }
  43093. sendProgress();
  43094. if (running()) {
  43095. setTimeout(this._stabilizationBatch.bind(this), 0);
  43096. } else {
  43097. this._finalizeStabilization();
  43098. }
  43099. }
  43100. /**
  43101. * Wrap up the stabilization, fit and emit the events.
  43102. * @private
  43103. */
  43104. }, {
  43105. key: '_finalizeStabilization',
  43106. value: function _finalizeStabilization() {
  43107. this.body.emitter.emit('_allowRedraw');
  43108. if (this.options.stabilization.fit === true) {
  43109. this.body.emitter.emit('fit');
  43110. }
  43111. if (this.options.stabilization.onlyDynamicEdges === true) {
  43112. this._restoreFrozenNodes();
  43113. }
  43114. this.body.emitter.emit('stabilizationIterationsDone');
  43115. this.body.emitter.emit('_requestRedraw');
  43116. if (this.stabilized === true) {
  43117. this._emitStabilized();
  43118. } else {
  43119. this.startSimulation();
  43120. }
  43121. this.ready = true;
  43122. }
  43123. //--------------------------- DEBUGGING BELOW ---------------------------//
  43124. /**
  43125. * Debug function that display arrows for the forces currently active in the network.
  43126. *
  43127. * Use this when debugging only.
  43128. *
  43129. * @param {CanvasRenderingContext2D} ctx
  43130. * @private
  43131. */
  43132. }, {
  43133. key: '_drawForces',
  43134. value: function _drawForces(ctx) {
  43135. for (var i = 0; i < this.physicsBody.physicsNodeIndices.length; i++) {
  43136. var index = this.physicsBody.physicsNodeIndices[i];
  43137. var node = this.body.nodes[index];
  43138. var force = this.physicsBody.forces[index];
  43139. var factor = 20;
  43140. var colorFactor = 0.03;
  43141. var forceSize = Math.sqrt(Math.pow(force.x, 2) + Math.pow(force.x, 2));
  43142. var size = Math.min(Math.max(5, forceSize), 15);
  43143. var arrowSize = 3 * size;
  43144. var color = util.HSVToHex((180 - Math.min(1, Math.max(0, colorFactor * forceSize)) * 180) / 360, 1, 1);
  43145. var point = {
  43146. x: node.x + factor * force.x,
  43147. y: node.y + factor * force.y
  43148. };
  43149. ctx.lineWidth = size;
  43150. ctx.strokeStyle = color;
  43151. ctx.beginPath();
  43152. ctx.moveTo(node.x, node.y);
  43153. ctx.lineTo(point.x, point.y);
  43154. ctx.stroke();
  43155. var angle = Math.atan2(force.y, force.x);
  43156. ctx.fillStyle = color;
  43157. EndPoints.draw(ctx, { type: 'arrow', point: point, angle: angle, length: arrowSize });
  43158. ctx.fill();
  43159. }
  43160. }
  43161. }]);
  43162. return PhysicsEngine;
  43163. }();
  43164. exports['default'] = PhysicsEngine;
  43165. /***/
  43166. }),
  43167. /* 221 */
  43168. /***/
  43169. (function(module, exports, __webpack_require__) {
  43170. "use strict";
  43171. Object.defineProperty(exports, "__esModule", {
  43172. value: true
  43173. });
  43174. var _classCallCheck2 = __webpack_require__(0);
  43175. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  43176. var _createClass2 = __webpack_require__(1);
  43177. var _createClass3 = _interopRequireDefault(_createClass2);
  43178. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  43179. /**
  43180. * Repulsion Solver
  43181. */
  43182. var RepulsionSolver = function() {
  43183. /**
  43184. * @param {Object} body
  43185. * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
  43186. * @param {Object} options
  43187. */
  43188. function RepulsionSolver(body, physicsBody, options) {
  43189. (0, _classCallCheck3["default"])(this, RepulsionSolver);
  43190. this.body = body;
  43191. this.physicsBody = physicsBody;
  43192. this.setOptions(options);
  43193. }
  43194. /**
  43195. *
  43196. * @param {Object} options
  43197. */
  43198. (0, _createClass3["default"])(RepulsionSolver, [{
  43199. key: "setOptions",
  43200. value: function setOptions(options) {
  43201. this.options = options;
  43202. }
  43203. /**
  43204. * Calculate the forces the nodes apply on each other based on a repulsion field.
  43205. * This field is linearly approximated.
  43206. *
  43207. * @private
  43208. */
  43209. }, {
  43210. key: "solve",
  43211. value: function solve() {
  43212. var dx, dy, distance, fx, fy, repulsingForce, node1, node2;
  43213. var nodes = this.body.nodes;
  43214. var nodeIndices = this.physicsBody.physicsNodeIndices;
  43215. var forces = this.physicsBody.forces;
  43216. // repulsing forces between nodes
  43217. var nodeDistance = this.options.nodeDistance;
  43218. // approximation constants
  43219. var a = -2 / 3 / nodeDistance;
  43220. var b = 4 / 3;
  43221. // we loop from i over all but the last entree in the array
  43222. // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
  43223. for (var i = 0; i < nodeIndices.length - 1; i++) {
  43224. node1 = nodes[nodeIndices[i]];
  43225. for (var j = i + 1; j < nodeIndices.length; j++) {
  43226. node2 = nodes[nodeIndices[j]];
  43227. dx = node2.x - node1.x;
  43228. dy = node2.y - node1.y;
  43229. distance = Math.sqrt(dx * dx + dy * dy);
  43230. // same condition as BarnesHutSolver, making sure nodes are never 100% overlapping.
  43231. if (distance === 0) {
  43232. distance = 0.1 * Math.random();
  43233. dx = distance;
  43234. }
  43235. if (distance < 2 * nodeDistance) {
  43236. if (distance < 0.5 * nodeDistance) {
  43237. repulsingForce = 1.0;
  43238. } else {
  43239. repulsingForce = a * distance + b; // linear approx of 1 / (1 + Math.exp((distance / nodeDistance - 1) * steepness))
  43240. }
  43241. repulsingForce = repulsingForce / distance;
  43242. fx = dx * repulsingForce;
  43243. fy = dy * repulsingForce;
  43244. forces[node1.id].x -= fx;
  43245. forces[node1.id].y -= fy;
  43246. forces[node2.id].x += fx;
  43247. forces[node2.id].y += fy;
  43248. }
  43249. }
  43250. }
  43251. }
  43252. }]);
  43253. return RepulsionSolver;
  43254. }();
  43255. exports["default"] = RepulsionSolver;
  43256. /***/
  43257. }),
  43258. /* 222 */
  43259. /***/
  43260. (function(module, exports, __webpack_require__) {
  43261. "use strict";
  43262. Object.defineProperty(exports, "__esModule", {
  43263. value: true
  43264. });
  43265. var _classCallCheck2 = __webpack_require__(0);
  43266. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  43267. var _createClass2 = __webpack_require__(1);
  43268. var _createClass3 = _interopRequireDefault(_createClass2);
  43269. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  43270. /**
  43271. * Hierarchical Repulsion Solver
  43272. */
  43273. var HierarchicalRepulsionSolver = function() {
  43274. /**
  43275. * @param {Object} body
  43276. * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
  43277. * @param {Object} options
  43278. */
  43279. function HierarchicalRepulsionSolver(body, physicsBody, options) {
  43280. (0, _classCallCheck3["default"])(this, HierarchicalRepulsionSolver);
  43281. this.body = body;
  43282. this.physicsBody = physicsBody;
  43283. this.setOptions(options);
  43284. }
  43285. /**
  43286. *
  43287. * @param {Object} options
  43288. */
  43289. (0, _createClass3["default"])(HierarchicalRepulsionSolver, [{
  43290. key: "setOptions",
  43291. value: function setOptions(options) {
  43292. this.options = options;
  43293. }
  43294. /**
  43295. * Calculate the forces the nodes apply on each other based on a repulsion field.
  43296. * This field is linearly approximated.
  43297. *
  43298. * @private
  43299. */
  43300. }, {
  43301. key: "solve",
  43302. value: function solve() {
  43303. var dx, dy, distance, fx, fy, repulsingForce, node1, node2, i, j;
  43304. var nodes = this.body.nodes;
  43305. var nodeIndices = this.physicsBody.physicsNodeIndices;
  43306. var forces = this.physicsBody.forces;
  43307. // repulsing forces between nodes
  43308. var nodeDistance = this.options.nodeDistance;
  43309. // we loop from i over all but the last entree in the array
  43310. // j loops from i+1 to the last. This way we do not double count any of the indices, nor i === j
  43311. for (i = 0; i < nodeIndices.length - 1; i++) {
  43312. node1 = nodes[nodeIndices[i]];
  43313. for (j = i + 1; j < nodeIndices.length; j++) {
  43314. node2 = nodes[nodeIndices[j]];
  43315. // nodes only affect nodes on their level
  43316. if (node1.level === node2.level) {
  43317. dx = node2.x - node1.x;
  43318. dy = node2.y - node1.y;
  43319. distance = Math.sqrt(dx * dx + dy * dy);
  43320. var steepness = 0.05;
  43321. if (distance < nodeDistance) {
  43322. repulsingForce = -Math.pow(steepness * distance, 2) + Math.pow(steepness * nodeDistance, 2);
  43323. } else {
  43324. repulsingForce = 0;
  43325. }
  43326. // normalize force with
  43327. if (distance === 0) {
  43328. distance = 0.01;
  43329. } else {
  43330. repulsingForce = repulsingForce / distance;
  43331. }
  43332. fx = dx * repulsingForce;
  43333. fy = dy * repulsingForce;
  43334. forces[node1.id].x -= fx;
  43335. forces[node1.id].y -= fy;
  43336. forces[node2.id].x += fx;
  43337. forces[node2.id].y += fy;
  43338. }
  43339. }
  43340. }
  43341. }
  43342. }]);
  43343. return HierarchicalRepulsionSolver;
  43344. }();
  43345. exports["default"] = HierarchicalRepulsionSolver;
  43346. /***/
  43347. }),
  43348. /* 223 */
  43349. /***/
  43350. (function(module, exports, __webpack_require__) {
  43351. "use strict";
  43352. Object.defineProperty(exports, "__esModule", {
  43353. value: true
  43354. });
  43355. var _classCallCheck2 = __webpack_require__(0);
  43356. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  43357. var _createClass2 = __webpack_require__(1);
  43358. var _createClass3 = _interopRequireDefault(_createClass2);
  43359. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  43360. /**
  43361. * Spring Solver
  43362. */
  43363. var SpringSolver = function() {
  43364. /**
  43365. * @param {Object} body
  43366. * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
  43367. * @param {Object} options
  43368. */
  43369. function SpringSolver(body, physicsBody, options) {
  43370. (0, _classCallCheck3["default"])(this, SpringSolver);
  43371. this.body = body;
  43372. this.physicsBody = physicsBody;
  43373. this.setOptions(options);
  43374. }
  43375. /**
  43376. *
  43377. * @param {Object} options
  43378. */
  43379. (0, _createClass3["default"])(SpringSolver, [{
  43380. key: "setOptions",
  43381. value: function setOptions(options) {
  43382. this.options = options;
  43383. }
  43384. /**
  43385. * This function calculates the springforces on the nodes, accounting for the support nodes.
  43386. *
  43387. * @private
  43388. */
  43389. }, {
  43390. key: "solve",
  43391. value: function solve() {
  43392. var edgeLength = void 0,
  43393. edge = void 0;
  43394. var edgeIndices = this.physicsBody.physicsEdgeIndices;
  43395. var edges = this.body.edges;
  43396. var node1 = void 0,
  43397. node2 = void 0,
  43398. node3 = void 0;
  43399. // forces caused by the edges, modelled as springs
  43400. for (var i = 0; i < edgeIndices.length; i++) {
  43401. edge = edges[edgeIndices[i]];
  43402. if (edge.connected === true && edge.toId !== edge.fromId) {
  43403. // only calculate forces if nodes are in the same sector
  43404. if (this.body.nodes[edge.toId] !== undefined && this.body.nodes[edge.fromId] !== undefined) {
  43405. if (edge.edgeType.via !== undefined) {
  43406. edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
  43407. node1 = edge.to;
  43408. node2 = edge.edgeType.via;
  43409. node3 = edge.from;
  43410. this._calculateSpringForce(node1, node2, 0.5 * edgeLength);
  43411. this._calculateSpringForce(node2, node3, 0.5 * edgeLength);
  43412. } else {
  43413. // the * 1.5 is here so the edge looks as large as a smooth edge. It does not initially because the smooth edges use
  43414. // the support nodes which exert a repulsive force on the to and from nodes, making the edge appear larger.
  43415. edgeLength = edge.options.length === undefined ? this.options.springLength * 1.5 : edge.options.length;
  43416. this._calculateSpringForce(edge.from, edge.to, edgeLength);
  43417. }
  43418. }
  43419. }
  43420. }
  43421. }
  43422. /**
  43423. * This is the code actually performing the calculation for the function above.
  43424. *
  43425. * @param {Node} node1
  43426. * @param {Node} node2
  43427. * @param {number} edgeLength
  43428. * @private
  43429. */
  43430. }, {
  43431. key: "_calculateSpringForce",
  43432. value: function _calculateSpringForce(node1, node2, edgeLength) {
  43433. var dx = node1.x - node2.x;
  43434. var dy = node1.y - node2.y;
  43435. var distance = Math.max(Math.sqrt(dx * dx + dy * dy), 0.01);
  43436. // the 1/distance is so the fx and fy can be calculated without sine or cosine.
  43437. var springForce = this.options.springConstant * (edgeLength - distance) / distance;
  43438. var fx = dx * springForce;
  43439. var fy = dy * springForce;
  43440. // handle the case where one node is not part of the physcis
  43441. if (this.physicsBody.forces[node1.id] !== undefined) {
  43442. this.physicsBody.forces[node1.id].x += fx;
  43443. this.physicsBody.forces[node1.id].y += fy;
  43444. }
  43445. if (this.physicsBody.forces[node2.id] !== undefined) {
  43446. this.physicsBody.forces[node2.id].x -= fx;
  43447. this.physicsBody.forces[node2.id].y -= fy;
  43448. }
  43449. }
  43450. }]);
  43451. return SpringSolver;
  43452. }();
  43453. exports["default"] = SpringSolver;
  43454. /***/
  43455. }),
  43456. /* 224 */
  43457. /***/
  43458. (function(module, exports, __webpack_require__) {
  43459. "use strict";
  43460. Object.defineProperty(exports, "__esModule", {
  43461. value: true
  43462. });
  43463. var _classCallCheck2 = __webpack_require__(0);
  43464. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  43465. var _createClass2 = __webpack_require__(1);
  43466. var _createClass3 = _interopRequireDefault(_createClass2);
  43467. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  43468. /**
  43469. * Hierarchical Spring Solver
  43470. */
  43471. var HierarchicalSpringSolver = function() {
  43472. /**
  43473. * @param {Object} body
  43474. * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
  43475. * @param {Object} options
  43476. */
  43477. function HierarchicalSpringSolver(body, physicsBody, options) {
  43478. (0, _classCallCheck3["default"])(this, HierarchicalSpringSolver);
  43479. this.body = body;
  43480. this.physicsBody = physicsBody;
  43481. this.setOptions(options);
  43482. }
  43483. /**
  43484. *
  43485. * @param {Object} options
  43486. */
  43487. (0, _createClass3["default"])(HierarchicalSpringSolver, [{
  43488. key: "setOptions",
  43489. value: function setOptions(options) {
  43490. this.options = options;
  43491. }
  43492. /**
  43493. * This function calculates the springforces on the nodes, accounting for the support nodes.
  43494. *
  43495. * @private
  43496. */
  43497. }, {
  43498. key: "solve",
  43499. value: function solve() {
  43500. var edgeLength, edge;
  43501. var dx, dy, fx, fy, springForce, distance;
  43502. var edges = this.body.edges;
  43503. var factor = 0.5;
  43504. var edgeIndices = this.physicsBody.physicsEdgeIndices;
  43505. var nodeIndices = this.physicsBody.physicsNodeIndices;
  43506. var forces = this.physicsBody.forces;
  43507. // initialize the spring force counters
  43508. for (var i = 0; i < nodeIndices.length; i++) {
  43509. var nodeId = nodeIndices[i];
  43510. forces[nodeId].springFx = 0;
  43511. forces[nodeId].springFy = 0;
  43512. }
  43513. // forces caused by the edges, modelled as springs
  43514. for (var _i = 0; _i < edgeIndices.length; _i++) {
  43515. edge = edges[edgeIndices[_i]];
  43516. if (edge.connected === true) {
  43517. edgeLength = edge.options.length === undefined ? this.options.springLength : edge.options.length;
  43518. dx = edge.from.x - edge.to.x;
  43519. dy = edge.from.y - edge.to.y;
  43520. distance = Math.sqrt(dx * dx + dy * dy);
  43521. distance = distance === 0 ? 0.01 : distance;
  43522. // the 1/distance is so the fx and fy can be calculated without sine or cosine.
  43523. springForce = this.options.springConstant * (edgeLength - distance) / distance;
  43524. fx = dx * springForce;
  43525. fy = dy * springForce;
  43526. if (edge.to.level != edge.from.level) {
  43527. if (forces[edge.toId] !== undefined) {
  43528. forces[edge.toId].springFx -= fx;
  43529. forces[edge.toId].springFy -= fy;
  43530. }
  43531. if (forces[edge.fromId] !== undefined) {
  43532. forces[edge.fromId].springFx += fx;
  43533. forces[edge.fromId].springFy += fy;
  43534. }
  43535. } else {
  43536. if (forces[edge.toId] !== undefined) {
  43537. forces[edge.toId].x -= factor * fx;
  43538. forces[edge.toId].y -= factor * fy;
  43539. }
  43540. if (forces[edge.fromId] !== undefined) {
  43541. forces[edge.fromId].x += factor * fx;
  43542. forces[edge.fromId].y += factor * fy;
  43543. }
  43544. }
  43545. }
  43546. }
  43547. // normalize spring forces
  43548. springForce = 1;
  43549. var springFx, springFy;
  43550. for (var _i2 = 0; _i2 < nodeIndices.length; _i2++) {
  43551. var _nodeId = nodeIndices[_i2];
  43552. springFx = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFx));
  43553. springFy = Math.min(springForce, Math.max(-springForce, forces[_nodeId].springFy));
  43554. forces[_nodeId].x += springFx;
  43555. forces[_nodeId].y += springFy;
  43556. }
  43557. // retain energy balance
  43558. var totalFx = 0;
  43559. var totalFy = 0;
  43560. for (var _i3 = 0; _i3 < nodeIndices.length; _i3++) {
  43561. var _nodeId2 = nodeIndices[_i3];
  43562. totalFx += forces[_nodeId2].x;
  43563. totalFy += forces[_nodeId2].y;
  43564. }
  43565. var correctionFx = totalFx / nodeIndices.length;
  43566. var correctionFy = totalFy / nodeIndices.length;
  43567. for (var _i4 = 0; _i4 < nodeIndices.length; _i4++) {
  43568. var _nodeId3 = nodeIndices[_i4];
  43569. forces[_nodeId3].x -= correctionFx;
  43570. forces[_nodeId3].y -= correctionFy;
  43571. }
  43572. }
  43573. }]);
  43574. return HierarchicalSpringSolver;
  43575. }();
  43576. exports["default"] = HierarchicalSpringSolver;
  43577. /***/
  43578. }),
  43579. /* 225 */
  43580. /***/
  43581. (function(module, exports, __webpack_require__) {
  43582. "use strict";
  43583. Object.defineProperty(exports, "__esModule", {
  43584. value: true
  43585. });
  43586. var _getPrototypeOf = __webpack_require__(3);
  43587. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  43588. var _classCallCheck2 = __webpack_require__(0);
  43589. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  43590. var _createClass2 = __webpack_require__(1);
  43591. var _createClass3 = _interopRequireDefault(_createClass2);
  43592. var _possibleConstructorReturn2 = __webpack_require__(4);
  43593. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  43594. var _inherits2 = __webpack_require__(5);
  43595. var _inherits3 = _interopRequireDefault(_inherits2);
  43596. var _BarnesHutSolver2 = __webpack_require__(120);
  43597. var _BarnesHutSolver3 = _interopRequireDefault(_BarnesHutSolver2);
  43598. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  43599. /**
  43600. * @extends BarnesHutSolver
  43601. */
  43602. var ForceAtlas2BasedRepulsionSolver = function(_BarnesHutSolver) {
  43603. (0, _inherits3["default"])(ForceAtlas2BasedRepulsionSolver, _BarnesHutSolver);
  43604. /**
  43605. * @param {Object} body
  43606. * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
  43607. * @param {Object} options
  43608. */
  43609. function ForceAtlas2BasedRepulsionSolver(body, physicsBody, options) {
  43610. (0, _classCallCheck3["default"])(this, ForceAtlas2BasedRepulsionSolver);
  43611. return (0, _possibleConstructorReturn3["default"])(this, (ForceAtlas2BasedRepulsionSolver.__proto__ || (0, _getPrototypeOf2["default"])(ForceAtlas2BasedRepulsionSolver)).call(this, body, physicsBody, options));
  43612. }
  43613. /**
  43614. * Calculate the forces based on the distance.
  43615. *
  43616. * @param {number} distance
  43617. * @param {number} dx
  43618. * @param {number} dy
  43619. * @param {Node} node
  43620. * @param {Object} parentBranch
  43621. * @private
  43622. */
  43623. (0, _createClass3["default"])(ForceAtlas2BasedRepulsionSolver, [{
  43624. key: "_calculateForces",
  43625. value: function _calculateForces(distance, dx, dy, node, parentBranch) {
  43626. if (distance === 0) {
  43627. distance = 0.1 * Math.random();
  43628. dx = distance;
  43629. }
  43630. if (this.overlapAvoidanceFactor < 1 && node.shape.radius) {
  43631. distance = Math.max(0.1 + this.overlapAvoidanceFactor * node.shape.radius, distance - node.shape.radius);
  43632. }
  43633. var degree = node.edges.length + 1;
  43634. // the dividing by the distance cubed instead of squared allows us to get the fx and fy components without sines and cosines
  43635. // it is shorthand for gravityforce with distance squared and fx = dx/distance * gravityForce
  43636. var gravityForce = this.options.gravitationalConstant * parentBranch.mass * node.options.mass * degree / Math.pow(distance, 2);
  43637. var fx = dx * gravityForce;
  43638. var fy = dy * gravityForce;
  43639. this.physicsBody.forces[node.id].x += fx;
  43640. this.physicsBody.forces[node.id].y += fy;
  43641. }
  43642. }]);
  43643. return ForceAtlas2BasedRepulsionSolver;
  43644. }(_BarnesHutSolver3["default"]);
  43645. exports["default"] = ForceAtlas2BasedRepulsionSolver;
  43646. /***/
  43647. }),
  43648. /* 226 */
  43649. /***/
  43650. (function(module, exports, __webpack_require__) {
  43651. "use strict";
  43652. Object.defineProperty(exports, "__esModule", {
  43653. value: true
  43654. });
  43655. var _getPrototypeOf = __webpack_require__(3);
  43656. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  43657. var _classCallCheck2 = __webpack_require__(0);
  43658. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  43659. var _createClass2 = __webpack_require__(1);
  43660. var _createClass3 = _interopRequireDefault(_createClass2);
  43661. var _possibleConstructorReturn2 = __webpack_require__(4);
  43662. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  43663. var _inherits2 = __webpack_require__(5);
  43664. var _inherits3 = _interopRequireDefault(_inherits2);
  43665. var _CentralGravitySolver2 = __webpack_require__(121);
  43666. var _CentralGravitySolver3 = _interopRequireDefault(_CentralGravitySolver2);
  43667. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  43668. /**
  43669. * @extends CentralGravitySolver
  43670. */
  43671. var ForceAtlas2BasedCentralGravitySolver = function(_CentralGravitySolver) {
  43672. (0, _inherits3["default"])(ForceAtlas2BasedCentralGravitySolver, _CentralGravitySolver);
  43673. /**
  43674. * @param {Object} body
  43675. * @param {{physicsNodeIndices: Array, physicsEdgeIndices: Array, forces: {}, velocities: {}}} physicsBody
  43676. * @param {Object} options
  43677. */
  43678. function ForceAtlas2BasedCentralGravitySolver(body, physicsBody, options) {
  43679. (0, _classCallCheck3["default"])(this, ForceAtlas2BasedCentralGravitySolver);
  43680. return (0, _possibleConstructorReturn3["default"])(this, (ForceAtlas2BasedCentralGravitySolver.__proto__ || (0, _getPrototypeOf2["default"])(ForceAtlas2BasedCentralGravitySolver)).call(this, body, physicsBody, options));
  43681. }
  43682. /**
  43683. * Calculate the forces based on the distance.
  43684. *
  43685. * @param {number} distance
  43686. * @param {number} dx
  43687. * @param {number} dy
  43688. * @param {Object<Node.id, Node>} forces
  43689. * @param {Node} node
  43690. * @private
  43691. */
  43692. (0, _createClass3["default"])(ForceAtlas2BasedCentralGravitySolver, [{
  43693. key: "_calculateForces",
  43694. value: function _calculateForces(distance, dx, dy, forces, node) {
  43695. if (distance > 0) {
  43696. var degree = node.edges.length + 1;
  43697. var gravityForce = this.options.centralGravity * degree * node.options.mass;
  43698. forces[node.id].x = dx * gravityForce;
  43699. forces[node.id].y = dy * gravityForce;
  43700. }
  43701. }
  43702. }]);
  43703. return ForceAtlas2BasedCentralGravitySolver;
  43704. }(_CentralGravitySolver3["default"]);
  43705. exports["default"] = ForceAtlas2BasedCentralGravitySolver;
  43706. /***/
  43707. }),
  43708. /* 227 */
  43709. /***/
  43710. (function(module, exports, __webpack_require__) {
  43711. "use strict";
  43712. Object.defineProperty(exports, "__esModule", {
  43713. value: true
  43714. });
  43715. var _keys = __webpack_require__(8);
  43716. var _keys2 = _interopRequireDefault(_keys);
  43717. var _typeof2 = __webpack_require__(6);
  43718. var _typeof3 = _interopRequireDefault(_typeof2);
  43719. var _classCallCheck2 = __webpack_require__(0);
  43720. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  43721. var _createClass2 = __webpack_require__(1);
  43722. var _createClass3 = _interopRequireDefault(_createClass2);
  43723. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  43724. /* ===========================================================================
  43725. # TODO
  43726. - `edgeReplacedById` not cleaned up yet on cluster edge removal
  43727. - allowSingleNodeCluster could be a global option as well; currently needs to always
  43728. be passed to clustering methods
  43729. ----------------------------------------------
  43730. # State Model for Clustering
  43731. The total state for clustering is non-trivial. It is useful to have a model
  43732. available as to how it works. The following documents the relevant state items.
  43733. ## Network State
  43734. The following `network`-members are relevant to clustering:
  43735. - `body.nodes` - all nodes actively participating in the network
  43736. - `body.edges` - same for edges
  43737. - `body.nodeIndices` - id's of nodes that are visible at a given moment
  43738. - `body.edgeIndices` - same for edges
  43739. This includes:
  43740. - helper nodes for dragging in `manipulation`
  43741. - helper nodes for edge type `dynamic`
  43742. - cluster nodes and edges
  43743. - there may be more than this.
  43744. A node/edge may be missing in the `Indices` member if:
  43745. - it is a helper node
  43746. - the node or edge state has option `hidden` set
  43747. - It is not visible due to clustering
  43748. ## Clustering State
  43749. For the hashes, the id's of the nodes/edges are used as key.
  43750. Member `network.clustering` contains the following items:
  43751. - `clusteredNodes` - hash with values: { clusterId: <id of cluster>, node: <node instance>}
  43752. - `clusteredEdges` - hash with values: restore information for given edge
  43753. Due to nesting of clusters, these members can contain cluster nodes and edges as well.
  43754. The important thing to note here, is that the clustered nodes and edges also
  43755. appear in the members of the cluster nodes. For data update, it is therefore
  43756. important to scan these lists as well as the cluster nodes.
  43757. ### Cluster Node
  43758. A cluster node has the following extra fields:
  43759. - `isCluster : true` - indication that this is a cluster node
  43760. - `containedNodes` - hash of nodes contained in this cluster
  43761. - `containedEdges` - same for edges
  43762. - `edges` - array of cluster edges for this node
  43763. **NOTE:**
  43764. - `containedEdges` can also contain edges which are not clustered; e.g. an edge
  43765. connecting two nodes in the same cluster.
  43766. ### Cluster Edge
  43767. These are the items in the `edges` member of a clustered node. They have the
  43768. following relevant members:
  43769. - 'clusteringEdgeReplacingIds` - array of id's of edges replaced by this edge
  43770. Note that it's possible to nest clusters, so that `clusteringEdgeReplacingIds`
  43771. can contain edge id's of other clusters.
  43772. ### Clustered Edge
  43773. This is any edge contained by a cluster edge. It gets the following additional
  43774. member:
  43775. - `edgeReplacedById` - id of the cluster edge in which current edge is clustered
  43776. =========================================================================== */
  43777. var util = __webpack_require__(2);
  43778. var NetworkUtil = __webpack_require__(76)['default'];
  43779. var Cluster = __webpack_require__(228)['default'];
  43780. var Edge = __webpack_require__(74)['default']; // Only needed for check on type!
  43781. var Node = __webpack_require__(47)['default']; // Only needed for check on type!
  43782. /**
  43783. * The clustering engine
  43784. */
  43785. var ClusterEngine = function() {
  43786. /**
  43787. * @param {Object} body
  43788. */
  43789. function ClusterEngine(body) {
  43790. var _this = this;
  43791. (0, _classCallCheck3['default'])(this, ClusterEngine);
  43792. this.body = body;
  43793. this.clusteredNodes = {}; // key: node id, value: { clusterId: <id of cluster>, node: <node instance>}
  43794. this.clusteredEdges = {}; // key: edge id, value: restore information for given edge
  43795. this.options = {};
  43796. this.defaultOptions = {};
  43797. util.extend(this.options, this.defaultOptions);
  43798. this.body.emitter.on('_resetData', function() {
  43799. _this.clusteredNodes = {};
  43800. _this.clusteredEdges = {};
  43801. });
  43802. }
  43803. /**
  43804. *
  43805. * @param {number} hubsize
  43806. * @param {Object} options
  43807. */
  43808. (0, _createClass3['default'])(ClusterEngine, [{
  43809. key: 'clusterByHubsize',
  43810. value: function clusterByHubsize(hubsize, options) {
  43811. if (hubsize === undefined) {
  43812. hubsize = this._getHubSize();
  43813. } else if ((typeof hubsize === 'undefined' ? 'undefined' : (0, _typeof3['default'])(hubsize)) === "object") {
  43814. options = this._checkOptions(hubsize);
  43815. hubsize = this._getHubSize();
  43816. }
  43817. var nodesToCluster = [];
  43818. for (var i = 0; i < this.body.nodeIndices.length; i++) {
  43819. var node = this.body.nodes[this.body.nodeIndices[i]];
  43820. if (node.edges.length >= hubsize) {
  43821. nodesToCluster.push(node.id);
  43822. }
  43823. }
  43824. for (var _i = 0; _i < nodesToCluster.length; _i++) {
  43825. this.clusterByConnection(nodesToCluster[_i], options, true);
  43826. }
  43827. this.body.emitter.emit('_dataChanged');
  43828. }
  43829. /**
  43830. * loop over all nodes, check if they adhere to the condition and cluster if needed.
  43831. * @param {Object} options
  43832. * @param {boolean} [refreshData=true]
  43833. */
  43834. }, {
  43835. key: 'cluster',
  43836. value: function cluster() {
  43837. var _this2 = this;
  43838. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  43839. var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  43840. if (options.joinCondition === undefined) {
  43841. throw new Error("Cannot call clusterByNodeData without a joinCondition function in the options.");
  43842. }
  43843. // check if the options object is fine, append if needed
  43844. options = this._checkOptions(options);
  43845. var childNodesObj = {};
  43846. var childEdgesObj = {};
  43847. // collect the nodes that will be in the cluster
  43848. util.forEach(this.body.nodes, function(node, nodeId) {
  43849. var clonedOptions = NetworkUtil.cloneOptions(node);
  43850. if (options.joinCondition(clonedOptions) === true) {
  43851. childNodesObj[nodeId] = node;
  43852. // collect the edges that will be in the cluster
  43853. util.forEach(node.edges, function(edge) {
  43854. if (_this2.clusteredEdges[edge.id] === undefined) {
  43855. childEdgesObj[edge.id] = edge;
  43856. }
  43857. });
  43858. }
  43859. });
  43860. this._cluster(childNodesObj, childEdgesObj, options, refreshData);
  43861. }
  43862. /**
  43863. * Cluster all nodes in the network that have only X edges
  43864. * @param {number} edgeCount
  43865. * @param {Object} options
  43866. * @param {boolean} [refreshData=true]
  43867. */
  43868. }, {
  43869. key: 'clusterByEdgeCount',
  43870. value: function clusterByEdgeCount(edgeCount, options) {
  43871. var _this3 = this;
  43872. var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
  43873. options = this._checkOptions(options);
  43874. var clusters = [];
  43875. var usedNodes = {};
  43876. var edge = void 0,
  43877. edges = void 0,
  43878. relevantEdgeCount = void 0;
  43879. // collect the nodes that will be in the cluster
  43880. var _loop = function _loop(i) {
  43881. var childNodesObj = {};
  43882. var childEdgesObj = {};
  43883. var nodeId = _this3.body.nodeIndices[i];
  43884. var node = _this3.body.nodes[nodeId];
  43885. // if this node is already used in another cluster this session, we do not have to re-evaluate it.
  43886. if (usedNodes[nodeId] === undefined) {
  43887. relevantEdgeCount = 0;
  43888. edges = [];
  43889. for (var j = 0; j < node.edges.length; j++) {
  43890. edge = node.edges[j];
  43891. if (_this3.clusteredEdges[edge.id] === undefined) {
  43892. if (edge.toId !== edge.fromId) {
  43893. relevantEdgeCount++;
  43894. }
  43895. edges.push(edge);
  43896. }
  43897. }
  43898. // this node qualifies, we collect its neighbours to start the clustering process.
  43899. if (relevantEdgeCount === edgeCount) {
  43900. checkJoinCondition = function checkJoinCondition(node) {
  43901. if (options.joinCondition === undefined || options.joinCondition === null) {
  43902. return true;
  43903. }
  43904. var clonedOptions = NetworkUtil.cloneOptions(node);
  43905. return options.joinCondition(clonedOptions);
  43906. };
  43907. var gatheringSuccessful = true;
  43908. for (var _j = 0; _j < edges.length; _j++) {
  43909. edge = edges[_j];
  43910. var childNodeId = _this3._getConnectedId(edge, nodeId);
  43911. // add the nodes to the list by the join condition.
  43912. if (checkJoinCondition(node)) {
  43913. childEdgesObj[edge.id] = edge;
  43914. childNodesObj[nodeId] = node;
  43915. childNodesObj[childNodeId] = _this3.body.nodes[childNodeId];
  43916. usedNodes[nodeId] = true;
  43917. } else {
  43918. // this node does not qualify after all.
  43919. gatheringSuccessful = false;
  43920. break;
  43921. }
  43922. }
  43923. // add to the cluster queue
  43924. if ((0, _keys2['default'])(childNodesObj).length > 0 && (0, _keys2['default'])(childEdgesObj).length > 0 && gatheringSuccessful === true) {
  43925. /**
  43926. * Search for cluster data that contains any of the node id's
  43927. * @returns {Boolean} true if no joinCondition, otherwise return value of joinCondition
  43928. */
  43929. findClusterData = function findClusterData() {
  43930. for (var n = 0; n < clusters.length; ++n) {
  43931. // Search for a cluster containing any of the node id's
  43932. for (var m in childNodesObj) {
  43933. if (clusters[n].nodes[m] !== undefined) {
  43934. return clusters[n];
  43935. }
  43936. }
  43937. }
  43938. return undefined;
  43939. };
  43940. // If any of the found nodes is part of a cluster found in this method,
  43941. // add the current values to that cluster
  43942. foundCluster = findClusterData();
  43943. if (foundCluster !== undefined) {
  43944. // Add nodes to found cluster if not present
  43945. for (var m in childNodesObj) {
  43946. if (foundCluster.nodes[m] === undefined) {
  43947. foundCluster.nodes[m] = childNodesObj[m];
  43948. }
  43949. }
  43950. // Add edges to found cluster, if not present
  43951. for (var _m in childEdgesObj) {
  43952. if (foundCluster.edges[_m] === undefined) {
  43953. foundCluster.edges[_m] = childEdgesObj[_m];
  43954. }
  43955. }
  43956. } else {
  43957. // Create a new cluster group
  43958. clusters.push({ nodes: childNodesObj, edges: childEdgesObj });
  43959. }
  43960. }
  43961. }
  43962. }
  43963. };
  43964. for (var i = 0; i < this.body.nodeIndices.length; i++) {
  43965. var checkJoinCondition;
  43966. var findClusterData;
  43967. var foundCluster;
  43968. _loop(i);
  43969. }
  43970. for (var i = 0; i < clusters.length; i++) {
  43971. this._cluster(clusters[i].nodes, clusters[i].edges, options, false);
  43972. }
  43973. if (refreshData === true) {
  43974. this.body.emitter.emit('_dataChanged');
  43975. }
  43976. }
  43977. /**
  43978. * Cluster all nodes in the network that have only 1 edge
  43979. * @param {Object} options
  43980. * @param {boolean} [refreshData=true]
  43981. */
  43982. }, {
  43983. key: 'clusterOutliers',
  43984. value: function clusterOutliers(options) {
  43985. var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  43986. this.clusterByEdgeCount(1, options, refreshData);
  43987. }
  43988. /**
  43989. * Cluster all nodes in the network that have only 2 edge
  43990. * @param {Object} options
  43991. * @param {boolean} [refreshData=true]
  43992. */
  43993. }, {
  43994. key: 'clusterBridges',
  43995. value: function clusterBridges(options) {
  43996. var refreshData = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  43997. this.clusterByEdgeCount(2, options, refreshData);
  43998. }
  43999. /**
  44000. * suck all connected nodes of a node into the node.
  44001. * @param {Node.id} nodeId
  44002. * @param {Object} options
  44003. * @param {boolean} [refreshData=true]
  44004. */
  44005. }, {
  44006. key: 'clusterByConnection',
  44007. value: function clusterByConnection(nodeId, options) {
  44008. var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
  44009. // kill conditions
  44010. if (nodeId === undefined) {
  44011. throw new Error("No nodeId supplied to clusterByConnection!");
  44012. }
  44013. if (this.body.nodes[nodeId] === undefined) {
  44014. throw new Error("The nodeId given to clusterByConnection does not exist!");
  44015. }
  44016. var node = this.body.nodes[nodeId];
  44017. options = this._checkOptions(options, node);
  44018. if (options.clusterNodeProperties.x === undefined) {
  44019. options.clusterNodeProperties.x = node.x;
  44020. }
  44021. if (options.clusterNodeProperties.y === undefined) {
  44022. options.clusterNodeProperties.y = node.y;
  44023. }
  44024. if (options.clusterNodeProperties.fixed === undefined) {
  44025. options.clusterNodeProperties.fixed = {};
  44026. options.clusterNodeProperties.fixed.x = node.options.fixed.x;
  44027. options.clusterNodeProperties.fixed.y = node.options.fixed.y;
  44028. }
  44029. var childNodesObj = {};
  44030. var childEdgesObj = {};
  44031. var parentNodeId = node.id;
  44032. var parentClonedOptions = NetworkUtil.cloneOptions(node);
  44033. childNodesObj[parentNodeId] = node;
  44034. // collect the nodes that will be in the cluster
  44035. for (var i = 0; i < node.edges.length; i++) {
  44036. var edge = node.edges[i];
  44037. if (this.clusteredEdges[edge.id] === undefined) {
  44038. var childNodeId = this._getConnectedId(edge, parentNodeId);
  44039. // if the child node is not in a cluster
  44040. if (this.clusteredNodes[childNodeId] === undefined) {
  44041. if (childNodeId !== parentNodeId) {
  44042. if (options.joinCondition === undefined) {
  44043. childEdgesObj[edge.id] = edge;
  44044. childNodesObj[childNodeId] = this.body.nodes[childNodeId];
  44045. } else {
  44046. // clone the options and insert some additional parameters that could be interesting.
  44047. var childClonedOptions = NetworkUtil.cloneOptions(this.body.nodes[childNodeId]);
  44048. if (options.joinCondition(parentClonedOptions, childClonedOptions) === true) {
  44049. childEdgesObj[edge.id] = edge;
  44050. childNodesObj[childNodeId] = this.body.nodes[childNodeId];
  44051. }
  44052. }
  44053. } else {
  44054. // swallow the edge if it is self-referencing.
  44055. childEdgesObj[edge.id] = edge;
  44056. }
  44057. }
  44058. }
  44059. }
  44060. var childNodeIDs = (0, _keys2['default'])(childNodesObj).map(function(childNode) {
  44061. return childNodesObj[childNode].id;
  44062. });
  44063. for (childNode in childNodesObj) {
  44064. if (!childNodesObj.hasOwnProperty(childNode)) continue;
  44065. var childNode = childNodesObj[childNode];
  44066. for (var y = 0; y < childNode.edges.length; y++) {
  44067. var childEdge = childNode.edges[y];
  44068. if (childNodeIDs.indexOf(this._getConnectedId(childEdge, childNode.id)) > -1) {
  44069. childEdgesObj[childEdge.id] = childEdge;
  44070. }
  44071. }
  44072. }
  44073. this._cluster(childNodesObj, childEdgesObj, options, refreshData);
  44074. }
  44075. /**
  44076. * This function creates the edges that will be attached to the cluster
  44077. * It looks for edges that are connected to the nodes from the "outside' of the cluster.
  44078. *
  44079. * @param {{Node.id: vis.Node}} childNodesObj
  44080. * @param {{vis.Edge.id: vis.Edge}} childEdgesObj
  44081. * @param {Object} clusterNodeProperties
  44082. * @param {Object} clusterEdgeProperties
  44083. * @private
  44084. */
  44085. }, {
  44086. key: '_createClusterEdges',
  44087. value: function _createClusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, clusterEdgeProperties) {
  44088. var edge = void 0,
  44089. childNodeId = void 0,
  44090. childNode = void 0,
  44091. toId = void 0,
  44092. fromId = void 0,
  44093. otherNodeId = void 0;
  44094. // loop over all child nodes and their edges to find edges going out of the cluster
  44095. // these edges will be replaced by clusterEdges.
  44096. var childKeys = (0, _keys2['default'])(childNodesObj);
  44097. var createEdges = [];
  44098. for (var i = 0; i < childKeys.length; i++) {
  44099. childNodeId = childKeys[i];
  44100. childNode = childNodesObj[childNodeId];
  44101. // construct new edges from the cluster to others
  44102. for (var j = 0; j < childNode.edges.length; j++) {
  44103. edge = childNode.edges[j];
  44104. // we only handle edges that are visible to the system, not the disabled ones from the clustering process.
  44105. if (this.clusteredEdges[edge.id] === undefined) {
  44106. // self-referencing edges will be added to the "hidden" list
  44107. if (edge.toId == edge.fromId) {
  44108. childEdgesObj[edge.id] = edge;
  44109. } else {
  44110. // set up the from and to.
  44111. if (edge.toId == childNodeId) {
  44112. // this is a double equals because ints and strings can be interchanged here.
  44113. toId = clusterNodeProperties.id;
  44114. fromId = edge.fromId;
  44115. otherNodeId = fromId;
  44116. } else {
  44117. toId = edge.toId;
  44118. fromId = clusterNodeProperties.id;
  44119. otherNodeId = toId;
  44120. }
  44121. }
  44122. // Only edges from the cluster outwards are being replaced.
  44123. if (childNodesObj[otherNodeId] === undefined) {
  44124. createEdges.push({ edge: edge, fromId: fromId, toId: toId });
  44125. }
  44126. }
  44127. }
  44128. }
  44129. //
  44130. // Here we actually create the replacement edges.
  44131. //
  44132. // We could not do this in the loop above as the creation process
  44133. // would add an edge to the edges array we are iterating over.
  44134. //
  44135. // NOTE: a clustered edge can have multiple base edges!
  44136. //
  44137. var newEdges = [];
  44138. /**
  44139. * Find a cluster edge which matches the given created edge.
  44140. * @param {vis.Edge} createdEdge
  44141. * @returns {vis.Edge}
  44142. */
  44143. var getNewEdge = function getNewEdge(createdEdge) {
  44144. for (var _j2 = 0; _j2 < newEdges.length; _j2++) {
  44145. var newEdge = newEdges[_j2];
  44146. // We replace both to and from edges with a single cluster edge
  44147. var matchToDirection = createdEdge.fromId === newEdge.fromId && createdEdge.toId === newEdge.toId;
  44148. var matchFromDirection = createdEdge.fromId === newEdge.toId && createdEdge.toId === newEdge.fromId;
  44149. if (matchToDirection || matchFromDirection) {
  44150. return newEdge;
  44151. }
  44152. }
  44153. return null;
  44154. };
  44155. for (var _j3 = 0; _j3 < createEdges.length; _j3++) {
  44156. var createdEdge = createEdges[_j3];
  44157. var _edge = createdEdge.edge;
  44158. var newEdge = getNewEdge(createdEdge);
  44159. if (newEdge === null) {
  44160. // Create a clustered edge for this connection
  44161. newEdge = this._createClusteredEdge(createdEdge.fromId, createdEdge.toId, _edge, clusterEdgeProperties);
  44162. newEdges.push(newEdge);
  44163. } else {
  44164. newEdge.clusteringEdgeReplacingIds.push(_edge.id);
  44165. }
  44166. // also reference the new edge in the old edge
  44167. this.body.edges[_edge.id].edgeReplacedById = newEdge.id;
  44168. // hide the replaced edge
  44169. this._backupEdgeOptions(_edge);
  44170. _edge.setOptions({ physics: false });
  44171. }
  44172. }
  44173. /**
  44174. * This function checks the options that can be supplied to the different cluster functions
  44175. * for certain fields and inserts defaults if needed
  44176. * @param {Object} options
  44177. * @returns {*}
  44178. * @private
  44179. */
  44180. }, {
  44181. key: '_checkOptions',
  44182. value: function _checkOptions() {
  44183. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  44184. if (options.clusterEdgeProperties === undefined) {
  44185. options.clusterEdgeProperties = {};
  44186. }
  44187. if (options.clusterNodeProperties === undefined) {
  44188. options.clusterNodeProperties = {};
  44189. }
  44190. return options;
  44191. }
  44192. /**
  44193. *
  44194. * @param {Object} childNodesObj | object with node objects, id as keys, same as childNodes except it also contains a source node
  44195. * @param {Object} childEdgesObj | object with edge objects, id as keys
  44196. * @param {Array} options | object with {clusterNodeProperties, clusterEdgeProperties, processProperties}
  44197. * @param {boolean} refreshData | when true, do not wrap up
  44198. * @private
  44199. */
  44200. }, {
  44201. key: '_cluster',
  44202. value: function _cluster(childNodesObj, childEdgesObj, options) {
  44203. var refreshData = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
  44204. // Remove nodes which are already clustered
  44205. var tmpNodesToRemove = [];
  44206. for (var _nodeId in childNodesObj) {
  44207. if (childNodesObj.hasOwnProperty(_nodeId)) {
  44208. if (this.clusteredNodes[_nodeId] !== undefined) {
  44209. tmpNodesToRemove.push(_nodeId);
  44210. }
  44211. }
  44212. }
  44213. for (var n = 0; n < tmpNodesToRemove.length; ++n) {
  44214. delete childNodesObj[tmpNodesToRemove[n]];
  44215. }
  44216. // kill condition: no nodes don't bother
  44217. if ((0, _keys2['default'])(childNodesObj).length == 0) {
  44218. return;
  44219. }
  44220. // allow clusters of 1 if options allow
  44221. if ((0, _keys2['default'])(childNodesObj).length == 1 && options.clusterNodeProperties.allowSingleNodeCluster != true) {
  44222. return;
  44223. }
  44224. var clusterNodeProperties = util.deepExtend({}, options.clusterNodeProperties);
  44225. // construct the clusterNodeProperties
  44226. if (options.processProperties !== undefined) {
  44227. // get the childNode options
  44228. var childNodesOptions = [];
  44229. for (var _nodeId2 in childNodesObj) {
  44230. if (childNodesObj.hasOwnProperty(_nodeId2)) {
  44231. var clonedOptions = NetworkUtil.cloneOptions(childNodesObj[_nodeId2]);
  44232. childNodesOptions.push(clonedOptions);
  44233. }
  44234. }
  44235. // get cluster properties based on childNodes
  44236. var childEdgesOptions = [];
  44237. for (var edgeId in childEdgesObj) {
  44238. if (childEdgesObj.hasOwnProperty(edgeId)) {
  44239. // these cluster edges will be removed on creation of the cluster.
  44240. if (edgeId.substr(0, 12) !== "clusterEdge:") {
  44241. var _clonedOptions = NetworkUtil.cloneOptions(childEdgesObj[edgeId], 'edge');
  44242. childEdgesOptions.push(_clonedOptions);
  44243. }
  44244. }
  44245. }
  44246. clusterNodeProperties = options.processProperties(clusterNodeProperties, childNodesOptions, childEdgesOptions);
  44247. if (!clusterNodeProperties) {
  44248. throw new Error("The processProperties function does not return properties!");
  44249. }
  44250. }
  44251. // check if we have an unique id;
  44252. if (clusterNodeProperties.id === undefined) {
  44253. clusterNodeProperties.id = 'cluster:' + util.randomUUID();
  44254. }
  44255. var clusterId = clusterNodeProperties.id;
  44256. if (clusterNodeProperties.label === undefined) {
  44257. clusterNodeProperties.label = 'cluster';
  44258. }
  44259. // give the clusterNode a position if it does not have one.
  44260. var pos = undefined;
  44261. if (clusterNodeProperties.x === undefined) {
  44262. pos = this._getClusterPosition(childNodesObj);
  44263. clusterNodeProperties.x = pos.x;
  44264. }
  44265. if (clusterNodeProperties.y === undefined) {
  44266. if (pos === undefined) {
  44267. pos = this._getClusterPosition(childNodesObj);
  44268. }
  44269. clusterNodeProperties.y = pos.y;
  44270. }
  44271. // force the ID to remain the same
  44272. clusterNodeProperties.id = clusterId;
  44273. // create the cluster Node
  44274. // Note that allowSingleNodeCluster, if present, is stored in the options as well
  44275. var clusterNode = this.body.functions.createNode(clusterNodeProperties, Cluster);
  44276. clusterNode.containedNodes = childNodesObj;
  44277. clusterNode.containedEdges = childEdgesObj;
  44278. // cache a copy from the cluster edge properties if we have to reconnect others later on
  44279. clusterNode.clusterEdgeProperties = options.clusterEdgeProperties;
  44280. // finally put the cluster node into global
  44281. this.body.nodes[clusterNodeProperties.id] = clusterNode;
  44282. this._clusterEdges(childNodesObj, childEdgesObj, clusterNodeProperties, options.clusterEdgeProperties);
  44283. // set ID to undefined so no duplicates arise
  44284. clusterNodeProperties.id = undefined;
  44285. // wrap up
  44286. if (refreshData === true) {
  44287. this.body.emitter.emit('_dataChanged');
  44288. }
  44289. }
  44290. /**
  44291. *
  44292. * @param {Edge} edge
  44293. * @private
  44294. */
  44295. }, {
  44296. key: '_backupEdgeOptions',
  44297. value: function _backupEdgeOptions(edge) {
  44298. if (this.clusteredEdges[edge.id] === undefined) {
  44299. this.clusteredEdges[edge.id] = { physics: edge.options.physics };
  44300. }
  44301. }
  44302. /**
  44303. *
  44304. * @param {Edge} edge
  44305. * @private
  44306. */
  44307. }, {
  44308. key: '_restoreEdge',
  44309. value: function _restoreEdge(edge) {
  44310. var originalOptions = this.clusteredEdges[edge.id];
  44311. if (originalOptions !== undefined) {
  44312. edge.setOptions({ physics: originalOptions.physics });
  44313. delete this.clusteredEdges[edge.id];
  44314. }
  44315. }
  44316. /**
  44317. * Check if a node is a cluster.
  44318. * @param {Node.id} nodeId
  44319. * @returns {*}
  44320. */
  44321. }, {
  44322. key: 'isCluster',
  44323. value: function isCluster(nodeId) {
  44324. if (this.body.nodes[nodeId] !== undefined) {
  44325. return this.body.nodes[nodeId].isCluster === true;
  44326. } else {
  44327. console.log("Node does not exist.");
  44328. return false;
  44329. }
  44330. }
  44331. /**
  44332. * get the position of the cluster node based on what's inside
  44333. * @param {object} childNodesObj | object with node objects, id as keys
  44334. * @returns {{x: number, y: number}}
  44335. * @private
  44336. */
  44337. }, {
  44338. key: '_getClusterPosition',
  44339. value: function _getClusterPosition(childNodesObj) {
  44340. var childKeys = (0, _keys2['default'])(childNodesObj);
  44341. var minX = childNodesObj[childKeys[0]].x;
  44342. var maxX = childNodesObj[childKeys[0]].x;
  44343. var minY = childNodesObj[childKeys[0]].y;
  44344. var maxY = childNodesObj[childKeys[0]].y;
  44345. var node = void 0;
  44346. for (var i = 1; i < childKeys.length; i++) {
  44347. node = childNodesObj[childKeys[i]];
  44348. minX = node.x < minX ? node.x : minX;
  44349. maxX = node.x > maxX ? node.x : maxX;
  44350. minY = node.y < minY ? node.y : minY;
  44351. maxY = node.y > maxY ? node.y : maxY;
  44352. }
  44353. return { x: 0.5 * (minX + maxX), y: 0.5 * (minY + maxY) };
  44354. }
  44355. /**
  44356. * Open a cluster by calling this function.
  44357. * @param {vis.Edge.id} clusterNodeId | the ID of the cluster node
  44358. * @param {Object} options
  44359. * @param {boolean} refreshData | wrap up afterwards if not true
  44360. */
  44361. }, {
  44362. key: 'openCluster',
  44363. value: function openCluster(clusterNodeId, options) {
  44364. var refreshData = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
  44365. // kill conditions
  44366. if (clusterNodeId === undefined) {
  44367. throw new Error("No clusterNodeId supplied to openCluster.");
  44368. }
  44369. var clusterNode = this.body.nodes[clusterNodeId];
  44370. if (clusterNode === undefined) {
  44371. throw new Error("The clusterNodeId supplied to openCluster does not exist.");
  44372. }
  44373. if (clusterNode.isCluster !== true || clusterNode.containedNodes === undefined || clusterNode.containedEdges === undefined) {
  44374. throw new Error("The node:" + clusterNodeId + " is not a valid cluster.");
  44375. }
  44376. // Check if current cluster is clustered itself
  44377. var stack = this.findNode(clusterNodeId);
  44378. var parentIndex = stack.indexOf(clusterNodeId) - 1;
  44379. if (parentIndex >= 0) {
  44380. // Current cluster is clustered; transfer contained nodes and edges to parent
  44381. var parentClusterNodeId = stack[parentIndex];
  44382. var parentClusterNode = this.body.nodes[parentClusterNodeId];
  44383. // clustering.clusteredNodes and clustering.clusteredEdges remain unchanged
  44384. parentClusterNode._openChildCluster(clusterNodeId);
  44385. // All components of child cluster node have been transferred. It can die now.
  44386. delete this.body.nodes[clusterNodeId];
  44387. if (refreshData === true) {
  44388. this.body.emitter.emit('_dataChanged');
  44389. }
  44390. return;
  44391. }
  44392. // main body
  44393. var containedNodes = clusterNode.containedNodes;
  44394. var containedEdges = clusterNode.containedEdges;
  44395. // allow the user to position the nodes after release.
  44396. if (options !== undefined && options.releaseFunction !== undefined && typeof options.releaseFunction === 'function') {
  44397. var positions = {};
  44398. var clusterPosition = { x: clusterNode.x, y: clusterNode.y };
  44399. for (var _nodeId3 in containedNodes) {
  44400. if (containedNodes.hasOwnProperty(_nodeId3)) {
  44401. var containedNode = this.body.nodes[_nodeId3];
  44402. positions[_nodeId3] = { x: containedNode.x, y: containedNode.y };
  44403. }
  44404. }
  44405. var newPositions = options.releaseFunction(clusterPosition, positions);
  44406. for (var _nodeId4 in containedNodes) {
  44407. if (containedNodes.hasOwnProperty(_nodeId4)) {
  44408. var _containedNode = this.body.nodes[_nodeId4];
  44409. if (newPositions[_nodeId4] !== undefined) {
  44410. _containedNode.x = newPositions[_nodeId4].x === undefined ? clusterNode.x : newPositions[_nodeId4].x;
  44411. _containedNode.y = newPositions[_nodeId4].y === undefined ? clusterNode.y : newPositions[_nodeId4].y;
  44412. }
  44413. }
  44414. }
  44415. } else {
  44416. // copy the position from the cluster
  44417. util.forEach(containedNodes, function(containedNode) {
  44418. // inherit position
  44419. if (containedNode.options.fixed.x === false) {
  44420. containedNode.x = clusterNode.x;
  44421. }
  44422. if (containedNode.options.fixed.y === false) {
  44423. containedNode.y = clusterNode.y;
  44424. }
  44425. });
  44426. }
  44427. // release nodes
  44428. for (var _nodeId5 in containedNodes) {
  44429. if (containedNodes.hasOwnProperty(_nodeId5)) {
  44430. var _containedNode2 = this.body.nodes[_nodeId5];
  44431. // inherit speed
  44432. _containedNode2.vx = clusterNode.vx;
  44433. _containedNode2.vy = clusterNode.vy;
  44434. _containedNode2.setOptions({ physics: true });
  44435. delete this.clusteredNodes[_nodeId5];
  44436. }
  44437. }
  44438. // copy the clusterNode edges because we cannot iterate over an object that we add or remove from.
  44439. var edgesToBeDeleted = [];
  44440. for (var i = 0; i < clusterNode.edges.length; i++) {
  44441. edgesToBeDeleted.push(clusterNode.edges[i]);
  44442. }
  44443. // actually handling the deleting.
  44444. for (var _i2 = 0; _i2 < edgesToBeDeleted.length; _i2++) {
  44445. var edge = edgesToBeDeleted[_i2];
  44446. var otherNodeId = this._getConnectedId(edge, clusterNodeId);
  44447. var otherNode = this.clusteredNodes[otherNodeId];
  44448. for (var j = 0; j < edge.clusteringEdgeReplacingIds.length; j++) {
  44449. var transferId = edge.clusteringEdgeReplacingIds[j];
  44450. var transferEdge = this.body.edges[transferId];
  44451. if (transferEdge === undefined) continue;
  44452. // if the other node is in another cluster, we transfer ownership of this edge to the other cluster
  44453. if (otherNode !== undefined) {
  44454. // transfer ownership:
  44455. var otherCluster = this.body.nodes[otherNode.clusterId];
  44456. otherCluster.containedEdges[transferEdge.id] = transferEdge;
  44457. // delete local reference
  44458. delete containedEdges[transferEdge.id];
  44459. // get to and from
  44460. var fromId = transferEdge.fromId;
  44461. var toId = transferEdge.toId;
  44462. if (transferEdge.toId == otherNodeId) {
  44463. toId = otherNode.clusterId;
  44464. } else {
  44465. fromId = otherNode.clusterId;
  44466. }
  44467. // create new cluster edge from the otherCluster
  44468. this._createClusteredEdge(fromId, toId, transferEdge, otherCluster.clusterEdgeProperties, { hidden: false, physics: true });
  44469. } else {
  44470. this._restoreEdge(transferEdge);
  44471. }
  44472. }
  44473. edge.remove();
  44474. }
  44475. // handle the releasing of the edges
  44476. for (var edgeId in containedEdges) {
  44477. if (containedEdges.hasOwnProperty(edgeId)) {
  44478. this._restoreEdge(containedEdges[edgeId]);
  44479. }
  44480. }
  44481. // remove clusterNode
  44482. delete this.body.nodes[clusterNodeId];
  44483. if (refreshData === true) {
  44484. this.body.emitter.emit('_dataChanged');
  44485. }
  44486. }
  44487. /**
  44488. *
  44489. * @param {Cluster.id} clusterId
  44490. * @returns {Array.<Node.id>}
  44491. */
  44492. }, {
  44493. key: 'getNodesInCluster',
  44494. value: function getNodesInCluster(clusterId) {
  44495. var nodesArray = [];
  44496. if (this.isCluster(clusterId) === true) {
  44497. var containedNodes = this.body.nodes[clusterId].containedNodes;
  44498. for (var _nodeId6 in containedNodes) {
  44499. if (containedNodes.hasOwnProperty(_nodeId6)) {
  44500. nodesArray.push(this.body.nodes[_nodeId6].id);
  44501. }
  44502. }
  44503. }
  44504. return nodesArray;
  44505. }
  44506. /**
  44507. * Get the stack clusterId's that a certain node resides in. cluster A -> cluster B -> cluster C -> node
  44508. *
  44509. * If a node can't be found in the chain, return an empty array.
  44510. *
  44511. * @param {string|number} nodeId
  44512. * @returns {Array}
  44513. */
  44514. }, {
  44515. key: 'findNode',
  44516. value: function findNode(nodeId) {
  44517. var stack = [];
  44518. var max = 100;
  44519. var counter = 0;
  44520. var node = void 0;
  44521. while (this.clusteredNodes[nodeId] !== undefined && counter < max) {
  44522. node = this.body.nodes[nodeId];
  44523. if (node === undefined) return [];
  44524. stack.push(node.id);
  44525. nodeId = this.clusteredNodes[nodeId].clusterId;
  44526. counter++;
  44527. }
  44528. node = this.body.nodes[nodeId];
  44529. if (node === undefined) return [];
  44530. stack.push(node.id);
  44531. stack.reverse();
  44532. return stack;
  44533. }
  44534. /**
  44535. * Using a clustered nodeId, update with the new options
  44536. * @param {vis.Edge.id} clusteredNodeId
  44537. * @param {object} newOptions
  44538. */
  44539. }, {
  44540. key: 'updateClusteredNode',
  44541. value: function updateClusteredNode(clusteredNodeId, newOptions) {
  44542. if (clusteredNodeId === undefined) {
  44543. throw new Error("No clusteredNodeId supplied to updateClusteredNode.");
  44544. }
  44545. if (newOptions === undefined) {
  44546. throw new Error("No newOptions supplied to updateClusteredNode.");
  44547. }
  44548. if (this.body.nodes[clusteredNodeId] === undefined) {
  44549. throw new Error("The clusteredNodeId supplied to updateClusteredNode does not exist.");
  44550. }
  44551. this.body.nodes[clusteredNodeId].setOptions(newOptions);
  44552. this.body.emitter.emit('_dataChanged');
  44553. }
  44554. /**
  44555. * Using a base edgeId, update all related clustered edges with the new options
  44556. * @param {vis.Edge.id} startEdgeId
  44557. * @param {object} newOptions
  44558. */
  44559. }, {
  44560. key: 'updateEdge',
  44561. value: function updateEdge(startEdgeId, newOptions) {
  44562. if (startEdgeId === undefined) {
  44563. throw new Error("No startEdgeId supplied to updateEdge.");
  44564. }
  44565. if (newOptions === undefined) {
  44566. throw new Error("No newOptions supplied to updateEdge.");
  44567. }
  44568. if (this.body.edges[startEdgeId] === undefined) {
  44569. throw new Error("The startEdgeId supplied to updateEdge does not exist.");
  44570. }
  44571. var allEdgeIds = this.getClusteredEdges(startEdgeId);
  44572. for (var i = 0; i < allEdgeIds.length; i++) {
  44573. var edge = this.body.edges[allEdgeIds[i]];
  44574. edge.setOptions(newOptions);
  44575. }
  44576. this.body.emitter.emit('_dataChanged');
  44577. }
  44578. /**
  44579. * Get a stack of clusterEdgeId's (+base edgeid) that a base edge is the same as. cluster edge C -> cluster edge B -> cluster edge A -> base edge(edgeId)
  44580. * @param {vis.Edge.id} edgeId
  44581. * @returns {Array.<vis.Edge.id>}
  44582. */
  44583. }, {
  44584. key: 'getClusteredEdges',
  44585. value: function getClusteredEdges(edgeId) {
  44586. var stack = [];
  44587. var max = 100;
  44588. var counter = 0;
  44589. while (edgeId !== undefined && this.body.edges[edgeId] !== undefined && counter < max) {
  44590. stack.push(this.body.edges[edgeId].id);
  44591. edgeId = this.body.edges[edgeId].edgeReplacedById;
  44592. counter++;
  44593. }
  44594. stack.reverse();
  44595. return stack;
  44596. }
  44597. /**
  44598. * Get the base edge id of clusterEdgeId. cluster edge (clusteredEdgeId) -> cluster edge B -> cluster edge C -> base edge
  44599. * @param {vis.Edge.id} clusteredEdgeId
  44600. * @returns {vis.Edge.id} baseEdgeId
  44601. *
  44602. * TODO: deprecate in 5.0.0. Method getBaseEdges() is the correct one to use.
  44603. */
  44604. }, {
  44605. key: 'getBaseEdge',
  44606. value: function getBaseEdge(clusteredEdgeId) {
  44607. // Just kludge this by returning the first base edge id found
  44608. return this.getBaseEdges(clusteredEdgeId)[0];
  44609. }
  44610. /**
  44611. * Get all regular edges for this clustered edge id.
  44612. *
  44613. * @param {vis.Edge.id} clusteredEdgeId
  44614. * @returns {Array.<vis.Edge.id>} all baseEdgeId's under this clustered edge
  44615. */
  44616. }, {
  44617. key: 'getBaseEdges',
  44618. value: function getBaseEdges(clusteredEdgeId) {
  44619. var IdsToHandle = [clusteredEdgeId];
  44620. var doneIds = [];
  44621. var foundIds = [];
  44622. var max = 100;
  44623. var counter = 0;
  44624. while (IdsToHandle.length > 0 && counter < max) {
  44625. var nextId = IdsToHandle.pop();
  44626. if (nextId === undefined) continue; // Paranoia here and onwards
  44627. var nextEdge = this.body.edges[nextId];
  44628. if (nextEdge === undefined) continue;
  44629. counter++;
  44630. var replacingIds = nextEdge.clusteringEdgeReplacingIds;
  44631. if (replacingIds === undefined) {
  44632. // nextId is a base id
  44633. foundIds.push(nextId);
  44634. } else {
  44635. // Another cluster edge, unravel this one as well
  44636. for (var i = 0; i < replacingIds.length; ++i) {
  44637. var replacingId = replacingIds[i];
  44638. // Don't add if already handled
  44639. // TODO: never triggers; find a test-case which does
  44640. if (IdsToHandle.indexOf(replacingIds) !== -1 || doneIds.indexOf(replacingIds) !== -1) {
  44641. continue;
  44642. }
  44643. IdsToHandle.push(replacingId);
  44644. }
  44645. }
  44646. doneIds.push(nextId);
  44647. }
  44648. return foundIds;
  44649. }
  44650. /**
  44651. * Get the Id the node is connected to
  44652. * @param {vis.Edge} edge
  44653. * @param {Node.id} nodeId
  44654. * @returns {*}
  44655. * @private
  44656. */
  44657. }, {
  44658. key: '_getConnectedId',
  44659. value: function _getConnectedId(edge, nodeId) {
  44660. if (edge.toId != nodeId) {
  44661. return edge.toId;
  44662. } else if (edge.fromId != nodeId) {
  44663. return edge.fromId;
  44664. } else {
  44665. return edge.fromId;
  44666. }
  44667. }
  44668. /**
  44669. * We determine how many connections denote an important hub.
  44670. * We take the mean + 2*std as the important hub size. (Assuming a normal distribution of data, ~2.2%)
  44671. *
  44672. * @returns {number}
  44673. * @private
  44674. */
  44675. }, {
  44676. key: '_getHubSize',
  44677. value: function _getHubSize() {
  44678. var average = 0;
  44679. var averageSquared = 0;
  44680. var hubCounter = 0;
  44681. var largestHub = 0;
  44682. for (var i = 0; i < this.body.nodeIndices.length; i++) {
  44683. var _node = this.body.nodes[this.body.nodeIndices[i]];
  44684. if (_node.edges.length > largestHub) {
  44685. largestHub = _node.edges.length;
  44686. }
  44687. average += _node.edges.length;
  44688. averageSquared += Math.pow(_node.edges.length, 2);
  44689. hubCounter += 1;
  44690. }
  44691. average = average / hubCounter;
  44692. averageSquared = averageSquared / hubCounter;
  44693. var variance = averageSquared - Math.pow(average, 2);
  44694. var standardDeviation = Math.sqrt(variance);
  44695. var hubThreshold = Math.floor(average + 2 * standardDeviation);
  44696. // always have at least one to cluster
  44697. if (hubThreshold > largestHub) {
  44698. hubThreshold = largestHub;
  44699. }
  44700. return hubThreshold;
  44701. }
  44702. /**
  44703. * Create an edge for the cluster representation.
  44704. *
  44705. * @param {Node.id} fromId
  44706. * @param {Node.id} toId
  44707. * @param {vis.Edge} baseEdge
  44708. * @param {Object} clusterEdgeProperties
  44709. * @param {Object} extraOptions
  44710. * @returns {Edge} newly created clustered edge
  44711. * @private
  44712. */
  44713. }, {
  44714. key: '_createClusteredEdge',
  44715. value: function _createClusteredEdge(fromId, toId, baseEdge, clusterEdgeProperties, extraOptions) {
  44716. // copy the options of the edge we will replace
  44717. var clonedOptions = NetworkUtil.cloneOptions(baseEdge, 'edge');
  44718. // make sure the properties of clusterEdges are superimposed on it
  44719. util.deepExtend(clonedOptions, clusterEdgeProperties);
  44720. // set up the edge
  44721. clonedOptions.from = fromId;
  44722. clonedOptions.to = toId;
  44723. clonedOptions.id = 'clusterEdge:' + util.randomUUID();
  44724. // apply the edge specific options to it if specified
  44725. if (extraOptions !== undefined) {
  44726. util.deepExtend(clonedOptions, extraOptions);
  44727. }
  44728. var newEdge = this.body.functions.createEdge(clonedOptions);
  44729. newEdge.clusteringEdgeReplacingIds = [baseEdge.id];
  44730. newEdge.connect();
  44731. // Register the new edge
  44732. this.body.edges[newEdge.id] = newEdge;
  44733. return newEdge;
  44734. }
  44735. /**
  44736. * Add the passed child nodes and edges to the given cluster node.
  44737. *
  44738. * @param {Object|Node} childNodes hash of nodes or single node to add in cluster
  44739. * @param {Object|Edge} childEdges hash of edges or single edge to take into account when clustering
  44740. * @param {Node} clusterNode cluster node to add nodes and edges to
  44741. * @param {Object} [clusterEdgeProperties]
  44742. * @private
  44743. */
  44744. }, {
  44745. key: '_clusterEdges',
  44746. value: function _clusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties) {
  44747. if (childEdges instanceof Edge) {
  44748. var edge = childEdges;
  44749. var obj = {};
  44750. obj[edge.id] = edge;
  44751. childEdges = obj;
  44752. }
  44753. if (childNodes instanceof Node) {
  44754. var _node2 = childNodes;
  44755. var _obj = {};
  44756. _obj[_node2.id] = _node2;
  44757. childNodes = _obj;
  44758. }
  44759. if (clusterNode === undefined || clusterNode === null) {
  44760. throw new Error("_clusterEdges: parameter clusterNode required");
  44761. }
  44762. if (clusterEdgeProperties === undefined) {
  44763. // Take the required properties from the cluster node
  44764. clusterEdgeProperties = clusterNode.clusterEdgeProperties;
  44765. }
  44766. // create the new edges that will connect to the cluster.
  44767. // All self-referencing edges will be added to childEdges here.
  44768. this._createClusterEdges(childNodes, childEdges, clusterNode, clusterEdgeProperties);
  44769. // disable the childEdges
  44770. for (var edgeId in childEdges) {
  44771. if (childEdges.hasOwnProperty(edgeId)) {
  44772. if (this.body.edges[edgeId] !== undefined) {
  44773. var _edge2 = this.body.edges[edgeId];
  44774. // cache the options before changing
  44775. this._backupEdgeOptions(_edge2);
  44776. // disable physics and hide the edge
  44777. _edge2.setOptions({ physics: false });
  44778. }
  44779. }
  44780. }
  44781. // disable the childNodes
  44782. for (var _nodeId7 in childNodes) {
  44783. if (childNodes.hasOwnProperty(_nodeId7)) {
  44784. this.clusteredNodes[_nodeId7] = { clusterId: clusterNode.id, node: this.body.nodes[_nodeId7] };
  44785. this.body.nodes[_nodeId7].setOptions({ physics: false });
  44786. }
  44787. }
  44788. }
  44789. /**
  44790. * Determine in which cluster given nodeId resides.
  44791. *
  44792. * If not in cluster, return undefined.
  44793. *
  44794. * NOTE: If you know a cleaner way to do this, please enlighten me (wimrijnders).
  44795. *
  44796. * @param {Node.id} nodeId
  44797. * @returns {Node|undefined} Node instance for cluster, if present
  44798. * @private
  44799. */
  44800. }, {
  44801. key: '_getClusterNodeForNode',
  44802. value: function _getClusterNodeForNode(nodeId) {
  44803. if (nodeId === undefined) return undefined;
  44804. var clusteredNode = this.clusteredNodes[nodeId];
  44805. // NOTE: If no cluster info found, it should actually be an error
  44806. if (clusteredNode === undefined) return undefined;
  44807. var clusterId = clusteredNode.clusterId;
  44808. if (clusterId === undefined) return undefined;
  44809. return this.body.nodes[clusterId];
  44810. }
  44811. /**
  44812. * Internal helper function for conditionally removing items in array
  44813. *
  44814. * Done like this because Array.filter() is not fully supported by all IE's.
  44815. *
  44816. * @param {Array} arr
  44817. * @param {function} callback
  44818. * @returns {Array}
  44819. * @private
  44820. */
  44821. }, {
  44822. key: '_filter',
  44823. value: function _filter(arr, callback) {
  44824. var ret = [];
  44825. util.forEach(arr, function(item) {
  44826. if (callback(item)) {
  44827. ret.push(item);
  44828. }
  44829. });
  44830. return ret;
  44831. }
  44832. /**
  44833. * Scan all edges for changes in clustering and adjust this if necessary.
  44834. *
  44835. * Call this (internally) after there has been a change in node or edge data.
  44836. *
  44837. * Pre: States of this.body.nodes and this.body.edges consistent
  44838. * Pre: this.clusteredNodes and this.clusteredEdge consistent with containedNodes and containedEdges
  44839. * of cluster nodes.
  44840. */
  44841. }, {
  44842. key: '_updateState',
  44843. value: function _updateState() {
  44844. var _this4 = this;
  44845. var nodeId = void 0;
  44846. var deletedNodeIds = [];
  44847. var deletedEdgeIds = [];
  44848. /**
  44849. * Utility function to iterate over clustering nodes only
  44850. *
  44851. * @param {Function} callback function to call for each cluster node
  44852. */
  44853. var eachClusterNode = function eachClusterNode(callback) {
  44854. util.forEach(_this4.body.nodes, function(node) {
  44855. if (node.isCluster === true) {
  44856. callback(node);
  44857. }
  44858. });
  44859. };
  44860. //
  44861. // Remove deleted regular nodes from clustering
  44862. //
  44863. // Determine the deleted nodes
  44864. for (nodeId in this.clusteredNodes) {
  44865. if (!this.clusteredNodes.hasOwnProperty(nodeId)) continue;
  44866. var _node3 = this.body.nodes[nodeId];
  44867. if (_node3 === undefined) {
  44868. deletedNodeIds.push(nodeId);
  44869. }
  44870. }
  44871. // Remove nodes from cluster nodes
  44872. eachClusterNode(function(clusterNode) {
  44873. for (var n = 0; n < deletedNodeIds.length; n++) {
  44874. delete clusterNode.containedNodes[deletedNodeIds[n]];
  44875. }
  44876. });
  44877. // Remove nodes from cluster list
  44878. for (var n = 0; n < deletedNodeIds.length; n++) {
  44879. delete this.clusteredNodes[deletedNodeIds[n]];
  44880. }
  44881. //
  44882. // Remove deleted edges from clustering
  44883. //
  44884. // Add the deleted clustered edges to the list
  44885. util.forEach(this.clusteredEdges, function(edgeId) {
  44886. var edge = _this4.body.edges[edgeId];
  44887. if (edge === undefined || !edge.endPointsValid()) {
  44888. deletedEdgeIds.push(edgeId);
  44889. }
  44890. });
  44891. // Cluster nodes can also contain edges which are not clustered,
  44892. // i.e. nodes 1-2 within cluster with an edge in between.
  44893. // So the cluster nodes also need to be scanned for invalid edges
  44894. eachClusterNode(function(clusterNode) {
  44895. util.forEach(clusterNode.containedEdges, function(edge, edgeId) {
  44896. if (!edge.endPointsValid() && deletedEdgeIds.indexOf(edgeId) === -1) {
  44897. deletedEdgeIds.push(edgeId);
  44898. }
  44899. });
  44900. });
  44901. // Also scan for cluster edges which need to be removed in the active list.
  44902. // Regular edges have been removed beforehand, so this only picks up the cluster edges.
  44903. util.forEach(this.body.edges, function(edge, edgeId) {
  44904. // Explicitly scan the contained edges for validity
  44905. var isValid = true;
  44906. var replacedIds = edge.clusteringEdgeReplacingIds;
  44907. if (replacedIds !== undefined) {
  44908. var numValid = 0;
  44909. util.forEach(replacedIds, function(containedEdgeId) {
  44910. var containedEdge = _this4.body.edges[containedEdgeId];
  44911. if (containedEdge !== undefined && containedEdge.endPointsValid()) {
  44912. numValid += 1;
  44913. }
  44914. });
  44915. isValid = numValid > 0;
  44916. }
  44917. if (!edge.endPointsValid() || !isValid) {
  44918. deletedEdgeIds.push(edgeId);
  44919. }
  44920. });
  44921. // Remove edges from cluster nodes
  44922. eachClusterNode(function(clusterNode) {
  44923. util.forEach(deletedEdgeIds, function(deletedEdgeId) {
  44924. delete clusterNode.containedEdges[deletedEdgeId];
  44925. util.forEach(clusterNode.edges, function(edge, m) {
  44926. if (edge.id === deletedEdgeId) {
  44927. clusterNode.edges[m] = null; // Don't want to directly delete here, because in the loop
  44928. return;
  44929. }
  44930. edge.clusteringEdgeReplacingIds = _this4._filter(edge.clusteringEdgeReplacingIds, function(id) {
  44931. return deletedEdgeIds.indexOf(id) === -1;
  44932. });
  44933. });
  44934. // Clean up the nulls
  44935. clusterNode.edges = _this4._filter(clusterNode.edges, function(item) {
  44936. return item !== null;
  44937. });
  44938. });
  44939. });
  44940. // Remove from cluster list
  44941. util.forEach(deletedEdgeIds, function(edgeId) {
  44942. delete _this4.clusteredEdges[edgeId];
  44943. });
  44944. // Remove cluster edges from active list (this.body.edges).
  44945. // deletedEdgeIds still contains id of regular edges, but these should all
  44946. // be gone when you reach here.
  44947. util.forEach(deletedEdgeIds, function(edgeId) {
  44948. delete _this4.body.edges[edgeId];
  44949. });
  44950. //
  44951. // Check changed cluster state of edges
  44952. //
  44953. // Iterating over keys here, because edges may be removed in the loop
  44954. var ids = (0, _keys2['default'])(this.body.edges);
  44955. util.forEach(ids, function(edgeId) {
  44956. var edge = _this4.body.edges[edgeId];
  44957. var shouldBeClustered = _this4._isClusteredNode(edge.fromId) || _this4._isClusteredNode(edge.toId);
  44958. if (shouldBeClustered === _this4._isClusteredEdge(edge.id)) {
  44959. return; // all is well
  44960. }
  44961. if (shouldBeClustered) {
  44962. // add edge to clustering
  44963. var clusterFrom = _this4._getClusterNodeForNode(edge.fromId);
  44964. if (clusterFrom !== undefined) {
  44965. _this4._clusterEdges(_this4.body.nodes[edge.fromId], edge, clusterFrom);
  44966. }
  44967. var clusterTo = _this4._getClusterNodeForNode(edge.toId);
  44968. if (clusterTo !== undefined) {
  44969. _this4._clusterEdges(_this4.body.nodes[edge.toId], edge, clusterTo);
  44970. }
  44971. // TODO: check that it works for both edges clustered
  44972. // (This might be paranoia)
  44973. } else {
  44974. // This should not be happening, the state should
  44975. // be properly updated at this point.
  44976. //
  44977. // If it *is* reached during normal operation, then we have to implement
  44978. // undo clustering for this edge here.
  44979. throw new Error('remove edge from clustering not implemented!');
  44980. }
  44981. });
  44982. // Clusters may be nested to any level. Keep on opening until nothing to open
  44983. var changed = false;
  44984. var continueLoop = true;
  44985. var _loop2 = function _loop2() {
  44986. var clustersToOpen = [];
  44987. // Determine the id's of clusters that need opening
  44988. eachClusterNode(function(clusterNode) {
  44989. var numNodes = (0, _keys2['default'])(clusterNode.containedNodes).length;
  44990. var allowSingle = clusterNode.options.allowSingleNodeCluster === true;
  44991. if (allowSingle && numNodes < 1 || !allowSingle && numNodes < 2) {
  44992. clustersToOpen.push(clusterNode.id);
  44993. }
  44994. });
  44995. // Open them
  44996. for (var _n = 0; _n < clustersToOpen.length; ++_n) {
  44997. _this4.openCluster(clustersToOpen[_n], {}, false /* Don't refresh, we're in an refresh/update already */ );
  44998. }
  44999. continueLoop = clustersToOpen.length > 0;
  45000. changed = changed || continueLoop;
  45001. };
  45002. while (continueLoop) {
  45003. _loop2();
  45004. }
  45005. if (changed) {
  45006. this._updateState(); // Redo this method (recursion possible! should be safe)
  45007. }
  45008. }
  45009. /**
  45010. * Determine if node with given id is part of a cluster.
  45011. *
  45012. * @param {Node.id} nodeId
  45013. * @return {boolean} true if part of a cluster.
  45014. */
  45015. }, {
  45016. key: '_isClusteredNode',
  45017. value: function _isClusteredNode(nodeId) {
  45018. return this.clusteredNodes[nodeId] !== undefined;
  45019. }
  45020. /**
  45021. * Determine if edge with given id is not visible due to clustering.
  45022. *
  45023. * An edge is considered clustered if:
  45024. * - it is directly replaced by a clustering edge
  45025. * - any of its connecting nodes is in a cluster
  45026. *
  45027. * @param {vis.Edge.id} edgeId
  45028. * @return {boolean} true if part of a cluster.
  45029. */
  45030. }, {
  45031. key: '_isClusteredEdge',
  45032. value: function _isClusteredEdge(edgeId) {
  45033. return this.clusteredEdges[edgeId] !== undefined;
  45034. }
  45035. }]);
  45036. return ClusterEngine;
  45037. }();
  45038. exports['default'] = ClusterEngine;
  45039. /***/
  45040. }),
  45041. /* 228 */
  45042. /***/
  45043. (function(module, exports, __webpack_require__) {
  45044. "use strict";
  45045. Object.defineProperty(exports, "__esModule", {
  45046. value: true
  45047. });
  45048. var _getPrototypeOf = __webpack_require__(3);
  45049. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  45050. var _classCallCheck2 = __webpack_require__(0);
  45051. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  45052. var _createClass2 = __webpack_require__(1);
  45053. var _createClass3 = _interopRequireDefault(_createClass2);
  45054. var _possibleConstructorReturn2 = __webpack_require__(4);
  45055. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  45056. var _inherits2 = __webpack_require__(5);
  45057. var _inherits3 = _interopRequireDefault(_inherits2);
  45058. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  45059. var util = __webpack_require__(2);
  45060. var Node = __webpack_require__(47)["default"];
  45061. /**
  45062. * A Cluster is a special Node that allows a group of Nodes positioned closely together
  45063. * to be represented by a single Cluster Node.
  45064. *
  45065. * @extends Node
  45066. */
  45067. var Cluster = function(_Node) {
  45068. (0, _inherits3["default"])(Cluster, _Node);
  45069. /**
  45070. * @param {Object} options
  45071. * @param {Object} body
  45072. * @param {Array.<HTMLImageElement>}imagelist
  45073. * @param {Array} grouplist
  45074. * @param {Object} globalOptions
  45075. * @param {Object} defaultOptions Global default options for nodes
  45076. */
  45077. function Cluster(options, body, imagelist, grouplist, globalOptions, defaultOptions) {
  45078. (0, _classCallCheck3["default"])(this, Cluster);
  45079. var _this = (0, _possibleConstructorReturn3["default"])(this, (Cluster.__proto__ || (0, _getPrototypeOf2["default"])(Cluster)).call(this, options, body, imagelist, grouplist, globalOptions, defaultOptions));
  45080. _this.isCluster = true;
  45081. _this.containedNodes = {};
  45082. _this.containedEdges = {};
  45083. return _this;
  45084. }
  45085. /**
  45086. * Transfer child cluster data to current and disconnect the child cluster.
  45087. *
  45088. * Please consult the header comment in 'Clustering.js' for the fields set here.
  45089. *
  45090. * @param {string|number} childClusterId id of child cluster to open
  45091. */
  45092. (0, _createClass3["default"])(Cluster, [{
  45093. key: "_openChildCluster",
  45094. value: function _openChildCluster(childClusterId) {
  45095. var _this2 = this;
  45096. var childCluster = this.body.nodes[childClusterId];
  45097. if (this.containedNodes[childClusterId] === undefined) {
  45098. throw new Error('node with id: ' + childClusterId + ' not in current cluster');
  45099. }
  45100. if (!childCluster.isCluster) {
  45101. throw new Error('node with id: ' + childClusterId + ' is not a cluster');
  45102. }
  45103. // Disconnect child cluster from current cluster
  45104. delete this.containedNodes[childClusterId];
  45105. util.forEach(childCluster.edges, function(edge) {
  45106. delete _this2.containedEdges[edge.id];
  45107. });
  45108. // Transfer nodes and edges
  45109. util.forEach(childCluster.containedNodes, function(node, nodeId) {
  45110. _this2.containedNodes[nodeId] = node;
  45111. });
  45112. childCluster.containedNodes = {};
  45113. util.forEach(childCluster.containedEdges, function(edge, edgeId) {
  45114. _this2.containedEdges[edgeId] = edge;
  45115. });
  45116. childCluster.containedEdges = {};
  45117. // Transfer edges within cluster edges which are clustered
  45118. util.forEach(childCluster.edges, function(clusterEdge) {
  45119. util.forEach(_this2.edges, function(parentClusterEdge) {
  45120. // Assumption: a clustered edge can only be present in a single clustering edge
  45121. // Not tested here
  45122. var index = parentClusterEdge.clusteringEdgeReplacingIds.indexOf(clusterEdge.id);
  45123. if (index === -1) return;
  45124. util.forEach(clusterEdge.clusteringEdgeReplacingIds, function(srcId) {
  45125. parentClusterEdge.clusteringEdgeReplacingIds.push(srcId);
  45126. // Maintain correct bookkeeping for transferred edge
  45127. _this2.body.edges[srcId].edgeReplacedById = parentClusterEdge.id;
  45128. });
  45129. // Remove cluster edge from parent cluster edge
  45130. parentClusterEdge.clusteringEdgeReplacingIds.splice(index, 1);
  45131. });
  45132. });
  45133. childCluster.edges = [];
  45134. }
  45135. }]);
  45136. return Cluster;
  45137. }(Node);
  45138. exports["default"] = Cluster;
  45139. /***/
  45140. }),
  45141. /* 229 */
  45142. /***/
  45143. (function(module, exports, __webpack_require__) {
  45144. "use strict";
  45145. Object.defineProperty(exports, "__esModule", {
  45146. value: true
  45147. });
  45148. var _classCallCheck2 = __webpack_require__(0);
  45149. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  45150. var _createClass2 = __webpack_require__(1);
  45151. var _createClass3 = _interopRequireDefault(_createClass2);
  45152. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  45153. /**
  45154. * Initializes window.requestAnimationFrame() to a usable form.
  45155. *
  45156. * Specifically, set up this method for the case of running on node.js with jsdom enabled.
  45157. *
  45158. * NOTES:
  45159. *
  45160. * * On node.js, when calling this directly outside of this class, `window` is not defined.
  45161. * This happens even if jsdom is used.
  45162. * * For node.js + jsdom, `window` is available at the moment the constructor is called.
  45163. * For this reason, the called is placed within the constructor.
  45164. * * Even then, `window.requestAnimationFrame()` is not defined, so it still needs to be added.
  45165. * * During unit testing, it happens that the window object is reset during execution, causing
  45166. * a runtime error due to missing `requestAnimationFrame()`. This needs to be compensated for,
  45167. * see `_requestNextFrame()`.
  45168. * * Since this is a global object, it may affect other modules besides `Network`. With normal
  45169. * usage, this does not cause any problems. During unit testing, errors may occur. These have
  45170. * been compensated for, see comment block in _requestNextFrame().
  45171. *
  45172. * @private
  45173. */
  45174. function _initRequestAnimationFrame() {
  45175. var func;
  45176. if (window !== undefined) {
  45177. func = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
  45178. }
  45179. if (func === undefined) {
  45180. // window or method not present, setting mock requestAnimationFrame
  45181. window.requestAnimationFrame = function(callback) {
  45182. //console.log("Called mock requestAnimationFrame");
  45183. callback();
  45184. };
  45185. } else {
  45186. window.requestAnimationFrame = func;
  45187. }
  45188. }
  45189. var util = __webpack_require__(2);
  45190. /**
  45191. * The canvas renderer
  45192. */
  45193. var CanvasRenderer = function() {
  45194. /**
  45195. * @param {Object} body
  45196. * @param {Canvas} canvas
  45197. */
  45198. function CanvasRenderer(body, canvas) {
  45199. (0, _classCallCheck3["default"])(this, CanvasRenderer);
  45200. _initRequestAnimationFrame();
  45201. this.body = body;
  45202. this.canvas = canvas;
  45203. this.redrawRequested = false;
  45204. this.renderTimer = undefined;
  45205. this.requiresTimeout = true;
  45206. this.renderingActive = false;
  45207. this.renderRequests = 0;
  45208. this.allowRedraw = true;
  45209. this.dragging = false;
  45210. this.options = {};
  45211. this.defaultOptions = {
  45212. hideEdgesOnDrag: false,
  45213. hideNodesOnDrag: false
  45214. };
  45215. util.extend(this.options, this.defaultOptions);
  45216. this._determineBrowserMethod();
  45217. this.bindEventListeners();
  45218. }
  45219. /**
  45220. * Binds event listeners
  45221. */
  45222. (0, _createClass3["default"])(CanvasRenderer, [{
  45223. key: "bindEventListeners",
  45224. value: function bindEventListeners() {
  45225. var _this = this;
  45226. this.body.emitter.on("dragStart", function() {
  45227. _this.dragging = true;
  45228. });
  45229. this.body.emitter.on("dragEnd", function() {
  45230. _this.dragging = false;
  45231. });
  45232. this.body.emitter.on("_resizeNodes", function() {
  45233. _this._resizeNodes();
  45234. });
  45235. this.body.emitter.on("_redraw", function() {
  45236. if (_this.renderingActive === false) {
  45237. _this._redraw();
  45238. }
  45239. });
  45240. this.body.emitter.on("_blockRedraw", function() {
  45241. _this.allowRedraw = false;
  45242. });
  45243. this.body.emitter.on("_allowRedraw", function() {
  45244. _this.allowRedraw = true;
  45245. _this.redrawRequested = false;
  45246. });
  45247. this.body.emitter.on("_requestRedraw", this._requestRedraw.bind(this));
  45248. this.body.emitter.on("_startRendering", function() {
  45249. _this.renderRequests += 1;
  45250. _this.renderingActive = true;
  45251. _this._startRendering();
  45252. });
  45253. this.body.emitter.on("_stopRendering", function() {
  45254. _this.renderRequests -= 1;
  45255. _this.renderingActive = _this.renderRequests > 0;
  45256. _this.renderTimer = undefined;
  45257. });
  45258. this.body.emitter.on('destroy', function() {
  45259. _this.renderRequests = 0;
  45260. _this.allowRedraw = false;
  45261. _this.renderingActive = false;
  45262. if (_this.requiresTimeout === true) {
  45263. clearTimeout(_this.renderTimer);
  45264. } else {
  45265. window.cancelAnimationFrame(_this.renderTimer);
  45266. }
  45267. _this.body.emitter.off();
  45268. });
  45269. }
  45270. /**
  45271. *
  45272. * @param {Object} options
  45273. */
  45274. }, {
  45275. key: "setOptions",
  45276. value: function setOptions(options) {
  45277. if (options !== undefined) {
  45278. var fields = ['hideEdgesOnDrag', 'hideNodesOnDrag'];
  45279. util.selectiveDeepExtend(fields, this.options, options);
  45280. }
  45281. }
  45282. /**
  45283. * Prepare the drawing of the next frame.
  45284. *
  45285. * Calls the callback when the next frame can or will be drawn.
  45286. *
  45287. * @param {function} callback
  45288. * @param {number} delay - timeout case only, wait this number of milliseconds
  45289. * @returns {function|undefined}
  45290. * @private
  45291. */
  45292. }, {
  45293. key: "_requestNextFrame",
  45294. value: function _requestNextFrame(callback, delay) {
  45295. // During unit testing, it happens that the mock window object is reset while
  45296. // the next frame is still pending. Then, either 'window' is not present, or
  45297. // 'requestAnimationFrame()' is not present because it is not defined on the
  45298. // mock window object.
  45299. //
  45300. // As a consequence, unrelated unit tests may appear to fail, even if the problem
  45301. // described happens in the current unit test.
  45302. //
  45303. // This is not something that will happen in normal operation, but we still need
  45304. // to take it into account.
  45305. //
  45306. if (typeof window === 'undefined') return; // Doing `if (window === undefined)` does not work here!
  45307. var timer = void 0;
  45308. var myWindow = window; // Grab a reference to reduce the possibility that 'window' is reset
  45309. // while running this method.
  45310. if (this.requiresTimeout === true) {
  45311. // wait given number of milliseconds and perform the animation step function
  45312. timer = myWindow.setTimeout(callback, delay);
  45313. } else {
  45314. if (myWindow.requestAnimationFrame) {
  45315. timer = myWindow.requestAnimationFrame(callback);
  45316. }
  45317. }
  45318. return timer;
  45319. }
  45320. /**
  45321. *
  45322. * @private
  45323. */
  45324. }, {
  45325. key: "_startRendering",
  45326. value: function _startRendering() {
  45327. if (this.renderingActive === true) {
  45328. if (this.renderTimer === undefined) {
  45329. this.renderTimer = this._requestNextFrame(this._renderStep.bind(this), this.simulationInterval);
  45330. }
  45331. }
  45332. }
  45333. /**
  45334. *
  45335. * @private
  45336. */
  45337. }, {
  45338. key: "_renderStep",
  45339. value: function _renderStep() {
  45340. if (this.renderingActive === true) {
  45341. // reset the renderTimer so a new scheduled animation step can be set
  45342. this.renderTimer = undefined;
  45343. if (this.requiresTimeout === true) {
  45344. // this schedules a new simulation step
  45345. this._startRendering();
  45346. }
  45347. this._redraw();
  45348. if (this.requiresTimeout === false) {
  45349. // this schedules a new simulation step
  45350. this._startRendering();
  45351. }
  45352. }
  45353. }
  45354. /**
  45355. * Redraw the network with the current data
  45356. * chart will be resized too.
  45357. */
  45358. }, {
  45359. key: "redraw",
  45360. value: function redraw() {
  45361. this.body.emitter.emit('setSize');
  45362. this._redraw();
  45363. }
  45364. /**
  45365. * Redraw the network with the current data
  45366. * @private
  45367. */
  45368. }, {
  45369. key: "_requestRedraw",
  45370. value: function _requestRedraw() {
  45371. var _this2 = this;
  45372. if (this.redrawRequested !== true && this.renderingActive === false && this.allowRedraw === true) {
  45373. this.redrawRequested = true;
  45374. this._requestNextFrame(function() {
  45375. _this2._redraw(false);
  45376. }, 0);
  45377. }
  45378. }
  45379. /**
  45380. * Redraw the network with the current data
  45381. * @param {boolean} [hidden=false] | Used to get the first estimate of the node sizes.
  45382. * Only the nodes are drawn after which they are quickly drawn over.
  45383. * @private
  45384. */
  45385. }, {
  45386. key: "_redraw",
  45387. value: function _redraw() {
  45388. var hidden = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  45389. if (this.allowRedraw === true) {
  45390. this.body.emitter.emit("initRedraw");
  45391. this.redrawRequested = false;
  45392. // when the container div was hidden, this fixes it back up!
  45393. if (this.canvas.frame.canvas.width === 0 || this.canvas.frame.canvas.height === 0) {
  45394. this.canvas.setSize();
  45395. }
  45396. this.canvas.setTransform();
  45397. var ctx = this.canvas.getContext();
  45398. // clear the canvas
  45399. var w = this.canvas.frame.canvas.clientWidth;
  45400. var h = this.canvas.frame.canvas.clientHeight;
  45401. ctx.clearRect(0, 0, w, h);
  45402. // if the div is hidden, we stop the redraw here for performance.
  45403. if (this.canvas.frame.clientWidth === 0) {
  45404. return;
  45405. }
  45406. // set scaling and translation
  45407. ctx.save();
  45408. ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
  45409. ctx.scale(this.body.view.scale, this.body.view.scale);
  45410. ctx.beginPath();
  45411. this.body.emitter.emit("beforeDrawing", ctx);
  45412. ctx.closePath();
  45413. if (hidden === false) {
  45414. if (this.dragging === false || this.dragging === true && this.options.hideEdgesOnDrag === false) {
  45415. this._drawEdges(ctx);
  45416. }
  45417. }
  45418. if (this.dragging === false || this.dragging === true && this.options.hideNodesOnDrag === false) {
  45419. this._drawNodes(ctx, hidden);
  45420. }
  45421. ctx.beginPath();
  45422. this.body.emitter.emit("afterDrawing", ctx);
  45423. ctx.closePath();
  45424. // restore original scaling and translation
  45425. ctx.restore();
  45426. if (hidden === true) {
  45427. ctx.clearRect(0, 0, w, h);
  45428. }
  45429. }
  45430. }
  45431. /**
  45432. * Redraw all nodes
  45433. *
  45434. * @param {CanvasRenderingContext2D} ctx
  45435. * @param {boolean} [alwaysShow]
  45436. * @private
  45437. */
  45438. }, {
  45439. key: "_resizeNodes",
  45440. value: function _resizeNodes() {
  45441. this.canvas.setTransform();
  45442. var ctx = this.canvas.getContext();
  45443. ctx.save();
  45444. ctx.translate(this.body.view.translation.x, this.body.view.translation.y);
  45445. ctx.scale(this.body.view.scale, this.body.view.scale);
  45446. var nodes = this.body.nodes;
  45447. var node = void 0;
  45448. // resize all nodes
  45449. for (var nodeId in nodes) {
  45450. if (nodes.hasOwnProperty(nodeId)) {
  45451. node = nodes[nodeId];
  45452. node.resize(ctx);
  45453. node.updateBoundingBox(ctx, node.selected);
  45454. }
  45455. }
  45456. // restore original scaling and translation
  45457. ctx.restore();
  45458. }
  45459. /**
  45460. * Redraw all nodes
  45461. *
  45462. * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
  45463. * @param {boolean} [alwaysShow]
  45464. * @private
  45465. */
  45466. }, {
  45467. key: "_drawNodes",
  45468. value: function _drawNodes(ctx) {
  45469. var alwaysShow = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  45470. var nodes = this.body.nodes;
  45471. var nodeIndices = this.body.nodeIndices;
  45472. var node = void 0;
  45473. var selected = [];
  45474. var margin = 20;
  45475. var topLeft = this.canvas.DOMtoCanvas({ x: -margin, y: -margin });
  45476. var bottomRight = this.canvas.DOMtoCanvas({
  45477. x: this.canvas.frame.canvas.clientWidth + margin,
  45478. y: this.canvas.frame.canvas.clientHeight + margin
  45479. });
  45480. var viewableArea = { top: topLeft.y, left: topLeft.x, bottom: bottomRight.y, right: bottomRight.x };
  45481. // draw unselected nodes;
  45482. for (var i = 0; i < nodeIndices.length; i++) {
  45483. node = nodes[nodeIndices[i]];
  45484. // set selected nodes aside
  45485. if (node.isSelected()) {
  45486. selected.push(nodeIndices[i]);
  45487. } else {
  45488. if (alwaysShow === true) {
  45489. node.draw(ctx);
  45490. } else if (node.isBoundingBoxOverlappingWith(viewableArea) === true) {
  45491. node.draw(ctx);
  45492. } else {
  45493. node.updateBoundingBox(ctx, node.selected);
  45494. }
  45495. }
  45496. }
  45497. // draw the selected nodes on top
  45498. for (var _i = 0; _i < selected.length; _i++) {
  45499. node = nodes[selected[_i]];
  45500. node.draw(ctx);
  45501. }
  45502. }
  45503. /**
  45504. * Redraw all edges
  45505. * @param {CanvasRenderingContext2D} ctx 2D context of a HTML canvas
  45506. * @private
  45507. */
  45508. }, {
  45509. key: "_drawEdges",
  45510. value: function _drawEdges(ctx) {
  45511. var edges = this.body.edges;
  45512. var edgeIndices = this.body.edgeIndices;
  45513. var edge = void 0;
  45514. for (var i = 0; i < edgeIndices.length; i++) {
  45515. edge = edges[edgeIndices[i]];
  45516. if (edge.connected === true) {
  45517. edge.draw(ctx);
  45518. }
  45519. }
  45520. }
  45521. /**
  45522. * Determine if the browser requires a setTimeout or a requestAnimationFrame. This was required because
  45523. * some implementations (safari and IE9) did not support requestAnimationFrame
  45524. * @private
  45525. */
  45526. }, {
  45527. key: "_determineBrowserMethod",
  45528. value: function _determineBrowserMethod() {
  45529. if (typeof window !== 'undefined') {
  45530. var browserType = navigator.userAgent.toLowerCase();
  45531. this.requiresTimeout = false;
  45532. if (browserType.indexOf('msie 9.0') != -1) {
  45533. // IE 9
  45534. this.requiresTimeout = true;
  45535. } else if (browserType.indexOf('safari') != -1) {
  45536. // safari
  45537. if (browserType.indexOf('chrome') <= -1) {
  45538. this.requiresTimeout = true;
  45539. }
  45540. }
  45541. } else {
  45542. this.requiresTimeout = true;
  45543. }
  45544. }
  45545. }]);
  45546. return CanvasRenderer;
  45547. }();
  45548. exports["default"] = CanvasRenderer;
  45549. /***/
  45550. }),
  45551. /* 230 */
  45552. /***/
  45553. (function(module, exports, __webpack_require__) {
  45554. "use strict";
  45555. Object.defineProperty(exports, "__esModule", {
  45556. value: true
  45557. });
  45558. var _classCallCheck2 = __webpack_require__(0);
  45559. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  45560. var _createClass2 = __webpack_require__(1);
  45561. var _createClass3 = _interopRequireDefault(_createClass2);
  45562. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  45563. var Hammer = __webpack_require__(10);
  45564. var hammerUtil = __webpack_require__(37);
  45565. var util = __webpack_require__(2);
  45566. /**
  45567. * Create the main frame for the Network.
  45568. * This function is executed once when a Network object is created. The frame
  45569. * contains a canvas, and this canvas contains all objects like the axis and
  45570. * nodes.
  45571. */
  45572. var Canvas = function() {
  45573. /**
  45574. * @param {Object} body
  45575. */
  45576. function Canvas(body) {
  45577. (0, _classCallCheck3['default'])(this, Canvas);
  45578. this.body = body;
  45579. this.pixelRatio = 1;
  45580. this.resizeTimer = undefined;
  45581. this.resizeFunction = this._onResize.bind(this);
  45582. this.cameraState = {};
  45583. this.initialized = false;
  45584. this.canvasViewCenter = {};
  45585. this.options = {};
  45586. this.defaultOptions = {
  45587. autoResize: true,
  45588. height: '100%',
  45589. width: '100%'
  45590. };
  45591. util.extend(this.options, this.defaultOptions);
  45592. this.bindEventListeners();
  45593. }
  45594. /**
  45595. * Binds event listeners
  45596. */
  45597. (0, _createClass3['default'])(Canvas, [{
  45598. key: 'bindEventListeners',
  45599. value: function bindEventListeners() {
  45600. var _this = this;
  45601. // bind the events
  45602. this.body.emitter.once("resize", function(obj) {
  45603. if (obj.width !== 0) {
  45604. _this.body.view.translation.x = obj.width * 0.5;
  45605. }
  45606. if (obj.height !== 0) {
  45607. _this.body.view.translation.y = obj.height * 0.5;
  45608. }
  45609. });
  45610. this.body.emitter.on("setSize", this.setSize.bind(this));
  45611. this.body.emitter.on("destroy", function() {
  45612. _this.hammerFrame.destroy();
  45613. _this.hammer.destroy();
  45614. _this._cleanUp();
  45615. });
  45616. }
  45617. /**
  45618. * @param {Object} options
  45619. */
  45620. }, {
  45621. key: 'setOptions',
  45622. value: function setOptions(options) {
  45623. var _this2 = this;
  45624. if (options !== undefined) {
  45625. var fields = ['width', 'height', 'autoResize'];
  45626. util.selectiveDeepExtend(fields, this.options, options);
  45627. }
  45628. if (this.options.autoResize === true) {
  45629. // automatically adapt to a changing size of the browser.
  45630. this._cleanUp();
  45631. this.resizeTimer = setInterval(function() {
  45632. var changed = _this2.setSize();
  45633. if (changed === true) {
  45634. _this2.body.emitter.emit("_requestRedraw");
  45635. }
  45636. }, 1000);
  45637. this.resizeFunction = this._onResize.bind(this);
  45638. util.addEventListener(window, 'resize', this.resizeFunction);
  45639. }
  45640. }
  45641. /**
  45642. * @private
  45643. */
  45644. }, {
  45645. key: '_cleanUp',
  45646. value: function _cleanUp() {
  45647. // automatically adapt to a changing size of the browser.
  45648. if (this.resizeTimer !== undefined) {
  45649. clearInterval(this.resizeTimer);
  45650. }
  45651. util.removeEventListener(window, 'resize', this.resizeFunction);
  45652. this.resizeFunction = undefined;
  45653. }
  45654. /**
  45655. * @private
  45656. */
  45657. }, {
  45658. key: '_onResize',
  45659. value: function _onResize() {
  45660. this.setSize();
  45661. this.body.emitter.emit("_redraw");
  45662. }
  45663. /**
  45664. * Get and store the cameraState
  45665. *
  45666. * @param {number} [pixelRatio=this.pixelRatio]
  45667. * @private
  45668. */
  45669. }, {
  45670. key: '_getCameraState',
  45671. value: function _getCameraState() {
  45672. var pixelRatio = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.pixelRatio;
  45673. if (this.initialized === true) {
  45674. this.cameraState.previousWidth = this.frame.canvas.width / pixelRatio;
  45675. this.cameraState.previousHeight = this.frame.canvas.height / pixelRatio;
  45676. this.cameraState.scale = this.body.view.scale;
  45677. this.cameraState.position = this.DOMtoCanvas({
  45678. x: 0.5 * this.frame.canvas.width / pixelRatio,
  45679. y: 0.5 * this.frame.canvas.height / pixelRatio
  45680. });
  45681. }
  45682. }
  45683. /**
  45684. * Set the cameraState
  45685. * @private
  45686. */
  45687. }, {
  45688. key: '_setCameraState',
  45689. value: function _setCameraState() {
  45690. if (this.cameraState.scale !== undefined && this.frame.canvas.clientWidth !== 0 && this.frame.canvas.clientHeight !== 0 && this.pixelRatio !== 0 && this.cameraState.previousWidth > 0) {
  45691. var widthRatio = this.frame.canvas.width / this.pixelRatio / this.cameraState.previousWidth;
  45692. var heightRatio = this.frame.canvas.height / this.pixelRatio / this.cameraState.previousHeight;
  45693. var newScale = this.cameraState.scale;
  45694. if (widthRatio != 1 && heightRatio != 1) {
  45695. newScale = this.cameraState.scale * 0.5 * (widthRatio + heightRatio);
  45696. } else if (widthRatio != 1) {
  45697. newScale = this.cameraState.scale * widthRatio;
  45698. } else if (heightRatio != 1) {
  45699. newScale = this.cameraState.scale * heightRatio;
  45700. }
  45701. this.body.view.scale = newScale;
  45702. // this comes from the view module.
  45703. var currentViewCenter = this.DOMtoCanvas({
  45704. x: 0.5 * this.frame.canvas.clientWidth,
  45705. y: 0.5 * this.frame.canvas.clientHeight
  45706. });
  45707. var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node
  45708. x: currentViewCenter.x - this.cameraState.position.x,
  45709. y: currentViewCenter.y - this.cameraState.position.y
  45710. };
  45711. this.body.view.translation.x += distanceFromCenter.x * this.body.view.scale;
  45712. this.body.view.translation.y += distanceFromCenter.y * this.body.view.scale;
  45713. }
  45714. }
  45715. /**
  45716. *
  45717. * @param {number|string} value
  45718. * @returns {string}
  45719. * @private
  45720. */
  45721. }, {
  45722. key: '_prepareValue',
  45723. value: function _prepareValue(value) {
  45724. if (typeof value === 'number') {
  45725. return value + 'px';
  45726. } else if (typeof value === 'string') {
  45727. if (value.indexOf('%') !== -1 || value.indexOf('px') !== -1) {
  45728. return value;
  45729. } else if (value.indexOf('%') === -1) {
  45730. return value + 'px';
  45731. }
  45732. }
  45733. throw new Error('Could not use the value supplied for width or height:' + value);
  45734. }
  45735. /**
  45736. * Create the HTML
  45737. */
  45738. }, {
  45739. key: '_create',
  45740. value: function _create() {
  45741. // remove all elements from the container element.
  45742. while (this.body.container.hasChildNodes()) {
  45743. this.body.container.removeChild(this.body.container.firstChild);
  45744. }
  45745. this.frame = document.createElement('div');
  45746. this.frame.className = 'vis-network';
  45747. this.frame.style.position = 'relative';
  45748. this.frame.style.overflow = 'hidden';
  45749. this.frame.tabIndex = 900; // tab index is required for keycharm to bind keystrokes to the div instead of the window
  45750. //////////////////////////////////////////////////////////////////
  45751. this.frame.canvas = document.createElement("canvas");
  45752. this.frame.canvas.style.position = 'relative';
  45753. this.frame.appendChild(this.frame.canvas);
  45754. if (!this.frame.canvas.getContext) {
  45755. var noCanvas = document.createElement('DIV');
  45756. noCanvas.style.color = 'red';
  45757. noCanvas.style.fontWeight = 'bold';
  45758. noCanvas.style.padding = '10px';
  45759. noCanvas.innerHTML = 'Error: your browser does not support HTML canvas';
  45760. this.frame.canvas.appendChild(noCanvas);
  45761. } else {
  45762. this._setPixelRatio();
  45763. this.setTransform();
  45764. }
  45765. // add the frame to the container element
  45766. this.body.container.appendChild(this.frame);
  45767. this.body.view.scale = 1;
  45768. this.body.view.translation = { x: 0.5 * this.frame.canvas.clientWidth, y: 0.5 * this.frame.canvas.clientHeight };
  45769. this._bindHammer();
  45770. }
  45771. /**
  45772. * This function binds hammer, it can be repeated over and over due to the uniqueness check.
  45773. * @private
  45774. */
  45775. }, {
  45776. key: '_bindHammer',
  45777. value: function _bindHammer() {
  45778. var _this3 = this;
  45779. if (this.hammer !== undefined) {
  45780. this.hammer.destroy();
  45781. }
  45782. this.drag = {};
  45783. this.pinch = {};
  45784. // init hammer
  45785. this.hammer = new Hammer(this.frame.canvas);
  45786. this.hammer.get('pinch').set({ enable: true });
  45787. // enable to get better response, todo: test on mobile.
  45788. this.hammer.get('pan').set({ threshold: 5, direction: Hammer.DIRECTION_ALL });
  45789. hammerUtil.onTouch(this.hammer, function(event) {
  45790. _this3.body.eventListeners.onTouch(event);
  45791. });
  45792. this.hammer.on('tap', function(event) {
  45793. _this3.body.eventListeners.onTap(event);
  45794. });
  45795. this.hammer.on('doubletap', function(event) {
  45796. _this3.body.eventListeners.onDoubleTap(event);
  45797. });
  45798. this.hammer.on('press', function(event) {
  45799. _this3.body.eventListeners.onHold(event);
  45800. });
  45801. this.hammer.on('panstart', function(event) {
  45802. _this3.body.eventListeners.onDragStart(event);
  45803. });
  45804. this.hammer.on('panmove', function(event) {
  45805. _this3.body.eventListeners.onDrag(event);
  45806. });
  45807. this.hammer.on('panend', function(event) {
  45808. _this3.body.eventListeners.onDragEnd(event);
  45809. });
  45810. this.hammer.on('pinch', function(event) {
  45811. _this3.body.eventListeners.onPinch(event);
  45812. });
  45813. // TODO: neatly cleanup these handlers when re-creating the Canvas, IF these are done with hammer, event.stopPropagation will not work?
  45814. this.frame.canvas.addEventListener('mousewheel', function(event) {
  45815. _this3.body.eventListeners.onMouseWheel(event);
  45816. });
  45817. this.frame.canvas.addEventListener('DOMMouseScroll', function(event) {
  45818. _this3.body.eventListeners.onMouseWheel(event);
  45819. });
  45820. this.frame.canvas.addEventListener('mousemove', function(event) {
  45821. _this3.body.eventListeners.onMouseMove(event);
  45822. });
  45823. this.frame.canvas.addEventListener('contextmenu', function(event) {
  45824. _this3.body.eventListeners.onContext(event);
  45825. });
  45826. this.hammerFrame = new Hammer(this.frame);
  45827. hammerUtil.onRelease(this.hammerFrame, function(event) {
  45828. _this3.body.eventListeners.onRelease(event);
  45829. });
  45830. }
  45831. /**
  45832. * Set a new size for the network
  45833. * @param {string} width Width in pixels or percentage (for example '800px'
  45834. * or '50%')
  45835. * @param {string} height Height in pixels or percentage (for example '400px'
  45836. * or '30%')
  45837. * @returns {boolean}
  45838. */
  45839. }, {
  45840. key: 'setSize',
  45841. value: function setSize() {
  45842. var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.width;
  45843. var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.height;
  45844. width = this._prepareValue(width);
  45845. height = this._prepareValue(height);
  45846. var emitEvent = false;
  45847. var oldWidth = this.frame.canvas.width;
  45848. var oldHeight = this.frame.canvas.height;
  45849. // update the pixel ratio
  45850. //
  45851. // NOTE: Comment in following is rather inconsistent; this is the ONLY place in the code
  45852. // where it is assumed that the pixel ratio could change at runtime.
  45853. // The only way I can think of this happening is a rotating screen or tablet; but then
  45854. // there should be a mechanism for reloading the data (TODO: check if this is present).
  45855. //
  45856. // If the assumption is true (i.e. pixel ratio can change at runtime), then *all* usage
  45857. // of pixel ratio must be overhauled for this.
  45858. //
  45859. // For the time being, I will humor the assumption here, and in the rest of the code assume it is
  45860. // constant.
  45861. var previousRatio = this.pixelRatio; // we cache this because the camera state storage needs the old value
  45862. this._setPixelRatio();
  45863. if (width != this.options.width || height != this.options.height || this.frame.style.width != width || this.frame.style.height != height) {
  45864. this._getCameraState(previousRatio);
  45865. this.frame.style.width = width;
  45866. this.frame.style.height = height;
  45867. this.frame.canvas.style.width = '100%';
  45868. this.frame.canvas.style.height = '100%';
  45869. this.frame.canvas.width = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
  45870. this.frame.canvas.height = Math.round(this.frame.canvas.clientHeight * this.pixelRatio);
  45871. this.options.width = width;
  45872. this.options.height = height;
  45873. this.canvasViewCenter = {
  45874. x: 0.5 * this.frame.clientWidth,
  45875. y: 0.5 * this.frame.clientHeight
  45876. };
  45877. emitEvent = true;
  45878. } else {
  45879. // this would adapt the width of the canvas to the width from 100% if and only if
  45880. // there is a change.
  45881. var newWidth = Math.round(this.frame.canvas.clientWidth * this.pixelRatio);
  45882. var newHeight = Math.round(this.frame.canvas.clientHeight * this.pixelRatio);
  45883. // store the camera if there is a change in size.
  45884. if (this.frame.canvas.width !== newWidth || this.frame.canvas.height !== newHeight) {
  45885. this._getCameraState(previousRatio);
  45886. }
  45887. if (this.frame.canvas.width !== newWidth) {
  45888. this.frame.canvas.width = newWidth;
  45889. emitEvent = true;
  45890. }
  45891. if (this.frame.canvas.height !== newHeight) {
  45892. this.frame.canvas.height = newHeight;
  45893. emitEvent = true;
  45894. }
  45895. }
  45896. if (emitEvent === true) {
  45897. this.body.emitter.emit('resize', {
  45898. width: Math.round(this.frame.canvas.width / this.pixelRatio),
  45899. height: Math.round(this.frame.canvas.height / this.pixelRatio),
  45900. oldWidth: Math.round(oldWidth / this.pixelRatio),
  45901. oldHeight: Math.round(oldHeight / this.pixelRatio)
  45902. });
  45903. // restore the camera on change.
  45904. this._setCameraState();
  45905. }
  45906. // set initialized so the get and set camera will work from now on.
  45907. this.initialized = true;
  45908. return emitEvent;
  45909. }
  45910. /**
  45911. *
  45912. * @returns {CanvasRenderingContext2D}
  45913. */
  45914. }, {
  45915. key: 'getContext',
  45916. value: function getContext() {
  45917. return this.frame.canvas.getContext("2d");
  45918. }
  45919. /**
  45920. * Determine the pixel ratio for various browsers.
  45921. *
  45922. * @returns {number}
  45923. * @private
  45924. */
  45925. }, {
  45926. key: '_determinePixelRatio',
  45927. value: function _determinePixelRatio() {
  45928. var ctx = this.getContext();
  45929. if (ctx === undefined) {
  45930. throw new Error("Could not get canvax context");
  45931. }
  45932. var numerator = 1;
  45933. if (typeof window !== 'undefined') {
  45934. // (window !== undefined) doesn't work here!
  45935. // Protection during unit tests, where 'window' can be missing
  45936. numerator = window.devicePixelRatio || 1;
  45937. }
  45938. var denominator = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1;
  45939. return numerator / denominator;
  45940. }
  45941. /**
  45942. * Lazy determination of pixel ratio.
  45943. *
  45944. * @private
  45945. */
  45946. }, {
  45947. key: '_setPixelRatio',
  45948. value: function _setPixelRatio() {
  45949. this.pixelRatio = this._determinePixelRatio();
  45950. }
  45951. /**
  45952. * Set the transform in the contained context, based on its pixelRatio
  45953. */
  45954. }, {
  45955. key: 'setTransform',
  45956. value: function setTransform() {
  45957. var ctx = this.getContext();
  45958. if (ctx === undefined) {
  45959. throw new Error("Could not get canvax context");
  45960. }
  45961. ctx.setTransform(this.pixelRatio, 0, 0, this.pixelRatio, 0, 0);
  45962. }
  45963. /**
  45964. * Convert the X coordinate in DOM-space (coordinate point in browser relative to the container div) to
  45965. * the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
  45966. * @param {number} x
  45967. * @returns {number}
  45968. * @private
  45969. */
  45970. }, {
  45971. key: '_XconvertDOMtoCanvas',
  45972. value: function _XconvertDOMtoCanvas(x) {
  45973. return (x - this.body.view.translation.x) / this.body.view.scale;
  45974. }
  45975. /**
  45976. * Convert the X coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
  45977. * the X coordinate in DOM-space (coordinate point in browser relative to the container div)
  45978. * @param {number} x
  45979. * @returns {number}
  45980. * @private
  45981. */
  45982. }, {
  45983. key: '_XconvertCanvasToDOM',
  45984. value: function _XconvertCanvasToDOM(x) {
  45985. return x * this.body.view.scale + this.body.view.translation.x;
  45986. }
  45987. /**
  45988. * Convert the Y coordinate in DOM-space (coordinate point in browser relative to the container div) to
  45989. * the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon)
  45990. * @param {number} y
  45991. * @returns {number}
  45992. * @private
  45993. */
  45994. }, {
  45995. key: '_YconvertDOMtoCanvas',
  45996. value: function _YconvertDOMtoCanvas(y) {
  45997. return (y - this.body.view.translation.y) / this.body.view.scale;
  45998. }
  45999. /**
  46000. * Convert the Y coordinate in canvas-space (the simulation sandbox, which the camera looks upon) to
  46001. * the Y coordinate in DOM-space (coordinate point in browser relative to the container div)
  46002. * @param {number} y
  46003. * @returns {number}
  46004. * @private
  46005. */
  46006. }, {
  46007. key: '_YconvertCanvasToDOM',
  46008. value: function _YconvertCanvasToDOM(y) {
  46009. return y * this.body.view.scale + this.body.view.translation.y;
  46010. }
  46011. /**
  46012. * @param {point} pos
  46013. * @returns {point}
  46014. */
  46015. }, {
  46016. key: 'canvasToDOM',
  46017. value: function canvasToDOM(pos) {
  46018. return { x: this._XconvertCanvasToDOM(pos.x), y: this._YconvertCanvasToDOM(pos.y) };
  46019. }
  46020. /**
  46021. *
  46022. * @param {point} pos
  46023. * @returns {point}
  46024. */
  46025. }, {
  46026. key: 'DOMtoCanvas',
  46027. value: function DOMtoCanvas(pos) {
  46028. return { x: this._XconvertDOMtoCanvas(pos.x), y: this._YconvertDOMtoCanvas(pos.y) };
  46029. }
  46030. }]);
  46031. return Canvas;
  46032. }();
  46033. exports['default'] = Canvas;
  46034. /***/
  46035. }),
  46036. /* 231 */
  46037. /***/
  46038. (function(module, exports, __webpack_require__) {
  46039. "use strict";
  46040. Object.defineProperty(exports, "__esModule", {
  46041. value: true
  46042. });
  46043. var _classCallCheck2 = __webpack_require__(0);
  46044. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  46045. var _createClass2 = __webpack_require__(1);
  46046. var _createClass3 = _interopRequireDefault(_createClass2);
  46047. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  46048. var util = __webpack_require__(2);
  46049. var NetworkUtil = __webpack_require__(76)['default'];
  46050. /**
  46051. * The view
  46052. */
  46053. var View = function() {
  46054. /**
  46055. * @param {Object} body
  46056. * @param {Canvas} canvas
  46057. */
  46058. function View(body, canvas) {
  46059. var _this = this;
  46060. (0, _classCallCheck3['default'])(this, View);
  46061. this.body = body;
  46062. this.canvas = canvas;
  46063. this.animationSpeed = 1 / this.renderRefreshRate;
  46064. this.animationEasingFunction = "easeInOutQuint";
  46065. this.easingTime = 0;
  46066. this.sourceScale = 0;
  46067. this.targetScale = 0;
  46068. this.sourceTranslation = 0;
  46069. this.targetTranslation = 0;
  46070. this.lockedOnNodeId = undefined;
  46071. this.lockedOnNodeOffset = undefined;
  46072. this.touchTime = 0;
  46073. this.viewFunction = undefined;
  46074. this.body.emitter.on("fit", this.fit.bind(this));
  46075. this.body.emitter.on("animationFinished", function() {
  46076. _this.body.emitter.emit("_stopRendering");
  46077. });
  46078. this.body.emitter.on("unlockNode", this.releaseNode.bind(this));
  46079. }
  46080. /**
  46081. *
  46082. * @param {Object} [options={}]
  46083. */
  46084. (0, _createClass3['default'])(View, [{
  46085. key: 'setOptions',
  46086. value: function setOptions() {
  46087. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  46088. this.options = options;
  46089. }
  46090. /**
  46091. * This function zooms out to fit all data on screen based on amount of nodes
  46092. * @param {Object} [options={{nodes=Array}}]
  46093. * @param {boolean} [initialZoom=false] | zoom based on fitted formula or range, true = fitted, default = false;
  46094. */
  46095. }, {
  46096. key: 'fit',
  46097. value: function fit() {
  46098. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { nodes: [] };
  46099. var initialZoom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  46100. var range = void 0;
  46101. var zoomLevel = void 0;
  46102. if (options.nodes === undefined || options.nodes.length === 0) {
  46103. options.nodes = this.body.nodeIndices;
  46104. }
  46105. if (initialZoom === true) {
  46106. // check if more than half of the nodes have a predefined position. If so, we use the range, not the approximation.
  46107. var positionDefined = 0;
  46108. for (var nodeId in this.body.nodes) {
  46109. if (this.body.nodes.hasOwnProperty(nodeId)) {
  46110. var node = this.body.nodes[nodeId];
  46111. if (node.predefinedPosition === true) {
  46112. positionDefined += 1;
  46113. }
  46114. }
  46115. }
  46116. if (positionDefined > 0.5 * this.body.nodeIndices.length) {
  46117. this.fit(options, false);
  46118. return;
  46119. }
  46120. range = NetworkUtil.getRange(this.body.nodes, options.nodes);
  46121. var numberOfNodes = this.body.nodeIndices.length;
  46122. zoomLevel = 12.662 / (numberOfNodes + 7.4147) + 0.0964822; // this is obtained from fitting a dataset from 5 points with scale levels that looked good.
  46123. // correct for larger canvasses.
  46124. var factor = Math.min(this.canvas.frame.canvas.clientWidth / 600, this.canvas.frame.canvas.clientHeight / 600);
  46125. zoomLevel *= factor;
  46126. } else {
  46127. this.body.emitter.emit("_resizeNodes");
  46128. range = NetworkUtil.getRange(this.body.nodes, options.nodes);
  46129. var xDistance = Math.abs(range.maxX - range.minX) * 1.1;
  46130. var yDistance = Math.abs(range.maxY - range.minY) * 1.1;
  46131. var xZoomLevel = this.canvas.frame.canvas.clientWidth / xDistance;
  46132. var yZoomLevel = this.canvas.frame.canvas.clientHeight / yDistance;
  46133. zoomLevel = xZoomLevel <= yZoomLevel ? xZoomLevel : yZoomLevel;
  46134. }
  46135. if (zoomLevel > 1.0) {
  46136. zoomLevel = 1.0;
  46137. } else if (zoomLevel === 0) {
  46138. zoomLevel = 1.0;
  46139. }
  46140. var center = NetworkUtil.findCenter(range);
  46141. var animationOptions = { position: center, scale: zoomLevel, animation: options.animation };
  46142. this.moveTo(animationOptions);
  46143. }
  46144. // animation
  46145. /**
  46146. * Center a node in view.
  46147. *
  46148. * @param {number} nodeId
  46149. * @param {number} [options]
  46150. */
  46151. }, {
  46152. key: 'focus',
  46153. value: function focus(nodeId) {
  46154. var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  46155. if (this.body.nodes[nodeId] !== undefined) {
  46156. var nodePosition = { x: this.body.nodes[nodeId].x, y: this.body.nodes[nodeId].y };
  46157. options.position = nodePosition;
  46158. options.lockedOnNode = nodeId;
  46159. this.moveTo(options);
  46160. } else {
  46161. console.log("Node: " + nodeId + " cannot be found.");
  46162. }
  46163. }
  46164. /**
  46165. *
  46166. * @param {Object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
  46167. * | options.scale = number // scale to move to
  46168. * | options.position = {x:number, y:number} // position to move to
  46169. * | options.animation = {duration:number, easingFunction:String} || Boolean // position to move to
  46170. */
  46171. }, {
  46172. key: 'moveTo',
  46173. value: function moveTo(options) {
  46174. if (options === undefined) {
  46175. options = {};
  46176. return;
  46177. }
  46178. if (options.offset === undefined) {
  46179. options.offset = { x: 0, y: 0 };
  46180. }
  46181. if (options.offset.x === undefined) {
  46182. options.offset.x = 0;
  46183. }
  46184. if (options.offset.y === undefined) {
  46185. options.offset.y = 0;
  46186. }
  46187. if (options.scale === undefined) {
  46188. options.scale = this.body.view.scale;
  46189. }
  46190. if (options.position === undefined) {
  46191. options.position = this.getViewPosition();
  46192. }
  46193. if (options.animation === undefined) {
  46194. options.animation = { duration: 0 };
  46195. }
  46196. if (options.animation === false) {
  46197. options.animation = { duration: 0 };
  46198. }
  46199. if (options.animation === true) {
  46200. options.animation = {};
  46201. }
  46202. if (options.animation.duration === undefined) {
  46203. options.animation.duration = 1000;
  46204. } // default duration
  46205. if (options.animation.easingFunction === undefined) {
  46206. options.animation.easingFunction = "easeInOutQuad";
  46207. } // default easing function
  46208. this.animateView(options);
  46209. }
  46210. /**
  46211. *
  46212. * @param {Object} options | options.offset = {x:number, y:number} // offset from the center in DOM pixels
  46213. * | options.time = number // animation time in milliseconds
  46214. * | options.scale = number // scale to animate to
  46215. * | options.position = {x:number, y:number} // position to animate to
  46216. * | options.easingFunction = String // linear, easeInQuad, easeOutQuad, easeInOutQuad,
  46217. * // easeInCubic, easeOutCubic, easeInOutCubic,
  46218. * // easeInQuart, easeOutQuart, easeInOutQuart,
  46219. * // easeInQuint, easeOutQuint, easeInOutQuint
  46220. */
  46221. }, {
  46222. key: 'animateView',
  46223. value: function animateView(options) {
  46224. if (options === undefined) {
  46225. return;
  46226. }
  46227. this.animationEasingFunction = options.animation.easingFunction;
  46228. // release if something focussed on the node
  46229. this.releaseNode();
  46230. if (options.locked === true) {
  46231. this.lockedOnNodeId = options.lockedOnNode;
  46232. this.lockedOnNodeOffset = options.offset;
  46233. }
  46234. // forcefully complete the old animation if it was still running
  46235. if (this.easingTime != 0) {
  46236. this._transitionRedraw(true); // by setting easingtime to 1, we finish the animation.
  46237. }
  46238. this.sourceScale = this.body.view.scale;
  46239. this.sourceTranslation = this.body.view.translation;
  46240. this.targetScale = options.scale;
  46241. // set the scale so the viewCenter is based on the correct zoom level. This is overridden in the transitionRedraw
  46242. // but at least then we'll have the target transition
  46243. this.body.view.scale = this.targetScale;
  46244. var viewCenter = this.canvas.DOMtoCanvas({ x: 0.5 * this.canvas.frame.canvas.clientWidth, y: 0.5 * this.canvas.frame.canvas.clientHeight });
  46245. var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node
  46246. x: viewCenter.x - options.position.x,
  46247. y: viewCenter.y - options.position.y
  46248. };
  46249. this.targetTranslation = {
  46250. x: this.sourceTranslation.x + distanceFromCenter.x * this.targetScale + options.offset.x,
  46251. y: this.sourceTranslation.y + distanceFromCenter.y * this.targetScale + options.offset.y
  46252. };
  46253. // if the time is set to 0, don't do an animation
  46254. if (options.animation.duration === 0) {
  46255. if (this.lockedOnNodeId != undefined) {
  46256. this.viewFunction = this._lockedRedraw.bind(this);
  46257. this.body.emitter.on("initRedraw", this.viewFunction);
  46258. } else {
  46259. this.body.view.scale = this.targetScale;
  46260. this.body.view.translation = this.targetTranslation;
  46261. this.body.emitter.emit("_requestRedraw");
  46262. }
  46263. } else {
  46264. this.animationSpeed = 1 / (60 * options.animation.duration * 0.001) || 1 / 60; // 60 for 60 seconds, 0.001 for milli's
  46265. this.animationEasingFunction = options.animation.easingFunction;
  46266. this.viewFunction = this._transitionRedraw.bind(this);
  46267. this.body.emitter.on("initRedraw", this.viewFunction);
  46268. this.body.emitter.emit("_startRendering");
  46269. }
  46270. }
  46271. /**
  46272. * used to animate smoothly by hijacking the redraw function.
  46273. * @private
  46274. */
  46275. }, {
  46276. key: '_lockedRedraw',
  46277. value: function _lockedRedraw() {
  46278. var nodePosition = { x: this.body.nodes[this.lockedOnNodeId].x, y: this.body.nodes[this.lockedOnNodeId].y };
  46279. var viewCenter = this.canvas.DOMtoCanvas({ x: 0.5 * this.canvas.frame.canvas.clientWidth, y: 0.5 * this.canvas.frame.canvas.clientHeight });
  46280. var distanceFromCenter = { // offset from view, distance view has to change by these x and y to center the node
  46281. x: viewCenter.x - nodePosition.x,
  46282. y: viewCenter.y - nodePosition.y
  46283. };
  46284. var sourceTranslation = this.body.view.translation;
  46285. var targetTranslation = {
  46286. x: sourceTranslation.x + distanceFromCenter.x * this.body.view.scale + this.lockedOnNodeOffset.x,
  46287. y: sourceTranslation.y + distanceFromCenter.y * this.body.view.scale + this.lockedOnNodeOffset.y
  46288. };
  46289. this.body.view.translation = targetTranslation;
  46290. }
  46291. /**
  46292. * Resets state of a locked on Node
  46293. */
  46294. }, {
  46295. key: 'releaseNode',
  46296. value: function releaseNode() {
  46297. if (this.lockedOnNodeId !== undefined && this.viewFunction !== undefined) {
  46298. this.body.emitter.off("initRedraw", this.viewFunction);
  46299. this.lockedOnNodeId = undefined;
  46300. this.lockedOnNodeOffset = undefined;
  46301. }
  46302. }
  46303. /**
  46304. * @param {boolean} [finished=false]
  46305. * @private
  46306. */
  46307. }, {
  46308. key: '_transitionRedraw',
  46309. value: function _transitionRedraw() {
  46310. var finished = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  46311. this.easingTime += this.animationSpeed;
  46312. this.easingTime = finished === true ? 1.0 : this.easingTime;
  46313. var progress = util.easingFunctions[this.animationEasingFunction](this.easingTime);
  46314. this.body.view.scale = this.sourceScale + (this.targetScale - this.sourceScale) * progress;
  46315. this.body.view.translation = {
  46316. x: this.sourceTranslation.x + (this.targetTranslation.x - this.sourceTranslation.x) * progress,
  46317. y: this.sourceTranslation.y + (this.targetTranslation.y - this.sourceTranslation.y) * progress
  46318. };
  46319. // cleanup
  46320. if (this.easingTime >= 1.0) {
  46321. this.body.emitter.off("initRedraw", this.viewFunction);
  46322. this.easingTime = 0;
  46323. if (this.lockedOnNodeId != undefined) {
  46324. this.viewFunction = this._lockedRedraw.bind(this);
  46325. this.body.emitter.on("initRedraw", this.viewFunction);
  46326. }
  46327. this.body.emitter.emit("animationFinished");
  46328. }
  46329. }
  46330. /**
  46331. *
  46332. * @returns {number}
  46333. */
  46334. }, {
  46335. key: 'getScale',
  46336. value: function getScale() {
  46337. return this.body.view.scale;
  46338. }
  46339. /**
  46340. *
  46341. * @returns {{x: number, y: number}}
  46342. */
  46343. }, {
  46344. key: 'getViewPosition',
  46345. value: function getViewPosition() {
  46346. return this.canvas.DOMtoCanvas({ x: 0.5 * this.canvas.frame.canvas.clientWidth, y: 0.5 * this.canvas.frame.canvas.clientHeight });
  46347. }
  46348. }]);
  46349. return View;
  46350. }();
  46351. exports['default'] = View;
  46352. /***/
  46353. }),
  46354. /* 232 */
  46355. /***/
  46356. (function(module, exports, __webpack_require__) {
  46357. "use strict";
  46358. Object.defineProperty(exports, "__esModule", {
  46359. value: true
  46360. });
  46361. var _classCallCheck2 = __webpack_require__(0);
  46362. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  46363. var _createClass2 = __webpack_require__(1);
  46364. var _createClass3 = _interopRequireDefault(_createClass2);
  46365. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  46366. var util = __webpack_require__(2);
  46367. var NavigationHandler = __webpack_require__(233)['default'];
  46368. var Popup = __webpack_require__(104)['default'];
  46369. /**
  46370. * Handler for interactions
  46371. */
  46372. var InteractionHandler = function() {
  46373. /**
  46374. * @param {Object} body
  46375. * @param {Canvas} canvas
  46376. * @param {SelectionHandler} selectionHandler
  46377. */
  46378. function InteractionHandler(body, canvas, selectionHandler) {
  46379. (0, _classCallCheck3['default'])(this, InteractionHandler);
  46380. this.body = body;
  46381. this.canvas = canvas;
  46382. this.selectionHandler = selectionHandler;
  46383. this.navigationHandler = new NavigationHandler(body, canvas);
  46384. // bind the events from hammer to functions in this object
  46385. this.body.eventListeners.onTap = this.onTap.bind(this);
  46386. this.body.eventListeners.onTouch = this.onTouch.bind(this);
  46387. this.body.eventListeners.onDoubleTap = this.onDoubleTap.bind(this);
  46388. this.body.eventListeners.onHold = this.onHold.bind(this);
  46389. this.body.eventListeners.onDragStart = this.onDragStart.bind(this);
  46390. this.body.eventListeners.onDrag = this.onDrag.bind(this);
  46391. this.body.eventListeners.onDragEnd = this.onDragEnd.bind(this);
  46392. this.body.eventListeners.onMouseWheel = this.onMouseWheel.bind(this);
  46393. this.body.eventListeners.onPinch = this.onPinch.bind(this);
  46394. this.body.eventListeners.onMouseMove = this.onMouseMove.bind(this);
  46395. this.body.eventListeners.onRelease = this.onRelease.bind(this);
  46396. this.body.eventListeners.onContext = this.onContext.bind(this);
  46397. this.touchTime = 0;
  46398. this.drag = {};
  46399. this.pinch = {};
  46400. this.popup = undefined;
  46401. this.popupObj = undefined;
  46402. this.popupTimer = undefined;
  46403. this.body.functions.getPointer = this.getPointer.bind(this);
  46404. this.options = {};
  46405. this.defaultOptions = {
  46406. dragNodes: true,
  46407. dragView: true,
  46408. hover: false,
  46409. keyboard: {
  46410. enabled: false,
  46411. speed: { x: 10, y: 10, zoom: 0.02 },
  46412. bindToWindow: true
  46413. },
  46414. navigationButtons: false,
  46415. tooltipDelay: 300,
  46416. zoomView: true
  46417. };
  46418. util.extend(this.options, this.defaultOptions);
  46419. this.bindEventListeners();
  46420. }
  46421. /**
  46422. * Binds event listeners
  46423. */
  46424. (0, _createClass3['default'])(InteractionHandler, [{
  46425. key: 'bindEventListeners',
  46426. value: function bindEventListeners() {
  46427. var _this = this;
  46428. this.body.emitter.on('destroy', function() {
  46429. clearTimeout(_this.popupTimer);
  46430. delete _this.body.functions.getPointer;
  46431. });
  46432. }
  46433. /**
  46434. *
  46435. * @param {Object} options
  46436. */
  46437. }, {
  46438. key: 'setOptions',
  46439. value: function setOptions(options) {
  46440. if (options !== undefined) {
  46441. // extend all but the values in fields
  46442. var fields = ['hideEdgesOnDrag', 'hideNodesOnDrag', 'keyboard', 'multiselect', 'selectable', 'selectConnectedEdges'];
  46443. util.selectiveNotDeepExtend(fields, this.options, options);
  46444. // merge the keyboard options in.
  46445. util.mergeOptions(this.options, options, 'keyboard');
  46446. if (options.tooltip) {
  46447. util.extend(this.options.tooltip, options.tooltip);
  46448. if (options.tooltip.color) {
  46449. this.options.tooltip.color = util.parseColor(options.tooltip.color);
  46450. }
  46451. }
  46452. }
  46453. this.navigationHandler.setOptions(this.options);
  46454. }
  46455. /**
  46456. * Get the pointer location from a touch location
  46457. * @param {{x: number, y: number}} touch
  46458. * @return {{x: number, y: number}} pointer
  46459. * @private
  46460. */
  46461. }, {
  46462. key: 'getPointer',
  46463. value: function getPointer(touch) {
  46464. return {
  46465. x: touch.x - util.getAbsoluteLeft(this.canvas.frame.canvas),
  46466. y: touch.y - util.getAbsoluteTop(this.canvas.frame.canvas)
  46467. };
  46468. }
  46469. /**
  46470. * On start of a touch gesture, store the pointer
  46471. * @param {Event} event The event
  46472. * @private
  46473. */
  46474. }, {
  46475. key: 'onTouch',
  46476. value: function onTouch(event) {
  46477. if (new Date().valueOf() - this.touchTime > 50) {
  46478. this.drag.pointer = this.getPointer(event.center);
  46479. this.drag.pinched = false;
  46480. this.pinch.scale = this.body.view.scale;
  46481. // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame)
  46482. this.touchTime = new Date().valueOf();
  46483. }
  46484. }
  46485. /**
  46486. * handle tap/click event: select/unselect a node
  46487. * @param {Event} event
  46488. * @private
  46489. */
  46490. }, {
  46491. key: 'onTap',
  46492. value: function onTap(event) {
  46493. var pointer = this.getPointer(event.center);
  46494. var multiselect = this.selectionHandler.options.multiselect && (event.changedPointers[0].ctrlKey || event.changedPointers[0].metaKey);
  46495. this.checkSelectionChanges(pointer, event, multiselect);
  46496. this.selectionHandler._generateClickEvent('click', event, pointer);
  46497. }
  46498. /**
  46499. * handle doubletap event
  46500. * @param {Event} event
  46501. * @private
  46502. */
  46503. }, {
  46504. key: 'onDoubleTap',
  46505. value: function onDoubleTap(event) {
  46506. var pointer = this.getPointer(event.center);
  46507. this.selectionHandler._generateClickEvent('doubleClick', event, pointer);
  46508. }
  46509. /**
  46510. * handle long tap event: multi select nodes
  46511. * @param {Event} event
  46512. * @private
  46513. */
  46514. }, {
  46515. key: 'onHold',
  46516. value: function onHold(event) {
  46517. var pointer = this.getPointer(event.center);
  46518. var multiselect = this.selectionHandler.options.multiselect;
  46519. this.checkSelectionChanges(pointer, event, multiselect);
  46520. this.selectionHandler._generateClickEvent('click', event, pointer);
  46521. this.selectionHandler._generateClickEvent('hold', event, pointer);
  46522. }
  46523. /**
  46524. * handle the release of the screen
  46525. *
  46526. * @param {Event} event
  46527. * @private
  46528. */
  46529. }, {
  46530. key: 'onRelease',
  46531. value: function onRelease(event) {
  46532. if (new Date().valueOf() - this.touchTime > 10) {
  46533. var pointer = this.getPointer(event.center);
  46534. this.selectionHandler._generateClickEvent('release', event, pointer);
  46535. // to avoid double fireing of this event because we have two hammer instances. (on canvas and on frame)
  46536. this.touchTime = new Date().valueOf();
  46537. }
  46538. }
  46539. /**
  46540. *
  46541. * @param {Event} event
  46542. */
  46543. }, {
  46544. key: 'onContext',
  46545. value: function onContext(event) {
  46546. var pointer = this.getPointer({ x: event.clientX, y: event.clientY });
  46547. this.selectionHandler._generateClickEvent('oncontext', event, pointer);
  46548. }
  46549. /**
  46550. * Select and deselect nodes depending current selection change.
  46551. *
  46552. * For changing nodes, select/deselect events are fired.
  46553. *
  46554. * NOTE: For a given edge, if one connecting node is deselected and with the same
  46555. * click the other node is selected, no events for the edge will fire.
  46556. * It was selected and it will remain selected.
  46557. *
  46558. * TODO: This is all SelectionHandler calls; the method should be moved to there.
  46559. *
  46560. * @param {{x: number, y: number}} pointer
  46561. * @param {Event} event
  46562. * @param {boolean} [add=false]
  46563. */
  46564. }, {
  46565. key: 'checkSelectionChanges',
  46566. value: function checkSelectionChanges(pointer, event) {
  46567. var add = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  46568. var previousSelection = this.selectionHandler.getSelection();
  46569. var selected = false;
  46570. if (add === true) {
  46571. selected = this.selectionHandler.selectAdditionalOnPoint(pointer);
  46572. } else {
  46573. selected = this.selectionHandler.selectOnPoint(pointer);
  46574. }
  46575. var currentSelection = this.selectionHandler.getSelection();
  46576. // See NOTE in method comment for the reason to do it like this
  46577. var deselectedItems = this._determineDifference(previousSelection, currentSelection);
  46578. var selectedItems = this._determineDifference(currentSelection, previousSelection);
  46579. if (deselectedItems.edges.length > 0) {
  46580. this.selectionHandler._generateClickEvent('deselectEdge', event, pointer, previousSelection);
  46581. selected = true;
  46582. }
  46583. if (deselectedItems.nodes.length > 0) {
  46584. this.selectionHandler._generateClickEvent('deselectNode', event, pointer, previousSelection);
  46585. selected = true;
  46586. }
  46587. if (selectedItems.nodes.length > 0) {
  46588. this.selectionHandler._generateClickEvent('selectNode', event, pointer);
  46589. selected = true;
  46590. }
  46591. if (selectedItems.edges.length > 0) {
  46592. this.selectionHandler._generateClickEvent('selectEdge', event, pointer);
  46593. selected = true;
  46594. }
  46595. // fire the select event if anything has been selected or deselected
  46596. if (selected === true) {
  46597. // select or unselect
  46598. this.selectionHandler._generateClickEvent('select', event, pointer);
  46599. }
  46600. }
  46601. /**
  46602. * Remove all node and edge id's from the first set that are present in the second one.
  46603. *
  46604. * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} firstSet
  46605. * @param {{nodes: Array.<Node>, edges: Array.<vis.Edge>}} secondSet
  46606. * @returns {{nodes: Array.<Node>, edges: Array.<vis.Edge>}}
  46607. * @private
  46608. */
  46609. }, {
  46610. key: '_determineDifference',
  46611. value: function _determineDifference(firstSet, secondSet) {
  46612. var arrayDiff = function arrayDiff(firstArr, secondArr) {
  46613. var result = [];
  46614. for (var i = 0; i < firstArr.length; i++) {
  46615. var value = firstArr[i];
  46616. if (secondArr.indexOf(value) === -1) {
  46617. result.push(value);
  46618. }
  46619. }
  46620. return result;
  46621. };
  46622. return {
  46623. nodes: arrayDiff(firstSet.nodes, secondSet.nodes),
  46624. edges: arrayDiff(firstSet.edges, secondSet.edges)
  46625. };
  46626. }
  46627. /**
  46628. * This function is called by onDragStart.
  46629. * It is separated out because we can then overload it for the datamanipulation system.
  46630. *
  46631. * @param {Event} event
  46632. * @private
  46633. */
  46634. }, {
  46635. key: 'onDragStart',
  46636. value: function onDragStart(event) {
  46637. //in case the touch event was triggered on an external div, do the initial touch now.
  46638. if (this.drag.pointer === undefined) {
  46639. this.onTouch(event);
  46640. }
  46641. // note: drag.pointer is set in onTouch to get the initial touch location
  46642. var node = this.selectionHandler.getNodeAt(this.drag.pointer);
  46643. this.drag.dragging = true;
  46644. this.drag.selection = [];
  46645. this.drag.translation = util.extend({}, this.body.view.translation); // copy the object
  46646. this.drag.nodeId = undefined;
  46647. if (node !== undefined && this.options.dragNodes === true) {
  46648. this.drag.nodeId = node.id;
  46649. // select the clicked node if not yet selected
  46650. if (node.isSelected() === false) {
  46651. this.selectionHandler.unselectAll();
  46652. this.selectionHandler.selectObject(node);
  46653. }
  46654. // after select to contain the node
  46655. this.selectionHandler._generateClickEvent('dragStart', event, this.drag.pointer);
  46656. var selection = this.selectionHandler.selectionObj.nodes;
  46657. // create an array with the selected nodes and their original location and status
  46658. for (var nodeId in selection) {
  46659. if (selection.hasOwnProperty(nodeId)) {
  46660. var object = selection[nodeId];
  46661. var s = {
  46662. id: object.id,
  46663. node: object,
  46664. // store original x, y, xFixed and yFixed, make the node temporarily Fixed
  46665. x: object.x,
  46666. y: object.y,
  46667. xFixed: object.options.fixed.x,
  46668. yFixed: object.options.fixed.y
  46669. };
  46670. object.options.fixed.x = true;
  46671. object.options.fixed.y = true;
  46672. this.drag.selection.push(s);
  46673. }
  46674. }
  46675. } else {
  46676. // fallback if no node is selected and thus the view is dragged.
  46677. this.selectionHandler._generateClickEvent('dragStart', event, this.drag.pointer, undefined, true);
  46678. }
  46679. }
  46680. /**
  46681. * handle drag event
  46682. * @param {Event} event
  46683. * @private
  46684. */
  46685. }, {
  46686. key: 'onDrag',
  46687. value: function onDrag(event) {
  46688. var _this2 = this;
  46689. if (this.drag.pinched === true) {
  46690. return;
  46691. }
  46692. // remove the focus on node if it is focussed on by the focusOnNode
  46693. this.body.emitter.emit('unlockNode');
  46694. var pointer = this.getPointer(event.center);
  46695. var selection = this.drag.selection;
  46696. if (selection && selection.length && this.options.dragNodes === true) {
  46697. this.selectionHandler._generateClickEvent('dragging', event, pointer);
  46698. // calculate delta's and new location
  46699. var deltaX = pointer.x - this.drag.pointer.x;
  46700. var deltaY = pointer.y - this.drag.pointer.y;
  46701. // update position of all selected nodes
  46702. selection.forEach(function(selection) {
  46703. var node = selection.node;
  46704. // only move the node if it was not fixed initially
  46705. if (selection.xFixed === false) {
  46706. node.x = _this2.canvas._XconvertDOMtoCanvas(_this2.canvas._XconvertCanvasToDOM(selection.x) + deltaX);
  46707. }
  46708. // only move the node if it was not fixed initially
  46709. if (selection.yFixed === false) {
  46710. node.y = _this2.canvas._YconvertDOMtoCanvas(_this2.canvas._YconvertCanvasToDOM(selection.y) + deltaY);
  46711. }
  46712. });
  46713. // start the simulation of the physics
  46714. this.body.emitter.emit('startSimulation');
  46715. } else {
  46716. // move the network
  46717. if (this.options.dragView === true) {
  46718. this.selectionHandler._generateClickEvent('dragging', event, pointer, undefined, true);
  46719. // if the drag was not started properly because the click started outside the network div, start it now.
  46720. if (this.drag.pointer === undefined) {
  46721. this.onDragStart(event);
  46722. return;
  46723. }
  46724. var diffX = pointer.x - this.drag.pointer.x;
  46725. var diffY = pointer.y - this.drag.pointer.y;
  46726. this.body.view.translation = { x: this.drag.translation.x + diffX, y: this.drag.translation.y + diffY };
  46727. this.body.emitter.emit('_requestRedraw');
  46728. }
  46729. }
  46730. }
  46731. /**
  46732. * handle drag start event
  46733. * @param {Event} event
  46734. * @private
  46735. */
  46736. }, {
  46737. key: 'onDragEnd',
  46738. value: function onDragEnd(event) {
  46739. this.drag.dragging = false;
  46740. var selection = this.drag.selection;
  46741. if (selection && selection.length) {
  46742. selection.forEach(function(s) {
  46743. // restore original xFixed and yFixed
  46744. s.node.options.fixed.x = s.xFixed;
  46745. s.node.options.fixed.y = s.yFixed;
  46746. });
  46747. this.selectionHandler._generateClickEvent('dragEnd', event, this.getPointer(event.center));
  46748. this.body.emitter.emit('startSimulation');
  46749. } else {
  46750. this.selectionHandler._generateClickEvent('dragEnd', event, this.getPointer(event.center), undefined, true);
  46751. this.body.emitter.emit('_requestRedraw');
  46752. }
  46753. }
  46754. /**
  46755. * Handle pinch event
  46756. * @param {Event} event The event
  46757. * @private
  46758. */
  46759. }, {
  46760. key: 'onPinch',
  46761. value: function onPinch(event) {
  46762. var pointer = this.getPointer(event.center);
  46763. this.drag.pinched = true;
  46764. if (this.pinch['scale'] === undefined) {
  46765. this.pinch.scale = 1;
  46766. }
  46767. // TODO: enabled moving while pinching?
  46768. var scale = this.pinch.scale * event.scale;
  46769. this.zoom(scale, pointer);
  46770. }
  46771. /**
  46772. * Zoom the network in or out
  46773. * @param {number} scale a number around 1, and between 0.01 and 10
  46774. * @param {{x: number, y: number}} pointer Position on screen
  46775. * @private
  46776. */
  46777. }, {
  46778. key: 'zoom',
  46779. value: function zoom(scale, pointer) {
  46780. if (this.options.zoomView === true) {
  46781. var scaleOld = this.body.view.scale;
  46782. if (scale < 0.00001) {
  46783. scale = 0.00001;
  46784. }
  46785. if (scale > 10) {
  46786. scale = 10;
  46787. }
  46788. var preScaleDragPointer = undefined;
  46789. if (this.drag !== undefined) {
  46790. if (this.drag.dragging === true) {
  46791. preScaleDragPointer = this.canvas.DOMtoCanvas(this.drag.pointer);
  46792. }
  46793. }
  46794. // + this.canvas.frame.canvas.clientHeight / 2
  46795. var translation = this.body.view.translation;
  46796. var scaleFrac = scale / scaleOld;
  46797. var tx = (1 - scaleFrac) * pointer.x + translation.x * scaleFrac;
  46798. var ty = (1 - scaleFrac) * pointer.y + translation.y * scaleFrac;
  46799. this.body.view.scale = scale;
  46800. this.body.view.translation = { x: tx, y: ty };
  46801. if (preScaleDragPointer != undefined) {
  46802. var postScaleDragPointer = this.canvas.canvasToDOM(preScaleDragPointer);
  46803. this.drag.pointer.x = postScaleDragPointer.x;
  46804. this.drag.pointer.y = postScaleDragPointer.y;
  46805. }
  46806. this.body.emitter.emit('_requestRedraw');
  46807. if (scaleOld < scale) {
  46808. this.body.emitter.emit('zoom', { direction: '+', scale: this.body.view.scale, pointer: pointer });
  46809. } else {
  46810. this.body.emitter.emit('zoom', { direction: '-', scale: this.body.view.scale, pointer: pointer });
  46811. }
  46812. }
  46813. }
  46814. /**
  46815. * Event handler for mouse wheel event, used to zoom the timeline
  46816. * See http://adomas.org/javascript-mouse-wheel/
  46817. * https://github.com/EightMedia/hammer.js/issues/256
  46818. * @param {MouseEvent} event
  46819. * @private
  46820. */
  46821. }, {
  46822. key: 'onMouseWheel',
  46823. value: function onMouseWheel(event) {
  46824. if (this.options.zoomView === true) {
  46825. // retrieve delta
  46826. var delta = 0;
  46827. if (event.wheelDelta) {
  46828. /* IE/Opera. */
  46829. delta = event.wheelDelta / 120;
  46830. } else if (event.detail) {
  46831. /* Mozilla case. */
  46832. // In Mozilla, sign of delta is different than in IE.
  46833. // Also, delta is multiple of 3.
  46834. delta = -event.detail / 3;
  46835. }
  46836. // If delta is nonzero, handle it.
  46837. // Basically, delta is now positive if wheel was scrolled up,
  46838. // and negative, if wheel was scrolled down.
  46839. if (delta !== 0) {
  46840. // calculate the new scale
  46841. var scale = this.body.view.scale;
  46842. var zoom = delta / 10;
  46843. if (delta < 0) {
  46844. zoom = zoom / (1 - zoom);
  46845. }
  46846. scale *= 1 + zoom;
  46847. // calculate the pointer location
  46848. var pointer = this.getPointer({ x: event.clientX, y: event.clientY });
  46849. // apply the new scale
  46850. this.zoom(scale, pointer);
  46851. }
  46852. // Prevent default actions caused by mouse wheel.
  46853. event.preventDefault();
  46854. }
  46855. }
  46856. /**
  46857. * Mouse move handler for checking whether the title moves over a node with a title.
  46858. * @param {Event} event
  46859. * @private
  46860. */
  46861. }, {
  46862. key: 'onMouseMove',
  46863. value: function onMouseMove(event) {
  46864. var _this3 = this;
  46865. var pointer = this.getPointer({ x: event.clientX, y: event.clientY });
  46866. var popupVisible = false;
  46867. // check if the previously selected node is still selected
  46868. if (this.popup !== undefined) {
  46869. if (this.popup.hidden === false) {
  46870. this._checkHidePopup(pointer);
  46871. }
  46872. // if the popup was not hidden above
  46873. if (this.popup.hidden === false) {
  46874. popupVisible = true;
  46875. this.popup.setPosition(pointer.x + 3, pointer.y - 5);
  46876. this.popup.show();
  46877. }
  46878. }
  46879. // if we bind the keyboard to the div, we have to highlight it to use it. This highlights it on mouse over.
  46880. if (this.options.keyboard.bindToWindow === false && this.options.keyboard.enabled === true) {
  46881. this.canvas.frame.focus();
  46882. }
  46883. // start a timeout that will check if the mouse is positioned above an element
  46884. if (popupVisible === false) {
  46885. if (this.popupTimer !== undefined) {
  46886. clearInterval(this.popupTimer); // stop any running calculationTimer
  46887. this.popupTimer = undefined;
  46888. }
  46889. if (!this.drag.dragging) {
  46890. this.popupTimer = setTimeout(function() {
  46891. return _this3._checkShowPopup(pointer);
  46892. }, this.options.tooltipDelay);
  46893. }
  46894. }
  46895. // adding hover highlights
  46896. if (this.options.hover === true) {
  46897. this.selectionHandler.hoverObject(event, pointer);
  46898. }
  46899. }
  46900. /**
  46901. * Check if there is an element on the given position in the network
  46902. * (a node or edge). If so, and if this element has a title,
  46903. * show a popup window with its title.
  46904. *
  46905. * @param {{x:number, y:number}} pointer
  46906. * @private
  46907. */
  46908. }, {
  46909. key: '_checkShowPopup',
  46910. value: function _checkShowPopup(pointer) {
  46911. var x = this.canvas._XconvertDOMtoCanvas(pointer.x);
  46912. var y = this.canvas._YconvertDOMtoCanvas(pointer.y);
  46913. var pointerObj = {
  46914. left: x,
  46915. top: y,
  46916. right: x,
  46917. bottom: y
  46918. };
  46919. var previousPopupObjId = this.popupObj === undefined ? undefined : this.popupObj.id;
  46920. var nodeUnderCursor = false;
  46921. var popupType = 'node';
  46922. // check if a node is under the cursor.
  46923. if (this.popupObj === undefined) {
  46924. // search the nodes for overlap, select the top one in case of multiple nodes
  46925. var nodeIndices = this.body.nodeIndices;
  46926. var nodes = this.body.nodes;
  46927. var node = void 0;
  46928. var overlappingNodes = [];
  46929. for (var i = 0; i < nodeIndices.length; i++) {
  46930. node = nodes[nodeIndices[i]];
  46931. if (node.isOverlappingWith(pointerObj) === true) {
  46932. if (node.getTitle() !== undefined) {
  46933. overlappingNodes.push(nodeIndices[i]);
  46934. }
  46935. }
  46936. }
  46937. if (overlappingNodes.length > 0) {
  46938. // if there are overlapping nodes, select the last one, this is the one which is drawn on top of the others
  46939. this.popupObj = nodes[overlappingNodes[overlappingNodes.length - 1]];
  46940. // if you hover over a node, the title of the edge is not supposed to be shown.
  46941. nodeUnderCursor = true;
  46942. }
  46943. }
  46944. if (this.popupObj === undefined && nodeUnderCursor === false) {
  46945. // search the edges for overlap
  46946. var edgeIndices = this.body.edgeIndices;
  46947. var edges = this.body.edges;
  46948. var edge = void 0;
  46949. var overlappingEdges = [];
  46950. for (var _i = 0; _i < edgeIndices.length; _i++) {
  46951. edge = edges[edgeIndices[_i]];
  46952. if (edge.isOverlappingWith(pointerObj) === true) {
  46953. if (edge.connected === true && edge.getTitle() !== undefined) {
  46954. overlappingEdges.push(edgeIndices[_i]);
  46955. }
  46956. }
  46957. }
  46958. if (overlappingEdges.length > 0) {
  46959. this.popupObj = edges[overlappingEdges[overlappingEdges.length - 1]];
  46960. popupType = 'edge';
  46961. }
  46962. }
  46963. if (this.popupObj !== undefined) {
  46964. // show popup message window
  46965. if (this.popupObj.id !== previousPopupObjId) {
  46966. if (this.popup === undefined) {
  46967. this.popup = new Popup(this.canvas.frame);
  46968. }
  46969. this.popup.popupTargetType = popupType;
  46970. this.popup.popupTargetId = this.popupObj.id;
  46971. // adjust a small offset such that the mouse cursor is located in the
  46972. // bottom left location of the popup, and you can easily move over the
  46973. // popup area
  46974. this.popup.setPosition(pointer.x + 3, pointer.y - 5);
  46975. this.popup.setText(this.popupObj.getTitle());
  46976. this.popup.show();
  46977. this.body.emitter.emit('showPopup', this.popupObj.id);
  46978. }
  46979. } else {
  46980. if (this.popup !== undefined) {
  46981. this.popup.hide();
  46982. this.body.emitter.emit('hidePopup');
  46983. }
  46984. }
  46985. }
  46986. /**
  46987. * Check if the popup must be hidden, which is the case when the mouse is no
  46988. * longer hovering on the object
  46989. * @param {{x:number, y:number}} pointer
  46990. * @private
  46991. */
  46992. }, {
  46993. key: '_checkHidePopup',
  46994. value: function _checkHidePopup(pointer) {
  46995. var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
  46996. var stillOnObj = false;
  46997. if (this.popup.popupTargetType === 'node') {
  46998. if (this.body.nodes[this.popup.popupTargetId] !== undefined) {
  46999. stillOnObj = this.body.nodes[this.popup.popupTargetId].isOverlappingWith(pointerObj);
  47000. // if the mouse is still one the node, we have to check if it is not also on one that is drawn on top of it.
  47001. // we initially only check stillOnObj because this is much faster.
  47002. if (stillOnObj === true) {
  47003. var overNode = this.selectionHandler.getNodeAt(pointer);
  47004. stillOnObj = overNode === undefined ? false : overNode.id === this.popup.popupTargetId;
  47005. }
  47006. }
  47007. } else {
  47008. if (this.selectionHandler.getNodeAt(pointer) === undefined) {
  47009. if (this.body.edges[this.popup.popupTargetId] !== undefined) {
  47010. stillOnObj = this.body.edges[this.popup.popupTargetId].isOverlappingWith(pointerObj);
  47011. }
  47012. }
  47013. }
  47014. if (stillOnObj === false) {
  47015. this.popupObj = undefined;
  47016. this.popup.hide();
  47017. this.body.emitter.emit('hidePopup');
  47018. }
  47019. }
  47020. }]);
  47021. return InteractionHandler;
  47022. }();
  47023. exports['default'] = InteractionHandler;
  47024. /***/
  47025. }),
  47026. /* 233 */
  47027. /***/
  47028. (function(module, exports, __webpack_require__) {
  47029. "use strict";
  47030. Object.defineProperty(exports, "__esModule", {
  47031. value: true
  47032. });
  47033. var _classCallCheck2 = __webpack_require__(0);
  47034. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  47035. var _createClass2 = __webpack_require__(1);
  47036. var _createClass3 = _interopRequireDefault(_createClass2);
  47037. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  47038. var Hammer = __webpack_require__(10);
  47039. var hammerUtil = __webpack_require__(37);
  47040. var keycharm = __webpack_require__(35);
  47041. /**
  47042. * Navigation Handler
  47043. */
  47044. var NavigationHandler = function() {
  47045. /**
  47046. * @param {Object} body
  47047. * @param {Canvas} canvas
  47048. */
  47049. function NavigationHandler(body, canvas) {
  47050. var _this = this;
  47051. (0, _classCallCheck3['default'])(this, NavigationHandler);
  47052. this.body = body;
  47053. this.canvas = canvas;
  47054. this.iconsCreated = false;
  47055. this.navigationHammers = [];
  47056. this.boundFunctions = {};
  47057. this.touchTime = 0;
  47058. this.activated = false;
  47059. this.body.emitter.on("activate", function() {
  47060. _this.activated = true;
  47061. _this.configureKeyboardBindings();
  47062. });
  47063. this.body.emitter.on("deactivate", function() {
  47064. _this.activated = false;
  47065. _this.configureKeyboardBindings();
  47066. });
  47067. this.body.emitter.on("destroy", function() {
  47068. if (_this.keycharm !== undefined) {
  47069. _this.keycharm.destroy();
  47070. }
  47071. });
  47072. this.options = {};
  47073. }
  47074. /**
  47075. *
  47076. * @param {Object} options
  47077. */
  47078. (0, _createClass3['default'])(NavigationHandler, [{
  47079. key: 'setOptions',
  47080. value: function setOptions(options) {
  47081. if (options !== undefined) {
  47082. this.options = options;
  47083. this.create();
  47084. }
  47085. }
  47086. /**
  47087. * Creates or refreshes navigation and sets key bindings
  47088. */
  47089. }, {
  47090. key: 'create',
  47091. value: function create() {
  47092. if (this.options.navigationButtons === true) {
  47093. if (this.iconsCreated === false) {
  47094. this.loadNavigationElements();
  47095. }
  47096. } else if (this.iconsCreated === true) {
  47097. this.cleanNavigation();
  47098. }
  47099. this.configureKeyboardBindings();
  47100. }
  47101. /**
  47102. * Cleans up previous navigation items
  47103. */
  47104. }, {
  47105. key: 'cleanNavigation',
  47106. value: function cleanNavigation() {
  47107. // clean hammer bindings
  47108. if (this.navigationHammers.length != 0) {
  47109. for (var i = 0; i < this.navigationHammers.length; i++) {
  47110. this.navigationHammers[i].destroy();
  47111. }
  47112. this.navigationHammers = [];
  47113. }
  47114. // clean up previous navigation items
  47115. if (this.navigationDOM && this.navigationDOM['wrapper'] && this.navigationDOM['wrapper'].parentNode) {
  47116. this.navigationDOM['wrapper'].parentNode.removeChild(this.navigationDOM['wrapper']);
  47117. }
  47118. this.iconsCreated = false;
  47119. }
  47120. /**
  47121. * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation
  47122. * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent
  47123. * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false.
  47124. * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas.
  47125. *
  47126. * @private
  47127. */
  47128. }, {
  47129. key: 'loadNavigationElements',
  47130. value: function loadNavigationElements() {
  47131. var _this2 = this;
  47132. this.cleanNavigation();
  47133. this.navigationDOM = {};
  47134. var navigationDivs = ['up', 'down', 'left', 'right', 'zoomIn', 'zoomOut', 'zoomExtends'];
  47135. var navigationDivActions = ['_moveUp', '_moveDown', '_moveLeft', '_moveRight', '_zoomIn', '_zoomOut', '_fit'];
  47136. this.navigationDOM['wrapper'] = document.createElement('div');
  47137. this.navigationDOM['wrapper'].className = 'vis-navigation';
  47138. this.canvas.frame.appendChild(this.navigationDOM['wrapper']);
  47139. for (var i = 0; i < navigationDivs.length; i++) {
  47140. this.navigationDOM[navigationDivs[i]] = document.createElement('div');
  47141. this.navigationDOM[navigationDivs[i]].className = 'vis-button vis-' + navigationDivs[i];
  47142. this.navigationDOM['wrapper'].appendChild(this.navigationDOM[navigationDivs[i]]);
  47143. var hammer = new Hammer(this.navigationDOM[navigationDivs[i]]);
  47144. if (navigationDivActions[i] === "_fit") {
  47145. hammerUtil.onTouch(hammer, this._fit.bind(this));
  47146. } else {
  47147. hammerUtil.onTouch(hammer, this.bindToRedraw.bind(this, navigationDivActions[i]));
  47148. }
  47149. this.navigationHammers.push(hammer);
  47150. }
  47151. // use a hammer for the release so we do not require the one used in the rest of the network
  47152. // the one the rest uses can be overloaded by the manipulation system.
  47153. var hammerFrame = new Hammer(this.canvas.frame);
  47154. hammerUtil.onRelease(hammerFrame, function() {
  47155. _this2._stopMovement();
  47156. });
  47157. this.navigationHammers.push(hammerFrame);
  47158. this.iconsCreated = true;
  47159. }
  47160. /**
  47161. *
  47162. * @param {string} action
  47163. */
  47164. }, {
  47165. key: 'bindToRedraw',
  47166. value: function bindToRedraw(action) {
  47167. if (this.boundFunctions[action] === undefined) {
  47168. this.boundFunctions[action] = this[action].bind(this);
  47169. this.body.emitter.on("initRedraw", this.boundFunctions[action]);
  47170. this.body.emitter.emit("_startRendering");
  47171. }
  47172. }
  47173. /**
  47174. *
  47175. * @param {string} action
  47176. */
  47177. }, {
  47178. key: 'unbindFromRedraw',
  47179. value: function unbindFromRedraw(action) {
  47180. if (this.boundFunctions[action] !== undefined) {
  47181. this.body.emitter.off("initRedraw", this.boundFunctions[action]);
  47182. this.body.emitter.emit("_stopRendering");
  47183. delete this.boundFunctions[action];
  47184. }
  47185. }
  47186. /**
  47187. * this stops all movement induced by the navigation buttons
  47188. *
  47189. * @private
  47190. */
  47191. }, {
  47192. key: '_fit',
  47193. value: function _fit() {
  47194. if (new Date().valueOf() - this.touchTime > 700) {
  47195. // TODO: fix ugly hack to avoid hammer's double fireing of event (because we use release?)
  47196. this.body.emitter.emit("fit", { duration: 700 });
  47197. this.touchTime = new Date().valueOf();
  47198. }
  47199. }
  47200. /**
  47201. * this stops all movement induced by the navigation buttons
  47202. *
  47203. * @private
  47204. */
  47205. }, {
  47206. key: '_stopMovement',
  47207. value: function _stopMovement() {
  47208. for (var boundAction in this.boundFunctions) {
  47209. if (this.boundFunctions.hasOwnProperty(boundAction)) {
  47210. this.body.emitter.off("initRedraw", this.boundFunctions[boundAction]);
  47211. this.body.emitter.emit("_stopRendering");
  47212. }
  47213. }
  47214. this.boundFunctions = {};
  47215. }
  47216. /**
  47217. *
  47218. * @private
  47219. */
  47220. }, {
  47221. key: '_moveUp',
  47222. value: function _moveUp() {
  47223. this.body.view.translation.y += this.options.keyboard.speed.y;
  47224. }
  47225. /**
  47226. *
  47227. * @private
  47228. */
  47229. }, {
  47230. key: '_moveDown',
  47231. value: function _moveDown() {
  47232. this.body.view.translation.y -= this.options.keyboard.speed.y;
  47233. }
  47234. /**
  47235. *
  47236. * @private
  47237. */
  47238. }, {
  47239. key: '_moveLeft',
  47240. value: function _moveLeft() {
  47241. this.body.view.translation.x += this.options.keyboard.speed.x;
  47242. }
  47243. /**
  47244. *
  47245. * @private
  47246. */
  47247. }, {
  47248. key: '_moveRight',
  47249. value: function _moveRight() {
  47250. this.body.view.translation.x -= this.options.keyboard.speed.x;
  47251. }
  47252. /**
  47253. *
  47254. * @private
  47255. */
  47256. }, {
  47257. key: '_zoomIn',
  47258. value: function _zoomIn() {
  47259. var scaleOld = this.body.view.scale;
  47260. var scale = this.body.view.scale * (1 + this.options.keyboard.speed.zoom);
  47261. var translation = this.body.view.translation;
  47262. var scaleFrac = scale / scaleOld;
  47263. var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
  47264. var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
  47265. this.body.view.scale = scale;
  47266. this.body.view.translation = { x: tx, y: ty };
  47267. this.body.emitter.emit('zoom', { direction: '+', scale: this.body.view.scale, pointer: null });
  47268. }
  47269. /**
  47270. *
  47271. * @private
  47272. */
  47273. }, {
  47274. key: '_zoomOut',
  47275. value: function _zoomOut() {
  47276. var scaleOld = this.body.view.scale;
  47277. var scale = this.body.view.scale / (1 + this.options.keyboard.speed.zoom);
  47278. var translation = this.body.view.translation;
  47279. var scaleFrac = scale / scaleOld;
  47280. var tx = (1 - scaleFrac) * this.canvas.canvasViewCenter.x + translation.x * scaleFrac;
  47281. var ty = (1 - scaleFrac) * this.canvas.canvasViewCenter.y + translation.y * scaleFrac;
  47282. this.body.view.scale = scale;
  47283. this.body.view.translation = { x: tx, y: ty };
  47284. this.body.emitter.emit('zoom', { direction: '-', scale: this.body.view.scale, pointer: null });
  47285. }
  47286. /**
  47287. * bind all keys using keycharm.
  47288. */
  47289. }, {
  47290. key: 'configureKeyboardBindings',
  47291. value: function configureKeyboardBindings() {
  47292. var _this3 = this;
  47293. if (this.keycharm !== undefined) {
  47294. this.keycharm.destroy();
  47295. }
  47296. if (this.options.keyboard.enabled === true) {
  47297. if (this.options.keyboard.bindToWindow === true) {
  47298. this.keycharm = keycharm({ container: window, preventDefault: true });
  47299. } else {
  47300. this.keycharm = keycharm({ container: this.canvas.frame, preventDefault: true });
  47301. }
  47302. this.keycharm.reset();
  47303. if (this.activated === true) {
  47304. this.keycharm.bind("up", function() {
  47305. _this3.bindToRedraw("_moveUp");
  47306. }, "keydown");
  47307. this.keycharm.bind("down", function() {
  47308. _this3.bindToRedraw("_moveDown");
  47309. }, "keydown");
  47310. this.keycharm.bind("left", function() {
  47311. _this3.bindToRedraw("_moveLeft");
  47312. }, "keydown");
  47313. this.keycharm.bind("right", function() {
  47314. _this3.bindToRedraw("_moveRight");
  47315. }, "keydown");
  47316. this.keycharm.bind("=", function() {
  47317. _this3.bindToRedraw("_zoomIn");
  47318. }, "keydown");
  47319. this.keycharm.bind("num+", function() {
  47320. _this3.bindToRedraw("_zoomIn");
  47321. }, "keydown");
  47322. this.keycharm.bind("num-", function() {
  47323. _this3.bindToRedraw("_zoomOut");
  47324. }, "keydown");
  47325. this.keycharm.bind("-", function() {
  47326. _this3.bindToRedraw("_zoomOut");
  47327. }, "keydown");
  47328. this.keycharm.bind("[", function() {
  47329. _this3.bindToRedraw("_zoomOut");
  47330. }, "keydown");
  47331. this.keycharm.bind("]", function() {
  47332. _this3.bindToRedraw("_zoomIn");
  47333. }, "keydown");
  47334. this.keycharm.bind("pageup", function() {
  47335. _this3.bindToRedraw("_zoomIn");
  47336. }, "keydown");
  47337. this.keycharm.bind("pagedown", function() {
  47338. _this3.bindToRedraw("_zoomOut");
  47339. }, "keydown");
  47340. this.keycharm.bind("up", function() {
  47341. _this3.unbindFromRedraw("_moveUp");
  47342. }, "keyup");
  47343. this.keycharm.bind("down", function() {
  47344. _this3.unbindFromRedraw("_moveDown");
  47345. }, "keyup");
  47346. this.keycharm.bind("left", function() {
  47347. _this3.unbindFromRedraw("_moveLeft");
  47348. }, "keyup");
  47349. this.keycharm.bind("right", function() {
  47350. _this3.unbindFromRedraw("_moveRight");
  47351. }, "keyup");
  47352. this.keycharm.bind("=", function() {
  47353. _this3.unbindFromRedraw("_zoomIn");
  47354. }, "keyup");
  47355. this.keycharm.bind("num+", function() {
  47356. _this3.unbindFromRedraw("_zoomIn");
  47357. }, "keyup");
  47358. this.keycharm.bind("num-", function() {
  47359. _this3.unbindFromRedraw("_zoomOut");
  47360. }, "keyup");
  47361. this.keycharm.bind("-", function() {
  47362. _this3.unbindFromRedraw("_zoomOut");
  47363. }, "keyup");
  47364. this.keycharm.bind("[", function() {
  47365. _this3.unbindFromRedraw("_zoomOut");
  47366. }, "keyup");
  47367. this.keycharm.bind("]", function() {
  47368. _this3.unbindFromRedraw("_zoomIn");
  47369. }, "keyup");
  47370. this.keycharm.bind("pageup", function() {
  47371. _this3.unbindFromRedraw("_zoomIn");
  47372. }, "keyup");
  47373. this.keycharm.bind("pagedown", function() {
  47374. _this3.unbindFromRedraw("_zoomOut");
  47375. }, "keyup");
  47376. }
  47377. }
  47378. }
  47379. }]);
  47380. return NavigationHandler;
  47381. }();
  47382. exports['default'] = NavigationHandler;
  47383. /***/
  47384. }),
  47385. /* 234 */
  47386. /***/
  47387. (function(module, exports, __webpack_require__) {
  47388. "use strict";
  47389. Object.defineProperty(exports, "__esModule", {
  47390. value: true
  47391. });
  47392. var _classCallCheck2 = __webpack_require__(0);
  47393. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  47394. var _createClass2 = __webpack_require__(1);
  47395. var _createClass3 = _interopRequireDefault(_createClass2);
  47396. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  47397. var Node = __webpack_require__(47)['default'];
  47398. var Edge = __webpack_require__(74)['default'];
  47399. var util = __webpack_require__(2);
  47400. /**
  47401. * The handler for selections
  47402. */
  47403. var SelectionHandler = function() {
  47404. /**
  47405. * @param {Object} body
  47406. * @param {Canvas} canvas
  47407. */
  47408. function SelectionHandler(body, canvas) {
  47409. var _this = this;
  47410. (0, _classCallCheck3['default'])(this, SelectionHandler);
  47411. this.body = body;
  47412. this.canvas = canvas;
  47413. this.selectionObj = { nodes: [], edges: [] };
  47414. this.hoverObj = { nodes: {}, edges: {} };
  47415. this.options = {};
  47416. this.defaultOptions = {
  47417. multiselect: false,
  47418. selectable: true,
  47419. selectConnectedEdges: true,
  47420. hoverConnectedEdges: true
  47421. };
  47422. util.extend(this.options, this.defaultOptions);
  47423. this.body.emitter.on("_dataChanged", function() {
  47424. _this.updateSelection();
  47425. });
  47426. }
  47427. /**
  47428. *
  47429. * @param {Object} [options]
  47430. */
  47431. (0, _createClass3['default'])(SelectionHandler, [{
  47432. key: 'setOptions',
  47433. value: function setOptions(options) {
  47434. if (options !== undefined) {
  47435. var fields = ['multiselect', 'hoverConnectedEdges', 'selectable', 'selectConnectedEdges'];
  47436. util.selectiveDeepExtend(fields, this.options, options);
  47437. }
  47438. }
  47439. /**
  47440. * handles the selection part of the tap;
  47441. *
  47442. * @param {{x: number, y: number}} pointer
  47443. * @returns {boolean}
  47444. */
  47445. }, {
  47446. key: 'selectOnPoint',
  47447. value: function selectOnPoint(pointer) {
  47448. var selected = false;
  47449. if (this.options.selectable === true) {
  47450. var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
  47451. // unselect after getting the objects in order to restore width and height.
  47452. this.unselectAll();
  47453. if (obj !== undefined) {
  47454. selected = this.selectObject(obj);
  47455. }
  47456. this.body.emitter.emit("_requestRedraw");
  47457. }
  47458. return selected;
  47459. }
  47460. /**
  47461. *
  47462. * @param {{x: number, y: number}} pointer
  47463. * @returns {boolean}
  47464. */
  47465. }, {
  47466. key: 'selectAdditionalOnPoint',
  47467. value: function selectAdditionalOnPoint(pointer) {
  47468. var selectionChanged = false;
  47469. if (this.options.selectable === true) {
  47470. var obj = this.getNodeAt(pointer) || this.getEdgeAt(pointer);
  47471. if (obj !== undefined) {
  47472. selectionChanged = true;
  47473. if (obj.isSelected() === true) {
  47474. this.deselectObject(obj);
  47475. } else {
  47476. this.selectObject(obj);
  47477. }
  47478. this.body.emitter.emit("_requestRedraw");
  47479. }
  47480. }
  47481. return selectionChanged;
  47482. }
  47483. /**
  47484. * Create an object containing the standard fields for an event.
  47485. *
  47486. * @param {Event} event
  47487. * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
  47488. * @returns {{}}
  47489. * @private
  47490. */
  47491. }, {
  47492. key: '_initBaseEvent',
  47493. value: function _initBaseEvent(event, pointer) {
  47494. var properties = {};
  47495. properties['pointer'] = {
  47496. DOM: { x: pointer.x, y: pointer.y },
  47497. canvas: this.canvas.DOMtoCanvas(pointer)
  47498. };
  47499. properties['event'] = event;
  47500. return properties;
  47501. }
  47502. /**
  47503. * Generate an event which the user can catch.
  47504. *
  47505. * This adds some extra data to the event with respect to cursor position and
  47506. * selected nodes and edges.
  47507. *
  47508. * @param {string} eventType Name of event to send
  47509. * @param {Event} event
  47510. * @param {{x: number, y: number}} pointer Object with the x and y screen coordinates of the mouse
  47511. * @param {Object|undefined} oldSelection If present, selection state before event occured
  47512. * @param {boolean|undefined} [emptySelection=false] Indicate if selection data should be passed
  47513. */
  47514. }, {
  47515. key: '_generateClickEvent',
  47516. value: function _generateClickEvent(eventType, event, pointer, oldSelection) {
  47517. var emptySelection = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
  47518. var properties = this._initBaseEvent(event, pointer);
  47519. if (emptySelection === true) {
  47520. properties.nodes = [];
  47521. properties.edges = [];
  47522. } else {
  47523. var tmp = this.getSelection();
  47524. properties.nodes = tmp.nodes;
  47525. properties.edges = tmp.edges;
  47526. }
  47527. if (oldSelection !== undefined) {
  47528. properties['previousSelection'] = oldSelection;
  47529. }
  47530. if (eventType == 'click') {
  47531. // For the time being, restrict this functionality to
  47532. // just the click event.
  47533. properties.items = this.getClickedItems(pointer);
  47534. }
  47535. this.body.emitter.emit(eventType, properties);
  47536. }
  47537. /**
  47538. *
  47539. * @param {Object} obj
  47540. * @param {boolean} [highlightEdges=this.options.selectConnectedEdges]
  47541. * @returns {boolean}
  47542. */
  47543. }, {
  47544. key: 'selectObject',
  47545. value: function selectObject(obj) {
  47546. var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.options.selectConnectedEdges;
  47547. if (obj !== undefined) {
  47548. if (obj instanceof Node) {
  47549. if (highlightEdges === true) {
  47550. this._selectConnectedEdges(obj);
  47551. }
  47552. }
  47553. obj.select();
  47554. this._addToSelection(obj);
  47555. return true;
  47556. }
  47557. return false;
  47558. }
  47559. /**
  47560. *
  47561. * @param {Object} obj
  47562. */
  47563. }, {
  47564. key: 'deselectObject',
  47565. value: function deselectObject(obj) {
  47566. if (obj.isSelected() === true) {
  47567. obj.selected = false;
  47568. this._removeFromSelection(obj);
  47569. }
  47570. }
  47571. /**
  47572. * retrieve all nodes overlapping with given object
  47573. * @param {Object} object An object with parameters left, top, right, bottom
  47574. * @return {number[]} An array with id's of the overlapping nodes
  47575. * @private
  47576. */
  47577. }, {
  47578. key: '_getAllNodesOverlappingWith',
  47579. value: function _getAllNodesOverlappingWith(object) {
  47580. var overlappingNodes = [];
  47581. var nodes = this.body.nodes;
  47582. for (var i = 0; i < this.body.nodeIndices.length; i++) {
  47583. var nodeId = this.body.nodeIndices[i];
  47584. if (nodes[nodeId].isOverlappingWith(object)) {
  47585. overlappingNodes.push(nodeId);
  47586. }
  47587. }
  47588. return overlappingNodes;
  47589. }
  47590. /**
  47591. * Return a position object in canvasspace from a single point in screenspace
  47592. *
  47593. * @param {{x: number, y: number}} pointer
  47594. * @returns {{left: number, top: number, right: number, bottom: number}}
  47595. * @private
  47596. */
  47597. }, {
  47598. key: '_pointerToPositionObject',
  47599. value: function _pointerToPositionObject(pointer) {
  47600. var canvasPos = this.canvas.DOMtoCanvas(pointer);
  47601. return {
  47602. left: canvasPos.x - 1,
  47603. top: canvasPos.y + 1,
  47604. right: canvasPos.x + 1,
  47605. bottom: canvasPos.y - 1
  47606. };
  47607. }
  47608. /**
  47609. * Get the top node at the passed point (like a click)
  47610. *
  47611. * @param {{x: number, y: number}} pointer
  47612. * @param {boolean} [returnNode=true]
  47613. * @return {Node | undefined} node
  47614. */
  47615. }, {
  47616. key: 'getNodeAt',
  47617. value: function getNodeAt(pointer) {
  47618. var returnNode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  47619. // we first check if this is an navigation controls element
  47620. var positionObject = this._pointerToPositionObject(pointer);
  47621. var overlappingNodes = this._getAllNodesOverlappingWith(positionObject);
  47622. // if there are overlapping nodes, select the last one, this is the
  47623. // one which is drawn on top of the others
  47624. if (overlappingNodes.length > 0) {
  47625. if (returnNode === true) {
  47626. return this.body.nodes[overlappingNodes[overlappingNodes.length - 1]];
  47627. } else {
  47628. return overlappingNodes[overlappingNodes.length - 1];
  47629. }
  47630. } else {
  47631. return undefined;
  47632. }
  47633. }
  47634. /**
  47635. * retrieve all edges overlapping with given object, selector is around center
  47636. * @param {Object} object An object with parameters left, top, right, bottom
  47637. * @param {number[]} overlappingEdges An array with id's of the overlapping nodes
  47638. * @private
  47639. */
  47640. }, {
  47641. key: '_getEdgesOverlappingWith',
  47642. value: function _getEdgesOverlappingWith(object, overlappingEdges) {
  47643. var edges = this.body.edges;
  47644. for (var i = 0; i < this.body.edgeIndices.length; i++) {
  47645. var edgeId = this.body.edgeIndices[i];
  47646. if (edges[edgeId].isOverlappingWith(object)) {
  47647. overlappingEdges.push(edgeId);
  47648. }
  47649. }
  47650. }
  47651. /**
  47652. * retrieve all nodes overlapping with given object
  47653. * @param {Object} object An object with parameters left, top, right, bottom
  47654. * @return {number[]} An array with id's of the overlapping nodes
  47655. * @private
  47656. */
  47657. }, {
  47658. key: '_getAllEdgesOverlappingWith',
  47659. value: function _getAllEdgesOverlappingWith(object) {
  47660. var overlappingEdges = [];
  47661. this._getEdgesOverlappingWith(object, overlappingEdges);
  47662. return overlappingEdges;
  47663. }
  47664. /**
  47665. * Get the edges nearest to the passed point (like a click)
  47666. *
  47667. * @param {{x: number, y: number}} pointer
  47668. * @param {boolean} [returnEdge=true]
  47669. * @return {Edge | undefined} node
  47670. */
  47671. }, {
  47672. key: 'getEdgeAt',
  47673. value: function getEdgeAt(pointer) {
  47674. var returnEdge = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  47675. // Iterate over edges, pick closest within 10
  47676. var canvasPos = this.canvas.DOMtoCanvas(pointer);
  47677. var mindist = 10;
  47678. var overlappingEdge = null;
  47679. var edges = this.body.edges;
  47680. for (var i = 0; i < this.body.edgeIndices.length; i++) {
  47681. var edgeId = this.body.edgeIndices[i];
  47682. var edge = edges[edgeId];
  47683. if (edge.connected) {
  47684. var xFrom = edge.from.x;
  47685. var yFrom = edge.from.y;
  47686. var xTo = edge.to.x;
  47687. var yTo = edge.to.y;
  47688. var dist = edge.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, canvasPos.x, canvasPos.y);
  47689. if (dist < mindist) {
  47690. overlappingEdge = edgeId;
  47691. mindist = dist;
  47692. }
  47693. }
  47694. }
  47695. if (overlappingEdge !== null) {
  47696. if (returnEdge === true) {
  47697. return this.body.edges[overlappingEdge];
  47698. } else {
  47699. return overlappingEdge;
  47700. }
  47701. } else {
  47702. return undefined;
  47703. }
  47704. }
  47705. /**
  47706. * Add object to the selection array.
  47707. *
  47708. * @param {Object} obj
  47709. * @private
  47710. */
  47711. }, {
  47712. key: '_addToSelection',
  47713. value: function _addToSelection(obj) {
  47714. if (obj instanceof Node) {
  47715. this.selectionObj.nodes[obj.id] = obj;
  47716. } else {
  47717. this.selectionObj.edges[obj.id] = obj;
  47718. }
  47719. }
  47720. /**
  47721. * Add object to the selection array.
  47722. *
  47723. * @param {Object} obj
  47724. * @private
  47725. */
  47726. }, {
  47727. key: '_addToHover',
  47728. value: function _addToHover(obj) {
  47729. if (obj instanceof Node) {
  47730. this.hoverObj.nodes[obj.id] = obj;
  47731. } else {
  47732. this.hoverObj.edges[obj.id] = obj;
  47733. }
  47734. }
  47735. /**
  47736. * Remove a single option from selection.
  47737. *
  47738. * @param {Object} obj
  47739. * @private
  47740. */
  47741. }, {
  47742. key: '_removeFromSelection',
  47743. value: function _removeFromSelection(obj) {
  47744. if (obj instanceof Node) {
  47745. delete this.selectionObj.nodes[obj.id];
  47746. this._unselectConnectedEdges(obj);
  47747. } else {
  47748. delete this.selectionObj.edges[obj.id];
  47749. }
  47750. }
  47751. /**
  47752. * Unselect all. The selectionObj is useful for this.
  47753. */
  47754. }, {
  47755. key: 'unselectAll',
  47756. value: function unselectAll() {
  47757. for (var nodeId in this.selectionObj.nodes) {
  47758. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  47759. this.selectionObj.nodes[nodeId].unselect();
  47760. }
  47761. }
  47762. for (var edgeId in this.selectionObj.edges) {
  47763. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  47764. this.selectionObj.edges[edgeId].unselect();
  47765. }
  47766. }
  47767. this.selectionObj = { nodes: {}, edges: {} };
  47768. }
  47769. /**
  47770. * return the number of selected nodes
  47771. *
  47772. * @returns {number}
  47773. * @private
  47774. */
  47775. }, {
  47776. key: '_getSelectedNodeCount',
  47777. value: function _getSelectedNodeCount() {
  47778. var count = 0;
  47779. for (var nodeId in this.selectionObj.nodes) {
  47780. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  47781. count += 1;
  47782. }
  47783. }
  47784. return count;
  47785. }
  47786. /**
  47787. * return the selected node
  47788. *
  47789. * @returns {number}
  47790. * @private
  47791. */
  47792. }, {
  47793. key: '_getSelectedNode',
  47794. value: function _getSelectedNode() {
  47795. for (var nodeId in this.selectionObj.nodes) {
  47796. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  47797. return this.selectionObj.nodes[nodeId];
  47798. }
  47799. }
  47800. return undefined;
  47801. }
  47802. /**
  47803. * return the selected edge
  47804. *
  47805. * @returns {number}
  47806. * @private
  47807. */
  47808. }, {
  47809. key: '_getSelectedEdge',
  47810. value: function _getSelectedEdge() {
  47811. for (var edgeId in this.selectionObj.edges) {
  47812. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  47813. return this.selectionObj.edges[edgeId];
  47814. }
  47815. }
  47816. return undefined;
  47817. }
  47818. /**
  47819. * return the number of selected edges
  47820. *
  47821. * @returns {number}
  47822. * @private
  47823. */
  47824. }, {
  47825. key: '_getSelectedEdgeCount',
  47826. value: function _getSelectedEdgeCount() {
  47827. var count = 0;
  47828. for (var edgeId in this.selectionObj.edges) {
  47829. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  47830. count += 1;
  47831. }
  47832. }
  47833. return count;
  47834. }
  47835. /**
  47836. * return the number of selected objects.
  47837. *
  47838. * @returns {number}
  47839. * @private
  47840. */
  47841. }, {
  47842. key: '_getSelectedObjectCount',
  47843. value: function _getSelectedObjectCount() {
  47844. var count = 0;
  47845. for (var nodeId in this.selectionObj.nodes) {
  47846. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  47847. count += 1;
  47848. }
  47849. }
  47850. for (var edgeId in this.selectionObj.edges) {
  47851. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  47852. count += 1;
  47853. }
  47854. }
  47855. return count;
  47856. }
  47857. /**
  47858. * Check if anything is selected
  47859. *
  47860. * @returns {boolean}
  47861. * @private
  47862. */
  47863. }, {
  47864. key: '_selectionIsEmpty',
  47865. value: function _selectionIsEmpty() {
  47866. for (var nodeId in this.selectionObj.nodes) {
  47867. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  47868. return false;
  47869. }
  47870. }
  47871. for (var edgeId in this.selectionObj.edges) {
  47872. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  47873. return false;
  47874. }
  47875. }
  47876. return true;
  47877. }
  47878. /**
  47879. * check if one of the selected nodes is a cluster.
  47880. *
  47881. * @returns {boolean}
  47882. * @private
  47883. */
  47884. }, {
  47885. key: '_clusterInSelection',
  47886. value: function _clusterInSelection() {
  47887. for (var nodeId in this.selectionObj.nodes) {
  47888. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  47889. if (this.selectionObj.nodes[nodeId].clusterSize > 1) {
  47890. return true;
  47891. }
  47892. }
  47893. }
  47894. return false;
  47895. }
  47896. /**
  47897. * select the edges connected to the node that is being selected
  47898. *
  47899. * @param {Node} node
  47900. * @private
  47901. */
  47902. }, {
  47903. key: '_selectConnectedEdges',
  47904. value: function _selectConnectedEdges(node) {
  47905. for (var i = 0; i < node.edges.length; i++) {
  47906. var edge = node.edges[i];
  47907. edge.select();
  47908. this._addToSelection(edge);
  47909. }
  47910. }
  47911. /**
  47912. * select the edges connected to the node that is being selected
  47913. *
  47914. * @param {Node} node
  47915. * @private
  47916. */
  47917. }, {
  47918. key: '_hoverConnectedEdges',
  47919. value: function _hoverConnectedEdges(node) {
  47920. for (var i = 0; i < node.edges.length; i++) {
  47921. var edge = node.edges[i];
  47922. edge.hover = true;
  47923. this._addToHover(edge);
  47924. }
  47925. }
  47926. /**
  47927. * unselect the edges connected to the node that is being selected
  47928. *
  47929. * @param {Node} node
  47930. * @private
  47931. */
  47932. }, {
  47933. key: '_unselectConnectedEdges',
  47934. value: function _unselectConnectedEdges(node) {
  47935. for (var i = 0; i < node.edges.length; i++) {
  47936. var edge = node.edges[i];
  47937. edge.unselect();
  47938. this._removeFromSelection(edge);
  47939. }
  47940. }
  47941. /**
  47942. * Remove the highlight from a node or edge, in response to mouse movement
  47943. *
  47944. * @param {Event} event
  47945. * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
  47946. * @param {Node|vis.Edge} object
  47947. * @private
  47948. */
  47949. }, {
  47950. key: 'emitBlurEvent',
  47951. value: function emitBlurEvent(event, pointer, object) {
  47952. var properties = this._initBaseEvent(event, pointer);
  47953. if (object.hover === true) {
  47954. object.hover = false;
  47955. if (object instanceof Node) {
  47956. properties.node = object.id;
  47957. this.body.emitter.emit("blurNode", properties);
  47958. } else {
  47959. properties.edge = object.id;
  47960. this.body.emitter.emit("blurEdge", properties);
  47961. }
  47962. }
  47963. }
  47964. /**
  47965. * Create the highlight for a node or edge, in response to mouse movement
  47966. *
  47967. * @param {Event} event
  47968. * @param {{x: number, y: number}} pointer object with the x and y screen coordinates of the mouse
  47969. * @param {Node|vis.Edge} object
  47970. * @returns {boolean} hoverChanged
  47971. * @private
  47972. */
  47973. }, {
  47974. key: 'emitHoverEvent',
  47975. value: function emitHoverEvent(event, pointer, object) {
  47976. var properties = this._initBaseEvent(event, pointer);
  47977. var hoverChanged = false;
  47978. if (object.hover === false) {
  47979. object.hover = true;
  47980. this._addToHover(object);
  47981. hoverChanged = true;
  47982. if (object instanceof Node) {
  47983. properties.node = object.id;
  47984. this.body.emitter.emit("hoverNode", properties);
  47985. } else {
  47986. properties.edge = object.id;
  47987. this.body.emitter.emit("hoverEdge", properties);
  47988. }
  47989. }
  47990. return hoverChanged;
  47991. }
  47992. /**
  47993. * Perform actions in response to a mouse movement.
  47994. *
  47995. * @param {Event} event
  47996. * @param {{x: number, y: number}} pointer | object with the x and y screen coordinates of the mouse
  47997. */
  47998. }, {
  47999. key: 'hoverObject',
  48000. value: function hoverObject(event, pointer) {
  48001. var object = this.getNodeAt(pointer);
  48002. if (object === undefined) {
  48003. object = this.getEdgeAt(pointer);
  48004. }
  48005. var hoverChanged = false;
  48006. // remove all node hover highlights
  48007. for (var nodeId in this.hoverObj.nodes) {
  48008. if (this.hoverObj.nodes.hasOwnProperty(nodeId)) {
  48009. if (object === undefined || object instanceof Node && object.id != nodeId || object instanceof Edge) {
  48010. this.emitBlurEvent(event, pointer, this.hoverObj.nodes[nodeId]);
  48011. delete this.hoverObj.nodes[nodeId];
  48012. hoverChanged = true;
  48013. }
  48014. }
  48015. }
  48016. // removing all edge hover highlights
  48017. for (var edgeId in this.hoverObj.edges) {
  48018. if (this.hoverObj.edges.hasOwnProperty(edgeId)) {
  48019. // if the hover has been changed here it means that the node has been hovered over or off
  48020. // we then do not use the emitBlurEvent method here.
  48021. if (hoverChanged === true) {
  48022. this.hoverObj.edges[edgeId].hover = false;
  48023. delete this.hoverObj.edges[edgeId];
  48024. }
  48025. // if the blur remains the same and the object is undefined (mouse off) or another
  48026. // edge has been hovered, or another node has been hovered we blur the edge.
  48027. else if (object === undefined || object instanceof Edge && object.id != edgeId || object instanceof Node && !object.hover) {
  48028. this.emitBlurEvent(event, pointer, this.hoverObj.edges[edgeId]);
  48029. delete this.hoverObj.edges[edgeId];
  48030. hoverChanged = true;
  48031. }
  48032. }
  48033. }
  48034. if (object !== undefined) {
  48035. hoverChanged = hoverChanged || this.emitHoverEvent(event, pointer, object);
  48036. if (object instanceof Node && this.options.hoverConnectedEdges === true) {
  48037. this._hoverConnectedEdges(object);
  48038. }
  48039. }
  48040. if (hoverChanged === true) {
  48041. this.body.emitter.emit('_requestRedraw');
  48042. }
  48043. }
  48044. /**
  48045. *
  48046. * retrieve the currently selected objects
  48047. * @return {{nodes: Array.<string>, edges: Array.<string>}} selection
  48048. */
  48049. }, {
  48050. key: 'getSelection',
  48051. value: function getSelection() {
  48052. var nodeIds = this.getSelectedNodes();
  48053. var edgeIds = this.getSelectedEdges();
  48054. return { nodes: nodeIds, edges: edgeIds };
  48055. }
  48056. /**
  48057. *
  48058. * retrieve the currently selected nodes
  48059. * @return {string[]} selection An array with the ids of the
  48060. * selected nodes.
  48061. */
  48062. }, {
  48063. key: 'getSelectedNodes',
  48064. value: function getSelectedNodes() {
  48065. var idArray = [];
  48066. if (this.options.selectable === true) {
  48067. for (var nodeId in this.selectionObj.nodes) {
  48068. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  48069. idArray.push(this.selectionObj.nodes[nodeId].id);
  48070. }
  48071. }
  48072. }
  48073. return idArray;
  48074. }
  48075. /**
  48076. *
  48077. * retrieve the currently selected edges
  48078. * @return {Array} selection An array with the ids of the
  48079. * selected nodes.
  48080. */
  48081. }, {
  48082. key: 'getSelectedEdges',
  48083. value: function getSelectedEdges() {
  48084. var idArray = [];
  48085. if (this.options.selectable === true) {
  48086. for (var edgeId in this.selectionObj.edges) {
  48087. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  48088. idArray.push(this.selectionObj.edges[edgeId].id);
  48089. }
  48090. }
  48091. }
  48092. return idArray;
  48093. }
  48094. /**
  48095. * Updates the current selection
  48096. * @param {{nodes: Array.<string>, edges: Array.<string>}} selection
  48097. * @param {Object} options Options
  48098. */
  48099. }, {
  48100. key: 'setSelection',
  48101. value: function setSelection(selection) {
  48102. var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  48103. var i = void 0,
  48104. id = void 0;
  48105. if (!selection || !selection.nodes && !selection.edges) throw 'Selection must be an object with nodes and/or edges properties';
  48106. // first unselect any selected node, if option is true or undefined
  48107. if (options.unselectAll || options.unselectAll === undefined) {
  48108. this.unselectAll();
  48109. }
  48110. if (selection.nodes) {
  48111. for (i = 0; i < selection.nodes.length; i++) {
  48112. id = selection.nodes[i];
  48113. var node = this.body.nodes[id];
  48114. if (!node) {
  48115. throw new RangeError('Node with id "' + id + '" not found');
  48116. }
  48117. // don't select edges with it
  48118. this.selectObject(node, options.highlightEdges);
  48119. }
  48120. }
  48121. if (selection.edges) {
  48122. for (i = 0; i < selection.edges.length; i++) {
  48123. id = selection.edges[i];
  48124. var edge = this.body.edges[id];
  48125. if (!edge) {
  48126. throw new RangeError('Edge with id "' + id + '" not found');
  48127. }
  48128. this.selectObject(edge);
  48129. }
  48130. }
  48131. this.body.emitter.emit('_requestRedraw');
  48132. }
  48133. /**
  48134. * select zero or more nodes with the option to highlight edges
  48135. * @param {number[] | string[]} selection An array with the ids of the
  48136. * selected nodes.
  48137. * @param {boolean} [highlightEdges]
  48138. */
  48139. }, {
  48140. key: 'selectNodes',
  48141. value: function selectNodes(selection) {
  48142. var highlightEdges = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
  48143. if (!selection || selection.length === undefined) throw 'Selection must be an array with ids';
  48144. this.setSelection({ nodes: selection }, { highlightEdges: highlightEdges });
  48145. }
  48146. /**
  48147. * select zero or more edges
  48148. * @param {number[] | string[]} selection An array with the ids of the
  48149. * selected nodes.
  48150. */
  48151. }, {
  48152. key: 'selectEdges',
  48153. value: function selectEdges(selection) {
  48154. if (!selection || selection.length === undefined) throw 'Selection must be an array with ids';
  48155. this.setSelection({ edges: selection });
  48156. }
  48157. /**
  48158. * Validate the selection: remove ids of nodes which no longer exist
  48159. * @private
  48160. */
  48161. }, {
  48162. key: 'updateSelection',
  48163. value: function updateSelection() {
  48164. for (var nodeId in this.selectionObj.nodes) {
  48165. if (this.selectionObj.nodes.hasOwnProperty(nodeId)) {
  48166. if (!this.body.nodes.hasOwnProperty(nodeId)) {
  48167. delete this.selectionObj.nodes[nodeId];
  48168. }
  48169. }
  48170. }
  48171. for (var edgeId in this.selectionObj.edges) {
  48172. if (this.selectionObj.edges.hasOwnProperty(edgeId)) {
  48173. if (!this.body.edges.hasOwnProperty(edgeId)) {
  48174. delete this.selectionObj.edges[edgeId];
  48175. }
  48176. }
  48177. }
  48178. }
  48179. /**
  48180. * Determine all the visual elements clicked which are on the given point.
  48181. *
  48182. * All elements are returned; this includes nodes, edges and their labels.
  48183. * The order returned is from highest to lowest, i.e. element 0 of the return
  48184. * value is the topmost item clicked on.
  48185. *
  48186. * The return value consists of an array of the following possible elements:
  48187. *
  48188. * - `{nodeId:number}` - node with given id clicked on
  48189. * - `{nodeId:number, labelId:0}` - label of node with given id clicked on
  48190. * - `{edgeId:number}` - edge with given id clicked on
  48191. * - `{edge:number, labelId:0}` - label of edge with given id clicked on
  48192. *
  48193. * ## NOTES
  48194. *
  48195. * - Currently, there is only one label associated with a node or an edge,
  48196. * but this is expected to change somewhere in the future.
  48197. * - Since there is no z-indexing yet, it is not really possible to set the nodes and
  48198. * edges in the correct order. For the time being, nodes come first.
  48199. *
  48200. * @param {point} pointer mouse position in screen coordinates
  48201. * @returns {Array.<nodeClickItem|nodeLabelClickItem|edgeClickItem|edgeLabelClickItem>}
  48202. * @private
  48203. */
  48204. }, {
  48205. key: 'getClickedItems',
  48206. value: function getClickedItems(pointer) {
  48207. var point = this.canvas.DOMtoCanvas(pointer);
  48208. var items = [];
  48209. // Note reverse order; we want the topmost clicked items to be first in the array
  48210. // Also note that selected nodes are disregarded here; these normally display on top
  48211. var nodeIndices = this.body.nodeIndices;
  48212. var nodes = this.body.nodes;
  48213. for (var i = nodeIndices.length - 1; i >= 0; i--) {
  48214. var node = nodes[nodeIndices[i]];
  48215. var ret = node.getItemsOnPoint(point);
  48216. items.push.apply(items, ret); // Append the return value to the running list.
  48217. }
  48218. var edgeIndices = this.body.edgeIndices;
  48219. var edges = this.body.edges;
  48220. for (var _i = edgeIndices.length - 1; _i >= 0; _i--) {
  48221. var edge = edges[edgeIndices[_i]];
  48222. var _ret = edge.getItemsOnPoint(point);
  48223. items.push.apply(items, _ret); // Append the return value to the running list.
  48224. }
  48225. return items;
  48226. }
  48227. }]);
  48228. return SelectionHandler;
  48229. }();
  48230. exports['default'] = SelectionHandler;
  48231. /***/
  48232. }),
  48233. /* 235 */
  48234. /***/
  48235. (function(module, exports, __webpack_require__) {
  48236. "use strict";
  48237. /**
  48238. * There's a mix-up with terms in the code. Following are the formal definitions:
  48239. *
  48240. * tree - a strict hierarchical network, i.e. every node has at most one parent
  48241. * forest - a collection of trees. These distinct trees are thus not connected.
  48242. *
  48243. * So:
  48244. * - in a network that is not a tree, there exist nodes with multiple parents.
  48245. * - a network consisting of unconnected sub-networks, of which at least one
  48246. * is not a tree, is not a forest.
  48247. *
  48248. * In the code, the definitions are:
  48249. *
  48250. * tree - any disconnected sub-network, strict hierarchical or not.
  48251. * forest - a bunch of these sub-networks
  48252. *
  48253. * The difference between tree and not-tree is important in the code, notably within
  48254. * to the block-shifting algorithm. The algorithm assumes formal trees and fails
  48255. * for not-trees, often in a spectacular manner (search for 'exploding network' in the issues).
  48256. *
  48257. * In order to distinguish the definitions in the following code, the adjective 'formal' is
  48258. * used. If 'formal' is absent, you must assume the non-formal definition.
  48259. *
  48260. * ----------------------------------------------------------------------------------
  48261. * NOTES
  48262. * =====
  48263. *
  48264. * A hierarchical layout is a different thing from a hierarchical network.
  48265. * The layout is a way to arrange the nodes in the view; this can be done
  48266. * on non-hierarchical networks as well. The converse is also possible.
  48267. */
  48268. Object.defineProperty(exports, "__esModule", {
  48269. value: true
  48270. });
  48271. var _slicedToArray2 = __webpack_require__(30);
  48272. var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
  48273. var _typeof2 = __webpack_require__(6);
  48274. var _typeof3 = _interopRequireDefault(_typeof2);
  48275. var _keys = __webpack_require__(8);
  48276. var _keys2 = _interopRequireDefault(_keys);
  48277. var _classCallCheck2 = __webpack_require__(0);
  48278. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  48279. var _createClass2 = __webpack_require__(1);
  48280. var _createClass3 = _interopRequireDefault(_createClass2);
  48281. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  48282. var util = __webpack_require__(2);
  48283. var NetworkUtil = __webpack_require__(76)['default'];
  48284. var _require = __webpack_require__(236),
  48285. HorizontalStrategy = _require.HorizontalStrategy,
  48286. VerticalStrategy = _require.VerticalStrategy;
  48287. /**
  48288. * Container for derived data on current network, relating to hierarchy.
  48289. *
  48290. * @private
  48291. */
  48292. var HierarchicalStatus = function() {
  48293. /**
  48294. * @ignore
  48295. */
  48296. function HierarchicalStatus() {
  48297. (0, _classCallCheck3['default'])(this, HierarchicalStatus);
  48298. this.childrenReference = {}; // child id's per node id
  48299. this.parentReference = {}; // parent id's per node id
  48300. this.trees = {}; // tree id per node id; i.e. to which tree does given node id belong
  48301. this.distributionOrdering = {}; // The nodes per level, in the display order
  48302. this.levels = {}; // hierarchy level per node id
  48303. this.distributionIndex = {}; // The position of the node in the level sorting order, per node id.
  48304. this.isTree = false; // True if current network is a formal tree
  48305. this.treeIndex = -1; // Highest tree id in current network.
  48306. }
  48307. /**
  48308. * Add the relation between given nodes to the current state.
  48309. *
  48310. * @param {Node.id} parentNodeId
  48311. * @param {Node.id} childNodeId
  48312. */
  48313. (0, _createClass3['default'])(HierarchicalStatus, [{
  48314. key: 'addRelation',
  48315. value: function addRelation(parentNodeId, childNodeId) {
  48316. if (this.childrenReference[parentNodeId] === undefined) {
  48317. this.childrenReference[parentNodeId] = [];
  48318. }
  48319. this.childrenReference[parentNodeId].push(childNodeId);
  48320. if (this.parentReference[childNodeId] === undefined) {
  48321. this.parentReference[childNodeId] = [];
  48322. }
  48323. this.parentReference[childNodeId].push(parentNodeId);
  48324. }
  48325. /**
  48326. * Check if the current state is for a formal tree or formal forest.
  48327. *
  48328. * This is the case if every node has at most one parent.
  48329. *
  48330. * Pre: parentReference init'ed properly for current network
  48331. */
  48332. }, {
  48333. key: 'checkIfTree',
  48334. value: function checkIfTree() {
  48335. for (var i in this.parentReference) {
  48336. if (this.parentReference[i].length > 1) {
  48337. this.isTree = false;
  48338. return;
  48339. }
  48340. }
  48341. this.isTree = true;
  48342. }
  48343. /**
  48344. * Return the number of separate trees in the current network.
  48345. * @returns {number}
  48346. */
  48347. }, {
  48348. key: 'numTrees',
  48349. value: function numTrees() {
  48350. return this.treeIndex + 1; // This assumes the indexes are assigned consecitively
  48351. }
  48352. /**
  48353. * Assign a tree id to a node
  48354. * @param {Node} node
  48355. * @param {string|number} treeId
  48356. */
  48357. }, {
  48358. key: 'setTreeIndex',
  48359. value: function setTreeIndex(node, treeId) {
  48360. if (treeId === undefined) return; // Don't bother
  48361. if (this.trees[node.id] === undefined) {
  48362. this.trees[node.id] = treeId;
  48363. this.treeIndex = Math.max(treeId, this.treeIndex);
  48364. }
  48365. }
  48366. /**
  48367. * Ensure level for given id is defined.
  48368. *
  48369. * Sets level to zero for given node id if not already present
  48370. *
  48371. * @param {Node.id} nodeId
  48372. */
  48373. }, {
  48374. key: 'ensureLevel',
  48375. value: function ensureLevel(nodeId) {
  48376. if (this.levels[nodeId] === undefined) {
  48377. this.levels[nodeId] = 0;
  48378. }
  48379. }
  48380. /**
  48381. * get the maximum level of a branch.
  48382. *
  48383. * TODO: Never entered; find a test case to test this!
  48384. * @param {Node.id} nodeId
  48385. * @returns {number}
  48386. */
  48387. }, {
  48388. key: 'getMaxLevel',
  48389. value: function getMaxLevel(nodeId) {
  48390. var _this = this;
  48391. var accumulator = {};
  48392. var _getMaxLevel = function _getMaxLevel(nodeId) {
  48393. if (accumulator[nodeId] !== undefined) {
  48394. return accumulator[nodeId];
  48395. }
  48396. var level = _this.levels[nodeId];
  48397. if (_this.childrenReference[nodeId]) {
  48398. var children = _this.childrenReference[nodeId];
  48399. if (children.length > 0) {
  48400. for (var i = 0; i < children.length; i++) {
  48401. level = Math.max(level, _getMaxLevel(children[i]));
  48402. }
  48403. }
  48404. }
  48405. accumulator[nodeId] = level;
  48406. return level;
  48407. };
  48408. return _getMaxLevel(nodeId);
  48409. }
  48410. /**
  48411. *
  48412. * @param {Node} nodeA
  48413. * @param {Node} nodeB
  48414. */
  48415. }, {
  48416. key: 'levelDownstream',
  48417. value: function levelDownstream(nodeA, nodeB) {
  48418. if (this.levels[nodeB.id] === undefined) {
  48419. // set initial level
  48420. if (this.levels[nodeA.id] === undefined) {
  48421. this.levels[nodeA.id] = 0;
  48422. }
  48423. // set level
  48424. this.levels[nodeB.id] = this.levels[nodeA.id] + 1;
  48425. }
  48426. }
  48427. /**
  48428. * Small util method to set the minimum levels of the nodes to zero.
  48429. *
  48430. * @param {Array.<Node>} nodes
  48431. */
  48432. }, {
  48433. key: 'setMinLevelToZero',
  48434. value: function setMinLevelToZero(nodes) {
  48435. var minLevel = 1e9;
  48436. // get the minimum level
  48437. for (var nodeId in nodes) {
  48438. if (nodes.hasOwnProperty(nodeId)) {
  48439. if (this.levels[nodeId] !== undefined) {
  48440. minLevel = Math.min(this.levels[nodeId], minLevel);
  48441. }
  48442. }
  48443. }
  48444. // subtract the minimum from the set so we have a range starting from 0
  48445. for (var _nodeId in nodes) {
  48446. if (nodes.hasOwnProperty(_nodeId)) {
  48447. if (this.levels[_nodeId] !== undefined) {
  48448. this.levels[_nodeId] -= minLevel;
  48449. }
  48450. }
  48451. }
  48452. }
  48453. /**
  48454. * Get the min and max xy-coordinates of a given tree
  48455. *
  48456. * @param {Array.<Node>} nodes
  48457. * @param {number} index
  48458. * @returns {{min_x: number, max_x: number, min_y: number, max_y: number}}
  48459. */
  48460. }, {
  48461. key: 'getTreeSize',
  48462. value: function getTreeSize(nodes, index) {
  48463. var min_x = 1e9;
  48464. var max_x = -1e9;
  48465. var min_y = 1e9;
  48466. var max_y = -1e9;
  48467. for (var nodeId in this.trees) {
  48468. if (this.trees.hasOwnProperty(nodeId)) {
  48469. if (this.trees[nodeId] === index) {
  48470. var node = nodes[nodeId];
  48471. min_x = Math.min(node.x, min_x);
  48472. max_x = Math.max(node.x, max_x);
  48473. min_y = Math.min(node.y, min_y);
  48474. max_y = Math.max(node.y, max_y);
  48475. }
  48476. }
  48477. }
  48478. return {
  48479. min_x: min_x,
  48480. max_x: max_x,
  48481. min_y: min_y,
  48482. max_y: max_y
  48483. };
  48484. }
  48485. /**
  48486. * Check if two nodes have the same parent(s)
  48487. *
  48488. * @param {Node} node1
  48489. * @param {Node} node2
  48490. * @return {boolean} true if the two nodes have a same ancestor node, false otherwise
  48491. */
  48492. }, {
  48493. key: 'hasSameParent',
  48494. value: function hasSameParent(node1, node2) {
  48495. var parents1 = this.parentReference[node1.id];
  48496. var parents2 = this.parentReference[node2.id];
  48497. if (parents1 === undefined || parents2 === undefined) {
  48498. return false;
  48499. }
  48500. for (var i = 0; i < parents1.length; i++) {
  48501. for (var j = 0; j < parents2.length; j++) {
  48502. if (parents1[i] == parents2[j]) {
  48503. return true;
  48504. }
  48505. }
  48506. }
  48507. return false;
  48508. }
  48509. /**
  48510. * Check if two nodes are in the same tree.
  48511. *
  48512. * @param {Node} node1
  48513. * @param {Node} node2
  48514. * @return {Boolean} true if this is so, false otherwise
  48515. */
  48516. }, {
  48517. key: 'inSameSubNetwork',
  48518. value: function inSameSubNetwork(node1, node2) {
  48519. return this.trees[node1.id] === this.trees[node2.id];
  48520. }
  48521. /**
  48522. * Get a list of the distinct levels in the current network
  48523. *
  48524. * @returns {Array}
  48525. */
  48526. }, {
  48527. key: 'getLevels',
  48528. value: function getLevels() {
  48529. return (0, _keys2['default'])(this.distributionOrdering);
  48530. }
  48531. /**
  48532. * Add a node to the ordering per level
  48533. *
  48534. * @param {Node} node
  48535. * @param {number} level
  48536. */
  48537. }, {
  48538. key: 'addToOrdering',
  48539. value: function addToOrdering(node, level) {
  48540. if (this.distributionOrdering[level] === undefined) {
  48541. this.distributionOrdering[level] = [];
  48542. }
  48543. var isPresent = false;
  48544. var curLevel = this.distributionOrdering[level];
  48545. for (var n in curLevel) {
  48546. //if (curLevel[n].id === node.id) {
  48547. if (curLevel[n] === node) {
  48548. isPresent = true;
  48549. break;
  48550. }
  48551. }
  48552. if (!isPresent) {
  48553. this.distributionOrdering[level].push(node);
  48554. this.distributionIndex[node.id] = this.distributionOrdering[level].length - 1;
  48555. }
  48556. }
  48557. }]);
  48558. return HierarchicalStatus;
  48559. }();
  48560. /**
  48561. * The Layout Engine
  48562. */
  48563. var LayoutEngine = function() {
  48564. /**
  48565. * @param {Object} body
  48566. */
  48567. function LayoutEngine(body) {
  48568. (0, _classCallCheck3['default'])(this, LayoutEngine);
  48569. this.body = body;
  48570. this.initialRandomSeed = Math.round(Math.random() * 1000000);
  48571. this.randomSeed = this.initialRandomSeed;
  48572. this.setPhysics = false;
  48573. this.options = {};
  48574. this.optionsBackup = { physics: {} };
  48575. this.defaultOptions = {
  48576. randomSeed: undefined,
  48577. improvedLayout: true,
  48578. hierarchical: {
  48579. enabled: false,
  48580. levelSeparation: 150,
  48581. nodeSpacing: 100,
  48582. treeSpacing: 200,
  48583. blockShifting: true,
  48584. edgeMinimization: true,
  48585. parentCentralization: true,
  48586. direction: 'UD', // UD, DU, LR, RL
  48587. sortMethod: 'hubsize' // hubsize, directed
  48588. }
  48589. };
  48590. util.extend(this.options, this.defaultOptions);
  48591. this.bindEventListeners();
  48592. }
  48593. /**
  48594. * Binds event listeners
  48595. */
  48596. (0, _createClass3['default'])(LayoutEngine, [{
  48597. key: 'bindEventListeners',
  48598. value: function bindEventListeners() {
  48599. var _this2 = this;
  48600. this.body.emitter.on('_dataChanged', function() {
  48601. _this2.setupHierarchicalLayout();
  48602. });
  48603. this.body.emitter.on('_dataLoaded', function() {
  48604. _this2.layoutNetwork();
  48605. });
  48606. this.body.emitter.on('_resetHierarchicalLayout', function() {
  48607. _this2.setupHierarchicalLayout();
  48608. });
  48609. this.body.emitter.on('_adjustEdgesForHierarchicalLayout', function() {
  48610. if (_this2.options.hierarchical.enabled !== true) {
  48611. return;
  48612. }
  48613. // get the type of static smooth curve in case it is required
  48614. var type = _this2.direction.curveType();
  48615. // force all edges into static smooth curves.
  48616. _this2.body.emitter.emit('_forceDisableDynamicCurves', type, false);
  48617. });
  48618. }
  48619. /**
  48620. *
  48621. * @param {Object} options
  48622. * @param {Object} allOptions
  48623. * @returns {Object}
  48624. */
  48625. }, {
  48626. key: 'setOptions',
  48627. value: function setOptions(options, allOptions) {
  48628. if (options !== undefined) {
  48629. var hierarchical = this.options.hierarchical;
  48630. var prevHierarchicalState = hierarchical.enabled;
  48631. util.selectiveDeepExtend(["randomSeed", "improvedLayout"], this.options, options);
  48632. util.mergeOptions(this.options, options, 'hierarchical');
  48633. if (options.randomSeed !== undefined) {
  48634. this.initialRandomSeed = options.randomSeed;
  48635. }
  48636. if (hierarchical.enabled === true) {
  48637. if (prevHierarchicalState === true) {
  48638. // refresh the overridden options for nodes and edges.
  48639. this.body.emitter.emit('refresh', true);
  48640. }
  48641. // make sure the level separation is the right way up
  48642. if (hierarchical.direction === 'RL' || hierarchical.direction === 'DU') {
  48643. if (hierarchical.levelSeparation > 0) {
  48644. hierarchical.levelSeparation *= -1;
  48645. }
  48646. } else {
  48647. if (hierarchical.levelSeparation < 0) {
  48648. hierarchical.levelSeparation *= -1;
  48649. }
  48650. }
  48651. this.setDirectionStrategy();
  48652. this.body.emitter.emit('_resetHierarchicalLayout');
  48653. // because the hierarchical system needs it's own physics and smooth curve settings,
  48654. // we adapt the other options if needed.
  48655. return this.adaptAllOptionsForHierarchicalLayout(allOptions);
  48656. } else {
  48657. if (prevHierarchicalState === true) {
  48658. // refresh the overridden options for nodes and edges.
  48659. this.body.emitter.emit('refresh');
  48660. return util.deepExtend(allOptions, this.optionsBackup);
  48661. }
  48662. }
  48663. }
  48664. return allOptions;
  48665. }
  48666. /**
  48667. *
  48668. * @param {Object} allOptions
  48669. * @returns {Object}
  48670. */
  48671. }, {
  48672. key: 'adaptAllOptionsForHierarchicalLayout',
  48673. value: function adaptAllOptionsForHierarchicalLayout(allOptions) {
  48674. if (this.options.hierarchical.enabled === true) {
  48675. var backupPhysics = this.optionsBackup.physics;
  48676. // set the physics
  48677. if (allOptions.physics === undefined || allOptions.physics === true) {
  48678. allOptions.physics = {
  48679. enabled: backupPhysics.enabled === undefined ? true : backupPhysics.enabled,
  48680. solver: 'hierarchicalRepulsion'
  48681. };
  48682. backupPhysics.enabled = backupPhysics.enabled === undefined ? true : backupPhysics.enabled;
  48683. backupPhysics.solver = backupPhysics.solver || 'barnesHut';
  48684. } else if ((0, _typeof3['default'])(allOptions.physics) === 'object') {
  48685. backupPhysics.enabled = allOptions.physics.enabled === undefined ? true : allOptions.physics.enabled;
  48686. backupPhysics.solver = allOptions.physics.solver || 'barnesHut';
  48687. allOptions.physics.solver = 'hierarchicalRepulsion';
  48688. } else if (allOptions.physics !== false) {
  48689. backupPhysics.solver = 'barnesHut';
  48690. allOptions.physics = { solver: 'hierarchicalRepulsion' };
  48691. }
  48692. // get the type of static smooth curve in case it is required
  48693. var type = this.direction.curveType();
  48694. // disable smooth curves if nothing is defined. If smooth curves have been turned on,
  48695. // turn them into static smooth curves.
  48696. if (allOptions.edges === undefined) {
  48697. this.optionsBackup.edges = { smooth: { enabled: true, type: 'dynamic' } };
  48698. allOptions.edges = { smooth: false };
  48699. } else if (allOptions.edges.smooth === undefined) {
  48700. this.optionsBackup.edges = { smooth: { enabled: true, type: 'dynamic' } };
  48701. allOptions.edges.smooth = false;
  48702. } else {
  48703. if (typeof allOptions.edges.smooth === 'boolean') {
  48704. this.optionsBackup.edges = { smooth: allOptions.edges.smooth };
  48705. allOptions.edges.smooth = { enabled: allOptions.edges.smooth, type: type };
  48706. } else {
  48707. var smooth = allOptions.edges.smooth;
  48708. // allow custom types except for dynamic
  48709. if (smooth.type !== undefined && smooth.type !== 'dynamic') {
  48710. type = smooth.type;
  48711. }
  48712. // TODO: this is options merging; see if the standard routines can be used here.
  48713. this.optionsBackup.edges = {
  48714. smooth: smooth.enabled === undefined ? true : smooth.enabled,
  48715. type: smooth.type === undefined ? 'dynamic' : smooth.type,
  48716. roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
  48717. forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
  48718. };
  48719. // NOTE: Copying an object to self; this is basically setting defaults for undefined variables
  48720. allOptions.edges.smooth = {
  48721. enabled: smooth.enabled === undefined ? true : smooth.enabled,
  48722. type: type,
  48723. roundness: smooth.roundness === undefined ? 0.5 : smooth.roundness,
  48724. forceDirection: smooth.forceDirection === undefined ? false : smooth.forceDirection
  48725. };
  48726. }
  48727. }
  48728. // Force all edges into static smooth curves.
  48729. // Only applies to edges that do not use the global options for smooth.
  48730. this.body.emitter.emit('_forceDisableDynamicCurves', type);
  48731. }
  48732. return allOptions;
  48733. }
  48734. /**
  48735. *
  48736. * @returns {number}
  48737. */
  48738. }, {
  48739. key: 'seededRandom',
  48740. value: function seededRandom() {
  48741. var x = Math.sin(this.randomSeed++) * 10000;
  48742. return x - Math.floor(x);
  48743. }
  48744. /**
  48745. *
  48746. * @param {Array.<Node>} nodesArray
  48747. */
  48748. }, {
  48749. key: 'positionInitially',
  48750. value: function positionInitially(nodesArray) {
  48751. if (this.options.hierarchical.enabled !== true) {
  48752. this.randomSeed = this.initialRandomSeed;
  48753. var radius = nodesArray.length + 50;
  48754. for (var i = 0; i < nodesArray.length; i++) {
  48755. var node = nodesArray[i];
  48756. var angle = 2 * Math.PI * this.seededRandom();
  48757. if (node.x === undefined) {
  48758. node.x = radius * Math.cos(angle);
  48759. }
  48760. if (node.y === undefined) {
  48761. node.y = radius * Math.sin(angle);
  48762. }
  48763. }
  48764. }
  48765. }
  48766. /**
  48767. * Use Kamada Kawai to position nodes. This is quite a heavy algorithm so if there are a lot of nodes we
  48768. * cluster them first to reduce the amount.
  48769. */
  48770. }, {
  48771. key: 'layoutNetwork',
  48772. value: function layoutNetwork() {
  48773. if (this.options.hierarchical.enabled !== true && this.options.improvedLayout === true) {
  48774. var indices = this.body.nodeIndices;
  48775. // first check if we should Kamada Kawai to layout. The threshold is if less than half of the visible
  48776. // nodes have predefined positions we use this.
  48777. var positionDefined = 0;
  48778. for (var i = 0; i < indices.length; i++) {
  48779. var node = this.body.nodes[indices[i]];
  48780. if (node.predefinedPosition === true) {
  48781. positionDefined += 1;
  48782. }
  48783. }
  48784. // if less than half of the nodes have a predefined position we continue
  48785. if (positionDefined < 0.5 * indices.length) {
  48786. var MAX_LEVELS = 10;
  48787. var level = 0;
  48788. var clusterThreshold = 150; // TODO add this to options
  48789. //
  48790. // Define the options for the hidden cluster nodes
  48791. // These options don't propagate outside the clustering phase.
  48792. //
  48793. // Some options are explicitly disabled, because they may be set in group or default node options.
  48794. // The clusters are never displayed, so most explicit settings here serve as performance optimizations.
  48795. //
  48796. // The explicit setting of 'shape' is to avoid `shape: 'image'`; images are not passed to the hidden
  48797. // cluster nodes, leading to an exception on creation.
  48798. //
  48799. // All settings here are performance related, except when noted otherwise.
  48800. //
  48801. var clusterOptions = {
  48802. clusterNodeProperties: {
  48803. shape: 'ellipse', // Bugfix: avoid type 'image', no images supplied
  48804. label: '', // avoid label handling
  48805. group: '', // avoid group handling
  48806. font: { multi: false } // avoid font propagation
  48807. },
  48808. clusterEdgeProperties: {
  48809. label: '', // avoid label handling
  48810. font: { multi: false }, // avoid font propagation
  48811. smooth: {
  48812. enabled: false // avoid drawing penalty for complex edges
  48813. }
  48814. }
  48815. };
  48816. // if there are a lot of nodes, we cluster before we run the algorithm.
  48817. // NOTE: this part fails to find clusters for large scale-free networks, which should
  48818. // be easily clusterable.
  48819. // TODO: examine why this is so
  48820. if (indices.length > clusterThreshold) {
  48821. var startLength = indices.length;
  48822. while (indices.length > clusterThreshold && level <= MAX_LEVELS) {
  48823. //console.time("clustering")
  48824. level += 1;
  48825. var before = indices.length;
  48826. // if there are many nodes we do a hubsize cluster
  48827. if (level % 3 === 0) {
  48828. this.body.modules.clustering.clusterBridges(clusterOptions);
  48829. } else {
  48830. this.body.modules.clustering.clusterOutliers(clusterOptions);
  48831. }
  48832. var after = indices.length;
  48833. if (before == after && level % 3 !== 0) {
  48834. this._declusterAll();
  48835. this.body.emitter.emit("_layoutFailed");
  48836. console.info("This network could not be positioned by this version of the improved layout algorithm." + " Please disable improvedLayout for better performance.");
  48837. return;
  48838. }
  48839. //console.timeEnd("clustering")
  48840. //console.log(before,level,after);
  48841. }
  48842. // increase the size of the edges
  48843. this.body.modules.kamadaKawai.setOptions({ springLength: Math.max(150, 2 * startLength) });
  48844. }
  48845. if (level > MAX_LEVELS) {
  48846. console.info("The clustering didn't succeed within the amount of interations allowed," + " progressing with partial result.");
  48847. }
  48848. // position the system for these nodes and edges
  48849. this.body.modules.kamadaKawai.solve(indices, this.body.edgeIndices, true);
  48850. // shift to center point
  48851. this._shiftToCenter();
  48852. // perturb the nodes a little bit to force the physics to kick in
  48853. var offset = 70;
  48854. for (var _i = 0; _i < indices.length; _i++) {
  48855. // Only perturb the nodes that aren't fixed
  48856. var _node = this.body.nodes[indices[_i]];
  48857. if (_node.predefinedPosition === false) {
  48858. _node.x += (0.5 - this.seededRandom()) * offset;
  48859. _node.y += (0.5 - this.seededRandom()) * offset;
  48860. }
  48861. }
  48862. // uncluster all clusters
  48863. this._declusterAll();
  48864. // reposition all bezier nodes.
  48865. this.body.emitter.emit("_repositionBezierNodes");
  48866. }
  48867. }
  48868. }
  48869. /**
  48870. * Move all the nodes towards to the center so gravitational pull wil not move the nodes away from view
  48871. * @private
  48872. */
  48873. }, {
  48874. key: '_shiftToCenter',
  48875. value: function _shiftToCenter() {
  48876. var range = NetworkUtil.getRangeCore(this.body.nodes, this.body.nodeIndices);
  48877. var center = NetworkUtil.findCenter(range);
  48878. for (var i = 0; i < this.body.nodeIndices.length; i++) {
  48879. var node = this.body.nodes[this.body.nodeIndices[i]];
  48880. node.x -= center.x;
  48881. node.y -= center.y;
  48882. }
  48883. }
  48884. /**
  48885. * Expands all clusters
  48886. * @private
  48887. */
  48888. }, {
  48889. key: '_declusterAll',
  48890. value: function _declusterAll() {
  48891. var clustersPresent = true;
  48892. while (clustersPresent === true) {
  48893. clustersPresent = false;
  48894. for (var i = 0; i < this.body.nodeIndices.length; i++) {
  48895. if (this.body.nodes[this.body.nodeIndices[i]].isCluster === true) {
  48896. clustersPresent = true;
  48897. this.body.modules.clustering.openCluster(this.body.nodeIndices[i], {}, false);
  48898. }
  48899. }
  48900. if (clustersPresent === true) {
  48901. this.body.emitter.emit('_dataChanged');
  48902. }
  48903. }
  48904. }
  48905. /**
  48906. *
  48907. * @returns {number|*}
  48908. */
  48909. }, {
  48910. key: 'getSeed',
  48911. value: function getSeed() {
  48912. return this.initialRandomSeed;
  48913. }
  48914. /**
  48915. * This is the main function to layout the nodes in a hierarchical way.
  48916. * It checks if the node details are supplied correctly
  48917. *
  48918. * @private
  48919. */
  48920. }, {
  48921. key: 'setupHierarchicalLayout',
  48922. value: function setupHierarchicalLayout() {
  48923. if (this.options.hierarchical.enabled === true && this.body.nodeIndices.length > 0) {
  48924. // get the size of the largest hubs and check if the user has defined a level for a node.
  48925. var node = void 0,
  48926. nodeId = void 0;
  48927. var definedLevel = false;
  48928. var undefinedLevel = false;
  48929. this.lastNodeOnLevel = {};
  48930. this.hierarchical = new HierarchicalStatus();
  48931. for (nodeId in this.body.nodes) {
  48932. if (this.body.nodes.hasOwnProperty(nodeId)) {
  48933. node = this.body.nodes[nodeId];
  48934. if (node.options.level !== undefined) {
  48935. definedLevel = true;
  48936. this.hierarchical.levels[nodeId] = node.options.level;
  48937. } else {
  48938. undefinedLevel = true;
  48939. }
  48940. }
  48941. }
  48942. // if the user defined some levels but not all, alert and run without hierarchical layout
  48943. if (undefinedLevel === true && definedLevel === true) {
  48944. throw new Error('To use the hierarchical layout, nodes require either no predefined levels' + ' or levels have to be defined for all nodes.');
  48945. } else {
  48946. // define levels if undefined by the users. Based on hubsize.
  48947. if (undefinedLevel === true) {
  48948. var sortMethod = this.options.hierarchical.sortMethod;
  48949. if (sortMethod === 'hubsize') {
  48950. this._determineLevelsByHubsize();
  48951. } else if (sortMethod === 'directed') {
  48952. this._determineLevelsDirected();
  48953. } else if (sortMethod === 'custom') {
  48954. this._determineLevelsCustomCallback();
  48955. }
  48956. }
  48957. // fallback for cases where there are nodes but no edges
  48958. for (var _nodeId2 in this.body.nodes) {
  48959. if (this.body.nodes.hasOwnProperty(_nodeId2)) {
  48960. this.hierarchical.ensureLevel(_nodeId2);
  48961. }
  48962. }
  48963. // check the distribution of the nodes per level.
  48964. var distribution = this._getDistribution();
  48965. // get the parent children relations.
  48966. this._generateMap();
  48967. // place the nodes on the canvas.
  48968. this._placeNodesByHierarchy(distribution);
  48969. // condense the whitespace.
  48970. this._condenseHierarchy();
  48971. // shift to center so gravity does not have to do much
  48972. this._shiftToCenter();
  48973. }
  48974. }
  48975. }
  48976. /**
  48977. * @private
  48978. */
  48979. }, {
  48980. key: '_condenseHierarchy',
  48981. value: function _condenseHierarchy() {
  48982. var _this3 = this;
  48983. // Global var in this scope to define when the movement has stopped.
  48984. var stillShifting = false;
  48985. var branches = {};
  48986. // first we have some methods to help shifting trees around.
  48987. // the main method to shift the trees
  48988. var shiftTrees = function shiftTrees() {
  48989. var treeSizes = getTreeSizes();
  48990. var shiftBy = 0;
  48991. for (var i = 0; i < treeSizes.length - 1; i++) {
  48992. var diff = treeSizes[i].max - treeSizes[i + 1].min;
  48993. shiftBy += diff + _this3.options.hierarchical.treeSpacing;
  48994. shiftTree(i + 1, shiftBy);
  48995. }
  48996. };
  48997. // shift a single tree by an offset
  48998. var shiftTree = function shiftTree(index, offset) {
  48999. var trees = _this3.hierarchical.trees;
  49000. for (var nodeId in trees) {
  49001. if (trees.hasOwnProperty(nodeId)) {
  49002. if (trees[nodeId] === index) {
  49003. _this3.direction.shift(nodeId, offset);
  49004. }
  49005. }
  49006. }
  49007. };
  49008. // get the width of all trees
  49009. var getTreeSizes = function getTreeSizes() {
  49010. var treeWidths = [];
  49011. for (var i = 0; i < _this3.hierarchical.numTrees(); i++) {
  49012. treeWidths.push(_this3.direction.getTreeSize(i));
  49013. }
  49014. return treeWidths;
  49015. };
  49016. // get a map of all nodes in this branch
  49017. var getBranchNodes = function getBranchNodes(source, map) {
  49018. if (map[source.id]) {
  49019. return;
  49020. }
  49021. map[source.id] = true;
  49022. if (_this3.hierarchical.childrenReference[source.id]) {
  49023. var children = _this3.hierarchical.childrenReference[source.id];
  49024. if (children.length > 0) {
  49025. for (var i = 0; i < children.length; i++) {
  49026. getBranchNodes(_this3.body.nodes[children[i]], map);
  49027. }
  49028. }
  49029. }
  49030. };
  49031. // get a min max width as well as the maximum movement space it has on either sides
  49032. // we use min max terminology because width and height can interchange depending on the direction of the layout
  49033. var getBranchBoundary = function getBranchBoundary(branchMap) {
  49034. var maxLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1e9;
  49035. var minSpace = 1e9;
  49036. var maxSpace = 1e9;
  49037. var min = 1e9;
  49038. var max = -1e9;
  49039. for (var branchNode in branchMap) {
  49040. if (branchMap.hasOwnProperty(branchNode)) {
  49041. var node = _this3.body.nodes[branchNode];
  49042. var level = _this3.hierarchical.levels[node.id];
  49043. var position = _this3.direction.getPosition(node);
  49044. // get the space around the node.
  49045. var _getSpaceAroundNode2 = _this3._getSpaceAroundNode(node, branchMap),
  49046. _getSpaceAroundNode3 = (0, _slicedToArray3['default'])(_getSpaceAroundNode2, 2),
  49047. minSpaceNode = _getSpaceAroundNode3[0],
  49048. maxSpaceNode = _getSpaceAroundNode3[1];
  49049. minSpace = Math.min(minSpaceNode, minSpace);
  49050. maxSpace = Math.min(maxSpaceNode, maxSpace);
  49051. // the width is only relevant for the levels two nodes have in common. This is why we filter on this.
  49052. if (level <= maxLevel) {
  49053. min = Math.min(position, min);
  49054. max = Math.max(position, max);
  49055. }
  49056. }
  49057. }
  49058. return [min, max, minSpace, maxSpace];
  49059. };
  49060. // check what the maximum level is these nodes have in common.
  49061. var getCollisionLevel = function getCollisionLevel(node1, node2) {
  49062. var maxLevel1 = _this3.hierarchical.getMaxLevel(node1.id);
  49063. var maxLevel2 = _this3.hierarchical.getMaxLevel(node2.id);
  49064. return Math.min(maxLevel1, maxLevel2);
  49065. };
  49066. /**
  49067. * Condense elements. These can be nodes or branches depending on the callback.
  49068. *
  49069. * @param {function} callback
  49070. * @param {Array.<number>} levels
  49071. * @param {*} centerParents
  49072. */
  49073. var shiftElementsCloser = function shiftElementsCloser(callback, levels, centerParents) {
  49074. var hier = _this3.hierarchical;
  49075. for (var i = 0; i < levels.length; i++) {
  49076. var level = levels[i];
  49077. var levelNodes = hier.distributionOrdering[level];
  49078. if (levelNodes.length > 1) {
  49079. for (var j = 0; j < levelNodes.length - 1; j++) {
  49080. var node1 = levelNodes[j];
  49081. var node2 = levelNodes[j + 1];
  49082. // NOTE: logic maintained as it was; if nodes have same ancestor,
  49083. // then of course they are in the same sub-network.
  49084. if (hier.hasSameParent(node1, node2) && hier.inSameSubNetwork(node1, node2)) {
  49085. callback(node1, node2, centerParents);
  49086. }
  49087. }
  49088. }
  49089. }
  49090. };
  49091. // callback for shifting branches
  49092. var branchShiftCallback = function branchShiftCallback(node1, node2) {
  49093. var centerParent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  49094. //window.CALLBACKS.push(() => {
  49095. var pos1 = _this3.direction.getPosition(node1);
  49096. var pos2 = _this3.direction.getPosition(node2);
  49097. var diffAbs = Math.abs(pos2 - pos1);
  49098. var nodeSpacing = _this3.options.hierarchical.nodeSpacing;
  49099. //console.log("NOW CHECKING:", node1.id, node2.id, diffAbs);
  49100. if (diffAbs > nodeSpacing) {
  49101. var branchNodes1 = {};
  49102. var branchNodes2 = {};
  49103. getBranchNodes(node1, branchNodes1);
  49104. getBranchNodes(node2, branchNodes2);
  49105. // check the largest distance between the branches
  49106. var maxLevel = getCollisionLevel(node1, node2);
  49107. var branchNodeBoundary1 = getBranchBoundary(branchNodes1, maxLevel);
  49108. var branchNodeBoundary2 = getBranchBoundary(branchNodes2, maxLevel);
  49109. var max1 = branchNodeBoundary1[1];
  49110. var min2 = branchNodeBoundary2[0];
  49111. var minSpace2 = branchNodeBoundary2[2];
  49112. //console.log(node1.id, getBranchBoundary(branchNodes1, maxLevel), node2.id,
  49113. // getBranchBoundary(branchNodes2, maxLevel), maxLevel);
  49114. var diffBranch = Math.abs(max1 - min2);
  49115. if (diffBranch > nodeSpacing) {
  49116. var offset = max1 - min2 + nodeSpacing;
  49117. if (offset < -minSpace2 + nodeSpacing) {
  49118. offset = -minSpace2 + nodeSpacing;
  49119. //console.log("RESETTING OFFSET", max1 - min2 + this.options.hierarchical.nodeSpacing, -minSpace2, offset);
  49120. }
  49121. if (offset < 0) {
  49122. //console.log("SHIFTING", node2.id, offset);
  49123. _this3._shiftBlock(node2.id, offset);
  49124. stillShifting = true;
  49125. if (centerParent === true) _this3._centerParent(node2);
  49126. }
  49127. }
  49128. }
  49129. //this.body.emitter.emit("_redraw");})
  49130. };
  49131. var minimizeEdgeLength = function minimizeEdgeLength(iterations, node) {
  49132. //window.CALLBACKS.push(() => {
  49133. // console.log("ts",node.id);
  49134. var nodeId = node.id;
  49135. var allEdges = node.edges;
  49136. var nodeLevel = _this3.hierarchical.levels[node.id];
  49137. // gather constants
  49138. var C2 = _this3.options.hierarchical.levelSeparation * _this3.options.hierarchical.levelSeparation;
  49139. var referenceNodes = {};
  49140. var aboveEdges = [];
  49141. for (var i = 0; i < allEdges.length; i++) {
  49142. var edge = allEdges[i];
  49143. if (edge.toId != edge.fromId) {
  49144. var otherNode = edge.toId == nodeId ? edge.from : edge.to;
  49145. referenceNodes[allEdges[i].id] = otherNode;
  49146. if (_this3.hierarchical.levels[otherNode.id] < nodeLevel) {
  49147. aboveEdges.push(edge);
  49148. }
  49149. }
  49150. }
  49151. // differentiated sum of lengths based on only moving one node over one axis
  49152. var getFx = function getFx(point, edges) {
  49153. var sum = 0;
  49154. for (var _i2 = 0; _i2 < edges.length; _i2++) {
  49155. if (referenceNodes[edges[_i2].id] !== undefined) {
  49156. var a = _this3.direction.getPosition(referenceNodes[edges[_i2].id]) - point;
  49157. sum += a / Math.sqrt(a * a + C2);
  49158. }
  49159. }
  49160. return sum;
  49161. };
  49162. // doubly differentiated sum of lengths based on only moving one node over one axis
  49163. var getDFx = function getDFx(point, edges) {
  49164. var sum = 0;
  49165. for (var _i3 = 0; _i3 < edges.length; _i3++) {
  49166. if (referenceNodes[edges[_i3].id] !== undefined) {
  49167. var a = _this3.direction.getPosition(referenceNodes[edges[_i3].id]) - point;
  49168. sum -= C2 * Math.pow(a * a + C2, -1.5);
  49169. }
  49170. }
  49171. return sum;
  49172. };
  49173. var getGuess = function getGuess(iterations, edges) {
  49174. var guess = _this3.direction.getPosition(node);
  49175. // Newton's method for optimization
  49176. var guessMap = {};
  49177. for (var _i4 = 0; _i4 < iterations; _i4++) {
  49178. var fx = getFx(guess, edges);
  49179. var dfx = getDFx(guess, edges);
  49180. // we limit the movement to avoid instability.
  49181. var limit = 40;
  49182. var ratio = Math.max(-limit, Math.min(limit, Math.round(fx / dfx)));
  49183. guess = guess - ratio;
  49184. // reduce duplicates
  49185. if (guessMap[guess] !== undefined) {
  49186. break;
  49187. }
  49188. guessMap[guess] = _i4;
  49189. }
  49190. return guess;
  49191. };
  49192. var moveBranch = function moveBranch(guess) {
  49193. // position node if there is space
  49194. var nodePosition = _this3.direction.getPosition(node);
  49195. // check movable area of the branch
  49196. if (branches[node.id] === undefined) {
  49197. var branchNodes = {};
  49198. getBranchNodes(node, branchNodes);
  49199. branches[node.id] = branchNodes;
  49200. }
  49201. var branchBoundary = getBranchBoundary(branches[node.id]);
  49202. var minSpaceBranch = branchBoundary[2];
  49203. var maxSpaceBranch = branchBoundary[3];
  49204. var diff = guess - nodePosition;
  49205. // check if we are allowed to move the node:
  49206. var branchOffset = 0;
  49207. if (diff > 0) {
  49208. branchOffset = Math.min(diff, maxSpaceBranch - _this3.options.hierarchical.nodeSpacing);
  49209. } else if (diff < 0) {
  49210. branchOffset = -Math.min(-diff, minSpaceBranch - _this3.options.hierarchical.nodeSpacing);
  49211. }
  49212. if (branchOffset != 0) {
  49213. //console.log("moving branch:",branchOffset, maxSpaceBranch, minSpaceBranch)
  49214. _this3._shiftBlock(node.id, branchOffset);
  49215. //this.body.emitter.emit("_redraw");
  49216. stillShifting = true;
  49217. }
  49218. };
  49219. var moveNode = function moveNode(guess) {
  49220. var nodePosition = _this3.direction.getPosition(node);
  49221. // position node if there is space
  49222. var _getSpaceAroundNode4 = _this3._getSpaceAroundNode(node),
  49223. _getSpaceAroundNode5 = (0, _slicedToArray3['default'])(_getSpaceAroundNode4, 2),
  49224. minSpace = _getSpaceAroundNode5[0],
  49225. maxSpace = _getSpaceAroundNode5[1];
  49226. var diff = guess - nodePosition;
  49227. // check if we are allowed to move the node:
  49228. var newPosition = nodePosition;
  49229. if (diff > 0) {
  49230. newPosition = Math.min(nodePosition + (maxSpace - _this3.options.hierarchical.nodeSpacing), guess);
  49231. } else if (diff < 0) {
  49232. newPosition = Math.max(nodePosition - (minSpace - _this3.options.hierarchical.nodeSpacing), guess);
  49233. }
  49234. if (newPosition !== nodePosition) {
  49235. //console.log("moving Node:",diff, minSpace, maxSpace);
  49236. _this3.direction.setPosition(node, newPosition);
  49237. //this.body.emitter.emit("_redraw");
  49238. stillShifting = true;
  49239. }
  49240. };
  49241. var guess = getGuess(iterations, aboveEdges);
  49242. moveBranch(guess);
  49243. guess = getGuess(iterations, allEdges);
  49244. moveNode(guess);
  49245. //})
  49246. };
  49247. // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
  49248. var minimizeEdgeLengthBottomUp = function minimizeEdgeLengthBottomUp(iterations) {
  49249. var levels = _this3.hierarchical.getLevels();
  49250. levels = levels.reverse();
  49251. for (var i = 0; i < iterations; i++) {
  49252. stillShifting = false;
  49253. for (var j = 0; j < levels.length; j++) {
  49254. var level = levels[j];
  49255. var levelNodes = _this3.hierarchical.distributionOrdering[level];
  49256. for (var k = 0; k < levelNodes.length; k++) {
  49257. minimizeEdgeLength(1000, levelNodes[k]);
  49258. }
  49259. }
  49260. if (stillShifting !== true) {
  49261. //console.log("FINISHED minimizeEdgeLengthBottomUp IN " + i);
  49262. break;
  49263. }
  49264. }
  49265. };
  49266. // method to remove whitespace between branches. Because we do bottom up, we can center the parents.
  49267. var shiftBranchesCloserBottomUp = function shiftBranchesCloserBottomUp(iterations) {
  49268. var levels = _this3.hierarchical.getLevels();
  49269. levels = levels.reverse();
  49270. for (var i = 0; i < iterations; i++) {
  49271. stillShifting = false;
  49272. shiftElementsCloser(branchShiftCallback, levels, true);
  49273. if (stillShifting !== true) {
  49274. //console.log("FINISHED shiftBranchesCloserBottomUp IN " + (i+1));
  49275. break;
  49276. }
  49277. }
  49278. };
  49279. // center all parents
  49280. var centerAllParents = function centerAllParents() {
  49281. for (var nodeId in _this3.body.nodes) {
  49282. if (_this3.body.nodes.hasOwnProperty(nodeId)) _this3._centerParent(_this3.body.nodes[nodeId]);
  49283. }
  49284. };
  49285. // center all parents
  49286. var centerAllParentsBottomUp = function centerAllParentsBottomUp() {
  49287. var levels = _this3.hierarchical.getLevels();
  49288. levels = levels.reverse();
  49289. for (var i = 0; i < levels.length; i++) {
  49290. var level = levels[i];
  49291. var levelNodes = _this3.hierarchical.distributionOrdering[level];
  49292. for (var j = 0; j < levelNodes.length; j++) {
  49293. _this3._centerParent(levelNodes[j]);
  49294. }
  49295. }
  49296. };
  49297. // the actual work is done here.
  49298. if (this.options.hierarchical.blockShifting === true) {
  49299. shiftBranchesCloserBottomUp(5);
  49300. centerAllParents();
  49301. }
  49302. // minimize edge length
  49303. if (this.options.hierarchical.edgeMinimization === true) {
  49304. minimizeEdgeLengthBottomUp(20);
  49305. }
  49306. if (this.options.hierarchical.parentCentralization === true) {
  49307. centerAllParentsBottomUp();
  49308. }
  49309. shiftTrees();
  49310. }
  49311. /**
  49312. * This gives the space around the node. IF a map is supplied, it will only check against nodes NOT in the map.
  49313. * This is used to only get the distances to nodes outside of a branch.
  49314. * @param {Node} node
  49315. * @param {{Node.id: vis.Node}} map
  49316. * @returns {number[]}
  49317. * @private
  49318. */
  49319. }, {
  49320. key: '_getSpaceAroundNode',
  49321. value: function _getSpaceAroundNode(node, map) {
  49322. var useMap = true;
  49323. if (map === undefined) {
  49324. useMap = false;
  49325. }
  49326. var level = this.hierarchical.levels[node.id];
  49327. if (level !== undefined) {
  49328. var index = this.hierarchical.distributionIndex[node.id];
  49329. var position = this.direction.getPosition(node);
  49330. var ordering = this.hierarchical.distributionOrdering[level];
  49331. var minSpace = 1e9;
  49332. var maxSpace = 1e9;
  49333. if (index !== 0) {
  49334. var prevNode = ordering[index - 1];
  49335. if (useMap === true && map[prevNode.id] === undefined || useMap === false) {
  49336. var prevPos = this.direction.getPosition(prevNode);
  49337. minSpace = position - prevPos;
  49338. }
  49339. }
  49340. if (index != ordering.length - 1) {
  49341. var nextNode = ordering[index + 1];
  49342. if (useMap === true && map[nextNode.id] === undefined || useMap === false) {
  49343. var nextPos = this.direction.getPosition(nextNode);
  49344. maxSpace = Math.min(maxSpace, nextPos - position);
  49345. }
  49346. }
  49347. return [minSpace, maxSpace];
  49348. } else {
  49349. return [0, 0];
  49350. }
  49351. }
  49352. /**
  49353. * We use this method to center a parent node and check if it does not cross other nodes when it does.
  49354. * @param {Node} node
  49355. * @private
  49356. */
  49357. }, {
  49358. key: '_centerParent',
  49359. value: function _centerParent(node) {
  49360. if (this.hierarchical.parentReference[node.id]) {
  49361. var parents = this.hierarchical.parentReference[node.id];
  49362. for (var i = 0; i < parents.length; i++) {
  49363. var parentId = parents[i];
  49364. var parentNode = this.body.nodes[parentId];
  49365. var children = this.hierarchical.childrenReference[parentId];
  49366. if (children !== undefined) {
  49367. // get the range of the children
  49368. var newPosition = this._getCenterPosition(children);
  49369. var position = this.direction.getPosition(parentNode);
  49370. var _getSpaceAroundNode6 = this._getSpaceAroundNode(parentNode),
  49371. _getSpaceAroundNode7 = (0, _slicedToArray3['default'])(_getSpaceAroundNode6, 2),
  49372. minSpace = _getSpaceAroundNode7[0],
  49373. maxSpace = _getSpaceAroundNode7[1];
  49374. var diff = position - newPosition;
  49375. if (diff < 0 && Math.abs(diff) < maxSpace - this.options.hierarchical.nodeSpacing || diff > 0 && Math.abs(diff) < minSpace - this.options.hierarchical.nodeSpacing) {
  49376. this.direction.setPosition(parentNode, newPosition);
  49377. }
  49378. }
  49379. }
  49380. }
  49381. }
  49382. /**
  49383. * This function places the nodes on the canvas based on the hierarchial distribution.
  49384. *
  49385. * @param {Object} distribution | obtained by the function this._getDistribution()
  49386. * @private
  49387. */
  49388. }, {
  49389. key: '_placeNodesByHierarchy',
  49390. value: function _placeNodesByHierarchy(distribution) {
  49391. this.positionedNodes = {};
  49392. // start placing all the level 0 nodes first. Then recursively position their branches.
  49393. for (var level in distribution) {
  49394. if (distribution.hasOwnProperty(level)) {
  49395. // sort nodes in level by position:
  49396. var nodeArray = (0, _keys2['default'])(distribution[level]);
  49397. nodeArray = this._indexArrayToNodes(nodeArray);
  49398. this.direction.sort(nodeArray);
  49399. var handledNodeCount = 0;
  49400. for (var i = 0; i < nodeArray.length; i++) {
  49401. var node = nodeArray[i];
  49402. if (this.positionedNodes[node.id] === undefined) {
  49403. var spacing = this.options.hierarchical.nodeSpacing;
  49404. var pos = spacing * handledNodeCount;
  49405. // We get the X or Y values we need and store them in pos and previousPos.
  49406. // The get and set make sure we get X or Y
  49407. if (handledNodeCount > 0) {
  49408. pos = this.direction.getPosition(nodeArray[i - 1]) + spacing;
  49409. }
  49410. this.direction.setPosition(node, pos, level);
  49411. this._validatePositionAndContinue(node, level, pos);
  49412. handledNodeCount++;
  49413. }
  49414. }
  49415. }
  49416. }
  49417. }
  49418. /**
  49419. * This is a recursively called function to enumerate the branches from the largest hubs and place the nodes
  49420. * on a X position that ensures there will be no overlap.
  49421. *
  49422. * @param {Node.id} parentId
  49423. * @param {number} parentLevel
  49424. * @private
  49425. */
  49426. }, {
  49427. key: '_placeBranchNodes',
  49428. value: function _placeBranchNodes(parentId, parentLevel) {
  49429. var childRef = this.hierarchical.childrenReference[parentId];
  49430. // if this is not a parent, cancel the placing. This can happen with multiple parents to one child.
  49431. if (childRef === undefined) {
  49432. return;
  49433. }
  49434. // get a list of childNodes
  49435. var childNodes = [];
  49436. for (var i = 0; i < childRef.length; i++) {
  49437. childNodes.push(this.body.nodes[childRef[i]]);
  49438. }
  49439. // use the positions to order the nodes.
  49440. this.direction.sort(childNodes);
  49441. // position the childNodes
  49442. for (var _i5 = 0; _i5 < childNodes.length; _i5++) {
  49443. var childNode = childNodes[_i5];
  49444. var childNodeLevel = this.hierarchical.levels[childNode.id];
  49445. // check if the child node is below the parent node and if it has already been positioned.
  49446. if (childNodeLevel > parentLevel && this.positionedNodes[childNode.id] === undefined) {
  49447. // get the amount of space required for this node. If parent the width is based on the amount of children.
  49448. var spacing = this.options.hierarchical.nodeSpacing;
  49449. var pos = void 0;
  49450. // we get the X or Y values we need and store them in pos and previousPos.
  49451. // The get and set make sure we get X or Y
  49452. if (_i5 === 0) {
  49453. pos = this.direction.getPosition(this.body.nodes[parentId]);
  49454. } else {
  49455. pos = this.direction.getPosition(childNodes[_i5 - 1]) + spacing;
  49456. }
  49457. this.direction.setPosition(childNode, pos, childNodeLevel);
  49458. this._validatePositionAndContinue(childNode, childNodeLevel, pos);
  49459. } else {
  49460. return;
  49461. }
  49462. }
  49463. // center the parent nodes.
  49464. var center = this._getCenterPosition(childNodes);
  49465. this.direction.setPosition(this.body.nodes[parentId], center, parentLevel);
  49466. }
  49467. /**
  49468. * This method checks for overlap and if required shifts the branch. It also keeps records of positioned nodes.
  49469. * Finally it will call _placeBranchNodes to place the branch nodes.
  49470. * @param {Node} node
  49471. * @param {number} level
  49472. * @param {number} pos
  49473. * @private
  49474. */
  49475. }, {
  49476. key: '_validatePositionAndContinue',
  49477. value: function _validatePositionAndContinue(node, level, pos) {
  49478. // This method only works for formal trees and formal forests
  49479. // Early exit if this is not the case
  49480. if (!this.hierarchical.isTree) return;
  49481. // if overlap has been detected, we shift the branch
  49482. if (this.lastNodeOnLevel[level] !== undefined) {
  49483. var previousPos = this.direction.getPosition(this.body.nodes[this.lastNodeOnLevel[level]]);
  49484. if (pos - previousPos < this.options.hierarchical.nodeSpacing) {
  49485. var diff = previousPos + this.options.hierarchical.nodeSpacing - pos;
  49486. var sharedParent = this._findCommonParent(this.lastNodeOnLevel[level], node.id);
  49487. this._shiftBlock(sharedParent.withChild, diff);
  49488. }
  49489. }
  49490. this.lastNodeOnLevel[level] = node.id; // store change in position.
  49491. this.positionedNodes[node.id] = true;
  49492. this._placeBranchNodes(node.id, level);
  49493. }
  49494. /**
  49495. * Receives an array with node indices and returns an array with the actual node references.
  49496. * Used for sorting based on node properties.
  49497. * @param {Array.<Node.id>} idArray
  49498. * @returns {Array.<Node>}
  49499. */
  49500. }, {
  49501. key: '_indexArrayToNodes',
  49502. value: function _indexArrayToNodes(idArray) {
  49503. var array = [];
  49504. for (var i = 0; i < idArray.length; i++) {
  49505. array.push(this.body.nodes[idArray[i]]);
  49506. }
  49507. return array;
  49508. }
  49509. /**
  49510. * This function get the distribution of levels based on hubsize
  49511. *
  49512. * @returns {Object}
  49513. * @private
  49514. */
  49515. }, {
  49516. key: '_getDistribution',
  49517. value: function _getDistribution() {
  49518. var distribution = {};
  49519. var nodeId = void 0,
  49520. node = void 0;
  49521. // we fix Y because the hierarchy is vertical,
  49522. // we fix X so we do not give a node an x position for a second time.
  49523. // the fix of X is removed after the x value has been set.
  49524. for (nodeId in this.body.nodes) {
  49525. if (this.body.nodes.hasOwnProperty(nodeId)) {
  49526. node = this.body.nodes[nodeId];
  49527. var level = this.hierarchical.levels[nodeId] === undefined ? 0 : this.hierarchical.levels[nodeId];
  49528. this.direction.fix(node, level);
  49529. if (distribution[level] === undefined) {
  49530. distribution[level] = {};
  49531. }
  49532. distribution[level][nodeId] = node;
  49533. }
  49534. }
  49535. return distribution;
  49536. }
  49537. /**
  49538. * Return the active (i.e. visible) edges for this node
  49539. *
  49540. * @param {Node} node
  49541. * @returns {Array.<vis.Edge>} Array of edge instances
  49542. * @private
  49543. */
  49544. }, {
  49545. key: '_getActiveEdges',
  49546. value: function _getActiveEdges(node) {
  49547. var _this4 = this;
  49548. var result = [];
  49549. util.forEach(node.edges, function(edge) {
  49550. if (_this4.body.edgeIndices.indexOf(edge.id) !== -1) {
  49551. result.push(edge);
  49552. }
  49553. });
  49554. return result;
  49555. }
  49556. /**
  49557. * Get the hubsizes for all active nodes.
  49558. *
  49559. * @returns {number}
  49560. * @private
  49561. */
  49562. }, {
  49563. key: '_getHubSizes',
  49564. value: function _getHubSizes() {
  49565. var _this5 = this;
  49566. var hubSizes = {};
  49567. var nodeIds = this.body.nodeIndices;
  49568. util.forEach(nodeIds, function(nodeId) {
  49569. var node = _this5.body.nodes[nodeId];
  49570. var hubSize = _this5._getActiveEdges(node).length;
  49571. hubSizes[hubSize] = true;
  49572. });
  49573. // Make an array of the size sorted descending
  49574. var result = [];
  49575. util.forEach(hubSizes, function(size) {
  49576. result.push(Number(size));
  49577. });
  49578. result.sort(function(a, b) {
  49579. return b - a;
  49580. });
  49581. return result;
  49582. }
  49583. /**
  49584. * this function allocates nodes in levels based on the recursive branching from the largest hubs.
  49585. *
  49586. * @private
  49587. */
  49588. }, {
  49589. key: '_determineLevelsByHubsize',
  49590. value: function _determineLevelsByHubsize() {
  49591. var _this6 = this;
  49592. var levelDownstream = function levelDownstream(nodeA, nodeB) {
  49593. _this6.hierarchical.levelDownstream(nodeA, nodeB);
  49594. };
  49595. var hubSizes = this._getHubSizes();
  49596. var _loop = function _loop(i) {
  49597. var hubSize = hubSizes[i];
  49598. if (hubSize === 0) return 'break';
  49599. util.forEach(_this6.body.nodeIndices, function(nodeId) {
  49600. var node = _this6.body.nodes[nodeId];
  49601. if (hubSize === _this6._getActiveEdges(node).length) {
  49602. _this6._crawlNetwork(levelDownstream, nodeId);
  49603. }
  49604. });
  49605. };
  49606. for (var i = 0; i < hubSizes.length; ++i) {
  49607. var _ret = _loop(i);
  49608. if (_ret === 'break') break;
  49609. }
  49610. }
  49611. /**
  49612. * TODO: release feature
  49613. * TODO: Determine if this feature is needed at all
  49614. *
  49615. * @private
  49616. */
  49617. }, {
  49618. key: '_determineLevelsCustomCallback',
  49619. value: function _determineLevelsCustomCallback() {
  49620. var _this7 = this;
  49621. var minLevel = 100000;
  49622. // TODO: this should come from options.
  49623. var customCallback = function customCallback(nodeA, nodeB, edge) { // eslint-disable-line no-unused-vars
  49624. };
  49625. // TODO: perhaps move to HierarchicalStatus.
  49626. // But I currently don't see the point, this method is not used.
  49627. var levelByDirection = function levelByDirection(nodeA, nodeB, edge) {
  49628. var levelA = _this7.hierarchical.levels[nodeA.id];
  49629. // set initial level
  49630. if (levelA === undefined) {
  49631. levelA = _this7.hierarchical.levels[nodeA.id] = minLevel;
  49632. }
  49633. var diff = customCallback(NetworkUtil.cloneOptions(nodeA, 'node'), NetworkUtil.cloneOptions(nodeB, 'node'), NetworkUtil.cloneOptions(edge, 'edge'));
  49634. _this7.hierarchical.levels[nodeB.id] = levelA + diff;
  49635. };
  49636. this._crawlNetwork(levelByDirection);
  49637. this.hierarchical.setMinLevelToZero(this.body.nodes);
  49638. }
  49639. /**
  49640. * Allocate nodes in levels based on the direction of the edges.
  49641. *
  49642. * @private
  49643. */
  49644. }, {
  49645. key: '_determineLevelsDirected',
  49646. value: function _determineLevelsDirected() {
  49647. var _this8 = this;
  49648. var minLevel = 10000;
  49649. /**
  49650. * Check if there is an edge going the opposite direction for given edge
  49651. *
  49652. * @param {Edge} edge edge to check
  49653. * @returns {boolean} true if there's another edge going into the opposite direction
  49654. */
  49655. var isBidirectional = function isBidirectional(edge) {
  49656. util.forEach(_this8.body.edges, function(otherEdge) {
  49657. if (otherEdge.toId === edge.fromId && otherEdge.fromId === edge.toId) {
  49658. return true;
  49659. }
  49660. });
  49661. return false;
  49662. };
  49663. var levelByDirection = function levelByDirection(nodeA, nodeB, edge) {
  49664. var levelA = _this8.hierarchical.levels[nodeA.id];
  49665. var levelB = _this8.hierarchical.levels[nodeB.id];
  49666. if (isBidirectional(edge) && levelA !== undefined && levelB !== undefined) {
  49667. // Don't redo the level determination if already done in this case.
  49668. return;
  49669. }
  49670. // set initial level
  49671. if (levelA === undefined) {
  49672. levelA = _this8.hierarchical.levels[nodeA.id] = minLevel;
  49673. }
  49674. if (edge.toId == nodeB.id) {
  49675. _this8.hierarchical.levels[nodeB.id] = levelA + 1;
  49676. } else {
  49677. _this8.hierarchical.levels[nodeB.id] = levelA - 1;
  49678. }
  49679. };
  49680. this._crawlNetwork(levelByDirection);
  49681. this.hierarchical.setMinLevelToZero(this.body.nodes);
  49682. }
  49683. /**
  49684. * Update the bookkeeping of parent and child.
  49685. * @private
  49686. */
  49687. }, {
  49688. key: '_generateMap',
  49689. value: function _generateMap() {
  49690. var _this9 = this;
  49691. var fillInRelations = function fillInRelations(parentNode, childNode) {
  49692. if (_this9.hierarchical.levels[childNode.id] > _this9.hierarchical.levels[parentNode.id]) {
  49693. _this9.hierarchical.addRelation(parentNode.id, childNode.id);
  49694. }
  49695. };
  49696. this._crawlNetwork(fillInRelations);
  49697. this.hierarchical.checkIfTree();
  49698. }
  49699. /**
  49700. * Crawl over the entire network and use a callback on each node couple that is connected to each other.
  49701. * @param {function} [callback=function(){}] | will receive nodeA, nodeB and the connecting edge. A and B are distinct.
  49702. * @param {Node.id} startingNodeId
  49703. * @private
  49704. */
  49705. }, {
  49706. key: '_crawlNetwork',
  49707. value: function _crawlNetwork() {
  49708. var _this10 = this;
  49709. var callback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function() {};
  49710. var startingNodeId = arguments[1];
  49711. var progress = {};
  49712. var crawler = function crawler(node, tree) {
  49713. if (progress[node.id] === undefined) {
  49714. _this10.hierarchical.setTreeIndex(node, tree);
  49715. progress[node.id] = true;
  49716. var childNode = void 0;
  49717. var edges = _this10._getActiveEdges(node);
  49718. for (var i = 0; i < edges.length; i++) {
  49719. var edge = edges[i];
  49720. if (edge.connected === true) {
  49721. if (edge.toId == node.id) {
  49722. // Not '===' because id's can be string and numeric
  49723. childNode = edge.from;
  49724. } else {
  49725. childNode = edge.to;
  49726. }
  49727. if (node.id != childNode.id) {
  49728. // Not '!==' because id's can be string and numeric
  49729. callback(node, childNode, edge);
  49730. crawler(childNode, tree);
  49731. }
  49732. }
  49733. }
  49734. }
  49735. };
  49736. if (startingNodeId === undefined) {
  49737. // Crawl over all nodes
  49738. var treeIndex = 0; // Serves to pass a unique id for the current distinct tree
  49739. for (var i = 0; i < this.body.nodeIndices.length; i++) {
  49740. var nodeId = this.body.nodeIndices[i];
  49741. if (progress[nodeId] === undefined) {
  49742. var node = this.body.nodes[nodeId];
  49743. crawler(node, treeIndex);
  49744. treeIndex += 1;
  49745. }
  49746. }
  49747. } else {
  49748. // Crawl from the given starting node
  49749. var _node2 = this.body.nodes[startingNodeId];
  49750. if (_node2 === undefined) {
  49751. console.error("Node not found:", startingNodeId);
  49752. return;
  49753. }
  49754. crawler(_node2);
  49755. }
  49756. }
  49757. /**
  49758. * Shift a branch a certain distance
  49759. * @param {Node.id} parentId
  49760. * @param {number} diff
  49761. * @private
  49762. */
  49763. }, {
  49764. key: '_shiftBlock',
  49765. value: function _shiftBlock(parentId, diff) {
  49766. var _this11 = this;
  49767. var progress = {};
  49768. var shifter = function shifter(parentId) {
  49769. if (progress[parentId]) {
  49770. return;
  49771. }
  49772. progress[parentId] = true;
  49773. _this11.direction.shift(parentId, diff);
  49774. var childRef = _this11.hierarchical.childrenReference[parentId];
  49775. if (childRef !== undefined) {
  49776. for (var i = 0; i < childRef.length; i++) {
  49777. shifter(childRef[i]);
  49778. }
  49779. }
  49780. };
  49781. shifter(parentId);
  49782. }
  49783. /**
  49784. * Find a common parent between branches.
  49785. * @param {Node.id} childA
  49786. * @param {Node.id} childB
  49787. * @returns {{foundParent, withChild}}
  49788. * @private
  49789. */
  49790. }, {
  49791. key: '_findCommonParent',
  49792. value: function _findCommonParent(childA, childB) {
  49793. var _this12 = this;
  49794. var parents = {};
  49795. var iterateParents = function iterateParents(parents, child) {
  49796. var parentRef = _this12.hierarchical.parentReference[child];
  49797. if (parentRef !== undefined) {
  49798. for (var i = 0; i < parentRef.length; i++) {
  49799. var parent = parentRef[i];
  49800. parents[parent] = true;
  49801. iterateParents(parents, parent);
  49802. }
  49803. }
  49804. };
  49805. var findParent = function findParent(parents, child) {
  49806. var parentRef = _this12.hierarchical.parentReference[child];
  49807. if (parentRef !== undefined) {
  49808. for (var i = 0; i < parentRef.length; i++) {
  49809. var parent = parentRef[i];
  49810. if (parents[parent] !== undefined) {
  49811. return { foundParent: parent, withChild: child };
  49812. }
  49813. var branch = findParent(parents, parent);
  49814. if (branch.foundParent !== null) {
  49815. return branch;
  49816. }
  49817. }
  49818. }
  49819. return { foundParent: null, withChild: child };
  49820. };
  49821. iterateParents(parents, childA);
  49822. return findParent(parents, childB);
  49823. }
  49824. /**
  49825. * Set the strategy pattern for handling the coordinates given the current direction.
  49826. *
  49827. * The individual instances contain all the operations and data specific to a layout direction.
  49828. *
  49829. * @param {Node} node
  49830. * @param {{x: number, y: number}} position
  49831. * @param {number} level
  49832. * @param {boolean} [doNotUpdate=false]
  49833. * @private
  49834. */
  49835. }, {
  49836. key: 'setDirectionStrategy',
  49837. value: function setDirectionStrategy() {
  49838. var isVertical = this.options.hierarchical.direction === 'UD' || this.options.hierarchical.direction === 'DU';
  49839. if (isVertical) {
  49840. this.direction = new VerticalStrategy(this);
  49841. } else {
  49842. this.direction = new HorizontalStrategy(this);
  49843. }
  49844. }
  49845. /**
  49846. * Determine the center position of a branch from the passed list of child nodes
  49847. *
  49848. * This takes into account the positions of all the child nodes.
  49849. * @param {Array.<Node|vis.Node.id>} childNodes Array of either child nodes or node id's
  49850. * @return {number}
  49851. * @private
  49852. */
  49853. }, {
  49854. key: '_getCenterPosition',
  49855. value: function _getCenterPosition(childNodes) {
  49856. var minPos = 1e9;
  49857. var maxPos = -1e9;
  49858. for (var i = 0; i < childNodes.length; i++) {
  49859. var childNode = void 0;
  49860. if (childNodes[i].id !== undefined) {
  49861. childNode = childNodes[i];
  49862. } else {
  49863. var childNodeId = childNodes[i];
  49864. childNode = this.body.nodes[childNodeId];
  49865. }
  49866. var position = this.direction.getPosition(childNode);
  49867. minPos = Math.min(minPos, position);
  49868. maxPos = Math.max(maxPos, position);
  49869. }
  49870. return 0.5 * (minPos + maxPos);
  49871. }
  49872. }]);
  49873. return LayoutEngine;
  49874. }();
  49875. exports['default'] = LayoutEngine;
  49876. /***/
  49877. }),
  49878. /* 236 */
  49879. /***/
  49880. (function(module, exports, __webpack_require__) {
  49881. "use strict";
  49882. Object.defineProperty(exports, "__esModule", {
  49883. value: true
  49884. });
  49885. exports.VerticalStrategy = exports.HorizontalStrategy = undefined;
  49886. var _getPrototypeOf = __webpack_require__(3);
  49887. var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
  49888. var _possibleConstructorReturn2 = __webpack_require__(4);
  49889. var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
  49890. var _inherits2 = __webpack_require__(5);
  49891. var _inherits3 = _interopRequireDefault(_inherits2);
  49892. var _classCallCheck2 = __webpack_require__(0);
  49893. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  49894. var _createClass2 = __webpack_require__(1);
  49895. var _createClass3 = _interopRequireDefault(_createClass2);
  49896. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  49897. /**
  49898. * Helper classes for LayoutEngine.
  49899. *
  49900. * Strategy pattern for usage of direction methods for hierarchical layouts.
  49901. */
  49902. /**
  49903. * Interface definition for direction strategy classes.
  49904. *
  49905. * This class describes the interface for the Strategy
  49906. * pattern classes used to differentiate horizontal and vertical
  49907. * direction of hierarchical results.
  49908. *
  49909. * For a given direction, one coordinate will be 'fixed', meaning that it is
  49910. * determined by level.
  49911. * The other coordinate is 'unfixed', meaning that the nodes on a given level
  49912. * can still move along that coordinate. So:
  49913. *
  49914. * - `vertical` layout: `x` unfixed, `y` fixed per level
  49915. * - `horizontal` layout: `x` fixed per level, `y` unfixed
  49916. *
  49917. * The local methods are stubs and should be regarded as abstract.
  49918. * Derived classes **must** implement all the methods themselves.
  49919. *
  49920. * @private
  49921. */
  49922. var DirectionInterface = function() {
  49923. function DirectionInterface() {
  49924. (0, _classCallCheck3['default'])(this, DirectionInterface);
  49925. }
  49926. (0, _createClass3['default'])(DirectionInterface, [{
  49927. key: 'abstract',
  49928. /** @ignore **/
  49929. value: function abstract() {
  49930. throw new Error("Can't instantiate abstract class!");
  49931. }
  49932. /**
  49933. * This is a dummy call which is used to suppress the jsdoc errors of type:
  49934. *
  49935. * "'param' is assigned a value but never used"
  49936. *
  49937. * @ignore
  49938. **/
  49939. }, {
  49940. key: 'fake_use',
  49941. value: function fake_use() {}
  49942. // Do nothing special
  49943. /**
  49944. * Type to use to translate dynamic curves to, in the case of hierarchical layout.
  49945. * Dynamic curves do not work for these.
  49946. *
  49947. * The value should be perpendicular to the actual direction of the layout.
  49948. *
  49949. * @return {string} Direction, either 'vertical' or 'horizontal'
  49950. */
  49951. }, {
  49952. key: 'curveType',
  49953. value: function curveType() {
  49954. return this.abstract();
  49955. }
  49956. /**
  49957. * Return the value of the coordinate that is not fixed for this direction.
  49958. *
  49959. * @param {Node} node The node to read
  49960. * @return {number} Value of the unfixed coordinate
  49961. */
  49962. }, {
  49963. key: 'getPosition',
  49964. value: function getPosition(node) {
  49965. this.fake_use(node);
  49966. return this.abstract();
  49967. }
  49968. /**
  49969. * Set the value of the coordinate that is not fixed for this direction.
  49970. *
  49971. * @param {Node} node The node to adjust
  49972. * @param {number} position
  49973. * @param {number} [level] if specified, the hierarchy level that this node should be fixed to
  49974. */
  49975. }, {
  49976. key: 'setPosition',
  49977. value: function setPosition(node, position) {
  49978. var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
  49979. this.fake_use(node, position, level);
  49980. this.abstract();
  49981. }
  49982. /**
  49983. * Get the width of a tree.
  49984. *
  49985. * A `tree` here is a subset of nodes within the network which are not connected to other nodes,
  49986. * only among themselves. In essence, it is a sub-network.
  49987. *
  49988. * @param {number} index The index number of a tree
  49989. * @return {number} the width of a tree in the view coordinates
  49990. */
  49991. }, {
  49992. key: 'getTreeSize',
  49993. value: function getTreeSize(index) {
  49994. this.fake_use(index);
  49995. return this.abstract();
  49996. }
  49997. /**
  49998. * Sort array of nodes on the unfixed coordinates.
  49999. *
  50000. * @param {Array.<Node>} nodeArray array of nodes to sort
  50001. */
  50002. }, {
  50003. key: 'sort',
  50004. value: function sort(nodeArray) {
  50005. this.fake_use(nodeArray);
  50006. this.abstract();
  50007. }
  50008. /**
  50009. * Assign the fixed coordinate of the node to the given level
  50010. *
  50011. * @param {Node} node The node to adjust
  50012. * @param {number} level The level to fix to
  50013. */
  50014. }, {
  50015. key: 'fix',
  50016. value: function fix(node, level) {
  50017. this.fake_use(node, level);
  50018. this.abstract();
  50019. }
  50020. /**
  50021. * Add an offset to the unfixed coordinate of the given node.
  50022. *
  50023. * @param {NodeId} nodeId Id of the node to adjust
  50024. * @param {number} diff Offset to add to the unfixed coordinate
  50025. */
  50026. }, {
  50027. key: 'shift',
  50028. value: function shift(nodeId, diff) {
  50029. this.fake_use(nodeId, diff);
  50030. this.abstract();
  50031. }
  50032. }]);
  50033. return DirectionInterface;
  50034. }();
  50035. /**
  50036. * Vertical Strategy
  50037. *
  50038. * Coordinate `y` is fixed on levels, coordinate `x` is unfixed.
  50039. *
  50040. * @extends DirectionInterface
  50041. * @private
  50042. */
  50043. var VerticalStrategy = function(_DirectionInterface) {
  50044. (0, _inherits3['default'])(VerticalStrategy, _DirectionInterface);
  50045. /**
  50046. * Constructor
  50047. *
  50048. * @param {Object} layout reference to the parent LayoutEngine instance.
  50049. */
  50050. function VerticalStrategy(layout) {
  50051. (0, _classCallCheck3['default'])(this, VerticalStrategy);
  50052. var _this = (0, _possibleConstructorReturn3['default'])(this, (VerticalStrategy.__proto__ || (0, _getPrototypeOf2['default'])(VerticalStrategy)).call(this));
  50053. _this.layout = layout;
  50054. return _this;
  50055. }
  50056. /** @inheritdoc */
  50057. (0, _createClass3['default'])(VerticalStrategy, [{
  50058. key: 'curveType',
  50059. value: function curveType() {
  50060. return 'horizontal';
  50061. }
  50062. /** @inheritdoc */
  50063. }, {
  50064. key: 'getPosition',
  50065. value: function getPosition(node) {
  50066. return node.x;
  50067. }
  50068. /** @inheritdoc */
  50069. }, {
  50070. key: 'setPosition',
  50071. value: function setPosition(node, position) {
  50072. var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
  50073. if (level !== undefined) {
  50074. this.layout.hierarchical.addToOrdering(node, level);
  50075. }
  50076. node.x = position;
  50077. }
  50078. /** @inheritdoc */
  50079. }, {
  50080. key: 'getTreeSize',
  50081. value: function getTreeSize(index) {
  50082. var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
  50083. return { min: res.min_x, max: res.max_x };
  50084. }
  50085. /** @inheritdoc */
  50086. }, {
  50087. key: 'sort',
  50088. value: function sort(nodeArray) {
  50089. nodeArray.sort(function(a, b) {
  50090. // Test on 'undefined' takes care of divergent behaviour in chrome
  50091. if (a.x === undefined || b.x === undefined) return 0; // THIS HAPPENS
  50092. return a.x - b.x;
  50093. });
  50094. }
  50095. /** @inheritdoc */
  50096. }, {
  50097. key: 'fix',
  50098. value: function fix(node, level) {
  50099. node.y = this.layout.options.hierarchical.levelSeparation * level;
  50100. node.options.fixed.y = true;
  50101. }
  50102. /** @inheritdoc */
  50103. }, {
  50104. key: 'shift',
  50105. value: function shift(nodeId, diff) {
  50106. this.layout.body.nodes[nodeId].x += diff;
  50107. }
  50108. }]);
  50109. return VerticalStrategy;
  50110. }(DirectionInterface);
  50111. /**
  50112. * Horizontal Strategy
  50113. *
  50114. * Coordinate `x` is fixed on levels, coordinate `y` is unfixed.
  50115. *
  50116. * @extends DirectionInterface
  50117. * @private
  50118. */
  50119. var HorizontalStrategy = function(_DirectionInterface2) {
  50120. (0, _inherits3['default'])(HorizontalStrategy, _DirectionInterface2);
  50121. /**
  50122. * Constructor
  50123. *
  50124. * @param {Object} layout reference to the parent LayoutEngine instance.
  50125. */
  50126. function HorizontalStrategy(layout) {
  50127. (0, _classCallCheck3['default'])(this, HorizontalStrategy);
  50128. var _this2 = (0, _possibleConstructorReturn3['default'])(this, (HorizontalStrategy.__proto__ || (0, _getPrototypeOf2['default'])(HorizontalStrategy)).call(this));
  50129. _this2.layout = layout;
  50130. return _this2;
  50131. }
  50132. /** @inheritdoc */
  50133. (0, _createClass3['default'])(HorizontalStrategy, [{
  50134. key: 'curveType',
  50135. value: function curveType() {
  50136. return 'vertical';
  50137. }
  50138. /** @inheritdoc */
  50139. }, {
  50140. key: 'getPosition',
  50141. value: function getPosition(node) {
  50142. return node.y;
  50143. }
  50144. /** @inheritdoc */
  50145. }, {
  50146. key: 'setPosition',
  50147. value: function setPosition(node, position) {
  50148. var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
  50149. if (level !== undefined) {
  50150. this.layout.hierarchical.addToOrdering(node, level);
  50151. }
  50152. node.y = position;
  50153. }
  50154. /** @inheritdoc */
  50155. }, {
  50156. key: 'getTreeSize',
  50157. value: function getTreeSize(index) {
  50158. var res = this.layout.hierarchical.getTreeSize(this.layout.body.nodes, index);
  50159. return { min: res.min_y, max: res.max_y };
  50160. }
  50161. /** @inheritdoc */
  50162. }, {
  50163. key: 'sort',
  50164. value: function sort(nodeArray) {
  50165. nodeArray.sort(function(a, b) {
  50166. // Test on 'undefined' takes care of divergent behaviour in chrome
  50167. if (a.y === undefined || b.y === undefined) return 0; // THIS HAPPENS
  50168. return a.y - b.y;
  50169. });
  50170. }
  50171. /** @inheritdoc */
  50172. }, {
  50173. key: 'fix',
  50174. value: function fix(node, level) {
  50175. node.x = this.layout.options.hierarchical.levelSeparation * level;
  50176. node.options.fixed.x = true;
  50177. }
  50178. /** @inheritdoc */
  50179. }, {
  50180. key: 'shift',
  50181. value: function shift(nodeId, diff) {
  50182. this.layout.body.nodes[nodeId].y += diff;
  50183. }
  50184. }]);
  50185. return HorizontalStrategy;
  50186. }(DirectionInterface);
  50187. exports.HorizontalStrategy = HorizontalStrategy;
  50188. exports.VerticalStrategy = VerticalStrategy;
  50189. /***/
  50190. }),
  50191. /* 237 */
  50192. /***/
  50193. (function(module, exports, __webpack_require__) {
  50194. "use strict";
  50195. Object.defineProperty(exports, "__esModule", {
  50196. value: true
  50197. });
  50198. var _keys = __webpack_require__(8);
  50199. var _keys2 = _interopRequireDefault(_keys);
  50200. var _stringify = __webpack_require__(19);
  50201. var _stringify2 = _interopRequireDefault(_stringify);
  50202. var _typeof2 = __webpack_require__(6);
  50203. var _typeof3 = _interopRequireDefault(_typeof2);
  50204. var _classCallCheck2 = __webpack_require__(0);
  50205. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  50206. var _createClass2 = __webpack_require__(1);
  50207. var _createClass3 = _interopRequireDefault(_createClass2);
  50208. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  50209. var util = __webpack_require__(2);
  50210. var Hammer = __webpack_require__(10);
  50211. var hammerUtil = __webpack_require__(37);
  50212. /**
  50213. * Clears the toolbar div element of children
  50214. *
  50215. * @private
  50216. */
  50217. var ManipulationSystem = function() {
  50218. /**
  50219. * @param {Object} body
  50220. * @param {Canvas} canvas
  50221. * @param {SelectionHandler} selectionHandler
  50222. */
  50223. function ManipulationSystem(body, canvas, selectionHandler) {
  50224. var _this = this;
  50225. (0, _classCallCheck3['default'])(this, ManipulationSystem);
  50226. this.body = body;
  50227. this.canvas = canvas;
  50228. this.selectionHandler = selectionHandler;
  50229. this.editMode = false;
  50230. this.manipulationDiv = undefined;
  50231. this.editModeDiv = undefined;
  50232. this.closeDiv = undefined;
  50233. this.manipulationHammers = [];
  50234. this.temporaryUIFunctions = {};
  50235. this.temporaryEventFunctions = [];
  50236. this.touchTime = 0;
  50237. this.temporaryIds = { nodes: [], edges: [] };
  50238. this.guiEnabled = false;
  50239. this.inMode = false;
  50240. this.selectedControlNode = undefined;
  50241. this.options = {};
  50242. this.defaultOptions = {
  50243. enabled: false,
  50244. initiallyActive: false,
  50245. addNode: true,
  50246. addEdge: true,
  50247. editNode: undefined,
  50248. editEdge: true,
  50249. deleteNode: true,
  50250. deleteEdge: true,
  50251. controlNodeStyle: {
  50252. shape: 'dot',
  50253. size: 6,
  50254. color: { background: '#ff0000', border: '#3c3c3c', highlight: { background: '#07f968', border: '#3c3c3c' } },
  50255. borderWidth: 2,
  50256. borderWidthSelected: 2
  50257. }
  50258. };
  50259. util.extend(this.options, this.defaultOptions);
  50260. this.body.emitter.on('destroy', function() {
  50261. _this._clean();
  50262. });
  50263. this.body.emitter.on('_dataChanged', this._restore.bind(this));
  50264. this.body.emitter.on('_resetData', this._restore.bind(this));
  50265. }
  50266. /**
  50267. * If something changes in the data during editing, switch back to the initial datamanipulation state and close all edit modes.
  50268. * @private
  50269. */
  50270. (0, _createClass3['default'])(ManipulationSystem, [{
  50271. key: '_restore',
  50272. value: function _restore() {
  50273. if (this.inMode !== false) {
  50274. if (this.options.initiallyActive === true) {
  50275. this.enableEditMode();
  50276. } else {
  50277. this.disableEditMode();
  50278. }
  50279. }
  50280. }
  50281. /**
  50282. * Set the Options
  50283. *
  50284. * @param {Object} options
  50285. * @param {Object} allOptions
  50286. * @param {Object} globalOptions
  50287. */
  50288. }, {
  50289. key: 'setOptions',
  50290. value: function setOptions(options, allOptions, globalOptions) {
  50291. if (allOptions !== undefined) {
  50292. if (allOptions.locale !== undefined) {
  50293. this.options.locale = allOptions.locale;
  50294. } else {
  50295. this.options.locale = globalOptions.locale;
  50296. }
  50297. if (allOptions.locales !== undefined) {
  50298. this.options.locales = allOptions.locales;
  50299. } else {
  50300. this.options.locales = globalOptions.locales;
  50301. }
  50302. }
  50303. if (options !== undefined) {
  50304. if (typeof options === 'boolean') {
  50305. this.options.enabled = options;
  50306. } else {
  50307. this.options.enabled = true;
  50308. util.deepExtend(this.options, options);
  50309. }
  50310. if (this.options.initiallyActive === true) {
  50311. this.editMode = true;
  50312. }
  50313. this._setup();
  50314. }
  50315. }
  50316. /**
  50317. * Enable or disable edit-mode. Draws the DOM required and cleans up after itself.
  50318. *
  50319. * @private
  50320. */
  50321. }, {
  50322. key: 'toggleEditMode',
  50323. value: function toggleEditMode() {
  50324. if (this.editMode === true) {
  50325. this.disableEditMode();
  50326. } else {
  50327. this.enableEditMode();
  50328. }
  50329. }
  50330. /**
  50331. * Enables Edit Mode
  50332. */
  50333. }, {
  50334. key: 'enableEditMode',
  50335. value: function enableEditMode() {
  50336. this.editMode = true;
  50337. this._clean();
  50338. if (this.guiEnabled === true) {
  50339. this.manipulationDiv.style.display = 'block';
  50340. this.closeDiv.style.display = 'block';
  50341. this.editModeDiv.style.display = 'none';
  50342. this.showManipulatorToolbar();
  50343. }
  50344. }
  50345. /**
  50346. * Disables Edit Mode
  50347. */
  50348. }, {
  50349. key: 'disableEditMode',
  50350. value: function disableEditMode() {
  50351. this.editMode = false;
  50352. this._clean();
  50353. if (this.guiEnabled === true) {
  50354. this.manipulationDiv.style.display = 'none';
  50355. this.closeDiv.style.display = 'none';
  50356. this.editModeDiv.style.display = 'block';
  50357. this._createEditButton();
  50358. }
  50359. }
  50360. /**
  50361. * Creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar.
  50362. *
  50363. * @private
  50364. */
  50365. }, {
  50366. key: 'showManipulatorToolbar',
  50367. value: function showManipulatorToolbar() {
  50368. // restore the state of any bound functions or events, remove control nodes, restore physics
  50369. this._clean();
  50370. // reset global variables
  50371. this.manipulationDOM = {};
  50372. // if the gui is enabled, draw all elements.
  50373. if (this.guiEnabled === true) {
  50374. // a _restore will hide these menus
  50375. this.editMode = true;
  50376. this.manipulationDiv.style.display = 'block';
  50377. this.closeDiv.style.display = 'block';
  50378. var selectedNodeCount = this.selectionHandler._getSelectedNodeCount();
  50379. var selectedEdgeCount = this.selectionHandler._getSelectedEdgeCount();
  50380. var selectedTotalCount = selectedNodeCount + selectedEdgeCount;
  50381. var locale = this.options.locales[this.options.locale];
  50382. var needSeperator = false;
  50383. if (this.options.addNode !== false) {
  50384. this._createAddNodeButton(locale);
  50385. needSeperator = true;
  50386. }
  50387. if (this.options.addEdge !== false) {
  50388. if (needSeperator === true) {
  50389. this._createSeperator(1);
  50390. } else {
  50391. needSeperator = true;
  50392. }
  50393. this._createAddEdgeButton(locale);
  50394. }
  50395. if (selectedNodeCount === 1 && typeof this.options.editNode === 'function') {
  50396. if (needSeperator === true) {
  50397. this._createSeperator(2);
  50398. } else {
  50399. needSeperator = true;
  50400. }
  50401. this._createEditNodeButton(locale);
  50402. } else if (selectedEdgeCount === 1 && selectedNodeCount === 0 && this.options.editEdge !== false) {
  50403. if (needSeperator === true) {
  50404. this._createSeperator(3);
  50405. } else {
  50406. needSeperator = true;
  50407. }
  50408. this._createEditEdgeButton(locale);
  50409. }
  50410. // remove buttons
  50411. if (selectedTotalCount !== 0) {
  50412. if (selectedNodeCount > 0 && this.options.deleteNode !== false) {
  50413. if (needSeperator === true) {
  50414. this._createSeperator(4);
  50415. }
  50416. this._createDeleteButton(locale);
  50417. } else if (selectedNodeCount === 0 && this.options.deleteEdge !== false) {
  50418. if (needSeperator === true) {
  50419. this._createSeperator(4);
  50420. }
  50421. this._createDeleteButton(locale);
  50422. }
  50423. }
  50424. // bind the close button
  50425. this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this));
  50426. // refresh this bar based on what has been selected
  50427. this._temporaryBindEvent('select', this.showManipulatorToolbar.bind(this));
  50428. }
  50429. // redraw to show any possible changes
  50430. this.body.emitter.emit('_redraw');
  50431. }
  50432. /**
  50433. * Create the toolbar for adding Nodes
  50434. */
  50435. }, {
  50436. key: 'addNodeMode',
  50437. value: function addNodeMode() {
  50438. // when using the gui, enable edit mode if it wasnt already.
  50439. if (this.editMode !== true) {
  50440. this.enableEditMode();
  50441. }
  50442. // restore the state of any bound functions or events, remove control nodes, restore physics
  50443. this._clean();
  50444. this.inMode = 'addNode';
  50445. if (this.guiEnabled === true) {
  50446. var locale = this.options.locales[this.options.locale];
  50447. this.manipulationDOM = {};
  50448. this._createBackButton(locale);
  50449. this._createSeperator();
  50450. this._createDescription(locale['addDescription'] || this.options.locales['en']['addDescription']);
  50451. // bind the close button
  50452. this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this));
  50453. }
  50454. this._temporaryBindEvent('click', this._performAddNode.bind(this));
  50455. }
  50456. /**
  50457. * call the bound function to handle the editing of the node. The node has to be selected.
  50458. */
  50459. }, {
  50460. key: 'editNode',
  50461. value: function editNode() {
  50462. var _this2 = this;
  50463. // when using the gui, enable edit mode if it wasnt already.
  50464. if (this.editMode !== true) {
  50465. this.enableEditMode();
  50466. }
  50467. // restore the state of any bound functions or events, remove control nodes, restore physics
  50468. this._clean();
  50469. var node = this.selectionHandler._getSelectedNode();
  50470. if (node !== undefined) {
  50471. this.inMode = 'editNode';
  50472. if (typeof this.options.editNode === 'function') {
  50473. if (node.isCluster !== true) {
  50474. var data = util.deepExtend({}, node.options, false);
  50475. data.x = node.x;
  50476. data.y = node.y;
  50477. if (this.options.editNode.length === 2) {
  50478. this.options.editNode(data, function(finalizedData) {
  50479. if (finalizedData !== null && finalizedData !== undefined && _this2.inMode === 'editNode') {
  50480. // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
  50481. _this2.body.data.nodes.getDataSet().update(finalizedData);
  50482. }
  50483. _this2.showManipulatorToolbar();
  50484. });
  50485. } else {
  50486. throw new Error('The function for edit does not support two arguments (data, callback)');
  50487. }
  50488. } else {
  50489. alert(this.options.locales[this.options.locale]['editClusterError'] || this.options.locales['en']['editClusterError']);
  50490. }
  50491. } else {
  50492. throw new Error('No function has been configured to handle the editing of nodes.');
  50493. }
  50494. } else {
  50495. this.showManipulatorToolbar();
  50496. }
  50497. }
  50498. /**
  50499. * create the toolbar to connect nodes
  50500. */
  50501. }, {
  50502. key: 'addEdgeMode',
  50503. value: function addEdgeMode() {
  50504. // when using the gui, enable edit mode if it wasnt already.
  50505. if (this.editMode !== true) {
  50506. this.enableEditMode();
  50507. }
  50508. // restore the state of any bound functions or events, remove control nodes, restore physics
  50509. this._clean();
  50510. this.inMode = 'addEdge';
  50511. if (this.guiEnabled === true) {
  50512. var locale = this.options.locales[this.options.locale];
  50513. this.manipulationDOM = {};
  50514. this._createBackButton(locale);
  50515. this._createSeperator();
  50516. this._createDescription(locale['edgeDescription'] || this.options.locales['en']['edgeDescription']);
  50517. // bind the close button
  50518. this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this));
  50519. }
  50520. // temporarily overload functions
  50521. this._temporaryBindUI('onTouch', this._handleConnect.bind(this));
  50522. this._temporaryBindUI('onDragEnd', this._finishConnect.bind(this));
  50523. this._temporaryBindUI('onDrag', this._dragControlNode.bind(this));
  50524. this._temporaryBindUI('onRelease', this._finishConnect.bind(this));
  50525. this._temporaryBindUI('onDragStart', this._dragStartEdge.bind(this));
  50526. this._temporaryBindUI('onHold', function() {});
  50527. }
  50528. /**
  50529. * create the toolbar to edit edges
  50530. */
  50531. }, {
  50532. key: 'editEdgeMode',
  50533. value: function editEdgeMode() {
  50534. // when using the gui, enable edit mode if it wasn't already.
  50535. if (this.editMode !== true) {
  50536. this.enableEditMode();
  50537. }
  50538. // restore the state of any bound functions or events, remove control nodes, restore physics
  50539. this._clean();
  50540. this.inMode = 'editEdge';
  50541. if ((0, _typeof3['default'])(this.options.editEdge) === 'object' && typeof this.options.editEdge.editWithoutDrag === "function") {
  50542. this.edgeBeingEditedId = this.selectionHandler.getSelectedEdges()[0];
  50543. if (this.edgeBeingEditedId !== undefined) {
  50544. var edge = this.body.edges[this.edgeBeingEditedId];
  50545. this._performEditEdge(edge.from, edge.to);
  50546. return;
  50547. }
  50548. }
  50549. if (this.guiEnabled === true) {
  50550. var locale = this.options.locales[this.options.locale];
  50551. this.manipulationDOM = {};
  50552. this._createBackButton(locale);
  50553. this._createSeperator();
  50554. this._createDescription(locale['editEdgeDescription'] || this.options.locales['en']['editEdgeDescription']);
  50555. // bind the close button
  50556. this._bindHammerToDiv(this.closeDiv, this.toggleEditMode.bind(this));
  50557. }
  50558. this.edgeBeingEditedId = this.selectionHandler.getSelectedEdges()[0];
  50559. if (this.edgeBeingEditedId !== undefined) {
  50560. var _edge = this.body.edges[this.edgeBeingEditedId];
  50561. // create control nodes
  50562. var controlNodeFrom = this._getNewTargetNode(_edge.from.x, _edge.from.y);
  50563. var controlNodeTo = this._getNewTargetNode(_edge.to.x, _edge.to.y);
  50564. this.temporaryIds.nodes.push(controlNodeFrom.id);
  50565. this.temporaryIds.nodes.push(controlNodeTo.id);
  50566. this.body.nodes[controlNodeFrom.id] = controlNodeFrom;
  50567. this.body.nodeIndices.push(controlNodeFrom.id);
  50568. this.body.nodes[controlNodeTo.id] = controlNodeTo;
  50569. this.body.nodeIndices.push(controlNodeTo.id);
  50570. // temporarily overload UI functions, cleaned up automatically because of _temporaryBindUI
  50571. this._temporaryBindUI('onTouch', this._controlNodeTouch.bind(this)); // used to get the position
  50572. this._temporaryBindUI('onTap', function() {}); // disabled
  50573. this._temporaryBindUI('onHold', function() {}); // disabled
  50574. this._temporaryBindUI('onDragStart', this._controlNodeDragStart.bind(this)); // used to select control node
  50575. this._temporaryBindUI('onDrag', this._controlNodeDrag.bind(this)); // used to drag control node
  50576. this._temporaryBindUI('onDragEnd', this._controlNodeDragEnd.bind(this)); // used to connect or revert control nodes
  50577. this._temporaryBindUI('onMouseMove', function() {}); // disabled
  50578. // create function to position control nodes correctly on movement
  50579. // automatically cleaned up because we use the temporary bind
  50580. this._temporaryBindEvent('beforeDrawing', function(ctx) {
  50581. var positions = _edge.edgeType.findBorderPositions(ctx);
  50582. if (controlNodeFrom.selected === false) {
  50583. controlNodeFrom.x = positions.from.x;
  50584. controlNodeFrom.y = positions.from.y;
  50585. }
  50586. if (controlNodeTo.selected === false) {
  50587. controlNodeTo.x = positions.to.x;
  50588. controlNodeTo.y = positions.to.y;
  50589. }
  50590. });
  50591. this.body.emitter.emit('_redraw');
  50592. } else {
  50593. this.showManipulatorToolbar();
  50594. }
  50595. }
  50596. /**
  50597. * delete everything in the selection
  50598. */
  50599. }, {
  50600. key: 'deleteSelected',
  50601. value: function deleteSelected() {
  50602. var _this3 = this;
  50603. // when using the gui, enable edit mode if it wasnt already.
  50604. if (this.editMode !== true) {
  50605. this.enableEditMode();
  50606. }
  50607. // restore the state of any bound functions or events, remove control nodes, restore physics
  50608. this._clean();
  50609. this.inMode = 'delete';
  50610. var selectedNodes = this.selectionHandler.getSelectedNodes();
  50611. var selectedEdges = this.selectionHandler.getSelectedEdges();
  50612. var deleteFunction = undefined;
  50613. if (selectedNodes.length > 0) {
  50614. for (var i = 0; i < selectedNodes.length; i++) {
  50615. if (this.body.nodes[selectedNodes[i]].isCluster === true) {
  50616. alert(this.options.locales[this.options.locale]['deleteClusterError'] || this.options.locales['en']['deleteClusterError']);
  50617. return;
  50618. }
  50619. }
  50620. if (typeof this.options.deleteNode === 'function') {
  50621. deleteFunction = this.options.deleteNode;
  50622. }
  50623. } else if (selectedEdges.length > 0) {
  50624. if (typeof this.options.deleteEdge === 'function') {
  50625. deleteFunction = this.options.deleteEdge;
  50626. }
  50627. }
  50628. if (typeof deleteFunction === 'function') {
  50629. var data = { nodes: selectedNodes, edges: selectedEdges };
  50630. if (deleteFunction.length === 2) {
  50631. deleteFunction(data, function(finalizedData) {
  50632. if (finalizedData !== null && finalizedData !== undefined && _this3.inMode === 'delete') {
  50633. // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
  50634. _this3.body.data.edges.getDataSet().remove(finalizedData.edges);
  50635. _this3.body.data.nodes.getDataSet().remove(finalizedData.nodes);
  50636. _this3.body.emitter.emit('startSimulation');
  50637. _this3.showManipulatorToolbar();
  50638. } else {
  50639. _this3.body.emitter.emit('startSimulation');
  50640. _this3.showManipulatorToolbar();
  50641. }
  50642. });
  50643. } else {
  50644. throw new Error('The function for delete does not support two arguments (data, callback)');
  50645. }
  50646. } else {
  50647. this.body.data.edges.getDataSet().remove(selectedEdges);
  50648. this.body.data.nodes.getDataSet().remove(selectedNodes);
  50649. this.body.emitter.emit('startSimulation');
  50650. this.showManipulatorToolbar();
  50651. }
  50652. }
  50653. //********************************************** PRIVATE ***************************************//
  50654. /**
  50655. * draw or remove the DOM
  50656. * @private
  50657. */
  50658. }, {
  50659. key: '_setup',
  50660. value: function _setup() {
  50661. if (this.options.enabled === true) {
  50662. // Enable the GUI
  50663. this.guiEnabled = true;
  50664. this._createWrappers();
  50665. if (this.editMode === false) {
  50666. this._createEditButton();
  50667. } else {
  50668. this.showManipulatorToolbar();
  50669. }
  50670. } else {
  50671. this._removeManipulationDOM();
  50672. // disable the gui
  50673. this.guiEnabled = false;
  50674. }
  50675. }
  50676. /**
  50677. * create the div overlays that contain the DOM
  50678. * @private
  50679. */
  50680. }, {
  50681. key: '_createWrappers',
  50682. value: function _createWrappers() {
  50683. // load the manipulator HTML elements. All styling done in css.
  50684. if (this.manipulationDiv === undefined) {
  50685. this.manipulationDiv = document.createElement('div');
  50686. this.manipulationDiv.className = 'vis-manipulation';
  50687. if (this.editMode === true) {
  50688. this.manipulationDiv.style.display = 'block';
  50689. } else {
  50690. this.manipulationDiv.style.display = 'none';
  50691. }
  50692. this.canvas.frame.appendChild(this.manipulationDiv);
  50693. }
  50694. // container for the edit button.
  50695. if (this.editModeDiv === undefined) {
  50696. this.editModeDiv = document.createElement('div');
  50697. this.editModeDiv.className = 'vis-edit-mode';
  50698. if (this.editMode === true) {
  50699. this.editModeDiv.style.display = 'none';
  50700. } else {
  50701. this.editModeDiv.style.display = 'block';
  50702. }
  50703. this.canvas.frame.appendChild(this.editModeDiv);
  50704. }
  50705. // container for the close div button
  50706. if (this.closeDiv === undefined) {
  50707. this.closeDiv = document.createElement('div');
  50708. this.closeDiv.className = 'vis-close';
  50709. this.closeDiv.style.display = this.manipulationDiv.style.display;
  50710. this.canvas.frame.appendChild(this.closeDiv);
  50711. }
  50712. }
  50713. /**
  50714. * generate a new target node. Used for creating new edges and editing edges
  50715. *
  50716. * @param {number} x
  50717. * @param {number} y
  50718. * @returns {Node}
  50719. * @private
  50720. */
  50721. }, {
  50722. key: '_getNewTargetNode',
  50723. value: function _getNewTargetNode(x, y) {
  50724. var controlNodeStyle = util.deepExtend({}, this.options.controlNodeStyle);
  50725. controlNodeStyle.id = 'targetNode' + util.randomUUID();
  50726. controlNodeStyle.hidden = false;
  50727. controlNodeStyle.physics = false;
  50728. controlNodeStyle.x = x;
  50729. controlNodeStyle.y = y;
  50730. // we have to define the bounding box in order for the nodes to be drawn immediately
  50731. var node = this.body.functions.createNode(controlNodeStyle);
  50732. node.shape.boundingBox = { left: x, right: x, top: y, bottom: y };
  50733. return node;
  50734. }
  50735. /**
  50736. * Create the edit button
  50737. */
  50738. }, {
  50739. key: '_createEditButton',
  50740. value: function _createEditButton() {
  50741. // restore everything to it's original state (if applicable)
  50742. this._clean();
  50743. // reset the manipulationDOM
  50744. this.manipulationDOM = {};
  50745. // empty the editModeDiv
  50746. util.recursiveDOMDelete(this.editModeDiv);
  50747. // create the contents for the editMode button
  50748. var locale = this.options.locales[this.options.locale];
  50749. var button = this._createButton('editMode', 'vis-button vis-edit vis-edit-mode', locale['edit'] || this.options.locales['en']['edit']);
  50750. this.editModeDiv.appendChild(button);
  50751. // bind a hammer listener to the button, calling the function toggleEditMode.
  50752. this._bindHammerToDiv(button, this.toggleEditMode.bind(this));
  50753. }
  50754. /**
  50755. * this function cleans up after everything this module does. Temporary elements, functions and events are removed, physics restored, hammers removed.
  50756. * @private
  50757. */
  50758. }, {
  50759. key: '_clean',
  50760. value: function _clean() {
  50761. // not in mode
  50762. this.inMode = false;
  50763. // _clean the divs
  50764. if (this.guiEnabled === true) {
  50765. util.recursiveDOMDelete(this.editModeDiv);
  50766. util.recursiveDOMDelete(this.manipulationDiv);
  50767. // removes all the bindings and overloads
  50768. this._cleanManipulatorHammers();
  50769. }
  50770. // remove temporary nodes and edges
  50771. this._cleanupTemporaryNodesAndEdges();
  50772. // restore overloaded UI functions
  50773. this._unbindTemporaryUIs();
  50774. // remove the temporaryEventFunctions
  50775. this._unbindTemporaryEvents();
  50776. // restore the physics if required
  50777. this.body.emitter.emit('restorePhysics');
  50778. }
  50779. /**
  50780. * Each dom element has it's own hammer. They are stored in this.manipulationHammers. This cleans them up.
  50781. * @private
  50782. */
  50783. }, {
  50784. key: '_cleanManipulatorHammers',
  50785. value: function _cleanManipulatorHammers() {
  50786. // _clean hammer bindings
  50787. if (this.manipulationHammers.length != 0) {
  50788. for (var i = 0; i < this.manipulationHammers.length; i++) {
  50789. this.manipulationHammers[i].destroy();
  50790. }
  50791. this.manipulationHammers = [];
  50792. }
  50793. }
  50794. /**
  50795. * Remove all DOM elements created by this module.
  50796. * @private
  50797. */
  50798. }, {
  50799. key: '_removeManipulationDOM',
  50800. value: function _removeManipulationDOM() {
  50801. // removes all the bindings and overloads
  50802. this._clean();
  50803. // empty the manipulation divs
  50804. util.recursiveDOMDelete(this.manipulationDiv);
  50805. util.recursiveDOMDelete(this.editModeDiv);
  50806. util.recursiveDOMDelete(this.closeDiv);
  50807. // remove the manipulation divs
  50808. if (this.manipulationDiv) {
  50809. this.canvas.frame.removeChild(this.manipulationDiv);
  50810. }
  50811. if (this.editModeDiv) {
  50812. this.canvas.frame.removeChild(this.editModeDiv);
  50813. }
  50814. if (this.closeDiv) {
  50815. this.canvas.frame.removeChild(this.closeDiv);
  50816. }
  50817. // set the references to undefined
  50818. this.manipulationDiv = undefined;
  50819. this.editModeDiv = undefined;
  50820. this.closeDiv = undefined;
  50821. }
  50822. /**
  50823. * create a seperator line. the index is to differentiate in the manipulation dom
  50824. * @param {number} [index=1]
  50825. * @private
  50826. */
  50827. }, {
  50828. key: '_createSeperator',
  50829. value: function _createSeperator() {
  50830. var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
  50831. this.manipulationDOM['seperatorLineDiv' + index] = document.createElement('div');
  50832. this.manipulationDOM['seperatorLineDiv' + index].className = 'vis-separator-line';
  50833. this.manipulationDiv.appendChild(this.manipulationDOM['seperatorLineDiv' + index]);
  50834. }
  50835. // ---------------------- DOM functions for buttons --------------------------//
  50836. /**
  50837. *
  50838. * @param {Locale} locale
  50839. * @private
  50840. */
  50841. }, {
  50842. key: '_createAddNodeButton',
  50843. value: function _createAddNodeButton(locale) {
  50844. var button = this._createButton('addNode', 'vis-button vis-add', locale['addNode'] || this.options.locales['en']['addNode']);
  50845. this.manipulationDiv.appendChild(button);
  50846. this._bindHammerToDiv(button, this.addNodeMode.bind(this));
  50847. }
  50848. /**
  50849. *
  50850. * @param {Locale} locale
  50851. * @private
  50852. */
  50853. }, {
  50854. key: '_createAddEdgeButton',
  50855. value: function _createAddEdgeButton(locale) {
  50856. var button = this._createButton('addEdge', 'vis-button vis-connect', locale['addEdge'] || this.options.locales['en']['addEdge']);
  50857. this.manipulationDiv.appendChild(button);
  50858. this._bindHammerToDiv(button, this.addEdgeMode.bind(this));
  50859. }
  50860. /**
  50861. *
  50862. * @param {Locale} locale
  50863. * @private
  50864. */
  50865. }, {
  50866. key: '_createEditNodeButton',
  50867. value: function _createEditNodeButton(locale) {
  50868. var button = this._createButton('editNode', 'vis-button vis-edit', locale['editNode'] || this.options.locales['en']['editNode']);
  50869. this.manipulationDiv.appendChild(button);
  50870. this._bindHammerToDiv(button, this.editNode.bind(this));
  50871. }
  50872. /**
  50873. *
  50874. * @param {Locale} locale
  50875. * @private
  50876. */
  50877. }, {
  50878. key: '_createEditEdgeButton',
  50879. value: function _createEditEdgeButton(locale) {
  50880. var button = this._createButton('editEdge', 'vis-button vis-edit', locale['editEdge'] || this.options.locales['en']['editEdge']);
  50881. this.manipulationDiv.appendChild(button);
  50882. this._bindHammerToDiv(button, this.editEdgeMode.bind(this));
  50883. }
  50884. /**
  50885. *
  50886. * @param {Locale} locale
  50887. * @private
  50888. */
  50889. }, {
  50890. key: '_createDeleteButton',
  50891. value: function _createDeleteButton(locale) {
  50892. var deleteBtnClass;
  50893. if (this.options.rtl) {
  50894. deleteBtnClass = 'vis-button vis-delete-rtl';
  50895. } else {
  50896. deleteBtnClass = 'vis-button vis-delete';
  50897. }
  50898. var button = this._createButton('delete', deleteBtnClass, locale['del'] || this.options.locales['en']['del']);
  50899. this.manipulationDiv.appendChild(button);
  50900. this._bindHammerToDiv(button, this.deleteSelected.bind(this));
  50901. }
  50902. /**
  50903. *
  50904. * @param {Locale} locale
  50905. * @private
  50906. */
  50907. }, {
  50908. key: '_createBackButton',
  50909. value: function _createBackButton(locale) {
  50910. var button = this._createButton('back', 'vis-button vis-back', locale['back'] || this.options.locales['en']['back']);
  50911. this.manipulationDiv.appendChild(button);
  50912. this._bindHammerToDiv(button, this.showManipulatorToolbar.bind(this));
  50913. }
  50914. /**
  50915. *
  50916. * @param {number|string} id
  50917. * @param {string} className
  50918. * @param {label} label
  50919. * @param {string} labelClassName
  50920. * @returns {HTMLElement}
  50921. * @private
  50922. */
  50923. }, {
  50924. key: '_createButton',
  50925. value: function _createButton(id, className, label) {
  50926. var labelClassName = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'vis-label';
  50927. this.manipulationDOM[id + 'Div'] = document.createElement('div');
  50928. this.manipulationDOM[id + 'Div'].className = className;
  50929. this.manipulationDOM[id + 'Label'] = document.createElement('div');
  50930. this.manipulationDOM[id + 'Label'].className = labelClassName;
  50931. this.manipulationDOM[id + 'Label'].innerHTML = label;
  50932. this.manipulationDOM[id + 'Div'].appendChild(this.manipulationDOM[id + 'Label']);
  50933. return this.manipulationDOM[id + 'Div'];
  50934. }
  50935. /**
  50936. *
  50937. * @param {Label} label
  50938. * @private
  50939. */
  50940. }, {
  50941. key: '_createDescription',
  50942. value: function _createDescription(label) {
  50943. this.manipulationDiv.appendChild(this._createButton('description', 'vis-button vis-none', label));
  50944. }
  50945. // -------------------------- End of DOM functions for buttons ------------------------------//
  50946. /**
  50947. * this binds an event until cleanup by the clean functions.
  50948. * @param {Event} event The event
  50949. * @param {function} newFunction
  50950. * @private
  50951. */
  50952. }, {
  50953. key: '_temporaryBindEvent',
  50954. value: function _temporaryBindEvent(event, newFunction) {
  50955. this.temporaryEventFunctions.push({ event: event, boundFunction: newFunction });
  50956. this.body.emitter.on(event, newFunction);
  50957. }
  50958. /**
  50959. * this overrides an UI function until cleanup by the clean function
  50960. * @param {string} UIfunctionName
  50961. * @param {function} newFunction
  50962. * @private
  50963. */
  50964. }, {
  50965. key: '_temporaryBindUI',
  50966. value: function _temporaryBindUI(UIfunctionName, newFunction) {
  50967. if (this.body.eventListeners[UIfunctionName] !== undefined) {
  50968. this.temporaryUIFunctions[UIfunctionName] = this.body.eventListeners[UIfunctionName];
  50969. this.body.eventListeners[UIfunctionName] = newFunction;
  50970. } else {
  50971. throw new Error('This UI function does not exist. Typo? You tried: ' + UIfunctionName + ' possible are: ' + (0, _stringify2['default'])((0, _keys2['default'])(this.body.eventListeners)));
  50972. }
  50973. }
  50974. /**
  50975. * Restore the overridden UI functions to their original state.
  50976. *
  50977. * @private
  50978. */
  50979. }, {
  50980. key: '_unbindTemporaryUIs',
  50981. value: function _unbindTemporaryUIs() {
  50982. for (var functionName in this.temporaryUIFunctions) {
  50983. if (this.temporaryUIFunctions.hasOwnProperty(functionName)) {
  50984. this.body.eventListeners[functionName] = this.temporaryUIFunctions[functionName];
  50985. delete this.temporaryUIFunctions[functionName];
  50986. }
  50987. }
  50988. this.temporaryUIFunctions = {};
  50989. }
  50990. /**
  50991. * Unbind the events created by _temporaryBindEvent
  50992. * @private
  50993. */
  50994. }, {
  50995. key: '_unbindTemporaryEvents',
  50996. value: function _unbindTemporaryEvents() {
  50997. for (var i = 0; i < this.temporaryEventFunctions.length; i++) {
  50998. var eventName = this.temporaryEventFunctions[i].event;
  50999. var boundFunction = this.temporaryEventFunctions[i].boundFunction;
  51000. this.body.emitter.off(eventName, boundFunction);
  51001. }
  51002. this.temporaryEventFunctions = [];
  51003. }
  51004. /**
  51005. * Bind an hammer instance to a DOM element.
  51006. *
  51007. * @param {Element} domElement
  51008. * @param {function} boundFunction
  51009. */
  51010. }, {
  51011. key: '_bindHammerToDiv',
  51012. value: function _bindHammerToDiv(domElement, boundFunction) {
  51013. var hammer = new Hammer(domElement, {});
  51014. hammerUtil.onTouch(hammer, boundFunction);
  51015. this.manipulationHammers.push(hammer);
  51016. }
  51017. /**
  51018. * Neatly clean up temporary edges and nodes
  51019. * @private
  51020. */
  51021. }, {
  51022. key: '_cleanupTemporaryNodesAndEdges',
  51023. value: function _cleanupTemporaryNodesAndEdges() {
  51024. // _clean temporary edges
  51025. for (var i = 0; i < this.temporaryIds.edges.length; i++) {
  51026. this.body.edges[this.temporaryIds.edges[i]].disconnect();
  51027. delete this.body.edges[this.temporaryIds.edges[i]];
  51028. var indexTempEdge = this.body.edgeIndices.indexOf(this.temporaryIds.edges[i]);
  51029. if (indexTempEdge !== -1) {
  51030. this.body.edgeIndices.splice(indexTempEdge, 1);
  51031. }
  51032. }
  51033. // _clean temporary nodes
  51034. for (var _i = 0; _i < this.temporaryIds.nodes.length; _i++) {
  51035. delete this.body.nodes[this.temporaryIds.nodes[_i]];
  51036. var indexTempNode = this.body.nodeIndices.indexOf(this.temporaryIds.nodes[_i]);
  51037. if (indexTempNode !== -1) {
  51038. this.body.nodeIndices.splice(indexTempNode, 1);
  51039. }
  51040. }
  51041. this.temporaryIds = { nodes: [], edges: [] };
  51042. }
  51043. // ------------------------------------------ EDIT EDGE FUNCTIONS -----------------------------------------//
  51044. /**
  51045. * the touch is used to get the position of the initial click
  51046. * @param {Event} event The event
  51047. * @private
  51048. */
  51049. }, {
  51050. key: '_controlNodeTouch',
  51051. value: function _controlNodeTouch(event) {
  51052. this.selectionHandler.unselectAll();
  51053. this.lastTouch = this.body.functions.getPointer(event.center);
  51054. this.lastTouch.translation = util.extend({}, this.body.view.translation); // copy the object
  51055. }
  51056. /**
  51057. * the drag start is used to mark one of the control nodes as selected.
  51058. * @param {Event} event The event
  51059. * @private
  51060. */
  51061. }, {
  51062. key: '_controlNodeDragStart',
  51063. value: function _controlNodeDragStart(event) {
  51064. // eslint-disable-line no-unused-vars
  51065. var pointer = this.lastTouch;
  51066. var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
  51067. var from = this.body.nodes[this.temporaryIds.nodes[0]];
  51068. var to = this.body.nodes[this.temporaryIds.nodes[1]];
  51069. var edge = this.body.edges[this.edgeBeingEditedId];
  51070. this.selectedControlNode = undefined;
  51071. var fromSelect = from.isOverlappingWith(pointerObj);
  51072. var toSelect = to.isOverlappingWith(pointerObj);
  51073. if (fromSelect === true) {
  51074. this.selectedControlNode = from;
  51075. edge.edgeType.from = from;
  51076. } else if (toSelect === true) {
  51077. this.selectedControlNode = to;
  51078. edge.edgeType.to = to;
  51079. }
  51080. // we use the selection to find the node that is being dragged. We explicitly select it here.
  51081. if (this.selectedControlNode !== undefined) {
  51082. this.selectionHandler.selectObject(this.selectedControlNode);
  51083. }
  51084. this.body.emitter.emit('_redraw');
  51085. }
  51086. /**
  51087. * dragging the control nodes or the canvas
  51088. * @param {Event} event The event
  51089. * @private
  51090. */
  51091. }, {
  51092. key: '_controlNodeDrag',
  51093. value: function _controlNodeDrag(event) {
  51094. this.body.emitter.emit('disablePhysics');
  51095. var pointer = this.body.functions.getPointer(event.center);
  51096. var pos = this.canvas.DOMtoCanvas(pointer);
  51097. if (this.selectedControlNode !== undefined) {
  51098. this.selectedControlNode.x = pos.x;
  51099. this.selectedControlNode.y = pos.y;
  51100. } else {
  51101. // if the drag was not started properly because the click started outside the network div, start it now.
  51102. var diffX = pointer.x - this.lastTouch.x;
  51103. var diffY = pointer.y - this.lastTouch.y;
  51104. this.body.view.translation = { x: this.lastTouch.translation.x + diffX, y: this.lastTouch.translation.y + diffY };
  51105. }
  51106. this.body.emitter.emit('_redraw');
  51107. }
  51108. /**
  51109. * connecting or restoring the control nodes.
  51110. * @param {Event} event The event
  51111. * @private
  51112. */
  51113. }, {
  51114. key: '_controlNodeDragEnd',
  51115. value: function _controlNodeDragEnd(event) {
  51116. var pointer = this.body.functions.getPointer(event.center);
  51117. var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
  51118. var edge = this.body.edges[this.edgeBeingEditedId];
  51119. // if the node that was dragged is not a control node, return
  51120. if (this.selectedControlNode === undefined) {
  51121. return;
  51122. }
  51123. // we use the selection to find the node that is being dragged. We explicitly DEselect the control node here.
  51124. this.selectionHandler.unselectAll();
  51125. var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
  51126. var node = undefined;
  51127. for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
  51128. if (overlappingNodeIds[i] !== this.selectedControlNode.id) {
  51129. node = this.body.nodes[overlappingNodeIds[i]];
  51130. break;
  51131. }
  51132. }
  51133. // perform the connection
  51134. if (node !== undefined && this.selectedControlNode !== undefined) {
  51135. if (node.isCluster === true) {
  51136. alert(this.options.locales[this.options.locale]['createEdgeError'] || this.options.locales['en']['createEdgeError']);
  51137. } else {
  51138. var from = this.body.nodes[this.temporaryIds.nodes[0]];
  51139. if (this.selectedControlNode.id === from.id) {
  51140. this._performEditEdge(node.id, edge.to.id);
  51141. } else {
  51142. this._performEditEdge(edge.from.id, node.id);
  51143. }
  51144. }
  51145. } else {
  51146. edge.updateEdgeType();
  51147. this.body.emitter.emit('restorePhysics');
  51148. }
  51149. this.body.emitter.emit('_redraw');
  51150. }
  51151. // ------------------------------------ END OF EDIT EDGE FUNCTIONS -----------------------------------------//
  51152. // ------------------------------------------- ADD EDGE FUNCTIONS -----------------------------------------//
  51153. /**
  51154. * the function bound to the selection event. It checks if you want to connect a cluster and changes the description
  51155. * to walk the user through the process.
  51156. *
  51157. * @param {Event} event
  51158. * @private
  51159. */
  51160. }, {
  51161. key: '_handleConnect',
  51162. value: function _handleConnect(event) {
  51163. // check to avoid double fireing of this function.
  51164. if (new Date().valueOf() - this.touchTime > 100) {
  51165. this.lastTouch = this.body.functions.getPointer(event.center);
  51166. this.lastTouch.translation = util.extend({}, this.body.view.translation); // copy the object
  51167. var pointer = this.lastTouch;
  51168. var node = this.selectionHandler.getNodeAt(pointer);
  51169. if (node !== undefined) {
  51170. if (node.isCluster === true) {
  51171. alert(this.options.locales[this.options.locale]['createEdgeError'] || this.options.locales['en']['createEdgeError']);
  51172. } else {
  51173. // create a node the temporary line can look at
  51174. var targetNode = this._getNewTargetNode(node.x, node.y);
  51175. this.body.nodes[targetNode.id] = targetNode;
  51176. this.body.nodeIndices.push(targetNode.id);
  51177. // create a temporary edge
  51178. var connectionEdge = this.body.functions.createEdge({
  51179. id: 'connectionEdge' + util.randomUUID(),
  51180. from: node.id,
  51181. to: targetNode.id,
  51182. physics: false,
  51183. smooth: {
  51184. enabled: true,
  51185. type: 'continuous',
  51186. roundness: 0.5
  51187. }
  51188. });
  51189. this.body.edges[connectionEdge.id] = connectionEdge;
  51190. this.body.edgeIndices.push(connectionEdge.id);
  51191. this.temporaryIds.nodes.push(targetNode.id);
  51192. this.temporaryIds.edges.push(connectionEdge.id);
  51193. }
  51194. }
  51195. this.touchTime = new Date().valueOf();
  51196. }
  51197. }
  51198. /**
  51199. *
  51200. * @param {Event} event
  51201. * @private
  51202. */
  51203. }, {
  51204. key: '_dragControlNode',
  51205. value: function _dragControlNode(event) {
  51206. var pointer = this.body.functions.getPointer(event.center);
  51207. if (this.temporaryIds.nodes[0] !== undefined) {
  51208. var targetNode = this.body.nodes[this.temporaryIds.nodes[0]]; // there is only one temp node in the add edge mode.
  51209. targetNode.x = this.canvas._XconvertDOMtoCanvas(pointer.x);
  51210. targetNode.y = this.canvas._YconvertDOMtoCanvas(pointer.y);
  51211. this.body.emitter.emit('_redraw');
  51212. } else {
  51213. var diffX = pointer.x - this.lastTouch.x;
  51214. var diffY = pointer.y - this.lastTouch.y;
  51215. this.body.view.translation = { x: this.lastTouch.translation.x + diffX, y: this.lastTouch.translation.y + diffY };
  51216. }
  51217. }
  51218. /**
  51219. * Connect the new edge to the target if one exists, otherwise remove temp line
  51220. * @param {Event} event The event
  51221. * @private
  51222. */
  51223. }, {
  51224. key: '_finishConnect',
  51225. value: function _finishConnect(event) {
  51226. var pointer = this.body.functions.getPointer(event.center);
  51227. var pointerObj = this.selectionHandler._pointerToPositionObject(pointer);
  51228. // remember the edge id
  51229. var connectFromId = undefined;
  51230. if (this.temporaryIds.edges[0] !== undefined) {
  51231. connectFromId = this.body.edges[this.temporaryIds.edges[0]].fromId;
  51232. }
  51233. // get the overlapping node but NOT the temporary node;
  51234. var overlappingNodeIds = this.selectionHandler._getAllNodesOverlappingWith(pointerObj);
  51235. var node = undefined;
  51236. for (var i = overlappingNodeIds.length - 1; i >= 0; i--) {
  51237. // if the node id is NOT a temporary node, accept the node.
  51238. if (this.temporaryIds.nodes.indexOf(overlappingNodeIds[i]) === -1) {
  51239. node = this.body.nodes[overlappingNodeIds[i]];
  51240. break;
  51241. }
  51242. }
  51243. // clean temporary nodes and edges.
  51244. this._cleanupTemporaryNodesAndEdges();
  51245. // perform the connection
  51246. if (node !== undefined) {
  51247. if (node.isCluster === true) {
  51248. alert(this.options.locales[this.options.locale]['createEdgeError'] || this.options.locales['en']['createEdgeError']);
  51249. } else {
  51250. if (this.body.nodes[connectFromId] !== undefined && this.body.nodes[node.id] !== undefined) {
  51251. this._performAddEdge(connectFromId, node.id);
  51252. }
  51253. }
  51254. }
  51255. // No need to do _generateclickevent('dragEnd') here, the regular dragEnd event fires.
  51256. this.body.emitter.emit('_redraw');
  51257. }
  51258. /**
  51259. *
  51260. * @param {Event} event
  51261. * @private
  51262. */
  51263. }, {
  51264. key: '_dragStartEdge',
  51265. value: function _dragStartEdge(event) {
  51266. var pointer = this.lastTouch;
  51267. this.selectionHandler._generateClickEvent('dragStart', event, pointer, undefined, true);
  51268. }
  51269. // --------------------------------------- END OF ADD EDGE FUNCTIONS -------------------------------------//
  51270. // ------------------------------ Performing all the actual data manipulation ------------------------//
  51271. /**
  51272. * Adds a node on the specified location
  51273. *
  51274. * @param {Object} clickData
  51275. * @private
  51276. */
  51277. }, {
  51278. key: '_performAddNode',
  51279. value: function _performAddNode(clickData) {
  51280. var _this4 = this;
  51281. var defaultData = {
  51282. id: util.randomUUID(),
  51283. x: clickData.pointer.canvas.x,
  51284. y: clickData.pointer.canvas.y,
  51285. label: 'new'
  51286. };
  51287. if (typeof this.options.addNode === 'function') {
  51288. if (this.options.addNode.length === 2) {
  51289. this.options.addNode(defaultData, function(finalizedData) {
  51290. if (finalizedData !== null && finalizedData !== undefined && _this4.inMode === 'addNode') {
  51291. // if for whatever reason the mode has changes (due to dataset change) disregard the callback
  51292. _this4.body.data.nodes.getDataSet().add(finalizedData);
  51293. _this4.showManipulatorToolbar();
  51294. }
  51295. });
  51296. } else {
  51297. this.showManipulatorToolbar();
  51298. throw new Error('The function for add does not support two arguments (data,callback)');
  51299. }
  51300. } else {
  51301. this.body.data.nodes.getDataSet().add(defaultData);
  51302. this.showManipulatorToolbar();
  51303. }
  51304. }
  51305. /**
  51306. * connect two nodes with a new edge.
  51307. *
  51308. * @param {Node.id} sourceNodeId
  51309. * @param {Node.id} targetNodeId
  51310. * @private
  51311. */
  51312. }, {
  51313. key: '_performAddEdge',
  51314. value: function _performAddEdge(sourceNodeId, targetNodeId) {
  51315. var _this5 = this;
  51316. var defaultData = { from: sourceNodeId, to: targetNodeId };
  51317. if (typeof this.options.addEdge === 'function') {
  51318. if (this.options.addEdge.length === 2) {
  51319. this.options.addEdge(defaultData, function(finalizedData) {
  51320. if (finalizedData !== null && finalizedData !== undefined && _this5.inMode === 'addEdge') {
  51321. // if for whatever reason the mode has changes (due to dataset change) disregard the callback
  51322. _this5.body.data.edges.getDataSet().add(finalizedData);
  51323. _this5.selectionHandler.unselectAll();
  51324. _this5.showManipulatorToolbar();
  51325. }
  51326. });
  51327. } else {
  51328. throw new Error('The function for connect does not support two arguments (data,callback)');
  51329. }
  51330. } else {
  51331. this.body.data.edges.getDataSet().add(defaultData);
  51332. this.selectionHandler.unselectAll();
  51333. this.showManipulatorToolbar();
  51334. }
  51335. }
  51336. /**
  51337. * connect two nodes with a new edge.
  51338. *
  51339. * @param {Node.id} sourceNodeId
  51340. * @param {Node.id} targetNodeId
  51341. * @private
  51342. */
  51343. }, {
  51344. key: '_performEditEdge',
  51345. value: function _performEditEdge(sourceNodeId, targetNodeId) {
  51346. var _this6 = this;
  51347. var defaultData = { id: this.edgeBeingEditedId, from: sourceNodeId, to: targetNodeId, label: this.body.data.edges._data[this.edgeBeingEditedId].label };
  51348. var eeFunct = this.options.editEdge;
  51349. if ((typeof eeFunct === 'undefined' ? 'undefined' : (0, _typeof3['default'])(eeFunct)) === 'object') {
  51350. eeFunct = eeFunct.editWithoutDrag;
  51351. }
  51352. if (typeof eeFunct === 'function') {
  51353. if (eeFunct.length === 2) {
  51354. eeFunct(defaultData, function(finalizedData) {
  51355. if (finalizedData === null || finalizedData === undefined || _this6.inMode !== 'editEdge') {
  51356. // if for whatever reason the mode has changes (due to dataset change) disregard the callback) {
  51357. _this6.body.edges[defaultData.id].updateEdgeType();
  51358. _this6.body.emitter.emit('_redraw');
  51359. _this6.showManipulatorToolbar();
  51360. } else {
  51361. _this6.body.data.edges.getDataSet().update(finalizedData);
  51362. _this6.selectionHandler.unselectAll();
  51363. _this6.showManipulatorToolbar();
  51364. }
  51365. });
  51366. } else {
  51367. throw new Error('The function for edit does not support two arguments (data, callback)');
  51368. }
  51369. } else {
  51370. this.body.data.edges.getDataSet().update(defaultData);
  51371. this.selectionHandler.unselectAll();
  51372. this.showManipulatorToolbar();
  51373. }
  51374. }
  51375. }]);
  51376. return ManipulationSystem;
  51377. }();
  51378. exports['default'] = ManipulationSystem;
  51379. /***/
  51380. }),
  51381. /* 238 */
  51382. /***/
  51383. (function(module, exports, __webpack_require__) {
  51384. "use strict";
  51385. Object.defineProperty(exports, "__esModule", {
  51386. value: true
  51387. });
  51388. var _slicedToArray2 = __webpack_require__(30);
  51389. var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
  51390. var _classCallCheck2 = __webpack_require__(0);
  51391. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  51392. var _createClass2 = __webpack_require__(1);
  51393. var _createClass3 = _interopRequireDefault(_createClass2);
  51394. var _FloydWarshall = __webpack_require__(239);
  51395. var _FloydWarshall2 = _interopRequireDefault(_FloydWarshall);
  51396. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  51397. /**
  51398. * KamadaKawai positions the nodes initially based on
  51399. *
  51400. * "AN ALGORITHM FOR DRAWING GENERAL UNDIRECTED GRAPHS"
  51401. * -- Tomihisa KAMADA and Satoru KAWAI in 1989
  51402. *
  51403. * Possible optimizations in the distance calculation can be implemented.
  51404. */
  51405. var KamadaKawai = function() {
  51406. /**
  51407. * @param {Object} body
  51408. * @param {number} edgeLength
  51409. * @param {number} edgeStrength
  51410. */
  51411. function KamadaKawai(body, edgeLength, edgeStrength) {
  51412. (0, _classCallCheck3["default"])(this, KamadaKawai);
  51413. this.body = body;
  51414. this.springLength = edgeLength;
  51415. this.springConstant = edgeStrength;
  51416. this.distanceSolver = new _FloydWarshall2["default"]();
  51417. }
  51418. /**
  51419. * Not sure if needed but can be used to update the spring length and spring constant
  51420. * @param {Object} options
  51421. */
  51422. (0, _createClass3["default"])(KamadaKawai, [{
  51423. key: "setOptions",
  51424. value: function setOptions(options) {
  51425. if (options) {
  51426. if (options.springLength) {
  51427. this.springLength = options.springLength;
  51428. }
  51429. if (options.springConstant) {
  51430. this.springConstant = options.springConstant;
  51431. }
  51432. }
  51433. }
  51434. /**
  51435. * Position the system
  51436. * @param {Array.<Node>} nodesArray
  51437. * @param {Array.<vis.Edge>} edgesArray
  51438. * @param {boolean} [ignoreClusters=false]
  51439. */
  51440. }, {
  51441. key: "solve",
  51442. value: function solve(nodesArray, edgesArray) {
  51443. var ignoreClusters = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  51444. // get distance matrix
  51445. var D_matrix = this.distanceSolver.getDistances(this.body, nodesArray, edgesArray); // distance matrix
  51446. // get the L Matrix
  51447. this._createL_matrix(D_matrix);
  51448. // get the K Matrix
  51449. this._createK_matrix(D_matrix);
  51450. // initial E Matrix
  51451. this._createE_matrix();
  51452. // calculate positions
  51453. var threshold = 0.01;
  51454. var innerThreshold = 1;
  51455. var iterations = 0;
  51456. var maxIterations = Math.max(1000, Math.min(10 * this.body.nodeIndices.length, 6000));
  51457. var maxInnerIterations = 5;
  51458. var maxEnergy = 1e9;
  51459. var highE_nodeId = 0,
  51460. dE_dx = 0,
  51461. dE_dy = 0,
  51462. delta_m = 0,
  51463. subIterations = 0;
  51464. while (maxEnergy > threshold && iterations < maxIterations) {
  51465. iterations += 1;
  51466. var _getHighestEnergyNode2 = this._getHighestEnergyNode(ignoreClusters);
  51467. var _getHighestEnergyNode3 = (0, _slicedToArray3["default"])(_getHighestEnergyNode2, 4);
  51468. highE_nodeId = _getHighestEnergyNode3[0];
  51469. maxEnergy = _getHighestEnergyNode3[1];
  51470. dE_dx = _getHighestEnergyNode3[2];
  51471. dE_dy = _getHighestEnergyNode3[3];
  51472. delta_m = maxEnergy;
  51473. subIterations = 0;
  51474. while (delta_m > innerThreshold && subIterations < maxInnerIterations) {
  51475. subIterations += 1;
  51476. this._moveNode(highE_nodeId, dE_dx, dE_dy);
  51477. var _getEnergy2 = this._getEnergy(highE_nodeId);
  51478. var _getEnergy3 = (0, _slicedToArray3["default"])(_getEnergy2, 3);
  51479. delta_m = _getEnergy3[0];
  51480. dE_dx = _getEnergy3[1];
  51481. dE_dy = _getEnergy3[2];
  51482. }
  51483. }
  51484. }
  51485. /**
  51486. * get the node with the highest energy
  51487. * @param {boolean} ignoreClusters
  51488. * @returns {number[]}
  51489. * @private
  51490. */
  51491. }, {
  51492. key: "_getHighestEnergyNode",
  51493. value: function _getHighestEnergyNode(ignoreClusters) {
  51494. var nodesArray = this.body.nodeIndices;
  51495. var nodes = this.body.nodes;
  51496. var maxEnergy = 0;
  51497. var maxEnergyNodeId = nodesArray[0];
  51498. var dE_dx_max = 0,
  51499. dE_dy_max = 0;
  51500. for (var nodeIdx = 0; nodeIdx < nodesArray.length; nodeIdx++) {
  51501. var m = nodesArray[nodeIdx];
  51502. // by not evaluating nodes with predefined positions we should only move nodes that have no positions.
  51503. if (nodes[m].predefinedPosition === false || nodes[m].isCluster === true && ignoreClusters === true || nodes[m].options.fixed.x === true || nodes[m].options.fixed.y === true) {
  51504. var _getEnergy4 = this._getEnergy(m),
  51505. _getEnergy5 = (0, _slicedToArray3["default"])(_getEnergy4, 3),
  51506. delta_m = _getEnergy5[0],
  51507. dE_dx = _getEnergy5[1],
  51508. dE_dy = _getEnergy5[2];
  51509. if (maxEnergy < delta_m) {
  51510. maxEnergy = delta_m;
  51511. maxEnergyNodeId = m;
  51512. dE_dx_max = dE_dx;
  51513. dE_dy_max = dE_dy;
  51514. }
  51515. }
  51516. }
  51517. return [maxEnergyNodeId, maxEnergy, dE_dx_max, dE_dy_max];
  51518. }
  51519. /**
  51520. * calculate the energy of a single node
  51521. * @param {Node.id} m
  51522. * @returns {number[]}
  51523. * @private
  51524. */
  51525. }, {
  51526. key: "_getEnergy",
  51527. value: function _getEnergy(m) {
  51528. var _E_sums$m = (0, _slicedToArray3["default"])(this.E_sums[m], 2),
  51529. dE_dx = _E_sums$m[0],
  51530. dE_dy = _E_sums$m[1];
  51531. var delta_m = Math.sqrt(Math.pow(dE_dx, 2) + Math.pow(dE_dy, 2));
  51532. return [delta_m, dE_dx, dE_dy];
  51533. }
  51534. /**
  51535. * move the node based on it's energy
  51536. * the dx and dy are calculated from the linear system proposed by Kamada and Kawai
  51537. * @param {number} m
  51538. * @param {number} dE_dx
  51539. * @param {number} dE_dy
  51540. * @private
  51541. */
  51542. }, {
  51543. key: "_moveNode",
  51544. value: function _moveNode(m, dE_dx, dE_dy) {
  51545. var nodesArray = this.body.nodeIndices;
  51546. var nodes = this.body.nodes;
  51547. var d2E_dx2 = 0;
  51548. var d2E_dxdy = 0;
  51549. var d2E_dy2 = 0;
  51550. var x_m = nodes[m].x;
  51551. var y_m = nodes[m].y;
  51552. var km = this.K_matrix[m];
  51553. var lm = this.L_matrix[m];
  51554. for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
  51555. var i = nodesArray[iIdx];
  51556. if (i !== m) {
  51557. var x_i = nodes[i].x;
  51558. var y_i = nodes[i].y;
  51559. var kmat = km[i];
  51560. var lmat = lm[i];
  51561. var denominator = 1.0 / Math.pow(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2), 1.5);
  51562. d2E_dx2 += kmat * (1 - lmat * Math.pow(y_m - y_i, 2) * denominator);
  51563. d2E_dxdy += kmat * (lmat * (x_m - x_i) * (y_m - y_i) * denominator);
  51564. d2E_dy2 += kmat * (1 - lmat * Math.pow(x_m - x_i, 2) * denominator);
  51565. }
  51566. }
  51567. // make the variable names easier to make the solving of the linear system easier to read
  51568. var A = d2E_dx2,
  51569. B = d2E_dxdy,
  51570. C = dE_dx,
  51571. D = d2E_dy2,
  51572. E = dE_dy;
  51573. // solve the linear system for dx and dy
  51574. var dy = (C / A + E / B) / (B / A - D / B);
  51575. var dx = -(B * dy + C) / A;
  51576. // move the node
  51577. nodes[m].x += dx;
  51578. nodes[m].y += dy;
  51579. // Recalculate E_matrix (should be incremental)
  51580. this._updateE_matrix(m);
  51581. }
  51582. /**
  51583. * Create the L matrix: edge length times shortest path
  51584. * @param {Object} D_matrix
  51585. * @private
  51586. */
  51587. }, {
  51588. key: "_createL_matrix",
  51589. value: function _createL_matrix(D_matrix) {
  51590. var nodesArray = this.body.nodeIndices;
  51591. var edgeLength = this.springLength;
  51592. this.L_matrix = [];
  51593. for (var i = 0; i < nodesArray.length; i++) {
  51594. this.L_matrix[nodesArray[i]] = {};
  51595. for (var j = 0; j < nodesArray.length; j++) {
  51596. this.L_matrix[nodesArray[i]][nodesArray[j]] = edgeLength * D_matrix[nodesArray[i]][nodesArray[j]];
  51597. }
  51598. }
  51599. }
  51600. /**
  51601. * Create the K matrix: spring constants times shortest path
  51602. * @param {Object} D_matrix
  51603. * @private
  51604. */
  51605. }, {
  51606. key: "_createK_matrix",
  51607. value: function _createK_matrix(D_matrix) {
  51608. var nodesArray = this.body.nodeIndices;
  51609. var edgeStrength = this.springConstant;
  51610. this.K_matrix = [];
  51611. for (var i = 0; i < nodesArray.length; i++) {
  51612. this.K_matrix[nodesArray[i]] = {};
  51613. for (var j = 0; j < nodesArray.length; j++) {
  51614. this.K_matrix[nodesArray[i]][nodesArray[j]] = edgeStrength * Math.pow(D_matrix[nodesArray[i]][nodesArray[j]], -2);
  51615. }
  51616. }
  51617. }
  51618. /**
  51619. * Create matrix with all energies between nodes
  51620. * @private
  51621. */
  51622. }, {
  51623. key: "_createE_matrix",
  51624. value: function _createE_matrix() {
  51625. var nodesArray = this.body.nodeIndices;
  51626. var nodes = this.body.nodes;
  51627. this.E_matrix = {};
  51628. this.E_sums = {};
  51629. for (var mIdx = 0; mIdx < nodesArray.length; mIdx++) {
  51630. this.E_matrix[nodesArray[mIdx]] = [];
  51631. }
  51632. for (var _mIdx = 0; _mIdx < nodesArray.length; _mIdx++) {
  51633. var m = nodesArray[_mIdx];
  51634. var x_m = nodes[m].x;
  51635. var y_m = nodes[m].y;
  51636. var dE_dx = 0;
  51637. var dE_dy = 0;
  51638. for (var iIdx = _mIdx; iIdx < nodesArray.length; iIdx++) {
  51639. var i = nodesArray[iIdx];
  51640. if (i !== m) {
  51641. var x_i = nodes[i].x;
  51642. var y_i = nodes[i].y;
  51643. var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
  51644. this.E_matrix[m][iIdx] = [this.K_matrix[m][i] * (x_m - x_i - this.L_matrix[m][i] * (x_m - x_i) * denominator), this.K_matrix[m][i] * (y_m - y_i - this.L_matrix[m][i] * (y_m - y_i) * denominator)];
  51645. this.E_matrix[i][_mIdx] = this.E_matrix[m][iIdx];
  51646. dE_dx += this.E_matrix[m][iIdx][0];
  51647. dE_dy += this.E_matrix[m][iIdx][1];
  51648. }
  51649. }
  51650. //Store sum
  51651. this.E_sums[m] = [dE_dx, dE_dy];
  51652. }
  51653. }
  51654. /**
  51655. * Update method, just doing single column (rows are auto-updated) (update all sums)
  51656. *
  51657. * @param {number} m
  51658. * @private
  51659. */
  51660. }, {
  51661. key: "_updateE_matrix",
  51662. value: function _updateE_matrix(m) {
  51663. var nodesArray = this.body.nodeIndices;
  51664. var nodes = this.body.nodes;
  51665. var colm = this.E_matrix[m];
  51666. var kcolm = this.K_matrix[m];
  51667. var lcolm = this.L_matrix[m];
  51668. var x_m = nodes[m].x;
  51669. var y_m = nodes[m].y;
  51670. var dE_dx = 0;
  51671. var dE_dy = 0;
  51672. for (var iIdx = 0; iIdx < nodesArray.length; iIdx++) {
  51673. var i = nodesArray[iIdx];
  51674. if (i !== m) {
  51675. //Keep old energy value for sum modification below
  51676. var cell = colm[iIdx];
  51677. var oldDx = cell[0];
  51678. var oldDy = cell[1];
  51679. //Calc new energy:
  51680. var x_i = nodes[i].x;
  51681. var y_i = nodes[i].y;
  51682. var denominator = 1.0 / Math.sqrt(Math.pow(x_m - x_i, 2) + Math.pow(y_m - y_i, 2));
  51683. var dx = kcolm[i] * (x_m - x_i - lcolm[i] * (x_m - x_i) * denominator);
  51684. var dy = kcolm[i] * (y_m - y_i - lcolm[i] * (y_m - y_i) * denominator);
  51685. colm[iIdx] = [dx, dy];
  51686. dE_dx += dx;
  51687. dE_dy += dy;
  51688. //add new energy to sum of each column
  51689. var sum = this.E_sums[i];
  51690. sum[0] += dx - oldDx;
  51691. sum[1] += dy - oldDy;
  51692. }
  51693. }
  51694. //Store sum at -1 index
  51695. this.E_sums[m] = [dE_dx, dE_dy];
  51696. }
  51697. }]);
  51698. return KamadaKawai;
  51699. }(); // distance finding algorithm
  51700. exports["default"] = KamadaKawai;
  51701. /***/
  51702. }),
  51703. /* 239 */
  51704. /***/
  51705. (function(module, exports, __webpack_require__) {
  51706. "use strict";
  51707. Object.defineProperty(exports, "__esModule", {
  51708. value: true
  51709. });
  51710. var _classCallCheck2 = __webpack_require__(0);
  51711. var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
  51712. var _createClass2 = __webpack_require__(1);
  51713. var _createClass3 = _interopRequireDefault(_createClass2);
  51714. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
  51715. /**
  51716. * The Floyd–Warshall algorithm is an algorithm for finding shortest paths in
  51717. * a weighted graph with positive or negative edge weights (but with no negative
  51718. * cycles). - https://en.wikipedia.org/wiki/Floyd–Warshall_algorithm
  51719. */
  51720. var FloydWarshall = function() {
  51721. /**
  51722. * @ignore
  51723. */
  51724. function FloydWarshall() {
  51725. (0, _classCallCheck3["default"])(this, FloydWarshall);
  51726. }
  51727. /**
  51728. *
  51729. * @param {Object} body
  51730. * @param {Array.<Node>} nodesArray
  51731. * @param {Array.<Edge>} edgesArray
  51732. * @returns {{}}
  51733. */
  51734. (0, _createClass3["default"])(FloydWarshall, [{
  51735. key: "getDistances",
  51736. value: function getDistances(body, nodesArray, edgesArray) {
  51737. var D_matrix = {};
  51738. var edges = body.edges;
  51739. // prepare matrix with large numbers
  51740. for (var i = 0; i < nodesArray.length; i++) {
  51741. var node = nodesArray[i];
  51742. var cell = {};
  51743. D_matrix[node] = cell;
  51744. for (var j = 0; j < nodesArray.length; j++) {
  51745. cell[nodesArray[j]] = i == j ? 0 : 1e9;
  51746. }
  51747. }
  51748. // put the weights for the edges in. This assumes unidirectionality.
  51749. for (var _i = 0; _i < edgesArray.length; _i++) {
  51750. var edge = edges[edgesArray[_i]];
  51751. // edge has to be connected if it counts to the distances. If it is connected to inner clusters it will crash so we also check if it is in the D_matrix
  51752. if (edge.connected === true && D_matrix[edge.fromId] !== undefined && D_matrix[edge.toId] !== undefined) {
  51753. D_matrix[edge.fromId][edge.toId] = 1;
  51754. D_matrix[edge.toId][edge.fromId] = 1;
  51755. }
  51756. }
  51757. var nodeCount = nodesArray.length;
  51758. // Adapted FloydWarshall based on unidirectionality to greatly reduce complexity.
  51759. for (var k = 0; k < nodeCount; k++) {
  51760. var knode = nodesArray[k];
  51761. var kcolm = D_matrix[knode];
  51762. for (var _i2 = 0; _i2 < nodeCount - 1; _i2++) {
  51763. var inode = nodesArray[_i2];
  51764. var icolm = D_matrix[inode];
  51765. for (var _j = _i2 + 1; _j < nodeCount; _j++) {
  51766. var jnode = nodesArray[_j];
  51767. var jcolm = D_matrix[jnode];
  51768. var val = Math.min(icolm[jnode], icolm[knode] + kcolm[jnode]);
  51769. icolm[jnode] = val;
  51770. jcolm[inode] = val;
  51771. }
  51772. }
  51773. }
  51774. return D_matrix;
  51775. }
  51776. }]);
  51777. return FloydWarshall;
  51778. }();
  51779. exports["default"] = FloydWarshall;
  51780. /***/
  51781. })
  51782. /******/
  51783. ]);
  51784. });