迷香 發表於 2019-7-29 08:25:00

基于 HTML5 Canvas 的可交互旋钮组件

<h2>前言</h2>
<p>此次的 <span style="font-family: &quot;times new roman&quot;, times">Demo</span> 效果如下:</p>
<p><img src="https://img2018.cnblogs.com/blog/1496396/201907/1496396-20190728133149212-1911661542.gif"></p>
<p>Demo 链接:<span style="font-family: &quot;times new roman&quot;, times">https://hightopo.com/demo/comp-knob/</span></p>
<h2><span style="font-family: &quot;times new roman&quot;, times">整体思路</span></h2>
<ul>
<li><span style="font-family: &quot;times new roman&quot;, times">组件参数</span></li>
<li><span style="font-family: &quot;times new roman&quot;, times">绘制旋钮</span></li>
<li><span style="font-family: &quot;times new roman&quot;, times">绘制刻度</span></li>
<li><span style="font-family: &quot;times new roman&quot;, times">绘制指针</span></li>
<li><span style="font-family: &quot;times new roman&quot;, times">绘制标尺</span></li>
<li><span style="font-family: &quot;times new roman&quot;, times">绘制文本</span></li>
<li><span style="font-family: &quot;times new roman&quot;, times">交互效果</span></li>
</ul>
<h2><span style="font-family: &quot;times new roman&quot;, times">1.组件参数</span></h2>
<p><span style="font-family: &quot;times new roman&quot;, times"><img src="https://img2018.cnblogs.com/blog/1496396/201907/1496396-20190728130322711-1136222518.jpg"></span></p>
<p>&nbsp;</p>
<p>以下是下文会使用到的部分变量,在此先贴出来</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> origin, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 原点</span>
    percent, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 显示刻度占总刻度的百分比</span>
    partAngle, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 每个刻度所占的角度</span>
    startAngle, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">刻度起始的角度</span>
    calibrationPoints, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 每个刻度的信息</span>
    pointer, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 指针的信息</span>
    scaleLine, <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 标尺的信息</span>
    calibrationColors <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 刻度渐变色</span></pre>
</div>
<h2>2.绘制旋钮</h2>
<p>这里主要就使用了 <span style="font-family: &quot;times new roman&quot;, times">canvas api</span> 中的<span style="font-family: &quot;times new roman&quot;, times"> arc()</span> 和 <span style="font-family: &quot;times new roman&quot;, times">createRadialGradient()</span> 。</p>
<p>主要代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">g.beginPath();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> ringRadial = g.createRadialGradient(origin.x, origin.y, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, origin.x, origin.y, ringRadio);
ringRadial.addColorStop(</span><span style="color: rgba(128, 0, 128, 1)">0</span>, ht.Default.brighter(ringColor, <span style="color: rgba(128, 0, 128, 1)">20</span><span style="color: rgba(0, 0, 0, 1)">));
ringRadial.addColorStop(</span><span style="color: rgba(128, 0, 128, 1)">0.95</span>, ht.Default.brighter(ringColor, <span style="color: rgba(128, 0, 128, 1)">40</span><span style="color: rgba(0, 0, 0, 1)">));
ringRadial.addColorStop(</span><span style="color: rgba(128, 0, 128, 1)">1</span>, ht.Default.darker(ringColor, <span style="color: rgba(128, 0, 128, 1)">20</span><span style="color: rgba(0, 0, 0, 1)">));

