學習用 JS CSS 畫乙個時鐘

2021-09-25 21:39:51 字數 3140 閱讀 6121

看到某君的時鐘 clock **,想學習怎麼畫乙個時鐘,逐重構之,把裡面不合理的地方改進(例如用 js 寫 css,那肯定不好)。

全部**如下:

首先讀者要懂得 css relative/absoulte 布局:容器定義了為 relative 布局後,自建乙個內部的座標系,我們就可以在裡面把 absulte 的元素通過定義 top/left 分配座標。

然後看看 clock 這個類。構造引數 box 是個元素,讀取其 clientheight/clientwidth 獲取高寬,分配給 bh、bw。bh/2、bw/2 自然就是中間的座標,即變數 centerx、y。我們還要將變數分配給當前物件乙份引用,以便後面的方法讀取它們,即 this.centerx = centerx, this.centery = centery;, box 也是如此。raduis 是半徑,我們也分配給 this,即 this.raduis = (centery >= centerx ? centery : centerx) - 10; 減去 10 是我們希望這個時鐘範圍小一點,相當於內邊距 padding。

目標是把12個點平均分配在圓中,如下圖所示。

createpoint() 繪製了這十二個點,如下所示。

createpoint() 

},

createpoint() 中,首先建立 span 元素,這元素是 absolute 定位,通過 left/top 可指定元素座標。怎麼確定座標呢?首先乙個圓有 360 度,被刻畫為 12 點,即平均劃分十二份,點與點之間的夾角是 360/12 = 30 度。於是,我們寫出乙個 for 迴圈,從零度開始到 360 度,步進是 30。然後,複製 12 個點,即 _el.clonenode(true);

因為已知半徑和夾角角度,所以可以通過三角函式 sin/cos 即可求得對邊和鄰邊長度,對應就是 x、y 的距離。不過 js 的 math.sin/cos 函式要求傳入的引數是弧度,所以我們要轉換一下角度到弧度。最後因為圓心座標是 centerx、centery 所以最終刻點座標還是加起來。

var fn_sin = (angle, raduis) => math.round(math.sin(angle * math.pi / 180) * raduis);

var fn_cos = (angle, raduis) => math.round(math.cos(angle * math.pi / 180) * raduis);

math.round 的作用是取整。

繪製黑色的時針、灰色的分針和紅色的秒針,結果如下圖。

雖然看上去是直線,但是仔細看還是有不少鋸齒的,這是因為用乙個個點構成直線的緣故,遇到有一定的角度如果點數量不夠多的話,就容易出現鋸齒。這裡,乙個點就是乙個 span 元素,當然也是通過 left/top 定位。

首先是畫出刻針 createel(amount, clsname),指定 span 數量和樣式類即可。

var hour = this.createel(30, 'hourone'),

minute = this.createel(30, 'minuteone'),

second = this.createel(40, 'secondone');

……createel(amount, clsname)

return arr;

},

可見 createel() 過程比較簡單的,只是 for 一下然後返回元素的陣列即可。

時針目前的需求是:

下面結合我們的 js 程式,解決思路如下。

var d = new date();

var h = math.abs(d.gethours()), m = d.getutcminutes(), s = d.getseconds();

var calhour = (h, m) => ((h * 60 + m) / (12 * 60)) * 360 - 90; // 時針

var calaa = (m) => (m / 60) * 360 - 90; // 分針、秒針

相比之下,求出分針的角度比較簡單的,我們先說一下(即 calaa())。一小時 60 分鐘,表示我們在圓上等分 60 份,即有了 m 分鐘即 m * (360/60) 角度。又因刻針相對 12 點的餘角的角度,故減去 90 度,得出分針之角度。一分鐘等於 60 秒,於是秒針亦是同理。

相比之下,求出時針較複雜。十二個小時,圓被等分 360/60,這個沒問題。然後指標的角度產生的頂點不一定是落在 1、2、3 整數上,例如一點半(1:30),指標應指向 1 點與 2 點之間的中間位置上。於是 calhour 函式除 hour 引數外還需要 min 分的引數。轉化為小數 (60 h + m)/60 再乘以 360/60,最後仍要減去 90,便最後得出時分的角度。注意 calhour 括號優先順序不同,不影響結果。

角度確定了,我們接著就要在頂點與圓心之間畫一條直線。之前我們不是弄了點的陣列麼,我們此時此刻就要將它們排列成一條線。我們令其半徑不一樣(角度是一樣的了),所以座標也不一樣。怎麼計算半徑呢?與陣列裡面的索引 i 成比例,另外還加入一定偏移量令其更好看一點。如下 set 函式所示。

set(arr, angle, offset) 

}

最後的 left/top 計算就是復用前面的三角函式。

至此乙個簡單的時鐘完成了。用 span 元素繪圖效率還是比較低,可以考慮用 canvas 或 svg 元素改進吧!

2019-8-23 update: 基於 canvcas 製作的,可見行數很短。

CSS 畫乙個心

效果圖 實現原理 可以把這個心分為兩部分,兩個長方形,分別設定 border radius,transform rotate 設定屬性之後 再次新增乙個,設定相反的 rotate 設定其中乙個的 left 值 就成了 為了看起來有立體感,可以設定左邊的 box shadow cssbodydivdi...

CSS 畫乙個心

效果圖 實現原理 可以把這個心分為兩部分,兩個長方形,分別設定 border radius,transform rotate 設定屬性之後 再次新增乙個,設定相反的 rotate 設定其中乙個的 left 值 就成了 為了看起來有立體感,可以設定左邊的 box shadow cssbodydivdi...

ShaderToy 畫乙個球體

嗯,其實渲染球體,可以看做就是乙個2d圓形圖案 渲染光澤的函式。定義球體結構 半徑,球心座標 struct sphere edzx 定義光線 光源座標,方向 struct ray 檢測 光線 與 球體 是否相交,若未相交返回false,相交返回從光源到球面的距離 數學解釋如下 圖中紅色線條即光線,重...