Rev. 2.73

자바스크립트 이펙트의 대명사 스크립타큘러스(Scriptaculous)는 1.7 베타에 추가되는 모프(Morph)와 트랜스폼(Transform) 이펙트의 데모를 시연했습니다. 현재 테스트 파일이 정식으로 배포된 상태는 아니지만 테스트 소스를 추출하여 사용해 보았습니다. Prototype 1.5.0의 RC2가 베이스로 사용되고 있더군요. 트랜스폼 이펙트는 List Item 에서 특정 메시지를 부각시키는 역할을 합니다. 그리고 모프 이펙트는 아래에서 직접 체험해 봅시다.

Effect.Morph

// Usage : Element morph
new Effect.Morph('error_message',{
style:'background:#f00; color:#fff; border: 20px solid #f88; font-size:2em',
duration:0.8
});

// same thing with Element morph is
$('error_message').morph(
'background:#f00; color:#fff; border: 20px solid #f88; font-size:2em',
{duration:0.8}
);

Usage를 보면, 스타일시트의 코드 자체가 스트링으로 입력받는 모습이 독특합니다. { background: '#f00', fontSize: '2em' } 요딴 식으로 작성하기가 무척 불편했었는데 말이죠. 아무튼 멋집니다.

Comments

스크립타큘러스가 1.6.5를 발표했습니다. 자세한 변동사항은 아래와 같습니다. Prototype 1.5.0 RC1도 변경이 있는듯 합니다.

* Update to Prototype 1.5.0_rc1 revision [5462]
* Support the HTML 'for' attribute in Builder by using 'htmlFor', fixes #6472 [gjones, tdd]
var node = Builder.node('label', { htmlFor: 'myinput' });
* Add support to run a specific failing unit test by clicking on the corresponding test result, fixes #6290 [leeo]
* Add modifier key support to Event.simulateMouse, fixes #6391 [savetheclocktower]
* Add rails-trunk update task, clean up references to MIT license
* Add new 'with-last' queue position option to queue effects to occur in parallel with the last effect to start in the queue
* Add new special core effect Effect.Event for one-shot events that follow timelines defined by effect queues
new Effect.Event({ afterFinish:function(){
// do some code here
}, position: 'end' });
* Do some refactoring to make use of Prototype 1.5 functionalities and save LOC
* Fix an possible crash of IE on Effect.SlideUp, fixes #3192 [thx nel]
* Add Builder.build() to create nodes from strings containing HTML, [DHH]
var node = Builder.build("<p>this is <b>neat!</b></p>");
* Add a pulses parameter to Effect.Pulsate to control the amount of pulses, fixes #6245 [leeo]
For example, Effect.Pulsate('d8', {pulses: 2}) would pulsate twice. If the option is not given, it defaults to five pulses.
* Fix an issue with clicking on a slider span resulting in an exception, fixes #4707 [thx sergeykojin]
* Fix an issue with Draggables when no options are supplied, fixes #6045 [thx tdd]

Comments

Ajax가 성행하면서 자바스크립트로 DOM을 직접 다뤄야 하는 일이 잦아졌다. 만약 자바스크립트를 이용해 노드를 대량으로 생산해야하는 임무가 주어졌다면 어떻게 처리하는 것이 효과적일까? 실제로 이와 비슷한 프로세스를 수행하는 이미지 리플랙터의 소스코드를 분석하고 이를 개선해 보자. 참고로, 이미지 리플랙터는 이미지의 반사된 잔상효과를 만들어주는 이펙트 라이브러리이다.

var Reflector = {
    reflect: function(element){
        element = $(element);
        var options = $H({
            amount: 1/3,
            opacity: 1/3
        }).merge(arguments[1] || {});
        var p = element.parentNode, n = element.nextSibling;
        var d = 1.0/(element.height*options.amount);
        (element.height*options.amount).times( function(line){
            var h = Builder.node('div',{style:'height:1px;overflow:hidden;'},
            [Builder.node('img',{src:element.src,
                style:'margin-top:-'+(element.height-line-1)+'px'
            })]);
            p.insertBefore(h,n);
            $(h).setOpacity((1-d*line)*options.opacity);
        });
    }
};

// Run
Reflector.reflect('img_id',{ amount:1/5, opacity:1/4 });

위 코드는 이미지 리플랙터의 원본 코드로서 실행되면 브라우저가 먹통이 되는 증상을 보인이다. Scriptaculous 프레임웍의 builder.js 라이브러리를 사용하는 Builder 메서드를 사용해서 높이 1px짜리 DIV와 IMG태그를 대량으로 생산하고 있다. Builder메서드는 엘리먼트를 생성하기 위한 document.createElement()와 innerHTML, Prototype의 setStyle 등을 간단하게 사용할 수 있게한다. 즉 createElement와 setStyle 메서드가 루프를 돌면서 브라우저에게 마비증상을 선사(?)하는 것이다.

var Reflector = {
    reflect: function(element){
        element = $(element);
        var options = $H({
            amount: 1/3,
            opacity: 1/3
        }).merge(arguments[1] || {});
        var p = element.parentNode, h = '';
        var d = 1.0/(element.height*options.amount);
        var m = document.createElement('DIV');
        for(var i=0; i < element.height*options.amount; i++){
            h += '<div style="height:1px; overflow:hidden;'+this.setOpacity((1-d*i)*options.opacity)+'">';
            h += '<img src="'+element.src+'" style="margin-top:-'+(element.height-i-1)+'px" alt="" /></div>';
        }
        m.innerHTML = h;
        p.insertBefore(m, element.nextSibling);
    },
    setOpacity: function(value) {
        var style = 'opacity:'+value;  
        if(Prototype.Browser.IE) style = 'filter:alpha(opacity='+value*100+')';
        return style;
    }
};

이것은 innerHTML에 직접 코드를 삽입하는 방식으로 변경한 것이다. 이미지 하단에 들어갈 'DIV'엘리먼트를 하나만 생성하고 루프되는 코드를 직접 작성하여 생성한 DIV에 innerHTML로 넣어준다. 결과는 완전히 동일하지만 소요되는 시간차이는 상당하다. createElement메서드로 640x360 이미지의 효과를 만들어 내는데 걸리는 시간은 파이어폭스가 2.25~4.563초, 익스플로러(IE7)가 12.19~15.18(HTML이 들고있는 주변 태그에 영향을 크게 받는다. 상단의 문법 하이라이트 코드를 수정했더니 결과가 확 바뀌었다.)초 정도가 소요된다. innerHTML 방식은 파이어폭스가 0.07~0.11초, 익스플로러가 0.04~0.11초 정도로 환경에 따라 다르겠지만 약 30 ~ 50배 가까이 소요시간을 단축하는 효과를 볼 수 있다. 생성하는 노드의 수가 많으면 많을 수록 더욱 큰 차이를 보인다. 아래의 이미지를 직접 테스트해 보자.

Faux_Fur_wide_screen.jpg

최근에는 노드를 대량으로 생성하는 방식으로 엘리먼트의 코너를 둥글게하거나, 대각선을 그리는 등 굳이 이미지를 사용하지 않아도 자바스크립트를 사용하여 DOM을 동적으로 표현하는 꼼수들이 속속 선보이고 있다. 가뜩이나 새로선보인 IE7 RC1의 노드생성속도는 완전 쉣이다. 랙현상으로 인해 사용이 꺼려진다면 innerHTML로 DOM을 직접 그려보는 것도 좋은 대안이 될 수 있겠다.

Comments