基于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.mzph.cn/news/260323.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 并发模型总类_java并发编程系列-内存模型基础

java线程之间的通信对程序开发人员是完全透明的,内存的可见性问题很容易困扰很多开发人员。本篇博文将揭开java内存模型的神秘面纱,来看看内存模型到底是怎样的。并发编程模型的分类并发编程中需要处理的两个关键问题:线程之间如何通信线程之…

ATS读小文件(内存命中)

一个资源根据其大小可能会存在多个存储对象中。如果足够小(连同doc结构的大小小于一个fragment的size),连同这个资源的meta信息一起存储在一个doc中。如果比较大,第一个存储对象保存资源的meta信息,后面跟着若干个frag…

fatal error C1902: 程序数据库管理器不匹配;请检查安装解决

终于找到原因了,原来是我安装的字体渲染,并且采用注册表的加载方式!改掉就好了!上天哪,这是怎么影响到的 卸载MacType程序后,进行尝试! VS2008 和 VS2010 又能用了! 我想求教育。。。…

[译]多线程网络服务模型

2019独角兽企业重金招聘Python工程师标准>>> 多线程网络服务模型 /*** 谨献给Yoyo** 原文出处&#xff1a;https://www.toptal.com/software/guide-to-multi-processing-network-server-models* author dogstar.huang <chanzonghuanggmail.com> 2016-04-02*/作…

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

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

极域电子书包课堂管理系统_【君莲微讯】君莲学校(小学部)开展电子书包第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;二是…

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…

我的atom插件

atom插件实在是太多了&#xff0c;下面就说说我的插件 1.minimap 右边的小地图&#xff0c;和sublime里面的差不多&#xff1b; 2.open-in-browser 右击默认浏览器打开&#xff1b; 3.emmet 这个不用多说吧&#xff0c;html快速编译 4.git-plus 直接在atom提交代码&#xff0…

MonoRail - 简介 [基础知识篇]

MonoRail - 简介 起源 MonoRail是一个.NET的MVC web开发框架, 原名Castle On Rails, 是CastleProject的一个子项目. 作者hammett在使用过Ruby On Rails后, 觉得非常棒, 他希望在享受ror的开发模式的同时能使用大量现有的资源, 于是就用.NET写出了一个Castle On Rails. 后来ror那…

结对编程(黄金点游戏)

我扮演的角色是驾驶员 一、结对伙伴 领航员&#xff1a;赵峻 作业地址见我的博客。 二、代码地址 https://coding.net/u/k2048/p/huangjindian/git/blob/master/main.c 三、总结 1、个人总结 本次作业我扮演驾驶员&#xff0c;赵峻扮演领航员&#xff0c;我负责算法实现以及代码…

qtgl 鼠标平移 c++_罗技真爱粉的MX Master 3无线鼠标体验

​这是一篇关于罗技MX Master3的晒单&#xff0c;顺带也翻出我的库存清洁整理一下吧。在决定购买一款新鼠标的时候&#xff0c;我的第一目标其实是MX Vertical垂直鼠标&#xff0c;不过MX Vertical目前优势只在外形上&#xff0c;在MX系列中明显属于低配&#xff0c;自由滚轮、…

下载网页中的图片到本地

简单的一个下载如下 &#xff1a; string url "http://avatar.csdn.net/A/2/6/2_yefengzhixia.jpg";string filepath "D:\\pic.jpg";WebClient mywebclient new WebClient();mywebclient.DownloadFile(url, filepath);MessageBox.Show("OK");…

nacos linux启动_微服务系列之Nacos配置中心之一:Nacos介绍与安装

一、Nacos 介绍Nacos 是 Alibaba 公司推出的开源工具&#xff0c;用于实现分布式系统的服务发现与配置管理。英文全称 Dynamic Naming and Configuration Service&#xff0c;Na 为 Naming/NameServer 即注册中心&#xff0c;co 为 Configuration 即配置中心&#xff0c;Servic…

演练:在组件设计器中创建 Windows 服务应用程序

http://msdn.microsoft.com/zh-cn/library/zt39148a(vvs.80).aspx 演练&#xff1a;在组件设计器中创建 Windows 服务应用程序 .NET Framework 2.0其他版本5&#xff08;共 5&#xff09;对本文的评价是有帮助 - 评价此主题注意 Visual Studio 标准版中不提供“Windows 服务”模…

绝对震撼 7款HTML5动画应用及源码

除非特别声明&#xff0c;PHP100新闻均为原创或投稿报道&#xff0c;转载请注明作者及原文链接 原文地址&#xff1a; http://www.php100.com/html/it/mobile/2014/0702/7030.html [导读] 关于HTML5动画&#xff0c;我们已经分享太多了&#xff0c;当然也有很多利用纯CSS3实现的…

maven打包指定main函数

2019独角兽企业重金招聘Python工程师标准>>> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> <configuration> <archive> …

简易贪吃蛇小游戏java版_用GUI实现java版贪吃蛇小游戏

本文实例为大家分享了java版贪吃蛇小游戏的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下项目结构新建一个JFrame窗口,作为程序入口public class GameStart{public static void main(String[] args) {JFrame jFrame new JFrame();jFrame.setBounds(100,100,900,720…