Programujeme DHTML aplikace – drag and drop systém

28. prosince 2002

Tentokrát se společně pustíme do klasické úlohy, kterou by si měl každý kodér pokusit sám napsat. Každý, kdo již něco podobného psal, či brouzdal internetem po nějakém vytvořeném zdroji, ví, že asi neexistuje identický kód. Co programátor, to jiný přístup. Určitě i při studiu mého skriptu zjistíte proč nejde tohle jinak atd. Proto bych rád předeslal, že se jedná pouze o návrh, který si jistě dle svých potřeb upravíte.

Nejprve však musím začít milou povinností. Jak mnozí z vás jistě postřehli, na světe je další verze Opery. Ač se jedná o beta verzi, i ta naznačila mnoho pozitivního. Pro mne je tím největším krokem vpřed mnohem větší podpora DOM. Pravda, není kompletní, ale mnohým skriptům dostačující. Jak jsem v diskusi nad některým z minulých dílů prohlásil, tím jediným důvodem, proč jsem Operu vyloučil z tohoto seriálu, byla její chybějící DOM implementace.

Tento ale již argument padá, proto je nuné nejprve změnit skript pro rozpoznávání prohlížečů sniffer.js. Jednak přibylo rozpoznání Opery 7.0, dále pak rozlišení verzí MSIE 5.5, 5 a 6. To proto, neb některé drobné rozdíly mohou vadit a bylo by na škodu všechny MSIE házet do jednoho pytle. Na obranu proti možné falešné identifikaci Opery byla zpřísněna kritéria pro přiřazení jednotlivých proměnných (IE a NS), pouhá identifikace názvu a základních metod již nestačily.

// Identifikace OPERY 7
if(ua.indexOf(‚opera‘)>-1 && document.getElementById && document.childNodes) {OPERA=true;}
….
// Identifikace OPERY 7 s falesnym oznacovanim
if(!IE && !NS && !OPERA && document.addEventListener) {OPERA=true;}

Ale zpět k nosnému tématu toho článku. Nejprve co budeme k realizaci potřebovat. Jak všichni víte, drag&drop je vlastně uchycení nějakého objektu, tažení na jinou pozici a upuštění na cílové pozici, vše pomocí kursoru. Mísí se zde události, pozicování a práce se strukturou dokumentu. Než začnu popisovat své myšlenkové pochody, podívejte se na jednoduchou ukázku, využívající zmiňovanou knihovnu sniffer.js a popisovanou knihovnu dragdrop.js.

Iniciátorem každého pokusu o přesunutí objektu je stisknutí tlačítka myši nad daným elementem. Tuto událost obslouží metoda m_move. Než se k ní ale dostanu, začnu nejdříve procedurou, umožňující elementu být přetahován. V této implementaci je označení řešeno konkrétní konstrukcí stargDrag, jež objektu (parametr what) přiřadí reakci na stisk tlačítka v podobě volání zmiňované metody m_down:

function startDrag(what)
{
  what.onmousedown = function(e) {if(e) {event=e;} m_down(event,what);}
  what.drag = 1;
}
function stopDrag(what)
{
  what.onmousedown = null;
  what.drag = 0;
}

Pouze nad označenými elementy se tedy vyvolá obsluhující funkce m_down se vstupujícím parametrem objektu, který právě obsluhuje (parametr object) a vyvolané události (parametr event). Možná se setkáte se zápisem, přiřazující celému dokumentu reakci na každý stisk. Jenže v takovémto případě je třeba složitěji zjišťovat, který objekt vlastně obsluhuje událost stisku a zda-li je vůbec určen k přetahování. K označování se pak obvykle zneužívá atribut class, což se mi osobně nezamlouvá, neb se drag&drop omezuje jen na konkrétní třídu. Určitým východiskem by bylo použití atributu name či zcela jiného smyšleného atributu. To ale zase odmítne validátor.

Jakmile je nad označeným objektem kliknuto myší, je to signál, že by měl být přetahován, a je zavolána metoda m_down. Ta ve svém těle zaznamená především aktuální pozici objektu (atributy top a left) a myši (atributy clickX a clickY) v době stisku a dále pověsí na pohyb myši proceduru m_move. Jakýkoli pohyb tedy bude obsluhován touto metodou.

