123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842 |
- var __defProp = Object.defineProperty;
- var __defProps = Object.defineProperties;
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
- var __hasOwnProp = Object.prototype.hasOwnProperty;
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
- var __spreadValues = (a, b) => {
- for (var prop in b || (b = {}))
- if (__hasOwnProp.call(b, prop))
- __defNormalProp(a, prop, b[prop]);
- if (__getOwnPropSymbols)
- for (var prop of __getOwnPropSymbols(b)) {
- if (__propIsEnum.call(b, prop))
- __defNormalProp(a, prop, b[prop]);
- }
- return a;
- };
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
- var __async = (__this, __arguments, generator) => {
- return new Promise((resolve, reject) => {
- var fulfilled = (value) => {
- try {
- step(generator.next(value));
- } catch (e) {
- reject(e);
- }
- };
- var rejected = (value) => {
- try {
- step(generator.throw(value));
- } catch (e) {
- reject(e);
- }
- };
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
- step((generator = generator.apply(__this, __arguments)).next());
- });
- };
- var eventemitter3 = { exports: {} };
- (function(module) {
- var has = Object.prototype.hasOwnProperty, prefix = "~";
- function Events() {
- }
- if (Object.create) {
- Events.prototype = /* @__PURE__ */ Object.create(null);
- if (!new Events().__proto__)
- prefix = false;
- }
- function EE(fn, context, once) {
- this.fn = fn;
- this.context = context;
- this.once = once || false;
- }
- function addListener(emitter, event, fn, context, once) {
- if (typeof fn !== "function") {
- throw new TypeError("The listener must be a function");
- }
- var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event;
- if (!emitter._events[evt])
- emitter._events[evt] = listener, emitter._eventsCount++;
- else if (!emitter._events[evt].fn)
- emitter._events[evt].push(listener);
- else
- emitter._events[evt] = [emitter._events[evt], listener];
- return emitter;
- }
- function clearEvent(emitter, evt) {
- if (--emitter._eventsCount === 0)
- emitter._events = new Events();
- else
- delete emitter._events[evt];
- }
- function EventEmitter2() {
- this._events = new Events();
- this._eventsCount = 0;
- }
- EventEmitter2.prototype.eventNames = function eventNames() {
- var names = [], events, name;
- if (this._eventsCount === 0)
- return names;
- for (name in events = this._events) {
- if (has.call(events, name))
- names.push(prefix ? name.slice(1) : name);
- }
- if (Object.getOwnPropertySymbols) {
- return names.concat(Object.getOwnPropertySymbols(events));
- }
- return names;
- };
- EventEmitter2.prototype.listeners = function listeners(event) {
- var evt = prefix ? prefix + event : event, handlers = this._events[evt];
- if (!handlers)
- return [];
- if (handlers.fn)
- return [handlers.fn];
- for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
- ee[i] = handlers[i].fn;
- }
- return ee;
- };
- EventEmitter2.prototype.listenerCount = function listenerCount(event) {
- var evt = prefix ? prefix + event : event, listeners = this._events[evt];
- if (!listeners)
- return 0;
- if (listeners.fn)
- return 1;
- return listeners.length;
- };
- EventEmitter2.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
- var evt = prefix ? prefix + event : event;
- if (!this._events[evt])
- return false;
- var listeners = this._events[evt], len = arguments.length, args, i;
- if (listeners.fn) {
- if (listeners.once)
- this.removeListener(event, listeners.fn, void 0, true);
- switch (len) {
- case 1:
- return listeners.fn.call(listeners.context), true;
- case 2:
- return listeners.fn.call(listeners.context, a1), true;
- case 3:
- return listeners.fn.call(listeners.context, a1, a2), true;
- case 4:
- return listeners.fn.call(listeners.context, a1, a2, a3), true;
- case 5:
- return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
- case 6:
- return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
- }
- for (i = 1, args = new Array(len - 1); i < len; i++) {
- args[i - 1] = arguments[i];
- }
- listeners.fn.apply(listeners.context, args);
- } else {
- var length = listeners.length, j;
- for (i = 0; i < length; i++) {
- if (listeners[i].once)
- this.removeListener(event, listeners[i].fn, void 0, true);
- switch (len) {
- case 1:
- listeners[i].fn.call(listeners[i].context);
- break;
- case 2:
- listeners[i].fn.call(listeners[i].context, a1);
- break;
- case 3:
- listeners[i].fn.call(listeners[i].context, a1, a2);
- break;
- case 4:
- listeners[i].fn.call(listeners[i].context, a1, a2, a3);
- break;
- default:
- if (!args)
- for (j = 1, args = new Array(len - 1); j < len; j++) {
- args[j - 1] = arguments[j];
- }
- listeners[i].fn.apply(listeners[i].context, args);
- }
- }
- }
- return true;
- };
- EventEmitter2.prototype.on = function on(event, fn, context) {
- return addListener(this, event, fn, context, false);
- };
- EventEmitter2.prototype.once = function once(event, fn, context) {
- return addListener(this, event, fn, context, true);
- };
- EventEmitter2.prototype.removeListener = function removeListener(event, fn, context, once) {
- var evt = prefix ? prefix + event : event;
- if (!this._events[evt])
- return this;
- if (!fn) {
- clearEvent(this, evt);
- return this;
- }
- var listeners = this._events[evt];
- if (listeners.fn) {
- if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
- clearEvent(this, evt);
- }
- } else {
- for (var i = 0, events = [], length = listeners.length; i < length; i++) {
- if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
- events.push(listeners[i]);
- }
- }
- if (events.length)
- this._events[evt] = events.length === 1 ? events[0] : events;
- else
- clearEvent(this, evt);
- }
- return this;
- };
- EventEmitter2.prototype.removeAllListeners = function removeAllListeners(event) {
- var evt;
- if (event) {
- evt = prefix ? prefix + event : event;
- if (this._events[evt])
- clearEvent(this, evt);
- } else {
- this._events = new Events();
- this._eventsCount = 0;
- }
- return this;
- };
- EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener;
- EventEmitter2.prototype.addListener = EventEmitter2.prototype.on;
- EventEmitter2.prefixed = prefix;
- EventEmitter2.EventEmitter = EventEmitter2;
- {
- module.exports = EventEmitter2;
- }
- })(eventemitter3);
- var EventEmitter = eventemitter3.exports;
- const createCanvas = (width, height, opt = { noStyle: false, noTranslate: false, className: "" }) => {
- let canvas = document.createElement("canvas");
- if (!opt.noStyle) {
- canvas.style.cssText = `
- position: absolute;
- left: 0;
- top: 0;
- `;
- }
- if (opt.className) {
- canvas.className = opt.className;
- }
- let ctx = canvas.getContext("2d");
- canvas.width = width;
- canvas.height = height;
- if (!opt.noTranslate) {
- ctx.translate(canvas.width / 2, canvas.height / 2);
- }
- return {
- canvas,
- ctx
- };
- };
- const getTowPointDistance = (x1, y1, x2, y2) => {
- return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
- };
- const getPointToLineDistance = (x, y, x1, y1, x2, y2) => {
- if (x1 === x2) {
- return Math.abs(x - x1);
- } else {
- let B = 1;
- let A, C;
- A = (y1 - y2) / (x2 - x1);
- C = 0 - B * y1 - A * x1;
- return Math.abs((A * x + B * y + C) / Math.sqrt(A * A + B * B));
- }
- };
- const checkIsAtSegment = (x, y, x1, y1, x2, y2, dis = 10) => {
- if (getPointToLineDistance(x, y, x1, y1, x2, y2) > dis) {
- return false;
- }
- let dis1 = getTowPointDistance(x, y, x1, y1);
- let dis2 = getTowPointDistance(x, y, x2, y2);
- let dis3 = getTowPointDistance(x1, y1, x2, y2);
- let max = Math.sqrt(dis * dis + dis3 * dis3);
- if (dis1 <= max && dis2 <= max) {
- return true;
- }
- return false;
- };
- const radToDeg = (rad) => {
- return rad * (180 / Math.PI);
- };
- const degToRad = (deg) => {
- return deg * (Math.PI / 180);
- };
- const getTowPointRotate = (cx, cy, tx, ty, fx, fy) => {
- return radToDeg(Math.atan2(ty - cy, tx - cx) - Math.atan2(fy - cy, fx - cx));
- };
- const getRotatedPoint = (x, y, cx, cy, rotate) => {
- let deg = radToDeg(Math.atan2(y - cy, x - cx));
- let del = deg + rotate;
- let dis = getTowPointDistance(x, y, cx, cy);
- return {
- x: Math.cos(degToRad(del)) * dis + cx,
- y: Math.sin(degToRad(del)) * dis + cy
- };
- };
- const getElementCenterPoint = (element) => {
- let { x, y, width, height } = element;
- return {
- x: x + width / 2,
- y: y + height / 2
- };
- };
- const transformPointReverseRotate = (x, y, cx, cy, rotate) => {
- if (rotate !== 0) {
- let rp = getRotatedPoint(x, y, cx, cy, -rotate);
- x = rp.x;
- y = rp.y;
- }
- return {
- x,
- y
- };
- };
- const transformPointOnElement = (x, y, element) => {
- let center = getElementCenterPoint(element);
- return transformPointReverseRotate(x, y, center.x, center.y, element.rotate);
- };
- const getElementCornerPoint = (element, dir) => {
- let { x, y, width, height } = element;
- switch (dir) {
- case "topLeft":
- return {
- x,
- y
- };
- case "topRight":
- return {
- x: x + width,
- y
- };
- case "bottomRight":
- return {
- x: x + width,
- y: y + height
- };
- case "bottomLeft":
- return {
- x,
- y: y + height
- };
- }
- };
- const getElementRotatedCornerPoint = (element, dir) => {
- let center = getElementCenterPoint(element);
- let dirPos = getElementCornerPoint(element, dir);
- return getRotatedPoint(dirPos.x, dirPos.y, center.x, center.y, element.rotate);
- };
- const checkPointIsInRectangle = (x, y, rx, ry, rw, rh) => {
- if (typeof rx === "object") {
- let element = rx;
- rx = element.x;
- ry = element.y;
- rw = element.width;
- rh = element.height;
- }
- return x >= rx && x <= rx + rw && y >= ry && y <= ry + rh;
- };
- const getBoundingRect = (pointArr = [], returnCorners = false) => {
- let minX = Infinity;
- let maxX = -Infinity;
- let minY = Infinity;
- let maxY = -Infinity;
- pointArr.forEach((point) => {
- let [x2, y2] = point;
- if (x2 < minX) {
- minX = x2;
- }
- if (x2 > maxX) {
- maxX = x2;
- }
- if (y2 < minY) {
- minY = y2;
- }
- if (y2 > maxY) {
- maxY = y2;
- }
- });
- let x = minX;
- let y = minY;
- let width = maxX - minX;
- let height = maxY - minY;
- if (returnCorners) {
- return [
- {
- x,
- y
- },
- {
- x: x + width,
- y
- },
- {
- x: x + width,
- y: y + height
- },
- {
- x,
- y: y + height
- }
- ];
- }
- return {
- x,
- y,
- width,
- height
- };
- };
- const deepCopy = (obj) => {
- return JSON.parse(JSON.stringify(obj));
- };
- const getFontString = (fontSize, fontFamily) => {
- return `${fontSize}px ${fontFamily}`;
- };
- const splitTextLines = (text) => {
- return text.replace(/\r\n?/g, "\n").split("\n");
- };
- let textCheckEl = null;
- const getTextActWidth = (text, style) => {
- if (!textCheckEl) {
- textCheckEl = document.createElement("div");
- textCheckEl.style.position = "fixed";
- textCheckEl.style.left = "-99999px";
- document.body.appendChild(textCheckEl);
- }
- let { fontSize, fontFamily } = style;
- textCheckEl.innerText = text;
- textCheckEl.style.fontSize = fontSize + "px";
- textCheckEl.style.fontFamily = fontFamily;
- let { width } = textCheckEl.getBoundingClientRect();
- return width;
- };
- const getMaxFontSizeInWidth = (text, width, style) => {
- let fontSize = 12;
- while (getTextActWidth(text, __spreadProps(__spreadValues({}, style), {
- fontSize: fontSize + 1
- })) < width) {
- fontSize++;
- }
- return fontSize;
- };
- const getWrapTextActWidth = (element) => {
- let { text } = element;
- let textArr = splitTextLines(text);
- let maxWidth = -Infinity;
- textArr.forEach((textRow) => {
- let width = getTextActWidth(textRow, element.style);
- if (width > maxWidth) {
- maxWidth = width;
- }
- });
- return maxWidth;
- };
- const getWrapTextMaxRowTextNumber = (text) => {
- let textArr = splitTextLines(text);
- let maxNumber = -Infinity;
- textArr.forEach((textRow) => {
- if (textRow.length > maxNumber) {
- maxNumber = textRow.length;
- }
- });
- return maxNumber;
- };
- const getTextElementSize = (element) => {
- let { text, style } = element;
- let width = getWrapTextActWidth(element);
- const lines = Math.max(splitTextLines(text).length, 1);
- let lineHeight = style.fontSize * style.lineHeightRatio;
- let height = lines * lineHeight;
- return {
- width,
- height
- };
- };
- const throttle = (fn, ctx, time = 100) => {
- let timer = null;
- return (...args) => {
- if (timer) {
- return;
- }
- timer = setTimeout(() => {
- fn.call(ctx, ...args);
- timer = null;
- }, time);
- };
- };
- const computedLineWidthBySpeed = (speed, lastLineWidth, baseLineWidth = 2) => {
- let lineWidth = 0;
- let maxLineWidth = baseLineWidth;
- let maxSpeed = 10;
- let minSpeed = 0.5;
- if (speed >= maxSpeed) {
- lineWidth = baseLineWidth;
- } else if (speed <= minSpeed) {
- lineWidth = maxLineWidth + 1;
- } else {
- lineWidth = maxLineWidth - (speed - minSpeed) / (maxSpeed - minSpeed) * maxLineWidth;
- }
- if (lastLineWidth === -1) {
- lastLineWidth = maxLineWidth;
- }
- return lineWidth * (1 / 2) + lastLineWidth * (1 / 2);
- };
- const downloadFile = (file, fileName) => {
- let a = document.createElement("a");
- a.href = file;
- a.download = fileName;
- a.click();
- };
- const getElementCorners = (element) => {
- let topLeft = getElementRotatedCornerPoint(element, "topLeft");
- let topRight = getElementRotatedCornerPoint(element, "topRight");
- let bottomLeft = getElementRotatedCornerPoint(element, "bottomLeft");
- let bottomRight = getElementRotatedCornerPoint(element, "bottomRight");
- return [topLeft, topRight, bottomLeft, bottomRight];
- };
- const getMultiElementRectInfo = (elementList = []) => {
- if (elementList.length <= 0) {
- return {
- minx: 0,
- maxx: 0,
- miny: 0,
- maxy: 0
- };
- }
- let minx = Infinity;
- let maxx = -Infinity;
- let miny = Infinity;
- let maxy = -Infinity;
- elementList.forEach((element) => {
- let pointList = element.getEndpointList();
- pointList.forEach(({ x, y }) => {
- if (x < minx) {
- minx = x;
- }
- if (x > maxx) {
- maxx = x;
- }
- if (y < miny) {
- miny = y;
- }
- if (y > maxy) {
- maxy = y;
- }
- });
- });
- return {
- minx,
- maxx,
- miny,
- maxy
- };
- };
- const createImageObj = (url) => {
- return new Promise((resolve) => {
- let img = new Image();
- img.setAttribute("crossOrigin", "anonymous");
- img.onload = () => {
- resolve(img);
- };
- img.onerror = () => {
- resolve(null);
- };
- img.src = url;
- });
- };
- let nodeKeyIndex = 0;
- const createNodeKey = () => {
- return nodeKeyIndex++;
- };
- var utils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
- __proto__: null,
- createCanvas,
- getTowPointDistance,
- getPointToLineDistance,
- checkIsAtSegment,
- radToDeg,
- degToRad,
- getTowPointRotate,
- getRotatedPoint,
- getElementCenterPoint,
- transformPointReverseRotate,
- transformPointOnElement,
- getElementCornerPoint,
- getElementRotatedCornerPoint,
- checkPointIsInRectangle,
- getBoundingRect,
- deepCopy,
- getFontString,
- splitTextLines,
- getTextActWidth,
- getMaxFontSizeInWidth,
- getWrapTextActWidth,
- getWrapTextMaxRowTextNumber,
- getTextElementSize,
- throttle,
- computedLineWidthBySpeed,
- downloadFile,
- getElementCorners,
- getMultiElementRectInfo,
- createImageObj,
- createNodeKey
- }, Symbol.toStringTag, { value: "Module" }));
- const CORNERS = {
- TOP_LEFT: "topLeft",
- TOP_RIGHT: "topRight",
- BOTTOM_RIGHT: "bottomRight",
- BOTTOM_LEFT: "bottomLeft"
- };
- const DRAG_ELEMENT_PARTS = {
- BODY: "body",
- ROTATE: "rotate",
- TOP_LEFT_BTN: "topLeftBtn",
- TOP_RIGHT_BTN: "topRightBtn",
- BOTTOM_RIGHT_BTN: "bottomRightBtn",
- BOTTOM_LEFT_BTN: "bottomLeftBtn"
- };
- const HIT_DISTANCE = 10;
- const checkIsAtMultiSegment = (segments, rp) => {
- let res = false;
- segments.forEach((seg) => {
- if (res)
- return;
- if (checkIsAtSegment(rp.x, rp.y, ...seg, HIT_DISTANCE)) {
- res = true;
- }
- });
- return res;
- };
- const checkIsAtRectangleEdge = (element, rp) => {
- let { x, y, width, height } = element;
- let segments = [
- [x, y, x + width, y],
- [x + width, y, x + width, y + height],
- [x + width, y + height, x, y + height],
- [x, y + height, x, y]
- ];
- return checkIsAtMultiSegment(segments, rp) ? element : null;
- };
- const checkIsAtRectangleInner = (element, rp) => {
- return checkPointIsInRectangle(rp.x, rp.y, element) ? element : null;
- };
- const getCircleRadius = (width, height) => {
- return Math.min(Math.abs(width), Math.abs(height)) / 2;
- };
- const checkIsAtCircleEdge = (element, rp) => {
- let { width, height, x, y } = element;
- let radius = getCircleRadius(width, height);
- let dis = getTowPointDistance(rp.x, rp.y, x + radius, y + radius);
- let onCircle = dis >= radius - HIT_DISTANCE && dis <= radius + HIT_DISTANCE;
- return onCircle ? element : null;
- };
- const checkIsAtLineEdge = (element, rp) => {
- let segments = [];
- let len = element.pointArr.length;
- let arr = element.pointArr;
- for (let i = 0; i < len - 1; i++) {
- segments.push([...arr[i], ...arr[i + 1]]);
- }
- return checkIsAtMultiSegment(segments, rp) ? element : null;
- };
- const checkIsAtFreedrawLineEdge = (element, rp) => {
- let res = null;
- element.pointArr.forEach((point) => {
- if (res)
- return;
- let dis = getTowPointDistance(rp.x, rp.y, point[0], point[1]);
- if (dis <= HIT_DISTANCE) {
- res = element;
- }
- });
- return res;
- };
- const checkIsAtDiamondEdge = (element, rp) => {
- let { x, y, width, height } = element;
- let segments = [
- [x + width / 2, y, x + width, y + height / 2],
- [x + width, y + height / 2, x + width / 2, y + height],
- [x + width / 2, y + height, x, y + height / 2],
- [x, y + height / 2, x + width / 2, y]
- ];
- return checkIsAtMultiSegment(segments, rp) ? element : null;
- };
- const checkIsAtTriangleEdge = (element, rp) => {
- let { x, y, width, height } = element;
- let segments = [
- [x + width / 2, y, x + width, y + height],
- [x + width, y + height, x, y + height],
- [x, y + height, x + width / 2, y]
- ];
- return checkIsAtMultiSegment(segments, rp) ? element : null;
- };
- const checkIsAtArrowEdge = (element, rp) => {
- let pointArr = element.pointArr;
- let x = pointArr[0][0];
- let y = pointArr[0][1];
- let tx = pointArr[pointArr.length - 1][0];
- let ty = pointArr[pointArr.length - 1][1];
- let segments = [[x, y, tx, ty]];
- return checkIsAtMultiSegment(segments, rp) ? element : null;
- };
- var checkHit = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
- __proto__: null,
- checkIsAtMultiSegment,
- checkIsAtRectangleEdge,
- checkIsAtRectangleInner,
- getCircleRadius,
- checkIsAtCircleEdge,
- checkIsAtLineEdge,
- checkIsAtFreedrawLineEdge,
- checkIsAtDiamondEdge,
- checkIsAtTriangleEdge,
- checkIsAtArrowEdge
- }, Symbol.toStringTag, { value: "Module" }));
- const drawWrap = (ctx, fn, fill = false) => {
- ctx.beginPath();
- fn();
- ctx.stroke();
- if (fill) {
- ctx.fill();
- }
- };
- const drawRect = (ctx, x, y, width, height, fill = false) => {
- drawWrap(ctx, () => {
- ctx.rect(x, y, width, height);
- if (fill) {
- ctx.fillRect(x, y, width, height);
- }
- });
- };
- const drawDiamond = (ctx, x, y, width, height, fill = false) => {
- drawWrap(
- ctx,
- () => {
- ctx.moveTo(x + width / 2, y);
- ctx.lineTo(x + width, y + height / 2);
- ctx.lineTo(x + width / 2, y + height);
- ctx.lineTo(x, y + height / 2);
- ctx.closePath();
- },
- fill
- );
- };
- const drawTriangle = (ctx, x, y, width, height, fill = false) => {
- drawWrap(
- ctx,
- () => {
- ctx.moveTo(x + width / 2, y);
- ctx.lineTo(x + width, y + height);
- ctx.lineTo(x, y + height);
- ctx.closePath();
- },
- fill
- );
- };
- const drawCircle = (ctx, x, y, r, fill = false) => {
- drawWrap(
- ctx,
- () => {
- ctx.arc(x, y, r, 0, 2 * Math.PI);
- },
- fill
- );
- };
- const drawLine = (ctx, points) => {
- drawWrap(ctx, () => {
- let first = true;
- points.forEach((point) => {
- if (first) {
- first = false;
- ctx.moveTo(point[0], point[1]);
- } else {
- ctx.lineTo(point[0], point[1]);
- }
- });
- });
- };
- const drawArrow = (ctx, pointArr) => {
- let x = pointArr[0][0];
- let y = pointArr[0][1];
- let tx = pointArr[pointArr.length - 1][0];
- let ty = pointArr[pointArr.length - 1][1];
- drawWrap(
- ctx,
- () => {
- ctx.moveTo(x, y);
- ctx.lineTo(tx, ty);
- },
- true
- );
- let l = 30;
- let deg = 30;
- let lineDeg = radToDeg(Math.atan2(ty - y, tx - x));
- drawWrap(
- ctx,
- () => {
- let plusDeg = deg - lineDeg;
- let _x = tx - l * Math.cos(degToRad(plusDeg));
- let _y = ty + l * Math.sin(degToRad(plusDeg));
- ctx.moveTo(_x, _y);
- ctx.lineTo(tx, ty);
- },
- true
- );
- drawWrap(ctx, () => {
- let plusDeg = 90 - lineDeg - deg;
- let _x = tx - l * Math.sin(degToRad(plusDeg));
- let _y = ty - l * Math.cos(degToRad(plusDeg));
- ctx.moveTo(_x, _y);
- ctx.lineTo(tx, ty);
- });
- };
- const transformFreeLinePoint = (point, opt) => {
- let { x, y } = opt.app.coordinate.transform(point[0], point[1]);
- return [x - opt.cx, y - opt.cy, ...point.slice(2)];
- };
- const drawFreeLine = (ctx, points, opt) => {
- for (let i = 0; i < points.length - 1; i++) {
- drawWrap(
- ctx,
- () => {
- let point = transformFreeLinePoint(points[i], opt);
- let nextPoint = transformFreeLinePoint(points[i + 1], opt);
- drawLineSegment(
- ctx,
- point[0],
- point[1],
- nextPoint[0],
- nextPoint[1],
- nextPoint[2]
- );
- },
- true
- );
- }
- };
- const drawLineSegment = (ctx, mx, my, tx, ty, lineWidth = 0) => {
- drawWrap(ctx, () => {
- if (lineWidth > 0) {
- ctx.lineWidth = lineWidth;
- }
- ctx.moveTo(mx, my);
- ctx.lineTo(tx, ty);
- ctx.lineCap = "round";
- ctx.lineJoin = "round";
- });
- };
- const drawText = (ctx, textObj, x, y, width, height) => {
- let { text, style } = textObj;
- let lineHeight = style.fontSize * style.lineHeightRatio;
- drawWrap(ctx, () => {
- ctx.font = getFontString(style.fontSize, style.fontFamily);
- ctx.textBaseline = "middle";
- let textArr = splitTextLines(text);
- textArr.forEach((textRow, index) => {
- ctx.fillText(textRow, x, y + (index * lineHeight + lineHeight / 2));
- });
- });
- };
- const drawImage = (ctx, element, x, y, width, height) => {
- drawWrap(ctx, () => {
- let ratio = width / height;
- let showWidth = 0;
- let showHeight = 0;
- if (ratio > element.ratio) {
- showHeight = height;
- showWidth = element.ratio * height;
- } else {
- showWidth = width;
- showHeight = width / element.ratio;
- }
- ctx.drawImage(element.imageObj, x, y, showWidth, showHeight);
- });
- };
- var draw = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
- __proto__: null,
- drawWrap,
- drawRect,
- drawDiamond,
- drawTriangle,
- drawCircle,
- drawLine,
- drawArrow,
- drawFreeLine,
- drawLineSegment,
- drawText,
- drawImage
- }, Symbol.toStringTag, { value: "Module" }));
- class Coordinate {
- constructor(app) {
- this.app = app;
- }
- addScrollY(y) {
- return y + this.app.state.scrollY;
- }
- addScrollX(x) {
- return x + this.app.state.scrollX;
- }
- subScrollY(y) {
- return y - this.app.state.scrollY;
- }
- subScrollX(x) {
- return x - this.app.state.scrollX;
- }
- transformToCanvasCoordinate(x, y) {
- x -= this.app.width / 2;
- y -= this.app.height / 2;
- return {
- x,
- y
- };
- }
- transformToScreenCoordinate(x, y) {
- x += this.app.width / 2;
- y += this.app.height / 2;
- return {
- x,
- y
- };
- }
- transform(x, y) {
- let t = this.transformToCanvasCoordinate(x, y);
- return {
- x: this.subScrollX(t.x),
- y: this.subScrollY(t.y)
- };
- }
- windowToContainer(x, y) {
- return {
- x: x - this.app.left,
- y: y - this.app.top
- };
- }
- containerToWindow(x, y) {
- return {
- x: x + this.app.left,
- y: y + this.app.top
- };
- }
- scale(x, y) {
- let { state } = this.app;
- let wp = this.transformToCanvasCoordinate(x, y);
- let sp = this.transformToScreenCoordinate(
- wp.x * state.scale,
- wp.y * state.scale
- );
- return {
- x: sp.x,
- y: sp.y
- };
- }
- reverseScale(x, y) {
- let { state } = this.app;
- let tp = this.transformToCanvasCoordinate(x, y);
- let sp = this.transformToScreenCoordinate(
- tp.x / state.scale,
- tp.y / state.scale
- );
- return {
- x: sp.x,
- y: sp.y
- };
- }
- gridAdsorbent(x, y) {
- let { gridConfig, showGrid } = this.app.state;
- if (!showGrid) {
- return {
- x,
- y
- };
- }
- let gridSize = gridConfig.size;
- return {
- x: x - x % gridSize,
- y: y - y % gridSize
- };
- }
- }
- class Event extends EventEmitter {
- constructor(app) {
- super();
- this.app = app;
- this.coordinate = app.coordinate;
- this.isMousedown = false;
- this.mousedownPos = {
- x: 0,
- y: 0,
- unGridClientX: 0,
- unGridClientY: 0,
- originClientX: 0,
- originClientY: 0
- };
- this.mouseOffset = {
- x: 0,
- y: 0,
- originX: 0,
- originY: 0
- };
- this.lastMousePos = {
- x: 0,
- y: 0
- };
- this.mouseDistance = 0;
- this.lastMouseTime = Date.now();
- this.mouseDuration = 0;
- this.mouseSpeed = 0;
- this.onMousedown = this.onMousedown.bind(this);
- this.onMousemove = this.onMousemove.bind(this);
- this.onMouseup = this.onMouseup.bind(this);
- this.onDblclick = this.onDblclick.bind(this);
- this.onMousewheel = this.onMousewheel.bind(this);
- this.onKeydown = this.onKeydown.bind(this);
- this.onKeyup = this.onKeyup.bind(this);
- this.onContextmenu = this.onContextmenu.bind(this);
- this.bindEvent();
- }
- bindEvent() {
- this.app.container.addEventListener("mousedown", this.onMousedown);
- this.app.container.addEventListener("mousemove", this.onMousemove);
- this.app.container.addEventListener("mouseup", this.onMouseup);
- this.app.container.addEventListener("dblclick", this.onDblclick);
- this.app.container.addEventListener("mousewheel", this.onMousewheel);
- this.app.container.addEventListener("contextmenu", this.onContextmenu);
- window.addEventListener("keydown", this.onKeydown);
- window.addEventListener("keyup", this.onKeyup);
- }
- unbindEvent() {
- this.app.container.removeEventListener("mousedown", this.onMousedown);
- this.app.container.removeEventListener("mousemove", this.onMousemove);
- this.app.container.removeEventListener("mouseup", this.onMouseup);
- this.app.container.removeEventListener("dblclick", this.onDblclick);
- this.app.container.removeEventListener("mousewheel", this.onMousewheel);
- this.app.container.removeEventListener("contextmenu", this.onContextmenu);
- window.removeEventListener("keydown", this.onKeydown);
- window.removeEventListener("keyup", this.onKeyup);
- }
- transformEvent(e) {
- let { coordinate } = this.app;
- let wp = coordinate.windowToContainer(e.clientX, e.clientY);
- let { x, y } = coordinate.reverseScale(wp.x, wp.y);
- x = coordinate.addScrollX(x);
- y = coordinate.addScrollY(y);
- let unGridClientX = x;
- let unGridClientY = y;
- let gp = coordinate.gridAdsorbent(x, y);
- let newEvent = {
- originEvent: e,
- unGridClientX,
- unGridClientY,
- clientX: gp.x,
- clientY: gp.y
- };
- return newEvent;
- }
- onMousedown(e) {
- e = this.transformEvent(e);
- this.isMousedown = true;
- this.mousedownPos.x = e.clientX;
- this.mousedownPos.y = e.clientY;
- this.mousedownPos.unGridClientX = e.unGridClientX;
- this.mousedownPos.unGridClientY = e.unGridClientY;
- this.mousedownPos.originClientX = e.originEvent.clientX;
- this.mousedownPos.originClientY = e.originEvent.clientY;
- this.emit("mousedown", e, this);
- }
- onMousemove(e) {
- e = this.transformEvent(e);
- let x = e.clientX;
- let y = e.clientY;
- if (this.isMousedown) {
- this.mouseOffset.x = x - this.mousedownPos.x;
- this.mouseOffset.y = y - this.mousedownPos.y;
- this.mouseOffset.originX = e.originEvent.clientX - this.mousedownPos.originClientX;
- this.mouseOffset.originY = e.originEvent.clientY - this.mousedownPos.originClientY;
- }
- let curTime = Date.now();
- this.mouseDuration = curTime - this.lastMouseTime;
- this.mouseDistance = getTowPointDistance(
- x,
- y,
- this.lastMousePos.x,
- this.lastMousePos.y
- );
- this.mouseSpeed = this.mouseDistance / this.mouseDuration;
- this.emit("mousemove", e, this);
- this.lastMouseTime = curTime;
- this.lastMousePos.x = x;
- this.lastMousePos.y = y;
- }
- onMouseup(e) {
- e = this.transformEvent(e);
- this.isMousedown = false;
- this.mousedownPos.x = 0;
- this.mousedownPos.y = 0;
- this.emit("mouseup", e, this);
- }
- onDblclick(e) {
- e = this.transformEvent(e);
- this.emit("dblclick", e, this);
- }
- onMousewheel(e) {
- e = this.transformEvent(e);
- this.emit("mousewheel", e.originEvent.wheelDelta < 0 ? "down" : "up");
- }
- onContextmenu(e) {
- e.stopPropagation();
- e.preventDefault();
- e = this.transformEvent(e);
- this.emit("contextmenu", e, this);
- }
- onKeydown(e) {
- this.emit("keydown", e, this);
- }
- onKeyup(e) {
- this.emit("keyup", e, this);
- }
- }
- class BaseElement extends EventEmitter {
- constructor(opts = {}, app) {
- super();
- this.app = app;
- this.groupId = opts.groupId || "";
- this.type = opts.type || "";
- this.key = createNodeKey();
- this.isCreating = true;
- this.isActive = true;
- this.isSelected = false;
- this.startX = 0;
- this.startY = 0;
- this.x = opts.x || 0;
- this.y = opts.y || 0;
- this.width = opts.width || 0;
- this.height = opts.height || 0;
- this.startRotate = 0;
- this.rotate = opts.rotate || 0;
- this.noRender = false;
- this.style = __spreadValues({
- strokeStyle: "",
- fillStyle: "",
- lineWidth: "small",
- lineDash: 0,
- globalAlpha: 1
- }, opts.style || {});
- this.dragElement = null;
- }
- serialize() {
- return {
- groupId: this.groupId,
- type: this.type,
- width: this.width,
- height: this.height,
- x: this.x,
- y: this.y,
- rotate: this.rotate,
- style: __spreadValues({}, this.style)
- };
- }
- render() {
- throw new Error("\u5B50\u7C7B\u9700\u8981\u5B9E\u73B0\u8BE5\u65B9\u6CD5\uFF01");
- }
- setGroupId(groupId) {
- this.groupId = groupId;
- }
- getGroupId() {
- return this.groupId;
- }
- removeGroupId() {
- this.groupId = "";
- }
- hasGroup() {
- return !!this.groupId;
- }
- renderDragElement() {
- if (this.isActive && !this.isCreating) {
- this.dragElement.showAll();
- this.dragElement.render();
- } else if (this.isSelected) {
- this.dragElement.onlyShowBody();
- this.dragElement.render();
- }
- }
- handleStyle(style) {
- Object.keys(style).forEach((key) => {
- if (key === "lineWidth") {
- if (style[key] === "small") {
- style[key] = 2;
- } else if (style[key] === "middle") {
- style[key] = 4;
- } else if (style[key] === "large") {
- style[key] = 6;
- }
- }
- if (style[key] === "") {
- if (this.app.state[key] !== void 0 && this.app.state[key] !== null && this.app.state[key] !== "") {
- style[key] = this.app.state[key];
- }
- }
- });
- return style;
- }
- setStyle(style = {}) {
- let _style = this.handleStyle(style);
- Object.keys(_style).forEach((key) => {
- if (key === "lineDash") {
- if (_style.lineDash > 0) {
- this.app.ctx.setLineDash([_style.lineDash]);
- }
- } else if (_style[key] !== void 0 && _style[key] !== "" && _style[key] !== null) {
- this.app.ctx[key] = _style[key];
- }
- });
- return this;
- }
- warpRender(renderFn) {
- let { x, y, width, height, rotate, style } = this;
- let { x: tx, y: ty } = this.app.coordinate.transform(x, y);
- let halfWidth = width / 2;
- let halfHeight = height / 2;
- let cx = tx + halfWidth;
- let cy = ty + halfHeight;
- this.app.ctx.save();
- this.app.ctx.translate(cx, cy);
- this.app.ctx.rotate(degToRad(rotate));
- this.setStyle(style);
- renderFn({
- halfWidth,
- halfHeight,
- tx,
- ty,
- cx,
- cy
- });
- this.app.ctx.restore();
- return this;
- }
- saveState() {
- let { rotate, x, y } = this;
- this.startRotate = rotate;
- this.startX = x;
- this.startY = y;
- return this;
- }
- move(ox, oy) {
- let { startX, startY } = this;
- this.x = startX + ox;
- this.y = startY + oy;
- this.emit("elementPositionChange", this.x, this.y);
- return this;
- }
- updateRect(x, y, width, height) {
- this.updatePos(x, y);
- this.updateSize(width, height);
- return this;
- }
- updateSize(width, height) {
- this.width = width;
- this.height = height;
- this.emit("elementSizeChange", this.width, this.height);
- return this;
- }
- updatePos(x, y) {
- this.x = x;
- this.y = y;
- this.emit("elementPositionChange", this.x, this.y);
- return this;
- }
- offsetRotate(or) {
- this.updateRotate(this.startRotate + or);
- return this;
- }
- updateRotate(rotate) {
- rotate = rotate % 360;
- if (rotate < 0) {
- rotate = 360 + rotate;
- }
- this.rotate = parseInt(rotate);
- this.emit("elementRotateChange", this.rotate);
- }
- rotateByCenter(rotate, cx, cy) {
- this.offsetRotate(rotate);
- let np = getRotatedPoint(this.startX, this.startY, cx, cy, rotate);
- this.updatePos(np.x, np.y);
- }
- isHit(x, y) {
- throw new Error("\u5B50\u7C7B\u9700\u8981\u5B9E\u73B0\u8BE5\u65B9\u6CD5!");
- }
- startResize(resizeType, e) {
- this.dragElement.startResize(resizeType, e);
- return this;
- }
- endResize() {
- this.dragElement.endResize();
- return this;
- }
- resize(...args) {
- this.dragElement.handleResizeElement(...args);
- return this;
- }
- getEndpointList() {
- return getElementCorners(this);
- }
- }
- class DragElement extends BaseElement {
- constructor(element, app, opts = {}) {
- super(
- {
- type: "dragElement",
- notNeedDragElement: true
- },
- app
- );
- this.opts = __spreadValues({
- lockRatio: false
- }, opts);
- this.style = {
- strokeStyle: this.app.state.dragStrokeStyle,
- fillStyle: "transparent",
- lineWidth: "small",
- lineDash: 0,
- globalAlpha: 1
- };
- this.element = element;
- this.offset = 5;
- this.size = 10;
- this.resizeType = "";
- this.diagonalPoint = {
- x: 0,
- y: 0
- };
- this.mousedownPosAndElementPosOffset = {
- x: 0,
- y: 0
- };
- this.elementRatio = 0;
- this.hideParts = [];
- }
- setHideParts(parts = []) {
- this.hideParts = parts;
- }
- showAll() {
- this.setHideParts([]);
- }
- onlyShowBody() {
- this.setHideParts([
- DRAG_ELEMENT_PARTS.ROTATE,
- DRAG_ELEMENT_PARTS.TOP_LEFT_BTN,
- DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN,
- DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN,
- DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN
- ]);
- }
- update() {
- this.x = this.element.x - this.offset;
- this.y = this.element.y - this.offset;
- this.width = this.element.width + this.offset * 2;
- this.height = this.element.height + this.offset * 2;
- this.rotate = this.element.rotate;
- }
- render() {
- if (this.element.hasGroup())
- return;
- this.update();
- let { width, height } = this;
- this.warpRender(({ halfWidth, halfHeight }) => {
- this.app.ctx.save();
- if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.BODY)) {
- this.app.ctx.setLineDash([5]);
- drawRect(this.app.ctx, -halfWidth, -halfHeight, width, height);
- this.app.ctx.restore();
- }
- if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.TOP_LEFT_BTN)) {
- drawRect(
- this.app.ctx,
- -halfWidth - this.size,
- -halfHeight - this.size,
- this.size,
- this.size
- );
- }
- if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN)) {
- drawRect(
- this.app.ctx,
- -halfWidth + this.element.width + this.size,
- -halfHeight - this.size,
- this.size,
- this.size
- );
- }
- if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN)) {
- drawRect(
- this.app.ctx,
- -halfWidth + this.element.width + this.size,
- -halfHeight + this.element.height + this.size,
- this.size,
- this.size
- );
- }
- if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN)) {
- drawRect(
- this.app.ctx,
- -halfWidth - this.size,
- -halfHeight + this.element.height + this.size,
- this.size,
- this.size
- );
- }
- if (!this.hideParts.includes(DRAG_ELEMENT_PARTS.ROTATE)) {
- drawCircle(
- this.app.ctx,
- -halfWidth + this.element.width / 2 + this.size / 2,
- -halfHeight - this.size * 2,
- this.size
- );
- }
- });
- }
- checkPointInDragElementWhere(x, y) {
- let part = "";
- let rp = transformPointOnElement(x, y, this.element);
- if (checkPointIsInRectangle(rp.x, rp.y, this)) {
- part = DRAG_ELEMENT_PARTS.BODY;
- } else if (getTowPointDistance(
- rp.x,
- rp.y,
- this.x + this.width / 2,
- this.y - this.size * 2
- ) <= this.size) {
- part = DRAG_ELEMENT_PARTS.ROTATE;
- } else if (this._checkPointIsInBtn(rp.x, rp.y, CORNERS.TOP_LEFT)) {
- part = DRAG_ELEMENT_PARTS.TOP_LEFT_BTN;
- } else if (this._checkPointIsInBtn(rp.x, rp.y, CORNERS.TOP_RIGHT)) {
- part = DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN;
- } else if (this._checkPointIsInBtn(rp.x, rp.y, CORNERS.BOTTOM_RIGHT)) {
- part = DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN;
- } else if (this._checkPointIsInBtn(rp.x, rp.y, CORNERS.BOTTOM_LEFT)) {
- part = DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN;
- }
- if (this.hideParts.includes(part)) {
- part = "";
- }
- return part;
- }
- _checkPointIsInBtn(x, y, dir) {
- let _x = 0;
- let _y = 0;
- switch (dir) {
- case CORNERS.TOP_LEFT:
- _x = this.x - this.size;
- _y = this.y - this.size;
- break;
- case CORNERS.TOP_RIGHT:
- _x = this.x + this.width;
- _y = this.y - this.size;
- break;
- case CORNERS.BOTTOM_RIGHT:
- _x = this.x + this.width;
- _y = this.y + this.height;
- break;
- case CORNERS.BOTTOM_LEFT:
- _x = this.x - this.size;
- _y = this.y + this.height;
- break;
- }
- return checkPointIsInRectangle(x, y, _x, _y, this.size, this.size);
- }
- startResize(resizeType, e) {
- this.resizeType = resizeType;
- if (this.opts.lockRatio) {
- this.elementRatio = this.element.width / this.element.height;
- }
- if (resizeType === DRAG_ELEMENT_PARTS.BODY) {
- this.element.saveState();
- } else if (resizeType === DRAG_ELEMENT_PARTS.ROTATE) {
- this.element.saveState();
- } else if (resizeType === DRAG_ELEMENT_PARTS.TOP_LEFT_BTN) {
- this.handleDragMousedown(e, CORNERS.TOP_LEFT);
- } else if (resizeType === DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN) {
- this.handleDragMousedown(e, CORNERS.TOP_RIGHT);
- } else if (resizeType === DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN) {
- this.handleDragMousedown(e, CORNERS.BOTTOM_RIGHT);
- } else if (resizeType === DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN) {
- this.handleDragMousedown(e, CORNERS.BOTTOM_LEFT);
- }
- }
- endResize() {
- this.resizeType = "";
- this.diagonalPoint = {
- x: 0,
- y: 0
- };
- this.mousedownPosAndElementPosOffset = {
- x: 0,
- y: 0
- };
- this.elementRatio = 0;
- }
- handleDragMousedown(e, corner) {
- let centerPos = getElementCenterPoint(this.element);
- let pos = getElementRotatedCornerPoint(this.element, corner);
- this.diagonalPoint.x = 2 * centerPos.x - pos.x;
- this.diagonalPoint.y = 2 * centerPos.y - pos.y;
- this.mousedownPosAndElementPosOffset.x = e.clientX - pos.x;
- this.mousedownPosAndElementPosOffset.y = e.clientY - pos.y;
- this.element.saveState();
- }
- handleResizeElement(e, mx, my, offsetX, offsetY) {
- let resizeType = this.resizeType;
- if (resizeType === DRAG_ELEMENT_PARTS.BODY) {
- this.handleMoveElement(offsetX, offsetY);
- } else if (resizeType === DRAG_ELEMENT_PARTS.ROTATE) {
- this.handleRotateElement(e, mx, my);
- } else if (resizeType === DRAG_ELEMENT_PARTS.TOP_LEFT_BTN) {
- this.handleStretchElement(
- e,
- (newCenter, rp) => {
- return {
- width: (newCenter.x - rp.x) * 2,
- height: (newCenter.y - rp.y) * 2
- };
- },
- (rp) => {
- return {
- x: rp.x,
- y: rp.y
- };
- },
- (newRatio, newRect) => {
- let x = newRect.x;
- let y = newRect.y;
- if (newRatio > this.elementRatio) {
- x = newRect.x + newRect.width - this.elementRatio * newRect.height;
- } else if (newRatio < this.elementRatio) {
- y = newRect.y + (newRect.height - newRect.width / this.elementRatio);
- }
- return {
- x,
- y
- };
- }
- );
- } else if (resizeType === DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN) {
- this.handleStretchElement(
- e,
- (newCenter, rp) => {
- return {
- width: (rp.x - newCenter.x) * 2,
- height: (newCenter.y - rp.y) * 2
- };
- },
- (rp, newSize) => {
- return {
- x: rp.x - newSize.width,
- y: rp.y
- };
- },
- (newRatio, newRect) => {
- let x = newRect.x;
- let y = newRect.y;
- if (newRatio > this.elementRatio) {
- x = newRect.x + this.elementRatio * newRect.height;
- } else if (newRatio < this.elementRatio) {
- x = newRect.x + newRect.width;
- y = newRect.y + (newRect.height - newRect.width / this.elementRatio);
- }
- return {
- x,
- y
- };
- }
- );
- } else if (resizeType === DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN) {
- this.handleStretchElement(
- e,
- (newCenter, rp) => {
- return {
- width: (rp.x - newCenter.x) * 2,
- height: (rp.y - newCenter.y) * 2
- };
- },
- (rp, newSize) => {
- return {
- x: rp.x - newSize.width,
- y: rp.y - newSize.height
- };
- },
- (newRatio, newRect) => {
- let x = newRect.x;
- let y = newRect.y;
- if (newRatio > this.elementRatio) {
- x = newRect.x + this.elementRatio * newRect.height;
- y = newRect.y + newRect.height;
- } else if (newRatio < this.elementRatio) {
- x = newRect.x + newRect.width;
- y = newRect.y + newRect.width / this.elementRatio;
- }
- return {
- x,
- y
- };
- }
- );
- } else if (resizeType === DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN) {
- this.handleStretchElement(
- e,
- (newCenter, rp) => {
- return {
- width: (newCenter.x - rp.x) * 2,
- height: (rp.y - newCenter.y) * 2
- };
- },
- (rp, newSize) => {
- return {
- x: rp.x,
- y: rp.y - newSize.height
- };
- },
- (newRatio, newRect) => {
- let x = newRect.x;
- let y = newRect.y;
- if (newRatio > this.elementRatio) {
- x = newRect.x + newRect.width - this.elementRatio * newRect.height;
- y = newRect.y + newRect.height;
- } else if (newRatio < this.elementRatio) {
- y = newRect.y + newRect.width / this.elementRatio;
- }
- return {
- x,
- y
- };
- }
- );
- }
- }
- handleMoveElement(offsetX, offsetY) {
- this.element.move(offsetX, offsetY);
- }
- handleRotateElement(e, mx, my) {
- let centerPos = getElementCenterPoint(this.element);
- let rotate = getTowPointRotate(
- centerPos.x,
- centerPos.y,
- e.clientX,
- e.clientY,
- mx,
- my
- );
- this.element.offsetRotate(rotate);
- }
- stretchCalc(x, y, calcSize, calcPos) {
- let newCenter = {
- x: (x + this.diagonalPoint.x) / 2,
- y: (y + this.diagonalPoint.y) / 2
- };
- let rp = transformPointReverseRotate(
- x,
- y,
- newCenter.x,
- newCenter.y,
- this.element.rotate
- );
- let newSize = calcSize(newCenter, rp);
- let isWidthReverse = false;
- if (newSize.width < 0) {
- newSize.width = 0;
- isWidthReverse = true;
- }
- let isHeightReverse = false;
- if (newSize.height < 0) {
- newSize.height = 0;
- isHeightReverse = true;
- }
- let newPos = calcPos(rp, newSize);
- let newRect = {
- x: newPos.x,
- y: newPos.y,
- width: newSize.width,
- height: newSize.height
- };
- if (isWidthReverse || isHeightReverse) {
- newRect.x = this.element.x;
- newRect.y = this.element.y;
- }
- return {
- newRect,
- newCenter
- };
- }
- handleStretchElement(e, calcSize, calcPos, fixPos) {
- let actClientX = e.clientX - this.mousedownPosAndElementPosOffset.x;
- let actClientY = e.clientY - this.mousedownPosAndElementPosOffset.y;
- let { newRect, newCenter } = this.stretchCalc(
- actClientX,
- actClientY,
- calcSize,
- calcPos
- );
- if (this.opts.lockRatio) {
- this.fixStretch(newRect, newCenter, calcSize, calcPos, fixPos);
- return;
- }
- this.element.updateRect(newRect.x, newRect.y, newRect.width, newRect.height);
- }
- fixStretch(newRect, newCenter, calcSize, calcPos, fixPos) {
- let newRatio = newRect.width / newRect.height;
- let fp = fixPos(newRatio, newRect);
- let rp = getRotatedPoint(
- fp.x,
- fp.y,
- newCenter.x,
- newCenter.y,
- this.element.rotate
- );
- let fixNewRect = this.stretchCalc(rp.x, rp.y, calcSize, calcPos).newRect;
- if (fixNewRect.width === 0 && fixNewRect.height === 0) {
- return;
- }
- this.element.updateRect(
- fixNewRect.x,
- fixNewRect.y,
- fixNewRect.width,
- fixNewRect.height
- );
- }
- }
- class Rectangle extends BaseElement {
- constructor(...args) {
- super(...args);
- this.dragElement = new DragElement(this, this.app);
- }
- render() {
- let { width, height } = this;
- this.warpRender(({ halfWidth, halfHeight }) => {
- drawRect(this.app.ctx, -halfWidth, -halfHeight, width, height, true);
- });
- this.renderDragElement();
- }
- isHit(x, y) {
- let rp = transformPointOnElement(x, y, this);
- return checkIsAtRectangleEdge(this, rp);
- }
- }
- class Circle extends BaseElement {
- constructor(...args) {
- super(...args);
- this.dragElement = new DragElement(this, this.app, {
- lockRatio: true
- });
- }
- render() {
- let { width, height } = this;
- this.warpRender(({ halfWidth, halfHeight }) => {
- drawCircle(this.app.ctx, 0, 0, getCircleRadius(width, height), true);
- });
- this.renderDragElement();
- }
- isHit(x, y) {
- let rp = transformPointOnElement(x, y, this);
- return checkIsAtCircleEdge(this, rp);
- }
- }
- class Diamond extends BaseElement {
- constructor(...args) {
- super(...args);
- this.dragElement = new DragElement(this, this.app);
- }
- render() {
- let { width, height } = this;
- this.warpRender(({ halfWidth, halfHeight }) => {
- drawDiamond(this.app.ctx, -halfWidth, -halfHeight, width, height, true);
- });
- this.renderDragElement();
- }
- isHit(x, y) {
- let rp = transformPointOnElement(x, y, this);
- return checkIsAtDiamondEdge(this, rp);
- }
- getEndpointList() {
- let { x, y, width, height, rotate } = this;
- let points = [
- [x + width / 2, y],
- [x + width, y + height / 2],
- [x + width / 2, y + height],
- [x, y + height / 2]
- ];
- let center = getElementCenterPoint(this);
- return points.map((point) => {
- return getRotatedPoint(point[0], point[1], center.x, center.y, rotate);
- });
- }
- }
- class Triangle extends BaseElement {
- constructor(...args) {
- super(...args);
- this.dragElement = new DragElement(this, this.app);
- }
- render() {
- let { width, height } = this;
- this.warpRender(({ halfWidth, halfHeight }) => {
- drawTriangle(this.app.ctx, -halfWidth, -halfHeight, width, height, true);
- });
- this.renderDragElement();
- }
- isHit(x, y) {
- let rp = transformPointOnElement(x, y, this);
- return checkIsAtTriangleEdge(this, rp);
- }
- getEndpointList() {
- let { x, y, width, height, rotate } = this;
- let points = [
- [x + width / 2, y],
- [x + width, y + height],
- [x, y + height]
- ];
- let center = getElementCenterPoint(this);
- return points.map((point) => {
- return getRotatedPoint(point[0], point[1], center.x, center.y, rotate);
- });
- }
- }
- class BaseMultiPointElement extends BaseElement {
- constructor(opts = {}, app) {
- super(opts, app);
- this.startPointArr = [];
- this.pointArr = opts.pointArr || [];
- this.startWidth = 0;
- this.startHeight = 0;
- this.fictitiousPoint = {
- x: 0,
- y: 0
- };
- }
- serialize() {
- let base = super.serialize();
- return __spreadProps(__spreadValues({}, base), {
- pointArr: [...this.pointArr]
- });
- }
- addPoint(x, y, ...args) {
- if (!Array.isArray(this.pointArr)) {
- return;
- }
- this.pointArr.push([x, y, ...args]);
- return this;
- }
- updateMultiPointBoundingRect() {
- let rect = getBoundingRect(this.pointArr);
- this.x = rect.x;
- this.y = rect.y;
- this.width = rect.width;
- this.height = rect.height;
- return this;
- }
- updateFictitiousPoint(x, y) {
- this.fictitiousPoint.x = x;
- this.fictitiousPoint.y = y;
- }
- saveState() {
- let { rotate, x, y, width, height, pointArr } = this;
- this.startRotate = rotate;
- this.startX = x;
- this.startY = y;
- this.startPointArr = deepCopy(pointArr);
- this.startWidth = width;
- this.startHeight = height;
- return this;
- }
- move(ox, oy) {
- this.pointArr = this.startPointArr.map((point) => {
- return [point[0] + ox, point[1] + oy, ...point.slice(2)];
- });
- let { startX, startY } = this;
- this.x = startX + ox;
- this.y = startY + oy;
- return this;
- }
- updateRect(x, y, width, height) {
- let { startWidth, startHeight, startPointArr } = this;
- let scaleX = width / startWidth;
- let scaleY = height / startHeight;
- this.pointArr = startPointArr.map((point) => {
- let nx = point[0] * scaleX;
- let ny = point[1] * scaleY;
- return [nx, ny, ...point.slice(2)];
- });
- let rect = getBoundingRect(this.pointArr);
- let offsetX = rect.x - x;
- let offsetY = rect.y - y;
- this.pointArr = this.pointArr.map((point) => {
- return [point[0] - offsetX, point[1] - offsetY, ...point.slice(2)];
- });
- this.updatePos(x, y);
- this.updateSize(width, height);
- return this;
- }
- rotateByCenter(rotate, cx, cy) {
- this.pointArr = this.startPointArr.map((point) => {
- let np = getRotatedPoint(point[0], point[1], cx, cy, rotate);
- return [np.x, np.y, ...point.slice(2)];
- });
- this.updateMultiPointBoundingRect();
- }
- getEndpointList() {
- return this.pointArr.map((point) => {
- let center = getElementCenterPoint(this);
- let np = getRotatedPoint(
- point[0],
- point[1],
- center.x,
- center.y,
- this.rotate
- );
- return {
- x: np.x,
- y: np.y
- };
- });
- }
- }
- class Freedraw extends BaseMultiPointElement {
- constructor(...args) {
- super(...args);
- this.dragElement = new DragElement(this, this.app);
- this.lastLineWidth = -1;
- }
- render() {
- let { pointArr } = this;
- this.warpRender(({ cx, cy }) => {
- drawFreeLine(this.app.ctx, pointArr, {
- app: this.app,
- cx,
- cy
- });
- });
- this.renderDragElement();
- }
- isHit(x, y) {
- let rp = transformPointOnElement(x, y, this);
- return checkIsAtFreedrawLineEdge(this, rp);
- }
- singleRender(mx, my, tx, ty, lineWidth) {
- this.app.ctx.save();
- this.setStyle(this.style);
- drawLineSegment(this.app.ctx, mx, my, tx, ty, lineWidth);
- this.app.ctx.restore();
- }
- }
- class Arrow extends BaseMultiPointElement {
- constructor(...args) {
- super(...args);
- this.dragElement = new DragElement(this, this.app);
- }
- render() {
- let { pointArr, fictitiousPoint } = this;
- this.warpRender(({ cx, cy }) => {
- let realtimePoint = [];
- if (pointArr.length > 0 && this.isCreating) {
- let { x: fx, y: fy } = this.app.coordinate.transform(
- fictitiousPoint.x - cx,
- fictitiousPoint.y - cy
- );
- realtimePoint = [[fx, fy]];
- }
- drawArrow(
- this.app.ctx,
- pointArr.map((point) => {
- let { x, y } = this.app.coordinate.transform(point[0], point[1]);
- return [x - cx, y - cy];
- }).concat(realtimePoint)
- );
- });
- this.renderDragElement();
- }
- isHit(x, y) {
- let rp = transformPointOnElement(x, y, this);
- return checkIsAtArrowEdge(this, rp);
- }
- }
- class Image$1 extends BaseElement {
- constructor(opts = {}, app) {
- super(opts, app);
- this.dragElement = new DragElement(this, this.app, {
- lockRatio: true
- });
- this.url = opts.url || "";
- this.imageObj = opts.imageObj || null;
- this.ratio = opts.ratio || 1;
- }
- serialize() {
- let base = super.serialize();
- return __spreadProps(__spreadValues({}, base), {
- url: this.url,
- ratio: this.ratio
- });
- }
- render() {
- let { width, height } = this;
- this.warpRender(({ halfWidth, halfHeight }) => {
- drawImage(this.app.ctx, this, -halfWidth, -halfHeight, width, height);
- });
- this.renderDragElement();
- }
- isHit(x, y) {
- let rp = transformPointOnElement(x, y, this);
- return checkIsAtRectangleInner(this, rp);
- }
- }
- class Line extends BaseMultiPointElement {
- constructor(opts = {}, app) {
- super(opts, app);
- this.dragElement = new DragElement(this, this.app);
- this.isSingle = opts.isSingle;
- }
- render() {
- let { pointArr, fictitiousPoint } = this;
- this.warpRender(({ cx, cy }) => {
- let realtimePoint = [];
- if (pointArr.length > 0 && this.isCreating) {
- let { x: fx, y: fy } = this.app.coordinate.transform(
- fictitiousPoint.x - cx,
- fictitiousPoint.y - cy
- );
- realtimePoint = [[fx, fy]];
- }
- drawLine(
- this.app.ctx,
- pointArr.map((point) => {
- let { x, y } = this.app.coordinate.transform(point[0], point[1]);
- return [x - cx, y - cy];
- }).concat(realtimePoint)
- );
- });
- this.renderDragElement();
- }
- isHit(x, y) {
- let rp = transformPointOnElement(x, y, this);
- return checkIsAtLineEdge(this, rp);
- }
- }
- class Text extends BaseElement {
- constructor(opts = {}, app) {
- var _a, _b, _c, _d;
- super(opts, app);
- this.dragElement = new DragElement(this, this.app, {
- lockRatio: true
- });
- this.text = opts.text || "";
- this.style.fillStyle = ((_a = opts.style) == null ? void 0 : _a.fillStyle) || this.app.state.strokeStyle || "#000";
- this.style.fontSize = ((_b = opts.style) == null ? void 0 : _b.fontSize) || this.app.state.fontSize || 18;
- this.style.lineHeightRatio = ((_c = opts.style) == null ? void 0 : _c.lineHeightRatio) || 1.5;
- this.style.fontFamily = ((_d = opts.style) == null ? void 0 : _d.fontFamily) || this.app.state.fontFamily || "\u5FAE\u8F6F\u96C5\u9ED1, Microsoft YaHei";
- }
- serialize() {
- let base = super.serialize();
- return __spreadProps(__spreadValues({}, base), {
- text: this.text
- });
- }
- render() {
- this.warpRender(({ halfWidth, halfHeight }) => {
- drawText(this.app.ctx, this, -halfWidth, -halfHeight);
- });
- this.renderDragElement();
- }
- isHit(x, y) {
- let rp = transformPointOnElement(x, y, this);
- return checkIsAtRectangleInner(this, rp);
- }
- updateRect(x, y, width, height) {
- let { text, style } = this;
- let fontSize = Math.floor(
- height / splitTextLines(text).length / style.lineHeightRatio
- );
- this.style.fontSize = fontSize;
- super.updateRect(x, y, width, height);
- }
- updateTextSize() {
- let { width, height } = getTextElementSize(this);
- this.width = width;
- this.height = height;
- }
- }
- class Elements$1 {
- constructor(app) {
- this.app = app;
- this.elementList = [];
- this.activeElement = null;
- this.isCreatingElement = false;
- this.isResizing = false;
- this.resizingElement = null;
- this.handleResize = throttle(this.handleResize, this, 16);
- }
- serialize(stringify = false) {
- let data = this.elementList.map((element) => {
- return element.serialize();
- });
- return stringify ? JSON.stringify(data) : data;
- }
- getElementsNum() {
- return this.elementList.length;
- }
- hasElements() {
- return this.elementList.length > 0;
- }
- addElement(element) {
- this.elementList.push(element);
- return this;
- }
- unshiftElement(element) {
- this.elementList.unshift(element);
- return this;
- }
- insertElement(element, index) {
- this.elementList.splice(index, 0, element);
- }
- deleteElement(element) {
- let index = this.getElementIndex(element);
- if (index !== -1) {
- this.elementList.splice(index, 1);
- if (element.isActive) {
- this.cancelActiveElement(element);
- }
- }
- return this;
- }
- deleteAllElements() {
- this.activeElement = null;
- this.elementList = [];
- this.isCreatingElement = false;
- this.isResizing = false;
- this.resizingElement = null;
- return this;
- }
- getElementIndex(element) {
- return this.elementList.findIndex((item) => {
- return item === element;
- });
- }
- createElementsFromData(data) {
- data.forEach((item) => {
- let element = this.pureCreateElement(item);
- element.isActive = false;
- element.isCreating = false;
- this.addElement(element);
- });
- this.app.group.initIdToElementList(this.elementList);
- return this;
- }
- hasActiveElement() {
- return !!this.activeElement;
- }
- setActiveElement(element) {
- this.cancelActiveElement();
- this.activeElement = element;
- if (element) {
- element.isActive = true;
- }
- this.app.emit("activeElementChange", this.activeElement);
- return this;
- }
- cancelActiveElement() {
- if (!this.hasActiveElement()) {
- return this;
- }
- this.activeElement.isActive = false;
- this.activeElement = null;
- this.app.emit("activeElementChange", this.activeElement);
- return this;
- }
- checkIsHitElement(e) {
- let x = e.unGridClientX;
- let y = e.unGridClientY;
- for (let i = this.elementList.length - 1; i >= 0; i--) {
- let element = this.elementList[i];
- if (element.isHit(x, y)) {
- return element;
- }
- }
- return null;
- }
- pureCreateElement(opts = {}) {
- switch (opts.type) {
- case "rectangle":
- return new Rectangle(opts, this.app);
- case "diamond":
- return new Diamond(opts, this.app);
- case "triangle":
- return new Triangle(opts, this.app);
- case "circle":
- return new Circle(opts, this.app);
- case "freedraw":
- return new Freedraw(opts, this.app);
- case "image":
- return new Image$1(opts, this.app);
- case "arrow":
- return new Arrow(opts, this.app);
- case "line":
- return new Line(opts, this.app);
- case "text":
- return new Text(opts, this.app);
- default:
- return null;
- }
- }
- createElement(opts = {}, callback = () => {
- }, ctx = null, notActive) {
- if (this.hasActiveElement() || this.isCreatingElement) {
- return this;
- }
- let element = this.pureCreateElement(opts);
- if (!element) {
- return this;
- }
- this.addElement(element);
- if (!notActive) {
- this.setActiveElement(element);
- }
- this.isCreatingElement = true;
- callback.call(ctx, element);
- return this;
- }
- copyElement(element, notActive = false, pos) {
- return new Promise((resolve) => __async(this, null, function* () {
- if (!element) {
- return resolve();
- }
- let data = this.app.group.handleCopyElementData(element.serialize());
- if (data.type === "image") {
- data.imageObj = yield createImageObj(data.url);
- }
- if (data.type === "text") {
- if (typeof data.text === "string") {
- if (isNumeric$1(data.text)) {
- const num = parseFloat(data.text);
- const incrementedNum = num + 1;
- data.text = incrementedNum.toString(10).padStart(data.text.length, "0");
- }
- }
- }
- this.createElement(
- data,
- (element2) => {
- this.app.group.handleCopyElement(element2);
- element2.startResize(DRAG_ELEMENT_PARTS.BODY);
- let ox = 20;
- let oy = 20;
- if (pos) {
- ox = pos.x - element2.x - element2.width / 2;
- oy = pos.y - element2.y - element2.height / 2;
- }
- let gridAdsorbentPos = this.app.coordinate.gridAdsorbent(ox, oy);
- element2.resize(
- null,
- null,
- null,
- gridAdsorbentPos.x,
- gridAdsorbentPos.y
- );
- element2.isCreating = false;
- if (notActive) {
- element2.isActive = false;
- }
- this.isCreatingElement = false;
- resolve(element2);
- },
- this,
- notActive
- );
- }));
- }
- creatingRectangleLikeElement(type, x, y, offsetX, offsetY) {
- this.createElement({
- type,
- x,
- y,
- width: offsetX,
- height: offsetY
- });
- this.activeElement.updateSize(offsetX, offsetY);
- }
- creatingCircle(x, y, e) {
- this.createElement({
- type: "circle",
- x,
- y
- });
- let radius = getTowPointDistance(e.clientX, e.clientY, x, y);
- this.activeElement.updateSize(radius, radius);
- }
- creatingFreedraw(e, event) {
- this.createElement({
- type: "freedraw"
- });
- let element = this.activeElement;
- let lineWidth = computedLineWidthBySpeed(
- event.mouseSpeed,
- element.lastLineWidth
- );
- element.lastLineWidth = lineWidth;
- element.addPoint(e.clientX, e.clientY, lineWidth);
- let { coordinate, ctx, state } = this.app;
- let tfp = coordinate.transformToCanvasCoordinate(
- coordinate.subScrollX(event.lastMousePos.x),
- coordinate.subScrollY(event.lastMousePos.y)
- );
- let ttp = coordinate.transformToCanvasCoordinate(
- coordinate.subScrollX(e.clientX),
- coordinate.subScrollY(e.clientY)
- );
- ctx.save();
- ctx.scale(state.scale, state.scale);
- element.singleRender(tfp.x, tfp.y, ttp.x, ttp.y, lineWidth);
- ctx.restore();
- }
- creatingImage(e, { width, height, imageObj, url, ratio }) {
- let gp = this.app.coordinate.gridAdsorbent(
- e.unGridClientX - width / 2,
- e.unGridClientY - height / 2
- );
- this.createElement({
- type: "image",
- x: gp.x,
- y: gp.y,
- url,
- imageObj,
- width,
- height,
- ratio
- });
- }
- editingText(element) {
- if (element.type !== "text") {
- return;
- }
- element.noRender = true;
- this.setActiveElement(element);
- }
- completeEditingText() {
- let element = this.activeElement;
- if (!element || element.type !== "text") {
- return;
- }
- if (!element.text.trim()) {
- this.deleteElement(element);
- this.setActiveElement(null);
- return;
- }
- element.noRender = false;
- }
- completeCreateArrow(e) {
- this.activeElement.addPoint(e.clientX, e.clientY);
- }
- creatingArrow(x, y, e) {
- this.createElement(
- {
- type: "arrow",
- x,
- y
- },
- (element) => {
- element.addPoint(x, y);
- }
- );
- this.activeElement.updateFictitiousPoint(e.clientX, e.clientY);
- }
- creatingLine(x, y, e, isSingle = false, notCreate = false) {
- if (!notCreate) {
- this.createElement(
- {
- type: "line",
- x,
- y,
- isSingle
- },
- (element2) => {
- element2.addPoint(x, y);
- }
- );
- }
- let element = this.activeElement;
- if (element) {
- element.updateFictitiousPoint(e.clientX, e.clientY);
- }
- }
- completeCreateLine(e, completeCallback = () => {
- }) {
- let element = this.activeElement;
- let x = e.clientX;
- let y = e.clientY;
- if (element && element.isSingle) {
- element.addPoint(x, y);
- completeCallback();
- } else {
- this.createElement({
- type: "line",
- isSingle: false
- });
- element = this.activeElement;
- element.addPoint(x, y);
- element.updateFictitiousPoint(x, y);
- }
- }
- completeCreateElement() {
- this.isCreatingElement = false;
- let element = this.activeElement;
- if (!element) {
- return this;
- }
- if (["freedraw", "arrow", "line"].includes(element.type)) {
- element.updateMultiPointBoundingRect();
- }
- element.isCreating = false;
- this.app.emitChange();
- return this;
- }
- setActiveElementStyle(style = {}) {
- if (!this.hasActiveElement()) {
- return this;
- }
- Object.keys(style).forEach((key) => {
- this.activeElement.style[key] = style[key];
- if (key === "fontSize" && this.activeElement.type === "text") {
- this.activeElement.updateTextSize();
- }
- });
- return this;
- }
- checkInResizeHand(x, y) {
- let element = this.activeElement;
- let hand = element.dragElement.checkPointInDragElementWhere(x, y);
- if (hand) {
- return {
- element,
- hand
- };
- }
- return null;
- }
- checkIsResize(x, y, e) {
- if (!this.hasActiveElement()) {
- return false;
- }
- let res = this.checkInResizeHand(x, y);
- if (res) {
- this.isResizing = true;
- this.resizingElement = res.element;
- this.resizingElement.startResize(res.hand, e);
- this.app.cursor.setResize(res.hand);
- return true;
- }
- return false;
- }
- handleResize(...args) {
- if (!this.isResizing) {
- return;
- }
- this.resizingElement.resize(...args);
- this.app.render.render();
- }
- endResize() {
- this.isResizing = false;
- this.resizingElement.endResize();
- this.resizingElement = null;
- }
- }
- function isNumeric$1(str) {
- const trimmedStr = str.trim();
- const num = Number(trimmedStr);
- return !isNaN(num) && trimmedStr === num.toString().padStart(trimmedStr.length, "0");
- }
- class ImageEdit extends EventEmitter {
- constructor(app) {
- super();
- this.app = app;
- this.el = null;
- this.isReady = false;
- this.previewEl = null;
- this.imageData = null;
- this.maxWidth = 750;
- this.maxHeight = 450;
- this.maxRatio = this.maxWidth / this.maxHeight;
- this.onImageSelectChange = this.onImageSelectChange.bind(this);
- }
- reset() {
- this.el.value = "";
- this.isReady = false;
- document.body.removeChild(this.previewEl);
- this.previewEl = null;
- this.imageData = null;
- }
- selectImage() {
- if (!this.el) {
- this.el = document.createElement("input");
- this.el.type = "file";
- this.el.accept = "image/*";
- this.el.style.position = "fixed";
- this.el.style.left = "-999999px";
- this.el.addEventListener("change", this.onImageSelectChange);
- document.body.appendChild(this.el);
- }
- this.el.click();
- }
- updatePreviewElPos(x, y) {
- let width = 100;
- let height = width / this.imageData.ratio;
- if (!this.previewEl) {
- this.previewEl = document.createElement("div");
- this.previewEl.style.position = "fixed";
- this.previewEl.style.width = width + "px";
- this.previewEl.style.height = height + "px";
- this.previewEl.style.backgroundImage = `url('${this.imageData.url}')`;
- this.previewEl.style.backgroundSize = "cover";
- this.previewEl.style.pointerEvents = "none";
- document.body.appendChild(this.previewEl);
- }
- let tp = this.app.coordinate.containerToWindow(x, y);
- this.previewEl.style.left = tp.x - width / 2 + "px";
- this.previewEl.style.top = tp.y - height / 2 + "px";
- }
- getImageSize(url) {
- return __async(this, null, function* () {
- return new Promise((resolve, reject) => {
- let img = new Image();
- img.setAttribute("crossOrigin", "anonymous");
- img.onload = () => {
- let width = img.width;
- let height = img.height;
- let ratio = img.width / img.height;
- if (img.width > this.maxWidth || img.height > this.maxHeight) {
- if (ratio > this.maxRatio) {
- width = this.maxWidth;
- height = this.maxWidth / ratio;
- } else {
- height = this.maxHeight;
- width = this.maxHeight * ratio;
- }
- }
- resolve({
- imageObj: img,
- size: {
- width,
- height
- },
- ratio
- });
- };
- img.onerror = () => {
- reject();
- };
- img.src = url;
- });
- });
- }
- onImageSelectChange(e) {
- return __async(this, null, function* () {
- let url = yield this.getImageUrl(e.target.files[0]);
- let { imageObj, size, ratio } = yield this.getImageSize(url);
- this.isReady = true;
- this.imageData = __spreadProps(__spreadValues({
- url
- }, size), {
- ratio,
- imageObj
- });
- this.emit("imageSelectChange", this.imageData);
- });
- }
- getImageUrl(file) {
- return __async(this, null, function* () {
- return new Promise((resolve, reject) => {
- let reader = new FileReader();
- reader.onloadend = () => {
- resolve(reader.result);
- };
- reader.onerror = () => {
- reject();
- };
- reader.readAsDataURL(file);
- });
- });
- }
- }
- class Cursor {
- constructor(app) {
- this.app = app;
- this.currentType = "default";
- }
- set(type = "default") {
- this.currentType = type;
- let style = type;
- if (type === "eraser") {
- style = `url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAARRJREFUOE/dlDFLxEAQhd+BVouFZ3vlQuwSyI+5a7PBRkk6k9KzTOwStJFsWv0xgaQzkNLWszim0kL2OOFc9oKRYHFTz37Lm/dmJhi5JiPzcBjAOYDz7WheADz3jalP8oIxds85P3Zd90RBqqpad133SUSXAJ5M4H3AhWVZd1EUzYQQP96VZYkkSV7btr02QY1Axtgqz/NTz/OM6qSUCMNwRURneoMJOLdt+7Gu643MfeU4zrppmgt9pibgjRBiWRRFb0R934eUcgngdrfxX4CjSwZj7C3Lsqnu8Lc05XQQBO9ENP2NKapnE5s4jme608rhNE2HxWb7qwr2A+f8SAv2BxFdDQ32rpLRVu9Pl+0wztcg6V/VPW4Vw1FsawAAAABJRU5ErkJggg==) 10 10, auto`;
- }
- this.app.container.style.cursor = style;
- }
- hide() {
- this.set("none");
- }
- reset() {
- this.set();
- }
- setCrosshair() {
- this.set("crosshair");
- }
- setMove() {
- this.set("move");
- }
- setResize(dir) {
- let type = "";
- switch (dir) {
- case DRAG_ELEMENT_PARTS.BODY:
- type = "move";
- break;
- case DRAG_ELEMENT_PARTS.ROTATE:
- type = "grab";
- break;
- case DRAG_ELEMENT_PARTS.TOP_LEFT_BTN:
- type = "nw-resize";
- break;
- case DRAG_ELEMENT_PARTS.TOP_RIGHT_BTN:
- type = "ne-resize";
- break;
- case DRAG_ELEMENT_PARTS.BOTTOM_RIGHT_BTN:
- type = "se-resize";
- break;
- case DRAG_ELEMENT_PARTS.BOTTOM_LEFT_BTN:
- type = "sw-resize";
- break;
- }
- this.set(type);
- }
- setEraser() {
- this.set("eraser");
- }
- }
- class TextEdit extends EventEmitter {
- constructor(app) {
- super();
- this.app = app;
- this.editable = null;
- this.isEditing = false;
- this.onTextInput = this.onTextInput.bind(this);
- this.onTextBlur = this.onTextBlur.bind(this);
- }
- crateTextInputEl() {
- this.editable = document.createElement("textarea");
- this.editable.dir = "auto";
- this.editable.tabIndex = 0;
- this.editable.wrap = "off";
- this.editable.className = "textInput";
- Object.assign(this.editable.style, {
- position: "fixed",
- display: "block",
- minHeight: "1em",
- backfaceVisibility: "hidden",
- margin: 0,
- padding: 0,
- border: 0,
- outline: 0,
- resize: "none",
- background: "transparent",
- overflow: "hidden",
- whiteSpace: "pre"
- });
- this.editable.addEventListener("input", this.onTextInput);
- this.editable.addEventListener("blur", this.onTextBlur);
- document.body.appendChild(this.editable);
- }
- updateTextInputStyle() {
- let activeElement = this.app.elements.activeElement;
- if (!activeElement) {
- return;
- }
- let { x, y, width, height, style, text, rotate } = activeElement;
- let { coordinate, state } = this.app;
- this.editable.value = text;
- x = coordinate.subScrollX(x);
- y = coordinate.subScrollY(y);
- let sp = coordinate.scale(x, y);
- let tp = coordinate.containerToWindow(sp.x, sp.y);
- let fontSize = style.fontSize * state.scale;
- let styles = {
- font: getFontString(fontSize, style.fontFamily),
- lineHeight: `${fontSize * style.lineHeightRatio}px`,
- left: `${tp.x}px`,
- top: `${tp.y}px`,
- color: style.fillStyle,
- width: Math.max(width, 100) * state.scale + "px",
- height: height * state.scale + "px",
- transform: `rotate(${rotate}deg)`,
- opacity: style.globalAlpha
- };
- Object.assign(this.editable.style, styles);
- }
- onTextInput() {
- let activeElement = this.app.elements.activeElement;
- if (!activeElement) {
- return;
- }
- activeElement.text = this.editable.value;
- let { width, height } = getTextElementSize(activeElement);
- activeElement.width = width;
- activeElement.height = height;
- this.updateTextInputStyle();
- }
- onTextBlur() {
- this.editable.style.display = "none";
- this.editable.value = "";
- this.emit("blur");
- this.isEditing = false;
- }
- showTextEdit() {
- if (!this.editable) {
- this.crateTextInputEl();
- } else {
- this.editable.style.display = "block";
- }
- this.updateTextInputStyle();
- this.editable.focus();
- this.editable.select();
- this.isEditing = true;
- }
- }
- class History {
- constructor(app) {
- this.app = app;
- this.historyStack = [];
- this.length = 0;
- this.index = -1;
- }
- add(data) {
- let prev = this.length > 0 ? this.historyStack[this.length - 1] : null;
- let copyData = deepCopy(data);
- if (copyData === prev) {
- return;
- }
- this.historyStack.push(copyData);
- this.length++;
- this.index = this.length - 1;
- this.emitChange();
- }
- undo() {
- if (this.index <= 0) {
- return;
- }
- this.index--;
- this.shuttle();
- }
- redo() {
- if (this.index >= this.length - 1) {
- return;
- }
- this.index++;
- this.shuttle();
- }
- shuttle() {
- return __async(this, null, function* () {
- let data = this.historyStack[this.index];
- yield this.app.setData(data, true);
- this.emitChange();
- this.app.emit("change", data);
- });
- }
- clear() {
- this.index = -1;
- this.length = 0;
- this.historyStack = [];
- this.emitChange();
- }
- emitChange() {
- this.app.emit("shuttle", this.index, this.length);
- }
- }
- class Export {
- constructor(app) {
- this.app = app;
- this.openTest = false;
- this.saveState = {
- scale: 0,
- scrollX: 0,
- scrollY: 0,
- width: 0,
- height: 0
- };
- }
- show(canvas) {
- if (this.openTest) {
- canvas.style.cssText = `
- position: absolute;
- left: 0;
- top: 0;
- background-color: #fff;
- `;
- document.body.appendChild(canvas);
- }
- }
- getElementList(onlySelected = true) {
- if (!onlySelected) {
- return this.app.elements.elementList;
- } else {
- let selectedElements = [];
- if (this.app.elements.activeElement) {
- selectedElements.push(this.app.elements.activeElement);
- } else if (this.app.selection.hasSelectionElements()) {
- selectedElements = this.app.selection.getSelectionElements();
- }
- let res = this.app.elements.elementList.filter((element) => {
- return selectedElements.includes(element);
- });
- return res;
- }
- }
- exportImage({
- type = "image/png",
- renderBg = true,
- useBlob = false,
- paddingX = 10,
- paddingY = 10,
- onlySelected
- } = {}) {
- let { minx, maxx, miny, maxy } = getMultiElementRectInfo(
- this.getElementList(onlySelected)
- );
- let width = maxx - minx + paddingX * 2;
- let height = maxy - miny + paddingY * 2;
- let { canvas, ctx } = createCanvas(width, height, {
- noStyle: true,
- noTranslate: true
- });
- this.show(canvas);
- this.saveAppState();
- this.changeAppState(minx - paddingX, miny - paddingY, ctx);
- if (renderBg && this.app.state.backgroundColor) {
- this.app.background.canvasAddBackgroundColor(
- ctx,
- width,
- height,
- this.app.state.backgroundColor
- );
- }
- this.render(ctx, onlySelected);
- this.recoveryAppState();
- if (useBlob) {
- return new Promise((resolve, reject) => {
- canvas.toBlob((blob) => {
- if (blob) {
- resolve(blob);
- } else {
- reject();
- }
- }, type);
- });
- } else {
- return canvas.toDataURL(type);
- }
- }
- saveAppState() {
- let { width, height, state, ctx } = this.app;
- this.saveState.width = width;
- this.saveState.height = height;
- this.saveState.scale = state.scale;
- this.saveState.scrollX = state.scrollX;
- this.saveState.scrollY = state.scrollY;
- this.saveState.ctx = ctx;
- }
- changeAppState(minx, miny, ctx) {
- this.app.ctx = ctx;
- this.app.state.scale = 1;
- this.app.state.scrollX = 0;
- this.app.state.scrollY = 0;
- this.app.width = minx * 2;
- this.app.height = miny * 2;
- }
- recoveryAppState() {
- let { width, height, scale, scrollX, scrollY, ctx } = this.saveState;
- this.app.state.scale = scale;
- this.app.state.scrollX = scrollX;
- this.app.state.scrollY = scrollY;
- this.app.width = width;
- this.app.height = height;
- this.app.ctx = ctx;
- }
- render(ctx, onlySelected) {
- ctx.save();
- this.getElementList(onlySelected).forEach((element) => {
- if (element.noRender) {
- return;
- }
- let cacheActive = element.isActive;
- let cacheSelected = element.isSelected;
- element.isActive = false;
- element.isSelected = false;
- element.render();
- element.isActive = cacheActive;
- element.isSelected = cacheSelected;
- });
- ctx.restore();
- }
- exportJson() {
- return this.app.getData();
- }
- }
- class Background {
- constructor(app) {
- this.app = app;
- }
- set() {
- if (this.app.state.backgroundColor) {
- this.addBackgroundColor();
- } else {
- this.remove();
- }
- }
- addBackgroundColor() {
- this.app.container.style.backgroundColor = this.app.state.backgroundColor;
- }
- remove() {
- this.app.container.style.backgroundColor = "";
- }
- canvasAddBackgroundColor(ctx, width, height, backgroundColor) {
- ctx.save();
- ctx.rect(0, 0, width, height);
- ctx.fillStyle = backgroundColor;
- ctx.fill();
- ctx.restore();
- }
- }
- class Canvas {
- constructor(width, height, opt) {
- this.width = width;
- this.height = height;
- let { canvas, ctx } = createCanvas(width, height, opt);
- this.el = canvas;
- this.ctx = ctx;
- }
- clearCanvas() {
- let { width, height } = this;
- this.ctx.clearRect(-width / 2, -height / 2, width, height);
- }
- }
- class MultiSelectElement extends BaseElement {
- constructor(opts = {}, app) {
- super(opts, app);
- this.dragElement = new DragElement(this, this.app);
- this.selectedElementList = [];
- this.wholeCenterPos = { x: 0, y: 0 };
- }
- setSelectedElementList(list) {
- this.selectedElementList.forEach((element) => {
- element.isSelected = false;
- });
- this.selectedElementList = list;
- this.selectedElementList.forEach((element) => {
- element.isSelected = true;
- });
- }
- updateElements(elements) {
- let exists = [];
- this.selectedElementList.forEach((element) => {
- if (elements.includes(element)) {
- exists.push(element);
- }
- });
- this.setSelectedElementList(exists);
- }
- updateRect() {
- if (this.selectedElementList.length <= 0) {
- super.updateRect(0, 0, 0, 0);
- return;
- }
- let { minx, maxx, miny, maxy } = getMultiElementRectInfo(
- this.selectedElementList
- );
- super.updateRect(minx, miny, maxx - minx, maxy - miny);
- }
- startResize(...args) {
- this.selectedElementList.forEach((element) => {
- if (args[0] === "rotate") {
- this.wholeCenterPos = getElementCenterPoint(this);
- }
- element.startResize(...args);
- });
- }
- resize(...args) {
- this.selectedElementList.forEach((element) => {
- if (element.dragElement.resizeType === "rotate") {
- this.handleRotate(element, ...args);
- } else {
- element.resize(...args);
- }
- });
- }
- handleRotate(element, e, mx, my, offsetX, offsetY) {
- let rotate = getTowPointRotate(
- this.wholeCenterPos.x,
- this.wholeCenterPos.y,
- e.clientX,
- e.clientY,
- mx,
- my
- );
- element.rotateByCenter(rotate, this.wholeCenterPos.x, this.wholeCenterPos.y);
- }
- endResize() {
- this.selectedElementList.forEach((element) => {
- element.endResize();
- });
- }
- render() {
- if (this.selectedElementList.length > 0) {
- if (this.width <= 0 || this.height <= 0) {
- return;
- }
- this.dragElement.render();
- }
- }
- }
- class Selection {
- constructor(app) {
- this.app = app;
- this.canvas = null;
- this.ctx = null;
- this.creatingSelection = false;
- this.hasSelection = false;
- this.isResizing = false;
- this.state = this.app.state;
- this.width = this.app.width;
- this.height = this.app.height;
- this.coordinate = new Coordinate(this);
- this.rectangle = new Rectangle(
- {
- type: "rectangle",
- style: {
- strokeStyle: "rgba(9,132,227,0.3)",
- fillStyle: "rgba(9,132,227,0.3)"
- }
- },
- this
- );
- this.multiSelectElement = new MultiSelectElement(
- {
- type: "multiSelectElement"
- },
- this
- );
- this.checkInNodes = throttle(this.checkInNodes, this, 500);
- this.handleResize = throttle(this.handleResize, this, 16);
- this.init();
- this.bindEvent();
- }
- init() {
- if (this.canvas) {
- this.app.container.removeChild(this.canvas.el);
- }
- this.width = this.app.width;
- this.height = this.app.height;
- this.canvas = new Canvas(this.width, this.height, {
- className: "selection"
- });
- this.ctx = this.canvas.ctx;
- this.app.container.appendChild(this.canvas.el);
- }
- bindEvent() {
- this.app.on("change", () => {
- this.state = this.app.state;
- this.multiSelectElement.updateElements(this.app.elements.elementList);
- this.renderSelection();
- });
- this.app.on("scrollChange", () => {
- this.renderSelection();
- });
- this.app.on("zoomChange", () => {
- this.renderSelection();
- });
- }
- onMousedown(e, event) {
- if (e.originEvent.which !== 1) {
- return;
- }
- this.creatingSelection = true;
- this.rectangle.updatePos(event.mousedownPos.x, event.mousedownPos.y);
- }
- onMousemove(e, event) {
- if (Math.abs(event.mouseOffset.x) <= 10 && Math.abs(event.mouseOffset.y) <= 10) {
- return;
- }
- this.onMove(e, event);
- }
- onMouseup() {
- this.creatingSelection = false;
- this.rectangle.updateRect(0, 0, 0, 0);
- this.hasSelection = this.hasSelectionElements();
- this.multiSelectElement.updateRect();
- this.renderSelection();
- this.emitChange();
- }
- reset() {
- this.setMultiSelectElements([]);
- this.hasSelection = false;
- this.renderSelection();
- this.emitChange();
- }
- renderSelection() {
- this.canvas.clearCanvas();
- this.ctx.save();
- this.ctx.scale(this.app.state.scale, this.app.state.scale);
- this.rectangle.render();
- this.multiSelectElement.render();
- this.ctx.restore();
- }
- onMove(e, event) {
- this.rectangle.updateSize(event.mouseOffset.x, event.mouseOffset.y);
- this.renderSelection();
- this.checkInElements(e, event);
- }
- checkInElements(e, event) {
- let minx = Math.min(event.mousedownPos.x, e.clientX);
- let miny = Math.min(event.mousedownPos.y, e.clientY);
- let maxx = Math.max(event.mousedownPos.x, e.clientX);
- let maxy = Math.max(event.mousedownPos.y, e.clientY);
- let selectedElementList = [];
- this.app.elements.elementList.forEach((element) => {
- let _minx = Infinity;
- let _maxx = -Infinity;
- let _miny = Infinity;
- let _maxy = -Infinity;
- let endPointList = element.getEndpointList();
- let rect = getBoundingRect(
- endPointList.map((point) => {
- return [point.x, point.y];
- }),
- true
- );
- rect.forEach(({ x, y }) => {
- if (x < _minx) {
- _minx = x;
- }
- if (x > _maxx) {
- _maxx = x;
- }
- if (y < _miny) {
- _miny = y;
- }
- if (y > _maxy) {
- _maxy = y;
- }
- });
- if (_minx >= minx && _maxx <= maxx && _miny >= miny && _maxy <= maxy) {
- selectedElementList.push(element);
- }
- });
- let finalList = [...selectedElementList];
- selectedElementList.forEach((item) => {
- if (item.hasGroup()) {
- finalList.push(...this.app.group.getGroupElements(item));
- }
- });
- finalList = new Set(finalList);
- finalList = Array.from(finalList);
- this.setMultiSelectElements(finalList, true);
- this.app.render.render();
- }
- checkInResizeHand(x, y) {
- return this.multiSelectElement.dragElement.checkPointInDragElementWhere(
- x,
- y
- );
- }
- checkIsResize(x, y, e) {
- if (!this.hasSelection) {
- return false;
- }
- let hand = this.multiSelectElement.dragElement.checkPointInDragElementWhere(
- x,
- y
- );
- if (hand) {
- this.isResizing = true;
- this.multiSelectElement.startResize(hand, e);
- this.app.cursor.setResize(hand);
- return true;
- }
- return false;
- }
- handleResize(...args) {
- if (!this.isResizing) {
- return;
- }
- this.multiSelectElement.resize(...args);
- this.app.render.render();
- this.multiSelectElement.updateRect();
- this.renderSelection();
- }
- endResize() {
- this.isResizing = false;
- this.multiSelectElement.endResize();
- }
- setSelectedElementStyle(style = {}) {
- if (!this.hasSelectionElements()) {
- return;
- }
- Object.keys(style).forEach((key) => {
- this.getSelectionElements().forEach((element) => {
- element.style[key] = style[key];
- if (key === "fontSize" && element.type === "text") {
- element.updateTextSize();
- this.multiSelectElement.updateRect();
- }
- });
- });
- this.app.render.render();
- this.app.emitChange();
- }
- deleteSelectedElements() {
- this.getSelectionElements().forEach((element) => {
- this.app.elements.deleteElement(element);
- });
- this.selectElements([]);
- this.app.emitChange();
- }
- hasSelectionElements() {
- return this.getSelectionElements().length > 0;
- }
- getSelectionElements() {
- return this.multiSelectElement.selectedElementList;
- }
- copySelectionElements(pos) {
- return __async(this, null, function* () {
- let task = this.getSelectionElements().map((element) => {
- return this.app.elements.copyElement(element, true);
- });
- this.app.group.clearCopyMap();
- let elements = yield Promise.all(task);
- this.setMultiSelectElements(elements);
- if (pos) {
- this.multiSelectElement.startResize(DRAG_ELEMENT_PARTS.BODY);
- let ox = pos.x - this.multiSelectElement.x - this.multiSelectElement.width / 2;
- let oy = pos.y - this.multiSelectElement.y - this.multiSelectElement.height / 2;
- let gridAdsorbentPos = this.app.coordinate.gridAdsorbent(ox, oy);
- this.multiSelectElement.resize(
- null,
- null,
- null,
- gridAdsorbentPos.x,
- gridAdsorbentPos.y
- );
- this.multiSelectElement.endResize();
- this.multiSelectElement.updateRect();
- }
- this.app.render.render();
- this.renderSelection();
- this.app.emitChange();
- });
- }
- selectElements(elements = []) {
- this.hasSelection = elements.length > 0;
- this.setMultiSelectElements(elements);
- this.app.render.render();
- this.renderSelection();
- this.emitChange();
- }
- setMultiSelectElements(elements = [], notUpdateRect) {
- this.multiSelectElement.setSelectedElementList(elements);
- if (!notUpdateRect) {
- this.multiSelectElement.updateRect();
- }
- }
- emitChange() {
- this.app.emit("multiSelectChange", this.getSelectionElements());
- }
- }
- class Grid {
- constructor(app) {
- this.app = app;
- this.canvas = null;
- this.ctx = null;
- this.init();
- this.app.on("zoomChange", this.renderGrid, this);
- this.app.on("scrollChange", this.renderGrid, this);
- }
- init() {
- if (this.canvas) {
- this.app.container.removeChild(this.canvas.el);
- }
- let { width, height } = this.app;
- this.canvas = new Canvas(width, height, {
- className: "grid"
- });
- this.ctx = this.canvas.ctx;
- this.app.container.insertBefore(
- this.canvas.el,
- this.app.container.children[0]
- );
- }
- drawHorizontalLine(i) {
- let { coordinate, width, state } = this.app;
- let _i = coordinate.subScrollY(i);
- this.ctx.beginPath();
- this.ctx.moveTo(-width / state.scale / 2, _i);
- this.ctx.lineTo(width / state.scale / 2, _i);
- this.ctx.stroke();
- }
- renderHorizontalLines() {
- let { coordinate, height, state } = this.app;
- let { gridConfig, scale } = state;
- let maxBottom = 0;
- for (let i = -height / 2; i < height / 2; i += gridConfig.size) {
- this.drawHorizontalLine(i);
- maxBottom = i;
- }
- for (let i = -height / 2 - gridConfig.size; i > -coordinate.subScrollY(height / scale / 2); i -= gridConfig.size) {
- this.drawHorizontalLine(i);
- }
- for (let i = maxBottom + gridConfig.size; i < coordinate.addScrollY(height / scale / 2); i += gridConfig.size) {
- this.drawHorizontalLine(i);
- }
- }
- drawVerticalLine(i) {
- let { coordinate, height, state } = this.app;
- let _i = coordinate.subScrollX(i);
- this.ctx.beginPath();
- this.ctx.moveTo(_i, -height / state.scale / 2);
- this.ctx.lineTo(_i, height / state.scale / 2);
- this.ctx.stroke();
- }
- renderVerticalLines() {
- let { coordinate, width, state } = this.app;
- let { gridConfig, scale } = state;
- let maxRight = 0;
- for (let i = -width / 2; i < width / 2; i += gridConfig.size) {
- this.drawVerticalLine(i);
- maxRight = i;
- }
- for (let i = -width / 2 - gridConfig.size; i > -coordinate.subScrollX(width / scale / 2); i -= gridConfig.size) {
- this.drawVerticalLine(i);
- }
- for (let i = maxRight + gridConfig.size; i < coordinate.addScrollX(width / scale / 2); i += gridConfig.size) {
- this.drawVerticalLine(i);
- }
- }
- renderGrid() {
- this.canvas.clearCanvas();
- let { gridConfig, scale, showGrid } = this.app.state;
- if (!showGrid) {
- return;
- }
- this.ctx.save();
- this.ctx.scale(scale, scale);
- this.ctx.strokeStyle = gridConfig.strokeStyle;
- this.ctx.lineWidth = gridConfig.lineWidth;
- this.renderHorizontalLines();
- this.renderVerticalLines();
- this.ctx.restore();
- }
- showGrid() {
- this.app.updateState({
- showGrid: true
- });
- this.renderGrid();
- }
- hideGrid() {
- this.app.updateState({
- showGrid: false
- });
- this.canvas.clearCanvas();
- }
- updateGrid(config = {}) {
- this.app.updateState({
- gridConfig: __spreadValues(__spreadValues({}, this.app.state.gridConfig), config)
- });
- if (this.app.state.showGrid) {
- this.hideGrid();
- this.showGrid();
- }
- }
- }
- const map = {
- Tab: 9,
- Enter: 13,
- Shift: 16,
- Control: 17,
- Alt: 18,
- CapsLock: 20,
- Esc: 27,
- Space: 32,
- PageUp: 33,
- PageDown: 34,
- End: 35,
- Home: 36,
- Insert: 45,
- Left: 37,
- Up: 38,
- Right: 39,
- Down: 40,
- Del: 46,
- NumLock: 144,
- Cmd: 91,
- CmdFF: 224,
- F1: 112,
- F2: 113,
- F3: 114,
- F4: 115,
- F5: 116,
- F6: 117,
- F7: 118,
- F8: 119,
- F9: 120,
- F10: 121,
- F11: 122,
- F12: 123,
- "`": 192,
- "=": 187,
- "+": 187,
- "-": 189,
- "'": 222,
- "/": 191,
- ".": 190
- };
- for (let i = 0; i <= 9; i++) {
- map[i] = i + 48;
- }
- "abcdefghijklmnopqrstuvwxyz".split("").forEach((n, index) => {
- map[n] = index + 65;
- });
- const keyMap = map;
- class Mode {
- constructor(app) {
- this.app = app;
- this.startScrollX = 0;
- this.startScrollY = 0;
- this.isDragMode = false;
- this.onMove = throttle(this.onMove, this, 16);
- this.bindEvent();
- }
- bindEvent() {
- this.app.event.on("keydown", (e) => {
- if (e.keyCode === keyMap.Space) {
- this.isDragMode = true;
- this.app.cursor.set("grab");
- }
- });
- this.app.event.on("keyup", (e) => {
- if (this.isDragMode) {
- this.isDragMode = false;
- this.app.cursor.set("default");
- }
- });
- }
- setEditMode() {
- this.app.cursor.set("default");
- this.app.updateState({
- readonly: false
- });
- }
- setReadonlyMode() {
- this.app.cursor.set("grab");
- this.app.updateState({
- readonly: true
- });
- }
- onStart() {
- this.startScrollX = this.app.state.scrollX;
- this.startScrollY = this.app.state.scrollY;
- }
- onMove(e, event) {
- this.app.scrollTo(
- this.startScrollX - event.mouseOffset.originX / this.app.state.scale,
- this.startScrollY - event.mouseOffset.originY / this.app.state.scale
- );
- }
- onEnd() {
- this.startScrollX = 0;
- this.startScrollY = 0;
- }
- }
- class KeyCommand {
- constructor(app) {
- this.app = app;
- this.keyMap = keyMap;
- this.shortcutMap = {};
- this.bindEvent();
- }
- bindEvent() {
- this.app.event.on("keydown", this.onKeydown, this);
- }
- unBindEvent() {
- this.app.event.off("keydown", this.onKeydown);
- }
- onKeydown(e) {
- Object.keys(this.shortcutMap).forEach((key) => {
- if (this.checkKey(e, key)) {
- e.stopPropagation();
- e.preventDefault();
- this.shortcutMap[key].forEach((f) => {
- f.fn.call(f.ctx);
- });
- }
- });
- }
- checkKey(e, key) {
- let o = this.getOriginEventCodeArr(e);
- let k = this.getKeyCodeArr(key);
- if (o.length !== k.length) {
- return false;
- }
- for (let i = 0; i < o.length; i++) {
- let index = k.findIndex((item) => {
- return item === o[i];
- });
- if (index === -1) {
- return false;
- } else {
- k.splice(index, 1);
- }
- }
- return true;
- }
- getOriginEventCodeArr(e) {
- let arr = [];
- if (e.ctrlKey || e.metaKey) {
- arr.push(keyMap["Control"]);
- }
- if (e.altKey) {
- arr.push(keyMap["Alt"]);
- }
- if (e.shiftKey) {
- arr.push(keyMap["Shift"]);
- }
- if (!arr.includes(e.keyCode)) {
- arr.push(e.keyCode);
- }
- return arr;
- }
- getKeyCodeArr(key) {
- key = key.replace(/\+\+/, "+add");
- let keyArr = key.split(/\s*\+\s*/).map((item) => {
- return item === "add" ? "+" : item;
- });
- let arr = [];
- keyArr.forEach((item) => {
- arr.push(keyMap[item]);
- });
- return arr;
- }
- addShortcut(key, fn, ctx) {
- key.split(/\s*\|\s*/).forEach((item) => {
- if (this.shortcutMap[item]) {
- this.shortcutMap[item].push({
- fn,
- ctx
- });
- } else {
- this.shortcutMap[item] = [
- {
- fn,
- ctx
- }
- ];
- }
- });
- }
- removeShortcut(key, fn) {
- key.split(/\s*\|\s*/).forEach((item) => {
- if (this.shortcutMap[item]) {
- if (fn) {
- let index = this.shortcutMap[item].findIndex((f) => {
- return f.fn === fn;
- });
- if (index !== -1) {
- this.shortcutMap[item].splice(index, 1);
- }
- } else {
- this.shortcutMap[item] = [];
- delete this.shortcutMap[item];
- }
- }
- });
- }
- }
- class Render {
- constructor(app) {
- this.app = app;
- this.beingCopyActiveElement = null;
- this.beingCopySelectedElements = [];
- this.registerShortcutKeys();
- }
- clearCanvas() {
- let { width, height } = this.app;
- this.app.ctx.clearRect(-width / 2, -height / 2, width, height);
- return this;
- }
- render() {
- let { state } = this.app;
- this.clearCanvas();
- this.app.ctx.save();
- this.app.ctx.scale(state.scale, state.scale);
- this.app.elements.elementList.forEach((element) => {
- if (element.noRender) {
- return;
- }
- element.render();
- });
- this.app.group.render();
- this.app.ctx.restore();
- return this;
- }
- registerShortcutKeys() {
- this.app.keyCommand.addShortcut("Del|Backspace", () => {
- this.deleteCurrentElements();
- });
- this.app.keyCommand.addShortcut("Control+c", () => {
- this.copyCurrentElement();
- });
- this.app.keyCommand.addShortcut("Control+x", () => {
- this.cutCurrentElement();
- });
- this.app.keyCommand.addShortcut("Control+z", () => {
- this.app.history.undo();
- });
- this.app.keyCommand.addShortcut("Control+y", () => {
- this.app.history.redo();
- });
- this.app.keyCommand.addShortcut("Control+v", () => {
- this.pasteCurrentElement(true);
- });
- this.app.keyCommand.addShortcut("Control++", () => {
- this.zoomIn();
- });
- this.app.keyCommand.addShortcut("Control+-", () => {
- this.zoomOut();
- });
- this.app.keyCommand.addShortcut("Shift+1", () => {
- this.fit();
- });
- this.app.keyCommand.addShortcut("Control+a", () => {
- this.selectAll();
- });
- this.app.keyCommand.addShortcut("Control+0", () => {
- this.setZoom(1);
- });
- this.app.keyCommand.addShortcut("Control+'", () => {
- if (this.app.state.showGrid) {
- this.app.grid.hideGrid();
- } else {
- this.app.grid.showGrid();
- }
- });
- }
- copyCurrentElement() {
- if (this.app.elements.activeElement) {
- this.beingCopySelectedElements = [];
- this.beingCopyElement = this.app.elements.activeElement;
- } else if (this.app.selection.hasSelectionElements()) {
- this.beingCopyElement = null;
- this.beingCopySelectedElements = this.app.selection.getSelectionElements();
- }
- }
- cutCurrentElement() {
- if (this.app.elements.activeElement) {
- this.copyCurrentElement();
- this.deleteCurrentElements();
- } else if (this.app.selection.hasSelectionElements()) {
- this.copyCurrentElement();
- this.deleteCurrentElements();
- this.app.selection.setMultiSelectElements(this.beingCopySelectedElements);
- this.app.selection.emitChange();
- }
- }
- pasteCurrentElement(useCurrentEventPos = false) {
- let pos = null;
- if (useCurrentEventPos) {
- let x = this.app.event.lastMousePos.x;
- let y = this.app.event.lastMousePos.y;
- pos = {
- x,
- y
- };
- }
- if (this.beingCopyElement) {
- this.copyElement(this.beingCopyElement, false, pos);
- } else if (this.beingCopySelectedElements.length > 0) {
- this.app.selection.selectElements(this.beingCopySelectedElements);
- this.app.selection.copySelectionElements(useCurrentEventPos ? pos : null);
- }
- }
- deleteElement(element) {
- this.app.elements.deleteElement(element);
- this.render();
- this.app.emitChange();
- }
- copyElement(element, notActive = false, pos) {
- return __async(this, null, function* () {
- this.app.elements.cancelActiveElement();
- yield this.app.elements.copyElement(element, notActive, pos);
- this.app.group.clearCopyMap();
- this.render();
- this.app.emitChange();
- });
- }
- deleteActiveElement() {
- if (!this.app.elements.hasActiveElement()) {
- return;
- }
- this.deleteElement(this.app.elements.activeElement);
- }
- deleteCurrentElements() {
- this.deleteActiveElement();
- this.app.selection.deleteSelectedElements();
- }
- moveUpCurrentElement() {
- this.moveLevelCurrentElement("up");
- }
- moveDownCurrentElement() {
- this.moveLevelCurrentElement("down");
- }
- moveTopCurrentElement() {
- this.moveLevelCurrentElement("top");
- }
- moveBottomCurrentElement() {
- this.moveLevelCurrentElement("bottom");
- }
- moveLevelCurrentElement(level) {
- let element = null;
- if (this.app.elements.hasActiveElement()) {
- element = this.app.elements.activeElement;
- } else if (this.app.selection.getSelectionElements().length === 1) {
- element = this.app.selection.getSelectionElements()[0];
- }
- if (!element) {
- return;
- }
- let index = this.app.elements.getElementIndex(element);
- this.app.elements.elementList.splice(index, 1);
- if (level === "up") {
- this.app.elements.insertElement(element, index + 1);
- } else if (level === "down") {
- this.app.elements.insertElement(element, index - 1);
- } else if (level === "top") {
- this.app.elements.addElement(element);
- } else if (level === "bottom") {
- this.app.elements.unshiftElement(element);
- }
- }
- setActiveElementStyle(style = {}) {
- if (!this.app.elements.hasActiveElement()) {
- return this;
- }
- this.app.elements.setActiveElementStyle(style);
- this.render();
- if (!this.app.elements.isCreatingElement) {
- this.app.emitChange();
- }
- return this;
- }
- setCurrentElementsStyle(style = {}) {
- this.setActiveElementStyle(style);
- this.app.selection.setSelectedElementStyle(style);
- }
- cancelActiveElement() {
- if (!this.app.elements.hasActiveElement()) {
- return this;
- }
- this.app.elements.cancelActiveElement();
- this.render();
- return this;
- }
- updateActiveElementPosition(x, y) {
- if (!this.app.elements.hasActiveElement()) {
- return this;
- }
- this.app.elements.activeElement.updatePos(x, y);
- this.render();
- return this;
- }
- updateActiveElementSize(width, height) {
- if (!this.app.elements.hasActiveElement()) {
- return this;
- }
- this.app.elements.activeElement.updateSize(width, height);
- this.render();
- return this;
- }
- updateActiveElementRotate(rotate) {
- if (!this.app.elements.hasActiveElement()) {
- return this;
- }
- this.app.elements.activeElement.updateRotate(rotate);
- this.render();
- return this;
- }
- empty() {
- this.app.elements.deleteAllElements();
- this.render();
- this.app.history.clear();
- this.app.emitChange();
- }
- zoomIn(num = 0.1) {
- this.app.updateState({
- scale: this.app.state.scale + num
- });
- this.render();
- this.app.emit("zoomChange", this.app.state.scale);
- }
- zoomOut(num = 0.1) {
- this.app.updateState({
- scale: this.app.state.scale - num > 0 ? this.app.state.scale - num : 0
- });
- this.render();
- this.app.emit("zoomChange", this.app.state.scale);
- }
- setZoom(zoom) {
- if (zoom < 0) {
- return;
- }
- this.app.updateState({
- scale: zoom
- });
- this.render();
- this.app.emit("zoomChange", this.app.state.scale);
- }
- fit() {
- if (!this.app.elements.hasElements()) {
- return;
- }
- this.scrollToCenter();
- let { minx, maxx, miny, maxy } = getMultiElementRectInfo(
- this.app.elements.elementList
- );
- let width = maxx - minx;
- let height = maxy - miny;
- let maxScale = Math.min(this.app.width / width, this.app.height / height);
- console.log(maxScale);
- this.setZoom(maxScale);
- }
- scrollTo(scrollX, scrollY) {
- this.app.updateState({
- scrollX,
- scrollY
- });
- this.render();
- this.app.emit(
- "scrollChange",
- this.app.state.scrollX,
- this.app.state.scrollY
- );
- }
- scrollToCenter() {
- if (!this.app.elements.hasElements()) {
- this.scrollTo(0, 0);
- return;
- }
- let { minx, maxx, miny, maxy } = getMultiElementRectInfo(
- this.app.elements.elementList
- );
- let width = maxx - minx;
- let height = maxy - miny;
- this.scrollTo(
- minx - (this.app.width - width) / 2,
- miny - (this.app.height - height) / 2
- );
- }
- copyPasteCurrentElements() {
- this.copyCurrentElement();
- this.pasteCurrentElement();
- }
- setBackgroundColor(color) {
- this.app.updateState({
- backgroundColor: color
- });
- this.app.background.set();
- }
- selectAll() {
- this.app.selection.selectElements(this.app.elements.elementList);
- }
- }
- class Elements {
- constructor(app) {
- this.app = app;
- this.elementList = [];
- this.activeElement = null;
- this.isCreatingElement = false;
- this.isResizing = false;
- this.resizingElement = null;
- this.handleResize = throttle(this.handleResize, this, 16);
- }
- serialize(stringify = false) {
- let data = this.elementList.map((element) => {
- return element.serialize();
- });
- return stringify ? JSON.stringify(data) : data;
- }
- getElementsNum() {
- return this.elementList.length;
- }
- hasElements() {
- return this.elementList.length > 0;
- }
- addElement(element) {
- this.elementList.push(element);
- return this;
- }
- unshiftElement(element) {
- this.elementList.unshift(element);
- return this;
- }
- insertElement(element, index) {
- this.elementList.splice(index, 0, element);
- }
- deleteElement(element) {
- let index = this.getElementIndex(element);
- if (index !== -1) {
- this.elementList.splice(index, 1);
- if (element.isActive) {
- this.cancelActiveElement(element);
- }
- }
- return this;
- }
- deleteAllElements() {
- this.activeElement = null;
- this.elementList = [];
- this.isCreatingElement = false;
- this.isResizing = false;
- this.resizingElement = null;
- return this;
- }
- getElementIndex(element) {
- return this.elementList.findIndex((item) => {
- return item === element;
- });
- }
- createElementsFromData(data) {
- data.forEach((item) => {
- let element = this.pureCreateElement(item);
- element.isActive = false;
- element.isCreating = false;
- this.addElement(element);
- });
- this.app.group.initIdToElementList(this.elementList);
- return this;
- }
- hasActiveElement() {
- return !!this.activeElement;
- }
- setActiveElement(element) {
- this.cancelActiveElement();
- this.activeElement = element;
- if (element) {
- element.isActive = true;
- }
- this.app.emit("activeElementChange", this.activeElement);
- return this;
- }
- cancelActiveElement() {
- if (!this.hasActiveElement()) {
- return this;
- }
- this.activeElement.isActive = false;
- this.activeElement = null;
- this.app.emit("activeElementChange", this.activeElement);
- return this;
- }
- checkIsHitElement(e) {
- let x = e.unGridClientX;
- let y = e.unGridClientY;
- for (let i = this.elementList.length - 1; i >= 0; i--) {
- let element = this.elementList[i];
- if (element.isHit(x, y)) {
- return element;
- }
- }
- return null;
- }
- pureCreateElement(opts = {}) {
- switch (opts.type) {
- case "rectangle":
- return new Rectangle(opts, this.app);
- case "diamond":
- return new Diamond(opts, this.app);
- case "triangle":
- return new Triangle(opts, this.app);
- case "circle":
- return new Circle(opts, this.app);
- case "freedraw":
- return new Freedraw(opts, this.app);
- case "image":
- return new Image$1(opts, this.app);
- case "arrow":
- return new Arrow(opts, this.app);
- case "line":
- return new Line(opts, this.app);
- case "text":
- return new Text(opts, this.app);
- default:
- return null;
- }
- }
- createElement(opts = {}, callback = () => {
- }, ctx = null, notActive) {
- if (this.hasActiveElement() || this.isCreatingElement) {
- return this;
- }
- let element = this.pureCreateElement(opts);
- if (!element) {
- return this;
- }
- this.addElement(element);
- if (!notActive) {
- this.setActiveElement(element);
- }
- this.isCreatingElement = true;
- callback.call(ctx, element);
- return this;
- }
- copyElement(element, notActive = false, pos) {
- return new Promise((resolve) => __async(this, null, function* () {
- if (!element) {
- return resolve();
- }
- let data = this.app.group.handleCopyElementData(element.serialize());
- if (data.type === "image") {
- data.imageObj = yield createImageObj(data.url);
- }
- if (data.type === "text") {
- if (typeof data.text === "string") {
- if (isNumeric(data.text)) {
- const num = parseFloat(data.text);
- const incrementedNum = num + 1;
- data.text = incrementedNum.toString(10).padStart(data.text.length, "0");
- }
- }
- }
- this.createElement(
- data,
- (element2) => {
- this.app.group.handleCopyElement(element2);
- element2.startResize(DRAG_ELEMENT_PARTS.BODY);
- let ox = 20;
- let oy = 20;
- if (pos) {
- ox = pos.x - element2.x - element2.width / 2;
- oy = pos.y - element2.y - element2.height / 2;
- }
- let gridAdsorbentPos = this.app.coordinate.gridAdsorbent(ox, oy);
- element2.resize(
- null,
- null,
- null,
- gridAdsorbentPos.x,
- gridAdsorbentPos.y
- );
- element2.isCreating = false;
- if (notActive) {
- element2.isActive = false;
- }
- this.isCreatingElement = false;
- resolve(element2);
- },
- this,
- notActive
- );
- }));
- }
- creatingRectangleLikeElement(type, x, y, offsetX, offsetY) {
- this.createElement({
- type,
- x,
- y,
- width: offsetX,
- height: offsetY
- });
- this.activeElement.updateSize(offsetX, offsetY);
- }
- creatingCircle(x, y, e) {
- this.createElement({
- type: "circle",
- x,
- y
- });
- let radius = getTowPointDistance(e.clientX, e.clientY, x, y);
- this.activeElement.updateSize(radius, radius);
- }
- creatingFreedraw(e, event) {
- this.createElement({
- type: "freedraw"
- });
- let element = this.activeElement;
- let lineWidth = computedLineWidthBySpeed(
- event.mouseSpeed,
- element.lastLineWidth
- );
- element.lastLineWidth = lineWidth;
- element.addPoint(e.clientX, e.clientY, lineWidth);
- let { coordinate, ctx, state } = this.app;
- let tfp = coordinate.transformToCanvasCoordinate(
- coordinate.subScrollX(event.lastMousePos.x),
- coordinate.subScrollY(event.lastMousePos.y)
- );
- let ttp = coordinate.transformToCanvasCoordinate(
- coordinate.subScrollX(e.clientX),
- coordinate.subScrollY(e.clientY)
- );
- ctx.save();
- ctx.scale(state.scale, state.scale);
- element.singleRender(tfp.x, tfp.y, ttp.x, ttp.y, lineWidth);
- ctx.restore();
- }
- creatingImage(e, { width, height, imageObj, url, ratio }) {
- let gp = this.app.coordinate.gridAdsorbent(
- e.unGridClientX - width / 2,
- e.unGridClientY - height / 2
- );
- this.createElement({
- type: "image",
- x: gp.x,
- y: gp.y,
- url,
- imageObj,
- width,
- height,
- ratio
- });
- }
- editingText(element) {
- if (element.type !== "text") {
- return;
- }
- element.noRender = true;
- this.setActiveElement(element);
- }
- completeEditingText() {
- let element = this.activeElement;
- if (!element || element.type !== "text") {
- return;
- }
- if (!element.text.trim()) {
- this.deleteElement(element);
- this.setActiveElement(null);
- return;
- }
- element.noRender = false;
- }
- completeCreateArrow(e) {
- this.activeElement.addPoint(e.clientX, e.clientY);
- }
- creatingArrow(x, y, e) {
- this.createElement(
- {
- type: "arrow",
- x,
- y
- },
- (element) => {
- element.addPoint(x, y);
- }
- );
- this.activeElement.updateFictitiousPoint(e.clientX, e.clientY);
- }
- creatingLine(x, y, e, isSingle = false, notCreate = false) {
- if (!notCreate) {
- this.createElement(
- {
- type: "line",
- x,
- y,
- isSingle
- },
- (element2) => {
- element2.addPoint(x, y);
- }
- );
- }
- let element = this.activeElement;
- if (element) {
- element.updateFictitiousPoint(e.clientX, e.clientY);
- }
- }
- completeCreateLine(e, completeCallback = () => {
- }) {
- let element = this.activeElement;
- let x = e.clientX;
- let y = e.clientY;
- if (element && element.isSingle) {
- element.addPoint(x, y);
- completeCallback();
- } else {
- this.createElement({
- type: "line",
- isSingle: false
- });
- element = this.activeElement;
- element.addPoint(x, y);
- element.updateFictitiousPoint(x, y);
- }
- }
- completeCreateElement() {
- this.isCreatingElement = false;
- let element = this.activeElement;
- if (!element) {
- return this;
- }
- if (["freedraw", "arrow", "line"].includes(element.type)) {
- element.updateMultiPointBoundingRect();
- }
- element.isCreating = false;
- this.app.emitChange();
- return this;
- }
- setActiveElementStyle(style = {}) {
- if (!this.hasActiveElement()) {
- return this;
- }
- Object.keys(style).forEach((key) => {
- this.activeElement.style[key] = style[key];
- if (key === "fontSize" && this.activeElement.type === "text") {
- this.activeElement.updateTextSize();
- }
- });
- return this;
- }
- checkInResizeHand(x, y) {
- let element = this.activeElement;
- let hand = element.dragElement.checkPointInDragElementWhere(x, y);
- if (hand) {
- return {
- element,
- hand
- };
- }
- return null;
- }
- checkIsResize(x, y, e) {
- if (!this.hasActiveElement()) {
- return false;
- }
- let res = this.checkInResizeHand(x, y);
- if (res) {
- this.isResizing = true;
- this.resizingElement = res.element;
- this.resizingElement.startResize(res.hand, e);
- this.app.cursor.setResize(res.hand);
- return true;
- }
- return false;
- }
- handleResize(...args) {
- if (!this.isResizing) {
- return;
- }
- this.resizingElement.resize(...args);
- this.app.render.render();
- }
- endResize() {
- this.isResizing = false;
- this.resizingElement.endResize();
- this.resizingElement = null;
- }
- }
- function isNumeric(str) {
- const trimmedStr = str.trim();
- const num = Number(trimmedStr);
- return !isNaN(num) && trimmedStr === num.toString().padStart(trimmedStr.length, "0");
- }
- let getRandomValues;
- const rnds8 = new Uint8Array(16);
- function rng() {
- if (!getRandomValues) {
- getRandomValues = typeof crypto !== "undefined" && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
- if (!getRandomValues) {
- throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
- }
- }
- return getRandomValues(rnds8);
- }
- const byteToHex = [];
- for (let i = 0; i < 256; ++i) {
- byteToHex.push((i + 256).toString(16).slice(1));
- }
- function unsafeStringify(arr, offset = 0) {
- return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
- }
- const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
- var native = {
- randomUUID
- };
- function v4(options, buf, offset) {
- if (native.randomUUID && !buf && !options) {
- return native.randomUUID();
- }
- options = options || {};
- const rnds = options.random || (options.rng || rng)();
- rnds[6] = rnds[6] & 15 | 64;
- rnds[8] = rnds[8] & 63 | 128;
- if (buf) {
- offset = offset || 0;
- for (let i = 0; i < 16; ++i) {
- buf[offset + i] = rnds[i];
- }
- return buf;
- }
- return unsafeStringify(rnds);
- }
- class Group {
- constructor(app) {
- this.app = app;
- this.groupIdToElementList = {};
- this.newGroupIdMap = {};
- }
- render() {
- Object.keys(this.groupIdToElementList).forEach((groupId) => {
- let group = this.groupIdToElementList[groupId];
- let selected = group[0].isSelected;
- if (selected) {
- let mElement = new MultiSelectElement(
- {
- type: "multiSelectElement"
- },
- this.app
- );
- mElement.setSelectedElementList(group);
- mElement.updateRect();
- mElement.dragElement.onlyShowBody();
- mElement.render();
- }
- });
- }
- setToMap(element) {
- let groupId = element.getGroupId();
- if (groupId) {
- if (!this.groupIdToElementList[groupId]) {
- this.groupIdToElementList[groupId] = [];
- }
- this.groupIdToElementList[groupId].push(element);
- }
- }
- initIdToElementList(elementList) {
- this.groupIdToElementList = {};
- elementList.forEach((element) => {
- this.setToMap(element);
- });
- }
- handleCopyElementData(data) {
- if (data.groupId) {
- if (this.newGroupIdMap[data.groupId]) {
- data.groupId = this.newGroupIdMap[data.groupId];
- } else {
- data.groupId = this.newGroupIdMap[data.groupId] = v4();
- }
- }
- return data;
- }
- clearCopyMap() {
- this.newGroupIdMap = {};
- }
- handleCopyElement(element) {
- this.setToMap(element);
- }
- dogroup() {
- if (!this.app.selection.hasSelection || this.app.selection.multiSelectElement.selectedElementList.length <= 1) {
- return;
- }
- let groupElement = this.app.selection.multiSelectElement.selectedElementList;
- let groupId = v4();
- this.groupIdToElementList[groupId] = groupElement;
- groupElement.forEach((element) => {
- element.setGroupId(groupId);
- });
- this.app.render.render();
- this.app.emitChange();
- }
- ungroup() {
- if (!this.app.selection.hasSelection || this.app.selection.multiSelectElement.selectedElementList.length <= 1) {
- return;
- }
- let groupElement = this.app.selection.multiSelectElement.selectedElementList;
- let groupId = groupElement[0].getGroupId();
- this.groupIdToElementList[groupId] = [];
- delete this.groupIdToElementList[groupId];
- groupElement.forEach((element) => {
- element.removeGroupId(groupId);
- });
- this.app.render.render();
- this.app.emitChange();
- }
- setSelection(element) {
- let groupId = element.getGroupId();
- if (this.groupIdToElementList[groupId]) {
- this.app.selection.selectElements(this.groupIdToElementList[groupId]);
- }
- }
- getGroupElements(element) {
- let groupId = element.getGroupId();
- return this.groupIdToElementList[groupId] || [];
- }
- }
- class TinyWhiteboard extends EventEmitter {
- constructor(opts = {}) {
- super();
- this.opts = opts;
- this.container = opts.container;
- this.drawType = opts.drawType || "selection";
- if (!this.container) {
- throw new Error("\u7F3A\u5C11 container \u53C2\u6570\uFF01");
- }
- if (!["absolute", "fixed", "relative"].includes(
- window.getComputedStyle(this.container).position
- )) {
- throw new Error("container\u5143\u7D20\u9700\u8981\u8BBE\u7F6E\u5B9A\u4F4D\uFF01");
- }
- this.width = 0;
- this.height = 0;
- this.left = 0;
- this.top = 0;
- this.canvas = null;
- this.ctx = null;
- this.state = __spreadValues({
- scale: 1,
- scrollX: 0,
- scrollY: 0,
- scrollStep: 50,
- backgroundColor: "",
- strokeStyle: "#000000",
- fillStyle: "transparent",
- fontFamily: "\u5FAE\u8F6F\u96C5\u9ED1, Microsoft YaHei",
- fontSize: 18,
- dragStrokeStyle: "#666",
- showGrid: false,
- readonly: false,
- gridConfig: {
- size: 20,
- strokeStyle: "#dfe0e1",
- lineWidth: 1
- }
- }, opts.state || {});
- this.initCanvas();
- this.coordinate = new Coordinate(this);
- this.event = new Event(this);
- this.event.on("mousedown", this.onMousedown, this);
- this.event.on("mousemove", this.onMousemove, this);
- this.event.on("mouseup", this.onMouseup, this);
- this.event.on("dblclick", this.onDblclick, this);
- this.event.on("mousewheel", this.onMousewheel, this);
- this.event.on("contextmenu", this.onContextmenu, this);
- this.keyCommand = new KeyCommand(this);
- this.imageEdit = new ImageEdit(this);
- this.imageEdit.on("imageSelectChange", this.onImageSelectChange, this);
- this.textEdit = new TextEdit(this);
- this.textEdit.on("blur", this.onTextInputBlur, this);
- this.cursor = new Cursor(this);
- this.history = new History(this);
- this.export = new Export(this);
- this.background = new Background(this);
- this.selection = new Selection(this);
- this.group = new Group(this);
- this.grid = new Grid(this);
- this.mode = new Mode(this);
- this.elements = new Elements$1(this);
- this.render = new Render(this);
- this.proxy();
- this.checkIsOnElement = throttle(this.checkIsOnElement, this);
- this.emitChange();
- this.helpUpdate();
- }
- proxy() {
- ["undo", "redo"].forEach((method) => {
- this[method] = this.history[method].bind(this.history);
- });
- [].forEach((method) => {
- this[method] = this.elements[method].bind(this.elements);
- });
- [
- "deleteElement",
- "setActiveElementStyle",
- "setCurrentElementsStyle",
- "cancelActiveElement",
- "deleteActiveElement",
- "deleteCurrentElements",
- "empty",
- "zoomIn",
- "zoomOut",
- "setZoom",
- "scrollTo",
- "scrollToCenter",
- "copyPasteCurrentElements",
- "setBackgroundColor",
- "copyElement",
- "copyCurrentElement",
- "cutCurrentElement",
- "pasteCurrentElement",
- "updateActiveElementRotate",
- "updateActiveElementSize",
- "updateActiveElementPosition",
- "moveBottomCurrentElement",
- "moveTopCurrentElement",
- "moveUpCurrentElement",
- "moveDownCurrentElement",
- "selectAll",
- "fit"
- ].forEach((method) => {
- this[method] = this.render[method].bind(this.render);
- });
- ["exportImage", "exportJson"].forEach((method) => {
- this[method] = this.export[method].bind(this.export);
- });
- ["setSelectedElementStyle"].forEach((method) => {
- this[method] = this.selection[method].bind(this.selection);
- });
- ["dogroup", "ungroup"].forEach((method) => {
- this[method] = this.group[method].bind(this.group);
- });
- ["showGrid", "hideGrid", "updateGrid"].forEach((method) => {
- this[method] = this.grid[method].bind(this.grid);
- });
- ["setEditMode", "setReadonlyMode"].forEach((method) => {
- this[method] = this.mode[method].bind(this.mode);
- });
- }
- getContainerRectInfo() {
- let { width, height, left, top } = this.container.getBoundingClientRect();
- this.width = width;
- this.height = height;
- this.left = left;
- this.top = top;
- }
- helpUpdate() {
- this.background.set();
- if (this.state.showGrid) {
- this.grid.showGrid();
- }
- if (this.state.readonly) {
- this.setReadonlyMode();
- }
- }
- setData(_0, _1) {
- return __async(this, arguments, function* ({ state = {}, elements = [] }, noEmitChange) {
- this.state = state;
- for (let i = 0; i < elements.length; i++) {
- if (elements[i].type === "image") {
- elements[i].imageObj = yield createImageObj(elements[i].url);
- }
- }
- this.helpUpdate();
- this.elements.deleteAllElements().createElementsFromData(elements);
- this.render.render();
- if (!noEmitChange) {
- this.emitChange();
- }
- });
- }
- initCanvas() {
- this.getContainerRectInfo();
- if (this.canvas) {
- this.container.removeChild(this.canvas);
- }
- let { canvas, ctx } = createCanvas(this.width, this.height, {
- className: "main"
- });
- this.canvas = canvas;
- this.ctx = ctx;
- this.container.appendChild(this.canvas);
- }
- resize() {
- this.initCanvas();
- this.render.render();
- this.selection.init();
- this.grid.init();
- this.grid.renderGrid();
- }
- updateState(data = {}) {
- this.state = __spreadValues(__spreadValues({}, this.state), data);
- this.emitChange();
- }
- updateCurrentType(drawType) {
- this.drawType = drawType;
- if (this.drawType === "image") {
- this.imageEdit.selectImage();
- }
- if (this.drawType === "eraser") {
- this.cursor.setEraser();
- this.cancelActiveElement();
- } else if (this.drawType !== "selection") {
- this.cursor.setCrosshair();
- } else {
- this.cursor.reset();
- }
- this.emit("currentTypeChange", this.drawType);
- }
- getData() {
- return {
- state: __spreadValues({}, this.state),
- elements: this.elements.serialize()
- };
- }
- onImageSelectChange() {
- this.cursor.hide();
- }
- onMousedown(e, event) {
- if (this.state.readonly || this.mode.isDragMode) {
- this.mode.onStart();
- return;
- }
- if (!this.elements.isCreatingElement && !this.textEdit.isEditing) {
- let hitElement = this.elements.checkIsHitElement(e);
- if (this.drawType === "selection") {
- if (this.elements.hasActiveElement()) {
- let isResizing = this.elements.checkIsResize(
- event.mousedownPos.unGridClientX,
- event.mousedownPos.unGridClientY,
- e
- );
- if (!isResizing) {
- this.elements.setActiveElement(hitElement);
- this.render.render();
- }
- } else {
- if (this.selection.hasSelection) {
- let isResizing = this.selection.checkIsResize(
- event.mousedownPos.unGridClientX,
- event.mousedownPos.unGridClientY,
- e
- );
- if (!isResizing) {
- this.selection.reset();
- this.elements.setActiveElement(hitElement);
- this.render.render();
- }
- } else if (hitElement) {
- if (hitElement.hasGroup()) {
- this.group.setSelection(hitElement);
- this.onMousedown(e, event);
- } else {
- this.elements.setActiveElement(hitElement);
- this.render.render();
- this.onMousedown(e, event);
- }
- } else {
- this.selection.onMousedown(e, event);
- }
- }
- } else if (this.drawType === "eraser") {
- this.deleteElement(hitElement);
- }
- }
- }
- onMousemove(e, event) {
- if (this.state.readonly || this.mode.isDragMode) {
- if (event.isMousedown) {
- this.mode.onMove(e, event);
- }
- return;
- }
- if (event.isMousedown) {
- let mx = event.mousedownPos.x;
- let my = event.mousedownPos.y;
- let offsetX = Math.max(event.mouseOffset.x, 0);
- let offsetY = Math.max(event.mouseOffset.y, 0);
- if (this.drawType === "selection") {
- if (this.selection.isResizing) {
- this.selection.handleResize(
- e,
- mx,
- my,
- event.mouseOffset.x,
- event.mouseOffset.y
- );
- } else if (this.selection.creatingSelection) {
- this.selection.onMousemove(e, event);
- } else {
- this.elements.handleResize(
- e,
- mx,
- my,
- event.mouseOffset.x,
- event.mouseOffset.y
- );
- }
- } else if (["rectangle", "diamond", "triangle"].includes(this.drawType)) {
- this.elements.creatingRectangleLikeElement(
- this.drawType,
- mx,
- my,
- offsetX,
- offsetY
- );
- this.render.render();
- } else if (this.drawType === "circle") {
- this.elements.creatingCircle(mx, my, e);
- this.render.render();
- } else if (this.drawType === "freedraw") {
- this.elements.creatingFreedraw(e, event);
- } else if (this.drawType === "arrow") {
- this.elements.creatingArrow(mx, my, e);
- this.render.render();
- } else if (this.drawType === "line") {
- if (getTowPointDistance(mx, my, e.clientX, e.clientY) > 3) {
- this.elements.creatingLine(mx, my, e, true);
- this.render.render();
- }
- }
- } else {
- if (this.imageEdit.isReady) {
- this.cursor.hide();
- this.imageEdit.updatePreviewElPos(
- e.originEvent.clientX,
- e.originEvent.clientY
- );
- } else if (this.drawType === "selection") {
- if (this.elements.hasActiveElement()) {
- let handData = "";
- if (handData = this.elements.checkInResizeHand(
- e.unGridClientX,
- e.unGridClientY
- )) {
- this.cursor.setResize(handData.hand);
- } else {
- this.checkIsOnElement(e);
- }
- } else if (this.selection.hasSelection) {
- let hand = this.selection.checkInResizeHand(
- e.unGridClientX,
- e.unGridClientY
- );
- if (hand) {
- this.cursor.setResize(hand);
- } else {
- this.checkIsOnElement(e);
- }
- } else {
- this.checkIsOnElement(e);
- }
- } else if (this.drawType === "line") {
- this.elements.creatingLine(null, null, e, false, true);
- this.render.render();
- }
- }
- }
- checkIsOnElement(e) {
- let hitElement = this.elements.checkIsHitElement(e);
- if (hitElement) {
- this.cursor.setMove();
- } else {
- this.cursor.reset();
- }
- }
- resetCurrentType() {
- if (this.drawType !== "selection") {
- this.drawType = "selection";
- this.emit("currentTypeChange", "selection");
- }
- }
- completeCreateNewElement() {
- this.resetCurrentType();
- this.elements.completeCreateElement();
- this.render.render();
- }
- onMouseup(e) {
- if (this.state.readonly || this.mode.isDragMode) {
- return;
- }
- if (this.drawType === "text") {
- if (!this.textEdit.isEditing) {
- this.createTextElement(e);
- this.resetCurrentType();
- }
- } else if (this.imageEdit.isReady) {
- this.elements.creatingImage(e, this.imageEdit.imageData);
- this.completeCreateNewElement();
- this.cursor.reset();
- this.imageEdit.reset();
- } else if (this.drawType === "arrow") {
- this.elements.completeCreateArrow(e);
- this.completeCreateNewElement();
- } else if (this.drawType === "line") {
- this.elements.completeCreateLine(e, () => {
- this.completeCreateNewElement();
- });
- this.render.render();
- } else if (this.elements.isCreatingElement) {
- if (this.drawType === "freedraw") {
- this.elements.completeCreateElement();
- this.elements.setActiveElement();
- } else {
- this.completeCreateNewElement();
- }
- } else if (this.elements.isResizing) {
- this.elements.endResize();
- this.emitChange();
- } else if (this.selection.creatingSelection) {
- this.selection.onMouseup(e);
- } else if (this.selection.isResizing) {
- this.selection.endResize();
- this.emitChange();
- }
- }
- onDblclick(e) {
- if (this.drawType === "line") {
- this.completeCreateNewElement();
- } else {
- let hitElement = this.elements.checkIsHitElement(e);
- if (hitElement) {
- if (hitElement.type === "text") {
- this.elements.editingText(hitElement);
- this.render.render();
- this.keyCommand.unBindEvent();
- this.textEdit.showTextEdit();
- }
- } else {
- if (!this.textEdit.isEditing) {
- this.createTextElement(e);
- }
- }
- }
- }
- onTextInputBlur() {
- this.keyCommand.bindEvent();
- this.elements.completeEditingText();
- this.render.render();
- this.emitChange();
- }
- createTextElement(e) {
- this.elements.createElement({
- type: "text",
- x: e.clientX,
- y: e.clientY
- });
- this.keyCommand.unBindEvent();
- this.textEdit.showTextEdit();
- }
- onMousewheel(dir) {
- let stepNum = this.state.scrollStep / this.state.scale;
- let step = dir === "down" ? stepNum : -stepNum;
- this.scrollTo(this.state.scrollX, this.state.scrollY + step);
- }
- onContextmenu(e) {
- let elements = [];
- if (this.elements.hasActiveElement()) {
- elements = [this.elements.activeElement];
- } else if (this.selection.hasSelectionElements()) {
- elements = this.selection.getSelectionElements();
- }
- this.emit("contextmenu", e.originEvent, elements);
- }
- emitChange() {
- let data = this.getData();
- this.history.add(data);
- this.emit("change", data);
- }
- }
- TinyWhiteboard.utils = utils;
- TinyWhiteboard.checkHit = checkHit;
- TinyWhiteboard.draw = draw;
- TinyWhiteboard.elements = Elements;
- export { TinyWhiteboard as default };
|