Skip to content

Instantly share code, notes, and snippets.

@innermond
Created August 1, 2018 09:16
Show Gist options
  • Save innermond/69dda0cc34e0f310965da366a808a503 to your computer and use it in GitHub Desktop.
Save innermond/69dda0cc34e0f310965da366a808a503 to your computer and use it in GitHub Desktop.
remade of calculator widget as plain js
window.$ = document.getElementById.bind(document);
window.$$ = document.querySelectorAll.bind(document);
Packer = function(w, h) {
this.init(w, h);
};
Packer.prototype = {
init: function(w, h) {
this.root = { x: 0, y: 0, w: w, h: h };
},
fit: function(blocks) {
var n, node, block;
for (n = 0; n < blocks.length; n++) {
block = blocks[n];
if (node = this.findNode(this.root, block.w, block.h))
block.fit = this.splitNode(node, block.w, block.h);
}
},
findNode: function(root, w, h) {
if (root.used)
return this.findNode(root.right, w, h) || this.findNode(root.down, w, h);
else if ((w <= root.w) && (h <= root.h))
return root;
else
return null;
},
splitNode: function(node, w, h) {
node.used = true;
node.down = { x: node.x, y: node.y + h, w: node.w, h: node.h - h };
node.right = { x: node.x + w, y: node.y, w: node.w - w, h: h };
return node;
}
}
Demo = {
init: function() {
Demo.el = {
blocks: $('blocks'),
canvas: $('canvas'),
size: $('size'),
color: $('color'),
ratio: $('ratio'),
nofit: $('nofit')
};
if (!Demo.el.canvas.getContext) // no support for canvas
return false;
Demo.el.draw = Demo.el.canvas.getContext("2d");
Demo.el.blocks.onchange = Demo.run;
Demo.el.color.onchange = Demo.run;
Demo.run();
Demo.el.blocks.onkeypress = function(ev) {
if (ev.which == 13)
Demo.run(); // run on <enter> while entering block information
};
},
//---------------------------------------------------------------------------
run: function() {
var blocks = Demo.blocks.deserialize(Demo.el.blocks.value);
var packer = Demo.packer();
packer.fit(blocks);
Demo.canvas.reset(packer.root.w, packer.root.h);
Demo.canvas.blocks(blocks);
Demo.canvas.boundary(packer.root);
Demo.report(blocks, packer.root.w, packer.root.h);
},
//---------------------------------------------------------------------------
packer: function() {
var size = Demo.el.size.value;
if (size == 'automatic') {
return new GrowingPacker();
}
else {
var dims = size.split("x");
return new Packer(parseInt(dims[0]), parseInt(dims[1]));
}
},
//---------------------------------------------------------------------------
report: function(blocks, w, h) {
var fit = 0, nofit = [], block, n, len = blocks.length;
for (n = 0 ; n < len ; n++) {
block = blocks[n];
if (block.fit)
fit = fit + block.area;
else
nofit.push("" + block.w + "x" + block.h);
}
Demo.incap = blocks.length - nofit.length;
Demo.el.ratio.innerHTML = Math.round(100 * fit / (w * h));
Demo.el.nofit.innerHTML = "Nu au incaput (" + nofit.length + ")"
Demo.el.nofit.style.display = nofit.length > 0 ? 'inline' : 'none';
},
canvas: {
reset: function(width, height) {
Demo.el.canvas.width = width + 1; // add 1 because we draw boundaries offset by 0.5 in order to pixel align and get crisp boundaries
Demo.el.canvas.height = height + 1; // (ditto)
Demo.el.draw.clearRect(0, 0, Demo.el.canvas.width, Demo.el.canvas.height);
},
rect: function(x, y, w, h, color) {
Demo.el.draw.fillStyle = color;
Demo.el.draw.fillRect(x + 0.5, y + 0.5, w, h);
},
stroke: function(x, y, w, h) {
Demo.el.draw.strokeRect(x + 0.5, y + 0.5, w, h);
},
blocks: function(blocks) {
var n, block;
for (n = 0 ; n < blocks.length ; n++) {
block = blocks[n];
if (block.fit)
Demo.canvas.rect(block.fit.x, block.fit.y, block.w, block.h, Demo.color(n));
}
},
boundary: function(node) {
if (node) {
Demo.canvas.stroke(node.x, node.y, node.w, node.h);
Demo.canvas.boundary(node.down);
Demo.canvas.boundary(node.right);
}
}
},
//---------------------------------------------------------------------------
blocks: {
deserialize: function(val) {
var scale = Demo.el.size.getAttribute('data-scale') || 1;
scale = 1.0*scale;
var i, j, block, blocks = val.split("\n"), result = [];
for(i = 0 ; i < blocks.length ; i++) {
block = blocks[i].split("x");
if (block.length >= 2)
result.push({w: parseInt(block[0]), h: parseInt(block[1]), num: (block.length == 2 ? 1 : parseInt(block[2])) });
}
var expanded = [];
for(i = 0 ; i < result.length ; i++) {
for(j = 0 ; j < result[i].num ; j++)
expanded.push({
w: scale*result[i].w,
h: scale*result[i].h,
area: scale*result[i].w * scale*result[i].h
});
}
return expanded;
},
serialize: function(blocks) {
var i, block, str = "";
for(i = 0; i < blocks.length ; i++) {
block = blocks[i];
str = str + block.w + "x" + block.h + (block.num > 1 ? "x" + block.num : "") + "\n";
}
return str;
}
},
colors: {
pastel: [ "#FFF7A5", "#FFA5E0", "#A5B3FF", "#BFFFA5", "#FFCBA5" ],
basic: [ "silver", "gray", "red", "maroon", "yellow", "olive", "lime", "green", "aqua", "teal", "blue", "navy", "fuchsia", "purple" ],
gray: [ "#111", "#222", "#333", "#444", "#555", "#666", "#777", "#888", "#999", "#AAA", "#BBB", "#CCC", "#DDD", "#EEE" ],
vintage: [ "#EFD279", "#95CBE9", "#024769", "#AFD775", "#2C5700", "#DE9D7F", "#7F9DDE", "#00572C", "#75D7AF", "#694702", "#E9CB95", "#79D2EF" ],
solarized: [ "#b58900", "#cb4b16", "#dc322f", "#d33682", "#6c71c4", "#268bd2", "#2aa198", "#859900" ],
none: [ "transparent" ]
},
color: function(n) {
var cols = Demo.colors[Demo.el.color.value];
return cols[n % cols.length];
}
//---------------------------------------------------------------------------
}
document.addEventListener('DOMContentLoaded', function() {
Demo.init();
function triggerEvent(el, type){
if ('createEvent' in document) {
// modern browsers, IE9+
var e = document.createEvent('HTMLEvents');
e.initEvent(type, false, true);
el.dispatchEvent(e);
} else {
// IE 8
var e = document.createEventObject();
e.eventType = type;
el.fireEvent('on'+e.eventType, e);
}
}
var mapFormats = {
'formate deschise': {
'A3': {w:297, h:420, num:1},
'A4': {w:297, h:210, num:2},
'A5': {w:148, h:210, num:4},
'1/3A4': {w:99, h:210, num:6},
'A6': {w:148, h:105, num:8}
},
'autocolant interior': {
'A4': {w:297, h:210, num:2, tip_hartie:'autocolant interior'},
'A5': {w:148, h:210, num:4, tip_hartie:'autocolant interior'},
'1/3A4': {w:99, h:210, num:6, tip_hartie:'autocolant interior'},
'A6 (105 x 148 mm)': {w:148, h:105, num:8, tip_hartie:'autocolant interior'},
'A7 (74 x 105 mm)': {w:74, h:105, num:16, tip_hartie:'autocolant interior'},
'A8 (52 x 74 mm)': {w:74, h:52, num:32, tip_hartie:'autocolant interior'},
},
'autocolant transparent': {
'A4': {w:297, h:210, num:2, tip_hartie:'autocolant transparent'},
'A5': {w:148, h:210, num:4, tip_hartie:'autocolant transparent'},
'1/3A4': {w:99, h:210, num:6, tip_hartie:'autocolant transparent'},
'A6 (105 x 148 mm)': {w:148, h:105, num:8, tip_hartie:'autocolant transparent'},
'A7 (74 x 105 mm)': {w:74, h:105, num:16, tip_hartie:'autocolant transparent'},
'A8 (52 x 74 mm)': {w:74, h:52, num:32, tip_hartie:'autocolant transparent'},
},
'flyere': {
'A4': {w:297, h:210, num:2, tiraj: 50},
'A5': {w:148, h:210, num:4, tiraj: 50},
'1/3A4': {w:99, h:210, num:6, tiraj: 50},
'A6': {w:148, h:105, num:8, tiraj: 50}
},
'carti vizita': {
'50x90': {w:50, h:90, num:24, tip_hartie:300, culori:'fata', tiraj: 100},
'55x85': {w:85, h:55, num:21, tip_hartie:300, culori:'fata', tiraj: 100},
'folio carton standard': {w:50, h:90, num:24, tip_hartie:300, culori:'fata', tiraj: 100, extra_serviciu: 0.15},
'print carton standard dublat': {w:50, h:90, num:24, tip_hartie:300, culori:'fata', tiraj: 100, extra_serviciu: 0.1},
'folio carton standard dublat': {w:50, h:90, num:24, tip_hartie:300, culori:'fata', tiraj: 100, extra_serviciu: 0.2},
'folio pe carton Plike standard': {w:50, h:90, num:24, tip_hartie:300, culori:'fata', tiraj: 100, extra_serviciu: 0.4},
'folio pe carton Plike dublat': {w:50, h:90, num:24, tip_hartie:300, culori:'fata', tiraj: 100, extra_serviciu: 0.6},
},
'diplome': {
'A4+': {w:297, h:210, num:2, tip_hartie:300, culori:'fata', tiraj: 50, extra_serviciu: 0.1},
'A4+ securizare folio': {w:297, h:210, num:2, tip_hartie:300, culori:'fata', tiraj: 50, extra_serviciu: 0.75},
},
'pliante' : {
'A6 1 pliere': {w:148, h:210, num:4, nr_plieri:'una'},
'A5 1 pliere': {w:297, h:210, num:2, nr_plieri:'una'},
'1/3A4 2 plieri': {w:297, h:210, num:2, nr_plieri:'doua'},
'A4 1 pliere': {w:297, h:420, num:1, nr_plieri:'una'}
},
'mape personalizate' : {
'A3+ fara cotor si buzunar': {w:297, h:420, num:1, tip_hartie:300, nr_plieri:'una', buzunare:'fara', culori:'fata'},
'A3+ fara cotor, un buzunar': {w:297, h:420, num:1, tip_hartie:300, nr_plieri:'una', buzunare:'cu', culori:'fata'},
'A3+ cu cotor, un buzunar': {w:297, h:420, num:1, tip_hartie:300, nr_plieri:'doua', buzunare:'cu', culori:'fata'},
'A3+ cu cotor, fara buzunar, cu alonja': {w:297, h:420, num:1, tip_hartie:300, nr_plieri:'doua', buzunare:'fara', culori:'fata', extra_serviciu: 0.5},
'A3+ cu cotor, un buzunar si alonja': {w:297, h:420, num:1, tip_hartie:300, nr_plieri:'doua', buzunare:'cu', culori:'fata', extra_serviciu: 0.5},
'A3+ cu cotor, un buzunar si buton CD/DVD': {w:297, h:420, num:1, tip_hartie:300, nr_plieri:'doua', buzunare:'cu', culori:'fata', extra_serviciu: 0.2},
'A3+ cu cotor, un buzunar, alonja si buton CD/DVD': {w:297, h:420, num:1, tip_hartie:300, nr_plieri:'doua', buzunare:'cu', culori:'fata', extra_serviciu: 0.45},
}
};
var only = window.only || null;
var
mapSection = {},
htmlSection = '';
for(var prop in mapFormats){
if (mapFormats.hasOwnProperty(prop)) {
Object.assign(mapSection, mapFormats[prop])
htmlSection += '<optgroup label="'+prop+'">';
for(var n in mapFormats[prop]) {
if (mapFormats[prop].hasOwnProperty(n))
htmlSection += '<option>'+n+'</option>'
}
htmlSection += '</optgroup>'
}
}
if (only && mapFormats.hasOwnProperty(only)) {
prop = only;
htmlSection = '<optgroup label="'+prop+'">';
mapSection = {};
for(var n in mapFormats[prop]){
if (mapFormats[prop].hasOwnProperty(n))
htmlSection += '<option>'+n+'</option>'
}
htmlSection += '</optgroup>'
Object.assign(mapSection, mapFormats[prop]);
prop = 'formate deschise';
htmlSection += '<optgroup label="'+prop+'">';
for(var n in mapFormats[prop]){
if (mapFormats[prop].hasOwnProperty(n))
htmlSection += '<option>'+n+'</option>'
}
htmlSection += '</optgroup>'
Object.assign(mapSection, mapFormats[prop]);
}
var FORM = {
url: 'https://www.printuridigital.ro/evaluator',
values:{},
updateFrom : function(jelem) {
var elem = jelem.dataset['shortname'];
jelem.tagName.toLowerCase() === 'select'
? FORM.values[elem] = jelem[jelem.selectedIndex].value + ''
: FORM.values[elem] = jelem.value + '';
},
mapFormatDefault: {
culori: 'fata-verso', tiraj: 1, tip_hartie: '90',
nr_plieri: 'fara', plastifiere: 'fara', buzunare: 'fara',
extra_serviciu: 0
},
mapFormatFit: mapSection,
selectOptionThatHas: function(selectId, textOption) {
var p = Array.prototype.filter.call(
FORM['$' + selectId].getElementsByTagName('option'),
function(opt){return opt.innerHTML == textOption});
p[0].setAttribute('selected', 'selected');
},
selectAllFor: function(map){
var $elem;
for(var prop in map) {
$elem = FORM['$' + prop];
if(map.hasOwnProperty(prop) && $elem){
if ($elem.tagName.toLowerCase() === 'select')
FORM.selectOptionThatHas(prop, map[prop]);
else if ($elem.tagName.toLowerCase() === 'input')
$elem.value = map[prop];
else if ($elem.tagName.toLowerCase() === 'textarea')
$elem.innerHTML = map[prop];
else if ($elem.tagName.toLowerCase() === 'checkbox')
map[prop] ? $elem.setAttribute('checked', 'checked') : $elem.removeAttribute('checked');
triggerEvent($elem, 'change');
}
}
},
reset: function(){
Object.assign(FORM.values, FORM.mapFormatDefault)
FORM.selectAllFor(FORM.mapFormatDefault)
}
},
elems = [
'format', 'incap', 'tiraj',
'tip_hartie', 'culori',
'nr_plieri', 'plastifiere', 'buzunare', 'rotunjiri_colturi',
'extra_serviciu'
]
for (var i = elems.length - 1; i >= 0; i--) {
var elem = elems[i];
var jelem = $('-pd-' + elem);
jelem.dataset['shortname'] = elem;
FORM['$' + elem] = jelem;
jelem.onchange = function(evt){
FORM.updateFrom(this) // this NOT jelem
};
FORM.updateFrom(jelem)
};
FORM.$format.innerHTML = htmlSection;
var resultInitialInfo = '<span class="tag is-warning">Preț</span><p>Aici se afișează oferta calculată.</p>';
var resultError = '<span class="tag is-danger">Eroare</span><p>Oferta de preț nu a putut fi calculată.</p>';
FORM.$format.onchange = function(event){
FORM.reset();
var map = FORM.mapFormatFit[event.target.value];
FORM.$incap.value = map.num;
FORM.$extra_serviciu.value = map.extra_serviciu;
FORM.updateFrom(FORM.$incap)
FORM.updateFrom(event.target)
$('blocks').value = [map.w, map.h, map.num].join('x');
var label = FORM.$format.querySelector('option:checked').parentNode.getAttribute('label');
document.querySelector('label[for=-pd-format]').innerText = label;
FORM.selectAllFor(map)
$('-pd-rezultat').innerHTML = resultInitialInfo;
FORM.$buzunare.parentNode.parentNode.parentNode.style.display = 'none';//label == 'mape personalizate' ? 'block' : 'none';
Demo.run()
}
triggerEvent(FORM.$format, 'change');
function status(response) {
if (response.status >= 200 && response.status < 300) {
return Promise.resolve(response)
} else {
return Promise.reject(new Error(response.statusText))
}
}
function json(response) {
return response.json()
}
$('-pd-calculeaza').addEventListener('click', function(evt){
evt.preventDefault();
var $button = evt.target;
var $result = $('-pd-rezultat');
$result.innerHTML = resultInitialInfo;
$button.classList.add('is-loading');
var out = [];
for (var key in FORM.values) {
out.push(key + '=' + encodeURIComponent(FORM.values[key]));
}
out = out.join('&');
fetch(FORM.url + '?' + out)
.then(status)
.then(json)
.then(function(data){
var total = 0;
for (var key in data)
if (data.hasOwnProperty(key)) total = data[key];
var
tva = 0.24, valute = 'RON',
tiraj = FORM.values.tiraj || 1, hartie = FORM.values.tip_hartie,
priceUnit = (total/tiraj).toFixed(2),
priceTotal = priceUnit*tiraj,
priceTotalTVA = priceTotal*(1 + tva);
var msg = [];
msg.push('<span class="tag is-light is-size-3"><i class="fas fa-tag"></i> ' + tiraj + '</span> bucați pe ' + hartie + ' grame');
msg.push('<span class="tag is-info is-size-5"><i class="fas fa-tag"></i> ' + priceUnit + '</span> preț bucata ');
msg.push('<span class="tag is-success is-size-4"><i class="fas fa-tag"></i> ' + priceTotal.toFixed(2) + '</span> preț total');
msg.push('<span class="tag is-warning is-size-3"><i class="fas fa-tag"></i> ' + priceTotalTVA.toFixed(2) + '</span> preț cu tva');
msg.push('prețuri in ' + valute);
msg = '<ul><li>' +
msg.join('</li><li>') + '</li></ul>'
$result.innerHTML = msg;
$button.classList.remove('is-loading');
})
.catch(function(error) {
$result.innerHTML = resultError;
$button.classList.remove('is-loading');
console.log('Request failed', error)
});
});
var $blocks = $('blocks');
$blocks.addEventListener('keyup', function(){
Demo.run()
FORM.$incap.value = Demo.incap || 0;
FORM.updateFrom(FORM.$incap);
});
$('-pd-switch').addEventListener('click', function(evt){evt.preventDefault();
var b = $('blocks'), x = b.value.split('x');
x.length = 3;
var incap = x.pop();
x.reverse().push(incap)
b.value = x.join('x');
triggerEvent(b, 'keyup');
});
$('-pd-edit').addEventListener('click', function(event){
event.preventDefault();
event.target.innerHTML = $blocks.disabled ? '<i class="fa fa-lock"></i> blocheaza' : '<i class="fas fa-pencil-alt"></i> editeaza';
$blocks.disabled = ! $blocks.disabled;
if ( ! $blocks.disabled) $blocks.removeAttribute('disabled');
setTimeout(function() {$blocks.focus();}, 300);
});
var $packing = $('packing');
$('-pd-sheet').addEventListener('click', function(event) {
event.preventDefault();
var classes = $packing.classList;
var eye = '';
if (classes.contains('show')) {
eye = '<i class="fas fa-eye-slash"></i> încadrare pe coală';
} else {
eye = '<i class="fas fa-eye"></i> încadrare pe coală';
}
event.target.innerHTML = eye;
$packing.classList.toggle('show');
});
$$('.tabs ul li').forEach(function(el) {
el.addEventListener('click', function(event) {
var displayMode = 'block';
var tab = el.getAttribute('data-tab-to');
// tab became inactive
if (el.classList.contains('is-active')) {
displayMode = 'none';
}
// all tab related content is hidden
$$('[data-tab-from]').forEach(function(elem) {
elem.style.display = 'none';
});
// all tabs are made inactive
el.parentNode.querySelectorAll('li[class~=is-active]').forEach(function(li){
li.classList.remove('is-active');
});
// current tab status
if (displayMode === 'block') {
el.classList.add('is-active');
}
// current tab content status
$$('[data-tab-from=' + tab + ']').forEach(function(elem) {
elem.style.display = displayMode;
});
});
});
$$('.tabs ul li[data-tab-to=pliante]')[0].click();
$servicesAnchor = $('services');
$$('[href="#services"]').forEach(function($el) {
$el.addEventListener('click', function(event) {
event.preventDefault();
$servicesAnchor.scrollIntoView({
behavior: 'smooth'
});
})
});
var $megamenu = $('navbar-megamenu');
$('toggle-megamenu').addEventListener('click', function(event) {
$megamenu.classList.toggle('is-active');
});
var $scrollToTop = $('return-to-top');
window.onscroll = function() {
var scrollBottom = document.body.scrollHeight - window.innerHeight - window.scrollY;
var haveShow = $scrollToTop.classList.contains('show');
if (scrollBottom < 400 && !haveShow) {
$scrollToTop.classList.add('show');
} else if (scrollBottom >= 400) {
$scrollToTop.classList.remove('show');
}
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment