Tizen에서 Raphael JS 라이브러리 작업

이 문서에서는 Raphael JavaScript 라이브러리와 Tizen에서의 사용 방법을 설명합니다. 기본 제공(사각형, 원, 타원) 셰이프와 기타 셰이프(경로 사용) 등 간단한 2D 셰이프를 그리는 방법, Raphael 요소 속성으로 작업하는 방법, 간단한 애니메이션을 생성하는 방법 등을 설명합니다. 또한 요소(이동, 확장 및 회전)를 조작하는 방법도 알아볼 것입니다 .

Raphael JS 라이브러리 시작하기

Raphael JS는 Tizen 웹 애플리케이션에서 벡터 그래픽 작업을 허용하는 작은 JavaScript 라이브러리입니다. SVG W3C 권장 및 VML을 사용합니다. SVG 개체를 사용하여 각 개체는 예를 들어 이벤트 처리기를 첨부할 수 있는 SVG DOM 개체이기도 합니다.

Rapheal JS 라이브러리 사용하려면:

  1. 다운로드 페이지에서 Raphael JS 프레임워크를 다운로드합니다. 라이브러리의 축소 또는 압축된 버전을 다운로드하기 위해 선택할 수 있습니다.
  2. 헤드 섹션에서 프로젝트에 포함시킵니다.

참고: 쉬운 참조를 위해 본 문서에서 사용/설명된 특정 함수가 Raphael 문서의 해당 부분으로 하이퍼링크되었습니다.

Raphael JS 라이브러리와 몇 가지 놀라운 데모에 대한 자세한 내용은 raphaeljs.com에서 볼 수 있습니다. 문서는 여기에서 확인할 수 있습니다. Raphael JS 라이브러리의 기능을 보여주는 유용한 페이지를 여기에서 찾을 수 있습니다.

RaphaelPaint 샘플 애플리케이션 소개

RaphaelPaint 샘플 애플리케이션은 Raphael JavaScript 라이브러리를 사용하여 2D 벡터 그래픽을 만들고 작업하는 방법을 보여줍니다.

샘플 애플리케이션의 UI는 단일 페이지로 구성되어 있습니다. 실행 후 페이지 맨 위에 도구 모음과 빈 캔버스가 표시됩니다. 도구 모음에는 "화살표", "직사각형", "정사각형", "삼각형", "원", "타원", "별", "지우개", "채우기 색", "스트로크 색", "캔버스 지우기" 등의 옵션이 포함되어 있습니다. 첫 번째 옵션을 사용하면 선택한 셰이프(이동, 크기 조정 및 회전)를 조작할 수 있습니다 다음 6개의 옵션으로 일반적인 셰이프를 그릴 수 있습니다. 다른 도구 사용에는 따로 설명이 필요 없습니다.

그림 1 샘플 애플리케이션 스크린샷

샘플 애플리케이션은 전체 Tizen 뷰포트(720x1280)를 사용하고 jQuery Mobile 1.3.0 프레임워크 및 jQuery 1.9.0 라이브러리를 포함하여 Tizen SDK 2.0.0에서 테스트되었습니다.

셰이프 및 경로 그리기

두 가지 방법으로 Raphael JS를 사용하여 셰이프를 그릴 수 있습니다.

  • 기본 제공 셰이프 사용(라이브러리에서 제공): 사각형, 원, 타원
  • 경로 사용

이러한 방법은 모두 아래에 설명되어 있습니다.

모든 셰이프는 Raphael 종이에 그려지므로 Raphael JS 프레임워크를 사용하려면 우선 하나 이상의 인스턴스를 만들어야 합니다. Raphael() 함수를 사용하여 수행할 수 있습니다. 이 함수는 여러 가지 다른 인수 집합을 사용할 수 있습니다. 샘플 애플리케이션은 다음 중 하나를 사용합니다.

container = document.getElementById('canvas_container');
paper = new Raphael(container, config.canvas.width, config.canvas.height);

컨테이너는 다른 요소를 사용할 수 있는 DOM 요소를 나타냅니다. Raphael 종이는 이 요소 안에 그려집니다. 매개 변수로 컨테이너를 적용하는 대신 종이의 (x, y) 위치를 정의할 수도 있습니다.

