Sürüklenebilir Nesneleri Uygulamak
(redblobgames.com)- Red Blob Games’in etkileşimli diyagramlarında, okur nesneleri doğrudan hareket ettirdiğinde ekranın anında tepki vermesi gerekir; bu yüzden giriş işleme Pointer Events merkezli düzenlenerek fare ve dokunma birlikte ele alınır
- Eski
mousedown/mouseup/mousemoveyaklaşımında, işaretçi nesnenin dışına çıktığında veya düğme dışarıda bırakıldığında sürükleme durumu karışabildiği için, genel işleyiciler gibi ek önlemler gerekiyordu - Dokunma girdisinde olay iletimi fareden farklıdır ve tek parmakla sürükleme sayfanın kaymasına da yol açtığından,
touchstartiçindepreventDefault()çağrılarak çakışma azaltılır - Nihai tarif,
pointerdown,pointermove,pointerup,pointercancelvesetPointerCapture()birleşimini kullanır; ayrıca nesnenin aniden sıçramaması için sol düğme ile başlangıç ofseti kontrol edilir - Metin/görsel içeren nesneler, çoklu dokunma, iç içe sürükleme,
<canvas>, hover ile drag birleşimi velostpointercapturegibi platforma özgü istisnalar gerçek arayüzlerde ayrıca ele alınmalıdır
Sürükleme giriş işleyicisinin hedefi
- Birçok etkileşimli sayfada, okurun doğrudan hareket ettirdiği sürüklenebilir nesneler bulunur ve diyagramın nesne konumundaki değişime tepki vermesi gerekir
- Amaç, hem fare hem de dokunma girdisinde çalışan bir giriş olayı işleyicisi oluşturmaktır
- Temel akış,
pointerdownile sürüklemeyi başlatmak,pointermoveile konumu güncellemek vepointerupya da iptal olayında sürüklemeyi bitirmekten oluşur - Gerçek uygulamada fare düğmeleri, çok parmaklı dokunma, olayın iletildiği hedef ve sağ tık bağlam menüsü yüzünden yapı basit modelden daha karmaşık hale gelir
- Temel tarif şu öğeleri birleştirir
pointerdowniçindeevent.button !== 0ise dönerek yalnızca birincil düğmeyi işleme- Olay koordinatlarını diyagram koordinatlarına dönüştürme
- Başlangıçta nesne konumu ile işaretçi konumu arasındaki fark olan
dx,dydeğerlerini saklama el.setPointerCapture(event.pointerId)ile işaretçiyi yakalamapointermoveiçinde kayıtlı ofseti ekleyerekstate.posdeğerini güncellemepointerup,pointercanceliçindestate.dragging = nulltouchstartiçindepreventDefault()çağırma
- Bu tarif bir giriş olayı işleyicisidir; gerçek çıktı işleme mantığının ayrı bir durum işleyicisine bağlanması gerekir
- Tam kod examples page üzerinde yer alır; burada nesne taşımaya ek olarak sayıları sağa sola sürükleme, canvas boyama ve kısıtlı sürükleme örnekleri de bulunur
- Test kapsamı; Gecko/Firefox, Blink/Chrome, WebKit/Safari ile Mac, Windows, Linux, Android, iPhone ve iPad’i içerir
- Hover yapabilen stylus, hibrit dokunma+fare cihazları ve sesli giriş test edilmemiştir
- Bu yaklaşım, bir öğeyi başka bir öğenin üstüne bırakmak için kullanılan HTML Drag and Drop API değildir; diyagramlarda fare ve dokunma olaylarını doğrudan okumak gerekir
Yalnızca fare olaylarını kullanmanın sınırları
- İlk uygulama,
mousedown,mouseup,mousemoveolaylarını doğrudan sürüklenen öğeye bağlama yöntemiydi - Yüzeyde çalışıyor gibi görünse de iki sorun ortaya çıkıyordu
- İşaretçi hızlı hareket edince artık çemberin üstünde olmayabiliyor ve olayları alamıyordu
- Düğme çemberin dışında bırakılırsa
draggingdurumunda takılı kalınabiliyordu
- İyileştirme olarak
mousedownçemberden alınırken, sürükleme sırasındamousemovevemouseupolayları geçici olarakdocumentüzerine ekleniyordu mouseupiçindedocumentüzerine eklenenmousemove,mouseupişleyicileri kaldırılınca fareyle sürükleme daha kararlı çalışıyordu- Bu yaklaşım yalnızca fareyi ele alır; dokunma olaylarını kapsamaz
Dokunma olaylarının farkları
- Dokunma girdisi,
mousedown,mouseup,mousemoveyerinetouchstart,touchend,touchmovekullanır - Dokunma olayları
touchstartsonrasında otomatik olarak capture edilir; böylece tümtouchmoveolayları özgün öğeye iletilir - Bu özellik sayesinde, fare olaylarında olduğu gibi
documentüzerine geçici genel olay işleyicileri eklemek gerekmez - Tarayıcı dokunma dizisini iptal etmek zorunda kaldığında
touchcancelgönderir - Dokunma sürükleme uygulamasında
touchstartiçindepreventDefault()çağrılır vetouchmoveiçindeevent.changedTouches[0]koordinatlarıyla konum güncellenir - Bu yaklaşım yalnızca dokunmayı ele alır; fare olaylarını ele almaz
Pointer Events ile fare ve dokunmayı birleştirmek
- Hem fareyi hem dokunmayı desteklemek için çok sayıda olay işleyicisi gerekiyordu ve 2021’den önce bu şekilde çalışılıyordu
- 2011~2014 arasında d3 projelerinde d3-drag kullanıldı; d3 kullanılmayan projelerde ise ayrı fare+dokunma kodu yazıldı
- Pointer Events, fare ve dokunma işlemeyi birleştirip sadeleştirir
- MS IE, desteği 2012’de ekledi
- Chrome 2017’de, Firefox 2018’de, Safari 2020’de destek ekledi
- Tarayıcı davranışı zaman içinde değişti; 2017’de Chrome bazı olayları varsayılan olarak passive mode durumuna getirince, nesne sürüklemeye çalışırken sayfanın kayması sorunu ortaya çıktı
- Safari ve Firefox da 2018’de aynı değişikliği uyguladı
- pointer capture kullanıldığında, fare olaylarında gereken
documentgenel işleyicilerini ekleyip kaldırmadan daha basit mantıkla işlem yapılabilir
Pointer Capture ile işaretçi takibini sürdürmek
- Pointer capture, işaretçi çemberin, diyagramın ya da tarayıcı penceresinin dışına çıksa bile takibin sürmesini sağlar
- Fare olaylarında aynı etki için
documentüzerine olay işleyicileri eklemek gerekirken, Pointer Events tarafındasetPointerCapture(event.pointerId)daha basittir - İşaretçi yakalama yoksa, hızlı sürüklemede ya da diyagramın dışına çıkıp geri dönüldüğünde sürükleme durabilir
- Düğmenin diyagram dışında bırakılması ya da Alt+Tab ile başka pencereye geçilmesi gibi durumlarda da sürüklemenin sonlandırılması, capture olup olmamasına göre değişir
- Dokunmatik cihazlarda pointer capture varsayılan davranıştır, ancak farede açıkça ayarlanmalıdır
Dokunma kaydırması ve preventDefault()
- Dokunmatik cihazlarda tek parmakla sürükleme varsayılan olarak sayfanın kaymasına neden olur
- Aynı tek parmak sürüklemesi çemberi de hareket ettirirse kaydırma ve nesne sürükleme aynı anda gerçekleşir
- En basit çözüm, diyagrama CSS
touch-action: noneuygulamaktır; ancak bu durumda diyagramın hiçbir yerinde kaydırma yapılamaz - İstenen davranış, yalnızca çember sürüklenirken kaydırmayı engellemek; diyagramın kendisi sürüklenirken ise kaydırmaya izin vermektir
- Karşılaştırma sonuçları şöyledir
- Tüm diyagrama
touch-action: none: hem çember sürüklemede hem diyagram sürüklemede kaydırma durur - Varsayılan değer: ikisinde de kaydırma engellenemez
- Yalnızca çembere
touch-action: none: beklendiği gibi çalışmaz touchstartiçindepreventDefault(): yalnızca çember sürüklerken kaydırmayı engeller, diyagram kaydırmasına izin verir
- Tüm diyagrama
preventDefault()pointerstartyerinetouchstartüzerine eklenir- Bu yaklaşım çoğu durumda çalışır; ancak masaüstü Firefox’un “mobile emulation mode”unda çalışmadı, Android’deki mobil Firefox’ta ise çalıştı
Sürükleme başlangıç ofsetini kaydetme
- Nesnenin kenarından tutup sürüklerken nesnenin merkezinin işaretçi konumuna aniden atlaması kullanım hissini kötüleştirir
- Çözüm, sürükleme başlangıcında nesne merkezi ile işaretçi konumu arasındaki göreli konumu saklamaktır
- Sonrasında hareket ederken saklanan
dx,dydeğerleri mevcut işaretçi koordinatlarına eklenerek nesne konumu hesaplanır - Bu yöntem
state.draggingdeğerini basit birtrue/falseyerine{dx, dy}gibi göreli konum bilgisine dönüştürür - Farede kenardan tutulduğunda sıçrama farkı belirgin biçimde görünür; dokunmada ise parmak kapattığı için daha az fark edilebilir
- Bununla ilgili küçük ayrıntılar little details sayfasında da derlenmiştir
Bağlam menüsü ve fare düğmeleri
- Bağlam menüsünü etkinleştirme şekli platforma göre değişir
- Windows: sağ tık down+up, Shift+F10
- Linux: sağ düğme down, Shift+F10
- Mac: sağ düğme down, Ctrl+sol tık
- iOS: yalnızca metinde long press
- Android: her yerde long press
- Sorun şu ki
pointerdowngörünürkenpointerupher zaman görünmeyebilir - Düğme gerçekte bırakılmış olsa bile kod tarafında hâlâ basılı kabul edilebilir
- Buna karşılık olarak
draggingdurumunu yalnızca sol fare düğmesi için ayarlamak gerekir; sağ düğme yok sayılır - Pointer Events spesifikasyonundaki
buttonözelliğindebutton = 0, primary button anlamına gelir; bu da orta ve sağ düğmeleri hariç tutmak için kullanılabilir - Mac'te Chrome ve Safari'de Ctrl+tık, sol düğme
pointerdowngibi gelebileceğindenevent.ctrlKeyde kontrol edilmelidir - Seçenekler şunlardır
contextmenuiçindepreventDefault()ile menü engellenebilir, ancak bu varsayılan orta tık veya sürükleme davranışıyla çakışabilir- Yalnızca sol düğmeyle sürükleme yapmak çoğu sağ tık farkını önleyebilir
- Mac'teki Ctrl+tık durumunu da önlemek için
ctrlKeyde hariç tutulmalıdır
- Düğme değişimi
pointerdownya dapointerupile iletilmese bilepointermovesırasındaki düğme durumundan kısmen anlaşılabilir
Metin ve görsel içeren nesneler
- Sürüklenebilir öğenin içinde metin veya görsel varsa ek işlem gerekir
- Bir çember sürüklenirken içindeki metin seçilebilir
- Çözüm CSS
user-select: noneuygulamaktır- Her zaman uygulanırsa iç metin hiçbir zaman seçilemez
- Yalnızca sürükleme sırasında uygulanırsa normalde metin seçimi mümkün olur
- 2023 başı itibarıyla Safari, öneksiz
user-selectözelliğini hâlâ desteklemediği içinwebkitUserSelectde birlikte ayarlanmalıdır - Windows, Linux ve Mac; metin ve görseller için uygulamalar arası drag and drop destekler ve bu, nesne sürüklemeyle çakışır
dragstartiçindepreventDefault()çağırmak, seçili metin veya görsel sürüklemesindense nesne sürüklemesine öncelik verebilir- Davranış tarayıcıya ve işletim sistemine göre biraz değişir
Birden fazla işaretçi ve eşzamanlı sürükleme
- Birden fazla parmakla veya birden fazla fareyle birden fazla nesneyi aynı anda sürükleyebilmek bir edge case'tir
- Dokunmada verilen kod, birden fazla nesnenin aynı anda sürüklenmesinde zaten çalışır
- Aynı nesnenin iki parmakla sürüklenmesi durumu için ayrı işlem gerekir
- Çözüm,
pointerdownsırasındaevent.pointerIddeğerinistate.draggingiçine veya duruma kaydetmek vepointermovesırasında aynıpointerIddeğilse yok saymaktır - Bu uygulama örneği metne tamamen uygulanmış değildir; canvas dragging test içinde görülebilir
- Fare için Pointer Events spesifikasyonu, genel işletim sistemleri ve kullanıcı aracıların çoğunlukla birden fazla fare girdisi kavramına sahip olmadığını belirtir
- Trackpad ve harici fare birlikte bağlı olsa bile genelde tek bir fare işaretçisi olarak ele alındıklarından, farklı farelerle farklı nesneleri sürüklemenin mümkün olmadığı değerlendirilir
Birden fazla fare düğmesine aynı anda basıldığında
- Birden fazla fare düğmesine aynı anda basıldığında Pointer Events ile Mouse Events farklı davranır
- Mouse Events, her düğme basışı için
mousedown, her düğme bırakılışı içinmouseupgönderir - Pointer Events spesifikasyonuna göre
pointerdownilk basılan düğmede,pointerupise en son bırakılan düğmede oluşur - Bu nedenle
pointerdownvepointerupfarklı düğme durumlarında meydana gelebilir - Örneğin sol düğmeye basıp ardından sağ düğmeye basar, sonra sol düğmeyi bırakırsanız nesne sürükleme durumunda kalmaya devam edebilir
- Çözüm,
pointermoveiçindeevent.buttons & 1ile sol düğmenin durumunu kontrol etmek ve artık basılı değilseend(event)çağırmaktır - Pointer capture, tüm düğmeler bırakılana kadar sürebilir ve açıkça serbest bırakılmazsa devam edebilir
- Bu uygulama bu sorunu ve diğer birçok edge case'i tamamen ele almaz
İç içe sürüklenebilir öğeler
- Sürüklenebilir bir öğenin içinde başka bir sürüklenebilir öğe varsa hem içteki hem dıştaki öğe sürüklemeyi işler
- Çözüm, içteki sürükleme öğesinde
event.stopPropagation()çağırarak olayın dıştaki sürükleme öğesine yükselmesini engellemektir - Bunun için hem
pointerdownhem depointermovesırasında yayılım durdurulur - Demo metinde yoktur, ancak Vue playground örneğinde kırmızı sürüklenebilir öğenin sarı sürüklenebilir öğenin çocuğu olduğu örnek görülebilir
Canvas'ta sürükleme
- Genellikle SVG kullanılır, ancak
<canvas>içinde sürüklenebilir öğenin kendisine olay işleyicileri veya fare imleci biçimi atanamaz - 2D Canvas veya WebGL'de olay işleyicileri
<canvas>öğesine eklenmeli ve koordinatların sürüklenebilir nesnenin üzerinde olup olmadığı doğrudan belirlenmelidir - İşleme yöntemi şöyledir
pointerdown,touchstart,dragstart: sürüklenebilir nesnenin üzerinde değilse hemen geri dönpointermove: sürüklenebilir nesnenin üzerinde olup olmamasına göre imleci ayarla
- Demo examples page üzerinde bulunuyor
Fare hover ve dokunmatik drag birleşimi
- Bazı diyagramlar farede düğmeye basılmadan hover ile tepki verir; dokunmatik cihazlarda ise hover olmadığı için drag ile tepki vermelidir
- Temel tarif, hem fare hem de dokunmatik için drag bekler
- Fare hover ve dokunmatik drag'i birlikte kullanmak için
pointermoveiçindeif (!state.dragging)koşulu kaldırılır - Responsive Design page üzerinde fareyle satırın üzerine hover yapıldığında yerleşim değişir, dokunmatikte ise drag ile yerleşim değişir
- Hexagons Guide içinde de birçok diyagram fare hover ve dokunmatik drag'i birlikte kullanır
- Dokunmatikte A öğesinden B'ye sürüklerken capture korunursa move olayı A'ya iletilir; bu yüzden B'yi vurgulamak için capture'ın bırakılması gerekebilir
Toggle Paint ve drag durumunun genişletilmesi
- Rounded Cell Painter içinde
pointerdownbaşlangıç boya rengini yakalar - Sonrasında
pointerupolana kadar tümpointermoveolayları aynı boya rengini kullanır - Bunun için
state.dragging, yalnızca başlangıçxveydeğil, başlangıç boya rengini de içermelidir - Demo examples page üzerinde bulunuyor
lostpointercapture uç durumları
lostpointercapture, pointer capture'ın kaybedilip kaybedilmediğini algılamak için kullanılabilir- Hangi durumlarda oluştuğu ve ne yapılması gerektiği henüz tamamen netleşmiş değil
- Yorumlarda ele alınan senaryolar şunlardır
- Sol düğmeyle daireyi sürüklemeye başla
- Sol düğme basılıyken sürükleme alanının dışına çık
- Sağ düğmeye basıp ardından sol düğmeyi bırak
- Sürükleme alanı dışında herhangi bir yere tıkla
- standard, pointer capture bırakıldıktan sonra kullanıcı aracısının mutlaka
lostpointercaptureolayını tetiklemesi gerektiğini söyler - Gerçek tarayıcı davranışı büyük ölçüde farklılık gösterir; bazı sistemlerde
lostpointercapturetetiklenirken bazılarında başka bir yere tıklanana kadar tetiklenmez
1 yorum
Hacker News yorumları
Sürüklemeyi ele alan bir yazı; Amit'in bahsettiği tuzakların neredeyse hepsini yaşadım ve aynı çözüme ulaştım. Harika bir yazı.
Kullanıcı açısından sürükleyerek sıralamayı değiştirme çok doğal görünür, ama farklı boyutlarda öğeler, öğeler arasında yer tutucu oluşturma, kenar algılama ve kutu yerleştirme algoritmalarının tavşan deliğine girince, bunu kendiniz uygulamak epey zor işler arasına girer.
Fare her hareket ettiğinde bu konumlar arasından mevcut sürüklenen nesne konumuna en yakın olanı seçip, seçilen yerleşimi render etmek yeterli. Karmaşık yerleşimlerde veya reflow durumlarında bile hissiyatı iyi çalışır.
Sonunda, kartı elime aldığımda o kart panodan silinmiş gibi yerleşimi hesapladım; böylece iş kolaylaştı. Tek yapmanız gereken, farenin üzerinde bulunduğu konumdakileri itmekti.
Yine de istisna işleme inanılmaz fazlaydı; özellikle de veri modeline henüz “commit” edilmemiş yeni bir kartı düzenlemeye başladığınızda zordu. Mevcut kartları iterek bir hayalet kart yeri oluşturma seçeneği de eklemem gerekti.
Elle ele alınması gereken çok sayıda istisna olduğunu kabul etmek işe yarıyor. Daha genel ve homojen bir çözüm varmış gibi yaklaşırsanız tasarımda dönüp durursunuz. Bir gün çeşitli istisna durumlarını bir blog yazısında derlemem gerekecek gibi.
Daha iyi bir yerleşim yöntemi de buldum; gereksiz hesaplamaları azaltıyor ve yerleşim motorunu daha esnek, kullanıcı dostu hâle getiriyor. Veri modeli temsilini nasıl seçtiğinizin çözüme bu kadar büyük fark yaratması şaşırtıcı.
[1] https://www.ussherpress.com/cardbuddy/
Yazı iptal işlemeyi ele almıyor gibi. Örneğin Windows'ta Escape'e basınca sürüklemenin iptal edilmesi şeklinde bir teamül var.
Bazen fareyi tanımlı alanın dışında bırakırsanız sürüklemeyi iptal etmek de isteyebilirsiniz. İptal, kullanıcıya daha hızlı bir geri alma ya da “aa, aslında sürüklemek istemiyormuşum” türünden bir kaçış yolu sağlar.
Bu yüzden ayrı bir geri alma özelliği olmasa bile, sürükleme başlangıcındaki özgün durumu saklayıp iptal edilirse geri yüklemek gerekir.
Alan dışına sürükleyerek iptal durumunda iptali geri alma da vardır. İşaretçi alanın dışındayken görsel olarak özgün duruma dönmüş gibi gösterip, işaretçi tekrar alanın içine girdiğinde sürüklemeyi sürdürme yaklaşımıdır. Gerçek iptal fare bırakıldığında gerçekleşir, ama sürükleme sırasında da iptal edileceği önceden görsel olarak bildirilmiş olur.
Microsoft'un hâlâ bunu iyi bir UI tasarımı sandığına inanamıyorum. Kullanıcının kafasını tamamen karıştırıyor; ne olduğunu anlamayıp sol fare düğmesini bırakmaktan korkan ya da yo-yo gibi tekrar tekrar deneyen insanlar görebilirsiniz.
İptalin sıkça gözden kaçan büyük bir sorun olduğuna ve basit olmadığına katılıyorum. Sıradan kullanıcı ESC'nin işe yaradığını bile bilmez.
Ardour [0]'un GUI'sinde her tür nesneyi sürükleyerek geçirdiğim 20 yılda öğrendiğim ek bir ayrıntı var: Tüm düğmeye basma ve bırakma olaylarını, hareket içermeyen sürükleme olayları olarak ele almak gerekir.
Yani basma her zaman sürüklemeyi başlatır ve bırakma ile biter; bırakmayı işleyen kod da hareketsizlik koşulunu özel olarak ele alır.
[0] https://ardour.org/
Normal
mousedownvemouseupişleyicilerim var; bunun tıklama mı, sürükleme başlangıcı mı yoksa başka bir eylem mi olduğuna karar vermek için yaklaşık 150 ms'lik yapılandırılabilir bir timeout kullanıyorum.mouseupgerçekleşirse ya da fare ekranın dışına çıktıysa ve devam eden bir sürükleme varsastopdragyapıyorum. Benim için sürükleme, birçok özel durumdan yalnızca biri.Çok uzun zaman önce Minneapolis'te NSF tarafından desteklenen bir geometry center vardı. Hesaplamalı grup teorisi konferansı düzenlenmişti ve çevre alanlardan maskot gibi birkaç kişi davet edilmişti.
Bir cebirsel geometri sistemi yazdığım için davet edilmiştim; -20°F soğukta çok erken kalkıp o gün kullanacağım Silicon Graphics iş istasyonunu kaptıktan sonra grup üreteçlerini ve ilişkilerini daha iyi anlamaya yönelik bir oyun kodladım.
Oyunda sürükleme vardı. Sonuçta gece 2'de süren güzel sohbetler çıktı. Benim fikrim, sürüklemenin gerçek dünyanın fizik yasalarına uymak zorunda olmadığıydı; sürükleme çok güçlü bir LSD pulu gibi hissettirmeliydi. Herkes buna kapıldı ve kendi fikirlerini ortaya attı.
Yazı, web tarayıcılarında ortaya çıkan çeşitli istisnaları bir kenara bırakırsak, nispeten temel bir sürükleme uygulaması gerçekleştiriyor. Kılavuz çizgilere snap etme, sınırlar ya da başka nesnelerle çarpışmayı engelleme, sürükleme işlemine tepki olarak boyutu veya konumu değişen animasyonlu bırakma hedefleri gibi kısıtları olan sürükleme materyalleri var mı merak ediyorum
Eskiden, dairesel bir saati farklı uzunluklarda kama parçalarına bölerek odaklanma/dinlenme aralıklarını tanımlayan özel bir Pomodoro zamanlayıcı arayüzü yapmak istemiştim. Bu kama parçalarının sürüklenerek sırasının değiştirilmesini uygulamada pek ilerleme kaydedemedim
Kısıt sistemini olay işleme sisteminden ayırmak istiyordum. jquery-ui gibi kütüphaneler ikisini birbirine bağlıyor; bu yüzden olay işleme sisteminin olası tüm kısıtları bilmesi gerekiyor. jquery-ui sınırlayıcı kutu, eksen, kare ızgara ve DOM öğelerine snap etmeyi destekliyor. Ama altıgen ızgaraya, logaritmik ölçekli ızgaraya ya da dairesel sınıra snap etmek isterseniz desteklenmiyor
Kodda
state.pos = …ifadesini görebilirsiniz; durumun ayarlandığı yer orası. Kısıtlar içinposdeğerini bir setter’ın arkasına gizliyorum. Böylece sürükleme olayını işleyen kod hangi kısıtların gerektiğini bilmeden setter kısıtları uygulayabiliyorSayfayı güncelleyip kısıt örnekleri göstermem gerekecek. Kod tarifinde bu yönden bahsetmeyi tamamen unutmuşum
Eski bir kısıt örneği https://www.redblobgames.com/articles/curved-paths/making-of... adresinde, çarpışmayı önleme örneği ise https://redblobgames.github.io/circular-obstacle-pathfinding... adresinde var. Ancak sürükleyerek sıralamayı değiştirme ya da animasyonlu bırakma hedeflerini henüz denemedim
Bu siteye ben de minnettarım. Uber’de coğrafi analiz için altıgen sistem tasarlarken https://www.redblobgames.com/grids/hexagons/ kaynağından çok yararlandım
Düzgün etkileşimlerle uğraşırken ortaya çıkan tuzakları ve dikkat edilmesi gereken noktaları iyi özetleyen bir yazı
Daha “hemen kullanılabilir” tarafta, birkaç projede interactjs’i epey uzun süre kullandım
Herkese teşekkürler. Bugün HN’de yer aldığını görünce şaşırdım; soruları yanıtlayabilirim
draggable="true"niteliğine ve drag events’e bakıp bakmadığınızı merak ediyorumYerleşik özelliğin bu koda kıyasla eksik kaldığı noktalar var mı, onu da merak ediyorum
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...
Kısa bir sorum var.
dragstartgibi yerleşik DOM olaylarıyla sürükleme hareketini tek bir eksenle nasıl sınırlayabileceğimi merak ediyorum.dragstart/dragenter/dragover/dropolaylarıyla sürükle-bırak işlevini uyguladım, ancak hareketi x ekseni ile sınırlamanın hızlı bir yolunu bulamadım. JQuery’nin sürükle-bırak API’sinin bunu desteklediğini hatırlıyorum. Yalnızca yerel DOM olaylarını/API’lerini kullanmaya çalışıyorum; bu konuda bilgi ya da yönlendirme olursa iyi olurSafari’nin desteği 2020’de eklediği düşünüldüğünde, tarayıcıların bunu desteklememesinden endişe etmiyor musunuz merak ediyorum. macOS Mojave kullanıcıları da Safari 13 ya da 14 kullanıyor olmalı; umarım Safari 12 artık gerçekten kullanılmıyordur. Ama genel web kullanıcılarını hedefleyen bir production uygulamasında sürükleme kadar basit bir özelliğin çalışmaması oldukça kötü olurdu
Sürükleme sırasında
documentüzerine olay işleyicisi eklemek eski bir pratik; tarayıcılar belirli kullanım durumlarını basitleştirmeye yönelik yeni özellikler eklemeyi sürdürüyor, ama her birinin kendi istisnaları ve tuzakları var. Yazıda da bunun henüz tamamen ele alınmadığı söyleniyor. Nihai sonuçta da pointer event’ler ile touch event’lerin bir kombinasyonu kalıyorKodun azalması anlamındaki “basitliğin”; ek istisnalar, daha düşük tarayıcı desteği ve geliştiricilerin mouse event’lere kıyasla muhtemelen daha az anlaşılan ve belgelenen pointer event ayrıntılarını ve tarayıcı farklarını öğrenmek zorunda kalması pahasına değip değmediğini merak ediyorum
Eksik olan bir şey var: erişilebilirlik. Klavye kullanımıyla sürükleme nasıl mümkün kılınmalı?
Benim örneğimde erişilebilirlik yanıtı, bu işi tamamlamak için ek klavye kontrolleri sunmaktır. Mümkünse bir tuşa sürekli basılı tutmayı gerektirmeyen bir yol daha iyi olur. Örneğin bir kısayolla pan moduna girip, ok tuşlarıyla görünüm alanını tuval üzerinde hareket ettirmek çözüm olur
Sürüklenebilir nesneler söz konusu olduğunda görev sıralamayı değiştirmektir. Bunu erişilebilir yapmak için sıralamayı değiştirmenin alternatif bir yolunu sunmak yeterlidir. Örneğin TAB ile nesneler arasında odağı dolaştırmak, bir tuşla odaktaki nesneyi seçmek, ardından ok tuşlarıyla sürükleme önizlemesini o yöndeki en yakın geçerli konuma taşımak gibi
Yani sürükleme uygulamasının içine klavye desteğini zorla sıkıştırmak yerine, sürükleme işlevinden ayrı olarak anlamlı bir klavye işlevi eklemek gerekir
Güzel. Bu haftanın başında bir Vue uygulamasında SVG öğesi sürükleme uyguluyordum; yazarın anlattığı neredeyse her şeyi aynı sırayla kendim keşfetmek zorunda kaldım ve sonuçta neredeyse aynı bileşene ulaştım
Ancak ben bunu fonksiyonel bileşen yerine
useDraggingadlı bir composable yardımcı olarak yazdım