以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 SVG/GML/VRML/X3D/XAML 』  (http://bbs.xml.org.cn/list.asp?boardid=21)
----  [求助]请大虾们帮我翻译下这个程序的注释,以及程序说明。  (http://bbs.xml.org.cn/dispbbs.asp?boardid=21&rootid=&id=41786)


--  作者:zhzzhz520
--  发布时间:12/30/2006 2:55:00 PM

--  [求助]请大虾们帮我翻译下这个程序的注释,以及程序说明。
程序说明:
1, 首先,原图被分为几个小块, each block has column and row number, and border path type. Application should in
charge of the border path setting. For example, neighbours should have same kind of border path.

2. Regions consist of blocks, it can be merge into other regions by move all its blocks to other one. It is in charge of
generate path string for image object.

3. Image object is a SVG group consist of a <image> and a <clipPath> with <path> setting.
   One image object looks like:
 <g id="group" transform="matrix(a,b,c,d,e,f)" display="none">
  <clipPath id="clip"><path id="path" d="M 0 0"/></clipPath>
  <image id="image" width="400" height="400" xlink:href="1.jpg" clip-path="url(#clip)"/>
 </g>
 
4, Add mouse event to SVG canvas, including mouse down(grab), mouse up(drop) and mouse move(drag).
   Move or rotate will affect group transform string, keep clip-path and image relative fixed.
   Click on image object will "grab" it, keep mouse down and move will "drag" image, release mouse will "drop" image to a
new position.

5, In order to improve grap and drag speed, after select one image, swap svg node to bring selected image to then front.
(append selected one in SVG node proved to be very slowly);

6, After drop, image object will test it neighbour to determine which one should be merged toghther. Drop object will test
object borders in other group, if distance less than minimize value, drop object will be added to target group. Pay attention to
the check distance function, group transform matrix should be consider.
 border : neighbour, according to the blocks region hold
 translate : distance less than mindistance (arrording to translate offset, remember complete picture's all offset is equal, only clip offset is different)
 rotate angle : equal, only regions with same direction can be merge together

 loop1: Search other image objects which meet condition 2 and 3
 loop2: Search whether image object contain border block for each blocks in this region,
  Once got one then break and return,
  otherwise continue loop till finish iteration.
  

7, If no swap and no merge happen, and move distance less than min rotate distance, image will rotate round mouse point.

8, If merge group happened and after then target group contains "imageRow * imageCol" images, it indicate all works done, move group to origin
and show "Game over!".


--  作者:zhzzhz520
--  发布时间:12/30/2006 2:58:00 PM

--  
程序:
<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     xmlns:ev="http://www.w3.org/2001/xml-events"
     width="100%" height="100%" shape-rendering="optimizeSpeed" zoomAndPan="enable" onload="init(evt)" onmousedown="grab(evt)" onmousemove="drag(evt)" onmouseup="drop(evt)">
<title>Puzzle</title>
<desc>Puzzle</desc>

<script language="JavaScript" >
<![CDATA[

    
var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS="http://www.w3.org/1999/xlink";

var svgDocument = null;
var svgRoot = null;
var canvas = null;
var background = null; //to receive mouse event on drag
var dragImage = null;

var imageList = new Array();

var trueCoords = null;
var grabPoint = null;
var orgPoint = null;
var swapFlag = false; //Swap happen or not

//In order to keep all points is integer, imageWidth will be round to imageCol * 4 and imageHeight round to imageRow * 4
//For example, if imageCol = 3, 400%(3*4)=4, imageWidth will be round to 400-4=396.
var imageWidth = 400;  
var imageHeight = 400;

var imageRow = 3;   //You can change from Row and column number from 1 to 10
var imageCol = 3;
var rowUnit;  //Height of each row
var colUnit; //Width of each column

var MIN_MERGE_DISTANCE = 5;  //Merge distance
var MIN_ROTATE_DISTANCE = 2; //Rotate distance

var CANVAS_ID = "canvas";
var BACKGROUND_ID = "background";
var IMAGE_SOURCE = "1.jpg"; //Source file
var OUTLINE_ID = "outline";
var OUTLINE_STROKE = "silver";
var OUTLINE_STROKE_WIDTH = 2;

function init(evt)
{
 svgDocument = evt.target.ownerDocument;
 svgRoot = svgDocument.documentElement;
 
 //Resize image in order to round path point to int;
 roundSize();
 
 trueCoords = svgRoot.createSVGPoint();
 grabPoint = svgRoot.createSVGPoint();
 orgPoint = svgRoot.createSVGPoint();
 
 //Get backgroup and canvas element
 background = svgDocument.getElementById( BACKGROUND_ID );
 canvas = svgDocument.getElementById( CANVAS_ID );
 var blockList = createBlockList();
 
 for(var i = 0; i < imageRow; i++)
 {
  for(var j = 0; j < imageCol; j++)
  {
   var id = "part_" + i + "_" + j;
    
   var region = new Region();
   region.addBlock( blockList[ i*imageCol + j ] );
     
   var image = new ImageObject(id, CANVAS_ID, 0, region);
   image.create();
   image.updatePath();
   imageList[imageList.length] = image;
   
   //Random rotate and spread images
   var cx = Math.random() * innerWidth / 2;
   var cy = Math.random() * innerHeight / 2;
   var rotateFlag = parseInt( Math.random() * 10 ) % 4;
   var rx = j * colUnit + colUnit / 2;
   var ry = i * rowUnit + rowUnit / 2;
   
   image.updateImage(cx, cy, rotateFlag, rx, ry);
   
  }
 }
  
 //Create outline
 createOutline();
}

function createBlockList()
{
 //Edge type current support
 // 0: line; 1: one big circle; 2: one small circle
 var edgeTypeNumber = 2;
 
 //Horizontal edge [col][row+1] vertical [row][col+1]
 //In order to simplize usage, we just use string to hold edge type
 
 var hEdgesStr = "";
 var vEdgesStr = "";
 
 for(var i = 0; i < imageRow + 1; i++)
 {
  for(var j = 0; j < imageCol ; j++)
  {
   if( (i == 0) || ( i== imageRow ) )
    hEdgesStr = hEdgesStr + "0";
   else
    hEdgesStr = hEdgesStr + (( parseInt( Math.random() * 10 ) ) % edgeTypeNumber + 1);
  }
 }
  
 for(var i = 0; i < imageRow; i++)
 {
  for(var j = 0; j < imageCol + 1; j++)
  {
   if( (j == 0) || ( j == imageCol ) )
    vEdgesStr = vEdgesStr + "0";
   else
    vEdgesStr = vEdgesStr + (( parseInt(Math.random() * 10 ) ) % edgeTypeNumber + 1);
  }
 }
 
 //alert( hEdgesStr + "; " + vEdgesStr);

 var blockList = new Array();
 for(var i = 0; i < imageRow; i++)
 {
  for(var j = 0; j < imageCol; j++)
  {
   var block = new Block(i, j);
   block.topEdge = parseInt( hEdgesStr.substr(i*imageCol + j, 1) );
   block.bottomEdge = parseInt( hEdgesStr.substr( (i+1)*imageCol + j, 1) );
   
   block.leftEdge = parseInt( vEdgesStr.substr(i* (imageCol + 1) + j, 1) );
   block.rightEdge = parseInt( vEdgesStr.substr(i* (imageCol + 1) + j + 1, 1) );
   
   //alert(i + " " + j + ": " + block.topEdge + " " + block.rightEdge + " " + block.bottomEdge +  " " + block.leftEdge);
   blockList[blockList.length] = block;
  }
 }
 
 //alert(blockList.length);
 return blockList;
}

function createOutline()
{
 //Outline path
 var groups = svgDocument.getElementById(CANVAS_ID);
 if(groups != null)
 {
  var lastGroup = groups.lastChild;
  var path = svgDocument.createElementNS(svgNS, "path");
  path.setAttributeNS(null, "id", OUTLINE_ID);
  path.setAttributeNS(null, "d", "M 0 0");
  path.setAttributeNS(null, "fill", "none");
  path.setAttributeNS(null, "stroke", OUTLINE_STROKE);
  path.setAttributeNS(null, "stroke-width", OUTLINE_STROKE_WIDTH);
  path.setAttributeNS(null, "point-events", "none");
  lastGroup.appendChild(path);
 }
}

function showOutline(pathStr)
{
 var path = svgDocument.getElementById(OUTLINE_ID);
 if(path != null)
 {
  path.setAttributeNS(null,"d", pathStr);
 }
}

function roundSize()
{
 if( imageRow > 10)
  imageRow = 10;
 if( imageCol > 10 )
  imageCol = 10;
 
 imageWidth = imageWidth - imageWidth % ( imageCol * 4 );
 imageHeight = imageHeight - imageHeight % ( imageRow * 4 );
 
 rowUnit = imageHeight / imageRow;  //Row part unit
 colUnit = imageWidth / imageCol; //Col part unit
}

function matrixToStr(matrix)
{
 var transformStr = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + ","
    + matrix.d + "," + matrix.e + "," + matrix.f + ")";
 return transformStr;
}

//Get image object by SVG node id
function getImageObject(id)
{
 var index = id.indexOf("_");
 var str = id.substr(index+1);
 index = str.indexOf("_");
 
 var row = parseInt(str.substr(0,index));
 var col = parseInt(str.substr(index+1));
 
 //Search specific block in image object region
 for(var i=0; i<imageList.length; i++)
 {
  if( (imageList[i] != null) && (imageList[i].region.hasBlock(row, col) ))
   return  imageList[i];
 }
 
 return null;
}

function getTrueCoords(evt)
{
 var newScale = svgRoot.currentScale;
 var translation = svgRoot.currentTranslate;
 trueCoords.x = (evt.clientX - translation.x)/newScale;
 trueCoords.y = (evt.clientY - translation.y)/newScale;
}

//Swap selected SVG node to last one
function swapImage(id1, id2)
{
 var group1, clip1, path1, image1;
 var group2, clip2, path2, image2;
 
 var group1Id = "group" + id1;
 var clip1Id = "clip" + id1;
 var path1Id = "path" + id1;
 var image1Id = "image" + id1;
 
 group1 = svgDocument.getElementById(group1Id);
 clip1 = svgDocument.getElementById(clip1Id);
 path1 = svgDocument.getElementById(path1Id);
 image1 = svgDocument.getElementById(image1Id);
 
 var group2Id = "group" + id2;
 var clip2Id = "clip" + id2;
 var path2Id = "path" + id2;
 var image2Id = "image" + id2;
 
 group2 = svgDocument.getElementById(group2Id);
 clip2 = svgDocument.getElementById(clip2Id);
 path2 = svgDocument.getElementById(path2Id);
 image2 = svgDocument.getElementById(image2Id);
 
 swapNodeAttribute(group1, group2, "id");
 swapNodeAttribute(group1, group2, "transform");
 swapNodeAttribute(clip1, clip2, "id");
 swapNodeAttribute(path1, path2, "id");
 swapNodeAttribute(path1, path2, "d");
 swapNodeAttribute(image1, image2, "id");
 swapNodeAttribute(image1, image2, "clip-path");
 
}
 
function swapNodeAttribute(node1, node2, attrName)
{
 var value1 = node1.getAttributeNS(null, attrName);
 var value2 = node2.getAttributeNS(null, attrName);
 node1.setAttributeNS(null, attrName, value2);
 node2.setAttributeNS(null, attrName, value1);
}

//Search neighbours in image list
function getNeighbourImage()
{
 for(var i=0; i<imageList.length; i++)
 {
  if( (dragImage == imageList[i]) || (imageList[i] == null) )
   continue;
  
  if(dragImage.checkNeighbour(imageList[i]) == true)
  {
   //Return neighbour and remove it from image list
   var newImage = imageList[i];
   imageList[i] = null;
   return newImage;
  }
 }
 
 return null;
}

function gameOver()
{
 alert("Game Over!");
}

///
/// Block and Region class
///
function Block(row, col)
{
 //Data
 this.row = row;
 this.col = col;
 
 this.topEdge = 0;
 this.rightEdge = 0;
 this.bottomEdge = 0;
 this.leftEdge = 0;
}

function Region()
{
 //Data
 this.blocks = new Array();
 
 //Methods
 this.addBlock = addBlock;
 this.hasBlock = hasBlock;  //Test contain one specific block or not
 this.mergeRegion = mergeRegion;
 this.getPathStr = getPathStr;
 this.getOutline = getOutline;
 this.isNeighbour = isNeighbour; //Test other region has neighbour block or not
}

function addBlock(block)
{
 this.blocks[this.blocks.length] = block;
}

function hasBlock(row, col)
{
 for(var i = 0; i<this.blocks.length; i++)
 {
  if( (this.blocks[i].row == row) && (this.blocks[i].col == col) )
   return true;
 }
 
 return false;
}

function mergeRegion(newRegion)
{
 if( (newRegion == null) || (newRegion.blocks == null) )
  return;
  
 //Copy all block from new region
 for(var i = 0; i<newRegion.blocks.length; i++)
 {
  this.blocks[this.blocks.length] = newRegion.blocks[i];
 }
}

function isNeighbour(newRegion)
{
 if(newRegion.blocks == null)
  return false;
 
 var block1, block2;
 for(var i = 0; i<this.blocks.length; i++)
 {
  block1 = this.blocks[i];
  for(var j = 0; j<newRegion.blocks.length; j++)
  {
   block2 = newRegion.blocks[j];
   
   //Same row, previous or next col is neighbour
   if( (block1.row == block2.row) && (Math.abs(block1.col - block2.col) == 1) )
    return true;
   
   //Same col, previous or next row is neighbour
   if( (block1.col == block2.col) && (Math.abs(block1.row - block2.row) == 1) )
    return true;
  }
 }

 return false;
}

function getOutline()
{
 var pathStr = " ";
 var x, y;
 var rowPart = rowUnit / 4;
 var colPart = colUnit / 4;
 
 var topFlag = true;
 var rightFlag = true
 var bottomFlag = true;
 var leftFlag = true;
  
 for(var i = 0; i < this.blocks.length; i++)
 {
  var block = this.blocks[i];
  
  //Set outline edge flag
  if( (block.row > 0) && this.hasBlock(block.row - 1, block.col) )
   topFlag = false;
  if( (block.row < (imageRow - 1)) && this.hasBlock(block.row + 1, block.col) )
   bottomFlag = false;
  if( (block.col > 0) && this.hasBlock(block.row , block.col - 1) )
   leftFlag = false;
  if( (block.col < (imageCol - 1) ) && this.hasBlock(block.row , block.col + 1) )
   rightFlag = false; 
  
  var ox = block.col * colUnit;
  var oy = block.row * rowUnit;
  
  if(topFlag)
  {
   //Move to begin point
   x = ox;
   y = oy;
   pathStr = pathStr + "M " + x + " " + y + " ";
   
   //Top edge, y fixed to oy
   if(block.topEdge == 1)
   {
    x = ox + colPart;
    pathStr = pathStr + " L " + x + " " + y + " a " + colPart / 2 + " " + colPart / 2 + " 0 1 1 " + colPart + " 0 L";
    x = ox + colUnit;
    pathStr = pathStr + x + " " + y + " ";
   }
   else if(block.topEdge == 2)
   {
    x = ox + colPart * 2;
    pathStr = pathStr + " L " + x + " " + y + " a " + colPart / 2 + " " + colPart / 2 + " 0 1 1 " + colPart + " 0 L ";
    x = ox + colUnit;
    pathStr = pathStr + x + " " + y + " ";
   }
   else
   {
    x = ox + colUnit;
    pathStr = pathStr + " L " + x + " " + y + " ";
   }
  }
  
  if(rightFlag)
  {
   //Move to begin point
   x = ox + colUnit;
   y = oy;
   pathStr = pathStr + "M " + x + " " + y + " ";
   
   //Right edge, x fixed to ox + colUnit;
   if(block.rightEdge == 1)
   {
    y = oy + rowPart;
    
    pathStr = pathStr + " L " + x + " " + y + " a " + rowPart / 2 + " " + rowPart / 2 + " 0 1 1 0 " + rowPart + " L ";
    y = oy + rowUnit;
    pathStr = pathStr + x + " " + y + " ";
   }
   else if(block.rightEdge == 2)
   {
    y = oy + rowPart * 2;
    
    pathStr = pathStr + " L " + x + " " + y + " a " + rowPart / 2 + " " + rowPart / 2 + " 0 1 1 0 " + rowPart + " L ";
    y = oy + rowUnit;
    pathStr = pathStr + x + " " + y + " ";
   }
   else
   {
    y = oy + rowUnit;
    pathStr = pathStr + " L " + x + " " + y + " ";
   }
  }
  
  if(bottomFlag)
  {
   //Move to begin point
   x = ox + colUnit;
   y = oy + rowUnit;
   pathStr = pathStr + "M " + x + " " + y + " ";
   
   //Bottom edge, y fixed to oy + rowUnit;
   if(block.bottomEdge == 1)
   {
    x = ox + colUnit - 2 * colPart;
    
    pathStr = pathStr + " L " + x + " " + y + " a " + colPart / 2 + " " + colPart / 2 + " 0 1 0 -" + colPart + " 0 L";
    x = ox;
    pathStr = pathStr + x + " " + y + " ";
   }
   else if(block.bottomEdge == 2)
   {
    x = ox + colUnit - colPart;
    pathStr = pathStr + " L " + x + " " + y + " a " + colPart / 2 + " " + colPart / 2 + " 0 1 0 -" + colPart + " 0 L ";
    x = ox;
    pathStr = pathStr + x + " " + y + " ";
   }
   else
   {
    x = ox;
    pathStr = pathStr + " L " + x + " " + y + " ";
   }
  }
  
  if(leftFlag)
  {
   //Move to begin point
   x = ox;
   y = oy + rowUnit;
   pathStr = pathStr + "M " + x + " " + y + " ";
   
   //Left edge, x fixed to ox
   if(block.leftEdge == 1)
   {
    y = oy + rowUnit - 2 * rowPart;
    
    pathStr = pathStr + " L " + x + " " + y + " a " + rowPart / 2 + " " + rowPart / 2 + " 0 1 0 0 -" + rowPart + " L ";
    y = oy;
    pathStr = pathStr + x + " " + y + " ";
   }
   else if(block.leftEdge == 2)
   {
    y = oy + rowUnit - rowPart;
    
    pathStr = pathStr + " L " + x + " " + y + " a " + rowPart / 2 + " " + rowPart / 2 + " 0 1 0 0 -" + rowPart + " L ";
    y = oy;
    pathStr = pathStr + x + " " + y + " ";
   }
   else
   {
    y = oy;
    pathStr = pathStr + " L " + x + " " + oy + " ";
   }
  }
 }
 
 //alert(pathStr);
 return pathStr;
}

function getPathStr()
{
 var pathStr = " ";
 var x, y;
 var rowPart = rowUnit / 4;
 var colPart = colUnit / 4;
  
 for(var i = 0; i < this.blocks.length; i++)
 {
  var block = this.blocks[i];
    
  pathStr = pathStr + "M ";
   
  var ox = block.col * colUnit;
  var oy = block.row * rowUnit;
  
  //Move to begin point
  pathStr = pathStr + ox + " " + oy + " ";
  
  //Top edge, y fixed to oy
  y = oy;
  if(block.topEdge == 1)
  {
   x = ox + colPart;
   pathStr = pathStr + " L " + x + " " + y + " a " + colPart / 2 + " " + colPart / 2 + " 0 1 1 " + colPart + " 0 L";
   x = ox + colUnit;
   pathStr = pathStr + x + " " + y + " ";
  }
  else if(block.topEdge == 2)
  {
   x = ox + colPart * 2;
   pathStr = pathStr + " L " + x + " " + y + " a " + colPart / 2 + " " + colPart / 2 + " 0 1 1 " + colPart + " 0 L ";
   x = ox + colUnit;
   pathStr = pathStr + x + " " + y + " ";
  }
  else
  {
   x = ox + colUnit;
   pathStr = pathStr + " L " + x + " " + y + " ";
  }
  
  //Right edge, x fixed to ox + colUnit;
  x = ox + colUnit;
  if(block.rightEdge == 1)
  {
   y = oy + rowPart;
   
   pathStr = pathStr + " L " + x + " " + y + " a " + rowPart / 2 + " " + rowPart / 2 + " 0 1 1 0 " + rowPart + " L ";
   y = oy + rowUnit;
   pathStr = pathStr + x + " " + y + " ";
  }
  else if(block.rightEdge == 2)
  {
   y = oy + rowPart * 2;
   
   pathStr = pathStr + " L " + x + " " + y + " a " + rowPart / 2 + " " + rowPart / 2 + " 0 1 1 0 " + rowPart + " L ";
   y = oy + rowUnit;
   pathStr = pathStr + x + " " + y + " ";
  }
  else
  {
   y = oy + rowUnit;
   pathStr = pathStr + " L " + x + " " + y + " ";
  }
  
  //Bottom edge, y fixed to oy + rowUnit;
  y = oy + rowUnit;
  if(block.bottomEdge == 1)
  {
   x = ox + colUnit - 2 * colPart;
   
   pathStr = pathStr + " L " + x + " " + y + " a " + colPart / 2 + " " + colPart / 2 + " 0 1 0 -" + colPart + " 0 L";
   x = ox;
   pathStr = pathStr + x + " " + y + " ";
  }
  else if(block.bottomEdge == 2)
  {
   x = ox + colUnit - colPart;
   pathStr = pathStr + " L " + x + " " + y + " a " + colPart / 2 + " " + colPart / 2 + " 0 1 0 -" + colPart + " 0 L ";
   x = ox;
   pathStr = pathStr + x + " " + y + " ";
  }
  else
  {
   x = ox;
   pathStr = pathStr + " L " + x + " " + y + " ";
  }
  
  //Left edge, x fixed to ox
  x = ox;
  if(block.leftEdge == 1)
  {
   y = oy + rowUnit - 2 * rowPart;
   
   pathStr = pathStr + " L " + x + " " + y + " a " + rowPart / 2 + " " + rowPart / 2 + " 0 1 0 0 -" + rowPart + " L ";
   y = oy;
   pathStr = pathStr + x + " " + y + " ";
  }
  else if(block.leftEdge == 2)
  {
   y = oy + rowUnit - rowPart;
   
   pathStr = pathStr + " L " + x + " " + y + " a " + rowPart / 2 + " " + rowPart / 2 + " 0 1 0 0 -" + rowPart + " L ";
   y = oy;
   pathStr = pathStr + x + " " + y + " ";
  }
  else
  {
   y = oy;
   pathStr = pathStr + " L " + x + " " + oy + " ";
  }
 }
 
 //alert(pathStr);
 return pathStr;
}

///
/// ImageObject class begin
///
function ImageObject(id, parentId, angle, region)
{
 //Data
 this.id = id;
 this.parentId = parentId;
 
 this.angle = angle;
 this.region = region;
  
 //Methods 
 this.create = create; //Create SVG node and show
 this.updateImage = updateImage; //Update position and rotate status
 this.updatePath = updatePath; //Update clip path after merge with other images
 this.hide = hide; //Hide svg node
 this.deleteFromCanvas = deleteFromCanvas; //Delete svg node
 this.enableEvent = enableEvent;  //Enable/Disable svg mouse event
 
 this.checkNeighbour = checkNeighbour; //Check image neighbour or not
 this.mergeImage = mergeImage;
 
}

function deleteFromCanvas()
{
 var groupId = "group" + this.id;
 var parentGroup = svgDocument.getElementById(this.parentId);
 var group = svgDocument.getElementById(groupId);
 
 if ((parentGroup != null) && (group != null) )
  parentGroup.removeChild(group);
}

function hide()
{
 var groupId = "group" + this.id;
 var group = svgDocument.getElementById(groupId);
 if(group != null)
 {
  group.setAttributeNS(null, "display", "none");
 }
}

function mergeImage(newImage)
{
 if( (newImage == null) || (newImage.region == null))
  return;
  
 //Merge image clip region
 this.region.mergeRegion(newImage.region);
 newImage.enableEvent(false);
 newImage.hide();
}

function create()
{
 var parentGroup = svgDocument.getElementById(this.parentId);
 var group, clip, path, image;
 
 var groupId = "group" + this.id;
 var clipId = "clip" + this.id;
 var pathId = "path" + this.id;
 var imageId = "image" + this.id;
 
 group = svgDocument.getElementById(groupId);
 
 if(group == null)
 {
  //Create object, including group, clip-path and image
  group = svgDocument.createElementNS(svgNS, "g");
  parentGroup.appendChild(group);
  group.setAttributeNS(null, "id", groupId);
  //group.setAttributeNS(null, "opacity", "0.8");
  
  //Create clip and clip path
  clip = svgDocument.createElementNS(svgNS, "clipPath");
  clip.setAttributeNS(null,"id",clipId);
  path = svgDocument.createElementNS(svgNS, "path");
  path.setAttributeNS(null,"id",pathId);
  //path.setAttributeNS(null,"fill","none");
  //path.setAttributeNS(null,"stroke","none");
  clip.appendChild(path);
  
  //Create image
  image = svgDocument.createElementNS(svgNS, "image");
  image.setAttributeNS(null, "id", imageId);
  image.setAttributeNS(null, "width", imageWidth);
  image.setAttributeNS(null, "height", imageHeight);
  image.setAttributeNS(null, "preserveAspectRatio", "none");
  image.setAttributeNS(xlinkNS, "xlink:href", IMAGE_SOURCE);
  var urlClip = "url(#" + clipId + ")";
  image.setAttributeNS(null, "clip-path", urlClip);
 
  //Add clip and image to group 
  group.appendChild(clip);
  group.appendChild(image);
 }
  
 group.setAttributeNS(null, "display", "inline");
}

function updatePath()
{
 var pathId = "path" + this.id;
 path = svgDocument.getElementById(pathId);
 
 if(path != null)
  path.setAttributeNS(null,"d", this.region.getPathStr());
}

function updateImage(cx, cy, rotateFlag, rx, ry)
{
 var groupId = "group" + this.id;
 
 group = svgDocument.getElementById(groupId);
 
 if(group == null)
  return;
  
 var sin, cos;
 if(rotateFlag == 1) //90
 {
  sin = 1;
  cos = 0;
 }
 else if(rotateFlag == 2) //180
 {
  sin = 0;
  cos = -1;
 }
 else if(rotateFlag == 3) //270
 {
  sin = -1;
  cos = 0;
 }
 else //default 0
 {
  sin = 0;
  cos = 1;
 }
 
 //Update tranform matrix
 var transMatrix = group.getCTM();
 var newMatrix = svgRoot.createSVGMatrix();
 newMatrix.a = transMatrix.a * cos - transMatrix.b * sin;
 newMatrix.b = transMatrix.a * sin + transMatrix.b * cos;
 newMatrix.c = transMatrix.c * cos - transMatrix.d * sin;
 newMatrix.d = transMatrix.c * sin + transMatrix.d * cos;
 newMatrix.e = transMatrix.e * cos - transMatrix.f * sin - rx * cos + ry * sin + rx + cx ;
 newMatrix.f = transMatrix.e * sin + transMatrix.f * cos - rx * sin - ry * cos + ry + cy ;
 
 var transformStr = matrixToStr(newMatrix);
  
 group.setAttributeNS(null, "transform", transformStr);
 group.setAttributeNS(null, "display", "inline");
 
 //Update image object angle value
 this.angle = (this.angle + rotateFlag * 90) % 360;
}


function enableEvent(flag)
{
 //Enable or disable mouse event
 var elem = svgDocument.getElementById("image" + this.id);
 if(elem == null)
  return;
  
 if(flag)
  elem.setAttributeNS(null, "pointer-events", "all");
 else
  elem.setAttributeNS(null, "pointer-events", "none");
}

function checkNeighbour(newImage)
{
 if(newImage == null)
  return;
  
 //Same direction
 if(this.angle != newImage.angle)
 {
  //alert("direction wrong");
  return false;
 }
 
 //Check distance scope 
 var group1Id = "group" + this.id;
 var group1 = svgDocument.getElementById(group1Id);
 var transMatrix1 = group1.getCTM();
 
 var group2Id = "group" + newImage.id;
 var group2 = svgDocument.getElementById(group2Id);
 var transMatrix2 = group2.getCTM();
 
 var cx = transMatrix1.e - transMatrix2.e;
 var cy = transMatrix1.f - transMatrix2.f;
 
 
 if( (cx*cx + cy*cy) > (MIN_MERGE_DISTANCE * MIN_MERGE_DISTANCE) )
 {
  //alert("distance wrong");
  return false;
 }
 
 
 //Have neighbour block
 if( this.region.isNeighbour(newImage.region) == false )
 {
  //alert("blocks wrong");
  return false;
 }
 
 //Really a neighbour
 return true;
}

///
/// ImageObject class finished
///

//
//Mouse event handlers
//

//Grab by mouse 
function grab(evt)
{
 if(evt.button != 0) //Left mouse button
  return;
  
 var targetElement = evt.target;
 if ( background == targetElement )
 {
  //Do nothing about background
  return;
 }
   
 var id = targetElement.getAttributeNS(null, "id");
 //alert(id);
  
 dragImage = getImageObject(id);
 if(dragImage == null)
 {
  //alert("No drag");
  return;
 }
 
 //Swap svg node by id, move target to front(appendChild prove to be very slowly)
 var canvas = svgDocument.getElementById(CANVAS_ID);
 var lastId = canvas.lastChild.getAttributeNS(null, "id");
 
 if( id.substr(5) == lastId.substr(5))
 {
  swapFlag = false; // Front one, do not need swap
 }
 else
 {
  //var lastImage = getImageObject(lastId);
  swapImage(id.substr(5), lastId.substr(5));
  swapFlag = true;
 }
 
 //Set selected flag
 //canvas.lastChild.setAttributeNS(null, "opacity", "1");
  
 //Remember old position
 orgPoint.x = trueCoords.x;    
 orgPoint.y = trueCoords.y;    

 grabPoint.x = trueCoords.x;
 grabPoint.y = trueCoords.y;
 
 dragImage.enableEvent(false);
 showOutline(dragImage.region.getOutline());
}

function drag(evt)
{
 getTrueCoords(evt);
  
 if (dragImage)
 {
  var newX = trueCoords.x - grabPoint.x;
  var newY = trueCoords.y - grabPoint.y;
  
  dragImage.updateImage(newX, newY, 0, 0, 0);
  
  grabPoint.x = trueCoords.x;
  grabPoint.y = trueCoords.y;
 }
}

function drop(evt)
{
 getTrueCoords(evt);
 var mergeFlag = false;
 
 if ( dragImage )
 {
  var newImage = getNeighbourImage();
  if(newImage != null)
  {
   //Merge happened
   dragImage.mergeImage(newImage);
   dragImage.updatePath();
   showOutline(dragImage.region.getOutline());
   
   //Finish or not
   if(dragImage.region.blocks.length == imageRow * imageCol)
   {
    //Congratulations!
    setTimeout("gameOver()", 500);
   }
    
   mergeFlag = true;
   newImage.deleteFromCanvas(); //Delete SVG node
   newImage = null;
  }
   
  if( (!swapFlag) && (!mergeFlag) )
  {
   //Rotate image in case of no swap and no merge
   var cx = trueCoords.x - orgPoint.x;
   var cy = trueCoords.y - orgPoint.y;
   if( (cx*cx + cy*cy) <= (MIN_ROTATE_DISTANCE * MIN_ROTATE_DISTANCE) )
   {
    var newX = trueCoords.x - grabPoint.x;
    var newY = trueCoords.y - grabPoint.y;
    dragImage.updateImage(newX, newY, 1, trueCoords.x, trueCoords.y);
   }
  }
  
  dragImage.enableEvent(true);
  dragImage = null;
  swapFlag = false;
 }
}

// ]]>
</script>

 <defs>
  <menu id="menu1" >
   <header>Menu</header>
  </menu>
 </defs>
 
 <rect id="background" x="0" y="0" width="100%" height="100%" fill="white" pointer-events="all" />
 <g id="canvas" >
 </g>
 
</svg>


--  作者:alai7150
--  发布时间:1/6/2007 9:06:00 AM

--  
兄弟 你不能弄短一点的程序啊,看别人 的程序是最头疼的事情,更何况这么长!
慢慢啃吧。
--  作者:wwwtiger
--  发布时间:1/8/2007 10:29:00 AM

--  
Sorry,这是我为了测试SVG的图形处理速度编写的一个拼图小游戏,程序不是很严谨,也没有说明文档,仅仅供测试和参考。当时懒得写中文,于是写了一些英文注释,在http://blog.csdn.net/firefight/archive/2006/11/16/1387356.aspx有一些简短的程序说明,希望有所帮助。



W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
109.375ms