[HTML/JS] Idea wyświetlania tekstu na stronie

0

Witam,
Chcialbym sie zapytac jak zabrac sie za zrobienie takiej ciekawej animacji podczas wypisywania tekstu. Otoz pod linkiem

jest intro z gry Doom 3. A w nim od 12 sekundy zostaje wyswietlony tekst. Jak osiagnac taki efekt? Pytanie moze trywialne ale nie mam pomyslu jak cos takiego zrobic.

0

Chodzi o to, że tekst tak się pojawia jakby był powoli drukowany? Wstaw tekst do stringu i odpalaj funkcję wyświetlającą kolejną literę albo przy użyciu setInterval (wtedy po skończeniu wypisywania wewnątrz funkcji musiałbyś użyć clearInterval), albo setTimeout (rekurencyjnie, wewnątrz funkcji).

0

Tak o cos takiego mi chodzi. Poszukalem o setTimeout i napisalem funkcje, ktora wywoluje przycisk na stronie:

function fun()
{
    var help = new Array();
    var w, z, c;
    help[0] = "Linia pierwsza";
    help[1] = "Linia druga";
    help[2] = "Linia trzecia";
    help[3] = "Linia czwarta";
    help[4] = "Linia piata";

    for(w=0 ; w<help.length ; w++)
    {
        for(z=0 ; z<help[w].length ; z++)
        {
            //document.write(help[w][z]);
            window.setTimeout("document.write(help[w][z])", 5000);
        }
    }
}

Taki kod nie dziala. Pewnie czegos nie doczytalem/zrozumialem :/

0

Na początek parę rad ogólnych.

Nie używaj document.write. Zamiast tego wrzucaj poszczególne znaki do jakiegoś elementu, używając np. innerHTML lub metod DOM.

Jeśli chodzi o tablice, to nie używaj konstruktora Array(), tylko literału tablicowego. Jest bardziej zwięzły i przejrzysty.

Masz tak:

// niezalecane: użycie konstruktora Array()...
var help = new Array();
// i ręczne wypełnienie kolejnych elementów wartościami
help[0] = "Linia pierwsza";
help[1] = "Linia druga";
help[2] = "Linia trzecia";
help[3] = "Linia czwarta";
help[4] = "Linia piata";

Lepiej jest tak:

// literał tablicowy - zalecany
var help = ['Linia pierwsza', 'Linia druga', 'Linia trzecia', 'Linia czwarta', 'Linia piąta'];

Powyższy kod możesz też zapisać tak, jeśli linii jest dużo/są długie (to to samo, tylko wstawiłem entery):

// literał tablicowy - zalecany
var help = [
  'Linia pierwsza',
  'Linia druga',
  'Linia trzecia',
  'Linia czwarta',
  'Linia piąta'
];

Nie radzę też używać wersji setTimeout z pierwszym argumentem w postaci stringu z kodem JavaScript. Zamiast tego podaj po prostu funkcję. Nie musisz też pisać window.setTimeout. window to tzw. obiekt globalny. Używa się go tylko w dość rzadkich przypadkach. Ponieważ window to obiekt globalny, znajdujące się w nim funkcje, takie jak window.alert, czy window.setTimeout możesz równie dobrze wywoływać bez podawania tego obiektu. Zamiast "window.setTimeout" wystarczy po prostu "setTimeout".

Algorytm, który zapisałeś w kodzie jest niestety nieprawidłowy. Wywołanie setTimeout(f, t) powoduje, że funkcja f zostanie wywołana po czasie około t milisekund. setTimeout działa asynchronicznie. Znaczy to, że setTimeout tylko mówi "wykonaj to za tyle i tyle milisekund". setTimeout NIE mówi "zaczekaj w tym miejscu t milisekund i potem wywołaj f". Czyli gdy masz instrukcje:

a();
setTimeout(f, 1000);
b();
c();

To działa to tak, że wykonywana jest a(). Następnie wykonywana jest setTimeout(f, 1000). JavaScript notuje gdzieś sobie, że za 1000 milisekund musi wykonać funkcję f. Ale nie czeka tu tego 1000 ms. Natychmiast idzie dalej. Wywołuje b() i c(), co trwa zapewne tylko kilka milisekund. Czeka dalej te ponad 900 milisekund i dopiero wywołuje zanotowaną wcześniej f(). setTimeout nie działa jak Delay w Pascalu.

Spróbuj trochę pokombinować. Nie wiem, czy masz na tę chwilę taki poziom, który pozwalałby Ci na napisanie takiej animacji. Nie jest to wbrew pozorom aż tak proste. Choć sam kod jest dość zwięzły. Musisz przede wszystkim zrozumieć działanie setTimeout. Żeby to zrobić porządnie i schludnie, przydałaby Ci się też znajomość tzw. domknięć... Jeśli jesteś dopiero początkującym JavaScripterem, to to troszkę dużo. Polecić Ci mogę tę książkę, którą polecam każdemu JavaScripterowi: "JavaScript: Mocne strony" autorstwa Douglasa Crockforda. Raczej cienka i niedroga.

