├── .babelrc
├── .github
└── FUNDING.yml
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── config
├── dev.conf.js
├── index.js
├── prod.conf.js
└── test.conf.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── src
├── components
│ ├── vue-drag-resize.css
│ ├── vue-drag-resize.html
│ ├── vue-drag-resize.js
│ └── vue-drag-resize.vue
├── demo
│ ├── app.js
│ ├── app.vue
│ ├── components
│ │ └── toolbar
│ │ │ ├── toolbar.css
│ │ │ ├── toolbar.html
│ │ │ ├── toolbar.js
│ │ │ └── toolbar.vue
│ ├── icons
│ │ ├── index.js
│ │ ├── lock.js
│ │ ├── toBottom.js
│ │ └── toTop.js
│ └── store
│ │ ├── index.js
│ │ └── modules
│ │ └── rect
│ │ ├── actions.js
│ │ ├── getters.js
│ │ ├── index.js
│ │ ├── mutation-types.js
│ │ ├── mutations.js
│ │ └── state.js
└── index.js
├── static
└── index.html
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"],
3 | "plugins": ["@babel/plugin-proposal-class-properties"]
4 | }
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | open_collective: vue-drag-resize
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | .idea/
4 | npm-debug.log
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/demo.js
4 | static/
5 | npm-debug.log
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Maurizio Bonani
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 |

