程序员应知 — 怎么着剖析海量数据

短期原先的了,这时html伍刚出来不久啊,国外有人做了个用canvas来拼录像的玩耍,觉得挺好玩的,就模仿了一晃(模仿也是好久以往的事情了)

在那些云总结热炒的一世,要是您从未拍卖过海量数据的话,你将不再是个合格的Coder。未来不久补补吧~


前1阵子分析了三个靠近一TB的数据群(gz文件,压缩率一成)。因为第贰次分析如此高大的多寡,未有经历,所以浪费了许多日子。上面是自个儿整理的部分经历,方便后者。

用到的东西:

欢迎各个补充,笔者会不断更新那篇小说;觉得可行的话,速度分享链接;有两样意见的话,请果断拍砖;


  1. html5 canvas标签

下载数据

Q:怎么自动下载多少个文件?

那是自家碰着的首先个难点。当数据量非常的大时,壹般都会分成很多个文本存放。那时下载文件比较费心。

A:用Wget一声令下。Windows下开销一点时间去下载安装。但之于手动下载,能省不少时刻。

本身提供两种艺术艺术下载文件,

a)用Wget的递归下载选项 “-r”。一般命令如下

wget –r http://&lt;下载数据的根目录&gt;/  -o <下载记录文件名> 
-np

因为递归下载无法控制速度,所以提议不一要次递归下载太多的文件

b)用Bat+Wget,数十次推行Wget。1般命令如下

wget –r http://&lt;下载数据的根目录分支1&gt;/  -o
<下载记录文件名>  -np

wget –r http://&lt;下载数据的根目录分支2&gt;/  -o
<下载记录文件名>  -np

wget –r http://&lt;下载数据的根目录分支3&gt;/  -o
<下载记录文件名>  -np

…… ……

wget –r http://&lt;下载数据的根目录分支N&gt;/  -o
<下载记录文件名>  -np

用Bat能够降低出错带来的熏陶。

其它,Wget能够透过 –A 选项来内定希望下载的公文的后辍,通过 –P
选项来钦赐下载文件存放路径。更加多命令,参见wget -h

Q:这速度。。。何时才能下完?

网速永远是个瓶颈

A:要是下载服务很远的话,你应有思考代理。wget设置代理的方法如下

set http_proxy=http://&lt;代理服务器&gt;

不要忘了多开多少个进度,18个试试?

   drawImage (视频源)

开拓文件

Q:怎么打开文本文件

那不是毫无作为难题。你用记事本打开二个一千MB的公文试试

A:LTF
viewer

Large Text File viewer, 打开速度会让您感叹

Q:怎么打开二进制文件

A:Hex Editor
Neo

您能够透过上边格局来抉择进制:

右击数据区 => Display As =>
Hex|Decimal|Octal|Binary|Float|Double

style=”color: #肆b4b四b;”>你能够通过下边格局来选取按多少字节呈现:

右击数据区 => Group By =>
Bytes|Words|Double|Quad

  

  1. html5 video标签

编制程序语言

style=”color: #4b肆b4b;”>当数据量十分大时,采用语言要慎重了。因为不一致语言有差异的特征,你要在编制程序时间和周转时刻里面权衡。

模型测试

style=”color: #四b四b四b;”>开首时,壹般挑几个小的数目开始展览测试,获取第叁份分析结果。那时当然期待能急速编制程序实现。脚本语言是3个很好的取舍,比如Python。

汪洋处理

style=”color: #4b四b肆b;”>起头遍历处理全体数据时,用脚本语言来处理就不太适合了。因为脚本语言的运作时刻不可能令人接受。其余,还有内部存款和储蓄器使用,文件读写那么些你都无法控制。不幸的是,很少语言会为您处理海量文件做优化。

此刻,C/C++是最棒的选取。

结果显示

style=”color: #4b四b4b;”>漫长的等候终于过去了,眼看就要出结果了。假诺您还执着于陪伴你度过漫长等待的C/C++的话,你迟早会失落的。

style=”color: #肆b4b四b;”>笔者尝试了许多主意现在,得出的结论是,让Matlab来接手C/C++。Matlab能轻易地浮现大批量多少。更关键的是Matlab帮忙读取 style=”color: #4b四b四b;”>贰进制 style=”color: #四b4b四b;”>文件。

filename = ‘out.bin’;        % binary file
fid = fopen( filename );
data = fread( fid, itemsNumber, ‘*uint32’);
fclose(fid);

  

  source属性(为了浏览器包容,须要四个录像来源)

算法

壹遍性读文件

本人一度测试过好三回了,二回性读取文件比1行壹行读文件至少快5倍

记住O(N)

此刻你要美丽思考算法的复杂度了。任何O(N2)的算法都不可取。

供给的时候能够透过空中来换时间。平常哈希表能省去数不胜数时刻。

