├── .gitignore ├── LICENSE ├── README.md ├── README_KR.md ├── bin ├── build.js └── test.client.js ├── doc ├── API.md ├── API_KR.md ├── CONTRIBUTING.md ├── CONTRIBUTING_KR.md ├── FUNCTION_INTERFACE.md ├── FUNCTION_INTERFACE_KR.md ├── TEST.md └── TEST_KR.md ├── package-lock.json ├── package.json ├── src ├── Errors │ ├── CustomError.js │ └── IllegalArgumentError.js ├── LiveRotateTransform │ ├── LiveRotateTransform.index.js │ ├── LiveRotateTransform.spec.js │ └── README.md ├── LiveScaleTransform │ ├── LiveScaleTransform.index.js │ ├── LiveScaleTransform.spec.js │ └── README.md ├── LiveScaleTransform2 │ ├── LiveScaleTransform2.index.js │ ├── LiveScaleTransform2.spec.js │ └── README.md ├── LiveTransform │ ├── LiveTransform.index.js │ ├── LiveTransform.spec.js │ └── README.md ├── LiveTransformHandler │ ├── LiveTransformHandler.index.js │ ├── LiveTransformHandler.spec.js │ └── README.md ├── LiveTranslateTransform │ ├── LiveTranslateTransform.index.js │ ├── LiveTranslateTransform.spec.js │ └── README.md ├── appendRotateTransform │ ├── README.md │ ├── appendRotateTransform.index.js │ └── appendRotateTransform.spec.js ├── appendTranslateTransform │ ├── README.md │ ├── appendTranslateTransform.index.js │ └── appendTranslateTransform.spec.js ├── consolidateTransformList │ ├── README.md │ ├── consolidateTransformList.index.js │ └── consolidateTransformList.spec.js ├── convertClientToUserCoords │ ├── README.md │ ├── convertClientToUserCoords.index.js │ └── convertClientToUserCoords.spec.js ├── createSVGMatrix │ ├── README.md │ ├── createSVGMatrix.index.js │ └── createSVGMatrix.spec.js ├── createSVGPoint │ ├── README.md │ ├── createSVGPoint.index.js │ └── createSVGPoint.spec.js ├── createSVGRect │ ├── README.md │ ├── createSVGRect.index.js │ └── createSVGRect.spec.js ├── createSVGTransform │ ├── README.md │ ├── createSVGTransform.index.js │ └── createSVGTransform.spec.js ├── createSVGTransformMatrix │ ├── README.md │ ├── createSVGTransformMatrix.index.js │ └── createSVGTransformMatrix.spec.js ├── createSVGTransformRotate │ ├── README.md │ ├── createSVGTransformRotate.index.js │ └── createSVGTransformRotate.spec.js ├── createSVGTransformScale │ ├── README.md │ ├── createSVGTransformScale.index.js │ └── createSVGTransformScale.spec.js ├── createSVGTransformTranslate │ ├── README.md │ ├── createSVGTransformTranslate.index.js │ └── createSVGTransformTranslate.spec.js ├── el │ ├── README.md │ ├── el.index.js │ └── el.spec.js ├── els │ ├── README.md │ ├── els.index.js │ └── els.spec.js ├── fxsvg.js ├── getAnimTransformList │ ├── README.md │ ├── getAnimTransformList.index.js │ └── getAnimTransformList.spec.js ├── getAttrNS │ ├── README.md │ ├── getAttrNS.index.js │ └── getAttrNS.spec.js ├── getBaseTransformList │ ├── README.md │ ├── getBaseTransformList.index.js │ └── getBaseTransformList.spec.js ├── getBoundingPoints │ ├── README.md │ ├── getBoundingPoints.index.js │ └── getBoundingPoints.spec.js ├── getBoxPoints │ ├── README.md │ ├── getBoxPoints.index.js │ └── getBoxPoints.spec.js ├── getCenterPoint │ ├── README.md │ ├── getCenterPoint.index.js │ └── getCenterPoint.spec.js ├── getConsolidatedTransformMatrix │ ├── README.md │ ├── getConsolidatedTransformMatrix.index.js │ └── getConsolidatedTransformMatrix.spec.js ├── getSetSVG │ ├── getSetSVG.index.js │ └── getSetSVG.spec.js ├── hasAttrNS │ ├── README.md │ ├── hasAttrNS.index.js │ └── hasAttrNS.spec.js ├── index.js ├── initMatrixTransform │ ├── README.md │ ├── initMatrixTransform.index.js │ └── initMatrixTransform.spec.js ├── initRotateTransform │ ├── README.md │ ├── initRotateTransform.index.js │ └── initRotateTransform.spec.js ├── initScaleTransform │ ├── README.md │ ├── initScaleTransform.index.js │ └── initScaleTransform.spec.js ├── initTranslateTransform │ ├── README.md │ ├── initTranslateTransform.index.js │ └── initTranslateTransform.spec.js ├── isIdentityMatrix │ ├── README.md │ ├── isIdentityMatrix.index.js │ └── isIdentityMatrix.spec.js ├── isMatrixSVGTransform │ ├── README.md │ ├── isMatrixSVGTransform.index.js │ └── isMatrixSVGTransform.spec.js ├── isRotateSVGTransform │ ├── README.md │ ├── isRotateSVGTransform.index.js │ └── isRotateSVGTransform.spec.js ├── isSVGTransform │ ├── README.md │ ├── isSVGTransform.index.js │ └── isSVGTransform.spec.js ├── isScaleSVGTransform │ ├── README.md │ ├── isScaleSVGTransform.index.js │ └── isScaleSVGTransform.spec.js ├── isTranslateSVGTransform │ ├── README.md │ ├── isTranslateSVGTransform.index.js │ └── isTranslateSVGTransform.spec.js ├── isValidFxScaleSVGTransformList │ ├── README.md │ ├── isValidFxScaleSVGTransformList.index.js │ └── isValidFxScaleSVGTransformList.spec.js ├── joinPathData │ ├── README.md │ ├── joinPathData.index.js │ └── joinPathData.spec.js ├── mergeRotateTransform │ ├── README.md │ ├── mergeRotateTransform.index.js │ └── mergeRotateTransform.spec.js ├── mergeScaleTransform │ ├── README.md │ ├── mergeScaleTransform.index.js │ └── mergeScaleTransform.spec.js ├── mergeScaleTransform2 │ ├── README.md │ ├── mergeScaleTransform2.index.js │ └── mergeScaleTransform2.spec.js ├── mergeTranslateTransform │ ├── README.md │ ├── mergeTranslateTransform.index.js │ └── mergeTranslateTransform.spec.js ├── parsePathData │ ├── README.md │ ├── const.js │ ├── parsePathData.index.js │ └── parsePathData.spec.js ├── removeAttrNS │ ├── README.md │ ├── removeAttrNS.index.js │ └── removeAttrNS.spec.js ├── setAttrNS │ ├── README.md │ ├── setAttrNS.index.js │ └── setAttrNS.spec.js ├── updateMatrixTransform │ ├── README.md │ ├── updateMatrixTransform.index.js │ └── updateMatrixTransform.spec.js ├── updateRotateTransform │ ├── README.md │ ├── updateRotateTransform.index.js │ └── updateRotateTransform.spec.js ├── updateScaleTransform │ ├── README.md │ ├── updateScaleTransform.index.js │ └── updateScaleTransform.sepc.js └── updateTranslateTransform │ ├── README.md │ ├── updateTranslateTransform.index.js │ └── updateTranslateTransform.spec.js └── test ├── assertions ├── expectSameNumberEpsilon.js ├── expectSameValueSVGMatrix.js ├── expectSameValueSVGTransform.js ├── expectTransformWithRotateAngleCxCy.js ├── expectTransformWithScaleSxSy.js ├── expectTransformWithTranslateTxTy.js └── index.js ├── index.html ├── index.json.html ├── mount_fxsvg_in_browser.js ├── playground.html ├── run_tests_in_browser.js ├── server.js ├── spec.js └── utils ├── deepCopyTransformList.js ├── index.js ├── makeAllCombinations.js ├── makeMockRect.js ├── makeMockRectInitializedRotateTransform.js ├── makeMockRectInitializedScaleTransform.js ├── makeMockRectInitializedTranslateTransform.js ├── makeRandomBool.js ├── makeRandomInt.js ├── makeRandomNumber.js ├── makeRandomNumberExcept.js ├── makeRandomSVGMatrix.js ├── makeRandomSVGTransformMatrix.js ├── makeRandomSVGTransformRotate.js ├── makeRandomSVGTransformScale.js ├── makeRandomSVGTransformTranslate.js ├── makeRandomTransformAttributeValue.js ├── makeRandomTransformString.js └── makeRandomTransformStringList.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | /.idea/ 107 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 MARPPLE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FxSVG 2 | 3 | [EN](./README.md) | [KR](./README_KR.md) 4 | 5 | Functional SVG Handling Library 6 | 7 | ## Installation 8 | 9 | FxSVG use the ECMAScript Module system. 10 | 11 | There are two type packages provided. 12 | 13 | - ECMAScript Module 14 | - bundle file for using in browser environment 15 | 16 | ### ECMAScript Module 17 | 18 | ```shell script 19 | npm install fxsvg 20 | ``` 21 | 22 | ```javascript 23 | import { $$createSVGTransformTranslate } from "fxsvg"; 24 | import FxSVG from "fxsvg"; 25 | 26 | const $el = document.querySelector("svg rect"); 27 | const transform = $$createSVGTransformTranslate({ tx: 10, ty: 20 }); 28 | FxSVG.getBaseTransformList($el).initialize(transform); 29 | ``` 30 | 31 | ### In a Browser 32 | 33 | FxSVG supports only modern browsers that follow the ECMAScript 6+ spec and SVG 1.1+ spec. 34 | 35 | FxSVG uses `$$` property of `window` object as a namespace for itself. 36 | 37 | ```shell script 38 | npm install fxsvg 39 | ``` 40 | 41 | ```html 42 | 43 | ``` 44 | 45 | ```javascript 46 | const { $$el } = $$; 47 | 48 | const $rect = $$el(``); 49 | const { controller } = $$.controlTranslateTransform()($rect); 50 | controller.append({ tx: 10 }).append({ ty: 10 }).end(); 51 | ``` 52 | 53 | ## Documentation 54 | 55 | - [Function Interface](./doc/FUNCTION_INTERFACE.md) 56 | - [API Reference](./doc/API.md) 57 | - [Test](./doc/TEST.md) 58 | 59 | ## Contributing 60 | 61 | FxSVG always welcome all the developers who want to join in. 62 | Please following the guide when you contribute. 63 | 64 | - [Contributing Guide](./doc/CONTRIBUTING.md) 65 | -------------------------------------------------------------------------------- /README_KR.md: -------------------------------------------------------------------------------- 1 | # FxSVG 2 | 3 | [EN](./README.md) | [KR](./README_KR.md) 4 | 5 | Functional SVG Handling Library 6 | 7 | ## Installation 8 | 9 | FxSVG는 ECMAScript Module 로 작성된 패키지입니다. 10 | 11 | 다음과 같은 형태로 패키지를 제공합니다. 12 | 13 | - ECMAScript Module 14 | - 브라우저에서 사용할 수 있는 번들링 파일 15 | 16 | ### ECMAScript Module 17 | 18 | ```shell script 19 | npm install fxsvg 20 | ``` 21 | 22 | ```javascript 23 | import { $$createSVGTransformTranslate } from "fxsvg"; 24 | import FxSVG from "fxsvg"; 25 | 26 | const $el = document.querySelector("svg rect"); 27 | const transform = $$createSVGTransformTranslate({ tx: 10, ty: 20 }); 28 | FxSVG.getBaseTransformList($el).initialize(transform); 29 | ``` 30 | 31 | ### In a Browser 32 | 33 | FxSVG는 SVG, ECMAScript 6+ 표준을 따르는 모던 브라우저만 지원합니다. 34 | 35 | FxSVG는 `window` 객체의 `$$` property를 namespace로 사용합니다. 36 | 37 | ```shell script 38 | npm install fxsvg 39 | ``` 40 | 41 | ```html 42 | 43 | ``` 44 | 45 | ```javascript 46 | const { $$el } = $$; 47 | 48 | const $rect = $$el(``); 49 | const { controller } = $$.controlTranslateTransform()($rect); 50 | controller.append({ tx: 10 }).append({ ty: 10 }).end(); 51 | ``` 52 | 53 | ## Documentation 54 | 55 | - [Function Interface](doc/FUNCTION_INTERFACE_KR.md) 56 | - [API Reference](./doc/API_KR.md) 57 | - [Test](./doc/TEST_KR.md) 58 | 59 | ## Contributing 60 | 61 | FxSVG 개발에 참여하고 싶은 모든 분들을 환영합니다. 62 | FxSVG 코드에 기여하고 싶은 분은 아래 가이드를 참고해주세요. 63 | 64 | - [Contributing Guide](./doc/CONTRIBUTING_KR.md) 65 | -------------------------------------------------------------------------------- /bin/build.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { Readable } from "stream"; 4 | import url from "url"; 5 | import webpack from "webpack"; 6 | 7 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 8 | 9 | const BROWSER_INDEX_FILENAME = "browser_index"; 10 | 11 | (async () => { 12 | fs.rmdirSync(path.resolve(__dirname, "../dist"), { 13 | recursive: true, 14 | maxRetries: 10, 15 | retryDelay: 300, 16 | }); 17 | fs.mkdirSync(path.resolve(__dirname, "../dist")); 18 | 19 | const browser_index_js = ` 20 | import $$ from "../src/index.js"; 21 | window.$$ = $$; 22 | `.trimStart(); 23 | Readable.from([browser_index_js]).pipe( 24 | fs.createWriteStream( 25 | path.resolve(__dirname, `../dist/${BROWSER_INDEX_FILENAME}.js`), 26 | { 27 | flags: "w", 28 | } 29 | ) 30 | ); 31 | 32 | await new Promise((resolve, reject) => 33 | webpack( 34 | { 35 | mode: "production", 36 | context: path.resolve(__dirname, "../"), 37 | entry: `./dist/${BROWSER_INDEX_FILENAME}.js`, 38 | output: { 39 | filename: "fxsvg.js", 40 | path: path.resolve(__dirname, "../dist"), 41 | }, 42 | }, 43 | (error, stats) => { 44 | if (error) { 45 | return reject(error); 46 | } 47 | 48 | const info = stats.toJson("verbose"); 49 | 50 | if (stats.hasErrors()) { 51 | const error = new Error(JSON.stringify(info, null, 2)); 52 | return reject(error); 53 | } 54 | 55 | resolve(info); 56 | } 57 | ) 58 | ); 59 | 60 | fs.unlinkSync( 61 | path.resolve(__dirname, `../dist/${BROWSER_INDEX_FILENAME}.js`) 62 | ); 63 | })(); 64 | -------------------------------------------------------------------------------- /doc/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | [EN](./CONTRIBUTING.md) | [KR](./CONTRIBUTING_KR.md) 4 | 5 | ## Test Code 6 | 7 | Please use `function() {}` when write test runner function for `mocha`. 8 | We have to use `this` to access `mocha`'s `context`. 9 | If you use arrow function, you cannot use `this`. 10 | -------------------------------------------------------------------------------- /doc/CONTRIBUTING_KR.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | [EN](./CONTRIBUTING.md) | [KR](./CONTRIBUTING_KR.md) 4 | 5 | ## Test Code 6 | 7 | 테스트 코드를 작성할 때 `mocha` 테스트 러너의 실행 함수는 모두 `function() {}` 으로 작성해주세요. 8 | `mocha`의 `context`에 접근하기 위해서는 `this` 키워드를 사용해야 합니다. 9 | 화살표 함수를 사용하면 `this` 키워드를 사용할 수 없어요! 10 | -------------------------------------------------------------------------------- /doc/FUNCTION_INTERFACE.md: -------------------------------------------------------------------------------- 1 | # Function Interface 2 | 3 | [EN](FUNCTION_INTERFACE.md) | [KR](FUNCTION_INTERFACE_KR.md) 4 | 5 | All functions of FxSVG have functional style interface. 6 | It takes sub-arguments first, then takes a target object. 7 | If it needs sub-arguments, you must curry the function. 8 | 9 | If you want, you can inject a svg element for the last parameter of the second function call. 10 | 11 | ```javascript 12 | const $svg = document.querySelector("svg"); 13 | const input = { a: 10, b: 11, c: 12, d: 13, e: 14, f: 15 }; 14 | 15 | console.log($$createSVGMatrix()()); 16 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} 17 | console.log($$createSVGMatrix()($svg)); 18 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} 19 | console.log($$createSVGMatrix(input)($svg)); 20 | // SVGMatrix {a: 10, b: 11, c: 12, d: 13, e: 14, f: 15} 21 | ``` 22 | 23 | ```javascript 24 | const $svg = document.querySelector("svg"); 25 | const transform = $svg.createSVGTransform(); 26 | transform.setTranslate(10, 20); 27 | const [tx, ty] = [100, 200]; 28 | 29 | console.log($$updateTranslateTransform({ tx, ty })(transform)); 30 | // SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 31 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 100, f: 200} 32 | ``` 33 | -------------------------------------------------------------------------------- /doc/FUNCTION_INTERFACE_KR.md: -------------------------------------------------------------------------------- 1 | # Function Interface 2 | 3 | [EN](FUNCTION_INTERFACE.md) | [KR](FUNCTION_INTERFACE_KR.md) 4 | 5 | FxSVG 의 함수는 함수형 스타일 인터페이스를 가지고 있습니다. 6 | 함수 실행에 필요한 보조 인자를 먼저 받고, 함수 실행의 대상이 되는 객체를 나중에 받습니다. 7 | 보조 인자가 필요한 모든 함수는 강제로 커링하여 사용해야 합니다. 8 | 9 | 내부적으로 svg 엘리먼트가 필요한 경우 두 번째 실행의 마지막 인자로 svg 엘리먼트를 주입할 수 있습니다. 10 | 11 | ```javascript 12 | const $svg = document.querySelector("svg"); 13 | const input = { a: 10, b: 11, c: 12, d: 13, e: 14, f: 15 }; 14 | 15 | console.log($$createSVGMatrix()()); 16 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} 17 | console.log($$createSVGMatrix()($svg)); 18 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} 19 | console.log($$createSVGMatrix(input)($svg)); 20 | // SVGMatrix {a: 10, b: 11, c: 12, d: 13, e: 14, f: 15} 21 | ``` 22 | 23 | ```javascript 24 | const $svg = document.querySelector("svg"); 25 | const transform = $svg.createSVGTransform(); 26 | transform.setTranslate(10, 20); 27 | const [tx, ty] = [100, 200]; 28 | 29 | console.log($$updateTranslateTransform({ tx, ty })(transform)); 30 | // SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 31 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 100, f: 200} 32 | ``` 33 | -------------------------------------------------------------------------------- /doc/TEST.md: -------------------------------------------------------------------------------- 1 | # Test 2 | 3 | [EN](./TEST.md) | [KR](./TEST_KR.md) 4 | 5 | We write unit tests for all functions in FxSVG. 6 | 7 | Unit test file name is `name.spec.js`. 8 | The test file is in the same directory where the function file(`name.index.js`) is. 9 | 10 | When you run tests, 11 | 12 | 1. run `npm run test:server` 13 | 2. go to `http://localhost:8080/test` 14 | -------------------------------------------------------------------------------- /doc/TEST_KR.md: -------------------------------------------------------------------------------- 1 | # Test 2 | 3 | [EN](./TEST.md) | [KR](./TEST_KR.md) 4 | 5 | FxSVG 의 모든 함수는 유닛 테스트를 작성하고 있습니다. 6 | 7 | 각 함수의 유닛 테스트는 함수 본체 파일(`name.index.js`) 과 같은 디렉토리에 `name.spec.js` 라는 이름의 파일에 작성합니다. 8 | 9 | 유닛 테스트를 실행하고 싶은 경우 10 | 11 | 1. `npm run test:server` 명령어를 실행하고 12 | 2. `http://localhost:8080/test` 로 접속하면 됩니다. 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fxsvg", 3 | "version": "0.4.17", 4 | "description": "Functional SVG Handling Library", 5 | "type": "module", 6 | "main": "./src/index.js", 7 | "files": [ 8 | "src", 9 | "dist" 10 | ], 11 | "scripts": { 12 | "np": "npx -p np -c 'np --branch master --yolo --no-publish --no-yarn'", 13 | "test:server": "node test/server.js", 14 | "test:client": "node bin/test.client.js", 15 | "test:client:headless": "node bin/test.client.js --headless", 16 | "build": "node bin/build.js" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/marpple/FxSVG.git" 21 | }, 22 | "keywords": [ 23 | "SVG" 24 | ], 25 | "author": "dev_marpple ", 26 | "maintainers": [ 27 | "dev_marpple ", 28 | "kunholee ", 29 | "daengdaenglee " 30 | ], 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/marpple/FxSVG/issues" 34 | }, 35 | "homepage": "https://github.com/marpple/FxSVG#readme", 36 | "devDependencies": { 37 | "chai": "^4.3.0", 38 | "express": "^4.17.1", 39 | "mocha": "^8.3.0", 40 | "playwright": "^1.8.1", 41 | "prettier": "2.2.1", 42 | "webpack": "^5.24.0", 43 | "webpack-dev-middleware": "^4.1.0", 44 | "yargs": "^16.2.0" 45 | }, 46 | "dependencies": { 47 | "fxdom": "^0.8.0", 48 | "fxjs": "^0.21.1" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Errors/CustomError.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Custom error class for FxSVG package. 3 | * This is the most base error representing custom errors. 4 | * 5 | * @extends {Error} 6 | */ 7 | export class CustomError extends Error { 8 | /** 9 | * 10 | * @param {string} [fn_path=""] - function name or path that the error is occurred. 11 | * @param {string} [description] 12 | */ 13 | constructor(fn_path = "", description) { 14 | const message = `Failed to execute '${fn_path}' (FxSVG)${ 15 | description ? `: ${description}` : "" 16 | }`; 17 | super(message); 18 | 19 | if (Error.captureStackTrace) { 20 | Error.captureStackTrace(this, CustomError); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Errors/IllegalArgumentError.js: -------------------------------------------------------------------------------- 1 | import { CustomError } from "./CustomError.js"; 2 | 3 | /** 4 | * Custom error class for representing that there are illegal arguments. 5 | * 6 | * @extends {CustomError} 7 | */ 8 | export class IllegalArgumentError extends CustomError { 9 | /** 10 | * 11 | * @param {string} fn_path - function name or path that the error is occurred. 12 | * @param {string|number} parameter_name - parameter name or parameter position number bound with the invalid argument. 13 | * @param {string} [detail_description] - reason why the argument is invalid. 14 | */ 15 | constructor(fn_path, parameter_name, detail_description) { 16 | const description = `parameter ${parameter_name} is invalid.${ 17 | detail_description ? `: ${detail_description}` : "" 18 | }`; 19 | super(fn_path, description); 20 | 21 | if (Error.captureStackTrace) { 22 | Error.captureStackTrace(this, IllegalArgumentError); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/LiveRotateTransform/LiveRotateTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$appendRotateTransform } from "../appendRotateTransform/appendRotateTransform.index.js"; 2 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 3 | import { $$initRotateTransform } from "../initRotateTransform/initRotateTransform.index.js"; 4 | import { $$LiveTransform } from "../LiveTransform/LiveTransform.index.js"; 5 | import { $$mergeRotateTransform } from "../mergeRotateTransform/mergeRotateTransform.index.js"; 6 | import { $$updateRotateTransform } from "../updateRotateTransform/updateRotateTransform.index.js"; 7 | 8 | export class $$LiveRotateTransform extends $$LiveTransform { 9 | constructor( 10 | { index = 0, cx = 0, cy = 0, angle = 0 } = {}, 11 | $el, 12 | $svg = $$getSVG() 13 | ) { 14 | super(); 15 | 16 | this.is_done = false; 17 | 18 | this.transform = $$initRotateTransform({ angle, index, cx, cy })($el, $svg); 19 | this.index = index; 20 | this.$el = $el; 21 | this.$svg = $svg; 22 | } 23 | 24 | static $$create({ index = 0, cx = 0, cy = 0, angle = 0 } = {}) { 25 | return ($el, $svg = $$getSVG()) => 26 | new $$LiveRotateTransform({ index, cx, cy, angle }, $el, $svg); 27 | } 28 | 29 | $$getIsDone() { 30 | return this.is_done; 31 | } 32 | 33 | $$done() { 34 | this.is_done = true; 35 | } 36 | 37 | $$update({ angle } = {}) { 38 | $$updateRotateTransform({ angle, cx: 0, cy: 0 })(this.transform); 39 | } 40 | 41 | $$append({ angle = 0 } = {}) { 42 | $$appendRotateTransform({ angle })(this.transform); 43 | } 44 | 45 | $$merge() { 46 | $$mergeRotateTransform({ index: this.index + 1 })(this.$el, this.$svg); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/LiveRotateTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$LiveRotateTransform 2 | 3 | - [source](./LiveRotateTransform.index.js) 4 | - [test](./LiveRotateTransform.spec.js) 5 | 6 | SVG Rotate Transform 을 다루기 위한 `$$LiveTransform` 인터페이스의 구현체입니다. 7 | -------------------------------------------------------------------------------- /src/LiveScaleTransform/LiveScaleTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 2 | import { $$initScaleTransform } from "../initScaleTransform/initScaleTransform.index.js"; 3 | import { $$LiveTransform } from "../LiveTransform/LiveTransform.index.js"; 4 | import { $$mergeScaleTransform } from "../mergeScaleTransform/mergeScaleTransform.index.js"; 5 | import { $$updateScaleTransform } from "../updateScaleTransform/updateScaleTransform.index.js"; 6 | 7 | export class $$LiveScaleTransform extends $$LiveTransform { 8 | constructor( 9 | { index = 0, cx = 0, cy = 0, sx = 1, sy = 1 } = {}, 10 | $el, 11 | $svg = $$getSVG() 12 | ) { 13 | super(); 14 | 15 | this.is_done = false; 16 | 17 | this.transform = $$initScaleTransform({ index, cx, cy, sx, sy })($el, $svg); 18 | this.index = index; 19 | this.$el = $el; 20 | this.$svg = $svg; 21 | } 22 | 23 | static $$create({ index = 0, sx = 1, sy = 1, cx = 0, cy = 0 } = {}) { 24 | return ($el, $svg = $$getSVG()) => 25 | new $$LiveScaleTransform({ index, sx, sy, cx, cy }, $el, $svg); 26 | } 27 | 28 | $$getIsDone() { 29 | return this.is_done; 30 | } 31 | 32 | $$done() { 33 | this.is_done = true; 34 | } 35 | 36 | $$update({ sx, sy } = {}) { 37 | $$updateScaleTransform({ sx, sy })(this.transform); 38 | } 39 | 40 | $$merge() { 41 | const { index, $el, $svg } = this; 42 | $$mergeScaleTransform({ index: index + 1 })($el, $svg); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/LiveScaleTransform/README.md: -------------------------------------------------------------------------------- 1 | ## \$\$LiveScaleTransform 2 | 3 | - [source](./LiveScaleTransform.index.js) 4 | - [test](./LiveScaleTransform.spec.js) 5 | 6 | SVG Scale Transform 을 다루기 위한 `$$LiveTransform` 인터페이스의 구현체입니다. 7 | -------------------------------------------------------------------------------- /src/LiveScaleTransform2/LiveScaleTransform2.index.js: -------------------------------------------------------------------------------- 1 | import { defaultTo } from "fxjs/es"; 2 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 3 | import { $$initScaleTransform } from "../initScaleTransform/initScaleTransform.index.js"; 4 | import { $$LiveTransform } from "../LiveTransform/LiveTransform.index.js"; 5 | import { $$mergeScaleTransform2 } from "../mergeScaleTransform2/mergeScaleTransform2.index.js"; 6 | import { $$updateScaleTransform } from "../updateScaleTransform/updateScaleTransform.index.js"; 7 | 8 | export class $$LiveScaleTransform2 extends $$LiveTransform { 9 | constructor( 10 | { 11 | index = 0, 12 | cx = 0, 13 | cy = 0, 14 | sx = 1, 15 | sy = 1, 16 | is_need_correction = true, 17 | x_name, 18 | y_name, 19 | width_name, 20 | height_name, 21 | direction, 22 | } = {}, 23 | $el, 24 | $svg = $$getSVG() 25 | ) { 26 | super(); 27 | 28 | this.is_done = false; 29 | 30 | this.transform = $$initScaleTransform({ sx, sy, cx, cy, index })($el, $svg); 31 | this.index = index; 32 | this.is_need_correction = is_need_correction; 33 | this.x_name = x_name; 34 | this.y_name = y_name; 35 | this.width_name = width_name; 36 | this.height_name = height_name; 37 | this.direction = direction; 38 | this.$el = $el; 39 | } 40 | 41 | static $$create({ 42 | index = 0, 43 | cx = 0, 44 | cy = 0, 45 | sx = 1, 46 | sy = 1, 47 | is_need_correction = true, 48 | x_name, 49 | y_name, 50 | width_name, 51 | height_name, 52 | direction, 53 | } = {}) { 54 | return ($el, $svg = $$getSVG()) => 55 | new $$LiveScaleTransform2( 56 | { 57 | index, 58 | cx, 59 | cy, 60 | sx, 61 | sy, 62 | is_need_correction, 63 | x_name, 64 | y_name, 65 | width_name, 66 | height_name, 67 | direction, 68 | }, 69 | $el, 70 | $svg 71 | ); 72 | } 73 | 74 | $$getIsDone() { 75 | return this.is_done; 76 | } 77 | 78 | $$done() { 79 | this.is_done = true; 80 | } 81 | 82 | $$update({ sx, sy } = {}) { 83 | $$updateScaleTransform({ sx, sy })(this.transform); 84 | } 85 | 86 | $$merge({ 87 | is_need_correction: is_need_correction1, 88 | x_name: x_name1, 89 | y_name: y_name1, 90 | width_name: width_name1, 91 | height_name: height_name1, 92 | direction: direction1, 93 | } = {}) { 94 | const { 95 | $el, 96 | index, 97 | is_need_correction: is_need_correction2, 98 | x_name: x_name2, 99 | y_name: y_name2, 100 | width_name: width_name2, 101 | height_name: height_name2, 102 | direction: direction2, 103 | } = this; 104 | const is_need_correction = defaultTo( 105 | is_need_correction2, 106 | is_need_correction1 107 | ); 108 | const x_name = defaultTo(x_name2, x_name1); 109 | const y_name = defaultTo(y_name2, y_name1); 110 | const width_name = defaultTo(width_name2, width_name1); 111 | const height_name = defaultTo(height_name2, height_name1); 112 | const direction = defaultTo(direction2, direction1); 113 | $$mergeScaleTransform2({ 114 | index: index + 1, 115 | is_need_correction, 116 | x_name, 117 | y_name, 118 | width_name, 119 | height_name, 120 | direction, 121 | })($el); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/LiveScaleTransform2/README.md: -------------------------------------------------------------------------------- 1 | # \$\$LiveScaleTransform2 2 | 3 | - [source](./LiveScaleTransform2.index.js) 4 | - [test](./LiveScaleTransform2.spec.js) 5 | 6 | SVG Scale Transform 을 다루기 위한 `$$LiveTransform` 인터페이스의 구현체입니다. 7 | `$$mergeScaleTransform2` 를 사용하는 버전입니다. 8 | -------------------------------------------------------------------------------- /src/LiveTransform/LiveTransform.index.js: -------------------------------------------------------------------------------- 1 | export class $$LiveTransform { 2 | $$getIsDone() {} 3 | 4 | $$done() {} 5 | 6 | $$update(option) {} 7 | 8 | $$append(option) {} 9 | 10 | $$merge(option) {} 11 | } 12 | -------------------------------------------------------------------------------- /src/LiveTransform/LiveTransform.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { $$LiveTransform } from "./LiveTransform.index.js"; 3 | 4 | const { expect } = chai; 5 | 6 | export default ({ describe, it }) => [ 7 | describe(`$$LiveTransform`, function () { 8 | it(`An instance has "$$getIsDone", "$$done", "$$update", "$$append", "$$merge" methods.`, function () { 9 | const live_transform = new $$LiveTransform(); 10 | 11 | expect(live_transform.$$getIsDone).a("function"); 12 | expect(live_transform.$$done).a("function"); 13 | expect(live_transform.$$update).a("function"); 14 | expect(live_transform.$$append).a("function"); 15 | expect(live_transform.$$merge).a("function"); 16 | }); 17 | }), 18 | ]; 19 | -------------------------------------------------------------------------------- /src/LiveTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$LiveTransform 2 | 3 | - [source](./LiveTransform.index.js) 4 | - [test](./LiveTransform.spec.js) 5 | 6 | `FxSVG` 에서 SVG Transform 을 쉽게 다루기 위한 인터페이스입니다. 7 | 해당 클래스를 상속받아 각 메소드를 올바르게 구현하면 `$$LiveTransformHandler` 에서 사용이 가능합니다. 8 | 9 | ## 메소드 명세 10 | 11 | ### \$\$getIsDone 12 | 13 | 해당 `$$LiveTransform` 객체가 live 상태인지 여부를 나타내는 불리언 값을 반환합니다. 14 | `true` 를 반환하면 `$$LiveTransformWrapper` 에서 더 이상 해당 객체를 수정하지 않습니다. 15 | 16 | ### \$\$done 17 | 18 | 해당 `$$LiveTransform` 객체를 done 상태로 변환합니다. 19 | 이 메소드가 호출된 이후부터는 `$$getIsDone` 메소드가 `true` 를 반환해야 합니다. 20 | 21 | ### $$update, $$append, \$\$merge 22 | 23 | 해당 `$$LiveTransform` 객체가 가지고 있는 `SVGTransform` 에 `update`, `append`, `merge` 연산을 적용합니다. 24 | 인자로 단일 `option` 객체를 받습니다. 25 | -------------------------------------------------------------------------------- /src/LiveTransformHandler/LiveTransformHandler.index.js: -------------------------------------------------------------------------------- 1 | export class $$LiveTransformHandler { 2 | static $$update(option) { 3 | return (live_transform_handler) => live_transform_handler.$$update(option); 4 | } 5 | 6 | static $$append(option) { 7 | return (live_transform_handler) => live_transform_handler.$$append(option); 8 | } 9 | 10 | static $$merge(option) { 11 | return (live_transform_handler) => live_transform_handler.$$merge(option); 12 | } 13 | 14 | static $$wrap(live_transform) { 15 | return new $$LiveTransformHandler(live_transform); 16 | } 17 | 18 | static $$unwrap(live_transform_handler) { 19 | if (!live_transform_handler.live_transform) { 20 | return; 21 | } 22 | 23 | live_transform_handler.live_transform.$$done(); 24 | return live_transform_handler.live_transform; 25 | } 26 | 27 | constructor(live_transform) { 28 | this.live_transform = live_transform; 29 | } 30 | 31 | $$update(option) { 32 | if (this.live_transform.$$getIsDone()) { 33 | return this; 34 | } 35 | 36 | this.live_transform.$$update(option); 37 | return this; 38 | } 39 | 40 | $$append(option) { 41 | if (this.live_transform.$$getIsDone()) { 42 | return this; 43 | } 44 | 45 | this.live_transform.$$append(option); 46 | return this; 47 | } 48 | 49 | $$merge(option) { 50 | if (this.live_transform.$$getIsDone()) { 51 | return this; 52 | } 53 | 54 | this.live_transform.$$merge(option); 55 | this.live_transform.$$done(); 56 | return this; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/LiveTransformHandler/README.md: -------------------------------------------------------------------------------- 1 | # \$\$LiveTransformHandler 2 | 3 | - [source](./LiveTransformHandler.index.js) 4 | - [test](./LiveTransformHandler.spec.js) 5 | 6 | `$$LiveTransform` 타입의 객체를 함수형 스타일로 쉽게 다루기 위한 보조 클래스입니다. 7 | 8 | `$$LiveTransform` 객체를 등록한 뒤 `static` 메소드를 사용하여 파이프라인 형태로 함수를 실행할 수 있습니다. 9 | 마지막엔 `$$LiveTransform` 객체를 다시 꺼내올 수 있습니다. 10 | 11 | ## 사용 방법 12 | 13 | 1. `$$wrap` static 메소드를 통해 `$$LiveTransform` 객체를 등록합니다. 14 | 2. `option` 객체와 반환된 `$$LiveTransformWrapper` 객체를 인자로 `$$update`, `$$append`, `$$merge` static 메소드를 사용합니다. 15 | 3. 각 메소드는 자기 자신을 반환합니다. 따라서 파이프라인에서 사용하거나 함수 인자로 중첩할 수 있습니다. 16 | 4. `$$unwrap` static 메소드를 통해 `$$LiveTransform` 객체를 꺼내옵니다. 17 | 18 | ## 주의 사항 19 | 20 | 1. `$$LiveTransform` 객체의 `$$getIsDone` 메소드가 `true` 를 반환하면 핸들러는 더 이상 아무 변경을 가하지 않습니다. 21 | 2. `$$merge` 메소드는 `$$LiveTransform` 객체의 `$$done` 메소드를 호출하므로 1번에 의해 이후 다른 메소드는 동작하지 않습니다. 22 | -------------------------------------------------------------------------------- /src/LiveTranslateTransform/LiveTranslateTransform.index.js: -------------------------------------------------------------------------------- 1 | import { defaultTo } from "fxjs/es"; 2 | import { $$appendTranslateTransform } from "../appendTranslateTransform/appendTranslateTransform.index.js"; 3 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 4 | import { $$initTranslateTransform } from "../initTranslateTransform/initTranslateTransform.index.js"; 5 | import { $$LiveTransform } from "../LiveTransform/LiveTransform.index.js"; 6 | import { $$mergeTranslateTransform } from "../mergeTranslateTransform/mergeTranslateTransform.index.js"; 7 | import { $$updateTranslateTransform } from "../updateTranslateTransform/updateTranslateTransform.index.js"; 8 | 9 | export class $$LiveTranslateTransform extends $$LiveTransform { 10 | constructor( 11 | { index = 0, tx = 0, ty = 0, x_name, y_name } = {}, 12 | $el, 13 | $svg = $$getSVG() 14 | ) { 15 | super(); 16 | 17 | this.is_done = false; 18 | 19 | this.transform = $$initTranslateTransform({ tx, ty, index })($el, $svg); 20 | this.x_name = x_name; 21 | this.y_name = y_name; 22 | this.index = index; 23 | this.$el = $el; 24 | this.$svg = $svg; 25 | } 26 | 27 | static $$create({ index = 0, tx = 0, ty = 0, x_name, y_name } = {}) { 28 | return ($el, $svg = $$getSVG()) => 29 | new $$LiveTranslateTransform( 30 | { index, tx, ty, x_name, y_name }, 31 | $el, 32 | $svg 33 | ); 34 | } 35 | 36 | $$getIsDone() { 37 | return this.is_done; 38 | } 39 | 40 | $$done() { 41 | this.is_done = true; 42 | } 43 | 44 | $$update({ tx, ty } = {}) { 45 | $$updateTranslateTransform({ tx, ty })(this.transform); 46 | } 47 | 48 | $$append({ tx = 0, ty = 0 } = {}) { 49 | $$appendTranslateTransform({ tx, ty })(this.transform); 50 | } 51 | 52 | $$merge({ x_name: x_name1, y_name: y_name1 } = {}) { 53 | const { x_name: x_name2, y_name: y_name2, index, $el, $svg } = this; 54 | const x_name = defaultTo(x_name2, x_name1); 55 | const y_name = defaultTo(y_name2, y_name1); 56 | if (x_name && y_name) { 57 | $$mergeTranslateTransform({ index, x_name, y_name })($el, $svg); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/LiveTranslateTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$LiveTranslateTransform 2 | 3 | - [source](./LiveTranslateTransform.index.js) 4 | - [test](./LiveTranslateTransform.spec.js) 5 | 6 | SVG Translate Transform 을 다루기 위한 `$$LiveTransform` 인터페이스의 구현체입니다. 7 | -------------------------------------------------------------------------------- /src/appendRotateTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$appendRotateTransform 2 | 3 | - [source](./appendRotateTransform.index.js) 4 | - [test](./appendRotateTransform.spec.js) 5 | 6 | `SVGTransform.SVG_TRANSFORM_ROTATE` 타입의 `SVGTransform` 의 `angle` 값을 수정합니다. 7 | 기존 `angle`에 입력받은 `angle`을 더한 값으로 수정합니다. 8 | `cx`, `cy`는 항상 `0`으로 고정됩니다. 9 | 회전 중심을 설정해야 할 경우 `SVGTransform.SVG_TRANSFORM_TRANSLATE` 타입의 `SVGTransform` 을 앞, 뒤로 추가하는 방삭을 사용합니다. 10 | 수정한 `SVGTransform` 객체를 반환합니다. 11 | 이 함수는 인자로 받은 `SVGTransform` 객체를 직접 수정합니다. 12 | 13 | ```javascript 14 | const transform = $$createSVGTransformRotate({ angle: 45 })(); 15 | console.log(transform); 16 | // SVGTransform {type: 4, matrix: SVGMatrix, angle: 45} 17 | $$appendRotateTransform({ angle: 30 })(transform); 18 | console.log(transform); 19 | // SVGTransform {type: 4, matrix: SVGMatrix, angle: 75} 20 | ``` 21 | -------------------------------------------------------------------------------- /src/appendRotateTransform/appendRotateTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$isRotateSVGTransform } from "../isRotateSVGTransform/isRotateSVGTransform.index.js"; 2 | 3 | export const $$appendRotateTransform = ({ angle = 0 } = {}) => (transform) => { 4 | if (!$$isRotateSVGTransform(transform)) { 5 | return transform; 6 | } 7 | 8 | const { angle: prev_angle } = transform; 9 | transform.setRotate(prev_angle + angle, 0, 0); 10 | return transform; 11 | }; 12 | -------------------------------------------------------------------------------- /src/appendTranslateTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$appendTranslateTransform 2 | 3 | - [source](./appendTranslateTransform.index.js) 4 | - [test](./appendTranslateTransform.spec.js) 5 | 6 | `SVGTransform.SVG_TRANSFORM_TRANSLATE` 타입의 `SVGTransform` 의 `tx`, `ty` 값을 수정합니다. 7 | 기존 `tx`, `ty`에 입력받은 `tx`, `ty`를 더한 결과로 수정합니다. 8 | 수정한 `SVGTransform` 객체를 반환합니다. 9 | 이 함수는 인자로 받은 `SVGTransform` 객체를 직접 수정합니다. 10 | 11 | ```javascript 12 | const transform = $$createSVGTransformTranslate({ tx: 10, ty: 20 })(); 13 | console.log(transform); 14 | // SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 15 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 16 | $$appendTranslateTransform({ tx: 100, ty: 200 })(transform); 17 | console.log(transform); 18 | // SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 19 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 110, f: 220} 20 | ``` 21 | -------------------------------------------------------------------------------- /src/appendTranslateTransform/appendTranslateTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$isTranslateSVGTransform } from "../isTranslateSVGTransform/isTranslateSVGTransform.index.js"; 2 | 3 | export const $$appendTranslateTransform = ({ tx = 0, ty = 0 } = {}) => ( 4 | transform 5 | ) => { 6 | if (!$$isTranslateSVGTransform(transform)) { 7 | return transform; 8 | } 9 | 10 | const { e: prev_tx, f: prev_ty } = transform.matrix; 11 | transform.setTranslate(prev_tx + tx, prev_ty + ty); 12 | return transform; 13 | }; 14 | -------------------------------------------------------------------------------- /src/consolidateTransformList/README.md: -------------------------------------------------------------------------------- 1 | # \$\$consolidateTransformList 2 | 3 | - [source](./consolidateTransformList.index.js) 4 | - [test](./consolidateTransformList.spec.js) 5 | 6 | `SVGTransformList` 객체의 모든 `SVGTransform` 객체를 하나로 통합하여 `SVGTransformList` 객체를 새로 초기화합니다. 7 | 이 함수는 입력받은 `SVGTransformList`를 수정합니다. 8 | 9 | ```javascript 10 | const str = ` 11 | 18 | 19 | `; 20 | const $el = $$el(str)(); 21 | 22 | console.log($$getBaseTransformList($el)); 23 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, length: 2, numberOfItems: 2} 24 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 25 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 400, f: 500} 26 | // 1: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 27 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 28 | 29 | $$consolidateTransformList($$getBaseTransformList($el)); 30 | 31 | console.log($$getBaseTransformList($el)); 32 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 33 | // 0: SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 34 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 400, f: 500} 35 | ``` 36 | -------------------------------------------------------------------------------- /src/consolidateTransformList/consolidateTransformList.index.js: -------------------------------------------------------------------------------- 1 | export const $$consolidateTransformList = (transform_list) => { 2 | const consolidated_transform = transform_list.consolidate(); 3 | 4 | if (!consolidated_transform) return transform_list; 5 | 6 | transform_list.initialize(consolidated_transform); 7 | return transform_list; 8 | }; 9 | -------------------------------------------------------------------------------- /src/consolidateTransformList/consolidateTransformList.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { go, mapL, reduce } from "fxjs/es"; 3 | import { expectSameValueSVGMatrix } from "../../test/assertions/index.js"; 4 | import { 5 | makeMockRect, 6 | makeRandomTransformAttributeValue, 7 | } from "../../test/utils/index.js"; 8 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 9 | import { $$consolidateTransformList } from "./consolidateTransformList.index.js"; 10 | 11 | const { expect } = chai; 12 | 13 | const setupMock = ({ transform = makeRandomTransformAttributeValue() } = {}) => 14 | $$getBaseTransformList(makeMockRect({ transform })); 15 | 16 | export default ({ describe, it }) => [ 17 | describe(`$$consolidateTransformList`, function () { 18 | it(`The return transform list is the same reference with the input transform list.`, function () { 19 | const input_list = setupMock(); 20 | 21 | const output_list = $$consolidateTransformList(input_list); 22 | 23 | expect(output_list).equal(input_list); 24 | }); 25 | 26 | it(`The return transform list has 0 or 1 transform.`, function () { 27 | const transform_cases = [ 28 | [null, 0], 29 | [makeRandomTransformAttributeValue(1), 1], 30 | ]; 31 | for (const [transform, n] of transform_cases) { 32 | const input_list = setupMock({ transform }); 33 | 34 | const output_list = $$consolidateTransformList(input_list); 35 | 36 | expect(output_list.numberOfItems).equal(n); 37 | } 38 | }); 39 | 40 | it(`The consolidated transform's matrix is same with the matrix from multiplying all transform's matrix.`, function () { 41 | const input_list = setupMock({ 42 | transform: makeRandomTransformAttributeValue(1, 10), 43 | }); 44 | const matrix = go( 45 | input_list, 46 | mapL(({ matrix: m }) => m), 47 | reduce((m1, m2) => m1.multiply(m2)) 48 | ); 49 | 50 | const output_list = $$consolidateTransformList(input_list); 51 | 52 | expectSameValueSVGMatrix(output_list.getItem(0).matrix, matrix); 53 | }); 54 | }), 55 | ]; 56 | -------------------------------------------------------------------------------- /src/convertClientToUserCoords/README.md: -------------------------------------------------------------------------------- 1 | # \$\$convertClientToUserCoords 2 | 3 | - [source](./convertClientToUserCoords.index.js) 4 | - [test](./convertClientToUserCoords.spec.js) 5 | 6 | CSSOM 의 client coordinate system 좌표를 SVG 의 user coordinate system 좌표로 변환합니다. 7 | -------------------------------------------------------------------------------- /src/convertClientToUserCoords/convertClientToUserCoords.index.js: -------------------------------------------------------------------------------- 1 | import { $$createSVGPoint } from "../createSVGPoint/createSVGPoint.index.js"; 2 | 3 | export const $$convertClientToUserCoords = ({ 4 | x: client_x = 0, 5 | y: client_y = 0, 6 | } = {}) => ($svg) => 7 | $$createSVGPoint({ x: client_x, y: client_y })($svg).matrixTransform( 8 | $svg.getScreenCTM().inverse() 9 | ); 10 | -------------------------------------------------------------------------------- /src/convertClientToUserCoords/convertClientToUserCoords.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { html } from "fxjs/es"; 3 | import { $$el } from "../el/el.index.js"; 4 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 5 | import { $$convertClientToUserCoords } from "./convertClientToUserCoords.index.js"; 6 | 7 | const { expect } = chai; 8 | 9 | const waitFor = (ms = 0) => 10 | new Promise((resolve) => setTimeout(() => resolve(), ms)); 11 | 12 | export default ({ describe, it }) => [ 13 | describe(`$$convertClientToUserCoords`, async function () { 14 | it(`The function returns a SVGPoint instance.`, async function () { 15 | this.slow(500); 16 | 17 | // given 18 | const svg_el = $$getSVG(); 19 | const client_x = 100; 20 | const client_y = 100; 21 | document.body.appendChild(svg_el); 22 | 23 | await waitFor(100); 24 | 25 | // when 26 | const user_point = $$convertClientToUserCoords({ 27 | x: client_x, 28 | y: client_y, 29 | })(svg_el); 30 | 31 | // then 32 | expect(user_point).instanceof(SVGPoint); 33 | 34 | document.body.removeChild(svg_el); 35 | }); 36 | 37 | it(`The function converts a point from CSSOM's client coordinate system 38 | to a point of SVG DOM's user coordinate system.`, async function () { 39 | this.slow(500); 40 | 41 | // given 42 | const svg_el = $$el( 43 | html`` 50 | )(); 51 | document.body.appendChild(svg_el); 52 | const client_x = 125; 53 | const client_y = 150; 54 | const expect_x = 500; 55 | const expect_y = 420; 56 | 57 | await waitFor(100); 58 | 59 | // when 60 | const point = $$convertClientToUserCoords({ x: client_x, y: client_y })( 61 | svg_el 62 | ); 63 | 64 | // then 65 | expect(point.x).equal(expect_x); 66 | expect(point.y).equal(expect_y); 67 | 68 | document.body.removeChild(svg_el); 69 | }); 70 | }), 71 | ]; 72 | -------------------------------------------------------------------------------- /src/createSVGMatrix/README.md: -------------------------------------------------------------------------------- 1 | # \$\$createSVGMatrix 2 | 3 | - [source](./createSVGMatrix.index.js) 4 | - [test](./createSVGMatrix.spec.js) 5 | 6 | `SVGMatrix` 객체를 생성합니다. 7 | 8 | ```javascript 9 | console.log($$createSVGMatrix()()); 10 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} 11 | ``` 12 | 13 | ```javascript 14 | console.log($$createSVGMatrix({ e: 10, f: 20 })()); 15 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 16 | ``` 17 | 18 | ```javascript 19 | console.log($$createSVGMatrix({ a: 2, b: 0, c: 0, d: 4, e: 10, f: 20 })()); 20 | // SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 10, f: 20} 21 | ``` 22 | 23 | ```javascript 24 | const $svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 25 | console.log($$createSVGMatrix({ a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 })($svg)); 26 | // SVGMatrix {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6} 27 | ``` 28 | -------------------------------------------------------------------------------- /src/createSVGMatrix/createSVGMatrix.index.js: -------------------------------------------------------------------------------- 1 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 2 | 3 | export const $$createSVGMatrix = ({ 4 | a = 1, 5 | b = 0, 6 | c = 0, 7 | d = 1, 8 | e = 0, 9 | f = 0, 10 | } = {}) => ($svg = $$getSVG()) => { 11 | const matrix = $svg.createSVGMatrix(); 12 | matrix.a = a; 13 | matrix.b = b; 14 | matrix.c = c; 15 | matrix.d = d; 16 | matrix.e = e; 17 | matrix.f = f; 18 | return matrix; 19 | }; 20 | -------------------------------------------------------------------------------- /src/createSVGMatrix/createSVGMatrix.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | appendL, 4 | defaultTo, 5 | extend, 6 | flatMapL, 7 | go, 8 | mapL, 9 | object, 10 | } from "fxjs/es"; 11 | import { expectSameValueSVGMatrix } from "../../test/assertions/index.js"; 12 | import { makeAllCombinations, makeRandomInt } from "../../test/utils/index.js"; 13 | import { $$createSVGMatrix } from "./createSVGMatrix.index.js"; 14 | 15 | const { expect } = chai; 16 | 17 | const makeCases = () => 18 | go( 19 | ["a", "b", "c", "d", "e", "f"], 20 | makeAllCombinations, 21 | mapL(mapL((k) => [k, makeRandomInt(-100, 100)])), 22 | mapL(object), 23 | mapL((values) => ({ values, f: $$createSVGMatrix(values) })), 24 | appendL({ f: $$createSVGMatrix() }), 25 | flatMapL(({ values, f }) => 26 | mapL(($svg) => ({ values, matrix: f($svg) }), [ 27 | undefined, 28 | document.createElementNS("http://www.w3.org/2000/svg", "svg"), 29 | ]) 30 | ) 31 | ); 32 | 33 | export default ({ describe, it }) => [ 34 | describe(`$$createSVGMatrix`, function () { 35 | it(`The return value is a SVGMatrix.`, function () { 36 | for (const { matrix } of makeCases()) { 37 | expect(matrix).instanceof(SVGMatrix); 38 | } 39 | }); 40 | 41 | it(`Each value of the matrix will be same with the given value. 42 | If there is omitted values or no argument, 43 | the values will be {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} individually by default.`, function () { 44 | this.slow(100); 45 | 46 | for (const { matrix, values } of makeCases()) { 47 | const expect_values = extend( 48 | { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 }, 49 | defaultTo({}, values) 50 | ); 51 | expectSameValueSVGMatrix(matrix, expect_values); 52 | } 53 | }); 54 | }), 55 | ]; 56 | -------------------------------------------------------------------------------- /src/createSVGPoint/README.md: -------------------------------------------------------------------------------- 1 | # \$\$createSVGPoint 2 | 3 | - [source](./createSVGPoint.index.js) 4 | - [test](./createSVGPoint.spec.js) 5 | 6 | `SVGPoint` 객체를 생성합니다. 7 | 입력받은 `x`, `y` 값을 설정합니다. 8 | 소수점 값의 정확도 차이가 발생할 수 있습니다. 9 | 10 | ```javascript 11 | console.log($$createSVGPoint()()); 12 | // SVGPoint {x: 0, y: 0} 13 | ``` 14 | 15 | ```javascript 16 | console.log($$createSVGPoint({ x: 10 })()); 17 | // SVGPoint {x: 10, y: 0} 18 | ``` 19 | 20 | ```javascript 21 | console.log($$createSVGPoint({ y: 10 })()); 22 | // SVGPoint {x: 0, y: 10} 23 | ``` 24 | 25 | ```javascript 26 | console.log($$createSVGPoint({ x: 10, y: 10 })()); 27 | // SVGPoint {x: 10, y: 10} 28 | ``` 29 | 30 | ```javascript 31 | const $svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 32 | console.log($$createSVGPoint({ x: 15, y: 20 })($svg)); 33 | // SVGPoint {x: 15, y: 20} 34 | ``` 35 | -------------------------------------------------------------------------------- /src/createSVGPoint/createSVGPoint.index.js: -------------------------------------------------------------------------------- 1 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 2 | 3 | export const $$createSVGPoint = ({ x = 0, y = 0 } = {}) => ( 4 | $svg = $$getSVG() 5 | ) => { 6 | const point = $svg.createSVGPoint(); 7 | point.x = x; 8 | point.y = y; 9 | return point; 10 | }; 11 | -------------------------------------------------------------------------------- /src/createSVGPoint/createSVGPoint.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | appendL, 4 | defaultTo, 5 | extend, 6 | flatMapL, 7 | go, 8 | mapL, 9 | object, 10 | } from "fxjs/es"; 11 | import { makeAllCombinations, makeRandomInt } from "../../test/utils/index.js"; 12 | import { $$createSVGPoint } from "./createSVGPoint.index.js"; 13 | 14 | const { expect } = chai; 15 | 16 | const makeCases = () => 17 | go( 18 | ["x", "y"], 19 | makeAllCombinations, 20 | mapL(mapL((k) => [k, makeRandomInt(-100, 100)])), 21 | mapL(object), 22 | mapL((values) => ({ values, f: $$createSVGPoint(values) })), 23 | appendL({ f: $$createSVGPoint() }), 24 | flatMapL(({ values, f }) => 25 | mapL(($svg) => ({ values, point: f($svg) }), [ 26 | undefined, 27 | document.createElementNS("http://www.w3.org/2000/svg", "svg"), 28 | ]) 29 | ) 30 | ); 31 | 32 | export default ({ describe, it }) => [ 33 | describe(`$$createSVGPoint`, function () { 34 | it(`The return value is a SVGPoint.`, function () { 35 | for (const { point } of makeCases()) { 36 | expect(point).instanceof(SVGPoint); 37 | } 38 | }); 39 | 40 | it(`Each value of the point will be same with the given value. 41 | If there is omitted values or no argument, 42 | the values will be {x: 0, y: 0} individually by default.`, function () { 43 | for (const { point, values } of makeCases()) { 44 | const expect_values = extend({ x: 0, y: 0 }, defaultTo({}, values)); 45 | expect(point.x).equal(expect_values.x); 46 | expect(point.y).equal(expect_values.y); 47 | } 48 | }); 49 | }), 50 | ]; 51 | -------------------------------------------------------------------------------- /src/createSVGRect/README.md: -------------------------------------------------------------------------------- 1 | # \$\$createSVGRect 2 | 3 | - [source](./createSVGRect.index.js) 4 | - [test](./createSVGRect.spec.js) 5 | 6 | `SVGRect` 객체를 생성합니다. 7 | 주어진 `x`, `y`, `width`, `height` 값을 설정합니다. 8 | 주어지지 않은 값은 `0` 으로 설정합니다. 9 | 10 | 입력한 `x`, `y`, `width`, `height` 값과 실제 적용된 값은 정확도 차이가 발생할 수 있습니다. 11 | 12 | ```javascript 13 | console.log($$createSVGRect()()); 14 | // SVGRect {x: 0, y: 0, width: 0, height: 0} 15 | ``` 16 | 17 | ```javascript 18 | console.log($$createSVGRect({ x: 10 })()); 19 | // SVGRect {x: 10, y: 0, width: 0, height: 0} 20 | ``` 21 | 22 | ```javascript 23 | console.log($$createSVGRect({ width: 100 })()); 24 | // SVGRect {x: 0, y: 0, width: 100, height: 0} 25 | ``` 26 | 27 | ```javascript 28 | console.log($$createSVGRect({ x: 10, y: 10, width: 100, height: 100 })()); 29 | // SVGRect {x: 10, y: 10, width: 100, height: 100} 30 | ``` 31 | 32 | ```javascript 33 | const $svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 34 | console.log($$createSVGRect({ x: 20, y: 20, width: 200, height: 200 })($svg)); 35 | // SVGRect {x: 20, y: 20, width: 200, height: 200} 36 | ``` 37 | -------------------------------------------------------------------------------- /src/createSVGRect/createSVGRect.index.js: -------------------------------------------------------------------------------- 1 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 2 | 3 | export const $$createSVGRect = ({ 4 | x = 0, 5 | y = 0, 6 | width = 0, 7 | height = 0, 8 | } = {}) => ($svg = $$getSVG()) => { 9 | const rect = $svg.createSVGRect(); 10 | rect.x = x; 11 | rect.y = y; 12 | rect.width = width; 13 | rect.height = height; 14 | return rect; 15 | }; 16 | -------------------------------------------------------------------------------- /src/createSVGRect/createSVGRect.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | appendL, 4 | defaultTo, 5 | extend, 6 | flatMapL, 7 | go, 8 | mapL, 9 | object, 10 | } from "fxjs/es"; 11 | import { makeAllCombinations, makeRandomInt } from "../../test/utils/index.js"; 12 | import { $$createSVGRect } from "./createSVGRect.index.js"; 13 | 14 | const { expect } = chai; 15 | 16 | const makeCases = () => 17 | go( 18 | ["x", "y", "width", "height"], 19 | makeAllCombinations, 20 | mapL(mapL((k) => [k, makeRandomInt()])), 21 | mapL(object), 22 | mapL((values) => ({ values, f: $$createSVGRect(values) })), 23 | appendL({ f: $$createSVGRect() }), 24 | flatMapL(({ values, f }) => 25 | mapL(($svg) => ({ values, rect: f($svg) }), [ 26 | undefined, 27 | document.createElementNS("http://www.w3.org/2000/svg", "svg"), 28 | ]) 29 | ) 30 | ); 31 | 32 | export default ({ describe, it }) => [ 33 | describe(`$$createSVGRect`, function () { 34 | it(`The return value is a SVGRect.`, function () { 35 | for (const { rect } of makeCases()) { 36 | expect(rect).instanceof(SVGRect); 37 | } 38 | }); 39 | 40 | it(`Each value of the rect will be same with the given value. 41 | If there is omitted values or no argument, 42 | the values will be {x: 0, y: 0, width: 0, height: 0} individually by default.`, function () { 43 | for (const { rect, values } of makeCases()) { 44 | const expect_values = extend( 45 | { x: 0, y: 0, width: 0, height: 0 }, 46 | defaultTo({}, values) 47 | ); 48 | expect(rect.x).equal(expect_values.x); 49 | expect(rect.y).equal(expect_values.y); 50 | expect(rect.width).equal(expect_values.width); 51 | expect(rect.height).equal(expect_values.height); 52 | } 53 | }); 54 | }), 55 | ]; 56 | -------------------------------------------------------------------------------- /src/createSVGTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$createSVGTransform 2 | 3 | - [source](./createSVGTransform.index.js) 4 | - [test](./createSVGTransform.spec.js) 5 | 6 | `SVGTransform` 객체를 생성합니다. 7 | `SVGTransform.SVG_TRANSFORM_MATRIX` 타입을 가집니다. 8 | `transform.matrix` 값으로 `SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0}` 을 가집니다. 9 | 10 | ```javascript 11 | console.log($$createSVGTransform()); 12 | // SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 13 | ``` 14 | 15 | ```javascript 16 | const $svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 17 | console.log($$createSVGTransform($svg)); 18 | // SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 19 | ``` 20 | -------------------------------------------------------------------------------- /src/createSVGTransform/createSVGTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 2 | 3 | export const $$createSVGTransform = ($svg = $$getSVG()) => 4 | $svg.createSVGTransform(); 5 | -------------------------------------------------------------------------------- /src/createSVGTransform/createSVGTransform.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { mapL } from "fxjs/es"; 3 | import { expectSameValueSVGMatrix } from "../../test/assertions/index.js"; 4 | import { $$isMatrixSVGTransform } from "../isMatrixSVGTransform/isMatrixSVGTransform.index.js"; 5 | import { $$isSVGTransform } from "../isSVGTransform/isSVGTransform.index.js"; 6 | import { $$createSVGTransform } from "./createSVGTransform.index.js"; 7 | 8 | const { expect } = chai; 9 | 10 | const IDENTITY_MATRIX_VALUE = { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 }; 11 | 12 | const makeCases = () => 13 | mapL($$createSVGTransform, [ 14 | undefined, 15 | document.createElementNS("http://www.w3.org/2000/svg", "svg"), 16 | ]); 17 | 18 | export default ({ describe, it }) => [ 19 | describe(`$$createSVGTransform`, function () { 20 | it(`The return value is a SVGTransform.`, function () { 21 | for (const transform of makeCases()) { 22 | expect($$isSVGTransform(transform)).true; 23 | } 24 | }); 25 | 26 | it(`The transform is initialized with an identity matrix.`, function () { 27 | for (const transform of makeCases()) { 28 | expect($$isMatrixSVGTransform(transform)).equal(true); 29 | expectSameValueSVGMatrix(transform.matrix, IDENTITY_MATRIX_VALUE); 30 | } 31 | }); 32 | }), 33 | ]; 34 | -------------------------------------------------------------------------------- /src/createSVGTransformMatrix/README.md: -------------------------------------------------------------------------------- 1 | # \$\$createSVGTransformMatrix 2 | 3 | - [source](./createSVGTransformMatrix.index.js) 4 | - [test](./createSVGTransformMatrix.spec.js) 5 | 6 | `type`이 `SVGTransform.SVG_TRANSFORM_MATRIX`인 `SVGTransform` 객체를 생성합니다. 7 | `SVGTransform`에 인자로 받은 `SVGMatrix`를 설정합니다. 8 | 9 | ```javascript 10 | const matrix = $$createSVGMatrix()(); 11 | console.log($$createSVGTransformMatrix({ matrix })()); 12 | // SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 13 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} 14 | ``` 15 | 16 | ```javascript 17 | const matrix = $$createSVGMatrix({ a: 2, b: 3, c: 4, d: 5, e: 6, f: 7 })(); 18 | console.log($$createSVGTransformMatrix({ matrix })()); 19 | // SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 20 | // SVGMatrix {a: 2, b: 3, c: 4, d: 5, e: 6, f: 7} 21 | ``` 22 | 23 | ```javascript 24 | const $svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 25 | const matrix = $$createSVGMatrix({ 26 | a: 12, 27 | b: 13, 28 | c: 14, 29 | d: 15, 30 | e: 16, 31 | f: 17, 32 | })(); 33 | console.log($$createSVGTransformMatrix({ matrix })($svg)); 34 | // SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 35 | // SVGMatrix {a: 12, b: 13, c: 14, d: 15, e: 16, f: 17} 36 | ``` 37 | -------------------------------------------------------------------------------- /src/createSVGTransformMatrix/createSVGTransformMatrix.index.js: -------------------------------------------------------------------------------- 1 | import { defaultTo } from "fxjs/es"; 2 | import { $$createSVGMatrix } from "../createSVGMatrix/createSVGMatrix.index.js"; 3 | import { $$createSVGTransform } from "../createSVGTransform/createSVGTransform.index.js"; 4 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 5 | 6 | export const $$createSVGTransformMatrix = ({ matrix } = {}) => ( 7 | $svg = $$getSVG() 8 | ) => { 9 | const transform = $$createSVGTransform($svg); 10 | transform.setMatrix(defaultTo($$createSVGMatrix()($svg), matrix)); 11 | return transform; 12 | }; 13 | -------------------------------------------------------------------------------- /src/createSVGTransformMatrix/createSVGTransformMatrix.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | appendL, 4 | defaultTo, 5 | extend, 6 | flatMapL, 7 | go, 8 | mapL, 9 | object, 10 | } from "fxjs/es"; 11 | import { expectSameValueSVGMatrix } from "../../test/assertions/index.js"; 12 | import { 13 | makeAllCombinations, 14 | makeRandomNumber, 15 | makeRandomSVGMatrix, 16 | } from "../../test/utils/index.js"; 17 | import { $$createSVGMatrix } from "../createSVGMatrix/createSVGMatrix.index.js"; 18 | import { $$isMatrixSVGTransform } from "../isMatrixSVGTransform/isMatrixSVGTransform.index.js"; 19 | import { $$createSVGTransformMatrix } from "./createSVGTransformMatrix.index.js"; 20 | 21 | const { expect } = chai; 22 | 23 | const makeCases = () => 24 | go( 25 | ["matrix"], 26 | makeAllCombinations, 27 | mapL( 28 | mapL((k) => [k, makeRandomSVGMatrix(() => makeRandomNumber(-100, 100))]) 29 | ), 30 | mapL(object), 31 | mapL((values) => ({ values, f: $$createSVGTransformMatrix(values) })), 32 | appendL({ f: $$createSVGTransformMatrix() }), 33 | flatMapL(({ values, f }) => 34 | mapL(($svg) => ({ values, transform: f($svg) }), [ 35 | undefined, 36 | document.createElementNS("http://www.w3.org/2000/svg", "svg"), 37 | ]) 38 | ) 39 | ); 40 | 41 | export default ({ describe, it }) => [ 42 | describe(`$$createSVGTransformMatrix`, function () { 43 | it(`The return value is a SVGTransform.`, function () { 44 | for (const { transform } of makeCases()) { 45 | expect(transform).instanceof(SVGTransform); 46 | } 47 | }); 48 | 49 | it(`The transform is a matrix transform.`, function () { 50 | for (const { transform } of makeCases()) { 51 | expect($$isMatrixSVGTransform(transform)).true; 52 | } 53 | }); 54 | 55 | it(`The transform is initialized with the given matrix. 56 | If there is omitted values or no argument, the transform is initialized with an identity matrix.`, function () { 57 | for (const { transform, values } of makeCases()) { 58 | const { matrix } = extend( 59 | { matrix: $$createSVGMatrix()() }, 60 | defaultTo({}, values) 61 | ); 62 | expectSameValueSVGMatrix(transform.matrix, matrix); 63 | } 64 | }); 65 | }), 66 | ]; 67 | -------------------------------------------------------------------------------- /src/createSVGTransformRotate/README.md: -------------------------------------------------------------------------------- 1 | # \$\$createSVGTransformRotate 2 | 3 | - [source](./createSVGTransformRotate.index.js) 4 | - [test](./createSVGTransformRotate.spec.js) 5 | 6 | `type`이 `SVGTransform.SVG_TRANSFORM_ROTATE`인 `SVGTransform` 객체를 생성합니다. 7 | `cx`, `cy`로 회전할 중심의 좌포를 설정하고 `angle`로 회전할 각도(`deg` 단위)를 설정합니다. 8 | `cx`, `cy`를 설정하지 않으면 `(0, 0)`으로 설정합니다. 9 | 10 | ```javascript 11 | console.log($$createSVGTransformRotate()()); 12 | // SVGTransform {type: 4, matrix: SVGMatrix, angle: 0} 13 | ``` 14 | 15 | ```javascript 16 | console.log($$createSVGTransformRotate({ angle: 45 })()); 17 | // SVGTransform {type: 4, matrix: SVGMatrix, angle: 45} 18 | ``` 19 | 20 | ```javascript 21 | console.log($$createSVGTransformRotate({ cx: 10, cy: 10, angle: 30 })()); 22 | // SVGTransform {type: 4, matrix: SVGMatrix, angle: 30} 23 | ``` 24 | 25 | ```javascript 26 | const $svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 27 | console.log($$createSVGTransformRotate({ cx: 20, cy: 20, angle: 60 })($svg)); 28 | // SVGTransform {type: 4, matrix: SVGMatrix, angle: 60} 29 | ``` 30 | -------------------------------------------------------------------------------- /src/createSVGTransformRotate/createSVGTransformRotate.index.js: -------------------------------------------------------------------------------- 1 | import { $$createSVGTransform } from "../createSVGTransform/createSVGTransform.index.js"; 2 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 3 | 4 | export const $$createSVGTransformRotate = ({ 5 | angle = 0, 6 | cx = 0, 7 | cy = 0, 8 | } = {}) => ($svg = $$getSVG()) => { 9 | const transform = $$createSVGTransform($svg); 10 | transform.setRotate(angle, cx, cy); 11 | return transform; 12 | }; 13 | -------------------------------------------------------------------------------- /src/createSVGTransformRotate/createSVGTransformRotate.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | appendL, 4 | defaultTo, 5 | extend, 6 | flatMapL, 7 | go, 8 | mapL, 9 | object, 10 | } from "fxjs/es"; 11 | import { expectSameValueSVGTransform } from "../../test/assertions/index.js"; 12 | import { 13 | makeAllCombinations, 14 | makeRandomNumber, 15 | } from "../../test/utils/index.js"; 16 | import { $$createSVGTransform } from "../createSVGTransform/createSVGTransform.index.js"; 17 | import { $$isRotateSVGTransform } from "../isRotateSVGTransform/isRotateSVGTransform.index.js"; 18 | import { $$isSVGTransform } from "../isSVGTransform/isSVGTransform.index.js"; 19 | import { $$createSVGTransformRotate } from "./createSVGTransformRotate.index.js"; 20 | 21 | const { expect } = chai; 22 | 23 | const makeCases = () => 24 | go( 25 | ["angle", "cx", "cy"], 26 | makeAllCombinations, 27 | mapL(mapL((k) => [k, makeRandomNumber(-100, 100)])), 28 | mapL(object), 29 | mapL((values) => ({ values, f: $$createSVGTransformRotate(values) })), 30 | appendL({ f: $$createSVGTransformRotate() }), 31 | flatMapL(({ values, f }) => 32 | mapL(($svg) => ({ values, transform: f($svg) }), [ 33 | undefined, 34 | document.createElementNS("http://www.w3.org/2000/svg", "svg"), 35 | ]) 36 | ) 37 | ); 38 | 39 | export default ({ describe, it }) => [ 40 | describe(`$$createSVGTransformRotate`, function () { 41 | it(`The return value is a SVGTransform.`, function () { 42 | for (const { transform } of makeCases()) { 43 | expect($$isSVGTransform(transform)).true; 44 | } 45 | }); 46 | 47 | it(`The transform's type is the SVGTransform.SVG_TRANSFORM_ROTATE.`, function () { 48 | for (const { transform } of makeCases()) { 49 | expect($$isRotateSVGTransform(transform)).true; 50 | } 51 | }); 52 | 53 | it(`The transform is initialized with the given angle, cx, cy. 54 | If there are omitted values or no argument, 55 | the values will be {angle: 0, cx: 0, cy: 0} individually by default.`, function () { 56 | for (const { transform, values } of makeCases()) { 57 | const { angle, cx, cy } = extend( 58 | { angle: 0, cx: 0, cy: 0 }, 59 | defaultTo({}, values) 60 | ); 61 | const expect_transform = $$createSVGTransform(); 62 | expect_transform.setRotate(angle, cx, cy); 63 | expectSameValueSVGTransform(transform, expect_transform); 64 | } 65 | }); 66 | }), 67 | ]; 68 | -------------------------------------------------------------------------------- /src/createSVGTransformScale/README.md: -------------------------------------------------------------------------------- 1 | # \$\$createSVGTransformScale 2 | 3 | - [source](./createSVGTransformScale.index.js) 4 | - [test](./createSVGTransformScale.spec.js) 5 | 6 | `type`이 `SVGTransform.SVG_TRANSFORM_SCALE`인 `SVGTransform` 객체를 생성합니다. 7 | `sx`로 x축 방향으로 확대할 비율을, `sy`로 y축 방향으로 확대할 비율을 설정합니다. 8 | `sx`, `sy`가 음수일 경우 해당 축을 기준으로 대칭이동합니다. 9 | 10 | 입력한 `sx`, `sy` 값과 실제 적용된 Transform 값은 정확도 차이가 발생할 수 있습니다. 11 | 12 | ```javascript 13 | console.log($$createSVGTransformScale()()); 14 | // SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 15 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0} 16 | ``` 17 | 18 | ```javascript 19 | console.log($$createSVGTransformScale({ sx: 2 })()); 20 | // SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 21 | // SVGMatrix {a: 2, b: 0, c: 0, d: 1, e: 0, f: 0} 22 | ``` 23 | 24 | ```javascript 25 | console.log($$createSVGTransformScale({ sx: 2, sy: 4 })()); 26 | // SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 27 | // SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 28 | ``` 29 | 30 | ```javascript 31 | const $svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 32 | console.log($$createSVGTransformScale({ sx: 3, sy: 5 })($svg)); 33 | // SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 34 | // SVGMatrix {a: 3, b: 0, c: 0, d: 5, e: 0, f: 0} 35 | ``` 36 | -------------------------------------------------------------------------------- /src/createSVGTransformScale/createSVGTransformScale.index.js: -------------------------------------------------------------------------------- 1 | import { $$createSVGTransform } from "../createSVGTransform/createSVGTransform.index.js"; 2 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 3 | 4 | export const $$createSVGTransformScale = ({ sx = 1, sy = 1 } = {}) => ( 5 | $svg = $$getSVG() 6 | ) => { 7 | const transform = $$createSVGTransform($svg); 8 | transform.setScale(sx, sy); 9 | return transform; 10 | }; 11 | -------------------------------------------------------------------------------- /src/createSVGTransformScale/createSVGTransformScale.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | appendL, 4 | defaultTo, 5 | extend, 6 | flatMapL, 7 | go, 8 | mapL, 9 | object, 10 | } from "fxjs/es"; 11 | import { expectSameValueSVGTransform } from "../../test/assertions/index.js"; 12 | import { makeAllCombinations, makeRandomInt } from "../../test/utils/index.js"; 13 | import { $$createSVGTransform } from "../createSVGTransform/createSVGTransform.index.js"; 14 | import { $$isScaleSVGTransform } from "../isScaleSVGTransform/isScaleSVGTransform.index.js"; 15 | import { $$isSVGTransform } from "../isSVGTransform/isSVGTransform.index.js"; 16 | import { $$createSVGTransformScale } from "./createSVGTransformScale.index.js"; 17 | 18 | const { expect } = chai; 19 | 20 | const makeCases = () => 21 | go( 22 | ["sx", "sy"], 23 | makeAllCombinations, 24 | mapL(mapL((k) => [k, makeRandomInt()])), 25 | mapL(object), 26 | mapL((values) => ({ values, f: $$createSVGTransformScale(values) })), 27 | appendL({ f: $$createSVGTransformScale() }), 28 | flatMapL(({ values, f }) => 29 | mapL(($svg) => ({ values, transform: f($svg) }), [ 30 | undefined, 31 | document.createElementNS("http://www.w3.org/2000/svg", "svg"), 32 | ]) 33 | ) 34 | ); 35 | 36 | export default ({ describe, it }) => [ 37 | describe(`$$createSVGTransformScale`, function () { 38 | it(`The return value is a SVGTransform.`, function () { 39 | for (const { transform } of makeCases()) { 40 | expect($$isSVGTransform(transform)).true; 41 | } 42 | }); 43 | 44 | it(`The transform's type is the SVGTransform.SVG_TRANSFORM_SCALE.`, function () { 45 | for (const { transform } of makeCases()) { 46 | expect($$isScaleSVGTransform(transform)).true; 47 | } 48 | }); 49 | 50 | it(`The transform is initialized with the given sx, sy. 51 | If there are omitted values or no argument, 52 | the values will be {sx: 1, sy: 1} individually by default.`, function () { 53 | for (const { transform, values } of makeCases()) { 54 | const { sx, sy } = extend({ sx: 1, sy: 1 }, defaultTo({}, values)); 55 | const expect_transform = $$createSVGTransform(); 56 | expect_transform.setScale(sx, sy); 57 | expectSameValueSVGTransform(transform, expect_transform); 58 | } 59 | }); 60 | }), 61 | ]; 62 | -------------------------------------------------------------------------------- /src/createSVGTransformTranslate/README.md: -------------------------------------------------------------------------------- 1 | # \$\$createSVGTransformTranslate 2 | 3 | - [source](./createSVGTransformTranslate.index.js) 4 | - [test](./createSVGTransformTranslate.spec.js) 5 | 6 | `type`이 `SVGTransform.SVG_TRANSFORM_TRANSLATE`인 `SVGTransform` 객체를 생성합니다. 7 | `tx`로 x축 방향으로 이동할 값, `ty`로 y축 방향으로 이동할 값을 설정합니다. 8 | 9 | 입력한 `tx`, `ty` 값과 실제 Transform 에 적용된 값은 정확도 차이가 발생할 수 있습니다. 10 | 11 | ```javascript 12 | console.log($$createSVGTransformTranslate()()); 13 | // SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 14 | ``` 15 | 16 | ```javascript 17 | console.log($$createSVGTransformTranslate({ tx: 10 })()); 18 | // SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 19 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 0} 20 | ``` 21 | 22 | ```javascript 23 | console.log($$createSVGTransformTranslate({ tx: 10, ty: 20 })()); 24 | // SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 25 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 26 | ``` 27 | 28 | ```javascript 29 | const $svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 30 | console.log($$createSVGTransformTranslate({ tx: 100, ty: 200 })($svg)); 31 | // SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 32 | // SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 100, f: 200} 33 | ``` 34 | -------------------------------------------------------------------------------- /src/createSVGTransformTranslate/createSVGTransformTranslate.index.js: -------------------------------------------------------------------------------- 1 | import { $$createSVGTransform } from "../createSVGTransform/createSVGTransform.index.js"; 2 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 3 | 4 | export const $$createSVGTransformTranslate = ({ tx = 0, ty = 0 } = {}) => ( 5 | $svg = $$getSVG() 6 | ) => { 7 | const transform = $$createSVGTransform($svg); 8 | transform.setTranslate(tx, ty); 9 | return transform; 10 | }; 11 | -------------------------------------------------------------------------------- /src/createSVGTransformTranslate/createSVGTransformTranslate.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | appendL, 4 | defaultTo, 5 | extend, 6 | flatMapL, 7 | go, 8 | mapL, 9 | object, 10 | } from "fxjs/es"; 11 | import { expectSameValueSVGTransform } from "../../test/assertions/index.js"; 12 | import { makeAllCombinations, makeRandomInt } from "../../test/utils/index.js"; 13 | import { $$createSVGTransform } from "../createSVGTransform/createSVGTransform.index.js"; 14 | import { $$isTranslateSVGTransform } from "../isTranslateSVGTransform/isTranslateSVGTransform.index.js"; 15 | import { $$createSVGTransformTranslate } from "./createSVGTransformTranslate.index.js"; 16 | 17 | const { expect } = chai; 18 | 19 | const makeCases = () => 20 | go( 21 | ["tx", "ty"], 22 | makeAllCombinations, 23 | mapL(mapL((k) => [k, makeRandomInt()])), 24 | mapL(object), 25 | mapL((values) => ({ values, f: $$createSVGTransformTranslate(values) })), 26 | appendL({ f: $$createSVGTransformTranslate() }), 27 | flatMapL(({ values, f }) => 28 | mapL(($svg) => ({ values, transform: f($svg) }), [ 29 | undefined, 30 | document.createElementNS("http://www.w3.org/2000/svg", "svg"), 31 | ]) 32 | ) 33 | ); 34 | 35 | export default ({ describe, it }) => [ 36 | describe(`$$createSVGTransformTranslate`, function () { 37 | it(`The return value is a SVGTransform.`, function () { 38 | for (const { transform } of makeCases()) { 39 | expect(transform).instanceof(SVGTransform); 40 | } 41 | }); 42 | 43 | it(`The transform's type is the SVGTransform.SVG_TRANSFORM_TRANSLATE.`, function () { 44 | for (const { transform } of makeCases()) { 45 | expect($$isTranslateSVGTransform(transform)).true; 46 | } 47 | }); 48 | 49 | it(`The transform is initialized with the given tx, ty. 50 | If there are omitted values or no argument, 51 | the values will be {tx: 0, ty: 0} individually by default.`, function () { 52 | for (const { transform, values } of makeCases()) { 53 | const { tx, ty } = extend({ tx: 0, ty: 0 }, defaultTo({}, values)); 54 | const expect_transform = $$createSVGTransform(); 55 | expect_transform.setTranslate(tx, ty); 56 | expectSameValueSVGTransform(transform, expect_transform); 57 | } 58 | }); 59 | }), 60 | ]; 61 | -------------------------------------------------------------------------------- /src/el/README.md: -------------------------------------------------------------------------------- 1 | # \$\$el 2 | 3 | - [source](./el.index.js) 4 | - [test](./el.spec.js) 5 | 6 | SVG 문자열을 받아 `SVGElement` 를 생성합니다. 7 | 8 | ```javascript 9 | console.log($$el('')()); 10 | // rect 11 | ``` 12 | 13 | ```javascript 14 | const str = 15 | ''; 16 | console.log($$el(str)()); 17 | // rect 18 | ``` 19 | -------------------------------------------------------------------------------- /src/el/el.index.js: -------------------------------------------------------------------------------- 1 | import { head } from "fxjs/es"; 2 | import { $$els } from "../els/els.index.js"; 3 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 4 | 5 | export const $$el = (svg) => ($svg = $$getSVG()) => head($$els(svg)($svg)); 6 | -------------------------------------------------------------------------------- /src/el/el.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { flatMapL, mapL } from "fxjs/es"; 3 | import { $$getAttrNS } from "../getAttrNS/getAttrNS.index.js"; 4 | import { $$el } from "./el.index.js"; 5 | 6 | const { expect } = chai; 7 | 8 | const MOCK_STR = ``; 9 | 10 | const setupSVGList = () => [ 11 | undefined, 12 | document.createElementNS("http://www.w3.org/2000/svg", "svg"), 13 | ]; 14 | 15 | const expectElFromMockStr = ($el) => { 16 | expect($el).instanceof(SVGElement); 17 | expect($el.nodeName.toLowerCase()).equal("circle"); 18 | expect($$getAttrNS("cx")($el)).equal("10"); 19 | expect($$getAttrNS("cy")($el)).equal("20"); 20 | expect($$getAttrNS("r")($el)).equal("30"); 21 | }; 22 | 23 | export default ({ describe, it }) => [ 24 | describe(`$$el`, function () { 25 | it(`The return value is a SVG element using the input SVG string.`, function () { 26 | for (const $svg of setupSVGList()) { 27 | const $el = $$el(MOCK_STR)($svg); 28 | 29 | expectElFromMockStr($el); 30 | } 31 | }); 32 | 33 | it(`The return value is the first element from the input SVG string. 34 | All other elements will be ignored.`, function () { 35 | const svg_str = `${MOCK_STR} 36 | `; 37 | for (const $svg of setupSVGList()) { 38 | const $el = $$el(svg_str)($svg); 39 | 40 | expectElFromMockStr($el); 41 | expect($el.nodeName.toLowerCase()).not.equal("rect"); 42 | } 43 | }); 44 | 45 | it(`The return value is undefined 46 | when the input SVG string is empty string or there is no input SVG string.`, function () { 47 | const cases = flatMapL( 48 | ($svg) => mapL((svg_str) => ({ svg_str, $svg }), ["", undefined]), 49 | setupSVGList() 50 | ); 51 | for (const { $svg, svg_str } of cases) { 52 | const $el = $$el(svg_str)($svg); 53 | 54 | expect($el).undefined; 55 | } 56 | }); 57 | }), 58 | ]; 59 | -------------------------------------------------------------------------------- /src/els/README.md: -------------------------------------------------------------------------------- 1 | # \$\$els 2 | 3 | - [source](./els.index.js) 4 | - [test](./els.spec.js) 5 | 6 | SVG 문자열을 받아 `SVGElement` 를 담은 배열을 생성합니다. 7 | 8 | ```javascript 9 | console.log($$els('')()); 10 | // [rect] 11 | ``` 12 | 13 | ```javascript 14 | const str = 15 | ''; 16 | console.log($$els(str)()); 17 | // [rect, circle] 18 | ``` 19 | -------------------------------------------------------------------------------- /src/els/els.index.js: -------------------------------------------------------------------------------- 1 | import { each } from "fxjs/es"; 2 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 3 | 4 | export const $$els = (svg = "") => ($svg = $$getSVG()) => { 5 | svg = svg.trim(); 6 | $svg.innerHTML = svg; 7 | const result = each(($el) => $svg.removeChild($el), [...$svg.children]); 8 | $svg.innerHTML = ""; 9 | return result; 10 | }; 11 | -------------------------------------------------------------------------------- /src/els/els.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | entriesL, 4 | equals2, 5 | flatMapL, 6 | go, 7 | join, 8 | map, 9 | mapL, 10 | rangeL, 11 | zip, 12 | } from "fxjs/es"; 13 | import { makeRandomInt } from "../../test/utils/makeRandomInt.js"; 14 | import { $$getAttrNS } from "../getAttrNS/getAttrNS.index.js"; 15 | import { $$els } from "./els.index.js"; 16 | 17 | const { expect } = chai; 18 | 19 | const setupSVGList = () => [ 20 | undefined, 21 | document.createElementNS("http://www.w3.org/2000/svg", "svg"), 22 | ]; 23 | 24 | const setupMockIntString = (len, min = -100, max = 100) => 25 | go( 26 | rangeL(len), 27 | mapL(() => makeRandomInt(min, max)), 28 | mapL((n) => `${n}`) 29 | ); 30 | 31 | export default ({ describe, it }) => [ 32 | describe(`$$els`, function () { 33 | it(`The return value is a list of SVG elements using the input SVG string.`, function () { 34 | this.slow(1000); 35 | 36 | const list = go( 37 | rangeL(makeRandomInt(1)), 38 | mapL(() => makeRandomInt(0, 3)), 39 | map((flag) => { 40 | if (equals2(flag, 1)) { 41 | const [cx, cy] = setupMockIntString(2); 42 | const r = `${makeRandomInt(1)}`; 43 | const clazz = "circle dot"; 44 | return { 45 | name: "circle", 46 | attrs: { cx, cy, r, class: clazz }, 47 | str: ``, 48 | }; 49 | } 50 | 51 | if (equals2(flag, 2)) { 52 | const [cx, cy] = setupMockIntString(2); 53 | const [rx, ry] = setupMockIntString(2, 1); 54 | const style = "stroke: red;"; 55 | return { 56 | name: "ellipse", 57 | attrs: { cx, cy, rx, ry, style }, 58 | str: ``, 59 | }; 60 | } 61 | 62 | const [x, y] = setupMockIntString(2); 63 | const [width, height] = setupMockIntString(2, 1); 64 | return { 65 | name: "rect", 66 | attrs: { x, y, width, height }, 67 | str: ``, 68 | }; 69 | }) 70 | ); 71 | const svg_str = go( 72 | list, 73 | mapL(({ str }) => str), 74 | join("\n") 75 | ); 76 | 77 | for (const $svg of setupSVGList()) { 78 | const $list_el = $$els(svg_str)($svg); 79 | 80 | expect($list_el.length).equal(list.length); 81 | for (const [{ name, attrs }, $el] of zip(list, $list_el)) { 82 | expect($el).instanceof(SVGElement); 83 | expect($el.nodeName.toLowerCase()).equal(name); 84 | for (const [key, expect_value] of entriesL(attrs)) { 85 | const receive_value = $$getAttrNS(key)($el); 86 | expect(receive_value).equal(expect_value); 87 | } 88 | } 89 | } 90 | }); 91 | 92 | it(`The return value is a empty list 93 | when the input SVG string is empty string or there is no input SVG string.`, function () { 94 | const cases = flatMapL( 95 | ($svg) => mapL((svg_str) => ({ svg_str, $svg }), ["", undefined]), 96 | setupSVGList() 97 | ); 98 | 99 | for (const { $svg, svg_str } of cases) { 100 | const $list_el = $$els(svg_str)($svg); 101 | 102 | expect($list_el.length).equal(0); 103 | } 104 | }); 105 | }), 106 | ]; 107 | -------------------------------------------------------------------------------- /src/getAnimTransformList/README.md: -------------------------------------------------------------------------------- 1 | # \$\$getAnimTransformList 2 | 3 | - [source](./getAnimTransformList.index.js) 4 | - [test](./getAnimTransformList.spec.js) 5 | 6 | 입력받은 svg 객체의 `transform.animVal` 값을 반환합니다. 7 | 8 | `SVGGraphicsElement` 인터페이스는 `transform` 속성으로 `SVGAnimatedTransformList` 객체를 가지고 있고 9 | 해당 객체는 `animVal` 속성으로 `SVGTransformList` 객체를 가지고 있습니다. 10 | 11 | `animVal`은 SMIL 애니메이션이 적용된 경우에만 `baseVal`과 다릅니다. 특별한 상황이 아닌 한 동일한 값을 가집니다. 12 | 하지만 값은 동일해도 다른 래퍼런스를 가리킵니다. 13 | 14 | ```javascript 15 | const str = ` 16 | 23 | 24 | `; 25 | const $el = $$el(str)(); 26 | console.log($$getAnimTransformList($el)); 27 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, 2: SVGTransform, length: 3, numberOfItems: 3} 28 | // 0: SVGTransform - type: SVG_TRANSFORM_TRANSLATE 29 | // 1: SVGTransform - type: SVG_TRANSFORM_ROTATE 30 | // 2: SVGTransform - type: SVG_TRANSFORM_SCALE 31 | ``` 32 | -------------------------------------------------------------------------------- /src/getAnimTransformList/getAnimTransformList.index.js: -------------------------------------------------------------------------------- 1 | import { sel } from "fxjs/es"; 2 | 3 | export const $$getAnimTransformList = ($el) => sel("transform.animVal", $el); 4 | -------------------------------------------------------------------------------- /src/getAnimTransformList/getAnimTransformList.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { defaultTo, equals2, go, join, mapL, rangeL, zipL } from "fxjs/es"; 3 | import { expectSameValueSVGTransform } from "../../test/assertions/index.js"; 4 | import { 5 | makeMockRect, 6 | makeRandomInt, 7 | makeRandomTransformString, 8 | } from "../../test/utils/index.js"; 9 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 10 | import { $$getAnimTransformList } from "./getAnimTransformList.index.js"; 11 | 12 | const { expect } = chai; 13 | 14 | export default ({ describe, it }) => [ 15 | describe(`$$getAnimTransformList`, function () { 16 | it(`The return transform list is same with the base transform list if there is no animation.`, function () { 17 | const $el = go( 18 | makeRandomInt(), 19 | rangeL, 20 | mapL(() => makeRandomInt(0, 3)), 21 | mapL((flag) => { 22 | if (equals2(flag, 1)) { 23 | return `skewX(${makeRandomInt(-700, 700)})`; 24 | } 25 | 26 | if (equals2(flag, 2)) { 27 | return `skewY(${makeRandomInt(-700, 700)})`; 28 | } 29 | 30 | return makeRandomTransformString(() => makeRandomInt(-700, 700)); 31 | }), 32 | join(" "), 33 | defaultTo(null), 34 | (transform) => makeMockRect({ transform }) 35 | ); 36 | const base_transform_list = [...$$getBaseTransformList($el)]; 37 | const anim_transform_list = [...$$getAnimTransformList($el)]; 38 | 39 | expect(anim_transform_list.length).equal(base_transform_list.length); 40 | const pairs = zipL(base_transform_list, anim_transform_list); 41 | for (const [base_transform, anim_transform] of pairs) { 42 | expectSameValueSVGTransform(anim_transform, base_transform); 43 | } 44 | }); 45 | }), 46 | ]; 47 | -------------------------------------------------------------------------------- /src/getAttrNS/README.md: -------------------------------------------------------------------------------- 1 | # \$\$getAttrNS 2 | 3 | - [source](./getAttrNS.index.js) 4 | - [test](./getAttrNS.spec.js) 5 | 6 | SVG 엘리먼트의 속성에 해당하는 값을 반환합니다. 해당하는 속성이 없으면 `null`을 반환합니다. 7 | 필요한 경우 namespace 를 지정하여 사용할 수 있습니다. 8 | 9 | ```javascript 10 | const el = $$el(``)(); 11 | 12 | console.log($$hasAttrNS("data-foo")(el)); 13 | // "bar" 14 | 15 | console.log($$hasAttrNS("data-baz")(el)); 16 | // null 17 | ``` 18 | -------------------------------------------------------------------------------- /src/getAttrNS/getAttrNS.index.js: -------------------------------------------------------------------------------- 1 | export const $$getAttrNS = (key, namespace = null) => (el) => 2 | el.getAttributeNS(namespace, key); 3 | -------------------------------------------------------------------------------- /src/getAttrNS/getAttrNS.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { $$el } from "../el/el.index.js"; 3 | import { $$getAttrNS } from "./getAttrNS.index.js"; 4 | 5 | const { expect } = chai; 6 | 7 | export default ({ describe, it }) => [ 8 | describe(`$$getAttrNS`, function () { 9 | it(`The function return the attribute value of the element.`, function () { 10 | // given 11 | const key = "data-foo"; 12 | const value = "bar"; 13 | const el = $$el( 14 | `` 15 | )(); 16 | 17 | // when 18 | const received_value = $$getAttrNS(key)(el); 19 | 20 | // then 21 | expect(received_value).equal(value); 22 | }); 23 | 24 | it(`The function return "null" for the non-existing attribute.`, function () { 25 | // given 26 | const el = $$el(``)(); 27 | 28 | // when 29 | const received_value = $$getAttrNS("data-foo")(el); 30 | 31 | // then 32 | expect(received_value).null; 33 | }); 34 | }), 35 | ]; 36 | -------------------------------------------------------------------------------- /src/getBaseTransformList/README.md: -------------------------------------------------------------------------------- 1 | # \$\$getBaseTransformList 2 | 3 | - [source](./getBaseTransformList.index.js) 4 | - [test](./getBaseTransformList.spec.js) 5 | 6 | 입력받은 svg 객체의 `transform.baseVal` 값을 반환합니다. 7 | 8 | `SVGGraphicsElement` 인터페이스는 `transform` 속성으로 `SVGAnimatedTransformList` 객체를 가지고 있고 9 | 해당 객체는 `baseVal` 속성으로 `SVGTransformList` 객체를 가지고 있습니다. 10 | 11 | ```javascript 12 | const str = ` 13 | 20 | 21 | `; 22 | const $el = $$el(str)(); 23 | console.log($$getBaseTransformList($el)); 24 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, 2: SVGTransform, length: 3, numberOfItems: 3} 25 | // 0: SVGTransform - type: SVG_TRANSFORM_TRANSLATE 26 | // 1: SVGTransform - type: SVG_TRANSFORM_ROTATE 27 | // 2: SVGTransform - type: SVG_TRANSFORM_SCALE 28 | ``` 29 | -------------------------------------------------------------------------------- /src/getBaseTransformList/getBaseTransformList.index.js: -------------------------------------------------------------------------------- 1 | import { sel } from "fxjs/es"; 2 | 3 | export const $$getBaseTransformList = ($el) => sel("transform.baseVal", $el); 4 | -------------------------------------------------------------------------------- /src/getBoundingPoints/README.md: -------------------------------------------------------------------------------- 1 | # \$\$getBoundingPoints 2 | 3 | - [source](./getBoundingPoints.index.js) 4 | - [test](./getBoundingPoints.spec.js) 5 | 6 | 입력한 point 목록에서 x, y 의 개별 최솟값, 최댓값으로 이루어진 min, max point 를 반환합니다. 7 | x, y 는 독립적으로 비교됩니다. 따라서 반환된 point 는 입력한 point 목록에 없을 수 있습니다. 8 | -------------------------------------------------------------------------------- /src/getBoundingPoints/getBoundingPoints.index.js: -------------------------------------------------------------------------------- 1 | import { reduce } from "fxjs/es"; 2 | 3 | export const $$getBoundingPoints = (points = []) => 4 | reduce( 5 | (acc, { x, y }) => { 6 | acc[0].x = Math.min(acc[0].x, x); 7 | acc[0].y = Math.min(acc[0].y, y); 8 | acc[1].x = Math.max(acc[1].x, x); 9 | acc[1].y = Math.max(acc[1].y, y); 10 | return acc; 11 | }, 12 | [ 13 | { x: Infinity, y: Infinity }, 14 | { x: -Infinity, y: -Infinity }, 15 | ], 16 | points 17 | ); 18 | -------------------------------------------------------------------------------- /src/getBoundingPoints/getBoundingPoints.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { equals2, go, map, mapL, rangeL } from "fxjs/es"; 3 | import { makeRandomInt } from "../../test/utils/makeRandomInt.js"; 4 | import { makeRandomNumber } from "../../test/utils/makeRandomNumber.js"; 5 | import { $$getBoundingPoints } from "./getBoundingPoints.index.js"; 6 | 7 | const { expect } = chai; 8 | 9 | export default ({ describe, it }) => [ 10 | describe(`$$getBoundingPoints`, function () { 11 | it(`The function returns two points whose x, y are min and max within the given points.`, function () { 12 | // given 13 | const min_x = makeRandomNumber(-700, 700); 14 | const min_y = makeRandomNumber(-700, 700); 15 | const max_x = makeRandomNumber(min_x + 1, 1400); 16 | const max_y = makeRandomNumber(min_y + 1, 1400); 17 | const points = go( 18 | makeRandomInt(1), 19 | rangeL, 20 | mapL(() => makeRandomInt(0, 5)), 21 | map((flag) => { 22 | if (equals2(flag, 1)) { 23 | const x = min_x; 24 | const y = makeRandomNumber(min_y, max_y); 25 | return { 26 | x, 27 | y, 28 | }; 29 | } 30 | 31 | if (equals2(flag, 2)) { 32 | const x = max_x; 33 | const y = makeRandomNumber(min_y, max_y); 34 | return { 35 | x, 36 | y, 37 | }; 38 | } 39 | 40 | if (equals2(flag, 3)) { 41 | const x = makeRandomNumber(min_x, max_x); 42 | const y = min_y; 43 | return { 44 | x, 45 | y, 46 | }; 47 | } 48 | 49 | if (equals2(flag, 4)) { 50 | const x = makeRandomNumber(min_x, max_x); 51 | const y = max_y; 52 | return { 53 | x, 54 | y, 55 | }; 56 | } 57 | 58 | const x = makeRandomNumber(min_x, max_x); 59 | const y = makeRandomNumber(min_y, max_y); 60 | return { 61 | x, 62 | y, 63 | }; 64 | }) 65 | ); 66 | 67 | // when 68 | const [min, max] = $$getBoundingPoints(points); 69 | 70 | // then 71 | expect(min.x).equal(min_x); 72 | expect(min.y).equal(min_y); 73 | expect(max.x).equal(max_x); 74 | expect(max.y).equal(max_y); 75 | }); 76 | }), 77 | ]; 78 | -------------------------------------------------------------------------------- /src/getBoxPoints/README.md: -------------------------------------------------------------------------------- 1 | # \$\$getBoxPoints 2 | 3 | - [source](./getBoxPoints.index.js) 4 | - [test](./getBoxPoints.spec.js) 5 | 6 | svg 객체의 영역에 해당하는 `SVGPoint`들을 반환합니다. 해당 svg 객체는 DOM 트리의 `` 태그에 속해 있어야 합니다. 7 | 8 | `original` 속성은 svg 객체가 `transform` 하기 전 영역입니다. 9 | `transformed` 속성은 svg 객체가 `transform` 한 후 영역입니다. 10 | `bounding` 속성은 svg 객체가 `transform` 한 후 영역을 덮는 최소 직사각형 영역입니다. 11 | 12 | ```javascript 13 | const str = ` 14 | 21 | 22 | `; 23 | const $el = $$el(str)(); 24 | $$append($el)($svg); 25 | console.log($$getBoxPoints($el)); 26 | // {original: {...}, transformed: {...}, bounding: {...}} 27 | // original: 28 | // top_left: SVGPoint {x: 10, y: 20} 29 | // top_right: SVGPoint {x: 110, y: 20} 30 | // bottom_left: SVGPoint {x: 10, y: 220} 31 | // bottom_right: SVGPoint {x: 110, y: 220} 32 | // transformed: 33 | // top_left: SVGPoint {x: 410, y: 520} 34 | // top_right: SVGPoint {x: 510, y: 520} 35 | // bottom_left: SVGPoint {x: 410, y: 720} 36 | // bottom_right: SVGPoint {x: 510, y: 720} 37 | // bounding: 38 | // min: SVGPoint {x: 410, y: 520} 39 | // max: SVGPoint {x: 510, y: 720} 40 | ``` 41 | -------------------------------------------------------------------------------- /src/getBoxPoints/getBoxPoints.index.js: -------------------------------------------------------------------------------- 1 | import { go, go1, map, mapL, rangeL, reduce } from "fxjs/es"; 2 | import { $$createSVGPoint } from "../createSVGPoint/createSVGPoint.index.js"; 3 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 4 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 5 | 6 | const $$getOriginalBoxPoints = ($el, $svg = $$getSVG()) => { 7 | const { x, y, width, height } = $el.getBBox(); 8 | 9 | const top_left = $$createSVGPoint({ x, y })($svg); 10 | const top_right = $$createSVGPoint({ x: x + width, y })($svg); 11 | const bottom_left = $$createSVGPoint({ x, y: y + height })($svg); 12 | const bottom_right = $$createSVGPoint({ x: x + width, y: y + height })($svg); 13 | 14 | return { top_left, top_right, bottom_left, bottom_right }; 15 | }; 16 | 17 | const $$getTransformedBoxPoints = ({ 18 | top_left: original_top_left, 19 | top_right: original_top_right, 20 | bottom_right: original_bottom_right, 21 | bottom_left: original_bottom_left, 22 | }) => ($el) => { 23 | const transform_list = $$getBaseTransformList($el); 24 | const merged_matrix = go( 25 | rangeL(transform_list.numberOfItems), 26 | mapL((i) => transform_list.getItem(i)), 27 | mapL(({ matrix: m }) => m), 28 | reduce((m1, m2) => m1.multiply(m2)) 29 | ); 30 | const [top_left, top_right, bottom_left, bottom_right] = mapL( 31 | (p) => (merged_matrix ? p.matrixTransform(merged_matrix) : p), 32 | [ 33 | original_top_left, 34 | original_top_right, 35 | original_bottom_left, 36 | original_bottom_right, 37 | ] 38 | ); 39 | 40 | return { 41 | top_left, 42 | top_right, 43 | bottom_left, 44 | bottom_right, 45 | }; 46 | }; 47 | 48 | const $$getBoundingBoxPoints = ({ 49 | top_left: transformed_top_left, 50 | top_right: transformed_top_right, 51 | bottom_right: transformed_bottom_right, 52 | bottom_left: transformed_bottom_left, 53 | }) => ($el, $svg = $$getSVG()) => { 54 | const points = [ 55 | transformed_top_left, 56 | transformed_top_right, 57 | transformed_bottom_left, 58 | transformed_bottom_right, 59 | ]; 60 | const [min_x, max_x] = go1( 61 | map(({ x }) => x, points), 62 | (xs) => [Math.min(...xs), Math.max(...xs)] 63 | ); 64 | const [min_y, max_y] = go1( 65 | map(({ y }) => y, points), 66 | (ys) => [Math.min(...ys), Math.max(...ys)] 67 | ); 68 | const min = $$createSVGPoint({ x: min_x, y: min_y })($svg); 69 | const max = $$createSVGPoint({ x: max_x, y: max_y })($svg); 70 | 71 | return { min, max }; 72 | }; 73 | 74 | export const $$getBoxPoints = ($el, $svg = $$getSVG()) => { 75 | const original = $$getOriginalBoxPoints($el, $svg); 76 | const transformed = $$getTransformedBoxPoints(original)($el); 77 | const bounding = $$getBoundingBoxPoints(transformed)($el, $svg); 78 | 79 | return { original, transformed, bounding }; 80 | }; 81 | -------------------------------------------------------------------------------- /src/getCenterPoint/README.md: -------------------------------------------------------------------------------- 1 | # \$\$getCenterPoint 2 | 3 | - [source](./getCenterPoint.index.js) 4 | - [test](./getCenterPoint.spec.js) 5 | 6 | svg 객체의 중심에 해당하는 `SVGPoint`를 반환합니다. 해당 svg 객체는 DOM 트리의 `` 태그에 속해 있어야 합니다. 7 | 8 | `original` 속성은 svg 객체가 `transform` 하기 전 중심입니다. 9 | `transformed` 속성은 svg 객체가 `transform` 한 후 중심입니다. 10 | 11 | ```javascript 12 | const $svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 13 | document.body.appendChild($svg); 14 | 15 | const str = ` 16 | 23 | 24 | `; 25 | const $el = $$el(str)(); 26 | $$append($el)($svg); 27 | 28 | console.log($$getCenterPoint($el)); 29 | // {original: SVGPoint, transformed: SVGPoint} 30 | // original: SVGPoint {x: 60, y: 120} 31 | // transformed: SVGPoint {x: 460, y: 620} 32 | ``` 33 | -------------------------------------------------------------------------------- /src/getCenterPoint/getCenterPoint.index.js: -------------------------------------------------------------------------------- 1 | import { eachL, go, mapL, reduce } from "fxjs/es"; 2 | import { $$createSVGPoint } from "../createSVGPoint/createSVGPoint.index.js"; 3 | import { $$getBoxPoints } from "../getBoxPoints/getBoxPoints.index.js"; 4 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 5 | 6 | const $$sum = (a, b) => a + b; 7 | 8 | const $$calcReduceMean = (nums) => { 9 | let len = 0; 10 | const sum = go( 11 | nums, 12 | eachL(() => len++), 13 | reduce($$sum) 14 | ); 15 | return len ? sum / len : 0; 16 | }; 17 | 18 | const $$calcCenterPoint = ({ 19 | top_left, 20 | top_right, 21 | bottom_left, 22 | bottom_right, 23 | }) => ($svg = $$getSVG()) => { 24 | const points = [top_left, top_right, bottom_left, bottom_right]; 25 | const x = $$calcReduceMean(mapL(({ x }) => x, points)); 26 | const y = $$calcReduceMean(mapL(({ y }) => y, points)); 27 | return $$createSVGPoint({ x, y })($svg); 28 | }; 29 | 30 | export const $$getCenterPoint = ($el, $svg = $$getSVG()) => { 31 | const { original: _original, transformed: _transformed } = $$getBoxPoints( 32 | $el, 33 | $svg 34 | ); 35 | const [original, transformed] = mapL( 36 | (points) => $$calcCenterPoint(points)($svg), 37 | [_original, _transformed] 38 | ); 39 | return { original, transformed }; 40 | }; 41 | -------------------------------------------------------------------------------- /src/getCenterPoint/getCenterPoint.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { $append } from "fxdom/es"; 3 | import { go, mapL, reduce } from "fxjs/es"; 4 | import { makeMockRect } from "../../test/utils/makeMockRect.js"; 5 | import { makeRandomInt } from "../../test/utils/makeRandomInt.js"; 6 | import { makeRandomNumber } from "../../test/utils/makeRandomNumber.js"; 7 | import { makeRandomTransformAttributeValue } from "../../test/utils/makeRandomTransformAttributeValue.js"; 8 | import { $$createSVGPoint } from "../createSVGPoint/createSVGPoint.index.js"; 9 | import { $$getBoxPoints } from "../getBoxPoints/getBoxPoints.index.js"; 10 | import { $$getCenterPoint } from "./getCenterPoint.index.js"; 11 | 12 | const { expect } = chai; 13 | 14 | const setupMock = ({ transform } = {}) => { 15 | const $svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); 16 | 17 | const $el = makeMockRect({ 18 | x: `${makeRandomInt(-1000, 1000)}`, 19 | y: `${makeRandomInt(-1000, 1000)}`, 20 | width: `${makeRandomInt(1, 1000)}`, 21 | height: `${makeRandomInt(1, 1000)}`, 22 | transform, 23 | }); 24 | 25 | document.body.appendChild($svg); 26 | $append($el, $svg); 27 | 28 | return { $el, $svg }; 29 | }; 30 | 31 | const clearMock = ({ $svg }) => { 32 | document.body.removeChild($svg); 33 | }; 34 | 35 | export default ({ describe, it }) => [ 36 | describe(`$$getCenterPoint`, function () { 37 | it(`The return "original", "transformed" values are centers 38 | of the return "original", "transformed" values from "$$getBoxPoints()".`, function () { 39 | const transform = makeRandomTransformAttributeValue(1, 10, () => 40 | makeRandomNumber(-700, 700) 41 | ); 42 | const cases = [setupMock(), setupMock({ transform })]; 43 | for (const { $el, $svg } of cases) { 44 | const [ 45 | { x: expect_original_x, y: expect_original_y }, 46 | { x: expect_transformed_x, y: expect_transformed_y }, 47 | ] = go( 48 | $$getBoxPoints($el), 49 | ({ original, transformed }) => 50 | mapL( 51 | ({ top_left, top_right, bottom_right, bottom_left }) => [ 52 | top_left, 53 | top_right, 54 | bottom_right, 55 | bottom_left, 56 | ], 57 | [original, transformed] 58 | ), 59 | mapL( 60 | reduce(({ x: x1, y: y1 }, { x: x2, y: y2 }) => ({ 61 | x: x1 + x2, 62 | y: y1 + y2, 63 | })) 64 | ), 65 | mapL(({ x, y }) => $$createSVGPoint({ x: x / 4, y: y / 4 })()) 66 | ); 67 | const { 68 | original: { x: receive_original_x, y: receive_original_y }, 69 | transformed: { x: receive_transformed_x, y: receive_transformed_y }, 70 | } = $$getCenterPoint($el); 71 | 72 | expect(receive_original_x, "invalid_original_x").equal( 73 | expect_original_x 74 | ); 75 | expect(receive_original_y, "invalid_original_y").equal( 76 | expect_original_y 77 | ); 78 | expect(receive_transformed_x, "invalid_transformed_x").equal( 79 | expect_transformed_x 80 | ); 81 | expect(receive_transformed_y, "invalid_transformed_y").equal( 82 | expect_transformed_y 83 | ); 84 | 85 | clearMock({ $svg }); 86 | } 87 | }); 88 | }), 89 | ]; 90 | -------------------------------------------------------------------------------- /src/getConsolidatedTransformMatrix/README.md: -------------------------------------------------------------------------------- 1 | # \$\$getConsolidatedTransformMatrix 2 | 3 | - [source](./getConsolidatedTransformMatrix.index.js) 4 | - [test](./getConsolidatedTransformMatrix.spec.js) 5 | 6 | 입력받은 `SVGTransformList` 의 모든 `SVGTransform` 의 변환 행렬을 곱한 행렬을 반환합니다. 7 | `SVGTransformList.consolidate` 와 비슷한 동작을 수행하지만 `SVGTransformList` 를 변형하지 않습니다. 8 | 9 | ```javascript 10 | const el = $$el(` 11 | 12 | `)(); 13 | const transform_list = $$getBaseTransformList(el); 14 | 15 | const matrix = $$getConsolidatedTransformMatrix(transform_list); 16 | console.log(matrix); 17 | // {a: 52, b: 69, c: 64, d: 85, e: 82, f: 108} 18 | ``` 19 | -------------------------------------------------------------------------------- /src/getConsolidatedTransformMatrix/getConsolidatedTransformMatrix.index.js: -------------------------------------------------------------------------------- 1 | import { defaultTo, go, mapL, rangeL, reduce } from "fxjs/es"; 2 | import { $$createSVGMatrix } from "../createSVGMatrix/createSVGMatrix.index.js"; 3 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 4 | 5 | export const $$getConsolidatedTransformMatrix = ( 6 | transform_list = [], 7 | $svg = $$getSVG() 8 | ) => 9 | go( 10 | rangeL(transform_list.numberOfItems), 11 | mapL((i) => transform_list.getItem(i)), 12 | mapL(({ matrix }) => matrix), 13 | reduce((m1, m2) => m1.multiply(m2)), 14 | defaultTo($$createSVGMatrix({ a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 })($svg)) 15 | ); 16 | -------------------------------------------------------------------------------- /src/getConsolidatedTransformMatrix/getConsolidatedTransformMatrix.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { go, join, mapL, rangeL } from "fxjs/es"; 3 | import { expectSameValueSVGMatrix } from "../../test/assertions/expectSameValueSVGMatrix.js"; 4 | import { makeMockRect } from "../../test/utils/makeMockRect.js"; 5 | import { makeRandomInt } from "../../test/utils/makeRandomInt.js"; 6 | import { $$consolidateTransformList } from "../consolidateTransformList/consolidateTransformList.index.js"; 7 | import { $$createSVGMatrix } from "../createSVGMatrix/createSVGMatrix.index.js"; 8 | import { $$el } from "../el/el.index.js"; 9 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 10 | import { $$getConsolidatedTransformMatrix } from "./getConsolidatedTransformMatrix.index.js"; 11 | 12 | const { expect } = chai; 13 | 14 | export default ({ describe, it }) => [ 15 | describe(`$$getConsolidatedTransformMatrix`, function () { 16 | it(`The function returns the consolidated matrix of the transform list.`, function () { 17 | // given 18 | const el = go( 19 | makeRandomInt(1, 10), 20 | rangeL, 21 | mapL(() => 22 | go( 23 | rangeL(6), 24 | mapL(() => makeRandomInt(-10, 10)), 25 | mapL((i) => `${i}`), 26 | join(" "), 27 | (str) => `matrix(${str})` 28 | ) 29 | ), 30 | join(" "), 31 | (transform) => makeMockRect({ transform }) 32 | ); 33 | const transform_list = $$getBaseTransformList(el); 34 | const { matrix: expect_matrix } = $$consolidateTransformList( 35 | $$getBaseTransformList(el.cloneNode(true)) 36 | ).getItem(0); 37 | 38 | // when 39 | const receive_matrix = $$getConsolidatedTransformMatrix(transform_list); 40 | 41 | // then 42 | expectSameValueSVGMatrix(receive_matrix, expect_matrix); 43 | }); 44 | 45 | it(`The function returns an identity matrix when the transform list is empty.`, function () { 46 | // given 47 | const el = $$el(``)(); 48 | const transform_list = $$getBaseTransformList(el); 49 | const expect_matrix = $$createSVGMatrix()(); 50 | 51 | // when 52 | const receive_matrix = $$getConsolidatedTransformMatrix(transform_list); 53 | 54 | // then 55 | expect(receive_matrix).deep.equal(expect_matrix); 56 | }); 57 | }), 58 | ]; 59 | -------------------------------------------------------------------------------- /src/getSetSVG/getSetSVG.index.js: -------------------------------------------------------------------------------- 1 | import { isNil } from "fxjs/es"; 2 | 3 | let svg_el = null; 4 | 5 | /** 6 | * Set the SVGSVGElement used in other functions. 7 | * The SVGSVGElement will be returned by the $$getSVG function. 8 | * 9 | * @param {SVGSVGElement} new_svg_el 10 | * @return {SVGSVGElement} 11 | */ 12 | export const $$setSVG = (new_svg_el) => { 13 | svg_el = new_svg_el; 14 | return svg_el; 15 | }; 16 | 17 | /** 18 | * Return the SVGSVGElement set by the $$setSVG function. 19 | * 20 | * If there is no SVGSVGElement, the function will create and set a new SVGSVGElement 21 | * using document.createElementNS method. 22 | * 23 | * If there is no global document object or document.createElementNS method, 24 | * you should call $$setSVG first manually. 25 | * 26 | * @return {SVGSVGElement} 27 | */ 28 | export const $$getSVG = () => { 29 | if (isNil(svg_el)) { 30 | $$setSVG(document.createElementNS("http://www.w3.org/2000/svg", "svg")); 31 | } 32 | return svg_el; 33 | }; 34 | -------------------------------------------------------------------------------- /src/getSetSVG/getSetSVG.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { map, rangeL } from "fxjs/es"; 3 | import { $$getSVG, $$setSVG } from "./getSetSVG.index.js"; 4 | 5 | export default ({ describe, it, beforeEach }) => [ 6 | describe(`$$setSVG + $$getSVG`, function () { 7 | it(`$$getSVG returns the SVGSVGElement set by $$setSVG.`, function () { 8 | // given 9 | const svg_el = document.createElementNS( 10 | "http://www.w3.org/2000/svg", 11 | "svg" 12 | ); 13 | $$setSVG(svg_el); 14 | 15 | // when 16 | const received = $$getSVG(); 17 | 18 | // then 19 | chai.expect(received).equal(svg_el); 20 | }); 21 | }), 22 | describe(`$$setSVG`, function () { 23 | it(`$$setSVG returns the same reference with the input SVGSVGElement.`, function () { 24 | // given 25 | const svg_el = document.createElementNS( 26 | "http://www.w3.org/2000/svg", 27 | "svg" 28 | ); 29 | 30 | // when 31 | const received = $$setSVG(svg_el); 32 | 33 | // then 34 | chai.expect(received).equal(svg_el); 35 | }); 36 | }), 37 | describe(`$$getSVG`, function () { 38 | beforeEach(function () { 39 | $$setSVG(null); 40 | }); 41 | 42 | it(`$$getSVG returns a SVGSVGElement.`, function () { 43 | // given 44 | // document.createElementNS should be available. 45 | 46 | // when 47 | const svg_el = $$getSVG(); 48 | 49 | // then 50 | chai.expect(svg_el.nodeName.toLowerCase()).equal("svg"); 51 | chai.expect(svg_el).instanceof(SVGSVGElement); 52 | }); 53 | 54 | it(`$$getSVG always returns the same reference.`, function () { 55 | // given 56 | // document.createElementNS should be available. 57 | 58 | // when 59 | const received_list = map($$getSVG, rangeL(10)); 60 | 61 | // then 62 | const [first] = received_list; 63 | for (const a of received_list) { 64 | chai.expect(a).equal(first); 65 | } 66 | }); 67 | }), 68 | ]; 69 | -------------------------------------------------------------------------------- /src/hasAttrNS/README.md: -------------------------------------------------------------------------------- 1 | # \$\$hasAttrNS 2 | 3 | - [source](./hasAttrNS.index.js) 4 | - [test](./hasAttrNS.spec.js) 5 | 6 | SVG 엘리먼트가 속성을 가지고 있는지 여부를 판단합니다. 필요한 경우 namespace 를 지정하여 사용할 수 있습니다. 7 | 8 | ```javascript 9 | const el = $$el(``)(); 10 | 11 | console.log($$hasAttrNS("data-foo")(el)); 12 | // true 13 | 14 | console.log($$hasAttrNS("data-baz")(el)); 15 | // false 16 | ``` 17 | -------------------------------------------------------------------------------- /src/hasAttrNS/hasAttrNS.index.js: -------------------------------------------------------------------------------- 1 | export const $$hasAttrNS = (key, namespace = null) => (el) => 2 | el.hasAttributeNS(namespace, key); 3 | -------------------------------------------------------------------------------- /src/hasAttrNS/hasAttrNS.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { all, go, head, join, mapL } from "fxjs/es"; 3 | import { $$el } from "../el/el.index.js"; 4 | import { $$hasAttrNS } from "./hasAttrNS.index.js"; 5 | 6 | const { expect } = chai; 7 | 8 | export default ({ describe, it }) => [ 9 | describe(`$$hasAttrNS`, function () { 10 | it(`The function returns "true" if the element has the attribute.`, function () { 11 | // given 12 | const attrs = [ 13 | ["cx", 10], 14 | ["cy", 10], 15 | ["r", 20], 16 | ["data-hello", "world"], 17 | ]; 18 | const el = go( 19 | attrs, 20 | mapL(([k, v]) => `${k}="${v}"`), 21 | join(" "), 22 | (attrs) => $$el(``)() 23 | ); 24 | 25 | // when 26 | const received = go( 27 | attrs, 28 | mapL(head), 29 | mapL((attr_name) => $$hasAttrNS(attr_name)(el)), 30 | all 31 | ); 32 | 33 | // then 34 | expect(received).true; 35 | }); 36 | 37 | it(`The function returns "false" if the element has no attribute with the name.`, function () { 38 | // given 39 | const attr_name = "data-test"; 40 | const el = $$el(``)(); 41 | 42 | // when 43 | const receive = $$hasAttrNS(attr_name)(el); 44 | 45 | // then 46 | expect(receive).false; 47 | }); 48 | }), 49 | ]; 50 | -------------------------------------------------------------------------------- /src/initMatrixTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$initMatrixTransform 2 | 3 | - [source](./initMatrixTransform.index.js) 4 | - [test](./initMatrixTransform.spec.js) 5 | 6 | svg 엘리먼트에 `SVGTransform.SVG_TRANSFORM_MATRIX` 타입의 `SVGTransform` 을 추가합니다. 7 | `SVGTransform` 은 항상 `transform.baseVal` 에 해당하는 `SVGTransformList` 의 전달한 `index` 에 추가됩니다. 8 | `SVGTransformList` 는 역순으로 적용됩니다. 9 | 10 | `matrix` 값을 설정할 수 있으며 설정하지 않는 경우 Identity Matrix 로 초기화됩니다. 11 | `SVGTransform`을 삽입할 `index` 를 설정할 수 있으며 설정하지 않는 경우 `0` 으로 초기화됩니다. 12 | 13 | ```javascript 14 | const str = ` 15 | 21 | 22 | `; 23 | const $el = $$el(str)(); 24 | 25 | console.log($$getBaseTransformList($el)); 26 | // SVGTransformList {length: 0, numberOfItems: 0} 27 | 28 | const matrix = $$createSVGMatrix({ a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 })(); 29 | $$initMatrixTransform({ matrix })($el); 30 | 31 | console.log($$getBaseTransformList($el)); 32 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 33 | // 0: SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 34 | // matrix: SVGMatrix {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6} 35 | ``` 36 | 37 | ```javascript 38 | const str = ` 39 | 46 | 47 | `; 48 | const $el = $$el(str)(); 49 | 50 | console.log($$getBaseTransformList($el)); 51 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 52 | // 0: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 53 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 54 | 55 | const matrix = $$createSVGMatrix({ a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 })(); 56 | $$initMatrixTransform({ matrix, index: 1 })($el); 57 | // index 를 1 로 설정했기 때문에 58 | // SVGTransformList 의 1 인덱스 위치에 SVGTransform 삽입 59 | 60 | console.log($$getBaseTransformList($el)); 61 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, length: 2, numberOfItems: 2} 62 | // 0: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 63 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 64 | // 1: SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 65 | // matrix: SVGMatrix {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6} 66 | ``` 67 | -------------------------------------------------------------------------------- /src/initMatrixTransform/initMatrixTransform.index.js: -------------------------------------------------------------------------------- 1 | import { defaultTo } from "fxjs/es"; 2 | import { $$createSVGMatrix } from "../createSVGMatrix/createSVGMatrix.index.js"; 3 | import { $$createSVGTransformMatrix } from "../createSVGTransformMatrix/createSVGTransformMatrix.index.js"; 4 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 5 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 6 | 7 | export const $$initMatrixTransform = ({ matrix, index = 0 } = {}) => ( 8 | $el, 9 | $svg = $$getSVG() 10 | ) => { 11 | const transform = $$createSVGTransformMatrix({ 12 | matrix: defaultTo($$createSVGMatrix()($svg), matrix), 13 | })($svg); 14 | $$getBaseTransformList($el).insertItemBefore(transform, index); 15 | return transform; 16 | }; 17 | -------------------------------------------------------------------------------- /src/initRotateTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$initRotateTransform 2 | 3 | - [source](./initRotateTransform.index.js) 4 | - [test](./initRotateTransform.spec.js) 5 | 6 | svg 엘리먼트에 총 3개의 `SVGTransform`을 순서대로 추가합니다. 7 | 8 | 1. `SVGTransform.SVG_TRANSFORM_TRANSLATE` 타입의 `SVGTransform` (`index`) 9 | 2. `SVGTransform.SVG_TRANSFORM_ROTATE` 타입의 `SVGTransform` (`index + 1`) 10 | 3. `SVGTransform.SVG_TRANSFORM_TRANSLATE` 타입의 `SVGTransform` (`index + 2`) 11 | 12 | 2번 `SVGTransform` 객체를 반환합니다. 13 | 1번, 3번 `SVGTranform` 객체는 회전 중심을 설정합니다. 14 | 15 | 회전 중심 `cx`, `cy` 를 설정할 수 있습니다. 설정하지 않는 경우 모두 `0` 으로 초기화됩니다. 16 | 초기 회전 각도 `angle` 을 설정할 수 있습니다. 단위는 `deg` 입니다. 설정하지 않는 경우 `0` 으로 초기화됩니다. 17 | `SVGTransform` 을 추가할 `index` 를 설정할 수 있습니다. 설정하지 않는 경우 `0` 으로 초기화됩니다. 18 | 19 | ```javascript 20 | const str = ` 21 | 27 | 28 | `; 29 | const $el = $$el(str)(); 30 | 31 | console.log($$getBaseTransformList($el)); 32 | // SVGTransformList {length: 0, numberOfItems: 0} 33 | 34 | $$initRotateTransform({ angle: 30, cx: 10, cy: 20 })($el); 35 | 36 | console.log($$getBaseTransformList($el)); 37 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, 2: SVGTransform, length: 3, numberOfItems: 3} 38 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 39 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 40 | // 1: SVGTransform {type: 4, matrix: SVGMatrix, angle: 30} 41 | // 2: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 42 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: -10, f: -20} 43 | ``` 44 | 45 | ```javascript 46 | const str = ` 47 | 54 | 55 | `; 56 | const $el = $$el(str)(); 57 | 58 | console.log($$getBaseTransformList($el)); 59 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 60 | // 0: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 61 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 62 | 63 | $$initRotateTransform({ cx: 10, cy: 20, angle: 30, index: 1 })($el); 64 | // index 를 1 로 설정할 경우 65 | // 기존 SVGTransformList 의 1 번 인덱스부터 3개의 SVGTransform 이 추가됨 66 | // 즉 1, 2, 3 번 인덱스 사용 67 | 68 | console.log($$getBaseTransformList($el)); 69 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, 2: SVGTransform, 3: SVGTransform, length: 4, numberOfItems: 4} 70 | // 0: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 71 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 72 | // 1: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 73 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 74 | // 2: SVGTransform {type: 4, matrix: SVGMatrix, angle: 30} 75 | // 3: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 76 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: -10, f: -20} 77 | ``` 78 | -------------------------------------------------------------------------------- /src/initRotateTransform/initRotateTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$createSVGTransformRotate } from "../createSVGTransformRotate/createSVGTransformRotate.index.js"; 2 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 3 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 4 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 5 | 6 | export const $$initRotateTransform = ({ 7 | angle = 0, 8 | cx = 0, 9 | cy = 0, 10 | index = 0, 11 | } = {}) => ($el, $svg = $$getSVG()) => { 12 | const transform_list = $$getBaseTransformList($el); 13 | const positive_translate_transform = $$createSVGTransformTranslate({ 14 | tx: cx, 15 | ty: cy, 16 | })($svg); 17 | const negative_translate_transform = $$createSVGTransformTranslate({ 18 | tx: -cx, 19 | ty: -cy, 20 | })($svg); 21 | const rotate_transform = $$createSVGTransformRotate({ angle })($svg); 22 | 23 | transform_list.insertItemBefore(negative_translate_transform, index); 24 | transform_list.insertItemBefore(rotate_transform, index); 25 | transform_list.insertItemBefore(positive_translate_transform, index); 26 | 27 | return rotate_transform; 28 | }; 29 | -------------------------------------------------------------------------------- /src/initScaleTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$initScaleTransform 2 | 3 | - [source](./initScaleTransform.index.js) 4 | - [test](./initScaleTransform.spec.js) 5 | 6 | svg 엘리먼트에 총 3개의 `SVGTransform`을 순서대로 추가합니다. 7 | 8 | 1. `SVGTransform.SVG_TRANSFORM_TRANSLATE` 타입의 `SVGTransform` (`index`) 9 | 2. `SVGTransform.SVG_TRANSFORM_SCALE` 타입의 `SVGTransform` (`index + 1`) 10 | 3. `SVGTransform.SVG_TRANSFORM_TRANSLATE` 타입의 `SVGTransform` (`index + 2`) 11 | 12 | 2번 `SVGTransform` 객체를 반환합니다. 13 | 1번, 3번 `SVGTranform` 객체는 scale 중심을 설정합니다. 14 | 15 | scale 중심 `cx`, `cy` 를 설정할 수 있습니다. 설정하지 않는 경우 모두 `0` 으로 초기화됩니다. 16 | 초기 scale 정도 `sx`, `sy` 를 설정할 수 있습니다. 설정하지 않는 경우 모두 `1` 으로 초기화됩니다. 17 | `SVGTransform` 을 추가할 `index` 를 설정할 수 있습니다. 설정하지 않는 경우 `0` 으로 초기화됩니다. 18 | 19 | ```javascript 20 | const str = ` 21 | 27 | 28 | `; 29 | const $el = $$el(str)(); 30 | 31 | console.log($$getBaseTransformList($el)); 32 | // SVGTransformList {length: 0, numberOfItems: 0} 33 | 34 | $$initScaleTransform({ sx: 2, sy: 3, cx: 10, cy: 20, index: 0 })($el); 35 | 36 | console.log($$getBaseTransformList($el)); 37 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, 2: SVGTransform, length: 3, numberOfItems: 3} 38 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 39 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 40 | // 1: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 41 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 3, e: 0, f: 0} 42 | // 2: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 43 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: -10, f: -20} 44 | ``` 45 | 46 | ```javascript 47 | const str = ` 48 | 55 | 56 | `; 57 | const $el = $$el(str)(); 58 | 59 | console.log($$getBaseTransformList($el)); 60 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 61 | // 0: SVGTransform {type: 4, matrix: SVGMatrix, angle: 30} 62 | 63 | $$initScaleTransform({ cx: 10, cy: 20, sx: 2, sy: 3, index: 1 })($el); 64 | // index 를 1 로 설정할 경우 65 | // 기존 SVGTransformList 의 1 번 인덱스부터 3개의 SVGTransform 이 추가됨 66 | // 즉 1, 2, 3 번 인덱스 사용 67 | 68 | console.log($$getBaseTransformList($el)); 69 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, 2: SVGTransform, 3: SVGTransform, length: 4, numberOfItems: 4} 70 | // 0: SVGTransform {type: 4, matrix: SVGMatrix, angle: 30} 71 | // 1: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 72 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 73 | // 2: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 74 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 3, e: 0, f: 0} 75 | // 3: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 76 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: -10, f: -20} 77 | ``` 78 | -------------------------------------------------------------------------------- /src/initScaleTransform/initScaleTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$createSVGTransformScale } from "../createSVGTransformScale/createSVGTransformScale.index.js"; 2 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 3 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 4 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 5 | 6 | export const $$initScaleTransform = ({ 7 | sx = 1, 8 | sy = 1, 9 | cx = 0, 10 | cy = 0, 11 | index = 0, 12 | } = {}) => ($el, $svg = $$getSVG()) => { 13 | const transform_list = $$getBaseTransformList($el); 14 | const positive_translate_transform = $$createSVGTransformTranslate({ 15 | tx: cx, 16 | ty: cy, 17 | })($svg); 18 | const negative_translate_transform = $$createSVGTransformTranslate({ 19 | tx: -cx, 20 | ty: -cy, 21 | })($svg); 22 | const scale_transform = $$createSVGTransformScale({ sx, sy })($svg); 23 | 24 | transform_list.insertItemBefore(negative_translate_transform, index); 25 | transform_list.insertItemBefore(scale_transform, index); 26 | transform_list.insertItemBefore(positive_translate_transform, index); 27 | 28 | return scale_transform; 29 | }; 30 | -------------------------------------------------------------------------------- /src/initTranslateTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$initTranslateTransform 2 | 3 | - [source](./initTranslateTransform.index.js) 4 | - [test](./initTranslateTransform.spec.js) 5 | 6 | svg 엘리먼트에 `SVGTransform.SVG_TRANSFORM_TRANSLATE` 타입의 `SVGTransform` 을 추가합니다. 7 | `SVGTransform` 은 항상 `transform.baseVal` 에 해당하는 `SVGTransformList` 의 전달한 `index` 에 추가됩니다. 8 | `SVGTransformList` 는 역순으로 적용됩니다. 9 | 10 | 초기 `tx`, `ty` 값을 설정할 수 있으며 설정하지 않는 경우 모두 `0` 으로 초기화됩니다. 11 | `SVGTrnsform`을 삽입할 `index`를 설정할 수 있으며 설정하지 않는 경우 `0` 으로 초기화됩니다. 12 | 13 | ```javascript 14 | const str = ` 15 | 21 | 22 | `; 23 | const $el = $$el(str)(); 24 | 25 | console.log($$getBaseTransformList($el)); 26 | // SVGTransformList {length: 0, numberOfItems: 0} 27 | 28 | $$initTranslateTransform({ tx: 10, ty: 20 })($el); 29 | 30 | console.log($$getBaseTransformList($el)); 31 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 32 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 33 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 34 | ``` 35 | 36 | ```javascript 37 | const str = ` 38 | 45 | 46 | `; 47 | const $el = $$el(str)(); 48 | 49 | console.log($$getBaseTransformList($el)); 50 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 51 | // 0: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 52 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 53 | 54 | $$initTranslateTransform({ tx: 10, ty: 20, index: 1 })($el); 55 | // index 를 1 로 설정했기 때문에 56 | // SVGTransformList 의 1 인덱스 위치에 SVGTransform 삽입 57 | 58 | console.log($$getBaseTransformList($el)); 59 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, length: 2, numberOfItems: 2} 60 | // 0: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 61 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 62 | // 1: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 63 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 64 | ``` 65 | -------------------------------------------------------------------------------- /src/initTranslateTransform/initTranslateTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 2 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 3 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 4 | 5 | export const $$initTranslateTransform = ({ 6 | tx = 0, 7 | ty = 0, 8 | index = 0, 9 | } = {}) => ($el, $svg = $$getSVG()) => { 10 | const transform = $$createSVGTransformTranslate({ tx, ty })($svg); 11 | $$getBaseTransformList($el).insertItemBefore(transform, index); 12 | return transform; 13 | }; 14 | -------------------------------------------------------------------------------- /src/isIdentityMatrix/README.md: -------------------------------------------------------------------------------- 1 | # \$\$isIdentityMatrix 2 | 3 | - [source](./isIdentityMatrix.index.js) 4 | - [test](./isIdentityMatrix.spec.js) 5 | 6 | 입력한 matrix 가 단위행렬인지 여부를 판단합니다. 7 | 단위행렬의 각 요소와 `Number.EPSILON` 이내로 차이나는 경우 올바른 값으로 판정합니다. 8 | -------------------------------------------------------------------------------- /src/isIdentityMatrix/isIdentityMatrix.index.js: -------------------------------------------------------------------------------- 1 | import { every } from "fxjs/es"; 2 | 3 | export const $$isIdentityMatrix = ({ a, b, c, d, e, f } = {}) => 4 | every(([x, y]) => Number.isFinite(x) && Math.abs(x - y) < Number.EPSILON, [ 5 | [a, 1], 6 | [b, 0], 7 | [c, 0], 8 | [d, 1], 9 | [e, 0], 10 | [f, 0], 11 | ]); 12 | -------------------------------------------------------------------------------- /src/isIdentityMatrix/isIdentityMatrix.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { each, filterL, go, mapL, object } from "fxjs/es"; 3 | import { makeAllCombinations } from "../../test/utils/makeAllCombinations.js"; 4 | import { makeRandomNumberExcept } from "../../test/utils/makeRandomNumberExcept.js"; 5 | import { $$createSVGMatrix } from "../createSVGMatrix/createSVGMatrix.index.js"; 6 | import { $$isIdentityMatrix } from "./isIdentityMatrix.index.js"; 7 | 8 | const { expect } = chai; 9 | 10 | export default ({ describe, it }) => [ 11 | describe(`$$isIdentityMatrix`, function () { 12 | it(`The function returns "true" if the input matrix is an identity matrix.`, function () { 13 | // given 14 | const matrix = $$createSVGMatrix({ 15 | a: 1, 16 | b: 0, 17 | c: 0, 18 | d: 1, 19 | e: 0, 20 | f: 0, 21 | })(); 22 | 23 | // when 24 | const result = $$isIdentityMatrix(matrix); 25 | 26 | // then 27 | expect(result).true; 28 | }); 29 | 30 | it(`The function returns "true" if the input matrix is almost an identity matrix. 31 | The function ignores difference within the "Number.EPSILON" range.`, function () { 32 | // given 33 | const a = 1 + Number.EPSILON / 2; 34 | const b = 0 - Number.EPSILON / 2; 35 | const c = 0 + Number.EPSILON / 2; 36 | const d = 1 - Number.EPSILON / 2; 37 | const e = 0 + Number.EPSILON / 2; 38 | const f = 0 - Number.EPSILON / 2; 39 | const matrix = $$createSVGMatrix({ a, b, c, d, e, f })(); 40 | 41 | // when 42 | const result = $$isIdentityMatrix(matrix); 43 | 44 | // then 45 | expect(result).true; 46 | }); 47 | 48 | it(`The function returns "false" if the input matrix is not an identity matrix and even not close to it. 49 | (out of the range of "Number.EPSILON")`, function () { 50 | // given 51 | const cases = go( 52 | [ 53 | ["a", 1], 54 | ["b", 0], 55 | ["c", 0], 56 | ["d", 1], 57 | ["e", 0], 58 | ["f", 0], 59 | ], 60 | makeAllCombinations, 61 | filterL((l) => l.length), 62 | mapL( 63 | mapL(([name, expect_num]) => [ 64 | name, 65 | makeRandomNumberExcept(-10, 10, [expect_num]), 66 | ]) 67 | ), 68 | mapL(mapL(([name, num]) => [name, num + Number.EPSILON])), 69 | mapL(object), 70 | mapL((o) => $$createSVGMatrix(o)()) 71 | ); 72 | 73 | // when 74 | const result_list = mapL($$isIdentityMatrix, cases); 75 | 76 | // then 77 | each((result) => expect(result).false, result_list); 78 | }); 79 | }), 80 | ]; 81 | -------------------------------------------------------------------------------- /src/isMatrixSVGTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$isMatrixSVGTransform 2 | 3 | - [source](./isMatrixSVGTransform.index.js) 4 | - [test](./isMatrixSVGTransform.spec.js) 5 | 6 | 해당 `SVGTransform`의 `type`이 `SVGTransform.SVG_TRANSFORM_MATRIX`인지 여부를 판단합니다. 7 | 8 | ```javascript 9 | console.log($$isMatrixSVGTransform($$createSVGTransformMatrix()())); 10 | // true 11 | ``` 12 | 13 | ```javascript 14 | console.log($$isMatrixSVGTransform($$createSVGTransformTranslate()())); 15 | // false 16 | ``` 17 | -------------------------------------------------------------------------------- /src/isMatrixSVGTransform/isMatrixSVGTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$isSVGTransform } from "../isSVGTransform/isSVGTransform.index.js"; 2 | 3 | export const $$isMatrixSVGTransform = (transform) => { 4 | if (!$$isSVGTransform(transform)) { 5 | return false; 6 | } 7 | 8 | const { type, SVG_TRANSFORM_MATRIX } = transform; 9 | return type === SVG_TRANSFORM_MATRIX; 10 | }; 11 | -------------------------------------------------------------------------------- /src/isMatrixSVGTransform/isMatrixSVGTransform.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { makeRandomNumber } from "../../test/utils/makeRandomNumber.js"; 3 | import { makeRandomSVGMatrix } from "../../test/utils/makeRandomSVGMatrix.js"; 4 | import { $$createSVGTransformMatrix } from "../createSVGTransformMatrix/createSVGTransformMatrix.index.js"; 5 | import { $$createSVGTransformRotate } from "../createSVGTransformRotate/createSVGTransformRotate.index.js"; 6 | import { $$createSVGTransformScale } from "../createSVGTransformScale/createSVGTransformScale.index.js"; 7 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 8 | import { $$isMatrixSVGTransform } from "./isMatrixSVGTransform.index.js"; 9 | 10 | const { expect } = chai; 11 | 12 | export default ({ describe, it }) => [ 13 | describe(`$$isMatrixSVGTransform`, function () { 14 | describe(`The function will return false...`, function () { 15 | it(`When the input value is null.`, function () { 16 | const result = $$isMatrixSVGTransform(null); 17 | 18 | expect(result).false; 19 | }); 20 | 21 | it(`When the input value is a plain empty object.`, function () { 22 | const result = $$isMatrixSVGTransform({}); 23 | 24 | expect(result).false; 25 | }); 26 | 27 | it(`When the input value is a plain object like 28 | { type: SVGTransform.SVG_TRANSFORM_MATRIX, SVG_TRANSFORM_MATRIX: SVGTransform.SVG_TRANSFORM_MATRIX }.`, function () { 29 | const obj = { 30 | type: SVGTransform.SVG_TRANSFORM_MATRIX, 31 | SVG_TRANSFORM_MATRIX: SVGTransform.SVG_TRANSFORM_MATRIX, 32 | }; 33 | 34 | const result = $$isMatrixSVGTransform(obj); 35 | 36 | expect(result).false; 37 | }); 38 | 39 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_ROTATE.`, function () { 40 | const rotate_t = $$createSVGTransformRotate({ 41 | angle: makeRandomNumber(-700, 700), 42 | cx: makeRandomNumber(-100, 100), 43 | cy: makeRandomNumber(-100, 100), 44 | })(); 45 | 46 | const result = $$isMatrixSVGTransform(rotate_t); 47 | 48 | expect(result).false; 49 | }); 50 | 51 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_TRANSLATE.`, function () { 52 | const translate_t = $$createSVGTransformTranslate({ 53 | tx: makeRandomNumber(-100, 100), 54 | ty: makeRandomNumber(-100, 100), 55 | })(); 56 | 57 | const result = $$isMatrixSVGTransform(translate_t); 58 | 59 | expect(result).false; 60 | }); 61 | 62 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_SCALE.`, function () { 63 | const scale_t = $$createSVGTransformScale({ 64 | sx: makeRandomNumber(-100, 100), 65 | sy: makeRandomNumber(-100, 100), 66 | })(); 67 | 68 | const result = $$isMatrixSVGTransform(scale_t); 69 | 70 | expect(result).false; 71 | }); 72 | }); 73 | 74 | describe(`The function will return true...`, function () { 75 | it(`When the input value is a SVGTransform and the type is SVGTransform.SVG_TRANSFORM_MATRIX.`, function () { 76 | const matrix_t = $$createSVGTransformMatrix({ 77 | matrix: makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)), 78 | })(); 79 | 80 | const result = $$isMatrixSVGTransform(matrix_t); 81 | 82 | expect(result).true; 83 | }); 84 | }); 85 | }), 86 | ]; 87 | -------------------------------------------------------------------------------- /src/isRotateSVGTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$isRotateSVGTransform 2 | 3 | - [source](./isRotateSVGTransform.index.js) 4 | - [test](./isRotateSVGTransform.spec.js) 5 | 6 | 해당 `SVGTransform`의 `type`이 `SVGTransform.SVG_TRANSFORM_ROTATE`인지 여부를 판단합니다. 7 | 8 | ```javascript 9 | console.log($$isRotateSVGTransform($$createSVGTransformRotate()())); 10 | // true 11 | ``` 12 | 13 | ```javascript 14 | console.log($$isRotateSVGTransform($$createSVGTransformTranslate()())); 15 | // false 16 | ``` 17 | -------------------------------------------------------------------------------- /src/isRotateSVGTransform/isRotateSVGTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$isSVGTransform } from "../isSVGTransform/isSVGTransform.index.js"; 2 | 3 | export const $$isRotateSVGTransform = (transform) => { 4 | if (!$$isSVGTransform(transform)) { 5 | return false; 6 | } 7 | 8 | const { type, SVG_TRANSFORM_ROTATE } = transform; 9 | return type === SVG_TRANSFORM_ROTATE; 10 | }; 11 | -------------------------------------------------------------------------------- /src/isRotateSVGTransform/isRotateSVGTransform.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | makeRandomNumber, 4 | makeRandomSVGMatrix, 5 | } from "../../test/utils/index.js"; 6 | import { $$createSVGTransformMatrix } from "../createSVGTransformMatrix/createSVGTransformMatrix.index.js"; 7 | import { $$createSVGTransformRotate } from "../createSVGTransformRotate/createSVGTransformRotate.index.js"; 8 | import { $$createSVGTransformScale } from "../createSVGTransformScale/createSVGTransformScale.index.js"; 9 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 10 | import { $$isRotateSVGTransform } from "./isRotateSVGTransform.index.js"; 11 | 12 | const { expect } = chai; 13 | 14 | export default ({ describe, it }) => [ 15 | describe(`$$isRotateSVGTransform`, function () { 16 | describe(`The function will return false...`, function () { 17 | it(`When the input value is null.`, function () { 18 | const result = $$isRotateSVGTransform(null); 19 | 20 | expect(result).false; 21 | }); 22 | 23 | it(`When the input value is a plain empty object.`, function () { 24 | const result = $$isRotateSVGTransform({}); 25 | 26 | expect(result).false; 27 | }); 28 | 29 | it(`When the input value is a plain object like 30 | { type: SVGTransform.SVG_TRANSFORM_ROTATE, SVG_TRANSFORM_ROTATE: SVGTransform.SVG_TRANSFORM_ROTATE }.`, function () { 31 | const obj = { 32 | type: SVGTransform.SVG_TRANSFORM_ROTATE, 33 | SVG_TRANSFORM_ROTATE: SVGTransform.SVG_TRANSFORM_ROTATE, 34 | }; 35 | 36 | const result = $$isRotateSVGTransform(obj); 37 | 38 | expect(result).false; 39 | }); 40 | 41 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_MATRIX.`, function () { 42 | const matrix_t = $$createSVGTransformMatrix({ 43 | matrix: makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)), 44 | })(); 45 | 46 | const result = $$isRotateSVGTransform(matrix_t); 47 | 48 | expect(result).false; 49 | }); 50 | 51 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_SCALE.`, function () { 52 | const scale_t = $$createSVGTransformScale({ 53 | sx: makeRandomNumber(-100, 100), 54 | sy: makeRandomNumber(-100, 100), 55 | })(); 56 | 57 | const result = $$isRotateSVGTransform(scale_t); 58 | 59 | expect(result).false; 60 | }); 61 | 62 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_TRANSLATE.`, function () { 63 | const translate_t = $$createSVGTransformTranslate({ 64 | tx: makeRandomNumber(-100, 100), 65 | ty: makeRandomNumber(-100, 100), 66 | })(); 67 | 68 | const result = $$isRotateSVGTransform(translate_t); 69 | 70 | expect(result).false; 71 | }); 72 | }); 73 | 74 | describe(`The function will return true...`, function () { 75 | it(`When the input value is a SVGTransform and the type is SVGTransform.SVG_TRANSFORM_ROTATE.`, function () { 76 | const rotate_t = $$createSVGTransformRotate({ 77 | angle: makeRandomNumber(-700, 700), 78 | cx: makeRandomNumber(-100, 100), 79 | cy: makeRandomNumber(-100, 100), 80 | })(); 81 | 82 | const result = $$isRotateSVGTransform(rotate_t); 83 | 84 | expect(result).true; 85 | }); 86 | }); 87 | }), 88 | ]; 89 | -------------------------------------------------------------------------------- /src/isSVGTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$isSVGTransform 2 | 3 | - [source](./isSVGTransform.index.js) 4 | - [test](./isSVGTransform.spec.js) 5 | 6 | 해당 객체가 `SVGTransform` 인지 여부를 판단합니다. 7 | 8 | ```javascript 9 | const transform = $$createSVGTransformTranslate()(); 10 | console.log($$isSVGTransform(transform)); 11 | // true 12 | ``` 13 | 14 | ```javascript 15 | console.log($$isSVGTransform(null)); 16 | // false 17 | ``` 18 | -------------------------------------------------------------------------------- /src/isSVGTransform/isSVGTransform.index.js: -------------------------------------------------------------------------------- 1 | export const $$isSVGTransform = (transform) => 2 | transform instanceof SVGTransform; 3 | -------------------------------------------------------------------------------- /src/isSVGTransform/isSVGTransform.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | makeRandomNumber, 4 | makeRandomSVGTransformMatrix, 5 | makeRandomSVGTransformRotate, 6 | makeRandomSVGTransformScale, 7 | makeRandomSVGTransformTranslate, 8 | } from "../../test/utils/index.js"; 9 | import { $$createSVGTransform } from "../createSVGTransform/createSVGTransform.index.js"; 10 | import { $$isSVGTransform } from "./isSVGTransform.index.js"; 11 | 12 | const { expect } = chai; 13 | 14 | export default ({ describe, it }) => [ 15 | describe("$$isSVGTransform", function () { 16 | describe(`The function will return false...`, function () { 17 | it(`When the input value is null.`, function () { 18 | const is_transform = $$isSVGTransform(null); 19 | 20 | expect(is_transform).false; 21 | }); 22 | 23 | it(`When there is no input value.`, function () { 24 | const is_transform = $$isSVGTransform(); 25 | 26 | expect(is_transform).false; 27 | }); 28 | 29 | it(`When the input value is a plain object.`, function () { 30 | const obj = {}; 31 | 32 | const is_transform = $$isSVGTransform(obj); 33 | 34 | expect(is_transform).false; 35 | }); 36 | }); 37 | 38 | describe(`The function will return true if the input value is a SVGTransform.`, function () { 39 | it(`When the input transform is a matrix transform.`, function () { 40 | const matrix_transform = makeRandomSVGTransformMatrix(); 41 | 42 | const is_transform = $$isSVGTransform(matrix_transform); 43 | 44 | expect(is_transform).true; 45 | }); 46 | 47 | it(`When the input transform is a translate transform.`, function () { 48 | const translate_transform = makeRandomSVGTransformTranslate(); 49 | 50 | const is_transform = $$isSVGTransform(translate_transform); 51 | 52 | expect(is_transform).true; 53 | }); 54 | 55 | it(`When the input transform is a scale transform.`, function () { 56 | const scale_transform = makeRandomSVGTransformScale(); 57 | 58 | const is_transform = $$isSVGTransform(scale_transform); 59 | 60 | expect(is_transform).true; 61 | }); 62 | 63 | it(`When the input transform is a rotate transform.`, function () { 64 | const rotate_transform = makeRandomSVGTransformRotate(); 65 | 66 | const is_transform = $$isSVGTransform(rotate_transform); 67 | 68 | expect(is_transform).true; 69 | }); 70 | 71 | it(`When the input transform is a skew x transform.`, function () { 72 | const skew_x_transform = $$createSVGTransform(); 73 | skew_x_transform.setSkewX(makeRandomNumber(-100, 100)); 74 | 75 | const is_transform = $$isSVGTransform(skew_x_transform); 76 | 77 | expect(is_transform).true; 78 | }); 79 | 80 | it(`When the input transform is a skew y transform.`, function () { 81 | const skew_y_transform = $$createSVGTransform(); 82 | skew_y_transform.setSkewX(makeRandomNumber(-100, 100)); 83 | 84 | const is_transform = $$isSVGTransform(skew_y_transform); 85 | 86 | expect(is_transform).true; 87 | }); 88 | }); 89 | }), 90 | ]; 91 | -------------------------------------------------------------------------------- /src/isScaleSVGTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$isScaleSVGTransform 2 | 3 | - [source](./isScaleSVGTransform.index.js) 4 | - [test](./isScaleSVGTransform.spec.js) 5 | 6 | 해당 `SVGTransform`의 `type`이 `SVGTransform.SVG_TRANSFORM_SCALE`인지 여부를 판단합니다. 7 | 8 | ```javascript 9 | console.log($$isScaleSVGTransform($$createSVGTransformScale()())); 10 | // true 11 | ``` 12 | 13 | ```javascript 14 | console.log($$isScaleSVGTransform($$createSVGTransformTranslate()())); 15 | // false 16 | ``` 17 | -------------------------------------------------------------------------------- /src/isScaleSVGTransform/isScaleSVGTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$isSVGTransform } from "../isSVGTransform/isSVGTransform.index.js"; 2 | 3 | export const $$isScaleSVGTransform = (transform) => { 4 | if (!$$isSVGTransform(transform)) { 5 | return false; 6 | } 7 | 8 | const { type, SVG_TRANSFORM_SCALE } = transform; 9 | return type === SVG_TRANSFORM_SCALE; 10 | }; 11 | -------------------------------------------------------------------------------- /src/isScaleSVGTransform/isScaleSVGTransform.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | makeRandomNumber, 4 | makeRandomSVGMatrix, 5 | } from "../../test/utils/index.js"; 6 | import { $$createSVGTransformMatrix } from "../createSVGTransformMatrix/createSVGTransformMatrix.index.js"; 7 | import { $$createSVGTransformRotate } from "../createSVGTransformRotate/createSVGTransformRotate.index.js"; 8 | import { $$createSVGTransformScale } from "../createSVGTransformScale/createSVGTransformScale.index.js"; 9 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 10 | import { $$isScaleSVGTransform } from "./isScaleSVGTransform.index.js"; 11 | 12 | const { expect } = chai; 13 | 14 | export default ({ describe, it }) => [ 15 | describe(`$$isScaleSVGTransform`, function () { 16 | describe(`The function will return false...`, function () { 17 | it(`When the input value is null.`, function () { 18 | const result = $$isScaleSVGTransform(null); 19 | 20 | expect(result).false; 21 | }); 22 | 23 | it(`When the input value is a plain empty object.`, function () { 24 | const result = $$isScaleSVGTransform({}); 25 | 26 | expect(result).false; 27 | }); 28 | 29 | it(`When the input value is a plain object like 30 | { type: SVGTransform.SVG_TRANSFORM_SCALE, SVG_TRANSFORM_SCALE: SVGTransform.SVG_TRANSFORM_SCALE }.`, function () { 31 | const obj = { 32 | type: SVGTransform.SVG_TRANSFORM_SCALE, 33 | SVG_TRANSFORM_SCALE: SVGTransform.SVG_TRANSFORM_SCALE, 34 | }; 35 | 36 | const result = $$isScaleSVGTransform(obj); 37 | 38 | expect(result).false; 39 | }); 40 | 41 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_MATRIX.`, function () { 42 | const matrix_t = $$createSVGTransformMatrix({ 43 | matrix: makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)), 44 | })(); 45 | 46 | const result = $$isScaleSVGTransform(matrix_t); 47 | 48 | expect(result).false; 49 | }); 50 | 51 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_ROTATE.`, function () { 52 | const rotate_t = $$createSVGTransformRotate({ 53 | angle: makeRandomNumber(-700, 700), 54 | cx: makeRandomNumber(-100, 100), 55 | cy: makeRandomNumber(-100, 100), 56 | })(); 57 | 58 | const result = $$isScaleSVGTransform(rotate_t); 59 | 60 | expect(result).false; 61 | }); 62 | 63 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_TRANSLATE.`, function () { 64 | const translate_t = $$createSVGTransformTranslate({ 65 | tx: makeRandomNumber(-100, 100), 66 | ty: makeRandomNumber(-100, 100), 67 | })(); 68 | 69 | const result = $$isScaleSVGTransform(translate_t); 70 | 71 | expect(result).false; 72 | }); 73 | }); 74 | 75 | describe(`The function will return true...`, function () { 76 | it(`When the input value is a SVGTransform and the type is SVGTransform.SVG_TRANSFORM_SCALE.`, function () { 77 | const scale_t = $$createSVGTransformScale({ 78 | sx: makeRandomNumber(-100, 100), 79 | sy: makeRandomNumber(-100, 100), 80 | })(); 81 | 82 | const result = $$isScaleSVGTransform(scale_t); 83 | 84 | expect(result).true; 85 | }); 86 | }); 87 | }), 88 | ]; 89 | -------------------------------------------------------------------------------- /src/isTranslateSVGTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$isTranslateSVGTransform 2 | 3 | - [source](./isTranslateSVGTransform.index.js) 4 | - [test](./isTranslateSVGTransform.spec.js) 5 | 6 | 해당 `SVGTransform`의 `type`이 `SVGTransform.SVG_TRANSFORM_TRANSLATE`인지 여부를 판단합니다. 7 | 8 | ```javascript 9 | console.log($$isTranslateSVGTransform($$createSVGTransformTranslate()())); 10 | // true 11 | ``` 12 | 13 | ```javascript 14 | console.log($$isTranslateSVGTransform($$createSVGTransformRotate()())); 15 | // false 16 | ``` 17 | -------------------------------------------------------------------------------- /src/isTranslateSVGTransform/isTranslateSVGTransform.index.js: -------------------------------------------------------------------------------- 1 | import { $$isSVGTransform } from "../isSVGTransform/isSVGTransform.index.js"; 2 | 3 | export const $$isTranslateSVGTransform = (transform) => { 4 | if (!$$isSVGTransform(transform)) { 5 | return false; 6 | } 7 | 8 | const { type, SVG_TRANSFORM_TRANSLATE } = transform; 9 | return type === SVG_TRANSFORM_TRANSLATE; 10 | }; 11 | -------------------------------------------------------------------------------- /src/isTranslateSVGTransform/isTranslateSVGTransform.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { 3 | makeRandomNumber, 4 | makeRandomSVGMatrix, 5 | } from "../../test/utils/index.js"; 6 | import { $$createSVGTransformMatrix } from "../createSVGTransformMatrix/createSVGTransformMatrix.index.js"; 7 | import { $$createSVGTransformRotate } from "../createSVGTransformRotate/createSVGTransformRotate.index.js"; 8 | import { $$createSVGTransformScale } from "../createSVGTransformScale/createSVGTransformScale.index.js"; 9 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 10 | import { $$isTranslateSVGTransform } from "./isTranslateSVGTransform.index.js"; 11 | 12 | const { expect } = chai; 13 | 14 | export default ({ describe, it }) => [ 15 | describe(`$$isTranslateSVGTransform`, function () { 16 | describe(`The function will return false...`, function () { 17 | it(`When the input value is null.`, function () { 18 | const result = $$isTranslateSVGTransform(null); 19 | 20 | expect(result).false; 21 | }); 22 | 23 | it(`When the input value is a plain empty object.`, function () { 24 | const result = $$isTranslateSVGTransform({}); 25 | 26 | expect(result).false; 27 | }); 28 | 29 | it(`When the input value is a plain object like 30 | { type: SVGTransform.SVG_TRANSFORM_TRANSLATE, SVG_TRANSFORM_TRANSLATE: SVGTransform.SVG_TRANSFORM_TRANSLATE }.`, function () { 31 | const obj = { 32 | type: SVGTransform.SVG_TRANSFORM_TRANSLATE, 33 | SVG_TRANSFORM_TRANSLATE: SVGTransform.SVG_TRANSFORM_TRANSLATE, 34 | }; 35 | 36 | const result = $$isTranslateSVGTransform(obj); 37 | 38 | expect(result).false; 39 | }); 40 | 41 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_MATRIX.`, function () { 42 | const matrix_t = $$createSVGTransformMatrix({ 43 | matrix: makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)), 44 | })(); 45 | 46 | const result = $$isTranslateSVGTransform(matrix_t); 47 | 48 | expect(result).false; 49 | }); 50 | 51 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_ROTATE.`, function () { 52 | const rotate_t = $$createSVGTransformRotate({ 53 | angle: makeRandomNumber(-700, 700), 54 | cx: makeRandomNumber(-100, 100), 55 | cy: makeRandomNumber(-100, 100), 56 | })(); 57 | 58 | const result = $$isTranslateSVGTransform(rotate_t); 59 | 60 | expect(result).false; 61 | }); 62 | 63 | it(`When the input value is a SVGTransform whose type is the SVGTransform.SVG_TRANSFORM_SCALE.`, function () { 64 | const scale_t = $$createSVGTransformScale({ 65 | sx: makeRandomNumber(-100, 100), 66 | sy: makeRandomNumber(-100, 100), 67 | })(); 68 | 69 | const result = $$isTranslateSVGTransform(scale_t); 70 | 71 | expect(result).false; 72 | }); 73 | }); 74 | 75 | describe(`The function will return true...`, function () { 76 | it(`When the input value is a SVGTransform and the type is SVGTransform.SVG_TRANSFORM_TRANSLATE.`, function () { 77 | const translate_t = $$createSVGTransformTranslate({ 78 | tx: makeRandomNumber(-100, 100), 79 | ty: makeRandomNumber(-100, 100), 80 | })(); 81 | 82 | const result = $$isTranslateSVGTransform(translate_t); 83 | 84 | expect(result).true; 85 | }); 86 | }); 87 | }), 88 | ]; 89 | -------------------------------------------------------------------------------- /src/isValidFxScaleSVGTransformList/README.md: -------------------------------------------------------------------------------- 1 | # \$\$isValidFxScaleSVGTransformList 2 | 3 | - [source](./isValidFxScaleSVGTransformList.index.js) 4 | - [test](./isValidFxScaleSVGTransformList.spec.js) 5 | 6 | `$$initScaleTransform` 함수를 적용한 `SVGTransformList`인지 여부를 판단합니다. 7 | 8 | ```javascript 9 | const str = ``; 10 | const $el = $$el(str)(); 11 | $$initScaleTransform({ index: 0 })($el); 12 | const transform_list = $$getBaseTransformList($el); 13 | 14 | console.log($$isValidFxScaleSVGTransformList({ index: 1 })(transform_list)); 15 | // true 16 | ``` 17 | -------------------------------------------------------------------------------- /src/isValidFxScaleSVGTransformList/isValidFxScaleSVGTransformList.index.js: -------------------------------------------------------------------------------- 1 | import { go, mapL, rangeL } from "fxjs/es"; 2 | import { $$isScaleSVGTransform } from "../isScaleSVGTransform/isScaleSVGTransform.index.js"; 3 | import { $$isTranslateSVGTransform } from "../isTranslateSVGTransform/isTranslateSVGTransform.index.js"; 4 | 5 | export const $$isValidFxScaleSVGTransformList = ({ index = 0 } = {}) => ( 6 | transform_list 7 | ) => { 8 | if (index <= 0 || index >= transform_list.numberOfItems - 1) { 9 | return false; 10 | } 11 | 12 | const [ 13 | positive_translate_transform, 14 | scale_transform, 15 | negative_translate_transform, 16 | ] = go( 17 | rangeL(3), 18 | mapL((i) => index - 1 + i), 19 | mapL((i) => transform_list.getItem(i)) 20 | ); 21 | return ( 22 | $$isTranslateSVGTransform(positive_translate_transform) && 23 | $$isScaleSVGTransform(scale_transform) && 24 | $$isTranslateSVGTransform(negative_translate_transform) && 25 | positive_translate_transform.matrix.a === 1 && 26 | positive_translate_transform.matrix.b === 0 && 27 | positive_translate_transform.matrix.c === 0 && 28 | positive_translate_transform.matrix.d === 1 && 29 | negative_translate_transform.matrix.a === 1 && 30 | negative_translate_transform.matrix.b === 0 && 31 | negative_translate_transform.matrix.c === 0 && 32 | negative_translate_transform.matrix.d === 1 && 33 | positive_translate_transform.matrix.e + 34 | negative_translate_transform.matrix.e === 35 | 0 && 36 | positive_translate_transform.matrix.f + 37 | negative_translate_transform.matrix.f === 38 | 0 39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /src/joinPathData/README.md: -------------------------------------------------------------------------------- 1 | # \$\$toStringPathCommandParameters 2 | 3 | - [source](./joinPathData.index.js) 4 | - [test](./joinPathData.spec.js) 5 | 6 | 입력한 command + parameters 객체로 SVG path data 문자열을 생성합니다. 7 | 8 | # \$\$joinPathData 9 | 10 | - [source](./joinPathData.index.js) 11 | - [test](./joinPathData.spec.js) 12 | 13 | 입력한 command + parameters 객체의 배열로 SVG path data 문자열을 생성합니다. 14 | 반환한 문자열은 SVG 엘리먼트의 "d" 속성값에 해당합니다. 15 | -------------------------------------------------------------------------------- /src/mergeRotateTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$mergeRotateTransform 2 | 3 | - [source](./mergeRotateTransform.index.js) 4 | - [test](./mergeRotateTransform.spec.js) 5 | 6 | `$$initRotateTransform` 으로 적용된 3개의 `SVGTransform` 객체를 하나의 `SVGTransform` 으로 병합합니다. 7 | 한 번 병합한 `SVGTransform`을 `$$updateRotateTransform` 이나 `$$appendRotateTransform` 으로 변경하는 것은 안전하지 않습니다. 8 | `cx`, `cy`가 `0` 이 아닌 경우 회전 변환 중심이 의도치 않게 수정될 수 있습니다. 9 | 10 | ```javascript 11 | const str = ` 12 | 19 | 20 | `; 21 | const $el = $$el(str)(); 22 | 23 | console.log($$getBaseTransformList($el)); 24 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 25 | // 0: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 26 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 27 | 28 | $$initRotateTransform({ angle: 30, cx: 10, cy: 20 })($el); 29 | 30 | console.log($$getBaseTransformList($el)); 31 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, 2: SVGTransform, 3: SVGTransform, length: 4, numberOfItems: 4} 32 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 33 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 34 | // 1: SVGTransform {type: 4, matrix: SVGMatrix, angle: 30} 35 | // matrix: SVGMatrix {a: 0.8660254037844387, b: 0.49999999999999994, c: -0.49999999999999994, d: 0.8660254037844387, e: 0, f: 0} 36 | // 2: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 37 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: -10, f: -20} 38 | // 3: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 39 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 40 | 41 | $$mergeRotateTransform()($el); 42 | 43 | console.log($$getBaseTransformList($el)); 44 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, length: 2, numberOfItems: 2} 45 | // 0: SVGTransform {type: 4, matrix: SVGMatrix, angle: 30} 46 | // matrix: SVGMatrix {a: 0.8660254037844387, b: 0.49999999999999994, c: -0.49999999999999994, d: 0.8660254037844387, e: 11.339745962155611, f: -2.3205080756887746} 47 | // 1: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 48 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 49 | 50 | console.log($el); 51 | // 52 | ``` 53 | -------------------------------------------------------------------------------- /src/mergeRotateTransform/mergeRotateTransform.index.js: -------------------------------------------------------------------------------- 1 | import { each, go, mapL, rangeL } from "fxjs/es"; 2 | import { $$createSVGTransformRotate } from "../createSVGTransformRotate/createSVGTransformRotate.index.js"; 3 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 4 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 5 | import { $$isRotateSVGTransform } from "../isRotateSVGTransform/isRotateSVGTransform.index.js"; 6 | import { $$isTranslateSVGTransform } from "../isTranslateSVGTransform/isTranslateSVGTransform.index.js"; 7 | 8 | const $$isValidFxRotateSVGTransformList = ({ index }) => (transform_list) => { 9 | if (index > transform_list.numberOfItems - 2 || index < 1) { 10 | return false; 11 | } 12 | 13 | const [ 14 | positive_translate_transform, 15 | rotate_transform, 16 | negative_translate_transform, 17 | ] = go( 18 | rangeL(3), 19 | mapL((i) => index - 1 + i), 20 | mapL((i) => transform_list.getItem(i)) 21 | ); 22 | 23 | return ( 24 | $$isTranslateSVGTransform(positive_translate_transform) && 25 | $$isRotateSVGTransform(rotate_transform) && 26 | $$isTranslateSVGTransform(negative_translate_transform) && 27 | rotate_transform.matrix.e === 0 && 28 | rotate_transform.matrix.f === 0 && 29 | positive_translate_transform.matrix.a === 1 && 30 | positive_translate_transform.matrix.b === 0 && 31 | positive_translate_transform.matrix.c === 0 && 32 | positive_translate_transform.matrix.d === 1 && 33 | negative_translate_transform.matrix.a === 1 && 34 | negative_translate_transform.matrix.b === 0 && 35 | negative_translate_transform.matrix.c === 0 && 36 | negative_translate_transform.matrix.d === 1 && 37 | positive_translate_transform.matrix.e + 38 | negative_translate_transform.matrix.e === 39 | 0 && 40 | positive_translate_transform.matrix.f + 41 | negative_translate_transform.matrix.f === 42 | 0 43 | ); 44 | }; 45 | 46 | export const $$mergeRotateTransform = ({ index = 1 } = {}) => ( 47 | $el, 48 | $svg = $$getSVG() 49 | ) => { 50 | const base_transform_list = $$getBaseTransformList($el); 51 | if (!$$isValidFxRotateSVGTransformList({ index })(base_transform_list)) { 52 | return $el; 53 | } 54 | 55 | const { angle } = base_transform_list.getItem(index); 56 | const { e: cx, f: cy } = base_transform_list.getItem(index - 1).matrix; 57 | 58 | each(() => base_transform_list.removeItem(index - 1), rangeL(3)); 59 | 60 | const rotate_transform = $$createSVGTransformRotate({ angle, cx, cy })($svg); 61 | base_transform_list.insertItemBefore(rotate_transform, index - 1); 62 | 63 | return $el; 64 | }; 65 | -------------------------------------------------------------------------------- /src/mergeScaleTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$mergeScaleTransform 2 | 3 | - [source](./mergeScaleTransform.index.js) 4 | - [test](./mergeScaleTransform.spec.js) 5 | 6 | `$$initScaleTransform` 으로 적용된 3개의 `SVGTransform` 객체를 하나의 `SVGTransform` 으로 병합합니다. 7 | 병합된 `SVGTransform` 은 `SVGTransform.SVG_TRANSFORM_MATRIX` 타입입니다. 8 | 따라서 한 번 병합한 `SVGTransform`을 `$$updateScaleTransform` 이나 `$$appendScaleTransform` 으로 변경할 수 없습니다. 9 | 10 | ```javascript 11 | const str = ` 12 | 19 | 20 | `; 21 | const $el = $$el(str)(); 22 | 23 | console.log($$getBaseTransformList($el)); 24 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 25 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 26 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 200, f: 400} 27 | 28 | $$initScaleTransform({ sx: 2, sy: 3, cx: 60, cy: 70 })($el); 29 | 30 | console.log($$getBaseTransformList($el)); 31 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, 2: SVGTransform, 3: SVGTransform, length: 4, numberOfItems: 4} 32 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 33 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 60, f: 70} 34 | // 1: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 35 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 3, e: 0, f: 0} 36 | // 2: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 37 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: -60, f: -70} 38 | // 3: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 39 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 200, f: 400} 40 | 41 | $$mergeScaleTransform({ index: 1 })($el); 42 | // 인덱스 1 에 SVGTransform.SVG_TRANSFORM_SCALE 타입의 SVGTransform 위치 43 | 44 | console.log($$getBaseTransformList($el)); 45 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, length: 2, numberOfItems: 2} 46 | // 0: SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 47 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 3, e: -60, -140} 48 | // 1: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 49 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 200, f: 400} 50 | 51 | console.log($el); 52 | // 53 | ``` 54 | -------------------------------------------------------------------------------- /src/mergeScaleTransform/mergeScaleTransform.index.js: -------------------------------------------------------------------------------- 1 | import { each, go, mapL, rangeL, reduce } from "fxjs/es"; 2 | import { $$createSVGTransformMatrix } from "../createSVGTransformMatrix/createSVGTransformMatrix.index.js"; 3 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 4 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 5 | import { $$isValidFxScaleSVGTransformList } from "../isValidFxScaleSVGTransformList/isValidFxScaleSVGTransformList.index.js"; 6 | 7 | export const $$mergeScaleTransform = ({ index = 1 } = {}) => ( 8 | $el, 9 | $svg = $$getSVG() 10 | ) => { 11 | const transform_list = $$getBaseTransformList($el); 12 | if (!$$isValidFxScaleSVGTransformList({ index })(transform_list)) { 13 | return $el; 14 | } 15 | 16 | const merged_transform = go( 17 | rangeL(3), 18 | mapL((i) => index - 1 + i), 19 | mapL((i) => transform_list.getItem(i)), 20 | mapL(({ matrix }) => matrix), 21 | reduce((m1, m2) => m1.multiply(m2)), 22 | (matrix) => $$createSVGTransformMatrix({ matrix })($svg) 23 | ); 24 | each(() => transform_list.removeItem(index - 1), rangeL(3)); 25 | transform_list.insertItemBefore(merged_transform, index - 1); 26 | return $el; 27 | }; 28 | -------------------------------------------------------------------------------- /src/mergeScaleTransform2/README.md: -------------------------------------------------------------------------------- 1 | # \$\$mergeScaleTransform2 2 | 3 | - [source](./mergeScaleTransform2.index.js) 4 | - [test](./mergeScaleTransform2.spec.js) 5 | 6 | `$$initScaleTransform` 으로 적용된 3개의 `SVGTransform` 객체를 해당 svg 엘리먼트의 `x`, `y`, `width`, `height` 속성 7 | (혹은 그에 준하는 속성) 에 반영합니다. 8 | 9 | `index` 값을 통해 `SVGTransform.SVG_TRANSFORM_SCALE` 타입의 `SVGTransform` 의 위치를 설정할 수 있습니다. 10 | 지정하지 않을 경우 `1` 로 초기화됩니다. 11 | 12 | `direction` 값을 통해 scale 의 방향을 설정할 수 있습니다. 13 | 기본값을 설정하지 않기 때문에 필수 입력사항입니다. 14 | 15 | `is_need_correction` 값을 통해 `x`, `y` 값을 `s` 가 음수일 경우 조절할 것인지 여부를 설정할 수 있습니다. 16 | 지정하지 않을 경우 `true` 로 초기화됩니다. 17 | 18 | ```javascript 19 | const str = ` 20 | 27 | 28 | `; 29 | const $el = $$el(str)(); 30 | 31 | console.log($$getBaseTransformList($el)); 32 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 33 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 34 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 200, f: 400} 35 | 36 | $$initScaleTransform({ sx: 2, sy: 3, cx: 60, cy: 120, index: 1 })($el); 37 | // SVGTransformList 의 가장 뒤쪽에 추가 38 | // transform 이 적용되는 순서로는 가장 먼저 적용됨 39 | 40 | console.log($$getBaseTransformList($el)); 41 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, 2: SVGTransform, 3: SVGTransform, length: 4, numberOfItems: 4} 42 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 43 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 200, f: 400} 44 | // 1: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 45 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 60, f: 120} 46 | // 2: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 47 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 3, e: 0, f: 0} 48 | // 3: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 49 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: -60, f: -120} 50 | 51 | $$mergeScaleTransform2({ index: 2, direction: "se" })($el); 52 | // 인덱스 2 에 SVGTransform.SVG_TRANSFORM_SCALE 타입의 SVGTransform 위치 53 | 54 | console.log($$getBaseTransformList($el)); 55 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 56 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 57 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 200, f: 400} 58 | 59 | console.log($el); 60 | // 61 | ``` 62 | -------------------------------------------------------------------------------- /src/mergeScaleTransform2/mergeScaleTransform2.index.js: -------------------------------------------------------------------------------- 1 | import { each, go, go1, mapL, rangeL, some } from "fxjs/es"; 2 | import { $$getAttrNS } from "../getAttrNS/getAttrNS.index.js"; 3 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 4 | import { $$isValidFxScaleSVGTransformList } from "../isValidFxScaleSVGTransformList/isValidFxScaleSVGTransformList.index.js"; 5 | import { $$setAttrNS } from "../setAttrNS/setAttrNS.index.js"; 6 | 7 | const VALID_DIRECTION = new Set(["n", "ne", "e", "se", "s", "sw", "w", "nw"]); 8 | 9 | export const $$mergeScaleTransform2 = ({ 10 | index = 1, 11 | is_need_correction = true, 12 | x_name = "x", 13 | y_name = "y", 14 | width_name = "width", 15 | height_name = "height", 16 | direction, 17 | } = {}) => ($el) => { 18 | const transform_list = $$getBaseTransformList($el); 19 | if ( 20 | !$$isValidFxScaleSVGTransformList({ index })(transform_list) || 21 | !VALID_DIRECTION.has(direction) 22 | ) { 23 | return $el; 24 | } 25 | 26 | const [{ e: cx2, f: cy2 }, { a: sx, d: sy }, { e: cx1, f: cy1 }] = go( 27 | rangeL(3), 28 | mapL((i) => index - 1 + i), 29 | mapL((i) => transform_list.getItem(i)), 30 | mapL(({ matrix: m }) => m) 31 | ); 32 | const [x, y, width, height] = go( 33 | [x_name, y_name, width_name, height_name], 34 | mapL((name) => $$getAttrNS(name)($el)), 35 | mapL(parseFloat) 36 | ); 37 | 38 | go( 39 | [ 40 | [x, sx, cx1, cx2, width, ["e", "w"]], 41 | [y, sy, cy1, cy2, height, ["n", "s"]], 42 | ], 43 | mapL(([v, s, c1, c2, l, conditions]) => 44 | go( 45 | conditions, 46 | some((condition) => direction.includes(condition)), 47 | (is_changed) => 48 | is_changed 49 | ? go1((v + c1) * s + c2, (v) => 50 | s < 0 && is_need_correction ? v + l * s : v 51 | ) 52 | : v 53 | ) 54 | ), 55 | ([scaled_x, scaled_y]) => [ 56 | [x_name, scaled_x], 57 | [y_name, scaled_y], 58 | [width_name, width * Math.abs(sx)], 59 | [height_name, height * Math.abs(sy)], 60 | ], 61 | mapL(([k, v]) => [k, `${v}`]), 62 | each((kv) => $$setAttrNS(kv)($el)) 63 | ); 64 | 65 | each(() => transform_list.removeItem(index - 1), rangeL(3)); 66 | 67 | return $el; 68 | }; 69 | -------------------------------------------------------------------------------- /src/mergeTranslateTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$mergeTranslateTransform 2 | 3 | - [source](./mergeTranslateTransform.index.js) 4 | - [test](./mergeTranslateTransform.spec.js) 5 | 6 | svg 엘리먼트에 가장 마지막으로 적용된 `SVGTransform` 이 `SVGTransform.SVG_TRANSFORM_TRANSLATE` 타입인 경우 7 | 해당 `SVGTransform` 을 svg 엘리먼트의 `x`, `y` 속성 (혹은 그에 준하는 속성) 에 반영합니다. 8 | svg 엘리먼트에 다른 `SVGTransform` 이 있는 경우 각 `SVGTransform` 을 업데이트합니다. 9 | 10 | `cx`, `cy` 처럼 `x`, `y` 위치를 나타내는 속성명이 다른 경우 `x_name`, `y_name` 으로 해당 속성명을 설정할 수 있습니다. 11 | 12 | ```javascript 13 | const str = ` 14 | 21 | 22 | `; 23 | const $el = $$el(str)(); 24 | 25 | console.log($$getBaseTransformList($el)); 26 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 27 | // 0: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 28 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 29 | 30 | $$initTranslateTransform({ tx: 500, ty: 600 })($el); 31 | 32 | console.log($$getBaseTransformList($el)); 33 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, length: 2, numberOfItems: 2} 34 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 35 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 500, f: 600} 36 | // 1: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 37 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 38 | 39 | $$mergeTranslateTransform()($el); 40 | 41 | console.log($$getBaseTransformList($el)); 42 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 43 | // 0: SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 44 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: -500, f: -1800} 45 | 46 | console.log($el); 47 | // 48 | ``` 49 | 50 | ```javascript 51 | const str = ` 52 | 58 | 59 | `; 60 | const $el = $$el(str)(); 61 | 62 | console.log($$getBaseTransformList($el)); 63 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 64 | // 0: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 65 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 66 | 67 | $$initTranslateTransform({ tx: 500, ty: 600 })($el); 68 | 69 | console.log($$getBaseTransformList($el)); 70 | // SVGTransformList {0: SVGTransform, 1: SVGTransform, length: 2, numberOfItems: 2} 71 | // 0: SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 72 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 500, f: 600} 73 | // 1: SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 74 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: 0, f: 0} 75 | 76 | $$mergeTranslateTransform({ x_name: "cx", y_name: "cy" })($el); 77 | 78 | console.log($$getBaseTransformList($el)); 79 | // SVGTransformList {0: SVGTransform, length: 1, numberOfItems: 1} 80 | // 0: SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 81 | // matrix: SVGMatrix {a: 2, b: 0, c: 0, d: 4, e: -500, f: -1800} 82 | 83 | console.log($el); 84 | // 85 | ``` 86 | -------------------------------------------------------------------------------- /src/mergeTranslateTransform/mergeTranslateTransform.index.js: -------------------------------------------------------------------------------- 1 | import { each, go, mapL, rangeL } from "fxjs/es"; 2 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 3 | import { $$getAttrNS } from "../getAttrNS/getAttrNS.index.js"; 4 | import { $$getBaseTransformList } from "../getBaseTransformList/getBaseTransformList.index.js"; 5 | import { $$getSVG } from "../getSetSVG/getSetSVG.index.js"; 6 | import { $$isTranslateSVGTransform } from "../isTranslateSVGTransform/isTranslateSVGTransform.index.js"; 7 | import { $$setAttrNS } from "../setAttrNS/setAttrNS.index.js"; 8 | 9 | export const $$mergeTranslateTransform = ({ 10 | index = 0, 11 | x_name = "x", 12 | y_name = "y", 13 | } = {}) => ($el, $svg = $$getSVG()) => { 14 | const base_transform_list = $$getBaseTransformList($el); 15 | if (index > base_transform_list.numberOfItems - 1 || index < 0) { 16 | return $el; 17 | } 18 | 19 | const transform = base_transform_list.getItem(index); 20 | if (!$$isTranslateSVGTransform(transform)) { 21 | return $el; 22 | } 23 | 24 | const { e: tx, f: ty } = transform.matrix; 25 | 26 | go( 27 | [ 28 | { name: x_name, value: tx }, 29 | { name: y_name, value: ty }, 30 | ], 31 | mapL(({ name, value }) => [ 32 | name, 33 | `${parseFloat($$getAttrNS(name)($el)) + value}`, 34 | ]), 35 | each((kv) => $$setAttrNS(kv)($el)) 36 | ); 37 | 38 | base_transform_list.removeItem(index); 39 | 40 | go( 41 | rangeL(base_transform_list.numberOfItems), 42 | mapL((i) => base_transform_list.getItem(i)), 43 | mapL((t) => [ 44 | $$createSVGTransformTranslate({ tx, ty })($svg), 45 | t, 46 | $$createSVGTransformTranslate({ tx: -tx, ty: -ty })($svg), 47 | ]), 48 | each(([t1, t2, t3]) => { 49 | const matrix = t1.matrix.multiply(t2.matrix).multiply(t3.matrix); 50 | t2.setMatrix(matrix); 51 | }) 52 | ); 53 | 54 | return $el; 55 | }; 56 | -------------------------------------------------------------------------------- /src/parsePathData/README.md: -------------------------------------------------------------------------------- 1 | # \$\$splitPathDataByCommandL 2 | 3 | - [source](./parsePathData.index.js) 4 | - [test](./parsePathData.spec.js) 5 | 6 | path data 문자열을 command 단위로 잘라냅니다. 7 | 제너레이터는 command 와 해당 command 의 parameters 를 yield 합니다. 8 | command 와 parameters 는 문자열입니다. 9 | 10 | 이 함수는 입력 데이터의 유효성을 검사하지 않습니다! 11 | 12 | # \$\$parsePathCommandParameters 13 | 14 | - [source](./parsePathData.index.js) 15 | - [test](./parsePathData.spec.js) 16 | 17 | parameters 문자열을 숫자 배열로 변환합니다. 18 | 제너레이터는 command 와 해당 command 의 변환된 parameters 를 yield 합니다. 19 | 20 | # \$\$convertPathCommandParametersRelativeToAbsoluteL 21 | 22 | - [source](./parsePathData.index.js) 23 | - [test](./parsePathData.spec.js) 24 | 25 | path 의 command-parameters 이터러블을 relative 좌표에서 absolute 좌표로 변환합니다. 26 | 27 | 이 함수는 입력 데이터의 유효성을 검사하지 않습니다! 28 | 29 | # \$\$compressPathCommandL 30 | 31 | - [source](./parsePathData.index.js) 32 | - [test](./parsePathData.spec.js) 33 | 34 | 다른 command 에 의존적인 command 를 변환합니다. 35 | 36 | - "H", "V" -> "L" 37 | - "S" -> "C" 38 | - "T" -> "Q" 39 | 40 | 이 함수는 입력 데이터의 유효성을 검사하지 않습니다! 41 | 42 | # \$\$flatPathCommandParametersL 43 | 44 | - [source](./parsePathData.index.js) 45 | - [test](./parsePathData.spec.js) 46 | 47 | path 의 command-parameter 를 각 parameter 별로 펼칩니다. 48 | "command + parameter 시퀸스" 를 "command + parameter" 의 시퀸스로 평탄화합니다. 49 | 50 | 이 함수는 입력 데이터의 유효성을 검사하지 않습니다! 51 | 52 | # \$\$parsePathData 53 | 54 | - [source](./parsePathData.index.js) 55 | - [test](./parsePathData.spec.js) 56 | 57 | `` 엘리먼트의 `d` 속성의 값을 파싱하여 `{command, parameters}` 객체의 이터레이터를 반환합니다. 58 | 위의 splitting, parsing, converting, compressing, flattening 작업을 모두 진행합니다. 59 | -------------------------------------------------------------------------------- /src/parsePathData/const.js: -------------------------------------------------------------------------------- 1 | import { go, join, mapL } from "fxjs/es"; 2 | 3 | export const FN_PATH = `$$parsePathData`; 4 | export const FN_PATH_PARSE_COORDINATE_SEQ = `$$parseCoordinateSeqL`; 5 | export const FN_PATH_PARSE_PATH_COMMAND_PARAMETERS = `$$parsePathCommandParameters`; 6 | 7 | export const REGEXP_STR_COMMAND = `[MmZzLlHhVvCcSsQqTtAa]`; 8 | export const REGEXP_STR_WSP = `\\s`; 9 | export const REGEXP_STR_COMMA = `,`; 10 | /** @type {string} */ 11 | export const REGEXP_STR_COMMA_WSP = go( 12 | [ 13 | `${REGEXP_STR_WSP}+`, 14 | `${REGEXP_STR_WSP}*${REGEXP_STR_COMMA}${REGEXP_STR_WSP}*`, 15 | ], 16 | mapL((s) => `(?:${s})`), 17 | join("|"), 18 | (s) => `(?:${s})` 19 | ); 20 | export const REGEXP_STR_FLAG = `(?:0|1)`; 21 | export const REGEXP_STR_SIGN = `(?:\\+|-)`; 22 | export const REGEXP_STR_DIGIT = `\\d`; 23 | export const REGEXP_STR_DIGIT_SEQ = `(?:${REGEXP_STR_DIGIT}+)`; 24 | export const REGEXP_STR_EXPONENT = `(?:[eE]${REGEXP_STR_SIGN}?${REGEXP_STR_DIGIT_SEQ})`; 25 | /** @type {string} */ 26 | export const REGEXP_STR_FRACTIONAL_CONST = go( 27 | [ 28 | `${REGEXP_STR_DIGIT_SEQ}?\\.${REGEXP_STR_DIGIT_SEQ}`, 29 | `${REGEXP_STR_DIGIT_SEQ}\\.`, 30 | ], 31 | mapL((s) => `(?:${s})`), 32 | join("|"), 33 | (s) => `(?:${s})` 34 | ); 35 | /** @type {string} */ 36 | export const REGEXP_STR_FLOATING_POINT_CONST = go( 37 | [ 38 | `${REGEXP_STR_FRACTIONAL_CONST}${REGEXP_STR_EXPONENT}?`, 39 | `${REGEXP_STR_DIGIT_SEQ}${REGEXP_STR_EXPONENT}`, 40 | ], 41 | mapL((s) => `(?:${s})`), 42 | join("|"), 43 | (s) => `(?:${s})` 44 | ); 45 | /** @type {string} */ 46 | export const REGEXP_STR_NON_NEGATIVE_NUMBER = go( 47 | [REGEXP_STR_FLOATING_POINT_CONST, REGEXP_STR_DIGIT_SEQ], 48 | join("|"), 49 | (s) => `(?:${s})` 50 | ); 51 | export const REGEXP_STR_NUMBER = `(?:${REGEXP_STR_SIGN}?${REGEXP_STR_NON_NEGATIVE_NUMBER})`; 52 | -------------------------------------------------------------------------------- /src/removeAttrNS/README.md: -------------------------------------------------------------------------------- 1 | # \$\$removeAttrNS 2 | 3 | - [source](./removeAttrNS.index.js) 4 | - [test](./removeAttrNS.spec.js) 5 | 6 | SVG 엘리먼트의 속성을 제거합니다. 필요한 경우 namespace 를 지정하여 사용할 수 있습니다. 7 | 8 | ```javascript 9 | const el = $$el(``)(); 10 | 11 | console.log($$removeAttrNS("data-foo")(el)); 12 | // undefined 13 | console.log(el); 14 | // 15 | ``` 16 | -------------------------------------------------------------------------------- /src/removeAttrNS/removeAttrNS.index.js: -------------------------------------------------------------------------------- 1 | export const $$removeAttrNS = (key, namespace = null) => (el) => 2 | el.removeAttributeNS(namespace, key); 3 | -------------------------------------------------------------------------------- /src/removeAttrNS/removeAttrNS.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { $$el } from "../el/el.index.js"; 3 | import { $$hasAttrNS } from "../hasAttrNS/hasAttrNS.index.js"; 4 | import { $$removeAttrNS } from "./removeAttrNS.index.js"; 5 | 6 | const { expect } = chai; 7 | 8 | export default ({ describe, it }) => [ 9 | describe(`$$removeAttrNS`, function () { 10 | it(`The function returns "undefined" whether the attribute exists or not.`, function () { 11 | // given 12 | const key = "data-foo"; 13 | const dummy_key = "data-baz"; 14 | const el = $$el( 15 | `` 16 | )(); 17 | 18 | // when 19 | const received_value1 = $$removeAttrNS(key)(el); 20 | const received_value2 = $$removeAttrNS(dummy_key)(el); 21 | 22 | // then 23 | expect(received_value1).undefined; 24 | expect(received_value2).undefined; 25 | }); 26 | 27 | it(`The function remove the attribute from the element.`, function () { 28 | // given 29 | const key = "data-foo"; 30 | const el = $$el( 31 | `` 32 | )(); 33 | 34 | // when 35 | $$removeAttrNS(key)(el); 36 | 37 | // then 38 | expect($$hasAttrNS(key)(el)).false; 39 | }); 40 | }), 41 | ]; 42 | -------------------------------------------------------------------------------- /src/setAttrNS/README.md: -------------------------------------------------------------------------------- 1 | # \$\$setAttrNS 2 | 3 | - [source](./setAttrNS.index.js) 4 | - [test](./setAttrNS.spec.js) 5 | 6 | SVG 엘리먼트에 속성과 값을 추가합니다. 필요한 경우 namespace 를 지정하여 사용할 수 있습니다. 7 | 8 | ```javascript 9 | const el = $$el(``)(); 10 | 11 | $$setAttrNS(["data-foo", "bar"])(el); 12 | console.log(el); 13 | // 14 | ``` 15 | -------------------------------------------------------------------------------- /src/setAttrNS/setAttrNS.index.js: -------------------------------------------------------------------------------- 1 | export const $$setAttrNS = ([key, value], namespace = null) => (el) => 2 | el.setAttributeNS(namespace, key, value); 3 | -------------------------------------------------------------------------------- /src/setAttrNS/setAttrNS.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { $$el } from "../el/el.index.js"; 3 | import { $$getAttrNS } from "../getAttrNS/getAttrNS.index.js"; 4 | import { $$setAttrNS } from "./setAttrNS.index.js"; 5 | 6 | const { expect } = chai; 7 | 8 | export default ({ describe, it }) => [ 9 | describe(`$$setAttrNS`, function () { 10 | it(`The function returns "undefined".`, function () { 11 | // given 12 | const key = "data-foo"; 13 | const value = "bar"; 14 | const el = $$el(``)(); 15 | 16 | // when 17 | const received_value = $$setAttrNS([key, value])(el); 18 | 19 | // then 20 | expect(received_value).undefined; 21 | }); 22 | 23 | it(`The function makes the attribute with the value to the element.`, function () { 24 | // given 25 | const key = "data-foo"; 26 | const value = "bar"; 27 | const el = $$el(``)(); 28 | 29 | // when 30 | $$setAttrNS([key, value])(el); 31 | 32 | // then 33 | expect($$getAttrNS(key)(el)).equal(value); 34 | }); 35 | }), 36 | ]; 37 | -------------------------------------------------------------------------------- /src/updateMatrixTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$updateMatrixTransform 2 | 3 | - [source](./updateMatrixTransform.index.js) 4 | - [test](./updateMatrixTransform.spec.js) 5 | 6 | `SVGTransform.SVG_TRANSFORM_MATRIX` 타입의 `SVGTransform` 의 `matrix` 값을 수정합니다. 7 | 기존 `matrix`를 입력받은 `matrix`로 수정합니다. 8 | 수정한 `SVGTransform` 객체를 반환합니다. 9 | 이 함수는 인자로 받은 `SVGTransform` 객체를 직접 수정합니다. 10 | 11 | 입력한 `tx`, `ty` 값과 실제 Transform 에 적용된 값은 정확도 차이가 발생할 수 있습니다. 12 | 13 | ```javascript 14 | const matrix1 = $$createSVGMatrix({ a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 })(); 15 | const transform = $$createSVGTransformMatrix({ matrix: matrix1 })(); 16 | console.log(transform); 17 | // SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 18 | // matrix: SVGMatrix {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6} 19 | const matrix2 = $$createSVGMatrix({ a: 7, b: 8, c: 9, d: 10, e: 11, f: 12 })(); 20 | $$updateMatrixTransform({ matrix: matrix2 })(transform); 21 | console.log(transform); 22 | // SVGTransform {type: 1, matrix: SVGMatrix, angle: 0} 23 | // matrix: SVGMatrix {a: 7, b: 8, c: 9, d: 10, e: 11, f: 12} 24 | ``` 25 | -------------------------------------------------------------------------------- /src/updateMatrixTransform/updateMatrixTransform.index.js: -------------------------------------------------------------------------------- 1 | import { defaultTo } from "fxjs/es"; 2 | import { $$isMatrixSVGTransform } from "../isMatrixSVGTransform/isMatrixSVGTransform.index.js"; 3 | 4 | export const $$updateMatrixTransform = ({ matrix } = {}) => (transform) => { 5 | if (!$$isMatrixSVGTransform(transform)) { 6 | return transform; 7 | } 8 | 9 | transform.setMatrix(defaultTo(transform.matrix, matrix)); 10 | return transform; 11 | }; 12 | -------------------------------------------------------------------------------- /src/updateMatrixTransform/updateMatrixTransform.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { expectSameValueSVGTransform } from "../../test/assertions/index.js"; 3 | import { 4 | makeRandomNumber, 5 | makeRandomSVGMatrix, 6 | } from "../../test/utils/index.js"; 7 | import { $$createSVGTransform } from "../createSVGTransform/createSVGTransform.index.js"; 8 | import { $$createSVGTransformMatrix } from "../createSVGTransformMatrix/createSVGTransformMatrix.index.js"; 9 | import { $$createSVGTransformRotate } from "../createSVGTransformRotate/createSVGTransformRotate.index.js"; 10 | import { $$createSVGTransformScale } from "../createSVGTransformScale/createSVGTransformScale.index.js"; 11 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 12 | import { $$updateMatrixTransform } from "./updateMatrixTransform.index.js"; 13 | 14 | const { expect } = chai; 15 | 16 | const setupMockTransform = () => { 17 | const matrix = makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)); 18 | const transform = $$createSVGTransformMatrix({ matrix })(); 19 | return { transform, matrix }; 20 | }; 21 | 22 | const setupMockInputValues = () => ({ 23 | matrix: makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)), 24 | }); 25 | 26 | const expectTransformWithMatrix = ({ 27 | transform: receive_transform, 28 | matrix, 29 | }) => { 30 | const expect_transform = $$createSVGTransform(); 31 | expect_transform.setMatrix(matrix); 32 | expectSameValueSVGTransform( 33 | receive_transform, 34 | expect_transform, 35 | "expectTransformWithMatrix" 36 | ); 37 | }; 38 | 39 | export default ({ describe, it }) => [ 40 | describe(`$$updateMatrixTransform`, function () { 41 | it(`The matrix of the input transform is changed to input matrix.`, function () { 42 | const { transform } = setupMockTransform(); 43 | const { matrix } = setupMockInputValues(); 44 | 45 | $$updateMatrixTransform({ matrix })(transform); 46 | 47 | expectTransformWithMatrix({ transform, matrix }); 48 | }); 49 | 50 | it(`The matrix of the transform is same with before when there is no input matrix.`, function () { 51 | const { transform, matrix } = setupMockTransform(); 52 | 53 | $$updateMatrixTransform({})(transform); 54 | 55 | expectTransformWithMatrix({ transform, matrix }); 56 | }); 57 | 58 | it(`The matrix of the transform is same with before when there is no input object.`, function () { 59 | const { transform, matrix } = setupMockTransform(); 60 | 61 | $$updateMatrixTransform()(transform); 62 | 63 | expectTransformWithMatrix({ transform, matrix }); 64 | }); 65 | 66 | describe(`If the transform is another type transform, the function will do nothing but return the input.`, function () { 67 | it(`When the transform is a translate transform...`, function () { 68 | const before_t = $$createSVGTransformTranslate({ 69 | tx: makeRandomNumber(-100, 100), 70 | ty: makeRandomNumber(-100, 100), 71 | })(); 72 | const matrix = makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)); 73 | 74 | const after_t = $$updateMatrixTransform({ matrix })(before_t); 75 | 76 | expect(after_t).equal(before_t); 77 | expectSameValueSVGTransform(after_t, before_t); 78 | }); 79 | 80 | it(`When the transform is a rotate transform...`, function () { 81 | const before_t = $$createSVGTransformRotate({ 82 | angle: makeRandomNumber(-700, 700), 83 | cx: makeRandomNumber(-100, 100), 84 | cy: makeRandomNumber(-100, 100), 85 | })(); 86 | const matrix = makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)); 87 | 88 | const after_t = $$updateMatrixTransform({ matrix })(before_t); 89 | 90 | expect(after_t).equal(before_t); 91 | expectSameValueSVGTransform(after_t, before_t); 92 | }); 93 | 94 | it(`When the transform is a scale transform...`, function () { 95 | const before_t = $$createSVGTransformScale({ 96 | sx: makeRandomNumber(-100, 100), 97 | sy: makeRandomNumber(-100, 100), 98 | })(); 99 | const matrix = makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)); 100 | 101 | const after_t = $$updateMatrixTransform({ matrix })(before_t); 102 | 103 | expect(after_t).equal(before_t); 104 | expectSameValueSVGTransform(after_t, before_t); 105 | }); 106 | }); 107 | }), 108 | ]; 109 | -------------------------------------------------------------------------------- /src/updateRotateTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$updateRotateTransform 2 | 3 | - [source](./updateRotateTransform.index.js) 4 | - [test](./updateRotateTransform.spec.js) 5 | 6 | `SVGTransform.SVG_TRANSFORM_ROTATE` 타입의 `SVGTransform` 의 `angle` 값을 수정합니다. 7 | 기존 `angle`을 입력받은 `angle`로 수정합니다. 8 | `cx`, `cy`는 항상 `0`으로 고정됩니다. 9 | 회전 중심을 설정해야 할 경우 `SVGTransform.SVG_TRANSFORM_TRANSLATE` 타입의 `SVGTransform` 을 앞, 뒤로 추가하는 방삭을 사용합니다. 10 | 수정한 `SVGTransform` 객체를 반환합니다. 11 | 이 함수는 인자로 받은 `SVGTransform` 객체를 직접 수정합니다. 12 | 13 | ```javascript 14 | const transform = $$createSVGTransformRotate({ angle: 30 })(); 15 | console.log(transform); 16 | // SVGTransform {type: 4, matrix: SVGMatrix, angle: 30} 17 | $$updateRotateTransform({ angle: 60 })(transform); 18 | console.log(transform); 19 | // SVGTransform {type: 4, matrix: SVGMatrix, angle: 60} 20 | ``` 21 | -------------------------------------------------------------------------------- /src/updateRotateTransform/updateRotateTransform.index.js: -------------------------------------------------------------------------------- 1 | import { defaultTo } from "fxjs/es"; 2 | import { $$isRotateSVGTransform } from "../isRotateSVGTransform/isRotateSVGTransform.index.js"; 3 | 4 | export const $$updateRotateTransform = ({ angle, cx = 0, cy = 0 } = {}) => ( 5 | transform 6 | ) => { 7 | if (!$$isRotateSVGTransform(transform)) { 8 | return transform; 9 | } 10 | 11 | transform.setRotate(defaultTo(transform.angle, angle), cx, cy); 12 | return transform; 13 | }; 14 | -------------------------------------------------------------------------------- /src/updateScaleTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$updateScaleTransform 2 | 3 | - [source](./updateScaleTransform.index.js) 4 | - [test](./updateScaleTransform.sepc.js) 5 | 6 | `SVGTransform.SVG_TRANSFORM_SCALE` 타입의 `SVGTransform` 의 `sx`, `sy` 값을 수정합니다. 7 | 기존 `sx`, `sy`를 입력받은 `sx`, `sy`로 수정합니다. 8 | 수정한 `SVGTransform` 객체를 반환합니다. 9 | 이 함수는 인자로 받은 `SVGTransform` 객체를 직접 수정합니다. 10 | 11 | 입력한 `sx`, `sy` 값과 실제 Transform 에 적용된 값은 정확도 차이가 발생할 수 있습니다. 12 | 13 | ```javascript 14 | const transform = $$createSVGTransformScale({ sx: 10, sy: 20 })(); 15 | console.log(transform); 16 | // SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 17 | // matrix: SVGMatrix {a: 10, b: 0, c: 0, d: 20, e: 0, f: 0} 18 | $$updateScaleTransform({ sx: 100, sy: 200 })(transform); 19 | console.log(transform); 20 | // SVGTransform {type: 3, matrix: SVGMatrix, angle: 0} 21 | // matrix: SVGMatrix {a: 100, b: 0, c: 0, d: 200, e: 0, f: 0} 22 | ``` 23 | -------------------------------------------------------------------------------- /src/updateScaleTransform/updateScaleTransform.index.js: -------------------------------------------------------------------------------- 1 | import { defaultTo } from "fxjs/es"; 2 | import { $$isScaleSVGTransform } from "../isScaleSVGTransform/isScaleSVGTransform.index.js"; 3 | 4 | export const $$updateScaleTransform = ({ sx, sy } = {}) => (transform) => { 5 | if (!$$isScaleSVGTransform(transform)) { 6 | return transform; 7 | } 8 | 9 | transform.setScale( 10 | defaultTo(transform.matrix.a, sx), 11 | defaultTo(transform.matrix.d, sy) 12 | ); 13 | return transform; 14 | }; 15 | -------------------------------------------------------------------------------- /src/updateScaleTransform/updateScaleTransform.sepc.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { mapL, rangeL } from "fxjs/es"; 3 | import { 4 | expectSameValueSVGTransform, 5 | expectTransformWithScaleSxSy, 6 | } from "../../test/assertions/index.js"; 7 | import { 8 | makeRandomNumber, 9 | makeRandomSVGMatrix, 10 | } from "../../test/utils/index.js"; 11 | import { $$createSVGTransformMatrix } from "../createSVGTransformMatrix/createSVGTransformMatrix.index.js"; 12 | import { $$createSVGTransformRotate } from "../createSVGTransformRotate/createSVGTransformRotate.index.js"; 13 | import { $$createSVGTransformScale } from "../createSVGTransformScale/createSVGTransformScale.index.js"; 14 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 15 | import { $$updateScaleTransform } from "./updateScaleTransform.index.js"; 16 | 17 | const { expect } = chai; 18 | 19 | const setupMockTransform = () => { 20 | const [sx, sy] = mapL(() => makeRandomNumber(-100, 100), rangeL(2)); 21 | const transform = $$createSVGTransformScale({ sx, sy })(); 22 | return { transform, sx, sy }; 23 | }; 24 | 25 | const setupMockInputValues = () => ({ 26 | sx: makeRandomNumber(-100, 100), 27 | sy: makeRandomNumber(-100, 100), 28 | }); 29 | 30 | export default ({ describe, it }) => [ 31 | describe(`$$updateScaleTransform`, function () { 32 | it(`The sx, sy of the input transform is changed to input angle, sx, sy.`, function () { 33 | const { transform } = setupMockTransform(); 34 | const { sx, sy } = setupMockInputValues(); 35 | 36 | $$updateScaleTransform({ sx, sy })(transform); 37 | 38 | expectTransformWithScaleSxSy({ transform, sx, sy }); 39 | }); 40 | 41 | it(`The sx of the transform is same with before when there is no input sx.`, function () { 42 | const { transform, sx } = setupMockTransform(); 43 | const { sy } = setupMockInputValues(); 44 | 45 | $$updateScaleTransform({ sy })(transform); 46 | 47 | expectTransformWithScaleSxSy({ transform, sx, sy }); 48 | }); 49 | 50 | it(`The sy of the transform is same with before when there is no input sy.`, function () { 51 | const { transform, sy } = setupMockTransform(); 52 | const { sx } = setupMockInputValues(); 53 | 54 | $$updateScaleTransform({ sx })(transform); 55 | 56 | expectTransformWithScaleSxSy({ transform, sx, sy }); 57 | }); 58 | 59 | it(`The sx, sy of the transform is same with before when there is no input object.`, function () { 60 | const { transform, sx, sy } = setupMockTransform(); 61 | 62 | $$updateScaleTransform()(transform); 63 | 64 | expectTransformWithScaleSxSy({ transform, sx, sy }); 65 | }); 66 | 67 | describe(`If the transform is another type transform, the function will do nothing but return the input.`, function () { 68 | it(`When the transform is a matrix transform...`, function () { 69 | const before_t = $$createSVGTransformMatrix({ 70 | matrix: makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)), 71 | })(); 72 | const { sx, sy } = setupMockInputValues(); 73 | 74 | const after_t = $$updateScaleTransform({ sx, sy })(before_t); 75 | 76 | expect(after_t).equal(before_t); 77 | expectSameValueSVGTransform(after_t, before_t); 78 | }); 79 | 80 | it(`When the transform is a rotate transform...`, function () { 81 | const before_t = $$createSVGTransformRotate({ 82 | angle: makeRandomNumber(-700, 700), 83 | cx: makeRandomNumber(-100, 100), 84 | cy: makeRandomNumber(-100, 100), 85 | })(); 86 | const { sx, sy } = setupMockInputValues(); 87 | 88 | const after_t = $$updateScaleTransform({ sx, sy })(before_t); 89 | 90 | expect(after_t).equal(before_t); 91 | expectSameValueSVGTransform(after_t, before_t); 92 | }); 93 | 94 | it(`When the transform is a translate transform...`, function () { 95 | const before_t = $$createSVGTransformTranslate({ 96 | tx: makeRandomNumber(-100, 100), 97 | ty: makeRandomNumber(-100, 100), 98 | })(); 99 | const { sx, sy } = setupMockInputValues(); 100 | 101 | const after_t = $$updateScaleTransform({ sx, sy })(before_t); 102 | 103 | expect(after_t).equal(before_t); 104 | expectSameValueSVGTransform(after_t, before_t); 105 | }); 106 | }); 107 | }), 108 | ]; 109 | -------------------------------------------------------------------------------- /src/updateTranslateTransform/README.md: -------------------------------------------------------------------------------- 1 | # \$\$updateTranslateTransform 2 | 3 | - [source](./updateTranslateTransform.index.js) 4 | - [test](./updateTranslateTransform.spec.js) 5 | 6 | `SVGTransform.SVG_TRANSFORM_TRANSLATE` 타입의 `SVGTransform` 의 `tx`, `ty` 값을 수정합니다. 7 | 기존 `tx`, `ty`를 입력받은 `tx`, `ty`로 수정합니다. 8 | 수정한 `SVGTransform` 객체를 반환합니다. 9 | 이 함수는 인자로 받은 `SVGTransform` 객체를 직접 수정합니다. 10 | 11 | 입력한 `tx`, `ty` 값과 실제 Transform 에 적용된 값은 정확도 차이가 발생할 수 있습니다. 12 | 13 | ```javascript 14 | const transform = $$createSVGTransformTranslate({ tx: 10, ty: 20 })(); 15 | console.log(transform); 16 | // SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 17 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 10, f: 20} 18 | $$updateTranslateTransform({ tx: 100, ty: 200 })(transform); 19 | console.log(transform); 20 | // SVGTransform {type: 2, matrix: SVGMatrix, angle: 0} 21 | // matrix: SVGMatrix {a: 1, b: 0, c: 0, d: 1, e: 100, f: 200} 22 | ``` 23 | -------------------------------------------------------------------------------- /src/updateTranslateTransform/updateTranslateTransform.index.js: -------------------------------------------------------------------------------- 1 | import { defaultTo } from "fxjs/es"; 2 | import { $$isTranslateSVGTransform } from "../isTranslateSVGTransform/isTranslateSVGTransform.index.js"; 3 | 4 | export const $$updateTranslateTransform = ({ tx, ty } = {}) => (transform) => { 5 | if (!$$isTranslateSVGTransform(transform)) { 6 | return transform; 7 | } 8 | 9 | transform.setTranslate( 10 | defaultTo(transform.matrix.e, tx), 11 | defaultTo(transform.matrix.f, ty) 12 | ); 13 | return transform; 14 | }; 15 | -------------------------------------------------------------------------------- /src/updateTranslateTransform/updateTranslateTransform.spec.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { mapL, rangeL } from "fxjs/es"; 3 | import { 4 | expectSameValueSVGTransform, 5 | expectTransformWithTranslateTxTy, 6 | } from "../../test/assertions/index.js"; 7 | import { 8 | makeRandomInt, 9 | makeRandomNumber, 10 | makeRandomSVGMatrix, 11 | } from "../../test/utils/index.js"; 12 | import { $$createSVGTransformMatrix } from "../createSVGTransformMatrix/createSVGTransformMatrix.index.js"; 13 | import { $$createSVGTransformRotate } from "../createSVGTransformRotate/createSVGTransformRotate.index.js"; 14 | import { $$createSVGTransformScale } from "../createSVGTransformScale/createSVGTransformScale.index.js"; 15 | import { $$createSVGTransformTranslate } from "../createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 16 | import { $$updateTranslateTransform } from "./updateTranslateTransform.index.js"; 17 | 18 | const { expect } = chai; 19 | 20 | const setupMockTransform = () => { 21 | const [tx, ty] = mapL(() => makeRandomInt(-100, 100), rangeL(2)); 22 | const transform = $$createSVGTransformTranslate({ tx, ty })(); 23 | return { transform, tx, ty }; 24 | }; 25 | 26 | const setupMockInputValues = () => { 27 | const [tx, ty] = mapL(() => makeRandomInt(-100, 100), rangeL(2)); 28 | return { tx, ty }; 29 | }; 30 | 31 | export default ({ describe, it }) => [ 32 | describe(`$$updateTranslateTransform`, function () { 33 | it(`The tx, ty of the input transform is changed to input tx, ty.`, function () { 34 | const { transform } = setupMockTransform(); 35 | const { tx, ty } = setupMockInputValues(); 36 | 37 | $$updateTranslateTransform({ tx, ty })(transform); 38 | 39 | expectTransformWithTranslateTxTy({ transform, tx, ty }); 40 | }); 41 | 42 | it(`The tx of the transform is same with before when there is no input tx.`, function () { 43 | const { transform, tx } = setupMockTransform(); 44 | const { ty } = setupMockInputValues(); 45 | 46 | $$updateTranslateTransform({ ty })(transform); 47 | 48 | expectTransformWithTranslateTxTy({ transform, tx, ty }); 49 | }); 50 | 51 | it(`The ty of the transform is same with before when there is no input ty.`, function () { 52 | const { transform, ty } = setupMockTransform(); 53 | const { tx } = setupMockInputValues(); 54 | 55 | $$updateTranslateTransform({ tx })(transform); 56 | 57 | expectTransformWithTranslateTxTy({ transform, tx, ty }); 58 | }); 59 | 60 | it(`The tx, ty of the transform is same with before when there is no input object.`, function () { 61 | const { transform, tx, ty } = setupMockTransform(); 62 | 63 | $$updateTranslateTransform()(transform); 64 | 65 | expectTransformWithTranslateTxTy({ transform, tx, ty }); 66 | }); 67 | 68 | describe(`If the transform is another type transform, the function will do nothing but return the input.`, function () { 69 | it(`When the transform is a matrix transform...`, function () { 70 | const before_t = $$createSVGTransformMatrix({ 71 | matrix: makeRandomSVGMatrix(() => makeRandomNumber(-100, 100)), 72 | })(); 73 | const { tx, ty } = setupMockInputValues(); 74 | 75 | const after_t = $$updateTranslateTransform({ tx, ty })(before_t); 76 | 77 | expect(after_t).equal(before_t); 78 | expectSameValueSVGTransform(after_t, before_t); 79 | }); 80 | 81 | it(`When the transform is a rotate transform...`, function () { 82 | const before_t = $$createSVGTransformRotate({ 83 | angle: makeRandomNumber(-700, 700), 84 | cx: makeRandomNumber(-100, 100), 85 | cy: makeRandomNumber(-100, 100), 86 | })(); 87 | const { tx, ty } = setupMockInputValues(); 88 | 89 | const after_t = $$updateTranslateTransform({ tx, ty })(before_t); 90 | 91 | expect(after_t).equal(before_t); 92 | expectSameValueSVGTransform(after_t, before_t); 93 | }); 94 | 95 | it(`When the transform is a scale transform...`, function () { 96 | const before_t = $$createSVGTransformScale({ 97 | sx: makeRandomNumber(-100, 100), 98 | sy: makeRandomNumber(-100, 100), 99 | })(); 100 | const { tx, ty } = setupMockInputValues(); 101 | 102 | const after_t = $$updateTranslateTransform({ tx, ty })(before_t); 103 | 104 | expect(after_t).equal(before_t); 105 | expectSameValueSVGTransform(after_t, before_t); 106 | }); 107 | }); 108 | }), 109 | ]; 110 | -------------------------------------------------------------------------------- /test/assertions/expectSameNumberEpsilon.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | 3 | const { expect } = chai; 4 | 5 | export const expectSameNumberEpsilon = ( 6 | receive_number, 7 | expect_number, 8 | epsilon = Number.EPSILON, 9 | message = "" 10 | ) => 11 | expect( 12 | Math.abs(receive_number - expect_number) < epsilon, 13 | `${ 14 | message ? `${message}::` : "" 15 | }receive:${receive_number},expect:${expect_number}` 16 | ).true; 17 | -------------------------------------------------------------------------------- /test/assertions/expectSameValueSVGMatrix.js: -------------------------------------------------------------------------------- 1 | import { each, go, mapL } from "fxjs/es"; 2 | import { expectSameNumberEpsilon } from "./expectSameNumberEpsilon.js"; 3 | 4 | export const expectSameValueSVGMatrix = (receive_m, expect_m, message = "") => 5 | go( 6 | ["a", "b", "c", "d", "e", "f"], 7 | mapL((k) => [ 8 | receive_m[k], 9 | expect_m[k], 10 | `${message ? `${message}::` : ""}expectSameValueSVGMatrix::${k}`, 11 | ]), 12 | each(([receive_v, expect_v, m]) => 13 | expectSameNumberEpsilon(receive_v, expect_v, 0.001, m) 14 | ) 15 | ); 16 | -------------------------------------------------------------------------------- /test/assertions/expectSameValueSVGTransform.js: -------------------------------------------------------------------------------- 1 | import chai from "chai"; 2 | import { expectSameValueSVGMatrix } from "./expectSameValueSVGMatrix.js"; 3 | 4 | const { expect } = chai; 5 | 6 | export const expectSameValueSVGTransform = ( 7 | receive_transform, 8 | expect_transform, 9 | message = "" 10 | ) => { 11 | message = `${message ? `${message}::` : ""}expectSameValueSVGTransform`; 12 | 13 | expect(receive_transform.type, message).equal(expect_transform.type); 14 | expectSameValueSVGMatrix( 15 | receive_transform.matrix, 16 | expect_transform.matrix, 17 | message 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /test/assertions/expectTransformWithRotateAngleCxCy.js: -------------------------------------------------------------------------------- 1 | import { $$createSVGTransform } from "../../src/createSVGTransform/createSVGTransform.index.js"; 2 | import { expectSameValueSVGTransform } from "./expectSameValueSVGTransform.js"; 3 | 4 | export const expectTransformWithRotateAngleCxCy = ({ 5 | transform: receive_transform, 6 | angle, 7 | cx, 8 | cy, 9 | }) => { 10 | const expect_transform = $$createSVGTransform(); 11 | expect_transform.setRotate(angle, cx, cy); 12 | expectSameValueSVGTransform( 13 | receive_transform, 14 | expect_transform, 15 | "expectTransformWithRotateAngleCxCy" 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /test/assertions/expectTransformWithScaleSxSy.js: -------------------------------------------------------------------------------- 1 | import { $$createSVGTransform } from "../../src/createSVGTransform/createSVGTransform.index.js"; 2 | import { expectSameValueSVGTransform } from "./expectSameValueSVGTransform.js"; 3 | 4 | export const expectTransformWithScaleSxSy = ({ 5 | transform: receive_transform, 6 | sx, 7 | sy, 8 | }) => { 9 | const expect_transform = $$createSVGTransform(); 10 | expect_transform.setScale(sx, sy); 11 | expectSameValueSVGTransform( 12 | receive_transform, 13 | expect_transform, 14 | "expectTransformWithScaleSxSy" 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /test/assertions/expectTransformWithTranslateTxTy.js: -------------------------------------------------------------------------------- 1 | import { $$createSVGTransform } from "../../src/createSVGTransform/createSVGTransform.index.js"; 2 | import { expectSameValueSVGTransform } from "./expectSameValueSVGTransform.js"; 3 | 4 | export const expectTransformWithTranslateTxTy = ({ 5 | transform: receive_transform, 6 | tx, 7 | ty, 8 | }) => { 9 | const expect_transform = $$createSVGTransform(); 10 | expect_transform.setTranslate(tx, ty); 11 | expectSameValueSVGTransform( 12 | receive_transform, 13 | expect_transform, 14 | "expectTransformWithTranslateTxTy" 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /test/assertions/index.js: -------------------------------------------------------------------------------- 1 | export { expectSameNumberEpsilon } from "./expectSameNumberEpsilon.js"; 2 | export { expectSameValueSVGMatrix } from "./expectSameValueSVGMatrix.js"; 3 | export { expectSameValueSVGTransform } from "./expectSameValueSVGTransform.js"; 4 | export { expectTransformWithTranslateTxTy } from "./expectTransformWithTranslateTxTy.js"; 5 | export { expectTransformWithRotateAngleCxCy } from "./expectTransformWithRotateAngleCxCy.js"; 6 | export { expectTransformWithScaleSxSy } from "./expectTransformWithScaleSxSy.js"; 7 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | FxSVG TEST 12 | 13 | 14 |
15 | 16 | 17 | 18 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/index.json.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | FxSVG TEST 12 | 13 | 14 |
15 | 16 | 17 | 18 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/mount_fxsvg_in_browser.js: -------------------------------------------------------------------------------- 1 | import FxSVG from "../src/index.js"; 2 | 3 | window.FxSVG = FxSVG; 4 | -------------------------------------------------------------------------------- /test/playground.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | FxSVG Playground 11 | 19 | 20 | 21 | 22 | 23 | 24 | 34 | 35 | -------------------------------------------------------------------------------- /test/run_tests_in_browser.js: -------------------------------------------------------------------------------- 1 | import __spec__ from "./spec.js"; 2 | 3 | __spec__(); 4 | -------------------------------------------------------------------------------- /test/server.js: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import path from "path"; 3 | import url from "url"; 4 | import webpack from "webpack"; 5 | import middleware from "webpack-dev-middleware"; 6 | import yargs from "yargs"; 7 | import { hideBin } from "yargs/helpers"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | 11 | const argv = yargs(hideBin(process.argv)) 12 | .alias("p", "port") 13 | .default("port", "8080") 14 | .parse(); 15 | const port = parseInt(argv.port, 10); 16 | 17 | const app = express(); 18 | app.use(express.static(path.resolve(__dirname, "../"))); 19 | app.use( 20 | "/test", 21 | middleware( 22 | webpack({ 23 | mode: "development", 24 | context: __dirname, 25 | entry: { 26 | run_tests_in_browser: "./run_tests_in_browser.js", 27 | mount_fxsvg_in_browser: "./mount_fxsvg_in_browser.js", 28 | }, 29 | output: { 30 | filename: "[name].bundle.js", 31 | }, 32 | }) 33 | ) 34 | ); 35 | app.get("/", (req, res) => res.redirect("/test")); 36 | 37 | app.listen(port, () => console.log(`TEST SERVER LISTENING ON ${port} PORT`)); 38 | -------------------------------------------------------------------------------- /test/utils/deepCopyTransformList.js: -------------------------------------------------------------------------------- 1 | import { map } from "fxjs/es"; 2 | import { $$createSVGMatrix } from "../../src/createSVGMatrix/createSVGMatrix.index.js"; 3 | 4 | export const deepCopyTransformList = (transform_list) => 5 | map( 6 | ({ matrix, type }) => ({ type, matrix: $$createSVGMatrix(matrix)() }), 7 | transform_list 8 | ); 9 | -------------------------------------------------------------------------------- /test/utils/index.js: -------------------------------------------------------------------------------- 1 | export { makeAllCombinations } from "./makeAllCombinations.js"; 2 | export { makeRandomBool } from "./makeRandomBool.js"; 3 | export { makeRandomNumber } from "./makeRandomNumber.js"; 4 | export { makeRandomNumberExcept } from "./makeRandomNumberExcept.js"; 5 | export { makeRandomInt } from "./makeRandomInt.js"; 6 | export { makeRandomTransformString } from "./makeRandomTransformString.js"; 7 | export { makeRandomTransformStringList } from "./makeRandomTransformStringList.js"; 8 | export { makeRandomTransformAttributeValue } from "./makeRandomTransformAttributeValue.js"; 9 | export { deepCopyTransformList } from "./deepCopyTransformList.js"; 10 | export { makeRandomSVGMatrix } from "./makeRandomSVGMatrix.js"; 11 | export { makeMockRect } from "./makeMockRect.js"; 12 | export { makeMockRectInitializedRotateTransform } from "./makeMockRectInitializedRotateTransform.js"; 13 | export { makeMockRectInitiatedScaleTransform } from "./makeMockRectInitializedScaleTransform.js"; 14 | export { makeMockRectInitializedTranslateTransform } from "./makeMockRectInitializedTranslateTransform.js"; 15 | export { makeRandomSVGTransformMatrix } from "./makeRandomSVGTransformMatrix.js"; 16 | export { makeRandomSVGTransformRotate } from "./makeRandomSVGTransformRotate.js"; 17 | export { makeRandomSVGTransformScale } from "./makeRandomSVGTransformScale.js"; 18 | export { makeRandomSVGTransformTranslate } from "./makeRandomSVGTransformTranslate.js"; 19 | -------------------------------------------------------------------------------- /test/utils/makeAllCombinations.js: -------------------------------------------------------------------------------- 1 | const makeCombinations = (l1, l2, result) => { 2 | result.push(l1); 3 | for (let i = 0; i < l2.length; i++) { 4 | const x = l2[i]; 5 | makeCombinations([...l1, x], l2.slice(i + 1), result); 6 | } 7 | }; 8 | 9 | export const makeAllCombinations = (list) => { 10 | const result = []; 11 | makeCombinations([], list, result); 12 | return result; 13 | }; 14 | -------------------------------------------------------------------------------- /test/utils/makeMockRect.js: -------------------------------------------------------------------------------- 1 | import { 2 | entriesL, 3 | extend, 4 | flatL, 5 | go, 6 | isNil, 7 | join, 8 | mapL, 9 | object, 10 | rejectL, 11 | } from "fxjs/es"; 12 | import { $$el } from "../../src/el/el.index.js"; 13 | import { makeRandomNumber } from "./makeRandomNumber.js"; 14 | 15 | export const makeMockRect = (attrs = {}) => 16 | go( 17 | [ 18 | mapL((k) => [k, makeRandomNumber(-100, 100)], ["x", "y"]), 19 | mapL((k) => [k, makeRandomNumber(1)], ["width", "height"]), 20 | ], 21 | flatL, 22 | object, 23 | (o) => extend(o, attrs), 24 | entriesL, 25 | rejectL(([, v]) => isNil(v)), 26 | mapL(([k, v]) => `${k}="${v}"`), 27 | join(" "), 28 | (attr_str) => ``, 29 | (svg_str) => $$el(svg_str)() 30 | ); 31 | -------------------------------------------------------------------------------- /test/utils/makeMockRectInitializedRotateTransform.js: -------------------------------------------------------------------------------- 1 | import { 2 | appendL, 3 | defaultTo, 4 | go, 5 | isNil, 6 | isUndefined, 7 | mapL, 8 | object, 9 | rangeL, 10 | rejectL, 11 | } from "fxjs/es"; 12 | import { $$getAttrNS } from "../../src/getAttrNS/getAttrNS.index.js"; 13 | import { $$getBaseTransformList } from "../../src/getBaseTransformList/getBaseTransformList.index.js"; 14 | import { $$initRotateTransform } from "../../src/initRotateTransform/initRotateTransform.index.js"; 15 | import { makeMockRect } from "./makeMockRect.js"; 16 | import { makeRandomInt } from "./makeRandomInt.js"; 17 | import { makeRandomNumber } from "./makeRandomNumber.js"; 18 | import { makeRandomTransformAttributeValue } from "./makeRandomTransformAttributeValue.js"; 19 | 20 | export const makeMockRectInitializedRotateTransform = ({ 21 | x: _x, 22 | y: _y, 23 | width: _width, 24 | height: _height, 25 | angle: _angle, 26 | cx: _cx, 27 | cy: _cy, 28 | transform: _transform, 29 | } = {}) => { 30 | const $el = go( 31 | [ 32 | ["x", _x], 33 | ["y", _y], 34 | ["width", _width], 35 | ["height", _height], 36 | [ 37 | "transform", 38 | isUndefined(_transform) 39 | ? makeRandomTransformAttributeValue() 40 | : _transform, 41 | ], 42 | ], 43 | rejectL(([, v]) => isNil(v)), 44 | object, 45 | makeMockRect 46 | ); 47 | const transform_list = $$getBaseTransformList($el); 48 | const init_index = makeRandomInt(0, transform_list.numberOfItems + 1); 49 | go( 50 | rangeL(2), 51 | mapL(() => makeRandomNumber(-100, 100)), 52 | ([cx, cy]) => [ 53 | [_cx, cx], 54 | [_cy, cy], 55 | ], 56 | appendL([_angle, makeRandomNumber(-700, 700)]), 57 | mapL(([a, b]) => defaultTo(b, a)), 58 | ([cx, cy, angle]) => 59 | $$initRotateTransform({ angle, cx, cy, index: init_index })($el) 60 | ); 61 | const index = init_index + 1; 62 | const { e: cx, f: cy } = transform_list.getItem(index - 1).matrix; 63 | const { angle } = transform_list.getItem(index); 64 | const [x, y, width, height] = go( 65 | ["x", "y", "width", "height"], 66 | mapL((name) => $$getAttrNS(name)($el)), 67 | mapL(parseFloat) 68 | ); 69 | 70 | return { $el, index, angle, cx, cy, x, y, width, height }; 71 | }; 72 | -------------------------------------------------------------------------------- /test/utils/makeMockRectInitializedScaleTransform.js: -------------------------------------------------------------------------------- 1 | import { 2 | defaultTo, 3 | go, 4 | isNil, 5 | isUndefined, 6 | mapL, 7 | object, 8 | rangeL, 9 | rejectL, 10 | } from "fxjs/es"; 11 | import { $$getAttrNS } from "../../src/getAttrNS/getAttrNS.index.js"; 12 | import { $$getBaseTransformList } from "../../src/getBaseTransformList/getBaseTransformList.index.js"; 13 | import { $$initScaleTransform } from "../../src/initScaleTransform/initScaleTransform.index.js"; 14 | import { makeMockRect } from "./makeMockRect.js"; 15 | import { makeRandomInt } from "./makeRandomInt.js"; 16 | import { makeRandomNumber } from "./makeRandomNumber.js"; 17 | import { makeRandomTransformAttributeValue } from "./makeRandomTransformAttributeValue.js"; 18 | 19 | export const makeMockRectInitiatedScaleTransform = ({ 20 | x: _x, 21 | y: _y, 22 | width: _width, 23 | height: _height, 24 | sx: _sx, 25 | sy: _sy, 26 | cx: _cx, 27 | cy: _cy, 28 | transform: _transform, 29 | } = {}) => { 30 | const $el = go( 31 | [ 32 | ["x", _x], 33 | ["y", _y], 34 | ["width", _width], 35 | ["height", _height], 36 | [ 37 | "transform", 38 | isUndefined(_transform) 39 | ? makeRandomTransformAttributeValue() 40 | : _transform, 41 | ], 42 | ], 43 | rejectL(([, v]) => isNil(v)), 44 | object, 45 | makeMockRect 46 | ); 47 | const transform_list = $$getBaseTransformList($el); 48 | const init_index = makeRandomInt(0, transform_list.numberOfItems + 1); 49 | go( 50 | rangeL(4), 51 | mapL(() => makeRandomNumber(-100, 100)), 52 | ([sx, sy, cx, cy]) => [ 53 | [_sx, sx], 54 | [_sy, sy], 55 | [_cx, cx], 56 | [_cy, cy], 57 | ], 58 | mapL(([a, b]) => defaultTo(b, a)), 59 | ([sx, sy, cx, cy]) => 60 | $$initScaleTransform({ sx, sy, cx, cy, index: init_index })($el) 61 | ); 62 | const index = init_index + 1; 63 | const [{ e: cx, f: cy }, { a: sx, d: sy }] = go( 64 | rangeL(2), 65 | mapL((i) => index - 1 + i), 66 | mapL((i) => transform_list.getItem(i)), 67 | mapL(({ matrix: m }) => m) 68 | ); 69 | const [x, y, width, height] = go( 70 | ["x", "y", "width", "height"], 71 | mapL((name) => $$getAttrNS(name)($el)), 72 | mapL(parseFloat) 73 | ); 74 | 75 | return { $el, index, sx, sy, cx, cy, x, y, width, height }; 76 | }; 77 | -------------------------------------------------------------------------------- /test/utils/makeMockRectInitializedTranslateTransform.js: -------------------------------------------------------------------------------- 1 | import { 2 | defaultTo, 3 | go, 4 | isNil, 5 | isUndefined, 6 | mapL, 7 | object, 8 | rangeL, 9 | rejectL, 10 | } from "fxjs/es"; 11 | import { $$getAttrNS } from "../../src/getAttrNS/getAttrNS.index.js"; 12 | import { $$getBaseTransformList } from "../../src/getBaseTransformList/getBaseTransformList.index.js"; 13 | import { $$initTranslateTransform } from "../../src/initTranslateTransform/initTranslateTransform.index.js"; 14 | import { makeMockRect } from "./makeMockRect.js"; 15 | import { makeRandomInt } from "./makeRandomInt.js"; 16 | import { makeRandomNumber } from "./makeRandomNumber.js"; 17 | import { makeRandomTransformAttributeValue } from "./makeRandomTransformAttributeValue.js"; 18 | 19 | export const makeMockRectInitializedTranslateTransform = ({ 20 | x: _x, 21 | y: _y, 22 | width: _width, 23 | height: _height, 24 | tx: _tx, 25 | ty: _ty, 26 | transform: _transform, 27 | } = {}) => { 28 | const $el = go( 29 | [ 30 | ["x", _x], 31 | ["y", _y], 32 | ["width", _width], 33 | ["height", _height], 34 | [ 35 | "transform", 36 | isUndefined(_transform) 37 | ? makeRandomTransformAttributeValue() 38 | : _transform, 39 | ], 40 | ], 41 | rejectL(([, v]) => isNil(v)), 42 | object, 43 | makeMockRect 44 | ); 45 | const transform_list = $$getBaseTransformList($el); 46 | const index = makeRandomInt(0, transform_list.numberOfItems + 1); 47 | go( 48 | rangeL(2), 49 | mapL(() => makeRandomNumber(-100, 100)), 50 | ([tx, ty]) => [ 51 | [_tx, tx], 52 | [_ty, ty], 53 | ], 54 | mapL(([a, b]) => defaultTo(b, a)), 55 | ([tx, ty]) => $$initTranslateTransform({ tx, ty, index })($el) 56 | ); 57 | const { e: tx, f: ty } = transform_list.getItem(index).matrix; 58 | const [x, y, width, height] = go( 59 | ["x", "y", "width", "height"], 60 | mapL((name) => $$getAttrNS(name)($el)), 61 | mapL(parseFloat) 62 | ); 63 | 64 | return { $el, index, tx, ty, x, y, width, height }; 65 | }; 66 | -------------------------------------------------------------------------------- /test/utils/makeRandomBool.js: -------------------------------------------------------------------------------- 1 | export const makeRandomBool = () => Math.random() > 0.5; 2 | -------------------------------------------------------------------------------- /test/utils/makeRandomInt.js: -------------------------------------------------------------------------------- 1 | import { makeRandomNumber } from "./makeRandomNumber.js"; 2 | 3 | export const makeRandomInt = (min = 0, max = 1000) => 4 | Math.floor(makeRandomNumber(Math.ceil(min), max)); 5 | -------------------------------------------------------------------------------- /test/utils/makeRandomNumber.js: -------------------------------------------------------------------------------- 1 | export const makeRandomNumber = (min = 0, max = 1000) => 2 | min + Math.random() * (max - min); 3 | -------------------------------------------------------------------------------- /test/utils/makeRandomNumberExcept.js: -------------------------------------------------------------------------------- 1 | import { go, head, mapL, rangeL, rejectL } from "fxjs/es"; 2 | import { makeRandomNumber } from "./makeRandomNumber.js"; 3 | 4 | export const makeRandomNumberExcept = (min = 0, max = 1000, excepts = []) => { 5 | excepts = new Set(excepts); 6 | return go( 7 | rangeL(Infinity), 8 | mapL(() => makeRandomNumber(min, max)), 9 | rejectL((a) => excepts.has(a)), 10 | head 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /test/utils/makeRandomSVGMatrix.js: -------------------------------------------------------------------------------- 1 | import { go, mapL, object, split } from "fxjs/es"; 2 | import { $$createSVGMatrix } from "../../src/createSVGMatrix/createSVGMatrix.index.js"; 3 | import { makeRandomNumber } from "./makeRandomNumber.js"; 4 | 5 | export const makeRandomSVGMatrix = (random = makeRandomNumber) => 6 | go( 7 | "abcdef", 8 | split(""), 9 | mapL((k) => [k, random()]), 10 | object, 11 | (values) => $$createSVGMatrix(values)() 12 | ); 13 | -------------------------------------------------------------------------------- /test/utils/makeRandomSVGTransformMatrix.js: -------------------------------------------------------------------------------- 1 | import { go1 } from "fxjs/es"; 2 | import { $$createSVGTransformMatrix } from "../../src/createSVGTransformMatrix/createSVGTransformMatrix.index.js"; 3 | import { makeRandomNumber } from "./makeRandomNumber.js"; 4 | import { makeRandomSVGMatrix } from "./makeRandomSVGMatrix.js"; 5 | 6 | export const makeRandomSVGTransformMatrix = ( 7 | random = () => makeRandomNumber(-100, 100) 8 | ) => 9 | go1(makeRandomSVGMatrix(random), (matrix) => 10 | $$createSVGTransformMatrix({ matrix })() 11 | ); 12 | -------------------------------------------------------------------------------- /test/utils/makeRandomSVGTransformRotate.js: -------------------------------------------------------------------------------- 1 | import { go, mapL, rangeL } from "fxjs/es"; 2 | import { $$createSVGTransformRotate } from "../../src/createSVGTransformRotate/createSVGTransformRotate.index.js"; 3 | import { makeRandomNumber } from "./makeRandomNumber.js"; 4 | 5 | export const makeRandomSVGTransformRotate = ( 6 | random = () => makeRandomNumber(-700, 700) 7 | ) => 8 | go(rangeL(3), mapL(random), ([angle, cx, cy]) => 9 | $$createSVGTransformRotate({ angle, cx, cy })() 10 | ); 11 | -------------------------------------------------------------------------------- /test/utils/makeRandomSVGTransformScale.js: -------------------------------------------------------------------------------- 1 | import { go, mapL, rangeL } from "fxjs/es"; 2 | import { $$createSVGTransformScale } from "../../src/createSVGTransformScale/createSVGTransformScale.index.js"; 3 | import { makeRandomNumber } from "./makeRandomNumber.js"; 4 | 5 | export const makeRandomSVGTransformScale = ( 6 | random = () => makeRandomNumber(-100, 100) 7 | ) => 8 | go(rangeL(2), mapL(random), ([sx, sy]) => 9 | $$createSVGTransformScale({ sx, sy })() 10 | ); 11 | -------------------------------------------------------------------------------- /test/utils/makeRandomSVGTransformTranslate.js: -------------------------------------------------------------------------------- 1 | import { go, mapL, rangeL } from "fxjs/es"; 2 | import { $$createSVGTransformTranslate } from "../../src/createSVGTransformTranslate/createSVGTransformTranslate.index.js"; 3 | import { makeRandomNumber } from "./makeRandomNumber.js"; 4 | 5 | export const makeRandomSVGTransformTranslate = ( 6 | random = () => makeRandomNumber(-100, 100) 7 | ) => 8 | go(rangeL(2), mapL(random), ([tx, ty]) => 9 | $$createSVGTransformTranslate({ tx, ty })() 10 | ); 11 | -------------------------------------------------------------------------------- /test/utils/makeRandomTransformAttributeValue.js: -------------------------------------------------------------------------------- 1 | import { join } from "fxjs/es"; 2 | import { makeRandomNumber } from "./makeRandomNumber.js"; 3 | import { makeRandomTransformStringList } from "./makeRandomTransformStringList.js"; 4 | 5 | export const makeRandomTransformAttributeValue = ( 6 | min = 0, 7 | max = 100, 8 | random = makeRandomNumber 9 | ) => join(" ", makeRandomTransformStringList(min, max, random)); 10 | -------------------------------------------------------------------------------- /test/utils/makeRandomTransformString.js: -------------------------------------------------------------------------------- 1 | import { makeRandomInt } from "./makeRandomInt.js"; 2 | import { makeRandomNumber } from "./makeRandomNumber.js"; 3 | 4 | export const makeRandomTransformString = (random = makeRandomNumber) => 5 | [ 6 | `translate(${random()} ${random()})`, 7 | `rotate(${random()} ${random()} ${random()})`, 8 | `scale(${random()} ${random()})`, 9 | `matrix(${[...Array(6)].map(() => random()).join(" ")})`, 10 | ][makeRandomInt(0, 4)]; 11 | -------------------------------------------------------------------------------- /test/utils/makeRandomTransformStringList.js: -------------------------------------------------------------------------------- 1 | import { go, map, rangeL } from "fxjs/es"; 2 | import { makeRandomInt } from "./makeRandomInt.js"; 3 | import { makeRandomNumber } from "./makeRandomNumber.js"; 4 | import { makeRandomTransformString } from "./makeRandomTransformString.js"; 5 | 6 | export const makeRandomTransformStringList = ( 7 | min, 8 | max, 9 | random = makeRandomNumber 10 | ) => 11 | go( 12 | makeRandomInt(min, max), 13 | rangeL, 14 | map(() => makeRandomTransformString(random)) 15 | ); 16 | --------------------------------------------------------------------------------