├── .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 |
--------------------------------------------------------------------------------