내보내기(0) 인쇄
모두 확장
이 항목은 아직 평가되지 않았습니다.- 이 항목 평가

Mandelbrot 탐색기

.NET Framework 3.0

웹 작업자 활용에서 제공한 정보를 기반으로 여기에서는 최종 버전인 Mandelbrot 탐색기를 생성하도록 Mandelbrot 8을 향상시키는 방법에 대해 설명합니다.

Mandelbrot 8의 다음과 같은 기능을 개선하여 Mandelbrot 탐색기를 생성했습니다.

  • 그리기 상태: 특별한 관심을 끌지 않는 calculating... 메시지가 캔버스의 중앙에 위치하여 더 잘 보이는 애니메이션으로 바뀌었습니다.
  • 확대/축소 상자 그리기: 이제 임의의 모서리에서 시작하여 확대/축소 상자를 그릴 수 있으며 그 애니메이션 성능이 개선되었습니다.
  • 웹 작업자 대체: 웹 작업자를 지원하면 더 빠른 성능을 제공할 수 있지만 Mandelbrot 탐색기가 작동하기 위해 브라우저에서 웹 작업자를 지원할 필요가 없습니다.

그리기 상태

Mandelbrot 이미지가 실제로 그려지고 있음을 확인할 수 있도록 왼쪽 위의 calculating... 메시지가 <progress> 요소를 사용하여 캔버스의 중앙에 위치한 애니메이션으로 바뀌었습니다. progress 요소를 캔버스의 가운데에 배치하려면 다음 HTML을 사용합니다.


<div id="canvasWrapper">
  <progress id="progressIndicator"></progress>
  <canvas width="600" height="400" oncontextmenu="return false;">
    Canvas not supported - upgrade your browser (after checking that your browser is in the correct mode).
  </canvas>
</div>


<div id="canvasWrapper"> 래퍼를 사용하면 캔버스의 중앙을 쉽게 찾을 수 있으며 다음 CSS(주석에서 각 CSS 속성에 대해 설명)를 사용하여 이 중앙을 기준으로 progress 요소를 배치할 수 있습니다.


##canvasWrapper {
  position: relative; /* Allows any absolutely positioned child element to be positioned relative to this (parent) element. */
  width: 604px; /* Account for the two 2px wide borders of the 600px wide canvas element. */
  margin: 0 auto; /* Center the canvas wrapper on the page. */
}

progress {
  display: block; /* For browsers that do not recognize <progress> tags, this makes them work as expected (i.e., as a generic DIV element would). */
}

#progressIndicator {
  color: red; /* Make the progress bar highly visible. */
  display: none; /* Only display the <progress> tag when the Mandelbrot set is being calculated. */
  position: absolute; /* This is positioned relative to the #canvasWrapper DIV element. */
  width: 400px; /* The width of the progress bar. */
  height: 20px; /* The height of the progress bar. */
  left: 102px; /* The canvas is 600px wide, the progress bar is 400px wide, so to center the progress bar, the progress bar must start 100px from the left of the canvas plus a 2px border. */
  top: 192px; /* The canvas is 400px high, the progress bar is 20px tall, so to center the progress bar, the progress bar must start 190px from the top of the canvas plus a 2px border. */
}

이제 진행률 표시기를 표시하기 위해 프로그래밍 방식으로 해당 display CSS 속성을 progressIndicator.style.display = "none"에서 progressIndicator.style.display = "block"으로 전환합니다.

확대/축소 상자 그리기

기존 확대/축소 상자 구현의 문제점 중 하나는 왼쪽 위 모서리에서 오른쪽 아래로 확대/축소 상자를 그려야 한다는 점입니다. 여기에서는 사용자가 임의의 모서리에서 시작하여 확대/축소 상자를 그릴 수 있도록 이 제한을 제거하는 방법에 대해 설명합니다.

각각 서로 다른 모서리의 시작 지점을 보여 주는 네 개의 확대/축소 상자 예