0

No coz jestem poczatkujacy. Postaram sie troche poglowkowac i moze cos wykombinuje. To w zasadzie pierwsze uzycie tej metody i zostal taki misz-masz.

Kod wlasciwy dla mojego projektu juz jest gotowy a teraz chodzi mi o "ubranie" tego aby jakos to wszystko ladnie wygladalo.

Te domkniecia to cos na tym etapie troche zwiekszza nieczytelnosc kodu :) Znalazlem cos takiego jak na razie https://developer.mozilla.org/pl/Nowości_w_JavaScript_1.8

0

Oj, nie o to chodzi z tymi domknięciami. Nie używaj tego, co proponuje tam Mozilla. Nie działa to we wszystkich przeglądarkach. Domknięcia po angielsku zwą się "closure(s)", możesz to pogooglować.

Jeśli mogę spytać... projekt robisz komercyjnie? Dysponujesz kontem z możliwością internetowych przelewów? (jeśli odpowiesz to się dowiesz, czemu pytam)

0

Projekt jest calosciowo niekomercyjny. Zaliczenie na zajeciach.

Jeszcze zapytanie. Poniewaz ta funkcja ma zostac wykonana po nacisnieciu przycisku na stronie i wtedy ma zostac umiejscowiona w jakims konkretnym miejscu. Tak wiec pod przyciskiem wywoluje funkcje ze skryptu. I jesli dobrze rozumie to w tej funkcji ma nie byc metody setTimeout?

0

W ten czy inny sposób musisz tam wstawić to setTimeout lub setInterval. Tak się robi animacje.

Mógłbym Ci napisać porządne rozwiązanie do przetrawienia (jestem zawodowym webdeveloperem), ale na tym forum raczej tak nie robimy -- chyba że w dziale Praca, za wynagrodzeniem. Również w ramach działań przeciwko lenistwu. Ja nie potrzebuję jednak kasy, a jakbym miał wziąć normalną stawkę godzinową, to raczej by Ci się to nie opłacało w edukacyjnym projekcie. A co Ty na to, jakbym Ci napisał taką funkcję, a ty byś potem wpłacił chociaż te 10-20 zł (czy ile tam możesz) na wybrany przeze mnie cel charytatywny? Znam pewne bardzo chore małe dziecko potrzebujące pomocy. Nawet 10 zł to jak 100 kliknięć w brzuszek Pajacyka :). Myślę, że nagięcie zasad w ten sposób nie byłoby znowu takie złe, a choćbyś z mojego rozwiązania nie skorzystał (bo np. na tym etapie jednak byś go nie ogarniał), to i tak spełniłbyś dobry uczynek. Hm?

0

Co do pomocy charytatywnej - napisz na pw co i jak.
Co do projektu - jest on wlasnie po to aby samemu przebrnac przez trudy pisania skryptu, wiec wolalbym jedynie jakies drobne sugestie czy w dobra strone zmierzam :) Skoro mam i chce sie czegos nauczyc :) Zalozenia mojego projektu juz sa spelnione a teraz to po prostu moja wlasna ambicja i chcec zrobienia czegos porzadnie i tak jak to sobie zalozylem :)

0

@metal_man:
Doskonale! Ponieważ Twoje podejście uważam za słuszne, pokażę Ci po prostu jak to można napisać. Jeśli będziesz miał jakieś pytania odnośnie kodu, to chętnie na nie opowiem. Być może będą w nim jakieś błędy (nie testowałem zbyt intensywnie), wtedy też postaram się pokazać jak można zrobić łatki.

Czemu chcę pokazać kod, a nie tłumaczyć krok po kroku? Bo jest spora szansa, że jednak nie masz już statusu początkującego i umiesz czytać kod. Po popatrzeniu na mój możesz przecież napisać własny.

Dla ułatwienia zamieszczam cały kod HTML strony testowej, choć oczywiście nas interesuje głównie kod funkcji w JavaScripcie. Funkcję nazwałem sobie typewriter, to efekt przypomina mi pisanie na maszynie :).

Aha, funkcja używa standardowych metod DOM. Gdybym użył własności innerHTML, to mógłbym z dosłownie 10 linijek zrobić 1. Ale zapis do el.innerHTML niszczy m.in. wszystkie obserwatory zdarzeń na elementach znajdujących się wewnątrz elementu el. Funkcja przez to byłaby mniej uniwersalna, a ja chciałem pokazać, jak się tworzy łatwy do ponownego użycia kod. Stąd też funkcja ma dość spore możliwości. Przykładowe sposoby na ich wykorzystanie znajdują się w zakomentowanym kodzie.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" lang="pl">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta name="language" content="pl" />
  <title>JS: Printed text animation (4programmers.net)</title>
  <script type="text/javascript">
