aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src_js/opcut/common.js120
-rw-r--r--src_js/opcut/states.js4
-rw-r--r--src_js/opcut/validators.js7
-rw-r--r--src_js/opcut/vt.js38
-rw-r--r--src_web/style/main.scss7
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 {