>웹 프론트엔드 >H5 튜토리얼 >HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

高洛峰
高洛峰원래의
2016-11-23 10:02:491404검색

토폴로지의 이전 애플리케이션은 모두 정적 프리미티브였습니다. 오늘은 토폴로지에서 임펠러 회전이라는 움직이는 프리미티브를 디자인하겠습니다.

우리가 달성한 최종 효과를 살펴보겠습니다. http://www.hightopo.com/demo/fan/index.html

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

먼저 해 보세요 이 임펠러 모델이 어떻게 생겼는지 보세요

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

모델 관점에서 보면 이 임펠러 모델에는 블레이드가 3개 있는데 각 블레이드는 불규칙한 모양입니다. 우리 HT for Web 기본 그래픽에서는 사용할 수 없는데 어떻게 해야 할까요? 매우 간단합니다. HT for Web은 맞춤형 그래픽 솔루션을 제공하여 나뭇잎과 같은 불규칙한 그래픽을 그릴 수 있습니다.

나뭇잎을 그리기 전에 먼저 웹용 HT에서 그리는 사용자 정의 그래픽에 대한 기본 지식을 이해해야 합니다.

사용자 정의 그래픽을 그리려면 벡터 유형을 모양으로 지정하고 points Array 배열은 각 포인트 정보를 지정하며, 포인트는 [x1, y1, x2, y2, x3, y3, ...] 형식으로 포인트 좌표를 저장합니다. 곡선의 다각형은 세그먼트의 배열 배열로 설명할 수 있습니다. 세그먼트는 [1, 2, 1, 3...] 형식으로 각 선 세그먼트를 설명합니다.

1: moveTo, 1 포인트를 차지합니다. 정보, 새 경로의 시작점을 나타냄

2: lineTo, 1점 정보 점유, 마지막 마지막 점에서 이 점까지의 연결을 나타냄

3:quadraticCurveTo, 2점 정보 점유 , 첫 번째 한 점은 곡선 제어점으로, 두 번째 점은 곡선 끝점으로 사용됩니다.

4: bezierCurveTo, 3개 점 정보를 점유하고, 첫 번째와 두 번째 점은 곡선 제어점으로 사용되며, 세 번째 점은 곡선 끝점으로 사용됩니다.

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

5: closePath, 점 정보를 차지하지 않고 이 경로 그리기의 끝을 나타내며 시작점에 닫혀 있습니다. 경로 지점

닫힌 다각형과 비교하여 세그먼트 설정 외에도 closePath 속성을 설정할 수도 있습니다. * closePath는 다각형이 닫혀 있는지 여부를 가져오고 설정합니다. 방법은 세그먼트 매개변수를 설정하지 않고 닫힌 직선에 사용됩니다.

그럼 블레이드 디자인을 시작하겠습니다

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

ht.Default.setImage('vane', {
    width: 97,
    height: 106,
    comps: [
        {
            type: 'shape',
            points: [
                92, 67,
                62, 7,
                0, 70,
                60, 98
            ],
            segments: [
                1, 2, 2, 2
            ],
            background : 'red'
        }
    ]
});

벡터에 4개의 꼭지점을 정의하고 이 4개의 꼭지점을 결합하여 일반적인 모양을 설명합니다. 조금 추상적이지만 블레이드는 제어점을 추가하고 세그먼트 매개변수를 변경하여 다음으로 변형됩니다.

먼저 bezierCurveTo 메서드를 통해 첫 번째 꼭지점과 두 번째 꼭지점 사이의 선분에 두 개의 제어점을 추가하여 곡선을 그립니다.

points: [
    92, 67,
    93, 35, 78, 0, 62, 7,
    0, 70,
    60, 98
],
segments: [
    1, 4, 2, 2
]

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

이때, 이전 사진과 비교했을 때 모서리 중 하나가 약간 휘어져 있으므로 두 번째와 세 번째 모서리를 다루겠습니다

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

points: [
    92, 67,
    93, 35, 78, 0, 62, 7,
    29, 13, 4, 46, 0, 70,
    28, 53, 68, 60, 60, 98
],
segments: [
    1, 4, 4, 4
]

자, 이제 모양이 생겼으니 이제 블레이드 3개를 사용해 임펠러를 만들어 보겠습니다.