너비와 높이 매개 변수는 생성된 종이의 너비와 높이를 나타냅니다.

그리기 표면이 있으면 그 위에 몇 가지 셰이프를 그립니다. 이 표면을 작동하려면 클릭 위치 좌표가 필요합니다. 이러한 목적으로 컨테이너에 이벤트 처리기를 연결해야 합니다.

$("#canvas_container").on(
        "click",
        function(e) {
            e.preventDefault();
            var rect = container.getBoundingClientRect();
            var x0 = e.pageX, y0 = e.pageY;
            var x = x0 - rect.left, y = y0 - rect.top;
            var elem = paper.getElementByPoint(x0, y0);

            if (config.tool === "arrow") {
                ...
            } else {
                paint(x, y);
            }
        })

GetBoundingClientRect() 함수는 상단, 왼쪽, 오른쪽, 하단 등 4개의 속성을 가진 TextRectangle 개체를 반환합니다. 이러한 속성은 컨테이너의 위치를 정의합니다. 컨테이너의 내부를 클릭하면 콜백 함수가 클릭 위치를 사용하는 pageX 및 pageY를 가진 매개 변수로 이벤트 개체 (e)를 가져옵니다. 이 위치는 장치 화면의 왼쪽 상단 모서리를 기준으로 합니다. 약간의 수학을 하면서 컨터이너의 왼쪽 상단 모서리를 기준으로 한 위치로 개체를 변환해야 합니다.

여기서 rect는 getBoundingClientRect () 함수에서 반환하는 TextRectangle 개체를 의미합니다.

그림 2 그려진 개체의 좌표 결정

이제 (물론 화살표 이외의 도구를 선택하는 경우) 적절한 위치에 셰이프를 그릴 수 있습니다.

참고: Raphael의 좌표계는 캔버스와 동일합니다.

그림 3 Raphael JS 좌표계

기본 제공 셰이프

전에 언급했듯이 Raphael JS 라이브러리에서 제공하는 3개의 기본 제공 셰이프가 있습니다. 셰이프를 그리려면 다음 함수를 사용해야 합니다(다음 이미지는 입력 매개 변수를 이해하는 방법을 설명합니다).

var rect = paper.rect(x, y, width, height);

또한 paper.rect() 메서드를 사용하여 정사각형(너비와 높이가 같은 사각형)을 그립니다.

var circle = paper.circle(x, y, radius);

var ellipse = paper.ellipse(x, y, rx, ry);

경로 그리기

다른 셰이프(예: 삼각형, 다른 다각형)는 어떻게 그려야 할까요? "경로"를 사용할 수 있습니다.

경로는 명령과 인수로 분리된 공간으로 구성된 문자열입니다. 예:

"M 100 100 l 100 0 l 0 100 l -100 -100"

이 경로는 "(100, 100)으로 이동, 올바른 방향으로 100 정렬, 아래로 100 정렬, x축에서 100픽셀, y축에서 100픽셀로 왼쪽 상단 방향으로 선 그리기"를 의미합니다. 결과는 다음과 같습니다. 

동일한 효과가 경로에 영향을 미칩니다.

"M 100 100 l 100 0 l 0 100 z”

즉, "(100, 100)으로 이동, 올바른 방향으로 100 정렬, 아래 방향으로 100 정렬한 후 경로를 닫습니다(경로의 마지막 지점과 첫 번째 지점 연결)".

Raphael 참조에 따른 명령과 의미:

두 가지 유형의 명령이 있습니다. 명령 “L”(대문자)은 “l”(소문자)과 동일하지 않습니다. 첫 번째 유형은 절대적 명령, 두 번째 유형은 상대적 명령입니다. 차이점은 무엇입니까?

"L 100 0” 의미: 선 - 점(100, 0)

"l 100 0” 의미: 오른쪽으로 100 정렬

여기에서 명령에 대한 자세한 정보를 찾을 수 있습니다.

RaphaelPaint 샘플 애플리케이션은 경로를 사용하여 다음 셰이프를 그립니다.

  • 삼각형

새로 만들어진 셰이프는 경계 상자(선택한 대로)로 표시되었습니다. 모든 요소에 대한 경계 상자를 가져오려면 Element.getBBox() 함수를 사용할 수 있습니다. 함수를 사용하는 유일한 매개 변수는 부울 값입니다. (변환하기 전에) 원래 셰이프를 포함한 경계 상자를 가지려는지 여부를 지정합니다. 선택적이며 기본적으로 false와 같습니다. 이 함수를 사용하는 예: 

