From 04186fd56c546044f736aa18be9707a636778790 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Tue, 9 Jan 2018 11:21:26 +0100 Subject: [PATCH 01/13] Text can now be edited directly on the canvas --- package-lock.json | 6 --- package.json | 1 - src/actions/index.js | 6 --- src/components/D2Panel.js | 44 ++++++++++------- src/components/InputText.js | 94 ++++++++++++++++++++++++++++++++++++ src/constants/d2Constants.js | 1 + src/shape/shapeToPoints.js | 3 +- src/utils/textUtils.js | 16 +++--- 8 files changed, 131 insertions(+), 40 deletions(-) create mode 100644 src/components/InputText.js diff --git a/package-lock.json b/package-lock.json index 4c1f9a2..11e8644 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11747,12 +11747,6 @@ "prop-types": "15.6.0" } }, - "react-router-redux": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/react-router-redux/-/react-router-redux-4.0.8.tgz", - "integrity": "sha1-InQDWWtRUeGCN32rg1tdRfD4BU4=", - "dev": true - }, "react-svg-inline": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/react-svg-inline/-/react-svg-inline-2.0.1.tgz", diff --git a/package.json b/package.json index 8604d69..6a2f517 100755 --- a/package.json +++ b/package.json @@ -82,7 +82,6 @@ "normalize-jss": "^4.0.0", "raw-loader": "^0.5.1", "react-dom": "^16.1.1", - "react-router-redux": "^4.0.8", "react-tap-event-plugin": "^3.0.2", "redux": "^3.7.2", "redux-action-wrapper": "^1.0.1", diff --git a/src/actions/index.js b/src/actions/index.js index 9c6469d..d2eceab 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,6 +1,5 @@ import { ActionCreators as undo } from 'redux-undo'; import * as notification from 'react-notification-system-redux'; -import { routerActions as router } from 'react-router-redux'; import * as selectionUtils from '../utils/selectionUtils.js'; import { calculatePointInImage, decomposeMatrix } from '../utils/matrixUtils.js'; import { loadImage, prepareImage } from '../utils/imageUtils.js'; @@ -74,7 +73,6 @@ export const ALIGN = 'ALIGN'; export const ADD_IMAGE = 'ADD_IMAGE'; export const D2_TEXT_INIT = 'D2_TEXT_INIT'; export const D2_TEXT_INPUT_CHANGE = 'D2_TEXT_INPUT_CHANGE'; -export const D2_TEXT_ADD = 'D2_TEXT_ADD'; export const UNION = 'UNION'; export const INTERSECT = 'INTERSECT'; export const MOVE_SELECTION = 'MOVE_SELECTION'; @@ -390,15 +388,11 @@ export function addImage(file) { export function d2textInit(position, textId, screenMatrixContainer, screenMatrixZoom) { return (dispatch) => { dispatch({ type: D2_TEXT_INIT, position, textId, screenMatrixContainer, screenMatrixZoom }); - dispatch(router.push('/sketch/inputtext')); }; } export function d2textInputChange(text, family, weight, style, fill) { return { type: D2_TEXT_INPUT_CHANGE, text, family, weight, style, fill }; } -export function d2textAdd() { - return { type: D2_TEXT_ADD }; -} const traceDragThrottle = createThrottle(); diff --git a/src/components/D2Panel.js b/src/components/D2Panel.js index 83ce0a6..cd9438d 100644 --- a/src/components/D2Panel.js +++ b/src/components/D2Panel.js @@ -23,6 +23,7 @@ import ShapesManager from '../d2/ShapesManager.js'; import EventGroup from '../d2/EventGroup.js'; import ReactResizeDetector from 'react-resize-detector'; import { load as loadPattern } from '../d2/Shape.js'; +import InputText from './InputText.js'; // import createDebug from 'debug'; // const debug = createDebug('d3d:d2'); @@ -63,6 +64,9 @@ class D2Panel extends React.Component { dispatch: PropTypes.func.isRequired, classes: PropTypes.objectOf(PropTypes.string) }; + state = { + screenMatrix: new CAL.Matrix() + }; activeNeedRender = false; inactiveNeedRender = false; @@ -117,7 +121,7 @@ class D2Panel extends React.Component { } 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 if (this.tool) { this.tool.destroy(); @@ -135,18 +139,18 @@ class D2Panel extends React.Component { this.objectContainerActive.add(this.tool); } - update(newState) { - if (this.state === newState) return; + update(state) { + 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.inactive) this.inactiveNeedRender = true; // Update Objects Container Space with zoom & panning - const newCanvasMatrix = newState.d2.canvasMatrix; - if (this.state && newCanvasMatrix !== this.state.d2.canvasMatrix) { + const newCanvasMatrix = state.d2.canvasMatrix; + if (this.state.state && newCanvasMatrix !== this.state.state.d2.canvasMatrix) { this.objectContainerActive.copyMatrix(newCanvasMatrix); this.objectContainerInactive.copyMatrix(newCanvasMatrix); @@ -154,9 +158,9 @@ class D2Panel extends React.Component { this.inactiveNeedRender = true; } - const selection = (this.state) ? this.state.selection : null; - const newSelection = newState.selection; - if (!this.state || newSelection !== selection) { + const selection = (this.state.state) ? this.state.state.selection : null; + const newSelection = state.selection; + if (!this.state.state || newSelection !== selection) { const newSelectedObjects = newSelection.objects; if (!selection || selection.objects !== newSelectedObjects) { const selected = newSelectedObjects.map((object) => object.id); @@ -167,25 +171,29 @@ class D2Panel extends React.Component { } } - const dragSelect = (this.state) ? this.state.d2.transform.dragSelect : null; - const newDragSelect = newState.d2.transform.dragSelect; + const dragSelect = (this.state.state) ? this.state.state.d2.transform.dragSelect : null; + const newDragSelect = state.d2.transform.dragSelect; if (!dragSelect || dragSelect !== newDragSelect) { this.activeNeedRender = true; } - this.state = newState; + this.setState({ state }); } resizeHandler = (width, height) => { this.sceneActive.setSize(width, height, PIXEL_RATIO); this.sceneInactive.setSize(width, height, PIXEL_RATIO); - this.sceneInactive.x = this.sceneActive.x = Math.round(width / 2 * PIXEL_RATIO); - this.sceneInactive.y = this.sceneActive.y = Math.round(height / 2 * PIXEL_RATIO); - + const x = Math.round(width / 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); - 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.renderRequest(); @@ -210,12 +218,14 @@ class D2Panel extends React.Component { render() { // debug('this.props.state: ', this.props.state); const { state, classes } = this.props; + const { screenMatrix } = this.state; this.update(state); this.renderCanvas(); return (
+
); } diff --git a/src/components/InputText.js b/src/components/InputText.js new file mode 100644 index 0000000..c23610f --- /dev/null +++ b/src/components/InputText.js @@ -0,0 +1,94 @@ +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 'cal'; +import { TEXT_TOOL_FONT_SIZE } from '../constants/d2Constants.js'; + +document.createElement('canvas'); + +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 { + 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 { family, weight, style } = shapeData.text; + const text = this.refs.text.value; + + changeText(text, family, weight, style, true); + }; + + 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.refs.text) this.refs.text.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); + + return ( +
+ +
+ ); + } + return null; + } +} + +export default injectSheet(styles)(connect(state => ({ + state: state.sketcher.present +}), { + changeText: actions.d2textInputChange +})(InputText)); diff --git a/src/constants/d2Constants.js b/src/constants/d2Constants.js index 97777fa..71f9334 100644 --- a/src/constants/d2Constants.js +++ b/src/constants/d2Constants.js @@ -41,3 +41,4 @@ export const BRUSH_SIZES = { }; export const CLIPPER_PRECISION = 100; // accurate to the hundredth +export const TEXT_TOOL_FONT_SIZE = 40; diff --git a/src/shape/shapeToPoints.js b/src/shape/shapeToPoints.js index 730e0af..20cff6b 100644 --- a/src/shape/shapeToPoints.js +++ b/src/shape/shapeToPoints.js @@ -8,6 +8,7 @@ import { MAX_ANGLE } from '../constants/d3Constants.js'; import { SHAPE_CACHE_LIMIT } from '../constants/general.js'; import { createText } from '../utils/textUtils.js'; import { segmentBezierPath } from '../utils/curveUtils.js'; +import { TEXT_TOOL_FONT_SIZE } from '../constants/d2Constants.js'; const setDirection = (clockwise) => (path) => { return (THREE.ShapeUtils.isClockWise(path) === clockwise) ? path : path.reverse(); @@ -120,7 +121,7 @@ function shapeToPointsRaw(shapeData) { } case 'TEXT': { const { text, family, style, weight } = shapeData.text; - const textShapes = createText(text, 400, family, style, weight) + const textShapes = createText(text, TEXT_TOOL_FONT_SIZE, 10, family, style, weight) .map(([points, ...holes]) => ({ points, holes })); shapes.push(...textShapes); diff --git a/src/utils/textUtils.js b/src/utils/textUtils.js index 37b1b73..e0d059a 100644 --- a/src/utils/textUtils.js +++ b/src/utils/textUtils.js @@ -9,19 +9,17 @@ import memoize from 'memoizee'; const MARGIN = 200; export const createText = memoize(createTextRaw, { max: SHAPE_CACHE_LIMIT }); -export function createTextRaw(text, size, family, style, weight) { +export function createTextRaw(text, size, precision, family, style, weight) { if (text === '') return []; - const { width, height, canvas } = createTextCanvas(text, size, family, style, weight); + const canvas = createTextCanvas(text, size * precision, family, style, weight); // TODO merge with potrace in flood fill trace reducer const paths = POTRACE.getPaths(POTRACE.traceCanvas(canvas, POTRACE_OPTIONS)); - const halfWidth = width / 2; - const halfHeight = height / 2; const pathsOffset = paths.map(path => path.map(({ x, y }) => ({ - x: (x - halfWidth) / 10, - y: (y - halfHeight) / 10 + x: (x - MARGIN) / precision, + y: (y - MARGIN) / precision }))); const shapes = new ClipperShape(pathsOffset, true, true, false) @@ -33,7 +31,7 @@ export function createTextRaw(text, size, family, style, weight) { return shapes; } -const textContext = new Text(); +const textContext = new Text({ baseline: 'top' }); export function createTextCanvas(text, size, family, style, weight) { textContext.size = size; textContext.family = family; @@ -52,7 +50,7 @@ export function createTextCanvas(text, size, family, style, weight) { context.fillStyle = 'white'; context.fillRect(0, 0, width, height); - textContext.drawText(context, text, MARGIN, height / 2); + textContext.drawText(context, text, MARGIN, MARGIN); - return { width, height, canvas }; + return canvas; } From 1464a4b74f466b3f67334d21c13ac679ac95352b Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Tue, 9 Jan 2018 11:21:51 +0100 Subject: [PATCH 02/13] remove empty text --- src/reducer/d2/toolReducer.js | 3 ++- src/reducer/d2/tools/textReducer.js | 20 +++++++++++--------- src/reducer/index.js | 3 +-- src/utils/undoFilter.js | 1 - 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/reducer/d2/toolReducer.js b/src/reducer/d2/toolReducer.js index 3839b3b..c7c8a6d 100644 --- a/src/reducer/d2/toolReducer.js +++ b/src/reducer/d2/toolReducer.js @@ -8,7 +8,7 @@ import starReducer from './tools/shapes/starReducer.js'; import triangleReducer from './tools/shapes/triangleReducer.js'; import bucketReducer from './tools/bucketReducer.js'; import penReducer from './tools/penReducer.js'; -import textReducer from './tools/textReducer.js'; +import textReducer, { removeEmptyText } from './tools/textReducer.js'; import photoGuideReducer from './tools/photoGuideReducer.js'; import { transformReducer } from './tools/transformReducer.js'; import eraserReducer from './tools/eraserReducer.js'; @@ -44,6 +44,7 @@ export default function toolReducer(state, action) { // change 2D tool after explicit tool change action or on some selection if (action.type === actions.D2_CHANGE_TOOL) { state = updateTool(state, action.tool); + state = removeEmptyText(state); } if (action.category === actions.CAT_SELECTION) { state = updateTool(state, tools.TRANSFORM); diff --git a/src/reducer/d2/tools/textReducer.js b/src/reducer/d2/tools/textReducer.js index b7cb8bb..077c3ac 100644 --- a/src/reducer/d2/tools/textReducer.js +++ b/src/reducer/d2/tools/textReducer.js @@ -8,10 +8,11 @@ const debug = createDebug('d3d:reducer:text'); export default function textReducer(state, action) { if (action.log !== false) debug(action.type); - const activeShape = state.d2.activeShape; switch (action.type) { case actions.D2_TEXT_INIT: { + state = removeEmptyText(state); + const { position, textId, screenMatrixZoom } = action; const screenPosition = (position && screenMatrixZoom) ? position.applyMatrix(screenMatrixZoom.inverseMatrix()) : @@ -29,6 +30,7 @@ export default function textReducer(state, action) { } case actions.D2_TEXT_INPUT_CHANGE: { const { text, family, style, weight, fill } = action; + const { activeShape } = state.d2; return update(state, { objectsById: { [activeShape]: { @@ -43,16 +45,16 @@ export default function textReducer(state, action) { } }); } - case actions.D2_TEXT_ADD: { - if (activeShape && state.objectsById[activeShape].text.text.length === 0) { - return setActive2D(removeObject(state, activeShape), null); - } else { - return setActive2D(state, null); - } - break; - } default: return state; } +} + +export function removeEmptyText(state) { + const { activeShape } = state.d2; + + if (activeShape && state.objectsById[activeShape].text.text === '') { + return setActive2D(removeObject(state, activeShape), null); + } return state; } diff --git a/src/reducer/index.js b/src/reducer/index.js index 9fe70a2..141a060 100644 --- a/src/reducer/index.js +++ b/src/reducer/index.js @@ -142,7 +142,6 @@ function sketcherReducer(state = initialState, action) { case actions.MULTITOUCH_TRANSFORM_END: case actions.D2_TEXT_INIT: case actions.D2_TEXT_INPUT_CHANGE: - case actions.D2_TEXT_ADD: case actions.MOVE_SELECTION: return d2ToolReducer(state, action); @@ -188,11 +187,11 @@ function sketcherReducer(state = initialState, action) { return d3ToolReducer(state, action); case actions.D2_CHANGE_TOOL: - state = setActive2D(state, null); state = selectionReducer(state, action); state = d2ToolReducer(state, action); // switch and initialize tool state = updateMenus(state, action); state = contextReducer(state, action); + state = setActive2D(state, null); return state; case actions.D3_CHANGE_TOOL: diff --git a/src/utils/undoFilter.js b/src/utils/undoFilter.js index 136b56f..0a348f5 100644 --- a/src/utils/undoFilter.js +++ b/src/utils/undoFilter.js @@ -14,7 +14,6 @@ const INCLUDE = [ actions.DESELECT_ALL, actions.STAMP, actions.SELECT, - actions.D2_TEXT_ADD, actions.CLEAR, actions.TWIST_END, actions.SCULPT_END, From 2b5d24048738a3fb59ca6137943e45fa6482d6b3 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Tue, 9 Jan 2018 11:53:12 +0100 Subject: [PATCH 03/13] increase hit area of text shapes Hit area of text shapes is now the boundingbox --- src/d2/tools/BaseTool.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/d2/tools/BaseTool.js b/src/d2/tools/BaseTool.js index 66d2530..3b723b5 100644 --- a/src/d2/tools/BaseTool.js +++ b/src/d2/tools/BaseTool.js @@ -8,7 +8,7 @@ import { shapeToPoints } from '../../shape/shapeToPoints'; import { LINE_COLLISION_MARGIN } from '../../constants/d2Constants'; import { LINE_WIDTH } from '../../constants/d2Constants'; import { PIXEL_RATIO } from '../../constants/general'; -import { Matrix } from 'cal'; +import { Matrix, Vector } from 'cal'; const HIT_ORDER = { RECT: 0, @@ -132,8 +132,20 @@ export default class BaseTool extends EventGroup { const objects = shapeDatas .filter(shapeData => { const shapeMatrix = shapeData.transform.multiplyMatrix(matrix); + let shapePoints = shapeToPoints(shapeData); - const isHit = shapeToPoints(shapeData) + if (shapeData.type === 'TEXT') { + if (shapeData.text.text === '') return false; + const { min, max } = getPointsBounds(shapePoints); + shapePoints = [{ points: [ + new Vector(min.x, min.y), + new Vector(min.x, max.y), + new Vector(max.x, max.y), + new Vector(max.x, min.y) + ], holes: [] }]; + } + + const isHit = shapePoints .some(({ points, holes }) => { const shape = applyMatrixOnShape([points, ...holes], shapeMatrix); const clipperShape = new ClipperShape(shape, shapeData.fill, true, true); From 01bd55796e0b00ce19f3a6e2496c09f9dd85d974 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Tue, 9 Jan 2018 12:12:35 +0100 Subject: [PATCH 04/13] formatting --- src/components/InputText.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/InputText.js b/src/components/InputText.js index c23610f..9b31ab2 100644 --- a/src/components/InputText.js +++ b/src/components/InputText.js @@ -71,9 +71,7 @@ class InputText extends React.Component { > Date: Tue, 9 Jan 2018 15:42:25 +0100 Subject: [PATCH 05/13] make font face updatable and add google fonts --- img/contextmenu/btnFont.png | Bin 0 -> 16150 bytes package-lock.json | 54 +++++++++++++++++++++++++++ package.json | 1 + src/actions/index.js | 4 +- src/components/InputText.js | 5 +-- src/components/SketcherToolbars.js | 33 ++++++++++++---- src/constants/contextTools.js | 21 +++++++++++ src/constants/general.js | 11 ++++++ src/constants/menu.js | 5 +++ src/constants/shapeTypeProperties.js | 4 +- src/reducer/contextReducer.js | 34 ++++++++++++++++- src/reducer/d2/tools/textReducer.js | 19 +++++----- src/reducer/index.js | 5 ++- styles/styles.css | 7 ++++ webpack.config.js | 19 ++++++++-- 15 files changed, 193 insertions(+), 29 deletions(-) create mode 100644 img/contextmenu/btnFont.png diff --git a/img/contextmenu/btnFont.png b/img/contextmenu/btnFont.png new file mode 100644 index 0000000000000000000000000000000000000000..6cba1abfa72e928d4a4c3f6e326a14e64dc7310a GIT binary patch literal 16150 zcmeI3eQX@X6~OnbG)gXV8$fBInpVpJrB%G%kNetP-CZ2}Z0wM8EaxCLtrGTj=j^TT zZZEfc_SvD0L(_mkgeH(QN{~W}{0FYmC`xFdw185+1W{0FtB8iGPAQZ`RtqV#jUu44 z_wBj6k&*bLQs*q+?VC66y_w&#3mYAJ07JqIE6k+Tx9Hk#r{*(R(H{VDn^ORGl1ECC#-iIZGKoZ6=Ap^cHfb@uA8Rm%5AY@schgdJLrNy-;1Ql(XuE~7ZEp)iW4zJMV{y>cs!Cn zUJ6*{tR_%z%CwY}3X1d4VGxg?sj)b(!4gyBjK}NtF)@+j7}dx7L`jr{7!OLWtITU$ zhe1Xk16p^+Nao8Ytz=AKr*hC$%H?vs6&dG?LDp->q^Z0rseY0134+FWfaqbQxF#{0 z*CWM%hvRuSA7E?DD`SEI0tGcB`Po;l# zk|Loml3JM^tbbWi?d>XLDv-Plq^hklQz&zuL!6cJ_CNgnB zRNWF#fCiM3|0?swF~&zgDg^g$5vCQxNl{*ai6(RIwf08Nm0aa}HFjbeacf-3fc3+$ z^g@LLqrbF&(4C$30pX{=5m8hD~DRAkuWlFSRmvMu=SejT17$5+Nex`jJdEF^V@5OGQ6rp`58B6dBAf5;7dZG~dHcI)TCGM+hw!G=YSgr1d3#E?LP9Yb z(p+U_-?qv56xs|QRY1t+^}4+Q7Hvi?`t=-042E@hH)q;MrwHejw?P$k4Tl;TRw;^x zg%zuMsK_T~p%p%|z^5g){J2z;v*k?sJTEFU`aHcNzDN)R2wo((@O%(0!G!?9iv$;* z527Ww5FmJw;KK7kv;-Fd1TPX?cs_`h;6i}lMS=^@2hkE-2oStTaN+qNT7nA!f)@!c zJRd|$a3MhOBEf~{gJ=mZ1PERvxbS=sEy0BV!HWbJo)4lWxDX(Ck>JAfL9_%H0t7D- zTzEc+mf%8w;6;K9&j-;GTnG@nNO0l#AX4T@FKy5=YwboE(8c( zB)IT=5G}!l0Ktm{7oHEICAbhEc#+`3^Fg!(7Xkz?VsSYuFCc>yeCv1|zFyoB{qptj z)nr=j8HiBS*T5as#_F^|hIo|CJuaD;bIRDm# zefMxH_gr}K#IDHl!KQPk4?K2r4*vBlzjejI^v~N@JTiB1?&GJp-*E5I>pNfi_tlxV z=?lukl=IDxCRYi;wacg_E8D5%Q&iJ`4i4ShI{)bT2VU9qm!(Hud*_W8X4_|)jvn0* z{^gFR1b53@Ewk#`wf^|n$yn68df%~~JJy_d_@7&^Zgn2|^OgDYXI|a1W%tX;bKjc% z&V?I(@x(^ggZJJ2!t>8K?mY5lUwG`g`{yoBeSF}^eRm%o`t_+3ub$}}U-`J>UoZdY z_>Q-K*Rk@a(k-VY$Lr7Tx^2_bH$DF=|M|Aiv-d`CbIhMwJAG-?ygxK8{_S#0^M)Tg zU;p0e2kzYUr&Z_nZ#_%xnc4f@>ko~8>5k2zquI0i8E4|!?C86PdhT$K{ooPDFoC4`@h|tTKC-a zlBMmG1M+C1A&;IinPs#CGIHERH7%p3me^f>NWm-W+H&WYGU8s>34pA>`D90_1><&@XtE#y63+JQo0=g literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json index 11e8644..950584e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1932,6 +1932,11 @@ "isarray": "1.0.0" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, "buffer-from": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.1.tgz", @@ -4286,6 +4291,14 @@ } } }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "requires": { + "pend": "1.2.0" + } + }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", @@ -5666,6 +5679,33 @@ "pinkie-promise": "2.0.1" } }, + "google-fonts-webpack-plugin": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/google-fonts-webpack-plugin/-/google-fonts-webpack-plugin-0.4.4.tgz", + "integrity": "sha512-+e2D9/DVBG9EDydRovzoqMZ658SsTBGbC0c65GyZqkwNvdj8vRSYQKXqbz7/yt7QaXsCPT1MpH45r3ivWOitcw==", + "requires": { + "lodash": "4.17.4", + "node-fetch": "1.7.3", + "webpack-sources": "0.2.3", + "yauzl": "2.9.1" + }, + "dependencies": { + "source-list-map": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-1.1.2.tgz", + "integrity": "sha1-mIkBnRAkzOVc3AaUmDN+9hhqEaE=" + }, + "webpack-sources": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-0.2.3.tgz", + "integrity": "sha1-F8Yr+vE8cH+dAsR54Nzd6DgGl/s=", + "requires": { + "source-list-map": "1.1.2", + "source-map": "0.5.7" + } + } + } + }, "got": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/got/-/got-3.3.1.tgz", @@ -10550,6 +10590,11 @@ "integrity": "sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0=", "dev": true }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, "pepjs": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/pepjs/-/pepjs-0.4.3.tgz", @@ -14364,6 +14409,15 @@ } } }, + "yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=", + "requires": { + "buffer-crc32": "0.2.13", + "fd-slicer": "1.0.1" + } + }, "yml-loader": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/yml-loader/-/yml-loader-2.1.0.tgz", diff --git a/package.json b/package.json index 6a2f517..c3076bd 100755 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "blueimp-canvas-to-blob": "^3.14.0", "bowser": "^1.8.1", "fit-curve": "^0.1.6", + "google-fonts-webpack-plugin": "^0.4.4", "imports-loader": "^0.7.1", "jss": "^9.4.0", "keycode": "^2.1.9", diff --git a/src/actions/index.js b/src/actions/index.js index d2eceab..64285fe 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -390,8 +390,8 @@ export function d2textInit(position, textId, screenMatrixContainer, screenMatrix dispatch({ type: D2_TEXT_INIT, position, textId, screenMatrixContainer, screenMatrixZoom }); }; } -export function d2textInputChange(text, family, weight, style, fill) { - return { type: D2_TEXT_INPUT_CHANGE, text, family, weight, style, fill }; +export function d2textInputChange(text) { + return { type: D2_TEXT_INPUT_CHANGE, text }; } const traceDragThrottle = createThrottle(); diff --git a/src/components/InputText.js b/src/components/InputText.js index 9b31ab2..fe8528b 100644 --- a/src/components/InputText.js +++ b/src/components/InputText.js @@ -37,10 +37,9 @@ class InputText extends React.Component { if (!shapeData) return; const { changeText } = this.props; - const { family, weight, style } = shapeData.text; const text = this.refs.text.value; - changeText(text, family, weight, style, true); + changeText(text); }; getShapeData = () => { @@ -71,7 +70,7 @@ class InputText extends React.Component { > 0) { component = ( ); + } else if (FONT_TOOLS.includes(child.value)) { + component = ( + +

