forked from phodal/ideabook
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
4056 lines (3813 loc) · 326 KB
/
index.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
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
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>Phodal's Idea实战指南 – </title>
<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
</style>
<link rel="stylesheet" href="style.css">
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
<meta name="viewport" content="width=device-width">
</head>
<body>
<h1>Phodal's Idea实战指南</h1>
<p>By <a href="https://www.phodal.com/">Phodal</a> (Follow Me: <a href="http://weibo.com/phodal">微博</a>、<a href="https://www.zhihu.com/people/phodal">知乎</a>、<a href="https://segmentfault.com/u/phodal">SegmentFault</a>)
</p>
<p>GitHub: <a href="https://github.com/phodal/ideabook">Phodal's Idea实战指南</a></p>
<p>我的其他电子书:</p>
<ul>
<li>《<a href="https://github.com/phodal/designiot">一步步搭建物联网系统</a>》</li>
<li>《<a href="https://github.com/phodal/github-roam">GitHub 漫游指南</a>》</li>
<li>《<a href="https://github.com/phodal/repractise">RePractise</a>》</li>
<li>《<a href="https://github.com/phodal/growth-ebook">Growth: 全栈增长工程师指南</a>》</li>
</ul>
<p>微信公众号</p>
<p><img src="http://articles.phodal.com/qrcode.jpg" alt=""/></p>
<p>
当前为预览版,在使用的过程中遇到任何遇到请及时与我联系。阅读过程中问题,不烦在GitHub上提出来:
<a href="https://github.com/phodal/ideabook/issues">Idea Ebook Issues</a>
</p>
<p>
阅读过程中遇到语法错误、拼写错误、技术错误等等,不烦来个Pull Request,这样可以帮助到其他阅读这本电子书的童鞋。
</p>
<div style="width:800px">
<iframe src="http://ghbtns.com/github-btn.html?user=phodal&repo=ideabook&type=watch&count=true"
allowtransparency="true" frameborder="0" scrolling="0" width="110px" height="20px"></iframe>
</div>
<nav id="TOC">
<ul>
<li><a href="#分析网站日志打造访问地图">分析网站日志,打造访问地图</a><ul>
<li><a href="#概况">概况</a><ul>
<li><a href="#背景">背景</a></li>
<li><a href="#showcase">ShowCase</a></li>
<li><a href="#hadoop-pig-jython-ammap-elasticsearch">Hadoop + Pig + Jython + AmMap + ElasticSearch</a></li>
</ul></li>
<li><a href="#步骤">步骤</a><ul>
<li><a href="#step-1-搭建基础设施">Step 1: 搭建基础设施</a></li>
<li><a href="#step-2-解析access.log">Step 2: 解析access.log</a></li>
<li><a href="#step-3-转换ip为geo信息">Step 3: 转换IP为GEO信息</a></li>
<li><a href="#step-4-展示数据到地图上">Step 4: 展示数据到地图上</a></li>
<li><a href="#练习建议">练习建议</a></li>
</ul></li>
</ul></li>
<li><a href="#书籍录入移动应用条形码扫描">书籍录入移动应用:条形码扫描</a><ul>
<li><a href="#概况-1">概况</a><ul>
<li><a href="#背景-1">背景</a></li>
<li><a href="#showcase-1">ShowCase</a></li>
<li><a href="#ionic-zxing">Ionic + Zxing</a></li>
</ul></li>
<li><a href="#步骤-1">步骤</a><ul>
<li><a href="#step-1-zxing扫描与douban-api">Step 1: ZXing扫描与Douban API</a></li>
<li><a href="#step-2-存储数据库">Step 2: 存储数据库</a></li>
<li><a href="#上传数据">上传数据</a></li>
<li><a href="#练习建议-1">练习建议</a></li>
</ul></li>
</ul></li>
<li><a href="#制作专属badge">制作专属Badge</a><ul>
<li><a href="#概况-2">概况</a><ul>
<li><a href="#背景-2">背景</a></li>
<li><a href="#showcase-2">ShowCase</a></li>
<li><a href="#svg与svgwrite">SVG与SVGWrite</a></li>
</ul></li>
<li><a href="#步骤-2">步骤</a><ul>
<li><a href="#step-1-基本图形">Step 1: 基本图形</a></li>
<li><a href="#step-2-高级badge">Step 2: 高级Badge</a></li>
<li><a href="#step-3-完成">Step 3: 完成</a></li>
</ul></li>
<li><a href="#练习建议-2">练习建议</a></li>
</ul></li>
<li><a href="#微信文章编辑器">微信文章编辑器</a><ul>
<li><a href="#概况-3">概况</a><ul>
<li><a href="#背景-3">背景</a></li>
<li><a href="#showcase-3">ShowCase</a></li>
<li><a href="#ckeditor-ractive">CKEditor + Ractive</a></li>
</ul></li>
<li><a href="#步骤-3">步骤</a><ul>
<li><a href="#step-1-helloworld">Step 1: hello,world</a></li>
<li><a href="#step-2-require.js模块化">Step 2: Require.js模块化</a></li>
<li><a href="#step-3-初始化">Step 3: 初始化</a></li>
<li><a href="#step-4-创建对应的view">Step 4: 创建对应的View</a></li>
<li><a href="#练习建议-3">练习建议</a></li>
</ul></li>
</ul></li>
<li><a href="#javascript制作slide框架">JavaScript制作Slide框架</a><ul>
<li><a href="#概况-4">概况</a><ul>
<li><a href="#背景-4">背景</a></li>
<li><a href="#showcase-4">Showcase</a></li>
<li><a href="#需求">需求</a></li>
</ul></li>
<li><a href="#步骤-4">步骤</a><ul>
<li><a href="#step-1-基本的slide功能">Step 1: 基本的Slide功能</a></li>
<li><a href="#step-2-解析markdown">Step 2: 解析Markdown</a></li>
<li><a href="#step-3-事件处理">Step 3: 事件处理</a></li>
<li><a href="#step-4-解析字幕">Step 4: 解析字幕</a></li>
<li><a href="#step-5-进度条">Step 5: 进度条</a></li>
<li><a href="#step-6-同步">Step 6: 同步</a></li>
<li><a href="#练习建议-4">练习建议</a></li>
</ul></li>
</ul></li>
<li><a href="#编辑-发布-分离的博客系统">编辑-发布-分离的博客系统</a><ul>
<li><a href="#概况-5">概况</a><ul>
<li><a href="#背景-编辑-发布-开发分离">背景: 编辑-发布-开发分离</a></li>
<li><a href="#用户场景">用户场景</a></li>
</ul></li>
<li><a href="#步骤-5">步骤</a><ul>
<li><a href="#step-1-构建工具">Step 1: 构建工具</a></li>
<li><a href="#step-2-静态页面生成">Step 2: 静态页面生成</a></li>
</ul></li>
</ul></li>
<li><a href="#solr实现多边形地理搜索">Solr实现多边形地理搜索</a><ul>
<li><a href="#概况-6">概况</a><ul>
<li><a href="#背景-5">背景</a></li>
<li><a href="#showcase-5">Showcase</a></li>
<li><a href="#solr">Solr</a></li>
</ul></li>
<li><a href="#步骤-6">步骤</a><ul>
<li><a href="#step-1-solr-flask">Step 1: Solr Flask</a></li>
<li><a href="#step-2-google-map-polygon">Step 2: Google map Polygon</a></li>
</ul></li>
</ul></li>
<li><a href="#一份代码打造跨平台应用">一份代码打造跨平台应用</a><ul>
<li><a href="#概况-7">概况</a><ul>
<li><a href="#背景-6">背景</a></li>
<li><a href="#showcase-6">ShowCase</a></li>
<li><a href="#ionic-electron-cordova">Ionic & Electron & Cordova</a></li>
</ul></li>
<li><a href="#步骤-7">步骤</a><ul>
<li><a href="#step-1-从web到混合应用再到桌面应用">Step 1: 从Web到混合应用,再到桌面应用</a></li>
<li><a href="#step-2-响应式设计">Step 2: 响应式设计</a></li>
<li><a href="#step-3-平台特定代码">Step 3: 平台特定代码</a></li>
<li><a href="#未来">未来</a></li>
</ul></li>
</ul></li>
<li><a href="#ionic与elasticsearch打造o2o应用">Ionic与ElasticSearch打造O2O应用</a><ul>
<li><a href="#概况-8">概况</a><ul>
<li><a href="#背景-7">背景</a></li>
<li><a href="#showcase-7">Showcase</a></li>
<li><a href="#构架设计">构架设计</a></li>
</ul></li>
<li><a href="#步骤-8">步骤</a><ul>
<li><a href="#step-1-django-gis-设置">Step 1: Django GIS 设置</a></li>
<li><a href="#step-2-配置haystack">Step 2: 配置Haystack</a></li>
<li><a href="#step-3-django-haystack-model创建">Step 3: Django Haystack Model创建</a></li>
<li><a href="#step-4-创建search_index">Step 4: 创建search_index</a></li>
<li><a href="#step-4-ionic-elasticsearch-创建页面">Step 4: Ionic ElasticSearch 创建页面</a></li>
<li><a href="#step-5-ionic-elasticsearch-service">Step 5: Ionic ElasticSearch Service</a></li>
<li><a href="#step-6-ionic-openlayer-地图显示">Step 6: Ionic OpenLayer 地图显示</a></li>
</ul></li>
</ul></li>
<li><a href="#一步步搭建javascript框架">一步步搭建JavaScript框架</a><ul>
<li><a href="#概况-9">概况</a><ul>
<li><a href="#背景-8">背景</a></li>
</ul></li>
<li><a href="#步骤-9">步骤</a><ul>
<li><a href="#step-1-注册npm和bower包">Step 1: 注册npm和bower包</a></li>
<li><a href="#step-2-生成javascript项目框架">Step 2: 生成Javascript项目框架</a></li>
<li><a href="#step-3-寻找所需要的函数">Step 3: 寻找所需要的函数</a></li>
<li><a href="#step-4-整合">Step 4: 整合</a></li>
<li><a href="#step-5-测试">Step 5: 测试</a></li>
<li><a href="#练习建议-5">练习建议</a></li>
</ul></li>
</ul></li>
<li><a href="#制作简易mac-os上的伪锁屏工具">制作简易Mac OS上的伪锁屏工具</a><ul>
<li><a href="#概况-10">概况</a><ul>
<li><a href="#背景-9">背景</a></li>
</ul></li>
<li><a href="#步骤-10">步骤</a><ul>
<li><a href="#step-1屏幕截图">Step 1:屏幕截图</a></li>
<li><a href="#step-2调节亮度">Step 2:调节亮度</a></li>
<li><a href="#step-3全屏图片">Step 3:全屏图片</a></li>
</ul></li>
</ul></li>
<li><a href="#基于virtual-dom的测试代码生成">基于Virtual DOM的测试代码生成</a><ul>
<li><a href="#概况-11">概况</a><ul>
<li><a href="#背景-10">背景</a></li>
<li><a href="#showcase-8">ShowCase</a></li>
<li><a href="#基本原理">基本原理</a></li>
</ul></li>
<li><a href="#步骤-11">步骤</a><ul>
<li><a href="#step-1-virtual-dom与hyperscript">Step 1: Virtual-dom与HyperScript</a></li>
<li><a href="#step-2-标记dom变化">Step 2: 标记DOM变化</a></li>
</ul></li>
</ul></li>
<li><a href="#基于backbone的单页面移动应用">基于Backbone的单页面移动应用</a><ul>
<li><a href="#概况-12">概况</a><ul>
<li><a href="#背景-11">背景</a></li>
<li><a href="#showcase-9">Showcase</a></li>
<li><a href="#jquery-backbone-underscore-require.js">jQuery + Backbone + UnderScore + Require.JS</a></li>
</ul></li>
<li><a href="#步骤-12">步骤</a><ul>
<li><a href="#step-1-使用require.js管理依赖">Step 1: 使用Require.js管理依赖</a></li>
<li><a href="#step-2-添加路由">Step 2: 添加路由</a></li>
<li><a href="#step-3-创建主页view">Step 3: 创建主页View</a></li>
<li><a href="#step-4-jquery-sidr">Step 4: jQuery Sidr</a></li>
<li><a href="#step-5-django-tastypie示例">Step 5: Django Tastypie示例</a></li>
<li><a href="#step-6-requirejs-plugins">Step 6: RequireJS Plugins</a></li>
<li><a href="#step-6-简单的博客">Step 6: 简单的博客</a></li>
<li><a href="#step-7-重构">Step 7: 重构</a></li>
<li><a href="#step-8-移动cms滑动">Step 8: 移动CMS滑动</a></li>
</ul></li>
</ul></li>
<li><a href="#oculus-node.js-three.js-打造vr世界">Oculus + Node.js + Three.js 打造VR世界</a><ul>
<li><a href="#概况-13">概况</a><ul>
<li><a href="#背景-12">背景</a></li>
<li><a href="#showcase-10">Showcase</a></li>
<li><a href="#框架-oculus-rift-node-nmd">框架: Oculus Rift & Node NMD</a></li>
</ul></li>
<li><a href="#步骤-13">步骤</a><ul>
<li><a href="#step-1-node-oculus-services">Step 1: Node Oculus Services</a></li>
<li><a href="#step-2-node.js-oculus-helloworld">Step 2: Node.js Oculus Hello,World</a></li>
<li><a href="#step-3-node-oculus-websocket">Step 3: Node Oculus WebSocket</a></li>
<li><a href="#step-4-oculus-effect-dk2-control">Step 4: Oculus Effect + DK2 Control</a></li>
<li><a href="#step-5-three.js-keyhandler">Step 5: Three.js KeyHandler</a></li>
<li><a href="#练习建议-6">练习建议</a></li>
</ul></li>
</ul></li>
<li><a href="#手动制作照片地图">手动制作照片地图</a><ul>
<li><a href="#概况-14">概况</a><ul>
<li><a href="#background把照片放在地图上">Background:把照片放在地图上</a></li>
<li><a href="#showcase-11">Showcase</a></li>
<li><a href="#框架-exif-exifread-cartodb">框架: EXIF & ExifRead & CartoDB</a></li>
</ul></li>
<li><a href="#步骤-14">步骤</a><ul>
<li><a href="#step-1-解析读取照片信息">Step 1: 解析读取照片信息</a></li>
<li><a href="#step-2-上传数据">Step 2: 上传数据</a></li>
<li><a href="#练习建议-7">练习建议</a></li>
</ul></li>
</ul></li>
<li><a href="#d3.js打造技能树">D3.js打造技能树</a><ul>
<li><a href="#概况-15">概况</a><ul>
<li><a href="#背景-13">背景</a></li>
<li><a href="#showcase-12">Showcase</a></li>
<li><a href="#graphviz">Graphviz</a></li>
</ul></li>
<li><a href="#步骤-15">步骤</a><ul>
<li><a href="#step-1-打造简单的技能树">Step 1: 打造简单的技能树</a></li>
<li><a href="#step-3-d3.js-tooltipster">Step 3: D3.js Tooltipster</a></li>
</ul></li>
</ul></li>
<li><a href="#技术雷达趋势">技术雷达趋势</a><ul>
<li><a href="#概况-16">概况</a><ul>
<li><a href="#背景-14">背景</a></li>
<li><a href="#showcase-13">Showcase</a></li>
<li><a href="#d3.js">D3.js</a></li>
</ul></li>
<li><a href="#步骤-16">步骤</a><ul>
<li><a href="#step-1-schema与原始代码">Step 1: Schema与原始代码</a></li>
<li><a href="#step-2-处理数据">Step 2: 处理数据</a></li>
</ul></li>
</ul></li>
<li><a href="#文本转logo">文本转Logo</a><ul>
<li><a href="#概况-17">概况</a><ul>
<li><a href="#背景-15">背景</a></li>
<li><a href="#showcase-14">ShowCase</a></li>
<li><a href="#需求说明">需求说明</a></li>
</ul></li>
<li><a href="#步骤-17">步骤</a><ul>
<li><a href="#step-1-python-文字转logo实战">Step 1: Python 文字转Logo实战</a></li>
</ul></li>
</ul></li>
<li><a href="#geojson与elasticsearch实现高级图形搜索">GeoJSON与ElasticSearch实现高级图形搜索</a><ul>
<li><a href="#概况-18">概况</a><ul>
<li><a href="#showcase-15">Showcase</a></li>
<li><a href="#jquery-mustache-leaflet">jQuery + Mustache + Leaflet</a></li>
</ul></li>
<li><a href="#步骤-18">步骤</a><ul>
<li><a href="#step-1-离线地图与搜索">Step 1: 离线地图与搜索</a></li>
<li><a href="#step-2-从地点到地图上显示">Step 2: 从地点到地图上显示</a></li>
<li><a href="#step-3-从地图到地点上显示">Step 3: 从地图到地点上显示</a></li>
</ul></li>
</ul></li>
</ul>
</nav>
<h1 id="分析网站日志打造访问地图">分析网站日志,打造访问地图</h1>
<h2 id="概况">概况</h2>
<h3 id="背景">背景</h3>
<p>这个项目的背景是起源于,我有一个2G左右的网站访问日志。我想看看访问网站的人都来自哪里,于是我想开始想办法来分析这日志。当时正值大数据火热的时候,便想拿着Hadoop来做这样一件事。</p>
<h3 id="showcase">ShowCase</h3>
<p>最后的效果如下图如示:</p>
<figure>
<img src="http://ideabook.phodal.com/images/map_with_bg.jpg" alt="Demo" /><figcaption>Demo</figcaption>
</figure>
<p>这是一个Web生成的界面,通过Elastic.js向搜索引擎查询数据,将再这些数据渲染到地图上。</p>
<h3 id="hadoop-pig-jython-ammap-elasticsearch">Hadoop + Pig + Jython + AmMap + ElasticSearch</h3>
<p>我们使用的技术栈有上面这些,他们的简介如下:</p>
<ul>
<li>Hadoop是一个由Apache基金会所开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。</li>
<li>Pig 是一个基于Hadoop的大规模数据分析平台,它提供的SQL-LIKE语言叫Pig Latin,该语言的编译器会把类SQL的数据分析请求转换为一系列经过优化处理的MapReduce运算。</li>
<li>Jython是一种完整的语言,而不是一个Java翻译器或仅仅是一个Python编译器,它是一个Python语言在Java中的完全实现。Jython也有很多从CPython中继承的模块库。</li>
<li>AmMap是用于创建交互式Flash地图的工具。您可以使用此工具来显示您的办公室地点,您的行程路线,创建您的经销商地图等。</li>
<li>ElasticSearch是一个基于Lucene 构建的开源,分布式,RESTful 搜索引擎。 设计用于云计算中,能够达到搜索实时、稳定、可靠和快速,并且安装使用方便。</li>
</ul>
<h2 id="步骤">步骤</h2>
<p>总的步骤并不是很复杂,可以分为:</p>
<ul>
<li>搭建基础设施</li>
<li>解析access.log</li>
<li>转换IP为GEO信息</li>
<li>展示数据到地图上</li>
</ul>
<h3 id="step-1-搭建基础设施">Step 1: 搭建基础设施</h3>
<p>在这一些系列的实战中,比较麻烦的就是安装这些工具,我们需要安装上面提到的一系列工具。对于不同的系统来说,都有相似的安装工具:</p>
<ul>
<li>Windows上可以使用Chocolatey</li>
<li>Ubuntu / Mint上可以使用aptitude</li>
<li>CentOS / OpenSUSE上可以使用yum安装</li>
<li>Mac OS上可以使用brew安装</li>
</ul>
<p>如下是Mac OS下安装Hadoop、Pig、Elasticsearch、Jython的方式</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">brew</span> install hadoop
<span class="kw">brew</span> install pig
<span class="kw">brew</span> install elasticsearch
<span class="kw">brew</span> install jython</code></pre></div>
<p>对于其他操作系统也可以使用相似的方法来安装。接着我们还需要安装一个Hadoop的插件,用于连接Hadoop和ElasticSearch。</p>
<p>下载地址:<a href="https://github.com/elastic/elasticsearch-hadoop" class="uri">https://github.com/elastic/elasticsearch-hadoop</a></p>
<p>复制其中的<code>elasticsearch-hadoop-*.jar</code>、<code>elasticsearch-hadoop-pig-*.jar</code>到你的pig库的目录,如我的是:<code>/usr/local/Cellar/pig/0.14.0</code>。</p>
<p>由于我使用提早期的版本,所以这里我的文件名是:<code>elasticsearch-hadoop-2.1.0.Beta3.jar</code>、<code>elasticsearch-hadoop-pig-2.1.0.Beta3.jar</code>。</p>
<p>下面我们就可以尝试去解析我们的日志了。</p>
<h3 id="step-2-解析access.log">Step 2: 解析access.log</h3>
<p>在开始解析之前,先让我们来看看几条Nginx的日志:</p>
<pre><code>106.39.113.203 - - [28/Apr/2016:10:40:31 +0000] "GET / HTTP/2.0" 200 0 "https://www.phodal.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36" -
66.249.65.119 - - [28/Apr/2016:10:40:51 +0000] "GET /set_device/default/?next=/blog/use-falcon-peewee-build-high-performance-restful-services-wordpress/ HTTP/1.1" 302 5 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" -</code></pre>
<p>而上面的日志实际上是有对应的格式的,这个格式写在我们的Nginx配置文件中。如下是上面的日志的格式:</p>
<pre><code>log_format access $remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $http_x_forwarded_for';</code></pre>
<p>在最前面的是访问者的IP地址,然后是访问者的当地时间、请求的类型、状态码、访问的URL、用户的User Agent等等。随后,我们就可以针对上面的格式编写相应的程序,这些代码如下所示:</p>
<pre><code>register file:/usr/local/Cellar/pig/0.14.0/libexec/lib/piggybank.jar;
register file:/usr/local/Cellar/pig/0.14.0/libexec/lib/elasticsearch-hadoop-pig-2.1.0.Beta3.jar;
RAW_LOGS = LOAD 'data/access.log' USING TextLoader as (line:chararray);
LOGS_BASE = FOREACH RAW_LOGS GENERATE
FLATTEN(
REGEX_EXTRACT_ALL(line, '(\\S+) - - \\[([^\\[]+)\\]\\s+"([^"]+)"\\s+(\\d+)\\s+(\\d+)\\s+"([^"]+)"\\s+"([^"]+)"\\s+-')
)
AS (
ip: chararray,
timestamp: chararray,
url: chararray,
status: chararray,
bytes: chararray,
referrer: chararray,
useragent: chararray
);
A = FOREACH LOGS_BASE GENERATE ToDate(timestamp, 'dd/MMM/yyyy:HH:mm:ss Z') as date, ip, url,(int)status,(int)bytes,referrer,useragent;
--B = GROUP A BY (timestamp);
--C = FOREACH B GENERATE FLATTEN(group) as (timestamp), COUNT(A) as count;
--D = ORDER C BY timestamp,count desc;
STORE A INTO 'nginx/log' USING org.elasticsearch.hadoop.pig.EsStorage();</code></pre>
<p>在第1~2行里,我们使用了自定义的jar文件。接着在第4行,载入了log文件,并其值赋予RAW_LOGS。随后的第6行里,我们取出RAW_LOGS中的每一个值 ,根据下面的正则表达式,取出其对应的值到对象里,如<code>- -</code>前面的(\S+)对应的是ip,最后将这些值赋给LOGS_BASE。</p>
<p>接着,我们就可以对值进行一些特殊的处理,如A是转化时间戳后的结果。B是按时间戳排序后的结果。最后,我们再将这些值存储到ElasticSearch对应的索引<code>nginx/log</code>中。</p>
<h3 id="step-3-转换ip为geo信息">Step 3: 转换IP为GEO信息</h3>
<p>在简单地完成了一个Demo之后,我们就可以将IP转换为GEO信息了,这里我们需要用到一个名为pygeoip的库。GeoIP是一个根据IP地址查询位置的API的集成。它支持对国家、地区、城市、纬度和经度的查询。实际上,就是在一个数据库中有对应的国家和地区的IP段,根据这个IP段,我们就可以获取对应的地理位置。</p>
<p>由于使用Java来实现这个功能比较麻烦,这里我们就使用Jython来实现。大部分的过程和上面都是一样的,除了注册了一个自定义的库,并在这个库里使用了解析GEO的方法,代码如下所示:</p>
<pre><code>register file:/usr/local/Cellar/pig/0.14.0/libexec/lib/piggybank.jar;
register file:/usr/local/Cellar/pig/0.14.0/libexec/lib/elasticsearch-hadoop-pig-2.1.0.Beta3.jar;
register utils.py using jython as utils;
RAW_LOGS = LOAD 'data/access.log' USING TextLoader as (line:chararray);
LOGS_BASE = FOREACH RAW_LOGS GENERATE
FLATTEN(
REGEX_EXTRACT_ALL(line, '(\\S+) - - \\[([^\\[]+)\\]\\s+"([^"]+)"\\s+(\\d+)\\s+(\\d+)\\s+"([^"]+)"\\s+"([^"]+)"\\s+-')
)
AS (
ip: chararray,
timestamp: chararray,
url: chararray,
status: chararray,
bytes: chararray,
referrer: chararray,
useragent: chararray
);
A = FOREACH LOGS_BASE GENERATE ToDate(timestamp, 'dd/MMM/yyyy:HH:mm:ss Z') as date, utils.get_country(ip) as country,
utils.get_city(ip) as city, utils.get_geo(ip) as location,ip,
url, (int)status,(int)bytes,referrer,useragent;
STORE A INTO 'nginx/log' USING org.elasticsearch.hadoop.pig.EsStorage();</code></pre>
<p>在第三行里,我们注册了<code>utils.py</code>并将其中的函数作为utils。接着在倒数第二行里,我们执行了四个utils函数。即:</p>
<ul>
<li>get_country从IP中解析出国家</li>
<li>get_city从IP中解析出城市</li>
<li>get_geo从IP中解析出经纬度信息</li>
</ul>
<p>其对应的Python代码如下所示:</p>
<pre><code>#!/usr/bin/python
import sys
sys.path.append('/Users/fdhuang/test/lib/python2.7/site-packages/')
import pygeoip
gi = pygeoip.GeoIP("data/GeoLiteCity.dat")
@outputSchema('city:chararray')
def get_city(ip):
try:
city = gi.record_by_name(ip)["city"]
return city
except:
pass
@outputSchema('country:chararray')
def get_country(ip):
try:
city = gi.record_by_name(ip)["country_name"]
return city
except:
pass
@outputSchema('location:chararray')
def get_geo(ip):
try:
geo = str(gi.record_by_name(ip)["longitude"]) + "," + str(gi.record_by_name(ip)["latitude"])
return geo
except:
pass</code></pre>
<p>代码相应的简单,和一般的Python代码也没有啥区别。这里一些用户自定义函数,在函数的最前面有一个<code>outputSchema</code>,用于返回输出的结果。</p>
<h3 id="step-4-展示数据到地图上">Step 4: 展示数据到地图上</h3>
<p>现在,我们终于可以将数据转化到可视化界面了。开始之前,我们需要几个库</p>
<ul>
<li>jquery 地球人都知道</li>
<li>elasticsearch.jquery即用于搜索功能</li>
<li>ammap用于制作交互地图。</li>
</ul>
<p>添加这些库到html文件里:</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="kw"><script</span><span class="ot"> src=</span><span class="st">"bower_components/jquery/dist/jquery.js"</span><span class="kw">></script></span>
<span class="kw"><script</span><span class="ot"> src=</span><span class="st">"bower_components/elasticsearch/elasticsearch.jquery.js"</span><span class="kw">></script></span>
<span class="kw"><script</span><span class="ot"> src=</span><span class="st">"bower_components/ammap/dist/ammap/ammap.js"</span><span class="ot"> type=</span><span class="st">"text/javascript"</span><span class="kw">></script></span>
<span class="kw"><script</span><span class="ot"> src=</span><span class="st">"bower_components/ammap/dist/ammap/maps/js/worldLow.js"</span><span class="ot"> type=</span><span class="st">"text/javascript"</span><span class="kw">></script></span>
<span class="kw"><script</span><span class="ot"> src=</span><span class="st">"bower_components/ammap/dist/ammap/themes/black.js"</span><span class="ot"> type=</span><span class="st">"text/javascript"</span><span class="kw">></script></span>
<span class="kw"><script</span><span class="ot"> src=</span><span class="st">"scripts/latlng.js"</span><span class="kw">></script></span>
<span class="kw"><script</span><span class="ot"> src=</span><span class="st">"scripts/main_ammap.js"</span><span class="kw">></script></span></code></pre></div>
<p>生成过程大致如下所示:</p>
<ul>
<li>获取不同国家的全名,用于解析出全名,如US -> “United States”</li>
<li>查找ElasticSearch搜索引擎中的数据,并计算访问量</li>
<li>再将数据渲染到地图上</li>
</ul>
<p>对应的main文件如下所示:</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> client <span class="op">=</span> <span class="kw">new</span> <span class="va">$</span>.<span class="va">es</span>.<span class="at">Client</span>(<span class="op">{</span>
<span class="dt">hosts</span><span class="op">:</span> <span class="st">'localhost:9200'</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="co">// 创建ElasticSearch搜索条件</span>
<span class="kw">var</span> query <span class="op">=</span> <span class="op">{</span>
<span class="dt">index</span><span class="op">:</span> <span class="st">'nginx'</span><span class="op">,</span>
<span class="dt">type</span><span class="op">:</span> <span class="st">'log'</span><span class="op">,</span>
<span class="dt">size</span><span class="op">:</span> <span class="dv">200</span><span class="op">,</span>
<span class="dt">body</span><span class="op">:</span> <span class="op">{</span>
<span class="dt">query</span><span class="op">:</span> <span class="op">{</span>
<span class="dt">query_string</span><span class="op">:</span> <span class="op">{</span>
<span class="dt">query</span><span class="op">:</span> <span class="st">"*"</span>
<span class="op">}</span>
<span class="op">},</span>
<span class="dt">aggs</span><span class="op">:</span> <span class="op">{</span>
<span class="dv">2</span><span class="op">:</span> <span class="op">{</span>
<span class="dt">terms</span><span class="op">:</span> <span class="op">{</span>
<span class="dt">field</span><span class="op">:</span> <span class="st">"country"</span><span class="op">,</span>
<span class="dt">size</span><span class="op">:</span> <span class="dv">200</span><span class="op">,</span>
<span class="dt">order</span><span class="op">:</span> <span class="op">{</span>
<span class="dt">_count</span><span class="op">:</span> <span class="st">"desc"</span>
<span class="op">}</span>
<span class="op">}</span>
<span class="op">}</span>
<span class="op">}</span>
<span class="op">}</span>
<span class="op">};</span>
<span class="co">// 获取到country.json后生成数据</span>
<span class="at">$</span>(document).<span class="at">ready</span>(<span class="kw">function</span> () <span class="op">{</span>
<span class="va">$</span>.<span class="at">ajax</span>(<span class="op">{</span>
<span class="dt">type</span><span class="op">:</span> <span class="st">"GET"</span><span class="op">,</span>
<span class="dt">url</span><span class="op">:</span> <span class="st">"country.json"</span><span class="op">,</span>
<span class="dt">success</span><span class="op">:</span> <span class="kw">function</span> (data) <span class="op">{</span>
<span class="at">generate_info</span>(data)
<span class="op">}</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="co">// 根据数据中的国家名,来计算不同国家的访问量大小。</span>
<span class="kw">var</span> generate_info <span class="op">=</span> <span class="kw">function</span>(data)<span class="op">{</span>
<span class="kw">var</span> mapDatas <span class="op">=</span> []<span class="op">;</span>
<span class="va">client</span>.<span class="at">search</span>(query).<span class="at">then</span>(<span class="kw">function</span> (results) <span class="op">{</span>
<span class="va">$</span>.<span class="at">each</span>(<span class="va">results</span>.<span class="at">aggregations</span>[<span class="dv">2</span>].<span class="at">buckets</span><span class="op">,</span> <span class="kw">function</span>(index<span class="op">,</span> bucket)<span class="op">{</span>
<span class="kw">var</span> mapData<span class="op">;</span>
<span class="va">$</span>.<span class="at">each</span>(data<span class="op">,</span> <span class="kw">function</span>(index<span class="op">,</span> country)<span class="op">{</span>
<span class="cf">if</span>(<span class="va">country</span>.<span class="va">name</span>.<span class="at">toLowerCase</span>() <span class="op">===</span> <span class="va">bucket</span>.<span class="at">key</span>) <span class="op">{</span>
mapData <span class="op">=</span> <span class="op">{</span>
<span class="dt">code</span><span class="op">:</span> <span class="va">country</span>.<span class="at">code</span><span class="op">,</span>
<span class="dt">name</span><span class="op">:</span> <span class="va">country</span>.<span class="at">name</span><span class="op">,</span>
<span class="dt">value</span><span class="op">:</span> <span class="va">bucket</span>.<span class="at">doc_count</span><span class="op">,</span>
<span class="dt">color</span><span class="op">:</span> <span class="st">"#eea638"</span>
<span class="op">};</span>
<span class="op">}</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="cf">if</span>(mapData <span class="op">!==</span> <span class="kw">undefined</span>)<span class="op">{</span>
<span class="va">mapDatas</span>.<span class="at">push</span>(mapData)<span class="op">;</span>
<span class="op">}</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="at">create_map</span>(mapDatas)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op">};</span>
<span class="kw">var</span> create_map <span class="op">=</span> <span class="kw">function</span>(mapData)<span class="op">{</span>
<span class="kw">var</span> map<span class="op">;</span>
<span class="kw">var</span> minBulletSize <span class="op">=</span> <span class="dv">3</span><span class="op">;</span>
<span class="kw">var</span> maxBulletSize <span class="op">=</span> <span class="dv">70</span><span class="op">;</span>
<span class="kw">var</span> min <span class="op">=</span> <span class="kw">Infinity</span><span class="op">;</span>
<span class="kw">var</span> max <span class="op">=</span> <span class="op">-</span><span class="kw">Infinity</span><span class="op">;</span>
<span class="va">AmCharts</span>.<span class="at">theme</span> <span class="op">=</span> <span class="va">AmCharts</span>.<span class="va">themes</span>.<span class="at">black</span><span class="op">;</span>
<span class="cf">for</span> (<span class="kw">var</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> <span class="va">mapData</span>.<span class="at">length</span><span class="op">;</span> i<span class="op">++</span>) <span class="op">{</span>
<span class="kw">var</span> value <span class="op">=</span> mapData[i].<span class="at">value</span><span class="op">;</span>
<span class="cf">if</span> (value <span class="op"><</span> min) <span class="op">{</span>
min <span class="op">=</span> value<span class="op">;</span>
<span class="op">}</span>
<span class="cf">if</span> (value <span class="op">></span> max) <span class="op">{</span>
max <span class="op">=</span> value<span class="op">;</span>
<span class="op">}</span>
<span class="op">}</span>
map <span class="op">=</span> <span class="kw">new</span> <span class="va">AmCharts</span>.<span class="at">AmMap</span>()<span class="op">;</span>
<span class="va">map</span>.<span class="at">pathToImages</span> <span class="op">=</span> <span class="st">"bower_components/ammap/dist/ammap/images/"</span><span class="op">;</span>
<span class="va">map</span>.<span class="at">areasSettings</span> <span class="op">=</span> <span class="op">{</span>
<span class="dt">unlistedAreasColor</span><span class="op">:</span> <span class="st">"#FFFFFF"</span><span class="op">,</span>
<span class="dt">unlistedAreasAlpha</span><span class="op">:</span> <span class="fl">0.1</span>
<span class="op">};</span>
<span class="va">map</span>.<span class="at">imagesSettings</span> <span class="op">=</span> <span class="op">{</span>
<span class="dt">balloonText</span><span class="op">:</span> <span class="st">"<span style='font-size:14px;'><b>[[title]]</b>: [[value]]</span>"</span><span class="op">,</span>
<span class="dt">alpha</span><span class="op">:</span> <span class="fl">0.6</span>
<span class="op">};</span>
<span class="kw">var</span> dataProvider <span class="op">=</span> <span class="op">{</span>
<span class="dt">mapVar</span><span class="op">:</span> <span class="va">AmCharts</span>.<span class="va">maps</span>.<span class="at">worldLow</span><span class="op">,</span>
<span class="dt">images</span><span class="op">:</span> []
<span class="op">};</span>
<span class="kw">var</span> maxSquare <span class="op">=</span> maxBulletSize <span class="op">*</span> maxBulletSize <span class="op">*</span> <span class="dv">2</span> <span class="op">*</span> <span class="va">Math</span>.<span class="at">PI</span><span class="op">;</span>
<span class="kw">var</span> minSquare <span class="op">=</span> minBulletSize <span class="op">*</span> minBulletSize <span class="op">*</span> <span class="dv">2</span> <span class="op">*</span> <span class="va">Math</span>.<span class="at">PI</span><span class="op">;</span>
<span class="cf">for</span> (<span class="kw">var</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> <span class="va">mapData</span>.<span class="at">length</span><span class="op">;</span> i<span class="op">++</span>) <span class="op">{</span>
<span class="kw">var</span> dataItem <span class="op">=</span> mapData[i]<span class="op">;</span>
<span class="kw">var</span> value <span class="op">=</span> <span class="va">dataItem</span>.<span class="at">value</span><span class="op">;</span>
<span class="co">// calculate size of a bubble</span>
<span class="kw">var</span> square <span class="op">=</span> (value <span class="op">-</span> min) / (max <span class="op">-</span> min) <span class="op">*</span> (maxSquare <span class="op">-</span> minSquare) <span class="op">+</span> minSquare<span class="op">;</span>
<span class="cf">if</span> (square <span class="op"><</span> minSquare) <span class="op">{</span>
square <span class="op">=</span> minSquare<span class="op">;</span>
<span class="op">}</span>
<span class="kw">var</span> size <span class="op">=</span> <span class="va">Math</span>.<span class="at">sqrt</span>(square / (<span class="va">Math</span>.<span class="at">PI</span> <span class="op">*</span> <span class="dv">2</span>))<span class="op">;</span>
<span class="kw">var</span> id <span class="op">=</span> <span class="va">dataItem</span>.<span class="at">code</span><span class="op">;</span>
<span class="va">dataProvider</span>.<span class="va">images</span>.<span class="at">push</span>(<span class="op">{</span>
<span class="dt">type</span><span class="op">:</span> <span class="st">"circle"</span><span class="op">,</span>
<span class="dt">width</span><span class="op">:</span> size<span class="op">,</span>
<span class="dt">height</span><span class="op">:</span> size<span class="op">,</span>
<span class="dt">color</span><span class="op">:</span> <span class="va">dataItem</span>.<span class="at">color</span><span class="op">,</span>
<span class="dt">longitude</span><span class="op">:</span> latlong[id].<span class="at">longitude</span><span class="op">,</span>
<span class="dt">latitude</span><span class="op">:</span> latlong[id].<span class="at">latitude</span><span class="op">,</span>
<span class="dt">title</span><span class="op">:</span> <span class="va">dataItem</span>.<span class="at">name</span><span class="op">,</span>
<span class="dt">value</span><span class="op">:</span> value
<span class="op">}</span>)<span class="op">;</span>
<span class="op">}</span>
<span class="va">map</span>.<span class="at">dataProvider</span> <span class="op">=</span> dataProvider<span class="op">;</span>
<span class="va">map</span>.<span class="at">write</span>(<span class="st">"mapdiv"</span>)<span class="op">;</span>
<span class="op">};</span></code></pre></div>
<p>我们可以看到比较麻烦的地方就是生成地图上的数量点,也就是create_map函数。</p>
<h3 id="练习建议">练习建议</h3>
<h1 id="书籍录入移动应用条形码扫描">书籍录入移动应用:条形码扫描</h1>
<h2 id="概况-1">概况</h2>
<h3 id="背景-1">背景</h3>
<p>这个项目的起源是我想录入我的书架上的书籍——当时,大概有近四百本左右。由于大部分的手机软件都是收费的,或封闭的,因此我便想着自己写一个app来完成书籍的录入。</p>
<h3 id="showcase-1">ShowCase</h3>
<p>最后的效果如下图所示:</p>
<figure>
<img src="http://ideabook.phodal.com/images/bookshelf.jpg" alt="Bookshelf" /><figcaption>Bookshelf</figcaption>
</figure>
<p>代码见: <a href="https://github.com/phodal/bookshelf/" class="uri">https://github.com/phodal/bookshelf/</a></p>
<h3 id="ionic-zxing">Ionic + Zxing</h3>
<p>所需要的移动框架还是Ionic,用于扫描条形码的库是ZXing。</p>
<h2 id="步骤-1">步骤</h2>
<p>开始之前,我们需要先安装Ionic,并且使用它来创建一个APP。然后我们还需要添加对应的二维码扫描库,代码如下所示:</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">phonegap</span> plugin add phonegap-plugin-barcodescanner</code></pre></div>
<p>7 接着我们就可以开始制作我们的APP了。</p>
<h3 id="step-1-zxing扫描与douban-api">Step 1: ZXing扫描与Douban API</h3>
<p>我们需要在我们的模板里,添加一个ICON或者按钮来触发程序调用相应的函数:</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="kw"><i</span><span class="ot"> class=</span><span class="st">"icon icon-right ion-qr-scanner"</span><span class="ot"> ng-click=</span><span class="st">"scan()"</span><span class="kw">></i></span></code></pre></div>
<p>在我们的函数里,我们只需要调用cordovaBarcodeScanner的scan方法就可以获取到二维码的值。再用$http.get去获取豆瓣API的相应的结果,并且将这个结果存储到数据库中。代码如下所示:</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">$scope</span>.<span class="at">scan</span> <span class="op">=</span> <span class="kw">function</span> () <span class="op">{</span>
$cordovaBarcodeScanner
.<span class="at">scan</span>()
.<span class="at">then</span>(<span class="kw">function</span> (barcodeData) <span class="op">{</span>
<span class="va">$scope</span>.<span class="at">info</span> <span class="op">=</span> <span class="va">barcodeData</span>.<span class="at">text</span><span class="op">;</span>
<span class="va">$http</span>.<span class="at">get</span>(<span class="st">"https://api.douban.com/v2/book/isbn/"</span> <span class="op">+</span> <span class="va">barcodeData</span>.<span class="at">text</span>).<span class="at">success</span>(<span class="kw">function</span> (data) <span class="op">{</span>
<span class="va">$scope</span>.<span class="at">detail</span> <span class="op">=</span> data<span class="op">;</span>
<span class="at">saveToDatabase</span>(data<span class="op">,</span> barcodeData)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op">},</span> <span class="kw">function</span> (error) <span class="op">{</span>
<span class="at">alert</span>(error)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op">}</span></code></pre></div>
<p>随后,我们就可以创建我们的代码来保存数据到数据库中。</p>
<h3 id="step-2-存储数据库">Step 2: 存储数据库</h3>
<p>开始之前,我们需要添加Cordova的SQLite插件:</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">cordova</span> plugin add https://github.com/litehelpers/Cordova-sqlite-storage.git</code></pre></div>
<p>在系统初始化的时候,创建对应的数据库及其表。</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="cf">if</span>(<span class="va">window</span>.<span class="at">cordova</span>) <span class="op">{</span>
<span class="co">//$cordovaSQLite.deleteDB("my.db");</span>
db <span class="op">=</span> <span class="va">$cordovaSQLite</span>.<span class="at">openDB</span>(<span class="st">"my.db"</span>)<span class="op">;</span>
<span class="op">}</span> <span class="cf">else</span> <span class="op">{</span>
db <span class="op">=</span> <span class="va">window</span>.<span class="at">openDatabase</span>(<span class="st">"my.db"</span><span class="op">,</span> <span class="st">"1.0"</span><span class="op">,</span> <span class="st">"bookshelf"</span><span class="op">,</span> <span class="op">-</span><span class="dv">1</span>)<span class="op">;</span>
<span class="op">}</span>
<span class="va">$cordovaSQLite</span>.<span class="at">execute</span>(db<span class="op">,</span> <span class="st">"CREATE TABLE IF NOT EXISTS bookshelf (id integer primary key, title text, image text, publisher text, author text, isbn text, summary text)"</span>)<span class="op">;</span></code></pre></div>
<p>接着,我们就可以上一步获取的数据取出相应的字段,调用bookshelfDB服务将其存储到数据库中。</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">function</span> <span class="at">saveToDatabase</span>(data<span class="op">,</span> barcodeData) <span class="op">{</span>
<span class="va">bookshelfDB</span>.<span class="at">add</span>(<span class="op">{</span>
<span class="dt">title</span><span class="op">:</span> <span class="va">data</span>.<span class="at">title</span><span class="op">,</span>
<span class="dt">image</span><span class="op">:</span> <span class="va">data</span>.<span class="at">image</span><span class="op">,</span>
<span class="dt">publisher</span><span class="op">:</span> <span class="va">data</span>.<span class="at">publisher</span><span class="op">,</span>
<span class="dt">author</span><span class="op">:</span> <span class="va">data</span>.<span class="at">author</span><span class="op">,</span>
<span class="dt">summary</span><span class="op">:</span> <span class="va">data</span>.<span class="at">summary</span><span class="op">,</span>
<span class="dt">isbn</span><span class="op">:</span> <span class="va">barcodeData</span>.<span class="at">text</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op">}</span></code></pre></div>
<p>下面就是我们的bookshelfDB服务,我们实现了get、add、remove、update,即CRUD。</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">.<span class="at">factory</span>(<span class="st">'bookshelfDB'</span><span class="op">,</span> <span class="kw">function</span>($cordovaSQLite<span class="op">,</span> DBA) <span class="op">{</span>
<span class="kw">var</span> self <span class="op">=</span> <span class="kw">this</span><span class="op">;</span>
<span class="va">self</span>.<span class="at">all</span> <span class="op">=</span> <span class="kw">function</span>() <span class="op">{</span>
<span class="cf">return</span> <span class="va">DBA</span>.<span class="at">query</span>(<span class="st">"SELECT id, title, image, publisher, author, isbn, summary FROM bookshelf"</span>)
.<span class="at">then</span>(<span class="kw">function</span>(result)<span class="op">{</span>
<span class="cf">return</span> <span class="va">DBA</span>.<span class="at">getAll</span>(result)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op">};</span>
<span class="va">self</span>.<span class="at">get</span> <span class="op">=</span> <span class="kw">function</span>(memberId) <span class="op">{</span>
<span class="kw">var</span> parameters <span class="op">=</span> [memberId]<span class="op">;</span>
<span class="cf">return</span> <span class="va">DBA</span>.<span class="at">query</span>(<span class="st">"SELECT id, title, image, publisher, author, isbn, summary FROM bookshelf WHERE id = (?)"</span><span class="op">,</span> parameters)
.<span class="at">then</span>(<span class="kw">function</span>(result) <span class="op">{</span>
<span class="cf">return</span> <span class="va">DBA</span>.<span class="at">getById</span>(result)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op">};</span>
<span class="va">self</span>.<span class="at">add</span> <span class="op">=</span> <span class="kw">function</span>(member) <span class="op">{</span>
<span class="kw">var</span> parameters <span class="op">=</span> [<span class="va">member</span>.<span class="at">id</span><span class="op">,</span> <span class="va">member</span>.<span class="at">title</span><span class="op">,</span> <span class="va">member</span>.<span class="at">image</span><span class="op">,</span> <span class="va">member</span>.<span class="at">publisher</span><span class="op">,</span> <span class="va">member</span>.<span class="at">author</span><span class="op">,</span> <span class="va">member</span>.<span class="at">isbn</span><span class="op">,</span> <span class="va">member</span>.<span class="at">summary</span>]<span class="op">;</span>
<span class="cf">return</span> <span class="va">DBA</span>.<span class="at">query</span>(<span class="st">"INSERT INTO bookshelf (id, title, image, publisher, author, isbn, summary) VALUES (?,?,?,?,?,?,?)"</span><span class="op">,</span> parameters)<span class="op">;</span>
<span class="op">};</span>
<span class="va">self</span>.<span class="at">remove</span> <span class="op">=</span> <span class="kw">function</span>(member) <span class="op">{</span>
<span class="kw">var</span> parameters <span class="op">=</span> [<span class="va">member</span>.<span class="at">id</span>]<span class="op">;</span>
<span class="cf">return</span> <span class="va">DBA</span>.<span class="at">query</span>(<span class="st">"DELETE FROM bookshelf WHERE id = (?)"</span><span class="op">,</span> parameters)<span class="op">;</span>
<span class="op">};</span>
<span class="va">self</span>.<span class="at">update</span> <span class="op">=</span> <span class="kw">function</span>(origMember<span class="op">,</span> editMember) <span class="op">{</span>
<span class="kw">var</span> parameters <span class="op">=</span> [<span class="va">editMember</span>.<span class="at">id</span><span class="op">,</span> <span class="va">editMember</span>.<span class="at">title</span><span class="op">,</span> <span class="va">origMember</span>.<span class="at">id</span>]<span class="op">;</span>
<span class="cf">return</span> <span class="va">DBA</span>.<span class="at">query</span>(<span class="st">"UPDATE bookshelf SET id = (?), title = (?) WHERE id = (?)"</span><span class="op">,</span> parameters)<span class="op">;</span>
<span class="op">};</span>
<span class="cf">return</span> self<span class="op">;</span>
<span class="op">}</span>)</code></pre></div>
<h3 id="上传数据">上传数据</h3>
<h3 id="练习建议-1">练习建议</h3>
<h1 id="制作专属badge">制作专属Badge</h1>
<h2 id="概况-2">概况</h2>
<h3 id="背景-2">背景</h3>
<p>前几天,再次看到一些CI的Badge的时候,就想着要做一个自己的Badge:</p>
<figure>
<img src="http://ideabook.phodal.com/images/badge.png" alt="Badge" /><figcaption>Badge</figcaption>
</figure>
<p>接着,我就找了个图形工具简单地先设计了下面的一个Badge:</p>
<figure>
<img src="http://ideabook.phodal.com/images/demo.png" alt="Demo" /><figcaption>Demo</figcaption>
</figure>
<p>生成的格式是SVG,接着我就打开SVG看看里面发现了什么。</p>
<div class="sourceCode"><pre class="sourceCode xml"><code class="sourceCode xml"><span class="kw"><?xml</span> version="1.0" encoding="UTF-8" standalone="no"<span class="kw">?></span>
<span class="kw"><svg</span><span class="ot"> width=</span><span class="st">"1006px"</span><span class="ot"> height=</span><span class="st">"150px"</span><span class="ot"> viewBox=</span><span class="st">"0 0 1006 150"</span><span class="ot"> version=</span><span class="st">"1.1"</span><span class="ot"> xmlns=</span><span class="st">"http://www.w3.org/2000/svg"</span><span class="ot"> xmlns:xlink=</span><span class="st">"http://www.w3.org/1999/xlink"</span><span class="kw">></span>
<span class="co"><!-- Generator: Sketch 3.7 (28169) - http://www.bohemiancoding.com/sketch --></span>
<span class="kw"><title></span>phodal<span class="kw"></title></span>
<span class="kw"><desc></span>Created with Sketch.<span class="kw"></desc></span>
<span class="kw"><defs></defs></span>
<span class="kw"><g</span><span class="ot"> id=</span><span class="st">"Page-1"</span><span class="ot"> stroke=</span><span class="st">"none"</span><span class="ot"> stroke-width=</span><span class="st">"1"</span><span class="ot"> fill=</span><span class="st">"none"</span><span class="ot"> fill-rule=</span><span class="st">"evenodd"</span><span class="kw">></span>
<span class="kw"><rect</span><span class="ot"> id=</span><span class="st">"Rectangle-1"</span><span class="ot"> fill=</span><span class="st">"#5E6772"</span><span class="ot"> style=</span><span class="st">"mix-blend-mode: hue;"</span><span class="ot"> x=</span><span class="st">"0"</span><span class="ot"> y=</span><span class="st">"0"</span><span class="ot"> width=</span><span class="st">"640"</span><span class="ot"> height=</span><span class="st">"150"</span><span class="kw">></rect></span>
<span class="kw"><rect</span><span class="ot"> id=</span><span class="st">"Rectangle-1"</span><span class="ot"> fill=</span><span class="st">"#2196F3"</span><span class="ot"> style=</span><span class="st">"mix-blend-mode: hue;"</span><span class="ot"> x=</span><span class="st">"640"</span><span class="ot"> y=</span><span class="st">"0"</span><span class="ot"> width=</span><span class="st">"366"</span><span class="ot"> height=</span><span class="st">"150"</span><span class="kw">></rect></span>
<span class="kw"><text</span><span class="ot"> id=</span><span class="st">"PHODAL"</span><span class="ot"> font-family=</span><span class="st">"Helvetica"</span><span class="ot"> font-size=</span><span class="st">"120"</span><span class="ot"> font-weight=</span><span class="st">"normal"</span><span class="ot"> fill=</span><span class="st">"#FFFFFF"</span><span class="kw">></span>
<span class="kw"><tspan</span><span class="ot"> x=</span><span class="st">"83"</span><span class="ot"> y=</span><span class="st">"119"</span><span class="kw">></span>PHODAL<span class="kw"></tspan></span>
<span class="kw"></text></span>
<span class="kw"><text</span><span class="ot"> id=</span><span class="st">"idea"</span><span class="ot"> font-family=</span><span class="st">"Helvetica"</span><span class="ot"> font-size=</span><span class="st">"120"</span><span class="ot"> font-weight=</span><span class="st">"normal"</span><span class="ot"> fill=</span><span class="st">"#FFFFFF"</span><span class="kw">></span>
<span class="kw"><tspan</span><span class="ot"> x=</span><span class="st">"704"</span><span class="ot"> y=</span><span class="st">"122"</span><span class="kw">></span>idea<span class="kw"></tspan></span>
<span class="kw"></text></span>
<span class="kw"></g></span>
<span class="kw"></svg></span></code></pre></div>
<p>看了看代码很简单,我就想这可以用代码生成——我就可以生成出不同的样子了。</p>
<h3 id="showcase-2">ShowCase</h3>
<figure>
<img src="http://ideabook.phodal.com/images/finally-brand.jpg" alt="Finally" /><figcaption>Finally</figcaption>
</figure>
<p>代码: GitHub: <a href="https://github.com/phodal/brand" class="uri">https://github.com/phodal/brand</a></p>
<h3 id="svg与svgwrite">SVG与SVGWrite</h3>
<p>SVG就是一个XML</p>
<blockquote>
<p>可缩放矢量图形(Scalable Vector Graphics,SVG) ,是一种用来描述二维矢量图形的XML 标记语言。</p>
</blockquote>
<p>要对这个XML进行修改也是一件很容易的事。只是,先找了PIL发现不支持,就找到了一个名为SVGWrite的工具。</p>
<blockquote>
<p>A Python library to create SVG drawings.</p>
</blockquote>
<h2 id="步骤-2">步骤</h2>
<h3 id="step-1-基本图形">Step 1: 基本图形</h3>
<p>示例代码如下:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python"><span class="im">import</span> svgwrite
dwg <span class="op">=</span> svgwrite.Drawing(<span class="st">'test.svg'</span>, profile<span class="op">=</span><span class="st">'tiny'</span>)
dwg.add(dwg.line((<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">10</span>, <span class="dv">0</span>), stroke<span class="op">=</span>svgwrite.rgb(<span class="dv">10</span>, <span class="dv">10</span>, <span class="dv">16</span>, <span class="st">'%'</span>)))
dwg.add(dwg.text(<span class="st">'Test'</span>, insert<span class="op">=</span>(<span class="dv">0</span>, <span class="fl">0.2</span>)))
dwg.save()</code></pre></div>
<p>然后我就照猫画虎地写了一个:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python"><span class="im">import</span> svgwrite
dwg <span class="op">=</span> svgwrite.Drawing(<span class="st">'idea.svg'</span>, profile<span class="op">=</span><span class="st">'full'</span>, size<span class="op">=</span>(<span class="st">u'1006'</span>, <span class="st">u'150'</span>))
shapes <span class="op">=</span> dwg.add(dwg.g(<span class="bu">id</span><span class="op">=</span><span class="st">'shapes'</span>, fill<span class="op">=</span><span class="st">'none'</span>))
shapes.add(dwg.rect((<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">640</span>, <span class="dv">150</span>), fill<span class="op">=</span><span class="st">'#5E6772'</span>))
shapes.add(dwg.rect((<span class="dv">640</span>, <span class="dv">0</span>), (<span class="dv">366</span>, <span class="dv">150</span>), fill<span class="op">=</span><span class="st">'#2196F3'</span>))
shapes.add(dwg.text(<span class="st">'PHODAL'</span>, insert<span class="op">=</span>(<span class="dv">83</span>, <span class="dv">119</span>), fill<span class="op">=</span><span class="st">'#FFFFFF'</span>,font_size<span class="op">=</span><span class="dv">120</span>, font_family<span class="op">=</span><span class="st">'Helvetica'</span>))
shapes.add(dwg.text(<span class="st">'idea'</span>, insert<span class="op">=</span>(<span class="dv">704</span>, <span class="dv">122</span>), fill<span class="op">=</span><span class="st">'#FFFFFF'</span>, font_size<span class="op">=</span><span class="dv">120</span>, font_family<span class="op">=</span><span class="st">'Helvetica'</span>))
dwg.save()</code></pre></div>
<p>发现和上面的样式几乎是一样的,就顺手做了剩下的几个。然后想了想,我这样做都一样,一点都不好看。</p>
<h3 id="step-2-高级badge">Step 2: 高级Badge</h3>
<p>第一眼看到</p>
<figure>
<img src="http://ideabook.phodal.com/images/brand-idea-prototype.jpg" alt="Idea Prototype" /><figcaption>Idea Prototype</figcaption>
</figure>
<p>我就想着要不和这个一样好了,不就是画几条线的事么。</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">
<span class="kw">def</span> draw_for_bg_plus():
<span class="cf">for</span> x <span class="op">in</span> <span class="bu">range</span>(y_text_split <span class="op">+</span> rect_length, width, rect_length):
shapes.add(dwg.line((x, <span class="dv">0</span>), (x, height), stroke<span class="op">=</span><span class="st">'#EEEEEE'</span>, stroke_opacity<span class="op">=</span><span class="fl">0.3</span>))
<span class="cf">for</span> y <span class="op">in</span> <span class="bu">range</span>(rect_length, height, rect_length):
shapes.add(dwg.line((y_text_split, y), (width, y), stroke<span class="op">=</span><span class="st">'#EEEEEE'</span>, stroke_opacity<span class="op">=</span><span class="fl">0.3</span>))
<span class="cf">for</span> x <span class="op">in</span> <span class="bu">range</span>(y_text_split <span class="op">+</span> max_rect_length, width, max_rect_length):
<span class="cf">for</span> y <span class="op">in</span> <span class="bu">range</span>(<span class="dv">0</span>, height, max_rect_length):
shapes.add(dwg.line((x, y <span class="op">-</span> <span class="dv">4</span>), (x, y <span class="op">+</span> <span class="dv">4</span>), stroke<span class="op">=</span><span class="st">'#EEEEEE'</span>, stroke_width<span class="op">=</span><span class="st">'2'</span>, stroke_opacity<span class="op">=</span><span class="fl">0.4</span>))
<span class="cf">for</span> y <span class="op">in</span> <span class="bu">range</span>(<span class="dv">0</span>, height, max_rect_length):
<span class="cf">for</span> x <span class="op">in</span> <span class="bu">range</span>(y_text_split <span class="op">+</span> max_rect_length, width, max_rect_length):
shapes.add(dwg.line((x <span class="op">-</span> <span class="dv">4</span>, y), (x <span class="op">+</span> <span class="dv">4</span>, y), stroke<span class="op">=</span><span class="st">'#EEEEEE'</span>, stroke_width<span class="op">=</span><span class="st">'2'</span>, stroke_opacity<span class="op">=</span><span class="fl">0.4</span>))
draw_for_bg_plus()</code></pre></div>
<p>就有了下面的图,于是我又按照这种感觉来了好几下</p>
<figure>
<img src="http://ideabook.phodal.com/images/finally-brand.jpg" alt="Finally" /><figcaption>Finally</figcaption>
</figure>
<h3 id="step-3-完成">Step 3: 完成</h3>
<h2 id="练习建议-2">练习建议</h2>
<h1 id="微信文章编辑器">微信文章编辑器</h1>
<h2 id="概况-3">概况</h2>
<h3 id="背景-3">背景</h3>
<h3 id="showcase-3">ShowCase</h3>
<figure>
<img src="http://ideabook.phodal.com/images/congee.jpg" alt="Screenshot" /><figcaption>Screenshot</figcaption>
</figure>
<p>GitHub: <a href="https://github.com/phodal/congee" class="uri">https://github.com/phodal/congee</a></p>
<h3 id="ckeditor-ractive">CKEditor + Ractive</h3>
<p>选用怎样的前端框架是一个有趣的话题,我需要一个数据绑定和模板。首先,我排除了React这个框架,我觉得他的模板会给我带来一堆麻烦事。Angluar是一个不错的选择,但是考虑Angluar 2.0就放弃了,Backbone也用了那么久。Knockout.js又进入了我的视野,但是后来我发现数据绑定到模板有点难。最后选了Ractive,后来发现果然上手很轻松。</p>
<p>Ractive这个框架比React诞生早了一个月,还是以DOM为核心。Ractive自称是一个模板驱动UI的库,在Github上说是下一代的DOM操作。因为Virtual Dom的出现,这个框架并没有那么流行。</p>
<p>起先,这个框架是在卫报创建的用于产生新闻的应用程序 。有很多工具可以帮助我们构建Web应用程序 ,但是很少会考虑基本的问题:HTML,一个优秀的静态模板,但是并没有为交互设计。Ractive可以将一个模板插到DOM中,并且可以动态的改变它。</p>
<h2 id="步骤-3">步骤</h2>
<p>在创建这个项目的时候,我的迭代过程大致如下:</p>
<ul>
<li>创建hello,world —— 结合不同的几个框架</li>
<li>创建基本的样式集</li>
<li>引用ColorPicker来对颜色进行处理</li>
<li>重构代码</li>
</ul>
<h3 id="step-1-helloworld">Step 1: hello,world</h3>
<p>下面是一个简单的hello,world。</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"> <span class="kw"><script</span><span class="ot"> id=</span><span class="st">'template'</span><span class="ot"> type=</span><span class="st">'text/ractive'</span><span class="kw">></span>
<span class="op"><</span>p<span class="op">></span>Hello<span class="op">,</span> <span class="op">{{</span>name<span class="op">}}!<</span><span class="ss">/p></span>
<span class="ss"> </script</span><span class="op">></span>
<span class="op"><</span>script<span class="op">></span>
<span class="kw">var</span> ractive <span class="op">=</span> <span class="kw">new</span> <span class="at">Ractive</span>(<span class="op">{</span>
<span class="dt">template</span><span class="op">:</span> <span class="st">'#template'</span><span class="op">,</span>
<span class="dt">data</span><span class="op">:</span> <span class="op">{</span> <span class="dt">name</span><span class="op">:</span> <span class="st">'world'</span> <span class="op">}</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op"><</span><span class="ss">/script></span></code></pre></div>
<p>这个hello,world和一般的MVC框架并没有太大区别,甚至和我们用的Backbone很像。然后,让我们来看一个事件的例子:</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">listView <span class="op">=</span> <span class="kw">new</span> <span class="at">Ractive</span>(<span class="op">{</span>
<span class="dt">el</span><span class="op">:</span> <span class="st">'sandboxTitle'</span><span class="op">,</span>
<span class="dt">template</span><span class="op">:</span> listTemplate<span class="op">,</span>
<span class="dt">data</span><span class="op">:</span> <span class="op">{</span><span class="dt">color</span><span class="op">:</span> <span class="va">config</span>.<span class="at">defaultColor</span><span class="op">,</span> <span class="st">'fontSize'</span><span class="op">:</span> <span class="va">config</span>.<span class="at">defaultFontSize</span><span class="op">}</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="va">listView</span>.<span class="at">on</span>(<span class="st">'changeColor'</span><span class="op">,</span> <span class="kw">function</span> (args) <span class="op">{</span>
<span class="va">listView</span>.<span class="at">set</span>(<span class="st">'color'</span><span class="op">,</span> <span class="va">args</span>.<span class="at">color</span>)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span></code></pre></div>
<p>这是在监听,意味着你需要在某个地方Fire这个事件:</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">titleView</span>.<span class="at">fire</span>(<span class="st">'changeColor'</span><span class="op">,</span> <span class="op">{</span><span class="dt">color</span><span class="op">:</span> <span class="va">color</span>.<span class="at">toHexString</span>()<span class="op">}</span>)<span class="op">;</span></code></pre></div>
<p>接着,问题来了,这和我们jQuery的on,或者React的handleClick似乎没有太大的区别。接着Component来了:</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"> <span class="kw">var</span> Grid <span class="op">=</span> <span class="va">Ractive</span>.<span class="at">extend</span>(<span class="op">{</span>
<span class="dt">isolated</span><span class="op">:</span> <span class="kw">false</span><span class="op">,</span>
<span class="dt">template</span><span class="op">:</span> parasTemplate<span class="op">,</span>
<span class="dt">data</span><span class="op">:</span> <span class="op">{</span>
<span class="op">}</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="kw">var</span> dataValue <span class="op">=</span> <span class="dv">5</span><span class="op">;</span>
<span class="kw">var</span> category <span class="op">=</span> <span class="st">'category-3'</span><span class="op">;</span>
<span class="kw">var</span> color <span class="op">=</span> <span class="va">config</span>.<span class="at">defaultColor</span><span class="op">;</span>
parasView <span class="op">=</span> <span class="kw">new</span> <span class="at">Ractive</span>(<span class="op">{</span>
<span class="dt">el</span><span class="op">:</span> <span class="st">'parasSanbox'</span><span class="op">,</span>
<span class="dt">template</span><span class="op">:</span> <span class="st">'<Grid Style="{{styles}}" />'</span><span class="op">,</span>
<span class="dt">components</span><span class="op">:</span> <span class="op">{</span><span class="dt">Grid</span><span class="op">:</span> Grid<span class="op">},</span>
<span class="dt">data</span><span class="op">:</span> <span class="op">{</span>
<span class="dt">styles</span><span class="op">:</span> [
<span class="op">{</span><span class="dt">section_style</span><span class="op">:</span> <span class="st">'border: 2px dotted #4caf50; margin: 8px 14px; padding: 10px; border-radius: 14px;'</span><span class="op">,</span> <span class="dt">p_style</span><span class="op">:</span> <span class="st">'font-size: 14px;'</span><span class="op">,</span> <span class="dt">color</span><span class="op">:</span> color<span class="op">,</span> <span class="dt">data_value</span><span class="op">:</span> dataValue<span class="op">,</span> <span class="dt">category</span><span class="op">:</span> category<span class="op">},</span>
]
<span class="op">}</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="va">parasView</span>.<span class="at">on</span>(<span class="st">'changeColor'</span><span class="op">,</span> <span class="kw">function</span>(args) <span class="op">{</span>
<span class="va">parasView</span>.<span class="at">findComponent</span>(<span class="st">'Grid'</span>).<span class="at">set</span>(<span class="st">'Style.*.color'</span><span class="op">,</span> <span class="va">args</span>.<span class="at">color</span>)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span></code></pre></div>
<p>上面是在<a href="https://github.com/phodal/congee" class="uri">https://github.com/phodal/congee</a>中用到的多个模板的View,他们用了同一个component。</p>
<p>对比和介绍就在这里结束了,我们就可以开始这个项目的实战了。</p>
<h3 id="step-2-require.js模块化">Step 2: Require.js模块化</h3>
<p>同样的在这里,我们也使用Require.js来作模块化和依赖管理。我们的项目的配置如下:</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="at">require</span>([<span class="st">'scripts/app'</span><span class="op">,</span> <span class="st">'ractive'</span><span class="op">,</span> <span class="st">'scripts/views/titleView'</span><span class="op">,</span> <span class="st">'scripts/views/hrView'</span><span class="op">,</span> <span class="st">'scripts/views/parasView'</span><span class="op">,</span> <span class="st">'scripts/views/followView'</span><span class="op">,</span> <span class="st">'jquery'</span><span class="op">,</span> <span class="st">'spectrum'</span>]<span class="op">,</span>
<span class="kw">function</span> (App<span class="op">,</span> Ractive<span class="op">,</span> TitleView<span class="op">,</span> ParasView<span class="op">,</span> HRView<span class="op">,</span> FollowView<span class="op">,</span> $) <span class="op">{</span>
<span class="st">'use strict'</span><span class="op">;</span>
<span class="va">App</span>.<span class="at">init</span>()<span class="op">;</span>
<span class="va">Ractive</span>.<span class="at">DEBUG</span> <span class="op">=</span> <span class="kw">false</span><span class="op">;</span>
<span class="kw">var</span> config <span class="op">=</span> <span class="va">App</span>.<span class="at">config</span><span class="op">;</span>
<span class="kw">var</span> titleView <span class="op">=</span> <span class="va">TitleView</span>.<span class="at">init</span>(config)<span class="op">;</span>
<span class="kw">var</span> hrView <span class="op">=</span> <span class="va">HRView</span>.<span class="at">init</span>(config)<span class="op">;</span>
<span class="kw">var</span> parasView <span class="op">=</span> <span class="va">ParasView</span>.<span class="at">init</span>(config)<span class="op">;</span>
<span class="kw">var</span> followView <span class="op">=</span> <span class="va">FollowView</span>.<span class="at">init</span>(config)<span class="op">;</span>
<span class="va">App</span>.<span class="at">colorPicker</span>(<span class="kw">function</span> (color) <span class="op">{</span>
<span class="va">hrView</span>.<span class="at">fire</span>(<span class="st">'changeColor'</span><span class="op">,</span> <span class="op">{</span><span class="dt">color</span><span class="op">:</span> <span class="va">color</span>.<span class="at">toHexString</span>()<span class="op">}</span>)<span class="op">;</span>
<span class="va">titleView</span>.<span class="at">fire</span>(<span class="st">'changeColor'</span><span class="op">,</span> <span class="op">{</span><span class="dt">color</span><span class="op">:</span> <span class="va">color</span>.<span class="at">toHexString</span>()<span class="op">}</span>)<span class="op">;</span>
<span class="va">parasView</span>.<span class="at">fire</span>(<span class="st">'changeColor'</span><span class="op">,</span> <span class="op">{</span><span class="dt">color</span><span class="op">:</span> <span class="va">color</span>.<span class="at">toHexString</span>()<span class="op">}</span>)<span class="op">;</span>
<span class="va">followView</span>.<span class="at">fire</span>(<span class="st">'changeColor'</span><span class="op">,</span> <span class="op">{</span><span class="dt">color</span><span class="op">:</span> <span class="va">color</span>.<span class="at">toHexString</span>()<span class="op">}</span>)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="at">$</span>(<span class="st">'input#mpName'</span>).<span class="at">keyup</span>(<span class="kw">function</span> () <span class="op">{</span>
<span class="va">followView</span>.<span class="at">fire</span>(<span class="st">'changeName'</span><span class="op">,</span> <span class="op">{</span><span class="dt">mpName</span><span class="op">:</span> <span class="at">$</span>(<span class="kw">this</span>).<span class="at">val</span>()<span class="op">}</span>)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span></code></pre></div>
<p>在那之前,你自然需要先clone代码。然后在这里我们不同的几个模块进行初始化,并且为colorPicker配置了相应的监听事件。现在,让我们先到App模块中,看看我们做了些什么事?</p>
<h3 id="step-3-初始化">Step 3: 初始化</h3>
<p>初始化模块一共分为两部分,一部分是对CKEditor的初始化,一部分则是对colorPicker的初始化。</p>
<h4 id="ckeditor初始化">CKEditor初始化</h4>
<p>CKEditor自身的编辑器配置比较长,我们就不在这里面列出这些代码了。</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"> <span class="kw">var</span> init <span class="op">=</span> <span class="kw">function</span> () <span class="op">{</span>
<span class="co">/**</span>
<span class="co"> * </span>@license<span class="co"> Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.</span>
<span class="co"> * For licensing, see LICENSE.md or http://ckeditor.com/license</span>
<span class="co"> */</span>
<span class="va">CKEDITOR</span>.<span class="at">editorConfig</span> <span class="op">=</span> <span class="kw">function</span> (config) <span class="op">{</span>
<span class="co">// ...</span>
<span class="op">};</span>
<span class="kw">var</span> congee <span class="op">=</span> <span class="va">CKEDITOR</span>.<span class="at">replace</span>(<span class="st">'congee'</span><span class="op">,</span> <span class="op">{</span>
<span class="dt">uiColor</span><span class="op">:</span> <span class="st">'#fafafa'</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="va">congee</span>.<span class="at">on</span>(<span class="st">'change'</span><span class="op">,</span> <span class="kw">function</span> (evt) <span class="op">{</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="va">congee</span>.<span class="at">on</span>(<span class="st">'instanceReady'</span><span class="op">,</span> <span class="kw">function</span> (ev) <span class="op">{</span>
<span class="at">$</span>(<span class="st">'.tabset8'</span>).<span class="at">pwstabs</span>(<span class="op">{</span>
<span class="dt">effect</span><span class="op">:</span> <span class="st">'slideleft'</span><span class="op">,</span>
<span class="dt">defaultTab</span><span class="op">:</span> <span class="dv">1</span><span class="op">,</span>
<span class="dt">tabsPosition</span><span class="op">:</span> <span class="st">'vertical'</span><span class="op">,</span>
<span class="dt">verticalPosition</span><span class="op">:</span> <span class="st">'left'</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="at">$</span>(<span class="st">'#Container'</span>).<span class="at">mixItUp</span>().<span class="at">on</span>(<span class="st">'click'</span><span class="op">,</span> <span class="st">'.mix'</span><span class="op">,</span> <span class="kw">function</span> (event) <span class="op">{</span>
<span class="kw">var</span> template <span class="op">=</span> <span class="at">$</span>(<span class="va">event</span>.<span class="at">currentTarget</span>).<span class="at">html</span>()<span class="op">;</span>
<span class="va">congee</span>.<span class="at">insertHtml</span>(template)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="at">$</span>(document).<span class="at">ready</span>(<span class="kw">function</span> () <span class="op">{</span>
<span class="at">$</span>(<span class="st">'#Container'</span>).<span class="at">niceScroll</span>(<span class="op">{</span>
<span class="dt">mousescrollstep</span><span class="op">:</span> <span class="dv">40</span>
<span class="op">}</span>)<span class="op">;</span>
<span class="op">}</span>)<span class="op">;</span></code></pre></div>
<p><code>instanceReady</code>事件主要就是在编程器初始化后进行的。因此我们在这里初始化了jQuery插件PWS Tabs,以及jQuery插件mixItUp,他们用于进行页面的排版。</p>
<h4 id="colorpicker初始化">ColorPicker初始化</h4>
<p>下面的代码便是对ColorPicker进行初始化,我们设置了几个常用的颜色放在调色板上。</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"> <span class="kw">var</span> colorPicker <span class="op">=</span> <span class="kw">function</span> (changeCB) <span class="op">{</span>
<span class="at">$</span>(<span class="st">'#colorpicker'</span>).<span class="at">spectrum</span>(<span class="op">{</span>
<span class="dt">showPaletteOnly</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span>
<span class="dt">togglePaletteOnly</span><span class="op">:</span> <span class="kw">true</span><span class="op">,</span>
<span class="dt">togglePaletteMoreText</span><span class="op">:</span> <span class="st">'more'</span><span class="op">,</span>
<span class="dt">togglePaletteLessText</span><span class="op">:</span> <span class="st">'less'</span><span class="op">,</span>
<span class="dt">color</span><span class="op">:</span> <span class="st">'#4caf50'</span><span class="op">,</span>
<span class="dt">palette</span><span class="op">:</span> [
[<span class="st">'#1abc9c'</span><span class="op">,</span> <span class="st">'#16a085'</span><span class="op">,</span> <span class="st">'#2ecc71'</span><span class="op">,</span> <span class="st">'#27ae60'</span><span class="op">,</span> <span class="st">'#4caf50'</span><span class="op">,</span> <span class="st">'#8bc34a'</span><span class="op">,</span> <span class="st">'#cddc39'</span>]<span class="op">,</span>
[<span class="st">'#3498db'</span><span class="op">,</span> <span class="st">'#2980b9'</span><span class="op">,</span> <span class="st">'#34495e'</span><span class="op">,</span> <span class="st">'#2c3e50'</span><span class="op">,</span> <span class="st">'#2196f3'</span><span class="op">,</span> <span class="st">'#03a9f4'</span><span class="op">,</span> <span class="st">'#00bcd4'</span><span class="op">,</span> <span class="st">'#009688'</span>]<span class="op">,</span>
[<span class="st">'#e74c3c'</span><span class="op">,</span> <span class="st">'#c0392b'</span><span class="op">,</span> <span class="st">'#f44336'</span>]<span class="op">,</span>
[<span class="st">'#e67e22'</span><span class="op">,</span> <span class="st">'#d35400'</span><span class="op">,</span> <span class="st">'#f39c12'</span><span class="op">,</span> <span class="st">'#ff9800'</span><span class="op">,</span> <span class="st">'#ff5722'</span><span class="op">,</span> <span class="st">'#ffc107'</span>]<span class="op">,</span>
[<span class="st">'#f1c40f'</span><span class="op">,</span> <span class="st">'#ffeb3b'</span>]<span class="op">,</span>
[<span class="st">'#9b59b6'</span><span class="op">,</span> <span class="st">'#8e44ad'</span><span class="op">,</span> <span class="st">'#9c27b0'</span><span class="op">,</span> <span class="st">'#673ab7'</span><span class="op">,</span> <span class="st">'#e91e63'</span><span class="op">,</span> <span class="st">'#3f51b5'</span>]<span class="op">,</span>
[<span class="st">'#795548'</span>]<span class="op">,</span>
[<span class="st">'#9e9e9e'</span><span class="op">,</span> <span class="st">'#607d8b'</span><span class="op">,</span> <span class="st">'#7f8c8d'</span><span class="op">,</span> <span class="st">'#95a5a6'</span><span class="op">,</span> <span class="st">'#bdc3c7'</span>]<span class="op">,</span>
[<span class="st">'#ecf0f1'</span><span class="op">,</span> <span class="st">'efefef'</span>]
]<span class="op">,</span>
<span class="dt">change</span><span class="op">:</span> changeCB
<span class="op">}</span>)<span class="op">;</span>
<span class="op">};</span></code></pre></div>
<p>而实际上在这里我们已经完成了大部分的工作。</p>
<h3 id="step-4-创建对应的view">Step 4: 创建对应的View</h3>
<p>在这个项目里,比较麻烦的地方就是使用同样的颜色来显示一个模板,如下的代码是用于显示水平线的模板:</p>
<pre><code>{{#hrStyle}}
<div class="mix {{.category}}" data-value={{.data_value}}>
<section {{#section_style}}style="{{.section_style}}"{{/section_style}}>
<p style="{{.p_style}}{{#color}};border-color: {{.color}};{{/color}}"></p>
</section>
</div>
{{/hrStyle}}</code></pre>
<p>下面的代码就是对应的View:</p>
<pre><code> parasView = new Ractive({
el: 'sandboxHr',
template: '<Grid hrStyle="{{styles}}" />',
components: {Grid: Grid},
data: {
styles: [
{section_style: '', p_style: 'background-color: #fff;border-top: 1px solid', color: color, data_value: dataValue, category: category},
{section_style: '', p_style: 'background-color: #fff;border-top: 3px double', color: color, data_value: dataValue, category: category},
{section_style: '', p_style: 'background-color: #fff;border-top: 1px dashed', color: color, data_value: dataValue, category: category},
{section_style: '', p_style: 'background-color: #fff;border-top: 1px dotted', color: color, data_value: dataValue, category: category},
{section_style: '', p_style: 'background-color: #fff;border-top: 2px dashed', color: color, data_value: dataValue, category: category},