addBox : function() {
    ...

    var bBox = selectedShape.getBBox();
    lastbBox = paper.rect(bBox.x,bBox.y,bBox.width,bBox.height).attr({stroke:"#9a9a9a"});
},

보시다시피 함수는 선택한 셰이프의 경계 상자를 가져오고 그립니다. 상자는 셰이프를 만든 후 요소를 끌어갈 때마다 추가됩니다.

속성 작업

그려진 요소의 속성을 변경하거나 가져오려면 Element.attr() 함수를 사용할 수 있습니다.

이러한 두 가지 속성 설정 방법은 동일합니다.

elem.attr({
    // Attributes of the element
    "fill" : "#dfed48",
    "stroke" : "#dfed48"
});

Elem.attr("fill", "#dfed48");
Elem.attr("stroke ", "#dfed48");

한 번에 하나 또는 여러 요소의 속성을 설정할 수 있습니다. 여러 속성을 설정할 때 속성의 이름 및 속성의 값을 지정하는 값을 지정하여 키를 포함한 개체를 전달해야 합니다. 하나의 속성을 설정할 때 첫 번째 매개 변수는 속성 이름이고 두 번째 매개 변수는 새 값입니다.  단 하나의 매개 변수만이 전달되는 경우(속성의 이름) Element.attr() 함수는 이 속성의 값을 반환합니다. 예: Elem.attr("fill")는 "#dfed48" 문자열을 반환합니다. 가능한 속성 이름은 2011년 8월 16일 이후로 Raphael 참조W3C SVG 1.1 권장 사항에 설명되어 있습니다.

 

변환 추가

RaphaelPaint를 사용하면 개체를 이동, 크기 조정, 회전할 수 있습니다. 이러한 변환을 제공하려면 Element.transform() 함수를 사용할 수 있습니다. 이 함수를 호출하는 방법은 경로를 만드는 메서드와 비슷합니다. 명령 및 매개 변수를 가진 문자열을 만들어야 합니다. 샘플 애플리케이션은 Raphael JS에서 제공하는 4개의 명령 중 3개를 사용합니다.  

참고: m(매트릭스) 명령 설명은 이 문서의 범위를 벗어납니다. 생성된 문자열을 Element.transform() 함수의 매개 변수로 적용해야 합니다. 샘플 애플리케이션의 경우 applyTransforms() 함수는 이 작업을 수행할 수 있습니다.

/**
 * Adds specified transformation to the element
 *
 * @param that {Object} Element to which the transformation is added
 */
applyTransforms : function(that) {
    var str = "t" + that.translate[0] + "," + that.translate[1] + "r"
            + that.rotate + "s" + that.scale[0] + "," + that.scale[1];
    that.transform(str);
    …
}

that.translate, that.rotate and that.scale 속성은 새로 만들어진 셰이프 속성을 설정하는 동안 생성되고 초기화되었습니다. 이러한 속성은 나중에 보다 상세히 설명합니다. 

var setProperties = function(elem) {
    ...

    // Initial values of applied transforms
    elem.translate = [ 0, 0 ];
    elem.scale = [ 1, 1 ];
    elem.rotate = 0;

    ...

    return elem;
}

적절한 순서로 변환을 적용하는 것이 중요합니다. "t100,20r60"과 "r60t100,20"은 매우 유사해 보이지만 다른 결과를 제공합니다.   

1 - 변환 없는 삼각형

2 - "t100, 20r60" 변환 후 삼각형

3 - "r60t100, 20" 변환 후 삼각형

Raphael 요소에 변환을 추가하는 동안 유의하십시오.  

생성된 변환을 요소에 적용하는 방법을 알고 있습니다. 변환의 명령 속성을 설정합니다. 이러한 속성은 드래그 이벤트와 관련이 있습니다. 아래 단편에서 "방법"을 설명합니다. 첫째, Element.drag() 함수를 사용하여 요소의 드래그에 대한 이벤트 처리기를 추가해야 합니다. 

// Sets event handlers for moving, drag start and drag end
elem.drag(transforms.move, transforms.start, transforms.up);

