diff options
Diffstat (limited to 'print/resources')
| -rw-r--r-- | print/resources/inkstitch.js | 259 | ||||
| -rw-r--r-- | print/resources/style.css | 140 |
2 files changed, 323 insertions, 76 deletions
diff --git a/print/resources/inkstitch.js b/print/resources/inkstitch.js index 454c9ae2..498b1211 100644 --- a/print/resources/inkstitch.js +++ b/print/resources/inkstitch.js @@ -1,3 +1,12 @@ +$.postJSON = function(url, data, success=null) { + return $.ajax(url, { + type: 'POST', + data: JSON.stringify(data), + contentType: 'application/json', + success: success + }); +}; + function ping() { $.get("/ping") .done(function() { setTimeout(ping, 1000) }) @@ -13,46 +22,178 @@ function setPageNumbers() { }); } -// set preview svg scale to fit into its box -function scaleInksimulation() { - $('.inksimulation').each(function() { +// Scale SVG (fit || full size) +function scaleSVG(element, scale = 'fit') { + + // always center svg + transform = "translate(-50%, -50%)"; + + if(scale == 'fit') { var scale = Math.min( - $(this).width() / $(this).find('svg').width(), - $(this).height() / $(this).find('svg').height() + element.width() / element.find('svg').width(), + element.height() / element.find('svg').height() ); + } + + transform += " scale(" + scale + ")"; + var label = parseInt(scale*100); - // center the SVG - transform = "translate(-50%, -50%)"; + element.find('svg').css({ transform: transform }); + element.find('.scale').text(label); +} - if(scale <= 1) { - transform += " scale(" + scale + ")"; - label = parseInt(scale*100) + '%'; - } else { - label = "100%"; - } +// set preview svg scale to fit into its box if transform is not set +function scaleAllSvg() { + $('.page').each(function() { + if( $(this).find('.inksimulation svg').css('transform') == 'none') { + scaleSVG($(this).find('.inksimulation'), 'fit'); + } + }); +} - $(this).find('svg').css({ transform: transform }); - $(this).find('figcaption span').text(label); - }); +var saveTimerHandles = {}; + +function setSVGTransform(figure, transform) { + var field_name = $(figure).data('field-name'); + var scale = transform.match(/-?[\d\.]+/g)[0]; + figure.find('svg').css({ transform: transform }); + figure.find(".scale").text(parseInt(scale*100)); + + // avoid spamming updates + if (saveTimerHandles[field_name] != null) + clearTimeout(saveTimerHandles[field_name]); + + saveTimerHandles[field_name] = setTimeout(function() { + $.postJSON('/settings/' + field_name, {value: transform}); + }, 250); } $(function() { setTimeout(ping, 1000); setPageNumbers(); - scaleInksimulation(); - /* Contendeditable Fields */ + /* SCALING AND MOVING SVG */ - // When we focus out from a contenteditable field, we want to - // set the same content to all fields with the same classname - document.querySelectorAll('[contenteditable="true"]').forEach(function(elem) { - elem.addEventListener('focusout', function() { - var content = $(this).html(); - var field_name = $(this).attr('data-field-name'); - $('[data-field-name="' + field_name + '"]').html(content); - }); + /* Mousewheel scaling */ + $('figure.inksimulation').on( 'DOMMouseScroll mousewheel', function (e) { + if(e.ctrlKey == true) { + + var svg = $(this).find('svg'); + var transform = svg.css('transform').match(/-?[\d\.]+/g); + var scale = parseFloat(transform[0]); + + if (e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0) { + // scroll down = zoom out + scale *= 0.97; + if (scale < 0.01) + scale = 0.01; + } else { + //scroll up + scale *= 1.03; + } + + // set modified scale + transform[0] = scale; + transform[3] = scale; + + setSVGTransform($(this), 'matrix(' + transform + ')'); + + //prevent page fom scrolling + return false; + } + }); + + /* Fit SVG */ + $('button.svg-fit').click(function() { + var svgfigure = $(this).closest('figure'); + scaleSVG(svgfigure, 'fit'); + }); + + /* Full Size SVG */ + $('button.svg-full').click(function() { + var svgfigure = $(this).closest('figure'); + scaleSVG(svgfigure, '1'); }); + /* Drag SVG */ + $('figure.inksimulation').on('mousedown', function(e) { + var p0 = { x: e.pageX, y: e.pageY }; + var start_transform = $(this).find('svg').css('transform').match(/-?[\d\.]+/g); + var start_offset = { x: parseFloat(start_transform[4]), y: parseFloat(start_transform[5]) }; + + $(this).css({cursor: 'move'}); + $(this).on('mousemove', function(e) { + var p1 = { x: e.pageX, y: e.pageY }; + // set modified translate + var transform = $(this).find('svg').css('transform').match(/-?[\d\.]+/g); + transform[4] = start_offset.x + (p1.x - p0.x); + transform[5] = start_offset.y + (p1.y - p0.y); + + // I'd ike to use setSVGTransform() here but this code runs many + // times per second and it's just too CPU-intensive. + $(this).find('svg').css({transform: 'matrix(' + transform + ')'}); + }); + }).on('mouseup', function(e) { + $(this).css({cursor: 'auto'}); + $(this).data('p0', null); + $(this).off('mousemove'); + + // set it using setSVGTransform() to ensure that it's saved to the server + setSVGTransform($(this), $(this).find('svg').css('transform')); + }); + + /* Apply transforms to All */ + $('button.svg-apply').click(function() { + var transform = $(this).parent().siblings('svg').css('transform'); + $('.inksimulation').each(function() { + setSVGTransform($(this), transform); + }) + }); + + /* Contendeditable Fields */ + + $('[contenteditable="true"]').on('focusout', function() { + /* change svg scale */ + var content = $(this).html(); + var field_name = $(this).attr('data-field-name'); + if(field_name == 'svg-scale') { + var scale = parseInt(content); + var svg = $(this).parent().siblings('svg'); + var transform = svg.css('transform').match(/-?[\d\.]+/g); + + transform[0] = scale / 100; + transform[3] = scale / 100; + svg.css({ transform: 'matrix(' + transform + ')' }); + } else { + /* When we focus out from a contenteditable field, we want to + * set the same content to all fields with the same classname */ + $('[data-field-name="' + field_name + '"]').html(content); + $.postJSON('/settings/' + field_name, {value: content}); + } + }); + + // load up initial metadata values + $.getJSON('/settings', function(settings) { + $.each(settings, function(field_name, value) { + $('[data-field-name="' + field_name + '"]').each(function(i, item) { + var item = $(item); + if (item.is(':checkbox')) { + item.prop('checked', value).trigger('change'); + } else if (item.is('img')) { + item.attr('src', value); + } else if (item.is('select')) { + item.val(value).trigger('change'); + } else if (item.is('figure.inksimulation')) { + setSVGTransform(item, value); + } else { + item.text(value); + } + }); + }); + // wait until page size is set (if they've specified one) and then scale SVGs to fit + setTimeout(function() { scaleAllSvg() }, 500); + }); + $('[contenteditable="true"]').keypress(function(e) { if (e.which == 13) { // pressing enter defocuses the element @@ -64,14 +205,26 @@ $(function() { return true; } }); - - + + /* Settings Bar */ - + $('button.close').click(function() { $.post('/shutdown', {}) .done(function(data) { window.close(); + + /* Chrome and Firefox both have a rule: scripts can only close windows + * that they opened. Chrome seems to have an exception for windows that + * were opened by an outside program, so the above works fine. Firefox + * steadfastly refuses to allow us to close the window, so we'll tell + * the user (in their language) that they can close it. + */ + setTimeout(function() { + document.open(); + document.write("<html><body>" + data + "</body></html>"); + document.close(); + }, 1000); }); }); @@ -92,20 +245,54 @@ $(function() { $('#close-settings').click(function(){ $('#settings-ui').hide(); }); - + /* Settings */ - + // Paper Size $('select#printing-size').change(function(){ - $('.page').toggleClass('a4'); + var size = $(this).find(':selected').val(); + $('.page').toggleClass('a4', size == 'a4'); + $.postJSON('/settings/paper-size', {value: size}); }); - + //Checkbox $(':checkbox').change(function() { - $('.' + this.id).toggle(); + var checked = $(this).prop('checked'); + var field_name = $(this).attr('data-field-name'); + + $('.' + field_name).toggle(checked); setPageNumbers(); - scaleInksimulation(); + + $.postJSON('/settings/' + field_name, {value: checked}); + }); + + // Logo + $('#logo-picker').change(function(e) { + var file = e.originalEvent.srcElement.files[0]; + var reader = new FileReader(); + reader.onloadend = function() { + var data = reader.result; + $('figure.brandlogo img').attr('src', data); + $.postJSON('/settings/logo', {value: data}); + }; + reader.readAsDataURL(file); + }); + + // "save as defaults" button + $('#save-settings').click(function(e) { + var settings = {}; + settings["client-overview"] = $("[data-field-name='client-overview']").is(':checked'); + settings["client-detailedview"] = $("[data-field-name='client-detailedview']").is(':checked'); + settings["operator-overview"] = $("[data-field-name='operator-overview']").is(':checked'); + settings["operator-detailedview"] = $("[data-field-name='operator-detailedview']").is(':checked'); + settings["paper-size"] = $('select#printing-size').find(':selected').val(); + + var logo = $("figure.brandlogo img").attr('src'); + if (logo.startsWith("data:")) { + settings["logo"] = logo; + } + + $.postJSON('/defaults', {'value': settings}); }); - }); diff --git a/print/resources/style.css b/print/resources/style.css index 824f8dce..97dee6a8 100644 --- a/print/resources/style.css +++ b/print/resources/style.css @@ -70,6 +70,10 @@ margin: 0 !important; } + figure.inksimulation div { + display: none; + } + .ui { display: none; } @@ -77,7 +81,7 @@ #settings-ui { display: none !important; } - + #errors { display: none !important; } @@ -86,6 +90,10 @@ content: attr(data-label); padding-right: 0.5em; } + + span.logo-instructions { + display: none; + } } @page { @@ -109,7 +117,7 @@ body { .page { width: 210mm; height: 275mm; - padding: 5mm; + padding: 5mm; background: #fff; margin: 0 auto; vertical-align: text-bottom; @@ -163,13 +171,13 @@ body { .ui button.close { border: 1px solid rgb(197,5,5); - + } .ui button.close:hover { background: rgb(197,5,5); color: white; - + } .ui button.settings { @@ -207,7 +215,7 @@ body { border-bottom: 1px solid rgba(129, 129, 129, 0.5); box-shadow: 0 1px 1px 1px rgba(194, 191, 191, 0.5); } - + #settings-ui div { text-align: left; font-size: 12pt; @@ -226,6 +234,10 @@ body { cursor: pointer; } + #settings-ui fieldset { + margin-bottom: 1em; + } + /* Header */ @@ -247,18 +259,48 @@ body { margin: 2.5mm; } + figure.brandlogo label { + display: block; + width: 100%; + height: 100%; + line-height: 30mm; + text-align: center; + } + figure.brandlogo img { max-width: 30mm; max-height: 30mm; + display: inline; + vertical-align: middle; + } + + /* hide the actual file picker control, since we just want them to click the + * image instead + */ + #logo-picker { + width: 0px; + height: 0px; + opacity: 0%; + } + + .logo-instructions { + white-space: nowrap; + + /* chrome ignores this :( + text-align: center; + */ + + font-size: 10px; + color: rgb(192, 192, 192); } - + .operator-detailedview figure.brandlogo { height: 20mm; width: 30mm; margin: 0 2.5mm; text-align: left; } - + .operator-detailedview figure.brandlogo img { max-width: 30mm; max-height: 20mm; @@ -314,15 +356,15 @@ body { div.job-details p span:first-child { font-weight: bold; - padding-right: 1mm; + padding-right: 1mm; } div.job-details p span:last-child { - text-align: left; + text-align: left; } div.job-details > div:last-child span { - text-align: right !important; + text-align: right !important; } div.client-detailedview .job-details { @@ -347,16 +389,16 @@ body { font-size: 12pt; font-weight: bold; } - + /* client dedailed view header */ .client-detailedview div.job-details p span:first-child { - width: 20mm; + width: 20mm; } - + .client-detailedview div.job-details p span:last-child { - max-width: 60mm; + max-width: 60mm; } - + /* SVG Preview Image */ @@ -370,7 +412,7 @@ body { position: relative; overflow: hidden; } - + .client-overview-main figure.inksimulation { height: 155mm; } @@ -389,6 +431,24 @@ body { font-weight: bold; line-height: 12pt; margin: 2.5mm; + background: rgba(255, 255, 255, 0.73); + padding: 5px; + } + + figure.inksimulation div { + position: absolute; + bottom: 0; + left: 0; + right: 0; + margin-left: auto; + margin-right: auto; + width: fit-content; + } + + figure.inksimulation button { + border: none; + background: grey; + color: white; } /* Color Swatches */ @@ -415,7 +475,7 @@ body { font-weight: 700; font-size: 12pt; color: black; - background: white; + background: white; border: 0.5mm solid white; margin: 0px; padding: 0px; @@ -446,44 +506,44 @@ body { line-height: 30mm; text-align: center; } - + /* detailedview color swatch */ - + .color-palette.detailed > div { height: 100%; position: relative; } - + .color-palette.detailed .color-info { position: absolute; top: 2mm; left: 45mm; } - + .color-palette.detailed .color-info > div { display: table; } - + .color-palette.detailed .color-info p { display: table-row; } - + .color-palette.detailed .color-info span { display: table-cell; padding-right: 5mm; } - + /* Operator Detailed View */ .operator-detailedview header { height: 25mm; } - + .operator-detailedveiw figure.brandlogo{ height: 15mm; width: 15mm; } - + .operator-detailedveiw figure.brandlogo img { max-width: 12.5mm; max-height: 12.5mm; @@ -497,21 +557,21 @@ body { display: table; width: 100%; } - + .operator-job-info div { display: table-row; } - + div.job-headline { display: table-header-group; font-size: 9pt; font-weight: bold; } - + div.job-headline p { height: 1em; } - + .operator-job-info p { height: 15mm; max-width: 15mm; @@ -521,11 +581,11 @@ body { overflow: hidden; border: 1px solid rgb(239,239,239); } - + .operator-job-info span { display: block; } - + .operator-job-info span.color-index { position: absolute; top: 0; @@ -533,17 +593,17 @@ body { line-height: 15mm; width: 10mm; } - + .operator-svg.operator-colorswatch { width: 15mm; } - + .operator-svg.operator-preview { min-width: 15mm; max-width: 20mm; height: 15mm; } - + .operator-svg svg { position: absolute; top: 0; @@ -552,7 +612,7 @@ body { max-width: 30mm; height: 100%; } - + /* Footer */ @@ -565,7 +625,7 @@ body { white-space: wrap; text-align: center; padding-top: 2mm; - + } footer p.num_pages { @@ -625,7 +685,7 @@ body { /* five items */ .color-swatch:first-child:nth-last-child(n+5), .color-swatch:first-child:nth-last-child(n+5) ~ .color-swatch { - font-size: 9pt; + font-size: 9pt; width: calc(100% / 5); } @@ -665,7 +725,7 @@ body { /* fourteen items */ .color-swatch:first-child:nth-last-child(n+14), .color-swatch:first-child:nth-last-child(n+14) ~ .color-swatch { - width: calc(100% / 5); + width: calc(100% / 5); } /* sixteen items */ @@ -717,7 +777,7 @@ body { .color-swatch:first-child:nth-last-child(n+40) ~ .color-swatch { width: calc(100% / 12); } - + /* fourty-nine items */ .color-swatch:first-child:nth-last-child(n+49), .color-swatch:first-child:nth-last-child(n+40) ~ .color-swatch { |