//<![CDATA[

/**
 * Wyświetla stopniowo tekst tak, jakby był pisany na maszynie.
 * 
 * Nowe linie tekstu wymusza się poprzez wstawienie w parametr text
 * znaku nowej linii (\n).
 * 
 * W obiekcie options można ustawić następujące opcje:
 *   interval (number) - czas, który ma upłynąć pomiędzy wypisaniem kolejnych
 *                       liter (w milisekundach)
 *   random   (number) - losowość czasu pomiędzy wypisywaniem liter.
 *                       Liczba rzeczywista z zakresu <0.0..1.0>.
 *                       0.0 oznacza brak losowości (litery będą się pojawiać
 *                       równo co interval milisekund). 1.0 oznacza maksymalną
 *                       losowość (litery będą się pojawiały co 0-2*interval ms)
 *
 * @param {mixed}    container Element, do którego wstawiany będzie tekst.
 *                             Może być albo elementem DOM, albo stringiem
 *                             z ID elementu DOM.
 * @param {string}   text      Wypisywany tekst. Nie powinien zawierać kodu HTML.
 *                             Znaki nowej linii (\n) zostaną zamienione na <br>.
 * @param {object}   options   Obiekt z opcjami. Opisany wyżej (opcjonalny).
 * @param {function} done      Funkcja wywoływana po zakończeniu wyświetlania
 *                             tekstu (parametr opcjonalny).
 */  
function typewriter(container, text, options, done) {
  var interval      = 100, // wartość domyślna dla options.interval
      random        = 0.5, // wartość domyślna dla options.random
      pos           = 0,
      length        = 0,
      printNextChar = function() {
        var ch,
            delay,
            lastChild = container.lastChild;
        if (pos < length) {
          ch = text.charAt(pos);
          if (ch === '\n') {
            container.appendChild(document.createElement('br'));
          } else {
            if (lastChild && lastChild.nodeType === 3) { // 3 = TEXT_NODE
              // lepiej użyć textNode.data, bo textNode.appendData ma bugi w IE8
              lastChild.data += ch; 
            } else {
              container.appendChild(document.createTextNode(ch));
            }
          }
          pos++;
          delay = interval + random * interval * (Math.random() - 0.5);
          setTimeout(printNextChar, delay);
        } else if (typeof done === 'function') {
          done();
        }
      }
  ;
  options = options || {};
  if (typeof container === 'string') {
    container = document.getElementById(container);
  }
  if (container && container.nodeType === 1 // 1 = ELEMENT_NODE
      && typeof text === 'string') {
      if (options.interval >= 0) {
            interval = +options.interval;
      }
      if (options.random >= 0.0 && options.random <= 1.0) {
        random = +options.random;
      }
    length = text.length;
    printNextChar();
  } else {
      alert('typewriter() error: First param must be a HTMLElement reference '
              + 'or an ID string. Second param must be a string.');
  }
}

// trzeba użyć onload lub czegoś podobnego, bo element #doom musi być już gotowy
window.onload = function() {
    // przykłady użycia

  typewriter('doom', 'Hello world!\nDoom ]I[ ownz!\nAll your base are belong to us.');

// NOTKA: tutaj powinno się znajdować tylko jedno wywołanie typewriter,
// więc jak odkomentujesz którąś z poniższych linii, to zakomentuj pozostałe
// wywołania funkcji

// Dlugi okres pomiędzy wyświetleniem znaków  
// typewriter('doom', 'Hello world!\nDoom ]I[ ownz!\nAll your base are belong to us.', { interval: 500 });

// Równe odstępy pomiędzy znakami -- zawsze dokładnie 200 ms (random na 0!)  
// typewriter('doom', 'Hello world!\nDoom ]I[ ownz!\nAll your base are belong to us.', { interval: 200, random: 0 });

// Wyświetlenie komunikatu po wykonaniu animacji
//  typewriter('doom', 'Hello\nworld!', {}, function() { alert('Skończyłem!'); });

// Po wykonaniu animacji wyświetla komunikat, a następnie wypisuje dalszy tekst
//  typewriter('doom', 'Hello\nworld!', {}, function() {
//    alert('Skończyłem! Teraz dorzucę trochę znaków zapytania!');
//    typewriter('doom', '????????');
//  });

}

// ]]>  
  </script>  
</head>
<body>
  <h1>DOOM text!</h1>
  <!-- w #doom zostanie umieszczony tekst -->
  <div id="doom">
  </div>
</body>
</html>

PS. Wysłałem Ci PM, napisz proszę jeśli nie doszło bo w PM-ach na tym forum jestem totalnym n00bem, to była moja pierwsza :).

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0