./js/transforms.js 모듈에 그려진 모든 셰이프 이동, 드래그 시작, 드래그 끝에 대한 이벤트 처리기가 있습니다. 

/**
 * Event handler for drag start
 */
start : function() {
    that = this;

    ...

    if (config.tool === 'arrow') {
        ...

        switch (config.operation) {
        case "move": {
            // read last translation
            that.odx = that.translate[0];
            that.ody = that.translate[1];
        }
            break;

        case "scale": {
            // read last scale
            that.osx = that.scale[0];
            that.osy = that.scale[1];
        }
            break;

        default:
            break;
        }
    }
},

/**
 * Event handler for moving
 * @param dx {Number} shift by x axis from the start point
 * @param dy {Number} shift by y axis from the start point
 */
move : function(dx, dy) {
    if (config.tool === 'arrow') {
        switch (config.operation) {
        case "move": {
            // change translation
            that.translate[0] = that.odx + dx;
            that.translate[1] = that.ody + dy;
        }
            break;

        case "scale": {
            // change scaling
            if ((that.fig !== "circle") && (that.fig !== "square")) {
                // for all figures except circle and square
                that.scale[0] = that.osx + 10 * dx
                        / config.canvas.width;
                that.scale[1] = that.osy + 10 * dy
                        / config.canvas.height;
            } else {
                // for circle and square
                if (dx > dy) {
                    that.scale[0] = that.scale[1] = that.osx + 10 * dx
                            / config.canvas.width;
                } else {
                    that.scale[0] = that.scale[1] = that.osy + 10 * dy
                            / config.canvas.height;
                }
            }
        }
            break;

        default:
            break;
        }

        transforms.applyTransforms(that);
    }
},

 

간단한 애니메이션

개체에 애니메이션을 적용하려면 Element.animate() 함수를 사용해야 합니다. 지정된 요소에 대한 애니메이션을 만들고 시작합니다. Element.animate() 함수를 사용하는 예:

// Animation for selected element
that.animate({
    "fill-opacity" : 0.4
}, 500);

첫 번째 매개 변수는 애니메이션된 셰이프에 대한 마지막 속성의 값을 정의합니다. 두 번째 매개 변수는 애니메이션 기간(밀리초 단위)을 지정합니다. 또한 Element.animate() 함수 각각 감속/가속 유형과 콜백 함수를 나타내는 세 번째 매개 변수와 네 번째 매개 변수를 사용합니다(애니메이션이 종료될 때 호출됨).

RaphaelPaint 샘플 애플리케이션은 몇 가지 요소를 드래그하는 경우 Element.animate() 함수를 사용합니다. 드래그 시작 이벤트가 호출되는 경우 셰이프의 칠 불투명도 속성이 감소하고 드래그 엔드에서 이전 상태로 반환됩니다.

 

'종이' 작업

셰이프를 그리고 속성을 변경하며 변환 및 애니메이션을 추가할 수 있습니다. 그러나 조작하려는 요소는 어떻게 선택해야 합니까? Raphael JS에서 Paper.getElementByPoint(x, y) 함수를 제안합니다. 셰이프 내에 포함된 (x, y) 지점을 가진 최상위 요소를 반환합니다. x, y는 장치 화면의 왼쪽 상단 모서리에서 x 및 y 좌표를 나타냅니다(그림 2 참조).

var elem = paper.getElementByPoint(e.pageX, e.pageY);

  Element.remove() 함수를 호출하는 '지우개' 도구를 사용하여 종이에서 선택한 요소를 제거할 수 있습니다.

/**
 * Removes specified element (figure) from canvas
 * @param elem {Object} Element to be removed
 */
removeShape : function(elem) {
    elem.remove();
    if (lastbBox) {
        lastbBox.remove();
    }
},

종이에서 모든 요소를 제거하려면 Paper.clear() 함수를 사용할 수 있습니다. 매개 변수를 사용하지 않습니다. 예:

case "clear": {
    ...
    paper.clear();
    ...
}
break;

 

요약

이 문서가 Tizen 웹 애플리케이션에서 Raphael JS 라이브러리를 활용하는 데 도움이 되기를 바랍니다. 다음을 만드는 데 사용할 수 있습니다.

첨부 파일: