diff options
| author | bozokopic <bozo.kopic@gmail.com> | 2018-04-18 14:12:46 +0200 |
|---|---|---|
| committer | bozokopic <bozo.kopic@gmail.com> | 2018-04-18 14:12:46 +0200 |
| commit | 71893908e6f39772422ae45cb01038ca6e042f93 (patch) | |
| tree | c25364ea32e928d4d7712e1c6f8aedd22cb7293c | |
| parent | 7092128f80a9e2a7f4b91d7d33480e64406d39d2 (diff) | |
web frontent
| -rw-r--r-- | src_js/opcut/common.js | 120 | ||||
| -rw-r--r-- | src_js/opcut/states.js | 4 | ||||
| -rw-r--r-- | src_js/opcut/validators.js | 7 | ||||
| -rw-r--r-- | src_js/opcut/vt.js | 38 | ||||
| -rw-r--r-- | src_web/style/main.scss | 7 |
5 files changed, 114 insertions, 62 deletions
diff --git a/src_js/opcut/common.js b/src_js/opcut/common.js index 9c5d16d..323fc76 100644 --- a/src_js/opcut/common.js +++ b/src_js/opcut/common.js @@ -12,34 +12,12 @@ const generateOutputUrl = URI.resolve(window.location.href, './generate_output') export function calculate() { - const msg = { - method: r.get('form', 'method'), - params: { - cut_width: u.strictParseFloat(r.get('form', 'cut_width')), - panels: u.pipe( - u.map(panel => [panel.name, {width: u.strictParseFloat(panel.width), - height: u.strictParseFloat(panel.height)}]), - u.fromPairs - )(r.get('form', 'panels', 'items')), - items: u.pipe( - u.map(item => [item.name, {width: u.strictParseFloat(item.width), - height: u.strictParseFloat(item.height), - can_rotate: item.can_rotate}]), - u.fromPairs - )(r.get('form', 'items', 'items')), - } - }; try { - validateCalculateRequest(msg); + let msg = createValidateRequest(); + send(calculateUrl, msg).then(parseCalculateResponse); } catch (e) { showNotification(e, 'error'); - return; } - const req = new XMLHttpRequest(); - req.onload = () => parseCalculateResponse(JSON.parse(req.responseText)); - req.open('POST', calculateUrl); - req.setRequestHeader('Content-Type', 'application/json'); - req.send(JSON.stringify(msg)); } @@ -48,36 +26,84 @@ export function generateOutput(output_type) { output_type: output_type, result: r.get('result') }; - const req = new XMLHttpRequest(); - req.onload = () => parseGenerateOutputResponse(JSON.parse(req.responseText), output_type); - req.open('POST', generateOutputUrl); - req.setRequestHeader('Content-Type', 'application/json'); - req.send(JSON.stringify(msg)); + send(generateOutputUrl, msg).then(msg => parseGenerateOutputResponse(msg, output_type)); } -function validateCalculateRequest(msg) { - if (!Number.isFinite(msg.params.cut_width) || msg.params.cut_width < 0) +function send(url, msg) { + return new Promise(resolve => { + const req = new XMLHttpRequest(); + req.onload = () => { resolve(JSON.parse(req.responseText)); }; + req.open('POST', url); + req.setRequestHeader('Content-Type', 'application/json'); + req.send(JSON.stringify(msg)); + }); +} + + +function createValidateRequest() { + const cutWidth = u.strictParseFloat(r.get('form', 'cut_width')); + if (!Number.isFinite(cutWidth) || cutWidth < 0) throw 'Invalid cut width'; - if (u.equals(msg.params.panels, {})) - throw 'No panels defined'; - for (let [name, panel] of u.toPairs(msg.params.panels)) { - if (!name) + + const panels = {}; + for (let panel of r.get('form', 'panels', 'items')) { + const quantity = u.strictParseInt(panel.quantity); + const width = u.strictParseFloat(panel.width); + const height = u.strictParseFloat(panel.height); + if (!panel.name) throw 'Invalid panel name'; - if (!Number.isFinite(panel.width) || panel.width <= 0) - throw 'Invalid width for panel ' + name; - if (!Number.isFinite(panel.height) || panel.height <= 0) - throw 'Invalid height for panel ' + name; + if (!Number.isFinite(quantity) || quantity < 1) + throw 'Invalid quantity for panel ' + panel.name; + if (!Number.isFinite(width) || width <= 0) + throw 'Invalid width for panel ' + panel.name; + if (!Number.isFinite(height) || height <= 0) + throw 'Invalid height for panel ' + panel.name; + for (let i = 1; i <= quantity; ++i) { + const name = panel.name + ' ' + String(i); + if (name in panels) { + throw 'Duplicate panel name ' + name; + } + panels[name] = {width: width, + height: height}; + } } - if (u.equals(msg.params.items, {})) - throw 'No items defined'; - for (let [name, item] of u.toPairs(msg.params.items)) { - if (!name) + if (u.equals(panels, {})) + throw 'No panels defined'; + + const items = {}; + for (let item of r.get('form', 'items', 'items')) { + const quantity = u.strictParseInt(item.quantity); + const width = u.strictParseFloat(item.width); + const height = u.strictParseFloat(item.height); + if (!item.name) throw 'Invalid item name'; - if (!Number.isFinite(item.width) || item.width <= 0) - throw 'Invalid width for item ' + name; - if (!Number.isFinite(item.height) || item.height <= 0) - throw 'Invalid height for item ' + name; + if (!Number.isFinite(quantity) || quantity < 1) + throw 'Invalid quantity for item ' + item.name; + if (!Number.isFinite(width) || width <= 0) + throw 'Invalid width for item ' + item.name; + if (!Number.isFinite(height) || height <= 0) + throw 'Invalid height for item ' + item.name; + for (let i = 1; i <= quantity; ++i) { + const name = item.name + ' ' + String(i); + if (name in items) { + throw 'Duplicate item name ' + name; + } + items[name] = {width: width, + height: height, + can_rotate: item.can_rotate}; + } + } + if (u.equals(items, {})) + throw 'No items defined'; + + return { + method: r.get('form', 'method'), + params: { + cut_width: cutWidth, + panels: panels, + items: items + } } } diff --git a/src_js/opcut/states.js b/src_js/opcut/states.js index 1326a70..ffc8666 100644 --- a/src_js/opcut/states.js +++ b/src_js/opcut/states.js @@ -4,7 +4,7 @@ import * as grid from 'opcut/grid'; export const main = { form: { method: 'FORWARD_GREEDY', - cut_width: '1', + cut_width: '0.3', panels: grid.state, items: grid.state }, @@ -18,6 +18,7 @@ export const main = { export const panelsItem = { name: 'Panel', + quantity: '1', width: '100', height: '100' }; @@ -25,6 +26,7 @@ export const panelsItem = { export const itemsItem = { name: 'Item', + quantity: '1', width: '10', height: '10', can_rotate: true diff --git a/src_js/opcut/validators.js b/src_js/opcut/validators.js index eb49fac..713e73b 100644 --- a/src_js/opcut/validators.js +++ b/src_js/opcut/validators.js @@ -54,3 +54,10 @@ export function dimensionValidator(value) { if (!Number.isFinite(floatValue) || floatValue <= 0)
return 'not valid dimension';
}
+
+
+export function quantityValidator(value) {
+ const intValue = u.strictParseInt(value);
+ if (!Number.isFinite(intValue) || intValue < 1)
+ return 'not valid quantity';
+}
diff --git a/src_js/opcut/vt.js b/src_js/opcut/vt.js index 9f2209f..139ca33 100644 --- a/src_js/opcut/vt.js +++ b/src_js/opcut/vt.js @@ -83,6 +83,7 @@ function leftPanelPanels() { const nameValidator = validators.createChainValidator( validators.notEmptyValidator, validators.createUniqueValidator()); + const quantityValidator = validators.quantityValidator; const widthValidator = validators.dimensionValidator; const heightValidator = validators.dimensionValidator; const csvColumns = grid.createStringCsvColumns('name', 'width', 'height'); @@ -91,15 +92,16 @@ function leftPanelPanels() { ['thead', ['tr', ['th', 'Panel name'], - ['th.fixed', 'Width'], + ['th.fixed', 'Quantity'], ['th.fixed', 'Height'], + ['th.fixed', 'Width'], ['th.fixed'] ] ], grid.tbody(panelsPath, - ['name', 'width', 'height', deleteColumn], - [nameValidator, widthValidator, heightValidator]), - grid.tfoot(panelsPath, 4, states.panelsItem, csvColumns) + ['name', 'quantity', 'height', 'width', deleteColumn], + [nameValidator, quantityValidator, heightValidator, widthValidator]), + grid.tfoot(panelsPath, 5, states.panelsItem, csvColumns) ] ]; } @@ -112,6 +114,7 @@ function leftPanelItems() { const nameValidator = validators.createChainValidator( validators.notEmptyValidator, validators.createUniqueValidator()); + const quantityValidator = validators.quantityValidator; const widthValidator = validators.dimensionValidator; const heightValidator = validators.dimensionValidator; const csvColumns = u.merge( @@ -122,16 +125,17 @@ function leftPanelItems() { ['thead', ['tr', ['th', 'Item name'], - ['th.fixed', 'Width'], + ['th.fixed', 'Quantity'], ['th.fixed', 'Height'], + ['th.fixed', 'Width'], ['th.fixed', 'Rotate'], ['th.fixed'] ] ], grid.tbody(itemsPath, - ['name', 'width', 'height', rotateColumn, deleteColumn], - [nameValidator, widthValidator, heightValidator]), - grid.tfoot(itemsPath, 5, states.itemsItem, csvColumns) + ['name', 'quantity', 'height', 'width', rotateColumn, deleteColumn], + [nameValidator, quantityValidator, heightValidator, widthValidator]), + grid.tfoot(itemsPath, 6, states.itemsItem, csvColumns) ] ]; } @@ -181,11 +185,11 @@ function rightPanelPanel(panel) { (used.rotate ? ['span.item-rotate.fa.fa-refresh'] : []), ['div.item-x', 'X:', - String(used.x) + String(Math.round(used.x * 100) / 100) ], ['div.item-y', 'Y:', - String(used.y) + String(Math.round(used.y * 100) / 100) ] ]) ]; @@ -200,7 +204,7 @@ function centerPanel() { const panel = result.params.panels[selected.panel]; const used = u.filter(i => i.panel == selected.panel, result.used); const unused = u.filter(i => i.panel == selected.panel, result.unused); - const panelColor = 'rgb(189,189,189)'; + const panelColor = 'rgb(100,100,100)'; const itemColor = 'rgb(250,250,250)'; const selectedItemColor = 'rgb(200,140,140)'; const unusedColor = 'rgb(238,238,238)'; @@ -228,6 +232,9 @@ function centerPanel() { const width = (used.rotate ? item.height : item.width); const height = (used.rotate ? item.width : item.height); return ['rect', { + props: { + style: 'cursor: pointer' + }, attrs: { x: String(used.x), y: String(used.y), @@ -235,6 +242,9 @@ function centerPanel() { height: String(height), 'stroke-width': '0', fill: (used.item == selected.item ? selectedItemColor : itemColor) + }, + on: { + click: () => r.set(['selected', 'item'], used.item) }} ]; }), @@ -255,12 +265,18 @@ function centerPanel() { const width = (used.rotate ? item.height : item.width); const height = (used.rotate ? item.width : item.height); return ['text', { + props: { + style: 'cursor: pointer' + }, attrs: { x: String(used.x + width / 2), y: String(used.y + height / 2), 'alignment-baseline': 'middle', 'text-anchor': 'middle', 'font-size': fontSize + }, + on: { + click: () => r.set(['selected', 'item'], used.item) }}, used.item ]; diff --git a/src_web/style/main.scss b/src_web/style/main.scss index 2ea843e..897847c 100644 --- a/src_web/style/main.scss +++ b/src_web/style/main.scss @@ -24,7 +24,7 @@ html, body { .left-panel { @include shadow-4dp(); - width: 400px; + width: 450px; display: flex; flex-direction: column; background-color: $color-grey-100; @@ -77,14 +77,14 @@ html, body { width: 100%; .fixed { - width: 50px + width: 55px } tbody td:last-child { text-align: center; } - .grid-col-width, .grid-col-height { + .grid-col-width, .grid-col-height, .grid-col-quantity { text-align: right; input { @@ -132,6 +132,7 @@ html, body { display: flex; justify-content: center; margin: 10px; + flex-shrink: 0; } .panel { |