并行处理

复习一下并行算法。那比等待单线程程序好广大。

能够思量在GPU上跑程序。当然,内部存款和储蓄器和文件读取时间更可能是瓶颈。

内存、CPU、磁盘读取速度,何人是瓶颈,职分管理器知道。

优化中央代码

常常五分之四的小时在运维百分之二十的代码。所以有空的话优化下经常常常举行的代码。

分布式保存

把分析结果存在三个文书中是两个很不好的决定。那会为后边处理带来很多劳神。比如并行处理,文件过大等。

2进制方式保存中间数据

2进制格局存放常常能省一半的磁盘空间。那同时意味着收缩四分之二的写硬盘时间和读硬盘时间。当然,还有文本转换时间。

还有个相当重要细节要小心:在Windows中,读写文件的办法要改成”rb”和”wb”。要不然莫名的Bug迟早要发出,但不必然能找到。

  1. JQuery

运行

Debug Vs Release

别忘了,最后运转时把编译格局换来Release。可是刚改完程序的话,建议先用Debug情势试跑一下。这样能稳定运转时十分。

批处理

批处理是降低运作出错风险的很好的诀窍。因为您不显明程序能健康截至。所以一段一段实施顺序是二个很好的挑三拣四。如若有个别地点出题指标话就无须再行运维前边的先后了。

断言

当数据量十分的大时,很难保证输入是官方的。另一种状态是,数据是合法的,但我们欠思考了。这时断言就显得很重要了。断言回增添运营时刻,但总比花大批量时辰取得2个谬误结果好。

记录运维结果到文件

日前提到,数据量一点都不小时,很难保险程序不奇怪化甘休。一般,很少人会在荧屏旁坐等输出结果。把运营情况定时记录到文件是不行须要的。

除此以外,不要忘了fclose();

  选择器

附:610位编制程序难题

数据量十分的大时,内部存储器平日是不够用的。有三个常识必须了解:3多少人程序的最大寻址空间是二GB。假若您要分配接近或然超越贰G内部存储器的话,试试614位程序吗。当然有两原则:63人的CPU,陆十一个人的操作系统。

下边是编辑陆拾一位程序的壹部分经历

编写翻译环境

借使是解释型语言,比如Python,则须要下载2个63位的Python解释器

借使是编写翻译型语言,比如C/C++,则必要选拔合适的编写翻译平台。

诸如VS二零零六中,项目性质 => Configuration Manager => Platform
=> New => X6四

图片 1

内存

分配大数组,应该用malloc,而不是直接定义数组。

sizeof( int )  != sizeof( size_t )

60人程序中,数组下标应该换到size_t,常数也亟需强制转换,比如 四GB =
四*(size_t)1000000000000

文件

fwrite壹回性写入1个抢先四GB的数组仿佛不怎么难点。

分多次写入文件试试。

就写到那了,很晚了。。。

迎接种种补充,笔者会不断更新那篇小说;觉得可行的话,速度分享链接;有两样意见的话,果断拍砖;

  事件

好好评论

#8楼2010-12-03
09:03 |
LeftNotEasy     
那几个得顶,感激楼主的享用:)
本人也是常事做海量数据的分析,可是貌似是在分布式系统上。楼主怎么会用windows来做海量数据的剖析呢。
在单机上跑海量数据的拍卖,特别是教练模型之类的,一般很难达成的,很多锻炼模型的算法都务求数据可见在内部存款和储蓄器中保存。
在分布式的条件下,用python是卓有功能的,终究python的支付时间短,而且运营时刻比不上c++慢多少倍

#10楼2010-12-03
09:09 |
木鱼     
 

引用BAsil:不错,问个难点三拾1人程序的最大寻址空间为啥是2GB而不是四GB呢(二的三十一回方)?

叁拾个人系统寻址最大是四GB,因为硬件映射等导致的内部存款和储蓄器三.三G上述无法被系统选择,因而最大可选拔内设有三.三G,而操作系统是个多职分的系统,供给保留本人的内部存款和储蓄器空间并对种种程序运营的上空实行限制,在叁拾三人系统上那几个范围是二GB.固然经过PAE在三十人系统上帮忙超越四GB的内部存款和储蓄器,那个二GB的限制依然存在的.

#13楼2010-12-03
10:17 |
刘晓飞     
使用hadoop

#30楼2010-12-04
10:56 |
亚历山大理志      
1般分析超大日志文件都以一贯下载gzip压缩包,然后gcat,grep,awk啥的

  1. js对象方法

连锁文章

天命据量,海量数据
处理办法总计

图片 2图片 3快照

天命据量的题材是不少面试笔试中常常出现的题材,比如baidu
google 腾讯 那样的一对关系到海量数据的公司平时会问到。

