Heim > Artikel > Web-Frontend > Implementierung der Vektor-Industriesteuerung der Lüfterradrotation basierend auf HTML5 Canvas
Frühere Anwendungen in der Topologie waren alle statische Grundelemente. Heute werden wir ein bewegliches Grundelement in der Topologie entwerfen – Laufradrotation.
Werfen wir einen Blick auf den Endeffekt, den wir erzielt haben: http://www.hightopo.com/demo/fan/index.html
Lass uns Machen Sie es zuerst. Mal sehen, wie dieses Laufradmodell aussieht
Aus der Sicht des Modells hat dieses Laufradmodell drei Schaufeln, jede Schaufel hat eine unregelmäßige Form, das ist offensichtlich nicht möglich von unserem HT für die Basisgrafiken des Webs verwendet werden, wie sollen wir das also machen? Es ist ganz einfach. HT for Web bietet eine benutzerdefinierte Grafiklösung. Wir können unregelmäßige Grafiken wie Blätter durch benutzerdefinierte Grafiken zeichnen.
Bevor wir Blätter zeichnen, müssen wir zunächst die Grundkenntnisse des Zeichnens benutzerdefinierter Grafiken in HT für Web verstehen:
Um benutzerdefinierte Grafiken zu zeichnen, müssen Sie den Vektortyp als Form angeben und übergeben Punkte Das Array-Array spezifiziert die Informationen zu jedem Punkt und Punkte speichert Punktkoordinaten in der Form [x1, y1, x2, y2, x3, y3, ...]. Das Polygon der Kurve kann durch das Array-Array von Segmenten beschrieben werden. Segment beschreibt jedes Liniensegment in der Form [1, 2, 1, 3...]:
1: moveTo, belegt 1 Punkt Informationen, die den Startpunkt eines neuen Pfads darstellen
2: lineTo, belegt 1 Punktinformationen, stellt die Verbindung vom letzten letzten Punkt zu diesem Punkt dar
3: quadraticCurveTo, belegt 2 Punktinformationen , der erste Punkt wird als Kurvenkontrollpunkt verwendet, der zweite Punkt wird als Kurvenendpunkt verwendet
4: bezierCurveTo, belegt 3 Punktinformationen, der erste und der zweite Punkt werden als Kurvenkontrollpunkte verwendet, und der dritte Punkt wird als Kurvenendpunkt verwendet
5: closePath, der keine Punktinformationen belegt, stellt das Ende dieser Pfadzeichnung dar und ist zum Anfang hin geschlossen Punkt des Pfades
Im Vergleich zu geschlossenen Polygonen können Sie zusätzlich zu den Parametern auch das Attribut closePath festlegen: * closePath ruft ab und legt fest, ob das Polygon geschlossen ist Die Methode wird für geschlossene gerade Linien verwendet, ohne den Segmentparameter festzulegen.
Okay, dann beginnen wir mit dem Entwurf der Rotorblätter
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' } ] });
Wir haben 4 Eckpunkte im Vektor definiert und diese 4 kombiniert. Die Eckpunkte skizzieren die allgemeine Form der Klinge durch gerade Linien. Obwohl es etwas abstrakt ist, wird die Klinge als nächstes durch Hinzufügen von Kontrollpunkten und Ändern der Segmentparameter transformiert.
Zuerst fügen wir über die bezierCurveTo-Methode zwei Kontrollpunkte zum Liniensegment zwischen dem ersten und zweiten Scheitelpunkt hinzu, um die Kurve zu zeichnen. Die folgenden Punkte und Segmentattribute sind:
points: [ 92, 67, 93, 35, 78, 0, 62, 7, 0, 70, 60, 98 ], segments: [ 1, 4, 2, 2 ]
Zu diesem Zeitpunkt weist eine der Kanten im Vergleich zum vorherigen Bild eine leichte Krümmung auf, also beschäftigen wir uns mit der zweiten und dritten Kante
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 ]
Sehen Sie, jetzt hat es eine Form. Jetzt, wo die Schaufeln da sind, müssen Sie als Nächstes drei solcher Schaufeln verwenden, um sie zu einem Laufrad zu verbinden.
Um vorhandene Ressourcen zusammenzufügen, müssen Sie die Bildtypklasse im Vektor verwenden, um einen neuen Vektor zu definieren. Die spezifische Verwendungsmethode lautet wie folgt:
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 } ] });
Im Code haben wir drei Schaufeln definiert und die zweiten und dritten Schaufeln gedreht und positioniert, um die drei Schaufeln zu einem Laufrad anzuordnen und zu kombinieren. Aber wie können wir die Mitte des Laufrads herstellen? Es gibt ein leeres Dreieck. Dieses Problem ist nicht schwer zu lösen. Wir müssen nur einen weiteren Scheitelpunkt zum Punkteattribut der Klinge hinzufügen, um das Dreieck zu füllen. Der Code lautet wie folgt:
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 ]
für das Punkteattribut Nach dem Hinzufügen von a Vergessen Sie nicht, am Ende des Segmentarrays eine Beschreibung hinzuzufügen und sehen Sie sich dann den endgültigen Effekt an:
Die Ressourcen für dieses Laufrad sind bereit Dann besteht der nächste Schritt darin, das Laufrad in Rotation zu versetzen:
Um das Laufrad in Rotation zu versetzen, ist das Prinzip eigentlich sehr einfach. Wir müssen nur das Rotationsattribut festlegen, um dies zu erreichen Rotation Das Laufrad dreht sich nur, wenn sich die Attribute ständig ändern. Daher müssen Sie zu diesem Zeitpunkt einen Timer verwenden. Verwenden Sie den Timer, um das Rotationsattribut kontinuierlich einzustellen, damit sich das Laufrad bewegt.
Nun, es sieht so aus, also setzen wir es um:
首先是创建一个节点,并设置其引用的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');
看下效果:
果然生效了,这下好了,我们就可以让叶轮旋转变得更加完美了,来看看具体该这么做。
首先,我们先在节点上定义一个自定义属性,名字为: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就可以让节点中的叶轮旋转起来,并且不会影响到节点自身的属性,这就是我们想要的效果。
在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); }