ड्रैग किए जा सकने वाले ऑब्जेक्ट लागू करना
(redblobgames.com)- Red Blob Games के इंटरैक्टिव डायग्राम में, जब पाठक किसी ऑब्जेक्ट को सीधे हिलाते हैं तो स्क्रीन को तुरंत प्रतिक्रिया देनी होती है, इसलिए input handling को Pointer Events पर केंद्रित करके व्यवस्थित किया गया है ताकि mouse और touch दोनों को साथ संभाला जा सके
- पुराने
mousedown/mouseup/mousemoveतरीके में, जब pointer ऑब्जेक्ट से बाहर निकल जाता था या बाहर button छोड़ा जाता था, तो drag state गड़बड़ा सकती थी, इसलिए global handler जैसे पूरक उपायों की जरूरत पड़ती थी - touch input में event delivery का तरीका mouse से अलग होता है, और एक उंगली से drag करने पर page scroll भी हो सकता है, इसलिए टकराव कम करने के लिए
touchstartमेंpreventDefault()को call किया जाता है - अंतिम recipe में
pointerdown,pointermove,pointerup,pointercancelऔरsetPointerCapture()को मिलाया गया है, और left button व शुरुआती offset की जांच करके यह सुनिश्चित किया गया है कि ऑब्जेक्ट अचानक उछले नहीं - text·image वाले ऑब्जेक्ट, multi-touch, nested drag,
<canvas>, hover और drag का combination,lostpointercaptureजैसी platform-specific exceptions को वास्तविक UI में अलग से handle करना पड़ता है
Drag input handler का लक्ष्य
- कई interactive pages में ऐसे draggable objects होते हैं जिन्हें पाठक सीधे हिला सकते हैं, और diagram को object position में बदलाव पर प्रतिक्रिया देनी होती है
- लक्ष्य ऐसा input event handler बनाना है जो mouse और touch input दोनों पर काम करे
- basic flow यह है कि
pointerdownपर drag शुरू हो,pointermoveपर position update हो, औरpointerupया cancel event पर drag समाप्त हो - actual implementation में mouse buttons, कई उंगलियों का touch, event delivery target, और right-click context menu की वजह से यह simple model से ज्यादा जटिल हो जाता है
- basic recipe इन elements को combine करती है
pointerdownमें अगरevent.button !== 0हो तो return करके केवल primary button process करें- event coordinates को diagram coordinates में convert करें
- शुरुआत में object position और pointer position के बीच का अंतर
dx,dystore करें el.setPointerCapture(event.pointerId)से pointer capture करेंpointermoveमें stored offset जोड़करstate.posupdate करेंpointerup,pointercancelमेंstate.dragging = nulltouchstartमेंpreventDefault()call करें
- यह recipe input event handler है, और actual output processing को अलग state handler से जोड़ना होगा
- पूरा code examples page पर है, जिसमें object movement के अलावा number को left-right drag करना, canvas painting, और restricted drag के examples भी शामिल हैं
- test coverage में Gecko/Firefox, Blink/Chrome, WebKit/Safari के Mac, Windows, Linux, Android, iPhone, iPad शामिल हैं
- hover-capable stylus, hybrid touch+mouse devices, और voice input को test नहीं किया गया
- यह तरीका HTML Drag and Drop API नहीं है, जिसमें किसी element को दूसरे element के ऊपर रखा जाता है; diagrams में mouse·touch events को सीधे पढ़ना पड़ता है
केवल mouse events इस्तेमाल करने की सीमाएं
- शुरुआती implementation में
mousedown,mouseup,mousemoveको सीधे draggable element पर attach किया गया था - ऊपर से यह काम करता हुआ दिखता है, लेकिन दो समस्याएं आती हैं
- pointer को तेजी से हिलाने पर वह अब circle के ऊपर नहीं रहता, इसलिए events नहीं मिलते
- circle के बाहर button छोड़ने पर
draggingstate में फंस सकते हैं
- सुधार यह है कि
mousedowncircle पर लिया जाए, और drag के दौरानmousemoveवmouseupको अस्थायी रूप सेdocumentपर attach किया जाए mouseupमेंdocumentपर लगेmousemove,mouseuphandlers हटाने से mouse drag ज्यादा stable तरीके से काम करता है- यह तरीका केवल mouse को handle करता है और touch events को नहीं संभालता
touch events का अंतर
- touch input में
mousedown,mouseup,mousemoveकी जगहtouchstart,touchend,touchmoveका इस्तेमाल होता है touchstartके बाद touch events अपने-आप capture हो जाते हैं और सभीtouchmoveमूल element तक deliver होते हैं- इस वजह से mouse events की तरह
documentपर temporary global event handler attach करने की जरूरत नहीं होती - जब browser को touch sequence cancel करना होता है, तो वह
touchcancelभेजता है - touch drag implementation
touchstartमेंpreventDefault()call करता है, औरtouchmoveमेंevent.changedTouches[0]coordinates से position update करता है - यह तरीका केवल touch को handle करता है और mouse events को process नहीं करता
Pointer Events से mouse और touch को integrate करना
- mouse और touch दोनों को handle करने के लिए कई event handlers की जरूरत पड़ती थी, और 2021 से पहले इसी तरह का तरीका इस्तेमाल होता था
- 2011~2014 में d3 projects में d3-drag का इस्तेमाल किया गया, और जिन projects में d3 नहीं था उनमें अलग mouse+touch code बनाया गया
- Pointer Events mouse और touch handling को integrate और simplify करते हैं
- MS IE ने 2012 में support जोड़ा
- Chrome ने 2017 में, Firefox ने 2018 में, और Safari ने 2020 में support जोड़ा
- browser behavior समय के साथ बदला, और 2017 में Chrome ने कुछ events को default passive mode में बदल दिया, जिससे object को drag करने की कोशिश करते समय page scroll होने की समस्या आई
- Safari और Firefox ने भी 2018 में वही बदलाव लागू किया
- pointer capture का इस्तेमाल करने पर mouse events में जिन
documentglobal handlers को add/remove करना पड़ता था, उनके बिना simple logic से काम हो जाता है
Pointer Capture से pointer tracking बनाए रखना
- Pointer capture pointer के circle, diagram, या browser window से बाहर निकल जाने पर भी tracking जारी रखने देता है
- mouse events में वही effect पाने के लिए
documentपर event handler attach करना पड़ता था, लेकिन Pointer Events मेंsetPointerCapture(event.pointerId)ज्यादा simple है - pointer capture न हो तो तेजी से drag करने या diagram से बाहर जाकर वापस आने पर drag रुक सकता है
- diagram के बाहर button छोड़ने या Alt+Tab से दूसरी window में जाने जैसे मामलों में भी capture होने या न होने के आधार पर drag end handling अलग होती है
- touch devices में pointer capture default behavior है, लेकिन mouse में इसे explicitly set करना पड़ता है
touch scroll और preventDefault()
- touch devices पर एक उंगली से drag करना default रूप से page scroll कराता है
- अगर उसी one-finger drag से circle भी move हो, तो scroll और object drag साथ-साथ होते हैं
- सबसे simple solution diagram पर CSS
touch-action: noneapply करना है, लेकिन ऐसे में diagram के किसी भी हिस्से में scroll नहीं किया जा सकता - desired behavior यह है कि circle drag करते समय ही scroll रोका जाए, और diagram को drag करते समय scroll allow रहे
- comparison result इस प्रकार है
- पूरे diagram पर
touch-action: none: circle drag और diagram drag दोनों में scroll रुकता है - default value: दोनों में scroll को रोक नहीं पाती
- केवल circle पर
touch-action: none: उम्मीद के मुताबिक काम नहीं करता touchstartमेंpreventDefault(): circle drag के दौरान केवल scroll रोकता है और diagram scroll allow करता है
- पूरे diagram पर
preventDefault()कोpointerstartपर नहीं, बल्किtouchstartपर attach करें- यह तरीका ज्यादातर स्थितियों में काम करता है, लेकिन desktop Firefox के “mobile emulation mode” में काम नहीं किया, जबकि Android के mobile Firefox में काम करता है
ड्रैग शुरू होने का ऑफसेट सहेजना
- ऑब्जेक्ट के किनारे को पकड़कर ड्रैग करते समय अगर ऑब्जेक्ट का केंद्र तुरंत pointer की position पर jump कर जाए, तो usability खराब होती है
- समाधान है कि ड्रैग शुरू होते समय ऑब्जेक्ट के केंद्र और pointer position की relative position को सहेजा जाए
- इसके बाद move करते समय मौजूदा pointer coordinates में सहेजे गए
dx,dyजोड़कर ऑब्जेक्ट की position calculate की जाती है - इस तरीके में
state.draggingको simpletrue/falseके बजाय{dx, dy}जैसी relative position जानकारी में बदला जाता है - mouse में किनारे से पकड़ने पर jump का फर्क साफ दिखता है, जबकि touch में उंगली से ढक जाने की वजह से यह कम दिख सकता है
- इससे जुड़ी छोटी detail little details पेज पर भी संक्षेप में दी गई है
context menu और mouse button
- context menu activate करने का तरीका हर platform पर अलग होता है
- Windows: right-click down+up, Shift+F10
- Linux: right button down, Shift+F10
- Mac: right button down, Ctrl+left click
- iOS: केवल text पर long press
- Android: कहीं भी long press
- समस्या यह है कि कभी-कभी
pointerdownदिखता है, लेकिनpointerupहमेशा नहीं दिखता - button असल में release हो चुका हो, फिर भी code में उसे अभी pressed state में माना जा सकता है
- इसका उपाय है right button को ignore करना और केवल left mouse button पर ही
draggingstate set करना - Pointer Events specification के
buttonproperty मेंbutton = 0primary button को दर्शाता है, और इसका उपयोग करके middle और right button को exclude किया जाता है - Mac के Chrome और Safari में Ctrl+click left button
pointerdownकी तरह आ सकता है, इसलिएevent.ctrlKeyभी check करना चाहिए - विकल्प इस प्रकार हैं
contextmenuमेंpreventDefault()से menu को रोका जा सकता है, लेकिन यह default middle click या drag behavior से conflict कर सकता है- केवल left button से drag करने पर right-click से जुड़े ज्यादातर differences से बचा जा सकता है
- Mac Ctrl+click से भी बचना हो तो
ctrlKeyको भी exclude करना चाहिए
- button changes
pointerdownयाpointerupके रूप में deliver न हों, तब भीpointermoveके button state से कुछ हद तक check किया जा सकता है
text और image वाले ऑब्जेक्ट
- अगर draggable element के अंदर text या image हो, तो अतिरिक्त handling की जरूरत होती है
- circle को drag करते समय अंदर का text select हो सकता है
- समाधान है CSS
user-select: noneapply करना- हमेशा apply करने पर अंदर का text कभी select नहीं होगा
- केवल drag के दौरान apply करने पर सामान्य समय में text selection संभव रहेगा
- 2023 की शुरुआत तक Safari अभी unprefixed
user-selectsupport नहीं करता था, इसलिएwebkitUserSelectभी साथ में set करना चाहिए - Windows, Linux, Mac text और image के applications के बीच drag and drop को support करते हैं, और यह object drag से conflict करता है
dragstartमेंpreventDefault()call करने से selected text या image drag के बजाय object drag को priority दी जा सकती है- browser और operating system के अनुसार behavior थोड़ा-थोड़ा अलग होता है
multiple pointers और simultaneous drag
- कई fingers या कई mouse से कई objects को एक साथ drag किया जा सकता है या नहीं, यह edge case है
- touch में दिया गया code कई objects को साथ-साथ drag करने के लिए पहले से काम करता है
- दो fingers से उसी object को drag करने के मामले में अलग handling की जरूरत होती है
- समाधान है कि
pointerdownमेंevent.pointerIdकोstate.draggingया state में save किया जाए, औरpointermoveमें अगर वहीpointerIdनहीं है तो ignore किया जाए - यह implementation example article में पूरी तरह apply नहीं किया गया है, और इसे canvas dragging test में देखा जा सकता है
- mouse के मामले में Pointer Events specification बताता है कि सामान्य operating systems और user agents में आम तौर पर multiple mouse inputs की concept नहीं होती
- trackpad और external mouse साथ होने पर भी आम तौर पर उन्हें एक ही mouse pointer माना जाता है, इसलिए अलग-अलग mouse से अलग objects drag करने का तरीका नहीं माना जाता
कई mouse buttons साथ में दबाने पर
- कई mouse buttons एक साथ दबाने पर Pointer Events और Mouse Events का behavior अलग होता है
- Mouse Events हर button press पर
mousedown, और हर button release परmouseupभेजते हैं - Pointer Events specification के अनुसार पहले दबाए गए button पर
pointerdown, और आखिरी release किए गए button परpointerupfire होता है - इस वजह से
pointerdownऔरpointerupअलग-अलग button states में हो सकते हैं - उदाहरण के लिए left button दबाकर, right button दबाने के बाद, left button छोड़ने पर object लगातार dragging state में रह सकता है
- समाधान है कि
pointermoveमेंevent.buttons & 1से left button state check की जाए, और अगर वह अब pressed नहीं है तोend(event)call किया जाए - pointer capture सभी buttons छोड़े जाने तक जारी रह सकता है, और explicitly capture release न करने तक बना रह सकता है
- यह implementation इस समस्या और कई edge cases को पूरी तरह handle नहीं करता
nested drag elements
- अगर draggable element के अंदर एक और draggable element हो, तो inner और outer दोनों elements drag को handle करते हैं
- समाधान है कि inner drag element में
event.stopPropagation()call करके event को outer drag element तक ऊपर जाने से रोका जाए pointerdownऔरpointermoveदोनों में propagation रोकने का तरीका इस्तेमाल होता है- demo article में नहीं है, लेकिन Vue playground example में red drag element के yellow drag element का child होने वाला case देखा जा सकता है
Canvas में Drag
- आम तौर पर SVG का इस्तेमाल किया जाता है, लेकिन
<canvas>में drag किए जा सकने वाले element पर सीधे event handler या mouse pointer का आकार सेट नहीं किया जा सकता - 2D Canvas या WebGL में event handler को
<canvas>पर लगाना पड़ता है, और खुद तय करना पड़ता है कि coordinates किसी draggable object के ऊपर हैं या नहीं -处理 करने का तरीका इस प्रकार हैpointerdown,touchstart,dragstart: अगर draggable object के ऊपर नहीं है, तो तुरंत return करेंpointermove: cursor को इस आधार पर सेट करें कि वह draggable object के ऊपर है या नहीं
- Demo examples page पर है
Mouse Hover और Touch Drag का संयोजन
- कुछ diagrams mouse पर button दबाए बिना hover से react करते हैं, और touch devices में hover नहीं होता, इसलिए उन्हें drag से react करना चाहिए
- Basic recipe mouse और touch दोनों में drag की उम्मीद करती है
- Mouse hover और touch drag को साथ इस्तेमाल करने के लिए
pointermoveमेंif (!state.dragging)condition हटाएँ - Responsive Design page पर mouse से row पर hover करने पर layout बदलता है, और touch में drag करने पर layout बदलता है
- Hexagons Guide में भी कई diagrams mouse hover और touch drag को साथ इस्तेमाल करते हैं
- Touch में item A से B तक drag करते समय अगर capture बना रहता है, तो move event A को deliver होता है, इसलिए B को highlight करने के लिए capture release करना पड़ सकता है
Toggle Paint और Drag State का विस्तार
- Rounded Cell Painter में
pointerdownशुरुआती paint color को capture करता है - इसके बाद
pointerupतक सभीpointermoveवही paint color इस्तेमाल करते हैं - इसके लिए
state.draggingमें शुरुआतीx,yके साथ-साथ शुरुआती paint color भी शामिल होना चाहिए - Demo examples page पर है
lostpointercapture Edge Case
lostpointercaptureका इस्तेमाल यह detect करने के लिए किया जा सकता है कि pointer capture खो गया है या नहीं- यह किन situations में होता है और क्या करना चाहिए, यह अभी पूरी तरह व्यवस्थित नहीं है
- Comments में चर्चा किया गया scenario इस प्रकार है
- Left button से circle drag करना शुरू करें
- Left button दबाए रखते हुए drag area के बाहर जाएँ
- Right button दबाएँ और फिर left button छोड़ें
- Drag area के बाहर कहीं भी click करें
- standard कहता है कि pointer capture release होने के बाद user agent को
lostpointercaptureevent अनिवार्य रूप से fire करना चाहिए - वास्तविक browser behavior काफी अलग-अलग है; कुछ systems में
lostpointercapturefire होता है, लेकिन कुछ में यह तब तक fire नहीं होता जब तक कहीं और click न किया जाए
1 टिप्पणियां
Hacker News की टिप्पणियां
यह लेख drag के बारे में है, और Amit ने जिन pitfalls की बात की है उनमें से लगभग सभी से मैं गुजरा हूं और उसी समाधान तक पहुंचा हूं। शानदार लेख है
यूज़र के नजरिए से drag करके क्रम बदलना बहुत स्वाभाविक लगता है, लेकिन अलग-अलग आकार के items, items के बीच placeholder बनाना, edge detection, और box-fitting algorithms की rabbit hole तक पहुंचते-पहुंचते इसे खुद implement करना काफी मुश्किल श्रेणी में आ जाता है
mouse के हर move पर उन positions में से वर्तमान drag object position के सबसे करीब वाली चुनें, और selected layout render कर दें। complex layouts या reflow में भी यह अच्छा feel देता है
आखिर में मैंने ऐसा किया कि card उठाते ही layout ऐसे calculate किया जैसे वह card board से delete हो गया हो, और इससे काम आसान हो गया। बस mouse-over वाली position पर मौजूद चीजों को धकेलना था
फिर भी exception handling बहुत ज्यादा थी, खासकर तब जब कोई नया card edit करना शुरू होता था जो अभी data model में “commit” नहीं हुआ था। मौजूदा cards को धकेलकर ghost card की जगह बनाने का option भी जोड़ना पड़ा
यह मान लेना मददगार है कि बहुत सारे exceptions manually handle करने होंगे। अगर आप यह सोचकर approach करेंगे कि कोई ज्यादा general और homogeneous solution होगा, तो design में गोल-गोल घूमते रहेंगे। कभी न कभी अलग-अलग edge cases को blog post में整理 करना चाहिए
मुझे एक बेहतर layout तरीका भी मिला, जो अनावश्यक calculations कम करता है और layout engine को ज्यादा flexible और user-friendly बनाता है। data model representation कैसे चुना जाता है, यह solution में कितना बड़ा फर्क डालता है, यह हैरान करने वाला है
[1] https://www.ussherpress.com/cardbuddy/
लगता है लेख में cancel handling को cover नहीं किया गया है। उदाहरण के लिए Windows में Escape दबाने पर drag cancel करने की convention है
कभी-कभी आप यह भी चाहते हैं कि defined area के बाहर mouse छोड़ने पर drag cancel हो जाए। cancel यूज़र को तेज undo, या “अरे, असल में मैं drag करना नहीं चाहता था” जैसा escape route देता है
इसलिए अलग undo feature न भी हो, तब भी drag शुरू होने के समय की original state save रखनी चाहिए और cancel होने पर restore करनी चाहिए
area के बाहर drag cancel करने के मामले में cancel解除 भी होता है। जब pointer area के बाहर हो, तो visually दिखाएं कि original state पर वापस लौट गया है; और pointer फिर से area के अंदर आए तो drag resume हो जाए। actual cancel mouse छोड़ने पर होता है, लेकिन drag के दौरान ही पहले से visual संकेत दे दिया जाता है कि cancel होने वाला है
यकीन नहीं होता कि Microsoft अब भी इसे अच्छा UI design मानता है। यह यूज़र को पूरी तरह confuse कर देता है; कई बार लोग समझ नहीं पाते कि क्या हो रहा है और left mouse button छोड़ने से डरते हैं, या yo-yo की तरह बार-बार वही करते दिखते हैं
सहमत हूं कि cancel एक बड़ा मुद्दा है जिसे अक्सर नजरअंदाज किया जाता है, और यह simple नहीं है। आम यूज़र को यह भी पता नहीं होता कि ESC मदद कर सकता है
Ardour [0] के GUI में तरह-तरह के objects drag करने का काम 20 साल करते हुए मैंने कुछ अतिरिक्त details सीखी हैं: हर button press और release event को बिना movement वाले drag event की तरह treat करना चाहिए
यानी press हमेशा drag शुरू करता है और release पर खत्म होता है; release handle करने वाला code no-movement condition को special-case करता है
[0] https://ardour.org/
मेरे पास सामान्य
mousedownऔरmouseuphandlers हैं, और यह तय करने के लिए कि यह click है, drag की शुरुआत है या कोई दूसरी action, मैं करीब 150ms का configurable timeout इस्तेमाल करता हूं।mouseupआए, या mouse screen से बाहर चला गया हो और कोई drag चल रहा हो, तोstopdragकरता हूं। मेरे लिए drag कई special cases में से बस एक हैबहुत पहले Minneapolis में NSF द्वारा supported एक geometry center था। computational group theory की conference हुई थी, और आसपास के fields से mascot जैसे कुछ लोगों को invite किया गया था
मुझे इसलिए invite मिला क्योंकि मैंने algebraic geometry system लिखा था, और -20°F की ठंड में बहुत सुबह उठकर उस दिन इस्तेमाल करने के लिए Silicon Graphics workstation हासिल किया, फिर group generators और relations को बेहतर समझने के लिए एक game code किया
उस game में drag शामिल था। नतीजा यह हुआ कि रात 2 बजे तक चली conversations बहुत अच्छी रहीं। मेरा विचार था कि drag को real world के physics laws follow करने की जरूरत नहीं है, और drag को बहुत strong LSD tab जैसा feel होना चाहिए। हर कोई इसमें डूब गया और अपने-अपने ideas लेकर आया
यह लेख वेब ब्राउज़र में आने वाले कई edge cases को अलग रख दें तो अपेक्षाकृत बुनियादी drag को implement करता है। मैं जानना चाहूँगा कि क्या ऐसे drag resources हैं जिनमें constraints हों, जैसे guidelines पर snap करना, boundaries या दूसरे objects से collision रोकना, या drag action के response में size या position बदलने वाले animated drop targets
पहले मैं एक custom Pomodoro timer UI बनाना चाहता था, जिसमें circular clock को अलग-अलग लंबाई के wedge pieces में बाँटकर focus/rest intervals define किए जाते। उन wedge pieces की drag-based reordering implement करने में ज़्यादा progress नहीं हुई
मैं constraint system को event handling system से अलग रखना चाहता था। jquery-ui जैसी libraries दोनों को बाँध देती हैं, जिससे event handling system को सभी possible constraints के बारे में पता होना पड़ता है। jquery-ui bounding box, axis, square grid, और DOM element पर snap support करता है। लेकिन अगर आप hex grid, log-scale grid, या circular boundary पर snap करना चाहें, तो वह support नहीं है
Code में
state.pos = …दिखता है, वही जगह है जहाँ state set किया जाता है। Constraints के लिएposको setter के पीछे छिपा दें। तब drag event handling code को यह जाने बिना कि कौन-से constraints चाहिए, setter constraints apply कर सकता हैमुझे page update करके constraint example दिखाना चाहिए। Code recipe में इस पहलू का ज़िक्र करना मैं पूरी तरह भूल गया
पुराना constraint example https://www.redblobgames.com/articles/curved-paths/making-of... पर है, और collision avoidance example https://redblobgames.github.io/circular-obstacle-pathfinding... पर है। हालांकि drag-based reordering या animated drop targets अभी तक try नहीं किए
इस site का मैं भी आभारी हूँ। Uber में geo analysis के लिए hexagon system design करते समय https://www.redblobgames.com/grids/hexagons/ का बहुत reference लिया था
Proper interactions handle करते समय आने वाले pitfalls और सावधानियों को यह लेख अच्छी तरह summarize करता है
ज़्यादा “ready-to-use” तरफ़, मैंने कई projects में interactjs को काफी लंबे समय तक use किया है
सभी का धन्यवाद। आज HN पर इसे देखकर हैरानी हुई, और मैं questions का जवाब दे सकता हूँ
draggable="true"attribute और drag events देखे हैं?यह भी जानना चाहूँगा कि built-in functionality इस code की तुलना में कहाँ कम पड़ती है
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement...
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement...
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_att...
एक quick question है।
dragstartजैसे built-in DOM events से drag movement को एक axis तक limit कैसे करें? मैंनेdragstart/dragenter/dragover/dropevents से drag and drop functionality implement की है, लेकिन movement को x-axis तक limit करने का quick तरीका नहीं मिला। याद है कि JQuery का drag and drop API इसे support करता था। मैं केवल native DOM events/API use करने की कोशिश कर रहा हूँ, इसलिए इस बारे में कोई information या pointer मिले तो अच्छा होगायह देखते हुए कि Safari ने 2020 में support add किया था, क्या आपको चिंता नहीं होती कि browsers इसे support न करें? macOS Mojave users भी शायद Safari 13 या 14 use कर रहे होंगे, इसलिए उम्मीद है Safari 12 practically अब use में नहीं है, लेकिन general web users के लिए production app में drag जैसी simple functionality न चले तो यह काफी बुरा होगा
Drag के दौरान
documentपर event handler add करना पुरानी practice है, और browsers use cases को सरल बनाने के लिए नई features add करते रहते हैं, लेकिन हर feature के अपने exceptions और pitfalls होते हैं। लेख में भी कहा गया है कि इसे अभी पूरी तरह cover नहीं किया गया। Final result में भी pointer events और touch events का combination बचा हुआ हैमैं सोच रहा हूँ कि code कम होने के अर्थ में “simplicity” क्या इतने लायक है कि उसके बदले extra exceptions, कम browser support, और developers को pointer events की उन details और browser differences को समझने की cost उठानी पड़े, जो mouse events की तुलना में शायद कम understood और कम documented हैं
एक चीज़ छूट गई है: accessibility. कीबोर्ड ऑपरेशन से drag को कैसे संभव बनाना चाहिए?
मेरे उदाहरण में accessibility का जवाब यह है कि उस काम को पूरा करने के लिए अतिरिक्त keyboard operation दिया जाए. बेहतर हो तो ऐसा तरीका जिसमें key को लगातार दबाए रखना न पड़े. उदाहरण के लिए, shortcut से panning mode में जाएँ और arrow keys से viewport को canvas के इधर-उधर move करें, तो काम हो जाएगा
draggable object के मामले में काम order बदलना है. इसे accessible बनाने के लिए order बदलने का वैकल्पिक तरीका देना काफी है. उदाहरण के लिए, TAB से objects के बीच focus घुमाएँ, key से focused object को select करें, और फिर arrow keys से drag preview को उस दिशा में निकटतम valid position तक ले जाएँ
यानी drag implementation के अंदर keyboard support को जबरन न ठूँसें; drag feature से अलग, अर्थपूर्ण keyboard functionality जोड़नी चाहिए
बढ़िया. इस हफ्ते की शुरुआत में मैं एक Vue app में SVG elements को drag करना implement कर रहा था, और लेखक ने जिन लगभग सभी बातों को समझाया है, उन्हें मुझे उसी क्रम में खुद discover करना पड़ा; अंत में component भी लगभग वैसा ही बना
हालांकि मैंने functional component के बजाय इसे
useDraggingनाम की composable utility के रूप में लिखा