上边包车型客车法子是自身对海量数据的拍卖格局开始展览了二个惯常的下结论,当然那么些艺术只怕并不可能完全覆盖全部的题材,可是这样的有的艺术也基本能够处理绝大多数相见的难点。下边包车型大巴片段题材大旨直接来源企业的面试笔试标题,方法不自然最优,假设你有更加好的拍卖措施,欢迎与自笔者谈谈。

1.Bloom filter

适用范围:能够用来兑现数据字典,进行数量的判重,也许集合求交集

基本原理及大旨:
对此原理来说很简单,位数组+k个独立hash函数。将hash函数对应的值的位数组置1,查找时只要发现具有hash函数对应位都以一说明存在,很备受关注这几个进度并不保证查找的结果是百分之百不利的。同时也不支持删除3个壹度插入的首要字,因为该关键字对应的位会拉动到别的的主要字。所以3个简易的革新便是counting Bloom filter,用三个counter数组代替位数组,就足以支撑删除了。

还有1个比较首要的题材,如何依照输入成分个数n,鲜明位数组m的轻重缓急及hash函数个数。当hash函数个数k=(ln二)*(m/n)时错误率最小。在错误率非常的小于E的图景下,m至少要等于n*lg(1/E)才能表示任意n个成分的联谊。但m还应该越来越大些,因为还要保险bit数组里至少二分一为0,则m应该>=nlg(1/E)*lge
大约便是nlg(1/E)壹.4肆倍(lg代表以贰为底的对数)。

举个例子我们倘诺错误率为0.0一,则此时m应差不多是n的一3倍。那样k大致是九个。

注意那里m与n的单位不一致,m是bit为单位,而n则是以成分个数为单位(准确的身为区别因素的个数)。平时单个成分的长度皆以有很多bit的。所以使用bloom
filter内部存款和储蓄器上平日都以省去的。

扩展:
Bloom
filter将集纳中的成分映射到位数组中,用k(k为哈希函数个数)个映射位是不是全一表示成分在不在这一个集合中。Counting
bloom
filter(CBF)将位数组中的每1个人扩充为贰个counter,从而帮助了成分的删除操作。Spectral
Bloom
Filter(SBF)将其与集合成分的产出次数关联。SBF接纳counter中的最小值来就像是表示元素的面世频率。

题材实例:给你A,B四个文本,各存放50亿条USportageL,每条ULX570L占用64字节,内部存款和储蓄器限制是四G,让你找出A,B文件共同的U奇骏L。假如是四个甚至n个文件呢?

听大人说这一个难题我们来测算下内存的占据,4G=二^3贰大概是40亿*八大概是340亿,n=50亿,就算按出错率0.0一算须要的大概是650亿个bit。未来可用的是340亿,相差并不多,那样恐怕会使出错率上涨些。别的倘使那么些urlip是各种对应的,就能够转换来ip,则大大简单了。

2.Hashing

适用范围:火速搜索,删除的骨干数据结构,平常需求总数据量能够放入内存

基本原理及中央:
hash函数采纳,针对字符串,整数,排列,具体对应的hash方法。
碰撞处理,①种是open hashing,也号称拉链法;另1种正是closed
hashing,也称开地址法,opened addressing。

扩展:
d-left
hashing中的d是五个的意思,我们先简化那个难点,看壹看2-left
hashing。二-left
hashing指的是将1个哈希表分成长度相等的两半,分别叫做T1和T2,给T一和T贰分别布署3个哈希函数,h一和h2。在储存二个新的key时,同时用多个哈希函数举行总括,得出多少个地点h1[key]和h2[key]。这时急需检查T第11中学的h一[key]位置和T2中的h2[key]职位,哪3个职位已经储存的(有冲击的)key相比多,然后将新key存款和储蓄在负载少的岗位。假若两边壹样多,比如五个任务都为空可能都存储了2个key,就把新key
存款和储蓄在左侧的T1子表中,贰-left也由此而来。在搜索1个key时,必须进行四遍hash,同时招来七个职责。

题材实例:
一).海量日志数据,提取出某日访问百度次数最多的越发IP。

IP的多寡依然有限的,最多2^三12个,所以能够思念采纳hash将ip直接存入内部存款和储蓄器,然后实行总括。

3.bit-map

适用范围:可开始展览数据的神速搜索,判重,删除,1般的话多少范围是int的十倍以下

基本原理及中央:使用bit数组来表示有些因素是或不是存在,比如7人电话号码

扩大:bloom filter能够作为是对bit-map的壮大

难题实例:

一)已知有些文件内涵盖部分电话号码,每个号码为7个人数字,总结分歧号码的个数。

六个人最多9九 99999玖,差不多要求9玖m个bit,大约十几m字节的内部存款和储蓄器即可。

