基於 HTML5 Canvas 的可互動旋鈕元件
前言
此次的 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, 0, origin.x, origin.y, ringRadio); ringRadial.addColorStop(0, ht.Default.brighter(ringColor, 20)); ringRadial.addColorStop(0.95, 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.stroke();
效果圖:
3.繪製刻度
這裡繪製每個刻度採用的是繪製路徑的方法,所以宣告瞭一個變數 calibrationPoints 用來存放每個刻度的起始點座標,根據配置的引數去計算 calibrationPoints 的資訊。
首先根據引數 calibrationPercent 計算第一個刻度的起始角度 startAngle ,然後根絕 calibrationCount 的值去計算每個刻度所佔用的角度 partAngle ,最後根據三角函式和相應的角度,轉化為對應的座標。
主要程式碼:
var calibrationPoints = []; for (var i = 0; i < calibrationCount + 1; i++) { var point = { startx: origin.x + (ringRadio + ringBorderWidth + 0 * calibrationHeight) * Math.cos(startAngle - i * partAngle), starty: origin.y - (ringRadio + ringBorderWidth + 0 * calibrationHeight) * Math.sin(startAngle - i * partAngle), endx: origin.x + (ringRadio + ringBorderWidth + 1 * calibrationHeight) * Math.cos(startAngle - i * partAngle), endy: origin.y - (ringRadio + ringBorderWidth + 1 * calibrationHeight) * Math.sin(startAngle - i * partAngle) }; if (i <= (calibrationCount * percent) && percent > 0) { 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, 10); 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 - 1)); // 漸變次數 calibrationColors = []; for (var i = 0; i < colors.length - 1; i++) { for (var j = 1; j <= count; j++) { var item = 'rgb(' + Math.round((colors[i + 1][0] - colors[i][0]) / j + colors[i][0]) + ',' + Math.round((colors[i + 1][1] - colors[i][1]) / j + colors[i][1]) + ',' + Math.round((colors[i + 1][2] - colors[i][2]) / j + colors[i][2]) + ')'; calibrationColors.push(item) } } }
效果圖:
4.繪製指標
這個主要是根據三角函式去計算相對圓心的偏移角度,按照當前值和刻度最大值的比例來計算偏移量,然後換算成對應的座標。
主要程式碼:
pointer = { x: origin.x + (ringRadio - pointerRadio - ringBorderWidth) * Math.cos(startAngle - Math.PI * 2 * calibrationPercent * percent), y: origin.y - (ringRadio - pointerRadio - ringBorderWidth) * Math.sin(startAngle - Math.PI * 2 * calibrationPercent * percent), r: pointerRadio, color: percent > 0 ? calibrationBrightColor : calibrationDarkColor, show: true, } if (pointerShow) { g.beginPath(); g.fillStyle = pointer.color; g.arc(pointer.x, pointer.y, pointer.r, 0, Math.PI * 2); 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 );
相關文章
- 基於 Canvas 的 HTML5 互動式地鐵線路圖CanvasHTML
- 基於 HTML5 Canvas 的拓撲元件 ToolTip 應用HTMLCanvas元件
- 基於 Canvas 的 HTML5 文字動畫特效CanvasHTML動畫特效
- 基於 HTML5 Canvas 實現的文字動畫特效HTMLCanvas動畫特效
- 基於 HTML5 Canvas 實現文字動畫特效HTMLCanvas動畫特效
- 基於 Canvas 的 HTML5 工控機櫃 U 位動態管理CanvasHTML
- 基於 HTML5 Canvas 的工控機櫃 U 位動態管理HTMLCanvas
- 基於 HTML5 Canvas 的電信機櫃 U 位動態管理HTMLCanvas
- 基於 HTML5 Canvas 的元素週期表展示HTMLCanvas
- 基於 HTML5 Canvas 的樓宇自控系統HTMLCanvas
- 基於 HTML5 Canvas 的元素週期表的展示HTMLCanvas
- 基於HTML5Canvas的互動式地鐵線路圖HTMLCanvas
- 基於canvas的骨骼動畫Canvas動畫
- Html5 Canvas動畫基礎(碰撞檢測)HTMLCanvas動畫
- 基於 HTML5 Canvas 的 3D 熱力雲圖效果HTMLCanvas3D
- C#自定義控制元件—旋轉按鈕C#控制元件
- iOS Tabbar中間新增凸起可旋轉按鈕iOStabBar
- 基於 HTML5 Canvas 電信網路拓撲圖的快速搭建HTMLCanvas
- 基於ResponderChain的物件互動方式AI物件
- 基於 ResponderChain 的物件互動方式AI物件
- 基於HTML5的移動Web應用HTMLWeb
- 【WEB自動化測試之控制元件定位】基於HTML5控制元件的唯一控制元件屬性定位Web控制元件HTML
- 基於virtual dom 的canvas渲染Canvas
- 可互動的有趣的LoadingViewView
- HTML5學習之Canvas基礎知識HTMLCanvas
- Vue實現浮動按鈕元件 - 頁面滾動時自動隱藏 - 可拖拽Vue元件
- canvas 圍繞中心旋轉Canvas
- 基於 HTML5 Canvas 的 3D 渲染引擎構建生產管控系統HTMLCanvas3D
- 基於 HTML5 Canvas 實現的 TP-LINK 電信拓撲裝置皮膚HTMLCanvas
- ECharts 互動元件概述Echarts元件
- 基於HTML5的移動Web應用——檔案操作HTMLWeb
- 超酷!!HTML5 Canvas 水流樣式 Loading 動畫HTMLCanvas動畫
- 基於VUE自定義指令實現按鈕級許可權控制Vue
- 仿餓了麼加入購物車旋轉控制元件 – 自帶閃轉騰挪動畫 的按鈕控制元件動畫
- 基於canvas生成海報Canvas
- 基於canvas生成圖片Canvas
- 基於layui的省市區三級聯動(資料互動)UI
- 一個基於canvas的移動端圖片編輯器Canvas