摘要:在編寫的過程中,涉及到了中的各種位運算符,對進制色值的處理不再是循環遍歷了。只對位運算符感興趣的建議直接閱讀目錄中的色值的快速轉換。通過閱讀類,可以知道最終屬性均為一個或構造出來的對象,接下來就具體說說類中的這些位運算符起到了什么作用。
從最近寫的一個圖表庫中多帶帶抽象出來了顏色類庫,功能包括HEX、RGB/RGBA以及HSL/HSLA各種色值的轉換以及顏色明暗變化。
在編寫的過程中,涉及到了JS中的各種位運算符,對16進制色值的處理不再是循環遍歷了。只對位運算符感興趣的建議直接閱讀目錄中的“HEX色值的快速轉換”。
先上兩張圖,循環了1600個div,分別設置顏色的漸變和隨機。雖然現在css中對顏色的處理方法越來越豐富,但在一些場景——例如可視化圖表中我們還是需要用JS來控制顏色。
將各種格式的色值進行統一,方便操作,也確保展示效果一致。
對顏色進行明暗處理,最明時為白色(#fff),最暗時為黑色(#000)。
其中顏色格式包括:
3位Hex值
6位Hex值
整數型RGB
百分比型RGB
整數型RGBA
百分比型RGBA
HSL
HSLA
常見的顏色命名,如black
流程及接口要實現以上的功能,流程上應該包括:
通過正則表達式檢測顏色格式。
將顏色統一為一種最易操作的格式。由于我們的操作主要為明暗操作,那么RGB/RGBA格式顯然是最方便的,因此將各種格式統一為RGB/RGBA。
為每個格式化后的顏色添加“變明”、“變暗”兩個方法,并返回一個新的標準格式顏色對象,以便鏈式調用。
顏色對象還需要有一個輸出顏色字符串的方法,以便在所有操作完成后輸出最終的色值添加給對應的Dom。
檢測顏色格式注意,此類庫使用了部分ES6語法,如需轉化為瀏覽器可直接使用的版本,可用babel進行轉換。
檢測格式時,主要依靠的是正則表達式,具體如下:
const reHex3 = /^#([0-9a-f]{3})$/ const reHex6 = /^#([0-9a-f]{6})$/ const reRgbInteger = /^rgb(s*([-+]?d+)s*,s*([-+]?d+)s*,s*([-+]?d+)s*)$/ const reRgbPercent = /^rgb(s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*)$/ const reRgbaInteger = /^rgba(s*([-+]?d+)s*,s*([-+]?d+)s*,s*([-+]?d+)s*,s*([-+]?d+(?:.d+)?)s*)$/ const reRgbaPercent = /^rgba(s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)s*)$/ const reHslPercent = /^hsl(s*([-+]?d+(?:.d+)?)s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*)$/ const reHslaPercent = /^hsla(s*([-+]?d+(?:.d+)?)s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)%s*,s*([-+]?d+(?:.d+)?)s*)$/
對于已命名的顏色,則構建了一個named對象,key為顏色名稱,value則為16進制色值,例如:
const named = { aliceblue: 0xf0f8ff, antiquewhite: 0xfaebd7, ... yellowgreen: 0x9acd32 } 通過named.hasOwnProperty方法來檢測輸入的字符串是否是已命名的顏色,如果是,則用其16進制色值替換。
實際上,我創建了3個class,分別為Color、Rgb和Hsl。以上的顏色檢測均放在Color的format方法中,將格式化之后的顏色放入Color的f屬性里,代碼如下:
class Color { constructor () { this.f = {} } format (str) { let m str = (str + "").trim().toLowerCase() if (reHex3.exec(str)) { m = parseInt(reHex3.exec(str)[1], 16) this.f = new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1) } else if (reHex6.exec(str)) { m = parseInt(reHex6.exec(str)[1], 16) this.f = this.rgbn(m) } else if (reRgbInteger.exec(str)) { m = reRgbInteger.exec(str) this.f = new Rgb(m[1], m[2], m[3], 1) } else if (reRgbPercent.exec(str)) { m = reRgbPercent.exec(str) const r = 255 / 100 this.f = new Rgb(m[1] * r, m[2] * r, m[3] * r, 1) } else if (reRgbaInteger.exec(str)) { m = reRgbaInteger.exec(str) this.f = this.rgba(m[1], m[2], m[3], m[4]) } else if (reRgbaPercent.exec(str)) { m = reRgbaPercent.exec(str) const r = 255 / 100 this.f = this.rgba(m[1] * r, m[2] * r, m[3] * r, m[4]) } else if (reHslPercent.exec(str)) { m = reHslPercent.exec(str) this.f = this.hsla(m[1], m[2] / 100, m[3] / 100, 1) } else if (reHslaPercent.exec(str)) { m = reHslaPercent.exec(str) this.f = this.hsla(m[1], m[2] / 100, m[3] / 100, m[4]) } else if (named.hasOwnProperty(str)) { this.f = this.rgbn(named[str]) } else if (str === "transparent") { this.f = new Rgb(NaN, NaN, NaN, 0) } else { this.f = null throw new Error("Invalid color format.") } return this.f } rgbn (n) { return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1) } rgba (r, g, b, a) { if (a <= 0) r = g = b = NaN return new Rgb(r, g, b, a) } hsla (h, s, l, a) { if (a <= 0) { h = s = l = NaN } else if (l <= 0 || l >= 1) { h = s = NaN } else if (s <= 0) { h = NaN } return new Hsl(h, s, l, a).rgb() } }
為了方便讀者快速理解代碼,用了大量的if / else if,實際可以用三元表達式替代,讓代碼更優雅緊湊。
通過閱讀Color類,可以知道最終f屬性均為一個 new Rgb 或 new Hsl 構造出來的對象,接下來就具體說說Color類中的這些位運算符起到了什么作用。
HSL和RGB的轉換沒有什么黑魔法,都是查Wiki之后寫的方法,大同小異,所以重點講講16進制色值是怎樣處理的。
網上資料中,大部分的HEX轉Rgb都是通過遍歷字符串,將HEX色值分隔,再轉化為10進制數字。但在閱讀d3.js的源碼后,發現還有更巧妙的處理方法。
首先補充一下HEX色值的基本概念。HEX色值可以為3位或者6位,3位可以理解為一種簡寫,如#123,實際等于#112233。
而對于一個6位的HEX色值,如#112233,在轉換為RGB時,實際是每兩位對應RGB中的一個值,即11、22、33分別對應R、G、B。
首先以6位HEX色值為例,我們通過正則表達式取出其值后,parseInt(str, 16)轉化為16進制數字,也可以通過在前面加上"0x"來達到這一效果,目的都是告訴解析器,它是一個16進制的數。依然以#112233為例,具體看看代碼:
const m = parseInt("112233", 16) // 0x112233 // 分別獲取R、G、B的值 const r = m >> 16 & 0xff // 17 const g = m >> 8 & 0xff // 34 const b = m & 0xff // 51
那么>>和&分別起什么作用,為什么這樣一操作就能直接取出對應數值呢?
>>是JS中的右移運算符,用于將數字的二進制右移n位。對于一個16進制的數字而言,每一位數字都對應4位2進制數字,如0x112233的二進制就是0001 0001 0010 0010 0011 0011。
因此要取出最左端11對應的10進制數字,只需要將其右移16位,剩下左起的8位即可。
那么當我們需要取中間的22和最右端的33時該怎么辦呢?這就需要用到&。&是JS中位的與運算,說起來有點繞口,實際就是將兩端的值的二進制按位一一取與運算。
所以我們實際看看取22和33時發生了什么:
// 0x112233的二進制為0001 0001 0010 0010 0011 0011 let n = 0x112233 >> 8 // 0001 0001 0010 0010 // 將n和0xff按位與運算,0xff的二進制為1111 1111 n & 0xff // 0010 0010 也就是 0x22 n = 0x112233 & 0xff // 0011 0011 也就是 0x33
簡單的說,就是通過與0xff這個二進制最右端8均為1的數與運算,從而取出目標數最右端的八位,并舍棄其余所有位數。
總的來說,就是先用>>調整位置,再用&篩選。
我們接著處理3位HEX值,以#123為例,取出對應的R、G、B。
const m = parseInt("123", 16) // 0x123 const r = (m >> 8 & 0xf) | (m >> 4 & 0x0f0) // 17 const g = (m >> 4 & 0xf) | (m & 0xf0) // 34 const b = ((m & 0xf) << 4) | (m & 0xf) // 51
代碼中出現的|是位的或運算符,機制和&相類似。<<則是和>>對應的左移運算符。
同樣一步一步看看|是怎么起到作用的:
// 0x123的二進制為0001 0010 0011 0x123 >> 8 & 0xf // 0001 0x123 >> 4 & 0x0f0 // 0001 0000 0001 | 0001 0000 // 0001 0001 也就是 0x11 0x123 >> 4 & 0xf // 0010 0x123 & 0xf0 // 0010 0000 0010 | 0010 0000 // 0010 0010 也就是 0x22 (0x123 & 0xf) << 4 // 0011 0000 0x123 & 0xf // 0011 0011 0000 | 0011 // 0011 0011 也就是 0x33
思路和6位時一樣,只是增加了<<和|,更靈活的操作各種位運算。
剩余工作之后要做的主要就是一些HSL轉換、明暗變化以及各種錯誤處理,都是比較常規的做法,這里不多做贅述,有興趣的可以看看代碼:https://github.com/Yuyz0112/v...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80133.html
摘要:檢查設定位操作符還有一些其他有用的位屏蔽應用。請注意,位掩碼中的位將有效地關閉十進制數中的相應位,因為。 原文標題:Interesting use cases for JavaScript bitwise operators原文地址:https://blog.logrocket.com/in... 本文首發于公眾號:符合預期的CoyPan JavaScript提供了幾種運算符,可以對...
摘要:也就是說不僅是會產生這種問題,只要是采用的浮點數編碼方式來表示浮點數時,則會產生這類問題。到這里我們都理解只要采取的浮點數編碼的語言均會出現上述問題,只是它們的標準類庫已經為我們提供了解決方案而已。 Brief 一天有個朋友問我JS中計算0.7 * 180怎么會等于125.99999999998,坑也太多了吧!那時我猜測是二進制表示數值時發生round-off error所導致,但并不...
摘要:而通過實現名為的標準模塊,完美的解決了模塊導入問題。通常都被稱為包管理器,而這也是它最大的特色。例如,接受請求發送響應。該模塊主要處理文件相關內容,其中大多數都是文件讀寫功能。 在上一篇文章中,我們簡單的介紹了 Node.js 。了解到它基于 JavaScript、天生異步、擁有大量的第三方類庫。本文將會在之前的基礎上,對 Node.js 進行更深入的介紹。其中主要內容包括: Nod...
摘要:老實說,當時一進入世界的大門就暈了,各種規范概念和英文縮寫詞能把人整的暈暈乎乎。等新的英文縮寫又出現了,一口老血還沒來得及噴出,又重新振作開始新的學習征程。 showImg(http://upload-images.jianshu.io/upload_images/1131767-1c5d16e39435df10.jpg?imageMogr2/auto-orient/strip%7Ci...
閱讀 3096·2021-09-28 09:42
閱讀 3448·2021-09-22 15:21
閱讀 1122·2021-07-29 13:50
閱讀 3564·2019-08-30 15:56
閱讀 3367·2019-08-30 15:54
閱讀 1196·2019-08-30 13:12
閱讀 1172·2019-08-29 17:03
閱讀 1198·2019-08-29 10:59