Previous applications on topology were all static primitive, today we will design a moving primitive on the topology - impeller rotation
## Let’s take a look at the final effect we achieved:
Let’s first take a look at what this impellermodel looks like
From the model point of view, this impeller model has three blades, each blade is an irregular shape, obviously it cannot be used for our HT for Web basic graphics, so what should we do? It is very simple. HT for Web provides a custom graphics solution, we can use custom graphics. Drawing irregular graphics like leaves
## Before drawing leaves, we must first understand the basic knowledge of custom graphics drawing in HT for Web:To draw custom graphics, you need to specify the
vector type as shape, and specify each point information through the Array array of points. Points are represented by [x1, y1, x2, y2, x3, y3, ...] to store point coordinates. The polygon of the curve can be described by the Array array of segments, and segment describes each line segment in the form of [1, 2, 1, 3...]:
1: moveTo, occupies 1 point information, representing the starting point of a new path2: lineTo, occupies 1 point information, representing the connection from the last point To this point
3: quadraticCurveTo, occupies 2 point information, the first point is used as the curve control point, and the second point is used as the curve end point
4: bezierCurveTo, occupies 3 point information, the first and second points are used as curve control points, and the third point is used as the curve end point
5: closePath, does not occupy point information, represents the end of this path drawing and closes to the starting point of the path
In addition to setting the segments parameter, you can also set the closePath attribute for comparing closed polygons: * closePath gets and sets whether the polygon is closed. The default is false. This method is used for closed straight lines without setting the segments parameter.
Okay, then let’s start designing the blades
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' } ] });
vector, and used these 4 vertices to outline the general shape of the blade through straight lines. Although it is a bit abstract, what follows will be Make this leaf metamorphose by adding control points and changing segment parameters.
First we add two control points to the line segment between the first and second vertices through the bezierCurveTo method to draw the curve. The following are the points and segments attributes:points: [
92, 67,
93, 35, 78, 0, 62, 7,
0, 70,
60, 98
],
segments: [
1, 4, 2, 2
]
, then the next thing to do is to use three such blades to splice into an impeller. To splice existing resources together, you need to use the image type class in
Vectorto define a new vector. The specific usage method is as follows:
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 ]
在代码中,我们定义了三个叶片,并且对第二个和第三个叶片做了旋转和定位的处理,让这三个叶片排布组合成一个叶轮来,但是怎么能让叶轮中间空出一个三角形呢,这个问题解决起来不难,我们只需要在叶片的points属性上再多加一个顶点,就可以填充这个三角形了,代码如下: 在points属性上添加了一个顶点后,别忘了在segments数组的最后面添加一个描述,再来看看最终的效果: 到这个叶轮的资源就做好了,那么接下来就是要让这个叶轮旋转起来了,我们先来分析下: 要让叶轮旋转起来,其实原理很简单,我们只需要设置rotation属性就可以实现了,但是这个rotation属性只有在不断的变化中,才会让叶轮旋转起来,所以这个时候就需要用到定时器了,通过定时器来不断地设置rotation属性,让叶轮动起来。 恩,好像就是这样子的,那么我们来实现一下: 首先是创建一个节点,并设置其引用的image为impeller,再将其添加到DataModel,令节点在拓扑中显示出来: 接下来就是添加一个定时器了: 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颜色: 数据绑定的用法已经介绍得很清楚了,我们不妨先试试绑定叶片的背景色吧,看下好不好使。在矢量vane中的background属性设置成数据绑定的形式,代码如下: 在没有设置vane_background属性的时候,令其去red为默认值,那么接下来我们来定义下vane_background属性为blue,看看叶轮会不会变成蓝色: 看下效果: 果然生效了,这下好了,我们就可以让叶轮旋转变得更加完美了,来看看具体该这么做。 首先,我们先在节点上定义一个自定义属性,名字为:impeller_rotation 然后再定义一个名字为rotate_impeller的矢量,并将rotation属性绑定到节点的impeller_rotation上: 这时候我们在定时器中修改节点的rotation属性改成修改自定义属性impeller_rotation就可以让节点中的叶轮旋转起来,并且不会影响到节点自身的属性,这就是我们想要的效果。 在2D上可以实现,在3D上一样可以实现,下一章我们就来讲讲叶轮旋转在3D上的应用,今天就先到这里,下面附上今天Demo的源码,有什么问题欢迎大家咨询。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
]
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);
color: {
func: 'attr@stateColor',
value: 'yellow'
}
background : {
value : 'red',
func : 'attr@vane_background'
}
node.setAttr('vane_background', ‘blue');
node.setAttr('impeller_rotation', 0);
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');
}
}
}
]
});
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);
}
The above is the detailed content of Sample code to implement vector industrial control fan impeller rotation based on HTML5 Canvas. For more information, please follow other related articles on the PHP Chinese website!