前言

此次的 Demo 效果如下:

Demo 链接:https://hightopo.com/demo/comp-knob/

整体思路

  • 组件参数
  • 绘制旋钮
  • 绘制刻度
  • 绘制指针
  • 绘制标尺
  • 绘制文本
  • 交互效果

1.组件参数

以下是下文会使用到的部分变量,在此先贴出来

var origin, // 原点
percent, // 显示刻度占总刻度的百分比
partAngle, // 每个刻度所占的角度
startAngle, //刻度起始的角度
calibrationPoints, // 每个刻度的信息
pointer, // 指针的信息
scaleLine, // 标尺的信息
calibrationColors // 刻度渐变色

2.绘制旋钮

这里主要就使用了 canvas api 中的 arc() 和 createRadialGradient() 。

主要代码:

g.beginPath();
var ringRadial = g.createRadialGradient(origin.x, origin.y, , origin.x, origin.y, ringRadio);
ringRadial.addColorStop(, ht.Default.brighter(ringColor, ));
ringRadial.addColorStop(0.95, ht.Default.brighter(ringColor, ));
ringRadial.addColorStop(, ht.Default.darker(ringColor, )); var borderRadial = g.createRadialGradient(origin.x, origin.y, ringRadio - ringBorderWidth / , origin.x, origin.y, ringRadio + ringBorderWidth / );
borderRadial.addColorStop(, ht.Default.brighter(ringBorderColor, ));
borderRadial.addColorStop(0.5, ht.Default.brighter(ringBorderColor, ));
borderRadial.addColorStop(, ht.Default.darker(ringBorderColor, ));
g.fillStyle = ringRadial;
g.lineWidth = ringBorderWidth;
g.strokeStyle = borderRadial;
g.arc(origin.x, origin.y, ringRadio, , * Math.PI);
g.closePath();
g.fill();
g.stroke();

效果图:

3.绘制刻度

这里绘制每个刻度采用的是绘制路径的方法,所以声明了一个变量 calibrationPoints 用来存放每个刻度的起始点坐标,根据配置的参数去计算 calibrationPoints 的信息。

首先根据参数 calibrationPercent 计算第一个刻度的起始角度 startAngle ,然后根绝 calibrationCount 的值去计算每个刻度所占用的角度 partAngle ,最后根据三角函数和相应的角度,转化为对应的坐标。

主要代码:

var calibrationPoints = [];
for (var i = ; i < calibrationCount + ; i++) {
var point = {
startx: origin.x + (ringRadio + ringBorderWidth + * calibrationHeight) * Math.cos(startAngle - i * partAngle),
starty: origin.y - (ringRadio + ringBorderWidth + * calibrationHeight) * Math.sin(startAngle - i * partAngle),
endx: origin.x + (ringRadio + ringBorderWidth + * calibrationHeight) * Math.cos(startAngle - i * partAngle),
endy: origin.y - (ringRadio + ringBorderWidth + * calibrationHeight) * Math.sin(startAngle - i * partAngle)
};
if (i <= (calibrationCount * percent) && percent > ) {
point.show = true;
} else {
point.show = false;
}
calibrationPoints.push(point);
}

有了每个刻度的信息后,接下来就开始绘制刻度。

主要代码:

calibrationPoints.forEach(function (i, index) {
g.beginPath();
if (calibrationColorWheelShow) {
calibrationBrightColor = calibrationColors[index];
}
g.lineWidth = 1.2 * calibrationWidth;
g.strokeStyle = i.show ? calibrationBrightColor : ht.Default.brighter(calibrationDarkColor, ); g.moveTo(i.startx, i.starty);
g.lineTo(i.endx, i.endy);
g.closePath();
g.stroke();
}) calibrationPoints.forEach(function (i, index) {
g.beginPath();
if (calibrationColorWheelShow) {
calibrationBrightColor = calibrationColors[index];
}
g.lineWidth = calibrationWidth;
g.strokeStyle = i.show ? calibrationBrightColor : calibrationDarkColor; g.moveTo(i.startx, i.starty);
g.lineTo(i.endx, i.endy);
g.closePath();
g.stroke();
})

