diff --git a/common/config/rush/pnpm-config.json b/common/config/rush/pnpm-config.json index ca3a5c86..333d8ab6 100644 --- a/common/config/rush/pnpm-config.json +++ b/common/config/rush/pnpm-config.json @@ -89,7 +89,10 @@ * PNPM documentation: https://pnpm.io/package_json#pnpmoverrides */ "globalOverrides": { - // "example1": "^1.0.0", + "@visactor/vrender": "0.19.20-alpha.2", + "@visactor/vrender-core": "0.19.20-alpha.2", + "@visactor/vrender-kits": "0.19.20-alpha.2", + "@visactor/vrender-components": "0.19.20-alpha.2" // "example2": "npm:@company/example2@^1.0.0" }, diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 5105620c..0d83d6f4 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -1,5 +1,11 @@ lockfileVersion: 5.4 +overrides: + '@visactor/vrender': 0.19.20-alpha.2 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 + '@visactor/vrender-components': 0.19.20-alpha.2 + importers: .: @@ -70,10 +76,10 @@ importers: '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 '@visactor/vchart': 1.11.5 - '@visactor/vrender': 0.19.11 - '@visactor/vrender-components': 0.19.11 - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender': 0.19.20-alpha.2 + '@visactor/vrender-components': 0.19.20-alpha.2 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 '@visactor/vutils': ~0.18.4 '@vitejs/plugin-react': 3.1.0 canvas: 2.11.2 @@ -90,10 +96,10 @@ importers: vite: 3.2.6 dependencies: '@visactor/vchart': 1.11.5 - '@visactor/vrender': 0.19.11 - '@visactor/vrender-components': 0.19.11 - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender': 0.19.20-alpha.2 + '@visactor/vrender-components': 0.19.20-alpha.2 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 '@visactor/vutils': 0.18.8 devDependencies: '@douyinfe/semi-ui': 2.62.1_nnrd3gsncyragczmpvfhocinkq @@ -1965,7 +1971,6 @@ packages: - supports-color - ts-node - utf-8-validate - dev: true /@jest/core/26.6.3_canvas@2.11.2: resolution: {integrity: sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==} @@ -2005,6 +2010,7 @@ packages: - supports-color - ts-node - utf-8-validate + dev: true /@jest/environment/24.9.0: resolution: {integrity: sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==} @@ -2150,7 +2156,6 @@ packages: - supports-color - ts-node - utf-8-validate - dev: true /@jest/test-sequencer/26.6.3_canvas@2.11.2: resolution: {integrity: sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==} @@ -2167,6 +2172,7 @@ packages: - supports-color - ts-node - utf-8-validate + dev: true /@jest/transform/24.9.0: resolution: {integrity: sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==} @@ -2287,6 +2293,7 @@ packages: transitivePeerDependencies: - encoding - supports-color + dev: true /@mdx-js/mdx/3.0.1: resolution: {integrity: sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==} @@ -3217,9 +3224,9 @@ packages: '@visactor/vgrammar-venn': 0.13.10 '@visactor/vgrammar-wordcloud': 0.13.10 '@visactor/vgrammar-wordcloud-shape': 0.13.10 - '@visactor/vrender-components': 0.19.11 - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender-components': 0.19.20-alpha.2 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 '@visactor/vscale': 0.18.9 '@visactor/vutils': 0.18.9 '@visactor/vutils-extension': 1.11.5 @@ -3260,9 +3267,9 @@ packages: '@visactor/vdataset': 0.18.9 '@visactor/vgrammar-coordinate': 0.13.10 '@visactor/vgrammar-util': 0.13.10 - '@visactor/vrender-components': 0.19.11 - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender-components': 0.19.20-alpha.2 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 '@visactor/vscale': 0.18.9 '@visactor/vutils': 0.18.9 dev: false @@ -3272,8 +3279,8 @@ packages: dependencies: '@visactor/vgrammar-core': 0.13.10 '@visactor/vgrammar-util': 0.13.10 - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 '@visactor/vutils': 0.18.9 dev: false @@ -3291,8 +3298,8 @@ packages: dependencies: '@visactor/vgrammar-core': 0.13.10 '@visactor/vgrammar-util': 0.13.10 - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 '@visactor/vutils': 0.18.9 dev: false @@ -3307,8 +3314,8 @@ packages: dependencies: '@visactor/vgrammar-core': 0.13.10 '@visactor/vgrammar-util': 0.13.10 - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 '@visactor/vutils': 0.18.9 dev: false @@ -3317,8 +3324,8 @@ packages: dependencies: '@visactor/vgrammar-core': 0.13.10 '@visactor/vgrammar-util': 0.13.10 - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 '@visactor/vscale': 0.18.9 '@visactor/vutils': 0.18.9 dev: false @@ -3328,41 +3335,41 @@ packages: dependencies: '@visactor/vgrammar-core': 0.13.10 '@visactor/vgrammar-util': 0.13.10 - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 '@visactor/vutils': 0.18.9 dev: false - /@visactor/vrender-components/0.19.11: - resolution: {integrity: sha512-K9967q364GojufVIlEVxr9duE/ce7tHsBTHxWHjx+uGAiJy3gmG3Vx2Ch38yoDZorR47X+YFjBSJoIqNVOwi8Q==} + /@visactor/vrender-components/0.19.20-alpha.2: + resolution: {integrity: sha512-Clk9lFbdMDF1vOAyf4S/MBjCzLKurYSZZZLAzzTqRIimjFoaiZ0EqsspID4lscmmlBn4ENv396cusw4Aeoi3Kw==} dependencies: - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 '@visactor/vscale': 0.18.9 - '@visactor/vutils': 0.18.9 + '@visactor/vutils': 0.18.12 dev: false - /@visactor/vrender-core/0.19.11: - resolution: {integrity: sha512-an0zfDMJy9ygsXY1w2xSN2nWbUmy97YrBNDEvm0Nb/kS6tNpeB8G6z5t8KO2ivq5aVZihCIJv8342/yGOnDHfg==} + /@visactor/vrender-core/0.19.20-alpha.2: + resolution: {integrity: sha512-N0SN+lW5pFtBrUIl74n6VK//poLw4pdKga4EHsAJpPwDZUHLQdHG/69sMx9BMt60vKXgD5EnagH5uoh3DiJPkA==} dependencies: - '@visactor/vutils': 0.18.9 + '@visactor/vutils': 0.18.12 color-convert: 2.0.1 dev: false - /@visactor/vrender-kits/0.19.11: - resolution: {integrity: sha512-ZzVZKVrRCuxC8+awhG3yxTwE8/qZpSTNCettTsTNs12oifeN6m+z2mvCSdHcOUn5Hw/FJyTFm2Bv2HmFNerQhw==} + /@visactor/vrender-kits/0.19.20-alpha.2: + resolution: {integrity: sha512-Jg7r1ebMHjDWRaSJTneZBtNHkk9vVZp2YWtPbsLEmgrNso0bdSnA9O5RVooQ47UPhNjcdr4PnN+DApHcezFULA==} dependencies: '@resvg/resvg-js': 2.4.1 - '@visactor/vrender-core': 0.19.11 - '@visactor/vutils': 0.18.9 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vutils': 0.18.12 roughjs: 4.5.2 dev: false - /@visactor/vrender/0.19.11: - resolution: {integrity: sha512-Gf/UivpfLuAn9ZL6Tai1y0CISll65ddQq4uJuzRidLtNQ0sCqZ0ognvey9KV4R+d4p7iklMBkWG4v8JQ3594hg==} + /@visactor/vrender/0.19.20-alpha.2: + resolution: {integrity: sha512-FdBRAbs5ibctEzvMJnY3VK+IopHaJ0iF/gdktCXCISKuaVESke3L8GVPkZ0+CD7LA5ZPryf61KgYDKaJGPPE1g==} dependencies: - '@visactor/vrender-core': 0.19.11 - '@visactor/vrender-kits': 0.19.11 + '@visactor/vrender-core': 0.19.20-alpha.2 + '@visactor/vrender-kits': 0.19.20-alpha.2 dev: false /@visactor/vscale/0.18.9: @@ -3378,6 +3385,14 @@ packages: '@visactor/vutils': 0.18.9 dev: false + /@visactor/vutils/0.18.12: + resolution: {integrity: sha512-yPidlYp0daHX2bjR6CM8cAm6w3vK4MJhIuDMB41zoeFOeT8eP3kh6eLEU96DDOGxrxKZ/vDdBFJfqlPxZ3q6lw==} + dependencies: + '@turf/helpers': 6.5.0 + '@turf/invariant': 6.5.0 + eventemitter3: 4.0.7 + dev: false + /@visactor/vutils/0.18.8: resolution: {integrity: sha512-9+YODg9msVyObDbamt94lsEF/idV8gyW3lf31DhuKsLKbuB/ajvSg6jNKD/FTMoXpmCNwfZgZ0F6wXLwI5aIpw==} dependencies: @@ -3455,6 +3470,7 @@ packages: /abbrev/1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: true /abs-svg-path/0.1.1: resolution: {integrity: sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==} @@ -3628,6 +3644,7 @@ packages: /aproba/2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + dev: true /archy/1.0.0: resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} @@ -3640,6 +3657,7 @@ packages: dependencies: delegates: 1.0.0 readable-stream: 3.6.2 + dev: true /arg/4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -4305,6 +4323,7 @@ packages: transitivePeerDependencies: - encoding - supports-color + dev: true /capture-exit/2.0.0: resolution: {integrity: sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==} @@ -4419,6 +4438,7 @@ packages: /chownr/2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} + dev: true /ci-info/2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} @@ -4670,6 +4690,7 @@ packages: /console-control-strings/1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + dev: true /convert-source-map/1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -4927,6 +4948,7 @@ packages: engines: {node: '>=8'} dependencies: mimic-response: 2.1.0 + dev: true /deep-eql/4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} @@ -5004,6 +5026,7 @@ packages: /delegates/1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + dev: true /dequal/2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} @@ -5018,6 +5041,7 @@ packages: /detect-libc/2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} + dev: true /detect-newline/2.1.0: resolution: {integrity: sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==} @@ -6246,6 +6270,7 @@ packages: engines: {node: '>= 8'} dependencies: minipass: 3.3.6 + dev: true /fs-mkdirp-stream/1.0.0: resolution: {integrity: sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==} @@ -6308,6 +6333,7 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wide-align: 1.1.5 + dev: true /gensync/1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} @@ -6741,6 +6767,7 @@ packages: /has-unicode/2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + dev: true /has-value/0.3.1: resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} @@ -7470,7 +7497,6 @@ packages: - supports-color - ts-node - utf-8-validate - dev: true /jest-cli/26.6.3_canvas@2.11.2: resolution: {integrity: sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==} @@ -7496,6 +7522,7 @@ packages: - supports-color - ts-node - utf-8-validate + dev: true /jest-config/24.9.0: resolution: {integrity: sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==} @@ -7554,7 +7581,6 @@ packages: - canvas - supports-color - utf-8-validate - dev: true /jest-config/26.6.3_canvas@2.11.2: resolution: {integrity: sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==} @@ -7588,6 +7614,7 @@ packages: - canvas - supports-color - utf-8-validate + dev: true /jest-diff/24.9.0: resolution: {integrity: sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==} @@ -7702,7 +7729,6 @@ packages: - canvas - supports-color - utf-8-validate - dev: true /jest-environment-jsdom/26.6.2_canvas@2.11.2: resolution: {integrity: sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==} @@ -7720,6 +7746,7 @@ packages: - canvas - supports-color - utf-8-validate + dev: true /jest-environment-node/24.9.0: resolution: {integrity: sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==} @@ -7860,7 +7887,6 @@ packages: - supports-color - ts-node - utf-8-validate - dev: true /jest-jasmine2/26.6.3_canvas@2.11.2: resolution: {integrity: sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==} @@ -7890,6 +7916,7 @@ packages: - supports-color - ts-node - utf-8-validate + dev: true /jest-leak-detector/24.9.0: resolution: {integrity: sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==} @@ -8098,7 +8125,6 @@ packages: - supports-color - ts-node - utf-8-validate - dev: true /jest-runner/26.6.3_canvas@2.11.2: resolution: {integrity: sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==} @@ -8130,6 +8156,7 @@ packages: - supports-color - ts-node - utf-8-validate + dev: true /jest-runtime/24.9.0: resolution: {integrity: sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==} @@ -8201,7 +8228,6 @@ packages: - supports-color - ts-node - utf-8-validate - dev: true /jest-runtime/26.6.3_canvas@2.11.2: resolution: {integrity: sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==} @@ -8241,6 +8267,7 @@ packages: - supports-color - ts-node - utf-8-validate + dev: true /jest-serializer/24.9.0: resolution: {integrity: sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==} @@ -8388,7 +8415,6 @@ packages: - supports-color - ts-node - utf-8-validate - dev: true /jest/26.6.3_canvas@2.11.2: resolution: {integrity: sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==} @@ -8404,6 +8430,7 @@ packages: - supports-color - ts-node - utf-8-validate + dev: true /js-string-escape/1.0.1: resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} @@ -8501,7 +8528,6 @@ packages: - bufferutil - supports-color - utf-8-validate - dev: true /jsdom/16.7.0_canvas@2.11.2: resolution: {integrity: sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==} @@ -8544,6 +8570,7 @@ packages: - bufferutil - supports-color - utf-8-validate + dev: true /jsesc/0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} @@ -9586,6 +9613,7 @@ packages: /mimic-response/2.1.0: resolution: {integrity: sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==} engines: {node: '>=8'} + dev: true /minimatch/3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -9615,10 +9643,12 @@ packages: engines: {node: '>=8'} dependencies: yallist: 4.0.0 + dev: true /minipass/5.0.0: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} + dev: true /minizlib/2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} @@ -9626,6 +9656,7 @@ packages: dependencies: minipass: 3.3.6 yallist: 4.0.0 + dev: true /mixin-deep/1.3.2: resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} @@ -9735,6 +9766,7 @@ packages: optional: true dependencies: whatwg-url: 5.0.0 + dev: true /node-int64/0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -9760,6 +9792,7 @@ packages: hasBin: true dependencies: abbrev: 1.1.1 + dev: true /normalize-package-data/2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -9825,6 +9858,7 @@ packages: console-control-strings: 1.1.0 gauge: 3.0.2 set-blocking: 2.0.0 + dev: true /number-is-nan/1.0.1: resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} @@ -11365,6 +11399,7 @@ packages: /simple-concat/1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + dev: true /simple-get/3.1.1: resolution: {integrity: sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==} @@ -11372,6 +11407,7 @@ packages: decompress-response: 4.2.1 once: 1.4.0 simple-concat: 1.0.1 + dev: true /simple-statistics/7.8.3: resolution: {integrity: sha512-JFvMY00t6SBGtwMuJ+nqgsx9ylkMiJ5JlK9bkj8AdvniIe5615wWQYkKHXe84XtSuc40G/tlrPu0A5/NlJvv8A==} @@ -11827,6 +11863,7 @@ packages: minizlib: 2.1.2 mkdirp: 1.0.4 yallist: 4.0.0 + dev: true /terminal-link/2.1.1: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} @@ -12038,6 +12075,7 @@ packages: /tr46/0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: true /tr46/1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} @@ -12070,7 +12108,7 @@ packages: bs-logger: 0.2.6 buffer-from: 1.1.2 fast-json-stable-stringify: 2.1.0 - jest: 26.6.3_canvas@2.11.2 + jest: 26.6.3 jest-util: 26.6.2 json5: 2.2.3 lodash: 4.17.21 @@ -12788,6 +12826,7 @@ packages: /webidl-conversions/3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true /webidl-conversions/4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} @@ -12819,6 +12858,7 @@ packages: dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 + dev: true /whatwg-url/6.5.0: resolution: {integrity: sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==} @@ -12896,6 +12936,7 @@ packages: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} dependencies: string-width: 4.2.3 + dev: true /word-wrap/1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} diff --git a/packages/vstory/demo/src/App.tsx b/packages/vstory/demo/src/App.tsx index 62aef789..3841a316 100644 --- a/packages/vstory/demo/src/App.tsx +++ b/packages/vstory/demo/src/App.tsx @@ -1,14 +1,12 @@ import React, { Component, useCallback, useState } from 'react'; import { Nav } from '@douyinfe/semi-ui'; import { createRoot } from 'react-dom/client'; -import { SimpleBar } from './demos/SimpleBar'; -import { RankingBar } from './demos/RankingBar'; import { StoryBarDemo } from './demos/StoryBarDemo'; -import { StorySceneDemo } from './demos/StoryScene'; -import { AreaWithTag } from './demos/AreaWithTag'; -import { StoryLineDemo } from './demos/StoryLineDemo'; +// import { StorySceneDemo } from './demos/StoryScene'; +// import { AreaWithTag } from './demos/AreaWithTag'; +// import { StoryLineDemo } from './demos/StoryLineDemo'; import { useLocalStorage } from './hooks/useLocalStorage'; -import { StoryPieDemo } from './demos/StoryPieDemo'; +// import { StoryPieDemo } from './demos/StoryPieDemo'; import { GraphicActionDemo } from './demos/graphicAction'; import { VChartSiteDemo } from './demos/VChartSite/VChartSite'; import { DisAppear } from './demos/DisAppear'; @@ -18,6 +16,8 @@ import { GraphicEdit } from './demos/GraphicEdit'; import { Playground } from './demos/Playground'; import { Pictogram } from './demos/infographics/Pictogram'; import { LV_BAR1 } from './demos/lv/bar1'; +import { BarLineSeries } from './demos/BarLineSeries'; +import { wordcloud } from './demos/wordcloud'; type MenusType = ( | { @@ -38,26 +38,18 @@ type MenusType = ( const App = () => { const [activeName, setActiveName] = useLocalStorage('menuName', ''); const menus = [ - { - name: 'SimpleBar', - component: SimpleBar - }, - { - name: 'RankingBar', - component: RankingBar - }, { name: 'Bar', component: StoryBarDemo }, - { - name: 'Line', - component: StoryLineDemo - }, - { - name: 'Pie', - component: StoryPieDemo - }, + // { + // name: 'Line', + // component: StoryLineDemo + // }, + // { + // name: 'Pie', + // component: StoryPieDemo + // }, // { // name: 'StoryScene', // component: StorySceneDemo @@ -98,6 +90,14 @@ const App = () => { name: 'Infographic-Pictogram', component: Pictogram }, + { + name: 'BarLineSeries', + component: BarLineSeries + }, + { + name: 'wordcloud', + component: wordcloud + }, { name: 'lv_chart', subMenus: [ diff --git a/packages/vstory/demo/src/demos/AreaWithTag.tsx b/packages/vstory/demo/src/demos/AreaWithTag.tsx index e747eeeb..cbb51c76 100644 --- a/packages/vstory/demo/src/demos/AreaWithTag.tsx +++ b/packages/vstory/demo/src/demos/AreaWithTag.tsx @@ -1,160 +1,160 @@ -import React, { useEffect } from 'react'; -import VChart, { IAreaChartSpec } from '@visactor/vchart'; -import { StoryArea } from '../../../src/dsl/story-chart'; -import { StoryExecutor } from '../../../src/dsl/story-executor'; +// import React, { useEffect } from 'react'; +// import VChart, { IAreaChartSpec } from '@visactor/vchart'; +// import { StoryArea } from '../../../src/dsl/story-chart'; +// import { StoryExecutor } from '../../../src/dsl/story-executor'; -const values = [ - { type: 'Nail polish', country: 'Africa', value: 4229 }, - { type: 'Nail polish', country: 'EU', value: 4376 }, - { type: 'Nail polish', country: 'China', value: 3054 }, - { type: 'Nail polish', country: 'USA', value: 12814 }, - { type: 'Eyebrow pencil', country: 'Africa', value: 3932 }, - { type: 'Eyebrow pencil', country: 'EU', value: 3987 }, - { type: 'Eyebrow pencil', country: 'China', value: 5067 }, - { type: 'Eyebrow pencil', country: 'USA', value: 13012 }, - { type: 'Rouge', country: 'Africa', value: 5221 }, - { type: 'Rouge', country: 'EU', value: 3574 }, - { type: 'Rouge', country: 'China', value: 7004 }, - { type: 'Rouge', country: 'USA', value: 11624 }, - { type: 'Lipstick', country: 'Africa', value: 9256 }, - { type: 'Lipstick', country: 'EU', value: 4376 }, - { type: 'Lipstick', country: 'China', value: 9054 }, - { type: 'Lipstick', country: 'USA', value: 8814 }, - { type: 'Eyeshadows', country: 'Africa', value: 3308 }, - { type: 'Eyeshadows', country: 'EU', value: 4572 }, - { type: 'Eyeshadows', country: 'China', value: 12043 }, - { type: 'Eyeshadows', country: 'USA', value: 12998 }, - { type: 'Eyeliner', country: 'Africa', value: 5432 }, - { type: 'Eyeliner', country: 'EU', value: 3417 }, - { type: 'Eyeliner', country: 'China', value: 15067 }, - { type: 'Eyeliner', country: 'USA', value: 12321 }, - { type: 'Foundation', country: 'Africa', value: 13701 }, - { type: 'Foundation', country: 'EU', value: 5231 }, - { type: 'Foundation', country: 'China', value: 10119 }, - { type: 'Foundation', country: 'USA', value: 10342 }, - { type: 'Lip gloss', country: 'Africa', value: 4008 }, - { type: 'Lip gloss', country: 'EU', value: 4572 }, - { type: 'Lip gloss', country: 'China', value: 12043 }, - { type: 'Lip gloss', country: 'USA', value: 22998 }, - { type: 'Mascara', country: 'Africa', value: 18712 }, - { type: 'Mascara', country: 'EU', value: 6134 }, - { type: 'Mascara', country: 'China', value: 10419 }, - { type: 'Mascara', country: 'USA', value: 11261 } -]; +// const values = [ +// { type: 'Nail polish', country: 'Africa', value: 4229 }, +// { type: 'Nail polish', country: 'EU', value: 4376 }, +// { type: 'Nail polish', country: 'China', value: 3054 }, +// { type: 'Nail polish', country: 'USA', value: 12814 }, +// { type: 'Eyebrow pencil', country: 'Africa', value: 3932 }, +// { type: 'Eyebrow pencil', country: 'EU', value: 3987 }, +// { type: 'Eyebrow pencil', country: 'China', value: 5067 }, +// { type: 'Eyebrow pencil', country: 'USA', value: 13012 }, +// { type: 'Rouge', country: 'Africa', value: 5221 }, +// { type: 'Rouge', country: 'EU', value: 3574 }, +// { type: 'Rouge', country: 'China', value: 7004 }, +// { type: 'Rouge', country: 'USA', value: 11624 }, +// { type: 'Lipstick', country: 'Africa', value: 9256 }, +// { type: 'Lipstick', country: 'EU', value: 4376 }, +// { type: 'Lipstick', country: 'China', value: 9054 }, +// { type: 'Lipstick', country: 'USA', value: 8814 }, +// { type: 'Eyeshadows', country: 'Africa', value: 3308 }, +// { type: 'Eyeshadows', country: 'EU', value: 4572 }, +// { type: 'Eyeshadows', country: 'China', value: 12043 }, +// { type: 'Eyeshadows', country: 'USA', value: 12998 }, +// { type: 'Eyeliner', country: 'Africa', value: 5432 }, +// { type: 'Eyeliner', country: 'EU', value: 3417 }, +// { type: 'Eyeliner', country: 'China', value: 15067 }, +// { type: 'Eyeliner', country: 'USA', value: 12321 }, +// { type: 'Foundation', country: 'Africa', value: 13701 }, +// { type: 'Foundation', country: 'EU', value: 5231 }, +// { type: 'Foundation', country: 'China', value: 10119 }, +// { type: 'Foundation', country: 'USA', value: 10342 }, +// { type: 'Lip gloss', country: 'Africa', value: 4008 }, +// { type: 'Lip gloss', country: 'EU', value: 4572 }, +// { type: 'Lip gloss', country: 'China', value: 12043 }, +// { type: 'Lip gloss', country: 'USA', value: 22998 }, +// { type: 'Mascara', country: 'Africa', value: 18712 }, +// { type: 'Mascara', country: 'EU', value: 6134 }, +// { type: 'Mascara', country: 'China', value: 10419 }, +// { type: 'Mascara', country: 'USA', value: 11261 } +// ]; -export const AreaWithTag = () => { - const id = 'areaWithTag'; +// export const AreaWithTag = () => { +// const id = 'areaWithTag'; - useEffect(() => { - // 准备一个图表 - const spec: IAreaChartSpec = { - type: 'area', - theme: 'dark', - data: [ - { - id: 'data', - values: [] - } - ], - height: 500, - padding: { left: 50, right: 50 }, - title: { - visible: true, - text: '100% stacked area chart of cosmetic products sales' - }, - percent: true, - xField: 'type', - yField: 'value', - seriesField: 'country', - axes: [ - { - orient: 'left', - visible: false - }, - { - orient: 'bottom', - trimPadding: true - } - ] - }; +// useEffect(() => { +// // 准备一个图表 +// const spec: IAreaChartSpec = { +// type: 'area', +// theme: 'dark', +// data: [ +// { +// id: 'data', +// values: [] +// } +// ], +// height: 500, +// padding: { left: 50, right: 50 }, +// title: { +// visible: true, +// text: '100% stacked area chart of cosmetic products sales' +// }, +// percent: true, +// xField: 'type', +// yField: 'value', +// seriesField: 'country', +// axes: [ +// { +// orient: 'left', +// visible: false +// }, +// { +// orient: 'bottom', +// trimPadding: true +// } +// ] +// }; - const chartInstance = new VChart(spec, { - dom: id - }); +// const chartInstance = new VChart(spec, { +// dom: id +// }); - chartInstance.renderSync(); +// chartInstance.renderSync(); - // 创建叙事 - const area = new StoryArea(); +// // 创建叙事 +// const area = new StoryArea(); - const markPoint = area.createMarkPoint( - { - type: 'Nail polish', - value: 0.05 - }, - { - itemContent: { - offsetY: -10, - offsetX: -30, - type: 'text', - autoRotate: false, - text: { - text: '5%', - dx: -10, - style: { - fill: 'black', - fontSize: 14, - fontWeight: 'bold' - }, - labelBackground: { - padding: [5, 10, 5, 10], - style: { - fill: 'rgb(122,209,182)', - cornerRadius: 20 - } - } - } - }, - itemLine: { - endSymbol: { - visible: false - }, - startSymbol: { visible: false }, - line: { - style: { - visible: false - } - } - } - } - ); +// const markPoint = area.createMarkPoint( +// { +// type: 'Nail polish', +// value: 0.05 +// }, +// { +// itemContent: { +// offsetY: -10, +// offsetX: -30, +// type: 'text', +// autoRotate: false, +// text: { +// text: '5%', +// dx: -10, +// style: { +// fill: 'black', +// fontSize: 14, +// fontWeight: 'bold' +// }, +// labelBackground: { +// padding: [5, 10, 5, 10], +// style: { +// fill: 'rgb(122,209,182)', +// cornerRadius: 20 +// } +// } +// } +// }, +// itemLine: { +// endSymbol: { +// visible: false +// }, +// startSymbol: { visible: false }, +// line: { +// style: { +// visible: false +// } +// } +// } +// } +// ); - // 数据 - const usaData = values.filter(v => v.country === 'USA'); - const chinaData = values.filter(v => v.country === 'China'); - const EUData = values.filter(v => v.country === 'EU'); - const africaData = values.filter(v => v.country === 'Africa'); +// // 数据 +// const usaData = values.filter(v => v.country === 'USA'); +// const chinaData = values.filter(v => v.country === 'China'); +// const EUData = values.filter(v => v.country === 'EU'); +// const africaData = values.filter(v => v.country === 'Africa'); - area.add({ id: 'data', values: usaData }); - area.add({ id: 'data', values: EUData }); +// area.add({ id: 'data', values: usaData }); +// area.add({ id: 'data', values: EUData }); - markPoint.flicker(); +// markPoint.flicker(); - area.add({ id: 'data', values: chinaData }); - area.add({ id: 'data', values: africaData }); +// area.add({ id: 'data', values: chinaData }); +// area.add({ id: 'data', values: africaData }); - // TODO: executor 接口需要调整 - const storyPlayer = new StoryExecutor(area, { - chartInstance, - spec - }); +// // TODO: executor 接口需要调整 +// const storyPlayer = new StoryExecutor(area, { +// chartInstance, +// spec +// }); - storyPlayer.play(); +// storyPlayer.play(); - return () => { - chartInstance.release(); - }; - }, []); +// return () => { +// chartInstance.release(); +// }; +// }, []); - return
; -}; +// return
; +// }; diff --git a/packages/vstory/demo/src/demos/BarLineSeries.tsx b/packages/vstory/demo/src/demos/BarLineSeries.tsx new file mode 100644 index 00000000..078bac3d --- /dev/null +++ b/packages/vstory/demo/src/demos/BarLineSeries.tsx @@ -0,0 +1,136 @@ +import React, { useEffect } from 'react'; +import { IStorySpec } from '../../../src/story/interface'; +import { Story } from '../../../src/story/story'; +import '../../../src/story/index'; +// import { Animate } from '@visactor/vrender-core'; + +// Animate.AddInterpolate('clipRange', (k, r, from, to, target, out) => { +// console.log('animate', k, r, from, to); +// }); + +export const BarLineSeries = () => { + const id = 'storyBar'; + + useEffect(() => { + // 准备一个图表 + const tempSpec: IStorySpec = { + characters: [ + { + type: 'VChart', + id: 'bar-series', + zIndex: 10, + position: { + top: 40, + left: 50, + width: 500, + height: 500 + }, + options: { + spec: { + type: 'common', + animation: false, + seriesField: 'color', + data: [ + { + id: 'id0', + values: [ + { x: '周一', type: '早餐', y: 15 }, + { x: '周一', type: '午餐', y: 25 }, + { x: '周二', type: '早餐', y: 12 }, + { x: '周二', type: '午餐', y: 30 }, + { x: '周三', type: '早餐', y: 15 }, + { x: '周三', type: '午餐', y: 24 }, + { x: '周四', type: '早餐', y: 10 }, + { x: '周四', type: '午餐', y: 25 }, + { x: '周五', type: '早餐', y: 13 }, + { x: '周五', type: '午餐', y: 20 }, + { x: '周六', type: '早餐', y: 10 }, + { x: '周六', type: '午餐', y: 22 }, + { x: '周日', type: '早餐', y: 12 }, + { x: '周日', type: '午餐', y: 19 } + ] + }, + { + id: 'id1', + values: [ + { x: '周一', type: '饮料', y: 22 }, + { x: '周二', type: '饮料', y: 43 }, + { x: '周三', type: '饮料', y: 33 }, + { x: '周四', type: '饮料', y: 22 }, + { x: '周五', type: '饮料', y: 10 }, + { x: '周六', type: '饮料', y: 30 }, + { x: '周日', type: '饮料', y: 50 } + ] + } + ], + series: [ + { + type: 'bar', + id: 'bar', + dataIndex: 0, + label: { visible: true }, + seriesField: 'type', + dataIndex: 0, + xField: ['x', 'type'], + yField: 'y' + }, + { + type: 'line', + id: 'line', + dataIndex: 1, + label: { visible: true }, + seriesField: 'type', + xField: 'x', + yField: 'y', + stack: false + } + ], + axes: [ + { orient: 'left', seriesIndex: [0] }, + { orient: 'right', seriesId: ['line'], grid: { visible: false } }, + { orient: 'bottom', label: { visible: true }, type: 'band' } + ], + legends: { + visible: true, + orient: 'bottom' + } + } + } + } + ], + acts: [ + { + id: 'default-chapter', + scenes: [ + { + id: 'scene0', + actions: [ + { + characterId: 'bar-series', + characterActions: [ + { + startTime: 10, + action: 'appear', + selector: '*', + payload: { + style: {}, + animation: { + duration: 10000, + easing: 'linear' + } as any + } + } + ] + } + ] + } + ] + } + ] + }; + const story = new Story(tempSpec, { dom: id }); + story.play(); + }, []); + + return
; +}; diff --git a/packages/vstory/demo/src/demos/RankingBar.tsx b/packages/vstory/demo/src/demos/RankingBar.tsx deleted file mode 100644 index fb51d6a1..00000000 --- a/packages/vstory/demo/src/demos/RankingBar.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import React, { useEffect } from 'react'; - -import { Bar } from '../../../src/template/charts/simple-chart'; -import { Scene } from '../../../src/scene'; -import { Title, textWriter } from '../../../src/component/title'; - -import { RankingBar as RankingBarChart } from '../../../src/template/ranking-bar/ranking-bar'; -import { yearsData, countryImage } from '../../data/ranking-bar'; - -export const RankingBar = () => { - const domId = 'ranking'; - useEffect(() => { - const allData: any[] = []; - yearsData.forEach(value => { - allData.push(...value); - }); - - const scene = new Scene({ - dom: domId - }); - const rankingBar = new RankingBarChart({ - data: allData, - timeField: 'Year', - xField: 'Value', - yField: 'CountryName', - icon: Array.from(countryImage).reduce((obj: any, [key, value]) => { - obj[key] = value; - return obj; - }, {}), - // iconPosition: 'bar-end', - // duration: 30000, - interval: 400, - // iconShape: 'rect', - // iconPosition: 'axis', - color: { - China: 'red', - USA: 'rgb(0,43,127)', - India: '#FF9933', - Russia: '#D52B1E', - Japan: 'rgb(79,66,95)', - Brazil: ' #009B3A', - Mexico: 'rgb(1,101,69)', - Indonesia: '#CE1126', - Italy: '#009246', - UK: 'rgb(27,63,126)', - Germany: '#000000', - France: '#0055A4', - Pakistan: '#006600', - Nigeria: '#008000' - }, - nameLabel: { - visible: true, - position: 'bar-start', - style: { - // fill: 'white' - } - }, - timeLabel: { - // visible: false - }, - yAxis: { - // domainLine: { - // stroke: 'red', - // lineWidth: 10 - // } - } - }); - (window as any).rankingBar = rankingBar; - - const title = new Title({ - text: 'A Ranking Bar Chart Demo', - x: 0, - y: 0, - textStyle: { - fontSize: 20 - } - }); - - scene.wait(800); - scene.play(textWriter(title, 1000)); - scene.wait(1200); - - scene.add(rankingBar); - }, []); - - return
; -}; diff --git a/packages/vstory/demo/src/demos/SimpleBar.tsx b/packages/vstory/demo/src/demos/SimpleBar.tsx deleted file mode 100644 index 9c595927..00000000 --- a/packages/vstory/demo/src/demos/SimpleBar.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import React, { useEffect } from 'react'; - -import { Bar } from '../../../src/template/charts/simple-chart'; -import { Scene } from '../../../src/scene'; -import { highlight } from '../../../src/animate/highlight'; -import { Title, textWriter } from '../../../src/component/title'; -import { yearsData } from '../../data/ranking-bar'; - -export const SimpleBar = () => { - const domId = 'simpleBar'; - useEffect(() => { - const allData: any[] = []; - yearsData.forEach(value => { - allData.push(...value); - }); - - const scene = new Scene({ - dom: domId - }); - - const bar = new Bar({ - type: 'bar', - width: 400, - height: 300, - data: [ - { - id: 'barData', - values: [ - { month: 'Monday', sales: 22 }, - { month: 'Tuesday', sales: 13 }, - { month: 'Wednesday', sales: 25 }, - { month: 'Thursday', sales: 29 }, - { month: 'Friday', sales: 38 } - ] - } - ], - xField: 'month', - yField: 'sales', - bar: { - id: 'bar', - state: { - highlight: {} - } - } - }); - - const title = new Title({ - text: 'A Bar Chart Demo', - x: 0, - y: 0, - textStyle: { - fontSize: 20 - } - }); - - scene.wait(800); - scene.play(textWriter(title, 1000)); - scene.wait(1200); - - scene.add(bar); - - // scene.wait(1000); - // const ani = highlight(bar, [{ month: 'Friday' }, { month: 'Monday' }], { fill: 'green' }); - // scene.wait(1000); - - // ani && scene.play(ani); - // scene.wait(2000); - - // const ani2 = highlight(bar, [{ month: 'Tuesday' }], { - // fill: 'red', - // shadowColor: 'rgba(0, 0, 0, 0.8)', - // shadowBlur: 10 - // }); - // ani2 && scene.play(ani2); - // scene.wait(1000); - // scene.remove(title); - // scene.remove(bar); - }, []); - - return
; -}; diff --git a/packages/vstory/demo/src/demos/StoryBarDemoPlay.tsx b/packages/vstory/demo/src/demos/StoryBarDemoPlay.tsx index 5285930e..fa737541 100644 --- a/packages/vstory/demo/src/demos/StoryBarDemoPlay.tsx +++ b/packages/vstory/demo/src/demos/StoryBarDemoPlay.tsx @@ -1,101 +1,101 @@ -import React, { useEffect } from 'react'; -import VChart, { IChartSpec } from '@visactor/vchart'; -import { StoryBar } from '../../../src/dsl/story-chart'; -import { StoryExecutor } from '../../../src/dsl/story-executor'; - -// class Player { -// canvas: HTMLCanvasElement; -// dpr: number; -// width: number; -// height: number; -// constructor(canvas: HTMLCanvasElement, width: number, height: number) { -// this.canvas = canvas; -// this.dpr = window.devicePixelRatio; -// this.width = width; -// this.height = height; -// this.canvas.width = width * this.dpr; -// this.canvas.height = height * this.dpr; -// } -// addElements() { - -// } -// tickTo() { - -// } -// play() { - -// } -// } - -export const StoryBarDemo = () => { - const id = 'storyBar'; - - useEffect(() => { - // 准备一个图表 - const spec: IChartSpec = { - type: 'bar', - data: [ - { - id: 'data', - values: [{ value: 80, name: 'A' }] - } - ], - xField: 'name', - yField: 'value', - bar: { - state: { - updateStyle: {} - } - }, - animationUpdate: { - duration: 500 - } - }; - - const chartInstance = new VChart(spec, { - dom: id - }); - - // chartInstance.renderSync(); - - // 创建叙事 - const bar = new StoryBar(); - - // 数据 - const data = [ - { key: 'a', value: 80, name: 'B' }, - { key: 'b', value: 120, name: 'C' }, - { key: 'c', value: 100, name: 'D' }, - { key: 'd', value: 300, name: 'E' } - ]; - - data.forEach(val => { - bar.add(val, { - style: { - fillOpacity: 0.5 - } - }); - }); - - data.reverse().forEach(val => { - bar.updateStyle(val, { - style: { - fill: 'red' - } - }); - }); - - const storyPlayer = new StoryExecutor(bar, { - chartInstance, - spec - }); - - storyPlayer.play(); - - return () => { - chartInstance.release(); - }; - }, []); - - return
; -}; +// import React, { useEffect } from 'react'; +// import VChart, { IChartSpec } from '@visactor/vchart'; +// import { StoryBar } from '../../../src/dsl/story-chart'; +// import { StoryExecutor } from '../../../src/dsl/story-executor'; + +// // class Player { +// // canvas: HTMLCanvasElement; +// // dpr: number; +// // width: number; +// // height: number; +// // constructor(canvas: HTMLCanvasElement, width: number, height: number) { +// // this.canvas = canvas; +// // this.dpr = window.devicePixelRatio; +// // this.width = width; +// // this.height = height; +// // this.canvas.width = width * this.dpr; +// // this.canvas.height = height * this.dpr; +// // } +// // addElements() { + +// // } +// // tickTo() { + +// // } +// // play() { + +// // } +// // } + +// export const StoryBarDemo = () => { +// const id = 'storyBar'; + +// useEffect(() => { +// // 准备一个图表 +// const spec: IChartSpec = { +// type: 'bar', +// data: [ +// { +// id: 'data', +// values: [{ value: 80, name: 'A' }] +// } +// ], +// xField: 'name', +// yField: 'value', +// bar: { +// state: { +// updateStyle: {} +// } +// }, +// animationUpdate: { +// duration: 500 +// } +// }; + +// const chartInstance = new VChart(spec, { +// dom: id +// }); + +// // chartInstance.renderSync(); + +// // 创建叙事 +// const bar = new StoryBar(); + +// // 数据 +// const data = [ +// { key: 'a', value: 80, name: 'B' }, +// { key: 'b', value: 120, name: 'C' }, +// { key: 'c', value: 100, name: 'D' }, +// { key: 'd', value: 300, name: 'E' } +// ]; + +// data.forEach(val => { +// bar.add(val, { +// style: { +// fillOpacity: 0.5 +// } +// }); +// }); + +// data.reverse().forEach(val => { +// bar.updateStyle(val, { +// style: { +// fill: 'red' +// } +// }); +// }); + +// const storyPlayer = new StoryExecutor(bar, { +// chartInstance, +// spec +// }); + +// storyPlayer.play(); + +// return () => { +// chartInstance.release(); +// }; +// }, []); + +// return
; +// }; diff --git a/packages/vstory/demo/src/demos/StoryLineDemo.tsx b/packages/vstory/demo/src/demos/StoryLineDemo.tsx index d6a242c1..8f0079e6 100644 --- a/packages/vstory/demo/src/demos/StoryLineDemo.tsx +++ b/packages/vstory/demo/src/demos/StoryLineDemo.tsx @@ -1,97 +1,97 @@ -import VChart, { ISpec, IVChart } from '@visactor/vchart'; -import React, { useEffect } from 'react'; -import { StoryExecutor } from '../../../src/dsl/story-executor'; -import { StoryLine } from '../../../src/dsl/story-chart/line'; +// import VChart, { ISpec, IVChart } from '@visactor/vchart'; +// import React, { useEffect } from 'react'; +// import { StoryExecutor } from '../../../src/dsl/story-executor'; +// import { StoryLine } from '../../../src/dsl/story-chart/line'; -export const StoryLineDemo = () => { - const id = 'line'; +// export const StoryLineDemo = () => { +// const id = 'line'; - useEffect(() => { - // 准备一个图表 - const dataId = 'data'; - // 数据 - const values = [ - { - time: '2:00', - value: 8 - }, - { - time: '4:00', - value: 9 - }, - { - time: '6:00', - value: 11 - }, - { - time: '8:00', - value: 14 - }, - { - time: '10:00', - value: 16 - }, - { - time: '12:00', - value: 17 - }, - { - time: '14:00', - value: 17 - }, - { - time: '16:00', - value: 16 - }, - { - time: '18:00', - value: 15 - } - ]; - const data = { - id: dataId, - values: values - }; - const spec = { - type: 'line', - data: data, - xField: 'time', - yField: 'value' - }; +// useEffect(() => { +// // 准备一个图表 +// const dataId = 'data'; +// // 数据 +// const values = [ +// { +// time: '2:00', +// value: 8 +// }, +// { +// time: '4:00', +// value: 9 +// }, +// { +// time: '6:00', +// value: 11 +// }, +// { +// time: '8:00', +// value: 14 +// }, +// { +// time: '10:00', +// value: 16 +// }, +// { +// time: '12:00', +// value: 17 +// }, +// { +// time: '14:00', +// value: 17 +// }, +// { +// time: '16:00', +// value: 16 +// }, +// { +// time: '18:00', +// value: 15 +// } +// ]; +// const data = { +// id: dataId, +// values: values +// }; +// const spec = { +// type: 'line', +// data: data, +// xField: 'time', +// yField: 'value' +// }; - const chartInstance = new VChart(spec, { - dom: id - }); +// const chartInstance = new VChart(spec, { +// dom: id +// }); - chartInstance.renderSync(); +// chartInstance.renderSync(); - // 创建叙事 - const line = new StoryLine(); - line.setInstance(chartInstance as IVChart); +// // 创建叙事 +// const line = new StoryLine(); +// line.setInstance(chartInstance as IVChart); - values.forEach((val, index) => { - line.symbolStyle(val, { - size: 15 + 10 * index, - fill: 'red', - fillOpacity: Math.random() - }); - }); +// values.forEach((val, index) => { +// line.symbolStyle(val, { +// size: 15 + 10 * index, +// fill: 'red', +// fillOpacity: Math.random() +// }); +// }); - line.lineStyle(values[1], { - stroke: 'red' - }); +// line.lineStyle(values[1], { +// stroke: 'red' +// }); - const storyPlayer = new StoryExecutor(line, { - chartInstance: line.getInstance(), - spec - }); +// const storyPlayer = new StoryExecutor(line, { +// chartInstance: line.getInstance(), +// spec +// }); - storyPlayer.play(); +// storyPlayer.play(); - return () => { - chartInstance.release(); - }; - }, []); +// return () => { +// chartInstance.release(); +// }; +// }, []); - return
; -}; +// return
; +// }; diff --git a/packages/vstory/demo/src/demos/StoryPieDemo.tsx b/packages/vstory/demo/src/demos/StoryPieDemo.tsx index 466a4598..31746200 100644 --- a/packages/vstory/demo/src/demos/StoryPieDemo.tsx +++ b/packages/vstory/demo/src/demos/StoryPieDemo.tsx @@ -1,72 +1,72 @@ -import React, { useEffect } from 'react'; -import VChart, { IPieChartSpec } from '@visactor/vchart'; -import { StoryPie } from '../../../src/dsl/story-chart'; -import { StoryExecutor } from '../../../src/dsl/story-executor'; +// import React, { useEffect } from 'react'; +// import VChart, { IPieChartSpec } from '@visactor/vchart'; +// import { StoryPie } from '../../../src/dsl/story-chart'; +// import { StoryExecutor } from '../../../src/dsl/story-executor'; -export const StoryPieDemo = () => { - const id = 'storyBar'; +// export const StoryPieDemo = () => { +// const id = 'storyBar'; - useEffect(() => { - // 数据 - const values = new Array(10).fill(0).map((d, i) => ({ - type: i + 1, - value: i + 1 - })); - const dataId = 'data'; - const data = { - id: dataId, - values: [] - }; +// useEffect(() => { +// // 数据 +// const values = new Array(10).fill(0).map((d, i) => ({ +// type: i + 1, +// value: i + 1 +// })); +// const dataId = 'data'; +// const data = { +// id: dataId, +// values: [] +// }; - // 准备一个图表 - const spec: IPieChartSpec = { - type: 'pie', - data: data, - outerRadius: 0.1, - valueField: 'value', - categoryField: 'type', - animationUpdate: { - duration: 300 - }, - label: { - visible: true - }, - animationAppear: { - duration: 300 - } - }; +// // 准备一个图表 +// const spec: IPieChartSpec = { +// type: 'pie', +// data: data, +// outerRadius: 0.1, +// valueField: 'value', +// categoryField: 'type', +// animationUpdate: { +// duration: 300 +// }, +// label: { +// visible: true +// }, +// animationAppear: { +// duration: 300 +// } +// }; - const chartInstance = new VChart(spec, { - dom: id - }); +// const chartInstance = new VChart(spec, { +// dom: id +// }); - chartInstance.renderSync(); +// chartInstance.renderSync(); - // 创建叙事 - const pie = new StoryPie(); - pie.setInstance(chartInstance); +// // 创建叙事 +// const pie = new StoryPie(); +// pie.setInstance(chartInstance); - values.forEach((val, index) => { - pie.add({ id: dataId, values: val }, {}); - }); +// values.forEach((val, index) => { +// pie.add({ id: dataId, values: val }, {}); +// }); - values.forEach((val, index) => { - pie.arcStyle(val, { - outerRadius: 100 + index * 10 - }); - }); +// values.forEach((val, index) => { +// pie.arcStyle(val, { +// outerRadius: 100 + index * 10 +// }); +// }); - const storyPlayer = new StoryExecutor(pie, { - chartInstance, - spec - }); +// const storyPlayer = new StoryExecutor(pie, { +// chartInstance, +// spec +// }); - storyPlayer.play(); +// storyPlayer.play(); - return () => { - chartInstance.release(); - }; - }, []); +// return () => { +// chartInstance.release(); +// }; +// }, []); - return
; -}; +// return
; +// }; diff --git a/packages/vstory/demo/src/demos/wordcloud.tsx b/packages/vstory/demo/src/demos/wordcloud.tsx new file mode 100644 index 00000000..5a896b3d --- /dev/null +++ b/packages/vstory/demo/src/demos/wordcloud.tsx @@ -0,0 +1,110 @@ +import React, { useEffect } from 'react'; +import { IStorySpec } from '../../../src/story/interface'; +import { Story } from '../../../src/story/story'; +import '../../../src/story/index'; +// import { Animate } from '@visactor/vrender-core'; + +// Animate.AddInterpolate('clipRange', (k, r, from, to, target, out) => { +// console.log('animate', k, r, from, to); +// }); + +export const wordcloud = () => { + const id = 'storyBar'; + + useEffect(() => { + // 准备一个图表 + const tempSpec: IStorySpec = { + characters: [ + { + type: 'VChart', + id: 'bar-series', + zIndex: 10, + position: { + top: 40, + left: 50, + width: 500, + height: 500 + }, + options: { + spec: { + type: 'wordCloud', + nameField: 'name', + valueField: 'value', + wordCloudConfig: { + zoomToFit: { + enlarge: true, + fontSizeLimitMax: 20 + } + }, + data: { + name: 'baseData', + values: [ + { + name: '螺蛳粉', + value: 957 + }, + { + name: '钵钵鸡', + value: 942 + }, + { + name: '板栗', + value: 842 + }, + { + name: '胡辣汤', + value: 828 + }, + { + name: '关东煮', + value: 665 + }, + { + name: '羊肉汤', + value: 627 + }, + { + name: '热干面', + value: 574 + } + ] + } + } + } + } + ], + acts: [ + { + id: 'default-chapter', + scenes: [ + { + id: 'scene0', + actions: [ + { + characterId: 'bar-series', + characterActions: [ + { + startTime: 10, + action: 'appear', + payload: { + style: {}, + animation: { + duration: 10000, + easing: 'linear' + } as any + } + } + ] + } + ] + } + ] + } + ] + }; + const story = new Story(tempSpec, { dom: id }); + story.play(); + }, []); + + return
; +}; diff --git a/packages/vstory/package.json b/packages/vstory/package.json index 0f0d26cd..d0625f66 100644 --- a/packages/vstory/package.json +++ b/packages/vstory/package.json @@ -25,11 +25,11 @@ }, "dependencies": { "@visactor/vchart": "1.11.5", - "@visactor/vrender": "0.19.11", - "@visactor/vrender-core": "0.19.11", - "@visactor/vrender-kits": "0.19.11", - "@visactor/vutils": "~0.18.4", - "@visactor/vrender-components": "0.19.11" + "@visactor/vrender": "0.19.20-alpha.2", + "@visactor/vrender-core": "0.19.20-alpha.2", + "@visactor/vrender-kits": "0.19.20-alpha.2", + "@visactor/vrender-components": "0.19.20-alpha.2", + "@visactor/vutils": "~0.18.4" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/packages/vstory/src/animate/animate.ts b/packages/vstory/src/animate/animate.ts index 16c88e4e..52c6ba11 100644 --- a/packages/vstory/src/animate/animate.ts +++ b/packages/vstory/src/animate/animate.ts @@ -1,32 +1,32 @@ -import type { IAnimate as IVRenderAnimate, IGraphic } from '@visactor/vrender'; -import type { IContext } from '../interface/type'; -import type { ITask, TaskCb } from '../task'; -import { AbstractTask } from '../task'; +// import type { IAnimate as IVRenderAnimate, IGraphic } from '@visactor/vrender'; +// import type { IContext } from '../interface/type'; +// import type { ITask, TaskCb } from '../task'; +// import { AbstractTask } from '../task'; -export class GraphicAnimate extends AbstractTask { - protected _animate: IVRenderAnimate; +// export class GraphicAnimate extends AbstractTask { +// protected _animate: IVRenderAnimate; - prev: ITask; - next: ITask; +// prev: ITask; +// next: ITask; - protected _target: IGraphic; +// protected _target: IGraphic; - constructor(target: IGraphic) { - super(); - this._target = target; - if (this._target) { - this._animate = this._target.animate().afterAll(Array.from(this._target.animates.values())); - } - } +// constructor(target: IGraphic) { +// super(); +// this._target = target; +// if (this._target) { +// this._animate = this._target.animate().afterAll(Array.from(this._target.animates.values())); +// } +// } - runCb(cb: TaskCb) { - if (this._animate) { - this._animate.runCb(cb); - } - } +// runCb(cb: TaskCb) { +// if (this._animate) { +// this._animate.runCb(cb); +// } +// } - // 覆写这个方法 - run(context: Partial) { - return; - } -} +// // 覆写这个方法 +// run(context: Partial) { +// return; +// } +// } diff --git a/packages/vstory/src/animate/highlight.ts b/packages/vstory/src/animate/highlight.ts index f5f51882..4dc7cb71 100644 --- a/packages/vstory/src/animate/highlight.ts +++ b/packages/vstory/src/animate/highlight.ts @@ -1,54 +1,54 @@ -import type { Dict } from '@visactor/vutils'; -import { isArray } from '@visactor/vutils'; -import type { Template } from '../template/base-template'; -import type { Data, MaybeArray } from '../type/common'; -import { getAllSeriesMarksWithoutRoot } from '../util/vchart-api'; -import { GraphicAnimate } from './animate'; -import { Action } from '../scene/action'; +// import type { Dict } from '@visactor/vutils'; +// import { isArray } from '@visactor/vutils'; +// import type { Template } from '../template/base-template'; +// import type { Data, MaybeArray } from '../type/common'; +// import { getAllSeriesMarksWithoutRoot } from '../util/vchart-api'; +// import { GraphicAnimate } from './animate'; +// import { Action } from '../scene/action'; -export function highlight(template: Template, data: MaybeArray, style: Dict) { - if (!data || !template) { - return null; - } - const highlight = new HighLight(template, data, style); - return new Action(highlight, highlight => { - highlight.run(); - }); -} +// export function highlight(template: Template, data: MaybeArray, style: Dict) { +// if (!data || !template) { +// return null; +// } +// const highlight = new HighLight(template, data, style); +// return new Action(highlight, highlight => { +// highlight.run(); +// }); +// } -class HighLight extends GraphicAnimate { - type = 'highlight'; +// class HighLight extends GraphicAnimate { +// type = 'highlight'; - protected _duration: number; - protected _dataList: Data[]; - protected _template: Template; - protected _style: any; +// protected _duration: number; +// protected _dataList: Data[]; +// protected _template: Template; +// protected _style: any; - constructor(target: Template, data: MaybeArray, style: any, duration?: number) { - super(null); - this._duration = duration; - this._dataList = isArray(data) ? data : [data]; - this._template = target; - this._style = style; - } +// constructor(target: Template, data: MaybeArray, style: any, duration?: number) { +// super(null); +// this._duration = duration; +// this._dataList = isArray(data) ? data : [data]; +// this._template = target; +// this._style = style; +// } - run() { - if (this._dataList.length) { - const { _dataList, _style } = this; - const vchart = this._template.vchartInstance(); - if (vchart) { - const marks = getAllSeriesMarksWithoutRoot(vchart); - if (marks && marks.length) { - marks.forEach(mark => { - mark.getProduct().encodeState('highlight', _style); - }); - vchart.updateState({ - highlight: { - filter: { datums: _dataList, dataKeys: undefined } as any - } - }); - } - } - } - } -} +// run() { +// if (this._dataList.length) { +// const { _dataList, _style } = this; +// const vchart = this._template.vchartInstance(); +// if (vchart) { +// const marks = getAllSeriesMarksWithoutRoot(vchart); +// if (marks && marks.length) { +// marks.forEach(mark => { +// mark.getProduct().encodeState('highlight', _style); +// }); +// vchart.updateState({ +// highlight: { +// filter: { datums: _dataList, dataKeys: undefined } as any +// } +// }); +// } +// } +// } +// } +// } diff --git a/packages/vstory/src/component/title.ts b/packages/vstory/src/component/title.ts deleted file mode 100644 index c18d1df2..00000000 --- a/packages/vstory/src/component/title.ts +++ /dev/null @@ -1,77 +0,0 @@ -import type { IAnimate as IVRenderAnimate } from '@visactor/vrender'; -import { InputText } from '@visactor/vrender'; -import { GraphicAnimate } from '../animate/animate'; -import type { Title } from '@visactor/vrender-components'; -import type { IContext } from '../interface/type'; -import { Action } from '../scene/action'; -import type { TaskCb } from '../task'; - -export function textWriter(title: Title, duration: number) { - const _textWriter = new TextWriter(title, duration); - return new Action(_textWriter, (_textWriter, context) => { - if (context && context.stage) { - context.stage.defaultLayer.add(_textWriter.getEntity()); - _textWriter.run(); - } - }); -} - -export class TextWriter extends GraphicAnimate { - protected _title: Title; - getEntity() { - return this._title; - } - protected _duration: number; - - protected _mainAnimate: IVRenderAnimate; - protected _subAnimate: IVRenderAnimate; - - constructor(title: Title, duration: number) { - super(null); - this._title = title; - this._duration = duration; - } - - run(context: Partial): void { - if (this._title && this._duration > 0) { - // @ts-ignore - const { _subtitle: subtitle, _mainTitle: mainTitle } = this._title; - if (mainTitle) { - this._mainAnimate = mainTitle.animate().play( - new InputText( - { text: '' }, - { - text: mainTitle.attribute.text[0] - }, - this._duration, - 'linear' - ) - ); - } - if (subtitle) { - this._subAnimate = subtitle.animate().play( - new InputText( - { text: '' }, - { - text: subtitle.attribute.text - }, - this._duration, - 'linear' - ) - ); - } - } - } - - runCb(cb: TaskCb): void { - if (this._mainAnimate) { - this._mainAnimate.runCb(cb); - } - - if (this._subAnimate) { - this._subAnimate.runCb(cb); - } - } -} - -export { Title } from '@visactor/vrender-components'; diff --git a/packages/vstory/src/constants/action.ts b/packages/vstory/src/constants/action.ts new file mode 100644 index 00000000..ab03b83f --- /dev/null +++ b/packages/vstory/src/constants/action.ts @@ -0,0 +1,3 @@ +export const ACTION_TYPE = { + APPEAR: 'appear' +}; diff --git a/packages/vstory/src/constants/character.ts b/packages/vstory/src/constants/character.ts new file mode 100644 index 00000000..f4015003 --- /dev/null +++ b/packages/vstory/src/constants/character.ts @@ -0,0 +1,21 @@ +export const enum StoryChartType { + VCHART = 'VChart' +} + +export enum StoryGraphicType { + RECT = 'RectComponent', + SHAPE = 'ShapeComponent', + LINE = 'LineComponent', + ARC = 'ArcComponent', + // AREA = 'AreaComponent', + PATH = 'PathComponent', + TEXT = 'TextComponent', + RICH_TEXT = 'RichTextComponent', + QIPAO = 'QipaoComponent', + IMAGE = 'ImageComponent' +} + +export const enum StoryChartComponentType { + MARK_POINT = 'markPoint', + TITLE = 'title' +} diff --git a/packages/vstory/src/dsl/constant/index.ts b/packages/vstory/src/dsl/constant/index.ts index 53b2a506..5ec7902f 100644 --- a/packages/vstory/src/dsl/constant/index.ts +++ b/packages/vstory/src/dsl/constant/index.ts @@ -1,17 +1,18 @@ export const enum StoryChartType { - CHARACTER_CHART = 'CharacterChart', - BAR = 'BarChart', - LINE = 'LineChart', - AREA = 'AreaChart', - HISTOGRAM = 'HistogramChart', - PIE = 'PieChart', - ROSE = 'RoseChart', - RADAR = 'RadarChart', - RANGE_COLUMN = 'RangeColumnChart', - SCATTER = 'ScatterChart', - WORD_CLOUD = 'WordCloudChart', - TREE_MAP = 'TreeMapChart', - SUNBURST = 'SunburstChart' + // CHARACTER_CHART = 'CharacterChart', + // BAR = 'BarChart', + // LINE = 'LineChart', + // AREA = 'AreaChart', + // HISTOGRAM = 'HistogramChart', + // PIE = 'PieChart', + // ROSE = 'RoseChart', + // RADAR = 'RadarChart', + // RANGE_COLUMN = 'RangeColumnChart', + // SCATTER = 'ScatterChart', + // WORD_CLOUD = 'WordCloudChart', + // TREE_MAP = 'TreeMapChart', + // SUNBURST = 'SunburstChart', + VCHART = 'VChart' } export enum StoryGraphicType { RECT = 'RectComponent', diff --git a/packages/vstory/src/dsl/story-executor/index.ts b/packages/vstory/src/dsl/story-executor/index.ts index 3b995050..d884f7d4 100644 --- a/packages/vstory/src/dsl/story-executor/index.ts +++ b/packages/vstory/src/dsl/story-executor/index.ts @@ -1,52 +1,52 @@ -import { IVChart, IChartSpec } from '@visactor/vchart'; -import { StoryChart } from '../story-chart'; -import { processorMap } from '../story-processor'; -import { ActionNode } from '../types'; - -export interface StoryPlayerOption { - chartInstance: IVChart; - spec: IChartSpec; -} - -export class StoryExecutor { - private storyChart: StoryChart; - protected processor: Record = {}; - - private option: StoryPlayerOption; - private snapshots: ActionNode[] = []; - - constructor(storyChart: StoryChart, option: StoryPlayerOption) { - this.storyChart = storyChart; - this.processor = processorMap[storyChart.storyChartType]; - this.option = option; - this.snapshots = this.storyChart.exportSnapshot(); - } - - play = async () => { - console.log(this.snapshots); - for (let i = 0; i < this.snapshots.length; i++) { - // TODO: 上个动作执行完后, 执行下一个. - // eslint-disable-next-line promise/param-names - await new Promise(res => { - setTimeout(res, 500); - }); - - const snapshot = this.snapshots[i]; - const { action, elementId, elementType, callback } = snapshot; - - let processor; - if (elementId === this.storyChart.uid) { - processor = this.processor[action]; - } else { - processor = processorMap[elementType][action]; - } - - if (processor) { - await processor(this.option.chartInstance, this.option.spec, snapshot); - if (callback) { - callback(this.option.chartInstance, this.option.spec, snapshot as any); - } - } - } - }; -} +// import { IVChart, IChartSpec } from '@visactor/vchart'; +// import { StoryChart } from '../story-chart'; +// import { processorMap } from '../story-processor'; +// import { ActionNode } from '../types'; + +// export interface StoryPlayerOption { +// chartInstance: IVChart; +// spec: IChartSpec; +// } + +// export class StoryExecutor { +// private storyChart: StoryChart; +// protected processor: Record = {}; + +// private option: StoryPlayerOption; +// private snapshots: ActionNode[] = []; + +// constructor(storyChart: StoryChart, option: StoryPlayerOption) { +// this.storyChart = storyChart; +// this.processor = processorMap[storyChart.storyChartType]; +// this.option = option; +// this.snapshots = this.storyChart.exportSnapshot(); +// } + +// play = async () => { +// console.log(this.snapshots); +// for (let i = 0; i < this.snapshots.length; i++) { +// // TODO: 上个动作执行完后, 执行下一个. +// // eslint-disable-next-line promise/param-names +// await new Promise(res => { +// setTimeout(res, 500); +// }); + +// const snapshot = this.snapshots[i]; +// const { action, elementId, elementType, callback } = snapshot; + +// let processor; +// if (elementId === this.storyChart.uid) { +// processor = this.processor[action]; +// } else { +// processor = processorMap[elementType][action]; +// } + +// if (processor) { +// await processor(this.option.chartInstance, this.option.spec, snapshot); +// if (callback) { +// callback(this.option.chartInstance, this.option.spec, snapshot as any); +// } +// } +// } +// }; +// } diff --git a/packages/vstory/src/dsl/story-processor/processorMap/processorMap.ts b/packages/vstory/src/dsl/story-processor/processorMap/processorMap.ts index 7e7eac98..3073b273 100644 --- a/packages/vstory/src/dsl/story-processor/processorMap/processorMap.ts +++ b/packages/vstory/src/dsl/story-processor/processorMap/processorMap.ts @@ -60,52 +60,52 @@ export const componentProcessor = { // 图表processor export const processorChartMap = { - [StoryChartType.CHARACTER_CHART]: commonProcessorMap, - // [StoryChartType.CHARACTER_CHART]: characterProcessorMap, - [StoryChartType.BAR]: { - // 大多数都是通用的, 可以复用. - ...editProcessor, - ...viewProcessor, - // 通用的, 但实现不同的, 可以直接覆盖 - createMarkPoint: createMarkPointProcessor, - createTitle: createTitleProcessor, - // 不通用的, 可直接覆盖, 重新定义 - barStyle: createMarkStyleProcessorByMarkType('rect'), - appear: barAppearProcessor, - disappear: barDisappearProcessor, - dance: danceProcessor - }, - [StoryChartType.LINE]: { - ...editProcessor, - ...viewProcessor, - ...componentProcessor, - lineStyle: lineStyleProcessor, - appear: lineAppearProcessor, - symbolStyle: createMarkStyleProcessorByMarkType('symbol') - }, - [StoryChartType.PIE]: { - ...editProcessor, - ...viewProcessor, - ...componentProcessor, - arcStyle: createMarkStyleProcessorByMarkType('arc'), - appear: pieAppearProcessor, - disappear: pieDisappearProcessor - }, - [StoryChartType.AREA]: { - ...editProcessor, - ...viewProcessor, - ...componentProcessor, - appear: areaAppearProcessor, - disappear: areaDisappearProcessor, - arcStyle: createMarkStyleProcessorByMarkType('arc') - }, - [StoryChartType.RANGE_COLUMN]: rangeColumnProcessorMap, - [StoryChartType.SCATTER]: scatterProcessorMap, - [StoryChartType.ROSE]: roseProcessorMap, - [StoryChartType.RADAR]: radarProcessorMap, - [StoryChartType.WORD_CLOUD]: wordCloudProcessorMap, - [StoryChartType.TREE_MAP]: treeMapProcessorMap, - [StoryChartType.SUNBURST]: sunburstProcessorMap + // [StoryChartType.CHARACTER_CHART]: commonProcessorMap, + // // [StoryChartType.CHARACTER_CHART]: characterProcessorMap, + // [StoryChartType.BAR]: { + // // 大多数都是通用的, 可以复用. + // ...editProcessor, + // ...viewProcessor, + // // 通用的, 但实现不同的, 可以直接覆盖 + // createMarkPoint: createMarkPointProcessor, + // createTitle: createTitleProcessor, + // // 不通用的, 可直接覆盖, 重新定义 + // barStyle: createMarkStyleProcessorByMarkType('rect'), + // appear: barAppearProcessor, + // disappear: barDisappearProcessor, + // dance: danceProcessor + // }, + // [StoryChartType.LINE]: { + // ...editProcessor, + // ...viewProcessor, + // ...componentProcessor, + // lineStyle: lineStyleProcessor, + // appear: lineAppearProcessor, + // symbolStyle: createMarkStyleProcessorByMarkType('symbol') + // }, + // [StoryChartType.PIE]: { + // ...editProcessor, + // ...viewProcessor, + // ...componentProcessor, + // arcStyle: createMarkStyleProcessorByMarkType('arc'), + // appear: pieAppearProcessor, + // disappear: pieDisappearProcessor + // }, + // [StoryChartType.AREA]: { + // ...editProcessor, + // ...viewProcessor, + // ...componentProcessor, + // appear: areaAppearProcessor, + // disappear: areaDisappearProcessor, + // arcStyle: createMarkStyleProcessorByMarkType('arc') + // }, + // [StoryChartType.RANGE_COLUMN]: rangeColumnProcessorMap, + // [StoryChartType.SCATTER]: scatterProcessorMap, + // [StoryChartType.ROSE]: roseProcessorMap, + // [StoryChartType.RADAR]: radarProcessorMap, + // [StoryChartType.WORD_CLOUD]: wordCloudProcessorMap, + // [StoryChartType.TREE_MAP]: treeMapProcessorMap, + // [StoryChartType.SUNBURST]: sunburstProcessorMap }; // 组件processor @@ -127,7 +127,7 @@ export const commonMarkProcessor = { bounce: bounceProcessor }; -export const processorMarkMap = {}; +export const processorMarkMap: Record = {}; Object.values(StoryGraphicType).forEach(type => { processorMarkMap[type] = commonMarkProcessor; }); diff --git a/packages/vstory/src/player/encode.ts b/packages/vstory/src/player/encode.ts new file mode 100644 index 00000000..e8817470 --- /dev/null +++ b/packages/vstory/src/player/encode.ts @@ -0,0 +1,67 @@ +// import { FFmpeg, createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'; + +// export class Encoder { +// private _FFMPEG: FFmpeg | null = null; +// private _FFMPEG_Loaded = false; + +// constructor() { +// this.initFFMPEG(); +// } + +// async initFFMPEG() { +// this._FFMPEG = createFFmpeg({ log: true }); +// await this.loadFFmpeg(); +// } +// async loadFFmpeg() { +// if (this._FFMPEG_Loaded) { +// return; +// } +// if (!this._FFMPEG) { +// this._FFMPEG = createFFmpeg({ log: true }); +// } +// await this._FFMPEG.load(); +// console.log('加载'); +// this._FFMPEG_Loaded = true; +// } + +// async exportVideo(frameNum: number, fps: number, cb: (i: number) => Promise) { +// const outName = `out`; +// await this.loadFFmpeg(); +// const ffmpeg = this._FFMPEG; +// if (!ffmpeg) { +// return; +// } +// console.log(ffmpeg.isLoaded()); + +// for (let i = 0; i < frameNum; i++) { +// const data = await cb(i); +// console.log(frameNum, i, data); +// const num = `0000${i}`.slice(-3); + +// ffmpeg.FS('writeFile', `vstory.${num}.png`, await fetchFile(data)); +// } + +// await ffmpeg.run( +// '-framerate', +// fps.toString(), +// '-pattern_type', +// 'glob', +// '-i', +// '*.png', +// '-c:v', +// 'libx264', +// '-pix_fmt', +// 'yuv420p', +// `${outName}.mp4` +// ); +// for (let i = 0; i < frameNum; i++) { +// const num = `0000${i}`.slice(-3); +// ffmpeg.FS('unlink', `vstory.${num}.png`); +// } +// console.log('readFile'); +// const data = (this._FFMPEG as FFmpeg).FS('readFile', `${outName}.mp4`); +// console.log('data', data); +// const objUrl = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' })); +// return objUrl; +// } +// } diff --git a/packages/vstory/src/player/interface/player.ts b/packages/vstory/src/player/interface/player.ts new file mode 100644 index 00000000..cb637749 --- /dev/null +++ b/packages/vstory/src/player/interface/player.ts @@ -0,0 +1,11 @@ +import { ICharacter } from '../../story/character'; +import type { IActSpec } from '../../story/interface/dsl-interface'; + +export interface IPlayer { + tickTo: (t: number) => void; + play: () => void; + encodeToVideo: (millsecond: number, fps: number) => Promise; + pause: () => void; + release: () => void; + initActs: (acts: IActSpec[]) => void; +} diff --git a/packages/vstory/src/player/interface/scheduler.ts b/packages/vstory/src/player/interface/scheduler.ts new file mode 100644 index 00000000..81bd401a --- /dev/null +++ b/packages/vstory/src/player/interface/scheduler.ts @@ -0,0 +1,7 @@ +import type { IActSpec } from '../../story/interface'; +import type { IActionItem } from '../scheduler'; + +export interface IScheduler { + initActs: (acts: IActSpec[]) => void; + getActionsInRange: (fromTime: number, toTime: number) => IActionItem[]; +} diff --git a/packages/vstory/src/player/player.ts b/packages/vstory/src/player/player.ts new file mode 100644 index 00000000..724effc4 --- /dev/null +++ b/packages/vstory/src/player/player.ts @@ -0,0 +1,139 @@ +import type { IActSpec, IStory } from '../story/interface'; +import { IAction } from '../story/interface'; +import type { ICharacter } from '../story/character'; +import type { IPlayer } from './interface/player'; +import type { IActionProcessor } from './processor/interface/action-processor'; +import { ActionProcessor } from './processor/processor'; +import { processorMap } from './processor/processorMap'; +import type { IScheduler } from './interface/scheduler'; +import { Scheduler } from './scheduler'; + +export class Ticker { + cb?: (delta: number) => void; + rafIdx = 0; + start(cb: (t: number) => void) { + this.stop(); + this.cb = cb; + this._tick(0); + } + + _tick = (lt: number) => { + const ct = Date.now(); + this.cb && this.cb(lt === 0 ? 0 : ct - lt); + this.rafIdx = requestAnimationFrame(() => this._tick(ct)); + }; + + stop() { + this.rafIdx && cancelAnimationFrame(this.rafIdx); + this.rafIdx = 0; + } +} + +export class Player implements IPlayer { + protected _story: IStory; + protected _ticker: Ticker; + protected _currTime: number; + // protected _encoder: Encoder; + protected _actionProcessor: IActionProcessor; + protected _scheduler: IScheduler; + + constructor(story: IStory, options?: { scaleX?: number; scaleY?: number }) { + this._story = story; + this._ticker = new Ticker(); + this._currTime = 0; + this._story.canvas.getStage().defaultLayer.setAttributes({ + scaleX: options?.scaleX ?? 1, + scaleY: options?.scaleY ?? 1 + }); + // this._encoder = new Encoder(); + this._actionProcessor = new ActionProcessor(story, processorMap); + this._scheduler = new Scheduler(this._actionProcessor); + } + + initActs(acts: IActSpec[]) { + this._scheduler.initActs(acts); + } + + // 清除当前状态,一般用于回放操作 + reset() { + return; + } + + tickTo(t: number) { + // console.log(t); + const lastTime = this._currTime; + if (lastTime > t) { + this.reset(); + this._currTime = 0; + this.tickTo(0); + } + + const actions = this._scheduler.getActionsInRange(lastTime, t); + const characterSet = new Set(); + actions.forEach(action => { + const character = this._story.getCharactersById(action.characterId); + characterSet.add(character); + this._actionProcessor.doAction(character.spec.type, action.actionSpec.action, character, action.actionSpec); + }); + + // 将character show出来 + // TODO 后续放在appear处理,因为现在创建之后就会展示,所以只能先visible为false + characterSet.forEach(character => { + character.show(); + }); + + this._currTime = t; + this._story.canvas.getStage().ticker.tickAt(t); + this._story.canvas.getStage().render(); + } + + play(): void { + this._ticker.stop(); + this._currTime = 0; + this.reset(); + this._ticker.start(t => { + this.tickTo(this._currTime + t); + }); + } + + async encodeToVideo(millsecond: number, fps: number): Promise { + // // if (!this._currChapter) { + // // return; + // // } + // const frameNum = (millsecond / 1000) * fps; + // const deltaT = 1000 / fps; + // this.tickTo(0); + // const objUrl = await this._encoder.exportVideo(frameNum, fps, async i => { + // const t = deltaT * i; + // this.tickTo(t); + // return new Promise((resolve, reject) => { + // this._canvas + // .getStage() + // .window.getContext() + // .canvas.nativeCanvas.toBlob((blob: any) => { + // if (blob) { + // resolve(blob); + // } else { + // // console.log('no blob'); + // reject('no blob'); + // } + // }, `image/png`); + // }); + // }); + + // return objUrl; + return null; + } + + pause(): void { + this._ticker.stop(); + } + + resume(): void { + this._ticker._tick(this._currTime); + } + + release(): void { + return; + } +} diff --git a/packages/vstory/src/player/processor/chart/component/commonAppear.ts b/packages/vstory/src/player/processor/chart/component/commonAppear.ts new file mode 100644 index 00000000..d47fca05 --- /dev/null +++ b/packages/vstory/src/player/processor/chart/component/commonAppear.ts @@ -0,0 +1,32 @@ +import type { IGroup } from '@visactor/vrender-core'; +import type { IChartAppearAction } from '../../interface/appear-action'; + +export const commonGrow = ( + instance: IGroup, + animation: IChartAppearAction['payload']['animation'], + option: { disappear: boolean } +) => { + const { duration, easing } = animation; + const { disappear } = option; + + instance = instance.getChildAt(0) as IGroup; + const width = instance.AABBBounds.width(); + const height = instance.AABBBounds.height(); + const opacityMap = disappear ? { from: width, to: 0 } : { from: 0, to: width }; + + instance.setAttributes({ width: opacityMap.from, height, clip: true }); + instance.animate().to({ width: opacityMap.to }, duration, easing); +}; + +export const commonFade = ( + instance: IGroup, + animation: IChartAppearAction['payload']['animation'], + option: { disappear: boolean } +) => { + const { duration, easing } = animation; + const { disappear } = option; + const opacityMap = disappear ? { from: 1, to: 0 } : { from: 0, to: 1 }; + + instance.setAttributes({ baseOpacity: opacityMap.from }); + instance.animate().to({ baseOpacity: opacityMap.to }, duration, easing); +}; diff --git a/packages/vstory/src/player/processor/chart/component/legendsAppear.ts b/packages/vstory/src/player/processor/chart/component/legendsAppear.ts new file mode 100644 index 00000000..35004bec --- /dev/null +++ b/packages/vstory/src/player/processor/chart/component/legendsAppear.ts @@ -0,0 +1,21 @@ +import type { IChartAppearAction } from '../../interface/appear-action'; +import { commonFade, commonGrow } from './commonAppear'; +import type { IGroup } from '@visactor/vrender-core'; + +export const runLegendsAppear = ( + instance: IGroup, + animation: IChartAppearAction['payload']['animation'], + option: { disappear: boolean } +) => { + switch (animation.effect) { + case 'grow': { + return commonGrow(instance, animation, option); + } + case 'fade': { + return commonFade(instance, animation, option); + } + default: { + return commonFade(instance, animation, option); + } + } +}; diff --git a/packages/vstory/src/player/processor/chart/seriesmark/commonTransformMarkAppear.ts b/packages/vstory/src/player/processor/chart/seriesmark/commonTransformMarkAppear.ts new file mode 100644 index 00000000..cacf079a --- /dev/null +++ b/packages/vstory/src/player/processor/chart/seriesmark/commonTransformMarkAppear.ts @@ -0,0 +1,40 @@ +import type VChart from '@visactor/vchart'; +import type { IChartAppearAction } from '../../interface/appear-action'; + +export const commonGrow = ( + instance: VChart, + animation: IChartAppearAction['payload']['animation'], + typeList: string[], + option: { markIndex: number; disappear: boolean } +) => { + const { duration, loop, oneByOne, easing } = animation; + const { disappear } = option; + + const type = disappear ? typeList[1] : typeList[0]; + + return { + type, + duration, + loop, + oneByOne, + easing + }; +}; + +export const commonFade = ( + instance: VChart, + animation: IChartAppearAction['payload']['animation'], + option: { markIndex: number; disappear: boolean } +) => { + const { duration, loop, oneByOne, easing } = animation; + const { disappear } = option; + const type = disappear ? 'fadeOut' : 'fadeIn'; + + return { + type, + duration, + loop, + oneByOne, + easing + }; +}; diff --git a/packages/vstory/src/player/processor/chart/seriesmark/transformLineAppear.ts b/packages/vstory/src/player/processor/chart/seriesmark/transformLineAppear.ts new file mode 100644 index 00000000..d705c4ec --- /dev/null +++ b/packages/vstory/src/player/processor/chart/seriesmark/transformLineAppear.ts @@ -0,0 +1,21 @@ +import type VChart from '@visactor/vchart'; +import type { IChartAppearAction } from '../../interface/appear-action'; +import { commonFade, commonGrow } from './commonTransformMarkAppear'; + +export const transformLineAppear = ( + instance: VChart, + animation: IChartAppearAction['payload']['animation'], + option: { markIndex: number; disappear: boolean } +) => { + switch (animation.effect) { + case 'grow': { + return commonGrow(instance, animation, ['clipIn', 'clipOut'], option); + } + case 'fade': { + return commonFade(instance, animation, option); + } + default: { + return commonFade(instance, animation, option); + } + } +}; diff --git a/packages/vstory/src/player/processor/chart/seriesmark/transformRectAppear.ts b/packages/vstory/src/player/processor/chart/seriesmark/transformRectAppear.ts new file mode 100644 index 00000000..335fa66c --- /dev/null +++ b/packages/vstory/src/player/processor/chart/seriesmark/transformRectAppear.ts @@ -0,0 +1,96 @@ +import type VChart from '@visactor/vchart'; +// import type { IChartAppearAction } from '../../../../types/chart/appear'; +import type { IOrientType } from '@visactor/vrender-components'; +import type { IChartAppearAction } from '../../interface/appear-action'; +import { commonFade } from './commonTransformMarkAppear'; + +// 将payload转换为chart内置的动画type +export const transformRectAppear = ( + instance: VChart, + animation: IChartAppearAction['payload']['animation'], + option: { markIndex: number; disappear: boolean } +) => { + switch (animation.effect) { + case 'grow': { + return rectGrow(instance, animation, { + ...option, + center: false + }); + } + case 'centerGrow': { + return rectGrow(instance, animation, { + ...option, + center: true + }); + } + case 'fade': { + return commonFade(instance, animation, { + ...option + }); + } + } +}; + +const rectGrow = ( + instance: VChart, + animation: IChartAppearAction['payload']['animation'], + option = { center: false, disappear: false } +) => { + const { duration, loop, oneByOne, easing } = animation; + const { center, disappear } = option; + const direction = instance.getChart().getSpec().direction ?? 'vertical'; + const xField = instance.getChart().getSpec().xField; + const yField = instance.getChart().getSpec().yField; + const [xAxis, yAxis] = getXYAxis(instance); + + const type = disappear ? (center ? 'growCenterOut' : 'growHeightOut') : center ? 'growCenterIn' : 'growHeightIn'; + + return { + type: type, + duration, + loop, + oneByOne, + easing, + options: (datum: any, element: any, params: any) => { + const field = direction === 'vertical' ? yField : xField; + const data = datum?.[field]; + + if (direction === 'vertical') { + return { + overall: yAxis?.getScale(0).scale(0), + orient: data > 0 ? 'negative' : 'positive' + }; + } + return { + overall: xAxis?.getScale(0).scale(0), + orient: data > 0 ? 'negative' : 'positive' + }; + } + }; +}; + +function isXAxis(orient: IOrientType) { + return orient === 'bottom' || orient === 'top'; +} + +function isYAxis(orient: IOrientType) { + return orient === 'left' || orient === 'right'; +} + +const getXYAxis = (instance: VChart) => { + const axes = instance.getChart().getComponentsByKey('axes'); + const xAxis = axes.find(axis => { + const orient = (axis as any).getOrient(); + if (isXAxis(orient)) { + return true; + } + }) as any; + const yAxis = axes.find(axis => { + const orient = (axis as any).getOrient(); + if (isYAxis(orient)) { + return true; + } + }) as any; + + return [xAxis, yAxis]; +}; diff --git a/packages/vstory/src/player/processor/chart/seriesmark/transformSymbolAppear.ts b/packages/vstory/src/player/processor/chart/seriesmark/transformSymbolAppear.ts new file mode 100644 index 00000000..21cebe8d --- /dev/null +++ b/packages/vstory/src/player/processor/chart/seriesmark/transformSymbolAppear.ts @@ -0,0 +1,21 @@ +import type VChart from '@visactor/vchart'; +import type { IChartAppearAction } from '../../interface/appear-action'; +import { commonFade, commonGrow } from './commonTransformMarkAppear'; + +export const transformSymbolAppear = ( + instance: VChart, + animation: IChartAppearAction['payload']['animation'], + option: { markIndex: number; disappear: boolean } +) => { + switch (animation.effect) { + case 'grow': { + return commonGrow(instance, animation, ['scaleIn', 'scaleOut'], option); + } + case 'fade': { + return commonFade(instance, animation, option); + } + default: { + return commonFade(instance, animation, option); + } + } +}; diff --git a/packages/vstory/src/player/processor/chart/seriesmark/transformTextAppear.ts b/packages/vstory/src/player/processor/chart/seriesmark/transformTextAppear.ts new file mode 100644 index 00000000..e62e9cb9 --- /dev/null +++ b/packages/vstory/src/player/processor/chart/seriesmark/transformTextAppear.ts @@ -0,0 +1,25 @@ +import type VChart from '@visactor/vchart'; +import type { IChartAppearAction } from '../../interface/appear-action'; +import { commonFade, commonGrow } from './commonTransformMarkAppear'; + +// 将payload转换为chart内置的动画type +export const transformTextAppear = ( + instance: VChart, + animation: IChartAppearAction['payload']['animation'], + option: { + disappear: boolean; + markIndex: number; + } +) => { + switch (animation.effect) { + case 'grow': { + return commonGrow(instance, animation, ['scaleIn', 'scaleOut'], option); + } + case 'fade': { + return commonFade(instance, animation, option); + } + default: { + return commonFade(instance, animation, option); + } + } +}; diff --git a/packages/vstory/src/player/processor/chart/transformMap.ts b/packages/vstory/src/player/processor/chart/transformMap.ts new file mode 100644 index 00000000..3544e008 --- /dev/null +++ b/packages/vstory/src/player/processor/chart/transformMap.ts @@ -0,0 +1,17 @@ +import { runLegendsAppear } from './component/legendsAppear'; +import { transformLineAppear } from './seriesmark/transformLineAppear'; +import { transformRectAppear } from './seriesmark/transformRectAppear'; +import { transformSymbolAppear } from './seriesmark/transformSymbolAppear'; +import { transformTextAppear } from './seriesmark/transformTextAppear'; + +export const transformMap = { + appear: { + // series & mark + rect: transformRectAppear, + line: transformLineAppear, + symbol: transformSymbolAppear, + text: transformTextAppear, + // component + legends: runLegendsAppear + } +}; diff --git a/packages/vstory/src/player/processor/chart/vchart.ts b/packages/vstory/src/player/processor/chart/vchart.ts new file mode 100644 index 00000000..0f60d7be --- /dev/null +++ b/packages/vstory/src/player/processor/chart/vchart.ts @@ -0,0 +1,118 @@ +import type { IComponent, ISeries, IVChart } from '@visactor/vchart'; +import { merge } from '@visactor/vutils'; +import type { ICharacter } from '../../../story/character'; +import type { IAction } from '../../../story/interface'; +import { ActionProcessorItem } from '../processor-item'; +import { transformMap } from './transformMap'; +import type { IChartAppearAction } from '../interface/appear-action'; + +export class VChartAppearActionProcessor extends ActionProcessorItem { + name: 'appear'; + + constructor() { + super(); + } + + getStartTimeAndDuration(action: IAction): { startTime: number; duration: number } { + const { startTime: globalStartTime = 0, duration: globalDuration } = action; + const { startTime = 0, duration = 0 } = action.payload?.animation ?? ({} as any); + + const st = globalStartTime + startTime; + const d = globalDuration ?? duration; + return { + startTime: st, + duration: d + }; + } + + run(character: ICharacter, actionSpec: IAction): void { + const vchart = character.graphic._vchart as IVChart; + // series & mark + const seriesList = vchart.getChart().getAllSeries(); + seriesList.forEach(series => { + this.commonSeriesAppear(vchart, series, actionSpec); + }); + // component + const components = vchart.getChart().getAllComponents(); + components.forEach(component => { + this.componentAppear(vchart, component, actionSpec); + }); + } + + protected componentAppear(vchart: IVChart, component: IComponent, actionSpec: IAction) { + if (component.type === 'label') { + this.labelComponentAppear(vchart, component, actionSpec); + } else if (component.specKey === 'legends') { + this.legendsComponentAppear(vchart, component, actionSpec); + } + } + + protected labelComponentAppear(vchart: IVChart, component: IComponent, actionSpec: IAction) { + const vrenderComponents = component.getVRenderComponents(); + vrenderComponents.forEach(group => { + return; + }); + } + protected legendsComponentAppear(vchart: IVChart, component: IComponent, actionSpec: IAction) { + const vrenderComponents = component.getVRenderComponents(); + + vrenderComponents.forEach(group => { + const appearTransformFunc = (transformMap.appear as any).legends; + const { payload } = actionSpec; + const mergePayload = merge( + {}, + (VChartAppearActionProcessor as any).legendsPayload || {}, + payload + ) as IChartAppearAction['payload']; + appearTransformFunc(group, mergePayload.animation, { + disappear: false + }); + }); + } + + protected seriesTypeToMarkType(seriesType: string) { + if (seriesType === 'bar') { + return 'rect'; + } + return seriesType; + } + + protected commonSeriesAppear(vchart: IVChart, series: ISeries, actionSpec: IAction) { + const marks = series.getMarksWithoutRoot(); + if (!marks.length) { + return; + } + const { payload } = actionSpec; + marks.forEach((mark, markIndex) => { + const mergePayload = merge( + {}, + (VChartAppearActionProcessor as any)[`${mark.type}Payload`] || {}, + payload + ) as IChartAppearAction['payload']; + const product = mark.getProduct(); + const appearTransform = (transformMap.appear as any)[mark.type]; + const config = + appearTransform && + appearTransform(vchart as any, mergePayload.animation, { + index: markIndex, + disappear: false + }); + // @ts-ignore + product && product.animate.run(config || {}); + }); + } + + static rectPayload: IChartAppearAction['payload'] = { + animation: { + effect: 'grow', + duration: 2000, + easing: 'cubicOut', + oneByOne: false, + loop: false + } + }; + static linePayload: IChartAppearAction['payload'] = VChartAppearActionProcessor.rectPayload; + static symbolPayload: IChartAppearAction['payload'] = VChartAppearActionProcessor.rectPayload; + static textPayload: IChartAppearAction['payload'] = VChartAppearActionProcessor.rectPayload; + static legendsPayload: IChartAppearAction['payload'] = VChartAppearActionProcessor.rectPayload; +} diff --git a/packages/vstory/src/player/processor/interface/action-processor.ts b/packages/vstory/src/player/processor/interface/action-processor.ts new file mode 100644 index 00000000..70e92be0 --- /dev/null +++ b/packages/vstory/src/player/processor/interface/action-processor.ts @@ -0,0 +1,22 @@ +import type { ICharacter } from '../../../story/character'; +import type { IAction } from '../../../story/interface'; + +export interface IActionProcessorItem { + getStartTime: (action: IAction) => number; + getDuration: (action: IAction) => number; + getStartTimeAndDuration: (action: IAction) => { startTime: number; duration: number }; + + run: (...actionParams: any) => any; +} + +export interface IActionProcessor { + getActInfo: ( + characterId: string, + action: IAction + ) => { + startTime: number; + duration: number; + } | null; + + doAction: (name: string, actionName: string, character: ICharacter, actionSpec: IAction) => void; +} diff --git a/packages/vstory/src/player/processor/interface/appear-action.ts b/packages/vstory/src/player/processor/interface/appear-action.ts new file mode 100644 index 00000000..c756a1f0 --- /dev/null +++ b/packages/vstory/src/player/processor/interface/appear-action.ts @@ -0,0 +1,36 @@ +import type { EasingType } from '@visactor/vrender'; + +export interface IAction { + action: string; + payload: Record; +} + +export interface IAnimationParams { + duration: number; + easing?: EasingType; + loop?: number | boolean; +} + +export interface IActionPayload { + animation?: IAnimationParams; +} + +export interface IChartAppearPayLoad extends IActionPayload { + animation: IAnimationParams & { + oneByOne: boolean; + /** + * 柱状图支持: 'grow' | 'fade' | 'bounce' + * 折线图支持: 'grow' | 'fade' + * 饼图支持: 'grow' | 'fade' | 'growAngle' | 'growRadius' + */ + effect: string; + }; + fade?: { isBaseOpacity?: boolean }; +} + +export interface IChartAppearAction extends IAction { + action: 'appear'; + payload: IChartAppearPayLoad; +} + +export type AppearOption = Omit; diff --git a/packages/vstory/src/player/processor/processor-item.ts b/packages/vstory/src/player/processor/processor-item.ts new file mode 100644 index 00000000..c5b26a3e --- /dev/null +++ b/packages/vstory/src/player/processor/processor-item.ts @@ -0,0 +1,23 @@ +import type { ICharacter } from '../../story/character'; +import type { IAction } from '../../story/interface'; +import type { IActionProcessorItem } from './interface/action-processor'; + +export class ActionProcessorItem implements IActionProcessorItem { + getStartTime(action: IAction): number { + return this.getStartTimeAndDuration(action).startTime; + } + getDuration(action: IAction): number { + return this.getStartTimeAndDuration(action).duration; + } + + getStartTimeAndDuration(action: IAction): { startTime: number; duration: number } { + return { + startTime: 0, + duration: 0 + }; + } + + run(character: ICharacter, actionSpec: IAction): void { + return; + } +} diff --git a/packages/vstory/src/player/processor/processor.ts b/packages/vstory/src/player/processor/processor.ts new file mode 100644 index 00000000..c0aace5d --- /dev/null +++ b/packages/vstory/src/player/processor/processor.ts @@ -0,0 +1,121 @@ +import type { ICharacter } from '../../story/character'; +import type { IAction, IStory } from '../../story/interface'; +import { IActionsLink } from '../../story/interface'; +import { logger } from '../../util/output'; +import type { IActionProcessor, IActionProcessorItem } from './interface/action-processor'; + +export type IProcessorMap = Record>; + +export interface IProcessorReturnType { + totalTime: number; + revertActionParams?: { + action: string; + payload: Record; + }; +} + +export class ActionProcessor implements IActionProcessor { + protected _processorMap: Map>; + + private static _instance: ActionProcessor = null; + protected _story: IStory; + + constructor(story: IStory, processorMap?: IProcessorMap) { + if (!ActionProcessor._instance) { + this.init(story, processorMap); + ActionProcessor._instance = this; + } + return ActionProcessor._instance; + } + + protected init(story: IStory, processorMap?: IProcessorMap) { + this._processorMap = new Map(); + if (processorMap) { + for (const key in processorMap) { + logger('info', `register ${key} processor.`); // TODO: remove log + this.registerProcessor(key, processorMap[key]); + } + } + this._story = story; + } + + /** + * 添加Action,根据Action中的characterId添加对应的characterActions实例 + * @param action + */ + getActInfo( + characterId: string, + action: IAction + ): { + startTime: number; + duration: number; + } | null { + const character = this._story.getCharactersById(characterId); + if (!character) { + logger('error', `获取character失败,请检查 ${characterId} 是否绑定到一个合法的character`); + return null; + } + + const processor = this.getProcessor(character.spec.type, action.action); + + return processor.getStartTimeAndDuration(action); + + // characterActions.forEach(action => { + // const processor = this.getProcessor(character.spec.type, action.action); + // }); + } + + /** + * + * @param name 操作对象名称 + * @param processors 操作对象支持的 processor + * @returns boolean 注册是否成功 + */ + registerProcessor(name: string, processors: Record) { + if (!this._processorMap) { + return false; + } + // 重复注册,目前直接替代 + this._processorMap.set(name, processors); + return true; + } + + getProcessorList(name: string) { + return this._processorMap && this._processorMap.get(name); + } + + getProcessor(name: string, actionName: string) { + return this._processorMap && this._processorMap.get(name)?.[actionName]; + } + + /** + * Execute action + * @param name + * @param actionName + * @param actionParams + * @returns IProcessorReturnType + */ + doAction(name: string, actionName: string, character: ICharacter, actionSpec: IAction): void { + const processor = this.getProcessor(name, actionName); + if (processor) { + // eslint-disable-next-line no-console + logger('info', `Execute action => ${actionName}, character => ${name}`); // TODO: remove log + const actionResult = processor.run(character, actionSpec); + // eslint-disable-next-line no-console + logger('info', `Action Executed:`, actionResult); // TODO: remove log + return actionResult; + } + // eslint-disable-next-line no-console + logger('error', `Action not found: character => ${name}, action => ${actionName} `); // TODO: remove log + return undefined; + } + + release() { + ActionProcessor._instance = null; + + if (this._processorMap) { + this._processorMap.clear(); + this._processorMap = null; + } + } +} diff --git a/packages/vstory/src/player/processor/processorMap.ts b/packages/vstory/src/player/processor/processorMap.ts new file mode 100644 index 00000000..d72822f6 --- /dev/null +++ b/packages/vstory/src/player/processor/processorMap.ts @@ -0,0 +1,13 @@ +import { ACTION_TYPE } from '../../constants/action'; +import { StoryChartType } from '../../constants/character'; +import { VChartAppearActionProcessor } from './chart/vchart'; + +export const processorChartMap = { + [StoryChartType.VCHART]: { + [ACTION_TYPE.APPEAR]: new VChartAppearActionProcessor() + } +}; + +export const processorMap = { + ...processorChartMap +}; diff --git a/packages/vstory/src/player/scheduler.ts b/packages/vstory/src/player/scheduler.ts new file mode 100644 index 00000000..a5f19192 --- /dev/null +++ b/packages/vstory/src/player/scheduler.ts @@ -0,0 +1,179 @@ +import { isNumber } from '@visactor/vutils'; +import type { IAction, IActSpec, ISceneSpec } from '../story/interface'; +import { IStory } from '../story/interface'; +import type { IActionProcessor } from './processor/interface/action-processor'; +import type { IScheduler } from './interface/scheduler'; + +interface IActInfo { + startTime: number; + duration: number; + id: string; + sceneInfoList: ISceneInfo[]; +} +interface ISceneInfo { + startTime: number; + duration: number; + id: string; + actionList: IActionItem[]; +} + +export interface IActionItem { + startTime: number; + duration: number; + actionSpec: IAction; + characterId: string; +} + +class ActionItem implements IActionItem { + startTime: number; + duration: number; + actionSpec: IAction; + characterId: string; + + constructor(st: number, d: number, as: IAction, ci: string) { + this.startTime = st; + this.duration = d; + this.actionSpec = as; + this.characterId = ci; + } +} + +export class Scheduler implements IScheduler { + protected _actionProcessor: IActionProcessor; + protected _actsInfo: IActInfo[]; + + constructor(actionProcessor: IActionProcessor) { + this._actionProcessor = actionProcessor; + } + + // static formatTimeInAction(time: number, action: IActInfo): number { + // const { duration } = action; + // if (time < startTime) { + // return time; + // } + // if (startTime + duration <= 0) { + // return time; + // } + // while (time > startTime + duration) { + // time -= startTime + duration; + // } + // return time; + // } + + findActByTime(t: number) { + // 规范化t + const totalTime = this._actsInfo.reduce((t, actInfo) => Math.max(t, actInfo.startTime + actInfo.duration), 0); + if (totalTime <= 0) { + return { + actInfo: this._actsInfo[0], + t: 0 + }; + } + while (t > totalTime) { + t -= totalTime; + } + for (let i = 0; i < this._actsInfo.length; i++) { + const actInfo = this._actsInfo[i]; + if (actInfo.startTime <= t && actInfo.startTime + actInfo.duration > t) { + return { + actInfo: actInfo, + t: t - actInfo.startTime + }; + } + } + return { + actInfo: this._actsInfo[this._actsInfo.length - 1], + t: t - this._actsInfo[this._actsInfo.length - 1].startTime + }; + } + + /** + * 获取某个时间区间的所有Action,toTime实际上是当前时间,fromTime是上一次的时间 + * 避免跳帧 + * @param fromTime 上一次的时间 + * @param toTime 当前时间 + */ + getActionsInRange(fromTime: number, toTime: number) { + // 先找到目前是在哪个幕中 + const { actInfo: fromAct, t: formatFromTime } = this.findActByTime(fromTime); + const { actInfo: toAct, t: formatToTime } = this.findActByTime(toTime); + if (fromAct !== toAct) { + // TODO 跳帧了 + } + // const formatFromTime = Scheduler.formatTimeInAction(fromTime, toAct); + // const formatToTime = Scheduler.formatTimeInAction(toTime, toAct); + + const actions: IActionItem[] = []; + toAct.sceneInfoList.forEach(sceneInfo => { + const { startTime: sceneStartTime } = sceneInfo; + sceneInfo.actionList.forEach(actionInfo => { + const startTime = sceneStartTime + actionInfo.startTime; + if (startTime >= formatFromTime && startTime < formatToTime) { + actions.push(actionInfo); + } + }); + }); + + return actions; + } + + initActs(acts: IActSpec[]) { + // act与act之间是串联的 + let startTime = 0; + this._actsInfo = acts.map(act => { + const actInfo = this._getActInfo(act, startTime); + startTime += actInfo.duration; + return actInfo; + }); + } + + protected _getActInfo(act: IActSpec, actStartTime: number): IActInfo { + let sceneStartTime = 0; + const sceneInfoList = act.scenes.map(scene => { + const sceneInfo = this._getSceneInfo(scene, sceneStartTime); + sceneStartTime = sceneInfo.startTime + (scene.delay ?? 0) + sceneInfo.duration; + return sceneInfo; + }); + const startTime = sceneInfoList.reduce((st, info) => Math.min(info.startTime, st), 0); + const endTime = sceneInfoList.reduce((et, info) => Math.max(info.startTime + info.duration, et), 0); + return { + startTime: actStartTime, + duration: startTime + endTime - startTime, + id: act.id, + sceneInfoList + }; + } + + protected _getSceneInfo(scene: ISceneSpec, sceneStartTime: number): ISceneInfo { + let scene_st = 0; + let scene_et = 0; + const actionList: IActionItem[] = []; + scene.actions.forEach((action, actIdx) => { + let character_st = Infinity; + let character_et = -Infinity; + action.characterActions.forEach(ca => { + const info = this._actionProcessor.getActInfo(action.characterId, ca); + if (!info) { + return; + } + const item = new ActionItem(info.startTime, info.duration, ca, action.characterId); + + character_st = Math.max(Math.min(item.startTime, character_st), 0); + character_et = Math.max(item.startTime + item.duration, character_et); + actionList.push(item); + }); + + scene_st = !actIdx ? character_st : Math.max(Math.min(character_st, scene_st), 0); + scene_et = !actIdx ? character_et : Math.max(character_et, scene_et); + }); + + const sceneInfo: ISceneInfo = { + startTime: sceneStartTime + scene_st, + duration: sceneStartTime + scene_et - scene_st, + id: scene.id, + actionList + }; + + return sceneInfo; + } +} diff --git a/packages/vstory/src/dsl/story-chart/component/title.ts b/packages/vstory/src/player/ticker.ts similarity index 100% rename from packages/vstory/src/dsl/story-chart/component/title.ts rename to packages/vstory/src/player/ticker.ts diff --git a/packages/vstory/src/scene/action.ts b/packages/vstory/src/scene/action.ts index 5bf0c6d8..a2a06d4e 100644 --- a/packages/vstory/src/scene/action.ts +++ b/packages/vstory/src/scene/action.ts @@ -1,67 +1,67 @@ -import { IContext } from '../interface/type'; -import { AbstractTask, TaskCb } from '../task'; +// import { IContext } from '../interface/type'; +// import { AbstractTask, TaskCb } from '../task'; -export class Action extends AbstractTask { - type = 'action'; +// export class Action extends AbstractTask { +// type = 'action'; - protected _entity: any; - protected _action: (entity: any, context?: Partial) => void; +// protected _entity: any; +// protected _action: (entity: any, context?: Partial) => void; - protected _isResolved = false; +// protected _isResolved = false; - constructor(entity: any, add: (entity: any, context?: Partial) => void) { - super(); - this._entity = entity; - this._action = add; - } +// constructor(entity: any, add: (entity: any, context?: Partial) => void) { +// super(); +// this._entity = entity; +// this._action = add; +// } - run(context?: Partial) { - if (this._entity && this._action) { - this._action(this._entity, context); - this._isResolved = true; - } - } +// run(context?: Partial) { +// if (this._entity && this._action) { +// this._action(this._entity, context); +// this._isResolved = true; +// } +// } - runCb(cb: TaskCb): void { - const intervalId = setInterval(() => { - if (this._isResolved) { - clearInterval(intervalId); - cb(); - } - }); - } -} +// runCb(cb: TaskCb): void { +// const intervalId = setInterval(() => { +// if (this._isResolved) { +// clearInterval(intervalId); +// cb(); +// } +// }); +// } +// } -export class Wait extends AbstractTask { - type = 'wait'; +// export class Wait extends AbstractTask { +// type = 'wait'; - protected _duration: number; +// protected _duration: number; - protected _waiting = true; - protected _playing = false; +// protected _waiting = true; +// protected _playing = false; - constructor(duration: number) { - super(); - this._duration = duration; - } +// constructor(duration: number) { +// super(); +// this._duration = duration; +// } - run() { - if (this._duration > 0 && !this._playing) { - new Promise(resolve => { - setTimeout(() => { - this._waiting = false; - }, this._duration); - }); - this._playing = true; - } - } +// run() { +// if (this._duration > 0 && !this._playing) { +// new Promise(resolve => { +// setTimeout(() => { +// this._waiting = false; +// }, this._duration); +// }); +// this._playing = true; +// } +// } - runCb(cb: TaskCb): void { - const intervalId = setInterval(() => { - if (!this._waiting) { - clearInterval(intervalId); - cb(); - } - }); - } -} +// runCb(cb: TaskCb): void { +// const intervalId = setInterval(() => { +// if (!this._waiting) { +// clearInterval(intervalId); +// cb(); +// } +// }); +// } +// } diff --git a/packages/vstory/src/scene/index.ts b/packages/vstory/src/scene/index.ts index 15df9a6f..ab04424a 100644 --- a/packages/vstory/src/scene/index.ts +++ b/packages/vstory/src/scene/index.ts @@ -1 +1 @@ -export * from './scene'; +// export * from './scene'; diff --git a/packages/vstory/src/scene/scene.ts b/packages/vstory/src/scene/scene.ts index 56537984..de0c6e66 100644 --- a/packages/vstory/src/scene/scene.ts +++ b/packages/vstory/src/scene/scene.ts @@ -1,132 +1,132 @@ -import type { IContext } from 'src/interface/type'; -import { Template } from '../template/base-template'; -import type { INode, IStage } from '@visactor/vrender'; -import { container, createStage, preLoadAllModule, loadBrowserEnv } from '@visactor/vrender'; -import { calculateSize } from '../util/size'; -import { CreateUID } from '../util/common'; -import { AbstractComponent } from '@visactor/vrender-components'; -import type { ITask } from '../task'; -import { TaskManager } from '../task'; -import { Action, Wait } from './action'; - -export class Scene { - readonly id = CreateUID(); - - protected template: Template; - - protected _stage: IStage; - - protected _container: HTMLElement; - - protected _canvas: HTMLCanvasElement; - - protected _context: IContext; - - private _taskManager = new TaskManager(); - - constructor(options: any = {}) { - const { dom, width, height } = options; - if (document) { - this._container = document.getElementById(dom) as HTMLCanvasElement; - } - if (!this._container) { - throw Error('Container Not Found'); - } - - const { width: _width, height: _height } = calculateSize(this._container, { width, height }); - - const canvas = document.createElement('canvas'); - canvas.width = _width * window.devicePixelRatio; - canvas.height = _height * window.devicePixelRatio; - canvas.style.width = _width + 'px'; - canvas.style.height = _height + 'px'; - - canvas.id = `_story_chart_${this.id}_canvas`; - this._canvas = canvas; - this._container.append(canvas); - - const stage = this._initStage(_width, _height); - this._stage = stage; - - this._context = { - dom: this._container, - canvas: this._canvas, - width: _width, - height: _height, - stage - }; - this._taskManager.setContext(this._context); - } - - protected _initStage(width: number, height: number) { - preLoadAllModule(); - loadBrowserEnv(container); - const params = { - width: width, - height: height, - disableDirtyBounds: true, - autoRender: true, - canvas: this._canvas, - canvasControled: true, - dpr: window.devicePixelRatio - }; - return createStage(params) as unknown as IStage; - } - - add(entity: Template | AbstractComponent) { - let task: ITask; - if (entity instanceof Template) { - this.template = entity; - task = new Action(entity, (entity: any) => { - entity.render(this._context); - }); - } else if (entity instanceof AbstractComponent && this._stage) { - task = new Action(entity, (entity: any) => { - this._stage.defaultLayer.add(entity as unknown as INode); - }); - } - - if (task) { - this._taskManager.next(task); - } - - return this; - } - - remove(entity: Template | AbstractComponent) { - let task: ITask; - if (entity instanceof Template) { - this.template = entity; - task = new Action(entity, (entity: any) => { - entity.release(); - }); - } else if (entity instanceof AbstractComponent && this._stage) { - task = new Action(entity, (entity: any) => { - this._stage.defaultLayer.removeChild(entity as unknown as INode); - }); - } - - if (task) { - this._taskManager.next(task); - } - - return this; - } - - wait(duration: number) { - if (duration > 0) { - const wait = new Wait(duration); - this._taskManager.next(wait); - } - } - - play(animate: ITask) { - if (animate) { - this._taskManager.next(animate); - } - } - - release() { - return; - } -} +// import type { IContext } from 'src/interface/type'; +// import { Template } from '../template/base-template'; +// import type { INode, IStage } from '@visactor/vrender'; +// import { container, createStage, preLoadAllModule, loadBrowserEnv } from '@visactor/vrender'; +// import { calculateSize } from '../util/size'; +// import { CreateUID } from '../util/common'; +// import { AbstractComponent } from '@visactor/vrender-components'; +// import type { ITask } from '../task'; +// import { TaskManager } from '../task'; +// import { Action, Wait } from './action'; + +// export class Scene { +// readonly id = CreateUID(); + +// protected template: Template; + +// protected _stage: IStage; + +// protected _container: HTMLElement; + +// protected _canvas: HTMLCanvasElement; + +// protected _context: IContext; + +// private _taskManager = new TaskManager(); + +// constructor(options: any = {}) { +// const { dom, width, height } = options; +// if (document) { +// this._container = document.getElementById(dom) as HTMLCanvasElement; +// } +// if (!this._container) { +// throw Error('Container Not Found'); +// } + +// const { width: _width, height: _height } = calculateSize(this._container, { width, height }); + +// const canvas = document.createElement('canvas'); +// canvas.width = _width * window.devicePixelRatio; +// canvas.height = _height * window.devicePixelRatio; +// canvas.style.width = _width + 'px'; +// canvas.style.height = _height + 'px'; + +// canvas.id = `_story_chart_${this.id}_canvas`; +// this._canvas = canvas; +// this._container.append(canvas); + +// const stage = this._initStage(_width, _height); +// this._stage = stage; + +// this._context = { +// dom: this._container, +// canvas: this._canvas, +// width: _width, +// height: _height, +// stage +// }; +// this._taskManager.setContext(this._context); +// } + +// protected _initStage(width: number, height: number) { +// preLoadAllModule(); +// loadBrowserEnv(container); +// const params = { +// width: width, +// height: height, +// disableDirtyBounds: true, +// autoRender: true, +// canvas: this._canvas, +// canvasControled: true, +// dpr: window.devicePixelRatio +// }; +// return createStage(params) as unknown as IStage; +// } + +// add(entity: Template | AbstractComponent) { +// let task: ITask; +// if (entity instanceof Template) { +// this.template = entity; +// task = new Action(entity, (entity: any) => { +// entity.render(this._context); +// }); +// } else if (entity instanceof AbstractComponent && this._stage) { +// task = new Action(entity, (entity: any) => { +// this._stage.defaultLayer.add(entity as unknown as INode); +// }); +// } + +// if (task) { +// this._taskManager.next(task); +// } + +// return this; +// } + +// remove(entity: Template | AbstractComponent) { +// let task: ITask; +// if (entity instanceof Template) { +// this.template = entity; +// task = new Action(entity, (entity: any) => { +// entity.release(); +// }); +// } else if (entity instanceof AbstractComponent && this._stage) { +// task = new Action(entity, (entity: any) => { +// this._stage.defaultLayer.removeChild(entity as unknown as INode); +// }); +// } + +// if (task) { +// this._taskManager.next(task); +// } + +// return this; +// } + +// wait(duration: number) { +// if (duration > 0) { +// const wait = new Wait(duration); +// this._taskManager.next(wait); +// } +// } + +// play(animate: ITask) { +// if (animate) { +// this._taskManager.next(animate); +// } +// } + +// release() { +// return; +// } +// } diff --git a/packages/vstory/src/story/act/act.ts b/packages/vstory/src/story/act/act.ts deleted file mode 100644 index de3b214d..00000000 --- a/packages/vstory/src/story/act/act.ts +++ /dev/null @@ -1,3 +0,0 @@ -export class Chapter { - // 也许并不需要 -} diff --git a/packages/vstory/src/story/canvas/canvas.ts b/packages/vstory/src/story/canvas/canvas.ts index 6c2c77c9..a1bf0e1a 100644 --- a/packages/vstory/src/story/canvas/canvas.ts +++ b/packages/vstory/src/story/canvas/canvas.ts @@ -2,14 +2,14 @@ import type { Story } from '../story'; import type { IStage } from '@visactor/vrender'; import { createStage, vglobal, container, preLoadAllModule, ManualTicker } from '@visactor/vrender'; import { loadBrowserEnv } from '@visactor/vrender'; -import type { StoryEvent } from '../interface/runtime-interface'; +import type { IStoryCanvas, StoryEvent } from '../interface/runtime-interface'; import type { ICharacter } from '../character/runtime-interface'; preLoadAllModule(); loadBrowserEnv(container); vglobal.setEnv('browser'); -export class StoryCanvas { +export class StoryCanvas implements IStoryCanvas { protected _story: Story; protected _canvas: HTMLCanvasElement; protected _stage: IStage; diff --git a/packages/vstory/src/story/character-tree/character-tree.ts b/packages/vstory/src/story/character-tree/character-tree.ts new file mode 100644 index 00000000..4ea8bf73 --- /dev/null +++ b/packages/vstory/src/story/character-tree/character-tree.ts @@ -0,0 +1,52 @@ +import type { ICharacter, ICharacterSpec } from '../character'; +import { StoryFactory } from '../factory/factory'; +import type { ICharacterTree, IStory } from '../interface'; + +export class CharacterTree implements ICharacterTree { + protected _characters: { [key: string]: ICharacter } = {}; + protected _story: IStory; + + constructor(story: IStory) { + this._story = story; + } + + getCharacters(): { [key: string]: ICharacter } { + return this._characters; + } + + getCharactersById(key: string) { + return this._characters[key] || null; + } + + addCharacter(spec: ICharacterSpec) { + const option = { + story: this._story, + canvas: this._story.canvas, + graphicParent: this._story.canvas.getStage().defaultLayer + }; + if ((spec).id) { + if (!this._characters[(spec).id]) { + this._characters[(spec).id] = StoryFactory.createCharacter(spec, option); + } + return this._characters[(spec).id]; + } + return null; + } + + initCharacters(specs: ICharacterSpec[]): void { + const option = { + story: this._story, + canvas: this._story.canvas, + graphicParent: this._story.canvas.getStage().defaultLayer + }; + + specs.forEach(spec => { + if ((spec).id) { + if (!this._characters[(spec).id]) { + this._characters[(spec).id] = StoryFactory.createCharacter(spec, option); + } + return this._characters[(spec).id]; + } + }); + } +} diff --git a/packages/vstory/src/story/character/chart/character.ts b/packages/vstory/src/story/character/chart/character.ts index 0bf55ad2..8d16dfc3 100644 --- a/packages/vstory/src/story/character/chart/character.ts +++ b/packages/vstory/src/story/character/chart/character.ts @@ -15,25 +15,6 @@ import { SeriesSpecRuntime } from './runtime/series-spec'; import type { StoryEvent } from '../../interface/runtime-interface'; import type { ICharacterPickInfo } from '../runtime-interface'; -const tempSpec = { - type: 'bar', - data: [ - { - id: 'barData', - values: [ - { month: 'Monday', sales: 22 }, - { month: 'Tuesday', sales: 13 }, - { month: 'Wednesday', sales: 25 }, - { month: 'Thursday', sales: 29 }, - { month: 'Friday', sales: 38 } - ] - } - ], - xField: 'month', - yField: 'sales', - axes: [{ orient: 'bottom', label: { visible: false } }] -}; - export class CharacterChart extends CharacterVisactor { static type = 'CharacterChart'; static RunTime: IChartCharacterRuntimeConstructor[] = [ @@ -72,7 +53,7 @@ export class CharacterChart extends CharacterVisactor { y1: layout.y, y2: layout.y + layout.height }; - const spec = cloneDeep(this._specProcess.getVisSpec() ?? this._spec.options.spec); + const spec = cloneDeep(this._specProcess.getVisSpec()); spec.width = layout.width; spec.height = layout.height; // @ts-ignore diff --git a/packages/vstory/src/story/character/chart/characters/area.ts b/packages/vstory/src/story/character/chart/characters/area.ts deleted file mode 100644 index a1c2d441..00000000 --- a/packages/vstory/src/story/character/chart/characters/area.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { AreaTemp } from '../temp/templates/area'; - -StoryFactory.registerChartTemp(AreaTemp.type, AreaTemp); - -export class AreaChartCharacter extends CharacterChart { - static type = 'AreaChart'; -} diff --git a/packages/vstory/src/story/character/chart/characters/bar.ts b/packages/vstory/src/story/character/chart/characters/bar.ts deleted file mode 100644 index 124b9ab5..00000000 --- a/packages/vstory/src/story/character/chart/characters/bar.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { BarTemp } from '../temp/templates/bar'; - -StoryFactory.registerChartTemp(BarTemp.type, BarTemp); - -export class BarChartCharacter extends CharacterChart { - static type = 'BarChart'; -} diff --git a/packages/vstory/src/story/character/chart/characters/line.ts b/packages/vstory/src/story/character/chart/characters/line.ts deleted file mode 100644 index 809357f1..00000000 --- a/packages/vstory/src/story/character/chart/characters/line.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { LineTemp } from '../temp/templates/line'; - -StoryFactory.registerChartTemp(LineTemp.type, LineTemp); - -export class LineChartCharacter extends CharacterChart { - static type = 'LineChart'; -} diff --git a/packages/vstory/src/story/character/chart/characters/pie.ts b/packages/vstory/src/story/character/chart/characters/pie.ts deleted file mode 100644 index 6ce0d72e..00000000 --- a/packages/vstory/src/story/character/chart/characters/pie.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { PieTemp } from '../temp/templates/pie'; - -StoryFactory.registerChartTemp(PieTemp.type, PieTemp); - -export class PieChartCharacter extends CharacterChart { - static type = 'PieChart'; -} diff --git a/packages/vstory/src/story/character/chart/characters/radar.ts b/packages/vstory/src/story/character/chart/characters/radar.ts deleted file mode 100644 index 0c970b9b..00000000 --- a/packages/vstory/src/story/character/chart/characters/radar.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { RadarTemp } from '../temp/templates/radar'; - -StoryFactory.registerChartTemp(RadarTemp.type, RadarTemp); - -export class RadarChartCharacter extends CharacterChart { - static type = 'RadarChart'; -} diff --git a/packages/vstory/src/story/character/chart/characters/rangeColumn.ts b/packages/vstory/src/story/character/chart/characters/rangeColumn.ts deleted file mode 100644 index 977bb17e..00000000 --- a/packages/vstory/src/story/character/chart/characters/rangeColumn.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { RangeColumnTemp } from '../temp/templates/rangeColumn'; - -StoryFactory.registerChartTemp(RangeColumnTemp.type, RangeColumnTemp); - -export class RangeColumnChartCharacter extends CharacterChart { - static type = 'RangeColumnChart'; -} diff --git a/packages/vstory/src/story/character/chart/characters/rose.ts b/packages/vstory/src/story/character/chart/characters/rose.ts deleted file mode 100644 index de0009c4..00000000 --- a/packages/vstory/src/story/character/chart/characters/rose.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { RoseTemp } from '../temp/templates/rose'; - -StoryFactory.registerChartTemp(RoseTemp.type, RoseTemp); - -export class RoseChartCharacter extends CharacterChart { - static type = 'RoseChart'; -} diff --git a/packages/vstory/src/story/character/chart/characters/scatter.ts b/packages/vstory/src/story/character/chart/characters/scatter.ts deleted file mode 100644 index 4e4104a0..00000000 --- a/packages/vstory/src/story/character/chart/characters/scatter.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { ScatterTemp } from '../temp/templates/scatter'; - -StoryFactory.registerChartTemp(ScatterTemp.type, ScatterTemp); - -export class ScatterChartCharacter extends CharacterChart { - static type = 'ScatterChart'; -} diff --git a/packages/vstory/src/story/character/chart/characters/sunburst.ts b/packages/vstory/src/story/character/chart/characters/sunburst.ts deleted file mode 100644 index 56b2e046..00000000 --- a/packages/vstory/src/story/character/chart/characters/sunburst.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { SunburstTemp } from '../temp/templates/sunburst'; - -StoryFactory.registerChartTemp(SunburstTemp.type, SunburstTemp); - -export class SunburstChartCharacter extends CharacterChart { - static type = 'SunburstChart'; -} diff --git a/packages/vstory/src/story/character/chart/characters/treemap.ts b/packages/vstory/src/story/character/chart/characters/treemap.ts deleted file mode 100644 index fedd08e4..00000000 --- a/packages/vstory/src/story/character/chart/characters/treemap.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { TreeMapTemp } from '../temp/templates/treemap'; - -StoryFactory.registerChartTemp(TreeMapTemp.type, TreeMapTemp); - -export class TreeMapChartCharacter extends CharacterChart { - static type = 'TreeMapChart'; -} diff --git a/packages/vstory/src/story/character/chart/characters/vchart.ts b/packages/vstory/src/story/character/chart/characters/vchart.ts new file mode 100644 index 00000000..9e2ddb72 --- /dev/null +++ b/packages/vstory/src/story/character/chart/characters/vchart.ts @@ -0,0 +1,9 @@ +import { StoryFactory } from '../../../factory/factory'; +import { CharacterChart } from '../character'; +import { VChartTemp } from '../temp/templates/vchart-temp'; + +StoryFactory.registerChartTemp(VChartTemp.type, VChartTemp); + +export class VChartCharacter extends CharacterChart { + static type = 'VChart'; +} diff --git a/packages/vstory/src/story/character/chart/characters/wordcloud.ts b/packages/vstory/src/story/character/chart/characters/wordcloud.ts deleted file mode 100644 index d4a45130..00000000 --- a/packages/vstory/src/story/character/chart/characters/wordcloud.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { StoryFactory } from '../../../factory/factory'; -import { CharacterChart } from '../character'; -import { WordCloudTemp } from '../temp/templates/wordcloud'; - -StoryFactory.registerChartTemp(WordCloudTemp.type, WordCloudTemp); - -export class WordCloudCharacter extends CharacterChart { - static type = 'WordCloudChart'; -} diff --git a/packages/vstory/src/story/character/chart/graphic/vchart-graphic.ts b/packages/vstory/src/story/character/chart/graphic/vchart-graphic.ts index 7908cd78..b3aaa957 100644 --- a/packages/vstory/src/story/character/chart/graphic/vchart-graphic.ts +++ b/packages/vstory/src/story/character/chart/graphic/vchart-graphic.ts @@ -52,7 +52,7 @@ export class Chart extends Group implements IVisactorGraphic { // viewBox: params.vi dpr: params.dpr, interactive: params.interactive, - animation: params.animation, + animation: false, autoFit: false, disableTriggerEvent: params.disableTriggerEvent, disableDirtyBounds: params.disableDirtyBounds, diff --git a/packages/vstory/src/story/character/chart/runtime/series-spec.ts b/packages/vstory/src/story/character/chart/runtime/series-spec.ts index 51ad9721..42fefd09 100644 --- a/packages/vstory/src/story/character/chart/runtime/series-spec.ts +++ b/packages/vstory/src/story/character/chart/runtime/series-spec.ts @@ -23,7 +23,7 @@ export class SeriesSpecRuntime implements IChartCharacterRuntime { merge(rawSpec, options.seriesSpec[0].spec); return; } - options.seriesSpec.forEach(seriesSpec => { + options.seriesSpec?.forEach(seriesSpec => { if (!rawSpec.series) { rawSpec.series = [{ ...seriesSpec.spec }]; return; diff --git a/packages/vstory/src/story/character/chart/temp/constant.ts b/packages/vstory/src/story/character/chart/temp/constant.ts index dcd9dd4c..f606975c 100644 --- a/packages/vstory/src/story/character/chart/temp/constant.ts +++ b/packages/vstory/src/story/character/chart/temp/constant.ts @@ -1,15 +1,5 @@ -import { StoryChartType } from '../../../../dsl/constant'; +import { StoryChartType } from '../../../../constants/character'; export const TemplateChartType = { - bar: StoryChartType.BAR, - area: StoryChartType.AREA, - line: StoryChartType.LINE, - pie: StoryChartType.PIE, - scatter: StoryChartType.SCATTER, - rangeColumn: StoryChartType.RANGE_COLUMN, - rose: StoryChartType.ROSE, - radar: StoryChartType.RADAR, - wordcloud: StoryChartType.WORD_CLOUD, - treemap: StoryChartType.TREE_MAP, - sunburst: StoryChartType.SUNBURST + vchart: StoryChartType.VCHART }; diff --git a/packages/vstory/src/story/character/chart/temp/templates/area.ts b/packages/vstory/src/story/character/chart/temp/templates/area.ts deleted file mode 100644 index afc24799..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/area.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { TemplateChartType } from '../constant'; -import { CartesianSingleSeriesTemp } from './cartesian-single'; - -export class AreaTemp extends CartesianSingleSeriesTemp { - static type: string = TemplateChartType.area; - type: string = AreaTemp.type; - // 唯一系列类型 - seriesType = 'area'; - // 是否消除维度轴的2测留白 - trimPadding = true; - - protected _getSeriesSpec() { - return { - type: 'area', - stack: true, - direction: this.direction, - line: { - style: { - lineCap: 'butt' - } - } - }; - } -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/bar.ts b/packages/vstory/src/story/character/chart/temp/templates/bar.ts deleted file mode 100644 index baba1420..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/bar.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { TemplateChartType } from '../constant'; -import { CartesianSingleSeriesTemp } from './cartesian-single'; - -export class BarTemp extends CartesianSingleSeriesTemp { - static type: string = TemplateChartType.bar; - type: string = BarTemp.type; - // 唯一系列类型 - seriesType = 'bar'; - // 默认是否展示总计标签 - defaultTotalLabel = true; - - protected _getSeriesSpec() { - return { - type: 'bar', - stack: true, - direction: this.direction - }; - } - - afterInitializeChart(): void { - // eslint-disable-next-line no-console - console.log('afterInitializeChart'); - } -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/cartesian-single.ts b/packages/vstory/src/story/character/chart/temp/templates/cartesian-single.ts deleted file mode 100644 index 1f6d8627..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/cartesian-single.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { IChartCharacterSpec } from '../../../dsl-interface'; -import { DirectionType } from '../../const'; -import type { StandardData } from '../../data/interface'; -import { BaseTemp } from './base-temp'; -import { getCartesianCommonSpec, getCartesianSpec } from './common'; - -export abstract class CartesianSingleSeriesTemp extends BaseTemp { - // 唯一系列类型 - seriesType: string; - direction: DirectionType = 'vertical'; - // 是否有维度轴分组 - multiDimensionField = false; - // 是否堆积 - stack = true; - // 是否默认有总计标签 - defaultTotalLabel = false; - // 是否是百分百图表 - percent = false; - // 是否消除维度轴的2测留白 - trimPadding = false; - // 是否默认展示图例 - defaultLegendVisible = false; - - constructor(characterSpec: IChartCharacterSpec) { - super(); - this.direction = characterSpec.options.direction ?? 'vertical'; - } - - checkDataEnable(data: StandardData, opt?: any): boolean { - return !!data; // CommonStandardDataCheck(data); - } - getSpec(data: StandardData, opt?: any) { - const cartesianCommonSpec = getCartesianCommonSpec(this.direction, this.percent, this.trimPadding) as any; - if (cartesianCommonSpec.legends) { - cartesianCommonSpec.legends.visible = this.defaultLegendVisible; - } - - return getCartesianSpec(this._getSeriesSpec.bind(this), cartesianCommonSpec, this.direction, data, { - multiDimensionField: this.multiDimensionField, - stack: this.stack, - xField: opt.character.specProcess.getCharacterSpec().options.xField, - yField: opt.character.specProcess.getCharacterSpec().options.yField, - seriesField: opt.character.specProcess.getCharacterSpec().options.seriesField - }); - } - - protected abstract _getSeriesSpec(): any; -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/common.ts b/packages/vstory/src/story/character/chart/temp/templates/common.ts index d4d321fe..933a2b13 100644 --- a/packages/vstory/src/story/character/chart/temp/templates/common.ts +++ b/packages/vstory/src/story/character/chart/temp/templates/common.ts @@ -1,162 +1,5 @@ -import type { IDataValue } from '../../data/interface'; import { array } from '@visactor/vutils'; import type { DataInfo, StandardData } from '../../data/interface'; -import { ChartDimensionField, ChartTypeField, ChartValueField } from '../../const'; - -export function getCommonSpec() { - return { - type: 'common', - series: [] as any[], - region: [ - { - id: 'region-0' - } - ] - }; -} - -export function getPolarCommonSpec() { - return { - ...getCommonSpec(), - axes: getPolarAxesSpec() - }; -} - -export function getPolarAxesSpec() { - return [ - { - orient: 'radius' - }, - { - orient: 'angle' - } - ]; -} - -export function getPolarSpec( - seriesSpec: () => any, - spec: any, - data: StandardData, - option: { - seriesField?: string; - categoryField: string; - valueField: string; - } -) { - spec.data = array(data); - spec.series = spec.data.map((d: IDataValue) => { - return fillPolarSeriesSpec(seriesSpec(), d, option); - }); - return spec; -} - -export function fillPolarSeriesSpec( - spec: any, - d: IDataValue, - option: { - seriesField?: string; - categoryField: string; - valueField: string; - } -) { - spec.dataId = d.id; - spec.id = `series-${d.id}`; - spec.seriesField = option.seriesField; - return spec; -} - -export function getCartesianCommonSpec(direction: 'horizontal' | 'vertical', percent = false, trimPadding = false) { - return { - direction, - ...getCommonSpec(), - axes: getCartesianAxesSpec(direction, percent, trimPadding) - }; -} - -export function getCartesianAxesSpec(direction: 'horizontal' | 'vertical', percent = false, trimPadding = false) { - return direction === 'vertical' - ? [ - { - orient: 'left', - id: 'axis-left', - type: 'linear', - autoIndent: false, - maxWidth: null as number, - maxHeight: null as number - }, - { - orient: 'bottom', - id: 'axis-bottom', - type: 'band', - autoIndent: false, - maxWidth: null as number, - maxHeight: null as number, - trimPadding, - paddingInner: [0.2, 0], - paddingOuter: [0.2, 0] - } - ] - : [ - { - orient: 'left', - id: 'axis-left', - type: 'band', - autoIndent: false, - maxWidth: null as number, - maxHeight: null as number, - trimPadding - }, - { - orient: 'bottom', - id: 'axis-bottom', - type: 'linear', - autoIndent: false, - maxWidth: null as number, - maxHeight: null as number - } - ]; -} - -export function getCartesianSpec( - seriesSpec: () => any, - spec: any, - direction: 'horizontal' | 'vertical', - data: StandardData, - option: { - multiDimensionField?: boolean; - stack?: boolean; - xField: string[] | string; - yField: string[] | string; - seriesField: string; - } -) { - spec.data = array(data); - spec.series = spec.data.map((d: IDataValue) => { - return fillCartesianSeriesSpec(seriesSpec(), direction, d, option); - }); - return spec; -} - -export function fillCartesianSeriesSpec( - spec: any, - direction: 'horizontal' | 'vertical', - d: IDataValue, - option: { - multiDimensionField?: boolean; - stack?: boolean; - xField: string[] | string; - yField: string[] | string; - seriesField: string; - } -) { - spec.xField = option.xField; - spec.yField = option.yField; - spec.dataId = d.id; - spec.id = `series-${d.id}`; - spec.seriesField = option.seriesField; - spec.stack = option.stack === true; - return spec; -} export function getDimensions(info: DataInfo) { const ordinalFields: string[] = []; @@ -178,19 +21,6 @@ export function getDimensions(info: DataInfo) { }; } -export function CommonStandardDataCheck(data: StandardData) { - data = array(data); - if (data.length === 0) { - return false; - } - // mvp 使用total data 不再使用totalData - // const totalData = data.find(d => d.sourceKey === 'total'); - // if (totalData && totalData.values.length === 0) { - // return false; - // } - return true; -} - export function getSeriesLabelSpec(direction: 'horizontal' | 'vertical', visible = true) { return { visible, diff --git a/packages/vstory/src/story/character/chart/temp/templates/line.ts b/packages/vstory/src/story/character/chart/temp/templates/line.ts deleted file mode 100644 index 33579027..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/line.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { TemplateChartType } from '../constant'; -import { CartesianSingleSeriesTemp } from './cartesian-single'; -import { getSeriesLabelSpec } from './common'; - -export class LineTemp extends CartesianSingleSeriesTemp { - static type: string = TemplateChartType.line; - type: string = LineTemp.type; - // 唯一系列类型 - seriesType = 'line'; - stack = false; - // 是否消除维度轴的2测留白 - trimPadding = true; - - protected _getSeriesSpec() { - return { - direction: this.direction, - type: 'line', - stack: false, - line: { - style: { - lineCap: 'butt' - } - }, - label: { - visible: true, - position: 'top', - style: { - lineHeight: '100%', - fontSize: 16, - fontWeight: 'bold' - }, - overlap: true, - smartInvert: true - }, - seriesLabel: getSeriesLabelSpec(this.direction) - }; - } -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/pie.ts b/packages/vstory/src/story/character/chart/temp/templates/pie.ts deleted file mode 100644 index baa7984b..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/pie.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { array } from '@visactor/vutils'; -import type { StandardData } from '../../data/interface'; -import type { DataInfo } from '../../data/interface'; -import { BaseTemp } from './base-temp'; -import { CommonStandardDataCheck, getCommonSpec } from './common'; -import { TemplateChartType } from '../constant'; -import { ChartDimensionField, ChartValueField } from '../../const'; - -export function spec() { - return { - type: 'pie' - }; -} - -export class PieTemp extends BaseTemp { - static type: string = TemplateChartType.pie; - type: string = PieTemp.type; - checkDataEnable(data: StandardData, opt?: any): boolean { - return CommonStandardDataCheck(data); - } - getSpec(data: StandardData, opt?: any) { - const tempSpec = getCommonSpec() as any; - tempSpec.series = [spec()]; - tempSpec.data = array(data); - tempSpec.series[0].valueField = ChartValueField; - tempSpec.series[0].categoryField = ChartDimensionField; - tempSpec.series[0].dataId = tempSpec.data[0].id; - tempSpec.series[0].seriesField = ChartDimensionField; - tempSpec.series[0].id = `series-${tempSpec.data[0].id}`; - return tempSpec; - } -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/polar-single.ts b/packages/vstory/src/story/character/chart/temp/templates/polar-single.ts deleted file mode 100644 index 8d97d430..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/polar-single.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { IChartCharacterSpec } from '../../../dsl-interface'; -import type { StandardData } from '../../data/interface'; -import { BaseTemp } from './base-temp'; -import { getPolarCommonSpec, getPolarSpec } from './common'; - -export abstract class PolarSingleSeriesTemp extends BaseTemp { - // 唯一系列类型 - seriesType: string; - defaultLegendVisible = false; - - constructor(characterSpec: IChartCharacterSpec) { - super(); - } - - checkDataEnable(data: StandardData, opt?: any): boolean { - return !!data; // CommonStandardDataCheck(data); - } - getSpec(data: StandardData, opt?: any) { - const polarCommonSpec = getPolarCommonSpec() as any; - if (polarCommonSpec.legends) { - polarCommonSpec.legends.visible = this.defaultLegendVisible; - } - - return getPolarSpec(this._getSeriesSpec.bind(this), polarCommonSpec, data, { - categoryField: opt.character.specProcess.getCharacterSpec().options.categoryField, - valueField: opt.character.specProcess.getCharacterSpec().options.valueField, - seriesField: opt.character.specProcess.getCharacterSpec().options.seriesField - }); - } - - protected abstract _getSeriesSpec(): any; -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/radar.ts b/packages/vstory/src/story/character/chart/temp/templates/radar.ts deleted file mode 100644 index 38f90ee5..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/radar.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { StandardData } from '../../data/interface'; -import { CommonStandardDataCheck, getCommonSpec } from './common'; -import { TemplateChartType } from '../constant'; -import { PolarSingleSeriesTemp } from './polar-single'; - -export class RadarTemp extends PolarSingleSeriesTemp { - static type: string = TemplateChartType.radar; - type: string = RadarTemp.type; - checkDataEnable(data: StandardData, opt?: any): boolean { - return CommonStandardDataCheck(data); - } - - protected _getSeriesSpec() { - return { - type: 'radar' - }; - } -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/rangeColumn.ts b/packages/vstory/src/story/character/chart/temp/templates/rangeColumn.ts deleted file mode 100644 index 8f937812..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/rangeColumn.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { TemplateChartType } from '../constant'; -import { CartesianSingleSeriesTemp } from './cartesian-single'; -import type { CharacterChart } from '../../character'; - -export class RangeColumnTemp extends CartesianSingleSeriesTemp { - static type: string = TemplateChartType.rangeColumn; - type: string = RangeColumnTemp.type; - // 唯一系列类型 - seriesType = 'rangeColumn'; - // 是否消除维度轴的2测留白 - trimPadding = true; - - protected _getSeriesSpec() { - return { - type: 'rangeColumn', - stack: false, - direction: this.direction - }; - } - - standardizedSpec(spec: any, ctx: { character: CharacterChart }) { - if (spec.series) { - spec.series.forEach((seriesSpec: any) => { - if (seriesSpec.minField && seriesSpec.maxField) { - if (this.direction === 'vertical') { - if (!seriesSpec.yField) { - seriesSpec.yField = [seriesSpec.minField, seriesSpec.maxField]; - } - } else { - if (!seriesSpec.xField) { - seriesSpec.xField = [seriesSpec.minField, seriesSpec.maxField]; - } - } - } - }); - } - } -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/rose.ts b/packages/vstory/src/story/character/chart/temp/templates/rose.ts deleted file mode 100644 index 2b50f889..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/rose.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { array } from '@visactor/vutils'; -import type { StandardData } from '../../data/interface'; -import type { DataInfo } from '../../data/interface'; -import { BaseTemp } from './base-temp'; -import { CommonStandardDataCheck, getCommonSpec } from './common'; -import { TemplateChartType } from '../constant'; -import { ChartDimensionField, ChartValueField } from '../../const'; -import { PolarSingleSeriesTemp } from './polar-single'; - -export class RoseTemp extends PolarSingleSeriesTemp { - static type: string = TemplateChartType.rose; - type: string = RoseTemp.type; - protected _getSeriesSpec() { - return { - type: 'rose' - }; - } -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/scatter.ts b/packages/vstory/src/story/character/chart/temp/templates/scatter.ts deleted file mode 100644 index 9f038fa2..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/scatter.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { TemplateChartType } from '../constant'; -import { CartesianSingleSeriesTemp } from './cartesian-single'; - -export class ScatterTemp extends CartesianSingleSeriesTemp { - static type: string = TemplateChartType.scatter; - type: string = ScatterTemp.type; - // 唯一系列类型 - seriesType = 'scatter'; - // 是否消除维度轴的2测留白 - trimPadding = true; - - protected _getSeriesSpec() { - return { - type: 'scatter', - stack: false, - direction: this.direction - }; - } -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/sunburst.ts b/packages/vstory/src/story/character/chart/temp/templates/sunburst.ts deleted file mode 100644 index a1bc4947..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/sunburst.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { array } from '@visactor/vutils'; -import type { StandardData } from '../../data/interface'; -import type { DataInfo } from '../../data/interface'; -import { BaseTemp } from './base-temp'; -import { CommonStandardDataCheck, getCommonSpec } from './common'; -import { TemplateChartType } from '../constant'; -import { ChartDimensionField, ChartValueField } from '../../const'; - -export function spec() { - return { - type: 'sunburst' - }; -} - -export class SunburstTemp extends BaseTemp { - static type: string = TemplateChartType.sunburst; - type: string = SunburstTemp.type; - checkDataEnable(data: StandardData, opt?: any): boolean { - return CommonStandardDataCheck(data); - } - getSpec(data: StandardData, opt?: any) { - const tempSpec = getCommonSpec() as any; - tempSpec.series = [spec()]; - tempSpec.data = array(data); - tempSpec.series[0].valueField = ChartValueField; - tempSpec.series[0].categoryField = ChartDimensionField; - tempSpec.series[0].dataId = tempSpec.data[0].id; - tempSpec.series[0].seriesField = ChartDimensionField; - tempSpec.series[0].id = `series-${tempSpec.data[0].id}`; - return tempSpec; - } -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/treemap.ts b/packages/vstory/src/story/character/chart/temp/templates/treemap.ts deleted file mode 100644 index 22ff25e2..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/treemap.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { array } from '@visactor/vutils'; -import type { StandardData } from '../../data/interface'; -import type { DataInfo } from '../../data/interface'; -import { BaseTemp } from './base-temp'; -import { CommonStandardDataCheck, getCommonSpec } from './common'; -import { TemplateChartType } from '../constant'; -import { ChartDimensionField, ChartValueField } from '../../const'; - -export function spec() { - return { - type: 'treemap' - }; -} - -export class TreeMapTemp extends BaseTemp { - static type: string = TemplateChartType.treemap; - type: string = TreeMapTemp.type; - checkDataEnable(data: StandardData, opt?: any): boolean { - return CommonStandardDataCheck(data); - } - getSpec(data: StandardData, opt?: any) { - const tempSpec = getCommonSpec() as any; - tempSpec.series = [spec()]; - tempSpec.data = array(data); - tempSpec.series[0].valueField = ChartValueField; - tempSpec.series[0].categoryField = ChartDimensionField; - tempSpec.series[0].dataId = tempSpec.data[0].id; - tempSpec.series[0].seriesField = ChartDimensionField; - tempSpec.series[0].id = `series-${tempSpec.data[0].id}`; - return tempSpec; - } -} diff --git a/packages/vstory/src/story/character/chart/temp/templates/vchart-temp.ts b/packages/vstory/src/story/character/chart/temp/templates/vchart-temp.ts new file mode 100644 index 00000000..70c65385 --- /dev/null +++ b/packages/vstory/src/story/character/chart/temp/templates/vchart-temp.ts @@ -0,0 +1,15 @@ +import type { StandardData } from '../../data/interface'; +import { BaseTemp } from './base-temp'; +import { TemplateChartType } from '../constant'; + +export class VChartTemp extends BaseTemp { + static type: string = TemplateChartType.vchart; + type: string = VChartTemp.type; + checkDataEnable(data: StandardData, opt?: any): boolean { + return true; + } + getSpec(data: StandardData, opt: any) { + // TODO 转换特定chart Spec到通用common spec + return opt.character.spec.options.spec as any; + } +} diff --git a/packages/vstory/src/story/character/chart/temp/templates/wordcloud.ts b/packages/vstory/src/story/character/chart/temp/templates/wordcloud.ts deleted file mode 100644 index e3adaa7d..00000000 --- a/packages/vstory/src/story/character/chart/temp/templates/wordcloud.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { array } from '@visactor/vutils'; -import type { StandardData } from '../../data/interface'; -import type { DataInfo } from '../../data/interface'; -import { BaseTemp } from './base-temp'; -import { CommonStandardDataCheck, getCommonSpec } from './common'; -import { TemplateChartType } from '../constant'; -import { ChartDimensionField, ChartValueField } from '../../const'; - -export function spec() { - return { - type: 'wordCloud' - }; -} - -export class WordCloudTemp extends BaseTemp { - static type: string = TemplateChartType.wordcloud; - type: string = WordCloudTemp.type; - checkDataEnable(data: StandardData, opt?: any): boolean { - const check = CommonStandardDataCheck(data); - return check; - } - getSpec(data: StandardData, opt?: any) { - const tempSpec = getCommonSpec() as any; - tempSpec.series = [spec()]; - tempSpec.data = array(data); - tempSpec.series[0].valueField = ChartValueField; - tempSpec.series[0].nameField = ChartDimensionField; - tempSpec.series[0].dataId = tempSpec.data[0].id; - tempSpec.series[0].seriesField = ChartDimensionField; - tempSpec.series[0].id = `series-${tempSpec.data[0].id}`; - return tempSpec; - } -} diff --git a/packages/vstory/src/story/character/component/characters/character-image.ts b/packages/vstory/src/story/character/component/characters/character-image.ts index afdc42e5..33b2c3ad 100644 --- a/packages/vstory/src/story/character/component/characters/character-image.ts +++ b/packages/vstory/src/story/character/component/characters/character-image.ts @@ -1,6 +1,6 @@ import type { Graphic } from '../graphic/graphic'; import { CharacterComponent } from '../character'; -import { StoryGraphicType } from '../../../../dsl/constant'; +import { StoryGraphicType } from '../../../../constants/character'; import { GraphicImage } from '../graphic/image'; export class CharacterComponentImage extends CharacterComponent { diff --git a/packages/vstory/src/story/character/component/characters/character-line.ts b/packages/vstory/src/story/character/component/characters/character-line.ts index f0290740..1815c957 100644 --- a/packages/vstory/src/story/character/component/characters/character-line.ts +++ b/packages/vstory/src/story/character/component/characters/character-line.ts @@ -1,7 +1,7 @@ import type { Graphic } from '../graphic/graphic'; import { GraphicLine } from '../graphic/line'; import { CharacterComponent } from '../character'; -import { StoryGraphicType } from '../../../../dsl/constant'; +import { StoryGraphicType } from '../../../../constants/character'; export class CharacterComponentLine extends CharacterComponent { readonly graphicType: string = 'line'; diff --git a/packages/vstory/src/story/character/component/characters/character-rect.ts b/packages/vstory/src/story/character/component/characters/character-rect.ts index 377bf5ea..558ecc06 100644 --- a/packages/vstory/src/story/character/component/characters/character-rect.ts +++ b/packages/vstory/src/story/character/component/characters/character-rect.ts @@ -1,7 +1,7 @@ import type { Graphic } from '../graphic/graphic'; import { GraphicRect } from '../graphic/rect'; import { CharacterComponent } from '../character'; -import { StoryGraphicType } from '../../../../dsl/constant'; +import { StoryGraphicType } from '../../../../constants/character'; export class CharacterComponentRect extends CharacterComponent { readonly graphicType: string = 'rect'; diff --git a/packages/vstory/src/story/character/component/characters/character-richtext.ts b/packages/vstory/src/story/character/component/characters/character-richtext.ts index 58e0f65e..a662d990 100644 --- a/packages/vstory/src/story/character/component/characters/character-richtext.ts +++ b/packages/vstory/src/story/character/component/characters/character-richtext.ts @@ -1,7 +1,7 @@ import type { Graphic } from '../graphic/graphic'; import { GraphicRichText } from '../graphic/richtext'; import { CharacterComponent } from '../character'; -import { StoryGraphicType } from '../../../../dsl/constant'; +import { StoryGraphicType } from '../../../../constants/character'; export class CharacterComponentRichText extends CharacterComponent { readonly graphicType: string = 'richtext'; diff --git a/packages/vstory/src/story/character/component/characters/character-shape.ts b/packages/vstory/src/story/character/component/characters/character-shape.ts index b89795bc..898d3433 100644 --- a/packages/vstory/src/story/character/component/characters/character-shape.ts +++ b/packages/vstory/src/story/character/component/characters/character-shape.ts @@ -1,6 +1,6 @@ import type { Graphic } from '../graphic/graphic'; import { CharacterComponent } from '../character'; -import { StoryGraphicType } from '../../../../dsl/constant'; +import { StoryGraphicType } from '../../../../constants/character'; import { GraphicSymbol } from '../graphic/symbol'; export class CharacterComponentShape extends CharacterComponent { diff --git a/packages/vstory/src/story/character/component/characters/character-text.ts b/packages/vstory/src/story/character/component/characters/character-text.ts index 70115468..b2495311 100644 --- a/packages/vstory/src/story/character/component/characters/character-text.ts +++ b/packages/vstory/src/story/character/component/characters/character-text.ts @@ -1,7 +1,7 @@ import type { Graphic } from '../graphic/graphic'; import { GraphicPureText } from '../graphic/text'; import { CharacterComponent } from '../character'; -import { StoryGraphicType } from '../../../../dsl/constant'; +import { StoryGraphicType } from '../../../../constants/character'; /** * text component 没有关联 graphic,逻辑与 GraphicText 有所不同 diff --git a/packages/vstory/src/story/character/runtime-interface.ts b/packages/vstory/src/story/character/runtime-interface.ts index 23f75de8..61409fe9 100644 --- a/packages/vstory/src/story/character/runtime-interface.ts +++ b/packages/vstory/src/story/character/runtime-interface.ts @@ -1,7 +1,7 @@ import type { IGroup } from '@visactor/vrender'; import type { IPointLike } from '@visactor/vutils'; import type { StoryCanvas } from '../canvas/canvas'; -import type { IStory, StoryEvent } from '../interface/runtime-interface'; +import type { IStory, IStoryCanvas, StoryEvent } from '../interface/runtime-interface'; import type { ICharacterSpec } from './dsl-interface'; export interface ICharacterPickInfo { @@ -17,6 +17,7 @@ export interface ICharacter { show: () => void; hide: () => void; getGraphicParent: () => IGroup; + graphic: IGroup; tickTo: (t: number) => void; checkEvent: (event: StoryEvent) => false | (ICharacterPickInfo & any); @@ -28,7 +29,7 @@ export interface ICharacter { export interface ICharacterInitOption { story: IStory; - canvas: StoryCanvas; + canvas: IStoryCanvas; graphicParent: IGroup; } diff --git a/packages/vstory/src/story/index.ts b/packages/vstory/src/story/index.ts index 3ac4c982..1f5bc701 100644 --- a/packages/vstory/src/story/index.ts +++ b/packages/vstory/src/story/index.ts @@ -1,28 +1,17 @@ import { CharacterComponentQipao } from './character/component/characters/character-qipao'; import { CharacterComponentRect } from './character/component/characters/character-rect'; import { StoryFactory } from './factory/factory'; -import { CharacterChart } from './character/chart/character'; import { ContainerModule, GraphicRender, container } from '@visactor/vrender'; import { CanvasPickerContribution } from '@visactor/vrender'; import { ChartRender, VChartRender } from './character/chart/graphic/vchart-graphic-render'; -import { BarChartCharacter } from './character/chart/characters/bar'; -import { LineChartCharacter } from './character/chart/characters/line'; -import { AreaChartCharacter } from './character/chart/characters/area'; -import { PieChartCharacter } from './character/chart/characters/pie'; -import { RoseChartCharacter } from './character/chart/characters/rose'; -import { RadarChartCharacter } from './character/chart/characters/radar'; -import { WordCloudCharacter } from './character/chart/characters/wordcloud'; -import { TreeMapChartCharacter } from './character/chart/characters/treemap'; -import { SunburstChartCharacter } from './character/chart/characters/sunburst'; -import { ScatterChartCharacter } from './character/chart/characters/scatter'; -import { RangeColumnChartCharacter } from './character/chart/characters/rangeColumn'; import { CharacterComponentText } from './character/component/characters/character-text'; import { CharacterComponentRichText } from './character/component/characters/character-richtext'; import { VChartPicker } from './character/chart/graphic/vchart-graphic-picker'; -import { StoryGraphicType } from '../dsl/constant'; +import { StoryGraphicType } from '../constants/character'; import { CharacterComponentLine } from './character/component/characters/character-line'; import { CharacterComponentImage } from './character/component/characters/character-image'; import { CharacterComponentShape } from './character/component/characters/character-shape'; +import { VChartCharacter } from './character/chart/characters/vchart'; const splitModule = new ContainerModule((bind: any) => { // chart渲染器注入 @@ -39,18 +28,7 @@ export function registerCharacter() { return; } _register = true; - StoryFactory.registerCharacter(BarChartCharacter.type, BarChartCharacter); - StoryFactory.registerCharacter(LineChartCharacter.type, CharacterChart); - StoryFactory.registerCharacter(CharacterChart.type, CharacterChart); - StoryFactory.registerCharacter(AreaChartCharacter.type, AreaChartCharacter); - StoryFactory.registerCharacter(PieChartCharacter.type, PieChartCharacter); - StoryFactory.registerCharacter(RoseChartCharacter.type, RoseChartCharacter); - StoryFactory.registerCharacter(RadarChartCharacter.type, RadarChartCharacter); - StoryFactory.registerCharacter(WordCloudCharacter.type, WordCloudCharacter); - StoryFactory.registerCharacter(TreeMapChartCharacter.type, TreeMapChartCharacter); - StoryFactory.registerCharacter(SunburstChartCharacter.type, SunburstChartCharacter); - StoryFactory.registerCharacter(ScatterChartCharacter.type, ScatterChartCharacter); - StoryFactory.registerCharacter(RangeColumnChartCharacter.type, RangeColumnChartCharacter); + StoryFactory.registerCharacter(VChartCharacter.type, VChartCharacter); // StoryFactory.registerCharacter('BarChart', CharacterChart); // StoryFactory.registerCharacter('CharacterChart', CharacterChart); diff --git a/packages/vstory/src/story/interface/dsl-interface.ts b/packages/vstory/src/story/interface/dsl-interface.ts index 9e3dc4db..5e216a24 100644 --- a/packages/vstory/src/story/interface/dsl-interface.ts +++ b/packages/vstory/src/story/interface/dsl-interface.ts @@ -2,9 +2,9 @@ import type { Action } from '../../dsl/types'; import type { ICharacterSpec } from '../character'; export interface IAction { - startTime: number; + startTime?: number; action: string; - duration: number; + duration?: number; payload?: Action['payload']; } diff --git a/packages/vstory/src/story/interface/player.ts b/packages/vstory/src/story/interface/player.ts index af03d3c6..50fb1918 100644 --- a/packages/vstory/src/story/interface/player.ts +++ b/packages/vstory/src/story/interface/player.ts @@ -1,18 +1,17 @@ -import { ICharacter } from '../character'; -import { IActSpec } from './dsl-interface'; +import type { ICharacter } from '../character'; +import type { IActSpec } from './dsl-interface'; export interface IPlayer { - tickTo(t: number): void; - play(): void; - encodeToVideo(millsecond: number, fps: number): Promise; - pause(): void; - release(): void; - addAct( + tickTo: (t: number) => void; + play: () => void; + encodeToVideo: (millsecond: number, fps: number) => Promise; + pause: () => void; + release: () => void; + addAct: ( c: IActSpec, characters: { [key: string]: ICharacter; } - ): void; - setCurrentAct(id: number | string): void; - getCurrentAct(): number | string; + ) => void; + getCurrentAct: () => number | string; } diff --git a/packages/vstory/src/story/interface/runtime-interface.ts b/packages/vstory/src/story/interface/runtime-interface.ts index dcd84edb..865dd6b0 100644 --- a/packages/vstory/src/story/interface/runtime-interface.ts +++ b/packages/vstory/src/story/interface/runtime-interface.ts @@ -1,4 +1,5 @@ -import type { IGraphic } from '@visactor/vrender'; +import type { IGraphic, IStage } from '@visactor/vrender'; +import type { ICharacter, ICharacterSpec } from '../character'; export interface IStoryInitOption { dom: string | HTMLDivElement; // dom id @@ -8,8 +9,27 @@ export interface IStoryInitOption { }; } +export interface IStoryCanvas { + getStage: () => IStage; + getCanvas: () => HTMLCanvasElement; + getEventDetail: (event: StoryEvent) => { + character: ICharacter; + characterInfo: undefined; + }; + release: () => void; +} + export interface IStory { readonly id: string; + canvas: IStoryCanvas; + getCharacters: () => { [key: string]: ICharacter }; + getCharactersById: (key: string) => ICharacter | null; +} +export interface ICharacterTree { + getCharacters: () => { [key: string]: ICharacter }; + getCharactersById: (key: string) => ICharacter | null; + addCharacter: (spec: ICharacterSpec) => ICharacter; + initCharacters: (spec: ICharacterSpec[]) => void; } export type StoryEvent = Event & { diff --git a/packages/vstory/src/story/player/index.ts b/packages/vstory/src/story/player/index.ts index 680f6ac7..663799dc 100644 --- a/packages/vstory/src/story/player/index.ts +++ b/packages/vstory/src/story/player/index.ts @@ -1,216 +1,216 @@ -import { isNumber } from '@visactor/vutils'; -import type { StoryCanvas } from '../canvas/canvas'; -import type { IActSpec, IAction } from '../interface'; -import type { IPlayer } from '../interface/player'; -import { processorMap, ActionProcessor } from '../../dsl/story-processor'; -// import { Encoder } from './encode'; -import type { ICharacter } from '../character'; - -export class Ticker { - cb?: (delta: number) => void; - rafIdx = 0; - start(cb: (t: number) => void) { - this.stop(); - this.cb = cb; - this._tick(0); - } - - _tick = (lt: number) => { - const ct = Date.now(); - this.cb && this.cb(lt === 0 ? 0 : ct - lt); - this.rafIdx = requestAnimationFrame(() => this._tick(ct)); - }; - - stop() { - this.rafIdx && cancelAnimationFrame(this.rafIdx); - this.rafIdx = 0; - } -} - -type IChapterInstanceItem = { - id: string; - scenes: Array<{ - scene: { - character: ICharacter; - action: IAction; - }[]; - delay: number; - }>; - characters: ICharacter[]; -}; - -export class Player implements IPlayer { - protected _canvas: StoryCanvas; - protected _acts: IChapterInstanceItem[]; - protected _currAct: IChapterInstanceItem; - protected _ticker: Ticker; - protected _currTime: number; - // protected _encoder: Encoder; - protected _actionProcessor: ActionProcessor; - - constructor(c: StoryCanvas, options?: { scaleX?: number; scaleY?: number }) { - this._canvas = c; - this._acts = []; - this._ticker = new Ticker(); - this._currTime = 0; - c.getStage().defaultLayer.setAttributes({ - scaleX: options?.scaleX ?? 1, - scaleY: options?.scaleY ?? 1 - }); - // this._encoder = new Encoder(); - this._actionProcessor = new ActionProcessor(processorMap); - } - - addAct( - c: IActSpec, - characters: { - [key: string]: ICharacter; - } - ): void { - const scenes: IChapterInstanceItem['scenes'] = []; - const characterSet: Set = new Set(); - c.scenes.forEach(item => { - const scene: IChapterInstanceItem['scenes'][0] = { scene: [], delay: item.delay ?? 0 }; - item.actions.forEach(({ characterActions, characterId }) => { - const _actions = characterActions.slice(); - _actions.sort((a, b) => a.startTime - b.startTime); - _actions.forEach(action => { - const character = characters[characterId]; - scene.scene.push({ - character, - action: action - }); - characterSet.add(character); - }); - }); - scenes.push(scene); - }); - this._acts.push({ - id: c.id, - scenes: scenes, - characters: Array.from(characterSet.values()) - }); - } - - setCurrentAct(id: number | string) { - if (isNumber(id)) { - this._currAct = this._acts[id]; - } else { - this._currAct = this._acts.filter(item => item.id === id)[0]; - } - } - - getCurrentAct() { - return this._currAct?.id; - } - - // 清除当前状态,一般用于回放操作 - reset() { - this._currAct.characters.forEach(item => { - item.reset(); - }); - } - - tickTo(t: number) { - const lastTime = this._currTime; - if (lastTime > t) { - // 如果时间回退,那就重新走一遍 - this.reset(); - this._currTime = 0; - this.tickTo(0); - } - const characterSet = new Set(); - - let baseStartTime = 0; - for (let i = 0; i < this._currAct.scenes.length; i++) { - const scene = this._currAct.scenes[i]; - baseStartTime += scene.delay; - if (baseStartTime <= t) { - scene.scene.forEach(({ character, action }) => { - const { startTime: st } = action; - const startTime = st + baseStartTime; - if (startTime > t) { - return; - } - characterSet.add(character); - // 之前没走过,现在走 - if (startTime > lastTime && startTime <= t) { - const { type } = character.spec; - this._actionProcessor.doAction(type, action.action, [character, {}, action]); - } - character.show(); - }); - } - let sceneTime = 0; - scene.scene.forEach(({ action }) => { - const { startTime, duration } = action; - sceneTime = Math.max(startTime + duration, startTime); - }); - baseStartTime += sceneTime; - // if (baseStartTime > t) { - // break; - // } - } - - // roleSet.forEach(r => { - // r.tickTo && r.tickTo(t); - // }); - - this._currTime = t; - this._canvas.getStage().ticker.tickAt(t); - this._canvas.getStage().render(); - } - - play(): void { - if (!this._currAct) { - return; - } - this._ticker.stop(); - this._currTime = 0; - this.reset(); - this._ticker.start(t => { - this.tickTo(this._currTime + t); - }); - } - - async encodeToVideo(millsecond: number, fps: number): Promise { - // // if (!this._currChapter) { - // // return; - // // } - // const frameNum = (millsecond / 1000) * fps; - // const deltaT = 1000 / fps; - // this.tickTo(0); - // const objUrl = await this._encoder.exportVideo(frameNum, fps, async i => { - // const t = deltaT * i; - // this.tickTo(t); - // return new Promise((resolve, reject) => { - // this._canvas - // .getStage() - // .window.getContext() - // .canvas.nativeCanvas.toBlob((blob: any) => { - // if (blob) { - // resolve(blob); - // } else { - // // console.log('no blob'); - // reject('no blob'); - // } - // }, `image/png`); - // }); - // }); - - // return objUrl; - return null; - } - - pause(): void { - this._ticker.stop(); - } - - resume(): void { - this._ticker._tick(this._currTime); - } - - release(): void { - return; - } -} +// import { isNumber } from '@visactor/vutils'; +// import type { StoryCanvas } from '../canvas/canvas'; +// import type { IActSpec, IAction, IStoryCanvas } from '../interface'; +// import type { IPlayer } from '../../player/interface/player'; +// import { processorMap, ActionProcessor } from '../../dsl/story-processor'; +// // import { Encoder } from './encode'; +// import type { ICharacter } from '../character'; + +// export class Ticker { +// cb?: (delta: number) => void; +// rafIdx = 0; +// start(cb: (t: number) => void) { +// this.stop(); +// this.cb = cb; +// this._tick(0); +// } + +// _tick = (lt: number) => { +// const ct = Date.now(); +// this.cb && this.cb(lt === 0 ? 0 : ct - lt); +// this.rafIdx = requestAnimationFrame(() => this._tick(ct)); +// }; + +// stop() { +// this.rafIdx && cancelAnimationFrame(this.rafIdx); +// this.rafIdx = 0; +// } +// } + +// type IChapterInstanceItem = { +// id: string; +// scenes: Array<{ +// scene: { +// character: ICharacter; +// action: IAction; +// }[]; +// delay: number; +// }>; +// characters: ICharacter[]; +// }; + +// export class Player implements IPlayer { +// protected _canvas: IStoryCanvas; +// protected _acts: IChapterInstanceItem[]; +// protected _currAct: IChapterInstanceItem; +// protected _ticker: Ticker; +// protected _currTime: number; +// // protected _encoder: Encoder; +// protected _actionProcessor: ActionProcessor; + +// constructor(c: IStoryCanvas, options?: { scaleX?: number; scaleY?: number }) { +// this._canvas = c; +// this._acts = []; +// this._ticker = new Ticker(); +// this._currTime = 0; +// c.getStage().defaultLayer.setAttributes({ +// scaleX: options?.scaleX ?? 1, +// scaleY: options?.scaleY ?? 1 +// }); +// // this._encoder = new Encoder(); +// this._actionProcessor = new ActionProcessor(processorMap); +// } + +// addAct( +// c: IActSpec, +// characters: { +// [key: string]: ICharacter; +// } +// ): void { +// const scenes: IChapterInstanceItem['scenes'] = []; +// const characterSet: Set = new Set(); +// c.scenes.forEach(item => { +// const scene: IChapterInstanceItem['scenes'][0] = { scene: [], delay: item.delay ?? 0 }; +// item.actions.forEach(({ characterActions, characterId }) => { +// const _actions = characterActions.slice(); +// _actions.sort((a, b) => a.startTime - b.startTime); +// _actions.forEach(action => { +// const character = characters[characterId]; +// scene.scene.push({ +// character, +// action: action +// }); +// characterSet.add(character); +// }); +// }); +// scenes.push(scene); +// }); +// this._acts.push({ +// id: c.id, +// scenes: scenes, +// characters: Array.from(characterSet.values()) +// }); +// } + +// setCurrentAct(id: number | string) { +// if (isNumber(id)) { +// this._currAct = this._acts[id]; +// } else { +// this._currAct = this._acts.filter(item => item.id === id)[0]; +// } +// } + +// getCurrentAct() { +// return this._currAct?.id; +// } + +// // 清除当前状态,一般用于回放操作 +// reset() { +// this._currAct.characters.forEach(item => { +// item.reset(); +// }); +// } + +// tickTo(t: number) { +// const lastTime = this._currTime; +// if (lastTime > t) { +// // 如果时间回退,那就重新走一遍 +// this.reset(); +// this._currTime = 0; +// this.tickTo(0); +// } +// const characterSet = new Set(); + +// let baseStartTime = 0; +// for (let i = 0; i < this._currAct.scenes.length; i++) { +// const scene = this._currAct.scenes[i]; +// baseStartTime += scene.delay; +// if (baseStartTime <= t) { +// scene.scene.forEach(({ character, action }) => { +// const { startTime: st } = action; +// const startTime = st + baseStartTime; +// if (startTime > t) { +// return; +// } +// characterSet.add(character); +// // 之前没走过,现在走 +// if (startTime > lastTime && startTime <= t) { +// const { type } = character.spec; +// this._actionProcessor.doAction(type, action.action, [character, {}, action]); +// } +// character.show(); +// }); +// } +// let sceneTime = 0; +// scene.scene.forEach(({ action }) => { +// const { startTime, duration } = action; +// sceneTime = Math.max(startTime + duration, startTime); +// }); +// baseStartTime += sceneTime; +// // if (baseStartTime > t) { +// // break; +// // } +// } + +// // roleSet.forEach(r => { +// // r.tickTo && r.tickTo(t); +// // }); + +// this._currTime = t; +// this._canvas.getStage().ticker.tickAt(t); +// this._canvas.getStage().render(); +// } + +// play(): void { +// if (!this._currAct) { +// return; +// } +// this._ticker.stop(); +// this._currTime = 0; +// this.reset(); +// this._ticker.start(t => { +// this.tickTo(this._currTime + t); +// }); +// } + +// async encodeToVideo(millsecond: number, fps: number): Promise { +// // // if (!this._currChapter) { +// // // return; +// // // } +// // const frameNum = (millsecond / 1000) * fps; +// // const deltaT = 1000 / fps; +// // this.tickTo(0); +// // const objUrl = await this._encoder.exportVideo(frameNum, fps, async i => { +// // const t = deltaT * i; +// // this.tickTo(t); +// // return new Promise((resolve, reject) => { +// // this._canvas +// // .getStage() +// // .window.getContext() +// // .canvas.nativeCanvas.toBlob((blob: any) => { +// // if (blob) { +// // resolve(blob); +// // } else { +// // // console.log('no blob'); +// // reject('no blob'); +// // } +// // }, `image/png`); +// // }); +// // }); + +// // return objUrl; +// return null; +// } + +// pause(): void { +// this._ticker.stop(); +// } + +// resume(): void { +// this._ticker._tick(this._currTime); +// } + +// release(): void { +// return; +// } +// } diff --git a/packages/vstory/src/story/story.ts b/packages/vstory/src/story/story.ts index b1c92938..797e0820 100644 --- a/packages/vstory/src/story/story.ts +++ b/packages/vstory/src/story/story.ts @@ -1,13 +1,14 @@ import type { ICharacterSpec } from './character/dsl-interface'; import { isString } from '@visactor/vutils'; -import type { IStory, IStoryInitOption } from './interface/runtime-interface'; +import type { ICharacterTree, IStory, IStoryCanvas, IStoryInitOption } from './interface/runtime-interface'; import type { ICharacter } from './character/runtime-interface'; import { StoryCanvas } from './canvas/canvas'; import type { IStorySpec, IActSpec } from './interface'; import { StoryFactory } from './factory/factory'; import { defaultTicker, defaultTimeline } from '@visactor/vrender'; -import type { IPlayer } from './interface/player'; -import { Player } from './player'; +import { CharacterTree } from './character-tree/character-tree'; +import type { IPlayer } from '../player/interface/player'; +import { Player } from '../player/player'; defaultTicker.remTimeline(defaultTimeline); @@ -18,71 +19,55 @@ export class Story implements IStory { readonly id: string; - protected _canvas: StoryCanvas; + protected _canvas: IStoryCanvas; + + protected _characterTree: ICharacterTree; get canvas() { return this._canvas; } - protected _characters: { [key: string]: ICharacter } = {}; - constructor(spec: IStorySpec, option: IStoryInitOption) { this.id = 'test-mvp_' + Story._id_++; this._canvas = new StoryCanvas( this, isString(option.dom) ? (document.getElementById(option.dom) as HTMLDivElement) : option.dom ); - this._player = new Player(this._canvas, option.playerOption); + this._player = new Player(this, option.playerOption); + this._characterTree = new CharacterTree(this); if (spec) { this.load(spec); } } load(spec: IStorySpec) { - spec.characters.forEach(e => { - this._createCharacter(e); - }); - // @ts-ignore - spec.acts.forEach(e => { - this._createAct(e); - }); + this._characterTree.initCharacters(spec.characters); + this._player.initActs(spec.acts); } getCharacters(): { [key: string]: ICharacter } { - return this._characters; + return this._characterTree.getCharacters(); } - private _createCharacter(spec: ICharacterSpec) { - const option = { story: this, canvas: this._canvas, graphicParent: this._canvas.getStage().defaultLayer }; - if ((spec).id) { - if (!this._characters[(spec).id]) { - this._characters[(spec).id] = StoryFactory.createCharacter(spec, option); - } - return this._characters[(spec).id]; - } - // else if ((spec).characterId) { - // return this._characters[(spec).characterId]; - // } - return null; + getCharactersById(key: string) { + return this._characterTree.getCharactersById(key); } - private _createAct(spec: IActSpec) { - this._player.addAct(spec, this._characters); - } + // private _createAct(spec: IActSpec) { + // this._player.addAct(spec, this._characters); + // } - play(actIndex: string | number = 0) { + play(actIndexOrId: string | number = 0) { // player 开始播放 - this._player.setCurrentAct(actIndex); this._player.play(); } pause() { this._player.pause(); - return this._player.getCurrentAct(); + return; } - async encodeToVideo(actIndex: number, millsecond: number, fps: number) { - this._player.setCurrentAct(actIndex); + async encodeToVideo(actIndexOrId: number, millsecond: number, fps: number) { return this._player.encodeToVideo(millsecond, fps); } diff --git a/packages/vstory/src/task.ts b/packages/vstory/src/task.ts index f351df9c..e4eb6fe4 100644 --- a/packages/vstory/src/task.ts +++ b/packages/vstory/src/task.ts @@ -1,43 +1,43 @@ -import { IContext } from './interface/type'; +// import { IContext } from './interface/type'; -export type TaskCb = () => void; +// export type TaskCb = () => void; -export interface ITask { - runCb: (cb: TaskCb) => void; - run: (context?: Partial) => void; - next: ITask | null; - prev: ITask | null; -} +// export interface ITask { +// runCb: (cb: TaskCb) => void; +// run: (context?: Partial) => void; +// next: ITask | null; +// prev: ITask | null; +// } -export abstract class AbstractTask implements ITask { - prev: ITask; - next: ITask; +// export abstract class AbstractTask implements ITask { +// prev: ITask; +// next: ITask; - abstract runCb(cb: TaskCb): void; - abstract run(context?: Partial): void; -} +// abstract runCb(cb: TaskCb): void; +// abstract run(context?: Partial): void; +// } -export class TaskManager { - protected _tail: ITask; - protected _head: ITask; +// export class TaskManager { +// protected _tail: ITask; +// protected _head: ITask; - protected _context: Partial; - setContext(context: Partial) { - this._context = context; - } +// protected _context: Partial; +// setContext(context: Partial) { +// this._context = context; +// } - next(task: ITask) { - if (!this._tail) { - this._tail = task; - this._head = task; - task.run(this._context); - } else { - this._tail.next = task; - task.prev = this._tail; - this._tail.runCb(() => { - task.run(this._context); - }); - this._tail = task; - } - } -} +// next(task: ITask) { +// if (!this._tail) { +// this._tail = task; +// this._head = task; +// task.run(this._context); +// } else { +// this._tail.next = task; +// task.prev = this._tail; +// this._tail.runCb(() => { +// task.run(this._context); +// }); +// this._tail = task; +// } +// } +// } diff --git a/packages/vstory/src/template/base-template.ts b/packages/vstory/src/template/base-template.ts deleted file mode 100644 index a78acd77..00000000 --- a/packages/vstory/src/template/base-template.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type VChart from '@visactor/vchart'; -import type { IContext } from '../interface/type'; -import { IGraphic } from '@visactor/vrender'; -import { TaskManager } from '../task'; -import { forEachGraphicItem } from '../util/vrender-api'; - -export abstract class Template { - declare spec: Record; - protected _chartInstance: VChart; - vchartInstance() { - return this._chartInstance; - } - - // protected _graphicAnimationManager = new Map(); - - constructor(spec: Record) { - this.spec = spec; - } - - protected abstract isValid(): boolean; - - protected abstract setUp(): Record; - - abstract render(context: Partial): void; - - onRenderEnd(context: Partial) { - // const { stage } = context; - // if (stage && this._chartInstance) { - // forEachGraphicItem(stage as unknown as IGraphic, graphic => { - // if (!this._graphicAnimationManager.get(graphic)) { - // const manager = new TaskManager(); - // this._graphicAnimationManager.set(graphic, manager); - // } - // }); - // } - } - - release() { - this._chartInstance.release(); - this._chartInstance = null; - // this._graphicAnimationManager.clear(); - // this._graphicAnimationManager = null; - } -} diff --git a/packages/vstory/src/template/charts/simple-chart.ts b/packages/vstory/src/template/charts/simple-chart.ts deleted file mode 100644 index 23abbb13..00000000 --- a/packages/vstory/src/template/charts/simple-chart.ts +++ /dev/null @@ -1,42 +0,0 @@ -import VChart, { IChartSpec } from '@visactor/vchart'; -import { IContext } from '../../interface/type'; -import { Template } from '../base-template'; - -// TODO: 动态生成 -export const CHART_TYPES = ['line', 'bar']; - -export class Bar extends Template { - protected isValid() { - const { xField, yField, data } = this.spec; - if (!xField || !yField) { - throw new Error('Missing config: `xField`,`yField`'); - } - if (!data) { - throw new Error('Missing data'); - } - return true; - } - - protected setUp() { - if (this.spec) { - // TODO chart 会绘制整个background - this.spec.background = 'rgba(0,0,0,0)'; - } - return this.spec; - } - - render(context: Partial = {}) { - const spec = this.setUp(); - if (spec && context.dom) { - this._chartInstance = new VChart(spec as IChartSpec, { - dom: context.dom, - stage: context.stage, - renderCanvas: context.canvas - }); - if (this._chartInstance) { - this._chartInstance.renderSync(); - // this.onRenderEnd(context); - } - } - } -} diff --git a/packages/vstory/src/template/ranking-bar/interface.ts b/packages/vstory/src/template/ranking-bar/interface.ts deleted file mode 100644 index 82e19dde..00000000 --- a/packages/vstory/src/template/ranking-bar/interface.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { ILineGraphicAttribute, ITextGraphicAttribute } from '@visactor/vrender'; - -export type IRankingBarData = any[]; - -export interface IPlayConfig { - interval?: number; // 单位毫秒 -} - -export interface IRankingBarSpec extends IPlayConfig { - data: IRankingBarData; - - timeField: string; - xField: string; - yField: string; - - topN?: number; - - bar?: { - padding?: number; - cornerRadius?: number; - }; - - color?: Record; - - icon?: Record; - - iconPosition?: 'bar-end' | 'bar-start' | 'axis'; - - iconShape?: 'circle' | 'rect'; - - background?: string; - - label?: { - visible?: boolean; - style?: ITextGraphicAttribute; - }; - - nameLabel?: ITextGraphicAttribute & { - visible?: boolean; - position?: 'bar-end' | 'bar-start'; - style?: ITextGraphicAttribute; - }; - - timeLabel?: ITextGraphicAttribute; - - xAxis?: { - label?: ITextGraphicAttribute; - domainLine?: ILineGraphicAttribute; - grid?: ILineGraphicAttribute; - }; - - yAxis?: { - label?: ITextGraphicAttribute; - domainLine?: ILineGraphicAttribute; - grid?: ILineGraphicAttribute; - }; -} diff --git a/packages/vstory/src/template/ranking-bar/ranking-bar.ts b/packages/vstory/src/template/ranking-bar/ranking-bar.ts deleted file mode 100644 index 7d5fe07b..00000000 --- a/packages/vstory/src/template/ranking-bar/ranking-bar.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { IContext } from 'src/interface/type'; -import { IRankingBarSpec } from './interface'; -import { VChart } from '@visactor/vchart'; -import { specParser } from './spec-parser'; -import { Template } from '../base-template'; - -export class RankingBar extends Template { - declare spec: IRankingBarSpec; - - protected _chartInstance: VChart; - - protected _timeNodes: string[]; - protected _timeData: Map; - - constructor(spec: IRankingBarSpec) { - super(spec); - this.init(); - } - - protected init() { - if (!this.isValid()) { - return; - } - this._timeData = new Map(); - this._timeNodes = []; - } - - protected isValid() { - const { xField, yField, timeField, data } = this.spec; - if (!xField || !yField || !timeField) { - throw new Error('Missing config: `xField`,`yField`, `timeField`'); - } - if (!data) { - throw new Error('Missing data'); - } - return true; - } - - protected setUp() { - const { vchartSpec } = specParser(this.spec); - return vchartSpec; - } - - render(context: Partial = {}) { - const spec = this.setUp(); - if (spec && context.dom) { - this._chartInstance = new VChart(spec, { dom: context.dom, stage: context.stage }); - if (this._chartInstance) { - this._chartInstance.renderSync(); - this.onRenderEnd(context); - } - } - } - - release() { - super.release(); - this._timeData = null; - this._timeNodes = null; - } -} diff --git a/packages/vstory/src/template/ranking-bar/spec-parser.ts b/packages/vstory/src/template/ranking-bar/spec-parser.ts deleted file mode 100644 index f745bd60..00000000 --- a/packages/vstory/src/template/ranking-bar/spec-parser.ts +++ /dev/null @@ -1,364 +0,0 @@ -import type { IRankingBarSpec } from 'src/template/ranking-bar/interface'; -import type { ICartesianAxisSpec, ICommonChartSpec, ILabelSpec } from '@visactor/vchart'; -import { isValid } from '@visactor/vutils'; - -export function specParser(spec: IRankingBarSpec) { - const { xField, yField, timeField, data, topN = 10, icon, interval: userInterval } = spec; - - // 数据处理 - const timeNodes = new Set(); - const timeData = new Map(); - - data.sort((d1, d2) => Number(d2[xField]) - Number(d1[xField])); - - data.forEach(d => { - const time = d[timeField]; - if (isValid(time)) { - timeNodes.add(time); - } - if (!timeData.has(time)) { - timeData.set(time, []); - } - const currentData = timeData.get(time); - if (currentData.length < topN) { - const _d = { ...d }; - if (icon && icon[_d[yField]]) { - _d['icon'] = icon[_d[yField]]; - } - currentData.push(_d); - } - }); - - const interval = userInterval ? userInterval : 1000; - const exchangeDuration = Math.min(interval, 500); - - // 配置处理 - const vchartSpec = templateSpec( - spec, - { timeNodes: Array.from(timeNodes).sort(), timeData }, - { interval, exchangeDuration } - ); - console.log(vchartSpec); - return { timeData, timeNodes, vchartSpec }; -} - -function templateSpec( - { xField, yField, color, icon, iconPosition, iconShape, timeLabel, label, nameLabel, xAxis, yAxis }: IRankingBarSpec, - data: { timeNodes: string[]; timeData: Map }, - { interval, exchangeDuration }: any -): ICommonChartSpec { - const { timeData, timeNodes } = data; - const spec: ICommonChartSpec = { - type: 'common', - data: [ - { - id: 'timeData', - values: timeData.get(timeNodes[0]) - }, - { - id: 'time', - values: [{ time: timeNodes[0] }] - } - ], - // @ts-ignore - color: { - specified: { - ...color - } - }, - region: [{ clip: true }], - series: [ - { - type: 'bar', - id: 'ranking-bar', - dataId: 'timeData', - direction: 'horizontal', - yField, - xField, - seriesField: yField, - extensionMark: [], - label: labelSpec(label, { ...nameLabel, yField }, { interval, exchangeDuration }) as any - } - ], - axes: axisSpec(xAxis, yAxis), - player: { - type: 'continuous', - // visible: false, - auto: true, - loop: false, - interval, - // slider: { visible: false }, - // controller: { visible: false }, - specs: timeNodes.map(time => ({ - data: [ - { id: 'timeData', values: timeData.get(time) }, - { id: 'time', values: [{ time }] } - ] - })) - }, - tooltip: { visible: false }, - customMark: [], - animationAppear: false, - animationUpdate: { - bar: [ - { - type: 'update', - options: { excludeChannels: ['y'] }, - easing: 'linear', - duration: interval - }, - { - channel: ['y'], - easing: 'circInOut', - duration: exchangeDuration - } - ], - axis: { - duration: interval, - easing: 'linear' - } - }, - animationEnter: { - bar: [ - { - type: 'moveIn', - duration: exchangeDuration, - easing: 'cubicInOut', - options: { - direction: 'y', - orient: 'negative', - point: (datum: any, element: any, param: any, ctx: any) => { - return { - y: param.groupHeight + element.getBounds().height() - }; - } - } - } - ] - }, - animationExit: { - bar: [ - { - type: 'moveOut', - duration: exchangeDuration, - easing: 'cubicInOut', - options: { - direction: 'y', - orient: 'negative' - } - } - ] - } - }; - if (!timeLabel || timeLabel.visible !== false) { - spec.customMark.push(timeLabelSpec() as any); - } - if (icon) { - const icon = iconSpec(iconPosition, iconShape, { interval, exchangeDuration }); - spec.series[0].extensionMark.push(icon as any); - } - return spec; -} - -function labelSpec( - label: IRankingBarSpec['label'] = {}, - nameLabel: IRankingBarSpec['nameLabel'] & { yField: string }, - { interval, exchangeDuration }: any -) { - const spec: ILabelSpec[] = []; - - if (label.visible !== false) { - spec.push({ - visible: true, - overlap: false, - style: { - // @ts-ignore - fill: `rgb(64, 64, 64)`, - ...label.style - }, - smartInvert: { - fillStrategy: label.style?.fill ? 'null' : undefined, - strokeStrategy: label.style?.stroke ? 'null' : undefined - }, - animationUpdate: [ - { - duration: exchangeDuration, - easing: 'cubicInOut', - channel: ['y'] - }, - { - options: { excludeChannels: ['y'] }, - easing: 'linear', - duration: interval - } - ] - }); - } - - if (nameLabel.visible) { - spec.push({ - visible: true, - overlap: false, - // @ts-ignore - style: { - ...nameLabel.style - }, - smartInvert: { - fillStrategy: nameLabel.style?.fill ? 'null' : undefined, - strokeStrategy: nameLabel.style?.stroke ? 'null' : undefined - }, - position: nameLabel.position === 'bar-end' ? 'inside-right' : 'inside-left', - formatter: `{${nameLabel.yField}}`, - animationUpdate: customMarkUpdateAnimation(interval, exchangeDuration) - }); - } - - return spec; -} - -function axisSpec(xAxis: IRankingBarSpec['xAxis'] = {}, yAxis: IRankingBarSpec['yAxis'] = {}) { - const leftAxis: ICartesianAxisSpec = { - orient: 'left', - type: 'band', - inverse: true, - // @ts-ignore - label: { style: yAxis.label }, - domainLine: { style: yAxis.domainLine }, - // @ts-ignore - grid: { style: yAxis.grid } - }; - const bottomAxis: ICartesianAxisSpec = { - orient: 'bottom', - type: 'linear', - nice: false, - animation: true, - // @ts-ignore - label: { style: xAxis.label }, - domainLine: { style: xAxis.domainLine }, - // @ts-ignore - grid: { style: xAxis.grid }, - // @ts-ignore - innerOffset: { right: '10%' } - }; - - if (xAxis.label) { - bottomAxis.label = xAxis.label; - } - return [leftAxis, bottomAxis]; -} - -function timeLabelSpec() { - return { - type: 'text', - dataId: 'time', - style: { - textBaseline: 'bottom', - fontSize: 200, - textAlign: 'end', - fontWeight: 600, - text: (datum: any) => datum.time, - x: (datum: any, ctx: any) => { - return ctx.vchart.getChart().getCanvasRect()?.width - 50; - }, - y: (datum: any, ctx: any) => { - return ctx.vchart.getChart().getCanvasRect()?.height - 80; - }, - fill: 'grey', - fillOpacity: 0.5 - } - }; -} - -function iconSpec( - iconPosition: IRankingBarSpec['iconPosition'] = 'bar-end', - iconShape: IRankingBarSpec['iconShape'] = 'circle', - { interval, exchangeDuration }: any -) { - return { - type: 'symbol', - dataId: 'timeData', - style: { - symbolType: iconShape, - stroke: 'white', - lineWidth: 1, - size: (data: any, ctx: any) => { - const vchart = ctx.vchart; - const series = vchart.getChart()?.getSeriesInIndex(0)[0]; - if (vchart && series) { - const bandwidth = series.getYAxisHelper().getBandwidth(0) ?? 0; - return Math.max(bandwidth - 4, 0); - } - }, - background: (data: any) => data.icon, - // globalZIndex 有bug,会有动画闪烁和报错 - // globalZIndex: 1, // 否则会被 region 区域 clip - x: (data: any, ctx: any) => { - const vchart = ctx.vchart; - const series = vchart.getChart()?.getSeriesInIndex(0)[0]; - if (vchart && series) { - const bandwidth = series.getYAxisHelper().getBandwidth(0) ?? 0; - if (iconPosition === 'bar-start') { - return bandwidth / 2; - } else if (iconPosition === 'axis') { - return -bandwidth / 2; - } else { - return series.dataToPositionX(data) - bandwidth / 2; - } - } - }, - y: (data: any, ctx: any) => { - const vchart = ctx.vchart; - const series = vchart.getChart()?.getSeriesInIndex(0)[0]; - if (vchart && series) { - const bandwidth = series.getYAxisHelper().getBandwidth(0) ?? 0; - return series.dataToPositionY(data) + bandwidth / 2; - } - }, - scaleY: iconShape === 'rect' ? 1.2 : 1 - }, - animationUpdate: customMarkUpdateAnimation(interval, exchangeDuration), - animationEnter: [ - { - type: 'moveIn', - duration: exchangeDuration, - easing: 'cubicInOut', - options: { - direction: 'y', - orient: 'negative', - point: (datum: any, element: any, param: any) => { - return { - y: param.groupHeight + element.getBounds().height() - }; - } - } - } - ], - animationExit: [ - { - type: 'moveOut', - duration: exchangeDuration, - easing: 'cubicInOut', - options: { - direction: 'y', - orient: 'negative' - } - } - ] - }; -} - -function customMarkUpdateAnimation(duration: number, exchangeDuration: number) { - return [ - { - duration: exchangeDuration, - easing: 'cubicInOut', - channel: ['y'] - }, - { - options: { excludeChannels: ['y'] }, - channel: ['x', 'x2', 'x1'], - easing: 'linear', - duration - } - ]; -} diff --git a/packages/vstory/src/util/output.ts b/packages/vstory/src/util/output.ts new file mode 100644 index 00000000..eb7b475c --- /dev/null +++ b/packages/vstory/src/util/output.ts @@ -0,0 +1,11 @@ +const styles: Record = { + warn: 'color: orange;', + error: 'color: red;', + info: 'color: blue;' +}; + +// 定义输出函数 +export function logger(type: string, ...args: any) { + // eslint-disable-next-line no-console + console.log(`%c[${type.toUpperCase()}] ${args}`, styles[type]); +}