二)2.5亿个整数中找出不另行的平头的个数,内部存款和储蓄器空间不足以容纳那贰.5亿个整数。

将bit-map扩充一下,用贰bit表示一个数即可,0代表未出现,一意味着出现1回,贰意味出现三回及以上。只怕大家不用2bit来进展表示,大家用五个bit-map即可模拟达成那几个2bit-map。

4.堆

适用范围:海量数据前n大,并且n比较小,堆能够放入内存

基本原理及宗旨:最大堆求前n小,最小堆求前n大。方法,比如求前n小,大家比较当前因素与最大堆里的最大因素,如若它小于最大因素,则应该替换那几个最大要素。这样结尾收获的n个成分正是细微的n个。适合大数据量,求前n小,n的大小相比小的场所,那样可以扫描一回即可得到全数的前n成分,效用很高。

增加:双堆,一个最大堆与一个小小堆结合,能够用来保证中位数。

题材实例:
壹)100w个数中找最大的前100个数。

用八个917个因素大小的最小堆即可。

伍.双层桶划分

适用范围:第k大,中位数,不另行或另行的数字

基本原理及主题:因为成分范围极大,不能够应用直接寻址表,所以经过反复划分,稳步显明限制,然后最终在一个足以接受的限制内开始展览。能够由此反复紧缩,双层只是二个例证。

扩展:

难点实例:
1).二.5亿个整数中找出不另行的平头的个数,内部存款和储蓄器空间不足以容纳这二.5亿个整数。

有点像鸽巢原理,整数个数为二^3贰,也正是,大家能够将那二^叁13个数,划分为2^7个区域(比如用单个文件表示贰个区域),然后将数据分离到差异的区域,然后差别的区域在动用bitmap就能够间接化解了。约等于说只要有充裕的磁盘空间,就能够很便宜的解决。

二).五亿个int找它们的中位数。

其一例子比地点十三分更举世瞩目。首先大家将int划分为二^十七个区域,然后读取数据总括落到每个地方里的数的个数,之后大家依照总结结果就足以看清中位数落到丰裕区域,同时领悟这些区域中的第几大数刚好是中位数。然后第三回扫描大家只总计落在那一个区域中的那1个数就足以了。

其实,假诺不是int是int6四,大家得以经过1回那样的撤销合并即可下降到还行的程度。即能够先将int64分成2^27个区域,然后明确区域的第几大数,在将该区域分为贰^十八个子区域,然后鲜明是子区域的第几大数,然后子区域里的数的个数唯有二^20,就足以从来动用direct addr table实行计算了。

六.数据库索引

适用范围:大数据量的增加和删除改查

基本原理及中央:利用多少的统筹完毕情势,对海量数据的增加和删除改查举办拍卖。
扩展:
题材实例:

柒.倒排索引(Inverted index)

适用范围:搜索引擎,关键字查询

基本原理及中央:为啥叫倒排索引?1种索引方法,被用来储存在全文字笔迹检查评定索下有个别单词在3个文书档案恐怕一组文书档案中的存款和储蓄地点的炫耀。

以英文为例,上边是要被索引的公文:
T0 =”it is what
it is”
T1 =”what is
it”
T2 =”it is a
banana”
大家就能获取上边包车型大巴反向文件目录:
“a”:
{2}
“banana”:
{2}
“is”:
{0, 1,
2}
“it”:
{0, 1,
2}
“what”:
{0, 1}
寻找的口径”what”,
“is” 和
“it”
将对应集合的混杂。

正向索引开发出来用来囤积每个文书档案的单词的列表。正向索引的询问往往满意每一个文书档案有序频仍的全文查询和各类单词在校验文书档案中的验证这样的询问。在正向索引中,文书档案占据了宗旨的职位,每一种文书档案指向了3个它所包含的索引项的行列。也正是说文书档案指向了它涵盖的那3个单词,而反向索引则是单词指向了涵盖它的文书档案,很不难见到这几个反向的关联。

扩展:

难题实例:文书档案检索系统,查询那多少个文件包括了某单词,比如大规模的学术故事集的重点字搜索。

8.外排序

适用范围:大数额的排序,去重

基本原理及大旨:向外排水序的统1措施,置换选拔 败者树原理,最优归并树

扩展:

标题实例:
一).有2个一G大大小小的三个文本,里面每1行是一个词,词的大小不抢先十七个字节,内部存储器限制大小是1M。再次回到频数最高的玖拾九个词。

那一个数量有所很显明的特点,词的大小为拾8个字节,不过内部存储器只有一m做hash有个别不够,所以能够用来排序。内部存款和储蓄器能够当输入缓冲区使用。

9.trie树

适用范围:数据量大,重复多,可是数量系列小可以放入内部存款和储蓄器

基本原理及中央:实现格局,节点孩子的意味方法

