implement pipet

This commit is contained in:
casperlamboo 2017-11-29 18:12:01 +01:00
parent e1cd5c0260
commit 1021f5e8dc
14 changed files with 120 additions and 90 deletions

View File

@ -28,13 +28,13 @@ window.actions = actionWrapper(actions, store.dispatch);
// add inital shapes // add inital shapes
import * as CAL from 'cal'; import * as CAL from 'cal';
store.dispatch(actions.addObject({ // store.dispatch(actions.addObject({
type: 'FREE_HAND', // type: 'FREE_HAND',
fill: false, // fill: false,
solid: false, // solid: false,
points: [new CAL.Vector(-20, 0), new CAL.Vector(10, 1)], // points: [new CAL.Vector(-20, 0), new CAL.Vector(10, 1)],
transform: new CAL.Matrix({ x: 0, y: 0 }) // transform: new CAL.Matrix({ x: 0, y: 0 })
})); // }));
store.dispatch(actions.addObject({ store.dispatch(actions.addObject({
type: 'RECT', type: 'RECT',
fill: true, fill: true,

View File

@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import * as CAL from 'cal'; import * as CAL from 'cal';
import * as toolNames from '../constants/d2Tools'; import * as toolNames from '../constants/d2Tools';
import { PIPETTE } from '../constants/contextTools.js';
import { CANVAS_SIZE } from '../constants/d2Constants'; import { CANVAS_SIZE } from '../constants/d2Constants';
import createRAFOnce from '../utils/rafOnce.js'; import createRAFOnce from '../utils/rafOnce.js';
import Grid from '../d2/Grid.js'; import Grid from '../d2/Grid.js';
@ -13,6 +14,7 @@ import EraserTool from '../d2/tools/EraserTool.js';
import BrushTool from '../d2/tools/BrushTool.js'; import BrushTool from '../d2/tools/BrushTool.js';
import PolygonTool from '../d2/tools/PolygonTool.js'; import PolygonTool from '../d2/tools/PolygonTool.js';
import CircleTool from '../d2/tools/CircleTool.js'; import CircleTool from '../d2/tools/CircleTool.js';
import PipetteTool from '../d2/tools/PipetteTool.js';
import TextTool from '../d2/tools/TextTool.js'; import TextTool from '../d2/tools/TextTool.js';
import BucketTool from '../d2/tools/BucketTool.js'; import BucketTool from '../d2/tools/BucketTool.js';
import PhotoGuideTool from '../d2/tools/PhotoGuideTool.js'; import PhotoGuideTool from '../d2/tools/PhotoGuideTool.js';
@ -30,14 +32,15 @@ const CANVAS_WIDTH = CANVAS_SIZE * 2;
const CANVAS_HEIGHT = CANVAS_SIZE * 2; const CANVAS_HEIGHT = CANVAS_SIZE * 2;
const tools = { const tools = {
[toolNames.TRANSFORM]: TransformTool, [toolNames.TRANSFORM]: TransformTool,
[toolNames.ERASER]: EraserTool, [toolNames.ERASER]: EraserTool,
[toolNames.TEXT]: TextTool, [toolNames.TEXT]: TextTool,
[toolNames.BUCKET]: BucketTool, [toolNames.BUCKET]: BucketTool,
[toolNames.PHOTO_GUIDE]: PhotoGuideTool, [toolNames.PHOTO_GUIDE]: PhotoGuideTool,
[toolNames.BRUSH]: BrushTool, [toolNames.BRUSH]: BrushTool,
[toolNames.POLYGON]: PolygonTool, [toolNames.POLYGON]: PolygonTool,
[toolNames.CIRCLE]: CircleTool [toolNames.CIRCLE]: CircleTool,
[PIPETTE]: PipetteTool
}; };
// TODO the same as 3d // TODO the same as 3d

View File

@ -3,10 +3,12 @@ import PropTypes from 'prop-types';
import Button from './Button.js'; import Button from './Button.js';
import Menu from './Menu.js'; import Menu from './Menu.js';
import bowser from 'bowser'; import bowser from 'bowser';
import { connect } from 'react-redux';
import { hexToStyle } from '../utils/colorUtils.js';
// import createDebug from 'debug'; // import createDebug from 'debug';
// const debug = createDebug('d3d:ui:submenu'); // const debug = createDebug('d3d:ui:submenu');
export default class SubMenu extends React.Component { class SubMenu extends React.Component {
static propTypes = { static propTypes = {
onSelect: PropTypes.func, onSelect: PropTypes.func,
onOpen: PropTypes.func, onOpen: PropTypes.func,
@ -64,12 +66,17 @@ export default class SubMenu extends React.Component {
} }
}; };
render() { render() {
const { id, value, selected, open, selectedValue, children, svg, toggleBehavior } = this.props; const { id, value, selected, open, selectedValue, children, svg, toggleBehavior, color, solid } = this.props;
const style = {};
if (id === 'color-picker-tool') {
style.fill = solid ? hexToStyle(color) : 'url(#holepattern)';
}
let className = 'submenu'; let className = 'submenu';
if (open) className += ' open'; if (open) className += ' open';
return ( return (
<li id={id} className={className} ref="li"> <li id={id} className={className} ref="li" style={style}>
<Button <Button
id={`${selectedValue}-menu`} id={`${selectedValue}-menu`}
value={selectedValue} value={selectedValue}
@ -89,3 +96,8 @@ export default class SubMenu extends React.Component {
); );
} }
} }
export default connect(state => ({
color: state.sketcher.present.context.color,
solid: state.sketcher.present.context.solid
}))(SubMenu);

View File

@ -21,6 +21,7 @@ export const DARK_GREEN = 'color-dark-green';
export const DARK_PINK = 'color-dark-pink'; export const DARK_PINK = 'color-dark-pink';
export const DARK_YELLOW = 'color-dark-yellow'; export const DARK_YELLOW = 'color-dark-yellow';
export const HOLE_MATERIAL = 'color-hole-material'; export const HOLE_MATERIAL = 'color-hole-material';
export const PIPETTE = 'pipette-tool';
export const COLORS = [ export const COLORS = [
LIGHT_BLUE, LIGHT_BLUE,

View File

@ -5,6 +5,7 @@ export const TRANSFORM = 'transform-tool';
export const ERASER = 'eraser-tool'; export const ERASER = 'eraser-tool';
export const TEXT = 'text-tool'; export const TEXT = 'text-tool';
export const PHOTO_GUIDE = 'photo-guide-tool'; export const PHOTO_GUIDE = 'photo-guide-tool';
export const PIPETTE = 'pipette-tool';
export const CIRCLE = 'circle-tool'; export const CIRCLE = 'circle-tool';
export const CIRCLE_SEGMENT = 'circle-segment-tool'; export const CIRCLE_SEGMENT = 'circle-segment-tool';

View File

@ -18,22 +18,3 @@ export const COLOR_STRING_TO_HEX = {
[contextTools.DARK_PINK]: 0xe94481, [contextTools.DARK_PINK]: 0xe94481,
[contextTools.DARK_YELLOW]: 0xdfde24 [contextTools.DARK_YELLOW]: 0xdfde24
}; };
export const COLOR_HEX_TO_STRING = Object
.entries(COLOR_STRING_TO_HEX)
.reduce((obj, [key, value]) => {
obj[value] = key;
return obj;
}, {});
// LEGACY
// add old color codes to corresponding color strings
// so old doodles with old colors are previewd correctly in color picker color selector
COLOR_HEX_TO_STRING[0x96cbef] = contextTools.BLUE;
COLOR_HEX_TO_STRING[0x9bca87] = contextTools.GREEN;
COLOR_HEX_TO_STRING[0xf08eb2] = contextTools.PINK;
COLOR_HEX_TO_STRING[0xfff59a] = contextTools.YELLOW;
COLOR_HEX_TO_STRING[0x7098b3] = contextTools.DARK_BLUE;
COLOR_HEX_TO_STRING[0x7ab063] = contextTools.DARK_GREEN;
COLOR_HEX_TO_STRING[0xb36984] = contextTools.DARK_PINK;
COLOR_HEX_TO_STRING[0xf5e872] = contextTools.DARK_YELLOW;
COLOR_HEX_TO_STRING[0x00DDFF] = contextTools.BLUE;

View File

@ -66,7 +66,7 @@ const context = {
{ value: contextTools.LIGHT_GREEN, svg: '#color-picker-empty-fill' }, { value: contextTools.LIGHT_GREEN, svg: '#color-picker-empty-fill' },
{ value: contextTools.LIGHT_PINK, svg: '#color-picker-empty-fill' }, { value: contextTools.LIGHT_PINK, svg: '#color-picker-empty-fill' },
{ value: contextTools.LIGHT_YELLOW, svg: '#color-picker-empty-fill' }, { value: contextTools.LIGHT_YELLOW, svg: '#color-picker-empty-fill' },
// { value: contextTools.HOLE_MATERIAL, svg: '#color-picker-empty-fill' }, { value: contextTools.PIPETTE },
{ value: contextTools.BLUE, svg: '#color-picker-empty-fill' }, { value: contextTools.BLUE, svg: '#color-picker-empty-fill' },
{ value: contextTools.GREEN, svg: '#color-picker-empty-fill' }, { value: contextTools.GREEN, svg: '#color-picker-empty-fill' },
{ value: contextTools.PINK, svg: '#color-picker-empty-fill' }, { value: contextTools.PINK, svg: '#color-picker-empty-fill' },

View File

@ -0,0 +1,8 @@
import BaseTool from './BaseTool.js';
export default class PipetteTool extends BaseTool {
constructor(dispatch, sceneSpaceContainer, renderRequest) {
super(dispatch, sceneSpaceContainer, renderRequest);
this.enableHitDetection = true;
}
}

View File

@ -7,6 +7,8 @@ import * as actions from '../actions/index.js';
import { select } from './menusReducer.js'; import { select } from './menusReducer.js';
import { getSelectedObjectsSelector, getBoundingBox } from '../utils/selectionUtils.js'; import { getSelectedObjectsSelector, getBoundingBox } from '../utils/selectionUtils.js';
import { Matrix } from 'cal'; import { Matrix } from 'cal';
import { updateTool as updateTool2d } from './d2/toolReducer.js';
import { updateColor } from './selectionReducer.js';
export default function (state, action) { export default function (state, action) {
switch (action.category) { switch (action.category) {
@ -16,15 +18,7 @@ export default function (state, action) {
const [firstSelected] = state.selection.objects; const [firstSelected] = state.selection.objects;
const isSolid = firstSelected ? state.objectsById[firstSelected.id].solid : true; const isSolid = firstSelected ? state.objectsById[firstSelected.id].solid : true;
let color; const color = isSolid ? contextTools.PIPETTE : contextTools.HOLE_MATERIAL;
if (!isSolid) {
color = contextTools.HOLE_MATERIAL;
} else {
const colorHex = firstSelected ? state.objectsById[firstSelected.id].color : state.context.color;
// pick current draw color when color is unknown
color = COLOR_HEX_TO_STRING[colorHex] || COLOR_HEX_TO_STRING[state.context.color];
}
menus = select(menus, color); menus = select(menus, color);
const fillBool = firstSelected && state.objectsById[firstSelected.id].fill; const fillBool = firstSelected && state.objectsById[firstSelected.id].fill;
@ -40,7 +34,8 @@ export default function (state, action) {
switch (action.type) { switch (action.type) {
case actions.D2_CHANGE_TOOL: { case actions.D2_CHANGE_TOOL: {
const color = state.context.solid ? COLOR_HEX_TO_STRING[state.context.color] : contextTools.HOLE_MATERIAL; const color = state.context.solid ? contextTools.PIPETTE : contextTools.HOLE_MATERIAL;
return update(state, { return update(state, {
menus: { $set: select(state.menus, color) } menus: { $set: select(state.menus, color) }
}); });
@ -51,6 +46,17 @@ export default function (state, action) {
} }
switch (action.tool) { switch (action.tool) {
case contextTools.PIPETTE: {
state = update(state, {
context: {
lastTool: { $set: state.d2.tool }
}
});
state = updateTool2d(state, contextTools.PIPETTE);
return state;
}
case contextTools.HOLE_MATERIAL: { case contextTools.HOLE_MATERIAL: {
return update(state, { return update(state, {
objectsById: state.selection.objects.reduce((updateObject, { id }) => { objectsById: state.selection.objects.reduce((updateObject, { id }) => {
@ -76,19 +82,7 @@ export default function (state, action) {
case contextTools.DARK_PINK: case contextTools.DARK_PINK:
case contextTools.DARK_YELLOW: { case contextTools.DARK_YELLOW: {
const color = COLOR_STRING_TO_HEX[action.tool]; const color = COLOR_STRING_TO_HEX[action.tool];
return update(state, { return updateColor(state, color);
objectsById: state.selection.objects.reduce((updateObject, { id }) => {
updateObject[id] = {
color: { $set: color },
solid: { $set: true }
};
return updateObject;
}, {}),
context: {
solid: { $set: true },
color: { $set: color }
}
});
} }
case contextTools.ERASER_SIZE_SMALL: case contextTools.ERASER_SIZE_SMALL:

View File

@ -12,8 +12,10 @@ import textReducer from './tools/textReducer.js';
import photoGuideReducer from './tools/photoGuideReducer.js'; import photoGuideReducer from './tools/photoGuideReducer.js';
import { transformReducer } from './tools/transformReducer.js'; import { transformReducer } from './tools/transformReducer.js';
import eraserReducer from './tools/eraserReducer.js'; import eraserReducer from './tools/eraserReducer.js';
import pipetteReducer from './tools/pipetteReducer.js';
import * as actions from '../../actions/index.js'; import * as actions from '../../actions/index.js';
import * as tools from '../../constants/d2Tools.js'; import * as tools from '../../constants/d2Tools.js';
import { PIPETTE } from '../../constants/contextTools.js';
import createDebug from 'debug'; import createDebug from 'debug';
const debug = createDebug('d3d:reducer:d2:tool'); const debug = createDebug('d3d:reducer:d2:tool');
@ -32,7 +34,8 @@ const reducers = {
[tools.PHOTO_GUIDE]: photoGuideReducer, [tools.PHOTO_GUIDE]: photoGuideReducer,
[tools.BUCKET]: bucketReducer, [tools.BUCKET]: bucketReducer,
[tools.TEXT]: textReducer, [tools.TEXT]: textReducer,
[tools.BRUSH]: penReducer [tools.BRUSH]: penReducer,
[PIPETTE]: pipetteReducer
}; };
export default function toolReducer(state, action) { export default function toolReducer(state, action) {
@ -56,7 +59,7 @@ export default function toolReducer(state, action) {
} }
} }
function updateTool(state, newTool) { export function updateTool(state, newTool) {
if (newTool === state.d2.tool) { if (newTool === state.d2.tool) {
return state; return state;
} else { } else {

View File

@ -8,7 +8,6 @@ import { shapeToPoints } from '../../../shape/shapeToPoints.js';
import { applyMatrixOnShape, pathToVectorPath } from '../../../utils/vectorUtils.js'; import { applyMatrixOnShape, pathToVectorPath } from '../../../utils/vectorUtils.js';
import { addObject } from '../../../reducer/objectReducers.js'; import { addObject } from '../../../reducer/objectReducers.js';
import subtractShapeFromState from '../../../utils/subtractShapeFromState.js'; import subtractShapeFromState from '../../../utils/subtractShapeFromState.js';
import { getColor, getFirst, filterType, getObjectsFromIds } from '../../../utils/objectSelectors.js';
import createDebug from 'debug'; import createDebug from 'debug';
const debug = createDebug('d3d:reducer:bucket'); const debug = createDebug('d3d:reducer:bucket');
@ -20,19 +19,6 @@ export default function bucketReducer(state, action) {
switch (action.type) { switch (action.type) {
case actions.D2_TAP: case actions.D2_TAP:
const color = state.context.color; const color = state.context.color;
// if (experimentalColorPicker) {
// const imageColor = getColor(
// getFirst(
// filterType(
// getObjectsFromIds(state, action.objects),
// 'IMAGE_GUIDE'
// )
// ),
// action.position,
// action.screenMatrixZoom
// );
// if (imageColor !== null) color = imageColor;
// }
// if clicked on a filled shape change shape color // if clicked on a filled shape change shape color
const filledPathIndex = action.objects.findIndex(id => ( const filledPathIndex = action.objects.findIndex(id => (

View File

@ -0,0 +1,21 @@
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) {
const [object] = action.objects;
if (object) {
const shapeData = state.objectsById[object];
let color;
if (shapeData.type === 'IMAGE_GUIDE') {
color = getColor(shapeData, action.position, action.screenMatrixZoom);
} else {
color = shapeData.color;
}
state = updateColor(state, color);
}
state = updateTool2d(state, state.context.lastTool);
return state;
}

View File

@ -131,3 +131,19 @@ function deselectAll(state) {
}); });
} }
} }
export function updateColor(state, color) {
return update(state, {
objectsById: state.selection.objects.reduce((updateObject, { id }) => {
updateObject[id] = {
color: { $set: color },
solid: { $set: true }
};
return updateObject;
}, {}),
context: {
solid: { $set: true },
color: { $set: color }
}
});
}

View File

@ -257,45 +257,49 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
#color-light-blue, #color-light-blue-menu { #color-light-blue {
fill: #c8e4f7; fill: #c8e4f7;
} }
#color-light-green, #color-light-green-menu { #color-light-green {
fill: #cbe6c0; fill: #cbe6c0;
} }
#color-light-pink, #color-light-pink-menu { #color-light-pink {
fill: #f8c4d8; fill: #f8c4d8;
} }
#color-light-yellow, #color-light-yellow-menu { #color-light-yellow {
fill: #f5f5c0; fill: #f5f5c0;
} }
#color-blue, #color-blue-menu { #color-blue {
fill: #92c8ef; fill: #92c8ef;
} }
#color-green, #color-green-menu { #color-green {
fill: #99cc81; fill: #99cc81;
} }
#color-pink, #color-pink-menu { #color-pink {
fill: #f28bb1; fill: #f28bb1;
} }
#color-yellow, #color-yellow-menu { #color-yellow {
fill: #ebea7f; fill: #ebea7f;
} }
#color-dark-blue, #color-dark-blue-menu { #color-dark-blue {
fill: #50a8e4; fill: #50a8e4;
} }
#color-dark-green, #color-dark-green-menu { #color-dark-green {
fill: #5aae31; fill: #5aae31;
} }
#color-dark-pink, #color-dark-pink-menu { #color-dark-pink {
fill: #e94481; fill: #e94481;
} }
#color-dark-yellow, #color-dark-yellow-menu { #color-dark-yellow {
fill: #dfde24; fill: #dfde24;
} }
#color-hole-material, #color-hole-material-menu { #color-hole-material {
fill: url(#holepattern); fill: url(#holepattern);
} }
#pipette-tool {
background-size: 30px;
background-image: url('../img/contextmenu/btnPicker.png');
}
/* menu's */ /* menu's */
.menu { .menu {