基于HTML5 Canvas 實現矢量工控風機葉輪旋轉

之前在拓撲上的應用都是些靜態的圖元,今天我們將在拓撲上設計一個會動的圖元——葉輪旋轉。

先看看最后我們實現的效果:http://www.hightopo.com/demo/fan/index.html

我們先來看下這個葉輪模型長什么樣

?

從模型上看,這個葉輪模型有三個葉片,每一個葉片都是不規則圖形,顯然無法用上我們HT for Web的基礎圖形來拼接,那么我們該怎么做呢?很簡單,在HT for Web中提供了自定義圖形的方案,我們可以通過自定義圖形來繪制像葉片這種不規則圖形。

在繪制葉片之前,我們得先來了解下HT for Web的自定義圖形繪制的基本知識:

繪制自定義圖形需要制定矢量類型為shape,并通過points的Array數組指定每個點信息, points以[x1, y1, x2, y2, x3, y3, ...]的方式存儲點坐標。曲線的多邊形可通過segments的Array數組來描述, segment以[1, 2, 1, 3 ...]的方式描述每個線段:

1: moveTo,占用1個點信息,代表一個新路徑的起點

2: lineTo,占用1個點信息,代表從上次最后點連接到該點

3: quadraticCurveTo,占用2個點信息,第一個點作為曲線控制點,第二個點作為曲線結束點

4: bezierCurveTo,占用3個點信息,第一和第二個點作為曲線控制點,第三個點作為曲線結束點

?

5: closePath,不占用點信息,代表本次路徑繪制結束,并閉合到路徑的起始點

對比閉合多邊形除了設置segments參數外,還可以設置closePath屬性: * closePath獲取和設置多邊形是否閉合,默認為false,對閉合直線采用這種方式,無需設置segments參數。

好了,那么接下來我們開始設計葉片了

?

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個頂點通過直線勾勒出葉片的大致形狀,雖然有些抽象,但是,接下來將會通過增加控制點和改變segment參數來讓這個葉片發生蛻變。

首先我們通過bezierCurveTo方式向第一個和第二個頂點之間的線段添加兩個控制點,從而繪制出曲線,以下是points及segments屬性:

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

這時候與上一個圖相比較,有一條邊一件有些弧度了,那么接下來就來處理第二條邊和第三條邊

? ? ? ? ? ? ??

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
]

看吧,現在是不是有模有樣了,現在葉片已經有了,那么接下來要做的就是使用三個這樣的葉片拼接成一個葉輪。

將已有的資源拼接在一起需要用到矢量中的image類型類定義新的矢量,具體的使用方法如下:

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}]
});

在代碼中,我們定義了三個葉片,并且對第二個和第三個葉片做了旋轉和定位的處理,讓這三個葉片排布組合成一個葉輪來,但是怎么能讓葉輪中間空出一個三角形呢,這個問題解決起來不難,我們只需要在葉片的points屬性上再多加一個頂點,就可以填充這個三角形了,代碼如下:

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
]

?

在points屬性上添加了一個頂點后,別忘了在segments數組的最后面添加一個描述,再來看看最終的效果:

到這個葉輪的資源就做好了,那么接下來就是要讓這個葉輪旋轉起來了,我們先來分析下:

要讓葉輪旋轉起來,其實原理很簡單,我們只需要設置rotation屬性就可以實現了,但是這個rotation屬性只有在不斷的變化中,才會讓葉輪旋轉起來,所以這個時候就需要用到定時器了,通過定時器來不斷地設置rotation屬性,讓葉輪動起來。

恩,好像就是這樣子的,那么我們來實現一下:

首先是創建一個節點,并設置其引用的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);
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/260323.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/260323.shtml
英文地址,請注明出處:http://en.pswp.cn/news/260323.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java 并發模型總類_java并發編程系列-內存模型基礎

java線程之間的通信對程序開發人員是完全透明的,內存的可見性問題很容易困擾很多開發人員。本篇博文將揭開java內存模型的神秘面紗,來看看內存模型到底是怎樣的。并發編程模型的分類并發編程中需要處理的兩個關鍵問題:線程之間如何通信線程之…

