diff --git a/src/components/Field/Field.js b/src/components/Field/Field.js index 027e08b2..0e987a16 100644 --- a/src/components/Field/Field.js +++ b/src/components/Field/Field.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useCallback, useMemo } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import './Field.css'; import Brush from '../Tools/Brush'; @@ -19,33 +19,47 @@ const Field = () => { const field = useSelector((state) => state.auth.field); const pixelSize = useSelector((state) => state.auth.pixelSize); const brush = useSelector((state) => state.auth.brush); + const currentColor = useSelector((state) => state.auth.currentColor); + const historyColor = useSelector((state) => state.auth.historyColor); - const changePixelColor = (index) => { - dispatch({ - type: 'CHANGE_PIXEL_COLOR_AND_SAVE_TO_HISTORY', - payload: { index }, - }); - }; + const changePixelColor = useCallback( + (index) => { + if (!field || !field[index]) return; + + const color = field[index].color; + if (color && !historyColor.includes(color)) { + dispatch({ + type: 'ADD_COLOR_TO_HISTORY', + payload: { color }, + }); + } + dispatch({ + type: 'CHANGE_PIXEL_COLOR_AND_SAVE_TO_HISTORY', + payload: { index, color: currentColor }, + }); + }, + [dispatch, field, currentColor, historyColor] + ); - const clearField = () => { + const clearField = useCallback(() => { dispatch({ type: 'CLEAR_FIELD', }); - }; + }, [dispatch]); - const onKeyPressed = (e) => { + const onKeyPressed = useCallback((e) => { if (e.code === 'Space' || e.type === 'mousedown') { setContinueToDraw(true); } - }; + }, []); - const onKeyUp = (e) => { + const onKeyUp = useCallback((e) => { if (e.code === 'Space' || e.type === 'mouseup') { setContinueToDraw(false); } - }; + }, []); - const saveToImage = () => { + const saveToImage = useCallback(() => { domtoimage .toJpeg(document.getElementById('capture'), { quality: 0.95 }) .then((dataUrl) => { @@ -54,11 +68,49 @@ const Field = () => { link.href = dataUrl; link.click(); }); - }; + }, []); - if (!field || !Array.isArray(field)) { - return

Loading...

; - } + const fieldMemo = useMemo(() => { + if (!field || !Array.isArray(field)) { + return

Loading...

; + } + + return ( +
setContinueToDraw(false)} + tabIndex="0" + > + {field.map((el, i) => ( +
changePixelColor(i)} + onMouseOver={ + brush !== 'fill' && brush !== 'fillPart' + ? () => changePixelColor(continueToDraw ? i : undefined) + : null + } + > + {} +
+ ))} +
+ ); + }, [field, fieldSize, pixelSize, gridMap, brush, changePixelColor, onKeyPressed, onKeyUp, continueToDraw]); return (
@@ -103,41 +155,7 @@ const Field = () => {
{/* FIELD DRAW */} -
-
setContinueToDraw(false)} - tabIndex="0" - > - {field.map((el, i) => ( -
changePixelColor(i)} - onMouseOver={ - brush !== 'fill' && brush !== 'fillPart' - ? () => changePixelColor(continueToDraw ? i : undefined) - : null - } - > - {} -
- ))} -
-
+
{fieldMemo}
diff --git a/src/components/Field/FieldSize.js b/src/components/Field/FieldSize.js index 5a991f8b..7235a3c4 100644 --- a/src/components/Field/FieldSize.js +++ b/src/components/Field/FieldSize.js @@ -1,56 +1,53 @@ import React from 'react'; -import { connect } from 'react-redux'; +import { useSelector, useDispatch } from 'react-redux'; -const FieldSize = ({ currentSize, changeFieldSize }) => ( -
-
- changeFieldSize(100)} - checked={currentSize === 100} - /> - +const FieldSize = () => { + const dispatch = useDispatch(); + const currentSize = useSelector((state) => state.auth.fieldSize); - changeFieldSize(400)} - checked={currentSize === 400} - /> - - - changeFieldSize(1600)} - checked={currentSize === 1600} - /> - - -
-
-); - -const mapStateToProps = (state) => ({ - currentSize: state.fieldSize, -}); - -const mapDispatchToProps = (dispatch) => ({ - changeFieldSize: (size) => + const changeFieldSize = (size) => { dispatch({ type: 'CHANGE_FIELD_SIZE', payload: { size }, - }), -}); + }); + }; + + return ( +
+
+ changeFieldSize(100)} + checked={currentSize === 100} + /> + + + changeFieldSize(400)} + checked={currentSize === 400} + /> + + + changeFieldSize(1600)} + checked={currentSize === 1600} + /> + + +
+
+ ); +}; -export default connect(mapStateToProps, mapDispatchToProps)(FieldSize); +export default FieldSize; diff --git a/src/components/Tools/Brush.js b/src/components/Tools/Brush.js index 2782a1c4..5921dbb2 100644 --- a/src/components/Tools/Brush.js +++ b/src/components/Tools/Brush.js @@ -1,11 +1,14 @@ import React from 'react'; -import { connect } from 'react-redux'; +import { useSelector, useDispatch } from 'react-redux'; import classnames from 'classnames'; import fill from '../icons/fill.png'; import random from '../icons/random.jpeg'; import colorpicker from '../icons/colorpicker.png'; -const Brush = ({ changeBrush, fieldRandomBrush, brush }) => { +const Brush = () => { + const dispatch = useDispatch(); + const brush = useSelector((state) => state.auth.brush); + const brushTypes = [ { type: 'dot', label: '▣' }, { type: 'horizontal', label: '↔' }, @@ -15,9 +18,23 @@ const Brush = ({ changeBrush, fieldRandomBrush, brush }) => { { type: 'fillPart', label: 'fillPart' }, { type: 'mirrorH', label: '═' }, { type: 'mirrorV', label: '||' }, - { type: 'color-picker', label: icon-colorpicker } + { type: 'color-picker', label: icon-colorpicker }, ]; + const changeBrush = (type) => { + dispatch({ + type: 'CHANGE_BRUSH', + payload: { brush: type }, + }); + }; + + const fieldRandomBrush = () => { + dispatch({ + type: 'FILL_RANDOM_BRUSH', + payload: {}, + }); + }; + return (
{brushTypes.map(({ type, label }) => ( @@ -36,19 +53,4 @@ const Brush = ({ changeBrush, fieldRandomBrush, brush }) => { ); }; -const mapStateToProps = (state) => ({ - brush: state.brush -}); - -const mapDispatchToProps = (dispatch) => ({ - changeBrush: (brush) => dispatch({ - type: 'CHANGE_BRUSH', - payload: { brush } - }), - fieldRandomBrush: () => dispatch({ - type: 'FILL_RANDOM_BRUSH', - payload: {} - }) -}); - -export default connect(mapStateToProps, mapDispatchToProps)(Brush); +export default Brush; diff --git a/src/components/Tools/ColorHistory.js b/src/components/Tools/ColorHistory.js index 76379b39..4ae9d981 100644 --- a/src/components/Tools/ColorHistory.js +++ b/src/components/Tools/ColorHistory.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { v4 as uuidv4 } from 'uuid'; import history_del from '../icons/history_del.png'; @@ -6,19 +6,19 @@ import history_del from '../icons/history_del.png'; const ColorHistory = () => { const dispatch = useDispatch(); const historyColor = useSelector((state) => state.auth.historyColor); -console.log(historyColor) - const changeColor = (color) => { + + const changeColor = useCallback((color) => { dispatch({ type: 'CHANGE_CURRENT_COLOR', payload: { color }, }); - }; + }, [dispatch]); - const deleteColorHistory = () => { + const deleteColorHistory = useCallback(() => { dispatch({ type: 'DELETE_COLOR_HISTORY', }); - }; + }, [dispatch]); return (
@@ -43,4 +43,4 @@ console.log(historyColor) ); }; -export default ColorHistory; +export default React.memo(ColorHistory); diff --git a/src/components/redux/reducers.js b/src/components/redux/reducers.js index 57950ce8..bc5f207d 100644 --- a/src/components/redux/reducers.js +++ b/src/components/redux/reducers.js @@ -18,9 +18,16 @@ const drawField = (state = initialState, action) => { case 'CHANGE_CURRENT_COLOR': return { ...state, - currentColor: action.payload.color + currentColor: action.payload.color, }; - // ******** START DRAW FUNCTIONAL ********************** + case 'ADD_COLOR_TO_HISTORY': + if (!state.historyColor.includes(action.payload.color)) { + return { + ...state, + historyColor: [...state.historyColor, action.payload.color] + }; + } + return state; case 'CHANGE_PIXEL_COLOR_AND_SAVE_TO_HISTORY': let copyField; const copyHistoryColor = [...state.historyColor, state.currentColor]; @@ -28,7 +35,7 @@ const drawField = (state = initialState, action) => { if (action.payload.index) { return { ...state, - currentColor: state.field[action.payload.index].color + currentColor: state.field[action.payload.index].color, }; } } @@ -40,11 +47,11 @@ const drawField = (state = initialState, action) => { size, state.fieldSize, state.field[action.payload.index].color, - state.currentColor + state.currentColor, ); return { ...state, - field: newField + field: newField, }; } @@ -226,37 +233,40 @@ const drawField = (state = initialState, action) => { }; function fillParticip(arrJSON, current, size, max, oldColor, newColor) { - console.log(current, size, oldColor); const a = JSON.parse(arrJSON); if (oldColor === newColor) return a; let next = []; - const stop = []; + const stop = new Set(); function ch(current) { if (a[current] && a[current].color === oldColor) { a[current].color = newColor; - stop.push(current); + stop.add(current); let up = current - size; let down = current + size; let left = current - 1; let right = current + 1; - if (right % size === 0) { - stop.push(right); + + if (current % size !== 0) { + next.push(left); + } + if ((current + 1) % size !== 0) { + next.push(right); } - if (left % size === size - 1) { - stop.push(left); + if (up >= 0) { + next.push(up); } - next.push( - ...[up, down, left, right].filter( - (e) => e >= 0 && !stop.includes(e) && !next.includes(e) && e <= max - ) - ); + if (down < max) { + next.push(down); + } + + next = next.filter((e) => e >= 0 && !stop.has(e)); } else { - stop.push(current); + stop.add(current); } next = next.filter((el) => el !== current); - return next.length > 0 ? ch(next[0], size, newColor, max) : a; + return next.length > 0 ? ch(next[0]) : a; } return ch(current); diff --git a/src/styles.css b/src/styles.css index 3353b2a9..26d9ddb2 100644 --- a/src/styles.css +++ b/src/styles.css @@ -110,7 +110,10 @@ input:checked + .slider:before { .btn-pushed { background: linear-gradient(to bottom, #fceadd 5%, rgba(226, 91, 255, .94) 100%) } +.btn-pushed:hover{ + background: linear-gradient(to bottom, #fad5ba 5%, rgba(204, 30, 241, 0.94) 100%) +} .warn { background: linear-gradient(to bottom, #fcdde3 5%, rgba(245, 130, 140, .65) 100%); border: 1px solid #ef6565