티스토리 뷰

728x90
SMALL

이미지 스크립팅

HTML 문서에서 동적으로 하나의 이미지를 다른 이미지와 교체하는 기능은 몇 가지 특별한 효과를 가능하게 한다.

이미지 롤오버나 이와 유사한 동작이 유용하려면 즉각 반응해야 하므로 필요한 이미지가 브라우저 캐시에 이미 존재함을 보장할 필요가 있다. 이미지를 강제로 캐싱하기 위해, Image() 생성자를 사용하여 보이지 않는 화면 영역에 이미지 객체를 만들 수 있다.

ex) 이미지 롤오버(CSS의 :hover로도 가능)

<script>(new Image()).src="images/help_rollover.gif";</script?
<img src="images/help.gif"
  onmouseover="this.src='images/help_rollover.gif'"
  onmouseout="this.src='images/help.gif'">

비간섭 이미지 롤오버

위 예제는 완벽한 간섭 자바스크립트다. 이 말은 HTML을 혼란스럽게 할만큼 자바스크립트가 너무 많다는 말이다. 예제는 data-rollover 속성만 지정해서 이미지 롤오버를 생성시키는 비간섭적인 대안을 보여준다.

// Register the function f to run when the document finishes loading.
// If the document has already loaded, run it asynchronously ASAP.
function onLoad(f) {
    if (onLoad.loaded)                  // If document is already loaded
        window.setTimeout(f, 0);        // Queue f to be run as soon as possible
    else if (window.addEventListener)   // Standard event registration method
        window.addEventListener("load", f, false);
    else if (window.attachEvent)        // IE8 and earlier use this instead
        window.attachEvent("onload", f);
}
// Start by setting a flag that indicates that the document is not loaded yet.
onLoad.loaded = false;
// And register a function to set the flag when the document does load.
onLoad(function() { onLoad.loaded = true; });

위에는 onLoad 함수

/**
 * rollover.js: unobtrusive image rollovers.
 * 
 * To create image rollovers, include this module in your HTML file and
 * use the data-rollover attribute on any <img> element to specify the URL of
 * the rollover image. For example:
 * 
 *   <img src="normal_image.png" data-rollover="rollover_image.png">
 * 
 * Note that this module requires onLoad.js
 */
onLoad(function() { // Everything in one anonymous function: no symbols defined
    // Loop through all images, looking for the data-rollover attribute
    for(var i = 0; i < document.images.length; i++) {
        var img = document.images[i]; 
        var rollover = img.getAttribute("data-rollover"); 
        if (!rollover) continue;  // Skip images without data-rollover

        // Ensure that the rollover image is in the cache
        (new Image()).src = rollover;

        // Define an attribute to remember the default image URL
        img.setAttribute("data-rollout", img.src);

        // Register the event handlers that create the rollover effect
        img.onmouseover = function() {
            this.src = this.getAttribute("data-rollover");
        };
        img.onmouseout = function() {
            this.src = this.getAttribute("data-rollout");
        };
    }
});

오디오와 비디오 스크립팅

HTML5에서는 이론적으로 <img> 문서 요소처럼 사용하기 쉬운 <audio>와 <video> 문서 요소를 소개했다. HTML5를 지원하는 브라우저에서는 HTML 문서에 소리나 영상을 포함하기 위해 플래시같은 플러그인을 더이상 사용할 필요가 없다. 하지만 브라우저 제조사들이 오디오, 비디오 표준 코덱을 모두 지원하는데 동의하지 않아서 <source> 문서 요소를 사용하여 서로 다른 형식의 여러 미디어 출처를 지정해야만 한다.

타입 선택과 로딩

미디어 문서 요소가 특정 타입의 미디어를 재생할 수 있는지를 테스트해보려면, canPlayType() 메서드에 미디어의 MIME 타입을 전달하면 된다. 문서 요소는 해당 미디어 타입을 재새앟ㄹ 수 없으면 빈 문자열(부정값)을 반환한다. 재생이 가능하다면, "maybe" 또는 "probably"를 반환한다.

var a=new Audio();
if(a.canPlayType("audio/wav")){
  a.src="soundeffect.wav";
  a.play();
}

미디어 재생 장치 제어하기

<audio>와 <video> 문서 요소에서 가장 중요한 메서드는 미디어 재생을 시작하고 중단하는 play()와 pause()이다.

window.addEventListener("load",function(){
  document.getElementById("music").play();
  },false);

currentTime 프로퍼티 : 미디어를 건너뛰거나 탐색할 수 있다.

volume 프로퍼티 : 0과 1 사이의 숫자 값으로 재생 음량을 지정. 음소거하려면 muted 프로퍼티 true설정, 취소는 false

playbackRate 프로퍼티 : 재생되는 미디어의 속도. 1.0이 표준속도. <audio>와 <video> 문서 요소에는 defaultPlaybackRate 프로퍼티 존재. play() 호출될 때마다 playbackRate는 defaultPlaybackRate 값으로 설정

<audio>나 <video> 문서 요소에 controls 속성이 있으면 제어장치가 출력되며, 미디어가 어떻게 재생되고 있는지를 알아내려면 muted, currentTime 프로퍼티를 스크립트로 조회

HTML 속성인 controls, loop, preload, autoplay는 오디오와 비디오 재생에 영향을 주며, 자바스크립트 프로퍼티로도 조회와 지정이 가능

controls : 재생 제어 장치의 출력 여부. true면 출력, false면 숨김

loop : 불리언 값. 반복true, 마지막에 재생끝냄false

preload : 미디어의 내용을 사용자가 재생하기 전에 미리 불러올지, 불러온다면 얼마나 많이 불러올지. none이면 미리 불러오는 데이터가 없다는 의미, metadata이면 재생시간, 비트레이트, 프레임 크기 가틍ㄴ 메타 데이터가 로드되어야 한다는 의미. preload 속성을 지정하지 않는다면 메타 데이터를 로드. auto이면 적절한 크기의 미디어를 미리 불러들임.

autoplay : 미디어가 충분히 다운로드되면 자동으로 재생을 시작해야 하는지 지정. true이면 미디어 데이터를 부라우저가 미리 불러와야 함.

미디어 상태 가져오기

플레이어가 일시정지되면 puase 프로퍼티 true, 새로운 재생 위치로 건너뛰면 seeking 프로퍼티 true, 마지막에 도달하여 재생이 중단되면 ended true (loop가 true이면 ended는 절대 true 안돼)

duration 프로퍼티는 미디어의 재생 시간을 초단위로 나타낸다. 미디어의 메타 데이터가 로드되기전이라면 NaN. 재생 시간이 일정하지 않은 스트리밍 미디어에서는 Infinity

initialTime 프로퍼티는 미디어의 시작 시간을 초 단위로 나타낸다. 재생시간이 정해진 미디어 클립에서는 보통 0. 스트리밍 미디어에서 이 프로퍼티는 재생 가능한 미디어의 위치보다 빠른 시간과 역 방향 탐색이 가능한 위치를 제공. (currentTime은 initialTime보다 빠른 시간을 설정할 수 없다.)

played 프로퍼티를 사용하면 재생된 범위를 돌아다니거나 그 범위를 반환받을 수 있다. buffered 프로퍼티를 사용하면 버퍼링된 영역을 돌아다니거나 그 범위를 반환받을 수 있다. seekable 프로퍼티는 비디오나 오디오 플레이어가 탐색 가능한 영역을 돌아다니거나 그 범위를 반환받을 수 있다.

playes와 buffered, seekable은 TimeRanges 객체다. 이 객체에는 해당 범위를 숫자로 나타내는 length 프로퍼티와 해당 범위의 시작과 종료 시간을 초 단위로 반환하는 start()와 end() 메서드가 있다.

  ex) var percent_loaded=Math.floor(song.buffered.end(0)/song.duration*100);

readyState와 networkState, error 프로퍼티는 <audio>와 <video> 문서 요소에 대한 자세한 저수준 상태를 제공한다. 각 프로퍼티에는 수치 값이 존재하며, 개별 수치 값에 대해 정의된 상수가 있다.

  ex) if(song.readyState===song.HAVE_ENOUGH_DATA) song.play();

readyState

 

newworkState

 

error

 

미디어 이벤트

<audio>와 <video>는 꽤 복잡한 문서 요소다. 대부분의 HTML 문서 요소처럼 <audio>와 <video>도 자기 상태가 변경될 때에는 이벤트가 일어난다. 이 문서 요소에는 복잡한 상태가 존재하기 때문에 이벤트도 상당히 많이 발생한다. 핸들러 함수는 <audio>나 <video> 문서 요소의 addEventListener() 메서드를 사용하여 등록한다.

 

SVG:Scalable Vector Graphics