python調用java的jar包_python調用java的jar包報錯127

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓最近在弄python需要調用到Java的jar包,按照網上的教程走,最后總是報錯No matching overloads found for [init in find. at native\common\jp_method.cpp:127Java:package aes;import com.sun.cr…

iphone、Android接收System.Net.Mail發的郵件標題亂碼

參考地址:http://blog.csdn.net/whowhen21/article/details/5959225 在做項目時候,用到.Net的System.Net.Mail發送郵件,經測試,發現如果標題過長,收到的就會是亂碼了(那種Base64格式的數據),幾經測試&#…

數據倉庫與數據挖掘的一些基本概念

下面內容摘自互聯網并作了整理。 名詞: BI(Business Intelligence):商業智能, DW(Data Warehouse):數據倉庫,詳見正文Q1部分。 OLTP(On-Line Transaction Processing):聯機事務處理 也稱為面向交易的處理系…

ATS讀小文件(內存命中)

一個資源根據其大小可能會存在多個存儲對象中。如果足夠小(連同doc結構的大小小于一個fragment的size),連同這個資源的meta信息一起存儲在一個doc中。如果比較大,第一個存儲對象保存資源的meta信息,后面跟著若干個frag…

python 加密解密_python加密解密

EncodeFile(python2.7加密)# -*- coding: utf8 -*-import base64import sysreload(sys)sys.setdefaultencoding(utf8)inFilesys.argv[1]try:fin open(inFile, "rb")fout open(inFile".txt", "w")base64.encode(fin, fout)passexcept Exception…

java double 兩位_java double 保留兩位小數

java保留兩位小數問題:方式一:四舍五入double f 111231.5585;BigDecimal b new BigDecimal(f);double f1 b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();保留兩位小數---------------------------------------------…

fatal error C1902: 程序數據庫管理器不匹配;請檢查安裝解決

終于找到原因了,原來是我安裝的字體渲染,并且采用注冊表的加載方式!改掉就好了!上天哪,這是怎么影響到的 卸載MacType程序后,進行嘗試! VS2008 和 VS2010 又能用了! 我想求教育。。。…

一分鐘明確 VS manifest 原理

什么是vs 程序的manifest文件 manifest 是VS程序用來標明所依賴的side-by-side組建,如ATL, CRT等的清單。 為什么要有manifest文件 一臺pc上,用一組建往往會有不止一個版本號(c:/windows/winsxs或系統文件夾下),程序在載入的時候&…

[譯]多線程網絡服務模型

2019獨角獸企業重金招聘Python工程師標準>>> 多線程網絡服務模型 /*** 謹獻給Yoyo** 原文出處&#xff1a;https://www.toptal.com/software/guide-to-multi-processing-network-server-models* author dogstar.huang <chanzonghuanggmail.com> 2016-04-02*/作…

likely(x)與unlikely(x)函數,即__builtin_expect的使用

轉載自&#xff1a;http://velep.com/archives/795.html 本文講的likely()和unlikely()兩個宏&#xff0c;在linux內核代碼和一些應用中可常見到它們的身影。實質上&#xff0c;這兩個宏是關于GCC編譯器內置宏__builtin_expect的使用。顧名思義&#xff0c;likely()指“很有可能…

java mvc引擎_SpringMvc+JavaConfig+Idea 搭建項目

1.介紹之前搭建SpringMvc項目要配置一系列的配置文件&#xff0c;比如web.xml,applicationContext.xml,dispatcher.xml。Spring 3.X之后推出了基于JavaConfig方式以及注解的形式的配置。在一定程度上簡化了Spring項目的配置。近幾年特別火的SpringBoot&#xff0c;大大的簡化了…

window.parent和window.opener區別

下面一段代碼是關于window.parent和window.opener區別 來講的&#xff0c;我們如果要用到iframe的值傳到另一框架就要用到window.opener.document.getElementById(name).value uvalue;這種形式哦。 window.parent能獲取一個框架的父窗口或父框架。頂層窗口的parent引用的是它本…

極域電子書包課堂管理系統_【君蓮微訊】君蓮學校(小學部)開展電子書包第13共同體數學研討活動...

借 助 媒 體 技 術豐 富 圖 形 認 識君蓮學校(小學部)開展電子書包共同體 數學研討活動 2020年12月2日下午&#xff0c;君蓮學校(小學部)開展了以“借助媒體技術 豐富圖形認識”為主題的閔行區電子書包第13共同體的數學研討活動。共同體學校教師代表、學校電子書包項目組主管朱…

python批量改動指定文件夾文件名稱

這小樣例僅僅要是說明用python怎么批量改動指定文件夾的文件名稱&#xff1a; 記得要把腳本跟改動的文件放在同一個文件夾下 #encoding:utf-8 import os import sys files os.listdir(D:\\1) #路徑能夠自己for name in files:a os.path.splitext(name)if a[1] .txt: #txt能夠…

Linux vmstat命令實戰詳解

vmstat命令是最常見的Linux/Unix監控工具&#xff0c;可以展現給定時間間隔的服務器的狀態值,包括服務器的CPU使用率&#xff0c;內存使用&#xff0c;虛擬內存交換情況,IO讀寫情況。這個命令是我查看Linux/Unix最喜愛的命令&#xff0c;一個是Linux/Unix都支持&#xff0c;二是…

python的基礎網絡編程是下列_Python入門基礎之網絡編程、socket編程、TCP、UDP編程...

忙了兩天&#xff0c;繼續更文&#xff01;希望多多支持。套接字套接字是一種具有之前所說的"通訊端點"概念的計算機網絡數據結構。網絡化的應用程序在開始任何通訊之前都必需要創建套接字。套接字有三種&#xff1a;1、 AF_UNIX(在 POSIX1.g 標準中也叫 AF_LOCAL)&a…

java 入門 博客園_javaweb入門

復習&#xff1a;css的常用樣式&#xff1a;borderbackgroundpaddingmarginfloatposition 定位top left確定div在頁面中的位置&#xff0c;這兩個值可以為負數。cssdiv 布局方式cssdivtable 先由div劃分大塊兒&#xff0c;再由table進行整齊布局。下拉列表&#xff1a;層疊的布…

以ThreadStart方式實現多線程

3.1 使用ThreadStart委托 這里先以一個例子體現一下多線程帶來的好處&#xff0c;首先在Message類中建立一個方法ShowMessage()&#xff0c;里面顯示了當前運行線程的Id&#xff0c;并使用Thread.Sleep&#xff08;int ) 方法模擬部分工作。在main()中通過ThreadStart委托綁定M…

管理思考

管理基礎 分活 分錢 分責任 分權 安人(安排 配置) 流程 標準 考核 治人(協調 指揮 控制) 社會越來越復雜 分工越來越復雜 合作越來越重要 目標一定要一致共同的意愿共識 需要大家參與管理 業務劃分 責任劃分 流程梳理 如何合作做好安全工作 安全服務因為不承擔責任 責任主體是管…