UNPKG

jointjs

Version:

JavaScript diagramming library

252 lines (222 loc) 7.87 kB
joint.dia.Element.define('jigsaw.Piece', { attrs: { polygon: { tabs: [0, 0, 0, 0], image: ['', 0, 0], stroke: '#ddd' } } }, { markup: [{ tagName: 'polygon', selector: 'polygon' }] } , { attributes: { tabs: { /* [topTab, rightTab, bottomTab, leftTab] */ qualify: Array.isArray, set: function(tabs, refBBox) { var tabSize = this.model.prop('tabSize'); var points = []; var refCenter = refBBox.center(); var refPoints = [ refBBox.origin(), refBBox.topRight(), refBBox.corner(), refBBox.bottomLeft() ]; for (var i = 0; i < 4; i++) { var a = refPoints[i]; var b = refPoints[i + 1] || refPoints[0]; points.push(a); if (tabs[i]) { var mid = g.Line(a, b).midpoint(); points.push( mid.clone().move(b, tabSize), mid.clone().move(refCenter, tabs[i] * tabSize), mid.clone().move(a, tabSize) ); } } return { points: points.join(' ').replace(/@/g,' ') }; } }, image: { /* [imageId, rowIndex, columnIndex] */ qualify: Array.isArray, set: function(image) { var paper = this.paper; var model = this.model; var width = model.prop('size/width'); var height = model.prop('size/height'); var id = 'image-pattern-' + width + '-' + height + '-' + image.join('-'); if (!paper.isDefined(id)) { var tabSize = model.get('tabSize'); V('pattern', { id: id, x: - tabSize, y: - tabSize, width: width + 2 * tabSize, height: height + 2 * tabSize, patternUnits: 'userSpaceOnUse' }, [ V('use', { 'xlink:href': '#' + image[0], x: - (image[1] * width + tabSize), y: - (image[2] * height + tabSize) }) ]).appendTo(paper.defs); } return { fill: 'url(#' + id + ')' }; } } } }); var Jigsaw = { GRID: 10, PADDING: 200, TAB_RATIO: .15, IMAGE_ID: 'puzzle-image', createPuzzle: function(sizeArray, imageHref) { var graph = this.graph = new joint.dia.Graph; var paper = this.paper = new joint.dia.Paper({ el: document.getElementById('paper'), gridSize: this.GRID, model: graph, clickThreshold: 5, async: true, sorting: joint.dia.Paper.sorting.APPROX }).on({ 'cell:pointerdown': function(pieceView) { pieceView.model.toFront(); pieceView.highlight('polygon'); }, 'cell:pointerup': function(pieceView) { pieceView.unhighlight('polygon'); }, 'cell:pointerclick': function(pieceView) { pieceView.model.rotate(90); } }, this); this.vImage = V('image', { id: this.IMAGE_ID, preserveAspectRatio: 'none' }).appendTo(paper.defs); this._setImageHref(imageHref); this.resizePuzzle(sizeArray); }, resizePuzzle: function(sizeArray) { this._setSize.apply(this, sizeArray); this.playPuzzle(); }, changePuzzleImage: function(imageHref) { this._setImageHref(imageHref); this.playPuzzle(); }, playPuzzle: function() { this.paper.freeze(); this.generatePuzzle(); this.shufflePuzzle(3000); this.paper.unfreeze(); }, shufflePuzzle: function(delay) { var pieces = this.graph.getElements(); for (var i = 0, n = pieces.length; i < n; i++) { var piece = pieces[i]; piece.transition('position', g.Point({ x: this.PADDING + (Math.random() * this.width) - this.pieceSize / 2, y: this.PADDING + (Math.random() * this.height) - this.pieceSize / 2 }).snapToGrid(this.GRID).toJSON(), { valueFunction: joint.util.interpolate.object, delay: delay || 0, duration: 1000 }); piece.transition('angle', sample([0, 90, 180, 270]), { delay: delay || 0, duration: 1000 }); } }, generatePuzzle: function() { var rows = this.rows; var columns = this.columns; var pieceSize = this.pieceSize; this.graph.clear(); var pieces = []; for (var r = 0; r < rows; r++) { for (var c = 0; c < columns; c++) { var tabs = [0, 0, 0, 0]; if (c < (columns - 1)) { tabs[1] = sample([1, -1]); } if (r < (rows - 1)) { tabs[2] = sample([1, -1]); } if (r > 0) { tabs[0] -= pieces[(r - 1) * columns + c].attr('polygon/tabs/2'); } if (c > 0) { tabs[3] -= pieces[r * columns + c - 1].attr('polygon/tabs/1'); } pieces.push(new joint.shapes.jigsaw.Piece({ position: { x: this.PADDING + c * pieceSize, y: this.PADDING + r * pieceSize }, size: { width: pieceSize, height: pieceSize }, tabSize: this.TAB_RATIO * pieceSize, attrs: { polygon: { tabs: tabs, image: [this.IMAGE_ID, c, r] } }, z: 0 }).addTo(this.graph)); } } }, _setImageHref: function(imageHref) { this.vImage.attr('xlink:href', imageHref); }, _setImageSize: function(width, height, pieceSize) { this.vImage.attr({ x: 2 * this.TAB_RATIO * pieceSize, y: 2 * this.TAB_RATIO * pieceSize, width: width, height: height }); }, _setSize: function(rows, columns, pieceSize) { this.rows = rows; this.columns = columns; this.pieceSize = pieceSize; var width = this.width = columns * pieceSize; var height = this.height = rows * pieceSize; this._setImageSize(width, height, pieceSize); this.paper.setDimensions( 2 * this.PADDING + width, 2 * this.PADDING + height ); } }; // Initialization var imagePicker = document.getElementById('image-picker'); var sizePicker = document.getElementById('size-picker'); imagePicker.addEventListener('change', function() { Jigsaw.changePuzzleImage(this.value); }); sizePicker.addEventListener('change', function() { Jigsaw.resizePuzzle(JSON.parse(this.value)); }); Jigsaw.createPuzzle(JSON.parse(sizePicker.value), imagePicker.value); // Utils function sample(values) { return values[Math.ceil(Math.random() * values.length) - 1]; }