2 | Vue-drag-resize
3 |
4 |
5 |
6 | [](https://npmjs.com/package/vue-drag-resize)
7 | [](LICENSE.md)
8 | [](https://www.npmjs.com/package/vue-drag-resize)
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | > Vue Component for draggable and resizable elements.
18 |
19 | ## Table of Contents
20 |
21 | * [Features](#features)
22 | * [Install and basic usage](#install-and-basic-usage)
23 | * [Props](#props)
24 | * [Events](#events)
25 | * [Contributing](#contributing)
26 | * [License](#license)
27 |
28 | ### Demo
29 |
30 | [Demo](http://kirillmurashov.com/vue-drag-resize)
31 |
32 | ### Features
33 |
34 | * A lightweight, no-dependency
35 | * All props are reactive
36 | * Support touch events
37 | * Snap element to custom grid
38 | * Use draggable, resizable or both
39 | * Define sticks for resizing
40 | * Save aspect ratio for resizable components
41 | * Restrict size and movement to parent element
42 | * Restrict drag to vertical or horizontal axis
43 |
44 | ## Install and basic usage
45 |
46 | ```bash
47 | $ npm i -s vue-drag-resize
48 | ```
49 |
50 |
51 | Register the component:
52 |
53 | ```js
54 | import Vue from 'vue'
55 | import VueDragResize from 'vue-drag-resize'
56 |
57 | Vue.component('vue-drag-resize', VueDragResize)
58 | ```
59 |
60 | Use the component:
61 |
62 | ```vue
63 |
64 |
65 |
66 | Hello World!
67 | {{ top }} х {{ left }}
68 | {{ width }} х {{ height }}
69 |
70 |
71 |
72 |
73 |
102 | ```
103 |
104 | ### Props
105 |
106 | #### isActive
107 | Type: `Boolean`
108 | Required: `false`
109 | Default: `false`
110 |
111 | Determines whether the component should be active.
112 |
113 | 确定组件是否应处于活动状态。
114 |
115 | ```html
116 |
117 | ```
118 |
119 | #### preventActiveBehavior
120 | Type: `Boolean`
121 | Required: `false`
122 | Default: `false`
123 |
124 | Disable behavior of the component by clicking on it and clicking outside the component's area (isActive: true / false).
125 | If the prop is enabled, the component is oriented only to the specified.
126 |
127 | 通过单击组件并单击组件区域外部来禁用组件的行为(isActive:true / false)。
128 | 如果启用了prop,则组件仅面向指定的。
129 |
130 | ```html
131 |
132 | ```
133 |
134 | #### parentW
135 | Type: `Number`
136 | Required: `false`
137 | Default: `0`
138 |
139 | Define the initial width of the parent element. If not specified it calculated automatically.
140 | With this parameter, you can set the bounding area for the component, and also it is used when resizing in real time.
141 |
142 | 定义父元素的初始宽度。 如果未指定,则自动计算。
143 | 使用此参数,您可以设置组件的边界区域,并在实时调整大小时使用它。
144 | ```html
145 |
146 | ```
147 |
148 | #### parentH
149 | Type: `Number`
150 | Required: `false`
151 | Default: `0`
152 |
153 | Define the initial height of the parent element. If not specified it calculated automatically.
154 | With this parameter, you can set the bounding area for the component, and also it is used when resizing in real time.
155 |
156 | 定义父元素的初始高度。 如果未指定,则自动计算。
157 | 使用此参数,您可以设置组件的边界区域,并在实时调整大小时使用它。
158 |
159 | ```html
160 |
161 | ```
162 |
163 | #### parentScaleX
164 | Type: `Number`
165 | Required: `false`
166 | Default: `1`
167 |
168 | Define the initial horizontal scale or the parent element. Same value in parent's transform: scale() css definition.
169 | The drag/resize and the sticks' sizes will computed with this value.
170 |
171 | 定义初始水平比例或父元素。父级的transform:scale()css定义中的值相同。
172 | 拖动/调整大小和杆的大小将使用该值计算。
173 | ```html
174 |
175 | ```
176 |
177 | #### parentScaleY
178 | Type: `Number`
179 | Required: `false`
180 | Default: `1`
181 |
182 | Define the initial vertical scale or the parent element. Same value in parent's transform: scale() css definition.
183 | The drag/resize and the sticks' sizes will computed with this value.
184 |
185 | 定义初始垂直比例或父元素。父级的transform:scale()css定义中的值相同。
186 | 拖动/调整大小和杆的大小将使用该值计算。
187 |
188 | ```html
189 |
190 | ```
191 |
192 | #### isDraggable
193 | Type: `Boolean`
194 | Required: `false`
195 | Default: `true`
196 |
197 | Determines whether the component should draggable.
198 |
199 | 确定组件是否应可拖动。
200 |
201 |
202 | ```html
203 |
204 | ```
205 |
206 | #### isResizable
207 | Type: `Boolean`
208 | Required: `false`
209 | Default: `true`
210 |
211 | Determines whether the component should resize.
212 |
213 | 确定组件是否应调整大小。
214 |
215 |
216 | ```html
217 |
218 | ```
219 | #### parentLimitation
220 | Type: `Boolean`
221 | Required: `false`
222 | Default: `false`
223 |
224 | Limits the scope of the component's change to its parent size.
225 |
226 | 将组件更改的范围限制为其父大小。
227 |
228 |
229 | ```html
230 |
231 | ```
232 |
233 | #### snapToGrid
234 | Type: `Boolean`
235 | Required: `false`
236 | Default: `false`
237 |
238 | Determines whether the component should move and resize in predefined steps.
239 |
240 | ```html
241 |
242 | ```
243 |
244 | #### gridX
245 | Type: `Number`
246 | Required: `false`
247 | Default: `50`
248 |
249 | Define the grid step size for the horizontal axis. Both sides of the component (left and right) will snap to this step.
250 |
251 | ```html
252 |
253 | ```
254 |
255 | #### gridY
256 | Type: `Number`
257 | Required: `false`
258 | Default: `50`
259 |
260 | Define the grid step size for the vertical axis. Both sides of the component (top and bottom) will snap to this step.
261 |
262 | ```html
263 |
264 | ```
265 |
266 | #### aspectRatio
267 | Type: `Boolean`
268 | Required: `false`
269 | Default: `false`
270 |
271 | Determines whether the component should retain its proportions.
272 |
273 | 确定组件是否应保持其比例。
274 |
275 |
276 | ```html
277 |
278 | ```
279 |
280 | #### w
281 | Type: `Number|String`
282 | Required: `false`
283 | Default: `200`
284 |
285 | Define the initial width of the component.
286 | The value can either be a number >= 0 or the string 'auto'.
287 | If set to 'auto', the initial width value will be equal to the width of the content within the component.
288 |
289 | 定义组件的初始宽度。
290 |
291 |
292 | ```html
293 |
294 | ```
295 |
296 | #### h
297 | Type: `Number|String`
298 | Required: `false`
299 | Default: `200`
300 |
301 | Define the initial height of the component.
302 | The value can either be a number >= 0 or the string 'auto'.
303 | If set to 'auto', the initial height value will be equal to the height of the content within the component.
304 |
305 | 定义组件的初始高度。
306 |
307 |
308 |
309 | ```html
310 |
311 | ```
312 |
313 | #### minw
314 | Type: `Number`
315 | Required: `false`
316 | Default: `50`
317 |
318 | Define the minimal width of the component.
319 |
320 | 定义组件的初始宽度。
321 |
322 |
323 |
324 | ```html
325 |
326 | ```
327 |
328 | #### minh
329 | Type: `Number`
330 | Required: `false`
331 | Default: `50`
332 |
333 | Define the minimal height of the component.
334 |
335 | 定义组件的最小高度。
336 |
337 |
338 | ```html
339 |
340 | ```
341 |
342 | #### x
343 | Type: `Number`
344 | Required: `false`
345 | Default: `0`
346 |
347 | Define the initial x position of the component.
348 |
349 | 定义组件的初始X位置。
350 |
351 |
352 | ```html
353 |
354 | ```
355 |
356 | #### y
357 | Type: `Number`
358 | Required: `false`
359 | Default: `0`
360 |
361 | Define the initial y position of the component.
362 |
363 | 定义组件的初始Y位置。
364 |
365 |
366 | ```html
367 |
368 | ```
369 |
370 | #### z
371 | Type: `Number|String`
372 | Required: `false`
373 | Default: `auto`
374 |
375 | Define the zIndex of the component.
376 |
377 | 定义组件的zindex(层级)。
378 |
379 | ```html
380 |
381 | ```
382 |
383 | #### stickSize
384 | Type: `Number`
385 | Required: `false`
386 | Default `8`
387 |
388 | Define the sticks' size.
389 |
390 | ```html
391 |
392 | ```
393 |
394 | #### sticks
395 | Type: `Array`
396 | Required: `false`
397 | Default: `['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml']`
398 |
399 | Define the array of handles to restrict the element resizing:
400 |
401 | 定义句柄数组以限制元素大小调整:
402 |
403 | * `tl` - Top left
404 | * `tm` - Top middle
405 | * `tr` - Top right
406 | * `mr` - Middle right
407 | * `br` - Bottom right
408 | * `bm` - Bottom middle
409 | * `bl` - Bottom left
410 | * `ml` - Middle left
411 |
412 | ```html
413 |
414 | ```
415 |
416 | #### axis
417 | Type: `String`
418 | Required: `false`
419 | Default: `both`
420 |
421 | Define the axis on which the element is draggable. Available values are `x`, `y`, `both` or `none`.
422 |
423 | 定义元素可拖动的轴。 可用值为`x`,`y`,`both`或`none`。
424 |
425 | ```html
426 |
427 | ```
428 |
429 | #### dragHandle
430 | Type: `String`
431 | Required: `false`
432 |
433 | Defines the selector that should be used to drag the component.
434 |
435 | 定义应该用于拖动组件的选择器。
436 |
437 | ```html
438 |
439 | ```
440 |
441 | #### dragCancel
442 | Type: `String`
443 | Required: `false`
444 |
445 | Defines a selector that should be used to prevent drag initialization.
446 |
447 | 定义应该用于防止拖动初始化的选择器。
448 |
449 | ```html
450 |
451 | ```
452 |
453 | #### contentClass
454 | Type: `String`
455 | Required: `false`
456 |
457 | Defines a class that is applied on the div with the class vdr
458 |
459 | ```html
460 |
461 | ```
462 |
463 |
464 |
465 |
466 | ---
467 |
468 | ### Events
469 |
470 | #### clicked
471 |
472 | Required: `false`
473 | Parameters: `Original event handler`
474 |
475 | Called whenever the component gets clicked.
476 |
477 | 单击组件时调用。
478 |
479 | ```html
480 |
481 | ```
482 |
483 | #### activated
484 |
485 | Required: `false`
486 | Parameters: `-`
487 |
488 | Called whenever the component gets clicked, in order to show handles.
489 |
490 | 单击组件时调用,以显示句柄。
491 |
492 | ```html
493 |
494 | ```
495 |
496 | #### deactivated
497 |
498 | Required: `false`
499 | Parameters: `-`
500 |
501 | Called whenever the user clicks anywhere outside the component, in order to deactivate it.
502 |
503 | 每当用户单击组件外部的任何位置时调用,以便将其停用。
504 |
505 |
506 | ```html
507 |
508 | ```
509 |
510 | #### resizing
511 |
512 | Required: `false`
513 | Parameters: `object`
514 |
515 | ```javascript
516 | {
517 | left: Number, //the X position of the component
518 | top: Number, //the Y position of the component
519 | width: Number, //the width of the component
520 | height: Number //the height of the component
521 | }
522 | ```
523 |
524 | Called whenever the component gets resized.
525 |
526 | 每当组件调整大小时调用。
527 |
528 |
529 | ```html
530 |
531 | ```
532 |
533 | #### resizestop
534 |
535 | Required: `false`
536 | Parameters: `object`
537 | ```javascript
538 | {
539 | left: Number, //the X position of the component
540 | top: Number, //the Y position of the component
541 | width: Number, //the width of the component
542 | height: Number //the height of the component
543 | }
544 | ```
545 |
546 | Called whenever the component stops getting resized.
547 |
548 | 每当组件停止调整大小时调用。
549 |
550 |
551 | ```html
552 |
553 | ```
554 |
555 | #### dragging
556 |
557 | Required: `false`
558 | Parameters: `object`
559 | ```javascript
560 | {
561 | left: Number, //the X position of the component
562 | top: Number, //the Y position of the component
563 | width: Number, //the width of the component
564 | height: Number //the height of the component
565 | }
566 | ```
567 |
568 | Called whenever the component gets dragged.
569 |
570 | 每当拖动组件时调用。
571 |
572 |
573 | ```html
574 |
575 | ```
576 |
577 | #### dragstop
578 |
579 | Required: `false`
580 | Parameters: `object`
581 | ```javascript
582 | {
583 | left: Number, //the X position of the component
584 | top: Number, //the Y position of the component
585 | width: Number, //the width of the component
586 | height: Number //the height of the component
587 | }
588 | ```
589 |
590 |
591 | Called whenever the component stops getting dragged.
592 |
593 | 每当组件停止拖动时调用。
594 |
595 |
596 | ```html
597 |
598 | ```
599 |
600 | ## Contributing
601 |
602 | Any contribution to the code or any part of the documentation and any idea and/or suggestion are very welcome.
603 |
604 | ``` bash
605 | # serve with hot reload at localhost:8081
606 | npm run start
607 |
608 | # distribution build
609 | npm run build
610 |
611 | ```
612 |
613 | ## License
614 |
615 | [MIT license](LICENSE)
--------------------------------------------------------------------------------
/config/dev.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: {
3 | "app": './src/demo/app.js'
4 | },
5 | build: {
6 | env: '"development"',
7 | sourceMap: true,
8 | uglify: false,
9 | cssSourceMap: false,
10 | gzip: false
11 | }
12 | };
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var envConfig = process.env.NODE_ENV === 'develop' ?
3 | require('./dev.conf') : process.env.NODE_ENV === 'testing' ?
4 | require('./test.conf') : require('./prod.conf');
5 |
6 | var deepExtend = require('deep-extend');
7 |
8 | module.exports = deepExtend({
9 | build: {
10 | distPath: path.resolve(__dirname, '../dist'),
11 | bundleAnalyzerReport: false
12 | },
13 | server: {
14 | assetsPath: path.resolve(__dirname, '../static'),
15 | port: 8081,
16 | host: '0.0.0.0',
17 | autoOpenBrowser: true,
18 | }
19 | }, envConfig);
--------------------------------------------------------------------------------
/config/prod.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: {
3 | "index": './src',
4 | "demo": './src/demo/app'
5 | },
6 | build: {
7 | env: '"production"',
8 | sourceMap: false,
9 | uglify: true,
10 | cssSourceMap: false,
11 | gzip: false
12 | }
13 | };
--------------------------------------------------------------------------------
/config/test.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: {
3 | "app": './src/app.js'
4 | },
5 | build: {
6 | env: '"testing"',
7 | sourceMap: true,
8 | uglify: true,
9 | cssSourceMap: false,
10 | gzip: false
11 | }
12 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-drag-resize",
3 | "version": "1.5.4",
4 | "description": "Vue Component for resize and drag elements",
5 | "author": "Kirill Murashov ",
6 | "main": "dist/index.js",
7 | "scripts": {
8 | "start": "NODE_ENV=develop webpack-dev-server -d",
9 | "svg": "vsvg -s ./src/demo/svg -t ./src/demo/icons",
10 | "build": "webpack"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "https://github.com/kirillmurashov/vue-drag-resize.git"
15 | },
16 | "bugs": {
17 | "url": "https://github.com/kirillmurashov/vue-drag-resize/issues"
18 | },
19 | "homepage": "https://github.com/kirillmurashov/vue-drag-resize.git",
20 | "devDependencies": {
21 | "acorn-dynamic-import": "^3.0.0",
22 | "autoprefixer": "^6.7.2",
23 | "@babel/core": "^7.12.1",
24 | "@babel/plugin-proposal-class-properties": "^7.12.1",
25 | "@babel/preset-env": "^7.12.1",
26 | "babel-loader": "^8.1.0",
27 | "browserify": "^14.4.0",
28 | "chai": "^3.5.0",
29 | "chalk": "^1.1.3",
30 | "compression-webpack-plugin": "^1.0.0",
31 | "connect-history-api-fallback": "^1.3.0",
32 | "copy-webpack-plugin": "^4.0.1",
33 | "cross-env": "^5.0.5",
34 | "css-color-function": "^1.3.0",
35 | "css-loader": "^0.28.7",
36 | "cssnano": "^3.10.0",
37 | "deep-extend": "^0.5.0",
38 | "es6-promise": "^4.1.1",
39 | "eslint": "^4.18.2",
40 | "eslint-config-airbnb-base": "^11.1.3",
41 | "eslint-friendly-formatter": "^2.0.7",
42 | "eslint-import-resolver-webpack": "^0.8.1",
43 | "eslint-loader": "^1.7.1",
44 | "eslint-plugin-html": "^2.0.0",
45 | "eslint-plugin-import": "^2.2.0",
46 | "eventsource-polyfill": "^0.9.6",
47 | "express": "^4.14.1",
48 | "extract-text-webpack-plugin": "^3.0.2",
49 | "file-loader": "^1.1.11",
50 | "file-type": "^6.1.0",
51 | "friendly-errors-webpack-plugin": "^1.1.3",
52 | "function-bind": "^1.1.0",
53 | "gulp": "^3.9.1",
54 | "gulp-browserify": "^0.5.1",
55 | "gulp-bump": "^2.4.0",
56 | "gulp-clean": "^0.3.2",
57 | "gulp-concat": "^2.6.1",
58 | "gulp-concat-util": "^0.5.5",
59 | "gulp-copy": "0.0.2",
60 | "gulp-delete-file": "^1.0.2",
61 | "gulp-dotify": "^0.1.2",
62 | "gulp-file": "^0.3.0",
63 | "gulp-header": "^1.8.9",
64 | "gulp-htmlmin": "^3.0.0",
65 | "gulp-iconfont": "^9.0.1",
66 | "gulp-iconfont-css": "^2.1.0",
67 | "gulp-if": "^2.0.1",
68 | "gulp-json-css": "^0.2.3",
69 | "gulp-json-editor": "^2.2.1",
70 | "gulp-jst2": "^0.1.4",
71 | "gulp-load-plugins": "^1.3.0",
72 | "gulp-logwarn": "0.0.9",
73 | "gulp-match": "^1.0.3",
74 | "gulp-merge": "^0.1.1",
75 | "gulp-mocha": "^3.0.1",
76 | "gulp-multi-dest": "0.0.4",
77 | "gulp-postcss": "^7.0.0",
78 | "gulp-rename": "^1.2.2",
79 | "gulp-replace": "^0.5.4",
80 | "gulp-rtlcss": "^1.0.0",
81 | "gulp-run-sequence": "^0.3.2",
82 | "gulp-sourcemaps": "^2.6.1",
83 | "gulp-uglify": "^2.0.0",
84 | "html-webpack-plugin": "^2.28.0",
85 | "http-proxy-middleware": "^0.17.3",
86 | "jade": "^1.11.0",
87 | "json-loader": "^0.5.4",
88 | "karma": "^1.4.1",
89 | "karma-chai": "^0.1.0",
90 | "karma-chai-dom": "^1.1.0",
91 | "karma-chrome-launcher": "^2.2.0",
92 | "karma-coverage": "^1.1.1",
93 | "karma-firefox-launcher": "^1.1.0",
94 | "karma-mocha": "^1.3.0",
95 | "karma-phantomjs-launcher": "^1.0.2",
96 | "karma-phantomjs-shim": "^1.4.0",
97 | "karma-safari-launcher": "^1.0.0",
98 | "karma-sinon-chai": "^1.3.1",
99 | "karma-sourcemap-loader": "^0.3.7",
100 | "karma-spec-reporter": "0.0.31",
101 | "karma-webpack": "^2.0.2",
102 | "less": "^2.7.2",
103 | "less-loader": "^4.0.3",
104 | "mini-css-extract-plugin": "^0.4.0",
105 | "minimist": "^1.2.0",
106 | "mocha": "^3.0.2",
107 | "node-gyp": "3.4.0",
108 | "opn": "^4.0.2",
109 | "optimize-css-assets-webpack-plugin": "^1.3.1",
110 | "ora": "^1.2.0",
111 | "path": "^0.12.7",
112 | "phantomjs-prebuilt": "^2.1.14",
113 | "postcss-color-function": "^4.0.0",
114 | "postcss-cssnext": "^3.0.2",
115 | "postcss-import": "^10.0.0",
116 | "postcss-loader": "^2.0.6",
117 | "require-dir": "^0.3.0",
118 | "rimraf": "^2.6.0",
119 | "run-sequence": "^2.1.0",
120 | "script-loader": "^0.7.0",
121 | "semver": "^5.3.0",
122 | "sinon": "^2.1.0",
123 | "sinon-chai": "^2.8.0",
124 | "streamqueue": "^1.1.1",
125 | "style-loader": "^0.18.2",
126 | "stylus": "^0.54.5",
127 | "stylus-loader": "^3.0.1",
128 | "sugarss": "^1.0.0",
129 | "uglifyjs-webpack-plugin": "^0.4.6",
130 | "underscore": "^1.8.3",
131 | "url": "^0.11.0",
132 | "url-loader": "^0.5.9",
133 | "vue": "^2.5.16",
134 | "vue-loader": "^15.0.3",
135 | "vue-style-loader": "^3.0.0",
136 | "vue-svgicon": "^2.1.3",
137 | "vue-template-compiler": "^2.5.16",
138 | "vuex": "^3.0.1",
139 | "watchjs": "0.0.0",
140 | "watchpack": "^1.5.0",
141 | "webpack": "^4.6.0",
142 | "webpack-bundle-analyzer": "^3.3.2",
143 | "webpack-cli": "^2.0.14",
144 | "webpack-dev-middleware": "^3.1.2",
145 | "webpack-dev-server": "^3.1.3",
146 | "webpack-hot-middleware": "^2.18.0",
147 | "webpack-merge": "^4.1.0",
148 | "yargs": "^5.0.0"
149 | },
150 | "engines": {
151 | "node": ">= 4.0.0",
152 | "npm": ">= 3.0.0"
153 | },
154 | "browserslist": [
155 | "> 1%",
156 | "last 2 versions",
157 | "not ie <= 9"
158 | ],
159 | "license": "MIT",
160 | "dependencies": {
161 | "vue-drag-resize": "^1.5.0-rc3"
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | 'postcss-import': {},
4 | 'postcss-cssnext': {},
5 | 'cssnano': {autoprefixer: false}
6 | }
7 | };
--------------------------------------------------------------------------------
/src/components/vue-drag-resize.css:
--------------------------------------------------------------------------------
1 | .vdr {
2 | position: absolute;
3 | box-sizing: border-box;
4 | }
5 | .vdr.active:before{
6 | content: '';
7 | width: 100%;
8 | height: 100%;
9 | position: absolute;
10 | top: 0;
11 | left: 0;
12 | box-sizing: border-box;
13 | outline: 1px dashed #d6d6d6;
14 | }
15 | .vdr-stick {
16 | box-sizing: border-box;
17 | position: absolute;
18 | font-size: 1px;
19 | background: #ffffff;
20 | border: 1px solid #6c6c6c;
21 | box-shadow: 0 0 2px #bbb;
22 | }
23 | .inactive .vdr-stick {
24 | display: none;
25 | }
26 | .vdr-stick-tl, .vdr-stick-br {
27 | cursor: nwse-resize;
28 | }
29 | .vdr-stick-tm, .vdr-stick-bm {
30 | left: 50%;
31 | cursor: ns-resize;
32 | }
33 | .vdr-stick-tr, .vdr-stick-bl {
34 | cursor: nesw-resize;
35 | }
36 | .vdr-stick-ml, .vdr-stick-mr {
37 | top: 50%;
38 | cursor: ew-resize;
39 | }
40 | .vdr-stick.not-resizable{
41 | display: none;
42 | }
43 | .content-container{
44 | display: block;
45 | position: relative;
46 | }
--------------------------------------------------------------------------------
/src/components/vue-drag-resize.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/components/vue-drag-resize.js:
--------------------------------------------------------------------------------
1 | const styleMapping = {
2 | y: {
3 | t: 'top',
4 | m: 'marginTop',
5 | b: 'bottom',
6 | },
7 | x: {
8 | l: 'left',
9 | m: 'marginLeft',
10 | r: 'right',
11 | },
12 | };
13 |
14 | function addEvents(events) {
15 | events.forEach((cb, eventName) => {
16 | document.documentElement.addEventListener(eventName, cb);
17 | });
18 | }
19 |
20 | function removeEvents(events) {
21 | events.forEach((cb, eventName) => {
22 | document.documentElement.removeEventListener(eventName, cb);
23 | });
24 | }
25 |
26 | export default {
27 | name: 'vue-drag-resize',
28 |
29 | emits: ['clicked', 'dragging', 'dragstop', 'resizing', 'resizestop', 'activated', 'deactivated'],
30 |
31 | props: {
32 | stickSize: {
33 | type: Number, default: 8,
34 | },
35 | parentScaleX: {
36 | type: Number, default: 1,
37 | },
38 | parentScaleY: {
39 | type: Number, default: 1,
40 | },
41 | isActive: {
42 | type: Boolean, default: false,
43 | },
44 | preventActiveBehavior: {
45 | type: Boolean, default: false,
46 | },
47 | isDraggable: {
48 | type: Boolean, default: true,
49 | },
50 | isResizable: {
51 | type: Boolean, default: true,
52 | },
53 | aspectRatio: {
54 | type: Boolean, default: false,
55 | },
56 | parentLimitation: {
57 | type: Boolean, default: false,
58 | },
59 | snapToGrid: {
60 | type: Boolean, default: false,
61 | },
62 | gridX: {
63 | type: Number,
64 | default: 50,
65 | validator(val) {
66 | return val >= 0;
67 | },
68 | },
69 | gridY: {
70 | type: Number,
71 | default: 50,
72 | validator(val) {
73 | return val >= 0;
74 | },
75 | },
76 | parentW: {
77 | type: Number,
78 | default: 0,
79 | validator(val) {
80 | return val >= 0;
81 | },
82 | },
83 | parentH: {
84 | type: Number,
85 | default: 0,
86 | validator(val) {
87 | return val >= 0;
88 | },
89 | },
90 | w: {
91 | type: [String, Number],
92 | default: 200,
93 | validator(val) {
94 | return (typeof val === 'string') ? val === 'auto' : val >= 0;
95 | },
96 | },
97 | h: {
98 | type: [String, Number],
99 | default: 200,
100 | validator(val) {
101 | return (typeof val === 'string') ? val === 'auto' : val >= 0;
102 | },
103 | },
104 | minw: {
105 | type: Number,
106 | default: 50,
107 | validator(val) {
108 | return val >= 0;
109 | },
110 | },
111 | minh: {
112 | type: Number,
113 | default: 50,
114 | validator(val) {
115 | return val >= 0;
116 | },
117 | },
118 | x: {
119 | type: Number,
120 | default: 0,
121 | validator(val) {
122 | return typeof val === 'number';
123 | },
124 | },
125 | y: {
126 | type: Number,
127 | default: 0,
128 | validator(val) {
129 | return typeof val === 'number';
130 | },
131 | },
132 | z: {
133 | type: [String, Number],
134 | default: 'auto',
135 | validator(val) {
136 | return (typeof val === 'string') ? val === 'auto' : val >= 0;
137 | },
138 | },
139 | dragHandle: {
140 | type: String,
141 | default: null,
142 | },
143 | dragCancel: {
144 | type: String,
145 | default: null,
146 | },
147 | sticks: {
148 | type: Array,
149 | default() {
150 | return ['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'];
151 | },
152 | },
153 | axis: {
154 | type: String,
155 | default: 'both',
156 | validator(val) {
157 | return ['x', 'y', 'both', 'none'].indexOf(val) !== -1;
158 | },
159 | },
160 | contentClass: {
161 | type: String,
162 | required: false,
163 | default: '',
164 | },
165 | },
166 |
167 | data() {
168 | return {
169 | fixAspectRatio: null,
170 | active: null,
171 | zIndex: null,
172 | parentWidth: null,
173 | parentHeight: null,
174 | left: null,
175 | top: null,
176 | right: null,
177 | bottom: null,
178 | minHeight: null,
179 | };
180 | },
181 |
182 | beforeCreate() {
183 | this.stickDrag = false;
184 | this.bodyDrag = false;
185 | this.dimensionsBeforeMove = { pointerX: 0, pointerY: 0, x: 0, y: 0, w: 0, h: 0 };
186 | this.limits = {
187 | left: { min: null, max: null },
188 | right: { min: null, max: null },
189 | top: { min: null, max: null },
190 | bottom: { min: null, max: null },
191 | };
192 |
193 | this.currentStick = null;
194 | },
195 |
196 | mounted() {
197 | this.parentElement = this.$el.parentNode;
198 | this.parentWidth = this.parentW ? this.parentW : this.parentElement.clientWidth;
199 | this.parentHeight = this.parentH ? this.parentH : this.parentElement.clientHeight;
200 |
201 | this.left = this.x;
202 | this.top = this.y;
203 | this.right = this.parentWidth - (this.w === 'auto' ? this.$refs.container.scrollWidth : this.w) - this.left;
204 | this.bottom = this.parentHeight - (this.h === 'auto' ? this.$refs.container.scrollHeight : this.h) - this.top;
205 |
206 | this.domEvents = new Map([
207 | ['mousemove', this.move],
208 | ['mouseup', this.up],
209 | ['mouseleave', this.up],
210 | ['mousedown', this.deselect],
211 | ['touchmove', this.move],
212 | ['touchend', this.up],
213 | ['touchcancel', this.up],
214 | ['touchstart', this.up],
215 | ]);
216 |
217 | addEvents(this.domEvents);
218 |
219 | if (this.dragHandle) {
220 | [...this.$el.querySelectorAll(this.dragHandle)].forEach((dragHandle) => {
221 | dragHandle.setAttribute('data-drag-handle', this._uid);
222 | });
223 | }
224 |
225 | if (this.dragCancel) {
226 | [...this.$el.querySelectorAll(this.dragCancel)].forEach((cancelHandle) => {
227 | cancelHandle.setAttribute('data-drag-cancel', this._uid);
228 | });
229 | }
230 | },
231 |
232 | beforeDestroy() {
233 | removeEvents(this.domEvents);
234 | },
235 |
236 | methods: {
237 | deselect() {
238 | if (this.preventActiveBehavior) {
239 | return;
240 | }
241 | this.active = false;
242 | },
243 |
244 | move(ev) {
245 | if (!this.stickDrag && !this.bodyDrag) {
246 | return;
247 | }
248 |
249 | ev.stopPropagation();
250 |
251 | const pageX = typeof ev.pageX !== 'undefined' ? ev.pageX : ev.touches[0].pageX;
252 | const pageY = typeof ev.pageY !== 'undefined' ? ev.pageY : ev.touches[0].pageY;
253 |
254 | const { dimensionsBeforeMove } = this;
255 |
256 | const delta = {
257 | x: (dimensionsBeforeMove.pointerX - pageX) / this.parentScaleX,
258 | y: (dimensionsBeforeMove.pointerY - pageY) / this.parentScaleY,
259 | };
260 |
261 | if (this.stickDrag) {
262 | this.stickMove(delta);
263 | }
264 |
265 | if (this.bodyDrag) {
266 | if (this.axis === 'x') {
267 | delta.y = 0;
268 | } else if (this.axis === 'y') {
269 | delta.x = 0;
270 | } else if (this.axis === 'none') {
271 | return;
272 | }
273 | this.bodyMove(delta);
274 | }
275 | },
276 |
277 | up(ev) {
278 | if (this.stickDrag) {
279 | this.stickUp(ev);
280 | } else if (this.bodyDrag) {
281 | this.bodyUp(ev);
282 | }
283 | },
284 |
285 | bodyDown(ev) {
286 | const { target, button } = ev;
287 |
288 | if (!this.preventActiveBehavior) {
289 | this.active = true;
290 | }
291 |
292 | if (button && button !== 0) {
293 | return;
294 | }
295 |
296 | this.$emit('clicked', ev);
297 |
298 | if (!this.active) {
299 | return;
300 | }
301 |
302 | if (this.dragHandle && target.getAttribute('data-drag-handle') !== this._uid.toString()) {
303 | return;
304 | }
305 |
306 | if (this.dragCancel && target.getAttribute('data-drag-cancel') === this._uid.toString()) {
307 | return;
308 | }
309 |
310 | if (typeof ev.stopPropagation !== 'undefined') {
311 | ev.stopPropagation();
312 | }
313 |
314 | if (typeof ev.preventDefault !== 'undefined') {
315 | ev.preventDefault();
316 | }
317 |
318 | if (this.isDraggable) {
319 | this.bodyDrag = true;
320 | }
321 |
322 | const pointerX = typeof ev.pageX !== 'undefined' ? ev.pageX : ev.touches[0].pageX;
323 | const pointerY = typeof ev.pageY !== 'undefined' ? ev.pageY : ev.touches[0].pageY;
324 |
325 | this.saveDimensionsBeforeMove({ pointerX, pointerY });
326 |
327 | if (this.parentLimitation) {
328 | this.limits = this.calcDragLimitation();
329 | }
330 | },
331 |
332 | bodyMove(delta) {
333 | const { dimensionsBeforeMove, parentWidth, parentHeight, gridX, gridY, width, height } = this;
334 |
335 | let newTop = dimensionsBeforeMove.top - delta.y;
336 | let newBottom = dimensionsBeforeMove.bottom + delta.y;
337 | let newLeft = dimensionsBeforeMove.left - delta.x;
338 | let newRight = dimensionsBeforeMove.right + delta.x;
339 |
340 | if (this.snapToGrid) {
341 | let alignTop = true;
342 | let alignLeft = true;
343 |
344 | let diffT = newTop - Math.floor(newTop / gridY) * gridY;
345 | let diffB = (parentHeight - newBottom) - Math.floor((parentHeight - newBottom) / gridY) * gridY;
346 | let diffL = newLeft - Math.floor(newLeft / gridX) * gridX;
347 | let diffR = (parentWidth - newRight) - Math.floor((parentWidth - newRight) / gridX) * gridX;
348 |
349 | if (diffT > (gridY / 2)) {
350 | diffT -= gridY;
351 | }
352 | if (diffB > (gridY / 2)) {
353 | diffB -= gridY;
354 | }
355 | if (diffL > (gridX / 2)) {
356 | diffL -= gridX;
357 | }
358 | if (diffR > (gridX / 2)) {
359 | diffR -= gridX;
360 | }
361 |
362 | if (Math.abs(diffB) < Math.abs(diffT)) {
363 | alignTop = false;
364 | }
365 | if (Math.abs(diffR) < Math.abs(diffL)) {
366 | alignLeft = false;
367 | }
368 |
369 | newTop -= (alignTop ? diffT : diffB);
370 | newBottom = parentHeight - height - newTop;
371 | newLeft -= (alignLeft ? diffL : diffR);
372 | newRight = parentWidth - width - newLeft;
373 | }
374 |
375 | ({
376 | newLeft: this.left,
377 | newRight: this.right,
378 | newTop: this.top,
379 | newBottom: this.bottom,
380 | } = this.rectCorrectionByLimit({ newLeft, newRight, newTop, newBottom }));
381 |
382 | this.$emit('dragging', this.rect);
383 | },
384 |
385 | bodyUp() {
386 | this.bodyDrag = false;
387 | this.$emit('dragging', this.rect);
388 | this.$emit('dragstop', this.rect);
389 |
390 | this.dimensionsBeforeMove = { pointerX: 0, pointerY: 0, x: 0, y: 0, w: 0, h: 0 };
391 |
392 | this.limits = {
393 | left: { min: null, max: null },
394 | right: { min: null, max: null },
395 | top: { min: null, max: null },
396 | bottom: { min: null, max: null },
397 | };
398 | },
399 |
400 | stickDown(stick, ev, force = false) {
401 | if ((!this.isResizable || !this.active) && !force) {
402 | return;
403 | }
404 |
405 | this.stickDrag = true;
406 |
407 | const pointerX = typeof ev.pageX !== 'undefined' ? ev.pageX : ev.touches[0].pageX;
408 | const pointerY = typeof ev.pageY !== 'undefined' ? ev.pageY : ev.touches[0].pageY;
409 |
410 | this.saveDimensionsBeforeMove({ pointerX, pointerY });
411 |
412 | this.currentStick = stick;
413 |
414 | this.limits = this.calcResizeLimits();
415 | },
416 |
417 | saveDimensionsBeforeMove({ pointerX, pointerY }) {
418 | this.dimensionsBeforeMove.pointerX = pointerX;
419 | this.dimensionsBeforeMove.pointerY = pointerY;
420 |
421 | this.dimensionsBeforeMove.left = this.left;
422 | this.dimensionsBeforeMove.right = this.right;
423 | this.dimensionsBeforeMove.top = this.top;
424 | this.dimensionsBeforeMove.bottom = this.bottom;
425 |
426 | this.dimensionsBeforeMove.width = this.width;
427 | this.dimensionsBeforeMove.height = this.height;
428 |
429 | this.aspectFactor = this.width / this.height;
430 | },
431 |
432 | stickMove(delta) {
433 | const {
434 | currentStick,
435 | dimensionsBeforeMove,
436 | gridY,
437 | gridX,
438 | snapToGrid,
439 | parentHeight,
440 | parentWidth,
441 | } = this;
442 |
443 | let newTop = dimensionsBeforeMove.top;
444 | let newBottom = dimensionsBeforeMove.bottom;
445 | let newLeft = dimensionsBeforeMove.left;
446 | let newRight = dimensionsBeforeMove.right;
447 | switch(currentStick[0]) {
448 | case 'b':
449 | newBottom = dimensionsBeforeMove.bottom + delta.y;
450 |
451 | if (snapToGrid) {
452 | newBottom = parentHeight - Math.round((parentHeight - newBottom) / gridY) * gridY;
453 | }
454 |
455 | break;
456 |
457 | case 't':
458 | newTop = dimensionsBeforeMove.top - delta.y;
459 |
460 | if (snapToGrid) {
461 | newTop = Math.round(newTop / gridY) * gridY;
462 | }
463 |
464 | break;
465 | default:
466 | break;
467 | }
468 |
469 | switch(currentStick[1]) {
470 | case 'r':
471 | newRight = dimensionsBeforeMove.right + delta.x;
472 |
473 | if (snapToGrid) {
474 | newRight = parentWidth - Math.round((parentWidth - newRight) / gridX) * gridX;
475 | }
476 |
477 | break;
478 |
479 | case 'l':
480 | newLeft = dimensionsBeforeMove.left - delta.x;
481 |
482 | if (snapToGrid) {
483 | newLeft = Math.round(newLeft / gridX) * gridX;
484 | }
485 |
486 | break;
487 | default:
488 | break;
489 | }
490 |
491 | ({
492 | newLeft,
493 | newRight,
494 | newTop,
495 | newBottom,
496 | } = this.rectCorrectionByLimit({ newLeft, newRight, newTop, newBottom }));
497 |
498 | if (this.aspectRatio) {
499 | ({
500 | newLeft,
501 | newRight,
502 | newTop,
503 | newBottom,
504 | } = this.rectCorrectionByAspectRatio({ newLeft, newRight, newTop, newBottom }));
505 | }
506 |
507 | this.left = newLeft;
508 | this.right = newRight;
509 | this.top = newTop;
510 | this.bottom = newBottom;
511 |
512 | this.$emit('resizing', this.rect);
513 | },
514 |
515 | stickUp() {
516 | this.stickDrag = false;
517 | this.dimensionsBeforeMove = {
518 | pointerX: 0,
519 | pointerY: 0,
520 | x: 0,
521 | y: 0,
522 | w: 0,
523 | h: 0,
524 | };
525 | this.limits = {
526 | left: { min: null, max: null },
527 | right: { min: null, max: null },
528 | top: { min: null, max: null },
529 | bottom: { min: null, max: null },
530 | };
531 |
532 | this.$emit('resizing', this.rect);
533 | this.$emit('resizestop', this.rect);
534 | },
535 |
536 | calcDragLimitation() {
537 | const { parentWidth, parentHeight } = this;
538 |
539 | return {
540 | left: { min: 0, max: parentWidth - this.width },
541 | right: { min: 0, max: parentWidth - this.width },
542 | top: { min: 0, max: parentHeight - this.height },
543 | bottom: { min: 0, max: parentHeight - this.height },
544 | };
545 | },
546 |
547 | calcResizeLimits() {
548 | const { aspectFactor, width, height, bottom, top, left, right } = this;
549 | let { minh: minHeight, minw: minWidth } = this;
550 |
551 | const parentLim = this.parentLimitation ? 0 : null;
552 |
553 | if (this.aspectRatio) {
554 | if (minWidth / minHeight > aspectFactor) {
555 | minHeight = minWidth / aspectFactor;
556 | } else {
557 | minWidth = aspectFactor * minHeight;
558 | }
559 | }
560 |
561 | const limits = {
562 | left: { min: parentLim, max: left + (width - minWidth) },
563 | right: { min: parentLim, max: right + (width - minWidth) },
564 | top: { min: parentLim, max: top + (height - minHeight) },
565 | bottom: { min: parentLim, max: bottom + (height - minHeight) },
566 | };
567 |
568 | if (this.aspectRatio) {
569 | const aspectLimits = {
570 | left: {
571 | min: left - (Math.min(top, bottom) * aspectFactor) * 2,
572 | max: left + ((((height - minHeight) / 2) * aspectFactor) * 2),
573 | },
574 | right: {
575 | min: right - (Math.min(top, bottom) * aspectFactor) * 2,
576 | max: right + ((((height - minHeight) / 2) * aspectFactor) * 2),
577 | },
578 | top: {
579 | min: top - (Math.min(left, right) / aspectFactor) * 2,
580 | max: top + ((((width - minWidth) / 2) / aspectFactor) * 2),
581 | },
582 | bottom: {
583 | min: bottom - (Math.min(left, right) / aspectFactor) * 2,
584 | max: bottom + ((((width - minWidth) / 2) / aspectFactor) * 2),
585 | },
586 | };
587 |
588 | if (this.currentStick[0] === 'm') {
589 | limits.left = {
590 | min: Math.max(limits.left.min, aspectLimits.left.min),
591 | max: Math.min(limits.left.max, aspectLimits.left.max),
592 | };
593 | limits.right = {
594 | min: Math.max(limits.right.min, aspectLimits.right.min),
595 | max: Math.min(limits.right.max, aspectLimits.right.max),
596 | };
597 |
598 | } else if (this.currentStick[1] === 'm') {
599 | limits.top = {
600 | min: Math.max(limits.top.min, aspectLimits.top.min),
601 | max: Math.min(limits.top.max, aspectLimits.top.max),
602 | };
603 | limits.bottom = {
604 | min: Math.max(limits.bottom.min, aspectLimits.bottom.min),
605 | max: Math.min(limits.bottom.max, aspectLimits.bottom.max),
606 | };
607 | }
608 | }
609 |
610 | return limits;
611 | },
612 |
613 | sideCorrectionByLimit(limit, current) {
614 | let value = current;
615 |
616 | if (limit.min !== null && current < limit.min) {
617 | value = limit.min;
618 | } else if (limit.max !== null && limit.max < current) {
619 | value = limit.max;
620 | }
621 |
622 | return value;
623 | },
624 |
625 | rectCorrectionByLimit(rect) {
626 | const { limits } = this;
627 | let { newRight, newLeft, newBottom, newTop } = rect;
628 |
629 | newLeft = this.sideCorrectionByLimit(limits.left, newLeft);
630 | newRight = this.sideCorrectionByLimit(limits.right, newRight);
631 | newTop = this.sideCorrectionByLimit(limits.top, newTop);
632 | newBottom = this.sideCorrectionByLimit(limits.bottom, newBottom);
633 |
634 | return {
635 | newLeft,
636 | newRight,
637 | newTop,
638 | newBottom,
639 | };
640 | },
641 |
642 | rectCorrectionByAspectRatio(rect) {
643 | let { newLeft, newRight, newTop, newBottom } = rect;
644 | const { parentWidth, parentHeight, currentStick, aspectFactor, dimensionsBeforeMove } = this;
645 |
646 | let newWidth = parentWidth - newLeft - newRight;
647 | let newHeight = parentHeight - newTop - newBottom;
648 |
649 | if (currentStick[1] === 'm') {
650 | const deltaHeight = newHeight - dimensionsBeforeMove.height;
651 |
652 | newLeft -= (deltaHeight * aspectFactor) / 2;
653 | newRight -= (deltaHeight * aspectFactor) / 2;
654 | } else if (currentStick[0] === 'm') {
655 | const deltaWidth = newWidth - dimensionsBeforeMove.width;
656 |
657 | newTop -= (deltaWidth / aspectFactor) / 2;
658 | newBottom -= (deltaWidth / aspectFactor) / 2;
659 | } else if (newWidth / newHeight > aspectFactor) {
660 | newWidth = aspectFactor * newHeight;
661 |
662 | if (currentStick[1] === 'l') {
663 | newLeft = parentWidth - newRight - newWidth;
664 | } else {
665 | newRight = parentWidth - newLeft - newWidth;
666 | }
667 | } else {
668 | newHeight = newWidth / aspectFactor;
669 |
670 | if (currentStick[0] === 't') {
671 | newTop = parentHeight - newBottom - newHeight;
672 | } else {
673 | newBottom = parentHeight - newTop - newHeight;
674 | }
675 | }
676 |
677 | return { newLeft, newRight, newTop, newBottom };
678 | },
679 | },
680 |
681 | computed: {
682 | positionStyle() {
683 | return {
684 | top: this.top + 'px',
685 | left: this.left + 'px',
686 | zIndex: this.zIndex,
687 | };
688 | },
689 |
690 | sizeStyle(){
691 | return {
692 | width: this.w == 'auto' ? 'auto' : this.width + 'px',
693 | height: this.h == 'auto' ? 'auto' : this.height + 'px'
694 | };
695 | },
696 |
697 | vdrStick() {
698 | return (stick) => {
699 | const stickStyle = {
700 | width: `${this.stickSize / this.parentScaleX}px`,
701 | height: `${this.stickSize / this.parentScaleY}px`,
702 | };
703 | stickStyle[styleMapping.y[stick[0]]] = `${this.stickSize / this.parentScaleX / -2}px`;
704 | stickStyle[styleMapping.x[stick[1]]] = `${this.stickSize / this.parentScaleX / -2}px`;
705 | return stickStyle;
706 | };
707 | },
708 |
709 | width() {
710 | return this.parentWidth - this.left - this.right;
711 | },
712 |
713 | height() {
714 | return this.parentHeight - this.top - this.bottom;
715 | },
716 |
717 | rect() {
718 | return {
719 | left: Math.round(this.left),
720 | top: Math.round(this.top),
721 | width: Math.round(this.width),
722 | height: Math.round(this.height),
723 | };
724 | },
725 | },
726 |
727 | watch: {
728 | active(isActive) {
729 | if (isActive) {
730 | this.$emit('activated');
731 | } else {
732 | this.$emit('deactivated');
733 | }
734 | },
735 |
736 | isActive: {
737 | immediate: true,
738 | handler(val) {
739 | this.active = val;
740 | },
741 | },
742 |
743 | z: {
744 | immediate: true,
745 | handler(val) {
746 | if (val >= 0 || val === 'auto') {
747 | this.zIndex = val;
748 | }
749 | },
750 | },
751 |
752 | x: {
753 | handler(newVal, oldVal) {
754 | if (this.stickDrag || this.bodyDrag || (newVal === this.left)) {
755 | return;
756 | }
757 |
758 | const delta = oldVal - newVal;
759 |
760 | this.bodyDown({ pageX: this.left, pageY: this.top });
761 | this.bodyMove({ x: delta, y: 0 });
762 |
763 | this.$nextTick(() => {
764 | this.bodyUp();
765 | });
766 | },
767 | },
768 |
769 | y: {
770 | handler(newVal, oldVal) {
771 | if (this.stickDrag || this.bodyDrag || (newVal === this.top)) {
772 | return;
773 | }
774 |
775 | const delta = oldVal - newVal;
776 |
777 | this.bodyDown({ pageX: this.left, pageY: this.top });
778 | this.bodyMove({ x: 0, y: delta });
779 |
780 | this.$nextTick(() => {
781 | this.bodyUp();
782 | });
783 | },
784 | },
785 |
786 | w: {
787 | handler(newVal, oldVal) {
788 | if (this.stickDrag || this.bodyDrag || (newVal === this.width)) {
789 | return;
790 | }
791 |
792 | const stick = 'mr';
793 | const delta = oldVal - newVal;
794 |
795 | this.stickDown(stick, { pageX: this.right, pageY: this.top + (this.height / 2) }, true);
796 | this.stickMove({ x: delta, y: 0 });
797 |
798 | this.$nextTick(() => {
799 | this.stickUp();
800 | });
801 | },
802 | },
803 |
804 | h: {
805 | handler(newVal, oldVal) {
806 | if (this.stickDrag || this.bodyDrag || (newVal === this.height)) {
807 | return;
808 | }
809 |
810 | const stick = 'bm';
811 | const delta = oldVal - newVal;
812 |
813 | this.stickDown(stick, { pageX: this.left + (this.width / 2), pageY: this.bottom }, true);
814 | this.stickMove({ x: 0, y: delta });
815 |
816 | this.$nextTick(() => {
817 | this.stickUp();
818 | });
819 | },
820 | },
821 |
822 | parentW(val) {
823 | this.right = val - this.width - this.left;
824 | this.parentWidth = val;
825 | },
826 |
827 | parentH(val) {
828 | this.bottom = val - this.height - this.top;
829 | this.parentHeight = val;
830 | },
831 | },
832 | };
833 |
--------------------------------------------------------------------------------
/src/components/vue-drag-resize.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/demo/app.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import app from './app.vue';
3 | import store from './store';
4 | import * as svgicon from 'vue-svgicon';
5 |
6 | Vue.use(svgicon, {
7 | tagName: 'svgicon'
8 | });
9 |
10 | new Vue({
11 | el: '#app',
12 | store,
13 | template: '',
14 | components: { app }
15 | });
--------------------------------------------------------------------------------
/src/demo/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
34 |
35 |
36 |
73 |
74 |
--------------------------------------------------------------------------------
/src/demo/components/toolbar/toolbar.css:
--------------------------------------------------------------------------------
1 | :root{
2 | --toolbar-width: 220px;
3 | }
4 | .toolbar{
5 | position: absolute;
6 | right: 0;
7 | top: 0;
8 | width: var(--toolbar-width);
9 | padding: 15px 15px 0 15px;
10 | box-shadow: 0 0 2px #AAA;
11 | box-sizing: border-box;
12 | background-color: white;
13 | margin: 30px 30px 30px 0;
14 | }
15 | .toolbar-wh-row{
16 |
17 | margin-bottom: 20px;
18 | }
19 | .toolbar-row-title{
20 | width: var(--toolbar-width);
21 | font-size: 14px;
22 | font-family: 'Lato', sans-serif;
23 | font-weight: 500;
24 | margin: 0 0 3px 0;
25 | color: #1A173B;
26 | }
27 | .toolbar-position-inp, .toolbar-size-inp{
28 | width: 90px;
29 | font-size: 11px;
30 | color: #BBB;
31 | font-weight: 300;
32 | display: inline-block;
33 | position: relative;
34 | }
35 |
36 | .toolbar-size-inp input,.toolbar-position-inp input{
37 | width: 70px;
38 | display: inline-block;
39 | border: 1px solid #bfbfca;
40 | margin-top: 2px;
41 | height: 16px;
42 | }
43 |
44 | .toolbar-size-inp input[disabled],.toolbar-position-inp input[disabled]{
45 | border: 1px solid #dcdce7;
46 | color: #AAAAAA;
47 | }
48 |
49 | .position-lock-icon, .size-lock-icon{
50 | position: absolute;
51 | bottom: 3px;
52 | right: 17px;
53 | cursor: pointer;
54 | }
55 | .size-lock-icon{
56 | bottom: 2px;
57 | right: -3px;
58 | }
59 |
60 | .toolbar-check-inp{
61 | color: #445477;
62 | font-size: 13px;
63 | width: 180px;
64 | display: inline-block;
65 | margin: 2px 0;
66 | }
67 | .toolbar-row-title+label{
68 | margin-top: 5px;
69 | }
70 | .toolbar-check-inp input{
71 | border: 1px solid #bfbfca;
72 | }
73 | .to-top-icon, .to-bottom-icon{
74 | margin: 10px 30px;
75 | cursor: pointer;
76 | }
77 |
--------------------------------------------------------------------------------
/src/demo/components/toolbar/toolbar.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/demo/components/toolbar/toolbar.js:
--------------------------------------------------------------------------------
1 | export default {
2 | computed: {
3 | activeRect() {
4 | return this.$store.getters['rect/getActive'];
5 | },
6 |
7 | width() {
8 | return this.activeRect === null ? '' : this.$store.state.rect.rects[this.activeRect].width
9 | },
10 |
11 | height() {
12 | return this.activeRect === null ? '' : this.$store.state.rect.rects[this.activeRect].height
13 | },
14 |
15 | top() {
16 | return this.activeRect === null ? '' : this.$store.state.rect.rects[this.activeRect].top
17 | },
18 |
19 | left() {
20 | return this.activeRect === null ? '' : this.$store.state.rect.rects[this.activeRect].left
21 | },
22 |
23 | minw() {
24 | return this.activeRect === null ? '' : this.$store.state.rect.rects[this.activeRect].minw
25 | },
26 |
27 | minh() {
28 | return this.activeRect === null ? '' : this.$store.state.rect.rects[this.activeRect].minh
29 | },
30 |
31 | aspectRatio() {
32 | return this.activeRect === null ? false : this.$store.state.rect.rects[this.activeRect].aspectRatio;
33 | },
34 |
35 | parentLim() {
36 | return this.activeRect === null ? false : this.$store.state.rect.rects[this.activeRect].parentLim;
37 | },
38 |
39 | draggable() {
40 | return this.activeRect === null ? false : this.$store.state.rect.rects[this.activeRect].draggable;
41 | },
42 |
43 | resizable() {
44 | return this.activeRect === null ? false : this.$store.state.rect.rects[this.activeRect].resizable;
45 | },
46 |
47 | snapToGrid() {
48 | return this.activeRect === null ? false : this.$store.state.rect.rects[this.activeRect].snapToGrid;
49 | },
50 |
51 | topIsLocked() {
52 | if (this.activeRect === null) {
53 | return false;
54 | }
55 | return (this.$store.state.rect.rects[this.activeRect].axis === 'x' ||
56 | this.$store.state.rect.rects[this.activeRect].axis === 'none')
57 | },
58 |
59 | leftIsLocked() {
60 | if (this.activeRect === null) {
61 | return false;
62 | }
63 | return (this.$store.state.rect.rects[this.activeRect].axis === 'y' ||
64 | this.$store.state.rect.rects[this.activeRect].axis === 'none')
65 | },
66 |
67 | zIndex() {
68 | if (this.activeRect === null) {
69 | return null;
70 | }
71 |
72 | return this.$store.state.rect.rects[this.activeRect].zIndex === 1 ? 'isFirst' :
73 | this.$store.state.rect.rects[this.activeRect].zIndex === this.$store.state.rect.rects.length ? 'isLast' : 'normal'
74 |
75 | }
76 | },
77 | methods: {
78 | toggleYLock() {
79 | if (this.activeRect === null) {
80 | return
81 | }
82 |
83 | this.$store.dispatch('rect/changeYLock', {id: this.activeRect});
84 | },
85 | toggleXLock() {
86 | if (this.activeRect === null) {
87 | return
88 | }
89 |
90 | this.$store.dispatch('rect/changeXLock', {id: this.activeRect});
91 | },
92 |
93 | toggleAspect() {
94 | if (this.activeRect === null) {
95 | return
96 | }
97 | if (!this.$store.state.rect.rects[this.activeRect].aspectRatio) {
98 | this.$store.dispatch('rect/setAspect', {id: this.activeRect});
99 | } else {
100 | this.$store.dispatch('rect/unsetAspect', {id: this.activeRect});
101 | }
102 | },
103 |
104 | toggleParentLimitation() {
105 | this.$store.dispatch('rect/toggleParentLimitation', {id: this.activeRect});
106 | },
107 |
108 | toggleResizable() {
109 | this.$store.dispatch('rect/toggleResizable', {id: this.activeRect});
110 | },
111 |
112 | toggleDraggable() {
113 | this.$store.dispatch('rect/toggleDraggable', {id: this.activeRect});
114 | },
115 |
116 | toggleSnapToGrid() {
117 | this.$store.dispatch('rect/toggleSnapToGrid', {id: this.activeRect});
118 | },
119 |
120 | toTop() {
121 | this.$store.dispatch('rect/changeZToTop', {id: this.activeRect});
122 | },
123 |
124 | toBottom() {
125 | this.$store.dispatch('rect/changeZToBottom', {id: this.activeRect});
126 | },
127 |
128 | changeMinWidth(ev) {
129 | let minw = parseInt(ev.target.value);
130 | if (typeof minw !== 'number' || isNaN(minw)) {
131 | minw = 1;
132 | }
133 |
134 | if (minw <= 0) {
135 | minw = 1;
136 | } else if (minw > this.$store.state.rect.rects[this.activeRect].width) {
137 | minw = this.$store.state.rect.rects[this.activeRect].width;
138 | }
139 |
140 | ev.target.value = minw;
141 |
142 | this.$store.dispatch('rect/setMinWidth', {id: this.activeRect, width: minw});
143 | },
144 |
145 | changeMinHeight(ev) {
146 | let minh = parseInt(ev.target.value);
147 |
148 | if (typeof minh !== 'number' || isNaN(minh)) {
149 | minh = 1;
150 | }
151 |
152 | if (minh <= 0) {
153 | minh = 1;
154 | } else if (minh > this.$store.state.rect.rects[this.activeRect].height) {
155 | minh = this.$store.state.rect.rects[this.activeRect].height;
156 | }
157 |
158 | ev.target.value = minh;
159 |
160 | this.$store.dispatch('rect/setMinHeight', {id: this.activeRect, height: minh});
161 | },
162 |
163 | changeTop(ev) {
164 | let top = parseInt(ev.target.value);
165 |
166 | if (typeof top !== 'number' || isNaN(top)) {
167 | top = this.$store.state.rect.rects[this.activeRect].top;
168 | ev.target.value = top;
169 | return
170 | }
171 |
172 | this.$store.dispatch('rect/setTop', {id: this.activeRect, top: top});
173 | },
174 |
175 | changeLeft(ev) {
176 | let left = parseInt(ev.target.value);
177 |
178 | if (typeof left !== 'number' || isNaN(left)) {
179 | left = this.$store.state.rect.rects[this.activeRect].left;
180 | ev.target.value = left;
181 | }
182 |
183 | this.$store.dispatch('rect/setLeft', {id: this.activeRect, left: left});
184 | },
185 |
186 | changeWidth(ev){
187 | let width = parseInt(ev.target.value);
188 |
189 | if (typeof width !== 'number' || isNaN(width)) {
190 | width = this.$store.state.rect.rects[this.activeRect].width;
191 | ev.target.value = width;
192 | }
193 |
194 | this.$store.dispatch('rect/setWidth', {id: this.activeRect, width: width});
195 | },
196 |
197 | changeHeight(ev){
198 | let height = parseInt(ev.target.value);
199 |
200 | if (typeof height !== 'number' || isNaN(height)) {
201 | height = this.$store.state.rect.rects[this.activeRect].height;
202 | ev.target.value = height;
203 | }
204 |
205 | this.$store.dispatch('rect/setHeight', {id: this.activeRect, height: height});
206 | }
207 | }
208 | }
--------------------------------------------------------------------------------
/src/demo/components/toolbar/toolbar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/demo/icons/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | require('./lock')
3 | require('./toBottom')
4 | require('./toTop')
5 |
--------------------------------------------------------------------------------
/src/demo/icons/lock.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var icon = require('vue-svgicon')
3 | icon.register({
4 | 'lock': {
5 | width: 100,
6 | height: 100,
7 | viewBox: '0 0 100 100',
8 | data: ''
9 | }
10 | })
11 |
--------------------------------------------------------------------------------
/src/demo/icons/toBottom.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var icon = require('vue-svgicon')
3 | icon.register({
4 | 'toBottom': {
5 | width: 100,
6 | height: 100,
7 | viewBox: '0 0 100 100',
8 | data: ''
9 | }
10 | })
11 |
--------------------------------------------------------------------------------
/src/demo/icons/toTop.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var icon = require('vue-svgicon')
3 | icon.register({
4 | 'toTop': {
5 | width: 100,
6 | height: 100,
7 | viewBox: '0 0 100 100',
8 | data: ''
9 | }
10 | })
11 |
--------------------------------------------------------------------------------
/src/demo/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 | import rect from './modules/rect'
4 |
5 | Vue.use(Vuex);
6 |
7 | const debug = process.env.NODE_ENV !== 'production';
8 |
9 | export default new Vuex.Store({
10 | /**
11 | * Assign the modules to the store
12 | */
13 | modules: {'rect': rect },
14 |
15 | /**
16 | * If strict mode should be enabled
17 | */
18 | strict: debug
19 | });
20 |
--------------------------------------------------------------------------------
/src/demo/store/modules/rect/actions.js:
--------------------------------------------------------------------------------
1 | import types, {CHANGE_ZINDEX} from './mutation-types';
2 |
3 | export default {
4 | setActive({commit, state}, {id}) {
5 | for (let i = 0, l = state.rects.length; i < l; i++) {
6 | if (i === id) {
7 | commit(types.ENABLE_ACTIVE, i);
8 | continue;
9 | }
10 |
11 | commit(types.DISABLE_ACTIVE, i);
12 | }
13 | },
14 | unsetActive({commit}, {id}) {
15 | commit(types.DISABLE_ACTIVE, id);
16 | },
17 |
18 | toggleDraggable({commit, state}, {id}) {
19 | if (!state.rects[id].draggable) {
20 | commit(types.ENABLE_DRAGGABLE, id);
21 | } else {
22 | commit(types.DISABLE_DRAGGABLE, id);
23 | }
24 | },
25 |
26 | toggleResizable({commit, state}, {id}) {
27 | if (!state.rects[id].resizable) {
28 | commit(types.ENABLE_RESIZABLE, id);
29 | } else {
30 | commit(types.DISABLE_RESIZABLE, id);
31 | }
32 | },
33 |
34 | toggleParentLimitation({commit, state}, {id}) {
35 | if (!state.rects[id].parentLim) {
36 | commit(types.ENABLE_PARENT_LIMITATION, id);
37 | } else {
38 | commit(types.DISABLE_PARENT_LIMITATION, id);
39 | }
40 | },
41 |
42 | toggleSnapToGrid({commit, state}, {id}) {
43 | if (!state.rects[id].snapToGrid) {
44 | commit(types.ENABLE_SNAP_TO_GRID, id);
45 | } else {
46 | commit(types.DISABLE_SNAP_TO_GRID, id);
47 | }
48 | },
49 |
50 | setAspect({commit}, {id}) {
51 | commit(types.ENABLE_ASPECT, id);
52 | },
53 | unsetAspect({commit}, {id}) {
54 | commit(types.DISABLE_ASPECT, id);
55 | },
56 |
57 | setWidth({commit}, {id, width}) {
58 | commit(types.CHANGE_WIDTH, {id, width});
59 | },
60 |
61 | setHeight({commit}, {id, height}) {
62 | commit(types.CHANGE_HEIGHT, {id, height});
63 | },
64 |
65 | setTop({commit}, {id, top}) {
66 | commit(types.CHANGE_TOP, {id, top});
67 | },
68 |
69 | setLeft({commit}, {id, left}) {
70 | commit(types.CHANGE_LEFT, {id, left});
71 | },
72 |
73 | changeXLock({commit, state}, {id}) {
74 | switch (state.rects[id].axis) {
75 | case 'both':
76 | commit(types.ENABLE_Y_AXIS, id);
77 | break;
78 | case 'x':
79 | commit(types.ENABLE_NONE_AXIS, id);
80 | break;
81 | case 'y':
82 | commit(types.ENABLE_BOTH_AXIS, id);
83 | break;
84 | case 'none':
85 | commit(types.ENABLE_X_AXIS, id);
86 | break;
87 | }
88 | },
89 |
90 | changeYLock({commit, state}, {id}) {
91 | switch (state.rects[id].axis) {
92 | case 'both':
93 | commit(types.ENABLE_X_AXIS, id);
94 | break;
95 | case 'x':
96 | commit(types.ENABLE_BOTH_AXIS, id);
97 | break;
98 | case 'y':
99 | commit(types.ENABLE_NONE_AXIS, id);
100 | break;
101 | case 'none':
102 | commit(types.ENABLE_Y_AXIS, id);
103 | break;
104 | }
105 | },
106 |
107 | changeZToBottom({commit, state}, {id}) {
108 | if (state.rects[id].zIndex === 1) {
109 | return
110 | }
111 |
112 | commit(types.CHANGE_ZINDEX, {id, zIndex: 1});
113 |
114 | for (let i = 0, l = state.rects.length; i < l; i++) {
115 | if (i !== id) {
116 | if(state.rects[i].zIndex === state.rects.length){
117 | continue
118 | }
119 | commit(types.CHANGE_ZINDEX, {id: i, zIndex: state.rects[i].zIndex + 1});
120 | }
121 | }
122 | },
123 |
124 | changeZToTop({commit, state}, {id}) {
125 | if (state.rects[id].zIndex === state.rects.length) {
126 | return
127 | }
128 |
129 | commit(types.CHANGE_ZINDEX, {id, zIndex: state.rects.length});
130 |
131 | for (let i = 0, l = state.rects.length; i < l; i++) {
132 | if (i !== id) {
133 | if(state.rects[i].zIndex === 1){
134 | continue
135 | }
136 | commit(types.CHANGE_ZINDEX, {id: i, zIndex: state.rects[i].zIndex - 1});
137 | }
138 | }
139 | },
140 |
141 | setMinWidth({commit}, {id, width}) {
142 | commit(types.CHANGE_MINW, {id, minw:width});
143 | },
144 |
145 | setMinHeight({commit}, {id, height}) {
146 | commit(types.CHANGE_MINH, {id, minh:height});
147 | }
148 | };
149 |
--------------------------------------------------------------------------------
/src/demo/store/modules/rect/getters.js:
--------------------------------------------------------------------------------
1 | export default {
2 | getActive: state => {
3 | for (let i = 0, l = state.rects.length; i < l; i++) {
4 | let rect = state.rects[i];
5 |
6 | if (rect.active) {
7 | return i;
8 | }
9 | }
10 | return null;
11 | }
12 | }
--------------------------------------------------------------------------------
/src/demo/store/modules/rect/index.js:
--------------------------------------------------------------------------------
1 | import actions from './actions';
2 | import getters from './getters';
3 | import mutations from './mutations';
4 | import state from './state';
5 |
6 | export default {
7 | namespaced: true,
8 | actions,
9 | getters,
10 | mutations,
11 | state
12 | };
13 |
--------------------------------------------------------------------------------
/src/demo/store/modules/rect/mutation-types.js:
--------------------------------------------------------------------------------
1 | export const ENABLE_ACTIVE = 'ENABLE_ACTIVE';
2 | export const DISABLE_ACTIVE = 'DISABLE_ACTIVE';
3 |
4 | export const ENABLE_DRAGGABLE = 'ENABLE_DRAGGABLE';
5 | export const DISABLE_DRAGGABLE = 'DISABLE_DRAGGABLE';
6 |
7 | export const ENABLE_RESIZABLE = 'ENABLE_RESIZABLE';
8 | export const DISABLE_RESIZABLE = 'DISABLE_RESIZABLE';
9 |
10 | export const ENABLE_PARENT_LIMITATION = 'ENABLE_PARENT_LIMITATION';
11 | export const DISABLE_PARENT_LIMITATION = 'DISABLE_PARENT_LIMITATION';
12 |
13 | export const ENABLE_SNAP_TO_GRID = 'ENABLE_SNAP_TO_GRID';
14 | export const DISABLE_SNAP_TO_GRID = 'DISABLE_SNAP_TO_GRID';
15 |
16 | export const ENABLE_ASPECT = 'ENABLE_ASPECT';
17 | export const DISABLE_ASPECT = 'DISABLE_ASPECT';
18 |
19 | export const ENABLE_X_AXIS = 'ENABLE_X_AXIS';
20 | export const ENABLE_Y_AXIS = 'ENABLE_Y_AXIS';
21 | export const ENABLE_BOTH_AXIS = 'ENABLE_BOTH_AXIS';
22 | export const ENABLE_NONE_AXIS = 'ENABLE_NONE_AXIS';
23 |
24 | export const CHANGE_ZINDEX = 'CHANGE_ZINDEX';
25 |
26 | export const CHANGE_MINW = 'CHANGE_MINW';
27 | export const CHANGE_MINH = 'CHANGE_MINH';
28 |
29 | export const CHANGE_WIDTH = 'CHANGE_WIDTH';
30 | export const CHANGE_HEIGHT = 'CHANGE_HEIGHT';
31 | export const CHANGE_TOP = 'CHANGE_TOP';
32 | export const CHANGE_LEFT = 'CHANGE_LEFT';
33 |
34 | export default {
35 | ENABLE_ACTIVE,
36 | DISABLE_ACTIVE,
37 | ENABLE_DRAGGABLE,
38 | DISABLE_DRAGGABLE,
39 | ENABLE_RESIZABLE,
40 | DISABLE_RESIZABLE,
41 | ENABLE_PARENT_LIMITATION,
42 | DISABLE_PARENT_LIMITATION,
43 | ENABLE_SNAP_TO_GRID,
44 | DISABLE_SNAP_TO_GRID,
45 | ENABLE_ASPECT,
46 | DISABLE_ASPECT,
47 | ENABLE_X_AXIS,
48 | ENABLE_Y_AXIS,
49 | ENABLE_NONE_AXIS,
50 | ENABLE_BOTH_AXIS,
51 | CHANGE_ZINDEX,
52 | CHANGE_MINW,
53 | CHANGE_MINH,
54 | CHANGE_WIDTH,
55 | CHANGE_HEIGHT,
56 | CHANGE_TOP,
57 | CHANGE_LEFT
58 | }
--------------------------------------------------------------------------------
/src/demo/store/modules/rect/mutations.js:
--------------------------------------------------------------------------------
1 | import {
2 | ENABLE_ACTIVE,
3 | DISABLE_ACTIVE,
4 | ENABLE_ASPECT,
5 | DISABLE_ASPECT,
6 | ENABLE_DRAGGABLE,
7 | DISABLE_DRAGGABLE,
8 | ENABLE_RESIZABLE,
9 | DISABLE_RESIZABLE,
10 | ENABLE_PARENT_LIMITATION,
11 | DISABLE_PARENT_LIMITATION,
12 | ENABLE_SNAP_TO_GRID,
13 | DISABLE_SNAP_TO_GRID,
14 | CHANGE_ZINDEX,
15 | ENABLE_BOTH_AXIS,
16 | ENABLE_X_AXIS,
17 | ENABLE_Y_AXIS,
18 | ENABLE_NONE_AXIS,
19 | CHANGE_HEIGHT,
20 | CHANGE_LEFT,
21 | CHANGE_MINH,
22 | CHANGE_MINW,
23 | CHANGE_TOP,
24 | CHANGE_WIDTH
25 | } from './mutation-types';
26 |
27 | export default {
28 | [ENABLE_ACTIVE](state, id) {
29 | state.rects[id].active = true;
30 | },
31 | [DISABLE_ACTIVE](state, id) {
32 | state.rects[id].active = false;
33 | },
34 |
35 | [ENABLE_ASPECT](state, id) {
36 | state.rects[id].aspectRatio = true;
37 | },
38 | [DISABLE_ASPECT](state, id) {
39 | state.rects[id].aspectRatio = false;
40 | },
41 |
42 | [ENABLE_DRAGGABLE](state, id) {
43 | state.rects[id].draggable = true;
44 | },
45 | [DISABLE_DRAGGABLE](state, id) {
46 | state.rects[id].draggable = false;
47 | },
48 |
49 | [ENABLE_RESIZABLE](state, id) {
50 | state.rects[id].resizable = true;
51 | },
52 | [DISABLE_RESIZABLE](state, id) {
53 | state.rects[id].resizable = false;
54 | },
55 |
56 | [ENABLE_SNAP_TO_GRID](state, id) {
57 | state.rects[id].snapToGrid = true;
58 | },
59 | [DISABLE_SNAP_TO_GRID](state, id) {
60 | state.rects[id].snapToGrid = false;
61 | },
62 |
63 | [ENABLE_BOTH_AXIS](state, id) {
64 | state.rects[id].axis = 'both';
65 | },
66 | [ENABLE_NONE_AXIS](state, id) {
67 | state.rects[id].axis = 'none';
68 | },
69 | [ENABLE_X_AXIS](state, id) {
70 | state.rects[id].axis = 'x';
71 | },
72 | [ENABLE_Y_AXIS](state, id) {
73 | state.rects[id].axis = 'y';
74 | },
75 |
76 | [ENABLE_PARENT_LIMITATION](state, id) {
77 | state.rects[id].parentLim = true;
78 | },
79 | [DISABLE_PARENT_LIMITATION](state, id) {
80 | state.rects[id].parentLim = false;
81 | },
82 |
83 | [CHANGE_ZINDEX](state, payload) {
84 | state.rects[payload.id].zIndex = payload.zIndex;
85 | },
86 |
87 | [CHANGE_HEIGHT](state, payload) {
88 | state.rects[payload.id].height = payload.height;
89 | },
90 |
91 | [CHANGE_WIDTH](state, payload) {
92 | state.rects[payload.id].width = payload.width;
93 | },
94 |
95 | [CHANGE_TOP](state, payload) {
96 | state.rects[payload.id].top = payload.top;
97 | },
98 |
99 | [CHANGE_LEFT](state, payload) {
100 | state.rects[payload.id].left = payload.left;
101 | },
102 |
103 | [CHANGE_MINH](state, payload) {
104 |
105 | state.rects[payload.id].minh = payload.minh;
106 | },
107 |
108 | [CHANGE_MINW](state, payload) {
109 | state.rects[payload.id].minw = payload.minw;
110 | }
111 | };
--------------------------------------------------------------------------------
/src/demo/store/modules/rect/state.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'rects': [
3 | {
4 | 'width': 200,
5 | 'height': 150,
6 | 'top': 10,
7 | 'left': 10,
8 | 'draggable': true,
9 | 'resizable': true,
10 | 'minw': 10,
11 | 'minh': 10,
12 | 'axis': 'both',
13 | 'parentLim': true,
14 | 'snapToGrid': false,
15 | 'aspectRatio': false,
16 | 'zIndex': 1,
17 | 'color': '#EF9A9A',
18 | 'active': false
19 | },
20 | {
21 | 'width': 200,
22 | 'height': 150,
23 | 'top': 170,
24 | 'left': 220,
25 | 'draggable': true,
26 | 'resizable': true,
27 | 'minw': 10,
28 | 'minh': 10,
29 | 'axis': 'both',
30 | 'parentLim': true,
31 | 'snapToGrid': false,
32 | 'aspectRatio': false,
33 | 'zIndex': 1,
34 | 'color': '#E6C27A',
35 | 'active': false,
36 | 'class': 'box-shaddow'
37 | },
38 | {
39 | 'width': 200,
40 | 'height': 150,
41 | 'top': 10,
42 | 'left': 220,
43 | 'draggable': true,
44 | 'resizable': true,
45 | 'minw': 10,
46 | 'minh': 10,
47 | 'axis': 'both',
48 | 'parentLim': true,
49 | 'snapToGrid': false,
50 | 'aspectRatio': false,
51 | 'zIndex': 2,
52 | 'color': '#AED581',
53 | 'active': false
54 | },
55 | {
56 | 'width': 200,
57 | 'height': 150,
58 | 'top': 170,
59 | 'left': 10,
60 | 'draggable': true,
61 | 'resizable': true,
62 | 'minw': 10,
63 | 'minh': 10,
64 | 'axis': 'both',
65 | 'parentLim': true,
66 | 'snapToGrid': false,
67 | 'aspectRatio': false,
68 | 'zIndex': 3,
69 | 'color': '#81D4FA',
70 | 'active': false
71 | }
72 | ]
73 | };
74 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // Import vue component
2 | import VueDragResize from './components/vue-drag-resize.vue';
3 |
4 | // Declare install function executed by Vue.use()
5 | export function install(Vue) {
6 | if (install.installed) return;
7 | install.installed = true;
8 | Vue.component('vue-drag-resize', VueDragResize);
9 | }
10 |
11 | // Create module definition for Vue.use()
12 | const plugin = {
13 | install,
14 | };
15 |
16 | // Auto-install when vue is found (eg. in browser via
61 |