</span><span style="color: rgba(0, 0, 255, 1)">var</span> borderRadial = g.createRadialGradient(origin.x, origin.y, ringRadio - ringBorderWidth / <span style="color: rgba(128, 0, 128, 1)">2</span>, origin.x, origin.y, ringRadio + ringBorderWidth / <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">);
borderRadial.addColorStop(</span><span style="color: rgba(128, 0, 128, 1)">0</span>, ht.Default.brighter(ringBorderColor, <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">));
borderRadial.addColorStop(</span><span style="color: rgba(128, 0, 128, 1)">0.5</span>, ht.Default.brighter(ringBorderColor, <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">));
borderRadial.addColorStop(</span><span style="color: rgba(128, 0, 128, 1)">1</span>, ht.Default.darker(ringBorderColor, <span style="color: rgba(128, 0, 128, 1)">4</span><span style="color: rgba(0, 0, 0, 1)">));
g.fillStyle </span>=<span style="color: rgba(0, 0, 0, 1)"> ringRadial;
g.lineWidth </span>=<span style="color: rgba(0, 0, 0, 1)"> ringBorderWidth;
g.strokeStyle </span>=<span style="color: rgba(0, 0, 0, 1)"> borderRadial;
g.arc(origin.x, origin.y, ringRadio, </span><span style="color: rgba(128, 0, 128, 1)">0</span>, <span style="color: rgba(128, 0, 128, 1)">2</span> *<span style="color: rgba(0, 0, 0, 1)"> Math.PI);
g.closePath();
g.fill();
g.stroke();</span></pre>
</div>
<p>效果图:</p>
<p><img src="https://img2018.cnblogs.com/blog/1496396/201907/1496396-20190728130849670-1071720891.jpg"></p>
<h2>3.绘制刻度</h2>
<p>这里绘制每个刻度采用的是绘制路径的方法,所以声明了一个变量 <span style="font-family: &quot;times new roman&quot;, times">calibrationPoints</span> 用来存放每个刻度的起始点坐标,根据配置的参数去计算 <span style="font-family: &quot;times new roman&quot;, times">calibrationPoints</span> 的信息。</p>
<p>首先根据参数 <span style="font-family: &quot;times new roman&quot;, times">calibrationPercent</span> 计算第一个刻度的起始角度 <span style="font-family: &quot;times new roman&quot;, times">startAngle</span> ,然后根绝 <span style="font-family: &quot;times new roman&quot;, times">calibrationCount</span> 的值去计算每个刻度所占用的角度 <span style="font-family: &quot;times new roman&quot;, times">partAngle</span> ,最后根据三角函数和相应的角度,转化为对应的坐标。</p>
<p>主要代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> calibrationPoints =<span style="color: rgba(0, 0, 0, 1)"> [];
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; calibrationCount + <span style="color: rgba(128, 0, 128, 1)">1</span>; i++<span style="color: rgba(0, 0, 0, 1)">) {
    </span><span style="color: rgba(0, 0, 255, 1)">var</span> point =<span style="color: rgba(0, 0, 0, 1)"> {
      startx: origin.x </span>+ (ringRadio + ringBorderWidth + <span style="color: rgba(128, 0, 128, 1)">0</span> * calibrationHeight) * Math.cos(startAngle - i *<span style="color: rgba(0, 0, 0, 1)"> partAngle),
      starty: origin.y </span>- (ringRadio + ringBorderWidth + <span style="color: rgba(128, 0, 128, 1)">0</span> * calibrationHeight) * Math.sin(startAngle - i *<span style="color: rgba(0, 0, 0, 1)"> partAngle),
      endx: origin.x </span>+ (ringRadio + ringBorderWidth + <span style="color: rgba(128, 0, 128, 1)">1</span> * calibrationHeight) * Math.cos(startAngle - i *<span style="color: rgba(0, 0, 0, 1)"> partAngle),
      endy: origin.y </span>- (ringRadio + ringBorderWidth + <span style="color: rgba(128, 0, 128, 1)">1</span> * calibrationHeight) * Math.sin(startAngle - i *<span style="color: rgba(0, 0, 0, 1)"> partAngle)
    };
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (i &lt;= (calibrationCount * percent) &amp;&amp; percent &gt; <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">) {
      point.show </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
    } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
      point.show </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
    }
    calibrationPoints.push(point);
}</span></pre>
</div>
<p>有了每个刻度的信息后,接下来就开始绘制刻度。</p>
<p>&nbsp;</p>
<p>主要代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">calibrationPoints.forEach(function (i, index) {
    g.beginPath();
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (calibrationColorWheelShow) {
      calibrationBrightColor </span>=<span style="color: rgba(0, 0, 0, 1)"> calibrationColors;
    }
    g.lineWidth </span>= <span style="color: rgba(128, 0, 128, 1)">1.2</span> *<span style="color: rgba(0, 0, 0, 1)"> calibrationWidth;
    g.strokeStyle </span>= i.show ? calibrationBrightColor : ht.Default.brighter(calibrationDarkColor, <span style="color: rgba(128, 0, 128, 1)">10</span><span style="color: rgba(0, 0, 0, 1)">);

    g.moveTo(i.startx, i.starty);
    g.lineTo(i.endx, i.endy);
    g.closePath();
    g.stroke();
})

calibrationPoints.forEach(function (i, index) {
    g.beginPath();
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (calibrationColorWheelShow) {
      calibrationBrightColor </span>=<span style="color: rgba(0, 0, 0, 1)"> calibrationColors;
    }
    g.lineWidth </span>=<span style="color: rgba(0, 0, 0, 1)"> calibrationWidth;
    g.strokeStyle </span>= i.show ?<span style="color: rgba(0, 0, 0, 1)"> calibrationBrightColor : calibrationDarkColor;

    g.moveTo(i.startx, i.starty);
    g.lineTo(i.endx, i.endy);
    g.closePath();
    g.stroke();
})</span></pre>
</div>
<p>效果图:</p>
<p><img src="https://img2018.cnblogs.com/blog/1496396/201907/1496396-20190728131612240-843632813.jpg"></p>
<p>考虑到一种高亮颜色太单调,于是加了个色轮。思路:给每个刻度都添加了颜色的标识。<br>每个刻度的颜色计算方法:把颜色值转换成 <span style="font-family: &quot;times new roman&quot;, times">rgb</span> 方式,设定多少秒改变完成,每次改变多少值,计算需要多少次,比如<span style="font-family: &quot;times new roman&quot;, times"> rba(x,y,z)</span> 到 <span style="font-family: &quot;times new roman&quot;, times">rgb(a,b,c)</span>,假设需要 <span style="font-family: &quot;times new roman&quot;, times">100</span> 次,那么每次设定 <span style="font-family: &quot;times new roman&quot;, times">rgb((a - x) / 100 + x, (b - y) / 100 + y, (c - z) / 100 + z)</span> 。</p>
<p>主要代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">if</span> (calibrationColorWheelShow) { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 显示刻度色轮</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span> colors =<span style="color: rgba(0, 0, 0, 1)"> [];
    calibrationColorWheel.forEach(function (i) {
      colors.push(ht.Default.toColorData(i))
    })
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 把颜色值转换成rgb方式,设定多少秒改变完成,每次改变多少值,计算需要多少次
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ,比如rba(x,y,z)到rgb(a,b,c),假设需要100次,那么每次设定
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> rgb((a-x)/100+x,(b-y)/100+y,(c-z)/100+z)</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span> count = Math.ceil(calibrationCount / (calibrationColorWheel.length - <span style="color: rgba(128, 0, 128, 1)">1</span>)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 渐变次数</span>
    calibrationColors =<span style="color: rgba(0, 0, 0, 1)"> [];
    </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; colors.length - <span style="color: rgba(128, 0, 128, 1)">1</span>; i++<span style="color: rgba(0, 0, 0, 1)">) {
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> j = <span style="color: rgba(128, 0, 128, 1)">1</span>; j &lt;= count; j++<span style="color: rgba(0, 0, 0, 1)">) {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> item = <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">rgb(</span><span style="color: rgba(128, 0, 0, 1)">'</span>
                + Math.round((colors[<span style="color: rgba(128, 0, 128, 1)">0</span>] - colors[<span style="color: rgba(128, 0, 128, 1)">0</span>]) / j + colors[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">])
                </span>+ <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">,</span><span style="color: rgba(128, 0, 0, 1)">'</span>
                + Math.round((colors[<span style="color: rgba(128, 0, 128, 1)">1</span>] - colors[<span style="color: rgba(128, 0, 128, 1)">1</span>]) / j + colors[<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">])
                </span>+ <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">,</span><span style="color: rgba(128, 0, 0, 1)">'</span>
                + Math.round((colors[<span style="color: rgba(128, 0, 128, 1)">2</span>] - colors[<span style="color: rgba(128, 0, 128, 1)">2</span>]) / j + colors[<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">])
                </span>+ <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">)</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">;
            calibrationColors.push(item)
      }
    }
}</span></pre>
</div>
<p>效果图:</p>
<p><img src="https://img2018.cnblogs.com/blog/1496396/201907/1496396-20190728131929227-1638003267.jpg"></p>
<h2>4.绘制指针</h2>
<p>这个主要是根据三角函数去计算相对圆心的偏移角度,按照当前值和刻度最大值的比例来计算偏移量,然后换算成对应的坐标。</p>
<p>主要代码:</p>
<div class="cnblogs_code">
<pre>pointer =<span style="color: rgba(0, 0, 0, 1)"> {
    x: origin.x </span>+ (ringRadio - pointerRadio - ringBorderWidth) * Math.cos(startAngle - Math.PI * <span style="color: rgba(128, 0, 128, 1)">2</span> * calibrationPercent *<span style="color: rgba(0, 0, 0, 1)"> percent),
    y: origin.y </span>- (ringRadio - pointerRadio - ringBorderWidth) * Math.sin(startAngle - Math.PI * <span style="color: rgba(128, 0, 128, 1)">2</span> * calibrationPercent *<span style="color: rgba(0, 0, 0, 1)"> percent),
    r: pointerRadio,
    color: percent </span>&gt; <span style="color: rgba(128, 0, 128, 1)">0</span> ?<span style="color: rgba(0, 0, 0, 1)"> calibrationBrightColor : calibrationDarkColor,
    show: </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
}

</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (pointerShow) {
    g.beginPath();
    g.fillStyle </span>=<span style="color: rgba(0, 0, 0, 1)"> pointer.color;
    g.arc(pointer.x, pointer.y, pointer.r, </span><span style="color: rgba(128, 0, 128, 1)">0</span>, Math.PI * <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">);
    g.closePath();
    g.fill();
}</span></pre>
</div>
<p>效果图:</p>
<p><img src="https://img2018.cnblogs.com/blog/1496396/201907/1496396-20190728132240232-1504034869.jpg"></p>
<h2>5.绘制标尺</h2>
<p>计算标尺角度的算法同指针。</p>
<p>主要代码:</p>
<div class="cnblogs_code">
<pre>scaleLine =<span style="color: rgba(0, 0, 0, 1)"> {
    startx: origin.x,
    starty: origin.y,
    endx: origin.x </span>+ (ringRadio + ringBorderWidth + 2 * calibrationHeight) * Math.cos(startAngle - Math.PI * 2 * calibrationPercent *<span style="color: rgba(0, 0, 0, 1)"> percent),
    endy: origin.y </span>- (ringRadio + ringBorderWidth + 2 * calibrationHeight) * Math.sin(startAngle - Math.PI * 2 * calibrationPercent *<span style="color: rgba(0, 0, 0, 1)"> percent),
    color: percent </span>&gt; 0 ?<span style="color: rgba(0, 0, 0, 1)"> calibrationBrightColor : calibrationDarkColor,
    show: scaleLineShow,
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (scaleLine) {
    g.beginPath();
    g.strokeStyle </span>= 'red'<span style="color: rgba(0, 0, 0, 1)">;
    g.setLineDash([</span>1, 2<span style="color: rgba(0, 0, 0, 1)">]);
    g.lineWidth </span>= 0.5 *<span style="color: rgba(0, 0, 0, 1)"> calibrationWidth;
    g.moveTo(scaleLine.startx, scaleLine.starty);
    g.lineTo(scaleLine.endx, scaleLine.endy);
    g.closePath();
    g.stroke();
}</span></pre>
</div>
<p>效果图:</p>
<p><img src="https://img2018.cnblogs.com/blog/1496396/201907/1496396-20190728132518236-468392742.jpg"></p>
<h2>6.绘制文本</h2>
<p>这里主要的就是确定文本所要绘制的位置,然后根据 <span style="font-family: &quot;times new roman&quot;, times">ht.Default.getTextSize()</span> 来获取文本长度,方便设置文本居中。</p>
<p>主要代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (labelShow) {
    </span><span style="color: rgba(0, 0, 255, 1)">var</span> text =<span style="color: rgba(0, 0, 0, 1)"> ht.Default.getTextSize(font, value);
    g.fillStyle </span>=<span style="color: rgba(0, 0, 0, 1)"> labelColor;
    g.font </span>=<span style="color: rgba(0, 0, 0, 1)"> font;
    g.fillText(value.toFixed(</span>2<span style="color: rgba(0, 0, 0, 1)">), labelDot.x, labelDot.y);
}</span></pre>
</div>
<p>效果图:</p>
<p><img src="https://img2018.cnblogs.com/blog/1496396/201907/1496396-20190728132653065-899820612.jpg"></p>
<p>到这就完成了基本的旋钮组件,下面继续做一些细节上的优化。</p>
<p>例如加一些阴影效果,颜色渐变,配色调整等。</p>
<p>主要代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> 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<span style="color: rgba(0, 0, 0, 1)">)));
backgroundRadial.addColorStop(</span>0, 'rgba(220,220,220,1)'<span style="color: rgba(0, 0, 0, 1)">);
backgroundRadial.addColorStop(</span>1<span style="color: rgba(0, 0, 0, 1)">, backgroundColor);
g.fillStyle </span>=<span style="color: rgba(0, 0, 0, 1)"> backgroundRadial;
g.fillRect(x, y, width, height);

g.beginPath();
</span><span style="color: rgba(0, 0, 255, 1)">var</span> ringRadial = g.createRadialGradient(origin.x, origin.y - ringRadio / 2, 0, origin.x, origin.y - ringRadio / 2, 1.5 *<span style="color: rgba(0, 0, 0, 1)"> ringRadio);
ringRadial.addColorStop(</span>0, ht.Default.brighter(ringColor, 40<span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ringRadial.addColorStop(0.25, ht.Default.brighter(ringColor, 40));</span>
ringRadial.addColorStop(1, ht.Default.darker(ringColor, 20<span style="color: rgba(0, 0, 0, 1)">));

</span><span style="color: rgba(0, 0, 255, 1)">var</span> borderRadial = g.createRadialGradient(origin.x, origin.y, ringRadio - ringBorderWidth / 2, origin.x, origin.y, ringRadio + ringBorderWidth / 2<span style="color: rgba(0, 0, 0, 1)">);
borderRadial.addColorStop(</span>0, ht.Default.brighter(ringBorderColor, 2<span style="color: rgba(0, 0, 0, 1)">));
borderRadial.addColorStop(</span>0.5, ht.Default.brighter(ringBorderColor, 4<span style="color: rgba(0, 0, 0, 1)">));
borderRadial.addColorStop(</span>1, ht.Default.darker(ringBorderColor, 4<span style="color: rgba(0, 0, 0, 1)">));
g.fillStyle </span>=<span style="color: rgba(0, 0, 0, 1)"> ringRadial;

g.lineWidth </span>=<span style="color: rgba(0, 0, 0, 1)"> ringBorderWidth;
g.strokeStyle </span>=<span style="color: rgba(0, 0, 0, 1)"> borderRadial;
g.arc(origin.x, origin.y, ringRadio, </span>0, 2 *<span style="color: rgba(0, 0, 0, 1)"> Math.PI);
g.closePath();
g.fill();
g.shadowBlur </span>= 20<span style="color: rgba(0, 0, 0, 1)">;
g.shadowColor </span>=<span style="color: rgba(0, 0, 0, 1)"> shadowColor;
g.shadowOffsetY </span>=<span style="color: rgba(0, 0, 0, 1)"> ringBorderWidth;
g.stroke();
g.shadowBlur </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
g.shadowOffsetY </span>= 0;</pre>
</div>
<p>效果图:</p>
<p><img src="https://img2018.cnblogs.com/blog/1496396/201907/1496396-20190728132845698-835209225.jpg"></p>
<h2>&nbsp;7.交互效果</h2>
<p>以上就是绘制好了一张静态图,最后就只要再加上一些交互效果就可以了。<br>这里我采用的是 <span style="font-family: &quot;times new roman&quot;, times">HT for Web</span> 的矢量来实现。可参考 → 戳这</p>
<p>监听 <span style="font-family: &quot;times new roman&quot;, times">onUp</span> 和<span style="font-family: &quot;times new roman&quot;, times"> onDraw</span> 事件。<br><span style="font-family: &quot;times new roman&quot;, times">onUp</span>:<br>当鼠标抬起时,获取当前旋钮显示的值,然后四舍五入,取其最近的刻度校准,使用 <span style="font-family: &quot;times new roman&quot;, times">ht.Default.startAnim()</span> 添加动画效果。<br><span style="font-family: &quot;times new roman&quot;, times">onDraw</span>:<br>根据当前鼠标停留的位置,以旋钮原点为参照点,根据三角函数来计算指针和起始刻度的夹角 <span style="font-family: &quot;times new roman&quot;, times">A</span> ,计算 <span style="font-family: &quot;times new roman&quot;, times">A</span> 占总刻度的百分比 <span style="font-family: &quot;times new roman&quot;, times">p</span> ,然后设置当前值为 <span style="font-family: &quot;times new roman&quot;, times">max * p</span> 。</p>
<p>最后使用 HT 实现:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> gv = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ht.graph.GraphView();
      dm </span>=<span style="color: rgba(0, 0, 0, 1)"> gv.dm();
      dm.a(</span>'pannable', <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
      dm.a(</span>'zoomable', <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
      dm.a(</span>'rectSelectable', <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
      
      ht.Default.setCompType(</span>'knob',func); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注册组件</span>
      ht.Default.setImage('iconKnob', data); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注册图片</span>
      
<span style="color: rgba(0, 0, 255, 1)">var</span> node = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ht.Node();
      node.setImage(</span>'iconKnob'<span style="color: rgba(0, 0, 0, 1)">);
      node.s(</span>'2d.movable', <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
      dm.add(node);
      gv.fitContent();
      gv.addToDOM();
      window.addEventListener(
      </span>'resize'<span style="color: rgba(0, 0, 0, 1)">,
      </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(e) {
          gv.invalidate();
          gv.fitContent();
      },
      </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
      );</span></pre>
</div><br><br>
来源:https://www.cnblogs.com/htdaydayup/p/11258689.html
頁: [1]
查看完整版本: 基于 HTML5 Canvas 的可交互旋钮组件