{FONT_FACE[child.value]}

+
+ ); } else { component = ( = 2; const showIntersect = activeTool === d2Tools.TRANSFORM && numSelectedObjects >= 1; return { @@ -191,11 +206,14 @@ function filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidO case contextTools.HOLE_TOGGLE: return numSelectedObjects > 0; + case contextTools.FONT: + return selectionIncludesText || activeTool === d2Tools.TEXT; + default: return true; } }).map(child => { - return filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, child); + return filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText, child); }) }; } @@ -217,11 +235,12 @@ const getMenus = createSelector([ state => state.sketcher.present.d2.tool, 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.sketcher.present.objectsById[id].solid).length -], (menus, activeTool, numSelectedObjects, numFilledObjects, numSolidObjects) => ({ - toolbar2d: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, nestChildren(menus, menus[TOOLBAR2D])), - toolbar3d: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, nestChildren(menus, menus[TOOLBAR3D])), - context: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, nestChildren(menus, menus[CONTEXT])) + state => state.sketcher.present.selection.objects.filter(({ id }) => state.sketcher.present.objectsById[id].solid).length, + state => state.sketcher.present.selection.objects.some(({ id }) => state.sketcher.present.objectsById[id].type === 'TEXT') +], (menus, activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText) => ({ + toolbar2d: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText, nestChildren(menus, menus[TOOLBAR2D])), + toolbar3d: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText, nestChildren(menus, menus[TOOLBAR3D])), + context: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText, nestChildren(menus, menus[CONTEXT])) })); export default injectSheet(styles)(connect(getMenus)(SketcherToolbars)); diff --git a/src/constants/contextTools.js b/src/constants/contextTools.js index 382b2ea..aea829b 100644 --- a/src/constants/contextTools.js +++ b/src/constants/contextTools.js @@ -8,6 +8,7 @@ export const HOLE_TOGGLE = 'hole-toggle-tool'; export const ALIGN = 'align-tool'; export const UNION = 'union-tool'; export const INTERSECT = 'intersect-tool'; +export const FONT = 'font-tool'; export const LIGHT_BLUE_A = 'color-light-blue-a'; export const LIGHT_BLUE_B = 'color-light-blue-b'; @@ -79,3 +80,23 @@ export const ALIGN_TOOLS = [ ALIGN_VERTICAL, 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 +]; diff --git a/src/constants/general.js b/src/constants/general.js index ebb8606..4f84533 100644 --- a/src/constants/general.js +++ b/src/constants/general.js @@ -37,3 +37,14 @@ export const COLOR_STRING_TO_HEX = { [contextTools.BLACK_B]: 0xAAAAAA, [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' +}; diff --git a/src/constants/menu.js b/src/constants/menu.js index 680bb66..7377723 100644 --- a/src/constants/menu.js +++ b/src/constants/menu.js @@ -109,6 +109,11 @@ const context = { selected: contextTools.ALIGN_HORIZONTAL, children: contextTools.ALIGN_TOOLS.map(value => ({ value })), ...selectorBehavior + }, { + value: contextTools.FONT, + selected: contextTools.OSWALD, + children: contextTools.FONT_TOOLS.map(value => ({ value })), + ...selectorBehavior }, { value: contextTools.UNION }, { value: contextTools.INTERSECT } diff --git a/src/constants/shapeTypeProperties.js b/src/constants/shapeTypeProperties.js index 4e2f0a4..ca5b2f1 100644 --- a/src/constants/shapeTypeProperties.js +++ b/src/constants/shapeTypeProperties.js @@ -1,6 +1,8 @@ import { Vector, Matrix } from '@doodle3d/cal'; import * as d2Tools from './d2Tools'; import * as d3Tools from './d3Tools'; +import * as contextTools from './contextTools'; +import { FONT_FACE } from '../constants/general.js'; const SHAPE = { D3Visible: true, @@ -58,7 +60,7 @@ export const SHAPE_TYPE_PROPERTIES = { ...SHAPE, defaultProperties: { ...defaultProperties, - text: { text: '', family: 'Arial', weight: 'normal', style: 'normal' }, + text: { text: '', family: FONT_FACE[contextTools.OSWALD], weight: 'normal', style: 'normal' }, fill: true } }, diff --git a/src/reducer/contextReducer.js b/src/reducer/contextReducer.js index 34418b9..087ea76 100644 --- a/src/reducer/contextReducer.js +++ b/src/reducer/contextReducer.js @@ -1,6 +1,6 @@ import update from 'react-addons-update'; import * as contextTools from '../constants/contextTools.js'; -import { COLOR_STRING_TO_HEX } from '../constants/general.js'; +import { COLOR_STRING_TO_HEX, FONT_FACE } from '../constants/general.js'; import { ERASER_SIZES, BRUSH_SIZES } from '../constants/d2Constants.js'; import { SHAPE_TYPE_PROPERTIES } from '../constants/shapeTypeProperties.js'; import * as actions from '../actions/index.js'; @@ -69,6 +69,33 @@ export default function (state, action) { }); } + case contextTools.OSWALD: + case contextTools.RANGA: + case contextTools.JOTI_ONE: + case contextTools.BELLEFAIR: + case contextTools.LOBSTER: + case contextTools.ABRIL_FATFACE: + case contextTools.PLAY: + case contextTools.FASCINATE: { + const family = FONT_FACE[action.tool]; + const { activeShape } = state.d2; + if (activeShape && state.objectsById[activeShape].type === 'TEXT') { + state = update(state, { objectsById: { [activeShape]: { text: { family: { $set: family } } } } }); + } + + return update(state, { + objectsById: state.selection.objects.reduce((updateObject, { id }) => { + if (state.objectsById[id].type === 'TEXT') { + updateObject[id] = { text: { family: { $set: FONT_FACE[action.tool] } } }; + } + return updateObject; + }, {}), + context: { + font: { $set: FONT_FACE[action.tool] } + } + }); + } + case contextTools.LIGHT_BLUE_A: case contextTools.LIGHT_BLUE_B: case contextTools.LIGHT_BLUE_C: @@ -94,6 +121,11 @@ export default function (state, action) { case contextTools.BLACK_B: case contextTools.BLACK_C: { const color = COLOR_STRING_TO_HEX[action.tool]; + const { activeShape } = state.d2; + if (activeShape) { + state = update(state, { objectsById: { [activeShape]: { color: { $set: color } } } }); + } + return updateColor(state, color); } diff --git a/src/reducer/d2/tools/textReducer.js b/src/reducer/d2/tools/textReducer.js index 077c3ac..30fef0a 100644 --- a/src/reducer/d2/tools/textReducer.js +++ b/src/reducer/d2/tools/textReducer.js @@ -8,7 +8,6 @@ const debug = createDebug('d3d:reducer:text'); export default function textReducer(state, action) { if (action.log !== false) debug(action.type); - switch (action.type) { case actions.D2_TEXT_INIT: { state = removeEmptyText(state); @@ -23,24 +22,26 @@ export default function textReducer(state, action) { } else { return addObjectActive2D(state, { transform: new Matrix({ x: screenPosition.x, y: screenPosition.y }), - type: 'TEXT' + type: 'TEXT', + text: { + text: '', + family: state.context.font, + weight: 'normal', + style: 'normal' + } }); } return state; } case actions.D2_TEXT_INPUT_CHANGE: { - const { text, family, style, weight, fill } = action; + const { text } = action; const { activeShape } = state.d2; return update(state, { objectsById: { [activeShape]: { text: { - text: { $set: text }, - family: { $set: family }, - style: { $set: style }, - weight: { $set: weight } - }, - fill: { $set: fill } + text: { $set: text } + } } } }); diff --git a/src/reducer/index.js b/src/reducer/index.js index 141a060..3330090 100644 --- a/src/reducer/index.js +++ b/src/reducer/index.js @@ -4,7 +4,7 @@ import undoFilter from '../utils/undoFilter.js'; import * as actions from '../actions/index.js'; import * as d2Tools from '../constants/d2Tools.js'; import * as d3Tools from '../constants/d3Tools.js'; -import { COLOR_STRING_TO_HEX } from '../constants/general.js'; +import { COLOR_STRING_TO_HEX, FONT_FACE } from '../constants/general.js'; import * as contextTools from '../constants/contextTools.js'; import { ERASER_SIZES, BRUSH_SIZES } from '../constants/d2Constants.js'; import update from 'react-addons-update'; @@ -36,7 +36,8 @@ const initialState = { objectIdCounter: 0, context: { solid: true, - color: COLOR_STRING_TO_HEX[contextTools.LIGHT_BLUE_B] + color: COLOR_STRING_TO_HEX[contextTools.LIGHT_BLUE_B], + font: FONT_FACE[contextTools.OSWALD] }, selection: { transform: new Matrix(), diff --git a/styles/styles.css b/styles/styles.css index 656703f..c937f2b 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -249,6 +249,13 @@ flex-wrap: wrap; } +#font-tool > .button { + background-image: url('../img/contextmenu/btnFont.png'); + background-size: 40px auto; + width: 40px; + height: 40px; +} + #color-light-blue-a { fill: #BCFFFF; } #color-light-blue-b { fill: #68E1FD; } #color-light-blue-c { fill: #01B8FF; } diff --git a/webpack.config.js b/webpack.config.js index c116e80..22b7fc5 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,6 +3,7 @@ const path = require('path'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const HTMLWebpackPlugin = require('html-webpack-plugin'); const CordovaPlugin = require('webpack-cordova-plugin'); +const GoogleFontsPlugin = require('google-fonts-webpack-plugin'); const devMode = process.env.NODE_ENV !== 'production'; const appMode = process.env.TARGET === 'app'; @@ -75,9 +76,7 @@ module.exports = { }, plugins: [ new webpack.DefinePlugin({ - 'process.env': { - 'TARGET': JSON.stringify(process.env.TARGET) - } + 'process.env.TARGET': JSON.stringify(process.env.TARGET) }), new HTMLWebpackPlugin({ title: 'Doodle3D Core - Simple example', @@ -86,6 +85,18 @@ module.exports = { scripts: appMode ? ['cordova.js'] : null, appMountId: 'app' }), + new GoogleFontsPlugin({ + fonts: [ + { family: 'Oswald' }, + { family: 'Ranga' }, + { family: 'Joti One' }, + { family: 'Bellefair' }, + { family: 'Lobster' }, + { family: 'Abril Fatface' }, + { family: 'Play' }, + { family: 'Fascinate' } + ] + }), ...(appMode ? [ new CordovaPlugin({ config: 'config.xml', @@ -95,7 +106,7 @@ module.exports = { }) ] : []) ], - devtool: "source-map", + devtool: 'source-map', devServer: { contentBase: 'dist' } From a4a5afeb08fc21f3ef3b36ff83ec136cd0356a84 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Tue, 9 Jan 2018 15:42:30 +0100 Subject: [PATCH 06/13] formatting --- src/shape/shapeToPoints.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shape/shapeToPoints.js b/src/shape/shapeToPoints.js index 20cff6b..0795c4d 100644 --- a/src/shape/shapeToPoints.js +++ b/src/shape/shapeToPoints.js @@ -65,7 +65,7 @@ function shapeToPointsRaw(shapeData) { const points = []; let even = false; const numLines = rays * 2; - for (let i = 0, rad = 0; i <= numLines; i++, rad += Math.PI / rays) { + for (let i = 0, rad = 0; i <= numLines; i ++, rad += Math.PI / rays, even = !even) { if (i === numLines) { // last line? points.push(points[0].clone()); // go to first point } else { @@ -73,7 +73,6 @@ function shapeToPointsRaw(shapeData) { let x = Math.sin(rad) * radius; let y = -Math.cos(rad) * radius; points.push(new Vector(x, y)); - even = !even; } } shapes.push({ points, holes: [] }); From 7b9f647f11df0070db7e527e16203a76c985891d Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Tue, 9 Jan 2018 16:02:04 +0100 Subject: [PATCH 07/13] edit width of input based on number of characters --- src/components/InputText.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/InputText.js b/src/components/InputText.js index fe8528b..73e74bd 100644 --- a/src/components/InputText.js +++ b/src/components/InputText.js @@ -6,7 +6,7 @@ import * as actions from '../actions/index.js'; import * as CAL from 'cal'; import { TEXT_TOOL_FONT_SIZE } from '../constants/d2Constants.js'; -document.createElement('canvas'); +const CONTEXT = document.createElement('canvas').getContext('2d'); const styles = { textInputContainer: { @@ -63,6 +63,11 @@ class InputText extends React.Component { .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 (
Date: Tue, 9 Jan 2018 16:28:11 +0100 Subject: [PATCH 08/13] update font menu font menu now places different fonts in a column instead of a row --- styles/styles.css | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/styles/styles.css b/styles/styles.css index c937f2b..e3d1c51 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -256,6 +256,17 @@ height: 40px; } +#font-tool .menu { + flex-direction: column; + max-height: 170px; + width: 120px; + overflow-y: auto; +} + +#font-tool .menu .menuitem { + text-align: center; +} + #color-light-blue-a { fill: #BCFFFF; } #color-light-blue-b { fill: #68E1FD; } #color-light-blue-c { fill: #01B8FF; } From 87acf98f518c3f56a3c9bceceac59ab0b1a00787 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Wed, 10 Jan 2018 12:21:14 +0100 Subject: [PATCH 09/13] add anaglyph effect --- shaders/anaglyph_frag.glsl | 36 +++++++++++++++ shaders/anaglyph_vert.glsl | 5 ++ src/components/D3Panel.js | 6 +-- src/d3/RenderChain.js | 71 ++++++++++++++++++----------- src/d3/createScene.js | 7 +-- src/d3/effects/AnaglyphPass.js | 66 +++++++++++++++++++++++++++ src/d3/{ => effects}/OutlinePass.js | 12 ++--- src/d3/{ => effects}/RenderPass.js | 0 8 files changed, 165 insertions(+), 38 deletions(-) create mode 100644 shaders/anaglyph_frag.glsl create mode 100644 shaders/anaglyph_vert.glsl create mode 100644 src/d3/effects/AnaglyphPass.js rename src/d3/{ => effects}/OutlinePass.js (86%) rename src/d3/{ => effects}/RenderPass.js (100%) diff --git a/shaders/anaglyph_frag.glsl b/shaders/anaglyph_frag.glsl new file mode 100644 index 0000000..114e311 --- /dev/null +++ b/shaders/anaglyph_frag.glsl @@ -0,0 +1,36 @@ +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 ) ); + +} diff --git a/shaders/anaglyph_vert.glsl b/shaders/anaglyph_vert.glsl new file mode 100644 index 0000000..610d70b --- /dev/null +++ b/shaders/anaglyph_vert.glsl @@ -0,0 +1,5 @@ +varying vec2 vUv; +void main() { + vUv = vec2( uv.x, uv.y ); + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); +} diff --git a/src/components/D3Panel.js b/src/components/D3Panel.js index 52f18fc..2a043dd 100644 --- a/src/components/D3Panel.js +++ b/src/components/D3Panel.js @@ -16,7 +16,7 @@ import TwistTransformer from '../d3/transformers/TwistTransformer.js'; import SculptTransformer from '../d3/transformers/SculptTransformer.js'; import StampTransformer from '../d3/transformers/StampTransformer.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 Camera from '../d3/Camera.js'; import ReactResizeDetector from 'react-resize-detector'; @@ -62,8 +62,8 @@ class D3Panel extends React.Component { componentWillMount() { this.createScene(); - const toonShader = hasExtensionsFor.toonShaderPreview; - this.renderChain = new RenderChain(this.renderer, this.scene, this.camera, toonShader, { + const shader = hasExtensionsFor.toonShaderPreview ? TOONSHADER_OUTLINE : TOONSHADER; + this.renderChain = new RenderChain(this.renderer, this.scene, this.camera, shader, { UI: this.UIContainer, shapes: this.shapesManager, boundingBox: this.selectionBox, diff --git a/src/d3/RenderChain.js b/src/d3/RenderChain.js index 0d5b1cb..dccfa34 100644 --- a/src/d3/RenderChain.js +++ b/src/d3/RenderChain.js @@ -1,43 +1,62 @@ import * as THREE from 'three'; -import OutlinePass from './OutlinePass.js'; -import RenderPass from './RenderPass.js'; +import OutlinePass from './effects/OutlinePass.js'; +import RenderPass from './effects/RenderPass.js'; +import AnaglyphPass from './effects/AnaglyphPass.js'; import 'three/examples/js/shaders/CopyShader.js'; import 'three/examples/js/postprocessing/EffectComposer.js'; import 'three/examples/js/postprocessing/ShaderPass.js'; +export const TOONSHADER_OUTLINE = 'toonshader-outline'; +export const ANAGLYPH = 'anaglyph'; +export const TOONSHADER = 'toonshader'; + export default class RenderChain extends THREE.EffectComposer { - constructor(renderer, scene, camera, toonShader, groups) { + constructor(renderer, scene, camera, shader, groups) { super(renderer); this._groups = groups; - if (toonShader) { - const renderPass = new RenderPass(scene, camera, () => { - this._setVisible(this._initalValues, [groups.shapes, groups.plane, groups.boundingBox]); - }); - this.addPass(renderPass); + switch (shader) { + case TOONSHADER_OUTLINE: { + const renderPass = new RenderPass(scene, camera, () => { + this._setVisible(this._initalValues, [groups.shapes, groups.plane, groups.boundingBox]); + }); + this.addPass(renderPass); - const outlinePass = new OutlinePass(scene, camera, () => { - this._setVisible(this._initalValues, [groups.shapes]); - }); - outlinePass.renderToScreen = true; - this.addPass(outlinePass); + const outlinePass = new OutlinePass(scene, camera, () => { + this._setVisible(this._initalValues, [groups.shapes]); + }); + outlinePass.renderToScreen = true; + this.addPass(outlinePass); - const renderPassUI = new RenderPass(scene, camera, () => { - this._setVisible(this._initalValues, [groups.UI]); - }); - renderPassUI.clear = false; - renderPassUI.renderToScreen = true; - this.addPass(renderPassUI); - } else { - const renderPass = new RenderPass(scene, camera); - renderPass.renderToScreen = true; - this.addPass(renderPass); + const renderPassUI = new RenderPass(scene, camera, () => { + this._setVisible(this._initalValues, [groups.UI]); + }); + renderPassUI.clear = false; + renderPassUI.renderToScreen = true; + this.addPass(renderPassUI); + break; + } + + case ANAGLYPH: { + const anaglyphPass = new AnaglyphPass(scene, camera); + anaglyphPass.renderToScreen = true; + this.addPass(anaglyphPass); + break; + } + + case TOONSHADER: + default: { + const renderPass = new RenderPass(scene, camera); + renderPass.renderToScreen = true; + this.addPass(renderPass); + break; + } } this._renderer = renderer; this._camera = camera; this._scene = scene; - this._toonShader = toonShader; + this._shader = shader; } _getCurrentVisibleValues() { @@ -74,13 +93,13 @@ export default class RenderChain extends THREE.EffectComposer { } render() { - if (this._toonShader) { + if (this._shader === TOONSHADER_OUTLINE) { this._initalValues = this._getCurrentVisibleValues(); } super.render(); - if (this._toonShader) { + if (this._shader === TOONSHADER_OUTLINE) { const { shapes, UI, plane, boundingBox } = this._groups; this._setVisible(this._initalValues, [shapes, UI, plane, boundingBox]); } diff --git a/src/d3/createScene.js b/src/d3/createScene.js index 9987e7c..c50e392 100644 --- a/src/d3/createScene.js +++ b/src/d3/createScene.js @@ -1,6 +1,6 @@ import * as THREE from 'three'; import ShapesManager from './ShapesManager.js'; -import RenderChain from './RenderChain.js'; +import RenderChain, { TOONSHADER, TOONSHADER_OUTLINE } from './RenderChain.js'; import { hasExtensionsFor } from '../utils/webGLSupport.js'; import { CANVAS_SIZE } from '../constants/d2Constants.js'; @@ -17,7 +17,7 @@ export default function createScene(state, canvas) { scene.add(camera); - const shapesManager = new ShapesManager({ toonShader: hasExtensionsFor.toonShaderThumbnail }); + const shapesManager = new ShapesManager(); shapesManager.update(state); scene.add(shapesManager); @@ -37,7 +37,8 @@ export default function createScene(state, canvas) { const renderer = new THREE.WebGLRenderer({ canvas, alpha: true }); - const renderChain = new RenderChain(renderer, scene, camera, hasExtensionsFor.toonShaderThumbnail, { + const shader = hasExtensionsFor.toonShaderThumbnail ? TOONSHADER_OUTLINE : TOONSHADER; + const renderChain = new RenderChain(renderer, scene, camera, shader, { plane, UI: new THREE.Object3D(), shapes: shapesManager, diff --git a/src/d3/effects/AnaglyphPass.js b/src/d3/effects/AnaglyphPass.js new file mode 100644 index 0000000..990baf5 --- /dev/null +++ b/src/d3/effects/AnaglyphPass.js @@ -0,0 +1,66 @@ +import * as THREE from 'three'; +import anaglyphVert from '../../../shaders/anaglyph_vert.glsl'; +import anaglyphFrag from '../../../shaders/anaglyph_frag.glsl'; + +const COLOR_MATRIX_LEFT = new THREE.Matrix3().fromArray([ + 1.0671679973602295, -0.0016435992438346148, 0.0001777536963345483, + -0.028107794001698494, -0.00019593400065787137, -0.0002875397040043026, + -0.04279090091586113, 0.000015809757314855233, -0.00024287120322696865 +]); +const COLOR_MATRIX_RIGHT = new THREE.Matrix3().fromArray([ + -0.0355340838432312, -0.06440307199954987, 0.018319187685847282, + -0.10269022732973099, 0.8079727292060852, -0.04835830628871918, + 0.0001224992738571018, -0.009558862075209618, 0.567823588848114 +]); + +export default class AnaglyphPass { + constructor(scene, camera) { + this.scene = scene; + this.camera = camera; + + this.clear = true; + this.renderToScreen = false; + + const params = { + minFilter: THREE.LinearFilter, + magFilter: THREE.NearestFilter, + format: THREE.RGBAFormat + }; + + this._stereo = new THREE.StereoCamera(); + + this._renderTargetL = new THREE.WebGLRenderTarget(1, 1, params); + this._renderTargetR = new THREE.WebGLRenderTarget(1, 1, params); + + this._material = new THREE.ShaderMaterial({ + uniforms: { + mapLeft: { value: this._renderTargetL.texture }, + mapRight: { value: this._renderTargetR.texture }, + colorMatrixLeft: { value: COLOR_MATRIX_LEFT }, + colorMatrixRight: { value: COLOR_MATRIX_RIGHT } + }, + vertexShader: anaglyphVert, + fragmentShader: anaglyphFrag + }); + + this._camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); + this._scene = new THREE.Scene(); + this._quad = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2), this._material); + this._quad.frustumCulled = false; + this._scene.add(this._quad); + } + + setSize(width, height, pixelRatio = 1) { + this._renderTargetL.setSize(width * pixelRatio, height * pixelRatio); + this._renderTargetR.setSize(width * pixelRatio, height * pixelRatio); + } + + render(renderer, writeBuffer, readBuffer, delta, maskActive) { + this.scene.updateMatrixWorld(); + this._stereo.update(this.camera); + + renderer.render(this.scene, this._stereo.cameraL, this._renderTargetL, true); + renderer.render(this.scene, this._stereo.cameraR, this._renderTargetR, true); + renderer.render(this._scene, this._camera, this.renderToScreen ? null : readBuffer, this.clear); + } +} diff --git a/src/d3/OutlinePass.js b/src/d3/effects/OutlinePass.js similarity index 86% rename from src/d3/OutlinePass.js rename to src/d3/effects/OutlinePass.js index 606021f..993077c 100644 --- a/src/d3/OutlinePass.js +++ b/src/d3/effects/OutlinePass.js @@ -1,10 +1,10 @@ import * as THREE from 'three'; -import normalDepthVert from '../../shaders/normal_depth_vert.glsl'; -import normalDepthFrag from '../../shaders/normal_depth_frag.glsl'; -import edgeVert from '../../shaders/edge_vert.glsl'; -import edgeFrag from '../../shaders/edge_frag.glsl'; -import combineVert from '../../shaders/combine_vert.glsl'; -import combineFrag from '../../shaders/combine_frag.glsl'; +import normalDepthVert from '../../../shaders/normal_depth_vert.glsl'; +import normalDepthFrag from '../../../shaders/normal_depth_frag.glsl'; +import edgeVert from '../../../shaders/edge_vert.glsl'; +import edgeFrag from '../../../shaders/edge_frag.glsl'; +import combineVert from '../../../shaders/combine_vert.glsl'; +import combineFrag from '../../../shaders/combine_frag.glsl'; export default class OutlinePass { constructor(scene, camera, callbackBeforeRender) { diff --git a/src/d3/RenderPass.js b/src/d3/effects/RenderPass.js similarity index 100% rename from src/d3/RenderPass.js rename to src/d3/effects/RenderPass.js From 83113e65b26cee7b9e61a33274c893af0479d611 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Wed, 10 Jan 2018 14:15:09 +0100 Subject: [PATCH 10/13] remove unused imports --- src/d3/transformers/BaseTransformer.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/d3/transformers/BaseTransformer.js b/src/d3/transformers/BaseTransformer.js index e4d0415..36c2e5d 100644 --- a/src/d3/transformers/BaseTransformer.js +++ b/src/d3/transformers/BaseTransformer.js @@ -2,8 +2,6 @@ import * as THREE from 'three'; import * as actions from '../../actions/index.js'; import { EventObject3D } from '../EventScene.js'; import transposeEvents from '../../utils/transposeEvents.js'; -import ShapeMesh from '../ShapeMesh.js'; -import { SpriteHandle } from '../../utils/threeUtils.js'; const RAY_CASTER = new THREE.Raycaster(); const MOUSE = new THREE.Vector2(); From b674769ef8921196a79cbb61ee7f412a3bdf22ab Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Wed, 10 Jan 2018 14:19:57 +0100 Subject: [PATCH 11/13] normalize mouse wheel --- package-lock.json | 5 +++++ package.json | 1 + src/d2/EventGroup.js | 3 ++- src/d3/EventScene.js | 3 ++- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 950584e..9d2f26e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8438,6 +8438,11 @@ "sort-keys": "1.1.2" } }, + "normalize-wheel": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", + "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" + }, "npm": { "version": "2.15.12", "resolved": "https://registry.npmjs.org/npm/-/npm-2.15.12.tgz", diff --git a/package.json b/package.json index c3076bd..d789a6f 100755 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "keycode": "^2.1.9", "lodash": "^4.17.4", "memoizee": "^0.3.9", + "normalize-wheel": "^1.0.1", "pouchdb": "^6.3.4", "proptypes": "^1.1.0", "raf": "^3.4.0", diff --git a/src/d2/EventGroup.js b/src/d2/EventGroup.js index 7779e08..b5b8900 100644 --- a/src/d2/EventGroup.js +++ b/src/d2/EventGroup.js @@ -2,6 +2,7 @@ import { Group, Utils } from 'cal'; import createListener from 'touch-events'; import bowser from 'bowser'; import { convertEvent, isMouseEvent } from '../utils/pointerUtils.js'; +import normalizeWheel from 'normalize-wheel'; const events = [ 'wheel', 'tap', @@ -64,7 +65,7 @@ export default class EventGroup extends Group { if (event.event) gestureEvent.position = _convertEvent(event.event); if (event.events) gestureEvent.positions = event.events.map(_convertEvent); if (event.preEvents) gestureEvent.preDrags = event.preEvents.map(_convertEvent); - if (event.event && event.event.deltaY !== undefined) gestureEvent.wheelDelta = event.event.deltaY; + if (event.event && event.event.deltaY !== undefined) gestureEvent.wheelDelta = normalizeWheel(event.event).pixelY; this.onEvent(gestureEvent); } diff --git a/src/d3/EventScene.js b/src/d3/EventScene.js index 9f5414c..e499e8a 100644 --- a/src/d3/EventScene.js +++ b/src/d3/EventScene.js @@ -3,6 +3,7 @@ import { Utils } from 'cal'; import createListener from 'touch-events'; import bowser from 'bowser'; import { convertEvent, isMouseEvent } from '../utils/pointerUtils.js'; +import normalizeWheel from 'normalize-wheel'; const events = ['wheel', 'tap', 'dragstart', 'drag', 'dragend', 'seconddragstart', 'seconddrag', 'seconddragend', 'multitouchstart', 'multitouch', 'multitouchend']; @@ -41,7 +42,7 @@ export class EventScene extends THREE.Scene { if (event.event) gestureEvent.position = _convertEvent(event.event); if (event.events) gestureEvent.positions = event.events.map(_convertEvent); if (event.preEvents) gestureEvent.preDrags = event.preEvents.map(_convertEvent); - if (event.event && event.event.deltaY !== undefined) gestureEvent.wheelDelta = event.event.deltaY; + if (event.event && event.event.deltaY !== undefined) gestureEvent.wheelDelta = normalizeWheel(event.event).pixelY; this.onEvent(gestureEvent); }; From 1b66fc21e0f3ee94dbe41ec8a0c53be53122c1aa Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Wed, 10 Jan 2018 15:24:25 +0100 Subject: [PATCH 12/13] linter --- src/components/DoodlePreview.js | 2 +- src/components/Menu.js | 10 +++------- src/components/SketcherToolbars.js | 20 +++++++++++++------- src/components/SubMenu.js | 4 +++- src/d2/EventGroup.js | 4 +++- src/d2/tools/PolygonTool.js | 18 ------------------ src/d3/EventScene.js | 4 +++- src/d3/ShapeMesh.js | 2 +- src/d3/effects/AnaglyphPass.js | 2 +- src/d3/effects/RenderPass.js | 6 ++---- src/d3/transformers/StampTransformer.js | 1 - src/reducer/d2/pinchZoomReducer.js | 1 - src/reducer/d2/tools/eraserReducer.js | 5 ++++- src/reducer/d2/tools/pipetteReducer.js | 2 -- 14 files changed, 34 insertions(+), 47 deletions(-) diff --git a/src/components/DoodlePreview.js b/src/components/DoodlePreview.js index 8003515..4d1af00 100644 --- a/src/components/DoodlePreview.js +++ b/src/components/DoodlePreview.js @@ -45,7 +45,7 @@ class DoodlePreview extends React.Component { scene: null }; - async componentDidMount() { + async componentWillMount() { let { docData, sketchData } = this.props; if (docData) sketchData = await JSONToSketchData(this.props.docData); diff --git a/src/components/Menu.js b/src/components/Menu.js index 0b08362..3e1a6f7 100644 --- a/src/components/Menu.js +++ b/src/components/Menu.js @@ -1,7 +1,5 @@ import React from 'react'; import PropTypes from 'prop-types'; -import initialMenuStructure from '../constants/menu.js'; -import { connect } from 'react-redux'; // import createDebug from 'debug'; // const debug = createDebug('d3d:menu'); @@ -14,7 +12,7 @@ class Menu extends React.Component { value: PropTypes.string, className: PropTypes.string, children: PropTypes.node, - stateMenu: PropTypes.object + id: PropTypes.string }; onSelect = (event) => { const { onSelect, value } = this.props; @@ -23,7 +21,7 @@ class Menu extends React.Component { if (onSelect) onSelect({ ...event, menuValue }); }; render() { - const { className = '', id, selectedValue, onOpen, onClose, value, children, stateMenu } = this.props; + const { className = '', id, selectedValue, onOpen, onClose, children } = this.props; return (
    {React.Children.map(children, (child) => { @@ -39,6 +37,4 @@ class Menu extends React.Component { } } -export default connect(state => ({ - stateMenu: state.sketcher.present.menus -}))(Menu); +export default Menu; diff --git a/src/components/SketcherToolbars.js b/src/components/SketcherToolbars.js index 3255ed6..b22ea96 100644 --- a/src/components/SketcherToolbars.js +++ b/src/components/SketcherToolbars.js @@ -234,13 +234,19 @@ const getMenus = createSelector([ state => state.sketcher.present.menus, state => state.sketcher.present.d2.tool, 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.sketcher.present.objectsById[id].solid).length, - state => state.sketcher.present.selection.objects.some(({ id }) => state.sketcher.present.objectsById[id].type === 'TEXT') -], (menus, activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText) => ({ - toolbar2d: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText, nestChildren(menus, menus[TOOLBAR2D])), - toolbar3d: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText, nestChildren(menus, menus[TOOLBAR3D])), - context: filterMenus(activeTool, numSelectedObjects, numFilledObjects, numSolidObjects, selectionIncludesText, nestChildren(menus, menus[CONTEXT])) + state => state.sketcher.present.selection.objects.filter(({ id }) => { + return state.sketcher.present.objectsById[id].fill; + }).length, + state => state.sketcher.present.selection.objects.filter(({ id }) => { + return state.sketcher.present.objectsById[id].solid; + }).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)); diff --git a/src/components/SubMenu.js b/src/components/SubMenu.js index 8c8dceb..79e6eef 100644 --- a/src/components/SubMenu.js +++ b/src/components/SubMenu.js @@ -67,7 +67,9 @@ class SubMenu extends React.Component { } }; 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 = {}; if (id === 'color-picker-tool') { diff --git a/src/d2/EventGroup.js b/src/d2/EventGroup.js index b5b8900..880ae7d 100644 --- a/src/d2/EventGroup.js +++ b/src/d2/EventGroup.js @@ -65,7 +65,9 @@ export default class EventGroup extends Group { if (event.event) gestureEvent.position = _convertEvent(event.event); if (event.events) gestureEvent.positions = event.events.map(_convertEvent); if (event.preEvents) gestureEvent.preDrags = event.preEvents.map(_convertEvent); - if (event.event && event.event.deltaY !== undefined) gestureEvent.wheelDelta = normalizeWheel(event.event).pixelY; + if (event.event && event.event.deltaY !== undefined) { + gestureEvent.wheelDelta = normalizeWheel(event.event).pixelY; + } this.onEvent(gestureEvent); } diff --git a/src/d2/tools/PolygonTool.js b/src/d2/tools/PolygonTool.js index ce66b1e..1501191 100644 --- a/src/d2/tools/PolygonTool.js +++ b/src/d2/tools/PolygonTool.js @@ -58,24 +58,6 @@ export default class PolygonTool extends BaseTool { context.restore(); context.beginPath(); - - // const anglePosition = this.anglePosition.applyMatrix(matrix); - // context.arc(anglePosition.x, anglePosition.y, 20, 0, this.angleDegrees, this.angleDegrees > Math.PI); - // - // context.strokeStyle = 'black'; - // context.lineWidth = 1; - // context.stroke(); - // - // const angleTextPos = new Vector(28, 0) - // .rotate((this.angleDegrees < Math.PI ? this.angleDegrees : this.angleDegrees - Math.PI * 2.0) / 2) - // .add(anglePosition); - // context.textAlign = 'start'; - // context.textBaseline = 'middle'; - // context.fillStyle = '#000'; - // context.font = '10px Arial'; - // - // const angleDegrees = this.angleDegrees < Math.PI ? this.angleDegrees : Math.PI * 2 - this.angleDegrees; - // dimensionsText.drawText(context, humanReadable.degrees(angleDegrees), angleTextPos.x, angleTextPos.y); } } } diff --git a/src/d3/EventScene.js b/src/d3/EventScene.js index e499e8a..761b184 100644 --- a/src/d3/EventScene.js +++ b/src/d3/EventScene.js @@ -42,7 +42,9 @@ export class EventScene extends THREE.Scene { if (event.event) gestureEvent.position = _convertEvent(event.event); if (event.events) gestureEvent.positions = event.events.map(_convertEvent); if (event.preEvents) gestureEvent.preDrags = event.preEvents.map(_convertEvent); - if (event.event && event.event.deltaY !== undefined) gestureEvent.wheelDelta = normalizeWheel(event.event).pixelY; + if (event.event && event.event.deltaY !== undefined) { + gestureEvent.wheelDelta = normalizeWheel(event.event).pixelY; + } this.onEvent(gestureEvent); }; diff --git a/src/d3/ShapeMesh.js b/src/d3/ShapeMesh.js index ac69806..625bf61 100644 --- a/src/d3/ShapeMesh.js +++ b/src/d3/ShapeMesh.js @@ -21,7 +21,7 @@ class ShapeMesh extends THREE.Object3D { super(); this.name = shapeData.UID; - const { sculpt, rotate, twist, height, type, transform, z, color, fill, solid } = shapeData; + const { sculpt, rotate, twist, height, type, transform, z, color, solid } = shapeData; const material = new MatcapMaterial({ color: new THREE.Color(color) }); diff --git a/src/d3/effects/AnaglyphPass.js b/src/d3/effects/AnaglyphPass.js index 990baf5..98cbf32 100644 --- a/src/d3/effects/AnaglyphPass.js +++ b/src/d3/effects/AnaglyphPass.js @@ -55,7 +55,7 @@ export default class AnaglyphPass { this._renderTargetR.setSize(width * pixelRatio, height * pixelRatio); } - render(renderer, writeBuffer, readBuffer, delta, maskActive) { + render(renderer, writeBuffer, readBuffer) { this.scene.updateMatrixWorld(); this._stereo.update(this.camera); diff --git a/src/d3/effects/RenderPass.js b/src/d3/effects/RenderPass.js index c85ca24..20377f6 100644 --- a/src/d3/effects/RenderPass.js +++ b/src/d3/effects/RenderPass.js @@ -1,5 +1,3 @@ -import * as THREE from 'three'; - export default class RenderPass { constructor(scene, camera, callbackBeforeRender) { this.scene = scene; @@ -10,10 +8,10 @@ export default class RenderPass { this.renderToScreen = false; } - setSize(width, height) { + setSize() { } - render(renderer, writeBuffer, readBuffer, delta, maskActive) { + render(renderer, writeBuffer, readBuffer) { if (this._callbackBeforeRender) this._callbackBeforeRender(); let oldAutoClear; diff --git a/src/d3/transformers/StampTransformer.js b/src/d3/transformers/StampTransformer.js index f9abb0e..8a1b726 100644 --- a/src/d3/transformers/StampTransformer.js +++ b/src/d3/transformers/StampTransformer.js @@ -1,5 +1,4 @@ import { CANVAS_SIZE } from '../../constants/d2Constants'; -import ShapeMesh from '../ShapeMesh.js'; import * as THREE from 'three'; import BaseTransformer from './BaseTransformer.js'; import * as actions from '../../actions/index.js'; diff --git a/src/reducer/d2/pinchZoomReducer.js b/src/reducer/d2/pinchZoomReducer.js index d022730..cc74a85 100644 --- a/src/reducer/d2/pinchZoomReducer.js +++ b/src/reducer/d2/pinchZoomReducer.js @@ -1,5 +1,4 @@ import update from 'react-addons-update'; -import { Matrix } from 'cal'; import constrainMatrix from './constrainMatrix.js'; import { calculateGestureMatrix } from '../../utils/matrixUtils.js'; import * as actions from '../../actions/index.js'; diff --git a/src/reducer/d2/tools/eraserReducer.js b/src/reducer/d2/tools/eraserReducer.js index c1e457f..0348c9b 100644 --- a/src/reducer/d2/tools/eraserReducer.js +++ b/src/reducer/d2/tools/eraserReducer.js @@ -31,5 +31,8 @@ function handleEraser(state, path, screenMatrixZoom) { roundPrecision: 0.25 }); - return subtractShapeFromState(state, eraserShape, d2Tools.ERASER, { matrix: screenMatrixZoom, scale: CLIPPER_PRECISION }); + return subtractShapeFromState(state, eraserShape, d2Tools.ERASER, { + matrix: screenMatrixZoom, + scale: CLIPPER_PRECISION + }); } diff --git a/src/reducer/d2/tools/pipetteReducer.js b/src/reducer/d2/tools/pipetteReducer.js index 234fad0..3da13eb 100644 --- a/src/reducer/d2/tools/pipetteReducer.js +++ b/src/reducer/d2/tools/pipetteReducer.js @@ -1,7 +1,5 @@ import { updateColor } from '../../selectionReducer.js'; import { getColor } from '../../../utils/objectSelectors.js'; -import { select } from '../../menusReducer.js'; -import update from 'react-addons-update'; import { updateTool as updateTool2d } from '../toolReducer.js'; export default function pipetteReducer(state, action) { From 36a73c233e569fca79d2059a50edb6bdb511aa58 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Wed, 10 Jan 2018 15:49:00 +0100 Subject: [PATCH 13/13] Fix unfilled text hit area --- src/d2/tools/BaseTool.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/d2/tools/BaseTool.js b/src/d2/tools/BaseTool.js index 3b723b5..a6f05a3 100644 --- a/src/d2/tools/BaseTool.js +++ b/src/d2/tools/BaseTool.js @@ -133,6 +133,7 @@ export default class BaseTool extends EventGroup { .filter(shapeData => { const shapeMatrix = shapeData.transform.multiplyMatrix(matrix); let shapePoints = shapeToPoints(shapeData); + let { fill } = shapeData; if (shapeData.type === 'TEXT') { if (shapeData.text.text === '') return false; @@ -143,14 +144,15 @@ export default class BaseTool extends EventGroup { new Vector(max.x, max.y), new Vector(max.x, min.y) ], holes: [] }]; + fill = true; } const isHit = shapePoints .some(({ points, holes }) => { const shape = applyMatrixOnShape([points, ...holes], shapeMatrix); - const clipperShape = new ClipperShape(shape, shapeData.fill, true, true); + const clipperShape = new ClipperShape(shape, fill, true, true); - if (shapeData.fill) { + if (fill) { return clipperShape .fixOrientation() .pointInShape(position, true, true);