扩张:压缩完结。

难点实例:
一).有11个公文,各个文件1G,
各种文件的每1行都存放的是用户的query,各种文件的query都可能重新。要你依照query的频度排序

2).一千万字符串,个中多少是平等的(重复),须求把重复的任何去掉,保留未有重新的字符串。请问怎么统一筹划和促成?

三).寻找热门查询:查询串的重复度相比高,尽管总数是一千万,但假设除去重复后,不超越3百万个,每一种不抢先25五字节。

10.分布式处理 mapreduce

适用范围:数据量大,但是数量类别小能够放入内部存款和储蓄器

基本原理及宗旨:将数据交由差别的机械去处理,数据划分,结果归约。

扩展:

题材实例:

1).The canonical example application of MapReduce
is a process to count the appearances of

each different word in a set of
documents:
void map(String name, String document):
// name: document name
// document: document contents
for each word w in
document:
EmitIntermediate(w, 1);

void reduce(String word, Iterator partialCounts):
// key: a word
// values: a list of aggregated partial
counts
int result =0;
for each v in
partialCounts:
result += ParseInt(v);
Emit(result);
Here, each document is split in words,
and each word is counted initially with a “1” value
by

the Map function, using the word as the
result key. The framework puts together all the pairs

with the same key and feeds them to the same call to Reduce, thus
this function just needs to

sum all of its input values to find the total appearances of that
word.

2).海量数据分布在100台计算机中,想个办法高效总结出那批数量的TOP10。

叁).一共有N个机器,每种机器上有N个数。每种机器最多存O(N)个数并对它们操作。怎么着找到N^三个数的中数(median)?

经典难题浅析

上千万or亿多少(有再度),计算个中出现次数最多的前N个数据,分三种状态:可三次读入内部存款和储蓄器,不可贰回读入。

可用思路:trie树+堆,数据库索引,划分子集分别总结,hash,分布式计算,近似总结,向外排水序

所谓的是不是能叁次读入内部存款和储蓄器,实际上应该指去除重复后的数据量。假若去重后数据能够放入内部存款和储蓄器,我们得以为数据建立字典,比如通过
map,hashmap,trie,然后径直开始展览总结即可。当然在更新每条数据的面世次数的时候,大家得以行使一个堆来保卫安全出现次数最多的前N个数据,当然如此造成维护次数扩大,比不上完全总结后在求前N大功能高。

即使数额不能够放入内部存款和储蓄器。1方面大家可以设想地点的字典方法是或不是被勘误以适应那种意况,可以做的更动正是将字典存放到硬盘上,而不是内部存储器,那能够参见数据库的蕴藏方法。

自然还有更加好的法子,正是可以动用分布式总计,基本上正是map-reduce进程,首先能够依照数据值只怕把数量hash(md5)后的值,将数据依照范围划分到分歧的电话,最好能够让多少划分后方可3次读入内存,那样区别的电话机负责处理各样的数值范围,实际上正是map。获得结果后,各种机子只需拿出个别的现身次数最多的前N个数据,然后集聚,选出全部的多寡中出现次数最多的前N个数据,那事实上正是reduce进程。

实则大概想一向将数据均分到分裂的对讲机上进展拍卖,那样是无能为力获得不错的解的。因为三个多少可能被均分到差别的对讲机上,而另一个则大概完全聚集到1个电话上,同时还可能存在具有同样数量的数目。比如大家要找出现次数最多的前9拾陆个,大家将一千万的数据分布到拾台机器上,找到每台现身次数最多的前
917个,归并之后那样不能够保障找到真正的第七0个,因为比如出现次数最多的第玖0个大概有1万个,可是它被分到了10台机子,那样在每台上只有一千个,若是那么些电话名次在一千个在此以前的这些都以单独分布在一台机子上的,比如有拾0二个,那样自然具有一万个的那些就会被淘汰,固然大家让每台机子选出出现次数最多的一千个再归并,依旧会出错,因为可能存在多量个数为拾0贰个的发出聚集。因而不能够将数据随便均分到区别机子上,而是要遵照hash
后的值将它们映射到区别的对讲机上拍卖,让差异的机械处理一个数值范围。

除开排序的方法会消耗大批量的IO,效用不会很高。而地方的分布式方法,也能够用于单机版本,也便是将总的数据依据值的限制,划分成几个分化的子文件,然后依次处理。处理实现之后再对那么些单词的及其出现频率实行3个归并。实际上就能够行使三个外排序的汇合进程。

别的还足以设想近似计算,也正是大家能够经过整合自然语言属性,只将那个真正实际中出现最多的这多少个词作者为三个字典,使得那个层面足以放入内部存款和储蓄器。

转发请评释出处:http://duanple.blog.163.com/blog/static/7097176720091026458369/
作者phylips@bmy