기존 리소스를 함께 연결하려면 벡터의 이미지 유형 클래스를 사용하여 새 벡터를 정의해야 합니다. 구체적인 사용 방법은 다음과 같습니다.

ht.Default.setImage('impeller', {
    width: 166,
    height: 180.666,
    comps : [
        {
            type: 'image',
            name: 'vane',
            rect: [0, 0, 97, 106]
        },
        {
            type: 'image',
            name: 'vane',
            rect: [87.45, 26.95, 97, 106],
            rotation: 2 * Math.PI / 3
        },
        {
            type: 'image',
            name: 'vane',
            rect: [20.45, 89.2, 97, 106],
            rotation: 2 * Math.PI / 3 * 2
        }
    ]
});

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

코드에서는 3개의 블레이드를 정의하고, 두 번째와 세 번째 블레이드를 회전하여 위치를 지정하여 3개의 블레이드를 임펠러로 배열하고 결합하는데, 임펠러의 중앙을 어떻게 만들 수 있습니까? 빈 삼각형이 있습니다. 이 문제는 해결하기 어렵지 않습니다. 삼각형을 채우려면 블레이드의 포인트 속성에 꼭지점을 하나만 추가하면 됩니다. 코드는 다음과 같습니다. 포인트 속성에

points: [
    92, 67,
    93, 35, 78, 0, 62, 7,
    29, 13, 4, 46, 0, 70,
    28, 53, 68, 60, 60, 98,
    97, 106
],
segments: [
    1, 4, 4, 4, 2
]

정점의 경우 세그먼트 배열 끝에 설명을 추가하는 것을 잊지 말고 최종 효과를 살펴보세요.

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

이 임펠러에 대한 리소스가 준비되었습니다. , 다음 단계는 임펠러를 회전시키는 것입니다. 먼저 분석해 보겠습니다.

임펠러를 회전시키려면 원리는 실제로 매우 간단하지만 이를 구현하려면 회전 속성만 설정하면 됩니다. 회전 임펠러는 속성이 지속적으로 변할 때만 회전하므로 이때 타이머를 사용하여 회전 속성을 계속 설정하여 임펠러가 움직이도록 해야 합니다.

글쎄요, 그렇다면 구현해 보겠습니다.

首先是创建一个节点,并设置其引用的image为impeller,再将其添加到DataModel,令节点在拓扑中显示出来:

var node = new ht.Node();
node.setSize(166, 181);
node.setPosition(400, 400);
node.setImage('impeller');
dataModel.add(node);

接下来就是添加一个定时器了:

window.setInterval(function() {
    var rotation = node.getRotation() + Math.PI / 10;
    if (rotation > Math.PI * 2) {
        rotation -= Math.PI * 2;
    }
    node.setRotation(rotation);
}, 40);

OK了,好像就是这个效果,但是当你选中这个节点的时候,你会发现这个节点的边框在不停的闪动,看起来并不是那么的舒服,为什么会出现这种情况呢?原因很简单,当设置了节点的rotation属性后,节点的显示区域就会发生变化,这个时候节点的宽高自然就发生的变化,其边框也自然跟着改变。

还有,在很多情况下,节点的rotation属性及宽高属性会被当成业务属性来处理,不太适合被实时改变,那么我们该如何处理,才能在不不改变节点的rotation属性的前提下令叶轮转动起来呢?

在矢量中,好像有数据绑定的功能,在手册中是这么介绍的:

绑定的格式很简单,只需将以前的参数值用一个带func属性的对象替换即可,func的内容有以下几种类型:

1. function类型,直接调用该函数,并传入相关Data和view对象,由函数返回值决定参数值,即func(data, view);调用。

2. string类型:

    2.1 style@***开头,则返回data.getStyle(***)值,其中***代表style的属性名。

    2.2 attr@***开头,则返回data.getAttr(***)值,其中***代表attr的属性名。

    2.3 field@***开头,则返回data.***值,其中***代表data的属性名。

    2.4 如果不匹配以上情况,则直接将string类型作为data对象的函数名调用data.***(view),返回值作为参数值。