예를 보면 알 수 있듯이 확대/축소 상자는 모든 모서리(x1, y1)에서 시작하여 반대쪽 모서리(x2, y2)에서 끝나도록 정의할 수 있습니다.

확대/축소 상자는 handlePointer 이벤트 처리기에 의해 처리되므로 다음 이전 및 이후 표에서 빨간색 글꼴로 표시된 대로 handlePointer를 수정합니다.

이 예제와 마지막 예제의 코드 비교

첫 번째 차이점은 var point = {x: 0, y: 0} 줄입니다. 이 개체는 확대/축소 상자를 그리는 방식에 관계없이 확대/축소 상자의 왼쪽 위 모서리 점을 포함합니다.

다음으로 down 이벤트 절을 if 문에 포함하여 down 이벤트 코드가 한 번만 실행되도록 합니다.


if (!globals.pointer.down) {
  globals.pointer.down = true;      
  globals.pointer.x1 = canvasX;
  globals.pointer.y1 = canvasY;          
}

move 이벤트 절에서 requestAnimationFrame을 사용하여 적절한 간격으로 확대/축소 상자 및 기본 Mandelbrot 이미지를 그리는 방식으로만 확대/축소 상자의 애니메이션 성능을 개선합니다.


case 'MSGestureChange':                  
case 'mousemove':
  if (globals.pointer.down) {
    zoomBoxHeight = Math.abs(canvasY - globals.pointer.y1); 
    zoomBoxWidth = zoomBoxHeight * canvasWidthHeightRatio; 
               
    if (window.requestAnimationFrame.id) { 
      window.cancelAnimationFrame(window.requestAnimationFrame.id); 
    } 
    window.requestAnimationFrame.id = window.requestAnimationFrame(function() { 
      ctx.putImageData(ctx.imageDataObject, 0, 0); 
      point = getTopLeftZoomBoxPoint(globals.pointer.x1, globals.pointer.y1, canvasX, canvasY);
      ctx.fillRect(point.x, point.y, zoomBoxWidth, zoomBoxHeight); 
    });                        
  } 
  break;

handleLoad에서 requestAnimationFrame이 지원되지 않으면 setTimeout이 대신 사용됩니다.


if (!window.requestAnimationFrame) {
  window.cancelAnimationFrame = function(ID) {
    window.clearInterval(ID);
  }
  
  window.requestAnimationFrame = function(callback) { 
    return window.setTimeout(callback, 16.7);
  }
}

move 이벤트 절에서 보는 바와 같이 move 이벤트 중에 getTopLeftZoomBoxPoint가 호출되며, fillRect를 사용하여 확대/축소 상자를 그릴 수 있도록 확대/축소 상자의 왼쪽 위 모서리를 반환합니다.


point = getTopLeftZoomBoxPoint(globals.pointer.x1, globals.pointer.y1, canvasX, canvasY);
ctx.fillRect(point.x, point.y, zoomBoxWidth, zoomBoxHeight);

이 함수는 다음과 같이 정의됩니다.


function getTopLeftZoomBoxPoint(x1, y1, x2, y2) {
/* 
  (x1, y1) is where the down pointer event occurred. (x2, y2) is where the move or up pointer event occurred.
*/
  if (x1 <= x2) {
    if (y1 <= y2) {
      return {x: x1, y: y1}; // User has drawn (or is drawing) a zoom box from the upper-left toward the lower-right.
    } else { // y1 > y2
      return {x: x1, y: y1 - zoomBoxHeight}; // User has drawn (or is drawing) a zoom box from the lower-left toward the upper-right.
    } // if-else
  } else { // x1 > x2
    if (y1 <= y2) {
      return {x: x1 - zoomBoxWidth, y: y1}; // User has drawn (or is drawing) a zoom box from the upper-right toward the lower-left.
    } else { // y1 > y2
      return {x: x1 - zoomBoxWidth, y: y1 - zoomBoxHeight}; // User has drawn (or is drawing) a zoom box from the lower-right toward the upper-left.
    } // if-else
  } // if-else
} // getTopLeftZoomBoxPoint

