├── .eslintignore
├── .github
└── workflows
│ └── tests.yml
├── .gitignore
├── .nowignore
├── .npmignore
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── demo.png
├── dist
├── paintable.common.js
├── paintable.umd.js
└── paintable.umd.min.js
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── src
├── App.vue
├── Paintable.vue
├── components
│ └── Navigation.vue
├── main.js
└── plugin.js
├── tests
└── unit
│ ├── .eslintrc.js
│ └── example.spec.js
├── vercel.json
└── vue.config.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist/
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | strategy:
11 | matrix:
12 | node-version: [10.x, 12.x]
13 |
14 | steps:
15 | - uses: actions/checkout@v1
16 | - name: Use Node.js ${{ matrix.node-version }}
17 | uses: actions/setup-node@v1
18 | with:
19 | node-version: ${{ matrix.node-version }}
20 | - name: npm install, lint, build and test
21 | run: |
22 | npm install
23 | npm test
24 | npm run lint
25 | npm run now-build
26 | env:
27 | CI: true
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 |
13 | # Editor directories and files
14 | .idea
15 | .vscode
16 | *.suo
17 | *.ntvs*
18 | *.njsproj
19 | *.sln
20 | *.sw?
21 |
22 | demo
--------------------------------------------------------------------------------
/.nowignore:
--------------------------------------------------------------------------------
1 | demo.png
2 | .vscode
3 | tests
4 | public
5 | dist
6 | demo
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src/
2 | webpack.config.js
3 | travis.yml
4 | .vscode
5 | .prettierrc
6 | demo/
7 | coverage/
8 | .git/
9 | scripts/
10 | demo.png
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "travis.repository": "vue-paintable",
3 | "travis.username": "ph1p"
4 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 appcom interactive GmbH
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-paintable [](https://www.npmjs.com/package/vue-paintable) [](https://vue-paintable.vercel.app/)
2 |
3 | With this vue plugin and component you can add a paintable canvas through your page.
4 | All paintings are saved by default into localStorage.
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | ### How to use?
14 |
15 | ```bash
16 | npm install vue-paintable
17 | ```
18 |
19 | or
20 |
21 | ```bash
22 | yarn add vue-paintable
23 | ```
24 |
25 | Inside your main (typically main.js)
26 |
27 | ```javascript
28 | import Vue from 'vue';
29 | import Paintable from 'vue-paintable';
30 |
31 | Vue.use(Paintable, {
32 | // optional methods
33 | setItem(key, image) {
34 | localStorage.setItem(key, image);
35 | },
36 | // you also can use async
37 | getItem(key) {
38 | return localStorage.getItem(key);
39 | },
40 | removeItem(key) {
41 | localStorage.removeItem(key);
42 | }
43 | });
44 | //...
45 | ```
46 |
47 | #### Inside your components
48 |
49 | ```html
50 |
51 |
70 | Your content
71 |
72 |
73 |
74 | ```
75 |
76 | ### Navigation
77 |
78 | Set your own navigation content by adding an object to your `` component.
79 |
80 | ```javascript
81 | {
82 | 'draw-save': {
83 | body: 'draw',
84 | activeBody: 'save'
85 | },
86 | color: {
87 | body: 'CP'
88 | }
89 | }
90 | ```
91 |
92 | **Display navigation horizontal**
93 |
94 | To display the navigation horizontally add `horizontalNavigation` to prop list.
95 |
96 | **Available navigation items:**
97 |
98 | - color
99 | - line-width
100 | - undo
101 | - redo
102 | - delete
103 | - cancel
104 |
105 | **has active state (activeBody):**
106 |
107 | - draw-save
108 | - eraser-pencil
109 |
110 | ### Custom Navigation
111 |
112 | To use a custom navigation disable the default navigation with `disableNavigation`.
113 |
114 | #### use \$refs to call paintable methods
115 |
116 | ```html
117 | content
118 |
119 |
120 |
121 |
122 |
125 |
126 | ```
127 |
128 | Take a look at the [demo](https://vue-paintable.vercel.app/) (`/src/App.vue`)
129 |
130 |
131 | ### Props
132 |
133 | | name | type | required | default | description |
134 | | -------------------- | ------------------------------- | -------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------|
135 | | name | string - required | true | - | unique identifier |
136 | | showUndoRedo | boolean | false | true | show undo and redo button |
137 | | hide | boolean | false | false | hide the complete paintable |
138 | | colors | Array of colors (rgb, hex etc.) | false | ['black', '#f00', '#4481c7', 'rgba(255, 235, 59, 0.4)', '#999', 'green'] | array of choosable colors |
139 | | width | number | false | window.innerWidth | canvas width |
140 | | height | number | false | window.innerHeight | canvas height |
141 | | showLineWidth | boolean | false | true | show button to set line width |
142 | | lineWidth | number | false | 5 | line width |
143 | | alwaysOnTop | boolean | false | true | set canvas always as top layer |
144 | | factor | number | false | 1 | set a scale factor if needed |
145 | | lineWidthEraser | number | false | 20 | set eraser line width |
146 | | horizontalNavigation | boolean | false | true | display the navigation horizontally or vertically |
147 | | disableNavigation | boolean | false | false | hide navigation |
148 | | active | boolean | false | false | set paintable active/inactive |
149 | | color | string | false | #000 | current color |
150 | | useEraser | boolean | false | false | set to true, to use the eraser |
151 | | threshold | number | false | 0 | set the threshold on which an event gets triggered (see events)|
152 |
153 | ### Events
154 |
155 | | name | type | description |
156 | | ---------------- | ------- | ---------------------------------------------------- |
157 | | toggle-paintable | boolean | Is emitted, when changing paintable state |
158 | | thresholdReached | boolean | Is emitted, when the speciefied threshold is reached |
159 |
160 | ```html
161 |
162 |
163 |
164 | ```
165 |
166 | ### development
167 |
168 | If you want to develop with this plugin, follow these steps:
169 |
170 | - clone repo
171 | - run `yarn install` or `npm install`
172 | - run `yarn serve` or `npm run serve`
173 |
174 | ### build
175 |
176 | You can find all built files inside the `dist` folder.
177 |
178 | - run `yarn build` or `npm run build`
179 |
--------------------------------------------------------------------------------
/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ph1p/vue-paintable/15514940151106055fee5325ac5936f1d9222d7a/demo.png
--------------------------------------------------------------------------------
/dist/paintable.common.js:
--------------------------------------------------------------------------------
1 | module.exports =
2 | /******/ (function(modules) { // webpackBootstrap
3 | /******/ // The module cache
4 | /******/ var installedModules = {};
5 | /******/
6 | /******/ // The require function
7 | /******/ function __webpack_require__(moduleId) {
8 | /******/
9 | /******/ // Check if module is in cache
10 | /******/ if(installedModules[moduleId]) {
11 | /******/ return installedModules[moduleId].exports;
12 | /******/ }
13 | /******/ // Create a new module (and put it into the cache)
14 | /******/ var module = installedModules[moduleId] = {
15 | /******/ i: moduleId,
16 | /******/ l: false,
17 | /******/ exports: {}
18 | /******/ };
19 | /******/
20 | /******/ // Execute the module function
21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
22 | /******/
23 | /******/ // Flag the module as loaded
24 | /******/ module.l = true;
25 | /******/
26 | /******/ // Return the exports of the module
27 | /******/ return module.exports;
28 | /******/ }
29 | /******/
30 | /******/
31 | /******/ // expose the modules object (__webpack_modules__)
32 | /******/ __webpack_require__.m = modules;
33 | /******/
34 | /******/ // expose the module cache
35 | /******/ __webpack_require__.c = installedModules;
36 | /******/
37 | /******/ // define getter function for harmony exports
38 | /******/ __webpack_require__.d = function(exports, name, getter) {
39 | /******/ if(!__webpack_require__.o(exports, name)) {
40 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
41 | /******/ }
42 | /******/ };
43 | /******/
44 | /******/ // define __esModule on exports
45 | /******/ __webpack_require__.r = function(exports) {
46 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
47 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
48 | /******/ }
49 | /******/ Object.defineProperty(exports, '__esModule', { value: true });
50 | /******/ };
51 | /******/
52 | /******/ // create a fake namespace object
53 | /******/ // mode & 1: value is a module id, require it
54 | /******/ // mode & 2: merge all properties of value into the ns
55 | /******/ // mode & 4: return value when already ns object
56 | /******/ // mode & 8|1: behave like require
57 | /******/ __webpack_require__.t = function(value, mode) {
58 | /******/ if(mode & 1) value = __webpack_require__(value);
59 | /******/ if(mode & 8) return value;
60 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
61 | /******/ var ns = Object.create(null);
62 | /******/ __webpack_require__.r(ns);
63 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
64 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
65 | /******/ return ns;
66 | /******/ };
67 | /******/
68 | /******/ // getDefaultExport function for compatibility with non-harmony modules
69 | /******/ __webpack_require__.n = function(module) {
70 | /******/ var getter = module && module.__esModule ?
71 | /******/ function getDefault() { return module['default']; } :
72 | /******/ function getModuleExports() { return module; };
73 | /******/ __webpack_require__.d(getter, 'a', getter);
74 | /******/ return getter;
75 | /******/ };
76 | /******/
77 | /******/ // Object.prototype.hasOwnProperty.call
78 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
79 | /******/
80 | /******/ // __webpack_public_path__
81 | /******/ __webpack_require__.p = "";
82 | /******/
83 | /******/
84 | /******/ // Load entry module and return exports
85 | /******/ return __webpack_require__(__webpack_require__.s = "fb15");
86 | /******/ })
87 | /************************************************************************/
88 | /******/ ({
89 |
90 | /***/ "2443":
91 | /***/ (function(module, exports, __webpack_require__) {
92 |
93 | // style-loader: Adds some css to the DOM by adding a
183 |
--------------------------------------------------------------------------------
/src/Paintable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
21 |
22 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
534 |
535 |
566 |
--------------------------------------------------------------------------------
/src/components/Navigation.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
20 |
21 |
24 |
32 |
33 |
34 |
35 |
68 |
69 |
70 |
71 |
234 |
235 |
318 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import App from './App.vue';
3 | import Paintable from './plugin';
4 |
5 | Vue.use(Paintable);
6 |
7 | new Vue({
8 | render: h => h(App)
9 | }).$mount('#app');
10 |
--------------------------------------------------------------------------------
/src/plugin.js:
--------------------------------------------------------------------------------
1 | import Paintable from './Paintable.vue';
2 |
3 | const PaintablePlugin = {
4 | install(Vue, options) {
5 | if (options && options.setItem) {
6 | Paintable.methods.setItem = options.setItem;
7 | }
8 |
9 | if (options && options.getItem) {
10 | Paintable.methods.getItem = options.getItem;
11 | }
12 |
13 | if (options && options.removeItem) {
14 | Paintable.methods.removeItem = options.removeItem;
15 | }
16 |
17 | Vue.component('paintable', Paintable);
18 | }
19 | };
20 |
21 | export default PaintablePlugin;
22 |
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | jest: true
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/tests/unit/example.spec.js:
--------------------------------------------------------------------------------
1 | describe('', () => {
2 | it('', () => {});
3 | });
4 |
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "name": "vue-paintable",
4 | "alias": ["vue-paintable.vercel.app"],
5 | "builds": [
6 | {
7 | "src": "./package.json",
8 | "use": "@vercel/static-build",
9 | "config": {
10 | "distDir": "demo"
11 | }
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | productionSourceMap: false,
3 | css: {
4 | extract: false
5 | }
6 | };
7 |
--------------------------------------------------------------------------------