SVG는 그래픽을 위한 XML 문법이다. SVG란 이름에서 V의 'vector'는 픽셀 값을 모은 GIF, JPEG, PNG 같은 비트맵 이미지와는 근본적으로 다른 이미지를 나타낸다. SVG 이미지는 원하는 그래픽을 그리기 위한 정밀하고 해상도 독립적인 표현법이다. SVG는 XML 문법이므로, SVG 그래픽을 그리는 일이란 결국, 적절한 XML 요소를 생성하는 DOM을 사용하는 것과 같다.

ex) 자바스크립트와 SVG로 파이 차트 그리기

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body onload="document.body.appendChild(pieChart([12,23,34,45],640,400,200,200,150,
                ['red','blue','yellow','green'],
                ['North','South','East','West'],400,100));
                ">
</body>
</html>

<script>
/**
 * Create an <svg> element and draw a pie chart into it.
 * Arguments:
 *   data: an array of numbers to chart, one for each wedge of the pie.
 *   width,height: the size of the SVG graphic, in pixels
 *   cx, cy, r: the center and radius of the pie
 *   colors: an array of HTML color strings, one for each wedge
 *   labels: an array of labels to appear in the legend, one for each wedge
 *   lx, ly: the upper-left corner of the chart legend
 * Returns: 
 *    An <svg> element that holds the pie chart.
 *    The caller must insert the returned element into the document.
 */
function pieChart(data, width, height, cx, cy, r, colors, labels, lx, ly) {
    // This is the XML namespace for svg elements
    var svgns = "http://www.w3.org/2000/svg";    // Create the <svg> element, and specify pixel size and user coordinates
    var chart = document.createElementNS(svgns, "svg:svg");
    chart.setAttribute("width", width);
    chart.setAttribute("height", height);
    chart.setAttribute("viewBox", "0 0 " + width + " " + height);

    // Add up the data values so we know how big the pie is
    var total = 0;
    for(var i = 0; i < data.length; i++) total += data[i];
    
    // Now figure out how big each slice of pie is. Angles in radians.
    var angles = []
    for(var i = 0; i < data.length; i++) angles[i] = data[i]/total*Math.PI*2;

    // Loop through each slice of pie.
    startangle = 0;
    for(var i = 0; i < data.length; i++) {
        // This is where the wedge ends
        var endangle = startangle + angles[i];

        // Compute the two points where our wedge intersects the circle
        // These formulas are chosen so that an angle of 0 is at 12 o'clock
        // and positive angles increase clockwise.
        var x1 = cx + r * Math.sin(startangle);
        var y1 = cy - r * Math.cos(startangle);
        var x2 = cx + r * Math.sin(endangle);
        var y2 = cy - r * Math.cos(endangle);
        
        // This is a flag for angles larger than than a half circle
        // It is required by the SVG arc drawing component
        var big = 0;
        if (endangle - startangle > Math.PI) big = 1;
        
        // We describe a wedge with an <svg:path> element
        // Notice that we create this with createElementNS()
        var path = document.createElementNS(svgns, "path");
        
        // This string holds the path details
        var d = "M " + cx + "," + cy +  // Start at circle center
            " L " + x1 + "," + y1 +     // Draw line to (x1,y1)
            " A " + r + "," + r +       // Draw an arc of radius r
            " 0 " + big + " 1 " +       // Arc details...
            x2 + "," + y2 +             // Arc goes to to (x2,y2)
            " Z";                       // Close path back to (cx,cy)

        // Now set attributes on the <svg:path> element
        path.setAttribute("d", d);              // Set this path 
        path.setAttribute("fill", colors[i]);   // Set wedge color
        path.setAttribute("stroke", "black");   // Outline wedge in black
        path.setAttribute("stroke-width", "2"); // 2 units thick
        chart.appendChild(path);                // Add wedge to chart

        // The next wedge begins where this one ends
        startangle = endangle;

        // Now draw a little matching square for the key
        var icon = document.createElementNS(svgns, "rect");
        icon.setAttribute("x", lx);             // Position the square
        icon.setAttribute("y", ly + 30*i);
        icon.setAttribute("width", 20);         // Size the square
        icon.setAttribute("height", 20);
        icon.setAttribute("fill", colors[i]);   // Same fill color as wedge
        icon.setAttribute("stroke", "black");   // Same outline, too.
        icon.setAttribute("stroke-width", "2");
        chart.appendChild(icon);                // Add to the chart

        // And add a label to the right of the rectangle
        var label = document.createElementNS(svgns, "text");
        label.setAttribute("x", lx + 30);       // Position the text
        label.setAttribute("y", ly + 30*i + 18);
        // Text style attributes could also be set via CSS
        label.setAttribute("font-family", "sans-serif");
        label.setAttribute("font-size", "16");
        // Add a DOM text node to the <svg:text> element
        label.appendChild(document.createTextNode(labels[i]));
        chart.appendChild(label);               // Add text to the chart
    }

    return chart;
}
</script>

 