모서리에서 모서리로 확대/축소 상자를 그릴 수 있는 4가지 가능한 방법을 보여 주는 이 이미지를 살펴보면 if-else 절을 이해할 수 있습니다.

각각 서로 다른 모서리의 시작 지점을 보여 주는 네 개의 확대/축소 상자 예

사용자가 왼쪽 아래에서 시작하여 오른쪽 위에서 끝나는 경우(즉, x1 < x2y1 > y2)를 살펴보겠습니다. 이 경우 x1은 확대/축소 상자의 왼쪽 위 모서리에 대한 x-좌표이고 y1 - zoomBoxHeight는 확대/축소 상자의 왼쪽 아래 모서리에 대한 y-좌표이므로 getTopLeftZoomBoxPoint{x: x1, y: y1 - zoomBoxHeight} 점을 반환합니다. 확대/축소 상자를 그릴 수 있는 나머지 세 가지 방법은 유사한 방식으로 계산됩니다.

handlePointer로 돌아갑니다. up 이벤트 절의 주요 변경 내용은 globals.holdGesture 검사입니다.


if (zoomBoxHeight == 0 || globals.holdGesture)

길게 누르기 제스처 중에 up 이벤트가 발생하면 확대/축소 상자를 그리지 않은 경우와 동일한 코드를 실행합니다(zoomBoxHeight == 0). globals.holdGesturehandleLoad 이벤트에서 false로 초기화됩니다. (MSGestureHold 이벤트 절, globals.holdGesturetrue로 설정합니다).

웹 작업자

Mandelbrot 8은 단순히 웹 작업자가 필요하며 종료되었음을 알리며, 뛰어난 사용자 환경은 아닙니다. 웹 작업자를 지원하지 않는 브라우저를 수용하기 위해 Mandelbrot 7에서 비작업자 Mandelbrot 코드를 차용(drawMandelbrotWithoutWebWorkers로 이름 변경)한 다음 필요한 경우 handleHashChange에서 호출합니다.


if (window.Worker) {
  initializeWebWorkers('mandelbrotWebWorker.js');
  drawMandelbrotWithWebWorkers(globals.ReMax, globals.ReMin, globals.ImMax, globals.ImMin, globals.grayscaleFactor);              
}
else {
  drawMandelbrotWithoutWebWorkers(globals.ReMax, globals.ReMin, globals.ImMax, globals.ImMin, globals.grayscaleFactor);      
}

요약하면 HTML5를 사용하여 Mandelbrot 집합을 탐색하는 방법 자습서에서는 다음과 같은 주요 HTML5 기능을 보여 주었습니다.

다른 몇 가지 기능과 함께 이러한 기능을 사용하여 Mandelbrot 집합(영문)이라는 가장 복잡하고 아름다운 수학적 개체 중 하나를 탐색할 수 있는 성능이 우수한(영문) 웹 앱을 만들었습니다. 다음 표에는 이 놀라운 집합을 탐색하는 데 동기를 부여하기 위해 특히 흥미롭거나 특별한 Mandelbrot 집합의 영역에 대한 링크가 나와 있습니다.

링크
Black Spiral
Blatweasel
Boomerang
Cyclopes
Diamond Fur
Feather Ball
Fern Curl
Four Star
Galactic Spin
Lace
Mandel Swirl
North Star
River Styx
Round Square
Sparkler
Spiderweb
Star Cluster
Straight and Narrow
Swirly Bob
Twiggy

 

관련 항목

HTML5를 사용하여 Mandelbrot 집합을 탐색하는 방법

 

 

이 정보가 도움이 되었습니까?
(1500자 남음)
의견을 주셔서 감사합니다.
표시:
© 2014 Microsoft. All rights reserved.