diff --git a/README.md b/README.md index 846f2e1..62ab6d5 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,18 @@ No, I'm building a tool that does the bare minimum what I require and what I don find in other open source tools. That doesn't mean of course that contributions related to Photoshop-esque features aren't welcomed. +### All self-written ? + +Yep, though it helps having worked five years in the photo software industry and having +tackled problems before. + +PhotoMound does however make use of the following excellent libraries to speed up its development: + + * [Vue](https://github.com/vuejs/vue) with [Vuex](https://github.com/vuejs/vuex) and [VueI18n](https://github.com/kazupon/vue-i18n) + * [Pickr](https://github.com/Simonwep/pickr) by Simonwep + * [Vue slider component](https://github.com/NightCatSama/vue-slider-component) by NightCatSama + * [Vue search select](https://github.com/moreta/vue-search-select#readme) by Moreta + ## Dropbox integration Requires you to [register a client id or access token](https://www.dropbox.com/developers/apps). @@ -40,7 +52,7 @@ npm run lint * Unit tests for factories * DrawableLayer should only draw when brush too lis active * Canvas clearRect() is not doing full width and height ? -* Layer view in options-panel: allow naming, repositioning, toggle visibility, set as mask +* Layer view in options-panel: allow naming, repositioning, toggle visibility, change type (for masking), opacity * Canvas util : store transparency of images * Restored base64 images should be treated as binary once more (see layer-factory) * Add brush options > size, transparency @@ -53,6 +65,7 @@ npm run lint * Export output to image file (by rendering document content on separate canvas instead of taking snapshot at incorrect scale) * Load/save documents from/to Dropbox * Use hand cursor when draggable +* Text editing using Google fonts! * Use paint brush cursor when painting * Add tools for layer rotation and scaling * Implement clone brush diff --git a/package-lock.json b/package-lock.json index 4a1fd3c..5d19bbf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "version": "0.1.0", "dependencies": { + "@simonwep/pickr": "^1.8.0", "canvas": "^2.6.1", "core-js": "^3.6.5", "dropbox": "^8.2.0", @@ -1420,6 +1421,15 @@ "node": ">= 6" } }, + "node_modules/@simonwep/pickr": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.8.0.tgz", + "integrity": "sha512-VaSD7TwktOsro5nQ/FjRx5JAJ09k5CNfGRHacgVRxeVPolUQwelz1SjL8HAOKZwTSmcnIObptpHABQS4zgN7sw==", + "dependencies": { + "core-js": "^3.8.0", + "nanopop": "^2.1.0" + } + }, "node_modules/@soda/friendly-errors-webpack-plugin": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz", @@ -11736,6 +11746,11 @@ "node": ">=0.10.0" } }, + "node_modules/nanopop": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nanopop/-/nanopop-2.1.0.tgz", + "integrity": "sha512-jGTwpFRexSH+fxappnGQtN9dspgE2ipa1aOjtR24igG0pv6JCxImIAmrLRHX+zUF5+1wtsFVbKyfP51kIGAVNw==" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -19730,6 +19745,15 @@ "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true }, + "@simonwep/pickr": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.8.0.tgz", + "integrity": "sha512-VaSD7TwktOsro5nQ/FjRx5JAJ09k5CNfGRHacgVRxeVPolUQwelz1SjL8HAOKZwTSmcnIObptpHABQS4zgN7sw==", + "requires": { + "core-js": "^3.8.0", + "nanopop": "^2.1.0" + } + }, "@soda/friendly-errors-webpack-plugin": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz", @@ -28488,6 +28512,11 @@ "to-regex": "^3.0.1" } }, + "nanopop": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nanopop/-/nanopop-2.1.0.tgz", + "integrity": "sha512-jGTwpFRexSH+fxappnGQtN9dspgE2ipa1aOjtR24igG0pv6JCxImIAmrLRHX+zUF5+1wtsFVbKyfP51kIGAVNw==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", diff --git a/package.json b/package.json index 3d55068..6491c9d 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "lint": "vue-cli-service lint" }, "dependencies": { - "canvas": "^2.6.1", + "@simonwep/pickr": "^1.8.0", "core-js": "^3.6.5", "dropbox": "^8.2.0", "register-service-worker": "^1.7.1", diff --git a/src/components/options-panel/components/tool-options-brush/messages.json b/src/components/options-panel/components/tool-options-brush/messages.json index 74b157d..d6eea06 100644 --- a/src/components/options-panel/components/tool-options-brush/messages.json +++ b/src/components/options-panel/components/tool-options-brush/messages.json @@ -1,5 +1,6 @@ { "en-US": { - "brush": "Brush" + "brush": "Brush", + "brushColor": "Brush color" } } diff --git a/src/components/options-panel/components/tool-options-brush/tool-options-brush.vue b/src/components/options-panel/components/tool-options-brush/tool-options-brush.vue index 88a3f8e..f004fcb 100644 --- a/src/components/options-panel/components/tool-options-brush/tool-options-brush.vue +++ b/src/components/options-panel/components/tool-options-brush/tool-options-brush.vue @@ -23,13 +23,56 @@ diff --git a/src/components/ui/color-picker/color-picker.vue b/src/components/ui/color-picker/color-picker.vue new file mode 100644 index 0000000..fd70952 --- /dev/null +++ b/src/components/ui/color-picker/color-picker.vue @@ -0,0 +1,93 @@ +/** + * The MIT License (MIT) + * + * Igor Zinken 2020 - https://www.igorski.nl + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + + + + diff --git a/src/components/ui/zcanvas/drawable-layer.js b/src/components/ui/zcanvas/drawable-layer.js index 438515d..376748f 100644 --- a/src/components/ui/zcanvas/drawable-layer.js +++ b/src/components/ui/zcanvas/drawable-layer.js @@ -41,35 +41,43 @@ function DrawableLayer( layer ) { this.setDraggable( true ); // TODO: setters and cache for these - const radius = 30; // TODO: setter - const innerRadius = 5; - const outerRadius = 70; const opacity = .5; // 0 - 1 range ctx.globalAlpha = opacity; - const { cvs: brush, ctx: brushCtx } = createCanvas( radius * 2, radius * 2 ); + this.halfRadius = 0; - // Radii of the white glow. - // Radius of the entire circle. + const { cvs: brush, ctx: brushCtx } = createCanvas( 10, 10 ); - x = radius; - y = radius; - const gradient = brushCtx.createRadialGradient( x, y, innerRadius, x, y, outerRadius ); - gradient.addColorStop( 0, 'rgba(255,0,0,1)' ); - gradient.addColorStop( 1, 'rgba(255,255,255,1)' ); + this.cacheGradient = function( color, radius = 30, innerRadius = 5, outerRadius = 70 ) + { + x = radius; + y = radius; - brushCtx.arc( x, y, radius, 0, 2 * Math.PI ); + // update brush Canvas size + brush.width = radius * 2; + brush.height = radius * 2; - brushCtx.fillStyle = gradient; - brushCtx.fill(); + const gradient = brushCtx.createRadialGradient( x, y, innerRadius, x, y, outerRadius ); + gradient.addColorStop( 0, color ); + gradient.addColorStop( 1, 'rgba(255,255,255,1)' ); - this.handleMove = function( x, y ) { + brushCtx.arc( x, y, radius, 0, 2 * Math.PI ); + brushCtx.fillStyle = gradient; + brushCtx.fill(); + + this.halfRadius = radius / 2; + }, + + this.handleMove = function( x, y ) + { // TODO: this zoomFactor should be taken into account by handleInteraction of zCanvas !! // BECAUSE IT DOES NOT WORK FOR HANDLEPRESS CURRENTLY x /= this.canvas.zoomFactor; y /= this.canvas.zoomFactor; - ctx.drawImage( brush, x - radius / 2, y - radius / 2 ); + ctx.drawImage( brush, x - this.halfRadius, y - this.halfRadius ); } + + this.cacheGradient( "rgba(255,0,0,1)" ); } sprite.extend( DrawableLayer ); export default DrawableLayer; diff --git a/src/store/modules/tool-module.js b/src/store/modules/tool-module.js index ec6c2d3..64ce85c 100644 --- a/src/store/modules/tool-module.js +++ b/src/store/modules/tool-module.js @@ -28,12 +28,13 @@ export default { activeTool: null, options: { [ ToolTypes.ZOOM ] : { level: 1 }, - [ ToolTypes.BRUSH ]: { }, + [ ToolTypes.BRUSH ]: { color: "rgba(255,0,0,1)" }, } }, getters: { activeTool: state => state.activeTool, zoomOptions: state => state.options[ ToolTypes.ZOOM ], + brushOptions: state => state.options[ ToolTypes.BRUSH ], }, mutations: { setActiveTool( state, tool ) {