更新版本 hexo 2.8 to 3.1 惡夢

Parser Error

主要原因是因為 hexo 3.0 引入新的渲染引擎 mozilla/Nunjucks 的問題。

由於有 Nunjucks 的關係,有一些渲染方式要改變寫法。

Plugin Update

很多指令都模組化,所以要個別安裝需要的操作,並且插件一定要透過 npm 安裝,寫入到 blog/package.json 才會被接受。

1
2
3
$ npm install hexo-generator-sitemap --save 
$ npm install hexo-generator-feed --save
$ npm install hexo-deployer-git --save

由於 mozilla/Nunjucks 的關係,改變最麻煩的是 tag plugin 的名稱,例如 rawblock -> rawmath-block -> math 的更動,因此要寫個程式進行轉換。

由於 latex 的緣故,hexo-math 這個 plugin 需要更動,以免 Nunjucks 解析時發生錯誤,強制讓 inline 的寫法有對齊,所以我把 hexo-math 做了客製化修改。

1
2
3
4
5
6
7
hexo.extend.tag.register("math", function(args, content) {
var result;
result = "<span>$" + content + "$</span><!-- Has MathJax -->";
return result;
}, {
ends: true
});

並且取消自動注入,因為目前的 hexo server 在修改文章時,效能不佳,以下代碼是 hexo-math 在用自動注入的部分呼叫函數,若使用這個函數,速度拖累很多。

