├── .gitignore ├── LICENSE ├── index.html ├── package-lock.json ├── package.json ├── readme.md ├── resizer.css ├── resizer.js ├── resizer.min.js ├── resizer.png ├── script.js └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Govind Prasad Gupta 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 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | move-rotate-resizer:demo 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 22 |
23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "move-rotate-resizer", 3 | "version": "1.0.6", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "move-rotate-resizer", 9 | "version": "1.0.6", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "gh-pages": "^3.2.3" 13 | } 14 | }, 15 | "node_modules/array-union": { 16 | "version": "1.0.2", 17 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", 18 | "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", 19 | "dev": true, 20 | "dependencies": { 21 | "array-uniq": "^1.0.1" 22 | }, 23 | "engines": { 24 | "node": ">=0.10.0" 25 | } 26 | }, 27 | "node_modules/array-uniq": { 28 | "version": "1.0.3", 29 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 30 | "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", 31 | "dev": true, 32 | "engines": { 33 | "node": ">=0.10.0" 34 | } 35 | }, 36 | "node_modules/async": { 37 | "version": "2.6.4", 38 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", 39 | "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", 40 | "dev": true, 41 | "dependencies": { 42 | "lodash": "^4.17.14" 43 | } 44 | }, 45 | "node_modules/balanced-match": { 46 | "version": "1.0.2", 47 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 48 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 49 | "dev": true 50 | }, 51 | "node_modules/brace-expansion": { 52 | "version": "1.1.11", 53 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 54 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 55 | "dev": true, 56 | "dependencies": { 57 | "balanced-match": "^1.0.0", 58 | "concat-map": "0.0.1" 59 | } 60 | }, 61 | "node_modules/commander": { 62 | "version": "2.20.3", 63 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 64 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 65 | "dev": true 66 | }, 67 | "node_modules/commondir": { 68 | "version": "1.0.1", 69 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", 70 | "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", 71 | "dev": true 72 | }, 73 | "node_modules/concat-map": { 74 | "version": "0.0.1", 75 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 76 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 77 | "dev": true 78 | }, 79 | "node_modules/email-addresses": { 80 | "version": "3.1.0", 81 | "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz", 82 | "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==", 83 | "dev": true 84 | }, 85 | "node_modules/escape-string-regexp": { 86 | "version": "1.0.5", 87 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 88 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 89 | "dev": true, 90 | "engines": { 91 | "node": ">=0.8.0" 92 | } 93 | }, 94 | "node_modules/filename-reserved-regex": { 95 | "version": "2.0.0", 96 | "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", 97 | "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", 98 | "dev": true, 99 | "engines": { 100 | "node": ">=4" 101 | } 102 | }, 103 | "node_modules/filenamify": { 104 | "version": "4.3.0", 105 | "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", 106 | "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", 107 | "dev": true, 108 | "dependencies": { 109 | "filename-reserved-regex": "^2.0.0", 110 | "strip-outer": "^1.0.1", 111 | "trim-repeated": "^1.0.0" 112 | }, 113 | "engines": { 114 | "node": ">=8" 115 | }, 116 | "funding": { 117 | "url": "https://github.com/sponsors/sindresorhus" 118 | } 119 | }, 120 | "node_modules/find-cache-dir": { 121 | "version": "3.3.2", 122 | "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", 123 | "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", 124 | "dev": true, 125 | "dependencies": { 126 | "commondir": "^1.0.1", 127 | "make-dir": "^3.0.2", 128 | "pkg-dir": "^4.1.0" 129 | }, 130 | "engines": { 131 | "node": ">=8" 132 | }, 133 | "funding": { 134 | "url": "https://github.com/avajs/find-cache-dir?sponsor=1" 135 | } 136 | }, 137 | "node_modules/find-up": { 138 | "version": "4.1.0", 139 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 140 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 141 | "dev": true, 142 | "dependencies": { 143 | "locate-path": "^5.0.0", 144 | "path-exists": "^4.0.0" 145 | }, 146 | "engines": { 147 | "node": ">=8" 148 | } 149 | }, 150 | "node_modules/fs-extra": { 151 | "version": "8.1.0", 152 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", 153 | "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", 154 | "dev": true, 155 | "dependencies": { 156 | "graceful-fs": "^4.2.0", 157 | "jsonfile": "^4.0.0", 158 | "universalify": "^0.1.0" 159 | }, 160 | "engines": { 161 | "node": ">=6 <7 || >=8" 162 | } 163 | }, 164 | "node_modules/fs.realpath": { 165 | "version": "1.0.0", 166 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 167 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 168 | "dev": true 169 | }, 170 | "node_modules/gh-pages": { 171 | "version": "3.2.3", 172 | "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.2.3.tgz", 173 | "integrity": "sha512-jA1PbapQ1jqzacECfjUaO9gV8uBgU6XNMV0oXLtfCX3haGLe5Atq8BxlrADhbD6/UdG9j6tZLWAkAybndOXTJg==", 174 | "dev": true, 175 | "dependencies": { 176 | "async": "^2.6.1", 177 | "commander": "^2.18.0", 178 | "email-addresses": "^3.0.1", 179 | "filenamify": "^4.3.0", 180 | "find-cache-dir": "^3.3.1", 181 | "fs-extra": "^8.1.0", 182 | "globby": "^6.1.0" 183 | }, 184 | "bin": { 185 | "gh-pages": "bin/gh-pages.js", 186 | "gh-pages-clean": "bin/gh-pages-clean.js" 187 | }, 188 | "engines": { 189 | "node": ">=10" 190 | } 191 | }, 192 | "node_modules/glob": { 193 | "version": "7.2.3", 194 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 195 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 196 | "dev": true, 197 | "dependencies": { 198 | "fs.realpath": "^1.0.0", 199 | "inflight": "^1.0.4", 200 | "inherits": "2", 201 | "minimatch": "^3.1.1", 202 | "once": "^1.3.0", 203 | "path-is-absolute": "^1.0.0" 204 | }, 205 | "engines": { 206 | "node": "*" 207 | }, 208 | "funding": { 209 | "url": "https://github.com/sponsors/isaacs" 210 | } 211 | }, 212 | "node_modules/globby": { 213 | "version": "6.1.0", 214 | "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", 215 | "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", 216 | "dev": true, 217 | "dependencies": { 218 | "array-union": "^1.0.1", 219 | "glob": "^7.0.3", 220 | "object-assign": "^4.0.1", 221 | "pify": "^2.0.0", 222 | "pinkie-promise": "^2.0.0" 223 | }, 224 | "engines": { 225 | "node": ">=0.10.0" 226 | } 227 | }, 228 | "node_modules/graceful-fs": { 229 | "version": "4.2.11", 230 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 231 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 232 | "dev": true 233 | }, 234 | "node_modules/inflight": { 235 | "version": "1.0.6", 236 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 237 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 238 | "dev": true, 239 | "dependencies": { 240 | "once": "^1.3.0", 241 | "wrappy": "1" 242 | } 243 | }, 244 | "node_modules/inherits": { 245 | "version": "2.0.4", 246 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 247 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 248 | "dev": true 249 | }, 250 | "node_modules/jsonfile": { 251 | "version": "4.0.0", 252 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", 253 | "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", 254 | "dev": true, 255 | "optionalDependencies": { 256 | "graceful-fs": "^4.1.6" 257 | } 258 | }, 259 | "node_modules/locate-path": { 260 | "version": "5.0.0", 261 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 262 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 263 | "dev": true, 264 | "dependencies": { 265 | "p-locate": "^4.1.0" 266 | }, 267 | "engines": { 268 | "node": ">=8" 269 | } 270 | }, 271 | "node_modules/lodash": { 272 | "version": "4.17.21", 273 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 274 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 275 | "dev": true 276 | }, 277 | "node_modules/make-dir": { 278 | "version": "3.1.0", 279 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", 280 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", 281 | "dev": true, 282 | "dependencies": { 283 | "semver": "^6.0.0" 284 | }, 285 | "engines": { 286 | "node": ">=8" 287 | }, 288 | "funding": { 289 | "url": "https://github.com/sponsors/sindresorhus" 290 | } 291 | }, 292 | "node_modules/minimatch": { 293 | "version": "3.1.2", 294 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 295 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 296 | "dev": true, 297 | "dependencies": { 298 | "brace-expansion": "^1.1.7" 299 | }, 300 | "engines": { 301 | "node": "*" 302 | } 303 | }, 304 | "node_modules/object-assign": { 305 | "version": "4.1.1", 306 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 307 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 308 | "dev": true, 309 | "engines": { 310 | "node": ">=0.10.0" 311 | } 312 | }, 313 | "node_modules/once": { 314 | "version": "1.4.0", 315 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 316 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 317 | "dev": true, 318 | "dependencies": { 319 | "wrappy": "1" 320 | } 321 | }, 322 | "node_modules/p-limit": { 323 | "version": "2.3.0", 324 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 325 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 326 | "dev": true, 327 | "dependencies": { 328 | "p-try": "^2.0.0" 329 | }, 330 | "engines": { 331 | "node": ">=6" 332 | }, 333 | "funding": { 334 | "url": "https://github.com/sponsors/sindresorhus" 335 | } 336 | }, 337 | "node_modules/p-locate": { 338 | "version": "4.1.0", 339 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 340 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 341 | "dev": true, 342 | "dependencies": { 343 | "p-limit": "^2.2.0" 344 | }, 345 | "engines": { 346 | "node": ">=8" 347 | } 348 | }, 349 | "node_modules/p-try": { 350 | "version": "2.2.0", 351 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 352 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 353 | "dev": true, 354 | "engines": { 355 | "node": ">=6" 356 | } 357 | }, 358 | "node_modules/path-exists": { 359 | "version": "4.0.0", 360 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 361 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 362 | "dev": true, 363 | "engines": { 364 | "node": ">=8" 365 | } 366 | }, 367 | "node_modules/path-is-absolute": { 368 | "version": "1.0.1", 369 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 370 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 371 | "dev": true, 372 | "engines": { 373 | "node": ">=0.10.0" 374 | } 375 | }, 376 | "node_modules/pify": { 377 | "version": "2.3.0", 378 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 379 | "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", 380 | "dev": true, 381 | "engines": { 382 | "node": ">=0.10.0" 383 | } 384 | }, 385 | "node_modules/pinkie": { 386 | "version": "2.0.4", 387 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 388 | "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", 389 | "dev": true, 390 | "engines": { 391 | "node": ">=0.10.0" 392 | } 393 | }, 394 | "node_modules/pinkie-promise": { 395 | "version": "2.0.1", 396 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 397 | "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", 398 | "dev": true, 399 | "dependencies": { 400 | "pinkie": "^2.0.0" 401 | }, 402 | "engines": { 403 | "node": ">=0.10.0" 404 | } 405 | }, 406 | "node_modules/pkg-dir": { 407 | "version": "4.2.0", 408 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 409 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 410 | "dev": true, 411 | "dependencies": { 412 | "find-up": "^4.0.0" 413 | }, 414 | "engines": { 415 | "node": ">=8" 416 | } 417 | }, 418 | "node_modules/semver": { 419 | "version": "6.3.1", 420 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", 421 | "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", 422 | "dev": true, 423 | "bin": { 424 | "semver": "bin/semver.js" 425 | } 426 | }, 427 | "node_modules/strip-outer": { 428 | "version": "1.0.1", 429 | "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", 430 | "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", 431 | "dev": true, 432 | "dependencies": { 433 | "escape-string-regexp": "^1.0.2" 434 | }, 435 | "engines": { 436 | "node": ">=0.10.0" 437 | } 438 | }, 439 | "node_modules/trim-repeated": { 440 | "version": "1.0.0", 441 | "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", 442 | "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", 443 | "dev": true, 444 | "dependencies": { 445 | "escape-string-regexp": "^1.0.2" 446 | }, 447 | "engines": { 448 | "node": ">=0.10.0" 449 | } 450 | }, 451 | "node_modules/universalify": { 452 | "version": "0.1.2", 453 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", 454 | "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", 455 | "dev": true, 456 | "engines": { 457 | "node": ">= 4.0.0" 458 | } 459 | }, 460 | "node_modules/wrappy": { 461 | "version": "1.0.2", 462 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 463 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 464 | "dev": true 465 | } 466 | } 467 | } 468 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "move-rotate-resizer", 3 | "version": "1.0.7", 4 | "description": "A simple javascript object that provide easy way to make any dom element resizable. It provide handles to move, resize and rotate target element", 5 | "main": "resizer.min.js", 6 | "scripts": { 7 | "deploy": "gh-pages -d ." 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/developergovindgupta/move-rotate-resizer.git" 12 | }, 13 | "keywords": [ 14 | "move", 15 | "rotate", 16 | "resize", 17 | "ddmrr", 18 | "drag", 19 | "drop", 20 | "resizer" 21 | ], 22 | "author": "developergovindgupta@gmail.com", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/developergovindgupta/move-rotate-resizer/issues" 26 | }, 27 | "homepage": "https://github.com/developergovindgupta/move-rotate-resizer#readme", 28 | "devDependencies": { 29 | "gh-pages": "^3.2.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Move Rotate Resize Handler JavaScript 2 | ## resizer.js and resizer.css 3 | ### A simple javascript object that provide easy way to make any dom element resizable. It provide handles to move, resize and rotate target element. 4 | 5 | 6 | ## How to install 7 | npm install move-rotate-resizer 8 | 9 | ## [download from gitHub](https://github.com/developergovindgupta/move-rotate-resizer) 10 | ### [resizer.js](https://raw.githubusercontent.com/developergovindgupta/move-rotate-resizer/master/resizer.js) 11 | ### [resizer.min.js](https://raw.githubusercontent.com/developergovindgupta/move-rotate-resizer/master/resizer.min.js) 12 | ### [resizer.css](https://raw.githubusercontent.com/developergovindgupta/move-rotate-resizer/master/resizer.css) 13 | 14 | [](https://developergovindgupta.github.io/move-rotate-resizer) 15 | ## [DEMO-GH-Pages](https://developergovindgupta.github.io/move-rotate-resizer) 16 | ## [DEMO-CodeSandBox](https://codesandbox.io/s/move-rotate-resizer-demo-bh8q3) 17 | ## [DEMO-CodeSandBox](https://codesandbox.io/s/move-rotate-resizer-demo-2-3x33ys) 18 | 19 | ## How to use 20 | import resizer from 'move-rotate-resizer'; 21 | or 22 | import resizer from './js/resizer.min.js'; 23 | or 24 | 25 | 26 | 27 | 28 | 29 | 30 | ## Usase Example-1 31 | 32 | resizer.add(document.getElementById('div1')); 33 | 34 | ## Methods and Descriptions 35 | |Method|Description| 36 | |-|-| 37 | |add(target [,options])|add target dom element to resizer. it register event listener.| 38 | |remove(target)|remove target dom element from resizer. it remove all event listener.| 39 | |show(target)|show resizer handler on target dom element by javascript code.| 40 | |hide()|hide resizer handler by javascript code.| 41 | 42 | ## Properties and Descriptions 43 | |Propery|Description| 44 | |-|-| 45 | |target|return current selected target dom element| 46 | |resizer|return resizer handlers dom element| 47 | |hoverLine|return resizer hoverLine dom element| 48 | 49 | ## Dom Element Attribute 50 | |Attribute|Description| 51 | |-|-| 52 | |isLocked|"true" then resize handler can not change the target position or size| 53 | |isDisabled|"true" then resize handler not visible| 54 | 55 | ## Options passed with add method 56 | let options = { 57 | minWidth: 30, // minimum width in px 58 | minHeight: 30, // minimum height in px 59 | aspectRatio: true, // if true width height ratio will maintain 60 | resizeFromCenter: false, // if true then resize both side from center 61 | onDragStart: null, // call-back function that called when dragging start 62 | onDragging: null, // call-back function that called every mouse movement till mousedown 63 | onDragEnd: null, // call-back function that called when mouse button is released after move 64 | onResizeStart: null, // call-back function that called when any resize handler is start dragging 65 | onResizing: null, // call-back function that called every mouse movement till musedown 66 | onResizeEnd: null, // call-back function that called when release resize handler 67 | onRotateStart: null, // call-back function that called when rotate handler is started dragging 68 | onRotating: null, // call-back function that called every movement of rotate handler 69 | onRotateEnd: null, // call-back function that called when release rotate handler 70 | onResizerShown: null, // call-back function that called when resizer is first time shown on target 71 | onResizerHide: null, // call-back function that called when resizer is hide on target 72 | isHideOnResize: true, // if true then resizer will not visible at the time of dragging so that target visible clearly 73 | isHoverLine: true, // if true then target element on mouse hover hoverLine visible for highlight target element 74 | boundWithContainer:false, // if true/HTMLDivElement then target element can not move outside the container element. 75 | resizers: { 76 | n: true, // top middle resize handler true:visible|false:hidden 77 | s: true, // bottom middle resize handler 78 | e: true, // right middle resize handler 79 | w: true, // left middle resize handler 80 | ne: true, // top-right resize handler 81 | nw: true, // top-left resize handler 82 | se: true, // bottom-right resize handler 83 | sw: true, // bottom-left resize handler 84 | r: true, // rotate handler 85 | }, 86 | }; 87 | 88 | ### Note callBack function receive an props having properties 89 | |props-property|description| 90 | |-|-| 91 | |size|{left,top,width,height}| 92 | |angle|target element rotate angle| 93 | |evtTarget|resizer target element that call the callback function| 94 | |handler|current resize handler that is draging| 95 | 96 | 97 | ## Example Code 98 | ### HTML 99 | 100 | 101 | 102 | move-rotate-resize:demo 103 | 104 | 105 | 106 | 107 | 108 |

DEMO : move-rotate-resizer

109 |

resizer.js and resizer.css

110 |
111 |
112 |
div1
113 |
div2
114 |
115 | 116 | 117 | 118 | 119 | ### Script [index.js] 120 | import resizer from 'move-rotate-resizer'; 121 | 122 | document.querySelectorAll('.target').forEach((target) => { 123 | resizer.add(target); 124 | }); 125 | 126 | ## [DEMO](https://codesandbox.io/s/move-rotate-resizer-demo-bh8q3) 127 | 128 | ## Example Code 2 129 | 130 | ### HTML 131 | 132 | 133 | 134 | Parcel Sandbox 135 | 136 | 137 | 138 | 139 | 140 |
141 |
142 | 156 |
157 |
158 | 159 | 160 | 161 | 162 | 163 | ### Script [index.js] 164 | import resizer from "move-rotate-resizer"; 165 | 166 | let options = { 167 | onDragStart: function (e) { 168 | e.target.style.opacity = "0.8"; 169 | e.target.style.zIndex = "999"; 170 | }, 171 | onDragging: function (e) { }, 172 | onDragEnd: function (e) { 173 | e.target.style.opacity = ""; 174 | e.target.style.zIndex = ""; 175 | }, 176 | onRotateStart: function (e) { 177 | e.target.style.opacity = "0.8"; 178 | e.target.style.zIndex = "999"; 179 | }, 180 | onRotating: function (e) { }, 181 | onRotateEnd: function (e) { 182 | e.target.style.opacity = ""; 183 | e.target.style.zIndex = ""; 184 | }, 185 | onResizeStart: function (e) { 186 | e.target.style.opacity = "0.8"; 187 | e.target.style.zIndex = "999"; 188 | }, 189 | onResizing: function (e) { }, 190 | onResizeEnd: function (e) { 191 | e.target.style.opacity = ""; 192 | e.target.style.zIndex = ""; 193 | }, 194 | resizers: { 195 | n: true, 196 | s: true, 197 | e: true, 198 | w: true, 199 | ne: true, 200 | nw: true, 201 | se: true, 202 | sw: true, 203 | r: true 204 | } 205 | }; 206 | let div1 = document.querySelector("#center-resize"); 207 | resizer.add(div1, { ...options, ...{ resizeFromCenter: true } }); 208 | let div2 = document.querySelector("#corner-resize"); 209 | resizer.add(div2, { ...options, ...{} }); 210 | let div3 = document.querySelector("#free-resize"); 211 | resizer.add(div3, { ...options, ...{ aspectRatio: false } }); 212 | let div4 = document.querySelector("#bound-resize"); 213 | resizer.add(div4, { ...options, ...{ boundWithContainer: true } }); 214 | 215 | document.body.addEventListener("click", function (e) { 216 | resizer.hide(); 217 | }); 218 | 219 | 220 | 221 | ## [DEMO](https://codesandbox.io/s/move-rotate-resizer-demo-2-3x33ys) 222 | 223 | 224 | ### download css file and include in your html file. 225 | ### [resizer.css](https://raw.githubusercontent.com/developergovindgupta/move-rotate-resizer/master/resizer.css) 226 | 227 | ## Developed by Govind Gupta 228 | -------------------------------------------------------------------------------- /resizer.css: -------------------------------------------------------------------------------- 1 | .resizer-container { 2 | position: absolute; 3 | pointer-events: none; 4 | z-index: 99999; 5 | } 6 | .resizer-container * { 7 | transition: opacity 300ms ease; 8 | } 9 | .resizer-container .resizer-border { 10 | position: absolute; 11 | pointer-events: none; 12 | opacity: 1 !important; 13 | border: solid 4px rgb(0, 128, 255); 14 | left: 0px; 15 | top: 0px; 16 | width: calc(100% + 2px); 17 | height: calc(100% + 2px); 18 | } 19 | .resizer-container .nw-resizer, 20 | .resizer-container .ne-resizer, 21 | .resizer-container .sw-resizer, 22 | .resizer-container .se-resizer { 23 | position: absolute; 24 | width: 10px; 25 | height: 10px; 26 | border-radius: 50%; 27 | box-shadow: 0px 0px 3px black; 28 | background-color: rgba(255, 255, 255, 1); 29 | pointer-events: all; 30 | } 31 | .resizer-container .nw-resizer { 32 | top: -5px; 33 | left: -5px; 34 | cursor: nwse-resize; 35 | } 36 | .resizer-container .ne-resizer { 37 | top: -5px; 38 | right: -5px; 39 | cursor: nesw-resize; 40 | } 41 | .resizer-container .sw-resizer { 42 | bottom: -5px; 43 | left: -5px; 44 | cursor: nesw-resize; 45 | } 46 | .resizer-container .se-resizer { 47 | bottom: -5px; 48 | right: -5px; 49 | cursor: nwse-resize; 50 | } 51 | .resizer-container .n-resizer { 52 | position: absolute; 53 | pointer-events: all; 54 | display: flex; 55 | justify-content: center; 56 | align-items: center; 57 | top: -5px; 58 | left: 10px; 59 | right: 10px; 60 | height: 6px; 61 | cursor: ns-resize; 62 | } 63 | .resizer-container .n-resizer::before { 64 | content: ''; 65 | background-color: white; 66 | box-shadow: 0px 0px 3px black; 67 | width: 30px; 68 | height: 6px; 69 | } 70 | 71 | .resizer-container .e-resizer { 72 | position: absolute; 73 | pointer-events: all; 74 | display: flex; 75 | flex-direction: column; 76 | justify-content: center; 77 | align-items: center; 78 | top: 10px; 79 | bottom: 10px; 80 | right: -5px; 81 | width: 6px; 82 | cursor: ew-resize; 83 | } 84 | .resizer-container .e-resizer::before { 85 | content: ''; 86 | background-color: white; 87 | box-shadow: 0px 0px 3px black; 88 | width: 6px; 89 | height: 30px; 90 | } 91 | 92 | .resizer-container .s-resizer { 93 | position: absolute; 94 | pointer-events: all; 95 | display: flex; 96 | justify-content: center; 97 | align-items: center; 98 | bottom: -5px; 99 | left: 10px; 100 | right: 10px; 101 | height: 6px; 102 | cursor: ns-resize; 103 | } 104 | .resizer-container .s-resizer::before { 105 | content: ''; 106 | background-color: white; 107 | box-shadow: 0px 0px 3px rgb(0, 0, 0); 108 | width: 30px; 109 | height: 6px; 110 | } 111 | 112 | .resizer-container .w-resizer { 113 | position: absolute; 114 | pointer-events: all; 115 | display: flex; 116 | flex-direction: column; 117 | justify-content: center; 118 | align-items: center; 119 | top: 10px; 120 | bottom: 10px; 121 | left: -5px; 122 | width: 6px; 123 | cursor: ew-resize; 124 | } 125 | .resizer-container .w-resizer::before { 126 | content: ''; 127 | background-color: white; 128 | box-shadow: 0px 0px 3px black; 129 | width: 6px; 130 | height: 30px; 131 | } 132 | 133 | .resizer-container .r-resizer { 134 | position: absolute; 135 | bottom: -30px; 136 | left: calc(50% - 10px); 137 | width: 20px; 138 | height: 20px; 139 | border-radius: 50%; 140 | cursor: pointer; 141 | pointer-events: all; 142 | background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9Ii03NCA3NiA1MCA1MCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAtNzQgNzYgNTAgNTA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCS5zdDB7ZmlsbDojRkZGRkZGO30KCS5zdDF7ZmlsbDojMTc3NEI3O30KPC9zdHlsZT4KPGNpcmNsZSBpZD0iWE1MSURfM18iIGNsYXNzPSJzdDAiIGN4PSItNDkiIGN5PSIxMDEiIHI9IjI0LjkiLz4KPHBhdGggY2xhc3M9InN0MSIgZD0iTS00OSwxMTUuOWMtMy44LDAtNy42LTEuNS0xMC40LTQuMWMtMi45LTIuOC00LjYtNi41LTQuNy0xMC41Yy0wLjEtNCwxLjMtNy44LDQuMS0xMC43YzIuOS0zLDYuOC00LjcsMTAuOS00LjcKCWMzLDAsNS45LDAuOSw4LjMsMi41di0xLjRjMC0xLjMsMS0yLjMsMi4zLTIuM2MxLjMsMCwyLjMsMSwyLjMsMi4zdjYuNWMwLDEtMC43LDEuOS0xLjUsMi4ybC02LjQsMi4xYy0wLjMsMC4xLTAuNSwwLjEtMC43LDAuMQoJYy0xLDAtMS45LTAuNy0yLjItMS41Yy0wLjItMC42LTAuMi0xLjIsMC0xLjhjMC4zLTAuNiwwLjgtMSwxLjQtMS4xbDIuOC0xYy0xLjgtMS40LTQuMS0yLjItNi40LTIuMmMtMC42LDAtMS4yLDAuMS0xLjgsMC4yCgljLTUuOCwxLTkuNyw2LjUtOC43LDEyLjNjMC45LDUuMSw1LjMsOC45LDEwLjQsOC45YzAuNiwwLDEuMy0wLjEsMS44LTAuMmMyLjgtMC41LDUuMy0yLDYuOS00LjNjMS43LTIuNCwyLjMtNS4yLDEuOC03LjkKCWMtMC4xLTAuNiwwLTEuMiwwLjQtMS44YzAuNC0wLjUsMC44LTAuOCwxLjUtMC45bDAuMSwwaDAuM2MxLjEsMCwyLjEsMC44LDIuMiwxLjljMC44LDQuNy0wLjcsOS40LTMuOSwxMi45CglDLTQxLDExNC4zLTQ0LjgsMTE1LjktNDksMTE1Ljl6Ii8+Cjwvc3ZnPgo='); 143 | box-shadow: 0px 0px 3px black; 144 | background-color: rgba(255, 255, 255, 1); 145 | } 146 | 147 | .rotator-angle-div { 148 | position: absolute; 149 | padding: 5px 10px; 150 | border: solid 1px lightgray; 151 | border-radius: 5px; 152 | background-color: black; 153 | color: white; 154 | font-size: 14px; 155 | display: inline-block; 156 | text-align: center; 157 | line-height: 20px; 158 | z-index: 100000; 159 | margin-left: 20px; 160 | } 161 | .rotator-angle-div::after { 162 | content: 'O'; 163 | font-size: 8px; 164 | position: absolute; 165 | top: 0px; 166 | right: 3px; 167 | } 168 | .resizer-target-hover-line { 169 | position: absolute; 170 | pointer-events: none; 171 | z-index: 99999; 172 | border: solid 4px rgb(0, 128, 255); 173 | transition: opacity 100ms ease-in-out; 174 | } 175 | 176 | /*Custom Cursor Pointer*/ 177 | .cursor_0d { 178 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='scale(-1 1) rotate(45 -8.536 -13.435)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 179 | 12 12, 180 | auto !important; 181 | } 182 | .cursor_15d { 183 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='scale(-1 1) rotate(30 -11.83 -25.954)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 184 | 12 12, 185 | auto !important; 186 | } 187 | .cursor_30d { 188 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='scale(-1 1) rotate(15 -21.49 -62.66)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 189 | 12 12, 190 | auto !important; 191 | } 192 | .cursor_45d { 193 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='matrix(-1 0 0 1 19 5)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 194 | 12 12, 195 | auto !important; 196 | } 197 | .cursor_60d { 198 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='scale(-1 1) rotate(-15 16.49 81.66)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 199 | 12 12, 200 | auto !important; 201 | } 202 | .cursor_75d { 203 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='scale(-1 1) rotate(-30 6.83 44.954)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 204 | 12 12, 205 | auto !important; 206 | } 207 | .cursor_90d { 208 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='scale(-1 1) rotate(-45 3.536 32.435)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 209 | 12 12, 210 | auto !important; 211 | } 212 | .cursor_105d { 213 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='rotate(-30 18.83 .17)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 214 | 12 12, 215 | auto !important; 216 | } 217 | .cursor_120d { 218 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='rotate(-15 28.49 -9.49)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 219 | 12 12, 220 | auto !important; 221 | } 222 | .cursor_135d { 223 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='translate(5 5)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 224 | 12 12, 225 | auto !important; 226 | } 227 | .cursor_150d { 228 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cg filter='url(%23a)' transform='rotate(15 -9.49 28.49)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") 229 | 12 12, 230 | auto !important; 231 | } 232 | .cursor_165d { 233 | cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cdefs%3E%3Cfilter id='a' width='150%25' height='150%25' x='-25%25' y='-17.9%25' filterUnits='objectBoundingBox'%3E%3CfeOffset dy='1' in='SourceAlpha' result='shadowOffsetOuter1'/%3E%3CfeGaussianBlur in='shadowOffsetOuter1' result='shadowBlurOuter1' stdDeviation='1'/%3E%3CfeColorMatrix in='shadowBlurOuter1' result='shadowMatrixOuter1' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0'/%3E%3CfeMerge%3E%3CfeMergeNode in='shadowMatrixOuter1'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd' filter='url(%23a)' transform='rotate(30 .17 18.83)'%3E%3Cpath fill='%23FFF' d='M4.257 7.087l4.072 4.068L5.5 13.983l8.473-.013.013-8.47-2.841 2.842L7.07 4.274 5.656 2.859 8.5.017H.014v8.484l2.829-2.827z'/%3E%3Cpath fill='%23000' d='M5.317 6.733l4.427 4.424-1.828 1.828 5.056-.016.014-5.054-1.842 1.841-4.428-4.422-2.474-2.475 1.844-1.843H1.013v5.071l1.83-1.828z'/%3E%3C/g%3E%3C/svg%3E") 234 | 12 12, 235 | auto !important; 236 | } 237 | -------------------------------------------------------------------------------- /resizer.js: -------------------------------------------------------------------------------- 1 | if (document.querySelectorAll('link[href*="resizer.css"], style[src*="resizer.css"]').length === 0) { 2 | fetch('https://raw.githubusercontent.com/developergovindgupta/move-rotate-resizer/master/resizer.css') 3 | .then((response) => { 4 | if (response.ok) { 5 | response.text().then((data) => { 6 | let style = document.createElement('style'); 7 | style.setAttribute('type', 'text/css'); 8 | style.setAttribute('src', 'resizer.css'); 9 | style.innerHTML = data; 10 | document.head.appendChild(style); 11 | }); 12 | } else { 13 | console.info('download resizer.css and include in index.html'); 14 | } 15 | }) 16 | .catch((err) => { 17 | console.log(err); 18 | }); 19 | } 20 | const resizer = { 21 | target: null, 22 | resizer: null, 23 | hoverLine: null, 24 | add(target, options) { 25 | this.target = target; 26 | if (target) { 27 | let defaultOptions = { 28 | minWidth: 30, 29 | minHeight: 30, 30 | aspectRatio: true, 31 | resizeFromCenter: false, 32 | onDragStart: null, 33 | onDragging: null, 34 | onDragEnd: null, 35 | onResizeStart: null, 36 | onResizing: null, 37 | onResizeEnd: null, 38 | onRotateStart: null, 39 | onRotating: null, 40 | onRotateEnd: null, 41 | onResizerShown: null, 42 | onResizerHide: null, 43 | isHideOnResize: true, 44 | isHoverLine: true, 45 | boundWithContainer: false, 46 | resizers: { 47 | n: true, 48 | s: true, 49 | e: true, 50 | w: true, 51 | ne: true, 52 | nw: true, 53 | se: true, 54 | sw: true, 55 | r: true, 56 | }, 57 | }; 58 | let getAngle = (target) => { 59 | let angle = 0; 60 | if (target) { 61 | angle = parseFloat(target.angle); 62 | if (isNaN(angle)) { 63 | angle = 0; 64 | let tmatrix = window.getComputedStyle(target).transform; 65 | if (tmatrix && tmatrix != 'none') { 66 | let matrixValues = tmatrix.split('(')[1].split(')')[0].split(','); 67 | let matrix_a = matrixValues[0]; 68 | let matrix_b = matrixValues[1]; 69 | let rotationInRadians = Math.atan2(matrix_b, matrix_a); 70 | angle = parseInt(rotationInRadians * (180 / Math.PI)); 71 | if (angle < 0) { 72 | angle = 360 + angle; 73 | } 74 | } 75 | } 76 | target.angle = angle; 77 | } 78 | return angle; 79 | }; 80 | options = options || {}; 81 | target.options = { ...defaultOptions, ...options }; 82 | target.options.resizers = { ...target.options.resizers }; 83 | target.style.position = 'absolute'; 84 | target.style.left = target.offsetLeft + 'px'; 85 | target.style.top = target.offsetTop + 'px'; 86 | target.style.width = target.offsetWidth + 'px'; 87 | target.style.height = target.offsetHeight + 'px'; 88 | target.angle = getAngle(target); 89 | target.resizer = true; 90 | target.isDisabled = target.getAttribute('isDisabled') === 'true'; 91 | if (target.isDisabled) { 92 | target.resizer = false; 93 | } 94 | let bBox = this.show(target); 95 | target.bBox = bBox; 96 | target.scale = bBox.width / target.offsetWidth; 97 | target.moveCounter = 0; 98 | target.resizer = this.resizer; 99 | 100 | if (!document.querySelector('.resizer-container')) { 101 | document.body.appendChild(target.resizer); 102 | } 103 | let handleMousedown = (e) => { 104 | if (e.type === 'mousedown') { 105 | e.preventDefault(); 106 | if (e.button != 0) { 107 | return; 108 | } 109 | } 110 | e.stopPropagation(); 111 | target.isDisabled = target.getAttribute('isDisabled') === 'true'; 112 | if (target.isDisabled) { 113 | target.resizer = false; 114 | this.hide(); 115 | } 116 | target.isLocked = target.getAttribute('islocked') === 'true'; 117 | target.startPos = { x: e.clientX + document.body.scrollLeft, y: e.clientY + document.body.scrollTop }; 118 | target.size = { left: target.offsetLeft, top: target.offsetTop, width: target.offsetWidth, height: target.offsetHeight }; 119 | if (!target.isLocked && !target.isDisabled) { 120 | document.addEventListener('mousemove', handleMousemove); 121 | document.addEventListener('mouseup', handleMouseup); 122 | document.addEventListener('touchmove', handleMousemove); 123 | document.addEventListener('touchend', handleMouseup); 124 | } 125 | if (e.type === 'touchstart') { 126 | if (e.touches.length > 1) { 127 | return; 128 | } 129 | target.startPos = { x: e.touches[0].clientX + document.body.scrollLeft, y: e.touches[0].clientY + document.body.scrollTop }; 130 | } 131 | target.resizer && (target.resizer.visibile = false); 132 | this.show(target); 133 | this.target = target; 134 | let handleClick = (e) => { 135 | e.stopPropagation(); 136 | e.preventDefault(); 137 | this.show(target); 138 | window.removeEventListener('click', handleClick, true); 139 | }; 140 | window.addEventListener('click', handleClick, true); 141 | target.moveCounter = 0; 142 | this.hoverLine && (this.hoverLine.style.opacity = '0'); 143 | }; 144 | let handleMousemove = (e) => { 145 | e.stopPropagation(); 146 | e.type === 'mousemove' && e.preventDefault(); 147 | 148 | target.moveCounter++; 149 | if (target.moveCounter === 1) { 150 | e.size = { ...target.size }; 151 | e.angle = target.angle; 152 | e.evtTarget = target; 153 | e.handler = this.resizer; 154 | target.options.onDragStart && target.options.onDragStart(e); 155 | target.resizer && target.resizer.showHideResizer && target.resizer.showHideResizer(true); 156 | } 157 | 158 | let x = e.clientX + document.body.scrollLeft - target.startPos.x; 159 | let y = e.clientY + document.body.scrollTop - target.startPos.y; 160 | if (e.type === 'touchmove') { 161 | x = e.touches[0].clientX + document.body.scrollLeft - target.startPos.x; 162 | y = e.touches[0].clientY + document.body.scrollTop - target.startPos.y; 163 | } 164 | let newX = target.size.left + x / target.scale; 165 | let newY = target.size.top + y / target.scale; 166 | target.style.left = newX + 'px'; 167 | target.style.top = newY + 'px'; 168 | 169 | if (options.boundWithContainer) { 170 | let container = options.boundWithContainer instanceof HTMLDivElement ? options.boundWithContainer : target.offsetParent; 171 | if (container) { 172 | let bBox = container.getBoundingClientRect(); 173 | let xBox = target.getBoundingClientRect(); 174 | 175 | if (xBox.left < bBox.left) { 176 | let dx = bBox.left - xBox.left; 177 | newX += dx / target.scale; 178 | } 179 | if (xBox.top < bBox.top) { 180 | let dy = bBox.top - xBox.top; 181 | newY += dy / target.scale; 182 | } 183 | if (xBox.right > bBox.right) { 184 | let dx = bBox.right - xBox.right; 185 | newX += dx / target.scale; 186 | } 187 | if (xBox.bottom > bBox.bottom) { 188 | let dy = bBox.bottom - xBox.bottom; 189 | newY += dy / target.scale; 190 | } 191 | target.style.left = newX + 'px'; 192 | target.style.top = newY + 'px'; 193 | } 194 | } 195 | 196 | target.newSize = { ...target.size, left: newX, top: newY }; 197 | 198 | //dispatch Events 199 | if (target.options.onDragging) { 200 | e.size = { ...target.newSize }; 201 | e.angle = target.angle; 202 | e.evtTarget = target; 203 | e.handler = this.resizer; 204 | target.options.onDragging(e); 205 | } 206 | this.show(target); 207 | }; 208 | let handleMouseup = (e) => { 209 | e.stopPropagation(); 210 | e.type === 'mouseup' && e.preventDefault(); 211 | document.removeEventListener('mousemove', handleMousemove); 212 | document.removeEventListener('mouseup', handleMouseup); 213 | document.removeEventListener('touchmove', handleMousemove); 214 | document.removeEventListener('touchend', handleMouseup); 215 | target.resizer.showHideResizer(false); 216 | //dispatch Events 217 | if (target.moveCounter && target.options.onDragEnd) { 218 | e.size = { ...target.newSize }; 219 | e.angle = target.angle; 220 | e.evtTarget = target; 221 | e.handler = this.resizer; 222 | target.options.onDragEnd(e); 223 | } 224 | this.show(target); 225 | 226 | target.dispatchEvent(new MouseEvent('click')); 227 | }; 228 | 229 | target.handleMouseEnter = (e) => { 230 | if (this.target != e.target && e.target.options.isHoverLine) { 231 | let getBorderBox = (target) => { 232 | let _hoverLine = target.cloneNode(); 233 | _hoverLine.innerHTML = ''; 234 | _hoverLine.style.cssText = target.style.cssText; 235 | _hoverLine.style.opacity = '0'; 236 | _hoverLine.style.pointerEvents = 'none'; 237 | let transform = _hoverLine.style.transform; 238 | if (transform && transform.indexOf('rotate') >= 0) { 239 | _hoverLine.style.transform = transform.replace(/rotate\(\w*\)/gi, ''); 240 | } else if (target.angle) { 241 | _hoverLine.style.transform = transform + ' rotate(0deg)'; 242 | } 243 | target.parentNode.appendChild(_hoverLine); 244 | let bBox = _hoverLine.getBoundingClientRect(); 245 | _hoverLine.remove(); 246 | return bBox; 247 | }; 248 | 249 | let hoverLine = document.querySelector('.resizer-target-hover-line'); 250 | !hoverLine && (hoverLine = document.createElement('div')); 251 | hoverLine.className = 'resizer-target-hover-line'; 252 | hoverLine.style.position = 'absolute'; 253 | document.body.appendChild(hoverLine); 254 | this.hoverLine = hoverLine; 255 | let bBox = getBorderBox(e.target); 256 | hoverLine.style.left = parseInt(bBox.left + window.scrollX) + 'px'; 257 | hoverLine.style.top = parseInt(bBox.top + window.scrollY) + 'px'; 258 | hoverLine.style.width = parseInt(bBox.width + 2) + 'px'; 259 | hoverLine.style.height = parseInt(bBox.height + 2) + 'px'; 260 | hoverLine.style.opacity = '1'; 261 | hoverLine.style.transform = 'rotate(' + (e.target.angle || 0) + 'deg)'; 262 | hoverLine.target = e.target; 263 | } 264 | }; 265 | target.handleMouseLeave = (e) => { 266 | this.hoverLine && (this.hoverLine.style.opacity = '0'); 267 | }; 268 | 269 | if (!target.handleMousedown) { 270 | target.handleMousedown = handleMousedown; 271 | target.removeEventListener('mousedown', handleMousedown); 272 | target.addEventListener('mousedown', handleMousedown); 273 | target.removeEventListener('touchstart', handleMousedown); 274 | target.addEventListener('touchstart', handleMousedown); 275 | target.handleClick = (e) => { 276 | e.stopPropagation(); 277 | }; 278 | target.removeEventListener('click', target.handleClick); 279 | target.addEventListener('click', target.handleClick); 280 | target.addEventListener('mouseenter', target.handleMouseEnter); 281 | target.addEventListener('mouseleave', target.handleMouseLeave); 282 | } 283 | } 284 | }, 285 | show(target) { 286 | if (target && target.resizer) { 287 | if (!this.resizer) { 288 | let resizer = document.querySelector('.resizer-container'); 289 | resizer && resizer.remove(); 290 | //create new resizer-container 291 | resizer = document.createElement('div'); 292 | resizer.className = 'resizer-container'; 293 | resizer.style.position = 'absolute'; 294 | document.body.appendChild(resizer); 295 | this.resizer = resizer; 296 | 297 | let resizer_border = document.createElement('div'); 298 | resizer_border.className = 'resizer-border'; 299 | resizer_border.actionName = 'resizer-border'; 300 | resizer.resizer_border = resizer_border; 301 | resizer.appendChild(resizer_border); 302 | 303 | let nw_resizer = document.createElement('div'); 304 | nw_resizer.className = 'nw-resizer'; 305 | nw_resizer.actionName = 'nw-resizer'; 306 | resizer.nw_resizer = nw_resizer; 307 | resizer.appendChild(nw_resizer); 308 | 309 | let ne_resizer = document.createElement('div'); 310 | ne_resizer.className = 'ne-resizer'; 311 | ne_resizer.actionName = 'ne-resizer'; 312 | resizer.ne_resizer = ne_resizer; 313 | resizer.appendChild(ne_resizer); 314 | 315 | let sw_resizer = document.createElement('div'); 316 | sw_resizer.className = 'sw-resizer'; 317 | sw_resizer.actionName = 'sw-resizer'; 318 | resizer.sw_resizer = sw_resizer; 319 | resizer.appendChild(sw_resizer); 320 | 321 | let se_resizer = document.createElement('div'); 322 | se_resizer.className = 'se-resizer'; 323 | se_resizer.actionName = 'se-resizer'; 324 | resizer.se_resizer = se_resizer; 325 | resizer.appendChild(se_resizer); 326 | 327 | let n_resizer = document.createElement('div'); 328 | n_resizer.className = 'n-resizer'; 329 | n_resizer.actionName = 'n-resizer'; 330 | resizer.n_resizer = n_resizer; 331 | resizer.appendChild(n_resizer); 332 | 333 | let e_resizer = document.createElement('div'); 334 | e_resizer.className = 'e-resizer'; 335 | e_resizer.actionName = 'e-resizer'; 336 | resizer.e_resizer = e_resizer; 337 | resizer.appendChild(e_resizer); 338 | 339 | let s_resizer = document.createElement('div'); 340 | s_resizer.className = 's-resizer'; 341 | s_resizer.actionName = 's-resizer'; 342 | resizer.s_resizer = s_resizer; 343 | resizer.appendChild(s_resizer); 344 | 345 | let w_resizer = document.createElement('div'); 346 | w_resizer.className = 'w-resizer'; 347 | w_resizer.actionName = 'w-resizer'; 348 | resizer.w_resizer = w_resizer; 349 | resizer.appendChild(w_resizer); 350 | 351 | let r_resizer = document.createElement('div'); 352 | r_resizer.className = 'r-resizer'; 353 | r_resizer.actionName = 'r-resizer'; 354 | resizer.r_resizer = r_resizer; 355 | resizer.appendChild(r_resizer); 356 | 357 | let ddmrr_angle_div = document.createElement('div'); 358 | ddmrr_angle_div.className = 'rotator-angle-div'; 359 | ddmrr_angle_div.style.display = 'none'; 360 | document.body.appendChild(ddmrr_angle_div); 361 | resizer.showHideResizer = function (isHide, resizerHandle) { 362 | if (this.target.isLocked) { 363 | isHide = false; 364 | } 365 | resizer.querySelectorAll('*').forEach((x) => { 366 | x !== resizerHandle && (x.style.opacity = isHide ? 0 : 1); 367 | }); 368 | }; 369 | 370 | let showAngleValue = (x, y, angle) => { 371 | ddmrr_angle_div.style.display = ''; 372 | ddmrr_angle_div.style.left = x + 'px'; 373 | ddmrr_angle_div.style.top = y + 'px'; 374 | ddmrr_angle_div.innerHTML = angle; 375 | }; 376 | let hideAngleValue = () => { 377 | ddmrr_angle_div.style.display = 'none'; 378 | }; 379 | let rotateXY = (cx, cy, x, y, angle) => { 380 | let radians = (Math.PI / 180) * angle, 381 | cos = Math.cos(radians), 382 | sin = Math.sin(radians), 383 | nx = cos * (x - cx) + sin * (y - cy) + cx, 384 | ny = cos * (y - cy) - sin * (x - cx) + cy; 385 | return { x: nx, y: ny }; 386 | }; 387 | let getCoordinates = (size, angle) => { 388 | /* 389 | a(x,y) _____________________________ b(x,y) 390 | | | 391 | | | 392 | | | 393 | | | 394 | d(x,y)|_____________________________| c(x,y) 395 | */ 396 | 397 | let radians = (Math.PI / -180) * angle; 398 | let cos = Math.cos(radians); 399 | let sin = Math.sin(radians); 400 | let x1 = size.left; 401 | let y1 = size.top; 402 | let x2 = x1 + size.width; 403 | let y2 = y1; 404 | let x3 = x1 + size.width; 405 | let y3 = y1 + size.height; 406 | let x4 = x1; 407 | let y4 = y1 + size.height; 408 | let px = x1 + size.width / 2; 409 | let py = y1 + size.height / 2; 410 | // console.table({ angle, radians, cos, sin, x1, y1, x2, y2, x3, y3, x4, y4, px, py }); 411 | 412 | let ax = parseInt(cos * (x1 - px) + sin * (y1 - py) + px); 413 | let ay = parseInt(cos * (y1 - py) - sin * (x1 - px) + py); 414 | 415 | let bx = parseInt(cos * (x2 - px) + sin * (y2 - py) + px); 416 | let by = parseInt(cos * (y2 - py) - sin * (x2 - px) + py); 417 | 418 | let cx = parseInt(cos * (x3 - px) + sin * (y3 - py) + px); 419 | let cy = parseInt(cos * (y3 - py) - sin * (x3 - px) + py); 420 | 421 | let dx = parseInt(cos * (x4 - px) + sin * (y4 - py) + px); 422 | let dy = parseInt(cos * (y4 - py) - sin * (x4 - px) + py); 423 | 424 | return { ax, ay, bx, by, cx, cy, dx, dy, px, py }; 425 | }; 426 | let adjustRotateDiv = (size, oldSize, angle, fixToPos) => { 427 | let s1 = getCoordinates(oldSize, angle); 428 | let s2 = getCoordinates(size, angle); 429 | // console.log('--------------------'); 430 | // console.log('oldSize:=', oldSize); 431 | // console.log('s1:=', s1); 432 | // console.log('newSize:=', size); 433 | // console.log('s2:=', s2); 434 | 435 | let newX = 0; 436 | let newY = 0; 437 | 438 | switch (fixToPos) { 439 | case 1: 440 | case 'TopLeft': 441 | newX = size.left + s1.ax - s2.ax; 442 | newY = size.top + s1.ay - s2.ay; 443 | break; 444 | case 2: 445 | case 'TopRight': 446 | newX = size.left + s1.bx - s2.bx; 447 | newY = size.top + s1.by - s2.by; 448 | break; 449 | case 3: 450 | case 'BottomRight': 451 | newX = size.left + s1.cx - s2.cx; 452 | newY = size.top + s1.cy - s2.cy; 453 | break; 454 | case 4: 455 | case 'BottomLeft': 456 | newX = size.left + s1.dx - s2.dx; 457 | newY = size.top + s1.dy - s2.dy; 458 | break; 459 | default: 460 | newX = size.left + s1.ax - s2.ax; 461 | newY = size.top + s1.ay - s2.ay; 462 | break; 463 | } 464 | return { 465 | x: newX, 466 | y: newY, 467 | }; 468 | }; 469 | let handleMousedown = (e) => { 470 | if (e.type === 'mousedown') { 471 | if (e.button != 0) { 472 | return; 473 | } 474 | e.preventDefault(); 475 | } 476 | e.stopPropagation(); 477 | let target = this.target; 478 | target.isLocked = target.getAttribute('islocked') === 'true'; 479 | if (!target.isLocked) { 480 | window.addEventListener('mousemove', handleMousemove); 481 | window.addEventListener('mouseup', handleMouseup); 482 | window.addEventListener('touchmove', handleMousemove); 483 | window.addEventListener('touchend', handleMouseup); 484 | } 485 | resizer.current = e.target; 486 | moveCounter = 0; 487 | 488 | resizer.current.classList.add('active'); 489 | 490 | resizer.startPos = { 491 | x: e.clientX + document.body.scrollLeft, 492 | y: e.clientY + document.body.scrollTop, 493 | }; 494 | target.size = { 495 | left: target.offsetLeft, 496 | top: target.offsetTop, 497 | width: target.offsetWidth, 498 | height: target.offsetHeight, 499 | cx: target.offsetLeft + target.offsetWidth / 2, 500 | cy: target.offsetTop + target.offsetHeight / 2, 501 | angle: target.angle, 502 | }; 503 | target.prevSize = { ...target.size }; 504 | 505 | if (e.type === 'touchstart') { 506 | if (e.touches.length > 1) { 507 | return; 508 | } 509 | resizer.startPos = { 510 | x: e.touches[0].clientX + document.body.scrollLeft, 511 | y: e.touches[0].clientY + document.body.scrollTop, 512 | }; 513 | } 514 | target.bBox = target.getBoundingClientRect(); 515 | if (target.angle) { 516 | let bBox = target.bBox; 517 | let cx = bBox.left + bBox.width / 2; 518 | let cy = bBox.top + bBox.height / 2; 519 | resizer.startPos = rotateXY(cx, cy, resizer.startPos.x, resizer.startPos.y, target.angle); 520 | } 521 | if (target.angle && !target.options.resizeFromCenter) { 522 | let coord = getCoordinates(target.size, target.angle); 523 | target.coord = coord; 524 | switch (resizer.current.actionName) { 525 | case 'se-resizer': 526 | case 'e-resizer': 527 | case 's-resizer': 528 | // toFixPos = 'TopLeft'; 529 | resizer.style.transformOrigin = 'top left'; 530 | target.style.transformOrigin = 'top left'; 531 | target.style.left = coord.ax + 'px'; 532 | target.style.top = coord.ay + 'px'; 533 | break; 534 | case 'sw-resizer': 535 | case 'w-resizer': 536 | // toFixPos = 'TopRight'; 537 | resizer.style.transformOrigin = 'top right'; 538 | target.style.transformOrigin = 'top right'; 539 | target.style.left = coord.bx - target.size.width + 'px'; 540 | target.style.top = coord.by + 'px'; 541 | break; 542 | case 'ne-resizer': 543 | // toFixPos = 'BottomLeft'; 544 | resizer.style.transformOrigin = 'bottom left'; 545 | target.style.transformOrigin = 'bottom left'; 546 | target.style.left = coord.dx + 'px'; 547 | target.style.top = coord.dy - target.size.height + 'px'; 548 | break; 549 | case 'nw-resizer': 550 | case 'n-resizer': 551 | // toFixPos = 'BottomRight'; 552 | resizer.style.transformOrigin = 'bottom right'; 553 | target.style.transformOrigin = 'bottom right'; 554 | target.style.left = coord.cx - target.size.width + 'px'; 555 | target.style.top = coord.cy - target.size.height + 'px'; 556 | break; 557 | default: 558 | break; 559 | } 560 | } 561 | this.show(target); 562 | let handleClick = (e) => { 563 | e.stopPropagation(); 564 | e.preventDefault(); 565 | window.removeEventListener('click', handleClick, true); 566 | }; 567 | window.addEventListener('click', handleClick, true); 568 | resizer.showHideResizer(true, resizer.current); 569 | }; 570 | let handleMousemove = (e) => { 571 | e.stopPropagation(); 572 | e.type === 'mousemove' && e.preventDefault(); 573 | let target = this.target; 574 | let resizer = this.resizer; 575 | let resizeFromCenter = target.options.resizeFromCenter; 576 | let { minWidth, minHeight, aspectRatio } = target.options; 577 | let X = e.clientX + document.body.scrollLeft; 578 | let Y = e.clientY + document.body.scrollTop; 579 | let x = e.clientX + document.body.scrollLeft - resizer.startPos.x; 580 | let y = e.clientY + document.body.scrollTop - resizer.startPos.y; 581 | let left = target.size.left; 582 | let top = target.size.top; 583 | let width = target.size.width; 584 | let height = target.size.height; 585 | let bBox = target.bBox; 586 | let cx = bBox.left + bBox.width / 2; 587 | let cy = bBox.top + bBox.height / 2; 588 | let angle = target.angle; 589 | if (moveCounter === 0) { 590 | if (this.resizer.current.actionName === 'r-resizer') { 591 | if (target.options && target.options.onRotateStart) { 592 | e.size = { ...target.size }; 593 | e.angle = target.angle; 594 | e.evtTarget = target; 595 | e.handler = resizer.current; 596 | target.options.onRotateStart(e); 597 | } 598 | } else { 599 | if (target.options && target.options.onResizeStart) { 600 | e.size = { ...target.size }; 601 | e.angle = target.angle; 602 | e.evtTarget = target; 603 | e.handler = resizer.current; 604 | target.options.onResizeStart(e); 605 | } 606 | } 607 | } 608 | moveCounter++; 609 | 610 | if (e.type === 'touchmove') { 611 | x = e.touches[0].clientX + document.body.scrollLeft - resizer.startPos.x; 612 | y = e.touches[0].clientY + document.body.scrollTop - resizer.startPos.y; 613 | X = e.touches[0].clientX + document.body.scrollLeft; 614 | Y = e.touches[0].clientY + document.body.scrollTop; 615 | } 616 | if (angle) { 617 | let cx = bBox.left + bBox.width / 2; 618 | let cy = bBox.top + bBox.height / 2; 619 | let newXY = rotateXY(cx, cy, X, Y, angle); 620 | x = newXY.x - resizer.startPos.x; 621 | y = newXY.y - resizer.startPos.y; 622 | } 623 | 624 | if (resizeFromCenter) { 625 | x = x * 2; 626 | y = y * 2; 627 | } 628 | 629 | switch (this.resizer.current.actionName) { 630 | case 'se-resizer': 631 | { 632 | width = target.size.width + x / target.scale; 633 | height = target.size.height + y / target.scale; 634 | if (width < minWidth) { 635 | width = minWidth; 636 | } 637 | if (height < minHeight) { 638 | height = minHeight; 639 | } 640 | if (aspectRatio) { 641 | let hr = target.size.height / target.size.width; 642 | height = width * hr; 643 | if (height < minHeight) { 644 | height = minHeight; 645 | let wr = target.size.width / target.size.height; 646 | width = height * wr; 647 | } 648 | } 649 | width = parseInt(width); 650 | height = parseInt(height); 651 | } 652 | break; 653 | case 'sw-resizer': 654 | { 655 | width = target.size.width - x / target.scale; 656 | height = target.size.height + y / target.scale; 657 | if (width < minWidth) { 658 | width = minWidth; 659 | } 660 | if (height < minHeight) { 661 | height = minHeight; 662 | } 663 | if (aspectRatio) { 664 | let hr = target.size.height / target.size.width; 665 | height = width * hr; 666 | } 667 | width = parseInt(width); 668 | height = parseInt(height); 669 | left = left + target.size.width - width; 670 | } 671 | break; 672 | case 'ne-resizer': 673 | { 674 | width = target.size.width + x / target.scale; 675 | height = target.size.height - y / target.scale; 676 | if (width < minWidth) { 677 | width = minWidth; 678 | } 679 | if (height < minHeight) { 680 | height = minHeight; 681 | } 682 | if (aspectRatio) { 683 | let hr = target.size.height / target.size.width; 684 | height = width * hr; 685 | } 686 | width = parseInt(width); 687 | height = parseInt(height); 688 | top = top + target.size.height - height; 689 | } 690 | break; 691 | case 'nw-resizer': 692 | { 693 | width = target.size.width - x / target.scale; 694 | height = target.size.height - y / target.scale; 695 | if (width < minWidth) { 696 | width = minWidth; 697 | } 698 | if (height < minHeight) { 699 | height = minHeight; 700 | } 701 | if (aspectRatio) { 702 | let hr = target.size.height / target.size.width; 703 | height = width * hr; 704 | } 705 | width = parseInt(width); 706 | height = parseInt(height); 707 | top = top + target.size.height - height; 708 | left = left + target.size.width - width; 709 | } 710 | break; 711 | case 'n-resizer': 712 | { 713 | height = target.size.height - y / target.scale; 714 | if (height < minHeight) { 715 | height = minHeight; 716 | } 717 | width = parseInt(width); 718 | height = parseInt(height); 719 | top = top + target.size.height - height; 720 | } 721 | break; 722 | case 'e-resizer': 723 | { 724 | width = target.size.width + x / target.scale; 725 | if (width < minWidth) { 726 | width = minWidth; 727 | } 728 | width = parseInt(width); 729 | height = parseInt(height); 730 | } 731 | break; 732 | case 's-resizer': 733 | { 734 | height = target.size.height + y / target.scale; 735 | if (height < minHeight) { 736 | height = minHeight; 737 | } 738 | width = parseInt(width); 739 | height = parseInt(height); 740 | } 741 | break; 742 | case 'w-resizer': 743 | { 744 | width = target.size.width - x / target.scale; 745 | if (width < minWidth) { 746 | width = minWidth; 747 | } 748 | width = parseInt(width); 749 | height = parseInt(height); 750 | left = left + target.size.width - width; 751 | } 752 | break; 753 | case 'r-resizer': 754 | { 755 | angle = Math.atan2(X - cx, -(Y - cy)) * (180 / Math.PI) - 180; 756 | angle = parseInt(angle >= 0 ? angle : 360 + angle); 757 | target.angle = angle; 758 | if (target.style.transform.indexOf('rotate') >= 0) { 759 | target.style.transform = target.style.transform.replace(/rotate\(\w*\)/gi, 'rotate(' + angle + 'deg)'); 760 | } else { 761 | target.style.transform += ' rotate(' + angle + 'deg)'; 762 | } 763 | showAngleValue(X, Y, angle); 764 | } 765 | break; 766 | default: 767 | break; 768 | } 769 | if (target.angle && this.resizer.current.actionName !== 'r-resizer' && !resizeFromCenter) { 770 | let toFixPos = 'TopLeft'; 771 | switch (this.resizer.current.actionName) { 772 | case 'se-resizer': 773 | case 'e-resizer': 774 | case 's-resizer': 775 | // toFixPos = 'TopLeft'; 776 | left = target.coord.ax; 777 | top = target.coord.ay; 778 | break; 779 | case 'sw-resizer': 780 | case 'w-resizer': 781 | // toFixPos = 'TopRight'; 782 | left = target.coord.bx - width; 783 | top = target.coord.by; 784 | let s1 = getCoordinates({ left, top, width, height }, 0); 785 | break; 786 | case 'ne-resizer': 787 | // toFixPos = 'BottomLeft'; 788 | left = target.coord.dx; 789 | top = target.coord.dy - height; 790 | break; 791 | case 'nw-resizer': 792 | case 'n-resizer': 793 | // toFixPos = 'BottomRight'; 794 | left = target.coord.cx - width; 795 | top = target.coord.cy - height; 796 | break; 797 | default: 798 | break; 799 | } 800 | } 801 | if (resizeFromCenter) { 802 | left = target.size.cx - width / 2; 803 | top = target.size.cy - height / 2; 804 | } 805 | let newSize = { left, top, width, height }; 806 | target.newSize = newSize; 807 | target.style.left = left + 'px'; 808 | target.style.top = top + 'px'; 809 | target.style.width = width + 'px'; 810 | target.style.height = height + 'px'; 811 | 812 | if (target.options.boundWithContainer) { 813 | let container = target.options.boundWithContainer instanceof HTMLDivElement ? target.options.boundWithContainer : target.offsetParent; 814 | if (container) { 815 | let bBox = container.getBoundingClientRect(); 816 | let xBox = target.getBoundingClientRect(); 817 | if (xBox.left < bBox.left || xBox.top < bBox.top || xBox.right > bBox.right || xBox.bottom > bBox.bottom) { 818 | left = target.prevSize.left; 819 | top = target.prevSize.top; 820 | width = target.prevSize.width; 821 | height = target.prevSize.height; 822 | angle = target.prevSize.angle; 823 | newSize = { left, top, width, height }; 824 | 825 | target.newSize = newSize; 826 | target.style.left = left + 'px'; 827 | target.style.top = top + 'px'; 828 | target.style.width = width + 'px'; 829 | target.style.height = height + 'px'; 830 | target.angle = angle; 831 | if (target.style.transform.indexOf('rotate') >= 0) { 832 | target.style.transform = target.style.transform.replace(/rotate\(\w*\)/gi, 'rotate(' + angle + 'deg)'); 833 | } else { 834 | target.style.transform += ' rotate(' + angle + 'deg)'; 835 | } 836 | showAngleValue(X, Y, angle); 837 | } else { 838 | target.prevSize = { left, top, width, height, angle }; 839 | } 840 | } 841 | } 842 | 843 | //trigger onResizing Event 844 | if (this.resizer.current.actionName === 'r-resizer') { 845 | if (target.options && target.options.onRotating) { 846 | e.size = { ...target.newSize }; 847 | e.angle = target.angle; 848 | e.evtTarget = target; 849 | e.handler = resizer.current; 850 | target.options.onRotating(e); 851 | } 852 | } else { 853 | if (target.options && target.options.onResizing) { 854 | e.size = { ...target.newSize }; 855 | e.angle = target.angle; 856 | e.evtTarget = target; 857 | e.handler = resizer.current; 858 | target.options.onResizing(e); 859 | } 860 | } 861 | this.show(target); 862 | }; 863 | let handleMouseup = (e) => { 864 | e.stopPropagation(); 865 | e.type === 'mouseup' && e.preventDefault(); 866 | window.removeEventListener('mousemove', handleMousemove); 867 | window.removeEventListener('mouseup', handleMouseup); 868 | window.removeEventListener('touchmove', handleMousemove); 869 | window.removeEventListener('touchend', handleMouseup); 870 | hideAngleValue(); 871 | resizer.showHideResizer(false, resizer.current); 872 | let target = this.target; 873 | let resizeFromCenter = target.options.resizeFromCenter; 874 | if (target.angle && resizer.current.actionName !== 'r-resizer' && !resizeFromCenter) { 875 | let toFixPos = 'TopLeft'; 876 | resizer.style.transformOrigin = ''; 877 | target.style.transformOrigin = ''; 878 | let newSize; 879 | let adj; 880 | switch (this.resizer.current.actionName) { 881 | case 'se-resizer': 882 | toFixPos = 'TopLeft'; 883 | break; 884 | case 'sw-resizer': 885 | toFixPos = 'TopRight'; 886 | break; 887 | case 'ne-resizer': 888 | toFixPos = 'BottomLeft'; 889 | break; 890 | case 'nw-resizer': 891 | toFixPos = 'BottomRight'; 892 | break; 893 | case 'n-resizer': 894 | toFixPos = 'BottomRight'; 895 | break; 896 | case 'e-resizer': 897 | toFixPos = 'TopLeft'; 898 | break; 899 | case 's-resizer': 900 | toFixPos = 'TopLeft'; 901 | break; 902 | case 'w-resizer': 903 | toFixPos = 'TopRight'; 904 | break; 905 | default: 906 | break; 907 | } 908 | newSize = { left: target.size.left, top: target.size.top, width: target.newSize.width, height: target.newSize.height }; 909 | adj = adjustRotateDiv(newSize, target.size, target.angle, toFixPos); 910 | target.style.left = adj.x + 'px'; 911 | target.style.top = adj.y + 'px'; 912 | target.newSize = { ...newSize, left: adj.x, top: adj.y }; 913 | } 914 | if (moveCounter) { 915 | if (resizer.current.actionName === 'r-resizer') { 916 | if (target.options && target.options.onRotateEnd) { 917 | e.size = { ...target.newSize }; 918 | e.angle = target.angle; 919 | e.evtTarget = target; 920 | e.handler = resizer.current; 921 | target.options.onRotateEnd(e); 922 | } 923 | } else { 924 | if (target.options && target.options.onResizeEnd) { 925 | e.size = { ...target.newSize }; 926 | e.angle = target.angle; 927 | e.evtTarget = target; 928 | e.handler = resizer.current; 929 | target.options.onResizeEnd(e); 930 | } 931 | } 932 | } 933 | resizer.current.classList.remove('active'); 934 | this.show(target); 935 | }; 936 | let moveCounter = 0; 937 | resizer.removeEventListener('mousedown', handleMousedown); 938 | resizer.addEventListener('mousedown', handleMousedown); 939 | resizer.removeEventListener('touchstart', handleMousedown); 940 | resizer.addEventListener('touchstart', handleMousedown); 941 | 942 | let onWindowResize = (e) => { 943 | resizer.visibile && this.show(this.target); 944 | }; 945 | window.removeEventListener('resize', onWindowResize, true); 946 | window.addEventListener('resize', onWindowResize, true); 947 | let scrollHandler = (e) => { 948 | resizer.visibile && this.show(this.target); 949 | }; 950 | window.removeEventListener('scroll', scrollHandler, true); 951 | window.addEventListener('scroll', scrollHandler, true); 952 | } 953 | let resizer = this.resizer; 954 | let getBorderBox = (target) => { 955 | let _target = resizer._target; 956 | if (!_target) { 957 | _target = target.cloneNode(); 958 | _target.innerHTML = ''; 959 | target.parentNode.appendChild(_target); 960 | resizer._target = _target; 961 | } 962 | _target.style.cssText = target.style.cssText; 963 | _target.style.opacity = '0'; 964 | _target.style.pointerEvents = 'none'; 965 | let transform = _target.style.transform; 966 | if (transform && transform.indexOf('rotate') >= 0) { 967 | _target.style.transform = transform.replace(/rotate\(\w*\)/gi, ''); 968 | } else if (target.angle) { 969 | _target.style.transform = transform + ' rotate(0deg)'; 970 | } 971 | _target.timeOut && window.clearTimeout(_target.timeOut); 972 | _target.timeOut = window.setTimeout(() => { 973 | window.clearTimeout(_target.timeOut); 974 | _target.remove(); 975 | resizer._target = null; 976 | }, 1000); 977 | 978 | return _target.getBoundingClientRect(); 979 | }; 980 | let updateResizerCursor = (angle) => { 981 | if (angle != this.resizer.angle) { 982 | let a = (angle + 7) % 15; 983 | let d = (angle - a + 7) % 180; 984 | let resizer = this.resizer; 985 | resizer.angle = angle; 986 | 987 | resizer.ne_resizer.className = resizer.ne_resizer.className.replace(/ cursor_(\d)+d/gi, '') + ' cursor_' + ((d + 45) % 180) + 'd'; 988 | resizer.sw_resizer.className = resizer.sw_resizer.className.replace(/ cursor_(\d)+d/gi, '') + ' cursor_' + ((d + 45) % 180) + 'd'; 989 | resizer.nw_resizer.className = resizer.nw_resizer.className.replace(/ cursor_(\d)+d/gi, '') + ' cursor_' + ((d + 135) % 180) + 'd'; 990 | resizer.se_resizer.className = resizer.se_resizer.className.replace(/ cursor_(\d)+d/gi, '') + ' cursor_' + ((d + 135) % 180) + 'd'; 991 | resizer.n_resizer.className = resizer.n_resizer.className.replace(/ cursor_(\d)+d/gi, '') + ' cursor_' + ((d + 0) % 180) + 'd'; 992 | resizer.s_resizer.className = resizer.s_resizer.className.replace(/ cursor_(\d)+d/gi, '') + ' cursor_' + ((d + 0) % 180) + 'd'; 993 | resizer.w_resizer.className = resizer.w_resizer.className.replace(/ cursor_(\d)+d/gi, '') + ' cursor_' + ((d + 90) % 180) + 'd'; 994 | resizer.e_resizer.className = resizer.e_resizer.className.replace(/ cursor_(\d)+d/gi, '') + ' cursor_' + ((d + 90) % 180) + 'd'; 995 | } 996 | }; 997 | if (!resizer.visibile) { 998 | let resizers = target.options && target.options.resizers; 999 | if (resizers) { 1000 | resizer.nw_resizer.style.display = resizers.nw ? '' : 'none'; 1001 | resizer.ne_resizer.style.display = resizers.ne ? '' : 'none'; 1002 | resizer.sw_resizer.style.display = resizers.sw ? '' : 'none'; 1003 | resizer.se_resizer.style.display = resizers.se ? '' : 'none'; 1004 | resizer.n_resizer.style.display = resizers.n ? '' : 'none'; 1005 | resizer.e_resizer.style.display = resizers.e ? '' : 'none'; 1006 | resizer.s_resizer.style.display = resizers.s ? '' : 'none'; 1007 | resizer.w_resizer.style.display = resizers.w ? '' : 'none'; 1008 | resizer.r_resizer.style.display = resizers.r ? '' : 'none'; 1009 | } 1010 | } 1011 | 1012 | let bBox = getBorderBox(target); 1013 | resizer.style.left = parseInt(bBox.left + window.scrollX) + 'px'; 1014 | resizer.style.top = parseInt(bBox.top + window.scrollY) + 'px'; 1015 | resizer.style.width = parseInt(bBox.width + 1) + 'px'; 1016 | resizer.style.height = parseInt(bBox.height + 1) + 'px'; 1017 | resizer.style.display = ''; 1018 | resizer.style.transform = 'rotate(' + (target.angle || 0) + 'deg)'; 1019 | resizer.visibile = true; 1020 | resizer.target = target; 1021 | updateResizerCursor(target.angle); 1022 | return bBox; 1023 | } 1024 | return target.getBoundingClientRect(); 1025 | }, 1026 | hide() { 1027 | this.target = null; 1028 | this.resizer.style.display = 'none'; 1029 | this.resizer.visibile = false; 1030 | }, 1031 | remove(target) { 1032 | if (target && target.handleMousedown) { 1033 | target.removeEventListener('mousedown', target.handleMousedown); 1034 | target.removeEventListener('touchstart', target.handleMousedown); 1035 | target.removeEventListener('mouseenter', target.handleMouseEnter); 1036 | target.removeEventListener('mouseleave', target.handleMouseLeave); 1037 | target.options && (target.options = null); 1038 | target.resizer = null; 1039 | this.hide(); 1040 | } 1041 | }, 1042 | }; 1043 | export default resizer; 1044 | -------------------------------------------------------------------------------- /resizer.min.js: -------------------------------------------------------------------------------- 1 | 0===document.querySelectorAll('link[href*="resizer.css"], style[src*="resizer.css"]').length&&fetch("https://raw.githubusercontent.com/developergovindgupta/move-rotate-resizer/master/resizer.css").then(e=>{e.ok?e.text().then(e=>{let t=document.createElement("style");t.setAttribute("type","text/css"),t.setAttribute("src","resizer.css"),t.innerHTML=e,document.head.appendChild(t)}):console.info("download resizer.css and include in index.html")}).catch(e=>{console.log(e)});const resizer={target:null,resizer:null,hoverLine:null,add(e,t){if(this.target=e,e){let s={minWidth:30,minHeight:30,aspectRatio:!0,resizeFromCenter:!1,onDragStart:null,onDragging:null,onDragEnd:null,onResizeStart:null,onResizing:null,onResizeEnd:null,onRotateStart:null,onRotating:null,onRotateEnd:null,onResizerShown:null,onResizerHide:null,isHideOnResize:!0,isHoverLine:!0,boundWithContainer:!1,resizers:{n:!0,s:!0,e:!0,w:!0,ne:!0,nw:!0,se:!0,sw:!0,r:!0}},r=e=>{let t=0;if(e){if(t=parseFloat(e.angle),isNaN(t)){t=0;let s=window.getComputedStyle(e).transform;if(s&&"none"!=s){let e=s.split("(")[1].split(")")[0].split(","),r=e[0],i=e[1],o=Math.atan2(i,r);(t=parseInt(o*(180/Math.PI)))<0&&(t=360+t)}}e.angle=t}return t};t=t||{},e.options={...s,...t},e.options.resizers={...e.options.resizers},e.style.position="absolute",e.style.left=e.offsetLeft+"px",e.style.top=e.offsetTop+"px",e.style.width=e.offsetWidth+"px",e.style.height=e.offsetHeight+"px",e.angle=r(e),e.resizer=!0,e.isDisabled="true"===e.getAttribute("isDisabled"),e.isDisabled&&(e.resizer=!1);let i=this.show(e);e.bBox=i,e.scale=i.width/e.offsetWidth,e.moveCounter=0,e.resizer=this.resizer,document.querySelector(".resizer-container")||document.body.appendChild(e.resizer);let o=t=>{if("mousedown"===t.type&&(t.preventDefault(),0!=t.button))return;if(t.stopPropagation(),e.isDisabled="true"===e.getAttribute("isDisabled"),e.isDisabled&&(e.resizer=!1,this.hide()),e.isLocked="true"===e.getAttribute("islocked"),e.startPos={x:t.clientX+document.body.scrollLeft,y:t.clientY+document.body.scrollTop},e.size={left:e.offsetLeft,top:e.offsetTop,width:e.offsetWidth,height:e.offsetHeight},e.isLocked||e.isDisabled||(document.addEventListener("mousemove",n),document.addEventListener("mouseup",a),document.addEventListener("touchmove",n),document.addEventListener("touchend",a)),"touchstart"===t.type){if(t.touches.length>1)return;e.startPos={x:t.touches[0].clientX+document.body.scrollLeft,y:t.touches[0].clientY+document.body.scrollTop}}e.resizer&&(e.resizer.visibile=!1),this.show(e),this.target=e;let s=t=>{t.stopPropagation(),t.preventDefault(),this.show(e),window.removeEventListener("click",s,!0)};window.addEventListener("click",s,!0),e.moveCounter=0,this.hoverLine&&(this.hoverLine.style.opacity="0")},n=s=>{s.stopPropagation(),"mousemove"===s.type&&s.preventDefault(),e.moveCounter++,1===e.moveCounter&&(s.size={...e.size},s.angle=e.angle,s.evtTarget=e,s.handler=this.resizer,e.options.onDragStart&&e.options.onDragStart(s),e.resizer&&e.resizer.showHideResizer&&e.resizer.showHideResizer(!0));let r=s.clientX+document.body.scrollLeft-e.startPos.x,i=s.clientY+document.body.scrollTop-e.startPos.y;"touchmove"===s.type&&(r=s.touches[0].clientX+document.body.scrollLeft-e.startPos.x,i=s.touches[0].clientY+document.body.scrollTop-e.startPos.y);let o=e.size.left+r/e.scale,n=e.size.top+i/e.scale;if(e.style.left=o+"px",e.style.top=n+"px",t.boundWithContainer){let s=t.boundWithContainer instanceof HTMLDivElement?t.boundWithContainer:e.offsetParent;if(s){let t=s.getBoundingClientRect(),r=e.getBoundingClientRect();if(r.leftt.right){o+=(t.right-r.right)/e.scale}if(r.bottom>t.bottom){n+=(t.bottom-r.bottom)/e.scale}e.style.left=o+"px",e.style.top=n+"px"}}e.newSize={...e.size,left:o,top:n},e.options.onDragging&&(s.size={...e.newSize},s.angle=e.angle,s.evtTarget=e,s.handler=this.resizer,e.options.onDragging(s)),this.show(e)},a=t=>{t.stopPropagation(),"mouseup"===t.type&&t.preventDefault(),document.removeEventListener("mousemove",n),document.removeEventListener("mouseup",a),document.removeEventListener("touchmove",n),document.removeEventListener("touchend",a),e.resizer.showHideResizer(!1),e.moveCounter&&e.options.onDragEnd&&(t.size={...e.newSize},t.angle=e.angle,t.evtTarget=e,t.handler=this.resizer,e.options.onDragEnd(t)),this.show(e),e.dispatchEvent(new MouseEvent("click"))};e.handleMouseEnter=(e=>{if(this.target!=e.target&&e.target.options.isHoverLine){let t=e=>{let t=e.cloneNode();t.innerHTML="",t.style.cssText=e.style.cssText,t.style.opacity="0",t.style.pointerEvents="none";let s=t.style.transform;s&&s.indexOf("rotate")>=0?t.style.transform=s.replace(/rotate\(\w*\)/gi,""):e.angle&&(t.style.transform=s+" rotate(0deg)"),e.parentNode.appendChild(t);let r=t.getBoundingClientRect();return t.remove(),r},s=document.querySelector(".resizer-target-hover-line");!s&&(s=document.createElement("div")),s.className="resizer-target-hover-line",s.style.position="absolute",document.body.appendChild(s),this.hoverLine=s;let r=t(e.target);s.style.left=parseInt(r.left+window.scrollX)+"px",s.style.top=parseInt(r.top+window.scrollY)+"px",s.style.width=parseInt(r.width+2)+"px",s.style.height=parseInt(r.height+2)+"px",s.style.opacity="1",s.style.transform="rotate("+(e.target.angle||0)+"deg)",s.target=e.target}}),e.handleMouseLeave=(e=>{this.hoverLine&&(this.hoverLine.style.opacity="0")}),e.handleMousedown||(e.handleMousedown=o,e.removeEventListener("mousedown",o),e.addEventListener("mousedown",o),e.removeEventListener("touchstart",o),e.addEventListener("touchstart",o),e.handleClick=(e=>{e.stopPropagation()}),e.removeEventListener("click",e.handleClick),e.addEventListener("click",e.handleClick),e.addEventListener("mouseenter",e.handleMouseEnter),e.addEventListener("mouseleave",e.handleMouseLeave))}},show(e){if(e&&e.resizer){if(!this.resizer){let e=document.querySelector(".resizer-container");e&&e.remove(),(e=document.createElement("div")).className="resizer-container",e.style.position="absolute",document.body.appendChild(e),this.resizer=e;let t=document.createElement("div");t.className="resizer-border",t.actionName="resizer-border",e.resizer_border=t,e.appendChild(t);let s=document.createElement("div");s.className="nw-resizer",s.actionName="nw-resizer",e.nw_resizer=s,e.appendChild(s);let r=document.createElement("div");r.className="ne-resizer",r.actionName="ne-resizer",e.ne_resizer=r,e.appendChild(r);let i=document.createElement("div");i.className="sw-resizer",i.actionName="sw-resizer",e.sw_resizer=i,e.appendChild(i);let o=document.createElement("div");o.className="se-resizer",o.actionName="se-resizer",e.se_resizer=o,e.appendChild(o);let n=document.createElement("div");n.className="n-resizer",n.actionName="n-resizer",e.n_resizer=n,e.appendChild(n);let a=document.createElement("div");a.className="e-resizer",a.actionName="e-resizer",e.e_resizer=a,e.appendChild(a);let l=document.createElement("div");l.className="s-resizer",l.actionName="s-resizer",e.s_resizer=l,e.appendChild(l);let d=document.createElement("div");d.className="w-resizer",d.actionName="w-resizer",e.w_resizer=d,e.appendChild(d);let c=document.createElement("div");c.className="r-resizer",c.actionName="r-resizer",e.r_resizer=c,e.appendChild(c);let h=document.createElement("div");h.className="rotator-angle-div",h.style.display="none",document.body.appendChild(h),e.showHideResizer=function(t,s){this.target.isLocked&&(t=!1),e.querySelectorAll("*").forEach(e=>{e!==s&&(e.style.opacity=t?0:1)})};let p=(e,t,s)=>{h.style.display="",h.style.left=e+"px",h.style.top=t+"px",h.innerHTML=s},u=()=>{h.style.display="none"},z=(e,t,s,r,i)=>{let o=Math.PI/180*i,n=Math.cos(o),a=Math.sin(o);return{x:n*(s-e)+a*(r-t)+e,y:n*(r-t)-a*(s-e)+t}},m=(e,t)=>{let s=Math.PI/-180*t,r=Math.cos(s),i=Math.sin(s),o=e.left,n=e.top,a=o+e.width,l=n,d=o+e.width,c=n+e.height,h=o,p=n+e.height,u=o+e.width/2,z=n+e.height/2;return{ax:parseInt(r*(o-u)+i*(n-z)+u),ay:parseInt(r*(n-z)-i*(o-u)+z),bx:parseInt(r*(a-u)+i*(l-z)+u),by:parseInt(r*(l-z)-i*(a-u)+z),cx:parseInt(r*(d-u)+i*(c-z)+u),cy:parseInt(r*(c-z)-i*(d-u)+z),dx:parseInt(r*(h-u)+i*(p-z)+u),dy:parseInt(r*(p-z)-i*(h-u)+z),px:u,py:z}},g=(e,t,s,r)=>{let i=m(t,s),o=m(e,s),n=0,a=0;switch(r){case 1:case"TopLeft":n=e.left+i.ax-o.ax,a=e.top+i.ay-o.ay;break;case 2:case"TopRight":n=e.left+i.bx-o.bx,a=e.top+i.by-o.by;break;case 3:case"BottomRight":n=e.left+i.cx-o.cx,a=e.top+i.cy-o.cy;break;case 4:case"BottomLeft":n=e.left+i.dx-o.dx,a=e.top+i.dy-o.dy;break;default:n=e.left+i.ax-o.ax,a=e.top+i.ay-o.ay}return{x:n,y:a}},y=t=>{if("mousedown"===t.type){if(0!=t.button)return;t.preventDefault()}t.stopPropagation();let s=this.target;if(s.isLocked="true"===s.getAttribute("islocked"),s.isLocked||(window.addEventListener("mousemove",f),window.addEventListener("mouseup",w),window.addEventListener("touchmove",f),window.addEventListener("touchend",w)),e.current=t.target,v=0,e.current.classList.add("active"),e.startPos={x:t.clientX+document.body.scrollLeft,y:t.clientY+document.body.scrollTop},s.size={left:s.offsetLeft,top:s.offsetTop,width:s.offsetWidth,height:s.offsetHeight,cx:s.offsetLeft+s.offsetWidth/2,cy:s.offsetTop+s.offsetHeight/2,angle:s.angle},s.prevSize={...s.size},"touchstart"===t.type){if(t.touches.length>1)return;e.startPos={x:t.touches[0].clientX+document.body.scrollLeft,y:t.touches[0].clientY+document.body.scrollTop}}if(s.bBox=s.getBoundingClientRect(),s.angle){let t=s.bBox,r=t.left+t.width/2,i=t.top+t.height/2;e.startPos=z(r,i,e.startPos.x,e.startPos.y,s.angle)}if(s.angle&&!s.options.resizeFromCenter){let t=m(s.size,s.angle);switch(s.coord=t,e.current.actionName){case"se-resizer":case"e-resizer":case"s-resizer":e.style.transformOrigin="top left",s.style.transformOrigin="top left",s.style.left=t.ax+"px",s.style.top=t.ay+"px";break;case"sw-resizer":case"w-resizer":e.style.transformOrigin="top right",s.style.transformOrigin="top right",s.style.left=t.bx-s.size.width+"px",s.style.top=t.by+"px";break;case"ne-resizer":e.style.transformOrigin="bottom left",s.style.transformOrigin="bottom left",s.style.left=t.dx+"px",s.style.top=t.dy-s.size.height+"px";break;case"nw-resizer":case"n-resizer":e.style.transformOrigin="bottom right",s.style.transformOrigin="bottom right",s.style.left=t.cx-s.size.width+"px",s.style.top=t.cy-s.size.height+"px"}}this.show(s);let r=e=>{e.stopPropagation(),e.preventDefault(),window.removeEventListener("click",r,!0)};window.addEventListener("click",r,!0),e.showHideResizer(!0,e.current)},f=e=>{e.stopPropagation(),"mousemove"===e.type&&e.preventDefault();let t=this.target,s=this.resizer,r=t.options.resizeFromCenter,{minWidth:i,minHeight:o,aspectRatio:n}=t.options,a=e.clientX+document.body.scrollLeft,l=e.clientY+document.body.scrollTop,d=e.clientX+document.body.scrollLeft-s.startPos.x,c=e.clientY+document.body.scrollTop-s.startPos.y,h=t.size.left,u=t.size.top,g=t.size.width,y=t.size.height,f=t.bBox,w=f.left+f.width/2,b=f.top+f.height/2,x=t.angle;if(0===v&&("r-resizer"===this.resizer.current.actionName?t.options&&t.options.onRotateStart&&(e.size={...t.size},e.angle=t.angle,e.evtTarget=t,e.handler=s.current,t.options.onRotateStart(e)):t.options&&t.options.onResizeStart&&(e.size={...t.size},e.angle=t.angle,e.evtTarget=t,e.handler=s.current,t.options.onResizeStart(e))),v++,"touchmove"===e.type&&(d=e.touches[0].clientX+document.body.scrollLeft-s.startPos.x,c=e.touches[0].clientY+document.body.scrollTop-s.startPos.y,a=e.touches[0].clientX+document.body.scrollLeft,l=e.touches[0].clientY+document.body.scrollTop),x){let e=f.left+f.width/2,t=f.top+f.height/2,r=z(e,t,a,l,x);d=r.x-s.startPos.x,c=r.y-s.startPos.y}switch(r&&(d*=2,c*=2),this.resizer.current.actionName){case"se-resizer":if((g=t.size.width+d/t.scale)=0?x:360+x),t.angle=x,t.style.transform.indexOf("rotate")>=0?t.style.transform=t.style.transform.replace(/rotate\(\w*\)/gi,"rotate("+x+"deg)"):t.style.transform+=" rotate("+x+"deg)",p(a,l,x)}if(t.angle&&"r-resizer"!==this.resizer.current.actionName&&!r){switch(this.resizer.current.actionName){case"se-resizer":case"e-resizer":case"s-resizer":h=t.coord.ax,u=t.coord.ay;break;case"sw-resizer":case"w-resizer":h=t.coord.bx-g,u=t.coord.by;m({left:h,top:u,width:g,height:y},0);break;case"ne-resizer":h=t.coord.dx,u=t.coord.dy-y;break;case"nw-resizer":case"n-resizer":h=t.coord.cx-g,u=t.coord.cy-y}}r&&(h=t.size.cx-g/2,u=t.size.cy-y/2);let L={left:h,top:u,width:g,height:y};if(t.newSize=L,t.style.left=h+"px",t.style.top=u+"px",t.style.width=g+"px",t.style.height=y+"px",t.options.boundWithContainer){let e=t.options.boundWithContainer instanceof HTMLDivElement?t.options.boundWithContainer:t.offsetParent;if(e){let s=e.getBoundingClientRect(),r=t.getBoundingClientRect();r.lefts.right||r.bottom>s.bottom?(h=t.prevSize.left,u=t.prevSize.top,g=t.prevSize.width,y=t.prevSize.height,x=t.prevSize.angle,L={left:h,top:u,width:g,height:y},t.newSize=L,t.style.left=h+"px",t.style.top=u+"px",t.style.width=g+"px",t.style.height=y+"px",t.angle=x,t.style.transform.indexOf("rotate")>=0?t.style.transform=t.style.transform.replace(/rotate\(\w*\)/gi,"rotate("+x+"deg)"):t.style.transform+=" rotate("+x+"deg)",p(a,l,x)):t.prevSize={left:h,top:u,width:g,height:y,angle:x}}}"r-resizer"===this.resizer.current.actionName?t.options&&t.options.onRotating&&(e.size={...t.newSize},e.angle=t.angle,e.evtTarget=t,e.handler=s.current,t.options.onRotating(e)):t.options&&t.options.onResizing&&(e.size={...t.newSize},e.angle=t.angle,e.evtTarget=t,e.handler=s.current,t.options.onResizing(e)),this.show(t)},w=t=>{t.stopPropagation(),"mouseup"===t.type&&t.preventDefault(),window.removeEventListener("mousemove",f),window.removeEventListener("mouseup",w),window.removeEventListener("touchmove",f),window.removeEventListener("touchend",w),u(),e.showHideResizer(!1,e.current);let s=this.target,r=s.options.resizeFromCenter;if(s.angle&&"r-resizer"!==e.current.actionName&&!r){let t,r,i="TopLeft";switch(e.style.transformOrigin="",s.style.transformOrigin="",this.resizer.current.actionName){case"se-resizer":i="TopLeft";break;case"sw-resizer":i="TopRight";break;case"ne-resizer":i="BottomLeft";break;case"nw-resizer":case"n-resizer":i="BottomRight";break;case"e-resizer":case"s-resizer":i="TopLeft";break;case"w-resizer":i="TopRight"}t={left:s.size.left,top:s.size.top,width:s.newSize.width,height:s.newSize.height},r=g(t,s.size,s.angle,i),s.style.left=r.x+"px",s.style.top=r.y+"px",s.newSize={...t,left:r.x,top:r.y}}v&&("r-resizer"===e.current.actionName?s.options&&s.options.onRotateEnd&&(t.size={...s.newSize},t.angle=s.angle,t.evtTarget=s,t.handler=e.current,s.options.onRotateEnd(t)):s.options&&s.options.onResizeEnd&&(t.size={...s.newSize},t.angle=s.angle,t.evtTarget=s,t.handler=e.current,s.options.onResizeEnd(t))),e.current.classList.remove("active"),this.show(s)},v=0;e.removeEventListener("mousedown",y),e.addEventListener("mousedown",y),e.removeEventListener("touchstart",y),e.addEventListener("touchstart",y);let b=t=>{e.visibile&&this.show(this.target)};window.removeEventListener("resize",b,!0),window.addEventListener("resize",b,!0);let x=t=>{e.visibile&&this.show(this.target)};window.removeEventListener("scroll",x,!0),window.addEventListener("scroll",x,!0)}let t=this.resizer,s=e=>{let s=t._target;s||((s=e.cloneNode()).innerHTML="",e.parentNode.appendChild(s),t._target=s),s.style.cssText=e.style.cssText,s.style.opacity="0",s.style.pointerEvents="none";let r=s.style.transform;return r&&r.indexOf("rotate")>=0?s.style.transform=r.replace(/rotate\(\w*\)/gi,""):e.angle&&(s.style.transform=r+" rotate(0deg)"),s.timeOut&&window.clearTimeout(s.timeOut),s.timeOut=window.setTimeout(()=>{window.clearTimeout(s.timeOut),s.remove(),t._target=null},1e3),s.getBoundingClientRect()},r=e=>{if(e!=this.resizer.angle){let t=(e-(e+7)%15+7)%180,s=this.resizer;s.angle=e,s.ne_resizer.className=s.ne_resizer.className.replace(/ cursor_(\d)+d/gi,"")+" cursor_"+(t+45)%180+"d",s.sw_resizer.className=s.sw_resizer.className.replace(/ cursor_(\d)+d/gi,"")+" cursor_"+(t+45)%180+"d",s.nw_resizer.className=s.nw_resizer.className.replace(/ cursor_(\d)+d/gi,"")+" cursor_"+(t+135)%180+"d",s.se_resizer.className=s.se_resizer.className.replace(/ cursor_(\d)+d/gi,"")+" cursor_"+(t+135)%180+"d",s.n_resizer.className=s.n_resizer.className.replace(/ cursor_(\d)+d/gi,"")+" cursor_"+(t+0)%180+"d",s.s_resizer.className=s.s_resizer.className.replace(/ cursor_(\d)+d/gi,"")+" cursor_"+(t+0)%180+"d",s.w_resizer.className=s.w_resizer.className.replace(/ cursor_(\d)+d/gi,"")+" cursor_"+(t+90)%180+"d",s.e_resizer.className=s.e_resizer.className.replace(/ cursor_(\d)+d/gi,"")+" cursor_"+(t+90)%180+"d"}};if(!t.visibile){let s=e.options&&e.options.resizers;s&&(t.nw_resizer.style.display=s.nw?"":"none",t.ne_resizer.style.display=s.ne?"":"none",t.sw_resizer.style.display=s.sw?"":"none",t.se_resizer.style.display=s.se?"":"none",t.n_resizer.style.display=s.n?"":"none",t.e_resizer.style.display=s.e?"":"none",t.s_resizer.style.display=s.s?"":"none",t.w_resizer.style.display=s.w?"":"none",t.r_resizer.style.display=s.r?"":"none")}let i=s(e);return t.style.left=parseInt(i.left+window.scrollX)+"px",t.style.top=parseInt(i.top+window.scrollY)+"px",t.style.width=parseInt(i.width+1)+"px",t.style.height=parseInt(i.height+1)+"px",t.style.display="",t.style.transform="rotate("+(e.angle||0)+"deg)",t.visibile=!0,t.target=e,r(e.angle),i}return e.getBoundingClientRect()},hide(){this.target=null,this.resizer.style.display="none",this.resizer.visibile=!1},remove(e){e&&e.handleMousedown&&(e.removeEventListener("mousedown",e.handleMousedown),e.removeEventListener("touchstart",e.handleMousedown),e.removeEventListener("mouseenter",e.handleMouseEnter),e.removeEventListener("mouseleave",e.handleMouseLeave),e.options&&(e.options=null),e.resizer=null,this.hide())}};export default resizer; -------------------------------------------------------------------------------- /resizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developergovindgupta/move-rotate-resizer/914f6937461543e4bdacade564cc299cc621a247/resizer.png -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | import resizer from './resizer.min.js'; 2 | 3 | let options = { 4 | onDragStart: function (e) { 5 | // console.log('onDragStart:', e); 6 | // console.log(e.target.options); 7 | e.target.style.opacity = '0.8'; 8 | e.target.style.zIndex = '999'; 9 | }, 10 | onDragging: function (e) { 11 | // console.log('onDragging:', e); 12 | }, 13 | onDragEnd: function (e) { 14 | // console.log('onDragEnd:', e); 15 | // console.log(e.target); 16 | e.target.style.opacity = ''; 17 | e.target.style.zIndex = ''; 18 | }, 19 | onRotateStart: function (e) { 20 | // console.log('onRotateStart:', e); 21 | e.target.style.opacity = '0.8'; 22 | e.target.style.zIndex = '999'; 23 | }, 24 | onRotating: function (e) { 25 | // console.log('onRotating:', e); 26 | }, 27 | onRotateEnd: function (e) { 28 | // console.log('onRotateEnd:', e); 29 | e.target.style.opacity = ''; 30 | e.target.style.zIndex = ''; 31 | }, 32 | onResizeStart: function (e) { 33 | // console.log('onResizeStart:', e); 34 | e.target.style.opacity = '0.8'; 35 | e.target.style.zIndex = '999'; 36 | }, 37 | onResizing: function (e) { 38 | // console.log('onResizing:', e); 39 | }, 40 | onResizeEnd: function (e) { 41 | // console.log('onResizeEnd:', e); 42 | e.target.style.opacity = ''; 43 | e.target.style.zIndex = ''; 44 | }, 45 | resizers: { 46 | n: true, 47 | s: true, 48 | e: true, 49 | w: true, 50 | ne: true, 51 | nw: true, 52 | se: true, 53 | sw: true, 54 | r: true, 55 | }, 56 | }; 57 | let div1 = document.querySelector('#center-resize'); 58 | resizer.add(div1, { ...options, ...{ resizeFromCenter: true } }); 59 | let div2 = document.querySelector('#corner-resize'); 60 | resizer.add(div2, { ...options, ...{} }); 61 | let div3 = document.querySelector('#free-resize'); 62 | resizer.add(div3, { ...options, ...{ aspectRatio: false } }); 63 | let div4 = document.querySelector('#bound-resize'); 64 | resizer.add(div4, { ...options, ...{ boundWithContainer: true } }); 65 | 66 | document.body.addEventListener('click', function (e) { 67 | console.log('document.body.click', e); 68 | resizer.hide(); 69 | }); 70 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | padding: 0; 4 | margin: 0; 5 | } 6 | html, 7 | body { 8 | width: 100%; 9 | height: 100%; 10 | } 11 | body { 12 | background-color: lightblue; 13 | } 14 | .container { 15 | position: absolute; 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | left: 100px; 20 | top: 100px; 21 | right: 100px; 22 | bottom: 100px; 23 | border: solid 1px red; 24 | 25 | overflow: auto; 26 | } 27 | .content { 28 | width: 800px; 29 | height: 600px; 30 | background-color: white; 31 | } 32 | .print-area { 33 | position: relative; 34 | width: 1600px; 35 | height: 1200px; 36 | background-color: white; 37 | border: solid 1px black; 38 | transform-origin: 0px 0px; 39 | transform: scale(0.5); 40 | overflow: hidden; 41 | } 42 | .target { 43 | position: absolute; 44 | top: 300px; 45 | left: 400px; 46 | width: 300px; 47 | height: 300px; 48 | border: solid 2px black; 49 | background-color: lightgreen; 50 | display: flex; 51 | justify-content: center; 52 | align-items: center; 53 | font-size: 2em; 54 | cursor: default; 55 | } 56 | --------------------------------------------------------------------------------