除了func属性外,还可设置value属性作为默认值,如果对应的func取得的值为undefined或null时,则会采用value属性定义的默认值。 例如以下代码,如果对应的Data对象的attr属性stateColor为undefined或null时,则会采用yellow颜色:

color: {    
func: 'attr@stateColor',
    value: 'yellow'}

数据绑定的用法已经介绍得很清楚了,我们不妨先试试绑定叶片的背景色吧,看下好不好使。在矢量vane中的background属性设置成数据绑定的形式,代码如下:

background : {    
value : 'red',
    func : 'attr@vane_background'
    }

在没有设置vane_background属性的时候,令其去red为默认值,那么接下来我们来定义下vane_background属性为blue,看看叶轮会不会变成蓝色:

node.setAttr('vane_background', ‘blue');

看下效果:

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

果然生效了,这下好了,我们就可以让叶轮旋转变得更加完美了,来看看具体该这么做。

首先,我们先在节点上定义一个自定义属性,名字为:impeller_rotation

node.setAttr('impeller_rotation', 0);

然后再定义一个名字为rotate_impeller的矢量,并将rotation属性绑定到节点的impeller_rotation上:

ht.Default.setImage('rotate_impeller', {
    width : 220,
    height : 220,
    comps : [
        {
            type : 'image',
            name : 'impeller',
            rect : [27, 20, 166, 180.666],
            rotation : {
                func : function(data) { 
                    return data.getAttr('impeller_rotation'); 
                }
            }
        }
    ]
});

这时候我们在定时器中修改节点的rotation属性改成修改自定义属性impeller_rotation就可以让节点中的叶轮旋转起来,并且不会影响到节点自身的属性,这就是我们想要的效果。

HTML5 Canvas를 기반으로 벡터 산업용 제어 팬 임펠러 회전 구현

在2D上可以实现,在3D上一样可以实现,下一章我们就来讲讲叶轮旋转在3D上的应用,今天就先到这里,下面附上今天Demo的源码,有什么问题欢迎大家咨询。

http://www.hightopo.com/demo/fan/index.html

ht.Default.setImage('vane', {
    width : 97,
    height : 106,
    comps : [
        {
            type : 'shape',
            points : [
                92, 67,
                93, 35, 78, 0, 62, 7,
                29, 13, 4, 46, 0, 70,
                28, 53, 68, 60, 60, 98,
                97, 106
            ],
            segments : [
                1, 4, 4, 4, 2
            ],
            background : {
                value : 'red',
                func : 'attr@vane_background'
            }
        }
    ]
});

ht.Default.setImage('impeller', {
    width : 166,
    height : 180.666,
    comps : [
        {
            type : 'image',
            name : 'vane',
            rect : [0, 0, 97, 106]
        },
        {
            type : 'image',
            name : 'vane',
            rect : [87.45, 26.95, 97, 106],
            rotation : 2 * Math.PI / 3
        },
        {
            type : 'image',
            name : 'vane',
            rect : [20.45, 89.2, 97, 106],
            rotation : 2 * Math.PI / 3 * 2
        }
    ]
});

ht.Default.setImage('rotate_impeller', {
    width : 220,
    height : 220,
    comps : [
        {
            type : 'image',
            name : 'impeller',
            rect : [27, 20, 166, 180.666],
            rotation : {
                func : function(data) {
                    return data.getAttr('impeller_rotation');
                }
            }
        }
    ]
});

function init() {
    var dataModel = new ht.DataModel();

    var graphView = new ht.graph.GraphView(dataModel);
    var view = graphView.getView();
    view.className = "view";
    document.body.appendChild(view);

    var node = new ht.Node();
    node.setSize(220, 220);
    node.setPosition(200, 400);
    node.setImage('rotate_impeller');
    node.setAttr('impeller_rotation', 0);
    node.setAttr('vane_background', 'blue');
    dataModel.add(node);

    var node1 = new ht.Node();
    node1.setSize(166, 181);
    node1.setPosition(500, 400);
    node1.setImage('impeller');
    dataModel.add(node1);

    window.setInterval(function() {
        var rotation = node.a('impeller_rotation') + Math.PI / 10;
        if (rotation > Math.PI * 2) {
            rotation -= Math.PI * 2;
        }
        node.a('impeller_rotation', rotation);
        node1.setRotation(rotation);

    }, 40);
}


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.