1
2
3
hexo.extend.filter.register("after_render:html", function(src, data) {
return src;
}

New Feature

分頁支持

1
2
$ npm install hexo-generator-archive --save 
$ npm install hexo-generator-tag --save

在這幾個地方增加分頁設計,讓一次載入大量資料的需求減少。

Browser

開啟 hexo server 時,若更動文章內容,刷新速度變得非常慢,並且會造成 nodejs 狂吃 CPU 和 memory 同時也重新渲染所有文章。

Setting

blog/__config.yml 也做了些調整,簡化不少設定檔,若不特別需要,則不會出現。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
archive_generator:
per_page: 20
yearly: true
monthly: false
category_generator:
per_page: 10
tag_generator:
per_page: 20

browser_sync:
port: 4000
browser: "google chrome"
open: false

server:
port: 4000
log: true
ip: 127.0.0.1

以及在過去版本一直被我遺忘的 highlight 設定,要把 tab 換成四個空白,有時候貼上常常會發生 tab 變成四個空白的解析,現在版本先關閉自動偵測 highlight,官方說那裏解析速度上有問題。

1
2
3
4
5
highlight:
enable: true
line_number: true
auto_detect: false
tab_replace: " "

這裡還是有個問題,highlight.js 不處理以下情況

1
<tab><space><space><space><space><tab>

最後一個 tab 將不會被轉換,也就是只有行首的 tab 會自動轉換,想必是對齊部分不容易寫。

Read More +

部落格架構更新與狀態

當前使用主題為 hexo-theme-landscape,早期使用 pacman,自己修改成 moman 一個黑色系主題,但是隨著文章數量的增加,pacman 樣板的生成速度越來越慢,更新 hexo 後,發現 landscape 的速度異常地快,於是將整個樣板配色轉移到 landscape。

想打包我嗎?直接至 morris821028/morris821028.github.io 下載即可。還是即時的版本呢,可惜地是無法再用 hexo 繼續產生文章,也就是要新增一篇文章是困難的。這裡有純草稿 morris821028/HexoBlog 提供,偶爾會更新,這偶爾想必是挺久的日子。往後要在其他主題下部屬也不是問題!

反應速度

由於 hexo 本身就是 靜態網頁 的框架,所以不會有資料庫調用問題,反應速度理所當然會快很多。為了增加網頁的反應速度,要把不少重複的框捨去,siderbar 訊息最小化!

原理就當作編寫 markdown,利用 hexo 編譯成 html 後上傳。跟一般寫 cpp 程式很像呢!

  • Tags 搬移到額外的分頁,由於每一個頁面下都會出現在 sidebar,無用訊息量太多導致載入速度拉慢,不要忽視使用者經驗 (UX)!

額外分頁的建立

/blog/source/tags/index.md
1
2
3
title: Tags
layout: tags
---

hexo 配置是採用每一個 markdown 上的參數 layout。接著只需要在主題下寫一個 /themes/landscape/layout/tags.ejs,到時候會直接經過 layout.ejs 呼叫 tags.ejs

接著就可以在 http://localhost:4000/tags/ 下看到自己想要頁面,一般而言不會有這一頁,會呈現 NOT FOUND 404 狀態。

主題設定檔

既然有用 font awesome ,覺得在默認主題下 Home 顯得不太夠力且明瞭,直接點擊 logo 也是能返回主頁。於是把設定檔案改成以下內容,搭配圖示和文字描述,希望這種方式會更脫離死板的配置。

/themes/landscape/_config.yml
1
2
3
4
5
6
7
menu:
- {name: Home, path: /, class: icon-home, layout: 1}
- {name: About, path: /about, class: icon-user, layout: 2}
- {name: Archives, path: /archives, class: icon-archive, layout: 2}
- {name: Tags, path: /tags, class: icon-tags, layout: 2}
- {name: Pictures, path: /picture, class: icon-camera, layout: 2}
- {name: Works, path: /works, class: icon-trophy, layout: 2}

接著在 header.ejs 下修改一下內容,畢竟參數上有點調整。

/themes/landscape/layout/_partial/header.ejs
1
2
3
4
5
6
7
8
9
10
<a id="main-nav-toggle" class="nav-icon"></a>
<% for (var i in theme.menu){ %>
<% if (theme.menu[i].layout && theme.menu[i].layout == 1) { %>
<a class="main-nav-link" href="<%- url_for(theme.menu[i].path) %>"><i class=<%= theme.menu[i].class %> title='<%= theme.menu[i].name %>'></i></a>
<% } else if (theme.menu[i].layout && theme.menu[i].layout == 2) { %>
<a class="main-nav-link" href="<%- url_for(theme.menu[i].path) %>"><i class=<%= theme.menu[i].class %> title='<%= theme.menu[i].name %>'></i> <%= theme.menu[i].name %></a>
<% } else { %>
<a class="main-nav-link" href="<%- url_for(theme.menu[i].path) %>"><%= theme.menu[i].name %></a>
<% } %>
<% } %>

Ukagaka

由於 史蒂芙 任務結束,現在由 派拉斯 接管,她們的個人照片都可以在 Pictures 中見到哦!

關於 Ukagaka 的製作,目前把音樂坑解決,將可以在功能列表中看到音樂撥放功能!實作採用 HTML5 + js 的方式,並且把圖片部分全部用 font awesome 解決,功能還不夠齊全,希望已經能符合最低需求。

其實很早就用 HTML5 + js 弄過音樂撥放,但遲遲沒有嫁入到 Ukagaka 中。

音樂部份的免空是個問題,目前用容量較小的音樂檔案放置 hexo 中一起部屬。

至於 AIML 的 AI 智能對話部分,之前停留在 JAVA 那邊,暫且還不會去完成她,其一原因是必須轉成比較好跑在 server 上面的版本,並且能應付多人單一的狀態保留。如果不寫 web socket,必然要透過 ip 進行辨識,至少能記住當前使用者的名稱 (如果有教導 Ukagaka 的話)。

根據之前用 nodejs 寫 web socket 完成 chat room 的感想,有一部分是相當難理解的 js,同時存在瀏覽器要解析的 js 中,模組部分很好奇實際運作原理,詳細還沒有理解。

Read More +

Nodejs upload server 簡易上傳下載

Github upload-server

上傳的設定,要特別注意公開讀取的問題,採用 express 架構下,如果設定再 public 資料夾下,則任何人上傳都可以被任何人讀取。

中間有遇到一個問題 到底能不能限制使用者上傳速度

上網查了很多資料,不管是從前端還是後端,前端限制基本上沒有任何用處,後端則在這個架構中沒有找到相關的 API 限制,從作業系統中下手,則必須要找到 nodejs 執行緒中的網路限制。

奮鬥好幾天,仍然沒有這個解決方案。

Read More +

Simple Works Gallery

起源

鄰近要大學推研究所的時刻,自己做過什麼作品來說,對於推甄時相當重要,一直都沒有好好整理過自己做過什麼,有多少能拿出檯面的項目,現在發現除了 ACM 解題和曾經幫別人寫的作業以外,沒有幾項可以吸引到人的。一樣做一個 hexo tag plugin,將作品展示櫃用一個 generator.js 的方式,將展示櫃內容呈現出來,傳入的方式為 json。同樣地,你可以在這個部落格上方的 Works 看到相關作品介紹。

下載

Download on Github

使用

仍然以 github 上的 project 為優先版本。以下的內容也許不是最新版本。

html

當前採用 json 的原因是因為可以藉由較簡單的方式,以及往後可能使用 ajax 的方式運作。這樣彈性也許會比較大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<script type="text/works-gallery">
{
"works" : [
{
"title": "Chat Room Application",
"cover": "http://i.imgur.com/oUO30I6.jpg",
"description": "計算機網路-一個簡單的網路聊天室<br/> Socket programming practice (Java)",
"download": ["https://github.com/morris821028/hw-ChatRoom"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=7ExCn1ipKeg"]
},
{
"title": "Magic Circle",
"cover": "http://i.imgur.com/Fv8ebBY.jpg",
"description": "jquery-magic-circle, write funny for friends",
"download": ["https://github.com/morris821028/jquery-magic-circle"],
"demo": ["http://morris821028.github.io/jquery-magic-circle"],
"video": ["https://www.youtube.com/watch?v=TWqmGeuIJLo"]
},
{
"title": "Hex Image Gallery",
"cover": "http://i.imgur.com/VMf2G1v.png",
"description": "create beautiful hexagon shapes with CSS3, jquery, write funny for friends",
"download": ["https://github.com/morris821028/jquery-hex-gallery"],
"demo": ["http://morris821028.github.io/jquery-hex-gallery/"],
"video": []
}
]
}
</script>

css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
.wg-container
{
background: none repeat scroll 0% 0% #2d2d2d;
border-color: #ddd;
border-style: solid;
border-width: 1px 0;
color: #ccc;
line-height: 25.6px;
margin: 0 -20px;
overflow: auto;
padding: 15px 20px;
position: relative;
text-align: center;
width: 100%;
z-index: 0;
}
.wg-container hr
{
background: #333;
background-image: -moz-linear-gradient(to right, #333, #ccc, #333);
background-image: -ms-linear-gradient(to right, #333, #ccc, #333);
background-image: -o-linear-gradient(to right, #333, #ccc, #333);
background-image: -webkit-linear-gradient(to right, #333, #ccc, #333);
border: 0;
height: 5px;
}
.wg-item
{
list-style: none;
}
.wg-item .inner
{
height: 160px;
}
.wg-item li
{
display: block;
float: left;
margin: 16px;
width: 45%;
}
.wg-item li .header
{
border: 4px solid #b4b4b4;
box-shadow: 1px 1px 1px 1px #ccc;
cursor: pointer;
float: left;
height: 256px;
margin: 5px;
moz-box-shadow: 1px 1px 1px 1px #ccc;
overflow: hidden;
position: relative;
webkit-box-shadow: 1px 1px 1px 1px #ccc;
width: 100%;
}
.wg-item li .header:hover a
{
moz-transform: scale(1.2);
ms-transform: scale(1.2);
o-transform: scale(1.2);
transform: scale(1.2);
webkit-transform: scale(1.2);
}
.wg-item li .header a
{
left: 0;
moz-transition: all 300ms ease-out;
ms-transition: all 300ms ease-out;
o-transition: all 300ms ease-out;
position: absolute;
transition: all 300ms ease-out;
webkit-transition: all 300ms ease-out;
}
.wg-item li .image
{
background-size: cover;
display: block;
height: 95%;
moz-background-size: cover;
padding: .5em;
webkit-background-size: cover;
width: 100%;
}
.wg-item li h3
{
font-size: 24px;
font-weight: normal;
line-height: 22px;
margin-bottom: 10px;
margin-top: 10px;
text-align: center;
}
.wg-item li h3 a:hover
{
text-decoration: none;
}
.wg-item li ul.links
{
float: right;
}
.wg-item li .links li
{
display: block;
margin-left: 5px;
margin-right: 0 !important;
width: initial;
}
.wg-item li .links li a
{
background: #65a9d7;
border-radius: 5px;
box-shadow: 0 1px 0 #000;
color: #fff;
font-family: Georgia,Serif;
font-size: 16px;
padding: 5.5px 11px;
text-decoration: none;
text-shadow: 0 1px 0 rgba(0,0,0,0.4);
vertical-align: middle;
webkit-border-radius: 5px;
webkit-box-shadow: 0 1px 0 #000;
}
.wg-item .description
{
font-size: 16px;
margin: .2em 0;
text-align: left;
}

hexo plugin

我已經把產生方式寫在 hexo-tag-oj 裡頭,下載使用 hexo-tag-plugin

不過相關的 js 還有 css 要自己擺放,請參考上面的描述項目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{\% ojblock works \%}
{
"works" : [
{
"title": "Chat Room Application",
"cover": "http://i.imgur.com/oUO30I6.jpg",
"description": "計算機網路-一個簡單的網路聊天室<br/> Socket programming practice (Java)",
"download": ["https://github.com/morris821028/hw-ChatRoom"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=7ExCn1ipKeg"]
},
{
"title": "Fuzzy System",
"cover": "http://i.imgur.com/C44Hbrg.png",
"description": "計算型智慧-廣義型演算法最佳化<br/>Car simulation implements PSO, GA, and fuzzy system (Java)",
"download": ["https://github.com/morris821028/hw-FuzzySystem"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=kt2mu679elU"]
},
{
"title": "UML Editor",
"cover": "http://i.imgur.com/JCCweao.png",
"description": "物件導向程式設計-UML 編輯器架構設計<br/>OO design practice & make UML Editor (Java)",
"download": ["https://github.com/morris821028/hw-UML-Editor"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=DKDFy6uFk8Y"]
},
{
"title": "MapleStory 遊戲仿作",
"cover": "http://i.imgur.com/i62nNgG.png",
"description": "由於硬碟損壞代碼沒有救回來,只剩下舊版,收錄於 chat room 製作中的一環,由於課程時間不夠,沒有做完。 (Java)",
"download": ["https://github.com/morris821028/hw-ChatRoom"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=TWqmGeuIJLo"]
},
{
"title": "Magic Circle",
"cover": "http://i.imgur.com/Fv8ebBY.jpg",
"description": "jquery-magic-circle, write funny for friends",
"download": ["https://github.com/morris821028/jquery-magic-circle"],
"demo": ["http://morris821028.github.io/jquery-magic-circle"],
"video": ["https://www.youtube.com/watch?v=TWqmGeuIJLo"]
},
{
"title": "Hex Image Gallery",
"cover": "http://i.imgur.com/VMf2G1v.png",
"description": "create beautiful hexagon shapes with CSS3, jquery, write funny for friends",
"download": ["https://github.com/morris821028/jquery-hex-gallery"],
"demo": ["http://morris821028.github.io/jquery-hex-gallery/"],
"video": []
}
]
}
{\% endojblock \%}
Read More +

Jquery Hex Image Gallery

起源

六角形的圖片廊道,一開始給定的是提案是做出一個圖片展示櫃,可是想到要放在這個 hexo 部落格,要做到類似的相簿功能其實是很麻煩的,還有必須要關聯 generator 的產生方式,才能製作出相對的 static website,那只好將項目弄成單獨一頁,而這一頁要怎麼製作其實很難捉摸。失敗的設計總是這樣子開始的。

由於圖片量太大的話,變成一開始載入速度會太慢,因此找來了 lazyload.js,但是跟展示窗口銜接上仍有一些問題,無法適時地反映操作,所以需要 call back 操作,否則圖片會載入失敗。再者是原本六角 CSS 問題,找來網路上提供的 CSS,發現更換大型圖片的時候,會造成圖片顯示不正常,因此在這一塊費時了相當長的時間來符合預期的操作。

此項目已經放在我的 Github 上面,同時你也可以在這個 blog 上方的 Picture 中看到 demo,萬萬沒想到居然有人願意 Star 標記,真的是相當令人動容啊,從來沒想過有人對於這樣的蠢製作感興趣。

下載

Download on Github

Demo

使用

仍然以 github 上的 project 為優先版本。以下的內容也許不是最新版本。

html

為了方便產生器運行,產生方式採用 json 的生成方式。相關的動畫製作引入

  • jquery.lazyload.js 圖片動態載入
  • jquery.als.link-1.6.js 幻燈片的展示窗口 (經過修改,來完成跳轉操作)

當前採用 json 的原因是因為可以藉由較簡單的方式,以及往後可能使用 ajax 的方式運作。這樣彈性也許會比較大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
<script src="js/jquery.hex.gallery.js" type="text/javascript"></script>
<script src="js/jquery.lazyload.js" type="text/javascript"></script>
<script src="js/jquery.als.link-1.6.js" type="text/javascript"></script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
...
<script type="text/hex-gallery">
{
"album" : [
{
"cover": {"title": "<h4>THEME</h4><hr /><p>Stephanie Dola</p>", "class": "hex-1"},
"photo": [
{"imgur": "http://i.imgur.com/yIoACHc.gif"},
{"imgur": "http://i.imgur.com/uINck6K.gif"},
{"imgur": "http://i.imgur.com/zOZJEex.gif"}
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>萌~萌~哒~</p>", "class": "hex-2"},
"photo": [
{"imgur": "http://i.imgur.com/YSmWA3g.gif"},
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>其他</p>", "class": "hex-3"},
"photo": [
{"imgur": "http://i.imgur.com/vpKzynV.gif"},
{"imgur": "http://i.imgur.com/rctEEyS.gif"}
]
}
]
}
</script>

...
</body>
</html>

css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
.hex-container
{
display: block;
height: 320px;
position: relative;
width: 800px;
}
.hex
{
animation: animatedBackground 10s linear infinite;
background-color: #ccc;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: cover;
float: left;
font-family: Georgia,"Microsoft YaHei","Times New Roman",serif;
font-weight: bold;
height: 86px;
margin: 25px 5px;
moz-animation: animatedBackground 10s linear infinite;
moz-background-size: cover;
ms-animation: animatedBackground 10s linear infinite;
position: relative;
text-align: center;
webkit-animation: animatedBackground 10s linear infinite;
webkit-background-size: cover;
width: 150px;
zoom: 1;
}
.hex.hex-gap
{
margin-left: 86px;
}
.hex a
{
display: block;
height: 100%;
left: 0;
position: absolute;
text-indent: -9999em;
top: 0;
width: 100%;
}
.hex .corner-1
{
moz-transform: rotate(60deg);
ms-transform: rotate(60deg);
o-transform: rotate(60deg);
transform: rotate(60deg);
webkit-transform: rotate(60deg);
}
.hex .corner-1:before
{
moz-transform: rotate(-60deg) translate(-87px,0);
moz-transform-origin: 0 0;
ms-transform: rotate(-60deg) translate(-87px,0);
ms-transform-origin: 0 0;
o-transform: rotate(-60deg) translate(-87px,0);
o-transform-origin: 0 0;
transform: rotate(-60deg) translate(-87px,0);
transform-origin: 0 0;
webkit-transform: rotate(-60deg) translate(-87px,0);
webkit-transform-origin: 0 0;
}
.hex .corner-2
{
moz-transform: rotate(-60deg);
ms-transform: rotate(-60deg);
o-transform: rotate(-60deg);
transform: rotate(-60deg);
webkit-transform: rotate(-60deg);
}
.hex .corner-2:before
{
bottom: 0;
moz-transform: rotate(60deg) translate(-44px,-12px);
ms-transform: rotate(60deg) translate(-44px,-12px);
o-transform: rotate(60deg) translate(-44px,-12px);
transform: rotate(60deg) translate(-44px,-12px);
webkit-transform: rotate(60deg) translate(-44px,-12px);
}
.hex .corner-3
{
moz-transform: rotate(0);
ms-transform: rotate(0);
o-transform: rotate(0);
transform: rotate(0);
webkit-transform: rotate(0);
}
.hex .corner-3:before
{
moz-transform: rotate(0) translate(-12px,-44px);
ms-transform: rotate(0) translate(-12px,-44px);
o-transform: rotate(0) translate(-12px,-44px);
transform: rotate(0) translate(-12px,-44px);
webkit-transform: rotate(0) translate(-12px,-44px);
}
.hex .inner
{
color: #eee;
position: absolute;
right: 0;
top: 0;
display: inline;
float: left;
width: 98.3333%;
margin: 0px 0.833333%;
}
.hex .inner a
{
color: #fff;
text-indent: 0;
}
.hex h4
{
margin: 0;
}
.hex hr
{
border: 0;
border-top: 1px solid #eee;
margin: 15px auto;
width: 60%;
}
.hex p
{
font-size: 22px;
margin: 0 auto;
width: 80%;
}
.hex.hex-1
{
background: #74cddb;
}
.hex.hex-2
{
background: #f00;
}
.hex.hex-3
{
background: #80b971;
}
.hex.hex-back
{
background: #80b971;
}
.hex.hex-back a
{
padding: 0 4px;
}
.hex .corner-1,.hex .corner-2,.hex .corner-3
{
backface-visibility: hidden;
background: inherit;
height: 100%;
left: 0;
moz-backface-visibility: hidden;
ms-backface-visibility: hidden;
o-backface-visibility: hidden;
overflow: hidden;
position: absolute;
top: 0;
webkit-backface-visibility: hidden;
width: 100%;
}
.hex .corner-1:before,.hex .corner-2:before,.hex .corner-3:before
{
backface-visibility: hidden;
background: inherit;
background-repeat: no-repeat;
content: '';
height: 173px;
left: 0;
moz-backface-visibility: hidden;
ms-backface-visibility: hidden;
o-backface-visibility: hidden;
position: absolute;
top: 0;
webkit-backface-visibility: hidden;
width: 173px;
}
.hex-caption
{
background-color: rgba(0,0,0,0.5);
color: #fff;
left: 0;
moz-transition: all 300ms ease-out;
ms-transition: all 300ms ease-out;
o-transition: all 300ms ease-out;
position: absolute;
transition: all 300ms ease-out;
webkit-transition: all 300ms ease-out;
}
.hex:hover .hex-simple-caption
{
moz-transform: translateY(-100%);
ms-transform: translateY(-100%);
o-transform: translateY(-100%);
transform: translateY(-100%);
visibility: visible;
webkit-transform: translateY(-100%);
}
.hex-simple-caption
{
bottom: -60px;
display: block;
height: 30px;
line-height: 25pt;
text-align: center;
visibility: hidden;
width: 100%;
}
.hex-background
{
left: -80px;
position: absolute;
top: -136px;
width: 900px;
z-index: -1;
}
.hex-background .hex
{
background-color: #708090;
}
.als-viewport
{
height: 390px;
margin: 0 auto;
overflow: hidden;
position: relative;
}
.als-wrapper
{
list-style: none;
position: relative;
}
.als-item
{
cursor: pointer;
display: block;
float: left;
position: relative;
text-align: center;
}
.als-prev,.als-next
{
clear: both;
cursor: pointer;
position: absolute;
}
.als-container
{
background: none repeat scroll 0% 0% #2d2d2d;
border-color: #ddd;
border-style: solid;
border-width: 1px 0;
color: #ccc;
line-height: 25.6px;
margin: 0 -20px;
overflow: auto;
padding: 15px 20px;
position: relative;
text-align: center;
width: 100%;
z-index: 0;
}
.als-container .als-item
{
display: block;
margin: 0 5px;
margin: 0 auto;
min-height: 120px;
min-width: 100px;
padding: 4px 0;
text-align: center;
vertical-align: middle;
}
.als-container .als-prev
{
font-size: 30px;
left: 30px;
}
.als-container .als-next
{
font-size: 30px;
right: 30px;
}
.als-container .als-prev,.als-container .als-next
{
top: 175px;
}
.icon-arrow-left
{
display:inline-block;
width:32px;
height:32px;
line-height:32px;
border-top:3px solid #aaa;
border-right:3px solid #aaa;
-ms-transform:rotate(225deg);
-moz-transform:rotate(225deg);
-webkit-transform:rotate(225deg);
transform:rotate(225deg);
}
.icon-arrow-right
{
display:inline-block;
width:32px;
height:32px;
line-height:32px;
border-top:3px solid #aaa;
border-right:3px solid #aaa;
-ms-transform:rotate(45deg);
-moz-transform:rotate(45deg);
-webkit-transform:rotate(45deg);
transform:rotate(45deg);
}

架構

hex page

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="hex-container">
<div class="hex-background">
<div class="hex hex-gap" style="background-image: url();">
<div class="corner-1"></div>
<div class="corner-2"></div>
<div class="corner-3"></div>
<div class="inner"></div>
</div>
<div class="hex" style="background-image: url();">
<div class="corner-1"></div>
<div class="corner-2"></div>
<div class="corner-3"></div>
<div class="inner"></div>
</div>
...
</div>
</div>

原本網路提供 hex 只有 corner-1corner-2,這樣的做法無法產生 cover 的圖示,因此這裡增加 corner-3,但仍然會看到一條一條格線在斜邊上,不過已經相當足夠。

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="als-container" id="als-container_0" data-id="als-container_0">
<div class="als-viewport" data-id="als-viewport_0" style="width: 800px; height: 328px;">
<ul class="als-wrapper" data-id="als-wrapper_0" style="width: 4800px; height: 328px;">
<li class="als-item" data-linkid="-6" id="als-item_0_0" style="left: 0px;">
insert hex page
</li>
<li class="als-item" data-linkid="-1" id="als-item_0_0" style="left: 0px;">
insert hex page
</li>
...
</ul>
</div>
</div>

根據原本的 jquery.als-1.6.js 並沒有提供跳轉的操作,也就是說不能直接 shift 到指定位置,只能倚靠往左和往右的觸發,因此特別自己增加了 data-linkid 為操作手段。

hexo blog plugin

我已經把產生方式寫在 hexo-tag-oj 裡頭,下載使用 hexo-tag-plugin

不過相關的 js 還有 css 要自己擺放,請參考上面的描述項目。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{\% ojblock hex \%}
{
"album" : [
{
"cover": {"title": "<h4>THEME</h4><hr /><p>Stephanie Dola</p>", "class": "hex-1"},
"photo": [
{"imgur": "http://i.imgur.com/yIoACHc.gif"},
{"imgur": "http://i.imgur.com/4pzxseN.jpg"}
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>萌~萌~哒~</p>", "class": "hex-2"},
"photo": [
{"imgur": "http://i.imgur.com/YSmWA3g.gif"},
{"imgur": "http://i.imgur.com/5IHR8bQ.gif"}
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>其他</p>", "class": "hex-3"},
"photo": [
{"imgur": "http://i.imgur.com/vpKzynV.gif"},
{"imgur": "http://i.imgur.com/rctEEyS.gif"}
]
}
]
}
{\% endojblock \%}

#

Read More +

製作 hexo-tag-oj

Demo UVa OJ,標製作只有自己會用的 TAG,詳細請查閱 Github。

  • 目前 javascript 存放在 Google Drive
  • 每一篇限用一個 tag,無法解決多重匯入問題。如果硬是要匯入也行,只是會重複好幾次。
  • 請確保每個頁面的 <head> 有引入 jquery 1.7.0 以上的版本。

順手測一下

GitHub jQuery Repo Widget

TEST

事實上只是將上述的 jQuery 修改而已。

Read More +

Hexo Math Plugin

展示

A hexo plugin that uses MathJax to render math equations.
Simple inline $a = b + c$.

1
Simple inline {% math %}a = b + c{% endmath %}.

This equation$\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1$ is inline.

1
This equation{% math %}\cos 2\theta = \cos^2 \theta - \sin^2 \theta =  2 \cos^2 \theta - 1 {% endmath %} is inline.
$$\begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ \dot{z} & = -\beta z + xy \end{aligned}$$ {% math %} \begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ \dot{z} & = -\beta z + xy \end{aligned} {% endmath %}

更多

http://catx.me/2014/03/09/hexo-mathjax-plugin/

Read More +

HTML5 Music Player (本地拖曳撥放)

代碼起源

tommy351 提供的。基於 HTML5 和 JQuery 運行的撥放器,HTML5 支持 .mp3, .wav, .ogg 這三個種音樂格式的撥放。

HTML5 <audio> 支持音樂撥放,撥放種類有限,而且 HTML5 不知道穩定了沒。

  • 本次挑戰的項目
    • 增加 拖曳檔案 的撥放
    • 拖曳檔案 和 拖曳資料夾 的摸索
    • HTML5 圍觀

修改

demo
如上圖,最後一個檔案 mo - 45. not yet.mp3 是拖曳上傳的內容。

歷程

  • 增加本地拖曳撥放,操作方式為將本地 mp3 檔案上傳

檔案能知道的資訊有限

  • name 取得檔案名稱,如果需要做副檔名檢查,可利用它。
  • size 取得檔案大小 (bytes)。
  • type 取得檔案的 MIME 型別 (若無法對應會傳回空白)。

因為安全性,所以得不到路徑資訊,也就是不能隨便去掃描別人的本地資料。因此要完成資料夾下的所有檔案獲取會有困難。

其實瀏覽器本上就會支持檔案拖曳,並且在新分頁上顯示資訊,如果要避免瀏覽器自己開啟檔案,則使用 evt.stopPropagation() 將 drag 相關事件關閉,也就是說在當前頁面的 drag 事件都不會被瀏覽器知曉。

後記

  • 對於 .mp3 檔案要自動獲得專輯封面可能嗎?
    請參考 這裡

    1
    2
    3
    4
    5
    6
    7
    8
    Field      Length    Offsets
    Tag 3 0-2
    Songname 30 3-32
    Artist 30 33-62
    Album 30 63-92
    Year 4 93-96
    Comment 30 97-126
    Genre 1 127

    要自己擠去 parsing 這些資訊還是算了吧。WRYYYYY

  • 對於資料夾整包拖曳操作?HTML5 drag upload folder
    在寫這篇的時候,網路上有 demo,但是只有在 chrome 21 下才有支持,看起來是從瀏覽器 ( 本地軟件 ) 來協助遍歷資料夾下的內容。不然是沒有權限去運行的。

  • 讀取的異步操作 ?
    是的,最近在編寫時常會遇到異步操作,也就是必須全用 callback 來完成,因為讀檔的資訊完成的 callback function 中並沒有 file.name 之類的資訊,如果適用 for(var i in files) 運行,會發生變數找不到的情況,因此用 $.each()reader.onload() 來完成這個操作。

    • onloadstart、onprogress、onload、onabort、onerror 和 onloadend 這幾個可以協助監控上傳資訊,也就是能知曉現在上傳進度 … 等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
var dropbox = document.getElementById("dropbox")

// init event handlers
dropbox.addEventListener("dragenter", dragEnter, false);
dropbox.addEventListener("dragexit", dragExit, false);
dropbox.addEventListener("dragover", dragOver, false);
dropbox.addEventListener("drop", drop, false);

// init the widgets
$("#progressbar").progressbar();

function dragEnter(evt) {
evt.stopPropagation();
evt.preventDefault();
}

function dragExit(evt) {
evt.stopPropagation();
evt.preventDefault();
}

function dragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
}

function drop(evt) {
evt.stopPropagation();
evt.preventDefault();

var files = evt.dataTransfer.files;
var count = files.length;

// Only call the handler if 1 or more files was dropped.
if (count > 0)
handleFiles(files);
}


function handleFiles(files) {
var mp3Files = $.map(files, function(f, i) {
return f.type.indexOf("audio/mp3") == 0 ? f : null;
});

$.each(mp3Files, function(i, file) {
document.getElementById("droplabel").innerHTML = "Processing " + file.name;

var reader = new FileReader();

reader.onload = function(evt) {
$('#playlist').append('<li>' + 'mo' + ' - ' + file.name + '</li>');
playlist.push({
title: file.name,
mp3: evt.target.result
});

$('#playlist li').each(function(i) {
var _i = i;
$(this).on('click', function() {
switchTrack(_i);
});
});
}
// init the reader event handlers
reader.onprogress = handleReaderProgress;
reader.onloadend = handleReaderLoadEnd;

reader.readAsDataURL(file);

});
}

function handleReaderProgress(evt) {
if (evt.lengthComputable) {
var loaded = (evt.loaded / evt.total);

$("#progressbar").progressbar({
value: loaded * 100
});
}
}

function handleReaderLoadEnd(evt) {
$("#progressbar").progressbar({
value: 100
});
}

最後

html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title>Cover Art</title>
<link rel="stylesheet" href="css/stylesheets/style.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
</head>
<body>
<div id="playblock">
<div id="player">
<div class="cover"></div>
<div class="ctrl">
<div class="tag">
<strong>Title</strong>
<span class="artist">Artist</span>
<span class="album">Album</span>
</div>
<div class="control">
<div class="left">
<div class="rewind icon"></div>
<div class="playback icon"></div>
<div class="fastforward icon"></div>
</div>
<div class="volume right">
<div class="mute icon left"></div>
<div class="slider left">
<div class="pace"></div>
</div>
</div>
</div>
<div class="progress">
<div class="slider">
<div class="loaded"></div>
<div class="pace"></div>
</div>
<div class="timer left">0:00</div>
<div class="right">
<div class="repeat icon"></div>
<div class="shuffle icon"></div>
</div>
</div>
</div>
</div>
<div id="dropbox">
<div id="dropctrl">
<span id="droplabel">Drop mp3 file here...</span>
<div id="progressbar"></div>
</div>
<ul id="playlist"></ul>
</div>
</div>
<footer>
Copyright &copy; 2012 <a href="http://zespia.tw">SkyArrow</a>
</footer>

<script src="js/script.js"></script>

</body>
</html>

js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
(function($) {
// Settings
var repeat = localStorage.repeat || 0,
shuffle = localStorage.shuffle || 'false',
continous = true,
autoplay = false,
playlist = [{
title: 'ふわふわ時間',
artist: '桜高軽音部(平沢唯、秋山澪、田井中律、琴吹紬)',
album: 'TVアニメ「けいおん!」劇中歌 - ふわふわ時間',
cover: 'http://dl.dropbox.com/u/5480889/coverart/cover/ふわふわ時間.jpg',
mp3: 'http://dl.dropbox.com/u/5480889/coverart/music/ふわふわ時間.mp3',
ogg: 'http://dl.dropbox.com/u/5480889/coverart/music/ふわふわ時間.ogg'
}, {
title: 'リップシンク',
artist: 'nano.RIPE',
album: '細胞キオク',
cover: 'http://dl.dropbox.com/u/5480889/coverart/cover/リップシンク.jpg',
mp3: 'http://dl.dropbox.com/u/5480889/coverart/music/リップシンク.mp3',
ogg: 'http://dl.dropbox.com/u/5480889/coverart/music/リップシンク.ogg'
}];

for (var i = 0; i < playlist.length; i++) {
var item = playlist[i];
$('#playlist').append('<li>' + item.artist + ' - ' + item.title + '</li>');
}
// Load playlist

var time = new Date(),
currentTrack = shuffle === 'true' ? time.getTime() % playlist.length : 0,
trigger = false,
audio, timeout, isPlaying, playCounts;

var play = function() {
audio.play();
$('.playback').addClass('playing');
timeout = setInterval(updateProgress, 500);
isPlaying = true;
}

var pause = function() {
audio.pause();
$('.playback').removeClass('playing');
clearInterval(updateProgress);
isPlaying = false;
}

// Update progress
var setProgress = function(value) {
var currentSec = parseInt(value % 60) < 10 ? '0' + parseInt(value % 60) : parseInt(value % 60),
ratio = value / audio.duration * 100;

$('.timer').html(parseInt(value / 60) + ':' + currentSec);
$('.progress .pace').css('width', ratio + '%');
$('.progress .slider a').css('left', ratio + '%');
}

var updateProgress = function() {
setProgress(audio.currentTime);
}

// Progress slider
$('.progress .slider').slider({
step: 0.1,
slide: function(event, ui) {
$(this).addClass('enable');
setProgress(audio.duration * ui.value / 100);
clearInterval(timeout);
},
stop: function(event, ui) {
audio.currentTime = audio.duration * ui.value / 100;
$(this).removeClass('enable');
timeout = setInterval(updateProgress, 500);
}
});

// Volume slider
var setVolume = function(value) {
audio.volume = localStorage.volume = value;
$('.volume .pace').css('width', value * 100 + '%');
$('.volume .slider a').css('left', value * 100 + '%');
}

var volume = localStorage.volume || 0.5;
$('.volume .slider').slider({
max: 1,
min: 0,
step: 0.01,
value: volume,
slide: function(event, ui) {
setVolume(ui.value);
$(this).addClass('enable');
$('.mute').removeClass('enable');
},
stop: function() {
$(this).removeClass('enable');
}
}).children('.pace').css('width', volume * 100 + '%');

$('.mute').click(function() {
if ($(this).hasClass('enable')) {
setVolume($(this).data('volume'));
$(this).removeClass('enable');
} else {
$(this).data('volume', audio.volume).addClass('enable');
setVolume(0);
}
});

// Switch track
var switchTrack = function(i) {
if (i < 0) {
track = currentTrack = playlist.length - 1;
} else if (i >= playlist.length) {
track = currentTrack = 0;
} else {
track = i;
}

$('audio').remove();
loadMusic(track);
if (isPlaying == true) play();
}

// Shuffle
var shufflePlay = function() {
var time = new Date(),
lastTrack = currentTrack;
currentTrack = time.getTime() % playlist.length;
if (lastTrack == currentTrack)++currentTrack;
switchTrack(currentTrack);
}

// Fire when track ended
var ended = function() {
pause();
audio.currentTime = 0;
playCounts++;
if (continous == true) isPlaying = true;
if (repeat == 1) {
play();
} else {
if (shuffle === 'true') {
shufflePlay();
} else {
if (repeat == 2) {
switchTrack(++currentTrack);
} else {
if (currentTrack < playlist.length) switchTrack(++currentTrack);
}
}
}
}

var beforeLoad = function() {
var endVal = this.seekable && this.seekable.length ? this.seekable.end(0) : 0;
$('.progress .loaded').css('width', (100 / (this.duration || 1) * endVal) + '%');
}

// Fire when track loaded completely
var afterLoad = function() {
if (autoplay == true) play();
}

// Load track
var loadMusic = function(i) {
var item = playlist[i],
newaudio = $('<audio>').html('<source src="' + item.mp3 + '"><source src="' + item.ogg + '">').appendTo('#player');

$('.cover').html('<img src="' + item.cover + '" alt="' + item.album + '">');
$('.tag').html('<strong>' + item.title + '</strong><span class="artist">' + item.artist + '</span><span class="album">' + item.album + '</span>');
$('#playlist li').removeClass('playing').eq(i).addClass('playing');
audio = newaudio[0];
audio.volume = $('.mute').hasClass('enable') ? 0 : volume;
audio.addEventListener('progress', beforeLoad, false);
audio.addEventListener('durationchange', beforeLoad, false);
audio.addEventListener('canplay', afterLoad, false);
audio.addEventListener('ended', ended, false);
}

loadMusic(currentTrack);
$('.playback').on('click', function() {
if ($(this).hasClass('playing')) {
pause();
} else {
play();
}
});
$('.rewind').on('click', function() {
if (shuffle === 'true') {
shufflePlay();
} else {
switchTrack(--currentTrack);
}
});
$('.fastforward').on('click', function() {
if (shuffle === 'true') {
shufflePlay();
} else {
switchTrack(++currentTrack);
}
});
$('#playlist li').each(function(i) {
var _i = i;
$(this).on('click', function() {
switchTrack(_i);
});
});

if (shuffle === 'true') $('.shuffle').addClass('enable');
if (repeat == 1) {
$('.repeat').addClass('once');
} else if (repeat == 2) {
$('.repeat').addClass('all');
}

$('.repeat').on('click', function() {
if ($(this).hasClass('once')) {
repeat = localStorage.repeat = 2;
$(this).removeClass('once').addClass('all');
} else if ($(this).hasClass('all')) {
repeat = localStorage.repeat = 0;
$(this).removeClass('all');
} else {
repeat = localStorage.repeat = 1;
$(this).addClass('once');
}
});

$('.shuffle').on('click', function() {
if ($(this).hasClass('enable')) {
shuffle = localStorage.shuffle = 'false';
$(this).removeClass('enable');
} else {
shuffle = localStorage.shuffle = 'true';
$(this).addClass('enable');
}
});

var dropbox = document.getElementById("dropbox")

// init event handlers
dropbox.addEventListener("dragenter", dragEnter, false);
dropbox.addEventListener("dragexit", dragExit, false);
dropbox.addEventListener("dragover", dragOver, false);
dropbox.addEventListener("drop", drop, false);

// init the widgets
$("#progressbar").progressbar();

function dragEnter(evt) {
evt.stopPropagation();
evt.preventDefault();
}

function dragExit(evt) {
evt.stopPropagation();
evt.preventDefault();
}

function dragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
}

function drop(evt) {
evt.stopPropagation();
evt.preventDefault();

var files = evt.dataTransfer.files;
var count = files.length;

// Only call the handler if 1 or more files was dropped.
if (count > 0)
handleFiles(files);
}


function handleFiles(files) {
var mp3Files = $.map(files, function(f, i) {
return f.type.indexOf("audio/mp3") == 0 ? f : null;
});

$.each(mp3Files, function(i, file) {
document.getElementById("droplabel").innerHTML = "Processing " + file.name;

var reader = new FileReader();

reader.onload = function(evt) {
$('#playlist').append('<li>' + 'mo' + ' - ' + file.name + '</li>');
playlist.push({
title: file.name,
mp3: evt.target.result
});

$('#playlist li').each(function(i) {
var _i = i;
$(this).on('click', function() {
switchTrack(_i);
});
});
}
// init the reader event handlers
reader.onprogress = handleReaderProgress;
reader.onloadend = handleReaderLoadEnd;

reader.readAsDataURL(file);

});
}

function handleReaderProgress(evt) {
if (evt.lengthComputable) {
var loaded = (evt.loaded / evt.total);

$("#progressbar").progressbar({
value: loaded * 100
});
}
}

function handleReaderLoadEnd(evt) {
$("#progressbar").progressbar({
value: 100
});
}
})(jQuery);
Read More +

JQuery 魔法陣製作 Magic Circle

製作起源

魔法陣字型出處

也是因為在 2014-04-17 出了一款魔法陣字型,在藉由惡友們的催促下,不,是誘導下嘗試做了 jquery 的插件來完成魔法陣的製作。當然沒有網址中做得那麼好看。

不過具體下也努力去完成了。附圖如下:

製作

前置作業

  • JQuery
  • CSS 旋轉和陰影配置

開始

  • 配置多層圓,可以參考 這裡,先將內容拆成 <span>A</span> 的形式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    h1 span {
    font: 24px myFirstFont, Monaco, MonoSpace;
    height: 300px;
    position: absolute;
    width: 20px;
    left: 50%;
    top: 0;
    -webkit-transform-origin: 50% 50%;
    -moz-transform-origin: 50% 50%;
    -ms-transform-origin: 50% 50%;
    -o-transform-origin: 50% 50%;
    transform-origin: 50% 50%;
    }
  • 將每個 <span> 設置成絕對座標配置,乍看下是一個長條形,並且使用 transform-origin 50% 50% 設置旋轉中心,也就是長條形的正中間。rgba(177, 17, 22, 1) 為血紅色

更新

  • 接著要計算字距,來方便每一個字符偏轉角度。而且每一層圓的偏轉角度還有所不同,這裡我並沒有詳細去計算。

  • transform rotate(50 deg) 用來旋轉

  • 光暈效果呈現 box-shadow 0px 0px 10px rgba(177, 17, 22, 1) 於外部產生陰影。

    • 至於內部效果沒有做得很好看。

山田かみら 的建議下,進行的大幅度地修改,同時也發現之前的版本有過度延遲的問題,原因都發生於過多的 for each 計算。

  • 先修正過於愚蠢的 CSS,加入比較好的 class 處理,來達到可以物件化。
  • 原本文字的處理仍需要使用旋轉的方式運作,而考慮將每一個圈放到同一個正方形內,直接對正方形作旋轉即可,剩下的操作交給瀏覽器去進行計算。因此,做了架構上的分層。

關於代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
$(function() {
$("#test1").magicsquare('fire', {radius: 500, radius_padding: 150,
radius_center: 200, duration: 10});

$("#test2").magicsquare('fire', {radius: 300, radius_padding: 50,
radius_center: 50, duration: 30});

$("#test1").draggable();
$("#test2").draggable();
$(".center-content").click(function() {
$("#test1").magicsquare('boom');
$("#test2").magicsquare('boom');
});
});
</script>

不知道 CSS3 穩定了沒有,在動畫處理引用 animate.css。

但是如果要完成連續型的動畫播放,單純 CSS 目前不想去研究能不能寫腳本。所以在定秒處理之後呼叫 callback() 去進行下一個動畫放置 (仍以 jquery 為主)。

剩下的交給 山田君 了。

Demo & 下載

very old version demo gif
demo link

repo jquery-magic-circle on Github

Reference

Read More +