ex) SVG이미지로 시간 출력하기

<!DOCTYPE HTML>
<html>
<head>
<title>Analog Clock</title>
<script>
function updateTime() { // Update the SVG clock graphic to show current time
    var now = new Date();                       // Current time
    var min = now.getMinutes();                 // Minutes
    var hour = (now.getHours() % 12) + min/60;  // Fractional hours
    var minangle = min*6;                       // 6 degrees per minute
    var hourangle = hour*30;                    // 30 degrees per hour

    // Get SVG elements for the hands of the clock
    var minhand = document.getElementById("minutehand");
    var hourhand = document.getElementById("hourhand");

    // Set an SVG attribute on them to move them around the clock face
    minhand.setAttribute("transform", "rotate(" + minangle + ",50,50)");
    hourhand.setAttribute("transform", "rotate(" + hourangle + ",50,50)");

    // Update the clock again in 1 minute
    setTimeout(updateTime, 60000);
}
</script>
<style>
/* These CSS styles all apply to the SVG elements defined below */
#clock {                          /* styles for everything in the clock */
   stroke: black;                 /* black lines */
   stroke-linecap: round;         /* with rounded ends */
   fill: #eef;                    /* on a light blue gray background */
}
#face { stroke-width: 3px;}       /* clock face outline */
#ticks { stroke-width: 2; }       /* lines that mark each hour */
#hourhand {stroke-width: 5px;}    /* wide hour hand */
#minutehand {stroke-width: 3px;}  /* narrow minute hand */
#numbers {                        /* how to draw the numbers */
    font-family: sans-serif; font-size: 7pt; font-weight: bold; 
    text-anchor: middle; stroke: none; fill: black;
}
</style>
</head>
<body onload="updateTime()">
  <!-- viewBox is coordinate system, width and height are on-screen size -->
  <svg id="clock" viewBox="0 0 100 100" width="500" height="500"> 
    <defs>   <!-- Define a filter for drop-shadows -->
     <filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
        <feGaussianBlur in="SourceAlpha" stdDeviation="1" result="blur" />
        <feOffset in="blur" dx="1" dy="1" result="shadow" />
        <feMerge>
          <feMergeNode in="SourceGraphic"/><feMergeNode in="shadow"/>
        </feMerge>
      </filter>
    </defs>
    <circle id="face" cx="50" cy="50" r="45"/>  <!-- the clock face -->
    <g id="ticks">                              <!-- 12 hour tick marks -->
      <line x1='50' y1='5.000' x2='50.00' y2='10.00'/>
      <line x1='72.50' y1='11.03' x2='70.00' y2='15.36'/>
      <line x1='88.97' y1='27.50' x2='84.64' y2='30.00'/>
      <line x1='95.00' y1='50.00' x2='90.00' y2='50.00'/>
      <line x1='88.97' y1='72.50' x2='84.64' y2='70.00'/>
      <line x1='72.50' y1='88.97' x2='70.00' y2='84.64'/>
      <line x1='50.00' y1='95.00' x2='50.00' y2='90.00'/>
      <line x1='27.50' y1='88.97' x2='30.00' y2='84.64'/>
      <line x1='11.03' y1='72.50' x2='15.36' y2='70.00'/>
      <line x1='5.000' y1='50.00' x2='10.00' y2='50.00'/>
      <line x1='11.03' y1='27.50' x2='15.36' y2='30.00'/>
      <line x1='27.50' y1='11.03' x2='30.00' y2='15.36'/>
    </g>
    <g id="numbers">                     <!-- Number the cardinal directions-->
      <text x="50" y="18">12</text><text x="85" y="53">3</text>
      <text x="50" y="88">6</text><text x="15" y="53">9</text>
    </g>
    <!-- Draw hands pointing straight up. We rotate them in the code. -->
    <g id="hands" filter="url(#shadow)"> <!-- Add shadows to the hands -->
      <line id="hourhand" x1="50" y1="50" x2="50" y2="24"/>
      <line id="minutehand" x1="50" y1="50" x2="50" y2="20"/>
    </g>
  </svg>