dragobj.clickX = event.clientX;
dragobj.clickY = event.clientY;
dragobj.left = parseInt(dragobj.style.left);
dragobj.top = parseInt(dragobj.style.top);
if(IE)
{
 document.attachEvent(‚onmousemove‘, m_move);
 document.attachEvent(‚onmouseup‘, m_up);
}
if(NS || OPERA)
{
 document.addEventListener(‚mousemove‘, m_move, true);
 document.addEventListener(‚mouseup‘, m_up, true);
}

Jak jsem předeslal, až do chvíle, kdy sejmeme prst z tlačítka, se při každém pohybu volá m_move. Ta je ve své podstatě jen jakýsi prostředník, neb nerealizuje samotný přesun, ale pouze počítá rozdíl mezi pozici myši v okamžiku počátku přesunu a v jeho průběhu. Daný rozdíl se pak předá přímo metodě daného objektu, nesoucí povinný název ondragdrop, která pak podle potřeby provede samotnou změnu pozice přičtením vypočítaného rozdílu k původní pozici objektu. Zase se jistě setkáte s tím, že se přesun zajišťuje již na úrovni m_move. Ostatně vše potřebné je k dispozici. Pokud ale budete potřebovat s přesunem dále pracovat a každému objektu jej budete chtít měnit, například omezovat na určité osy nebo rozmezí, půjde to jen stěží.

function m_move(event)
{
 // Spocti rozdil mezi puvodni pozici mysi a nynejsi pozici
 dragobj.ondragdrop(event.clientX-dragobj.clickX,event.clientY-dragobj.clickY);
 return stopEvent(event);
}

Uvolnění tlačítka logicky znamená, že má uživatel přetahování dost a je třeba ukončit přesun a hlavně odstranit ovladače události pohybu myši. Pro možnou rozšiřitelnost je opět volána metoda ondragend, abychom mohli ještě po skončení provést nějakou volitelnou akci.

function m_up(event)
{
if(IE)
{
 document.detachEvent(‚onmousemove‘, m_move);
 document.detachEvent(‚onmouseup‘, m_up);
 if(dragobj.ondragend)dragobj.ondragend(event);
}
if(NS || OPERA)
{
 document.removeEventListener(‚mousemove‘, m_move, true);
 document.removeEventListener(‚mouseup‘, m_up, true);
 if(dragobj.ondragend)dragobj.ondragend(event);
}

To byl samotný systém knihovny dragdrop.js. Implementace je velmi jednoduchá a modifikovatelná dle potřeb. Nezapomeňte vložit knihovny sniffer.js a dragdrop.js. V druhé fázi pak každému objektu definujte „přesouvací“ metodu ondragdrop. Nakonec přesun aktivovujte voláním startDrag s parametrem souvisejícího objektu, například takto:

document.getElementById(‚box1‘).ondragdrop = function(posunx, posuny, event)
{
 this.style.left = (this.left + posunx)+“px“;
 this.style.top = (this.top + posuny)+“px“;
}
startDrag(document.getElementById(‚box1‘));

Na závěr bych v krátkosti uvedl dva mírně pokročilejší příklady. Ten původní se již objevil na Intervalu a jeho ekvivalent, vytvořený pomocí této knihovny, najdete v příloze. Zmiňuji jej proto, abych názorně ukázal, jak jednoduše lze drag&drop pro jednotlivé objekty specifikovat. V tomto případě je potřeba omezit jednu osu a rozsah, respektive provést diskretizaci.

document.getElementById(‚p‘).ondragdrop = function(posunx,posuny)
{
 temp = (this.left + posunx);
 // Presun pouze o kazdych 18 pixelu
 temp -= temp%18;
 // Omezeni rozsahu
 if(temp<0) temp=0;
 if(temp>34) temp=34;
 this.style.left = temp+“px“;
}

Druhý příklad vychází ze stále populárnějšího nastavování vlastního barevného schématu webu a ukazuje, jak by bylo možné umožnit uživateli interaktivně definovat vlastní barevné kombinace. Všechny soubory použité v tomto článku naleznete připravené ke stažení v souboru dhtml6.zip

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Předchozí článek Asistent profilu a autocomplete
Další článek olive.cz
Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *