├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── bower.json ├── example ├── dist │ └── index.html └── src │ ├── Main.purs │ └── Options.purs ├── package.json └── src └── Halogen └── ECharts.purs /.gitignore: -------------------------------------------------------------------------------- 1 | /.* 2 | !/.gitignore 3 | !/.travis.yml 4 | /bower_components/ 5 | /node_modules/ 6 | /output/ 7 | /example/dist/test.js 8 | package-lock.json 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | dist: trusty 3 | sudo: required 4 | node_js: stable 5 | install: 6 | - npm install 7 | - npm install -g bower 8 | - bower install 9 | script: 10 | - npm run build 11 | - npm run example 12 | after_success: 13 | - >- 14 | test $TRAVIS_TAG && 15 | echo $GITHUB_TOKEN | pulp login && 16 | echo y | pulp publish --no-push 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # purescript-halogen-echarts 2 | 3 | [![Latest release](http://img.shields.io/github/release/slamdata/purescript-halogen-echarts.svg)](https://github.com/slamdata/purescript-halogen-echarts/releases) 4 | [![Build status](https://travis-ci.org/slamdata/purescript-halogen-echarts.svg?branch=master)](https://travis-ci.org/slamdata/purescript-halogen-echarts) 5 | 6 | Halogen integration for Echarts via the `purescript-echarts` library. 7 | 8 | ## Installation 9 | 10 | ``` purescript 11 | bower install purescript-halogen-echarts 12 | ``` 13 | 14 | ## Notes 15 | 16 | - `purescript-echarts` depends on the specific `echarts` version _~2.1.10_. 17 | - Please include the `echarts-all.js` file from `echarts` via `script` tag in your html, or concatenate it with the bundled JavaScript file. 18 | 19 | ## Example 20 | 21 | ``` 22 | npm run example 23 | open example/dist/index.html 24 | ``` 25 | 26 | ## Documentation 27 | 28 | Module documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-halogen-echarts). 29 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "purescript-halogen-echarts", 3 | "license": "Apache-2.0", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/slamdata/purescript-halogen-echarts.git" 7 | }, 8 | "ignore": [ 9 | "**/.*", 10 | "bower_components", 11 | "node_modules", 12 | "output", 13 | "test", 14 | "bower.json", 15 | "package.json" 16 | ], 17 | "dependencies": { 18 | "purescript-halogen": "^3.1.1", 19 | "purescript-halogen-css": "^7.0.0", 20 | "purescript-echarts": "^10.1.0" 21 | }, 22 | "devDependencies": { 23 | "purescript-random": "^3.0.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | purescript-halogen-echarts examples 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /example/src/Main.purs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Prelude 4 | 5 | import Control.Monad.Aff (Aff) 6 | import Control.Monad.Eff (Eff) 7 | import Control.Monad.Eff.Class (liftEff) 8 | import Control.Monad.Eff.Random (randomInt, RANDOM) 9 | import Data.Array ((!!), length, snoc, sort, reverse, head, filter) 10 | import Data.Foldable (for_) 11 | import Data.Maybe (Maybe(..), maybe) 12 | import Data.Tuple.Nested ((/\)) 13 | import ECharts.Monad (interpret) 14 | import Halogen as H 15 | import Halogen.Aff (runHalogenAff, awaitBody) 16 | import Halogen.ECharts as EC 17 | import Halogen.HTML as HH 18 | import Halogen.HTML.Events as HE 19 | import Halogen.VDom.Driver (runUI) 20 | import Options (options) 21 | 22 | randomInArray ∷ ∀ e a. Array a → Eff (random ∷ RANDOM|e) (Maybe a) 23 | randomInArray arr = do 24 | n ← randomInt 0 (length arr - 1) 25 | pure $ arr !! n 26 | 27 | type State = 28 | { arr ∷ Array Int } 29 | 30 | 31 | initialState ∷ ∀ a. a → State 32 | initialState _ = { arr: [ ] } 33 | 34 | data Query a 35 | = SetRandomOption Int a 36 | | AddChart a 37 | | RemoveChart Int a 38 | | HandleEChartsMessage Int EC.EChartsMessage a 39 | 40 | type Slot = Int 41 | 42 | type AppEffects = EC.EChartsEffects ( random ∷ RANDOM ) 43 | 44 | type AffCharts = Aff AppEffects 45 | 46 | type HTML = H.ParentHTML Query EC.EChartsQuery Int AffCharts 47 | type DSL = H.ParentDSL State Query EC.EChartsQuery Int Void AffCharts 48 | 49 | comp ∷ H.Component HH.HTML Query Unit Void AffCharts 50 | comp = H.parentComponent 51 | { initialState 52 | , render 53 | , eval 54 | , receiver: const Nothing 55 | } 56 | 57 | render ∷ State → HTML 58 | render state = 59 | HH.div_ 60 | $ [ HH.h1_ [ HH.text "purescript-halogen-echarts" ] 61 | , HH.button 62 | [ HE.onClick (HE.input_ AddChart) ] 63 | [ HH.text "Add chart" ] 64 | ] 65 | <> map renderOne state.arr 66 | where 67 | renderOne ix = 68 | HH.div_ 69 | [ HH.div_ 70 | [ HH.slot ix (EC.echarts Nothing) ({width: 400, height: 300} /\ unit) 71 | (Just <<< H.action <<< HandleEChartsMessage ix) 72 | ] 73 | , HH.button 74 | [ HE.onClick (HE.input_ (SetRandomOption ix)) ] 75 | [ HH.text "Set random option" ] 76 | , HH.button 77 | [ HE.onClick (HE.input_ (RemoveChart ix)) ] 78 | [ HH.text "Remove" ] 79 | ] 80 | 81 | eval ∷ Query ~> DSL 82 | eval (SetRandomOption ix next) = do 83 | mbopt ← liftEff $ randomInArray options 84 | for_ mbopt \opt → 85 | void $ H.query ix $ H.action $ EC.Reset $ interpret opt 86 | pure next 87 | eval (AddChart next) = do 88 | H.modify (\x → x{arr = snoc x.arr (maybe 0 (add one) $ head $ reverse $ sort x.arr)}) 89 | pure next 90 | eval (RemoveChart ix next) = do 91 | H.modify (\x → x{arr = filter (_ /= ix) x.arr}) 92 | pure next 93 | eval (HandleEChartsMessage ix EC.Initialized next) = do 94 | mbopt ← liftEff $ randomInArray options 95 | for_ mbopt \opt → 96 | void $ H.query ix $ H.action $ EC.Set $ interpret opt 97 | pure next 98 | eval (HandleEChartsMessage ix (EC.EventRaised evt) next) = do 99 | pure next 100 | 101 | 102 | main ∷ Eff AppEffects Unit 103 | main = runHalogenAff do 104 | body ← awaitBody 105 | runUI comp unit body 106 | -------------------------------------------------------------------------------- /example/src/Options.purs: -------------------------------------------------------------------------------- 1 | module Options (options) where 2 | 3 | import Prelude 4 | 5 | import Data.Foldable as F 6 | 7 | import ECharts.Commands as E 8 | import ECharts.Types as ET 9 | import ECharts.Types.Phantom as ETP 10 | import ECharts.Monad (DSL') 11 | 12 | lineOptions ∷ DSL' ETP.OptionI 13 | lineOptions = do 14 | E.tooltip E.triggerAxis 15 | E.legend do 16 | E.leftLeft 17 | E.items 18 | $ map ET.strItem 19 | [ "email marketing" 20 | , "affiliate advertising" 21 | , "video ads" 22 | , "direct access" 23 | , "search engine" 24 | ] 25 | E.toolbox do 26 | E.shown 27 | E.leftRight 28 | E.topBottom 29 | E.feature do 30 | E.dataView do 31 | E.hidden 32 | E.readOnly false 33 | E.magicType do 34 | E.magics do 35 | E.magicStack 36 | E.magicTiled 37 | E.magicBar 38 | E.magicLine 39 | E.restore E.shown 40 | E.saveAsImage E.shown 41 | E.xAxis do 42 | E.axisType ET.Category 43 | E.disabledBoundaryGap 44 | E.items 45 | $ map ET.strItem 46 | [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ] 47 | E.yAxis $ E.axisType $ ET.Value 48 | E.series do 49 | E.line do 50 | E.name "email marketing" 51 | E.items $ map ET.numItem [ 120.0, 132.0, 101.0, 134.0, 90.0, 230.0, 210.0 ] 52 | E.line do 53 | E.name "affiliate advertising" 54 | E.items $ map ET.numItem [ 220.0, 182.0, 191.0, 234.0, 290.0, 330.0, 310.0 ] 55 | E.line do 56 | E.name "video ads" 57 | E.stack "total" 58 | E.items $ map ET.numItem [ 150.0, 232.0, 201.0, 154.0, 190.0, 330.0, 410.0 ] 59 | E.line do 60 | E.name "direct access" 61 | E.items $ map ET.numItem [ 320.0, 332.0, 301.0, 334.0, 390.0, 330.0, 320.0 ] 62 | 63 | E.line do 64 | E.name "search engine" 65 | E.items $ map ET.numItem [ 820.0, 932.0, 901.0, 934.0, 1290.0, 1330.0, 1320.0 ] 66 | 67 | 68 | graphOptions ∷ DSL' ETP.OptionI 69 | graphOptions = do 70 | E.title $ E.text "Graph" 71 | E.tooltip $ pure unit 72 | E.animationDurationUpdate 1500 73 | E.animationEasingUpdateQuinticInOut 74 | E.series do 75 | E.graph do 76 | E.layoutNone 77 | E.symbolSize 50 78 | E.roam true 79 | E.label $ E.normalLabel E.shown 80 | 81 | E.edgeSymbols do 82 | E.circleEdgeSymbol 83 | E.arrowEdgeSymbol 84 | E.edgeSymbolSizes 4 10 85 | 86 | E.edgeLabel $ E.normalEdgeLabel $ E.textStyle $ E.fontSize 20 87 | 88 | E.lineStylePair$ E.normalLineStyle do 89 | E.opacity 0.9 90 | E.width 2 91 | E.curveness 0.0 92 | 93 | E.buildItems do 94 | E.addItem do 95 | E.name "one" 96 | E.x 300.0 97 | E.y 300.0 98 | E.addItem do 99 | E.name "two" 100 | E.x 600.0 101 | E.y 300.0 102 | E.addItem do 103 | E.name "three" 104 | E.x 450.0 105 | E.y 100.0 106 | E.addItem do 107 | E.name "four" 108 | E.x 450.0 109 | E.y 500.0 110 | E.buildLinks do 111 | E.addLink do 112 | E.sourceIx 0 113 | E.targetIx 1 114 | E.symbolSizes 5 20 115 | E.label $ E.normalLabel E.shown 116 | E.lineStylePair $ E.normalLineStyle do 117 | E.width 5 118 | E.curveness 0.2 119 | E.addLink do 120 | E.sourceName "two" 121 | E.targetName "three" 122 | E.label $ E.normalLabel E.shown 123 | E.lineStylePair$ E.normalLineStyle $ E.curveness 0.2 124 | E.addLink do 125 | E.sourceName "one" 126 | E.targetName "three" 127 | E.addLink do 128 | E.sourceName "two" 129 | E.targetName "three" 130 | E.addLink do 131 | E.sourceName "two" 132 | E.targetName "four" 133 | E.addLink do 134 | E.sourceName "one" 135 | E.targetName "four" 136 | 137 | 138 | radarOptions ∷ DSL' ETP.OptionI 139 | radarOptions = do 140 | E.radar do 141 | E.indicators do 142 | E.indicator do 143 | E.name "sales" 144 | E.max 6000.0 145 | E.indicator do 146 | E.name "Administration" 147 | E.max 16000.0 148 | E.indicator do 149 | E.name "IT" 150 | E.max 30000.0 151 | E.indicator do 152 | E.name "Development" 153 | E.max 52000.0 154 | E.indicator do 155 | E.name "Customer Support" 156 | E.max 38000.0 157 | E.indicator do 158 | E.name "Marketing" 159 | E.max 25000.0 160 | E.series $ E.radarSeries do 161 | E.name "budget vs spending" 162 | E.buildItems do 163 | E.addItem do 164 | E.name "Allocated" 165 | E.values [ 4300.0, 10000.0, 28000.0, 35000.0, 50000.0, 19000.0 ] 166 | E.addItem do 167 | E.name "Actual" 168 | E.values [ 5000.0, 14000.0, 28000.0, 31000.0, 42000.0, 21000.0 ] 169 | 170 | kOptions ∷ DSL' ETP.OptionI 171 | kOptions = do 172 | E.xAxis do 173 | E.axisType ET.Category 174 | E.items $ map ET.strItem ["2013/1/24", "2013/1/25", "2013/1/28", "2013/1/29", "2013/1/30" ] 175 | E.yAxis do 176 | E.axisType ET.Value 177 | E.min 2200.0 178 | E.scale true 179 | E.series $ E.candlestick do 180 | E.buildItems 181 | $ F.traverse_ (E.addItem <<< E.values) 182 | [ [ 2320.26, 2302.6, 2287.3, 2362.94 ] 183 | , [ 2300.00, 2291.3, 2288.26, 2308.38 ] 184 | , [ 2295.35, 2346.5, 2295.35, 2346.92 ] 185 | , [ 2347.22, 2358.98, 2337.35, 2363.8 ] 186 | , [ 2360.75, 2382.48, 2347.89, 2383.76 ] 187 | ] 188 | 189 | 190 | funnelOptions ∷ DSL' ETP.OptionI 191 | funnelOptions = do 192 | E.series $ E.funnel do 193 | E.ascending 194 | E.buildItems do 195 | E.addItem do 196 | E.name "foo" 197 | E.value 60.0 198 | E.addItem do 199 | E.name "bar" 200 | E.value 80.0 201 | E.addItem do 202 | E.name "baz" 203 | E.value 12.0 204 | E.addItem do 205 | E.name "quux" 206 | E.value 123.0 207 | 208 | 209 | options ∷ Array (DSL' ETP.OptionI) 210 | options = 211 | [ lineOptions 212 | , graphOptions 213 | , radarOptions 214 | , kOptions 215 | , funnelOptions 216 | ] 217 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "clean": "rm -rf output .pulp-cache example/dist/test.js", 5 | "build": "pulp build -- --censor-lib --strict", 6 | "example": "pulp browserify --include example/src --to example/dist/test.js", 7 | "build:non-strict": "pulp build -- --censor-lib" 8 | }, 9 | "dependencies": { 10 | "pulp": "^12.0.1", 11 | "purescript": "^0.11.6", 12 | "purescript-psa": "^0.5.1" 13 | }, 14 | "devDependencies": { 15 | "echarts": "cryogenian/echarts#item-value-unshift-prebuild" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Halogen/ECharts.purs: -------------------------------------------------------------------------------- 1 | module Halogen.ECharts 2 | ( echarts 3 | , echarts' 4 | , EChartsState 5 | , EChartsQuery(..) 6 | , EChartsMessage(..) 7 | , EChartsEffects 8 | ) where 9 | 10 | import Prelude 11 | 12 | import CSS.Geometry (width, height) 13 | import CSS.Size (px) 14 | import Control.Monad.Aff.AVar (AVAR) 15 | import Control.Monad.Aff.Class (class MonadAff) 16 | import Control.Monad.Eff.Class (liftEff) 17 | import Control.Monad.Eff.Exception (EXCEPTION) 18 | import Control.Monad.Eff.Ref (REF) 19 | import DOM (DOM) 20 | import Data.Foldable (for_, traverse_) 21 | import Data.Foreign (Foreign) 22 | import Data.Int (toNumber) 23 | import Data.Maybe (Maybe(..), maybe) 24 | import Data.Traversable (for) 25 | import Data.Tuple.Nested (type (/\), (/\)) 26 | import ECharts.Chart as EC 27 | import ECharts.Event as EE 28 | import ECharts.Theme as ETheme 29 | import ECharts.Types as ET 30 | import Halogen as H 31 | import Halogen.HTML as HH 32 | import Halogen.HTML.CSS (style) 33 | import Halogen.HTML.Properties as HP 34 | import Halogen.Query.EventSource as ES 35 | 36 | type EChartsState = 37 | { chart ∷ Maybe ET.Chart 38 | , width ∷ Int 39 | , height ∷ Int 40 | } 41 | 42 | data EChartsQuery a 43 | = Init (Maybe ETheme.Theme) a 44 | | HandleEvent ET.EChartsEvent (H.SubscribeStatus → a) 45 | | Dispose a 46 | | Set ET.Option a 47 | | Reset ET.Option a 48 | | Resize a 49 | | Clear a 50 | | SetDimensions { width ∷ Int, height ∷ Int } a 51 | | GetOptions (Maybe Foreign → a) 52 | | GetWidth (Int → a) 53 | | GetHeight (Int → a) 54 | | Dispatch ET.EChartsEvent a 55 | 56 | data EChartsMessage 57 | = Initialized 58 | | EventRaised ET.EChartsEvent 59 | 60 | type EChartsEffects eff = 61 | ( echarts ∷ ET.ECHARTS 62 | , dom ∷ DOM 63 | , avar ∷ AVAR 64 | , exception ∷ EXCEPTION 65 | , ref ∷ REF 66 | | eff 67 | ) 68 | 69 | type Dimensions = { width ∷ Int, height ∷ Int } 70 | 71 | type HTML = H.ComponentHTML EChartsQuery 72 | 73 | type DSL g = H.ComponentDSL EChartsState EChartsQuery EChartsMessage g 74 | 75 | echarts 76 | ∷ ∀ eff g 77 | . Maybe ETheme.Theme 78 | → (MonadAff (EChartsEffects eff) g) 79 | ⇒ H.Component HH.HTML EChartsQuery (Dimensions /\ Unit) EChartsMessage g 80 | echarts theme = 81 | echarts' theme \(dim /\ _) → 82 | Just $ H.action $ SetDimensions dim 83 | 84 | echarts' 85 | ∷ ∀ eff g i 86 | . (MonadAff (EChartsEffects eff) g) 87 | ⇒ Maybe ETheme.Theme 88 | → (Dimensions /\ i → Maybe (EChartsQuery Unit)) 89 | → H.Component HH.HTML EChartsQuery (Dimensions /\ i) EChartsMessage g 90 | echarts' theme receiver = H.lifecycleComponent 91 | { initialState: \({width, height} /\ _) → { width, height, chart: Nothing } 92 | , render 93 | , eval 94 | , initializer: Just (H.action $ Init theme) 95 | , finalizer: Nothing 96 | , receiver 97 | } 98 | 99 | render 100 | ∷ EChartsState → HTML 101 | render state = 102 | HH.div 103 | [ HP.ref $ H.RefLabel "echarts" 104 | , style do 105 | height $ px $ toNumber state.height 106 | width $ px $ toNumber state.width 107 | ] 108 | [] 109 | 110 | eval 111 | ∷ ∀ eff g 112 | . (MonadAff (EChartsEffects eff) g) 113 | ⇒ EChartsQuery ~> (DSL g) 114 | eval (Init theme next) = do 115 | H.getHTMLElementRef (H.RefLabel "echarts") 116 | >>= traverse_ \el → do 117 | chart ← liftEff $ maybe EC.init EC.initWithTheme theme el 118 | H.modify _{ chart = Just chart } 119 | H.subscribe 120 | $ ES.eventSource (EE.listenAll chart) 121 | ( Just <<< H.request <<< HandleEvent ) 122 | H.raise Initialized 123 | pure next 124 | eval (HandleEvent evt reply) = do 125 | H.raise $ EventRaised evt 126 | pure $ reply H.Listening 127 | eval (Dispose next) = do 128 | state ← H.get 129 | for_ state.chart $ liftEff <<< EC.dispose 130 | pure next 131 | eval (Set opts next) = do 132 | state ← H.get 133 | for_ state.chart $ liftEff <<< EC.setOption opts 134 | pure next 135 | eval (Reset opts next) = do 136 | state ← H.get 137 | for_ state.chart $ liftEff <<< EC.resetOption opts 138 | pure next 139 | eval (Resize next) = do 140 | state ← H.get 141 | for_ state.chart $ liftEff <<< EC.resize 142 | pure next 143 | eval (Clear next) = do 144 | state ← H.get 145 | for_ state.chart $ liftEff <<< EC.clear 146 | pure next 147 | eval (SetDimensions { width, height } next) = do 148 | state ← H.get 149 | 150 | -- Only trigger a resize is the dimensions have actually changed. 151 | when (width /= state.width || height /= state.height) 152 | do H.modify _{ width = width, height = height } 153 | for_ state.chart $ liftEff <<< EC.resize 154 | pure next 155 | eval (GetOptions continue) = do 156 | state ← H.get 157 | mbOptions ← for state.chart $ liftEff <<< EC.getOption 158 | pure $ continue mbOptions 159 | eval (GetWidth continue) = do 160 | map continue $ H.gets _.width 161 | eval (GetHeight continue) = do 162 | map continue $ H.gets _.height 163 | eval (Dispatch a next) = do 164 | state ← H.get 165 | for_ state.chart $ EE.dispatch a 166 | pure next 167 | --------------------------------------------------------------------------------