Created
August 1, 2018 09:16
-
-
Save innermond/69dda0cc34e0f310965da366a808a503 to your computer and use it in GitHub Desktop.
remade of calculator widget as plain js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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