canvas图片生成各种拼图裁切分解代码
代码语言:html
所属分类:其他
代码描述:canvas图片生成各种拼图裁切分解代码
代码标签: canvas 图片 生成 各种 拼图 裁切 分解 代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> body { font-family: Arial, Helvetica, "Liberation Sans", FreeSans, sans-serif; background-color: #fff; margin: 0; padding: 0; border-width: 0; cursor: pointer; } #menu { position: relative; list-style-type: none; padding-left: 5px; z-index: 1000; /* 1 */ display: inline-block; text-align: center; } #menu li { margin: 2px; padding: 4px 10px; border-radius: 5px; background-color: #ffff80; } #menu li:hover { background-color: #ffDD60; } #forPuzzle { position: absolute; width: 95vw; height: 95vh; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #ffffdd; overflow: hidden; } .polypiece { display: block; overflow: hidden; position: absolute; } .moving { transition-property: top, left; transition-duration: 1s; transition-timing-function: linear; } .gameCanvas { display: none; overflow: hidden; position: absolute; } </style> </head> <body translate="no"> <div id=forPuzzle></div> <ul id="menu"> <li>☰</li> <li>Reset</li> <li>load image</li> <li>shape: <select id="shape"> <option value="1" selected>classic</option> <option value="2">triangle</option> <option value="3">round</option> <option value="4">straight</option> </select></li> <li>12 pieces</li> <li>25 pieces</li> <li>50 pieces</li> <li>100 pieces</li> <li>200 pieces</li> </ul> <script > "use strict"; let puzzle, autoStart; const mhypot = Math.hypot, mrandom = Math.random, mmax = Math.max, mmin = Math.min, mround = Math.round, mfloor = Math.floor, msqrt = Math.sqrt, mabs = Math.abs; //----------------------------------------------------------------------------- function isMiniature() { return location.pathname.includes('/fullcpgrid/'); } //----------------------------------------------------------------------------- function alea(min, max) { // random number [min..max[ . If no max is provided, [0..min[ if (typeof max == 'undefined') return min * mrandom(); return min + (max - min) * mrandom(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function intAlea(min, max) { // random integer number [min..max[ . If no max is provided, [0..min[ if (typeof max == 'undefined') { max = min;min = 0; } return mfloor(min + (max - min) * mrandom()); } // intAlea // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function arrayShuffle(array) { /* randomly changes the order of items in an array only the order is modified, not the elements */ let k1, temp; for (let k = array.length - 1; k >= 1; --k) { k1 = intAlea(0, k + 1); temp = array[k]; array[k] = array[k1]; array[k1] = temp; } // for k return array; } // arrayShuffle //----------------------------------------------------------------------------- // Point - - - - - - - - - - - - - - - - - - - - class Point { constructor(x, y) { this.x = Number(x); this.y = Number(y); } // constructor copy() { return new Point(this.x, this.y); } distance(otherPoint) { return mhypot(this.x - otherPoint.x, this.y - otherPoint.y); }} // class Point // Segment - - - - - - - - - - - - - - - - - - - - // those segments are oriented class Segment { constructor(p1, p2) { this.p1 = new Point(p1.x, p1.y); this.p2 = new Point(p2.x, p2.y); } dx() { return this.p2.x - this.p1.x; } dy() { return this.p2.y - this.p1.y; } length() { return mhypot(this.dx(), this.dy()); } // returns a point at a given distance of p1, positive direction beeing towards p2 pointOnRelative(coeff) { // attention if segment length can be 0 let dx = this.dx(); let dy = this.dy(); return new Point(this.p1.x + coeff * dx, this.p1.y + coeff * dy); }} // class Segment //----------------------------------------------------------------------------- // one side of a piece class Side { constructor() { this.type = ""; // "d" pour straight line or "z" pour classic this.points = []; // real points or Bezier curve points // this.scaledPoints will be added when we know the scale } // Side //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - reversed() { // returns a new Side, copy of current one but reversed const ns = new Side(); ns.type = this.type; ns.points = this.points.slice().reverse(); return ns; } // Side.reversed //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - scale(puzzle) { /* uses actual dimensions of puzzle to compute actual side points these points are not shifted by the piece position : the top left corner is at (0,0) */ const coefx = puzzle.scalex; const coefy = puzzle.scaley; this.scaledPoints = this.points.map(p => new Point(p.x * coefx, p.y * coefy)); } // //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* draws the path corresponding to a side Parameters : ctx : canvas context shiftx, shifty : position shift (used to create emboss effect) withoutMoveTo : to decide whether to do a moveTo to the first point. Without MoveTo must be done only for the first side of a piece, not for the following ones */ drawPath(ctx, shiftx, shifty, withoutMoveTo) { if (!withoutMoveTo) { ctx.moveTo(this.scaledPoints[0].x + shiftx, this.scaledPoints[0].y + shifty); } if (this.type == "d") { ctx.lineTo(this.scaledPoints[1].x + shiftx, this.scaledPoints[1].y + shifty); } else {// edge zigzag for (let k = 1; k < this.scaledPoints.length - 1; k += 3) { ctx.bezierCurveTo(this.scaledPoints[k].x + shiftx, this.scaledPoints[k].y + shifty, this.scaledPoints[k + 1].x + shiftx, this.scaledPoints[k + 1].y + shifty, this.scaledPoints[k + 2].x + shiftx, this.scaledPoints[k + 2].y + shifty); } // for k } // if jigsaw side } // Side.drawPath } // class Side //----------------------------------------------------------------------------- /* modifies a side changes it from a straight line (type "d") to a complex one (type "z") The change is done towards the opposite side (side between corners ca and cb) */ function twist0(side, ca, cb) { const seg0 = new Segment(side.points[0], side.points[1]); const dxh = seg0.dx(); const dyh = seg0.dy(); const seg1 = new Segment(ca, cb); const mid0 = seg0.pointOnRelative(0.5); const mid1 = seg1.pointOnRelative(0.5); const segMid = new Segment(mid0, mid1); const dxv = segMid.dx(); const dyv = segMid.dy(); const scalex = alea(0.8, 1); const scaley = alea(0.9, 1); const mid = alea(0.45, 0.55); const pa = pointAt(mid - 1 / 12 * scalex, 1 / 12 * scaley); const pb = pointAt(mid - 2 / 12 * scalex, 3 / 12 * scaley); const pc = pointAt(mid, 4 / 12 * scaley); const pd = pointAt(mid + 2 / 12 * scalex, 3 / 12 * scaley); const pe = pointAt(mid + 1 / 12 * scalex, 1 / 12 * scaley); side.points = [seg0.p1, new Point(seg0.p1.x + 5 / 12 * dxh * 0.52, seg0.p1.y + 5 / 12 * dyh * 0.52), new Point(pa.x - 1 / 12 * dxv * 0.72, pa.y - 1 / 12 * dyv * 0.72), pa, new Point(pa.x + 1 / 12 * dxv * 0.72, pa.y + 1 / 12 * dyv * 0.72), new Point(pb.x - 1 / 12 * dxv * 0.92, pb.y - 1 / 12 * dyv * 0.92), pb, new Point(pb.x + 1 / 12 * dxv * 0.52, pb.y + 1 / 12 * dyv * 0.52), new Point(pc.x - 2 / 12 * dxh * 0.40, pc.y - 2 / 12 * dyh * 0.40), pc, new Point(pc.x + 2 / 12 * dxh * 0.40, pc.y + 2 / 12 * dyh * 0.40), new Point(pd.x + 1 / 12 * dxv * 0.52, pd.y + 1 / 12 * dyv * 0.52), pd, new Point(pd.x - 1 / 12 * dxv * 0.92, pd.y - 1 / 12 * dyv * 0.92), new Point(pe.x + 1 / 12 * dxv * 0.72, pe.y + 1 / 12 * dyv * 0.72), pe, new Point(pe.x - 1 / 12 * dxv * 0.72, pe.y - 1 / 12 * dyv * 0.72), new Point(seg0.p2.x - 5 / 12 * dxh * 0.52, seg0.p2.y - 5 / 12 * dyh * 0.52), seg0.p2]; side.type = "z"; function pointAt(coeffh, coeffv) { return new Point(seg0.p1.x + coeffh * dxh + coeffv * dxv, seg0.p1.y + coeffh * dyh + coeffv * dyv); } // pointAt } // twist0 //----------------------------------------------------------------------------- /* modifies a side changes it from a straight line (type "d") to a complex one (type "z") The change is done towards the opposite side (side between corners ca and cb) */ function twist1(side, ca, cb) { const seg0 = new Segment(side.points[0], side.points[1]); const dxh = seg0.dx(); const dyh = seg0.dy(); const seg1 = new Segment(ca, cb); const mid0 = seg0.pointOnRelative(0.5); const mid1 = seg1.pointOnRelative(0.5); const segMid = new Segment(mid0, mid1); const dxv = segMid.dx(); const dyv = segMid.dy(); const pa = pointAt(alea(0.3, 0.35), alea(-0.05, 0.05)); const pb = pointAt(alea(0.45, 0.55), alea(0.2, 0.3)); const pc = pointAt(alea(0.65, 0.78), alea(-0.05, 0.05)); side.points = [seg0.p1, seg0.p1, pa, pa, pa, pb, pb, pb, pc, pc, pc, seg0.p2, seg0.p2]; side.type = "z"; function pointAt(coeffh, coeffv) { return new Point(seg0.p1.x + coeffh * dxh + coeffv * dxv, seg0.p1.y + coeffh * dyh + coeffv * dyv); } // pointAt } // twist1 //----------------------------------------------------------------------------- /* modifies a side changes it from a straight line (type "d") to a complex one (type "z") The change is done towards the opposite side (side between corners ca and cb) */ function twist2(side, ca, cb) { const seg0 = new Segment(side.points[0], side.points[1]); const dxh = seg0.dx(); const dyh = seg0.dy(); const seg1 = new Segment(ca, cb); const mid0 = seg0.pointOnRelative(0.5); const mid1 = seg1.pointOnRelative(0.5); const segMid = new Segment(mid0, mid1); const dxv = segMid.dx(); const dyv = segMid.dy(); const hmid = alea(0.45, 0.55); const vmid = alea(0.4, 0.5); const pc = pointAt(hmid, vmid); let sega = new Segment(seg0.p1, pc); const pb = sega.pointOnRelative(2 / 3); sega = new Segment(seg0.p2, pc); const pd = sega.pointOnRelative(2 / 3); side.points = [seg0.p1, pb, pd, seg0.p2]; side.type = "z"; function pointAt(coeffh, coeffv) { return new Point(seg0.p1.x + coeffh * dxh + coeffv * dxv, seg0.p1.y + coeffh * dyh + coeffv * dyv); } // pointAt } // twist2 //----------------------------------------------------------------------------- /* modifies a side changes it from a straight line (type "d") to a complex one (type "z") The change is done towards the opposite side (side between corners ca and cb) */ function twist3(side, ca, cb) { side.points = [side.points[0], side.points[1]]; } // twist3 //----------------------------------------------------------------------------- class Piece { constructor(kx, ky) {// object with 4 sides this.ts = new Side(); // top side this.rs = new Side(); // right side this.bs = new Side(); // bottom side this.ls = new Side(); // left side this.kx = kx; this.ky = ky; } //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - scale(puzzle) { this.ts.scale(puzzle); this.rs.scale(puzzle); this.bs.scale(puzzle); this.ls.scale(puzzle); } // Piece.scale } // class Piece //-------------------------------------------------------------- //-------------------------------------------------------------- class PolyPiece { // represents a group of pieces well positionned with respect to each other. // pckxmin, pckxmax, pckymin and pckymax record the lowest and highest kx and ky // creates a canvas to draw polypiece on, and appends this canvas to puzzle.container constructor(initialPiece, puzzle) { this.pckxmin = initialPiece.kx; this.pckxmax = initialPiece.kx + 1; this.pckymin = initialPiece.ky; this.pckymax = initialPiece.ky + 1; this.pieces = [initialPiece]; this.puzzle = puzzle; this.listLoops(); this.canvas = document.createElement('CANVAS'); // size and z-index will be defined later puzzle.container.appendChild(this.canvas); this.canvas.classList.add('polypiece'); this.ctx = this.canvas.getContext("2d"); } // PolyPiece // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* this method - adds pieces of otherPoly to this PolyPiece - reorders the pieces inside the polypiece - adjusts coordinates of new pieces to make them consistent with this polyPiece - re-evaluates the z - index of the polyPieces */ merge(otherPoly) { const orgpckxmin = this.pckxmin; const orgpckymin = this.pckymin; // remove otherPoly from list of polypieces const kOther = this.puzzle.polyPieces.indexOf(otherPoly); this.puzzle.polyPieces.splice(kOther, 1); // remove other canvas from container this.puzzle.container.removeChild(otherPoly.canvas); for (let k = 0; k < otherPoly.pieces.length; ++k) { this.pieces.push(otherPoly.pieces[k]); // watch leftmost, topmost... pieces if (otherPoly.pieces[k].kx < this.pckxmin) this.pckxmin = otherPoly.pieces[k].kx; if (otherPoly.pieces[k].kx + 1 > this.pckxmax) this.pckxmax = otherPoly.pieces[k].kx + 1; if (otherPoly.pieces[k].ky < this.pckymin) this.pckymin = otherPoly.pieces[k].ky; if (otherPoly.pieces[k].ky + 1 > this.pckymax) this.pckymax = otherPoly.pieces[k].ky + 1; } // for k // sort the pieces by increasing kx, ky this.pieces.sort(function (p1, p2) { if (p1.ky < p2.ky) return -1; if (p1.ky > p2.ky) return 1; if (p1.kx < p2.kx) return -1; if (p1.kx > p2.kx) return 1; return 0; // should not occur }); // redefine consecutive edges this.listLoops(); this.drawImage(); this.moveTo(this.x + this.puzzle.scalex * (this.pckxmin - orgpckxmin), this.y + this.puzzle.scaley * (this.pckymin - orgpckymin)); this.puzzle.evaluateZIndex(); } // merge // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ifNear(otherPoly) { let p1, p2; let puzzle = this.puzzle; // coordinates of origin of full picture for this PolyPieces let x = this.x - puzzle.scalex * this.pckxmin; let y = this.y - puzzle.scaley * this.pckymin; let ppx = otherPoly.x - puzzle.scalex * otherPoly.pckxmin; let ppy = otherPoly.y - puzzle.scaley * otherPoly.pckymin; if (mhypot(x - ppx, y - ppy) >= puzzle.dConnect) return false; // not close enough // this and otherPoly are in good relative position, have they a common side ? for (let k = this.pieces.length - 1; k >= 0; --k) { p1 = this.pieces[k]; for (let ko = otherPoly.pieces.length - 1; ko >= 0; --ko) { p2 = otherPoly.pieces[ko]; if (p1.kx == p2.kx && mabs(p1.ky - p2.ky) == 1) return true; // true neighbors found if (p1.ky == p2.ky && mabs(p1.kx - p2.kx) == 1) return true; // true neighbors found } // for k } // for k // nothing matches return false; } // ifNear // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* algorithm to determine the boundary of a PolyPiece input : a table of cells, hopefully defining a 'good' PolyPiece, i.e. all connected together every cell is given as an object {kx: indice, ky: indice} representing an element of a 2D array. returned value : table of Loops, because the boundary may be made of several simple loops : there may be a 'hole' in a PolyPiece every loop is a list of consecutive edges, every edge if an object {kp: index, edge: b} where kp is the index of the cell ine the input array, and edge the side (0(top), 1(right), 2(bottom), 3(left)) every edge contains kx and ky too, normally not used here This method does not depend on the fact that pieces have been scaled or not. */ listLoops() { // internal : checks if an edge given by kx, ky is common with another cell // returns true or false const that = this; function edgeIsCommon(kx, ky, edge) { let k; switch (edge) { case 0:ky--;break; // top edge case 1:kx++;break; // right edge case 2:ky++;break; // bottom edge case 3:kx--;break; // left edge } // switch for (k = 0; k < that.pieces.length; k++) { if (kx == that.pieces[k].kx && ky == that.pieces[k].ky) return true; // we found the neighbor } return false; // not a common edge } // function edgeIsCommon // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // internal : checks if an edge given by kx, ky is in tbEdges // return index in tbEdges, or false function edgeIsInTbEdges(kx, ky, edge) { let k; for (k = 0; k < tbEdges.length; k++) { if (kx == tbEdges[k].kx && ky == tbEdges[k].ky && edge == tbEdges[k].edge) return k; // found it } return false; // not found } // function edgeIsInTbEdges // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - let tbLoops = []; // for the result let tbEdges = []; // set of edges which are not shared by 2 pieces of input let k; let kEdge; // to count 4 edges let lp; // for loop during its creation let currEdge; // current edge let tries; // tries counter let edgeNumber; // number of edge found during research let potNext; // table of tries let tbTries = [ // if we are on edge 0 (top) [ { dkx: 0, dky: 0, edge: 1 }, // try # 0 { dkx: 1, dky: 0, edge: 0 }, // try # 1 { dkx: 1, dky: -1, edge: 3 } // try # 2 ], // if we are on edge 1 (right) [ { dkx: 0, dky: 0, edge: 2 }, { dkx: 0, dky: 1, edge: 1 }, { dkx: 1, dky: 1, edge: 0 }], // if we are on edge 2 (bottom) [ { dkx: 0, dky: 0, edge: 3 }, { dkx: -1, dky: 0, edge: 2 }, { dkx: -1, dky: 1, edge: 1 }], // if we are on edge 3 (left) [ { dkx: 0, dky: 0, edge: 0 }, { dkx: 0, dky: -1, edge: 3 }, { dkx: -1, dky: -1, edge: 2 }]]; // create list of not shared edges (=> belong to boundary) for (k = 0; k < this.pieces.length; k++) { for (kEdge = 0; kEdge < 4; kEdge++) { if (!edgeIsCommon(this.pieces[k].kx, this.pieces[k].ky, kEdge)) tbEdges.push({ kx: this.pieces[k].kx, ky: this.pieces[k].ky, edge: kEdge, kp: k }); } // for kEdge } // for k while (tbEdges.length > 0) { lp = []; // new loop currEdge = tbEdges[0]; // we begin with first available edge lp.push(currEdge); // add it to loop tbEdges.splice(0, 1); // remove from list of available sides do { for (tries = 0; tries < 3; tries++) { potNext = tbTries[currEdge.edge][tries]; edgeNumber = edgeIsInTbEdges(currEdge.kx + potNext.dkx, currEdge.ky + potNext.dky, potNext.edge); if (edgeNumber === false) continue; // can't here // new element in loop currEdge = tbEdges[edgeNumber]; // new current edge lp.push(currEdge); // add it to loop tbEdges.splice(edgeNumber, 1); // remove from list of available sides break; // stop tries ! } // for tries if (edgeNumber === false) break; // loop is closed } while (1); // do-while exited by break tbLoops.push(lp); // add this loop to loops list } // while tbEdges... // replace components of loops by actual pieces sides this.tbLoops = tbLoops.map(loop => loop.map(edge => { let cell = this.pieces[edge.kp]; if (edge.edge == 0) return cell.ts; if (edge.edge == 1) return cell.rs; if (edge.edge == 2) return cell.bs; return cell.ls; })); } // polyPiece.listLoops // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - drawPath(ctx, shiftx, shifty) { // ctx.beginPath(); No, not for Path2D this.tbLoops.forEach(loop => { let without = false; loop.forEach(side => { side.drawPath(ctx, shiftx, shifty, without); without = true; }); ctx.closePath(); }); } // PolyPiece.drawPath // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - drawImage() { /* resizes canvas to be bigger than if pieces were perfect rectangles so that their shapes actually fit in the canvas copies the relevant part of gamePicture clipped by path adds shadow and emboss */ // if (this.pieces[0].kx!=1 ||this.pieces[0].ky!= 1) return; puzzle = this.puzzle; this.nx = this.pckxmax - this.pckxmin + 1; this.ny = this.pckymax - this.pckymin + 1; this.canvas.width = this.nx * puzzle.scalex; this.canvas.height = this.ny * puzzle.scaley; // difference between position in this canvas and position in gameImage this.offsx = (this.pckxmin - 0.5) * puzzle.scalex; this.offsy = (this.pckymin - 0.5) * puzzle.scaley; this.path = new Path2D(); this.drawPath(this.path, -this.offsx, -this.offsy); // make shadow this.ctx.fillStyle = 'none'; this.ctx.shadowColor = 'rgba(0, 0, 0, 0.5)'; this.ctx.shadowBlur = 4; this.ctx.shadowOffsetX = 4; this.ctx.shadowOffsetY = 4; this.ctx.fill(this.path); this.ctx.shadowColor = 'rgba(0, 0, 0, 0)'; // stop shadow effect this.pieces.forEach((pp, kk) => { this.ctx.save(); const path = new Path2D(); const shiftx = -this.offsx; const shifty = -this.offsy; pp.ts.drawPath(path, shiftx, shifty, false); pp.rs.drawPath(path, shiftx, shifty, true); pp.bs.drawPath(path, shiftx, shifty, true); pp.ls.drawPath(path, shiftx, shifty, true); path.closePath(); this.ctx.clip(path); // do not copy from negative coordinates, does not work for all browsers const srcx = pp.kx ? (pp.kx - 0.5) * puzzle.scalex : 0; const srcy = pp.ky ? (pp.ky - 0.5) * puzzle.scaley : 0; const destx = (pp.kx ? 0 : puzzle.scalex / 2) + (pp.kx - this.pckxmin) * puzzle.scalex; const desty = (pp.ky ? 0 : puzzle.scaley / 2) + (pp.ky - this.pckymin) * puzzle.scaley; let w = 2 * puzzle.scalex; let h = 2 * puzzle.scaley; if (srcx + w > puzzle.gameCanvas.width) w = puzzle.gameCanvas.width - srcx; if (srcy + h > puzzle.gameCanvas.height) h = puzzle.gameCanvas.height - srcy; this.ctx.drawImage(puzzle.gameCanvas, srcx, srcy, w, h, destx, desty, w, h); this.ctx.translate(puzzle.embossThickness / 2, -puzzle.embossThickness / 2); this.ctx.lineWidth = puzzle.embossThickness; this.ctx.strokeStyle = "rgba(0, 0, 0, 0.35)"; this.ctx.stroke(path); this.ctx.translate(-puzzle.embossThickness, puzzle.embossThickness); this.ctx.strokeStyle = "rgba(255, 255, 255, 0.35)"; this.ctx.stroke(path); this.ctx.restore(); }); } // PolyPiece.drawImage moveTo(x, y) { // sets the left, top properties (relative to container) of this.canvas this.x = x; this.y = y; this.canvas.style.left = x + 'px'; this.canvas.style.top = y + 'px'; } // moveToInitialPlace() { const puzzle = this.puzzle; this.moveTo(puzzle.offsx + (this.pckxmin - 0.5) * puzzle.scalex, puzzle.offsy + (this.pckymin - 0.5) * puzzle.scaley); }} // class PolyPiece //----------------------------------------------------------------------------- class Puzzle { /* params contains : container : mandatory - given by id (string) or element it will not be resized in this script ONLY ONE Puzzle object should be instanced. only "container is mandatory, nbPieces and pictures may be provided to get initial default values. Once a puzzle is solved (and event if not solved) another game can be played by changing the image file or the number of pieces, NOT by invoking new Puzzle */ constructor(params) { this.autoStart = false; this.container = typeof params.container == "string" ? document.getElementById(params.container) : params.container; /* the following code will add the event Handlers several times if new Puzzle objects are created with same container. the presence of previous event listeners is NOT detectable */ this.container.addEventListener("mousedown", event => { event.preventDefault(); events.push({ event: 'touch', position: this.relativeMouseCoordinates(event) }); }); this.container.addEventListener("touchstart", event => { event.preventDefault(); if (event.touches.length != 1) return; let ev = event.touches[0]; events.push({ event: 'touch', position: this.relativeMouseCoordinates(ev) }); }, { passive: false }); this.container.addEventListener("mouseup", event => { event.preventDefault(); handleLeave(); }); this.container.addEventListener("touchend", handleLeave); this.container.addEventListener("touchleave", handleLeave); this.container.addEventListener("touchcancel", handleLeave); this.container.addEventListener("mousemove", event => { event.preventDefault(); // do not accumulate move event.........完整代码请登录后点击上方下载按钮下载查看
网友评论0