- (function($) {
- var puzzleConfig = {
- sizeX: 3,
- sizeY: 3
- };
- //全局常量
- var Constants={
- //每一片拼图透明度较低时候的透明度值
- fadeOpacity: 0.8,
- //放拼图元素的水平方向padding+border的合计值,用于载入拼图后控制容器尺寸
- puzzleContainerExtra: 42
- };
- //图片相关变量
- var puzzleImage=null,
- imageURL="",
- //图片上传标识,为true时表示相关设置合理,选择图片后将进入游戏
- checkFlag=false,
- imageWidth=0,
- imageHeight=0;
- //拼图相关变量
- var puzzleWidth=0,
- puzzleHeight=0,
- puzzleItemWidth=0,
- puzzleItemHeight=0,
- puzzleSizeX=0,
- puzzleSizeY=0,
- //拼图数目
- puzzleNumber=0,
- //计数器,计算从开始到完成游戏用的步数
- moveStepCount=0,
- //拼图步数以及是否完成的提示文字
- puzzleNote=null,
- //保存每一片拼图的正确的坐标值的数组
- validPosArrayX=[],
- validPosArrayY=[],
- //保存每一片拼图的数组,索引顺序和正确的拼图顺序相同
- puzzleArray = [],
- //整个拼图元素本身
- puzzle=null,
- //最终放置该拼图的父元素节点
- puzzleSetElem=null;
- //初始第一步,读取拼图设置和图片源,包括对填写内容的验证*/
- var puzzleConfigSet = function() {
- //类名常量
- var sizeInputClassName = "size_input",
- noteWarnClassName = "note_warn",
- currentProgressClassName = "current_progress",
- validImageSuffix = ".jpg|.jpeg|.gif|.bmp|.png";
- //放置拼图的由外层变量保存的元素
- puzzleSetElem=$ ("puzzleSet");
- //取得对应元素
- var sizeXElem = $("sizeX"),
- sizeYElem = $("sizeY"),
- sizeSetNote = $("sizeSetNote"),
- uploadBtn = $("uploadBtn"),
- fileImage = $("fileImage"),
- uploadProgress = $("uploadProgress"),
- currentProgress = uploadProgress.getFirst("." + currentProgressClassName),
- uploadNote = $("uploadNote");
- //拼图尺寸设定检查
- var puzzleSizeCheck = function() {
- var sizeX = sizeXElem.value,
- sizeY = sizeYElem.value,
- numberReg = /^\d{1,2}$/;
- if (numberReg.test(sizeX) && numberReg.test(sizeY)) {
- if (sizeX >= 2 && sizeX <= 10 && sizeY >= 2 && sizeY <= 10) {
- puzzleConfig.sizeX = sizeX;
- puzzleConfig.sizeY = sizeY;
- checkFlag = true;
- } else {
- sizeSetNote.addClass(noteWarnClassName);
- }
- } else {
- sizeSetNote.addClass(noteWarnClassName);
- }
- };
- //图片尺寸检查
- var imageCheck = function(image) {
- var minWidth = 30,
- maxWidth = 850,
- minHeight = 30;
- if (image.width >= 30 && image.width <= 850 && image.height > 30) {
- checkFlag = checkFlag && true;
- } else {
- uploadNote.addClass(noteWarnClassName);
- checkFlag = false;
- }
- };
- //图片格式检查
- var formatCheck = function(image) {
- var fileURL = fileImage.value.toLowerCase();
- //获取文件拓展名
- formatSuffix = fileURL.substring(fileURL.lastIndexOf("."));
- if (formatSuffix&&validImageSuffix.contains(formatSuffix)) {
- //如果是正确格式的图片文件
- checkFlag = checkFlag && true;
- } else {
- alert("请上传正确格式的图片文件(" + validImageSuffix + ")");
- checkFlag = false;
- }
- };
- //拼图尺寸输入框的事件
- $$("." + sizeInputClassName).addEvent("focus", function() {
- sizeSetNote.removeClass(noteWarnClassName);
- });
- //读取选择上传的图片
- puzzleImage = new Image();
- puzzleImage.onload = function() {
- imageCheck(puzzleImage);
- if (checkFlag) {
- imageWidth = puzzleImage.width;
- //由于图片尺寸不一定能被拼图尺寸整除,因此做边缘裁剪
- while(imageWidth % puzzleConfig.sizeX != 0){
- imageWidth--;
- }
- imageHeight = puzzleImage.height;
- while(imageHeight % puzzleConfig.sizeY != 0){
- imageHeight--;
- }
- imageURL= puzzleImage.src;
- puzzleSetElem.empty();
- var containerWidth = imageWidth+Constants.puzzleContainerExtra,
- properContainerWidth = containerWidth>120?containerWidth:120;
- puzzleSetElem.getParent().setStyles({
- width: properContainerWidth
- });
- createPuzzle(); //创建拼图
- }
- else{
- //如果读取后图片尺寸不合适的话,重置图片上传
- uploadProgress.style.display = "none";
- currentProgress.setStyle("width", 0);
- uploadBtn.style.display = "";
- }
- };
- if (typeof FileReader == "undefined") {
- //如果是不支持File API的浏览器
- fileImage.onchange = function() {
- puzzleSizeCheck();
- if (checkFlag) {
- formatCheck();
- }
- if (checkFlag) {
- puzzleImage.src = fileImage.value;
- }
- };
- } else {
- //如果支持File API,可以显示读取进度条
- var imageReader = new FileReader();
- //对象URL(blob URL),经测试新版Chrome也支持window.URL
- function createObjectURL(blob){
- if(window.URL){
- return window.URL.createObjectURL(blob);
- }else if(window.webkitURL){
- return window.webkitURL.createObjectURL(blob);
- }else{
- return null;
- }
- }
- //开始读取
- imageReader.onloadstart = function() {
- puzzleSizeCheck();
- if(checkFlag){
- formatCheck();
- }
- if (checkFlag) {
- uploadBtn.style.display = "none";
- uploadProgress.style.display = "";
- }
- };
- //读取中
- imageReader.onprogress = function(event) {
- if (checkFlag) {
- var percentage = 100 * parseInt(event.loaded / event.total) + "%";
- currentProgress.setStyle("width", percentage);
- }
- };
- imageReader.onload = function(event) {
- if (checkFlag) {
- //IE10也支持blob URL
- var url=createObjectURL(fileImage.files[0]);
- puzzleImage.src = url;
- }
- };
- fileImage.onchange = function() {
- imageReader.readAsDataURL(fileImage.files[0]);
- };
- }
- };
- //用于创建拼图
- var createPuzzle = function() {
- //classNameSet表示生成的元素的class名
- var classNameSet = {
- listContainer: "puzzle_container",
- list: "puzzle_list",
- item: "puzzle_item"
- };
- //各类元素对应的基本样式
- var puzzleStyle = {
- listContainer: {
- position: "relative",
- width: imageWidth,
- height: imageHeight,
- margin: "0 auto"
- },
- list: {
- },
- item: {
- position: "absolute"
- }
- };
- //计算得到每一块拼图的尺寸
- puzzleSizeX = puzzleConfig.sizeX;
- puzzleSizeY = puzzleConfig.sizeY;
- puzzleWidth = imageWidth;
- puzzleHeight = imageHeight;
- puzzleItemWidth = puzzleWidth / puzzleSizeX;
- puzzleItemHeight = puzzleHeight / puzzleSizeY;
- puzzleNumber = puzzleSizeX * puzzleSizeY;
- //建立一个临时数组,用于生成随机顺序的拼图块
- var randomOrderPuzzleArray=[];
- //创建元素
- puzzle = elementsCreate();
- showAnime();
- //创建整个拼图的dom,返回最外层的父级元素
- function elementsCreate() {
- var listContainer = new Element("div");
- listContainer.addClass(classNameSet.listContainer);
- listContainer.setStyles(puzzleStyle.listContainer);
- var list = new Element("ul");
- list.addClass(classNameSet.list);
- list.setStyles(puzzleStyle.list);
- //先通过循环,创建每一个拼图块,并按正确顺序存入数组
- for(var i = 0, len = puzzleNumber; i < len; i++) {
- var item = new Element("li");
- //为每块拼图保存自身的正确索引
- var indexSet = i + 1;
- item.store("puzzleIndex", indexSet);
- item.addClass(classNameSet.item);
- //增加基本样式
- item.setStyles(puzzleStyle.item);
- //以正确顺序保存每一个拼图块到数组
- puzzleArray.push(item);
- }
- //建立一个正确顺序数组的副本
- var puzzleArrayClone=puzzleArray.clone();
- //再次通过循环,创建一个乱序的拼图数组,并把这个数组显示到页面中
- for (i = 0, len = puzzleNumber; i < len; i++) {
- var randomItem = puzzleArrayClone.getRandom();
- //为避免重复,需要把被取出来的元素在副本数组中删除
- puzzleArrayClone.erase(randomItem);
- //为每一块取出来的元素设置可变的位置索引
- var posIndex = i + 1;
- randomItem.posIndex = posIndex;
- //获取取出来的元素的正确索引,用于接下来计算拼图背景图位置
- var correctIndex = randomItem.retrieve("puzzleIndex");
- //计算位置
- var topSet = Math.floor((posIndex - 1) / puzzleSizeX) * puzzleItemHeight,
- leftSet = (posIndex - 1) % puzzleSizeX * puzzleItemWidth,
- //计算符合正确索引的背景图位置
- backgroundSetX = -(correctIndex - 1) % puzzleSizeX * puzzleItemWidth,
- backgroundSetY = -(Math.floor((correctIndex - 1) / puzzleSizeX) * puzzleItemHeight),
- backgroundString = "url(" + imageURL + ") " + backgroundSetX + "px " + backgroundSetY + "px " + "no-repeat";
- //添加关键样式
- randomItem.setStyles({
- width: Math.ceil(puzzleItemWidth),
- height: Math.ceil(puzzleItemHeight),
- background: backgroundString,
- left: leftSet,
- top: topSet,
- zIndex: posIndex
- });
- //生成合理的位置坐标数组
- validPosArrayX.push(leftSet);
- validPosArrayY.push(topSet);
- //存放乱序元素到乱序数组
- randomOrderPuzzleArray.push(randomItem);
- }
- //组合拼图的各个元素
- list.adopt(randomOrderPuzzleArray);
- listContainer.adopt(list);
- return listContainer;
- }
- //为拼图的初始化创建动画
- function showAnime(){
- //一些动画参数
- var timeSpace=50,
- //垂直移动的间距
- distance=30,
- //计数用
- count=0,
- timeFlag;
- //所有拼图先隐藏,透明度置为0
- for(var i=0,len=puzzleArray.length;i<len;i++){
- puzzleArray[i].setStyle("opacity",0);
- }
- //更新到页面dom中,准备开始动画
- puzzleSetElem.grab(puzzle);
- var enterFrameHandler=function(){
- var puzzleItem=randomOrderPuzzleArray[count++];
- var endTop=parseInt(puzzleItem.getStyle("top"));
- var startTop=endTop-distance;
- puzzleItem.set("morph",{
- transition: Fx.Transitions.Quad.easeOut
- });
- puzzleItem.morph({
- top:[startTop,endTop],
- opacity:Constants.fadeOpacity
- });
- if(count<puzzleNumber){
- //对最后一个拼图块的动画结束做侦听
- if(count==puzzleNumber-1){
- var lastMorph=puzzleItem.get("morph");
- var showAnimeEnd=function(){
- lastMorph.removeEvent("complete",showAnimeEnd);
- puzzleEventBind();
- }
- lastMorph.addEvent("complete",showAnimeEnd);
- }
- timeFlag=setTimeout(enterFrameHandler,timeSpace);
- }
- };
- timeFlag=setTimeout(enterFrameHandler,timeSpace);
- }
- };
- //拼图的相关事件绑定,也是游戏的核心控制逻辑
- var puzzleEventBind=function(){
- //拼图游戏控制相关的变量
- var selectedItem=null,
- //当前选中的拼图位置索引
- selectedIndex=0,
- //用于保存当前鼠标正在拖动的拼图的zIndex值
- selectedItemZIndex=0,
- //每一次切换拼图位置的时候,都涉及到2块拼图,鼠标拖动的这块和交换位置的另外一块,这个就是另外一块
- relatedItem=null,
- //依照鼠标当前的位置,判断得到的目标索引,如果鼠标此时放开,就是说把选中的拼图移到现在鼠标所在的位置
- targetIndexNew=0,
- //通过new和old来区分鼠标从一个目标索引更换到另一个目标索引
- targetIndexOld=0,
- //判断是否进行一次拼图位置移动的逻辑值,只有当目标索引值有改变时,才允许进行拼图位置移动
- isTargetIndexChanged=false,
- //判断鼠标指针是否在拼图的区域之内
- isInsidePuzzle=false,
- //鼠标点击拼图的某一个点的时候,距离拼图的左上角定位点有的距离值
- disX=0,
- disY=0;
- //计算获取整个拼图的左上角点的坐标
- var puzzlePos=puzzle.getPosition();
- var puzzlePosX=puzzlePos.x,
- puzzlePosY=puzzlePos.y;
- //重新设置每一个元素的动画速度
- (function(){
- for(var i=0,len=puzzleArray.length;i<len;i++){
- var puzzleItem=puzzleArray[i];
- puzzleItem.set("morph",{
- duration:250
- });
- }
- })();
- //计数函数准备
- var updateCount = (function(){
- var stepCount = $("stepCount");
- puzzleNote = stepCount.getParent();
- return function(){
- stepCount.set("text", moveStepCount);
- };
- })();
- //添加事件
- puzzle.addEvent("mouseover",mouseOverHandler);
- puzzle.addEvent("mouseout",mouseOutHandler);
- puzzle.addEvent("mousedown",mouseDownHandler);
- puzzle.addEvent("mouseup",mouseUpHandler);
- //鼠标经过
- function mouseOverHandler(event){
- var target=event.target;
- if(puzzleArray.contains(target)){
- target.setStyle("opacity",1);
- }
- }
- //鼠标移出
- function mouseOutHandler(event){
- var target=event.target;
- if(puzzleArray.contains(target)){
- target.setStyle("opacity",Constants.fadeOpacity);
- }
- }
- //鼠标按下
- function mouseDownHandler(event){
- var target=event.target;
- //race("[mouseDownHandler]selectedItem ="+selectedItem);
- //如果当前没有其他目标选中,且鼠标选中的目标是拼图块
- if(!selectedItem&&puzzleArray.contains(target)){
- if(target.getStyle("opacity")<1){
- target.setStyle("opacity",1);
- }
- //设置当前选中的目标及索引
- selectedItemZIndex=target.getStyle("zIndex");
- target.setStyle("zIndex",5000);
- selectedItem=target;
- selectedIndex=target.posIndex;
- //设置初始目标索引
- targetIndexNew=targetIndexOld=selectedIndex;
- //计算出鼠标点击的点和拼图左上角定位点的偏差距离
- var targetPos=target.getPosition();
- disX=event.page.x-targetPos.x;
- disY=event.page.y-targetPos.y;
- //增加鼠标移动的事件侦听,让拼图块跟随鼠标移动,并判断当前位置
- document.addEvent("mousemove",mouseMoveHandler);
- }
- }
- //鼠标松开
- function mouseUpHandler(event){
- //如果有元素处于拖动状态,取消
- if(selectedItem){
- selectedItem.setStyle("opacity",Constants.fadeOpacity);
- selectedItem.setStyle("zIndex",selectedItemZIndex);
- document.removeEvent("mousemove",mouseMoveHandler);
- //松开之后,根据目标索引和拖动元素的索引,移动拼图,并更新dom结构
- if(isInsidePuzzle){
- //如果目标索引是一块别的拼图
- if(targetIndexNew!=selectedIndex){
- puzzleItemMove(selectedItem,targetIndexNew,puzzleItemSwitch);
- }else{
- //还原回原来的位置
- puzzleItemMove(selectedItem,selectedIndex);
- selectedItem=null;
- relatedItem=null;
- }
- }else{
- //如果鼠标在拼图之外的区域松开,则被拖动的拼图还原回原来的位置
- puzzleItemMove(selectedItem,selectedIndex);
- selectedItem=null;
- relatedItem=null;
- targetIndexNew = targetIndexOld = selectedIndex;
- }
- }
- }
- //鼠标移动
- function mouseMoveHandler(event){
- var mouseX=event.page.x,
- mouseY=event.page.y;
- event.preventDefault();
- //设置选中元素的位置,跟随鼠标
- selectedItem.setPosition({
- x:mouseX-disX-puzzlePosX,
- y:mouseY-disY-puzzlePosY
- })
- //计算鼠标当前位置是否在拼图区域之内(拼图边缘也算在外)
- isInsidePuzzle=(function(){
- if(mouseX<=puzzlePosX||mouseX-puzzlePosX>=puzzleWidth){
- return false;
- }
- if(mouseY<=puzzlePosY||mouseY-puzzlePosY>=puzzleHeight){
- return false;
- }
- return true;
- })();
- //如果鼠标当前位置在拼图区域之内,再做目标索引计算
- if(isInsidePuzzle){
- //race("[mouseMoveHandler]isInsidePuzzle = true");
- //计算目标索引,xIndex和yIndex分别表示当前位置所处的列序号和行序号
- var xIndex=Math.ceil((mouseX-puzzlePosX)/puzzleItemWidth),
- yIndex=Math.ceil((mouseY-puzzlePosY)/puzzleItemHeight);
- targetIndexNew=(yIndex-1)*puzzleSizeX+xIndex;
- if(targetIndexNew!=targetIndexOld){
- isTargetIndexChanged=true;
- }
- //只有当目标索引发生改变时,才移动拼图做示意
- if(isTargetIndexChanged){
- //如果上一个目标索引的拼图不是鼠标正在移动的这个,那么就需要恢复这张拼图的位置到它原来的地方
- if(targetIndexOld!=selectedIndex){
- var lastRelatedItemIndex=relatedItem.posIndex;
- puzzleItemMove(relatedItem,lastRelatedItemIndex);
- }
- //更新相关元素,取得拼图数组中posIndex等于当前的目标索引的元素
- relatedItem=puzzleArray.filter(function(item, index){
- return item.posIndex == targetIndexNew;
- })[0];
- //如果下一个目标索引,不是被拖走的拼图原来所在的位置,就移动新的目标索引的拼图到被拖走的拼图的位置
- if(targetIndexNew!=selectedIndex){
- puzzleItemMove(relatedItem,selectedIndex);
- }
- //重置目标索引改变的逻辑值
- isTargetIndexChanged=false;
- //更新上一个目标索引
- targetIndexOld=targetIndexNew;
- }
- }else{
- //如果移到拼图区域之外,则考虑还原上一个目标索引的拼图
- if(targetIndexOld!=selectedIndex){
- var lastRelatedItemIndex=relatedItem.posIndex;
- puzzleItemMove(relatedItem,lastRelatedItemIndex);
- }
- //还原targetIndexOld的值,以处理移到拼图外的情况。
- targetIndexOld = selectedIndex;
- }
- }
- //每一次拼图交换的功能实现的函数,更改对应元素的posIndex,并更改zIndex
- function puzzleItemSwitch(){
- //交换元素的posIndex
- selectedItem.posIndex=targetIndexNew;
- relatedItem.posIndex=selectedIndex;
- //交换元素的zIndex,通过posIndex来赋值
- selectedItem.setStyle("zIndex",selectedItem.posIndex);
- relatedItem.setStyle("zIndex",relatedItem.posIndex);
- //清除对相关元素的引用
- selectedItem=null;
- relatedItem=null;
- //一次更换完成,计数器+1
- moveStepCount++;
- updateCount();
- //然后再判断拼图游戏是否完成
- clearJudgement();
- }
- //每一块拼图在游戏中的移动函数
- function puzzleItemMove(moveItem,moveToIndex,endFn){
- var moveToX=validPosArrayX[moveToIndex-1],
- moveToY=validPosArrayY[moveToIndex-1],
- originZIndex=moveItem.posIndex;
- moveItemMorph=moveItem.get("morph");
- moveItemMorph.addEvent("start",moveStartHandler);
- moveItemMorph.addEvent("complete",moveEndHandler);
- moveItem.morph({
- left:moveToX,
- top:moveToY
- });
- function moveStartHandler(){
- moveItem.setStyle("zIndex",1000);
- }
- function moveEndHandler(){
- moveItemMorph.removeEvent("start",moveStartHandler);
- moveItemMorph.removeEvent("complete",moveEndHandler);
- moveItem.setStyle("zIndex",originZIndex);
- //结尾执行的函数,如果需要的话
- if(typeOf(endFn)=="function"){
- endFn();
- }
- }
- }
- //完成拼图游戏的判定函数
- function clearJudgement(){
- //检查puzzleArray中的每一个元素的puzzleIndex和posIndex是否全部一致
- var isGameClear=puzzleArray.every(function(item, index){
- var puzzleIndex=item.retrieve("puzzleIndex");
- return item.posIndex==puzzleIndex;
- });
- if(isGameClear){
- clearShow();
- }
- }
- //确定完成拼图游戏后,执行的函数
- function clearShow(){
- //清除所有事件侦听
- puzzle.removeEvent("mouseover",mouseOverHandler);
- puzzle.removeEvent("mouseout",mouseOutHandler);
- puzzle.removeEvent("mousedown",mouseDownHandler);
- puzzle.removeEvent("mouseup",mouseUpHandler);
- var clearAnimeFlag=null,
- count=0;
- //按顺序点亮所有拼图的动画
- var enterFrameHandler=function(){
- var item=puzzleArray[count++];
- item.fade(1);
- if(count<puzzleNumber){
- clearAnimeFlag=setTimeout(enterFrameHandler,50);
- }
- };
- clearAnimeFlag=setTimeout(enterFrameHandler,50);
- //游戏完成后的信息~❤
- puzzleNote.set('html','Congratulations ! Your final step count is <em class="step_count">'+moveStepCount+'</em>.');
- }
- }
- //创建全局变量puzzleGame
- window.puzzleGame={};
- //添加方法到全局变量puzzleGame中
- puzzleGame.start = function() {
- puzzleConfigSet();
- };
- })(document.id);
- puzzleGame.start();
来源: http://www.phpxs.com/code/1003849/