</body>
</html>

 

<canvas> 그래픽

<canvas> 문서 요소는 자체적인 외형은 없지만, 문서 내 드로잉 영역을 생성하고 클라이언트 측 자바스크립트에서 사용 가능한 강력한 드로잉 API를 포함하고 잇다. <canvas> 문서 요소와 SVG 사이의 가장 중요한 차이점은, 캔버스는 메서드 호출을 통해 그림을 생성하고, SVG는 XML 문서 요소 트리를 만들어 그림을 생성한다는 점이다.

생략~~

ex) <canvas>를 사용한 sparkline

/*
 * Find all elements of CSS class "sparkline", parse their content as
 * a series of numbers, and replace it with a graphical representation.
 *
 * Define sparklines with markup like this:
 *   <span class="sparkline">3 5 7 6 6 9 11 15</span>
 *
 * Style sparklines with CSS like this:
 *   .sparkline { background-color: #ddd; color: red; }
 *
 * - Sparkline color is from the computed style of the CSS color property.
 * - Sparklines are transparent, so the normal background color shows through.
 * - Sparkline height is from the data-height attribute if defined or from
 *   the computed style for the font-size otherwise.
 * - Sparkline width is from the data-width attribute if it is defined
 *   or the number of data points times data-dx if that is defined or
 *   the number of data points times the height divided by 6
 * - The minimum and maximum values of the y axis are taken from the data-ymin
 *   and data-ymax attributes if they are defined, and otherwise come from
 *   the minimum and maximum values of the data.
 */
onLoad(function() {   // When the document firsts loads
    // Find all elements of class "sparkline"
    var elts = document.getElementsByClassName("sparkline");
    main: for(var e = 0; e < elts.length; e++) { // For each element
        var elt = elts[e];

        // Get content of the element and convert to an array of numbers.
        // If the conversion fails, skip this element.
        var content = elt.textContent || elt.innerText;  // Element content
        var content = content.replace(/^\s+|\s+$/g, ""); // Strip spaces
        var text = content.replace(/#.*$/gm, "");  // Strip comments
        text = text.replace(/[\n\r\t\v\f]/g, " "); // Convert \n etc, to space
        var data = text.split(/\s+|\s*,\s*/);      // Split on space or comma
        for(var i = 0; i < data.length; i++) {     // For each chunk
            data[i] = Number(data[i]);             // Convert to a number
            if (isNaN(data[i])) continue main;     // and abort on failure
        }

        // Now compute the color, width, height, and y axis bounds of the 
        // sparkline from the data, from data- attributes of the element,
        // and from the computed style of the element.
        var style = getComputedStyle(elt, null); 
        var color = style.color;
        var height = parseInt(elt.getAttribute("data-height")) ||
            parseInt(style.fontSize) || 20;
        var width = parseInt(elt.getAttribute("data-width")) ||
            data.length * (parseInt(elt.getAttribute("data-dx")) || height/6);
        var ymin = parseInt(elt.getAttribute("data-ymin")) ||
            Math.min.apply(Math, data);
        var ymax = parseInt(elt.getAttribute("data-ymax")) ||
            Math.max.apply(Math, data);
        if (ymin >= ymax) ymax = ymin + 1;

        // Create the canvas element.
        var canvas = document.createElement("canvas"); 
        canvas.width = width;     // Set canvas dimensions
        canvas.height = height;
        canvas.title = content;   // Use the element content as a tooltip
        elt.innerHTML = "";       // Erase existing element content
        elt.appendChild(canvas);  // Insert the canvas into the element

        // Now plot the points (i,data[i]), transforming to canvas coordinates.
        var context = canvas.getContext('2d');
        for(var i = 0; i < data.length; i++) {          // For each data point
            var x = width*i/data.length;                // Scale i
            var y = (ymax-data[i])*height/(ymax-ymin);  // Scale data[i]
            context.lineTo(x,y); // First lineTo() does a moveTo() instead
        }
        context.strokeStyle = color;   // Specify the color of the sparkline
        context.stroke();              // and draw it
    }
});
728x90
LIST

' > 자바스크립트 완벽 가이드' 카테고리의 다른 글

22장 HTML5 API  (0) 2020.11.30
20장 클라이언트 스토리지  (0) 2020.11.28
18장 HTTP 스크립팅  (0) 2020.11.27
17장 이벤트 다루기  (0) 2020.11.23
16장 CSS 다루기  (0) 2020.11.22
댓글
공지사항