,只要會往`<canvas>`里面畫一個長方形,就可以做出來這樣子的效果,畫比較多的正方形實現像素風頭像生成器:
趕時間的客官可以直接去`正文開始`那里。
今天有個想法,整成手把手系列,就是假設客官是一個從來沒有接觸過網頁編輯、代碼、編程的新手。所以會說的比較詳細,比較累贅,大神們笑笑點個贊就好了,哈哈。
我的想法(初心)是,將一個有興趣寫網頁,但是不知道從何開始的人,通過幾篇很小的實例,讓他產生興趣,跟出效果,形成自己動手去學習的動力,便是最好了。
所以,努力寫得通俗易懂,簡單直接,拋開別的因素,先實現出來再說,那時候學寫代碼的時候也是聽師傅說“先有后優”,所以,粗糙點不管,能說明問題便好。
有客官對于我前面幾天碼的字,有反饋,有問題提出來,非常感謝有人搭理我。提出來的1,web字體設置的方法,2,響應式布局,3,網頁上面音頻播放的多瀏覽器兼容問題,4,不知從何入手學習一個東西...我都在拿著小本記下來,閑暇時間趕緊去搜集一些比較好的方法,盡力去更新分享這些方面的一小點經驗,還請各位客官多多搭理我呀。
這里先把昨天最后那個小坑給添一下,那個響應式布局,是通過在CSS里面定義不同屏幕寬度時候使用不同的樣式,直接帖代碼出來吧:
@media screen and ( max-width: 1920px ) { div.content { height: 600px; width: 300px; float: left; padding-top: 97px; } div.sider { float: right; } body { width: 600.111111px; margin: 0 auto; } } @media screen and ( max-width: 720px ) { div { display: block; clear:both; height: auto; } div.content { display: block; height: auto; width: 100%; } div.sider { display: block; width: 100%; padding-bottom: 100px; } body { margin: 0; padding: 0; width: 100%; } }
在1920到720這么寬的時候,兩個div左右浮動,在小于720的時候,兩個div顯示模式改為塊級元素,寬度定義為100%,也就變成豎著排列了。就這樣子。
接下來,正文開始:
1, 只用一個文件:`t.html`就好了,忘掉那些什么最佳實踐,干就完了,新建文本文件,然后重命名成`t.html`,注意,重命名成網頁之后,文件的圖標會發生變化,不是以前文本文檔時候的樣子,如果圖標沒變,你極可能重命名成了`t.html.txt`這樣子的,我的小視頻里面有如何設置windows7顯示擴展名,看看也是極好的。
2, 很簡單的網頁基本代碼:
<!doctype html> <html lang="zh"> <head> <meta charset="UTF-8"> <title>像素風頭像生成器</title> </head> <body> <div id="wrapper"> <!--第一個注釋,這里等下放畫板(canvas標簽)--> </div> <!--第二個注釋,這里等下放javascript代碼--> </body> </html>
復制上面的代碼到`t.html`里面,然后保存,存成utf-8編碼格式(實例001里面有個圖片演示了怎么保存)。
3, 繼續編輯`t.html`文件,在兩個注釋的地方,第一個放入`<canvas>`標簽,同時給它樣式,定義大小(寬500,高400),還有一個邊框(1像素實心線奶奶灰色),`<canvas>標簽中間的一句話,在不支持canvas標簽的瀏覽器里面會被顯示出來`:
<canvas id="myCanvas" width="500" height="400" style="border:1px solid #d3d3d3;"> 快看,這里有一個還在用IE6/8的老實人,大家快來~~ </canvas>
4, 第2步里面的第二個注釋的位置,加入javascript代碼,看代碼注釋理解語句的含義:
<script type="text/javascript"> //在html中用ID找到叫做`mycanvas`的畫布,給它取名叫c var c = document.getElementById("myCanvas"); //通過這個c(剛才找到的畫布),拿到一套可以畫2D圖片的基本工具, 取名叫ctx,可以理解成拿起一根畫筆 var ctx=c.getContext("2d"); //給ctx這根畫筆,蘸上橙色 ctx.fillStyle="orange"; //用ctx這根畫筆,在x=100,y=90這個坐標位置,畫一個長80,寬40的長方形 ctx.fillRect(100,90,80,40); </script>
效果:
在畫布的左上角,坐標為0,0
大小位置標注:
嗯,就是這樣
是不是很簡單呀,在網上可以搜索`html5 canvas 基本開關`了解更多,不知客官可否通過這個別樣的“畫布”畫出來一個五角星呢?歡迎挑戰。
晚安
言
25年過去了,Brooks博士著名的“沒有銀彈”的論斷依舊沒有被打破。HTML5也是一樣。但這并不妨礙HTML5是一個越來越有威力的“炸蛋”:發展迅速、勢不可擋。隨著HTML5技術的普及,用HTML5做可視化呈現的項目越來越多了。HTML5的優勢明顯:網頁上直接運行無需插件、手機平板方便兼容、代碼開發和維護相對容易,等等。一大波一大波的做Java、.NET甚至C++桌面的程序老手們都紛紛開始研究javascript了,而初出茅廬的新一代程序猿更是義無反顧的直奔HTML5這個技術大熱點而來。
HTML5涵蓋的技術點很多,甚至延伸到了前端、后端、通訊等各個層面。前端的canvas繪圖這塊無疑是它的核心內容。Canvas的API雖然不是很復雜很強大,但是做一般的2d繪圖基本都夠用了。基于這些API,一大堆的2d繪圖組件紛紛出爐。Echarts、d3.js都是很不錯的項目。 Echarts主要是chart組件,而d3相對雜一些,很多呈現方式很有創意,值得研究。
概述
研究d3的起因是最近有一個項目,用戶截了一張效果圖讓我們用HTML5做一下:
看著很眼熟,搜了一下,感覺就是d3例子中的sunburst效果,程序在這里:
http://bl.ocks.org/mbostock/4063423
看上去似乎也不難,就是一圈一圈的餅圖,把樹狀結構數據按占比一層一層繪制上去就行了。所以引起了自己動手做一個的興趣。“sunburst”英文里應該是“云開日出”的意思,類似強烈的光芒從云層背后透射出來,不知為何中文里大多把它翻譯成“日落”。比如這把Fender Telecaster吉他型號是Brown Sunburst款,就會被大家翻譯成“日落色”。
關于日出和日落更喜歡哪一個的問題,網上還真有這樣的調查。有意思的是,選擇喜歡日落的遠多于選擇日出的。日出代表希望,日落代表成熟,都是一種美,哪個更美要看你個人的心境,因為它的美麗是由心生。為了不在這個問題上站錯對,我們還是給他重新起一個更加響亮霸氣的中文名字:“彩虹爆炸圖”,怎么樣?
仔細研究一下彩虹爆炸圖的結構,無非就是一個樹形結構,并采用發射狀的布局。根節點在中間(也可以認為沒有唯一的根,而是一堆根節點圍繞在第一圈),一次向外發散排列。每一個節點有名稱、數值。節點可以按照自身數值在扇區所占比例進行繪制,這樣就不用管節點具體數值有多大多小了。
這種圖最先是由布朗大學教授John T. Stasko設計。
http://www.cc.gatech.edu/~john.stasko/
經過一天的折騰,終于做出了一個還算過得去的“彩虹爆炸圖”。先上個圖看看:
主要功能包括了:
可以通過json來定義數據和樣式(類似百度的echarts那樣);
顏色可以固定,也可以自動彩虹色;
自動計算數值及角度占比;
動態顯示導航路徑;
鼠標動態高亮顯示路徑;
動畫飛入、展開導航路徑;
文字顯示及角度控制;
全矢量,可鼠標縮放、平移,不失真;
下面重點碼一下折騰過程中的幾個重點:
一、定義節點對象
首先定義每一個小扇片節點。每個扇片可以用一段餅圖來繪制。為了簡單方便,這里用了最簡單高效偷懶的方法:用一個半徑很粗的線畫一段角度的arc,即可。如下圖:
另外還有文字等內容。所以定義它的json結構大概如下:
var item = {name: '名稱', color: 'red', angle: '45', …};
此外,下一圈的數據,可直接定義為這個節點的“孩子節點”,直接在item中定義一個data的子節點數據:
var item = {name: '名稱', color: 'red', angle: '45', data:[
{name:’孩子一’, color:’green’,…},
{name:’孩子二’, color:’yellow’,…},
]};
這樣就可以組成一個樹狀結構。接下來要在canvas上繪制圖形了。為了方便,這里直接使用了矢量圖進行定義:
twaver.Util.registerImage('node', {
v: [{
shape: 'circle',
r: ...
lineColor: function(data,view){return data.getClient("lineColor");},
lineWidth: ...
startAngle: ...
endAngle: ...
},{
shape: 'text',
textBaseline: 'middle',
textAlign: ...
text: ...
x: ...
y: ...
font: ...
fill: ...
rotate: ...
visible: ...
shadow: ...
}],
});
矢量圖中定義了2個圖形元素:一個arc弧線、一個文字對象,分別用于畫node和繪制其文字。顏色、字體、是否可見、陰影、對齊、位置、線寬、角度…等等均在上面的定義中用一個function動態獲取。例如,這個節點的半徑,通過下面的方法,就可以在圖形的lineColor屬性中保存并驅動,需要修改,直接修改lineColor這個client屬性即可,而不用去修改繪圖參數,非常方便:
r:function(data,view){return data.getClient("lineColor");}
這里有一個比較啰嗦的地方是:每個扇片的角度需要根據每個item定義的原始值進行計算角度占比。而且,對于太小的扇片,可以給一定的最小值(例如 1度),保證能視覺上看到它。否則,顯示10000和1兩個數值,由于對比過大,可能就杯具了,因為1連1度都占不到,顯示效果會非常差。還有,每個扇片之間應該盡量留有一定的空隙。如果連續繪制,就會連成一片,沒有“分片”感。這些可以在代碼中進行簡單控制。
二、文字控制
文字控制也比較啰嗦。首先是對齊方式。最簡單的方式當然是讓文字在所在扇片處,直接居中、旋轉。這樣文字會在徑向的中間位置,如下圖:
但這樣顯示感覺并不是很完美。對于中文來說,如果能統一靠近圓心方向的位置對齊,會更好看一些。這樣,即使文字過長,也會向外延伸,不會和里面的重疊。如下圖:
還有,當文字在左半圓時,如果不做特殊處理,文字旋轉會導致文字大頭朝下,閱讀起來有把脖子歪斷的風險。所以應該動態判斷,如果文字在左側,應該文字再增加旋轉180度。同時左側的文字對齊也要特殊考慮,應該變成右對齊,才能保持徑向的整齊一致。
文字還有一個細節就是顏色和陰影的問題。不使用陰影,單純的使用顏色(例如白色),則在一些方向上的節點的文字會看不清楚,因為我們做的是彩虹爆炸圖,各個方向顏色都不一樣,而且還會隨著圈數增加而變淡顏色,所以幾乎不可能用一個固定的顏色(例如白色或黑色)能保證文字在所有地方都能和node顏色搭配并看清楚。所以思來想去還是使用了陰影效果。
聯想了一下我們看美劇時候的字幕,似乎也是同樣的問題。視頻字幕要顯示在千變萬化的視頻場景里面,視頻場景的顏色完全隨機出現無從知曉,要想讓字幕看清楚,必然也會想一些辦法解決。我們仔細觀察一下視頻字幕:
仔細觀察,字幕是白色文字加了一圈黑色外框,這樣就不怕任何場景了。我們在文字定義時也模擬一下,設置陰影和陰影偏移試一試:
fill:'white',
shadow: {
offsetX: 2,
offsetY: 2,
blur: 4,
color: 'black',
},
看一下使用前和使用后的效果對比:
使用陰影后不但文字更清晰了,而且也增加了立體感,效果還是不錯的。下面圖顯示在應用在節點上的效果:
可見不論什么顏色,都能比較好的勾勒出文字輪廓,保持清晰可讀。
三、生成彩虹顏色
關于顏色,是一個有趣的話題。對于廣大程序猿來說,顏色是一個既簡單又困難的東西。我們隨手就能寫下’red’, ‘green’, ‘orange’, ‘yellow’這樣的色彩斑斕的顏色,還能保證沒有語法錯誤;我們還會寫’#FF55AA’、’#0c0’、’RGB(0,204,0)’、’ RGB(0%,80%,0%)’這樣的各種顏色寫法;我們也明白RGBA的含義和用途。但是,我們很少能把一個demo寫的顏色很好看、很搭配。關于顏色和配色以后再專門討論。這里我們只想自動生成一圈彩虹一樣的顏色。用我們熟悉的RGB方法好像比較困難了。于是想起了那個HSV的顏色定義方法,它貌似很適合解決這個問題。
HSV顏色模型定義了色調H、飽和度S和亮度V,由A. R. Smith在1978年創建的一種顏色空間。其中H用一圈360度表示所有顏色,從紅色開始按逆時針方向計算,紅色為0度。飽和度S從0到1,越大越飽和。亮度V從0到255(也可以轉換為從0到1,方便使用),越大越明亮,越小越暗淡。
Js里面并沒有直接處理HSV顏色的函數。不過用下面的代碼很方便可以從hsv轉為rgb:
寫一個對應的js函數也很簡單:
/* h, s, v (0 ~ 1) */
function getHSVColor(h, s, v) {
var r, g, b, i, f, p, q, t;
if (h && s === undefined && v === undefined) {
s = h.s, v = h.v, h = h.h;
}
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
var rgb='#'+toHex(r * 255)+toHex(g * 255)+toHex(b * 255);
return rgb;
}
再回到我們的彩虹爆炸圖。每一個節點對應的所在角度(中心角度)決定了它自己的顏色值。所以,我們可以直接根據這個角度得到顏色的h。然后,為了讓彩虹逐漸一圈一圈變淡,再把s飽和度從1逐圈遞減(例如0.1),產生變淡的效果。為了防止圈太多最后看不清,減到0.2到0.3左右可以停止遞減。
var fromAngle=node.getClient(‘fromAngle’);
var toAngle=node.getClient(‘toAngle’);
var level=node.getClient(‘level’);//節點在第幾圈
var h = (fromAngle+to)/2 % 360 /360; //中心角度,并轉換為弧度
var s = Math.max(0.2, 1-level*0.1);//每圈s遞減0.1,直到0.2為止
var v=1;
var color=getHSVColor(h, s, v);
這樣就獲得了一圈顏色。實驗效果如下:
如果相對某個節點的顏色做特殊處理,例如強制為橙色來凸顯,我們可以在數據中定義時加個標記,設置顏色時候直接使用而不用計算即可。
{name:'浦東新區', value: 2600, color: '#FE9A2E'}
接下來要實現鼠標劃過節點,自動計算路徑、高亮路徑節點、暗淡非路徑節點。為了方便路徑尋找,程序把每個節點的下一圈子數據定義為子節點,子節點通過getParent函數可以直接獲得父對象。這樣,通過不斷getParent就可以獲得整個路徑上的節點,并修改其顏色為預設顏色,實現高亮效果:
var node=highlightedNode;
while(node){
node.setClient(‘color’, node.getClient(‘color.original’));
node=node.getParent;
}
對于非路徑節點的顏色,可以設置為預設顏色但飽和度為0.1的淡顏色 ,讓它變淡,以便突出高亮路徑:
var color = getHSVColor(h, 0.1, v);
node.setClient(‘color’, color);
四、動畫效果
最后,為了圖形更生動,使用了一些動畫效果。首先想到的就是圖形出來時候,用動畫從小到大發散開來,會很動感。這樣做需要用動畫函數來驅動每一個節點的半徑位置,從0增加到所在的半徑位置,如果大家一起設置,整個圖就會動起來。這里用了一個動畫函數來驅動,并使用了網上常用的easing函數來控制,避免線性的動畫太死板:
new Animate({
from: 0,
to: 1,
dur: 3000+level*100,
easing: 'elasticOut',
onUpdate: function (value) {
node.setLocation('pie.location’, value);
},
}).play;
上面定義的動畫,用3秒鐘跑完,用'elasticOut'的easing方式。每一幀,修改node的位置信息。這樣就完成了橡皮筋一樣的環形彈出散開效果。
另外,導航條的出來也比較突兀,這里也使用一下動畫,讓它從左到右慢慢伸出:
new Animate({
from: {x:x1, y:y1},
to: {x:x2, y:y2},
delay:50,
type: 'point',
dur: 1000,
easing: 'bounceOut',
onUpdate: function (value) {
node.setCenterLocation(value.x, value.y);
和上一個動畫的不同之處在于這里使用了{x、y}的point結構,每一幀直接更新節點位置。同時設置了50毫秒的delay,讓動畫有一點點粘性停滯,不至于太突兀。效果不錯。
至此,彩虹爆炸圖基本上就做的差不多了。使用起來也很簡單,只要準備一些json數據就可以了,下面是一些有趣的數據做出來的效果。感興趣的同學可以到這里索取代碼。
實際應用在項目中的示意圖。如果你也希望項目中用一下彩虹爆炸圖,歡迎給我發郵件索取:info@servasoft.com
掃推薦微信:中國大數據
推薦理由:一手新鮮,絕對干貨
敗是通往成功的橋梁
Form中的幾種輸入類型
<input type="email" multiple>
可以輸入多個email
<input type="number" min="-4" max="12">
限定數字大小
<input type="number" step="2">
限定增減幅度
<input type="file" accept="image/*">
文件輸入,只接受圖片文件
兩種button的寫法
<input type="button" value="My Button">
<button>My Button</button>
后一種寫法的好處是可以給文件添加style
optgroup 給select的option分類
Form中用到的屬性
type,name,id, for,value,checked,selected,
placeholder,min,max,step,maxlength,
multiple,pattern,required
<label for="idname"></label>
<input type="text" disabled>
不能修改,不會提交到服務器
<input type="text" readonly value="value">
不能修改,會提交到服務器
<input type="text" hidden value ="value">
用戶看不見,會提交到服務器
<input type="text" pattern="[A-Z]{3}">
正則表達式驗證輸入模式
Form的樣式
1, input[type="date"] +label{
color:orange;
}
將輸入類型為日期的標簽文字變為橙色
2, form中的不同type的input,即使有相同的寬度,最后顯示出來也不是一樣寬,是因為默認的盒模型是content-size,解決的辦法是修改為border-box
input, textarea, select {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
3,通常的樣式寫法對checkbox不起作用,變通的方法有兩種
3.1)用label標簽checkboxbox標簽包裹起來,再針對label撰寫樣式
<label for="blue"><input id="blue" name="fav-color" type="checkbox" value="blue"> blue</label>
3.2)讓checkbox透明,然后針對checked和默認狀態應用不同的背景圖片
input[type="checkbox"] + label {
background: url(checkbox-empty.png) left center no-repeat;
background-size: 1em 1em;
padding-left: 1.5em;
margin-left: -1.5em;
}
input[type="checkbox"]:checked + label {
background: url(checkbox-checked.png) left center no-repeat;
background-size: 1em 1em;
使用背景圖片的checkbox
3.3)應用樣式讓checkbox看起來像按鈕
input[type="checkbox"] {
opacity: 0;
width: 0;
margin: 0;
}
input[type="checkbox"] + label {
border: 2px solid #138d75;
background-color: #e9f7ef;
padding: 4px 10px;
border-radius: 7px;
display: inline-block;
width: 4em;
text-align: center;
}
input[type="checkbox"]:checked + label {
border-color: #a93226;
background-color: #f5cba7;
font-weight: bold;
}
像按鈕的checkbox
4.應用偽類(pseudo class)
:checked :hover :active :valid :invalid :inrange :out-of-range :required :optional
*請認真填寫需求信息,我們會在24小時內與您取得聯系。