效果图:

考虑到一种高亮颜色太单调,于是加了个色轮。思路:给每个刻度都添加了颜色的标识。
每个刻度的颜色计算方法:把颜色值转换成 rgb 方式,设定多少秒改变完成,每次改变多少值,计算需要多少次,比如 rba(x,y,z) 到 rgb(a,b,c),假设需要 100 次,那么每次设定 rgb((a - x) / 100 + x, (b - y) / 100 + y, (c - z) / 100 + z) 。

主要代码:

if (calibrationColorWheelShow) { // 显示刻度色轮
var colors = [];
calibrationColorWheel.forEach(function (i) {
colors.push(ht.Default.toColorData(i))
})
// 把颜色值转换成rgb方式,设定多少秒改变完成,每次改变多少值,计算需要多少次
// ,比如rba(x,y,z)到rgb(a,b,c),假设需要100次,那么每次设定
// rgb((a-x)/100+x,(b-y)/100+y,(c-z)/100+z)
var count = Math.ceil(calibrationCount / (calibrationColorWheel.length - )); // 渐变次数
calibrationColors = [];
for (var i = ; i < colors.length - ; i++) {
for (var j = ; j <= count; j++) {
var item = 'rgb('
+ Math.round((colors[i + ][] - colors[i][]) / j + colors[i][])
+ ','
+ Math.round((colors[i + ][] - colors[i][]) / j + colors[i][])
+ ','
+ Math.round((colors[i + ][] - colors[i][]) / j + colors[i][])
+ ')';
calibrationColors.push(item)
}
}
}

效果图:

4.绘制指针

这个主要是根据三角函数去计算相对圆心的偏移角度,按照当前值和刻度最大值的比例来计算偏移量,然后换算成对应的坐标。

主要代码:

pointer = {
x: origin.x + (ringRadio - pointerRadio - ringBorderWidth) * Math.cos(startAngle - Math.PI * * calibrationPercent * percent),
y: origin.y - (ringRadio - pointerRadio - ringBorderWidth) * Math.sin(startAngle - Math.PI * * calibrationPercent * percent),
r: pointerRadio,
color: percent > ? calibrationBrightColor : calibrationDarkColor,
show: true,
} if (pointerShow) {
g.beginPath();
g.fillStyle = pointer.color;
g.arc(pointer.x, pointer.y, pointer.r, , Math.PI * );
g.closePath();
g.fill();
}

效果图:

5.绘制标尺

计算标尺角度的算法同指针。

主要代码:

scaleLine = {
startx: origin.x,
starty: origin.y,
endx: origin.x + (ringRadio + ringBorderWidth + 2 * calibrationHeight) * Math.cos(startAngle - Math.PI * 2 * calibrationPercent * percent),
endy: origin.y - (ringRadio + ringBorderWidth + 2 * calibrationHeight) * Math.sin(startAngle - Math.PI * 2 * calibrationPercent * percent),
color: percent > 0 ? calibrationBrightColor : calibrationDarkColor,
show: scaleLineShow,
}
if (scaleLine) {
g.beginPath();
g.strokeStyle = 'red';
g.setLineDash([1, 2]);
g.lineWidth = 0.5 * calibrationWidth;
g.moveTo(scaleLine.startx, scaleLine.starty);
g.lineTo(scaleLine.endx, scaleLine.endy);
g.closePath();
g.stroke();
}

效果图:

6.绘制文本

这里主要的就是确定文本所要绘制的位置,然后根据 ht.Default.getTextSize() 来获取文本长度,方便设置文本居中。

主要代码:

if (labelShow) {
var text = ht.Default.getTextSize(font, value);
g.fillStyle = labelColor;
g.font = font;
g.fillText(value.toFixed(2), labelDot.x, labelDot.y);
}

效果图:

到这就完成了基本的旋钮组件,下面继续做一些细节上的优化。

例如加一些阴影效果,颜色渐变,配色调整等。

主要代码:

