mirror of
https://github.com/Doodle3D/Doodle3D-Slicer.git
synced 2024-12-23 03:23:48 +01:00
implement local storage
This commit is contained in:
parent
9d47e8dc23
commit
7b59ba1108
674
package-lock.json
generated
674
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -21,12 +21,16 @@
|
||||
"file-saver": "^1.3.3",
|
||||
"lodash": "^4.17.4",
|
||||
"material-ui": "^0.19.4",
|
||||
"material-ui-icons": "^1.0.0-beta.17",
|
||||
"material-ui-textfield-icon": "^0.2.2-1",
|
||||
"proptypes": "^1.1.0",
|
||||
"query-string": "^5.0.1",
|
||||
"react": "^16.0.0",
|
||||
"react-addons-update": "^15.6.2",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-jss": "^7.2.0",
|
||||
"react-resize-detector": "^1.1.0",
|
||||
"shortid": "^2.2.8",
|
||||
"three": "^0.88.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,2 +1,3 @@
|
||||
export const PRECISION = 0.01;
|
||||
export const VERSION = '0.0.18';
|
||||
export const LOCAL_STORAGE_KEY = 'PRINTER_SETTINGS';
|
||||
|
@ -4,36 +4,58 @@ import _ from 'lodash';
|
||||
import injectSheet from 'react-jss';
|
||||
import MaterialUISelectField from 'material-ui/SelectField'
|
||||
import MaterialUICheckbox from 'material-ui/Checkbox';
|
||||
import MaterialUITextField from 'material-ui/TextField';
|
||||
import { blue500, grey500 } from 'material-ui/styles/colors';
|
||||
import TextFieldIcon from 'material-ui-textfield-icon';
|
||||
import Clear from 'material-ui-icons/Clear';
|
||||
|
||||
const contextTypes = { state: PropTypes.object, onChange: PropTypes.func, disabled: PropTypes.bool };
|
||||
const contextTypes = {
|
||||
settings: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
disabled: PropTypes.bool.isRequired,
|
||||
addPrinter: PropTypes.object.isRequired,
|
||||
advancedFields: PropTypes.array.isRequired,
|
||||
activePrinter: PropTypes.string
|
||||
};
|
||||
const propTypes = {
|
||||
name: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export const SelectField = (props, context) => (
|
||||
<MaterialUISelectField
|
||||
{...props}
|
||||
disabled={context.disabled}
|
||||
value={_.get(context.state, props.name)}
|
||||
value={_.get(context, props.name)}
|
||||
onChange={(event, index, value) => context.onChange(props.name, value)}
|
||||
/>
|
||||
);
|
||||
SelectField.contextTypes = contextTypes;
|
||||
SelectField.propTypes = propTypes;
|
||||
|
||||
export const TextField = (props, context) => (
|
||||
<MaterialUITextField
|
||||
<TextFieldIcon
|
||||
{...props}
|
||||
icon={context.advancedFields.includes(props.name) && <Clear onTouchTap={() => context.onChange(props.name, null)} />}
|
||||
floatingLabelStyle={{ color: context.advancedFields.includes(props.name) ? blue500 : grey500 }}
|
||||
disabled={context.disabled}
|
||||
value={_.get(context.state, props.name)}
|
||||
onChange={(event, value) => context.onChange(props.name, value)}
|
||||
value={_.get(context, props.name)}
|
||||
onChange={(event, value) => context.onChange(props.name, props.type === 'number' ? parseFloat(value) : value)}
|
||||
/>
|
||||
);
|
||||
TextField.contextTypes = contextTypes;
|
||||
TextField.propTypes = propTypes;
|
||||
|
||||
export const Checkbox = (props, context) => (
|
||||
<span style={{ display: 'flex' }}>
|
||||
<MaterialUICheckbox
|
||||
{...props}
|
||||
style={{ display: 'block' }}
|
||||
iconStyle={{ fill: context.advancedFields.includes(props.name) ? blue500 : grey500 }}
|
||||
disabled={context.disabled}
|
||||
checked={_.get(context.state, props.name)}
|
||||
checked={_.get(context, props.name)}
|
||||
onCheck={(event, value) => context.onChange(props.name, value)}
|
||||
/>
|
||||
{context.advancedFields.includes(props.name) && <Clear onTouchTap={() => context.onChange(props.name, null)} />}
|
||||
</span>
|
||||
);
|
||||
Checkbox.contextTypes = contextTypes;
|
||||
Checkbox.propTypes = propTypes;
|
||||
|
@ -5,7 +5,17 @@ import { Tabs, Tab } from 'material-ui/Tabs';
|
||||
import MenuItem from 'material-ui/MenuItem';
|
||||
import injectSheet from 'react-jss';
|
||||
import { SelectField, TextField, Checkbox } from './FormComponents.js';
|
||||
import { grey800, cyan500 } from 'material-ui/styles/colors';
|
||||
import { grey800, cyan500, red500 } from 'material-ui/styles/colors';
|
||||
import Divider from 'material-ui/Divider';
|
||||
import Dialog from 'material-ui/Dialog';
|
||||
import FlatButton from 'material-ui/FlatButton';
|
||||
import { LOCAL_STORAGE_KEY } from '../constants.js';
|
||||
import shortid from 'shortid';
|
||||
import defaultSettings from '../settings/default.yml';
|
||||
import printerSettings from '../settings/printer.yml';
|
||||
import materialSettings from '../settings/material.yml';
|
||||
import qualitySettings from '../settings/quality.yml';
|
||||
import update from 'react-addons-update';
|
||||
|
||||
const styles = {
|
||||
textFieldRow: {
|
||||
@ -19,74 +29,232 @@ const styles = {
|
||||
fontWeight: 'bold',
|
||||
margin: '30px 0 0 0'
|
||||
}
|
||||
},
|
||||
error: {
|
||||
color: red500
|
||||
}
|
||||
};
|
||||
|
||||
class Settings extends React.Component {
|
||||
static childContextTypes = { state: PropTypes.object, onChange: PropTypes.func, disabled: PropTypes.bool };
|
||||
static defaultProps: {
|
||||
disabled: false
|
||||
const getLocalStorage = () => {
|
||||
let localStorage = window.localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
|
||||
if (!localStorage) {
|
||||
localStorage = { printers: {}, active: null };
|
||||
updateLocalStorage(localStorage);
|
||||
} else {
|
||||
localStorage = JSON.parse(localStorage);
|
||||
}
|
||||
return localStorage;
|
||||
};
|
||||
|
||||
const updateLocalStorage = (localStorage) => {
|
||||
window.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(localStorage));
|
||||
};
|
||||
|
||||
class Settings extends React.Component {
|
||||
static propTypes = {
|
||||
classes: PropTypes.objectOf(PropTypes.string),
|
||||
onChange: PropTypes.func,
|
||||
printers: PropTypes.object.isRequired,
|
||||
defaultPrinter: PropTypes.string,
|
||||
quality: PropTypes.object.isRequired,
|
||||
defaultQuality: PropTypes.string.isRequired,
|
||||
material: PropTypes.object.isRequired,
|
||||
defaultMaterial: PropTypes.string.isRequired,
|
||||
initialSettings: PropTypes.object.isRequired,
|
||||
disabled: PropTypes.bool.isRequired
|
||||
};
|
||||
constructor(props) {
|
||||
super();
|
||||
this.state = {
|
||||
settings: props.initialSettings,
|
||||
printers: props.defaultPrinter,
|
||||
quality: props.defaultQuality,
|
||||
material: props.defaultMaterial
|
||||
static defaultProps: {
|
||||
disabled: false
|
||||
};
|
||||
static childContextTypes = {
|
||||
settings: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
disabled: PropTypes.bool.isRequired,
|
||||
addPrinter: PropTypes.object.isRequired,
|
||||
activePrinter: PropTypes.string,
|
||||
advancedFields: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
state = {
|
||||
localStorage: getLocalStorage(),
|
||||
addPrinter: {
|
||||
open: false,
|
||||
name: '',
|
||||
printer: '',
|
||||
error: null
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { onChange } = this.props;
|
||||
const { localStorage } = this.state;
|
||||
if (localStorage.active) {
|
||||
if (onChange) onChange(this.constructSettings(localStorage));
|
||||
} else {
|
||||
this.openAddPrinterDialog();
|
||||
}
|
||||
}
|
||||
|
||||
changeSettings = (fieldName, value) => {
|
||||
const { onChange } = this.props;
|
||||
const { localStorage } = this.state;
|
||||
|
||||
let state;
|
||||
switch (fieldName) {
|
||||
case 'printers':
|
||||
case 'quality':
|
||||
case 'material':
|
||||
state = {
|
||||
[fieldName]: value,
|
||||
settings: _.merge({}, this.state.settings, this.props[fieldName][value])
|
||||
let state = _.cloneDeep(this.state);
|
||||
|
||||
const removeAddPrinterError = () => {
|
||||
state = update(state, { addPrinter: { error: { $set: null } } });
|
||||
};
|
||||
|
||||
switch (fieldName) {
|
||||
case 'addPrinter.printer':
|
||||
state = update(state, { addPrinter: { printer: { $set: value } } });
|
||||
state = update(state, { addPrinter: { name: { $set: printerSettings[value].title } } });
|
||||
removeAddPrinterError();
|
||||
break;
|
||||
|
||||
case 'addPrinter.name':
|
||||
state = update(state, { addPrinter: { name: { $set: value } } });
|
||||
removeAddPrinterError();
|
||||
break;
|
||||
|
||||
case 'activePrinter':
|
||||
if (value !== 'add_printer') state = update(state, { localStorage: { active: { $set: value } } });
|
||||
break;
|
||||
|
||||
case 'settings.quality':
|
||||
case 'settings.material':
|
||||
if (!localStorage.active) return this.openAddPrinterDialog();
|
||||
|
||||
state = _.set(state, `localStorage.printers[${localStorage.active}].${fieldName}`, value);
|
||||
break;
|
||||
|
||||
case 'settings.layerHeight':
|
||||
case 'settings.dimensions.x':
|
||||
case 'settings.dimensions.y':
|
||||
case 'settings.dimensions.z':
|
||||
case 'settings.nozzleDiameter':
|
||||
case 'settings.bedTemperature':
|
||||
case 'settings.heatedBed':
|
||||
case 'settings.filamentThickness':
|
||||
case 'settings.temperature':
|
||||
case 'settings.thickness.top':
|
||||
case 'settings.thickness.bottom':
|
||||
case 'settings.thickness.shell':
|
||||
case 'settings.retraction.enabled':
|
||||
case 'settings.retraction.amount':
|
||||
case 'settings.retraction.speed':
|
||||
case 'settings.retraction.minDistance':
|
||||
case 'settings.travel.speed':
|
||||
case 'settings.combing':
|
||||
case 'settings.innerShell.speed':
|
||||
case 'settings.innerShell.flowRate':
|
||||
case 'settings.outerShell.speed':
|
||||
case 'settings.outerShell.flowRate':
|
||||
case 'settings.innerInfill.gridSize':
|
||||
case 'settings.innerInfill.speed':
|
||||
case 'settings.innerInfill.flowRate':
|
||||
case 'settings.outerInfill.speed':
|
||||
case 'settings.outerInfill.flowRate':
|
||||
case 'settings.brim.size':
|
||||
case 'settings.brim.speed':
|
||||
case 'settings.brim.flowRate':
|
||||
case 'settings.firstLayer.speed':
|
||||
case 'settings.firstLayer.flowRate':
|
||||
if (!localStorage.active) return this.openAddPrinterDialog();
|
||||
|
||||
if (value === null) {
|
||||
const advanced = { ...state.localStorage.printers[localStorage.active].settings.advanced };
|
||||
delete advanced[fieldName];
|
||||
state = update(state, { localStorage: { printers: { [localStorage.active]: { settings: { advanced: { $set: advanced } } } } } });
|
||||
} else {
|
||||
state = _.set(state, `localStorage.printers[${localStorage.active}].settings.advanced[${JSON.stringify(fieldName)}]`, value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
state = _.set(_.cloneDeep(this.state), fieldName, value);
|
||||
break;
|
||||
}
|
||||
if (onChange) onChange(state);
|
||||
if (state) this.setState(state);
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return { state: this.state, onChange: this.changeSettings, disabled: this.props.disabled };
|
||||
this.setState(state);
|
||||
if (localStorage.active) {
|
||||
if (onChange) onChange(this.constructSettings(state.localStorage));
|
||||
updateLocalStorage(state.localStorage);
|
||||
}
|
||||
}
|
||||
|
||||
getChildContext() {
|
||||
const { localStorage, addPrinter } = this.state;
|
||||
|
||||
return {
|
||||
addPrinter,
|
||||
activePrinter: localStorage.active,
|
||||
advancedFields: localStorage.active ? Object.keys(localStorage.printers[localStorage.active].settings.advanced) : [],
|
||||
settings: this.constructSettings(localStorage),
|
||||
onChange: this.changeSettings,
|
||||
disabled: this.props.disabled
|
||||
};
|
||||
}
|
||||
|
||||
constructSettings(localStorage) {
|
||||
if (!localStorage.active) return defaultSettings;
|
||||
|
||||
const { printer, material, quality, advanced } = localStorage.printers[localStorage.active].settings;
|
||||
let settings = {
|
||||
...defaultSettings,
|
||||
printer,
|
||||
material,
|
||||
quality
|
||||
};
|
||||
|
||||
settings = _.merge({}, settings, printerSettings[printer]);
|
||||
settings = _.merge({}, settings, qualitySettings[quality]);
|
||||
settings = _.merge({}, settings, materialSettings[material]);
|
||||
|
||||
for (const key in advanced) {
|
||||
const value = advanced[key];
|
||||
settings = _.set(_.cloneDeep(settings), key.replace('settings.', ''), value);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
addPrinter = () => {
|
||||
const { name, printer } = this.state.addPrinter;
|
||||
|
||||
if (!name || !printer) {
|
||||
this.setState({ addPrinter: { ...this.state.addPrinter, error: 'Please enter a name and printer' } });
|
||||
return;
|
||||
}
|
||||
|
||||
const id = shortid.generate();
|
||||
const localStorage = {
|
||||
active: id,
|
||||
printers: {
|
||||
...this.state.localStorage.printers,
|
||||
[id]: { name, settings: { printer, material: 'pla', quality: 'medium', advanced: {} } }
|
||||
}
|
||||
};
|
||||
this.setState({ localStorage });
|
||||
updateLocalStorage(localStorage);
|
||||
|
||||
this.closeAddPrinterDialog();
|
||||
|
||||
const { onChange } = this.props;
|
||||
if (onChange) onChange(this.constructSettings(localStorage));
|
||||
}
|
||||
|
||||
closeAddPrinterDialog = () => this.setAddPrinterDialog(false);
|
||||
openAddPrinterDialog = () => this.setAddPrinterDialog(true);
|
||||
setAddPrinterDialog = (open) => this.setState({ addPrinter: { name: '', printer: '', error: null, open } });
|
||||
|
||||
render() {
|
||||
const { classes, printers, quality, material, disabled } = this.props;
|
||||
const { addPrinter, localStorage } = this.state;
|
||||
const { classes, disabled } = this.props;
|
||||
|
||||
return (
|
||||
<div className={classes.container}>
|
||||
<SelectField name="printers" floatingLabelText="Printer" fullWidth>
|
||||
{Object.entries(printers).map(([value, { title }]) => (
|
||||
<MenuItem key={value} value={value} primaryText={title} />
|
||||
<SelectField name="activePrinter" floatingLabelText="Printer" fullWidth>
|
||||
{Object.entries(localStorage.printers).map(([id, { name }]) => (
|
||||
<MenuItem key={id} value={id} primaryText={name} />
|
||||
))}
|
||||
<Divider />
|
||||
<MenuItem onTouchTap={this.openAddPrinterDialog} value="add_printer" primaryText="Add Printer" />
|
||||
</SelectField>
|
||||
<SelectField name="material" floatingLabelText="Material" fullWidth>
|
||||
{Object.entries(material).map(([value, { title }]) => (
|
||||
<SelectField name="settings.material" floatingLabelText="Material" fullWidth>
|
||||
{Object.entries(materialSettings).map(([value, { title }]) => (
|
||||
<MenuItem key={value} value={value} primaryText={title} />
|
||||
))}
|
||||
</SelectField>
|
||||
@ -94,8 +262,8 @@ class Settings extends React.Component {
|
||||
<Tabs inkBarStyle={{ backgroundColor: cyan500 }}>
|
||||
<Tab buttonStyle={{ color: grey800, backgroundColor: 'white' }} label="Basic">
|
||||
<div>
|
||||
<SelectField name="quality" floatingLabelText="Quality" fullWidth>
|
||||
{Object.entries(quality).map(([value, { title }]) => (
|
||||
<SelectField name="settings.quality" floatingLabelText="Quality" fullWidth>
|
||||
{Object.entries(qualitySettings).map(([value, { title }]) => (
|
||||
<MenuItem key={value} value={value} primaryText={title} />
|
||||
))}
|
||||
</SelectField>
|
||||
@ -123,8 +291,6 @@ class Settings extends React.Component {
|
||||
<TextField name="settings.thickness.top" fullWidth floatingLabelText="top" type="number" />
|
||||
<TextField name="settings.thickness.bottom" fullWidth floatingLabelText="bottom" type="number" />
|
||||
<TextField name="settings.thickness.shell" fullWidth floatingLabelText="shell" type="number" />
|
||||
<p>Combing</p>
|
||||
<Checkbox name="settings.combing" label="Enabled" />
|
||||
<p>Retraction</p>
|
||||
<Checkbox name="settings.retraction.enabled" label="Enabled" />
|
||||
<TextField name="settings.retraction.amount" fullWidth floatingLabelText="Amount" type="number" />
|
||||
@ -156,6 +322,30 @@ class Settings extends React.Component {
|
||||
</div>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
<Dialog
|
||||
title="Add Printer"
|
||||
open={addPrinter.open}
|
||||
onRequestClose={this.closeAddPrinterDialog}
|
||||
contentStyle={{ maxWidth: '400px' }}
|
||||
actions={[
|
||||
<FlatButton
|
||||
label="Cancel"
|
||||
onTouchTap={this.closeAddPrinterDialog}
|
||||
/>,
|
||||
<FlatButton
|
||||
label="Add"
|
||||
primary
|
||||
onTouchTap={this.addPrinter}
|
||||
/>
|
||||
]}
|
||||
>
|
||||
<SelectField name="addPrinter.printer" floatingLabelText="Printer" fullWidth>
|
||||
{Object.entries(printerSettings).map(([value, { title }]) => (
|
||||
<MenuItem key={value} value={value} primaryText={title} /> ))}
|
||||
</SelectField>
|
||||
<TextField name="addPrinter.name" floatingLabelText="Name" fullWidth />
|
||||
{addPrinter.error && <p className={classes.error}>{addPrinter.error}</p>}
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -16,10 +16,6 @@ import Menu from 'material-ui/Menu';
|
||||
import MenuItem from 'material-ui/MenuItem';
|
||||
import { Tabs, Tab } from 'material-ui/Tabs';
|
||||
import Settings from './Settings.js';
|
||||
import defaultSettings from '../settings/default.yml';
|
||||
import printerSettings from '../settings/printer.yml';
|
||||
import materialSettings from '../settings/material.yml';
|
||||
import qualitySettings from '../settings/quality.yml';
|
||||
import ReactResizeDetector from 'react-resize-detector';
|
||||
import JSONToSketchData from 'doodle3d-core/shape/JSONToSketchData';
|
||||
import createSceneData from 'doodle3d-core/d3/createSceneData.js';
|
||||
@ -91,63 +87,40 @@ class Interface extends React.Component {
|
||||
PropTypes.string
|
||||
]).isRequired,
|
||||
classes: PropTypes.objectOf(PropTypes.string),
|
||||
defaultSettings: PropTypes.object.isRequired,
|
||||
printers: PropTypes.object.isRequired,
|
||||
defaultPrinter: PropTypes.string,
|
||||
quality: PropTypes.object.isRequired,
|
||||
defaultQuality: PropTypes.string.isRequired,
|
||||
material: PropTypes.object.isRequired,
|
||||
defaultMaterial: PropTypes.string.isRequired,
|
||||
pixelRatio: PropTypes.number.isRequired,
|
||||
onCancel: PropTypes.func,
|
||||
name: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
defaultSettings: defaultSettings,
|
||||
printers: printerSettings,
|
||||
quality: qualitySettings,
|
||||
defaultQuality: 'medium',
|
||||
material: materialSettings,
|
||||
defaultMaterial: 'pla',
|
||||
pixelRatio: 1,
|
||||
name: 'Doodle3D'
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { defaultPrinter, defaultQuality, defaultMaterial, printers, quality, material, defaultSettings } = props;
|
||||
|
||||
const scene = createScene(this.props);
|
||||
this.state = {
|
||||
scene,
|
||||
settings: null,
|
||||
showFullScreen: false,
|
||||
isSlicing: false,
|
||||
isLoading: true,
|
||||
error: null,
|
||||
printers: defaultPrinter,
|
||||
quality: defaultQuality,
|
||||
material: defaultMaterial,
|
||||
popover: {
|
||||
element: null,
|
||||
open: false
|
||||
},
|
||||
settings: _.merge(
|
||||
{},
|
||||
defaultSettings,
|
||||
printers[defaultPrinter],
|
||||
quality[defaultQuality],
|
||||
material[defaultMaterial]
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { canvas } = this.refs;
|
||||
const scene = createScene(canvas, this.props, this.state);
|
||||
|
||||
this.setState({ scene });
|
||||
const { scene } = this.state;
|
||||
scene.updateCanvas(canvas);
|
||||
|
||||
const { file } = this.props;
|
||||
|
||||
if (!file) {
|
||||
throw new Error('no file provided');
|
||||
} if (typeof file === 'string') {
|
||||
@ -220,22 +193,20 @@ class Interface extends React.Component {
|
||||
};
|
||||
|
||||
slice = async (target) => {
|
||||
const { isSlicing, isLoading, settings, printers, quality, mesh, scene: { material, mesh: { matrix } } } = this.state;
|
||||
const { isSlicing, isLoading, settings, mesh, scene: { material, mesh: { matrix } } } = this.state;
|
||||
const { name } = this.props;
|
||||
|
||||
if (isSlicing || isLoading) return;
|
||||
|
||||
this.closePopover();
|
||||
|
||||
this.setState({ isSlicing: true, progress: { action: '', percentage: 0, step: 0 }, error: null });
|
||||
|
||||
const exportMesh = new Mesh(mesh.geometry, mesh.material);
|
||||
exportMesh.applyMatrix(matrix);
|
||||
|
||||
try {
|
||||
await slice(target, name, exportMesh, settings, printers, quality, material, progress => {
|
||||
this.setState({ progress: { ...this.state.progress, ...progress } });
|
||||
});
|
||||
const updateProgres = progress => this.setState({ progress: { ...this.state.progress, ...progress } });
|
||||
await slice(target, name, exportMesh, settings, updateProgres);
|
||||
} catch (error) {
|
||||
this.setState({ error: error.message });
|
||||
throw error;
|
||||
@ -263,23 +234,6 @@ class Interface extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
onChangeSettings = (settings) => {
|
||||
this.setState(settings);
|
||||
};
|
||||
|
||||
componentWillUpdate(nextProps, nextState) {
|
||||
if (!this.state.scene) return;
|
||||
const { scene: { box, render, setSize } } = this.state;
|
||||
let changed = false;
|
||||
if (box && nextState.settings.dimensions !== this.state.settings.dimensions) {
|
||||
const { dimensions } = nextState.settings;
|
||||
box.scale.set(dimensions.y, dimensions.z, dimensions.x);
|
||||
box.updateMatrix();
|
||||
changed = true;
|
||||
}
|
||||
if (changed) render();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const { scene: { updateCanvas } } = this.state;
|
||||
const { canvas } = this.refs;
|
||||
@ -298,9 +252,23 @@ class Interface extends React.Component {
|
||||
this.setState({ showFullScreen: width > MAX_FULLSCREEN_WIDTH });
|
||||
};
|
||||
|
||||
onChangeSettings = (settings) => {
|
||||
const { scene: { box, render } } = this.state;
|
||||
|
||||
let changed = false;
|
||||
if (!this.state.settings || this.state.settings.dimensions !== settings.dimensions) {
|
||||
box.scale.set(settings.dimensions.y, settings.dimensions.z, settings.dimensions.x);
|
||||
box.updateMatrix();
|
||||
changed = true;
|
||||
}
|
||||
if (changed) render();
|
||||
|
||||
this.setState({ settings, error: null });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes, defaultPrinter, defaultQuality, defaultMaterial, onCancel } = this.props;
|
||||
const { isSlicing, isLoading, progress, settings, printers, quality, material, showFullScreen, error } = this.state;
|
||||
const { classes, onCancel } = this.props;
|
||||
const { isSlicing, isLoading, progress, showFullScreen, error } = this.state;
|
||||
|
||||
const disableUI = isSlicing || isLoading;
|
||||
const style = { ...(showFullScreen ? {} : { maxWidth: 'inherit', width: '100%', height: '100%' }) };
|
||||
@ -309,13 +277,6 @@ class Interface extends React.Component {
|
||||
<div className={classes.settingsBar} style={style}>
|
||||
<Settings
|
||||
disabled={disableUI}
|
||||
printers={printerSettings}
|
||||
defaultPrinter={defaultPrinter}
|
||||
quality={qualitySettings}
|
||||
defaultQuality={defaultQuality}
|
||||
material={materialSettings}
|
||||
defaultMaterial={defaultMaterial}
|
||||
initialSettings={settings}
|
||||
onChange={this.onChangeSettings}
|
||||
/>
|
||||
<div className={classes.sliceActions}>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import * as THREE from 'three';
|
||||
import { Box3 } from 'three/src/math/Box3.js';
|
||||
import { Matrix4 } from 'three/src/math/Matrix4.js';
|
||||
import { Vector3 } from 'three/src/math/Vector3.js';
|
||||
import { Scene } from 'three/src/scenes/Scene.js';
|
||||
import { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera.js';
|
||||
import { AmbientLight } from 'three/src/lights/AmbientLight.js';
|
||||
@ -34,14 +35,12 @@ export function centerGeometry(mesh) {
|
||||
mesh.geometry.applyMatrix(new Matrix4().makeTranslation(-center.x, -center.y, -center.z));
|
||||
}
|
||||
|
||||
export function createScene(canvas, props, state) {
|
||||
const { pixelRatio } = props;
|
||||
const { settings } = state;
|
||||
|
||||
export function createScene({ pixelRatio }) {
|
||||
const scene = new Scene();
|
||||
|
||||
const camera = new PerspectiveCamera(50, 1, 1, 10000);
|
||||
camera.position.set(0, 400, 300);
|
||||
camera.lookAt(new Vector3(0, 0, 0));
|
||||
|
||||
const directionalLightA = new DirectionalLight(0xa2a2a2);
|
||||
directionalLightA.position.set(1, 1, 1);
|
||||
@ -61,8 +60,10 @@ export function createScene(canvas, props, state) {
|
||||
const box = new BoxHelper(new Mesh(new BoxGeometry(1, 1, 1).applyMatrix(new Matrix4().makeTranslation(0, 0.5, 0))), 0x72bcd4);
|
||||
scene.add(box);
|
||||
|
||||
const { dimensions } = settings;
|
||||
box.scale.set(dimensions.y, dimensions.z, dimensions.x);
|
||||
let renderer = new WebGLRenderer({ alpha: true, antialias: true });
|
||||
let editorControls = new THREE.EditorControls(camera, renderer.domElement);
|
||||
|
||||
box.scale.set(1., 1., 1.);
|
||||
box.updateMatrix();
|
||||
|
||||
const render = () => renderer.render(scene, camera);
|
||||
@ -75,8 +76,6 @@ export function createScene(canvas, props, state) {
|
||||
render();
|
||||
};
|
||||
|
||||
let editorControls;
|
||||
let renderer;
|
||||
const updateCanvas = (canvas) => {
|
||||
if (!renderer || renderer.domElement !== canvas) {
|
||||
if (renderer) renderer.dispose();
|
||||
@ -86,13 +85,11 @@ export function createScene(canvas, props, state) {
|
||||
if (!editorControls || editorControls.domElement !== canvas) {
|
||||
if (editorControls) editorControls.dispose();
|
||||
editorControls = new THREE.EditorControls(camera, canvas);
|
||||
editorControls.focus(mesh);
|
||||
editorControls.addEventListener('change', render);
|
||||
}
|
||||
|
||||
render();
|
||||
};
|
||||
updateCanvas(canvas);
|
||||
|
||||
const focus = () => editorControls.focus(mesh);
|
||||
|
||||
@ -119,8 +116,8 @@ export function fetchProgress(url, { method = 'get', headers = {}, body = {} } =
|
||||
const GCODE_SERVER_URL = 'https://gcodeserver.doodle3d.com';
|
||||
const CONNECT_URL = 'http://connect.doodle3d.com/';
|
||||
|
||||
export async function slice(target, name, mesh, settings, printers, quality, material, updateProgress) {
|
||||
if (!printers) throw new Error('Please select a printer');
|
||||
export async function slice(target, name, mesh, settings, updateProgress) {
|
||||
if (!settings) throw new Error('please select a printer first');
|
||||
|
||||
let steps;
|
||||
let currentStep = 0;
|
||||
@ -167,22 +164,13 @@ export async function slice(target, name, mesh, settings, printers, quality, mat
|
||||
body.append(key, fields[key]);
|
||||
}
|
||||
|
||||
const file = ';' + JSON.stringify({
|
||||
name: `${name}.gcode`,
|
||||
const file = `;${JSON.stringify({
|
||||
...settings,
|
||||
printer: {
|
||||
type: printers,
|
||||
title: printerSettings[printers].title
|
||||
},
|
||||
material: {
|
||||
type: material,
|
||||
title: materialSettings[material].title
|
||||
},
|
||||
quality: {
|
||||
type: quality,
|
||||
title: qualitySettings[quality].title
|
||||
}
|
||||
}).trim() + '\n' + gcode;
|
||||
name: `${name}.gcode`,
|
||||
printer: { type: settings.printers, title: printerSettings[settings.printer].title },
|
||||
material: { type: settings.material, title: materialSettings[settings.material].title },
|
||||
quality: { type: settings.quality, title: qualitySettings[settings.quality].title }
|
||||
}).trim()}\n${gcode}`;
|
||||
body.append('file', file);
|
||||
|
||||
await fetchProgress(reservation.url, { method: 'POST', body }, (progess) => {
|
||||
@ -195,6 +183,7 @@ export async function slice(target, name, mesh, settings, printers, quality, mat
|
||||
|
||||
const popup = window.open(`${CONNECT_URL}?uuid=${id}`, '_blank');
|
||||
if (!popup) throw new Error('popup was blocked by browser');
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user