├── .gitignore ├── .npmignore ├── .npmrc ├── README.md ├── babel.config.js ├── dist ├── view-line.css └── view-line.js ├── package.json ├── sample ├── index.ts ├── move.gif ├── resize.gif └── tmp.html ├── src ├── constants.ts ├── index.less ├── index.ts ├── lines │ ├── align.ts │ ├── distance.ts │ ├── label.ts │ ├── lib.ts │ ├── space.ts │ └── store.ts ├── move.ts ├── resize.ts └── types.ts ├── tsconfig.json ├── tslint.json ├── webpack.base.config.js ├── webpack.dev.config.js └── webpack.prod.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | .project 3 | 4 | # Github defaults only below this comment 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # node-waf configuration 23 | .lock-wscript 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directory 29 | node_modules 30 | node_modules2 31 | # Optional npm cache directory 32 | .npm 33 | 34 | 35 | # Optional REPL history 36 | .node_repl_history 37 | 38 | # WebStorm 39 | .idea/ 40 | .DS_Store 41 | 42 | # VsCode 43 | .vscode 44 | 45 | dist 46 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | src/ 3 | tests/ 4 | sample/ 5 | __tests__/ 6 | node_modules/ 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | package-lock.json* 11 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # registry = https://registry.npm.taobao.org 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # view-line 2 | 3 | Use this library to add alignment lines, spacing blocks, adsorption to the free canvas 4 | 5 | ## 安装 6 | ``` 7 | npm install view-line --save 8 | ``` 9 | ## 使用 10 | 11 | Move view dom element: 12 | 13 | ```js 14 | import { moveByDom, resizeByDom, initLine } from 'view-line'; 15 | import 'view-line/dist/view-line.css'; 16 | moveByDom(view, top, left, function (top, left) { 17 | console.log(top, left); 18 | }); 19 | ``` 20 | 21 | Resize view dom element: 22 | 23 | ```js 24 | import { moveByDom, resizeByDom, initLine } from 'view-line'; 25 | import 'view-line/dist/view-line.css'; 26 | resizeByDom(view, top, left, height, width, function (top, left, height, width) { 27 | console.log(top, left, height, width); 28 | }); 29 | ``` 30 | 31 | ## API说明 32 | 33 | ### moveByDom(dom,top,left,onMoveEnd): Move elements to show alignment lines 34 | 35 | - dom: The dom element draged 36 | - top: The top value of the element relative to the container 37 | - left: The left value of the element relative to the container 38 | - onMoveEnd: Callback function for the end of the drag and drop, returning the last top and left 39 | 40 | ### resizeByDom(dom,top,left,height,width,onResizeEnd): Resize elements to show alignment lines 41 | 42 | - dom: The dom element resized 43 | - top: The top value of the element relative to the container 44 | - left: The left value of the element relative to the container 45 | - height: The height of element 46 | - width: The width of element 47 | - onResizeEnd: Callback function for the end of the drag and drop, returning the last top and left 48 | 49 | 50 | ## Example 51 | 52 | Run `npm run dev` under `sample` folder 53 | 54 | The rendering is as follows: 55 | 56 | Alignment line: 57 | 58 | ![resize](https://github.com/hongyin163/view-line/assets/3040906/08ce4fbb-6e3f-4221-ba1f-3d4c193fb74f) 59 | 60 | Spacing adsorption: 61 | 62 | ![move](https://github.com/hongyin163/view-line/assets/3040906/b50b2b03-c36f-4e35-aed2-2341f72d46c8) 63 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | 4 | const presets = [ 5 | ["@babel/preset-env",{ 6 | targets:{ 7 | browsers:'last 2 versions,ie >= 9' 8 | }, 9 | modules:false, 10 | }], 11 | "@babel/preset-typescript" 12 | ]; 13 | const plugins = [ 14 | "@babel/plugin-transform-runtime", 15 | "@babel/plugin-proposal-class-properties", 16 | ]; 17 | 18 | return { 19 | presets, 20 | plugins 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /dist/view-line.css: -------------------------------------------------------------------------------- 1 | .view__lines { 2 | display: none; 3 | pointer-events: none; 4 | } 5 | .view__lines i.line { 6 | position: absolute; 7 | } 8 | .view__lines .t { 9 | top: 0px; 10 | left: 0; 11 | right: 0; 12 | height: 0; 13 | width: auto; 14 | border: 0; 15 | border-top: 1px solid red; 16 | z-index: 10 ; 17 | } 18 | .view__lines .r { 19 | right: 0; 20 | top: 0; 21 | bottom: 0; 22 | width: 0; 23 | height: auto; 24 | border: 0; 25 | border-right: 1px solid red; 26 | z-index: 10 ; 27 | } 28 | .view__lines .b { 29 | bottom: 0; 30 | left: 0; 31 | right: 0; 32 | height: 0; 33 | width: auto; 34 | border: 0; 35 | border-bottom: 1px solid red; 36 | z-index: 10 ; 37 | } 38 | .view__lines .l { 39 | left: 0; 40 | top: 0; 41 | bottom: 0; 42 | height: auto; 43 | width: 0; 44 | border: 0; 45 | border-left: 1px solid red; 46 | z-index: 10 ; 47 | } 48 | .view__resize-label { 49 | position: fixed; 50 | height: 24px; 51 | padding: 0 5px; 52 | display: inline-block; 53 | line-height: 24px; 54 | font-size: 12px; 55 | z-index: 999; 56 | background: #FB7055; 57 | border-radius: 3px; 58 | color: #fff; 59 | transform: translateX(-50%); 60 | } 61 | .view__v-line { 62 | position: fixed; 63 | width: 0; 64 | border-left: 1px solid red; 65 | z-index: 999; 66 | pointer-events: none; 67 | } 68 | .view__h-line { 69 | position: fixed; 70 | height: 0; 71 | border-top: 1px solid red; 72 | z-index: 999; 73 | pointer-events: none; 74 | } 75 | .view__h-dist-line { 76 | position: fixed; 77 | height: 0; 78 | border-top: 1px dashed #adadad; 79 | z-index: 999; 80 | text-align: center; 81 | pointer-events: none; 82 | } 83 | .view__h-dist-line .label { 84 | position: absolute; 85 | left: 50%; 86 | top: -4px; 87 | height: 14px; 88 | display: inline-block; 89 | line-height: 14px; 90 | text-align: center; 91 | background: #FB7055; 92 | transform: translate(-50%, -100%); 93 | color: #fff; 94 | padding: 0 5px; 95 | pointer-events: none; 96 | border-radius: 7px; 97 | } 98 | .view__v-dist-line { 99 | position: fixed; 100 | width: 0; 101 | border-left: 1px dashed #adadad; 102 | z-index: 999; 103 | text-align: center; 104 | pointer-events: none; 105 | } 106 | .view__v-dist-line .label { 107 | position: absolute; 108 | top: 50%; 109 | left: -4px; 110 | height: 14px; 111 | display: inline-block; 112 | line-height: 14px; 113 | text-align: center; 114 | background: #FB7055; 115 | transform: translate(-100%, -50%); 116 | color: #fff; 117 | padding: 0 5px; 118 | border-radius: 7px; 119 | } 120 | .view__h-space-line { 121 | position: fixed; 122 | height: 0; 123 | z-index: 999; 124 | text-align: center; 125 | pointer-events: none; 126 | transform: translateY(-50%); 127 | background: #FB7055; 128 | opacity: 0.4; 129 | line-height: 100%; 130 | } 131 | .view__h-space-line .line { 132 | position: absolute; 133 | top: 50%; 134 | left: 0; 135 | right: 0; 136 | height: 0; 137 | pointer-events: none; 138 | } 139 | .view__v-space-line { 140 | position: fixed; 141 | z-index: 999; 142 | text-align: center; 143 | pointer-events: none; 144 | transform: translateX(-50%); 145 | background: #FB7055; 146 | opacity: 0.4; 147 | } 148 | .view__v-space-line .line { 149 | position: absolute; 150 | left: 50%; 151 | top: 0; 152 | bottom: 0; 153 | width: 0; 154 | pointer-events: none; 155 | } 156 | 157 | -------------------------------------------------------------------------------- /dist/view-line.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(); 4 | else if(typeof define === 'function' && define.amd) 5 | define([], factory); 6 | else if(typeof exports === 'object') 7 | exports["ViewLine"] = factory(); 8 | else 9 | root["ViewLine"] = factory(); 10 | })(window, function() { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) { 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ } 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 50 | /******/ } 51 | /******/ }; 52 | /******/ 53 | /******/ // define __esModule on exports 54 | /******/ __webpack_require__.r = function(exports) { 55 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 56 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 57 | /******/ } 58 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 59 | /******/ }; 60 | /******/ 61 | /******/ // create a fake namespace object 62 | /******/ // mode & 1: value is a module id, require it 63 | /******/ // mode & 2: merge all properties of value into the ns 64 | /******/ // mode & 4: return value when already ns object 65 | /******/ // mode & 8|1: behave like require 66 | /******/ __webpack_require__.t = function(value, mode) { 67 | /******/ if(mode & 1) value = __webpack_require__(value); 68 | /******/ if(mode & 8) return value; 69 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 70 | /******/ var ns = Object.create(null); 71 | /******/ __webpack_require__.r(ns); 72 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 73 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 74 | /******/ return ns; 75 | /******/ }; 76 | /******/ 77 | /******/ // getDefaultExport function for compatibility with non-harmony modules 78 | /******/ __webpack_require__.n = function(module) { 79 | /******/ var getter = module && module.__esModule ? 80 | /******/ function getDefault() { return module['default']; } : 81 | /******/ function getModuleExports() { return module; }; 82 | /******/ __webpack_require__.d(getter, 'a', getter); 83 | /******/ return getter; 84 | /******/ }; 85 | /******/ 86 | /******/ // Object.prototype.hasOwnProperty.call 87 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 88 | /******/ 89 | /******/ // __webpack_public_path__ 90 | /******/ __webpack_require__.p = ""; 91 | /******/ 92 | /******/ 93 | /******/ // Load entry module and return exports 94 | /******/ return __webpack_require__(__webpack_require__.s = "./src/index.ts"); 95 | /******/ }) 96 | /************************************************************************/ 97 | /******/ ({ 98 | 99 | /***/ "./node_modules/@babel/runtime/helpers/arrayLikeToArray.js": 100 | /*!*****************************************************************!*\ 101 | !*** ./node_modules/@babel/runtime/helpers/arrayLikeToArray.js ***! 102 | \*****************************************************************/ 103 | /*! no static exports found */ 104 | /***/ (function(module, exports) { 105 | 106 | function _arrayLikeToArray(arr, len) { 107 | if (len == null || len > arr.length) len = arr.length; 108 | 109 | for (var i = 0, arr2 = new Array(len); i < len; i++) { 110 | arr2[i] = arr[i]; 111 | } 112 | 113 | return arr2; 114 | } 115 | 116 | module.exports = _arrayLikeToArray; 117 | 118 | /***/ }), 119 | 120 | /***/ "./node_modules/@babel/runtime/helpers/arrayWithHoles.js": 121 | /*!***************************************************************!*\ 122 | !*** ./node_modules/@babel/runtime/helpers/arrayWithHoles.js ***! 123 | \***************************************************************/ 124 | /*! no static exports found */ 125 | /***/ (function(module, exports) { 126 | 127 | function _arrayWithHoles(arr) { 128 | if (Array.isArray(arr)) return arr; 129 | } 130 | 131 | module.exports = _arrayWithHoles; 132 | 133 | /***/ }), 134 | 135 | /***/ "./node_modules/@babel/runtime/helpers/defineProperty.js": 136 | /*!***************************************************************!*\ 137 | !*** ./node_modules/@babel/runtime/helpers/defineProperty.js ***! 138 | \***************************************************************/ 139 | /*! no static exports found */ 140 | /***/ (function(module, exports) { 141 | 142 | function _defineProperty(obj, key, value) { 143 | if (key in obj) { 144 | Object.defineProperty(obj, key, { 145 | value: value, 146 | enumerable: true, 147 | configurable: true, 148 | writable: true 149 | }); 150 | } else { 151 | obj[key] = value; 152 | } 153 | 154 | return obj; 155 | } 156 | 157 | module.exports = _defineProperty; 158 | 159 | /***/ }), 160 | 161 | /***/ "./node_modules/@babel/runtime/helpers/iterableToArrayLimit.js": 162 | /*!*********************************************************************!*\ 163 | !*** ./node_modules/@babel/runtime/helpers/iterableToArrayLimit.js ***! 164 | \*********************************************************************/ 165 | /*! no static exports found */ 166 | /***/ (function(module, exports) { 167 | 168 | function _iterableToArrayLimit(arr, i) { 169 | if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; 170 | var _arr = []; 171 | var _n = true; 172 | var _d = false; 173 | var _e = undefined; 174 | 175 | try { 176 | for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { 177 | _arr.push(_s.value); 178 | 179 | if (i && _arr.length === i) break; 180 | } 181 | } catch (err) { 182 | _d = true; 183 | _e = err; 184 | } finally { 185 | try { 186 | if (!_n && _i["return"] != null) _i["return"](); 187 | } finally { 188 | if (_d) throw _e; 189 | } 190 | } 191 | 192 | return _arr; 193 | } 194 | 195 | module.exports = _iterableToArrayLimit; 196 | 197 | /***/ }), 198 | 199 | /***/ "./node_modules/@babel/runtime/helpers/nonIterableRest.js": 200 | /*!****************************************************************!*\ 201 | !*** ./node_modules/@babel/runtime/helpers/nonIterableRest.js ***! 202 | \****************************************************************/ 203 | /*! no static exports found */ 204 | /***/ (function(module, exports) { 205 | 206 | function _nonIterableRest() { 207 | throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 208 | } 209 | 210 | module.exports = _nonIterableRest; 211 | 212 | /***/ }), 213 | 214 | /***/ "./node_modules/@babel/runtime/helpers/slicedToArray.js": 215 | /*!**************************************************************!*\ 216 | !*** ./node_modules/@babel/runtime/helpers/slicedToArray.js ***! 217 | \**************************************************************/ 218 | /*! no static exports found */ 219 | /***/ (function(module, exports, __webpack_require__) { 220 | 221 | var arrayWithHoles = __webpack_require__(/*! ./arrayWithHoles */ "./node_modules/@babel/runtime/helpers/arrayWithHoles.js"); 222 | 223 | var iterableToArrayLimit = __webpack_require__(/*! ./iterableToArrayLimit */ "./node_modules/@babel/runtime/helpers/iterableToArrayLimit.js"); 224 | 225 | var unsupportedIterableToArray = __webpack_require__(/*! ./unsupportedIterableToArray */ "./node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js"); 226 | 227 | var nonIterableRest = __webpack_require__(/*! ./nonIterableRest */ "./node_modules/@babel/runtime/helpers/nonIterableRest.js"); 228 | 229 | function _slicedToArray(arr, i) { 230 | return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || unsupportedIterableToArray(arr, i) || nonIterableRest(); 231 | } 232 | 233 | module.exports = _slicedToArray; 234 | 235 | /***/ }), 236 | 237 | /***/ "./node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js": 238 | /*!***************************************************************************!*\ 239 | !*** ./node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js ***! 240 | \***************************************************************************/ 241 | /*! no static exports found */ 242 | /***/ (function(module, exports, __webpack_require__) { 243 | 244 | var arrayLikeToArray = __webpack_require__(/*! ./arrayLikeToArray */ "./node_modules/@babel/runtime/helpers/arrayLikeToArray.js"); 245 | 246 | function _unsupportedIterableToArray(o, minLen) { 247 | if (!o) return; 248 | if (typeof o === "string") return arrayLikeToArray(o, minLen); 249 | var n = Object.prototype.toString.call(o).slice(8, -1); 250 | if (n === "Object" && o.constructor) n = o.constructor.name; 251 | if (n === "Map" || n === "Set") return Array.from(o); 252 | if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen); 253 | } 254 | 255 | module.exports = _unsupportedIterableToArray; 256 | 257 | /***/ }), 258 | 259 | /***/ "./src/constants.ts": 260 | /*!**************************!*\ 261 | !*** ./src/constants.ts ***! 262 | \**************************/ 263 | /*! exports provided: DIST */ 264 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 265 | 266 | "use strict"; 267 | __webpack_require__.r(__webpack_exports__); 268 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DIST", function() { return DIST; }); 269 | var DIST = 6; 270 | 271 | /***/ }), 272 | 273 | /***/ "./src/index.less": 274 | /*!************************!*\ 275 | !*** ./src/index.less ***! 276 | \************************/ 277 | /*! no static exports found */ 278 | /***/ (function(module, exports, __webpack_require__) { 279 | 280 | // extracted by mini-css-extract-plugin 281 | 282 | /***/ }), 283 | 284 | /***/ "./src/index.ts": 285 | /*!**********************!*\ 286 | !*** ./src/index.ts ***! 287 | \**********************/ 288 | /*! exports provided: moveByDom, resizeByDom, initLine */ 289 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 290 | 291 | "use strict"; 292 | __webpack_require__.r(__webpack_exports__); 293 | /* harmony import */ var _move__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./move */ "./src/move.ts"); 294 | /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "moveByDom", function() { return _move__WEBPACK_IMPORTED_MODULE_0__["moveByDom"]; }); 295 | 296 | /* harmony import */ var _resize__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./resize */ "./src/resize.ts"); 297 | /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "resizeByDom", function() { return _resize__WEBPACK_IMPORTED_MODULE_1__["resizeByDom"]; }); 298 | 299 | /* harmony import */ var _lines_store__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lines/store */ "./src/lines/store.ts"); 300 | /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "initLine", function() { return _lines_store__WEBPACK_IMPORTED_MODULE_2__["initLine"]; }); 301 | 302 | /* harmony import */ var _index_less__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./index.less */ "./src/index.less"); 303 | /* harmony import */ var _index_less__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_index_less__WEBPACK_IMPORTED_MODULE_3__); 304 | 305 | 306 | 307 | 308 | 309 | 310 | /***/ }), 311 | 312 | /***/ "./src/lines/align.ts": 313 | /*!****************************!*\ 314 | !*** ./src/lines/align.ts ***! 315 | \****************************/ 316 | /*! exports provided: showAlignLine, hideAlignLine */ 317 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 318 | 319 | "use strict"; 320 | __webpack_require__.r(__webpack_exports__); 321 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "showAlignLine", function() { return showAlignLine; }); 322 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hideAlignLine", function() { return hideAlignLine; }); 323 | /* harmony import */ var _babel_runtime_helpers_defineProperty__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/defineProperty */ "./node_modules/@babel/runtime/helpers/defineProperty.js"); 324 | /* harmony import */ var _babel_runtime_helpers_defineProperty__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_defineProperty__WEBPACK_IMPORTED_MODULE_0__); 325 | /* harmony import */ var _store__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./store */ "./src/lines/store.ts"); 326 | /* harmony import */ var _lib__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lib */ "./src/lines/lib.ts"); 327 | 328 | 329 | function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } 330 | 331 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _babel_runtime_helpers_defineProperty__WEBPACK_IMPORTED_MODULE_0___default()(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } 332 | 333 | /** 334 | * 对齐线 335 | */ 336 | 337 | 338 | /** 339 | * 340 | * @param {string} direction 方向,v垂直方向,h水平方向 341 | * @param {*} top 342 | * @param {*} left 343 | * @param {*} height 344 | * @param {*} width 345 | */ 346 | 347 | function getNearLine(direction, line) { 348 | // 获取两个方向的线数据 349 | // let line = calcLines(top, left, height, width); 350 | if (direction === 'v') { 351 | if (_store__WEBPACK_IMPORTED_MODULE_1__["Lines"].vLines.length == 0) { 352 | return; 353 | } 354 | 355 | if (line.v.length == 0) { 356 | return; 357 | } 358 | 359 | var nearLines = line.v.map(function (item) { 360 | return Object(_lib__WEBPACK_IMPORTED_MODULE_2__["findLine"])(item, _store__WEBPACK_IMPORTED_MODULE_1__["Lines"].vLines); 361 | }).map(function (item, i) { 362 | return _objectSpread({ 363 | val: Math.abs(item.pos - line.v[i].pos), 364 | from: line.v[i] 365 | }, item); 366 | }).sort(function (a, b) { 367 | return a.val - b.val; 368 | }); 369 | return nearLines.map(function (tarLine, index) { 370 | var display = tarLine.val === 0; 371 | 372 | if (index === 0 && tarLine.val > 0) { 373 | display = true; 374 | } 375 | 376 | return { 377 | type: tarLine.type, 378 | display: display, 379 | pos: tarLine.pos, 380 | start: Math.min(tarLine.from.start, tarLine.start), 381 | end: Math.max(tarLine.from.end, tarLine.end), 382 | from: tarLine.from 383 | }; 384 | }); 385 | } else { 386 | if (_store__WEBPACK_IMPORTED_MODULE_1__["Lines"].hLines.length == 0) { 387 | return; 388 | } 389 | 390 | if (line.h.length == 0) { 391 | return; 392 | } 393 | 394 | var _nearLines = line.h.map(function (item) { 395 | return Object(_lib__WEBPACK_IMPORTED_MODULE_2__["findLine"])(item, _store__WEBPACK_IMPORTED_MODULE_1__["Lines"].hLines); 396 | }).map(function (item, i) { 397 | return _objectSpread({ 398 | val: Math.abs(item.pos - line.h[i].pos), 399 | from: line.h[i] 400 | }, item); 401 | }).sort(function (a, b) { 402 | return a.val - b.val; 403 | }); 404 | 405 | return _nearLines.map(function (tarLine, index) { 406 | var display = tarLine.val === 0; 407 | 408 | if (index === 0 && tarLine.val > 0) { 409 | display = true; 410 | } 411 | 412 | return { 413 | type: tarLine.type, 414 | display: display, 415 | pos: tarLine.pos, 416 | start: Math.min(tarLine.from.start, tarLine.start), 417 | end: Math.max(tarLine.from.end, tarLine.end), 418 | from: tarLine.from 419 | }; 420 | }); // return [] 421 | } 422 | } 423 | 424 | function createSpaceLineRoot() { 425 | var id = "view__align-line-root"; 426 | var dom = document.getElementById(id); 427 | 428 | if (!dom) { 429 | var div = document.createElement('div'); 430 | div.id = id; 431 | document.body.appendChild(div); 432 | dom = div; 433 | } 434 | 435 | return dom; 436 | } 437 | 438 | function createVLines(key, _ref, offsetTop, offsetLeft) { 439 | var pos = _ref.pos, 440 | start = _ref.start, 441 | end = _ref.end, 442 | display = _ref.display; 443 | var id = 'view__v-line_' + key; 444 | var cls = 'view__v-line'; 445 | var dom = document.getElementById(id); 446 | var root = createSpaceLineRoot(); 447 | 448 | if (!dom) { 449 | var div = document.createElement('div'); 450 | div.id = id; 451 | div.className = cls; 452 | root.appendChild(div); 453 | dom = div; 454 | } 455 | 456 | dom.style.display = display ? 'block' : 'none'; 457 | dom.style.left = "".concat(pos + offsetLeft, "px"); 458 | dom.style.top = "".concat(start + offsetTop, "px"); 459 | dom.style.height = "".concat(end - start, "px"); 460 | } 461 | 462 | function createHLines(key, _ref2, offsetTop, offsetLeft) { 463 | var pos = _ref2.pos, 464 | start = _ref2.start, 465 | end = _ref2.end, 466 | display = _ref2.display; 467 | var id = 'view__h-line_' + key; 468 | var cls = 'view__h-line'; 469 | var dom = document.getElementById(id); 470 | var root = createSpaceLineRoot(); 471 | 472 | if (!dom) { 473 | var div = document.createElement('div'); 474 | div.id = id; 475 | div.className = cls; 476 | root.appendChild(div); 477 | dom = div; 478 | } 479 | 480 | dom.style.display = display ? 'block' : 'none'; 481 | dom.style.left = "".concat(start + offsetLeft, "px"); 482 | dom.style.top = "".concat(pos + offsetTop, "px"); 483 | dom.style.width = "".concat(end - start, "px"); 484 | } 485 | /** 486 | * 显示对齐线 487 | * @param {*} line 488 | * @param {*} offsetTop 489 | * @param {*} offsetLeft 490 | */ 491 | 492 | 493 | function showAlignLine(line, offsetTop, offsetLeft) { 494 | var vResult = getNearLine('v', line); 495 | var hResult = getNearLine('h', line); 496 | 497 | if (vResult && vResult.length > 0) { 498 | // console.log(vResult) 499 | vResult.forEach(function (item, index) { 500 | createVLines(index, item, offsetTop, offsetLeft); 501 | }); 502 | } 503 | 504 | if (hResult && hResult.length > 0) { 505 | // console.log(hResult) 506 | hResult.forEach(function (item, index) { 507 | createHLines(index, item, offsetTop, offsetLeft); 508 | }); 509 | } 510 | 511 | if (!vResult && !hResult) { 512 | return null; 513 | } 514 | 515 | return { 516 | vLine: vResult ? vResult.find(function (p) { 517 | return p.display; 518 | }) : null, 519 | hLine: hResult ? hResult.find(function (p) { 520 | return p.display; 521 | }) : null 522 | }; 523 | } 524 | /** 525 | * 隐藏 526 | */ 527 | 528 | var hideAlignLine = function hideAlignLine() { 529 | var root = createSpaceLineRoot(); 530 | 531 | if (root.parentNode) { 532 | root.parentNode.removeChild(root); 533 | } 534 | }; 535 | 536 | /***/ }), 537 | 538 | /***/ "./src/lines/distance.ts": 539 | /*!*******************************!*\ 540 | !*** ./src/lines/distance.ts ***! 541 | \*******************************/ 542 | /*! exports provided: showDistLine, hideDistLine */ 543 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 544 | 545 | "use strict"; 546 | __webpack_require__.r(__webpack_exports__); 547 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "showDistLine", function() { return showDistLine; }); 548 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hideDistLine", function() { return hideDistLine; }); 549 | /** 550 | * 距离线 551 | */ 552 | function createSpaceLineRoot() { 553 | var id = "view__dist-line-root"; 554 | var dom = document.getElementById(id); 555 | 556 | if (!dom) { 557 | var div = document.createElement('div'); 558 | div.id = id; 559 | document.body.appendChild(div); 560 | dom = div; 561 | } 562 | 563 | return dom; 564 | } 565 | /** 566 | * 创建距离线 567 | * @param {*} param0 568 | * @param {*} offsetTop 569 | * @param {*} offsetLeft 570 | */ 571 | 572 | 573 | function createHDistLine(_ref, offsetTop, offsetLeft) { 574 | var pos = _ref.pos, 575 | start = _ref.start, 576 | end = _ref.end; 577 | var id = 'view__h-dist-line'; 578 | var dom = document.getElementById(id); 579 | var root = createSpaceLineRoot(); 580 | 581 | if (!dom) { 582 | var div = document.createElement('div'); 583 | div.id = id; 584 | div.className = id; 585 | root.appendChild(div); 586 | dom = div; 587 | } 588 | 589 | var l = start, 590 | r = end; 591 | 592 | if (start > end) { 593 | l = end, r = start; 594 | } 595 | 596 | dom.innerHTML = "
".concat(r - l, "
"); 597 | dom.style.display = 'block'; 598 | dom.style.left = "".concat(l + offsetLeft, "px"); 599 | dom.style.top = "".concat(pos + offsetTop, "px"); 600 | dom.style.width = "".concat(Math.abs(r - l), "px"); 601 | } 602 | 603 | function createVDistLine(_ref2, offsetTop, offsetLeft) { 604 | var pos = _ref2.pos, 605 | start = _ref2.start, 606 | end = _ref2.end; 607 | var id = 'view__v-dist-line'; 608 | var dom = document.getElementById(id); 609 | var root = createSpaceLineRoot(); 610 | 611 | if (!dom) { 612 | var div = document.createElement('div'); 613 | div.id = id; 614 | div.className = id; 615 | root.appendChild(div); 616 | dom = div; 617 | } 618 | 619 | var t = start, 620 | b = end; 621 | 622 | if (start > end) { 623 | t = end, b = start; 624 | } 625 | 626 | dom.innerHTML = "
".concat(b - t, "
"); 627 | dom.style.display = 'block'; 628 | dom.style.left = "".concat(pos + offsetLeft, "px"); 629 | dom.style.top = "".concat(t + offsetTop, "px"); 630 | dom.style.height = "".concat(Math.abs(b - t), "px"); 631 | } 632 | /** 633 | * 显示距离线 634 | */ 635 | 636 | 637 | function showDistLine(direction, from, to, offsetTop, offsetLeft) { 638 | var start = from.start, 639 | end = from.end; 640 | var fromPos = from.pos, 641 | toPos = to.pos; // if (Math.abs(from.pos - to.pos) < 5) { 642 | // toPos = fromPos; 643 | // } 644 | 645 | if (direction === 'v') { 646 | var line = { 647 | start: fromPos, 648 | end: toPos, 649 | pos: (end + start) / 2 650 | }; // console.log(line) 651 | 652 | createHDistLine(line, offsetTop, offsetLeft); 653 | } else { 654 | var _line = { 655 | start: fromPos, 656 | end: toPos, 657 | pos: (end + start) / 2 658 | }; 659 | createVDistLine(_line, offsetTop, offsetLeft); 660 | } 661 | } 662 | /** 663 | * 隐藏 664 | */ 665 | 666 | var hideDistLine = function hideDistLine() { 667 | var root = createSpaceLineRoot(); 668 | 669 | if (root.parentNode) { 670 | root.parentNode.removeChild(root); 671 | } 672 | }; 673 | 674 | /***/ }), 675 | 676 | /***/ "./src/lines/label.ts": 677 | /*!****************************!*\ 678 | !*** ./src/lines/label.ts ***! 679 | \****************************/ 680 | /*! exports provided: hideLabel, showLabel */ 681 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 682 | 683 | "use strict"; 684 | __webpack_require__.r(__webpack_exports__); 685 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hideLabel", function() { return hideLabel; }); 686 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "showLabel", function() { return showLabel; }); 687 | /** 688 | * size标签 689 | */ 690 | 691 | /** 692 | * 隐藏label 693 | * @param {*} id 694 | */ 695 | var hideLabel = function hideLabel() { 696 | var id = 'view__resize-label'; 697 | var dom = document.getElementById(id); 698 | 699 | if (!dom) { 700 | return; 701 | } 702 | 703 | if (dom.parentNode) { 704 | dom.parentNode.removeChild(dom); 705 | } 706 | }; 707 | function showLabel(view, content) { 708 | var id = 'view__resize-label'; 709 | var rect = view.getBoundingClientRect(); 710 | var dom = document.getElementById(id); 711 | 712 | if (!dom) { 713 | var div = document.createElement('div'); 714 | div.id = id; 715 | div.className = id; 716 | document.body.appendChild(div); 717 | dom = div; 718 | } 719 | 720 | dom.style.display = 'block'; 721 | dom.style.top = "".concat(rect.bottom + 5, "px"); 722 | dom.style.left = "".concat(rect.left + rect.width / 2, "px"); 723 | dom.innerHTML = content; 724 | } 725 | 726 | /***/ }), 727 | 728 | /***/ "./src/lines/lib.ts": 729 | /*!**************************!*\ 730 | !*** ./src/lines/lib.ts ***! 731 | \**************************/ 732 | /*! exports provided: findLine, calcLines, calcDirectionCreator, calcDirection, debounce, throttle */ 733 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 734 | 735 | "use strict"; 736 | __webpack_require__.r(__webpack_exports__); 737 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "findLine", function() { return findLine; }); 738 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "calcLines", function() { return calcLines; }); 739 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "calcDirectionCreator", function() { return calcDirectionCreator; }); 740 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "calcDirection", function() { return calcDirection; }); 741 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return debounce; }); 742 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return throttle; }); 743 | /** 744 | * 寻找和tarLine邻近的线 745 | * @param {*} tarLine 源线 746 | * @param {*} lines 线的数组 747 | */ 748 | function findLine(tarLine, lines) { 749 | // 可以使用二分查找 750 | var l = 0, 751 | r = lines.length - 1; 752 | 753 | while (l <= r) { 754 | var i = Math.round(r - (r - l) / 2); 755 | 756 | if (tarLine.pos < lines[i].pos) { 757 | r = i - 1; 758 | } else if (tarLine.pos > lines[i].pos) { 759 | l = i + 1; 760 | } else { 761 | return lines[i]; 762 | } 763 | } 764 | 765 | if (l == r) { 766 | return lines[l]; 767 | } 768 | 769 | if (l > r) { 770 | if (l >= lines.length) { 771 | return lines[r]; 772 | } 773 | 774 | if (r < 0) { 775 | return lines[0]; 776 | } 777 | 778 | var x1 = Math.abs(lines[r].pos - tarLine.pos); 779 | var x2 = Math.abs(lines[l].pos - tarLine.pos); 780 | return x1 < x2 ? lines[r] : lines[l]; 781 | } 782 | } 783 | function calcLines(top, left, height, width) { 784 | return { 785 | v: [{ 786 | type: 'vl', 787 | pos: left, 788 | start: top, 789 | end: top + height 790 | }, { 791 | type: 'vm', 792 | pos: left + width / 2, 793 | start: top, 794 | end: top + height 795 | }, { 796 | type: 'vr', 797 | pos: left + width, 798 | start: top, 799 | end: top + height 800 | }], 801 | h: [{ 802 | type: 'ht', 803 | pos: top, 804 | start: left, 805 | end: left + width 806 | }, { 807 | type: 'hm', 808 | pos: top + height / 2, 809 | start: left, 810 | end: left + width 811 | }, { 812 | type: 'hb', 813 | pos: top + height, 814 | start: left, 815 | end: left + width 816 | }] 817 | }; 818 | } 819 | function calcDirectionCreator() { 820 | var lastTop, lastLeft, lastDirection; 821 | return function (top, left) { 822 | if (!lastTop) { 823 | lastTop = top; 824 | } 825 | 826 | if (!lastLeft) { 827 | lastLeft = left; 828 | } 829 | 830 | var direction; // console.log(top, left, lastTop, lastLeft) 831 | 832 | var topOffset = Math.abs(top - lastTop), 833 | leftOffset = Math.abs(left - lastLeft); 834 | 835 | if (topOffset > leftOffset) { 836 | direction = 'v'; 837 | } else if (topOffset < leftOffset) { 838 | direction = 'h'; 839 | } else { 840 | direction = lastDirection; 841 | } 842 | 843 | lastTop = top; 844 | lastLeft = left; 845 | lastDirection = direction; 846 | return direction; 847 | }; 848 | } 849 | var calcDirection = calcDirectionCreator(); 850 | function debounce(fn, delay) { 851 | var timer = null; 852 | return function () { 853 | var args = arguments, 854 | context = this; 855 | 856 | if (timer) { 857 | clearTimeout(timer); 858 | timer = setTimeout(function () { 859 | fn.apply(context, args); 860 | }, delay); 861 | } else { 862 | timer = setTimeout(function () { 863 | fn.apply(context, args); 864 | }, delay); 865 | } 866 | }; 867 | } 868 | function throttle(fn, delay) { 869 | var timer = null, 870 | remaining = 0, 871 | previous = Date.now(); 872 | return function () { 873 | var args = arguments, 874 | context = this; 875 | var now = Date.now(); 876 | remaining = now - previous; 877 | 878 | if (remaining >= delay) { 879 | if (timer) { 880 | clearTimeout(timer); 881 | } 882 | 883 | fn.apply(context, args); 884 | previous = now; 885 | } else { 886 | if (!timer) { 887 | timer = setTimeout(function () { 888 | fn.apply(context, args); 889 | previous = Date.now(); 890 | }, delay - remaining); 891 | } 892 | } 893 | }; 894 | } 895 | 896 | /***/ }), 897 | 898 | /***/ "./src/lines/space.ts": 899 | /*!****************************!*\ 900 | !*** ./src/lines/space.ts ***! 901 | \****************************/ 902 | /*! exports provided: createVSpaceLines, createHSpaceLines, showSpaceLine, calcSpaceLineList, hideSpaceLine */ 903 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 904 | 905 | "use strict"; 906 | __webpack_require__.r(__webpack_exports__); 907 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createVSpaceLines", function() { return createVSpaceLines; }); 908 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createHSpaceLines", function() { return createHSpaceLines; }); 909 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "showSpaceLine", function() { return showSpaceLine; }); 910 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "calcSpaceLineList", function() { return calcSpaceLineList; }); 911 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hideSpaceLine", function() { return hideSpaceLine; }); 912 | /* harmony import */ var _babel_runtime_helpers_slicedToArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/slicedToArray */ "./node_modules/@babel/runtime/helpers/slicedToArray.js"); 913 | /* harmony import */ var _babel_runtime_helpers_slicedToArray__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_slicedToArray__WEBPACK_IMPORTED_MODULE_0__); 914 | /* harmony import */ var _store__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./store */ "./src/lines/store.ts"); 915 | 916 | 917 | /** 918 | * 间距块 919 | */ 920 | 921 | 922 | function createSpaceLineRoot(direction) { 923 | var id = "view__".concat(direction, "-dist-line-root"); 924 | var dom = document.getElementById(id); 925 | 926 | if (!dom) { 927 | var div = document.createElement('div'); 928 | div.id = id; 929 | document.body.appendChild(div); 930 | dom = div; 931 | } 932 | 933 | return dom; 934 | } 935 | 936 | function createHSpaceLine(_ref, offsetTop, offsetLeft) { 937 | var pos = _ref.pos, 938 | start = _ref.start, 939 | end = _ref.end, 940 | height = _ref.height; 941 | var id = 'view__h-space-line_' + start; 942 | var root = createSpaceLineRoot('h'); 943 | var dom = document.getElementById(id); 944 | 945 | if (!dom) { 946 | var div = document.createElement('div'); 947 | div.id = id; 948 | div.className = 'view__h-space-line'; 949 | root.appendChild(div); 950 | dom = div; 951 | } 952 | 953 | var l = start, 954 | r = end; 955 | 956 | if (start > end) { 957 | l = end, r = start; 958 | } 959 | 960 | dom.innerHTML = ""; 961 | dom.style.display = 'block'; 962 | dom.style.left = "".concat(l + offsetLeft, "px"); 963 | dom.style.top = "".concat(pos + offsetTop, "px"); 964 | dom.style.width = "".concat(Math.abs(r - l), "px"); 965 | dom.style.height = "".concat(height, "px"); 966 | } 967 | 968 | function createVSpaceLine(_ref2, offsetTop, offsetLeft) { 969 | var pos = _ref2.pos, 970 | start = _ref2.start, 971 | end = _ref2.end, 972 | width = _ref2.width; 973 | var id = 'view__v-space-line_' + start; 974 | var root = createSpaceLineRoot('v'); 975 | var dom = document.getElementById(id); 976 | 977 | if (!dom) { 978 | var div = document.createElement('div'); 979 | div.id = id; 980 | div.className = 'view__v-space-line'; 981 | root.appendChild(div); 982 | dom = div; 983 | } 984 | 985 | var t = start, 986 | b = end; 987 | 988 | if (start > end) { 989 | t = end, b = start; 990 | } 991 | 992 | dom.innerHTML = ""; 993 | dom.style.display = 'block'; 994 | dom.style.left = "".concat(pos + offsetLeft, "px"); 995 | dom.style.top = "".concat(t + offsetTop, "px"); 996 | dom.style.width = "".concat(width, "px"); 997 | dom.style.height = "".concat(Math.abs(b - t), "px"); 998 | } 999 | 1000 | function createVSpaceLines() { 1001 | var lineIndexPairs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; 1002 | var offsetTop = arguments.length > 1 ? arguments[1] : undefined; 1003 | var offsetLeft = arguments.length > 2 ? arguments[2] : undefined; 1004 | hideSpaceLine('v'); 1005 | lineIndexPairs.forEach(function (item) { 1006 | var from = item.from, 1007 | to = item.to; 1008 | var l1 = from; 1009 | var l2 = to; // { pos, start, end }, offsetTop, offsetLeft 1010 | 1011 | var t = Math.min(l1.start, l2.start, l1.end, l2.end); 1012 | var b = Math.max(l1.start, l2.start, l1.end, l2.end); 1013 | var line = { 1014 | pos: (l1.start + l1.end) / 2, 1015 | start: l1.pos, 1016 | end: l2.pos, 1017 | height: b - t 1018 | }; 1019 | createHSpaceLine(line, offsetTop, offsetLeft); 1020 | }); 1021 | } 1022 | function createHSpaceLines() { 1023 | var lineIndexPairs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; 1024 | var offsetTop = arguments.length > 1 ? arguments[1] : undefined; 1025 | var offsetLeft = arguments.length > 2 ? arguments[2] : undefined; 1026 | hideSpaceLine('h'); 1027 | lineIndexPairs.forEach(function (item) { 1028 | var from = item.from, 1029 | to = item.to; 1030 | var l1 = from; 1031 | var l2 = to; // { pos, start, end }, offsetTop, offsetLeft 1032 | 1033 | var l = Math.min(l1.start, l2.start, l1.end, l2.end); 1034 | var r = Math.max(l1.start, l2.start, l1.end, l2.end); 1035 | var line = { 1036 | pos: (l1.start + l1.end) / 2, 1037 | start: l1.pos, 1038 | end: l2.pos, 1039 | width: r - l 1040 | }; 1041 | createVSpaceLine(line, offsetTop, offsetLeft); 1042 | }); 1043 | } 1044 | 1045 | function calcAllSpaceLines(direction) { 1046 | var allLines = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; 1047 | var tarLines = arguments.length > 2 ? arguments[2] : undefined; 1048 | // 计算vl,vr的间距,按顺序查找,确保vl>vr,连续的vl>vr的线 1049 | var i = 0, 1050 | j = 1, 1051 | results = []; 1052 | var l1type = direction === 'v' ? 'vr' : 'hb'; 1053 | var l2type = direction === 'v' ? 'vl' : 'ht'; 1054 | var mid = (tarLines[0].end - tarLines[0].start) / 2 + tarLines[0].start; 1055 | var lines = allLines.concat(tarLines).filter(function (line) { 1056 | // 父容器的线去除 1057 | if (line.start === 0) { 1058 | return false; 1059 | } 1060 | 1061 | if (line.type === 'vm' || line.type === 'hm') { 1062 | return false; 1063 | } 1064 | 1065 | if (line.start < mid && line.end > mid) { 1066 | return true; 1067 | } 1068 | 1069 | return false; 1070 | }).sort(function (a, b) { 1071 | return a.pos - b.pos; 1072 | }); 1073 | 1074 | while (j < lines.length) { 1075 | if (lines[i].type === l1type) { 1076 | if (lines[j].type !== l2type) { 1077 | j++; 1078 | continue; 1079 | } 1080 | 1081 | if (lines[i].pos <= tarLines[0].pos && lines[j].pos >= tarLines[2].pos) { 1082 | i++; 1083 | continue; 1084 | } // i 是vr j是vl 1085 | 1086 | 1087 | results.push([i, j]); 1088 | } 1089 | 1090 | i++; 1091 | j++; 1092 | } 1093 | 1094 | return results.map(function (item) { 1095 | var _item = _babel_runtime_helpers_slicedToArray__WEBPACK_IMPORTED_MODULE_0___default()(item, 2), 1096 | i = _item[0], 1097 | j = _item[1]; 1098 | 1099 | return { 1100 | from: lines[i], 1101 | to: lines[j], 1102 | dist: lines[j].pos - lines[i].pos 1103 | }; 1104 | }); 1105 | } 1106 | 1107 | function findTarSpaceLine(spaceLines, tarLines) { 1108 | var left = tarLines[0]; 1109 | var right = tarLines[2]; 1110 | var leftTar, rightTar; 1111 | 1112 | if (spaceLines.length <= 1) { 1113 | return []; 1114 | } 1115 | 1116 | spaceLines.forEach(function (line, index) { 1117 | var from = line.from, 1118 | to = line.to; 1119 | 1120 | if (left.pos === to.pos) { 1121 | if (index < 1) { 1122 | return; 1123 | } 1124 | 1125 | var _line = spaceLines[index - 1]; 1126 | var dist = _line.dist; 1127 | leftTar = from.pos + dist; 1128 | } 1129 | 1130 | if (right.pos === from.pos) { 1131 | if (index >= spaceLines.length - 1) { 1132 | return; 1133 | } 1134 | 1135 | var _line2 = spaceLines[index + 1]; 1136 | var _dist = _line2.dist; 1137 | rightTar = to.pos - _dist; 1138 | } 1139 | }); 1140 | return [leftTar, rightTar]; 1141 | } 1142 | /** 1143 | * 1144 | *显示间距线,返回最近的间距块以及目标吸附位置 1145 | */ 1146 | 1147 | 1148 | var showSpaceLine = function showSpaceLine(direction, line, offsetTop, offsetLeft) { 1149 | //判断是横向还是纵向, 1150 | //计算组件的间距,显示同一方向的间距, 1151 | // let results; 1152 | if (direction === 'h') { 1153 | var spaceLines = calcAllSpaceLines('h', _store__WEBPACK_IMPORTED_MODULE_1__["Lines"].hLines, line.h); 1154 | createHSpaceLines(spaceLines, offsetTop, offsetLeft); 1155 | } else { 1156 | var _spaceLines = calcAllSpaceLines('v', _store__WEBPACK_IMPORTED_MODULE_1__["Lines"].vLines, line.v); 1157 | 1158 | createVSpaceLines(_spaceLines, offsetTop, offsetLeft); 1159 | } 1160 | }; 1161 | var calcSpaceLineList = function calcSpaceLineList(direction, line) { 1162 | var results, spaceLines; 1163 | 1164 | if (direction === 'h') { 1165 | spaceLines = calcAllSpaceLines('h', _store__WEBPACK_IMPORTED_MODULE_1__["Lines"].hLines, line.h); 1166 | results = findTarSpaceLine(spaceLines, line.h); 1167 | } else { 1168 | spaceLines = calcAllSpaceLines('v', _store__WEBPACK_IMPORTED_MODULE_1__["Lines"].vLines, line.v); 1169 | results = findTarSpaceLine(spaceLines, line.v); 1170 | } 1171 | 1172 | return results; 1173 | }; 1174 | /** 1175 | * 隐藏 1176 | * @param {string} direction 方向 1177 | */ 1178 | 1179 | var hideSpaceLine = function hideSpaceLine(direction) { 1180 | var hdom = document.getElementById("view__".concat(direction, "-dist-line-root")); 1181 | 1182 | if (!hdom) { 1183 | return; 1184 | } 1185 | 1186 | hdom.remove(); 1187 | }; 1188 | 1189 | /***/ }), 1190 | 1191 | /***/ "./src/lines/store.ts": 1192 | /*!****************************!*\ 1193 | !*** ./src/lines/store.ts ***! 1194 | \****************************/ 1195 | /*! exports provided: Lines, initLine */ 1196 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 1197 | 1198 | "use strict"; 1199 | __webpack_require__.r(__webpack_exports__); 1200 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Lines", function() { return Lines; }); 1201 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "initLine", function() { return initLine; }); 1202 | /* harmony import */ var _lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib */ "./src/lines/lib.ts"); 1203 | /** 1204 | * 线的存储 1205 | */ 1206 | 1207 | /** 1208 | * line 集合,{pos,type,start,end} 1209 | */ 1210 | 1211 | var Lines = { 1212 | vLines: [], 1213 | hLines: [] 1214 | }; 1215 | /** 1216 | * 初始化容器内的线数据 1217 | */ 1218 | 1219 | function initLine(childs, dragDom) { 1220 | var vLines = [], 1221 | hLines = []; 1222 | 1223 | for (var i = 0; i < childs.length; i++) { 1224 | var child = childs[i]; 1225 | 1226 | if (child === dragDom) { 1227 | continue; 1228 | } 1229 | 1230 | var offsetTop = child.offsetTop, 1231 | offsetLeft = child.offsetLeft, 1232 | offsetHeight = child.offsetHeight, 1233 | offsetWidth = child.offsetWidth; 1234 | var l = Object(_lib__WEBPACK_IMPORTED_MODULE_0__["calcLines"])(offsetTop, offsetLeft, offsetHeight, offsetWidth); 1235 | vLines = vLines.concat(l.v); 1236 | hLines = hLines.concat(l.h); 1237 | } 1238 | 1239 | Lines.vLines = vLines.sort(function (a, b) { 1240 | return a.pos - b.pos; 1241 | }); 1242 | Lines.hLines = hLines.sort(function (a, b) { 1243 | return a.pos - b.pos; 1244 | }); 1245 | } 1246 | 1247 | /***/ }), 1248 | 1249 | /***/ "./src/move.ts": 1250 | /*!*********************!*\ 1251 | !*** ./src/move.ts ***! 1252 | \*********************/ 1253 | /*! exports provided: moveByDom */ 1254 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 1255 | 1256 | "use strict"; 1257 | __webpack_require__.r(__webpack_exports__); 1258 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "moveByDom", function() { return moveByDom; }); 1259 | /* harmony import */ var _babel_runtime_helpers_slicedToArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/slicedToArray */ "./node_modules/@babel/runtime/helpers/slicedToArray.js"); 1260 | /* harmony import */ var _babel_runtime_helpers_slicedToArray__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_slicedToArray__WEBPACK_IMPORTED_MODULE_0__); 1261 | /* harmony import */ var _lines_lib__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lines/lib */ "./src/lines/lib.ts"); 1262 | /* harmony import */ var _lines_align__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lines/align */ "./src/lines/align.ts"); 1263 | /* harmony import */ var _lines_distance__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./lines/distance */ "./src/lines/distance.ts"); 1264 | /* harmony import */ var _lines_space__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./lines/space */ "./src/lines/space.ts"); 1265 | /* harmony import */ var _lines_label__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./lines/label */ "./src/lines/label.ts"); 1266 | /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./constants */ "./src/constants.ts"); 1267 | 1268 | 1269 | 1270 | 1271 | 1272 | 1273 | 1274 | 1275 | function calcTarPos(top, left, height, width, vLine, hLine) { 1276 | var tarLeft = left, 1277 | tarTop = top; 1278 | 1279 | if (!vLine) { 1280 | tarLeft = left; 1281 | } else if (vLine.from.pos < vLine.pos + _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"] && vLine.from.pos > vLine.pos - _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"]) { 1282 | if (vLine.from.type === 'vl') { 1283 | tarLeft = vLine.pos; 1284 | } else if (vLine.from.type === 'vm') { 1285 | tarLeft = vLine.pos - width / 2; 1286 | } else if (vLine.from.type === 'vr') { 1287 | tarLeft = vLine.pos - width; 1288 | } 1289 | } 1290 | 1291 | if (!hLine) { 1292 | tarTop = top; 1293 | } else if (hLine.from.pos < hLine.pos + _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"] && hLine.from.pos > hLine.pos - _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"]) { 1294 | if (hLine.from.type === 'ht') { 1295 | tarTop = hLine.pos; 1296 | } else if (hLine.from.type === 'hm') { 1297 | tarTop = hLine.pos - height / 2; 1298 | } else if (hLine.from.type === 'hb') { 1299 | tarTop = hLine.pos - height; 1300 | } 1301 | } 1302 | 1303 | return { 1304 | top: tarTop, 1305 | left: tarLeft 1306 | }; 1307 | } 1308 | 1309 | function showSapceLines(direction, tarLine, _ref, offsetTop, offsetLeft) { 1310 | var top = _ref.top, 1311 | left = _ref.left, 1312 | width = _ref.width, 1313 | height = _ref.height; 1314 | var tarLeft = left; 1315 | var tarTop = top; 1316 | 1317 | if (direction == 'h') { 1318 | var _calcSpaceLineList = Object(_lines_space__WEBPACK_IMPORTED_MODULE_4__["calcSpaceLineList"])('v', tarLine), 1319 | _calcSpaceLineList2 = _babel_runtime_helpers_slicedToArray__WEBPACK_IMPORTED_MODULE_0___default()(_calcSpaceLineList, 2), 1320 | spaceLeft = _calcSpaceLineList2[0], 1321 | spaceRight = _calcSpaceLineList2[1]; 1322 | 1323 | if (tarLeft > spaceLeft - _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"] && tarLeft < spaceLeft + _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"]) { 1324 | tarLeft = spaceLeft; 1325 | Object(_lines_space__WEBPACK_IMPORTED_MODULE_4__["showSpaceLine"])('v', Object(_lines_lib__WEBPACK_IMPORTED_MODULE_1__["calcLines"])(tarTop, tarLeft, height, width), offsetTop, offsetLeft); 1326 | } 1327 | 1328 | if (tarLeft > spaceRight - width - _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"] && tarLeft < spaceRight - width + _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"]) { 1329 | tarLeft = spaceRight - width; 1330 | Object(_lines_space__WEBPACK_IMPORTED_MODULE_4__["showSpaceLine"])('v', Object(_lines_lib__WEBPACK_IMPORTED_MODULE_1__["calcLines"])(tarTop, tarLeft, height, width), offsetTop, offsetLeft); 1331 | } 1332 | } else { 1333 | var _calcSpaceLineList3 = Object(_lines_space__WEBPACK_IMPORTED_MODULE_4__["calcSpaceLineList"])('h', tarLine), 1334 | _calcSpaceLineList4 = _babel_runtime_helpers_slicedToArray__WEBPACK_IMPORTED_MODULE_0___default()(_calcSpaceLineList3, 2), 1335 | spaceTop = _calcSpaceLineList4[0], 1336 | spaceBottom = _calcSpaceLineList4[1]; 1337 | 1338 | if (tarTop > spaceTop - _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"] && tarTop < spaceTop + _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"]) { 1339 | tarTop = spaceTop; 1340 | Object(_lines_space__WEBPACK_IMPORTED_MODULE_4__["showSpaceLine"])('h', Object(_lines_lib__WEBPACK_IMPORTED_MODULE_1__["calcLines"])(tarTop, tarLeft, height, width), offsetTop, offsetLeft); 1341 | } 1342 | 1343 | if (tarTop > spaceBottom - height - _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"] && tarTop < spaceBottom - height + _constants__WEBPACK_IMPORTED_MODULE_6__["DIST"]) { 1344 | tarTop = spaceBottom - height; 1345 | Object(_lines_space__WEBPACK_IMPORTED_MODULE_4__["showSpaceLine"])('h', Object(_lines_lib__WEBPACK_IMPORTED_MODULE_1__["calcLines"])(tarTop, tarLeft, height, width), offsetTop, offsetLeft); 1346 | } 1347 | } 1348 | 1349 | return { 1350 | top: tarTop, 1351 | left: tarLeft 1352 | }; 1353 | } 1354 | 1355 | function showAlignLines(tarLine, _ref2, offsetTop, offsetLeft) { 1356 | var top = _ref2.top, 1357 | left = _ref2.left, 1358 | width = _ref2.width, 1359 | height = _ref2.height; 1360 | var nearLine = Object(_lines_align__WEBPACK_IMPORTED_MODULE_2__["showAlignLine"])(tarLine, offsetTop, offsetLeft); 1361 | var tarLeft = left, 1362 | tarTop = top; 1363 | 1364 | if (nearLine) { 1365 | var vLine = nearLine.vLine, 1366 | hLine = nearLine.hLine; 1367 | var tarPos = calcTarPos(top, left, height, width, vLine, hLine); 1368 | tarLeft = tarPos.left; 1369 | tarTop = tarPos.top; 1370 | 1371 | if (top != tarTop || left != tarLeft) { 1372 | Object(_lines_align__WEBPACK_IMPORTED_MODULE_2__["showAlignLine"])(Object(_lines_lib__WEBPACK_IMPORTED_MODULE_1__["calcLines"])(tarTop, tarLeft, height, width), offsetTop, offsetLeft); 1373 | } 1374 | 1375 | var fromVLine = vLine.from; 1376 | var fromHLine = hLine.from; 1377 | var map = { 1378 | 'vl': 0, 1379 | 'vm': 1, 1380 | 'vr': 2, 1381 | 'ht': 0, 1382 | 'hm': 1, 1383 | 'hb': 2 1384 | }; 1385 | 1386 | if (tarLeft != left || tarTop != top) { 1387 | var newLine = Object(_lines_lib__WEBPACK_IMPORTED_MODULE_1__["calcLines"])(tarTop, tarLeft, height, width); 1388 | fromVLine = newLine.v[map[fromVLine.type]]; 1389 | fromHLine = newLine.h[map[fromHLine.type]]; 1390 | } 1391 | 1392 | Object(_lines_distance__WEBPACK_IMPORTED_MODULE_3__["showDistLine"])('v', fromVLine, vLine, offsetTop, offsetLeft); 1393 | Object(_lines_distance__WEBPACK_IMPORTED_MODULE_3__["showDistLine"])('h', fromHLine, hLine, offsetTop, offsetLeft); 1394 | } 1395 | 1396 | return { 1397 | top: tarTop, 1398 | left: tarLeft 1399 | }; 1400 | } 1401 | 1402 | function hideLines() { 1403 | Object(_lines_align__WEBPACK_IMPORTED_MODULE_2__["hideAlignLine"])(); 1404 | Object(_lines_space__WEBPACK_IMPORTED_MODULE_4__["hideSpaceLine"])('h'); 1405 | Object(_lines_space__WEBPACK_IMPORTED_MODULE_4__["hideSpaceLine"])('v'); 1406 | Object(_lines_distance__WEBPACK_IMPORTED_MODULE_3__["hideDistLine"])(); 1407 | Object(_lines_label__WEBPACK_IMPORTED_MODULE_5__["hideLabel"])(); 1408 | } 1409 | 1410 | var moveDeb = Object(_lines_lib__WEBPACK_IMPORTED_MODULE_1__["debounce"])(function (cb) { 1411 | cb(); 1412 | }, 1000); 1413 | var moveByDom = function moveByDom(dom, top, left, onMoveEnd) { 1414 | if (!dom) { 1415 | return; 1416 | } 1417 | 1418 | var cotainer = dom.parentNode.getBoundingClientRect(); 1419 | var offsetTop = cotainer.top; 1420 | var offsetLeft = cotainer.left; 1421 | var rect = dom.getBoundingClientRect(); 1422 | var height = rect.height, 1423 | width = rect.width; 1424 | var direction = Object(_lines_lib__WEBPACK_IMPORTED_MODULE_1__["calcDirection"])(top, left); 1425 | var tarLine = Object(_lines_lib__WEBPACK_IMPORTED_MODULE_1__["calcLines"])(top, left, height, width); 1426 | var tarLeft = left, 1427 | tarTop = top; 1428 | var tarSpaceInfo = showSapceLines(direction, tarLine, { 1429 | top: tarTop, 1430 | left: tarLeft, 1431 | width: width, 1432 | height: height 1433 | }, offsetTop, offsetLeft); 1434 | tarTop = tarSpaceInfo.top; 1435 | tarLeft = tarSpaceInfo.left; 1436 | var alignLineInfo = showAlignLines(tarLine, { 1437 | top: tarTop, 1438 | left: tarLeft, 1439 | width: width, 1440 | height: height 1441 | }, offsetTop, offsetLeft); 1442 | tarTop = alignLineInfo.top; 1443 | tarLeft = alignLineInfo.left; 1444 | dom.style.left = "".concat(tarLeft, "px"); 1445 | dom.style.top = "".concat(tarTop, "px"); 1446 | Object(_lines_label__WEBPACK_IMPORTED_MODULE_5__["showLabel"])(dom, "X:".concat(tarLeft, ",Y:").concat(tarTop)); 1447 | moveDeb(function () { 1448 | hideLines(); 1449 | 1450 | if (onMoveEnd) { 1451 | onMoveEnd(tarTop, tarLeft); 1452 | } 1453 | }); 1454 | }; 1455 | 1456 | /***/ }), 1457 | 1458 | /***/ "./src/resize.ts": 1459 | /*!***********************!*\ 1460 | !*** ./src/resize.ts ***! 1461 | \***********************/ 1462 | /*! exports provided: resizeByDom */ 1463 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 1464 | 1465 | "use strict"; 1466 | __webpack_require__.r(__webpack_exports__); 1467 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resizeByDom", function() { return resizeByDom; }); 1468 | /* harmony import */ var _lines_lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lines/lib */ "./src/lines/lib.ts"); 1469 | /* harmony import */ var _lines_align__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lines/align */ "./src/lines/align.ts"); 1470 | /* harmony import */ var _lines_distance__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lines/distance */ "./src/lines/distance.ts"); 1471 | /* harmony import */ var _lines_label__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./lines/label */ "./src/lines/label.ts"); 1472 | /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./constants */ "./src/constants.ts"); 1473 | /* harmony import */ var _lines_space__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./lines/space */ "./src/lines/space.ts"); 1474 | 1475 | 1476 | 1477 | 1478 | 1479 | 1480 | 1481 | function calcTarSize(top, left, height, width, vLine, hLine) { 1482 | var tarLeft = left, 1483 | tarTop = top, 1484 | tarHeight = height, 1485 | tarWidth = width; 1486 | 1487 | if (vLine) { 1488 | if (vLine.from.pos < vLine.pos + _constants__WEBPACK_IMPORTED_MODULE_4__["DIST"] && vLine.from.pos > vLine.pos - _constants__WEBPACK_IMPORTED_MODULE_4__["DIST"]) { 1489 | if (vLine.from.type === 'vl') { 1490 | tarLeft = vLine.pos; 1491 | tarWidth = width + (vLine.from.pos - vLine.pos); 1492 | } else if (vLine.from.type === 'vm') {// tarLeft = vLine.pos - width / 2; 1493 | } else if (vLine.from.type === 'vr') { 1494 | tarWidth = width + (vLine.pos - vLine.from.pos); 1495 | tarLeft = vLine.pos - tarWidth; 1496 | } 1497 | } 1498 | } 1499 | 1500 | if (hLine) { 1501 | if (hLine.from.pos < hLine.pos + _constants__WEBPACK_IMPORTED_MODULE_4__["DIST"] && hLine.from.pos > hLine.pos - _constants__WEBPACK_IMPORTED_MODULE_4__["DIST"]) { 1502 | if (hLine.from.type === 'ht') { 1503 | tarTop = hLine.pos; 1504 | tarHeight = height + (hLine.from.pos - hLine.pos); 1505 | } else if (hLine.from.type === 'hm') { 1506 | tarTop = hLine.pos - height / 2; 1507 | } else if (hLine.from.type === 'hb') { 1508 | tarHeight = height + (hLine.pos - hLine.from.pos); 1509 | tarTop = hLine.pos - tarHeight; 1510 | } 1511 | } 1512 | } 1513 | 1514 | return { 1515 | top: tarTop, 1516 | left: tarLeft, 1517 | height: tarHeight, 1518 | width: tarWidth 1519 | }; 1520 | } 1521 | 1522 | var DIRECTION = { 1523 | 'tc': ['ht'], 1524 | 'bc': ['hb'], 1525 | 'rc': ['vr'], 1526 | 'lc': ['vl'], 1527 | 'tl': ['ht', 'vl'], 1528 | 'tr': ['ht', 'vr'], 1529 | 'br': ['hb', 'vr'], 1530 | 'bl': ['hb', 'vl'] 1531 | }; 1532 | 1533 | function getTarLine(line) { 1534 | var include = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; 1535 | var v = line.v.filter(function (item) { 1536 | return include.indexOf(item.type) >= 0; 1537 | }); 1538 | var h = line.h.filter(function (item) { 1539 | return include.indexOf(item.type) >= 0; 1540 | }); 1541 | return { 1542 | v: v, 1543 | h: h 1544 | }; 1545 | } 1546 | 1547 | var last; 1548 | 1549 | function caclHandType(top, left, height, width) { 1550 | if (!last) { 1551 | last = { 1552 | top: top, 1553 | left: left, 1554 | height: height, 1555 | width: width 1556 | }; 1557 | return []; 1558 | } 1559 | 1560 | var lines = []; 1561 | 1562 | if (top !== last.top) { 1563 | lines.push('ht'); 1564 | } 1565 | 1566 | if (left !== last.left) { 1567 | lines.push('vl'); 1568 | } 1569 | 1570 | if (top === last.top && left === last.left && width !== last.width) { 1571 | lines.push('vr'); 1572 | } 1573 | 1574 | if (top === last.top && left === last.left && height !== last.height) { 1575 | lines.push('hb'); 1576 | } 1577 | 1578 | return lines; 1579 | } 1580 | 1581 | function hideLines() { 1582 | last = null; 1583 | Object(_lines_align__WEBPACK_IMPORTED_MODULE_1__["hideAlignLine"])(); 1584 | Object(_lines_space__WEBPACK_IMPORTED_MODULE_5__["hideSpaceLine"])('h'); 1585 | Object(_lines_space__WEBPACK_IMPORTED_MODULE_5__["hideSpaceLine"])('v'); 1586 | Object(_lines_distance__WEBPACK_IMPORTED_MODULE_2__["hideDistLine"])(); 1587 | Object(_lines_label__WEBPACK_IMPORTED_MODULE_3__["hideLabel"])(); 1588 | } 1589 | 1590 | var moveDeb = Object(_lines_lib__WEBPACK_IMPORTED_MODULE_0__["debounce"])(function (cb) { 1591 | cb(); 1592 | }, 1000); 1593 | var resizeByDom = function resizeByDom(dom, top, left, height, width, onMoveEnd) { 1594 | if (!dom) { 1595 | return; 1596 | } 1597 | 1598 | var cotainer = dom.parentNode.getBoundingClientRect(); 1599 | var offsetTop = cotainer.top; 1600 | var offsetLeft = cotainer.left; 1601 | var handType = caclHandType(top, left, height, width); 1602 | console.log(handType); 1603 | var allLines = Object(_lines_lib__WEBPACK_IMPORTED_MODULE_0__["calcLines"])(top, left, height, width); 1604 | var tarLine = getTarLine(allLines, handType); 1605 | var nearLine = Object(_lines_align__WEBPACK_IMPORTED_MODULE_1__["showAlignLine"])(tarLine, offsetTop, offsetLeft); 1606 | var tarLeft = left, 1607 | tarTop = top, 1608 | tarHeight = height, 1609 | tarWidth = width; // console.log(nearLine) 1610 | 1611 | if (nearLine) { 1612 | var vLine = nearLine.vLine, 1613 | hLine = nearLine.hLine; 1614 | var tarPos = calcTarSize(top, left, height, width, vLine, hLine); 1615 | tarLeft = tarPos.left; 1616 | tarTop = tarPos.top; 1617 | tarHeight = tarPos.height; 1618 | tarWidth = tarPos.width; 1619 | 1620 | if (left != tarLeft || top != tarTop || height != tarHeight || width != tarWidth) { 1621 | Object(_lines_align__WEBPACK_IMPORTED_MODULE_1__["showAlignLine"])(Object(_lines_lib__WEBPACK_IMPORTED_MODULE_0__["calcLines"])(tarTop, tarLeft, tarHeight, tarWidth), offsetTop, offsetLeft); 1622 | } 1623 | 1624 | var map = { 1625 | 'vl': 0, 1626 | 'vm': 1, 1627 | 'vr': 2, 1628 | 'ht': 0, 1629 | 'hm': 1, 1630 | 'hb': 2 1631 | }; 1632 | 1633 | if (vLine) { 1634 | var fromVLine = vLine.from; 1635 | 1636 | if (tarLeft != left || tarWidth != width) { 1637 | var newLine = Object(_lines_lib__WEBPACK_IMPORTED_MODULE_0__["calcLines"])(tarTop, tarLeft, tarHeight, tarWidth); 1638 | fromVLine = newLine.v[map[fromVLine.type]]; 1639 | } 1640 | 1641 | Object(_lines_distance__WEBPACK_IMPORTED_MODULE_2__["showDistLine"])('v', fromVLine, vLine, offsetTop, offsetLeft); 1642 | } 1643 | 1644 | if (hLine) { 1645 | var fromHLine = hLine.from; 1646 | 1647 | if (tarTop != top || tarHeight != height) { 1648 | var _newLine = Object(_lines_lib__WEBPACK_IMPORTED_MODULE_0__["calcLines"])(tarTop, tarLeft, tarHeight, tarWidth); 1649 | 1650 | fromHLine = _newLine.h[map[fromHLine.type]]; 1651 | } 1652 | 1653 | Object(_lines_distance__WEBPACK_IMPORTED_MODULE_2__["showDistLine"])('h', fromHLine, hLine, offsetTop, offsetLeft); 1654 | } 1655 | } 1656 | 1657 | dom.style.top = "".concat(tarTop, "px"); 1658 | dom.style.left = "".concat(tarLeft, "px"); 1659 | dom.style.height = "".concat(tarHeight, "px"); 1660 | dom.style.width = "".concat(tarWidth, "px"); // showLabel(dom, rect.bottom + 3, rect.left + rect.width / 2, `W:${width},H:${height}`); 1661 | 1662 | Object(_lines_label__WEBPACK_IMPORTED_MODULE_3__["showLabel"])(dom, "W:".concat(width, ",H:").concat(height)); 1663 | moveDeb(function () { 1664 | hideLines(); 1665 | 1666 | if (onMoveEnd) { 1667 | onMoveEnd(tarTop, tarLeft, tarHeight, tarWidth); 1668 | } 1669 | }); 1670 | }; 1671 | 1672 | /***/ }) 1673 | 1674 | /******/ }); 1675 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "view-line", 3 | "version": "1.0.0", 4 | "description": "为自由画布加入对齐线、间距块、吸附能功能", 5 | "main": "dist/view-line.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "webpack --config webpack.prod.config.js", 9 | "dev": "webpack-dev-server --config webpack.dev.config.js --open" 10 | }, 11 | "repository": {}, 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": {}, 15 | "peerDependencies": {}, 16 | "devDependencies": { 17 | "typescript": "^3.8.3", 18 | "@babel/core": "^7.2.2", 19 | "@babel/plugin-proposal-class-properties": "^7.2.3", 20 | "@babel/plugin-transform-runtime": "^7.2.0", 21 | "@babel/preset-env": "^7.2.3", 22 | "@babel/preset-typescript": "^7.9.0", 23 | "@babel/runtime": "^7.2.0", 24 | "autoprefixer": "^9.7.6", 25 | "babel-loader": "^8.1.0", 26 | "babel-plugin-external-helpers": "^6.22.0", 27 | "babel-plugin-transform-es3-member-expression-literals": "^6.22.0", 28 | "babel-plugin-transform-es3-property-literals": "^6.22.0", 29 | "css-loader": "^3.5.0", 30 | "file-loader": "^6.0.0", 31 | "html-webpack-plugin": "^4.0.4", 32 | "less": "^3.11.1", 33 | "less-loader": "^5.0.0", 34 | "mini-css-extract-plugin": "^0.9.0", 35 | "postcss-loader": "^3.0.0", 36 | "url-loader": "^4.0.0", 37 | "webpack": "^4.28.4", 38 | "webpack-bundle-analyzer": "^3.6.1", 39 | "webpack-cli": "^3.2.1", 40 | "webpack-dev-server": "^3.10.3", 41 | "webpack-merge": "^4.2.2" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /sample/index.ts: -------------------------------------------------------------------------------- 1 | import { moveByDom, resizeByDom, initLine } from '../src/index'; 2 | 3 | import $ from 'jquery'; 4 | 5 | $(function () { 6 | let isDraging = false, isResizing = false; 7 | let offset = { top: 0, left: 0 } 8 | $('.view').mousedown((e) => { 9 | let os = e.target.getBoundingClientRect(); 10 | offset.top = e.clientY - os.top; 11 | offset.left = e.clientX - os.left; 12 | isDraging = true; 13 | let childs = (e.target as HTMLElement).parentNode.querySelectorAll('.view') as any; 14 | initLine(childs, e.target); 15 | }) 16 | $('.view').mousemove((e) => { 17 | if (!isDraging) { 18 | return; 19 | } 20 | 21 | let parentRect = e.target.parentNode.getBoundingClientRect(); 22 | let left = e.clientX - offset.left - parentRect.left; 23 | let top = e.clientY - offset.top - parentRect.top; 24 | // $(e.target).css('top', top).css('left', left); 25 | moveByDom(e.target, top, left, function (top, left) { 26 | console.log(top, left); 27 | }); 28 | }) 29 | $('.view').mouseup(() => { 30 | isDraging = false; 31 | 32 | }) 33 | $('.hand').mousedown((e: Event) => { 34 | e.stopPropagation(); 35 | isResizing = true; 36 | 37 | let view = e.currentTarget.parentNode; 38 | 39 | let childs = view.parentNode.querySelectorAll('.view') as any; 40 | initLine(childs, view); 41 | 42 | let parentRect = view.parentNode.getBoundingClientRect(); 43 | let rect = view.getBoundingClientRect(); 44 | 45 | let type = e.target.className; 46 | console.log(type) 47 | 48 | $(document).on('mousemove', function (e) { 49 | e.stopPropagation(); 50 | if (!isResizing) { 51 | return; 52 | } 53 | 54 | let left, top, width, height; 55 | switch (type) { 56 | case 'br': 57 | left = rect.left - parentRect.left; 58 | top = rect.top - parentRect.top; 59 | width = e.clientX - rect.left; 60 | height = e.clientY - rect.top; 61 | break; 62 | case 'tl': 63 | left = e.clientX - parentRect.left; 64 | top = e.clientY - parentRect.top; 65 | width = rect.left + rect.width - e.clientX; 66 | height = rect.top + rect.height - e.clientY; 67 | break; 68 | case 'tr': 69 | left = rect.left - parentRect.left; 70 | top = e.clientY - parentRect.top; 71 | width = e.clientX - rect.left; 72 | height = rect.bottom - e.clientY; 73 | break; 74 | case 'bl': 75 | left = e.clientX - parentRect.left; 76 | top = rect.top - parentRect.top; 77 | width = rect.right - e.clientX; 78 | height = e.clientY- rect.top; 79 | break; 80 | } 81 | 82 | resizeByDom(view, top, left, height, width, function (top, left, height, width) { 83 | console.log(top, left, height, width); 84 | }); 85 | }) 86 | $(document).mouseup(() => { 87 | isDraging = false; 88 | $(document).off(); 89 | }) 90 | }) 91 | 92 | 93 | }) 94 | -------------------------------------------------------------------------------- /sample/move.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyin163/view-line/b4ef3293d0e8ba9edfe92a5db56983fa72b7615e/sample/move.gif -------------------------------------------------------------------------------- /sample/resize.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyin163/view-line/b4ef3293d0e8ba9edfe92a5db56983fa72b7615e/sample/resize.gif -------------------------------------------------------------------------------- /sample/tmp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 42 | 45 | 46 | 47 | 48 |
49 |
50 |
51 |
52 |
53 | 54 | 55 | 56 | 57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const DIST = 6; 2 | -------------------------------------------------------------------------------- /src/index.less: -------------------------------------------------------------------------------- 1 | .view{ 2 | &__lines{ 3 | display: none; 4 | pointer-events: none; 5 | i.line{ position: absolute;} 6 | .t{top: 0px;left: 0;right: 0;height: 0;width: auto;border: 0; border-top: 1px solid red;z-index:10 ;} 7 | .r{right: 0;top: 0;bottom: 0;width: 0;height: auto;border: 0; border-right: 1px solid red;z-index:10 ;} 8 | .b{bottom: 0;left: 0;right: 0;height: 0;width: auto;border: 0; border-bottom: 1px solid red;z-index:10 ;} 9 | .l{left: 0;top: 0;bottom: 0;height: auto;width:0;border: 0; border-left: 1px solid red;z-index:10 ;} 10 | } 11 | 12 | &__resize-label{ 13 | position: fixed; 14 | height: 24px; 15 | padding: 0 5px; 16 | display: inline-block; 17 | line-height: 24px; 18 | font-size: 12px; 19 | z-index: 999; 20 | background: #FB7055; 21 | border-radius: 3px; 22 | color: #fff; 23 | transform: translateX(-50%); 24 | // display: none; 25 | 26 | } 27 | &__v-line{ 28 | position: fixed; 29 | width: 0; 30 | border-left: 1px solid red; 31 | z-index: 999; 32 | pointer-events: none; 33 | } 34 | &__h-line{ 35 | position: fixed; 36 | height: 0; 37 | border-top: 1px solid red; 38 | z-index: 999; 39 | pointer-events: none; 40 | } 41 | &__h-dist-line{ 42 | position: fixed; 43 | height: 0; 44 | border-top: 1px dashed #adadad; 45 | z-index: 999; 46 | text-align: center; 47 | pointer-events: none; 48 | .label{ 49 | position: absolute; 50 | left: 50%; 51 | top:-4px; 52 | height: 14px; 53 | display: inline-block; 54 | line-height: 14px; 55 | text-align: center; 56 | background: #FB7055; 57 | transform: translate(-50%,-100%); 58 | color: #fff; 59 | padding: 0 5px; 60 | pointer-events: none; 61 | border-radius: 7px; 62 | } 63 | } 64 | &__v-dist-line{ 65 | 66 | position: fixed; 67 | width: 0; 68 | border-left: 1px dashed #adadad; 69 | z-index: 999; 70 | text-align: center; 71 | pointer-events: none; 72 | .label{ 73 | position: absolute; 74 | top: 50%; 75 | left: -4px; 76 | height: 14px; 77 | display: inline-block; 78 | line-height: 14px; 79 | text-align: center; 80 | background: #FB7055; 81 | transform: translate(-100%,-50%); 82 | color: #fff; 83 | padding: 0 5px; 84 | border-radius: 7px; 85 | } 86 | } 87 | &__h-space-line{ 88 | position: fixed; 89 | height: 0; 90 | z-index: 999; 91 | text-align: center; 92 | pointer-events: none; 93 | transform: translateY(-50%); 94 | background: #FB7055; 95 | opacity: 0.4; 96 | line-height: 100%; 97 | .line{ 98 | position: absolute; 99 | top:50%; 100 | left: 0; 101 | right: 0; 102 | // border-bottom: 1px dashed #fff; 103 | height: 0; 104 | pointer-events: none; 105 | } 106 | } 107 | &__v-space-line{ 108 | position: fixed; 109 | z-index: 999; 110 | text-align: center; 111 | pointer-events: none; 112 | transform: translateX(-50%); 113 | background: #FB7055; 114 | opacity: 0.4; 115 | .line{ 116 | position: absolute; 117 | left: 50%; 118 | top:0; 119 | bottom: 0; 120 | width: 0; 121 | // border-right: 1px dashed #fff; 122 | pointer-events: none; 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { moveByDom } from './move'; 2 | import { resizeByDom } from './resize'; 3 | import { initLine } from './lines/store'; 4 | 5 | import './index.less'; 6 | 7 | export { 8 | moveByDom, 9 | resizeByDom, 10 | initLine, 11 | } 12 | -------------------------------------------------------------------------------- /src/lines/align.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 对齐线 3 | */ 4 | import { Lines } from './store'; 5 | import { findLine } from './lib' 6 | 7 | /** 8 | * 9 | * @param {string} direction 方向,v垂直方向,h水平方向 10 | * @param {*} top 11 | * @param {*} left 12 | * @param {*} height 13 | * @param {*} width 14 | */ 15 | function getNearLine(direction, line) { 16 | // 获取两个方向的线数据 17 | // let line = calcLines(top, left, height, width); 18 | if (direction === 'v') { 19 | if (Lines.vLines.length == 0) { 20 | return; 21 | } 22 | if (line.v.length == 0) { 23 | return; 24 | } 25 | let nearLines = line.v.map((item) => { 26 | return findLine(item, Lines.vLines); 27 | }).map((item, i) => { 28 | return { 29 | val: Math.abs(item.pos - line.v[i].pos), 30 | from: line.v[i], 31 | ...item, 32 | } 33 | }).sort((a, b) => a.val - b.val); 34 | 35 | return nearLines.map((tarLine, index) => { 36 | let display = tarLine.val === 0; 37 | if (index === 0 && tarLine.val > 0) { 38 | display = true; 39 | } 40 | return { 41 | type: tarLine.type, 42 | display, 43 | pos: tarLine.pos, 44 | start: Math.min(tarLine.from.start, tarLine.start), 45 | end: Math.max(tarLine.from.end, tarLine.end), 46 | from: tarLine.from, 47 | } 48 | }) 49 | 50 | } else { 51 | if (Lines.hLines.length == 0) { 52 | return; 53 | } 54 | if (line.h.length == 0) { 55 | return; 56 | } 57 | let nearLines = line.h.map((item) => { 58 | return findLine(item, Lines.hLines); 59 | }).map((item, i) => { 60 | return { 61 | val: Math.abs(item.pos - line.h[i].pos), 62 | from: line.h[i], 63 | ...item, 64 | } 65 | }).sort((a, b) => a.val - b.val); 66 | 67 | return nearLines.map((tarLine, index) => { 68 | let display = tarLine.val === 0; 69 | if (index === 0 && tarLine.val > 0) { 70 | display = true; 71 | } 72 | return { 73 | type: tarLine.type, 74 | display, 75 | pos: tarLine.pos, 76 | start: Math.min(tarLine.from.start, tarLine.start), 77 | end: Math.max(tarLine.from.end, tarLine.end), 78 | from: tarLine.from, 79 | } 80 | }) 81 | // return [] 82 | } 83 | } 84 | 85 | function createSpaceLineRoot() { 86 | let id = `view__align-line-root`; 87 | let dom = document.getElementById(id); 88 | if (!dom) { 89 | let div = document.createElement('div'); 90 | div.id = id; 91 | document.body.appendChild(div); 92 | dom = div; 93 | } 94 | return dom; 95 | } 96 | 97 | 98 | function createVLines(key, { pos, start, end, display }, offsetTop, offsetLeft) { 99 | let id = 'view__v-line_' + key; 100 | let cls = 'view__v-line'; 101 | let dom = document.getElementById(id); 102 | let root = createSpaceLineRoot(); 103 | if (!dom) { 104 | let div = document.createElement('div'); 105 | div.id = id; 106 | div.className = cls; 107 | root.appendChild(div); 108 | dom = div; 109 | } 110 | dom.style.display = display ? 'block' : 'none'; 111 | dom.style.left = `${pos + offsetLeft}px`; 112 | dom.style.top = `${start + offsetTop}px`; 113 | dom.style.height = `${end - start}px`; 114 | } 115 | 116 | function createHLines(key, { pos, start, end, display }, offsetTop, offsetLeft) { 117 | let id = 'view__h-line_' + key; 118 | let cls = 'view__h-line'; 119 | let dom = document.getElementById(id); 120 | let root = createSpaceLineRoot(); 121 | if (!dom) { 122 | let div = document.createElement('div'); 123 | div.id = id; 124 | div.className = cls; 125 | root.appendChild(div); 126 | dom = div; 127 | } 128 | dom.style.display = display ? 'block' : 'none'; 129 | dom.style.left = `${start + offsetLeft}px`; 130 | dom.style.top = `${pos + offsetTop}px`; 131 | dom.style.width = `${end - start}px`; 132 | } 133 | 134 | /** 135 | * 显示对齐线 136 | * @param {*} line 137 | * @param {*} offsetTop 138 | * @param {*} offsetLeft 139 | */ 140 | export function showAlignLine(line, offsetTop, offsetLeft) { 141 | 142 | let vResult = getNearLine('v', line); 143 | let hResult = getNearLine('h', line); 144 | 145 | if (vResult && vResult.length > 0) { 146 | // console.log(vResult) 147 | vResult.forEach((item, index) => { 148 | createVLines(index, item, offsetTop, offsetLeft); 149 | }) 150 | } 151 | if (hResult && hResult.length > 0) { 152 | // console.log(hResult) 153 | hResult.forEach((item, index) => { 154 | createHLines(index, item, offsetTop, offsetLeft); 155 | }) 156 | } 157 | 158 | if (!vResult && !hResult) { 159 | return null; 160 | } 161 | return { 162 | vLine: vResult ? vResult.find(p => p.display) : null, 163 | hLine: hResult ? hResult.find(p => p.display) : null, 164 | } 165 | } 166 | 167 | /** 168 | * 隐藏 169 | */ 170 | export const hideAlignLine = () => { 171 | let root = createSpaceLineRoot(); 172 | if (root.parentNode) { 173 | root.parentNode.removeChild(root); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/lines/distance.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 距离线 3 | */ 4 | 5 | function createSpaceLineRoot() { 6 | let id = `view__dist-line-root`; 7 | let dom = document.getElementById(id); 8 | if (!dom) { 9 | let div = document.createElement('div'); 10 | div.id = id; 11 | document.body.appendChild(div); 12 | dom = div; 13 | } 14 | return dom; 15 | } 16 | 17 | 18 | /** 19 | * 创建距离线 20 | * @param {*} param0 21 | * @param {*} offsetTop 22 | * @param {*} offsetLeft 23 | */ 24 | function createHDistLine({ pos, start, end }, offsetTop, offsetLeft) { 25 | let id = 'view__h-dist-line'; 26 | let dom = document.getElementById(id); 27 | let root = createSpaceLineRoot(); 28 | if (!dom) { 29 | let div = document.createElement('div'); 30 | div.id = id; 31 | div.className = id; 32 | root.appendChild(div); 33 | dom = div; 34 | } 35 | let l = start, r = end; 36 | if (start > end) { 37 | l = end, r = start 38 | } 39 | dom.innerHTML = `
${r - l}
`; 40 | dom.style.display = 'block'; 41 | dom.style.left = `${l + offsetLeft}px`; 42 | dom.style.top = `${pos + offsetTop}px`; 43 | dom.style.width = `${Math.abs(r - l)}px`; 44 | } 45 | 46 | function createVDistLine({ pos, start, end }, offsetTop, offsetLeft) { 47 | let id = 'view__v-dist-line'; 48 | let dom = document.getElementById(id); 49 | let root = createSpaceLineRoot(); 50 | if (!dom) { 51 | let div = document.createElement('div'); 52 | div.id = id; 53 | div.className = id; 54 | root.appendChild(div); 55 | dom = div; 56 | } 57 | let t = start, b = end; 58 | if (start > end) { 59 | t = end, b = start 60 | } 61 | dom.innerHTML = `
${b - t}
`; 62 | dom.style.display = 'block'; 63 | dom.style.left = `${pos + offsetLeft}px`; 64 | dom.style.top = `${t + offsetTop}px`; 65 | dom.style.height = `${Math.abs(b - t)}px`; 66 | } 67 | 68 | 69 | /** 70 | * 显示距离线 71 | */ 72 | export function showDistLine(direction, from, to, offsetTop, offsetLeft) { 73 | let { 74 | start, end, 75 | } = from; 76 | let fromPos = from.pos, toPos = to.pos; 77 | // if (Math.abs(from.pos - to.pos) < 5) { 78 | // toPos = fromPos; 79 | // } 80 | if (direction === 'v') { 81 | let line = { 82 | start: fromPos, 83 | end: toPos, 84 | pos: (end + start) / 2, 85 | } 86 | // console.log(line) 87 | createHDistLine(line, offsetTop, offsetLeft); 88 | } else { 89 | let line = { 90 | start: fromPos, 91 | end: toPos, 92 | pos: (end + start) / 2 93 | } 94 | createVDistLine(line, offsetTop, offsetLeft); 95 | } 96 | 97 | 98 | } 99 | 100 | /** 101 | * 隐藏 102 | */ 103 | export const hideDistLine = () => { 104 | let root = createSpaceLineRoot(); 105 | if (root.parentNode) { 106 | root.parentNode.removeChild(root); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/lines/label.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * size标签 3 | */ 4 | 5 | 6 | 7 | /** 8 | * 隐藏label 9 | * @param {*} id 10 | */ 11 | export const hideLabel = () => { 12 | let id = 'view__resize-label'; 13 | let dom = document.getElementById(id); 14 | if (!dom) { 15 | return; 16 | } 17 | if (dom.parentNode) { 18 | dom.parentNode.removeChild(dom); 19 | } 20 | } 21 | 22 | export function showLabel(view: HTMLElement, content) { 23 | let id = 'view__resize-label'; 24 | let rect = view.getBoundingClientRect(); 25 | let dom = document.getElementById(id); 26 | if (!dom) { 27 | let div = document.createElement('div'); 28 | div.id = id; 29 | div.className = id; 30 | document.body.appendChild(div); 31 | dom = div; 32 | } 33 | dom.style.display = 'block'; 34 | dom.style.top = `${rect.bottom + 5}px`; 35 | dom.style.left = `${rect.left + rect.width / 2}px`; 36 | dom.innerHTML = content; 37 | } 38 | -------------------------------------------------------------------------------- /src/lines/lib.ts: -------------------------------------------------------------------------------- 1 | import { ILine } from '../types'; 2 | /** 3 | * 寻找和tarLine邻近的线 4 | * @param {*} tarLine 源线 5 | * @param {*} lines 线的数组 6 | */ 7 | export function findLine(tarLine: ILine, lines: ILine[]) { 8 | // 可以使用二分查找 9 | let l = 0, r = lines.length - 1; 10 | 11 | while (l <= r) { 12 | let i = Math.round(((r - (r - l) / 2))); 13 | if (tarLine.pos < lines[i].pos) { 14 | r = i - 1; 15 | } else if (tarLine.pos > lines[i].pos) { 16 | l = i + 1; 17 | } else { 18 | return lines[i]; 19 | } 20 | } 21 | if (l == r) { 22 | return lines[l]; 23 | } 24 | 25 | if (l > r) { 26 | if (l >= lines.length) { 27 | return lines[r]; 28 | } 29 | if (r < 0) { 30 | return lines[0]; 31 | } 32 | let x1 = Math.abs(lines[r].pos - tarLine.pos); 33 | let x2 = Math.abs(lines[l].pos - tarLine.pos); 34 | return x1 < x2 ? lines[r] : lines[l]; 35 | } 36 | } 37 | 38 | 39 | export function calcLines(top: number, left: number, height: number, width: number) { 40 | return { 41 | v: [ 42 | { type: 'vl', pos: left, start: top, end: top + height }, 43 | { type: 'vm', pos: left + width / 2, start: top, end: top + height }, 44 | { type: 'vr', pos: left + width, start: top, end: top + height }], 45 | h: [ 46 | { type: 'ht', pos: top, start: left, end: left + width }, 47 | { type: 'hm', pos: top + height / 2, start: left, end: left + width }, 48 | { type: 'hb', pos: top + height, start: left, end: left + width }, 49 | ] 50 | } 51 | } 52 | 53 | 54 | 55 | export function calcDirectionCreator() { 56 | let lastTop, lastLeft, lastDirection; 57 | return function (top, left) { 58 | if (!lastTop) { 59 | lastTop = top; 60 | } 61 | if (!lastLeft) { 62 | lastLeft = left; 63 | } 64 | 65 | let direction; 66 | // console.log(top, left, lastTop, lastLeft) 67 | let topOffset = Math.abs(top - lastTop), 68 | leftOffset = Math.abs(left - lastLeft); 69 | if (topOffset > leftOffset) { 70 | direction = 'v'; 71 | } else if (topOffset < leftOffset) { 72 | direction = 'h'; 73 | } else { 74 | direction = lastDirection; 75 | } 76 | lastTop = top; 77 | lastLeft = left; 78 | lastDirection = direction; 79 | return direction; 80 | } 81 | } 82 | 83 | export const calcDirection = calcDirectionCreator(); 84 | 85 | 86 | 87 | export function debounce(fn, delay) { 88 | let timer: any = null; 89 | return function () { 90 | let args = arguments, 91 | context = this; 92 | if (timer) { 93 | clearTimeout(timer); 94 | 95 | timer = setTimeout(() => { 96 | fn.apply(context, args); 97 | }, delay); 98 | } else { 99 | timer = setTimeout(() => { 100 | fn.apply(context, args); 101 | }, delay); 102 | } 103 | }; 104 | } 105 | 106 | export function throttle(fn, delay) { 107 | let timer: any = null, 108 | remaining = 0, 109 | previous = Date.now(); 110 | 111 | return function () { 112 | let args = arguments, 113 | context = this; 114 | let now = Date.now(); 115 | remaining = now - previous; 116 | 117 | if (remaining >= delay) { 118 | if (timer) { 119 | clearTimeout(timer); 120 | } 121 | 122 | fn.apply(context, args); 123 | previous = now; 124 | } else { 125 | if (!timer) { 126 | timer = setTimeout(() => { 127 | fn.apply(context, args); 128 | previous = Date.now() 129 | }, delay - remaining); 130 | } 131 | } 132 | }; 133 | } 134 | -------------------------------------------------------------------------------- /src/lines/space.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 间距块 3 | */ 4 | import { ISpace, IDirection } from '../types'; 5 | import { Lines } from './store'; 6 | import { ILine } from 'src/types'; 7 | 8 | function createSpaceLineRoot(direction) { 9 | let id = `view__${direction}-dist-line-root`; 10 | let dom = document.getElementById(id); 11 | if (!dom) { 12 | let div = document.createElement('div'); 13 | div.id = id; 14 | document.body.appendChild(div); 15 | dom = div; 16 | } 17 | return dom; 18 | } 19 | 20 | function createHSpaceLine({ pos, start, end, height }, offsetTop, offsetLeft) { 21 | let id = 'view__h-space-line_' + start; 22 | let root = createSpaceLineRoot('h'); 23 | let dom = document.getElementById(id); 24 | if (!dom) { 25 | let div = document.createElement('div'); 26 | div.id = id; 27 | div.className = 'view__h-space-line'; 28 | root.appendChild(div); 29 | dom = div; 30 | } 31 | let l = start, r = end; 32 | if (start > end) { 33 | l = end, r = start 34 | } 35 | dom.innerHTML = ``; 36 | dom.style.display = 'block'; 37 | dom.style.left = `${l + offsetLeft}px`; 38 | dom.style.top = `${pos + offsetTop}px`; 39 | dom.style.width = `${Math.abs(r - l)}px`; 40 | dom.style.height = `${height}px`; 41 | } 42 | 43 | 44 | function createVSpaceLine({ pos, start, end, width }, offsetTop, offsetLeft) { 45 | let id = 'view__v-space-line_' + start; 46 | let root = createSpaceLineRoot('v'); 47 | let dom = document.getElementById(id); 48 | if (!dom) { 49 | let div = document.createElement('div'); 50 | div.id = id; 51 | div.className = 'view__v-space-line'; 52 | root.appendChild(div); 53 | dom = div; 54 | } 55 | let t = start, b = end; 56 | if (start > end) { 57 | t = end, b = start 58 | } 59 | dom.innerHTML = ``; 60 | dom.style.display = 'block'; 61 | dom.style.left = `${pos + offsetLeft}px`; 62 | dom.style.top = `${t + offsetTop}px`; 63 | dom.style.width = `${width}px`; 64 | dom.style.height = `${Math.abs(b - t)}px`; 65 | } 66 | 67 | export function createVSpaceLines(lineIndexPairs: ISpace[] = [], offsetTop, offsetLeft) { 68 | hideSpaceLine('v'); 69 | lineIndexPairs.forEach((item) => { 70 | let { from, to } = item; 71 | let l1 = from as ILine; 72 | let l2 = to as ILine; 73 | // { pos, start, end }, offsetTop, offsetLeft 74 | let t = Math.min(l1.start, l2.start, l1.end, l2.end); 75 | let b = Math.max(l1.start, l2.start, l1.end, l2.end); 76 | let line = { 77 | pos: (l1.start + l1.end) / 2, 78 | start: l1.pos, 79 | end: l2.pos, 80 | height: b - t, 81 | }; 82 | 83 | createHSpaceLine(line, offsetTop, offsetLeft); 84 | }); 85 | } 86 | 87 | 88 | export function createHSpaceLines(lineIndexPairs: ISpace[] = [], offsetTop, offsetLeft) { 89 | hideSpaceLine('h'); 90 | lineIndexPairs.forEach((item) => { 91 | let { from, to } = item; 92 | let l1 = from as ILine; 93 | let l2 = to as ILine; 94 | // { pos, start, end }, offsetTop, offsetLeft 95 | let l = Math.min(l1.start, l2.start, l1.end, l2.end); 96 | let r = Math.max(l1.start, l2.start, l1.end, l2.end); 97 | let line = { 98 | pos: (l1.start + l1.end) / 2, 99 | start: l1.pos, 100 | end: l2.pos, 101 | width: r - l, 102 | }; 103 | createVSpaceLine(line, offsetTop, offsetLeft); 104 | }); 105 | } 106 | 107 | function calcAllSpaceLines(direction: IDirection, allLines: ILine[] = [], tarLines: ILine): Array { 108 | // 计算vl,vr的间距,按顺序查找,确保vl>vr,连续的vl>vr的线 109 | let i: number = 0, j: number = 1, results: Array> = []; 110 | let l1type = direction === 'v' ? 'vr' : 'hb'; 111 | let l2type = direction === 'v' ? 'vl' : 'ht'; 112 | let mid = (tarLines[0].end - tarLines[0].start) / 2 + tarLines[0].start; 113 | 114 | let lines: ILine[] = allLines.concat(tarLines).filter((line: ILine) => { 115 | // 父容器的线去除 116 | if (line.start === 0) { 117 | return false; 118 | } 119 | if (line.type === 'vm' || line.type === 'hm') { 120 | return false; 121 | } 122 | if (line.start < mid && line.end > mid) { 123 | return true; 124 | } 125 | return false; 126 | }).sort((a: ILine, b: ILine) => a.pos - b.pos); 127 | 128 | while (j < lines.length) { 129 | if (lines[i].type === l1type) { 130 | if (lines[j].type !== l2type) { 131 | j++; 132 | continue; 133 | } 134 | if (lines[i].pos <= tarLines[0].pos && lines[j].pos >= tarLines[2].pos) { 135 | i++; 136 | continue; 137 | } 138 | // i 是vr j是vl 139 | results.push([i, j]); 140 | } 141 | 142 | i++; j++; 143 | } 144 | 145 | return results.map((item) => { 146 | let [i, j] = item; 147 | return { 148 | from: lines[i], 149 | to: lines[j], 150 | dist: lines[j].pos - lines[i].pos, 151 | } 152 | }) 153 | } 154 | 155 | function findTarSpaceLine(spaceLines, tarLines) { 156 | let left = tarLines[0]; 157 | let right = tarLines[2]; 158 | let leftTar, rightTar; 159 | if (spaceLines.length <= 1) { 160 | return [] 161 | } 162 | spaceLines.forEach((line, index) => { 163 | let { from, to } = line; 164 | if (left.pos === to.pos) { 165 | if (index < 1) { 166 | return; 167 | } 168 | let line = spaceLines[index - 1]; 169 | let dist = line.dist; 170 | leftTar = from.pos + dist; 171 | } 172 | if (right.pos === from.pos) { 173 | if (index >= spaceLines.length - 1) { 174 | return; 175 | } 176 | let line = spaceLines[index + 1]; 177 | let dist = line.dist; 178 | rightTar = to.pos - dist; 179 | } 180 | }) 181 | return [leftTar, rightTar] 182 | } 183 | 184 | /** 185 | * 186 | *显示间距线,返回最近的间距块以及目标吸附位置 187 | */ 188 | export const showSpaceLine = (direction: IDirection, line, offsetTop, offsetLeft) => { 189 | //判断是横向还是纵向, 190 | //计算组件的间距,显示同一方向的间距, 191 | // let results; 192 | if (direction === 'h') { 193 | let spaceLines = calcAllSpaceLines('h', Lines.hLines, line.h); 194 | createHSpaceLines(spaceLines, offsetTop, offsetLeft); 195 | } else { 196 | let spaceLines = calcAllSpaceLines('v', Lines.vLines, line.v); 197 | createVSpaceLines(spaceLines, offsetTop, offsetLeft) 198 | } 199 | } 200 | 201 | export const calcSpaceLineList = (direction, line) => { 202 | let results, spaceLines; 203 | if (direction === 'h') { 204 | spaceLines = calcAllSpaceLines('h', Lines.hLines, line.h); 205 | results = findTarSpaceLine(spaceLines, line.h); 206 | } else { 207 | spaceLines = calcAllSpaceLines('v', Lines.vLines, line.v); 208 | results = findTarSpaceLine(spaceLines, line.v); 209 | } 210 | return results; 211 | } 212 | 213 | 214 | /** 215 | * 隐藏 216 | * @param {string} direction 方向 217 | */ 218 | export const hideSpaceLine = (direction:IDirection) => { 219 | let hdom = document.getElementById(`view__${direction}-dist-line-root`); 220 | if (!hdom) { 221 | return; 222 | } 223 | hdom.remove(); 224 | } 225 | -------------------------------------------------------------------------------- /src/lines/store.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 线的存储 3 | */ 4 | import { ILineStore, ILine } from '../types'; 5 | 6 | import { 7 | calcLines 8 | } from './lib'; 9 | /** 10 | * line 集合,{pos,type,start,end} 11 | */ 12 | export const Lines: ILineStore = { 13 | vLines: [], 14 | hLines: [] 15 | } 16 | 17 | /** 18 | * 初始化容器内的线数据 19 | */ 20 | export function initLine(childs: HTMLElement[], dragDom: HTMLElement) { 21 | 22 | let vLines: Array = [], hLines: Array = []; 23 | 24 | for (let i = 0; i < childs.length; i++) { 25 | const child = childs[i] as HTMLElement; 26 | if (child === dragDom) { 27 | continue; 28 | } 29 | let { 30 | offsetTop, 31 | offsetLeft, 32 | offsetHeight, 33 | offsetWidth 34 | } = child; 35 | let l = calcLines(offsetTop, offsetLeft, offsetHeight, offsetWidth); 36 | vLines = vLines.concat(l.v); 37 | hLines = hLines.concat(l.h); 38 | } 39 | 40 | Lines.vLines = vLines.sort((a, b) => a.pos - b.pos); 41 | Lines.hLines = hLines.sort((a, b) => a.pos - b.pos); 42 | } 43 | -------------------------------------------------------------------------------- /src/move.ts: -------------------------------------------------------------------------------- 1 | import { 2 | calcLines, 3 | calcDirection, 4 | debounce, 5 | } from './lines/lib'; 6 | import { 7 | showAlignLine, 8 | hideAlignLine 9 | } from './lines/align'; 10 | import { 11 | showDistLine, 12 | hideDistLine 13 | } from './lines/distance'; 14 | import { 15 | showSpaceLine, 16 | calcSpaceLineList, 17 | hideSpaceLine 18 | } from './lines/space'; 19 | 20 | import { 21 | showLabel, hideLabel 22 | } from './lines/label'; 23 | 24 | import { DIST } from './constants' 25 | 26 | function calcTarPos(top, left, height, width, vLine, hLine) { 27 | let tarLeft = left, tarTop = top; 28 | if (!vLine) { 29 | tarLeft = left 30 | } else if (vLine.from.pos < vLine.pos + DIST && vLine.from.pos > vLine.pos - DIST) { 31 | if (vLine.from.type === 'vl') { 32 | tarLeft = vLine.pos; 33 | } else if (vLine.from.type === 'vm') { 34 | tarLeft = vLine.pos - width / 2; 35 | } else if (vLine.from.type === 'vr') { 36 | tarLeft = vLine.pos - width; 37 | } 38 | } 39 | if (!hLine) { 40 | tarTop = top 41 | } else if (hLine.from.pos < hLine.pos + DIST && hLine.from.pos > hLine.pos - DIST) { 42 | if (hLine.from.type === 'ht') { 43 | tarTop = hLine.pos; 44 | } else if (hLine.from.type === 'hm') { 45 | tarTop = hLine.pos - height / 2; 46 | } else if (hLine.from.type === 'hb') { 47 | tarTop = hLine.pos - height; 48 | } 49 | } 50 | return { 51 | top: tarTop, 52 | left: tarLeft, 53 | } 54 | } 55 | 56 | 57 | function showSapceLines(direction, tarLine, { top, left, width, height }, offsetTop, offsetLeft) { 58 | let tarLeft = left; 59 | let tarTop = top; 60 | 61 | if (direction == 'h') { 62 | 63 | let [spaceLeft, spaceRight] = calcSpaceLineList('v', tarLine); 64 | 65 | if (tarLeft > spaceLeft - DIST && tarLeft < spaceLeft + DIST) { 66 | tarLeft = spaceLeft; 67 | showSpaceLine('v', calcLines(tarTop, tarLeft, height, width), offsetTop, offsetLeft) 68 | } 69 | 70 | if (tarLeft > spaceRight - width - DIST && tarLeft < spaceRight - width + DIST) { 71 | tarLeft = spaceRight - width; 72 | showSpaceLine('v', calcLines(tarTop, tarLeft, height, width), offsetTop, offsetLeft) 73 | } 74 | } else { 75 | 76 | let [spaceTop, spaceBottom] = calcSpaceLineList('h', tarLine); 77 | 78 | if (tarTop > spaceTop - DIST && tarTop < spaceTop + DIST) { 79 | tarTop = spaceTop; 80 | showSpaceLine('h', calcLines(tarTop, tarLeft, height, width), offsetTop, offsetLeft) 81 | } 82 | 83 | if (tarTop > spaceBottom - height - DIST && tarTop < spaceBottom - height + DIST) { 84 | tarTop = spaceBottom - height; 85 | showSpaceLine('h', calcLines(tarTop, tarLeft, height, width), offsetTop, offsetLeft) 86 | } 87 | } 88 | return { 89 | top: tarTop, 90 | left: tarLeft, 91 | } 92 | } 93 | 94 | function showAlignLines(tarLine, { top, left, width, height }, offsetTop, offsetLeft) { 95 | let nearLine = showAlignLine(tarLine, offsetTop, offsetLeft); 96 | 97 | let tarLeft = left, tarTop = top; 98 | if (nearLine) { 99 | let { 100 | vLine, 101 | hLine 102 | } = nearLine; 103 | 104 | let tarPos = calcTarPos(top, left, height, width, vLine, hLine); 105 | 106 | tarLeft = tarPos.left; 107 | tarTop = tarPos.top; 108 | 109 | if (top != tarTop || left != tarLeft) { 110 | showAlignLine(calcLines(tarTop, tarLeft, height, width), offsetTop, offsetLeft); 111 | } 112 | 113 | let fromVLine = vLine.from; 114 | let fromHLine = hLine.from; 115 | let map = { 'vl': 0, 'vm': 1, 'vr': 2, 'ht': 0, 'hm': 1, 'hb': 2 }; 116 | if (tarLeft != left || tarTop != top) { 117 | let newLine = calcLines(tarTop, tarLeft, height, width); 118 | fromVLine = newLine.v[map[fromVLine.type]] 119 | fromHLine = newLine.h[map[fromHLine.type]] 120 | } 121 | showDistLine('v', fromVLine, vLine, offsetTop, offsetLeft); 122 | showDistLine('h', fromHLine, hLine, offsetTop, offsetLeft); 123 | } 124 | return { 125 | top: tarTop, 126 | left: tarLeft 127 | } 128 | } 129 | 130 | 131 | function hideLines() { 132 | hideAlignLine(); 133 | hideSpaceLine('h'); 134 | hideSpaceLine('v'); 135 | hideDistLine(); 136 | hideLabel() 137 | } 138 | 139 | const moveDeb: any = debounce((cb) => { 140 | cb(); 141 | }, 1000); 142 | 143 | export const moveByDom = (dom, top, left, onMoveEnd) => { 144 | 145 | if (!dom) { 146 | return; 147 | } 148 | let cotainer = dom.parentNode.getBoundingClientRect(); 149 | let offsetTop = cotainer.top; 150 | let offsetLeft = cotainer.left; 151 | 152 | let rect = dom.getBoundingClientRect(); 153 | let { 154 | height, width, 155 | } = rect; 156 | 157 | let direction = calcDirection(top, left); 158 | let tarLine = calcLines(top, left, height, width); 159 | let tarLeft = left, tarTop = top; 160 | 161 | 162 | let tarSpaceInfo = showSapceLines(direction, tarLine, { top: tarTop, left: tarLeft, width, height }, offsetTop, offsetLeft); 163 | 164 | tarTop = tarSpaceInfo.top; 165 | tarLeft = tarSpaceInfo.left; 166 | 167 | let alignLineInfo = showAlignLines(tarLine, { top: tarTop, left: tarLeft, width, height }, offsetTop, offsetLeft); 168 | 169 | tarTop = alignLineInfo.top; 170 | tarLeft = alignLineInfo.left; 171 | 172 | 173 | dom.style.left = `${tarLeft}px`; 174 | dom.style.top = `${tarTop}px`; 175 | 176 | showLabel(dom, `X:${tarLeft},Y:${tarTop}`); 177 | 178 | moveDeb(function () { 179 | hideLines(); 180 | if (onMoveEnd) { 181 | onMoveEnd(tarTop, tarLeft); 182 | } 183 | }) 184 | } 185 | -------------------------------------------------------------------------------- /src/resize.ts: -------------------------------------------------------------------------------- 1 | import { 2 | calcLines, debounce, 3 | } from './lines/lib'; 4 | import { 5 | showAlignLine, hideAlignLine 6 | } from './lines/align'; 7 | import { 8 | showDistLine, hideDistLine 9 | } from './lines/distance'; 10 | 11 | import { 12 | showLabel, hideLabel 13 | } from './lines/label' 14 | 15 | import { DIST } from './constants' 16 | import { hideSpaceLine } from './lines/space'; 17 | 18 | function calcTarSize(top, left, height, width, vLine, hLine) { 19 | let tarLeft = left, tarTop = top, tarHeight = height, tarWidth = width; 20 | if (vLine) { 21 | if (vLine.from.pos < vLine.pos + DIST && vLine.from.pos > vLine.pos - DIST) { 22 | if (vLine.from.type === 'vl') { 23 | tarLeft = vLine.pos; 24 | tarWidth = width + (vLine.from.pos - vLine.pos); 25 | } else if (vLine.from.type === 'vm') { 26 | // tarLeft = vLine.pos - width / 2; 27 | } else if (vLine.from.type === 'vr') { 28 | tarWidth = width + (vLine.pos - vLine.from.pos); 29 | tarLeft = vLine.pos - tarWidth; 30 | } 31 | } 32 | } 33 | if (hLine) { 34 | if (hLine.from.pos < hLine.pos + DIST && hLine.from.pos > hLine.pos - DIST) { 35 | if (hLine.from.type === 'ht') { 36 | tarTop = hLine.pos; 37 | tarHeight = height + (hLine.from.pos - hLine.pos); 38 | } else if (hLine.from.type === 'hm') { 39 | tarTop = hLine.pos - height / 2; 40 | } else if (hLine.from.type === 'hb') { 41 | tarHeight = height + (hLine.pos - hLine.from.pos); 42 | tarTop = hLine.pos - tarHeight; 43 | } 44 | } 45 | } 46 | return { 47 | top: tarTop, 48 | left: tarLeft, 49 | height: tarHeight, 50 | width: tarWidth 51 | } 52 | } 53 | 54 | const DIRECTION = { 55 | 'tc': ['ht'], 56 | 'bc': ['hb'], 57 | 'rc': ['vr'], 58 | 'lc': ['vl'], 59 | 'tl': ['ht', 'vl'], 60 | 'tr': ['ht', 'vr'], 61 | 'br': ['hb', 'vr'], 62 | 'bl': ['hb', 'vl'], 63 | } 64 | 65 | function getTarLine(line, include:string[]=[]) { 66 | let v = line.v.filter((item) => { 67 | return include.indexOf(item.type) >= 0; 68 | }); 69 | let h = line.h.filter((item) => { 70 | return include.indexOf(item.type) >= 0; 71 | }); 72 | return { 73 | v, h 74 | } 75 | } 76 | 77 | let last; 78 | function caclHandType(top, left, height, width) { 79 | if (!last) { 80 | last = { 81 | top, left, height, width 82 | } 83 | return []; 84 | } 85 | let lines: string[] = []; 86 | if (top !== last.top) { 87 | lines.push('ht'); 88 | } 89 | 90 | if (left !== last.left) { 91 | lines.push('vl'); 92 | } 93 | 94 | if (top === last.top && left === last.left && width !== last.width) { 95 | lines.push('vr'); 96 | } 97 | 98 | if (top === last.top && left === last.left && height !== last.height) { 99 | lines.push('hb'); 100 | } 101 | return lines; 102 | } 103 | 104 | function hideLines() { 105 | last = null; 106 | hideAlignLine(); 107 | hideSpaceLine('h'); 108 | hideSpaceLine('v'); 109 | hideDistLine(); 110 | hideLabel() 111 | } 112 | 113 | const moveDeb: any = debounce((cb) => { 114 | cb(); 115 | }, 1000); 116 | 117 | export const resizeByDom = (dom, top, left, height, width, onResizeEnd) => { 118 | 119 | if (!dom) { 120 | return; 121 | } 122 | let cotainer = dom.parentNode.getBoundingClientRect(); 123 | let offsetTop = cotainer.top; 124 | let offsetLeft = cotainer.left; 125 | let handType = caclHandType(top, left, height, width); 126 | console.log(handType) 127 | let allLines = calcLines(top, left, height, width); 128 | let tarLine = getTarLine(allLines, handType); 129 | let nearLine = showAlignLine(tarLine, offsetTop, offsetLeft); 130 | 131 | let tarLeft = left, tarTop = top, tarHeight = height, tarWidth = width; 132 | // console.log(nearLine) 133 | if (nearLine) { 134 | let { 135 | vLine, 136 | hLine 137 | } = nearLine; 138 | let tarPos = calcTarSize(top, left, height, width, vLine, hLine); 139 | tarLeft = tarPos.left; 140 | tarTop = tarPos.top; 141 | tarHeight = tarPos.height; 142 | tarWidth = tarPos.width; 143 | 144 | if (left != tarLeft || top != tarTop || height != tarHeight || width != tarWidth) { 145 | showAlignLine(calcLines(tarTop, tarLeft, tarHeight, tarWidth), offsetTop, offsetLeft); 146 | } 147 | 148 | let map = { 'vl': 0, 'vm': 1, 'vr': 2, 'ht': 0, 'hm': 1, 'hb': 2 }; 149 | if (vLine) { 150 | let fromVLine = vLine.from; 151 | if (tarLeft != left || tarWidth != width) { 152 | let newLine = calcLines(tarTop, tarLeft, tarHeight, tarWidth); 153 | fromVLine = newLine.v[map[fromVLine.type]]; 154 | } 155 | showDistLine('v', fromVLine, vLine, offsetTop, offsetLeft); 156 | } 157 | if (hLine) { 158 | let fromHLine = hLine.from; 159 | if (tarTop != top || tarHeight != height) { 160 | let newLine = calcLines(tarTop, tarLeft, tarHeight, tarWidth); 161 | fromHLine = newLine.h[map[fromHLine.type]]; 162 | } 163 | showDistLine('h', fromHLine, hLine, offsetTop, offsetLeft); 164 | } 165 | } 166 | 167 | dom.style.top = `${tarTop}px`; 168 | dom.style.left = `${tarLeft}px`; 169 | dom.style.height = `${tarHeight}px`; 170 | dom.style.width = `${tarWidth}px`; 171 | 172 | // showLabel(dom, rect.bottom + 3, rect.left + rect.width / 2, `W:${width},H:${height}`); 173 | showLabel(dom,`W:${width},H:${height}`); 174 | 175 | 176 | moveDeb(function () { 177 | hideLines(); 178 | if (onResizeEnd) { 179 | onResizeEnd(tarTop, tarLeft, tarHeight, tarWidth) 180 | } 181 | }) 182 | } 183 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | 2 | export type TLineType = 'vl' | 'vm' | 'vr' | 'ht' | 'hm' | 'hb'; 3 | export type IDirection = 'v' | 'h'; 4 | 5 | export interface ILine { 6 | type: TLineType; 7 | pos: number; 8 | start: number; 9 | end: number; 10 | } 11 | 12 | export interface ISpace { 13 | from: ILine; 14 | to: ILine; 15 | dist: number; 16 | 17 | } 18 | 19 | export interface ILineStore { 20 | vLines: Array; 21 | hLines: Array; 22 | } 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "noImplicitAny": false, 5 | "strictFunctionTypes":true, 6 | "target":"es6", 7 | "jsx": "react", 8 | "allowJs":true, 9 | "module":"esnext", 10 | "moduleResolution": "node", 11 | "baseUrl":".", 12 | "declaration":false, 13 | "noUnusedParameters": true, 14 | "noUnusedLocals": true, 15 | "strictNullChecks": true, 16 | "paths": { 17 | }, 18 | "allowSyntheticDefaultImports":true, 19 | "lib": [ 20 | "es2016", 21 | "dom", 22 | "es5" 23 | ] 24 | 25 | }, 26 | "include": ["src"], 27 | "exclude": ["node_modules", "lib", "es"] 28 | } 29 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:recommended", 4 | "tslint-config-prettier" 5 | ], 6 | "rules": { 7 | "class-name": true, 8 | "eofline": true, 9 | "forin": true, 10 | "jsdoc-format": false, 11 | "label-position": true, 12 | "member-ordering": [ 13 | true, 14 | { 15 | "order": "statics-first" 16 | } 17 | ], 18 | "new-parens": true, 19 | "no-arg": true, 20 | "no-bitwise": true, 21 | "no-conditional-assignment": true, 22 | "no-consecutive-blank-lines": true, 23 | "no-console": [ 24 | true, 25 | "debug", 26 | "info", 27 | "log", 28 | "time", 29 | "timeEnd", 30 | "trace" 31 | ], 32 | "no-construct": true, 33 | "no-debugger": true, 34 | "no-duplicate-variable": true, 35 | "no-eval": true, 36 | "no-internal-module": true, 37 | "no-multi-spaces": true, 38 | "no-namespace": true, 39 | "no-reference": true, 40 | "no-shadowed-variable": true, 41 | "no-string-literal": true, 42 | "no-trailing-whitespace": false, 43 | "no-unused-expression": true, 44 | "no-var-keyword": true, 45 | "object-literal-sort-keys":false, 46 | "interface-name":false, 47 | "one-variable-per-declaration":false, 48 | "prefer-const": [ 49 | true, 50 | { 51 | "destructuring": "all" 52 | } 53 | ], 54 | "radix": true, 55 | "space-in-parens": true, 56 | "switch-default": true, 57 | "trailing-comma": [ 58 | true, 59 | { 60 | "singleline": "never", 61 | "multiline": "always", 62 | "esSpecCompliant": true 63 | } 64 | ], 65 | "triple-equals": [ 66 | true, 67 | "allow-null-check" 68 | ], 69 | "typedef-whitespace": [ 70 | true, 71 | { 72 | "call-signature": "nospace", 73 | "index-signature": "nospace", 74 | "parameter": "nospace", 75 | "property-declaration": "nospace", 76 | "variable-declaration": "nospace" 77 | }, 78 | { 79 | "call-signature": "onespace", 80 | "index-signature": "onespace", 81 | "parameter": "onespace", 82 | "property-declaration": "onespace", 83 | "variable-declaration": "onespace" 84 | } 85 | ], 86 | "use-isnan": true, 87 | "variable-name": [ 88 | true, 89 | "allow-leading-underscore", 90 | "ban-keywords", 91 | "check-format", 92 | "allow-pascal-case" 93 | ], 94 | "jsx-no-lambda": false, 95 | "jsx-no-string-ref": false, 96 | "jsx-boolean-value": [ 97 | true, 98 | "never" 99 | ], 100 | "jsx-no-multiline-js": false, 101 | "whitespace": [ 102 | false, 103 | "check-branch", 104 | "check-decl", 105 | "check-operator", 106 | "check-module", 107 | "check-separator", 108 | "check-rest-spread", 109 | "check-type", 110 | "check-typecast", 111 | "check-type-operator", 112 | "check-preblock" 113 | ] 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /webpack.base.config.js: -------------------------------------------------------------------------------- 1 | let path = require('path'); 2 | let webpack = require('webpack'); 3 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 4 | module.exports = function (options) { 5 | let { 6 | cdn, 7 | dist, 8 | root, 9 | src 10 | } = options; 11 | let publicPath = `${cdn}`; 12 | let distPath = path.resolve(root, dist); 13 | let def = { 14 | mode: 'development', 15 | entry: { 16 | 'view-line': path.resolve(root, src, 'index.ts'), 17 | }, 18 | output: { 19 | path: distPath, 20 | filename: '[name].js', 21 | chunkFilename: '[name].chunk.js', 22 | publicPath: publicPath, 23 | // library: 'PropsEditor', 24 | // libraryTarget: 'umd' 25 | }, 26 | module: { 27 | rules: [ 28 | // or any other compile-to-css language 29 | { 30 | test: /\.less$/, 31 | use: [ 32 | { 33 | loader: MiniCssExtractPlugin.loader, 34 | options: { 35 | // you can specify a publicPath here 36 | // by default it use publicPath in webpackOptions.output 37 | publicPath 38 | } 39 | }, 40 | 'css-loader', 41 | { 42 | loader: 'postcss-loader', 43 | options: { 44 | plugins: function () { 45 | return [ 46 | require('autoprefixer') 47 | ]; 48 | } 49 | } 50 | }, { 51 | loader: 'less-loader', 52 | options: { 53 | javascriptEnabled: true, 54 | modifyVars: { 55 | '@primary-color': '#FB7055', 56 | '@border-radius-base': 0, 57 | '@border-radius-sm ': 0 58 | } 59 | } 60 | } 61 | ] 62 | }, 63 | { 64 | test: /\.css$/, 65 | use: [ 66 | { 67 | loader: MiniCssExtractPlugin.loader, 68 | options: { 69 | // you can specify a publicPath here 70 | // by default it use publicPath in webpackOptions.output 71 | publicPath 72 | } 73 | }, 74 | 'css-loader', 75 | { 76 | loader: 'postcss-loader', 77 | options: { 78 | plugins: function () { 79 | return [ 80 | require('autoprefixer') 81 | ]; 82 | } 83 | } 84 | } 85 | ] 86 | }, 87 | { 88 | test: /\.(js|jsx|ts|tsx)$/, 89 | exclude: /(node_modules|bower_components)/, 90 | use: [ 91 | { 92 | loader: 'babel-loader' 93 | } 94 | ] 95 | }, 96 | { 97 | test: /\.(jpg|png|gif)$/, 98 | use: [{ 99 | loader: 'url-loader', 100 | options: { 101 | limit: 1, 102 | name: 'img/[path][name].[ext]' 103 | } 104 | }] 105 | }, 106 | { 107 | test: /\.(eot|svg|ttf|woff)\??.*$/, 108 | use: [{ 109 | loader: 'url-loader', 110 | options: { 111 | limit: 1, 112 | name: 'iconfont/[name].[ext]' 113 | } 114 | }] 115 | } 116 | ] 117 | 118 | }, 119 | node: { 120 | // Mock Node.js modules that Babel require()s but that we don't 121 | // particularly care about. 122 | fs: 'empty', 123 | module: 'empty', 124 | net: 'empty' 125 | }, 126 | cache: true, 127 | resolve: { 128 | alias: { 129 | '@': path.resolve(root, './src'), 130 | }, 131 | extensions: ['.json', '.js', '.jsx','.ts','.tsx'] 132 | }, 133 | plugins: [ 134 | // new webpack.IgnorePlugin({ 135 | // resourceRegExp: /^\.\/locale$/, 136 | // contextRegExp: /moment$/ 137 | // }), 138 | 139 | ] 140 | }; 141 | return def; 142 | }; 143 | -------------------------------------------------------------------------------- /webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | let webpack = require('webpack'); 2 | let path = require('path'); 3 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | let BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 6 | let webpackBase = require('./webpack.base.config'); 7 | let webpackMerge = require('webpack-merge'); 8 | let options = { 9 | cdn: '', 10 | dist: 'sample/dist', 11 | root: __dirname, 12 | src: './src' 13 | } 14 | var config = webpackMerge(webpackBase(options), { 15 | mode: 'development', 16 | entry: { 17 | 'index': path.resolve(options.root, 'sample', 'index.ts'), 18 | }, 19 | output: { 20 | filename: '[name].js', 21 | chunkFilename: '[name].chunk.js' 22 | }, 23 | devServer: { 24 | contentBase: './sample', 25 | }, 26 | // optimization: { 27 | // splitChunks: { 28 | // cacheGroups: { 29 | // styles: { 30 | // name: 'styles', 31 | // test: /\.less$|\.css$/, 32 | // chunks: 'all', 33 | // enforce: true 34 | // } 35 | // } 36 | // } 37 | // }, 38 | externals: [ 39 | { 40 | // 'react': 'React', 41 | // 'react-dom': 'ReactDOM', 42 | // 'react-redux': 'ReactRedux', 43 | // 'redux': 'Redux', 44 | // 'immutable': 'Immutable', 45 | 'jquery': 'jQuery', 46 | // 'esprima-fb': 'esprima', 47 | // 'draft-js': 'Draft', 48 | // 'lodash': '_', 49 | // 'react-router-dom': 'ReactRouterDOM' 50 | }, 51 | ], 52 | plugins: [ 53 | new webpack.DefinePlugin({ 54 | 'process.env.NODE_ENV': JSON.stringify('development') 55 | }), 56 | new HtmlWebpackPlugin({ 57 | template:path.resolve(options.root,'sample/tmp.html'), 58 | title: '属性编辑器', 59 | }), 60 | new MiniCssExtractPlugin({ 61 | filename: "[name].css", 62 | }), 63 | new BundleAnalyzerPlugin({ 64 | analyzerPort: 9999 65 | }) 66 | ], 67 | devtool: 'inline-source-map', 68 | }); 69 | 70 | console.log(config) 71 | module.exports = config; 72 | -------------------------------------------------------------------------------- /webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | let webpack = require('webpack'); 2 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 3 | let BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 4 | let webpackBase = require('./webpack.base.config'); 5 | let webpackMerge = require('webpack-merge'); 6 | let options = { 7 | cdn: '', 8 | dist: 'dist', 9 | root: __dirname, 10 | src: './src' 11 | } 12 | var config = webpackMerge(webpackBase(options), { 13 | mode: 'development', 14 | output: { 15 | filename: '[name].js', 16 | chunkFilename: '[name].chunk.js', 17 | library: 'ViewLine', 18 | libraryTarget: 'umd' 19 | }, 20 | externals: [ 21 | { 22 | 'react': { 23 | commonjs: 'react', 24 | commonjs2: 'react', 25 | root: 'React' 26 | }, 27 | 'react-dom': { 28 | commonjs: 'react-dom', 29 | commonjs2: 'react-dom', 30 | root: 'ReactDOM' 31 | }, 32 | 'react-redux': { 33 | commonjs: 'react-redux', 34 | commonjs2: 'react-redux', 35 | root: 'ReactRedux' 36 | }, 37 | 'redux': { 38 | commonjs: 'redux', 39 | commonjs2: 'redux', 40 | root: 'Redux' 41 | }, 42 | 'immutable': { 43 | commonjs: 'immutable', 44 | commonjs2: 'immutable', 45 | root: 'Immutable' 46 | }, 47 | 'jquery': { 48 | commonjs: 'jquery', 49 | commonjs2: 'jquery', 50 | root: 'jQuery' 51 | }, 52 | 'esprima-fb': { 53 | commonjs: 'esprima-fb', 54 | commonjs2: 'esprima-fb', 55 | root: 'esprima' 56 | }, 57 | 'draft-js': { 58 | commonjs: 'draft-js', 59 | commonjs2: 'draft-js', 60 | root: 'Draft' 61 | }, 62 | 'lodash': { 63 | commonjs: 'lodash', 64 | commonjs2: 'lodash', 65 | amd: 'lodash', 66 | root: '_' // indicates global variable 67 | }, 68 | 'bondjs': 'bondjs', 69 | 'react-router-dom': { 70 | commonjs: 'react-router-dom', 71 | commonjs2: 'react-router-dom', 72 | amd: 'react-router-dom', 73 | root: 'ReactRouterDOM' // indicates global variable 74 | }, 75 | 'prop-types': { 76 | commonjs: 'prop-types', 77 | commonjs2: 'prop-types', 78 | amd: 'prop-types', 79 | root: 'PropTypes' // indicates global variable 80 | }, 81 | 'tinycolor2': { 82 | commonjs: 'tinycolor2', 83 | commonjs2: 'tinycolor2', 84 | amd: 'tinycolor2', 85 | root: 'tinycolor2' // indicates global variable 86 | }, 87 | 'SketchPicker': { 88 | commonjs: 'SketchPicker', 89 | amd: 'SketchPicker', 90 | root: 'ReactRouterDOM' // indicates global variable 91 | }, 92 | 'react-color': { 93 | commonjs: 'react-color', 94 | commonjs2: 'react-color', 95 | amd: 'react-color', 96 | root: 'reactColor' // indicates global variable 97 | }, 98 | 'axios': { 99 | commonjs: 'axios', 100 | commonjs2: 'axios', 101 | }, 102 | 'add-dom-event-listener': { 103 | commonjs: 'add-dom-event-listener', 104 | commonjs2: 'add-dom-event-listener', 105 | }, 106 | 'glamor': { 107 | commonjs: 'glamor', 108 | commonjs2: 'glamor', 109 | } 110 | }, 111 | /^antd/, 112 | /^jssha/, 113 | function (context, request, callback) { 114 | if (/antd/.test(request)) { 115 | return callback(null, 'commonjs ' + request); 116 | } 117 | callback(); 118 | } 119 | ], 120 | plugins: [ 121 | new webpack.DefinePlugin({ 122 | 'process.env.NODE_ENV': JSON.stringify('production') 123 | }), 124 | new MiniCssExtractPlugin({ 125 | filename: "[name].css", 126 | }), 127 | // new BundleAnalyzerPlugin({ 128 | // analyzerPort: 9999 129 | // }) 130 | ], 131 | devtool: 'none' 132 | }); 133 | 134 | module.exports = config; 135 | --------------------------------------------------------------------------------