var backgroundRadial = g.createRadialGradient(x + 0.5 * width, y + 0.2 * height, 0, x + 0.5 * width, y + 0.2 * height, Math.sqrt(Math.pow(width / 2, 2) + Math.pow(height, 2)));
backgroundRadial.addColorStop(0, 'rgba(220,220,220,1)');
backgroundRadial.addColorStop(1, backgroundColor);
g.fillStyle = backgroundRadial;
g.fillRect(x, y, width, height); g.beginPath();
var ringRadial = g.createRadialGradient(origin.x, origin.y - ringRadio / 2, 0, origin.x, origin.y - ringRadio / 2, 1.5 * ringRadio);
ringRadial.addColorStop(0, ht.Default.brighter(ringColor, 40));
// ringRadial.addColorStop(0.25, ht.Default.brighter(ringColor, 40));
ringRadial.addColorStop(1, ht.Default.darker(ringColor, 20)); var borderRadial = g.createRadialGradient(origin.x, origin.y, ringRadio - ringBorderWidth / 2, origin.x, origin.y, ringRadio + ringBorderWidth / 2);
borderRadial.addColorStop(0, ht.Default.brighter(ringBorderColor, 2));
borderRadial.addColorStop(0.5, ht.Default.brighter(ringBorderColor, 4));
borderRadial.addColorStop(1, ht.Default.darker(ringBorderColor, 4));
g.fillStyle = ringRadial; g.lineWidth = ringBorderWidth;
g.strokeStyle = borderRadial;
g.arc(origin.x, origin.y, ringRadio, 0, 2 * Math.PI);
g.closePath();
g.fill();
g.shadowBlur = 20;
g.shadowColor = shadowColor;
g.shadowOffsetY = ringBorderWidth;
g.stroke();
g.shadowBlur = 0;
g.shadowOffsetY = 0;

效果图:

7.交互效果

以上就是绘制好了一张静态图,最后就只要再加上一些交互效果就可以了。
这里我采用的是 HT for Web 的矢量来实现。可参考 → 戳这

监听 onUp 和 onDraw 事件。
onUp:
当鼠标抬起时,获取当前旋钮显示的值,然后四舍五入,取其最近的刻度校准,使用 ht.Default.startAnim() 添加动画效果。
onDraw:
根据当前鼠标停留的位置,以旋钮原点为参照点,根据三角函数来计算指针和起始刻度的夹角 A ,计算 A 占总刻度的百分比 p ,然后设置当前值为 max * p 。

最后使用 HT 实现:

var gv = new ht.graph.GraphView();
dm = gv.dm();
dm.a('pannable', true);
dm.a('zoomable', true);
dm.a('rectSelectable', true); ht.Default.setCompType('knob',func); //注册组件
ht.Default.setImage('iconKnob', data); //注册图片 var node = new ht.Node();
node.setImage('iconKnob');
node.s('2d.movable', false);
dm.add(node);
gv.fitContent();
gv.addToDOM();
window.addEventListener(
'resize',
function(e) {
gv.invalidate();
gv.fitContent();
},
false
);

