1
0
Fork 0
masonry-static/app/main.js

330 lines
8.8 KiB
JavaScript

const ShelfPack = require('@mapbox/shelf-pack');
const jQuery = require('jquery');
const fabric = require('fabric').fabric;
require('fabric-customise-controls');
const margin = 10;
let canvas = null;
let iscircle = false; // circle canvas shape
let isgrid = false; // grid layout
let globalbin = [];
function onimgload(event) {
let img = new Image();
img.src = event.target.result;
jQuery("#masonrydraglibrary")[0].appendChild(img);
jQuery("body").removeClass("drag");
jQuery("#pack").click();
}
/**
* Drag and drop. Dropping an image adds it to the #masonrydraglibrary.
*/
jQuery(document).on("drop", function(ev) {
ev.stopPropagation();
ev.preventDefault();
let dt = ev.originalEvent.dataTransfer;
if (dt.items) {
// Use DataTransferItemList interface to access the file(s)
for (let i=0; i < dt.items.length; i++) {
if (dt.items[i].kind == "file") {
let f = dt.items[i].getAsFile();
let fr = new FileReader();
fr.onload = onimgload;
fr.readAsDataURL(f);
}
}
}
});
jQuery(document).on("dragend", function(ev) {
ev.stopPropagation();
ev.preventDefault();
});
jQuery(document).on("dragenter", function(ev) {
ev.stopPropagation();
ev.preventDefault();
jQuery("body").addClass("drag");
});
jQuery(document).on("dragover", function(ev) {
ev.stopPropagation();
ev.preventDefault();
});
jQuery(document).ready(function() {
jQuery("#masonryslide-container").hide();
jQuery("#masonrylibrary").hide();
jQuery("#masonrydraglibrary").hide();
/*
fabric.Canvas.prototype.customiseControls({
mb: { // middle bottom
action: function (e, target) {
console.log(target);
target._element.cropX(50);
canvas.renderAll();
}
},
}, function() {
canvas.renderAll();
} );
*/
});
jQuery(document).on('click', '#square', function() {
jQuery("button.btn-secondary").removeClass("active");
jQuery(this).addClass("active");
window.cwidth = jQuery(".container").width();
window.cheight = window.cwidth;
jQuery("#masonryslide").html("<canvas id='canvase'></canvas>");
});
jQuery(document).on('click', '#rectangle', function() {
jQuery("button.btn-secondary").removeClass("active");
jQuery(this).addClass("active");
window.cwidth = jQuery(".container").width();
window.cheight = window.cwidth * 1.5;
jQuery("#masonryslide").html("<canvas id='canvase'></canvas>");
});
jQuery(document).on('click', '#circle', function() {
jQuery("button.btn-secondary").removeClass("active");
jQuery(this).addClass("active");
window.cwidth = jQuery(".container").width();
window.cheight = window.cwidth;
iscircle = true;
jQuery("#masonryslide").html("<canvas id='canvase'></canvas>");
});
// Read an image from file input
async function readImage(file) {
return new Promise((resolve, reject) => {
let fr = new FileReader();
fr.onload = (event) => {
let img = document.createElement('img');
img.src = event.target.result;
img.onload = function() {
globalbin.push({
data: this,
width: this.width,
height: this.height,
size: this.width * this.height
});
resolve();
};
};
fr.readAsDataURL(file);
});
}
/**
* Drag & drop is over, now with regular packing
*/
// Aspect ratio
jQuery(document).on('click', '#pack', async function() {
let cheight, cwidth, i, len, ref;
jQuery("#masonryslide-container").show();
let library = jQuery("#masonrylibrary");
library.empty();
library.css({
position: 'absolute',
left: '9999px'
}).show();
globalbin = [];
if (window.cwidth === undefined) {
window.cwidth = 660;
}
if (window.cwidth > jQuery("#masonryslide-container").width()){
window.cwidth = jQuery("#masonryslide-container").width();
}
if (window.cheight === undefined) {
window.cheight = 1000;
}
cwidth = window.cwidth;
cheight = window.cheight;
jQuery("#canvase").width(cwidth).height(cheight);
canvas = new fabric.Canvas("canvase");
canvas.setDimensions({
width: cwidth,
height: cheight
});
ref = document.getElementById('masonryslide-files').files;
if (ref.length > 0) {
for (i = 0, len = ref.length; i < len; i++) {
await readImage(ref[i]);
}
}
let images = document.querySelectorAll("#masonrydraglibrary img");
if (images.length > 0) {
for (i = 0, len = images.length; i < len; i++) {
let image = images[i];
let width = jQuery(image).width();
let height = jQuery(image).height();
globalbin.push({
data: image,
width: width,
height: height,
size: width * height
});
}
}
library.hide();
if (!isgrid) {
globalbin.sort(function(a,b){
return b.size - a.size;
});
}
if (iscircle) {
circlepack (globalbin, canvas);
} else {
pack (globalbin, canvas);
}
});
/**
* The actual packing.
*/
function pack (bin, canvas) {
const cwidth = canvas.width;
const cheight = canvas.height;
let i, len, j, len2;
let sprite = new ShelfPack(cwidth - margin, cheight - margin);
if (isgrid || bin.length <= 4) {
// desired width and height for every image
const dwidth = Math.floor((cwidth - margin) / Math.sqrt(bin.length));
const dheight = Math.floor((cheight - margin) / Math.sqrt(bin.length));
for (i = 0, len = bin.length; i < len; i++) {
if (bin[i].width > bin[i].height) {
bin[i].w = dwidth + margin;
bin[i].h = bin[i].height * (dwidth / bin[i].width) + margin;
} else {
bin[i].w = bin[i].width * (dheight / bin[i].height) + margin;
bin[i].h = dheight + margin;
}
bin[i].id = i;
bin[i] = packone(sprite, cwidth, cheight, bin[i]);
}
} else {
let size = 0;
for (i = 0; i < 4; i++) {
if (bin[i] === undefined) {
break;
}
size += bin[i].size;
}
const ratio = (cwidth * cheight) / size;
for (i = 0, len = bin.length; i < len; i++) {
bin[i].w = bin[i].width * ratio + margin;
bin[i].h = bin[i].height * ratio + margin;
bin[i].id = i;
bin[i] = packone(sprite, cwidth, cheight, bin[i]);
}
}
for (i = 0, len = bin.length; i < len; i++) {
let x = bin[i].x + margin;
let y = bin[i].y + margin;
let imgInstance = new fabric.Image(bin[i].data, {
left: x,
top: y,
angle: 0,
});
if (bin[i].width > bin[i].height) {
imgInstance.scaleToWidth(bin[i].w - margin);
} else {
imgInstance.scaleToHeight(bin[i].h - margin);
}
canvas.add(imgInstance);
}
}
function packone(sprite, cwidth, cheight, bin) {
let pbin = null;
let tsprite = sprite;
while (pbin === null) {
pbin = tsprite.packOne(bin.w, bin.h, bin.id);
if (pbin === null) {
bin.w = (bin.w - margin) / 2 + margin;
bin.h = (bin.h - margin) / 2 + margin;
tsprite = sprite;
}
}
bin.x = pbin.x;
bin.y = pbin.y;
bin.w = pbin.w;
bin.h = pbin.h;
return bin;
}
function circlecoords (width, height, t) {
return {
x: width * Math.cos(t),
y: height * Math.sin(t)
};
}
function circlepack(bin, canvas) {
const cwidth = canvas.width;
const cheight = canvas.height;
let i, len, t;
const area = (cwidth * cheight / 4) * Math.PI;
const ratio = area / bin[0].size * bin.length;
const linestep = Math.PI / 2 / Math.floor(ratio);
i = 0;
// A rectangular line in the circle
for (t = Math.PI * 0.75 ; t > Math.PI / 2; t = t - linestep) {
if (bin[i] === undefined) {
break;
}
let opposite = 0;
if ( t < Math.PI ) {
opposite = t - Math.PI / 2;
} else if (t > Math.PI) {
opposite = t + Math.PI / 2;
}
let endcoords = circlecoords(cwidth, cheight, opposite);
let coords = {};
// A series of images inside this line, limited by opposite end of the circle
while (coords.x < endcoords.x && coords.y < endcoords.y) {
let imgInstance = new fabric.Image(bin[i].data, coords);
imgInstance.scaleToWidth(bin[i].width * ratio);
imgInstance.scaleToHeight(bin[i].height * ratio);
canvas.add(imgInstance);
i++;
}
}
}
jQuery(document).on('click', '#repack', function() {
if (iscircle) {
circlerepack(canvas);
} else {
repack(canvas);
}
});
function repack(canvas) {
let bin = canvas.getObjects();
const cwidth = canvas.width;
const cheight = canvas.height;
for (i = 0, len = bin.length; i < len; i++) {
bin[i].w = bin[i].width * bin[i].scaleX + margin;
bin[i].h = bin[i].height * bin[i].scaleY + margin;
}
bin.sort(function(a,b){
return b.width * b.height - a.width * a.height;
});
let sprite = new ShelfPack(cwidth, cheight);
sprite.pack(bin, {
inPlace: true
});
for (i = 0, len = bin.length; i < len; i++) {
bin[i].scaleToWidth(bin[i].w - margin);
bin[i].scaleToHeight(bin[i].h - margin);
bin[i].setPositionByOrigin(
new fabric.Point(bin[i].x, bin[i].y),
'left',
'top'
);
}
canvas.renderAll();
}