Compare commits
105 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
35e4877326 | ||
|
d519033bd6 | ||
|
7418cce606 | ||
|
de19534d9d | ||
|
9f84cf406b | ||
|
83d03e8a1a | ||
|
011d9904a7 | ||
|
353793d867 | ||
|
395a116760 | ||
|
e11de849dd | ||
|
a0307f8ead | ||
|
80c08d7b2c | ||
|
bb1b2b73c0 | ||
|
f613c2b68d | ||
|
87b6e9851b | ||
|
31e9ec735f | ||
|
1a5f0fd9d0 | ||
|
a6eeb3f3f6 | ||
|
f514c9da45 | ||
|
d569a4f5b7 | ||
|
d43c55906b | ||
|
5f7e70027a | ||
|
4879f47d4c | ||
|
fed4146aea | ||
|
9e5c929da5 | ||
|
0c1cdb1580 | ||
|
6260e21c6d | ||
|
02e312247c | ||
|
3670802bea | ||
|
b5e0d809c7 | ||
|
023c416b5d | ||
|
c55750613f | ||
|
853d8a5c7e | ||
|
b5bf5eb8c7 | ||
|
ac2256d2c5 | ||
|
b0c0063039 | ||
|
ca4b886c93 | ||
|
582b8f8c37 | ||
|
fcd6bdbbf8 | ||
|
0a3686d8df | ||
|
24abade4b9 | ||
|
7a3ee5888a | ||
|
ab581cf79b | ||
|
efb1efe3d9 | ||
|
7360cdc85a | ||
|
d98b90bb2e | ||
|
3d63e349fe | ||
|
6e1660504b | ||
|
2b84cd0b11 | ||
|
5032018257 | ||
|
6b6b860c4a | ||
|
63b33c69b9 | ||
|
7d34f916ac | ||
|
42c2b1243f | ||
|
5564e8b533 | ||
|
eb19034e86 | ||
|
b9ed59c8d9 | ||
|
9996728f9c | ||
|
02a7f64d5f | ||
|
1d4562e2df | ||
|
7fd9220851 | ||
|
be8a49e5c7 | ||
|
f387297195 | ||
|
07c5d0635c | ||
|
9101a6325a | ||
|
68a36c29e3 | ||
|
ec22dc0cf7 | ||
|
dd8ab3263c | ||
|
da12939253 | ||
|
12ba7f624f | ||
|
4bd5c2f679 | ||
|
4080f0151c | ||
|
d300a31929 | ||
|
ff09b3942a | ||
|
4cb60940f8 | ||
|
ad94402400 | ||
|
908050bbd0 | ||
|
509cff2eae | ||
|
36a73c233e | ||
|
1b66fc21e0 | ||
|
b674769ef8 | ||
|
83113e65b2 | ||
|
9ce8594856 | ||
|
9ca5fd5205 | ||
|
e8243d84e3 | ||
|
8621ff9755 | ||
|
87acf98f51 | ||
|
b007ff3f33 | ||
|
7b9f647f11 | ||
|
a4a5afeb08 | ||
|
b42c7829ca | ||
|
01bd55796e | ||
|
2b5d240487 | ||
|
1464a4b74f | ||
|
04186fd56c | ||
|
834ca531fd | ||
|
ab27e7c8c2 | ||
|
9d1d51d357 | ||
|
e3cda119ce | ||
|
0e6fd5fb1c | ||
|
0c4e410a27 | ||
|
01f4b4c1f8 | ||
|
65592d6f48 | ||
|
c31115aa0b | ||
|
162016bbc9 |
1
.gitignore
vendored
|
@ -13,3 +13,4 @@ plugins
|
||||||
platforms
|
platforms
|
||||||
|
|
||||||
config.xml
|
config.xml
|
||||||
|
.DS_Store
|
||||||
|
|
22
LICENSE.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Copyright (c) 2015-2021 Doodle3D
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use,
|
||||||
|
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
14
README.md
|
@ -0,0 +1,14 @@
|
||||||
|
This repository contains the core functionality of Doodle3D Transform.
|
||||||
|
|
||||||
|
## Build & run locally
|
||||||
|
```bash
|
||||||
|
git clone git@github.com:Doodle3D/Doodle3D-Core.git
|
||||||
|
cd Doodle3D-Core
|
||||||
|
npm install # Make sure you have installed NPM / NodeJS first
|
||||||
|
npm run start
|
||||||
|
# visit http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
## Doodle3D-Transform
|
||||||
|
The Doodle3D-Core repo just contains the core drawing features of Doodle3D Transform. To get the other features like file management, exporting and slicing you should visit the Doodle3D Transform repository: https://github.com/Doodle3D/Doodle3D-Transform
|
||||||
|
|
BIN
favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
fonts/abril-fatface-v12-latin-regular.woff
Normal file
BIN
fonts/bellefair-v6-latin-regular.woff
Normal file
BIN
fonts/fascinate-v11-latin-regular.woff
Normal file
BIN
fonts/joti-one-v11-latin-regular.woff
Normal file
BIN
fonts/lobster-v23-latin-regular.woff
Normal file
BIN
fonts/oswald-v36-latin-regular.woff
Normal file
BIN
fonts/play-v12-latin-regular.woff
Normal file
BIN
fonts/ranga-v8-latin-regular.woff
Normal file
Before Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 113 KiB |
BIN
img/bannerBg.png
Before Width: | Height: | Size: 14 KiB |
BIN
img/btnCross.png
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 630 B |
Before Width: | Height: | Size: 524 B |
Before Width: | Height: | Size: 639 B |
Before Width: | Height: | Size: 930 B |
BIN
img/btnPlus.png
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 219 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 10 KiB |
BIN
img/logo.png
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 7.0 KiB |
BIN
img/menu/new.png
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 11 KiB |
BIN
img/platform.png
Before Width: | Height: | Size: 22 KiB |
BIN
img/trace.jpg
Before Width: | Height: | Size: 146 KiB |
31
index.js
|
@ -11,6 +11,7 @@ import thunkMiddleware from 'redux-thunk';
|
||||||
import promiseMiddleware from 'redux-promise-middleware';
|
import promiseMiddleware from 'redux-promise-middleware';
|
||||||
import { createLogger } from 'redux-logger';
|
import { createLogger } from 'redux-logger';
|
||||||
import sketcherReducer from './src/reducer/index.js';
|
import sketcherReducer from './src/reducer/index.js';
|
||||||
|
|
||||||
const reducer = combineReducers({ sketcher: sketcherReducer });
|
const reducer = combineReducers({ sketcher: sketcherReducer });
|
||||||
const enhancer = compose(applyMiddleware(thunkMiddleware, promiseMiddleware(), createLogger({ collapsed: true })));
|
const enhancer = compose(applyMiddleware(thunkMiddleware, promiseMiddleware(), createLogger({ collapsed: true })));
|
||||||
const store = createStore(reducer, enhancer);
|
const store = createStore(reducer, enhancer);
|
||||||
|
@ -23,16 +24,37 @@ import { saveAs as saveAsLib } from 'file-saver';
|
||||||
|
|
||||||
// download file
|
// download file
|
||||||
import { createFile } from './src/utils/exportUtils.js';
|
import { createFile } from './src/utils/exportUtils.js';
|
||||||
window.downloadStl = () => {
|
import sketchDataToJSON from './src/shape/sketchDataToJSON.js';
|
||||||
|
import { JSONToBlob } from './src/utils/binaryUtils.js';
|
||||||
|
|
||||||
|
// usage: downloadStl({lineWidth:20})
|
||||||
|
window.downloadStl = (options) => {
|
||||||
store.dispatch(async (dispatch, getState) => {
|
store.dispatch(async (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const blob = await createFile(state.sketcher.present, 'stl-blob');
|
const blob = await createFile(state.sketcher.present, 'stl-blob', options);
|
||||||
saveAsLib(blob, 'doodle.stl');
|
saveAsLib(blob, 'doodle.stl');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.downloadSketch = () => {
|
||||||
|
store.dispatch((dispatch, getState) => {
|
||||||
|
const state = getState();
|
||||||
|
const json = sketchDataToJSON(state.sketcher.present);
|
||||||
|
const blob = JSONToBlob(json);
|
||||||
|
saveAsLib(blob, 'doodle.doodle3d');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// import keycode from 'keycode';
|
||||||
|
// window.addEventListener('keydown', (event) => {
|
||||||
|
// // downloadSketch
|
||||||
|
// const key = keycode(event);
|
||||||
|
// if (key === 's') window.downloadSketch();
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
// add model to store
|
// add model to store
|
||||||
import modelData from './models/simple_hole.d3sketch';
|
import modelData from './models/circle_error.d3sketch';
|
||||||
import JSONToSketchData from './src/shape/JSONToSketchData.js';
|
import JSONToSketchData from './src/shape/JSONToSketchData.js';
|
||||||
JSONToSketchData(JSON.parse(modelData)).then(data => {
|
JSONToSketchData(JSON.parse(modelData)).then(data => {
|
||||||
store.dispatch(actions.openSketch({ data }));
|
store.dispatch(actions.openSketch({ data }));
|
||||||
|
@ -42,10 +64,11 @@ JSONToSketchData(JSON.parse(modelData)).then(data => {
|
||||||
import jss from 'jss';
|
import jss from 'jss';
|
||||||
import preset from 'jss-preset-default';
|
import preset from 'jss-preset-default';
|
||||||
import normalize from 'normalize-jss';
|
import normalize from 'normalize-jss';
|
||||||
|
|
||||||
jss.setup(preset());
|
jss.setup(preset());
|
||||||
jss.createStyleSheet(normalize).attach();
|
jss.createStyleSheet(normalize).attach();
|
||||||
jss.createStyleSheet({
|
jss.createStyleSheet({
|
||||||
'@global': {
|
'@global': {
|
||||||
'*': { margin: 0, padding: 0 },
|
'*': { margin: 0, padding: 0 },
|
||||||
'#app, body, html': { height: '100%', fontFamily: 'sans-serif' },
|
'#app, body, html': { height: '100%', fontFamily: 'sans-serif' },
|
||||||
body: { overflow: 'auto' },
|
body: { overflow: 'auto' },
|
||||||
|
|
1
models/circle_error.d3sketch
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"data":"{\"spaces\":[{\"matrix\":{\"metadata\":{\"type\":\"Matrix4\",\"library\":\"three.js\"},\"elements\":[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]},\"objects\":[{\"height\":20,\"transform\":{\"metadata\":{\"library\":\"CAL\",\"type\":\"Matrix\"},\"matrix\":[1,0,-16.42969984202213,0,1,-10.74249605055293]},\"z\":0,\"sculpt\":[{\"pos\":0,\"scale\":1},{\"pos\":1,\"scale\":1}],\"twist\":0,\"fill\":true,\"solid\":true,\"circle\":{\"radius\":31.061842611644483,\"segment\":6.283185307179586},\"color\":6873597,\"type\":\"CIRCLE\"},{\"height\":20,\"transform\":{\"metadata\":{\"library\":\"CAL\",\"type\":\"Matrix\"},\"matrix\":[1,0,-3.1595576619273373,0,1,-2.5276461295418784]},\"z\":0,\"sculpt\":[{\"pos\":0,\"scale\":1},{\"pos\":1,\"scale\":1}],\"twist\":0,\"fill\":true,\"solid\":false,\"circle\":{\"radius\":30.41228120273779,\"segment\":6.283185307179586},\"color\":6873597,\"type\":\"CIRCLE\"}]}]}","appVersion":"0.17.4"}
|
32720
package-lock.json
generated
29
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@doodle3d/doodle3d-core",
|
"name": "@doodle3d/doodle3d-core",
|
||||||
"version": "0.17.5",
|
"version": "0.23.0",
|
||||||
"description": "Core functions of Doodle3D Transform",
|
"description": "Core functions of Doodle3D Transform",
|
||||||
"main": "lib",
|
"main": "lib",
|
||||||
"module": "module",
|
"module": "module",
|
||||||
|
@ -10,46 +10,50 @@
|
||||||
"ios": "TARGET=app webpack -p && cordova run ios",
|
"ios": "TARGET=app webpack -p && cordova run ios",
|
||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
"lint": "eslint src",
|
"lint": "eslint src",
|
||||||
|
"dist": "NODE_ENV=production webpack -p",
|
||||||
"build": "npm run build:main && npm run build:module ",
|
"build": "npm run build:main && npm run build:module ",
|
||||||
"build:main": "BABEL_ENV=main babel src -s -d lib",
|
"build:main": "BABEL_ENV=main babel src -s -d lib",
|
||||||
"build:module": "BABEL_ENV=module babel src -s -d module"
|
"build:module": "BABEL_ENV=module babel src -s -d module"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@doodle3d/cal": "0.0.8",
|
"@doodle3d/cal": "0.0.8",
|
||||||
"@doodle3d/clipper-js": "^1.0.7",
|
"@doodle3d/clipper-js": "^1.0.11",
|
||||||
"@doodle3d/fill-path": "^1.0.7",
|
|
||||||
"@doodle3d/potrace-js": "0.0.6",
|
"@doodle3d/potrace-js": "0.0.6",
|
||||||
"@doodle3d/threejs-export-obj": "0.0.8",
|
"@doodle3d/threejs-export-obj": "0.0.8",
|
||||||
"@doodle3d/threejs-export-stl": "0.0.5",
|
"@doodle3d/threejs-export-stl": "0.0.5",
|
||||||
"@doodle3d/touch-events": "0.0.7",
|
"@doodle3d/touch-events": "0.0.9",
|
||||||
"babel-polyfill": "^6.26.0",
|
"babel-polyfill": "^6.26.0",
|
||||||
"bezier-js": "^2.2.3",
|
"bezier-js": "^2.2.3",
|
||||||
"blueimp-canvas-to-blob": "^3.14.0",
|
"blueimp-canvas-to-blob": "^3.14.0",
|
||||||
"bowser": "^1.8.1",
|
"bowser": "^1.8.1",
|
||||||
|
"file-loader": "^0.11.2",
|
||||||
|
"fill-path": "^1.0.11",
|
||||||
"fit-curve": "^0.1.6",
|
"fit-curve": "^0.1.6",
|
||||||
|
"font-loaded": "^1.0.0",
|
||||||
"imports-loader": "^0.7.1",
|
"imports-loader": "^0.7.1",
|
||||||
|
"jss": "^9.4.0",
|
||||||
"keycode": "^2.1.9",
|
"keycode": "^2.1.9",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"memoizee": "^0.3.9",
|
"memoizee": "^0.3.9",
|
||||||
"pouchdb": "^6.3.4",
|
"normalize-wheel": "^1.0.1",
|
||||||
"proptypes": "^1.1.0",
|
"proptypes": "^1.1.0",
|
||||||
"raf": "^3.4.0",
|
"raf": "^3.4.0",
|
||||||
"ramda": "^0.21.0",
|
"ramda": "^0.21.0",
|
||||||
"react": "^16.0.0",
|
"react": "^16.0.1",
|
||||||
"react-addons-update": "^15.6.2",
|
"react-addons-update": "^15.6.2",
|
||||||
"react-jss": "^7.0.2",
|
"react-jss": "^7.0.2",
|
||||||
"react-notification-system-redux": "^1.2.0",
|
"react-notification-system-redux": "^1.2.0",
|
||||||
"react-redux": "^5.0.6",
|
"react-redux": "^5.0.6",
|
||||||
"react-resize-detector": "^1.1.0",
|
"react-resize-detector": "^1.1.0",
|
||||||
"react-svg-inline": "^2.0.1",
|
"react-svg-inline": "^2.0.1",
|
||||||
|
"react-tap-event-plugin": "^3.0.3",
|
||||||
"redux-form": "^7.1.2",
|
"redux-form": "^7.1.2",
|
||||||
"redux-undo": "^1.0.0-beta9-9-7",
|
"redux-undo": "^1.0.0-beta9-9-7",
|
||||||
"reselect": "^3.0.1",
|
"reselect": "^3.0.1",
|
||||||
"semver": "^5.4.1",
|
"semver": "^5.4.1",
|
||||||
"shortid": "^2.2.8",
|
"shortid": "^2.2.8",
|
||||||
"three": "^0.88.0",
|
"three": "^0.88.0",
|
||||||
"three-js-csg": "github:Doodle3D/three-js-csg",
|
"three-js-csg": "github:Doodle3D/three-js-csg"
|
||||||
"valid-url": "^1.0.9"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "6.24.1",
|
"babel-cli": "6.24.1",
|
||||||
|
@ -81,8 +85,6 @@
|
||||||
"normalize-jss": "^4.0.0",
|
"normalize-jss": "^4.0.0",
|
||||||
"raw-loader": "^0.5.1",
|
"raw-loader": "^0.5.1",
|
||||||
"react-dom": "^16.1.1",
|
"react-dom": "^16.1.1",
|
||||||
"react-router-redux": "^4.0.8",
|
|
||||||
"react-tap-event-plugin": "^3.0.2",
|
|
||||||
"redux": "^3.7.2",
|
"redux": "^3.7.2",
|
||||||
"redux-action-wrapper": "^1.0.1",
|
"redux-action-wrapper": "^1.0.1",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
|
@ -94,16 +96,15 @@
|
||||||
"webpack-bundle-analyzer": "^2.9.1",
|
"webpack-bundle-analyzer": "^2.9.1",
|
||||||
"webpack-cordova-plugin": "^0.1.6",
|
"webpack-cordova-plugin": "^0.1.6",
|
||||||
"webpack-dev-server": "^2.9.4",
|
"webpack-dev-server": "^2.9.4",
|
||||||
"worker-loader": "^1.1.0",
|
"worker-loader": "^1.1.0"
|
||||||
"yml-loader": "^2.1.0"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/Doodle3D/Doodle3D-Core.git"
|
"url": "git+https://github.com/Doodle3D/Doodle3D-Core.git"
|
||||||
},
|
},
|
||||||
"author": "Casper @Doodle3D",
|
"author": "Casper @Doodle3D",
|
||||||
"license": "UNLICENSED",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": false,
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/Doodle3D/Doodle3D-Core/issues"
|
"url": "https://github.com/Doodle3D/Doodle3D-Core/issues"
|
||||||
},
|
},
|
||||||
|
|
29
shaders/anaglyph_frag.glsl
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
uniform sampler2D mapLeft;
|
||||||
|
uniform sampler2D mapRight;
|
||||||
|
varying vec2 vUv;
|
||||||
|
|
||||||
|
uniform mat3 colorMatrixLeft;
|
||||||
|
uniform mat3 colorMatrixRight;
|
||||||
|
|
||||||
|
float lin(float c) {
|
||||||
|
return c <= 0.04045 ? c * 0.0773993808 : pow(c * 0.9478672986 + 0.0521327014, 2.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 lin(vec4 c) {
|
||||||
|
return vec4(lin(c.r), lin(c.g), lin(c.b), c.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dev(float c) {
|
||||||
|
return c <= 0.0031308 ? c * 12.92 : pow(c, 0.41666) * 1.055 - 0.055;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 uv = vUv;
|
||||||
|
|
||||||
|
vec4 colorL = lin(texture2D(mapLeft, uv));
|
||||||
|
vec4 colorR = lin(texture2D(mapRight, uv));
|
||||||
|
|
||||||
|
vec3 color = clamp(colorMatrixLeft * colorL.rgb + colorMatrixRight * colorR.rgb, 0., 1.);
|
||||||
|
|
||||||
|
gl_FragColor = vec4(dev(color.r), dev(color.g), dev(color.b), max(colorL.a, colorR.a));
|
||||||
|
}
|
6
shaders/anaglyph_vert.glsl
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
varying vec2 vUv;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vUv = vec2(uv.x, uv.y);
|
||||||
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
import { ActionCreators as undo } from 'redux-undo';
|
import { ActionCreators as undo } from 'redux-undo';
|
||||||
import * as notification from 'react-notification-system-redux';
|
import * as notification from 'react-notification-system-redux';
|
||||||
import { routerActions as router } from 'react-router-redux';
|
|
||||||
import * as selectionUtils from '../utils/selectionUtils.js';
|
import * as selectionUtils from '../utils/selectionUtils.js';
|
||||||
import { calculatePointInImage, decomposeMatrix } from '../utils/matrixUtils.js';
|
import { calculatePointInImage, decomposeMatrix } from '../utils/matrixUtils.js';
|
||||||
import { loadImage, prepareImage } from '../utils/imageUtils.js';
|
import { loadImage, prepareImage } from '../utils/imageUtils.js';
|
||||||
|
@ -9,7 +8,7 @@ import { createThrottle } from '../utils/async.js';
|
||||||
import { tween } from '../utils/tweenUtils.js';
|
import { tween } from '../utils/tweenUtils.js';
|
||||||
import { DEFAULT_TRACE_TOLERANCE, MAX_TRACE_TOLERANCE } from '../constants/d2Constants.js';
|
import { DEFAULT_TRACE_TOLERANCE, MAX_TRACE_TOLERANCE } from '../constants/d2Constants.js';
|
||||||
import * as d2Tools from '../constants/d2Tools.js';
|
import * as d2Tools from '../constants/d2Tools.js';
|
||||||
import { Matrix } from 'cal';
|
import { Matrix } from '@doodle3d/cal';
|
||||||
// import createDebug from 'debug';
|
// import createDebug from 'debug';
|
||||||
// const debug = createDebug('d3d:actions');
|
// const debug = createDebug('d3d:actions');
|
||||||
|
|
||||||
|
@ -74,7 +73,6 @@ export const ALIGN = 'ALIGN';
|
||||||
export const ADD_IMAGE = 'ADD_IMAGE';
|
export const ADD_IMAGE = 'ADD_IMAGE';
|
||||||
export const D2_TEXT_INIT = 'D2_TEXT_INIT';
|
export const D2_TEXT_INIT = 'D2_TEXT_INIT';
|
||||||
export const D2_TEXT_INPUT_CHANGE = 'D2_TEXT_INPUT_CHANGE';
|
export const D2_TEXT_INPUT_CHANGE = 'D2_TEXT_INPUT_CHANGE';
|
||||||
export const D2_TEXT_ADD = 'D2_TEXT_ADD';
|
|
||||||
export const UNION = 'UNION';
|
export const UNION = 'UNION';
|
||||||
export const INTERSECT = 'INTERSECT';
|
export const INTERSECT = 'INTERSECT';
|
||||||
export const MOVE_SELECTION = 'MOVE_SELECTION';
|
export const MOVE_SELECTION = 'MOVE_SELECTION';
|
||||||
|
@ -86,6 +84,8 @@ export const TRACE_FLOOD_FILL = 'TRACE_FLOOD_FILL';
|
||||||
export const MENU_OPEN = 'MENU_OPEN';
|
export const MENU_OPEN = 'MENU_OPEN';
|
||||||
export const MENU_CLOSE = 'MENU_CLOSE';
|
export const MENU_CLOSE = 'MENU_CLOSE';
|
||||||
export const OPEN_SKETCH = 'OPEN_SKETCH';
|
export const OPEN_SKETCH = 'OPEN_SKETCH';
|
||||||
|
export const SET_PREVENT_SCROLL = 'SET_PREVENT_SCROLL';
|
||||||
|
export const SET_DISABLE_SCROLL = 'SET_DISABLE_SCROLL';
|
||||||
|
|
||||||
// CATEGORIES
|
// CATEGORIES
|
||||||
// actions that influence selected objects
|
// actions that influence selected objects
|
||||||
|
@ -390,14 +390,10 @@ export function addImage(file) {
|
||||||
export function d2textInit(position, textId, screenMatrixContainer, screenMatrixZoom) {
|
export function d2textInit(position, textId, screenMatrixContainer, screenMatrixZoom) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch({ type: D2_TEXT_INIT, position, textId, screenMatrixContainer, screenMatrixZoom });
|
dispatch({ type: D2_TEXT_INIT, position, textId, screenMatrixContainer, screenMatrixZoom });
|
||||||
dispatch(router.push('/sketch/inputtext'));
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export function d2textInputChange(text, family, weight, style, fill) {
|
export function d2textInputChange(text) {
|
||||||
return { type: D2_TEXT_INPUT_CHANGE, text, family, weight, style, fill };
|
return { type: D2_TEXT_INPUT_CHANGE, text };
|
||||||
}
|
|
||||||
export function d2textAdd() {
|
|
||||||
return { type: D2_TEXT_ADD };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const traceDragThrottle = createThrottle();
|
const traceDragThrottle = createThrottle();
|
||||||
|
@ -422,25 +418,25 @@ export function traceDrag(position, start, id, screenMatrixContainer, screenMatr
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export function traceTap(position, objects, screenMatrixContainer, screenMatrixZoom) {
|
// export function traceTap(position, objects, screenMatrixContainer, screenMatrixZoom) {
|
||||||
return async (dispatch, getState) => {
|
// return async (dispatch, getState) => {
|
||||||
dispatch({ type: TRACE_TAP });
|
// dispatch({ type: TRACE_TAP });
|
||||||
|
//
|
||||||
const state = getState();
|
// const state = getState();
|
||||||
const id = objects.find(_id => state.sketcher.present.objectsById[_id].type === 'IMAGE_GUIDE');
|
// const id = objects.find(_id => state.sketcher.present.objectsById[_id].type === 'IMAGE_GUIDE');
|
||||||
|
//
|
||||||
if (id) {
|
// if (id) {
|
||||||
const shapeData = state.sketcher.present.objectsById[id];
|
// const shapeData = state.sketcher.present.objectsById[id];
|
||||||
const traceStart = calculatePointInImage(position, shapeData, screenMatrixZoom);
|
// const traceStart = calculatePointInImage(position, shapeData, screenMatrixZoom);
|
||||||
|
//
|
||||||
const { value: traceData } = await dispatch(floodFill(DEFAULT_TRACE_TOLERANCE, shapeData, traceStart));
|
// const { value: traceData } = await dispatch(floodFill(DEFAULT_TRACE_TOLERANCE, shapeData, traceStart));
|
||||||
|
//
|
||||||
return dispatch(traceFloodFill(traceData, shapeData));
|
// return dispatch(traceFloodFill(traceData, shapeData));
|
||||||
} else {
|
// } else {
|
||||||
return dispatch(importImage());
|
// return dispatch(importImage());
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function importImage() {
|
export function importImage() {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
|
@ -502,3 +498,11 @@ export function menuClose(menuValue) {
|
||||||
export function openSketch(data) {
|
export function openSketch(data) {
|
||||||
return { type: OPEN_SKETCH, data };
|
return { type: OPEN_SKETCH, data };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setPreventScroll(preventScroll) {
|
||||||
|
return { type: SET_PREVENT_SCROLL, preventScroll };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setDisableScroll(disableScroll) {
|
||||||
|
return { type: SET_DISABLE_SCROLL, disableScroll };
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,10 @@ import JSONToSketchData from '../shape/JSONToSketchData.js';
|
||||||
import keycode from 'keycode';
|
import keycode from 'keycode';
|
||||||
import bowser from 'bowser';
|
import bowser from 'bowser';
|
||||||
import * as d2Tools from '../constants/d2Tools.js';
|
import * as d2Tools from '../constants/d2Tools.js';
|
||||||
|
import { isLoaded, load } from '../utils/loaded.js';
|
||||||
|
import { setConfig } from '@doodle3d/touch-events';
|
||||||
|
|
||||||
|
setConfig({ DRAG_THRESHOLD: 0 });
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
container: {
|
container: {
|
||||||
|
@ -71,23 +75,45 @@ class App extends React.Component {
|
||||||
selectAll: PropTypes.func.isRequired,
|
selectAll: PropTypes.func.isRequired,
|
||||||
d2ChangeTool: PropTypes.func.isRequired,
|
d2ChangeTool: PropTypes.func.isRequired,
|
||||||
moveSelection: PropTypes.func.isRequired,
|
moveSelection: PropTypes.func.isRequired,
|
||||||
selectedPen: PropTypes.string.isRequired
|
selectedPen: PropTypes.string.isRequired,
|
||||||
|
preventScroll: PropTypes.bool.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.container = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
loaded: isLoaded()
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { container } = this.refs;
|
if (!this.state.loaded) load.then(() => this.setState({ loaded: true }));
|
||||||
|
|
||||||
container.addEventListener('dragover', event => event.preventDefault());
|
if (this.container.current) {
|
||||||
container.addEventListener('drop', this.onDrop);
|
this.container.current.addEventListener('dragover', this.dragOver);
|
||||||
window.addEventListener('keydown', this.onKeyDown);
|
this.container.current.addEventListener('drop', this.onDrop);
|
||||||
|
this.container.current.addEventListener('wheel', this.onWheel);
|
||||||
|
window.addEventListener('keydown', this.onKeyDown);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
const { container } = this.refs;
|
if (this.container.current) {
|
||||||
container.removeEventListener('drop', this.onDrop);
|
|
||||||
window.removeEventListener('keydown', this.onKeyDown);
|
this.container.current.addEventListener('dragover', this.dragOver);
|
||||||
|
this.container.current.removeEventListener('drop', this.onDrop);
|
||||||
|
this.container.current.addEventListener('wheel', this.onWheel);
|
||||||
|
window.removeEventListener('keydown', this.onKeyDown);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dragOver = event => {
|
||||||
|
event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
onDrop = async event => {
|
onDrop = async event => {
|
||||||
const { openSketch, addImage } = this.props;
|
const { openSketch, addImage } = this.props;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -96,12 +122,13 @@ class App extends React.Component {
|
||||||
const extentions = file.name.split('.').pop();
|
const extentions = file.name.split('.').pop();
|
||||||
|
|
||||||
switch (extentions.toUpperCase()) {
|
switch (extentions.toUpperCase()) {
|
||||||
|
case 'DOODLE3D':
|
||||||
case 'D3SKETCH':
|
case 'D3SKETCH':
|
||||||
case 'JSON':
|
case 'JSON':
|
||||||
const url = URL.createObjectURL(file);
|
const url = URL.createObjectURL(file);
|
||||||
const data = await fetch(url).then(result => result.json());
|
const json = await fetch(url).then(result => result.json());
|
||||||
const sketchData = await JSONToSketchData(data);
|
const data = await JSONToSketchData(json);
|
||||||
openSketch({ data: sketchData });
|
openSketch({ data });
|
||||||
break;
|
break;
|
||||||
case 'JPG':
|
case 'JPG':
|
||||||
case 'JPEG':
|
case 'JPEG':
|
||||||
|
@ -145,6 +172,29 @@ class App extends React.Component {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 's': {
|
||||||
|
if (!commandKey) d2ChangeTool(d2Tools.TRANSFORM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'e': {
|
||||||
|
if (!commandKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
d2ChangeTool(d2Tools.ERASER);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'c': {
|
||||||
|
if (!commandKey) d2ChangeTool(d2Tools.CIRCLE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'l': {
|
||||||
|
if (!commandKey) d2ChangeTool(d2Tools.POLYGON);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 't': {
|
case 't': {
|
||||||
if (!commandKey) d2ChangeTool(d2Tools.TEXT);
|
if (!commandKey) d2ChangeTool(d2Tools.TEXT);
|
||||||
break;
|
break;
|
||||||
|
@ -176,16 +226,27 @@ class App extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onWheel = (event) => {
|
||||||
|
const { preventScroll } = this.props;
|
||||||
|
if (preventScroll) event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
dragover = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { classes, undo, redo } = this.props;
|
const { classes, undo, redo } = this.props;
|
||||||
|
const { loaded } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref="container" className={classes.container}>
|
<div ref={this.container} className={classes.container}>
|
||||||
<InlineIconsLoader />
|
<InlineIconsLoader />
|
||||||
<div className={classes.appContainer}>
|
{loaded && <div className={classes.appContainer}>
|
||||||
<D2Panel />
|
<D2Panel />
|
||||||
<div className={classes.vLine} />
|
<div className={classes.vLine} />
|
||||||
<D3Panel />
|
<D3Panel />
|
||||||
</div>
|
</div>}
|
||||||
<Logo />
|
<Logo />
|
||||||
<div className={classes.undoMenu}>
|
<div className={classes.undoMenu}>
|
||||||
<Button onSelect={undo} className={classes.undo} />
|
<Button onSelect={undo} className={classes.undo} />
|
||||||
|
@ -198,6 +259,7 @@ class App extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default injectSheet(styles)(connect(state => ({
|
export default injectSheet(styles)(connect(state => ({
|
||||||
|
preventScroll: state.sketcher.present.preventScroll,
|
||||||
selectedPen: state.sketcher.present.menus['pen-tools'].selected
|
selectedPen: state.sketcher.present.menus['pen-tools'].selected
|
||||||
}), {
|
}), {
|
||||||
undo: actions.undo.undo,
|
undo: actions.undo.undo,
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'proptypes';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { isWebUri } from 'valid-url';
|
|
||||||
import PouchDB from 'pouchdb';
|
|
||||||
// import createDebug from 'debug';
|
|
||||||
// const debug = createDebug('d3d:FileThumb');
|
|
||||||
|
|
||||||
class AuthImage extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
dispatch: PropTypes.func,
|
|
||||||
src: PropTypes.string.isRequired,
|
|
||||||
token: PropTypes.string,
|
|
||||||
password: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
src: null
|
|
||||||
};
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
const { src, token, password } = this.props;
|
|
||||||
|
|
||||||
if (src.startsWith('/') || src.startsWith('./')) {
|
|
||||||
this.setState({ src });
|
|
||||||
} else if (isWebUri(src)) {
|
|
||||||
if (token && password) {
|
|
||||||
const filteredSrc = src.replace(/:\/\/.+?@/, '://');
|
|
||||||
const headers = {
|
|
||||||
Authorization: `Basic ${btoa(`${token}:${password}`)}`
|
|
||||||
};
|
|
||||||
fetch(filteredSrc, { headers })
|
|
||||||
.then(response => response.blob())
|
|
||||||
.then(blob => this.setState({ src: URL.createObjectURL(blob) }));
|
|
||||||
} else {
|
|
||||||
this.setState({ src });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const [dbName, docName, attachmentName] = src.split('/');
|
|
||||||
const db = new PouchDB(dbName);
|
|
||||||
db.getAttachment(docName, attachmentName).then((blob) => {
|
|
||||||
this.setState({ src: URL.createObjectURL(blob) });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
URL.revokeObjectURL(this.state.src);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
// filter props before passing them to img element
|
|
||||||
const props = { ...this.props };
|
|
||||||
delete props.dispatch;
|
|
||||||
delete props.token;
|
|
||||||
delete props.password;
|
|
||||||
delete props.src;
|
|
||||||
return (<img { ...props } src={this.state.src} />);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(state => ({
|
|
||||||
token: state.user.session.token,
|
|
||||||
password: state.user.session.password
|
|
||||||
}))(AuthImage);
|
|
|
@ -37,7 +37,7 @@ export default class Button extends React.Component {
|
||||||
if (className) combinedClassName += ` ${className}`;
|
if (className) combinedClassName += ` ${className}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={id} className={combinedClassName} onTouchTap={this.onClick}>
|
<div id={id} className={combinedClassName} onClick={this.onClick}>
|
||||||
{svg && <svg>
|
{svg && <svg>
|
||||||
<use xlinkHref={svg}/>
|
<use xlinkHref={svg}/>
|
||||||
</svg>}
|
</svg>}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import injectSheet from 'react-jss';
|
import injectSheet from 'react-jss';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as CAL from 'cal';
|
import * as CAL from '@doodle3d/cal';
|
||||||
import * as toolNames from '../constants/d2Tools';
|
import * as toolNames from '../constants/d2Tools';
|
||||||
import { PIPETTE } from '../constants/contextTools.js';
|
import { PIPETTE } from '../constants/contextTools.js';
|
||||||
import { CANVAS_SIZE } from '../constants/d2Constants';
|
import { CANVAS_SIZE } from '../constants/d2Constants';
|
||||||
|
@ -22,7 +22,7 @@ import { PIXEL_RATIO } from '../constants/general';
|
||||||
import ShapesManager from '../d2/ShapesManager.js';
|
import ShapesManager from '../d2/ShapesManager.js';
|
||||||
import EventGroup from '../d2/EventGroup.js';
|
import EventGroup from '../d2/EventGroup.js';
|
||||||
import ReactResizeDetector from 'react-resize-detector';
|
import ReactResizeDetector from 'react-resize-detector';
|
||||||
import { load as loadPattern } from '../d2/Shape.js';
|
import InputText from './InputText.js';
|
||||||
// import createDebug from 'debug';
|
// import createDebug from 'debug';
|
||||||
// const debug = createDebug('d3d:d2');
|
// const debug = createDebug('d3d:d2');
|
||||||
|
|
||||||
|
@ -63,9 +63,17 @@ class D2Panel extends React.Component {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
classes: PropTypes.objectOf(PropTypes.string)
|
classes: PropTypes.objectOf(PropTypes.string)
|
||||||
};
|
};
|
||||||
|
state = {
|
||||||
|
screenMatrix: new CAL.Matrix()
|
||||||
|
};
|
||||||
activeNeedRender = false;
|
activeNeedRender = false;
|
||||||
inactiveNeedRender = false;
|
inactiveNeedRender = false;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.canvasContainer = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
// Scene space
|
// Scene space
|
||||||
this.sceneActive = new EventGroup({
|
this.sceneActive = new EventGroup({
|
||||||
|
@ -89,22 +97,17 @@ class D2Panel extends React.Component {
|
||||||
this.objectContainerInactive.add(new Grid(new CAL.Color(0xdddddd)));
|
this.objectContainerInactive.add(new Grid(new CAL.Color(0xdddddd)));
|
||||||
|
|
||||||
this.shapesManager = new ShapesManager(this.objectContainerActive, this.objectContainerInactive);
|
this.shapesManager = new ShapesManager(this.objectContainerActive, this.objectContainerInactive);
|
||||||
loadPattern.then(() => {
|
|
||||||
this.activeNeedRender = true;
|
|
||||||
this.inactiveNeedRender = true;
|
|
||||||
this.renderRequest();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.DOM = null;
|
this.DOM = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { canvasContainer } = this.refs;
|
if (this.canvasContainer.current) {
|
||||||
this.container = canvasContainer;
|
this.container = this.canvasContainer.current;
|
||||||
|
|
||||||
this.container.appendChild(this.sceneInactive.image);
|
|
||||||
this.container.appendChild(this.sceneActive.image);
|
|
||||||
|
|
||||||
|
this.container.appendChild(this.sceneInactive.image);
|
||||||
|
this.container.appendChild(this.sceneActive.image);
|
||||||
|
}
|
||||||
this.sceneActive.onClick = (event) => event.stopPropagation();
|
this.sceneActive.onClick = (event) => event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +120,7 @@ class D2Panel extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
switchTool(toolName) {
|
switchTool(toolName) {
|
||||||
if (this.state && toolName === this.state.d2.tool) return;
|
if (this.state.state && toolName === this.state.state.d2.tool) return;
|
||||||
// cleanup & remove previous tool
|
// cleanup & remove previous tool
|
||||||
if (this.tool) {
|
if (this.tool) {
|
||||||
this.tool.destroy();
|
this.tool.destroy();
|
||||||
|
@ -135,18 +138,18 @@ class D2Panel extends React.Component {
|
||||||
this.objectContainerActive.add(this.tool);
|
this.objectContainerActive.add(this.tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(newState) {
|
update(state) {
|
||||||
if (this.state === newState) return;
|
if (this.state.state === state) return;
|
||||||
|
|
||||||
this.updateTool(newState);
|
this.updateTool(state);
|
||||||
|
|
||||||
const shapesNeedRender = this.shapesManager.update(newState);
|
const shapesNeedRender = this.shapesManager.update(state);
|
||||||
if (shapesNeedRender.active) this.activeNeedRender = true;
|
if (shapesNeedRender.active) this.activeNeedRender = true;
|
||||||
if (shapesNeedRender.inactive) this.inactiveNeedRender = true;
|
if (shapesNeedRender.inactive) this.inactiveNeedRender = true;
|
||||||
|
|
||||||
// Update Objects Container Space with zoom & panning
|
// Update Objects Container Space with zoom & panning
|
||||||
const newCanvasMatrix = newState.d2.canvasMatrix;
|
const newCanvasMatrix = state.d2.canvasMatrix;
|
||||||
if (this.state && newCanvasMatrix !== this.state.d2.canvasMatrix) {
|
if (this.state.state && newCanvasMatrix !== this.state.state.d2.canvasMatrix) {
|
||||||
this.objectContainerActive.copyMatrix(newCanvasMatrix);
|
this.objectContainerActive.copyMatrix(newCanvasMatrix);
|
||||||
this.objectContainerInactive.copyMatrix(newCanvasMatrix);
|
this.objectContainerInactive.copyMatrix(newCanvasMatrix);
|
||||||
|
|
||||||
|
@ -154,9 +157,9 @@ class D2Panel extends React.Component {
|
||||||
this.inactiveNeedRender = true;
|
this.inactiveNeedRender = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selection = (this.state) ? this.state.selection : null;
|
const selection = (this.state.state) ? this.state.state.selection : null;
|
||||||
const newSelection = newState.selection;
|
const newSelection = state.selection;
|
||||||
if (!this.state || newSelection !== selection) {
|
if (!this.state.state || newSelection !== selection) {
|
||||||
const newSelectedObjects = newSelection.objects;
|
const newSelectedObjects = newSelection.objects;
|
||||||
if (!selection || selection.objects !== newSelectedObjects) {
|
if (!selection || selection.objects !== newSelectedObjects) {
|
||||||
const selected = newSelectedObjects.map((object) => object.id);
|
const selected = newSelectedObjects.map((object) => object.id);
|
||||||
|
@ -167,25 +170,29 @@ class D2Panel extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const dragSelect = (this.state) ? this.state.d2.transform.dragSelect : null;
|
const dragSelect = (this.state.state) ? this.state.state.d2.transform.dragSelect : null;
|
||||||
const newDragSelect = newState.d2.transform.dragSelect;
|
const newDragSelect = state.d2.transform.dragSelect;
|
||||||
if (!dragSelect || dragSelect !== newDragSelect) {
|
if (!dragSelect || dragSelect !== newDragSelect) {
|
||||||
this.activeNeedRender = true;
|
this.activeNeedRender = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state = newState;
|
this.setState({ state });
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeHandler = (width, height) => {
|
resizeHandler = (width, height) => {
|
||||||
this.sceneActive.setSize(width, height, PIXEL_RATIO);
|
this.sceneActive.setSize(width, height, PIXEL_RATIO);
|
||||||
this.sceneInactive.setSize(width, height, PIXEL_RATIO);
|
this.sceneInactive.setSize(width, height, PIXEL_RATIO);
|
||||||
|
|
||||||
this.sceneInactive.x = this.sceneActive.x = Math.round(width / 2 * PIXEL_RATIO);
|
const x = Math.round(width / 2 * PIXEL_RATIO);
|
||||||
this.sceneInactive.y = this.sceneActive.y = Math.round(height / 2 * PIXEL_RATIO);
|
const y = Math.round(height / 2 * PIXEL_RATIO);
|
||||||
|
|
||||||
const scale = Math.min(width * PIXEL_RATIO / CANVAS_WIDTH, height * PIXEL_RATIO / CANVAS_HEIGHT);
|
const scale = Math.min(width * PIXEL_RATIO / CANVAS_WIDTH, height * PIXEL_RATIO / CANVAS_HEIGHT);
|
||||||
|
|
||||||
this.sceneInactive.scale = this.sceneActive.scale = scale;
|
const screenMatrix = new CAL.Matrix({ sx: scale, sy: scale, x, y });
|
||||||
|
|
||||||
|
this.sceneInactive.copyMatrix(screenMatrix);
|
||||||
|
this.sceneActive.copyMatrix(screenMatrix);
|
||||||
|
|
||||||
|
this.setState({ screenMatrix });
|
||||||
|
|
||||||
this.inactiveNeedRender = this.activeNeedRender = true;
|
this.inactiveNeedRender = this.activeNeedRender = true;
|
||||||
this.renderRequest();
|
this.renderRequest();
|
||||||
|
@ -210,12 +217,14 @@ class D2Panel extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
// debug('this.props.state: ', this.props.state);
|
// debug('this.props.state: ', this.props.state);
|
||||||
const { state, classes } = this.props;
|
const { state, classes } = this.props;
|
||||||
|
const { screenMatrix } = this.state;
|
||||||
this.update(state);
|
this.update(state);
|
||||||
this.renderCanvas();
|
this.renderCanvas();
|
||||||
return (
|
return (
|
||||||
<div className={classes.container}>
|
<div className={classes.container}>
|
||||||
<ReactResizeDetector handleWidth handleHeight onResize={this.resizeHandler} />
|
<ReactResizeDetector handleWidth handleHeight onResize={this.resizeHandler} />
|
||||||
<div className={classes.canvasContainer} ref="canvasContainer" />
|
<div className={classes.canvasContainer} ref={this.canvasContainer} />
|
||||||
|
<InputText screenMatrix={screenMatrix} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,10 @@ import TwistTransformer from '../d3/transformers/TwistTransformer.js';
|
||||||
import SculptTransformer from '../d3/transformers/SculptTransformer.js';
|
import SculptTransformer from '../d3/transformers/SculptTransformer.js';
|
||||||
import StampTransformer from '../d3/transformers/StampTransformer.js';
|
import StampTransformer from '../d3/transformers/StampTransformer.js';
|
||||||
import SelectionBox from '../d3/SelectionBox.js';
|
import SelectionBox from '../d3/SelectionBox.js';
|
||||||
import RenderChain from '../d3/RenderChain';
|
import RenderChain, { TOONSHADER_OUTLINE, TOONSHADER } from '../d3/RenderChain';
|
||||||
import BaseTransformer from '../d3/transformers/BaseTransformer.js';
|
import BaseTransformer from '../d3/transformers/BaseTransformer.js';
|
||||||
import Camera from '../d3/Camera.js';
|
import Camera from '../d3/Camera.js';
|
||||||
import ReactResizeDetector from 'react-resize-detector';
|
import ReactResizeDetector from 'react-resize-detector';
|
||||||
import { load as loadMatcapMaterial } from '../d3/MatcapMaterial.js';
|
|
||||||
// import createDebug from 'debug';
|
// import createDebug from 'debug';
|
||||||
// const debug = createDebug('d3d:d3');
|
// const debug = createDebug('d3d:d3');
|
||||||
|
|
||||||
|
@ -51,6 +50,10 @@ const styles = {
|
||||||
};
|
};
|
||||||
|
|
||||||
class D3Panel extends React.Component {
|
class D3Panel extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.canvasContainer = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
state: PropTypes.object.isRequired,
|
state: PropTypes.object.isRequired,
|
||||||
|
@ -62,23 +65,23 @@ class D3Panel extends React.Component {
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.createScene();
|
this.createScene();
|
||||||
|
|
||||||
const toonShader = hasExtensionsFor.toonShaderPreview;
|
const shader = hasExtensionsFor.toonShaderPreview ? TOONSHADER_OUTLINE : TOONSHADER;
|
||||||
this.renderChain = new RenderChain(this.renderer, this.scene, this.camera, toonShader, {
|
this.renderChain = new RenderChain(this.renderer, this.scene, this.camera, shader, {
|
||||||
UI: this.UIContainer,
|
UI: this.UIContainer,
|
||||||
shapes: this.shapesManager,
|
shapes: this.shapesManager,
|
||||||
boundingBox: this.selectionBox,
|
boundingBox: this.selectionBox,
|
||||||
plane: this.plane
|
plane: this.plane
|
||||||
});
|
});
|
||||||
|
|
||||||
loadMatcapMaterial.then(this.renderRequest);
|
|
||||||
this.DOM = null;
|
this.DOM = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.container = this.refs.canvasContainer;
|
if (this.canvasContainer.current) {
|
||||||
this.container.appendChild(this.renderer.domElement);
|
this.container = this.canvasContainer.current;
|
||||||
|
this.container.appendChild(this.renderer.domElement);
|
||||||
this.renderScene(); // immidiatly render because when THREE.JS inits, a black screen is generated
|
this.renderScene(); // immidiatly render because when THREE.JS inits, a black screen is generated
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -223,7 +226,7 @@ class D3Panel extends React.Component {
|
||||||
return (
|
return (
|
||||||
<div className={classes.container}>
|
<div className={classes.container}>
|
||||||
<ReactResizeDetector handleWidth handleHeight onResize={this.resizeHandler} />
|
<ReactResizeDetector handleWidth handleHeight onResize={this.resizeHandler} />
|
||||||
<div className={classes.canvasContainer} ref="canvasContainer"/>
|
<div className={classes.canvasContainer} ref={this.canvasContainer}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import createScene from '../d3/createScene.js';
|
||||||
import injectSheet from 'react-jss';
|
import injectSheet from 'react-jss';
|
||||||
import ReactResizeDetector from 'react-resize-detector';
|
import ReactResizeDetector from 'react-resize-detector';
|
||||||
import requestAnimationFrame from 'raf';
|
import requestAnimationFrame from 'raf';
|
||||||
import { load as loadMatcapMaterial } from '../d3/MatcapMaterial.js';
|
|
||||||
import createRAFOnce from '../utils/rafOnce.js';
|
import createRAFOnce from '../utils/rafOnce.js';
|
||||||
|
|
||||||
const rafOnce = createRAFOnce();
|
const rafOnce = createRAFOnce();
|
||||||
|
@ -29,6 +28,11 @@ class DoodlePreview extends React.Component {
|
||||||
pixelRatio: 1
|
pixelRatio: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.canvas = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
classes: PropTypes.objectOf(PropTypes.string),
|
classes: PropTypes.objectOf(PropTypes.string),
|
||||||
width: PropTypes.number.isRequired,
|
width: PropTypes.number.isRequired,
|
||||||
|
@ -37,7 +41,7 @@ class DoodlePreview extends React.Component {
|
||||||
sketchData: PropTypes.object, // TODO
|
sketchData: PropTypes.object, // TODO
|
||||||
docData: PropTypes.shape({
|
docData: PropTypes.shape({
|
||||||
appVersion: PropTypes.string,
|
appVersion: PropTypes.string,
|
||||||
data: PropTypes.string
|
data: PropTypes.oneOf([PropTypes.string, PropTypes.object])
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,19 +52,15 @@ class DoodlePreview extends React.Component {
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
let { docData, sketchData } = this.props;
|
let { docData, sketchData } = this.props;
|
||||||
|
|
||||||
if (docData) sketchData = await JSONToSketchData(this.props.docData);
|
if (docData) sketchData = await JSONToSketchData(docData);
|
||||||
|
|
||||||
const { canvas } = this.refs;
|
const sceneData = await createSceneData(sketchData);
|
||||||
|
|
||||||
const sceneData = createSceneData(sketchData);
|
const scene = createScene(sceneData, this.canvas.current);
|
||||||
|
|
||||||
const scene = createScene(sceneData, canvas);
|
|
||||||
this.setState(scene);
|
this.setState(scene);
|
||||||
|
|
||||||
this.editorControls = new THREE.EditorControls(scene.camera, canvas);
|
this.editorControls = new THREE.EditorControls(scene.camera, this.canvas.current);
|
||||||
this.editorControls.addEventListener('change', () => rafOnce(scene.render));
|
this.editorControls.addEventListener('change', () => rafOnce(scene.render));
|
||||||
|
|
||||||
loadMatcapMaterial.then(scene.render);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -81,7 +81,7 @@ class DoodlePreview extends React.Component {
|
||||||
return (
|
return (
|
||||||
<div className={classes.container}>
|
<div className={classes.container}>
|
||||||
<ReactResizeDetector handleWidth handleHeight onResize={this.resizeHandler} />
|
<ReactResizeDetector handleWidth handleHeight onResize={this.resizeHandler} />
|
||||||
<canvas className={classes.canvas} ref="canvas" />
|
<canvas className={classes.canvas} ref={this.canvas} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
106
src/components/InputText.js
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import React from 'react';
|
||||||
|
import injectSheet from 'react-jss';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import * as actions from '../actions/index.js';
|
||||||
|
import * as CAL from '@doodle3d/cal';
|
||||||
|
import { TEXT_TOOL_FONT_SIZE } from '../constants/d2Constants.js';
|
||||||
|
|
||||||
|
const CONTEXT = document.createElement('canvas').getContext('2d');
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
textInputContainer: {
|
||||||
|
position: 'absolute',
|
||||||
|
display: 'flex'
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
position: 'absolute',
|
||||||
|
fontSize: `${TEXT_TOOL_FONT_SIZE}px`,
|
||||||
|
background: 'transparent',
|
||||||
|
border: 'none',
|
||||||
|
color: 'black',
|
||||||
|
textFillColor: 'transparent',
|
||||||
|
outline: 'none'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class InputText extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.text = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
state: PropTypes.object.isRequired,
|
||||||
|
classes: PropTypes.objectOf(PropTypes.string),
|
||||||
|
changeText: PropTypes.func.isRequired,
|
||||||
|
screenMatrix: PropTypes.instanceOf(CAL.Matrix).isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
onInputChange = () => {
|
||||||
|
const shapeData = this.getShapeData();
|
||||||
|
if (!shapeData) return;
|
||||||
|
|
||||||
|
const { changeText } = this.props;
|
||||||
|
const text = this.text.current.value;
|
||||||
|
|
||||||
|
changeText(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
getShapeData = () => {
|
||||||
|
const { state } = this.props;
|
||||||
|
if (!state.d2.activeShape) return null;
|
||||||
|
const shapeData = state.objectsById[state.d2.activeShape];
|
||||||
|
if (shapeData.type !== 'TEXT') return null;
|
||||||
|
return shapeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUpdate() {
|
||||||
|
if (this.text.current) this.text.current.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { classes, state, screenMatrix } = this.props;
|
||||||
|
const shapeData = this.getShapeData();
|
||||||
|
|
||||||
|
if (shapeData) {
|
||||||
|
const { _matrix: m } = shapeData.transform
|
||||||
|
.multiplyMatrix(state.d2.canvasMatrix)
|
||||||
|
.multiplyMatrix(screenMatrix);
|
||||||
|
|
||||||
|
const { family, style, weight, text } = shapeData.text;
|
||||||
|
|
||||||
|
CONTEXT.font = `${style} normal ${weight} ${TEXT_TOOL_FONT_SIZE}px ${family}`;
|
||||||
|
const width = Math.max(10, CONTEXT.measureText(shapeData.text.text).width);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classes.textInputContainer}
|
||||||
|
style={{ transform: `matrix(${m[0]}, ${m[3]}, ${m[1]}, ${m[4]}, ${m[2]}, ${m[5]})` }}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
className={classes.textInput}
|
||||||
|
style={{
|
||||||
|
fontFamily: family,
|
||||||
|
fontStyle: style,
|
||||||
|
fontWeight: weight,
|
||||||
|
width: `${width}px`
|
||||||
|
}}
|
||||||
|
value={text}
|
||||||
|
ref={this.text}
|
||||||
|
spellCheck="false"
|
||||||
|
autoFocus
|
||||||
|
onChange={this.onInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default injectSheet(styles)(connect(state => ({
|
||||||
|
state: state.sketcher.present
|
||||||
|
}), {
|
||||||
|
changeText: actions.d2textInputChange
|
||||||
|
})(InputText));
|
|
@ -8,11 +8,12 @@ const styles = {
|
||||||
top: '0px',
|
top: '0px',
|
||||||
right: '15%',
|
right: '15%',
|
||||||
width: '19%',
|
width: '19%',
|
||||||
|
backgroundImage: `url("${doodleSignImageURL}")`,
|
||||||
|
maxWidth: '290px',
|
||||||
|
height: '140px',
|
||||||
|
backgroundSize: '100%',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
pointerEvents: 'none', // enable clicking through logo
|
pointerEvents: 'none', // enable clicking through logo
|
||||||
'& img': {
|
|
||||||
width: '100%',
|
|
||||||
maxWidth: '290px'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
'@media (max-width: 555px)': {
|
'@media (max-width: 555px)': {
|
||||||
container: {
|
container: {
|
||||||
|
@ -22,8 +23,6 @@ const styles = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Logo = ({ classes }) => (
|
const Logo = ({ classes }) => (
|
||||||
<div className={classes.container}>
|
<div className={classes.container} />
|
||||||
<img src={doodleSignImageURL} />
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
export default injectSheet(styles)(Logo);
|
export default injectSheet(styles)(Logo);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import initialMenuStructure from '../constants/menu.js';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
// import createDebug from 'debug';
|
// import createDebug from 'debug';
|
||||||
// const debug = createDebug('d3d:menu');
|
// const debug = createDebug('d3d:menu');
|
||||||
|
|
||||||
|
@ -14,7 +12,7 @@ class Menu extends React.Component {
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
stateMenu: PropTypes.object
|
id: PropTypes.string
|
||||||
};
|
};
|
||||||
onSelect = (event) => {
|
onSelect = (event) => {
|
||||||
const { onSelect, value } = this.props;
|
const { onSelect, value } = this.props;
|
||||||
|
@ -23,7 +21,7 @@ class Menu extends React.Component {
|
||||||
if (onSelect) onSelect({ ...event, menuValue });
|
if (onSelect) onSelect({ ...event, menuValue });
|
||||||
};
|
};
|
||||||
render() {
|
render() {
|
||||||
const { className = '', id, selectedValue, onOpen, onClose, value, children, stateMenu } = this.props;
|
const { className = '', id, selectedValue, onOpen, onClose, children } = this.props;
|
||||||
return (
|
return (
|
||||||
<ul id={id} className={`menu ${className}`}>
|
<ul id={id} className={`menu ${className}`}>
|
||||||
{React.Children.map(children, (child) => {
|
{React.Children.map(children, (child) => {
|
||||||
|
@ -39,6 +37,4 @@ class Menu extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(state => ({
|
export default Menu;
|
||||||
stateMenu: state.sketcher.present.menus
|
|
||||||
}))(Menu);
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ import * as contextTools from '../constants/contextTools.js';
|
||||||
import * as d2Tools from '../constants/d2Tools.js';
|
import * as d2Tools from '../constants/d2Tools.js';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import injectSheet from 'react-jss';
|
import injectSheet from 'react-jss';
|
||||||
|
import { FONT_TOOLS } from '../constants/contextTools.js';
|
||||||
|
import { FONT_FACE } from '../constants/general.js';
|
||||||
// TODO move this to jss instead of css
|
// TODO move this to jss instead of css
|
||||||
import '../../styles/styles.css';
|
import '../../styles/styles.css';
|
||||||
// import createDebug from 'debug';
|
// import createDebug from 'debug';
|
||||||
|
@ -120,6 +122,7 @@ function renderChildren(children) {
|
||||||
|
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
let component;
|
let component;
|
||||||
|
|
||||||
if (child.children.length > 0) {
|
if (child.children.length > 0) {
|
||||||
component = (
|
component = (
|
||||||
<SubMenu
|
<SubMenu
|
||||||
|
@ -135,6 +138,18 @@ function renderChildren(children) {
|
||||||
{renderChildren(child.children)}
|
{renderChildren(child.children)}
|
||||||
</SubMenu>
|
</SubMenu>
|
||||||
);
|
);
|
||||||
|
} else if (FONT_TOOLS.includes(child.value)) {
|
||||||
|
component = (
|
||||||
|
<MenuItem
|
||||||
|
id={child.value}
|
||||||
|
value={child.value}
|
||||||
|
key={child.value}
|
||||||
|
svg={child.svg}
|
||||||
|
disabled={child.disabled}
|
||||||
|
>
|
||||||
|
<p style={{ fontFamily: FONT_FACE[child.value] }}>{FONT_FACE[child.value]}</p>
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
component = (
|
component = (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
|
@ -151,7 +166,7 @@ function renderChildren(children) {
|
||||||
return components;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, menus) {
|
function filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText, menus) {
|
||||||
const showUnion = activeTool === d2Tools.TRANSFORM && numFilledObjects && numSelectedObjects >= 2;
|
const showUnion = activeTool === d2Tools.TRANSFORM && numFilledObjects && numSelectedObjects >= 2;
|
||||||
const showIntersect = activeTool === d2Tools.TRANSFORM && numSelectedObjects >= 1;
|
const showIntersect = activeTool === d2Tools.TRANSFORM && numSelectedObjects >= 1;
|
||||||
return {
|
return {
|
||||||
|
@ -191,11 +206,14 @@ function filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidO
|
||||||
case contextTools.HOLE_TOGGLE:
|
case contextTools.HOLE_TOGGLE:
|
||||||
return numSelectedObjects > 0;
|
return numSelectedObjects > 0;
|
||||||
|
|
||||||
|
case contextTools.FONT:
|
||||||
|
return selectionIncludesText || activeTool === d2Tools.TEXT;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}).map(child => {
|
}).map(child => {
|
||||||
return filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, child);
|
return filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText, child);
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -216,12 +234,19 @@ const getMenus = createSelector([
|
||||||
state => state.sketcher.present.menus,
|
state => state.sketcher.present.menus,
|
||||||
state => state.sketcher.present.d2.tool,
|
state => state.sketcher.present.d2.tool,
|
||||||
state => state.sketcher.present.selection.objects.length,
|
state => state.sketcher.present.selection.objects.length,
|
||||||
state => state.sketcher.present.selection.objects.filter(({ id }) => state.sketcher.present.objectsById[id].fill).length,
|
state => state.sketcher.present.selection.objects.filter(({ id }) => {
|
||||||
state => state.sketcher.present.selection.objects.filter(({ id }) => state.sketcher.present.objectsById[id].solid).length
|
return state.sketcher.present.objectsById[id].fill;
|
||||||
], (menus, activeTool, numSelectedObjects, numFilledObjects, numSolidObjects) => ({
|
}).length,
|
||||||
toolbar2d: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, nestChildren(menus, menus[TOOLBAR2D])),
|
state => state.sketcher.present.selection.objects.filter(({ id }) => {
|
||||||
toolbar3d: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, nestChildren(menus, menus[TOOLBAR3D])),
|
return state.sketcher.present.objectsById[id].solid;
|
||||||
context: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, nestChildren(menus, menus[CONTEXT]))
|
}).length,
|
||||||
|
state => state.sketcher.present.selection.objects.some(({ id }) => {
|
||||||
|
return state.sketcher.present.objectsById[id].type === 'TEXT';
|
||||||
|
})
|
||||||
|
], (menus, ...args) => ({
|
||||||
|
toolbar2d: filterMenus(...args, nestChildren(menus, menus[TOOLBAR2D])),
|
||||||
|
toolbar3d: filterMenus(...args, nestChildren(menus, menus[TOOLBAR3D])),
|
||||||
|
context: filterMenus(...args, nestChildren(menus, menus[CONTEXT]))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default injectSheet(styles)(connect(getMenus)(SketcherToolbars));
|
export default injectSheet(styles)(connect(getMenus)(SketcherToolbars));
|
||||||
|
|
|
@ -8,6 +8,11 @@ import { hexToStyle } from '../utils/colorUtils.js';
|
||||||
// const debug = createDebug('d3d:ui:submenu');
|
// const debug = createDebug('d3d:ui:submenu');
|
||||||
|
|
||||||
class SubMenu extends React.Component {
|
class SubMenu extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.li = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onSelect: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
onOpen: PropTypes.func,
|
onOpen: PropTypes.func,
|
||||||
|
@ -61,13 +66,15 @@ class SubMenu extends React.Component {
|
||||||
const { open, onClose, value } = this.props;
|
const { open, onClose, value } = this.props;
|
||||||
if (open && onClose) {
|
if (open && onClose) {
|
||||||
// was click on this submenu?
|
// was click on this submenu?
|
||||||
const onSubmenu = this.refs.li.contains(event.target);
|
const onSubmenu = this.li.current.contains(event.target);
|
||||||
// debug(`onDocumentClick ${event.type} ${onSubmenu ? 'onSubmenu' : ''}`);
|
// debug(`onDocumentClick ${event.type} ${onSubmenu ? 'onSubmenu' : ''}`);
|
||||||
if (!onSubmenu) onClose({ menuValue: value });
|
if (!onSubmenu) onClose({ menuValue: value });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
render() {
|
render() {
|
||||||
const { id, value, selected, open, selectedValue, children, svg, toggleBehavior, color, solid } = this.props;
|
const {
|
||||||
|
id, value, selected, open, selectedValue, children, svg, toggleBehavior, color, solid
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
const style = {};
|
const style = {};
|
||||||
if (id === 'color-picker-tool') {
|
if (id === 'color-picker-tool') {
|
||||||
|
@ -77,7 +84,7 @@ class SubMenu extends React.Component {
|
||||||
let className = 'submenu';
|
let className = 'submenu';
|
||||||
if (open) className += ' open';
|
if (open) className += ' open';
|
||||||
return (
|
return (
|
||||||
<li id={id} className={className} ref="li" style={style}>
|
<li id={id} className={className} ref={this.li} style={style}>
|
||||||
<Button
|
<Button
|
||||||
id={`${selectedValue}-menu`}
|
id={`${selectedValue}-menu`}
|
||||||
value={selectedValue}
|
value={selectedValue}
|
||||||
|
|
|
@ -8,6 +8,7 @@ export const HOLE_TOGGLE = 'hole-toggle-tool';
|
||||||
export const ALIGN = 'align-tool';
|
export const ALIGN = 'align-tool';
|
||||||
export const UNION = 'union-tool';
|
export const UNION = 'union-tool';
|
||||||
export const INTERSECT = 'intersect-tool';
|
export const INTERSECT = 'intersect-tool';
|
||||||
|
export const FONT = 'font-tool';
|
||||||
|
|
||||||
export const LIGHT_BLUE_A = 'color-light-blue-a';
|
export const LIGHT_BLUE_A = 'color-light-blue-a';
|
||||||
export const LIGHT_BLUE_B = 'color-light-blue-b';
|
export const LIGHT_BLUE_B = 'color-light-blue-b';
|
||||||
|
@ -79,3 +80,23 @@ export const ALIGN_TOOLS = [
|
||||||
ALIGN_VERTICAL,
|
ALIGN_VERTICAL,
|
||||||
ALIGN_BOTTOM
|
ALIGN_BOTTOM
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const OSWALD = 'oswald';
|
||||||
|
export const RANGA = 'ranga';
|
||||||
|
export const JOTI_ONE = 'joti-one';
|
||||||
|
export const BELLEFAIR = 'bellefair';
|
||||||
|
export const LOBSTER = 'lobster';
|
||||||
|
export const ABRIL_FATFACE = 'abril-fatface';
|
||||||
|
export const PLAY = 'play';
|
||||||
|
export const FASCINATE = 'fascinate';
|
||||||
|
|
||||||
|
export const FONT_TOOLS = [
|
||||||
|
OSWALD,
|
||||||
|
RANGA,
|
||||||
|
JOTI_ONE,
|
||||||
|
BELLEFAIR,
|
||||||
|
LOBSTER,
|
||||||
|
ABRIL_FATFACE,
|
||||||
|
PLAY,
|
||||||
|
FASCINATE
|
||||||
|
];
|
||||||
|
|
|
@ -21,13 +21,6 @@ export const SNAPPING_DISTANCE = 7.0;
|
||||||
export const MAX_TRACE_TOLERANCE = 256;
|
export const MAX_TRACE_TOLERANCE = 256;
|
||||||
export const SELECTION_VIEW_MIN_SCALE = 50;
|
export const SELECTION_VIEW_MIN_SCALE = 50;
|
||||||
export const SELECTION_VIEW_MIN_AXIS_SCALE = 80;
|
export const SELECTION_VIEW_MIN_AXIS_SCALE = 80;
|
||||||
export const POTRACE_OPTIONS = {
|
|
||||||
turnpolicy: 'black',
|
|
||||||
turdsize: 5.0,
|
|
||||||
optcurve: false,
|
|
||||||
alphamax: 0.5,
|
|
||||||
opttolerance: 0.2
|
|
||||||
};
|
|
||||||
export const ERASER_SIZES = {
|
export const ERASER_SIZES = {
|
||||||
[contextTools.ERASER_SIZE_SMALL]: 10,
|
[contextTools.ERASER_SIZE_SMALL]: 10,
|
||||||
[contextTools.ERASER_SIZE_MEDIUM]: 30,
|
[contextTools.ERASER_SIZE_MEDIUM]: 30,
|
||||||
|
@ -41,3 +34,4 @@ export const BRUSH_SIZES = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CLIPPER_PRECISION = 100; // accurate to the hundredth
|
export const CLIPPER_PRECISION = 100; // accurate to the hundredth
|
||||||
|
export const TEXT_TOOL_FONT_SIZE = 40;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as contextTools from './contextTools.js';
|
import * as contextTools from './contextTools.js';
|
||||||
|
|
||||||
export const VERSION = '0.17.4';
|
export const VERSION = '0.23.0';
|
||||||
export const SHAPE_CACHE_LIMIT = 50;
|
export const SHAPE_CACHE_LIMIT = 50;
|
||||||
export const PIXEL_RATIO = 1.0;
|
export const PIXEL_RATIO = 1.0;
|
||||||
|
|
||||||
|
@ -37,3 +37,14 @@ export const COLOR_STRING_TO_HEX = {
|
||||||
[contextTools.BLACK_B]: 0xAAAAAA,
|
[contextTools.BLACK_B]: 0xAAAAAA,
|
||||||
[contextTools.BLACK_C]: 0x444444
|
[contextTools.BLACK_C]: 0x444444
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const FONT_FACE = {
|
||||||
|
[contextTools.OSWALD]: 'Oswald',
|
||||||
|
[contextTools.RANGA]: 'Ranga',
|
||||||
|
[contextTools.JOTI_ONE]: 'Joti One',
|
||||||
|
[contextTools.BELLEFAIR]: 'Bellefair',
|
||||||
|
[contextTools.LOBSTER]: 'Lobster',
|
||||||
|
[contextTools.ABRIL_FATFACE]: 'Abril Fatface',
|
||||||
|
[contextTools.PLAY]: 'Play',
|
||||||
|
[contextTools.FASCINATE]: 'Fascinate'
|
||||||
|
};
|
||||||
|
|