基于 HTML5 Canvas 的可交互旋钮组件的更多相关文章

  1. 基于HTML5 Canvas实现用户交互

    很多人都有这样的疑问,基于HTML5 Canvas实现的元素怎么和用户进行交互?在这里我们用到HT for Web(http://www.hightopo.com/guide/guide/core/b ...

  2. 基于html5 Canvas图表库 : ECharts

    ECharts开源来自百度商业前端数据可视化团队,基于html5 Canvas,是一个纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表.创新的拖拽重计算.数据视图.值 ...

  3. 基于 HTML5 Canvas 的智能安防 SCADA 巡逻模块

    基于 HTML5 Canvas 的智能安防 SCADA 巡逻模块 前言 最近学习了 HT for Web flow 插件,除了正常的 flow 效果,其中还有两个十分好用的两个接口 getPercen ...

  4. 基于HTML5 Canvas和jQuery 的绘图工具的实现

    简单介绍 HTML5 提供了强大的Canvas元素.使用Canvas并结合Javascript 能够实现一些很强大的功能.本文就介绍一下基于HTML5 Canvas 的绘图工具的实现.废话少说,先看成 ...

  5. 基于HTML5 Canvas实现的图片马赛克模糊特效

    效果请点击下面网址: http://hovertree.com/texiao/html5/1.htm 一.开门见山受美国肖像画家Chuck Close的启发,此脚本通过使用HTML5 canvas元素 ...

  6. 基于html5 canvas和js实现的水果忍者网页版

    今天爱编程小编给大家分享一款基于html5 canvas和js实现的水果忍者网页版. <水果忍者>是一款非常受喜欢的手机游戏,刚看到新闻说<水果忍者>四周年新版要上线了.网页版 ...

  7. 基于HTML5 Canvas的线性区域图表教程

    之前我们看到过很多用jQuery实现的网页图表,有些还是比较实用的.今天我们来介绍一款基于HTML5 Canvas的线性区域图表应用,这个图表应用允许你使用多组数据来同时展示,并且将数据结果以线性图的 ...

  8. 基于HTML5 Canvas的网页画板实现教程

    HTML5的功能非常强大,尤其是Canvas的应用更加广泛,Canvas画布上面不仅可以绘制任意的图形,而且可以实现多种多样的动画,甚至是一些交互式的应用,比如网页网版.这次我们要来看的就是一款基于H ...

  9. 基于html5 canvas 的客户端异步上传图片的插件,支持客户端压缩图片尺寸

    /** * Created by xx on 15-05-28. * 基于html5 canvas 的客户端异步上传画片的插件 * 在实际应用中,常常要用于上传图片的功能.在现在越来越多的手机weba ...

随机推荐

  1. 深入V8引擎-AST(1)

    没办法了,开坑吧,接下来的几篇会讲述JavaScript字符串源码在v8中转换成AST(抽象语法树)的过程. JS代码在V8的解析只有简单的几步,其中第一步就是将源字符串转换为抽象语法树,非常类似于v ...

  2. 【linux杂记】Ubuntu查看端口使用情况

    转载地址: https://www.linuxidc.com/Linux/2016-01/127345.htm Ubuntu查看端口使用情况,使用netstat命令: 查看已经连接的服务端口(ESTA ...

  3. webpack-simple之vagrant热加载

    "dev": "cross-env NODE_ENV=development webpack-dev-server --host 192.168.2.10 --port ...

  4. 使用pymysql操作mysql数据库

    PyMySQL的安装和连接 PyMySQL的安装 python3. -m pip install pymysql python连接数据库 import pymysql # 创建连接 conn = py ...

  5. Linux不重启识别新添加的磁盘

    现网的一台EXSI 下的虚拟机一般在进行配置变更后都会通过重启来识别新增的配置,不过业务侧某台主机因为业务需要无法重启,想通过不重启直接识别护容上去的新磁盘.经测试,发现如下方可以解决. 1.通过ex ...

  6. Java中字符串的一些常用操作方法

      package test; public class  maintest {public static void main(String[] args) {String str = "a ...

  7. HTTP 学习笔记01

    HTTP   hypertext transfer protocol (超文本传输协议) TCP/IP 协议集中的一个应用层协议 用于定义WEB浏览器与WEB服务器之间交换数据的过程以及数据本身的格式 ...

  8. 100天搞定机器学习|Day7 K-NN

    最近事情无比之多,换了工作.组队参加了一个比赛.和朋友搞了一些小项目,公号荒废许久.坚持是多么重要,又是多么艰难,目前事情都告一段落,我们继续100天搞定机器学习系列.想要继续做这个是因为,一方面在具 ...

  9. Codeforces 776D:The Door Problem(DFS染色)

    http://codeforces.com/problemset/problem/776/D 题意:有n个门,m个开关,每个门有一个当前的状态(0表示关闭,1表示打开),每个开关控制k个门,但是每个门 ...

  10. html手机自适应屏幕

    <meta name="viewport" content="height=device-width, initial-scale=1.0, maximum-sca ...