Merge pull request #15 from MaTeMaTuK/dev

new version release
This commit is contained in:
MaTeMaTuK 2021-08-03 21:42:11 +03:00 committed by GitHub
commit b316776aed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 522 additions and 234 deletions

View File

@ -81,10 +81,11 @@ npm start
### DisplayOption ### DisplayOption
| Parameter Name | Type | Description | | Parameter Name | Type | Description |
| :------------- | :----- | :---------------------------------------------------------------------------------------------- | | :------------- | :------ | :---------------------------------------------------------------------------------------------- |
| viewMode | enum | Specifies the time scale. Quarter Day, Half Day, Day, Week(ISO-8601, 1st day is Monday), Month. | | viewMode | enum | Specifies the time scale. Quarter Day, Half Day, Day, Week(ISO-8601, 1st day is Monday), Month. |
| locale | string | Specifies the month name language. Able formats: ISO 639-2, Java Locale. | | locale | string | Specifies the month name language. Able formats: ISO 639-2, Java Locale. |
| rtl | boolean | Sets rtl mode. |
### StylingOption ### StylingOption

View File

@ -34,19 +34,19 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": { "@babel/runtime": {
"version": "7.14.0", "version": "7.14.8",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz",
"integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==",
"requires": { "requires": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
} }
}, },
"@babel/runtime-corejs3": { "@babel/runtime-corejs3": {
"version": "7.14.0", "version": "7.14.9",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.9.tgz",
"integrity": "sha512-0R0HTZWHLk6G8jIk0FtoX+AatCtKnswS98VhXwGImFc759PJRp4Tru0PQYZofyijTFUr+gT8Mu7sgXVJLQ0ceg==", "integrity": "sha512-64RiH2ON4/y8qYtoa8rUiyam/tUVyGqRyNYhe+vCRGmjnV4bUlZvY+mwd0RrmLoCpJpdq3RsrNqKb7SJdw/4kw==",
"requires": { "requires": {
"core-js-pure": "^3.0.0", "core-js-pure": "^3.16.0",
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
} }
}, },
@ -63,9 +63,9 @@
}, },
"dependencies": { "dependencies": {
"chalk": { "chalk": {
"version": "4.1.1", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": { "requires": {
"ansi-styles": "^4.1.0", "ansi-styles": "^4.1.0",
"supports-color": "^7.1.0" "supports-color": "^7.1.0"
@ -87,47 +87,47 @@
} }
}, },
"@types/istanbul-reports": { "@types/istanbul-reports": {
"version": "3.0.0", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
"integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
"requires": { "requires": {
"@types/istanbul-lib-report": "*" "@types/istanbul-lib-report": "*"
} }
}, },
"@types/jest": { "@types/jest": {
"version": "26.0.23", "version": "26.0.24",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.23.tgz", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz",
"integrity": "sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA==", "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==",
"requires": { "requires": {
"jest-diff": "^26.0.0", "jest-diff": "^26.0.0",
"pretty-format": "^26.0.0" "pretty-format": "^26.0.0"
} }
}, },
"@types/node": { "@types/node": {
"version": "15.3.0", "version": "16.4.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.10.tgz",
"integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" "integrity": "sha512-TmVHsm43br64js9BqHWqiDZA+xMtbUpI1MBIA0EyiBmoV9pcEYFOSdj5fr6enZNfh4fChh+AGOLIzGwJnkshyQ=="
}, },
"@types/testing-library__jest-dom": { "@types/testing-library__jest-dom": {
"version": "5.9.5", "version": "5.14.1",
"resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.5.tgz", "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.1.tgz",
"integrity": "sha512-ggn3ws+yRbOHog9GxnXiEZ/35Mow6YtPZpd7Z5mKDeZS/o7zx3yAle0ov/wjhVB5QT4N2Dt+GNoGCdqkBGCajQ==", "integrity": "sha512-Gk9vaXfbzc5zCXI9eYE9BI5BNHEp4D3FWjgqBE/ePGYElLAP+KvxBcsdkwfIVvezs605oiyd/VrpiHe3Oeg+Aw==",
"requires": { "requires": {
"@types/jest": "*" "@types/jest": "*"
} }
}, },
"@types/yargs": { "@types/yargs": {
"version": "15.0.13", "version": "15.0.14",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz",
"integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==",
"requires": { "requires": {
"@types/yargs-parser": "*" "@types/yargs-parser": "*"
} }
}, },
"@types/yargs-parser": { "@types/yargs-parser": {
"version": "20.2.0", "version": "20.2.1",
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
}, },
"ansi-regex": { "ansi-regex": {
"version": "5.0.0", "version": "5.0.0",
@ -179,9 +179,9 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}, },
"core-js-pure": { "core-js-pure": {
"version": "3.12.1", "version": "3.16.0",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.12.1.tgz", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.0.tgz",
"integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ==" "integrity": "sha512-wzlhZNepF/QA9yvx3ePDgNGudU5KDB8lu/TRPKelYA/QtSnkS/cLl2W+TIdEX1FAFcBr0YpY7tPDlcmXJ7AyiQ=="
}, },
"css": { "css": {
"version": "3.0.0", "version": "3.0.0",
@ -235,9 +235,9 @@
}, },
"dependencies": { "dependencies": {
"chalk": { "chalk": {
"version": "4.1.1", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": { "requires": {
"ansi-styles": "^4.1.0", "ansi-styles": "^4.1.0",
"supports-color": "^7.1.0" "supports-color": "^7.1.0"
@ -286,9 +286,9 @@
} }
}, },
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.13.7", "version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
}, },
"source-map": { "source-map": {
"version": "0.6.1", "version": "0.6.1",
@ -331,24 +331,24 @@
}, },
"dependencies": { "dependencies": {
"@babel/code-frame": { "@babel/code-frame": {
"version": "7.12.13", "version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
"integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
"requires": { "requires": {
"@babel/highlight": "^7.12.13" "@babel/highlight": "^7.14.5"
} }
}, },
"@babel/helper-validator-identifier": { "@babel/helper-validator-identifier": {
"version": "7.14.0", "version": "7.14.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz",
"integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==" "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g=="
}, },
"@babel/highlight": { "@babel/highlight": {
"version": "7.14.0", "version": "7.14.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
"integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.14.0", "@babel/helper-validator-identifier": "^7.14.5",
"chalk": "^2.0.0", "chalk": "^2.0.0",
"js-tokens": "^4.0.0" "js-tokens": "^4.0.0"
}, },
@ -366,19 +366,19 @@
} }
}, },
"@babel/runtime": { "@babel/runtime": {
"version": "7.14.0", "version": "7.14.8",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz",
"integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==",
"requires": { "requires": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
} }
}, },
"@babel/runtime-corejs3": { "@babel/runtime-corejs3": {
"version": "7.14.0", "version": "7.14.9",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.9.tgz",
"integrity": "sha512-0R0HTZWHLk6G8jIk0FtoX+AatCtKnswS98VhXwGImFc759PJRp4Tru0PQYZofyijTFUr+gT8Mu7sgXVJLQ0ceg==", "integrity": "sha512-64RiH2ON4/y8qYtoa8rUiyam/tUVyGqRyNYhe+vCRGmjnV4bUlZvY+mwd0RrmLoCpJpdq3RsrNqKb7SJdw/4kw==",
"requires": { "requires": {
"core-js-pure": "^3.0.0", "core-js-pure": "^3.16.0",
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
} }
}, },
@ -395,24 +395,24 @@
} }
}, },
"@testing-library/dom": { "@testing-library/dom": {
"version": "7.31.0", "version": "7.31.2",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.0.tgz", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz",
"integrity": "sha512-0X7ACg4YvTRDFMIuTOEj6B4NpN7i3F/4j5igOcTI5NC5J+N4TribNdErCHOZF1LBWhhcyfwxelVwvoYNMUXTOA==", "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==",
"requires": { "requires": {
"@babel/code-frame": "^7.10.4", "@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@types/aria-query": "^4.2.0", "@types/aria-query": "^4.2.0",
"aria-query": "^4.2.2", "aria-query": "^4.2.2",
"chalk": "^4.1.0", "chalk": "^4.1.0",
"dom-accessibility-api": "^0.5.4", "dom-accessibility-api": "^0.5.6",
"lz-string": "^1.4.4", "lz-string": "^1.4.4",
"pretty-format": "^26.6.2" "pretty-format": "^26.6.2"
} }
}, },
"@types/aria-query": { "@types/aria-query": {
"version": "4.2.1", "version": "4.2.2",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz",
"integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==" "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig=="
}, },
"@types/istanbul-lib-coverage": { "@types/istanbul-lib-coverage": {
"version": "2.0.3", "version": "2.0.3",
@ -428,30 +428,30 @@
} }
}, },
"@types/istanbul-reports": { "@types/istanbul-reports": {
"version": "3.0.0", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
"integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
"requires": { "requires": {
"@types/istanbul-lib-report": "*" "@types/istanbul-lib-report": "*"
} }
}, },
"@types/node": { "@types/node": {
"version": "15.3.0", "version": "16.4.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.10.tgz",
"integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" "integrity": "sha512-TmVHsm43br64js9BqHWqiDZA+xMtbUpI1MBIA0EyiBmoV9pcEYFOSdj5fr6enZNfh4fChh+AGOLIzGwJnkshyQ=="
}, },
"@types/yargs": { "@types/yargs": {
"version": "15.0.13", "version": "15.0.14",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz",
"integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==",
"requires": { "requires": {
"@types/yargs-parser": "*" "@types/yargs-parser": "*"
} }
}, },
"@types/yargs-parser": { "@types/yargs-parser": {
"version": "20.2.0", "version": "20.2.1",
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
}, },
"ansi-regex": { "ansi-regex": {
"version": "5.0.0", "version": "5.0.0",
@ -476,9 +476,9 @@
} }
}, },
"chalk": { "chalk": {
"version": "4.1.1", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": { "requires": {
"ansi-styles": "^4.1.0", "ansi-styles": "^4.1.0",
"supports-color": "^7.1.0" "supports-color": "^7.1.0"
@ -534,14 +534,14 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
}, },
"core-js-pure": { "core-js-pure": {
"version": "3.12.1", "version": "3.16.0",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.12.1.tgz", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.0.tgz",
"integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ==" "integrity": "sha512-wzlhZNepF/QA9yvx3ePDgNGudU5KDB8lu/TRPKelYA/QtSnkS/cLl2W+TIdEX1FAFcBr0YpY7tPDlcmXJ7AyiQ=="
}, },
"dom-accessibility-api": { "dom-accessibility-api": {
"version": "0.5.4", "version": "0.5.6",
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz",
"integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==" "integrity": "sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw=="
}, },
"escape-string-regexp": { "escape-string-regexp": {
"version": "1.0.5", "version": "1.0.5",
@ -603,9 +603,9 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
}, },
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.13.7", "version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
}, },
"supports-color": { "supports-color": {
"version": "5.5.0", "version": "5.5.0",
@ -625,17 +625,17 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": { "@babel/runtime": {
"version": "7.14.0", "version": "7.14.8",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz",
"integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==",
"requires": { "requires": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
} }
}, },
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.13.7", "version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
} }
} }
}, },
@ -673,30 +673,30 @@
} }
}, },
"@types/istanbul-reports": { "@types/istanbul-reports": {
"version": "3.0.0", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
"integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==",
"requires": { "requires": {
"@types/istanbul-lib-report": "*" "@types/istanbul-lib-report": "*"
} }
}, },
"@types/node": { "@types/node": {
"version": "15.3.0", "version": "16.4.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.4.10.tgz",
"integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" "integrity": "sha512-TmVHsm43br64js9BqHWqiDZA+xMtbUpI1MBIA0EyiBmoV9pcEYFOSdj5fr6enZNfh4fChh+AGOLIzGwJnkshyQ=="
}, },
"@types/yargs": { "@types/yargs": {
"version": "15.0.13", "version": "15.0.14",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz",
"integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==",
"requires": { "requires": {
"@types/yargs-parser": "*" "@types/yargs-parser": "*"
} }
}, },
"@types/yargs-parser": { "@types/yargs-parser": {
"version": "20.2.0", "version": "20.2.1",
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
"integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
}, },
"ansi-regex": { "ansi-regex": {
"version": "5.0.0", "version": "5.0.0",
@ -712,9 +712,9 @@
} }
}, },
"chalk": { "chalk": {
"version": "4.1.1", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"requires": { "requires": {
"ansi-styles": "^4.1.0", "ansi-styles": "^4.1.0",
"supports-color": "^7.1.0" "supports-color": "^7.1.0"
@ -799,14 +799,14 @@
}, },
"dependencies": { "dependencies": {
"@types/prop-types": { "@types/prop-types": {
"version": "15.7.3", "version": "15.7.4",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
}, },
"@types/scheduler": { "@types/scheduler": {
"version": "0.16.1", "version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
}, },
"csstype": { "csstype": {
"version": "3.0.8", "version": "3.0.8",
@ -823,14 +823,14 @@
}, },
"dependencies": { "dependencies": {
"@types/prop-types": { "@types/prop-types": {
"version": "15.7.3", "version": "15.7.4",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
}, },
"@types/react": { "@types/react": {
"version": "17.0.5", "version": "17.0.15",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.15.tgz",
"integrity": "sha512-bj4biDB9ZJmGAYTWSKJly6bMr4BLUiBrx9ujiJEoP9XIDY9CTaPGxE5QWN/1WjpPLzYF7/jRNnV2nNxNe970sw==", "integrity": "sha512-uTKHDK9STXFHLaKv6IMnwp52fm0hwU+N89w/p9grdUqcFA6WuqDyPhaWopbNyE1k/VhgzmHl8pu1L4wITtmlLw==",
"requires": { "requires": {
"@types/prop-types": "*", "@types/prop-types": "*",
"@types/scheduler": "*", "@types/scheduler": "*",
@ -838,9 +838,9 @@
} }
}, },
"@types/scheduler": { "@types/scheduler": {
"version": "0.16.1", "version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
}, },
"csstype": { "csstype": {
"version": "3.0.8", "version": "3.0.8",

View File

@ -1,6 +1,6 @@
{ {
"name": "gantt-task-react", "name": "gantt-task-react",
"version": "0.3.2", "version": "0.3.3",
"description": "Interactive Gantt Chart for React with TypeScript.", "description": "Interactive Gantt Chart for React with TypeScript.",
"author": "MaTeMaTuK <maksym.vikarii@gmail.com>", "author": "MaTeMaTuK <maksym.vikarii@gmail.com>",
"homepage": "https://github.com/MaTeMaTuK/gantt-task-react", "homepage": "https://github.com/MaTeMaTuK/gantt-task-react",

View File

@ -2,6 +2,7 @@ import React, { ReactChild } from "react";
import { ViewMode } from "../../types/public-types"; import { ViewMode } from "../../types/public-types";
import { TopPartOfCalendar } from "./top-part-of-calendar"; import { TopPartOfCalendar } from "./top-part-of-calendar";
import { import {
getDaysInMonth,
getLocaleMonth, getLocaleMonth,
getWeekNumberISO8601, getWeekNumberISO8601,
} from "../../helpers/date-helper"; } from "../../helpers/date-helper";
@ -12,6 +13,7 @@ export type CalendarProps = {
dateSetup: DateSetup; dateSetup: DateSetup;
locale: string; locale: string;
viewMode: ViewMode; viewMode: ViewMode;
rtl: boolean;
headerHeight: number; headerHeight: number;
columnWidth: number; columnWidth: number;
fontFamily: string; fontFamily: string;
@ -22,6 +24,7 @@ export const Calendar: React.FC<CalendarProps> = ({
dateSetup, dateSetup,
locale, locale,
viewMode, viewMode,
rtl,
headerHeight, headerHeight,
columnWidth, columnWidth,
fontFamily, fontFamily,
@ -30,7 +33,6 @@ export const Calendar: React.FC<CalendarProps> = ({
const getCalendarValuesForMonth = () => { const getCalendarValuesForMonth = () => {
const topValues: ReactChild[] = []; const topValues: ReactChild[] = [];
const bottomValues: ReactChild[] = []; const bottomValues: ReactChild[] = [];
const topDefaultWidth = columnWidth * 6;
const topDefaultHeight = headerHeight * 0.5; const topDefaultHeight = headerHeight * 0.5;
for (let i = 0; i < dateSetup.dates.length; i++) { for (let i = 0; i < dateSetup.dates.length; i++) {
const date = dateSetup.dates[i]; const date = dateSetup.dates[i];
@ -50,6 +52,12 @@ export const Calendar: React.FC<CalendarProps> = ({
date.getFullYear() !== dateSetup.dates[i - 1].getFullYear() date.getFullYear() !== dateSetup.dates[i - 1].getFullYear()
) { ) {
const topValue = date.getFullYear().toString(); const topValue = date.getFullYear().toString();
let xText: number;
if (rtl) {
xText = (6 + i + date.getMonth() + 1) * columnWidth;
} else {
xText = (6 + i - date.getMonth()) * columnWidth;
}
topValues.push( topValues.push(
<TopPartOfCalendar <TopPartOfCalendar
key={topValue} key={topValue}
@ -57,9 +65,7 @@ export const Calendar: React.FC<CalendarProps> = ({
x1Line={columnWidth * i} x1Line={columnWidth * i}
y1Line={0} y1Line={0}
y2Line={topDefaultHeight} y2Line={topDefaultHeight}
xText={ xText={xText}
topDefaultWidth + columnWidth * i - date.getMonth() * columnWidth
}
yText={topDefaultHeight * 0.9} yText={topDefaultHeight * 0.9}
/> />
); );
@ -88,7 +94,7 @@ export const Calendar: React.FC<CalendarProps> = ({
<text <text
key={date.getTime()} key={date.getTime()}
y={headerHeight * 0.8} y={headerHeight * 0.8}
x={columnWidth * i} x={columnWidth * (i + +rtl)}
className={styles.calendarBottomText} className={styles.calendarBottomText}
> >
{bottomValue} {bottomValue}
@ -149,7 +155,12 @@ export const Calendar: React.FC<CalendarProps> = ({
x1Line={columnWidth * (i + 1)} x1Line={columnWidth * (i + 1)}
y1Line={0} y1Line={0}
y2Line={topDefaultHeight} y2Line={topDefaultHeight}
xText={columnWidth * (i + 1) - date.getDate() * columnWidth * 0.5} xText={
columnWidth * (i + 1) -
getDaysInMonth(date.getMonth(), date.getFullYear()) *
columnWidth *
0.5
}
yText={topDefaultHeight * 0.9} yText={topDefaultHeight * 0.9}
/> />
); );
@ -174,7 +185,7 @@ export const Calendar: React.FC<CalendarProps> = ({
<text <text
key={date.getTime()} key={date.getTime()}
y={headerHeight * 0.8} y={headerHeight * 0.8}
x={columnWidth * i} x={columnWidth * (i + +rtl)}
className={styles.calendarBottomText} className={styles.calendarBottomText}
fontFamily={fontFamily} fontFamily={fontFamily}
> >
@ -196,8 +207,10 @@ export const Calendar: React.FC<CalendarProps> = ({
); );
} }
} }
return [topValues, bottomValues]; return [topValues, bottomValues];
}; };
let topValues: ReactChild[] = []; let topValues: ReactChild[] = [];
let bottomValues: ReactChild[] = []; let bottomValues: ReactChild[] = [];
switch (dateSetup.viewMode) { switch (dateSetup.viewMode) {

View File

@ -38,6 +38,7 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
projectBackgroundSelectedColor = "#f7bb53", projectBackgroundSelectedColor = "#f7bb53",
milestoneBackgroundColor = "#f1c453", milestoneBackgroundColor = "#f1c453",
milestoneBackgroundSelectedColor = "#f29e4c", milestoneBackgroundSelectedColor = "#f29e4c",
rtl = false,
handleWidth = 8, handleWidth = 8,
timeStep = 300000, timeStep = 300000,
arrowColor = "grey", arrowColor = "grey",
@ -73,17 +74,23 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
const [selectedTask, setSelectedTask] = useState<BarTask>(); const [selectedTask, setSelectedTask] = useState<BarTask>();
const [failedTask, setFailedTask] = useState<BarTask | null>(null); const [failedTask, setFailedTask] = useState<BarTask | null>(null);
const [scrollY, setScrollY] = useState(0);
const [scrollX, setScrollX] = useState(0);
const [ignoreScrollEvent, setIgnoreScrollEvent] = useState(false);
const svgWidth = dateSetup.dates.length * columnWidth; const svgWidth = dateSetup.dates.length * columnWidth;
const ganttFullHeight = barTasks.length * rowHeight; const ganttFullHeight = barTasks.length * rowHeight;
const [scrollY, setScrollY] = useState(0);
const [scrollX, setScrollX] = useState(-1);
const [ignoreScrollEvent, setIgnoreScrollEvent] = useState(false);
// task change events // task change events
useEffect(() => { useEffect(() => {
const [startDate, endDate] = ganttDateRange(tasks, viewMode); const [startDate, endDate] = ganttDateRange(tasks, viewMode);
const newDates = seedDates(startDate, endDate, viewMode); let newDates = seedDates(startDate, endDate, viewMode);
if (rtl) {
newDates = newDates.reverse();
if (scrollX === -1) {
setScrollX(newDates.length * columnWidth);
}
}
setDateSetup({ dates: newDates, viewMode }); setDateSetup({ dates: newDates, viewMode });
setBarTasks( setBarTasks(
convertToBarTasks( convertToBarTasks(
@ -94,6 +101,7 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
taskHeight, taskHeight,
barCornerRadius, barCornerRadius,
handleWidth, handleWidth,
rtl,
barProgressColor, barProgressColor,
barProgressSelectedColor, barProgressSelectedColor,
barBackgroundColor, barBackgroundColor,
@ -124,6 +132,8 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
projectBackgroundSelectedColor, projectBackgroundSelectedColor,
milestoneBackgroundColor, milestoneBackgroundColor,
milestoneBackgroundSelectedColor, milestoneBackgroundSelectedColor,
rtl,
scrollX,
]); ]);
useEffect(() => { useEffect(() => {
@ -205,7 +215,7 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
} }
setScrollX(newScrollX); setScrollX(newScrollX);
event.preventDefault(); event.preventDefault();
} else { } else if (ganttHeight) {
let newScrollY = scrollY + event.deltaY; let newScrollY = scrollY + event.deltaY;
if (newScrollY < 0) { if (newScrollY < 0) {
newScrollY = 0; newScrollY = 0;
@ -232,7 +242,7 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
wrapperRef.current.removeEventListener("wheel", handleWheel); wrapperRef.current.removeEventListener("wheel", handleWheel);
} }
}; };
}, [wrapperRef.current, scrollY, scrollX, ganttHeight, svgWidth]); }, [wrapperRef.current, scrollY, scrollX, ganttHeight, svgWidth, rtl]);
const handleScrollY = (event: SyntheticEvent<HTMLDivElement>) => { const handleScrollY = (event: SyntheticEvent<HTMLDivElement>) => {
if (scrollY !== event.currentTarget.scrollTop && !ignoreScrollEvent) { if (scrollY !== event.currentTarget.scrollTop && !ignoreScrollEvent) {
@ -320,6 +330,7 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
rowHeight, rowHeight,
dates: dateSetup.dates, dates: dateSetup.dates,
todayColor, todayColor,
rtl,
}; };
const calendarProps: CalendarProps = { const calendarProps: CalendarProps = {
dateSetup, dateSetup,
@ -329,6 +340,7 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
columnWidth, columnWidth,
fontFamily, fontFamily,
fontSize, fontSize,
rtl,
}; };
const barProps: TaskGanttContentProps = { const barProps: TaskGanttContentProps = {
tasks: barTasks, tasks: barTasks,
@ -344,6 +356,7 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
fontSize, fontSize,
arrowIndent, arrowIndent,
svgWidth, svgWidth,
rtl,
setGanttEvent, setGanttEvent,
setFailedTask, setFailedTask,
setSelectedTask: handleSelectedTask, setSelectedTask: handleSelectedTask,
@ -401,6 +414,8 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
headerHeight={headerHeight} headerHeight={headerHeight}
taskListWidth={taskListWidth} taskListWidth={taskListWidth}
TooltipContent={TooltipContent} TooltipContent={TooltipContent}
rtl={rtl}
svgWidth={svgWidth}
/> />
)} )}
<VerticalScroll <VerticalScroll
@ -409,12 +424,14 @@ export const Gantt: React.FunctionComponent<GanttProps> = ({
headerHeight={headerHeight} headerHeight={headerHeight}
scroll={scrollY} scroll={scrollY}
onScroll={handleScrollY} onScroll={handleScrollY}
rtl={rtl}
/> />
</div> </div>
<HorizontalScroll <HorizontalScroll
svgWidth={svgWidth} svgWidth={svgWidth}
taskListWidth={taskListWidth} taskListWidth={taskListWidth}
scroll={scrollX} scroll={scrollX}
rtl={rtl}
onScroll={handleScrollX} onScroll={handleScrollX}
/> />
</div> </div>

View File

@ -26,6 +26,7 @@ export type TaskGanttContentProps = {
arrowIndent: number; arrowIndent: number;
fontSize: string; fontSize: string;
fontFamily: string; fontFamily: string;
rtl: boolean;
setGanttEvent: (value: GanttEvent) => void; setGanttEvent: (value: GanttEvent) => void;
setFailedTask: (value: BarTask | null) => void; setFailedTask: (value: BarTask | null) => void;
setSelectedTask: (taskId: string) => void; setSelectedTask: (taskId: string) => void;
@ -45,6 +46,7 @@ export const TaskGanttContent: React.FC<TaskGanttContentProps> = ({
arrowIndent, arrowIndent,
fontFamily, fontFamily,
fontSize, fontSize,
rtl,
setGanttEvent, setGanttEvent,
setFailedTask, setFailedTask,
setSelectedTask, setSelectedTask,
@ -85,7 +87,8 @@ export const TaskGanttContent: React.FC<TaskGanttContentProps> = ({
ganttEvent.changedTask, ganttEvent.changedTask,
xStep, xStep,
timeStep, timeStep,
initEventX1Delta initEventX1Delta,
rtl
); );
if (isChanged) { if (isChanged) {
setGanttEvent({ action: ganttEvent.action, changedTask }); setGanttEvent({ action: ganttEvent.action, changedTask });
@ -108,7 +111,8 @@ export const TaskGanttContent: React.FC<TaskGanttContentProps> = ({
changedTask, changedTask,
xStep, xStep,
timeStep, timeStep,
initEventX1Delta initEventX1Delta,
rtl
); );
const isNotLikeOriginal = const isNotLikeOriginal =
@ -256,6 +260,7 @@ export const TaskGanttContent: React.FC<TaskGanttContentProps> = ({
rowHeight={rowHeight} rowHeight={rowHeight}
taskHeight={taskHeight} taskHeight={taskHeight}
arrowIndent={arrowIndent} arrowIndent={arrowIndent}
rtl={rtl}
/> />
); );
}); });
@ -274,6 +279,7 @@ export const TaskGanttContent: React.FC<TaskGanttContentProps> = ({
onEventStart={handleBarEventStart} onEventStart={handleBarEventStart}
key={task.id} key={task.id}
isSelected={!!selectedTask && task.id === selectedTask.id} isSelected={!!selectedTask && task.id === selectedTask.id}
rtl={rtl}
/> />
); );
})} })}

View File

@ -41,6 +41,7 @@ export const TaskGantt: React.FC<TaskGanttProps> = ({
<div <div
className={styles.ganttVerticalContainer} className={styles.ganttVerticalContainer}
ref={verticalGanttContainerRef} ref={verticalGanttContainerRef}
dir="ltr"
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

View File

@ -10,6 +10,7 @@ export type GridBodyProps = {
rowHeight: number; rowHeight: number;
columnWidth: number; columnWidth: number;
todayColor: string; todayColor: string;
rtl: boolean;
}; };
export const GridBody: React.FC<GridBodyProps> = ({ export const GridBody: React.FC<GridBodyProps> = ({
tasks, tasks,
@ -18,6 +19,7 @@ export const GridBody: React.FC<GridBodyProps> = ({
svgWidth, svgWidth,
columnWidth, columnWidth,
todayColor, todayColor,
rtl,
}) => { }) => {
let y = 0; let y = 0;
const gridRows: ReactChild[] = []; const gridRows: ReactChild[] = [];
@ -95,6 +97,23 @@ export const GridBody: React.FC<GridBodyProps> = ({
/> />
); );
} }
// rtl for today
if (
rtl &&
i + 1 !== dates.length &&
date.getTime() >= now.getTime() &&
dates[i + 1].getTime() < now.getTime()
) {
today = (
<rect
x={tickX + columnWidth}
y={0}
width={columnWidth}
height={y}
fill={todayColor}
/>
);
}
tickX += columnWidth; tickX += columnWidth;
} }
return ( return (

View File

@ -7,6 +7,7 @@ type ArrowProps = {
rowHeight: number; rowHeight: number;
taskHeight: number; taskHeight: number;
arrowIndent: number; arrowIndent: number;
rtl: boolean;
}; };
export const Arrow: React.FC<ArrowProps> = ({ export const Arrow: React.FC<ArrowProps> = ({
taskFrom, taskFrom,
@ -14,19 +15,28 @@ export const Arrow: React.FC<ArrowProps> = ({
rowHeight, rowHeight,
taskHeight, taskHeight,
arrowIndent, arrowIndent,
rtl,
}) => { }) => {
const indexCompare = taskFrom.index > taskTo.index ? -1 : 1; let path: string;
const taskToEndPosition = taskTo.y + taskHeight / 2; let trianglePoints: string;
if (rtl) {
[path, trianglePoints] = drownPathAndTriangleRTL(
taskFrom,
taskTo,
rowHeight,
taskHeight,
arrowIndent
);
} else {
[path, trianglePoints] = drownPathAndTriangle(
taskFrom,
taskTo,
rowHeight,
taskHeight,
arrowIndent
);
}
const path = `M ${taskFrom.x2} ${taskFrom.y + taskHeight / 2}
h ${arrowIndent}
v ${(indexCompare * rowHeight) / 2}
H ${taskTo.x1 - arrowIndent}
V ${taskToEndPosition}
h ${arrowIndent}`;
const trianglePoints = `${taskTo.x1},${taskToEndPosition}
${taskTo.x1 - 5},${taskToEndPosition - 5}
${taskTo.x1 - 5},${taskToEndPosition + 5}`;
return ( return (
<g className="arrow"> <g className="arrow">
<path strokeWidth="1.5" d={path} fill="none" /> <path strokeWidth="1.5" d={path} fill="none" />
@ -34,3 +44,63 @@ export const Arrow: React.FC<ArrowProps> = ({
</g> </g>
); );
}; };
const drownPathAndTriangle = (
taskFrom: BarTask,
taskTo: BarTask,
rowHeight: number,
taskHeight: number,
arrowIndent: number
) => {
const indexCompare = taskFrom.index > taskTo.index ? -1 : 1;
const taskToEndPosition = taskTo.y + taskHeight / 2;
const taskFromEndPosition = taskFrom.x2 + arrowIndent * 2;
const taskFromHorizontalOffsetValue =
taskFromEndPosition < taskTo.x1 ? "" : `H ${taskTo.x1 - arrowIndent}`;
const taskToHorizontalOffsetValue =
taskFromEndPosition > taskTo.x1
? arrowIndent
: taskTo.x1 - taskFrom.x2 - arrowIndent;
const path = `M ${taskFrom.x2} ${taskFrom.y + taskHeight / 2}
h ${arrowIndent}
v ${(indexCompare * rowHeight) / 2}
${taskFromHorizontalOffsetValue}
V ${taskToEndPosition}
h ${taskToHorizontalOffsetValue}`;
const trianglePoints = `${taskTo.x1},${taskToEndPosition}
${taskTo.x1 - 5},${taskToEndPosition - 5}
${taskTo.x1 - 5},${taskToEndPosition + 5}`;
return [path, trianglePoints];
};
const drownPathAndTriangleRTL = (
taskFrom: BarTask,
taskTo: BarTask,
rowHeight: number,
taskHeight: number,
arrowIndent: number
) => {
const indexCompare = taskFrom.index > taskTo.index ? -1 : 1;
const taskToEndPosition = taskTo.y + taskHeight / 2;
const taskFromEndPosition = taskFrom.x1 - arrowIndent * 2;
const taskFromHorizontalOffsetValue =
taskFromEndPosition > taskTo.x2 ? "" : `H ${taskTo.x2 + arrowIndent}`;
const taskToHorizontalOffsetValue =
taskFromEndPosition < taskTo.x2
? -arrowIndent
: taskTo.x2 - taskFrom.x1 + arrowIndent;
const path = `M ${taskFrom.x1} ${taskFrom.y + taskHeight / 2}
h ${-arrowIndent}
v ${(indexCompare * rowHeight) / 2}
${taskFromHorizontalOffsetValue}
V ${taskToEndPosition}
h ${taskToHorizontalOffsetValue}`;
const trianglePoints = `${taskTo.x2},${taskToEndPosition}
${taskTo.x2 + 5},${taskToEndPosition + 5}
${taskTo.x2 + 5},${taskToEndPosition - 5}`;
return [path, trianglePoints];
};

View File

@ -5,8 +5,9 @@ export const HorizontalScroll: React.FC<{
scroll: number; scroll: number;
svgWidth: number; svgWidth: number;
taskListWidth: number; taskListWidth: number;
rtl: boolean;
onScroll: (event: SyntheticEvent<HTMLDivElement>) => void; onScroll: (event: SyntheticEvent<HTMLDivElement>) => void;
}> = ({ scroll, svgWidth, taskListWidth, onScroll }) => { }> = ({ scroll, svgWidth, taskListWidth, rtl, onScroll }) => {
const scrollRef = useRef<HTMLDivElement>(null); const scrollRef = useRef<HTMLDivElement>(null);
useEffect(() => { useEffect(() => {
@ -17,7 +18,12 @@ export const HorizontalScroll: React.FC<{
return ( return (
<div <div
style={{ marginLeft: taskListWidth }} dir="ltr"
style={{
margin: rtl
? `0px ${taskListWidth}px 0px 0px`
: `0px 0px 0px ${taskListWidth}px`,
}}
className={styles.scroll} className={styles.scroll}
onScroll={onScroll} onScroll={onScroll}
ref={scrollRef} ref={scrollRef}

View File

@ -6,8 +6,10 @@ import styles from "./tooltip.module.css";
export type TooltipProps = { export type TooltipProps = {
task: BarTask; task: BarTask;
arrowIndent: number; arrowIndent: number;
rtl: boolean;
svgContainerHeight: number; svgContainerHeight: number;
svgContainerWidth: number; svgContainerWidth: number;
svgWidth: number;
headerHeight: number; headerHeight: number;
taskListWidth: number; taskListWidth: number;
scrollX: number; scrollX: number;
@ -24,6 +26,7 @@ export type TooltipProps = {
export const Tooltip: React.FC<TooltipProps> = ({ export const Tooltip: React.FC<TooltipProps> = ({
task, task,
rowHeight, rowHeight,
rtl,
svgContainerHeight, svgContainerHeight,
svgContainerWidth, svgContainerWidth,
scrollX, scrollX,
@ -40,30 +43,41 @@ export const Tooltip: React.FC<TooltipProps> = ({
const [relatedX, setRelatedX] = useState(0); const [relatedX, setRelatedX] = useState(0);
useEffect(() => { useEffect(() => {
if (tooltipRef.current) { if (tooltipRef.current) {
let newRelatedX =
task.x2 + arrowIndent + arrowIndent * 0.5 + taskListWidth - scrollX;
let newRelatedY = task.index * rowHeight - scrollY + headerHeight;
const tooltipHeight = tooltipRef.current.offsetHeight * 1.1; const tooltipHeight = tooltipRef.current.offsetHeight * 1.1;
const tooltipWidth = tooltipRef.current.offsetWidth * 1.1; const tooltipWidth = tooltipRef.current.offsetWidth * 1.1;
const tooltipLowerPoint = tooltipHeight + newRelatedY - scrollY; let newRelatedY = task.index * rowHeight - scrollY + headerHeight;
const tooltipLeftmostPoint = tooltipWidth + newRelatedX; let newRelatedX: number;
const fullChartWidth = taskListWidth + svgContainerWidth; if (rtl) {
newRelatedX = task.x1 - arrowIndent * 1.5 - tooltipWidth - scrollX;
if (tooltipLeftmostPoint > fullChartWidth) { if (newRelatedX < 0) {
newRelatedX = newRelatedX = task.x2 + arrowIndent * 1.5 - scrollX;
task.x1 + }
taskListWidth - const tooltipLeftmostPoint = tooltipWidth + newRelatedX;
arrowIndent - if (tooltipLeftmostPoint > svgContainerWidth) {
arrowIndent * 0.5 - newRelatedX = svgContainerWidth - tooltipWidth;
scrollX - newRelatedY += rowHeight;
tooltipWidth; }
} else {
newRelatedX = task.x2 + arrowIndent * 1.5 + taskListWidth - scrollX;
const tooltipLeftmostPoint = tooltipWidth + newRelatedX;
const fullChartWidth = taskListWidth + svgContainerWidth;
if (tooltipLeftmostPoint > fullChartWidth) {
newRelatedX =
task.x1 +
taskListWidth -
arrowIndent * 1.5 -
scrollX -
tooltipWidth;
}
if (newRelatedX < taskListWidth) {
newRelatedX = svgContainerWidth + taskListWidth - tooltipWidth;
newRelatedY += rowHeight;
}
} }
if (newRelatedX < taskListWidth) {
newRelatedX = svgContainerWidth + taskListWidth - tooltipWidth; const tooltipLowerPoint = tooltipHeight + newRelatedY - scrollY;
newRelatedY += rowHeight; if (tooltipLowerPoint > svgContainerHeight - scrollY) {
} else if (tooltipLowerPoint > svgContainerHeight - scrollY) {
newRelatedY = svgContainerHeight - tooltipHeight; newRelatedY = svgContainerHeight - tooltipHeight;
} }
setRelatedY(newRelatedY); setRelatedY(newRelatedY);

View File

@ -1,6 +1,5 @@
.scroll { .scroll {
overflow: hidden auto; overflow: hidden auto;
margin-left: -17px;
width: 17px; width: 17px;
flex-shrink: 0; flex-shrink: 0;
} }

View File

@ -6,8 +6,16 @@ export const VerticalScroll: React.FC<{
ganttHeight: number; ganttHeight: number;
ganttFullHeight: number; ganttFullHeight: number;
headerHeight: number; headerHeight: number;
rtl: boolean;
onScroll: (event: SyntheticEvent<HTMLDivElement>) => void; onScroll: (event: SyntheticEvent<HTMLDivElement>) => void;
}> = ({ scroll, ganttHeight, ganttFullHeight, headerHeight, onScroll }) => { }> = ({
scroll,
ganttHeight,
ganttFullHeight,
headerHeight,
rtl,
onScroll,
}) => {
const scrollRef = useRef<HTMLDivElement>(null); const scrollRef = useRef<HTMLDivElement>(null);
useEffect(() => { useEffect(() => {
@ -18,7 +26,11 @@ export const VerticalScroll: React.FC<{
return ( return (
<div <div
style={{ height: ganttHeight, marginTop: headerHeight }} style={{
height: ganttHeight,
marginTop: headerHeight,
marginLeft: rtl ? "" : "-17px",
}}
className={styles.scroll} className={styles.scroll}
onScroll={onScroll} onScroll={onScroll}
ref={scrollRef} ref={scrollRef}

View File

@ -7,6 +7,8 @@ type BarDisplayProps = {
width: number; width: number;
height: number; height: number;
isSelected: boolean; isSelected: boolean;
/* progress start point */
progressX: number;
progressWidth: number; progressWidth: number;
barCornerRadius: number; barCornerRadius: number;
styles: { styles: {
@ -23,6 +25,7 @@ export const BarDisplay: React.FC<BarDisplayProps> = ({
width, width,
height, height,
isSelected, isSelected,
progressX,
progressWidth, progressWidth,
barCornerRadius, barCornerRadius,
styles, styles,
@ -49,7 +52,7 @@ export const BarDisplay: React.FC<BarDisplayProps> = ({
className={style.barBackground} className={style.barBackground}
/> />
<rect <rect
x={x} x={progressX}
width={progressWidth} width={progressWidth}
y={y} y={y}
height={height} height={height}

View File

@ -1,8 +1,5 @@
import React from "react"; import React from "react";
import { import { getProgressPoint } from "../../../helpers/bar-helper";
progressWithByParams,
getProgressPoint,
} from "../../../helpers/bar-helper";
import { BarDisplay } from "./bar-display"; import { BarDisplay } from "./bar-display";
import { BarProgressHandle } from "./bar-progress-handle"; import { BarProgressHandle } from "./bar-progress-handle";
import { TaskItemProps } from "../task-item"; import { TaskItemProps } from "../task-item";
@ -15,9 +12,8 @@ export const BarSmall: React.FC<TaskItemProps> = ({
onEventStart, onEventStart,
isSelected, isSelected,
}) => { }) => {
const progressWidth = progressWithByParams(task.x1, task.x2, task.progress);
const progressPoint = getProgressPoint( const progressPoint = getProgressPoint(
progressWidth + task.x1, task.progressWidth + task.x1,
task.y, task.y,
task.height task.height
); );
@ -28,7 +24,8 @@ export const BarSmall: React.FC<TaskItemProps> = ({
y={task.y} y={task.y}
width={task.x2 - task.x1} width={task.x2 - task.x1}
height={task.height} height={task.height}
progressWidth={progressWidth} progressX={task.progressX}
progressWidth={task.progressWidth}
barCornerRadius={task.barCornerRadius} barCornerRadius={task.barCornerRadius}
styles={task.styles} styles={task.styles}
isSelected={isSelected} isSelected={isSelected}

View File

@ -1,8 +1,5 @@
import React from "react"; import React from "react";
import { import { getProgressPoint } from "../../../helpers/bar-helper";
progressWithByParams,
getProgressPoint,
} from "../../../helpers/bar-helper";
import { BarDisplay } from "./bar-display"; import { BarDisplay } from "./bar-display";
import { BarDateHandle } from "./bar-date-handle"; import { BarDateHandle } from "./bar-date-handle";
import { BarProgressHandle } from "./bar-progress-handle"; import { BarProgressHandle } from "./bar-progress-handle";
@ -13,12 +10,12 @@ export const Bar: React.FC<TaskItemProps> = ({
task, task,
isProgressChangeable, isProgressChangeable,
isDateChangeable, isDateChangeable,
rtl,
onEventStart, onEventStart,
isSelected, isSelected,
}) => { }) => {
const progressWidth = progressWithByParams(task.x1, task.x2, task.progress);
const progressPoint = getProgressPoint( const progressPoint = getProgressPoint(
progressWidth + task.x1, +!rtl * task.progressWidth + task.progressX,
task.y, task.y,
task.height task.height
); );
@ -30,7 +27,8 @@ export const Bar: React.FC<TaskItemProps> = ({
y={task.y} y={task.y}
width={task.x2 - task.x1} width={task.x2 - task.x1}
height={task.height} height={task.height}
progressWidth={progressWidth} progressX={task.progressX}
progressWidth={task.progressWidth}
barCornerRadius={task.barCornerRadius} barCornerRadius={task.barCornerRadius}
styles={task.styles} styles={task.styles}
isSelected={isSelected} isSelected={isSelected}

View File

@ -1,5 +1,4 @@
import React from "react"; import React from "react";
import { progressWithByParams } from "../../../helpers/bar-helper";
import { TaskItemProps } from "../task-item"; import { TaskItemProps } from "../task-item";
import styles from "./project.module.css"; import styles from "./project.module.css";
@ -10,7 +9,6 @@ export const Project: React.FC<TaskItemProps> = ({ task, isSelected }) => {
const processColor = isSelected const processColor = isSelected
? task.styles.progressSelectedColor ? task.styles.progressSelectedColor
: task.styles.progressColor; : task.styles.progressColor;
const progressWidth = progressWithByParams(task.x1, task.x2, task.progress);
const projectWith = task.x2 - task.x1; const projectWith = task.x2 - task.x1;
const projectLeftTriangle = [ const projectLeftTriangle = [
@ -43,8 +41,8 @@ export const Project: React.FC<TaskItemProps> = ({ task, isSelected }) => {
className={styles.projectBackground} className={styles.projectBackground}
/> />
<rect <rect
x={task.x1} x={task.progressX}
width={progressWidth} width={task.progressWidth}
y={task.y} y={task.y}
height={task.height} height={task.height}
ry={task.barCornerRadius} ry={task.barCornerRadius}

View File

@ -15,6 +15,7 @@ export type TaskItemProps = {
isDateChangeable: boolean; isDateChangeable: boolean;
isDelete: boolean; isDelete: boolean;
isSelected: boolean; isSelected: boolean;
rtl: boolean;
onEventStart: ( onEventStart: (
action: GanttContentMoveAction, action: GanttContentMoveAction,
selectedTask: BarTask, selectedTask: BarTask,
@ -29,6 +30,7 @@ export const TaskItem: React.FC<TaskItemProps> = props => {
isDelete, isDelete,
taskHeight, taskHeight,
isSelected, isSelected,
rtl,
onEventStart, onEventStart,
} = { } = {
...props, ...props,
@ -63,9 +65,19 @@ export const TaskItem: React.FC<TaskItemProps> = props => {
const getX = () => { const getX = () => {
const width = task.x2 - task.x1; const width = task.x2 - task.x1;
const hasChild = task.barChildren.length > 0; const hasChild = task.barChildren.length > 0;
return isTextInside if (isTextInside) {
? task.x1 + width * 0.5 return task.x1 + width * 0.5;
: task.x1 + width + arrowIndent * +hasChild + arrowIndent * 0.2; }
if (rtl && textRef.current) {
return (
task.x1 -
textRef.current.getBBox().width -
arrowIndent * +hasChild -
arrowIndent * 0.2
);
} else {
return task.x1 + width + arrowIndent * +hasChild + arrowIndent * 0.2;
}
}; };
return ( return (

View File

@ -12,7 +12,7 @@ export const TaskListTableDefault: React.FC<{
selectedTaskId: string; selectedTaskId: string;
setSelectedTask: (taskId: string) => void; setSelectedTask: (taskId: string) => void;
}> = ({ rowHeight, rowWidth, tasks, fontFamily, fontSize, locale }) => { }> = ({ rowHeight, rowWidth, tasks, fontFamily, fontSize, locale }) => {
const dateTimeOptions = { const dateTimeOptions: Intl.DateTimeFormatOptions = {
weekday: "short", weekday: "short",
year: "numeric", year: "numeric",
month: "long", month: "long",

View File

@ -10,6 +10,7 @@ export const convertToBarTasks = (
taskHeight: number, taskHeight: number,
barCornerRadius: number, barCornerRadius: number,
handleWidth: number, handleWidth: number,
rtl: boolean,
barProgressColor: string, barProgressColor: string,
barProgressSelectedColor: string, barProgressSelectedColor: string,
barBackgroundColor: string, barBackgroundColor: string,
@ -37,6 +38,7 @@ export const convertToBarTasks = (
taskHeight, taskHeight,
barCornerRadius, barCornerRadius,
handleWidth, handleWidth,
rtl,
barProgressColor, barProgressColor,
barProgressSelectedColor, barProgressSelectedColor,
barBackgroundColor, barBackgroundColor,
@ -75,6 +77,7 @@ const convertToBarTask = (
taskHeight: number, taskHeight: number,
barCornerRadius: number, barCornerRadius: number,
handleWidth: number, handleWidth: number,
rtl: boolean,
barProgressColor: string, barProgressColor: string,
barProgressSelectedColor: string, barProgressSelectedColor: string,
barBackgroundColor: string, barBackgroundColor: string,
@ -114,6 +117,7 @@ const convertToBarTask = (
taskHeight, taskHeight,
barCornerRadius, barCornerRadius,
handleWidth, handleWidth,
rtl,
projectProgressColor, projectProgressColor,
projectProgressSelectedColor, projectProgressSelectedColor,
projectBackgroundColor, projectBackgroundColor,
@ -131,6 +135,7 @@ const convertToBarTask = (
taskHeight, taskHeight,
barCornerRadius, barCornerRadius,
handleWidth, handleWidth,
rtl,
barProgressColor, barProgressColor,
barProgressSelectedColor, barProgressSelectedColor,
barBackgroundColor, barBackgroundColor,
@ -151,13 +156,33 @@ const convertToBar = (
taskHeight: number, taskHeight: number,
barCornerRadius: number, barCornerRadius: number,
handleWidth: number, handleWidth: number,
rtl: boolean,
barProgressColor: string, barProgressColor: string,
barProgressSelectedColor: string, barProgressSelectedColor: string,
barBackgroundColor: string, barBackgroundColor: string,
barBackgroundSelectedColor: string barBackgroundSelectedColor: string
): BarTask => { ): BarTask => {
const x1 = taskXCoordinate(task.start, dates, dateDelta, columnWidth); let x1: number;
let x2 = taskXCoordinate(task.end, dates, dateDelta, columnWidth); let x2: number;
if (rtl) {
x2 = taskXCoordinateRTL(task.start, dates, dateDelta, columnWidth);
x1 = taskXCoordinateRTL(task.end, dates, dateDelta, columnWidth);
} else {
x1 = taskXCoordinate(task.start, dates, dateDelta, columnWidth);
x2 = taskXCoordinate(task.end, dates, dateDelta, columnWidth);
}
let typeInternal: TaskTypeInternal = task.type;
if (typeInternal === "task" && x2 - x1 < handleWidth * 2) {
typeInternal = "smalltask";
x2 = x1 + handleWidth * 2;
}
const [progressWidth, progressX] = progressWithByParams(
x1,
x2,
task.progress,
rtl
);
const y = taskYCoordinate(index, rowHeight, taskHeight); const y = taskYCoordinate(index, rowHeight, taskHeight);
const styles = { const styles = {
@ -167,11 +192,6 @@ const convertToBar = (
progressSelectedColor: barProgressSelectedColor, progressSelectedColor: barProgressSelectedColor,
...task.styles, ...task.styles,
}; };
let typeInternal: TaskTypeInternal = task.type;
if (typeInternal === "task" && x2 - x1 < handleWidth * 2) {
typeInternal = "smalltask";
x2 = x1 + handleWidth * 2;
}
return { return {
...task, ...task,
typeInternal, typeInternal,
@ -179,6 +199,8 @@ const convertToBar = (
x2, x2,
y, y,
index, index,
progressX,
progressWidth,
barCornerRadius, barCornerRadius,
handleWidth, handleWidth,
height: taskHeight, height: taskHeight,
@ -199,7 +221,7 @@ const convertToMilestone = (
handleWidth: number, handleWidth: number,
milestoneBackgroundColor: string, milestoneBackgroundColor: string,
milestoneBackgroundSelectedColor: string milestoneBackgroundSelectedColor: string
) => { ): BarTask => {
const x = taskXCoordinate(task.start, dates, dateDelta, columnWidth); const x = taskXCoordinate(task.start, dates, dateDelta, columnWidth);
const y = taskYCoordinate(index, rowHeight, taskHeight); const y = taskYCoordinate(index, rowHeight, taskHeight);
@ -221,6 +243,8 @@ const convertToMilestone = (
x2, x2,
y, y,
index, index,
progressX: 0,
progressWidth: 0,
barCornerRadius, barCornerRadius,
handleWidth, handleWidth,
typeInternal: task.type, typeInternal: task.type,
@ -255,7 +279,16 @@ const taskXCoordinate = (
); );
return x; return x;
}; };
const taskXCoordinateRTL = (
xDate: Date,
dates: Date[],
dateDelta: number,
columnWidth: number
) => {
let x = taskXCoordinate(xDate, dates, dateDelta, columnWidth);
x += columnWidth;
return x;
};
const taskYCoordinate = ( const taskYCoordinate = (
index: number, index: number,
rowHeight: number, rowHeight: number,
@ -268,9 +301,17 @@ const taskYCoordinate = (
export const progressWithByParams = ( export const progressWithByParams = (
taskX1: number, taskX1: number,
taskX2: number, taskX2: number,
progress: number progress: number,
rtl: boolean
) => { ) => {
return (taskX2 - taskX1) * progress * 0.01; const progressWidth = (taskX2 - taskX1) * progress * 0.01;
let progressX: number;
if (rtl) {
progressX = taskX2 - progressWidth;
} else {
progressX = taskX1;
}
return [progressWidth, progressX];
}; };
export const progressByProgressWidth = ( export const progressByProgressWidth = (
@ -281,9 +322,7 @@ export const progressByProgressWidth = (
const progressPercent = Math.round((progressWidth * 100) / barWidth); const progressPercent = Math.round((progressWidth * 100) / barWidth);
if (progressPercent >= 100) return 100; if (progressPercent >= 100) return 100;
else if (progressPercent <= 0) return 0; else if (progressPercent <= 0) return 0;
else { else return progressPercent;
return progressPercent;
}
}; };
const progressByX = (x: number, task: BarTask) => { const progressByX = (x: number, task: BarTask) => {
@ -295,6 +334,15 @@ const progressByX = (x: number, task: BarTask) => {
return progressPercent; return progressPercent;
} }
}; };
const progressByXRTL = (x: number, task: BarTask) => {
if (x >= task.x2) return 0;
else if (x <= task.x1) return 100;
else {
const barWidth = task.x2 - task.x1;
const progressPercent = Math.round(((task.x2 - x) * 100) / barWidth);
return progressPercent;
}
};
export const getProgressPoint = ( export const getProgressPoint = (
progressX: number, progressX: number,
@ -364,7 +412,8 @@ export const handleTaskBySVGMouseEvent = (
selectedTask: BarTask, selectedTask: BarTask,
xStep: number, xStep: number,
timeStep: number, timeStep: number,
initEventX1Delta: number initEventX1Delta: number,
rtl: boolean
): { isChanged: boolean; changedTask: BarTask } => { ): { isChanged: boolean; changedTask: BarTask } => {
let result: { isChanged: boolean; changedTask: BarTask }; let result: { isChanged: boolean; changedTask: BarTask };
switch (selectedTask.type) { switch (selectedTask.type) {
@ -385,7 +434,8 @@ export const handleTaskBySVGMouseEvent = (
selectedTask, selectedTask,
xStep, xStep,
timeStep, timeStep,
initEventX1Delta initEventX1Delta,
rtl
); );
break; break;
} }
@ -398,27 +448,60 @@ const handleTaskBySVGMouseEventForBar = (
selectedTask: BarTask, selectedTask: BarTask,
xStep: number, xStep: number,
timeStep: number, timeStep: number,
initEventX1Delta: number initEventX1Delta: number,
rtl: boolean
): { isChanged: boolean; changedTask: BarTask } => { ): { isChanged: boolean; changedTask: BarTask } => {
const changedTask: BarTask = { ...selectedTask }; const changedTask: BarTask = { ...selectedTask };
let isChanged = false; let isChanged = false;
switch (action) { switch (action) {
case "progress": case "progress":
changedTask.progress = progressByX(svgX, selectedTask); if (rtl) {
changedTask.progress = progressByXRTL(svgX, selectedTask);
} else {
changedTask.progress = progressByX(svgX, selectedTask);
}
isChanged = changedTask.progress !== selectedTask.progress; isChanged = changedTask.progress !== selectedTask.progress;
if (isChanged) {
const [progressWidth, progressX] = progressWithByParams(
changedTask.x1,
changedTask.x2,
changedTask.progress,
rtl
);
changedTask.progressWidth = progressWidth;
changedTask.progressX = progressX;
}
break; break;
case "start": { case "start": {
const newX1 = startByX(svgX, xStep, selectedTask); const newX1 = startByX(svgX, xStep, selectedTask);
changedTask.x1 = newX1; changedTask.x1 = newX1;
isChanged = changedTask.x1 !== selectedTask.x1; isChanged = changedTask.x1 !== selectedTask.x1;
if (isChanged) { if (isChanged) {
changedTask.start = dateByX( if (rtl) {
newX1, changedTask.end = dateByX(
selectedTask.x1, newX1,
selectedTask.start, selectedTask.x1,
xStep, selectedTask.end,
timeStep xStep,
timeStep
);
} else {
changedTask.start = dateByX(
newX1,
selectedTask.x1,
selectedTask.start,
xStep,
timeStep
);
}
const [progressWidth, progressX] = progressWithByParams(
changedTask.x1,
changedTask.x2,
changedTask.progress,
rtl
); );
changedTask.progressWidth = progressWidth;
changedTask.progressX = progressX;
} }
break; break;
} }
@ -427,13 +510,31 @@ const handleTaskBySVGMouseEventForBar = (
changedTask.x2 = newX2; changedTask.x2 = newX2;
isChanged = changedTask.x2 !== selectedTask.x2; isChanged = changedTask.x2 !== selectedTask.x2;
if (isChanged) { if (isChanged) {
changedTask.end = dateByX( if (rtl) {
newX2, changedTask.start = dateByX(
selectedTask.x2, newX2,
selectedTask.end, selectedTask.x2,
xStep, selectedTask.start,
timeStep xStep,
timeStep
);
} else {
changedTask.end = dateByX(
newX2,
selectedTask.x2,
selectedTask.end,
xStep,
timeStep
);
}
const [progressWidth, progressX] = progressWithByParams(
changedTask.x1,
changedTask.x2,
changedTask.progress,
rtl
); );
changedTask.progressWidth = progressWidth;
changedTask.progressX = progressX;
} }
break; break;
} }
@ -461,6 +562,14 @@ const handleTaskBySVGMouseEventForBar = (
); );
changedTask.x1 = newMoveX1; changedTask.x1 = newMoveX1;
changedTask.x2 = newMoveX2; changedTask.x2 = newMoveX2;
const [progressWidth, progressX] = progressWithByParams(
changedTask.x1,
changedTask.x2,
changedTask.progress,
rtl
);
changedTask.progressWidth = progressWidth;
changedTask.progressX = progressX;
} }
break; break;
} }

View File

@ -83,11 +83,17 @@ export const ganttDateRange = (tasks: Task[], viewMode: ViewMode) => {
newStartDate = addToDate(newStartDate, -1, "day"); newStartDate = addToDate(newStartDate, -1, "day");
newEndDate = addToDate(newEndDate, 19, "day"); newEndDate = addToDate(newEndDate, 19, "day");
break; break;
default: case ViewMode.QuarterDay:
newStartDate = startOfDate(newStartDate, "day"); newStartDate = startOfDate(newStartDate, "day");
newEndDate = startOfDate(newEndDate, "day"); newEndDate = startOfDate(newEndDate, "day");
newStartDate = addToDate(newStartDate, -1, "day"); newStartDate = addToDate(newStartDate, -1, "day");
newEndDate = addToDate(newEndDate, 5, "day"); newEndDate = addToDate(newEndDate, 66, "hour"); // 24(1 day)*3 - 6
break;
case ViewMode.HalfDay:
newStartDate = startOfDate(newStartDate, "day");
newEndDate = startOfDate(newEndDate, "day");
newStartDate = addToDate(newStartDate, -1, "day");
newEndDate = addToDate(newEndDate, 108, "hour"); // 24(1 day)*5 - 12
break; break;
} }
return [newStartDate, newEndDate]; return [newStartDate, newEndDate];
@ -163,3 +169,7 @@ export const getWeekNumberISO8601 = (date: Date) => {
return weekNumber; return weekNumber;
} }
}; };
export const getDaysInMonth = (month: number, year: number) => {
return new Date(year, month + 1, 0).getDate();
};

View File

@ -7,6 +7,8 @@ export interface BarTask extends Task {
x2: number; x2: number;
y: number; y: number;
height: number; height: number;
progressX: number;
progressWidth: number;
barCornerRadius: number; barCornerRadius: number;
handleWidth: number; handleWidth: number;
barChildren: number[]; barChildren: number[];

View File

@ -65,6 +65,7 @@ export interface DisplayOption {
* Specifies the month name language. Able formats: ISO 639-2, Java Locale * Specifies the month name language. Able formats: ISO 639-2, Java Locale
*/ */
locale?: string; locale?: string;
rtl?: boolean;
} }
export interface StylingOption { export interface StylingOption {