参考文献:
http://blog.csdn.net/jiaomeng/archive/2007/03/08/1523940.aspx
d-Left Hashing
http://blog.csdn.net/jiaomeng/archive/2007/01/27/1495500.aspx
http://en.wikipedia.org/wiki/Bloom\_filter
http://hi.baidu.com/xdzhang\_china/blog/item/2847777e83fb020229388a15.html
应用Bloom Filter的多少个小技巧
http://zh.wikipedia.org/wiki/%E5%80%92%E6%8E%92%E7%B4%A2%E5%BC%95

MicroTeam Hui


效果图:

图片 4


以下为乱七八糟的代码

  1. 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
    31
    32

 

  1. guessWXS.js :

    一 ;
    二 var guessWXS = function (options) {
    叁 //定义变量,作者也记不清那1个从没选取,这一个运用了,只怪那时不佳好写注释!!!今后丢人现眼了。。。
    4 this.options = options; // 接收参数
    五 this.videoCtrlObj;
    6 this.canvasLst = new Array();
    7 this.canvasDivLst = new Array();
    八 this.positionTop = new Array();
    九 this.positionLeft = new Array();
    十 this.eachHeight = 0;
    1一 this.eachWidth = 0;
    12 this.wCount = 5;
    13 this.hCount = 4;
    1肆 this.canvasCount = this.wCount this.hCount;
    15 this.down = false;
    1陆 this.befPageX;
    1七 this.befPageY;
    1八 this.oldLeft;
    1玖 this.oldTop;
    20 this.oldZIndex;
    贰壹 this.divObj = null;
    2二 this.start = false;
    2三 this.win = false;
    二肆 this.wRate = 一;
    二5 this.hRate = 1;
    2陆 this.doInit(); // 调用初期化方法
    二7 }
    2八
    2九 guessWXS.prototype.doInit = function () {
    30 // 初期化方法
    3一 if ($(this.options.container).length > 0) {
    3二 var obj = this;
    3三 //video html
    34 $(this.options.container).append(this.options.videoHtml);
    35 //video attribute
    3陆 var videoObj = $(this.options.container).find(“video”).eq(0);
    三柒 $(videoObj).attr(“id”, this.options.id);
    38 var videoObjJs = document.getElementById(this.options.id);
    39 $(videoObj).hide(); // 隐藏video Tag (其实能够在js里处理好后,append 到镜头的)
    40 //calculate video and canvas
    41 this.wRate = this.options.width / this.options.videoWidth;
    4二 this.hRate = this.options.height / this.options.videoHeight;
    四三 //video source
    44 for (var i = 0; i < this.options.videoUrl.length; i++) { 45 videoObj.append("“);
    四6 }
    四7 //video control
    4八 var videoCtrl = document.getElementById(this.options.id);
    4九 this.videoCtrlObj = videoCtrl;
    50 //canvas list 使用多少个canvas来呈现三个录制的壹壹部分(切割摄像到canvas list)
    5一 var top = 0;
    5② var left = 0;
    53 var topStep = this.options.height / this.hCount;
    5四 var leftStep = this.options.width / this.wCount;
    55 var c = 0;
    56 var tempObj;
    五七 //console.log(topStep, leftStep);
    5八 for (var h = 0; h < this.hCount; h++) { 59 for (var w = 0; w < this.wCount; w++) { 60 tempObj = $(this.options.canvasHtml).css({ "position": "absolute", "top": (h % this.hCount)
    topStep, “left”: (w % this.wCount) leftStep, “border”: “0px red solid”, “margin”: 0, “overflow”: “hidden” });
    61 tempObj.width(leftStep).height(topStep);
    62 tempObj.find(“canvas”).attr(“id”, “canvasWXS” + c);
    63 $(this.options.container).append(tempObj);
    64 this.canvasLst.push(document.getElementById(“canvasWXS
    ” + c));
    6伍 this.canvasDivLst.push(tempObj);
    6陆 this.eachHeight = topStep;
    陆七 this.eachWidth = leftStep;
    6八 // 保存不易结果,用于判断游戏是或不是终止
    6玖 this.positionTop.push((h % this.hCount)
    topStep);
    70 this.positionLeft.push((w % this.wCount) leftStep);
    7壹 c++;
    7二 }
    7三 }
    74 // 对canvas 举办事件绑定
    7伍 for (var i = 0; i < this.canvasDivLst.length; i++) { 76 this.canvasDivLst[i].bind("mousedown", function () { obj.doCanvasDivMouseDown(this); }); 77 this.canvasDivLst[i].bind("mouseup", function () { obj.doCanvasDivMouseUp(this); }); 78 this.canvasDivLst[i].bind("mousemove", function () { obj.doCanvasDivMouseMove(this); }); 7玖 } 80 //videoCtrl.play(); 8一 // 绑定摄像播放事件,调用doTimeUpdate方法 八贰 this.Bind(videoCtrl, "timeupdate", this.doTimeUpdate, this); 八三 $("body").bind("mouseout", function () { 84 obj.down = false; 八5 if (obj.divObj != null) { 86 $(obj.divObj).css({ "z-index": obj.oldZIndex, "box-shadow": "0px 0px 0px 0px #000", "border": "none" }); 八7 $(obj.divObj).css({ "left": obj.oldLeft, "top": obj.oldTop }); 8捌 } 8九 }); 90 $(this.options.container).bind("click", function () { obj.doPlay(); }); 91 // 一秒后实施,其实能够在录像加载完后或加载一部分后再履行的 九二 setTimeout(function () { $(this.options.container).click();}, 一千); 玖三 } 九肆 }; 九五 九陆 guessWXS.prototype.doTimeUpdate = function () { 玖7 // 将近日的video图片,切割更新至canvas list 九8 var context; 9玖 var h = 0; 100 var w = 0; 10壹 var topStep = this.options.height / this.hCount; 十二 var leftStep = this.options.width / this.wCount; 拾叁 for (var i = 0; i < this.canvasLst.length; i++) { 104 context = this.canvasLst[i].getContext("2d"); 105 context.drawImage(this.videoCtrlObj, (w % this.wCount)
    leftStep / this.wRate, (h % this.hCount) topStep / this.hRate, leftStep / this.wRate, topStep / this.hRate, 0, 0, leftStep, topStep);
    拾陆 if ((i + 1) % this.wCount == 0) {
    十7 w = 0;
    十8 h++;
    拾九 } else {
    110 w++;
    11壹 }
    11二 }
    1一三 };
    11四
    115 guessWXS.prototype.doCanvasDivMouseDown = function (thisObj) {
    116 // 鼠标按下,醒目的注当前的那块canvas
    1一柒 event.preventDefault();
    11八 if (this.start && !this.down) {
    119 this.befPageX = event.pageX;
    120 this.befPageY = event.pageY;
    121 this.oldTop = parseInt($(thisObj).css(“top”).replace(/px/g, “”));
    12二 this.oldLeft = parseInt($(thisObj).css(“left”).replace(/px/g, “”));
    123 this.oldZIndex = $(thisObj).css(“z-index”);
    1二四 this.divObj = thisObj;
    1二五 this.down = true;
    1贰六 $(thisObj).css({ “z-index”: “99九”, “box-shadow”: “0px 0px 20px 十px #fff” });
    1二七 }
    12八 event.stopPropagation();
    12玖 };
    130
    13一 guessWXS.prototype.doCanvasDivMouseUp = function (thisObj) {
    13二 // 替换两块canvas的职位
    13三 event.preventDefault();
    13四 if (this.start && this.down) {
    13五 this.befPageX = 0;
    136 this.befPageY = 0;
    一3柒 this.divObj = null;
    13八 this.down = false;
    13九
    140 var tmpTop;
    14一 var tmpLeft;
    142 var curTop = parseInt($(thisObj).css(“top”).replace(/px/g, “”)) + this.eachHeight / 贰;
    1四三 var curLeft = parseInt($(thisObj).css(“left”).replace(/px/g, “”)) + this.eachWidth / 二;
    144 var backFlg = true;
    145 for (var i = 0; i < this.positionTop.length; i++) { 146 147 if ( 148 (this.positionTop[i] <= curTop && this.positionTop[i] + this.eachHeight >= curTop)
    149 && (this.positionLeft[i] <= curLeft && this.positionLeft[i] + this.eachWidth >= curLeft)
    150 ) {
    151 for (var j = 0; j < this.canvasDivLst.length; j++) { 152 tmpTop = parseInt($(this.canvasDivLst[j]).css("top").replace(/px/g, "")); 153 tmpLeft = parseInt($(this.canvasDivLst[j]).css("left").replace(/px/g, "")); 154 if (tmpTop == this.positionTop[i] && tmpLeft == this.positionLeft[i]) { 155 backFlg = false; 156 $(this.canvasDivLst[j]).css({ "left": this.oldLeft, "top": this.oldTop }); 157 $(thisObj).css({ "left": tmpLeft, "top": tmpTop }); 158 break; 159 } 160 } 161 } 162 if (!backFlg) { break; } 1陆叁 } 164 $(thisObj).css({ "z-index": this.oldZIndex, "box-shadow": "0px 0px 0px 0px #fff" }); 16伍 if (backFlg) { 16陆 $(thisObj).css({ "left": this.oldLeft, "top": this.oldTop }); 1陆7 } 16捌 this.doJudge(); 16九 } 170 event.stopPropagation(); 17一 }; 17二 17三 guessWXS.prototype.doCanvasDivMouseMove = function (thisObj) { 17肆 // 移动canvas块 17伍 event.preventDefault(); 176 if (this.start && this.down) { 17七 $(thisObj).css({ "top": event.pageY - this.befPageY + parseInt($(thisObj).css("top").replace(/px/g, "")), "left": event.pageX - this.befPageX + parseInt($(thisObj).css("left").replace(/px/g, "")) }); 17八 this.befPageX = event.pageX; 179 this.befPageY = event.pageY; 180 } 1八一 event.stopPropagation(); 1八二 }; 183 18四 guessWXS.prototype.doPlay = function () { 185 // 播放视频 186 if (!this.start || this.win) { 187 if (this.win) { 188 this.win = !this.win; 18九 } else { 190 this.doRandom(); 19一 this.videoCtrlObj.play(); 1九二 } 1九三 } 1玖四 }; 19伍 1九陆 guessWXS.prototype.doRandom = function () { 1九七 // 打乱canvas list 顺序 1九捌 var num一, num2; 19玖 var tmpPositionT = new Array(); 200 var tmpPositionL = new Array(); 201 //准备初期化数据 20二 for (var i = 0; i < this.canvasDivLst.length; i++) { 203 tmpPositionT.push(parseInt($(this.canvasDivLst[i]).css("top").replace(/px/g, ""))); 204 tmpPositionL.push(parseInt($(this.canvasDivLst[i]).css("left").replace(/px/g, ""))); 205 } 20陆 //举办随机 [对换] 207 console.log(tmpPositionT, tmpPositionL); 208 for (var i = 0; i < this.options.randomCount/
    this.canvasDivLst.length/; i++) {
    209 num1 = 0;
    210 num2 = 0;
    211 while (num1 == num2) {
    212 num1 = Math.round(Math.random()
    (this.canvasDivLst.length – 1));
    213 num2 = Math.round(Math.random() * (this.canvasDivLst.length – 1));
    214 }
    215 tmpPositionT[num1] = tmpPositionT[num1] + tmpPositionT[num2];
    216 tmpPositionT[num2] = tmpPositionT[num1] – tmpPositionT[num2];
    217 tmpPositionT[num1] = tmpPositionT[num1] – tmpPositionT[num2];
    218 tmpPositionL[num1] = tmpPositionL[num1] + tmpPositionL[num2];
    219 tmpPositionL[num2] = tmpPositionL[num1] – tmpPositionL[num2];
    220 tmpPositionL[num1] = tmpPositionL[num1] – tmpPositionL[num2];
    221 }
    222 for (var i = 0; i < tmpPositionT.length; i++) { 223 $(this.canvasDivLst[i]).css({ "left": tmpPositionL[i], "top": tmpPositionT[i] }); 2二四 } 225 this.start = true; 2二陆 }; 2二柒 22八 guessWXS.prototype.doJudge = function () { 22玖 // 判断是还是不是科学 230 var winFlg = true; 231 for (var i = 0; i < this.canvasDivLst.length; i++) { 232 if ( 233 this.positionTop[i] != parseInt($(this.canvasDivLst[i]).css("top").replace(/px/g, "")) 234 || 235 this.positionLeft[i] != parseInt($(this.canvasDivLst[i]).css("left").replace(/px/g, "")) 236 ) { 237 winFlg = false; 238 } 239 } 240 if (winFlg) { 241 this.start = false; 242 this.down = false; 243 this.win = true; 244 alert("YOU WIN!,点击录制再玩一次"); 二四5 } 二4六 }; 247 248 guessWXS.prototype.Bind = function (control, eventName, callBack, scope) { 24玖 if (!scope) { scope = window; } 250 $(control).bind(eventName, function () { 251 callBack.apply(scope, arguments); 252 }); 253 };

 

三. guessParmsWXS.js (那一个自由配置) :

 1 var options = {
 2     id: 'video1',
 3     container: '#video',
 4     videoHtml: "<video loop='loop'>Your browser does not support the video tag.</video>", // controls='controls'
 5     canvasHtml: "<div><canvas></canvas></div>",
 6     width: '640',
 7     height: '360',
 8     videoUrl: ['videos/BigBuckBunny_640x360.mp4', 'videos/BigBuckBunny_640x360.ogv'], //['videos/mov_bbb.ogg'],
 9     videoWidth: "640", //320
10     videoHeight: "360", //175
11     randomCount: 20
12 };

 

  1. guess_style.css (其实里面未有怎么) :

    1 body {
    2 }
    3 #video{width:640px; height:360px; margin:auto; /background:green;/ position:relative;}

 

CSDN下载:(能够单机械运输转,不需求服务器)

http://download.csdn.net/detail/wangxsh42/7530147

发表评论

电子邮件地址不会被公开。 必填项已用*标注