├── .DS_Store ├── LICENSE ├── README.md ├── build.xml ├── classic └── Readme.md ├── examples ├── .DS_Store ├── Readme.md ├── basicMap │ ├── basicMap-example1.html │ ├── basicMap-example1.js │ ├── basicMap-example2.html │ ├── basicMap-example2.js │ ├── basicMap-example3.html │ ├── basicMap-example3.js │ ├── basicMap-example4.html │ └── basicMap-example4.js ├── cartoAccount │ ├── cartoAccount-example1.html │ └── cartoAccount-example1.js ├── chartMap │ ├── chartMap-example1.html │ └── chartMap-example1.js ├── fireMap │ ├── fireMap-example1.html │ ├── fireMap-example1.js │ ├── fireMap-example2.html │ ├── fireMap-example2.js │ ├── fireMap-example3.html │ └── fireMap-example3.js ├── gridMap │ ├── gridMap-example1.html │ ├── gridMap-example1.js │ ├── gridMap-example2.html │ ├── gridMap-example2.js │ ├── gridMap-example3.html │ ├── gridMap-example3.js │ ├── gridMap-example4.html │ ├── gridMap-example4.js │ ├── gridMap-example5.html │ ├── gridMap-example5.js │ ├── gridMap-example6.html │ ├── gridMap-example6.js │ ├── gridMap-example7.html │ └── gridMap-example7.js ├── gridpanel │ ├── gridPanel-example3.js │ ├── gridpanel-example1.html │ ├── gridpanel-example1.js │ ├── gridpanel-example2.html │ ├── gridpanel-example2.js │ └── gridpanel-example3.html ├── layerDemo │ ├── layerDemo-example1.html │ └── layerDemo-example1.js ├── playMap │ ├── playMap-example1.html │ └── playMap-example1.js ├── storeBinding │ ├── storeBinding-example1.html │ └── storeBinding-example1.js └── tornados │ ├── tornado-example.html │ └── tornado-example.js ├── licenses └── Readme.md ├── modern └── Readme.md ├── overrides └── Readme.md ├── package.json ├── resources └── Readme.md ├── sass ├── Readme.md ├── config.rb ├── etc │ └── Readme.md ├── example │ ├── custom.js │ ├── fashion.html │ ├── render.js │ └── theme.html ├── src │ └── Readme.md └── var │ └── Readme.md └── src ├── .DS_Store ├── AbstractLayer.js ├── CartoBasemaps.js ├── CartoDataModel.js ├── CartoFilter.js ├── CartoGroupBy.js ├── CartoMap.js ├── CartoProxy.js ├── CartoSqlMixin.js ├── CartoStore.js ├── CountryCodesLatLongISO3166.js ├── LayerManager.js ├── LeafletFunctionsMixin.js ├── Readme.md ├── css ├── Css.js ├── HeatMap.js ├── Intensity.js ├── Line.js ├── Point.js ├── Polygon.js ├── Torque.js └── TorqueCat.js ├── layer ├── LayerBase.js ├── LayerGroup.js └── Torque.js ├── mixin └── DataContainingLayer.js ├── sql ├── CartoField.js ├── CartoFrom.js ├── CartoSql.js └── CartoTable.js ├── sublayer ├── CartoDb.js └── SubLayerBase.js └── util ├── LayerCollection.js ├── SubLayerCollection.js └── TableCollection.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrestoneDigital/extjs-carto/a67036b54c48717290eb6cfc996cd37644cdc46f/.DS_Store -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # extjs-carto 2 | Native components for ExtJS to interact with Carto map layers, data and visualizations. 3 | 4 | 5 | ## CartoMap.js 6 | 7 | ### Configs 8 | 9 | Name | Type | Default | Description 10 | --- | --- | --- | --- 11 | `cartoMap` | [L.map] | [L.map] | The leaflet map for this component. 12 | `zoom` | Number | 4 | A zoom value to initialize the `cartoMap` with. 13 | `scrollWheelZoom` | Boolean | true | `true` to allow the map to be scrolled by the mouse wheel. 14 | `basemap` | String
Object
[L.tileLayer] | 'positronLite' | The basemap to be used for the `cartoMap`. 15 | `bounds` | [LatLngBounds] | null | The bounds of the `cartoMap`. 16 | `minZoom` | Number | 3 | The minimum possible zoom level of the `cartoMap`. 17 | `maxZoom` | Number | 18 | The maximum possible zoom level of the `cartoMap`. 18 | `mapLock` | Boolean | false | `true` for the map to update the filters in every store found in `storesToLock` when the `cartoMap` bounds change. 19 | `layers` | Carto.util.LayerCollection | null | A collection of the layers of the `cartoMap`. 20 | `selection` | [Ext.data.Model] | null | The selected record of the `cartoMap`. 21 | `selectedAction` | String
String[] | null | The actions to take when a record is selected. 22 | `stores` | [Ext.data.Store] | null | The stores associated with each subLayer of the `cartoMap`. 23 | `storesToLock` | String[] | null | An array of storeIds to be passed the `cartoMap`'s bounds when `mapLock` is true. 24 | 25 | ### Instance Properties 26 | 27 | Name | Type | Default | Description 28 | --- | --- | --- | --- 29 | `maskWhileLoading` | Boolean | false | `true` to mask the map component while tiles are loading. 30 | `loadingMessage` | String | 'Loading Tiles...' | The message to display while the tiles are loading. 31 | 32 | ### Binding 33 | 34 | The `map`'s selection is two-way bindable, similarly to other Extjs components. This means it plays well with things like `grid`s. 35 | 36 | #### Example 37 | 38 | ```javascript 39 | { 40 | xtype: 'grid', 41 | bind: { 42 | selection: '{selectedItem}', 43 | store: '{sampleStore}' 44 | } 45 | }, { 46 | xtype: 'cartoMap', 47 | bind: { 48 | selection: '{selectedItem}' 49 | }, 50 | basemap: 'darkMatterLite', 51 | layers: [{ 52 | subLayers: [{ 53 | bind: '{sampleStore}' 54 | }] 55 | }] 56 | } 57 | ``` 58 | 59 | #### Available Basemaps 60 | 61 | * positron 62 | * positronLite 63 | * positronLabelsBelow 64 | * darkMatter 65 | * darkMatterLite 66 | * darkMatterLabelsBelow 67 | * cartoWorldEco 68 | * cartoWorldFlatBlue 69 | * cartoWorldMidnightCommander 70 | * cartoAntique 71 | * toner 72 | * tonerLite 73 | * tonerLabelsBelow 74 | * tonerBackground 75 | * tonerLines 76 | * tonerHybrid 77 | * watercolor 78 | 79 | ##### Example Usage 80 | 81 | ```javascript 82 | { 83 | xtype: 'cartoMap', 84 | basemap: 'darkMatterLite' 85 | } 86 | ``` 87 | 88 | #### Available Selected Actions 89 | 90 | * placeMarker 91 | * panTo 92 | 93 | ##### Example Usage 94 | 95 | ```javascript 96 | { 97 | xtype: 'cartoMap', 98 | selectedAction: 'panTo' 99 | } 100 | ``` 101 | 102 | ```javascript 103 | { 104 | xtype: 'cartoMap', 105 | selectedAction: ['panTo', 'placeMarker'] 106 | } 107 | ``` 108 | 109 | ## Layers 110 | 111 | Layers are a combination of data (from SQL) and styling (from CartoCSS) that render the map. 112 | Carto has multiple different types of layers (see the [demo][Layer Demos] for some examples), but there are some configs common to them all. 113 | 114 | ### Configs 115 | 116 | Name | Type | Default | Description 117 | --- | --- | --- | --- 118 | `cartoLayer` | Layer | null | The underlying Layer object. 119 | `layerId` | String | Auto-generated id | The key by which this layer can be retrieved, removed, etc. 120 | `username` | String | '' | The username for the associated carto account. 121 | `table` | String | '' | The table that this layer draws from. 122 | `hidden` | Boolean | false | Set to `true` to hide this layer. 123 | `mapZIndex` | Number | null | Defines the order that the layers are rendered on the `map`. 124 | 125 | ## Layer Groups 126 | 127 | Carto can combine multiple layers into one layer group that is created and rendered as one layer, rather than multiple. 128 | 129 | ### Configs 130 | 131 | Name | Type | Default | Description 132 | --- | --- | --- | --- 133 | `subLayers` | Carto.util.SubLayerCollection | null | The collection of [Carto.sublayer.SubLayerBase] objects associated with this layer group. 134 | 135 | ## SubLayers 136 | 137 | ### Configs 138 | 139 | Name | Type | Default | Description 140 | --- | --- | --- | --- 141 | `layer` | [Carto.layer.LayerGroup] | null | The [Carto.layer.LayerGroup] that owns this subLayer. 142 | 143 | See also: [Carto.mixin.DataContainingLayer] 144 | 145 | ## Torque Layers 146 | 147 | Torque layers combine with [Carto.css.Torque][CartoCSS] to create powerful layer objects that can accomplish much more than traditional map layers. 148 | 149 | See also: [Carto.mixin.DataContainingLayer] 150 | 151 | ##### Example Usage 152 | 153 | ```javascript 154 | { 155 | xtype: 'cartoMap', 156 | layers: [{ 157 | type: 'torque', 158 | css: { 159 | type: 'torque' // or heatmap, torquecat 160 | }, 161 | ... 162 | }] 163 | } 164 | ``` 165 | 166 | ## DataContainingLayer.js 167 | 168 | Most layers (like [Carto.layer.Torque] and [Carto.sublayer.SubLayerBase]) contain data. 169 | This mixin defines the SQL, CartoCss, and store functionality for layers that render data. 170 | 171 | ### Configs 172 | 173 | Name | Type | Default | Description 174 | --- | --- | --- | --- 175 | `store` | [Carto.CartoStore] | null | A [Carto.CartoStore] associated with this layer. If defined, it will create the SQL for this layer. 176 | `sql` | String | '' | SQL for this layer to use when it is created. 177 | `css` | Object
String
String[] | [Carto.css.Point][CartoCSS] | The CartoCSS definition for this layer. 178 | `selection` | [Ext.data.Model] | null | The layer's current selected record. 179 | `interactivity` | Object | null | Use `enable: true` to enable interactity on this layer. 180 | 181 | ## CartoCSS 182 | 183 | CartoCSS defines how a layer is styled on the map. 184 | There are multiple types that are available to be used as-is or extended as appropriate. 185 | 186 | Name | Type | Description 187 | --- | --- | --- 188 | `point` | Carto.css.Point | A generic point-based style. 189 | `line` | Carto.css.Line | A generic line-based style. 190 | `polygon` | Carto.css.Polygon | A generic polygon-based style. 191 | `intensity` | Carto.css.Intensity | Point style with multiplying effect. 192 | `heatmap` | Carto.css.HeatMap | Torque style with multiplying effect. 193 | `torque` | Carto.css.Torque | Torque style for showing time-based effects. 194 | `torquecat` | Carto.css.TorqueCat | Torque style with added categorical grouping. 195 | 196 | ##### Example Usage 197 | 198 | ```javascript 199 | { 200 | css: { 201 | type: 'point', 202 | // the value config will extend, not overwrite 203 | value: { 204 | markerColor: 'blue' 205 | } 206 | } 207 | } 208 | ``` 209 | 210 | ## CartoStore.js 211 | 212 | ### Configs 213 | 214 | Name | Type | Default | Description 215 | --- | --- | --- | --- 216 | `groupBy` | [Carto.CartoGroupBy] | null | A groupBy object defining the GROUP BY clause of the `Carto.CartoProxy`'s SQL. 217 | 218 | 219 | ## CartoProxy.js 220 | 221 | ### Configs 222 | 223 | Name | Type | Default | Description 224 | --- | --- | --- | --- 225 | 226 | ## CartoGroupBy.js 227 | 228 | This is an SQL helper object for defining the GROUP BY clause in the SQL. 229 | 230 | ### Configs 231 | 232 | Name | Type | Default | Description 233 | --- | --- | --- | --- 234 | `fields` | Object[]
String[] | null | An array of field configs, in the order they should be presented in the GROUP BY clause. 235 | `countName` | String | 'cnt' | The name of the field that should contain the counts of the different groups. 236 | 237 | In addition, the [Carto.CartoGroupBy] object uses optional extra properties of the [Ext.data.field.Field] that are not native. 238 | 239 | Name | Type | Default | Description 240 | --- | --- | --- | --- 241 | `property` | String | undefined | Specifies the name of the column for this field, if different from the `name` of the field. 242 | `sql` | String | undefined | Use this to force the query to use this SQL for this field. Useful for more complicated queries. 243 | `aggregateType` | String | undefined | An SQL function for aggregating on this field. If specified, this field will not be included in the GROUP BY clause. 244 | 245 | ## Demos 246 | 247 | ### Basic 248 | 249 | * [Visualization of a Map in Ext JS](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/basicMap/basicMap-example1.html) 250 | * [A Map centered on Japan](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/basicMap/basicMap-example2.html) 251 | * [A Map with a simple Carto layer](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/basicMap/basicMap-example3.html) 252 | * [A Map whose layers can be added and removed](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/basicMap/basicMap-example4.html) 253 | 254 | ### Grid/Map 255 | 256 | * [Grid and Map bound to Carto Store](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/gridMap/gridMap-example1.html) 257 | * [Map with hidden layer and multiple selected actions](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/gridMap/gridMap-example2.html) 258 | * [Grid locked to Map bounds (with tooltip)](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/gridMap/gridMap-example3.html) 259 | * [Grid and Map with filter options](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/gridMap/gridMap-example4.html) 260 | * [Grid and Map with auto filter options](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/gridMap/gridMap-example5.html) 261 | * [Grid and Map with combo filter](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/gridMap/gridMap-example6.html) 262 | * [Grid and Map with combo filter](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/gridMap/gridMap-example7.html) 263 | 264 | ### Carto Account 265 | 266 | * [Carto Stores with tables and columns](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/cartoAccount/cartoAccount-example1.html) 267 | 268 | ### Chart/Map 269 | 270 | * [Chart and Map filtered by text input](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/chartMap/chartMap-example1.html) 271 | 272 | ### Layer Demos 273 | 274 | * [Demonstration of multiple layer types (point, polygon, heatmap, torque)](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/layerDemo/layerDemo-example1.html) 275 | 276 | ### Store Binding 277 | 278 | * [Grid and two Maps bound to one Carto Store](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/storeBinding/storeBinding-example1.html) 279 | 280 | ### Fire Map 281 | 282 | * [Wildfire Map with two styled layers](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/fireMap/fireMap-example1.html) 283 | * [Wildfire Map with styled layer and heatmap layer](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/fireMap/fireMap-example3.html) 284 | 285 | ### [Wildfire Exploration](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/fireMap/fireMap-example2.html) 286 | 287 | ### [Carto Map Explorer](http://rawgit.com/CrestoneDigital/extjs-carto/master/examples/playMap/playMap-example1.html) 288 | 289 | 290 | [Ext.data.Model]: http://docs.sencha.com/extjs/6.2.0/classic/Ext.data.Model.html 291 | [Ext.data.Store]: http://docs.sencha.com/extjs/6.2.0/classic/Ext.data.Store.html 292 | [L.tileLayer]: http://leafletjs.com/reference.html#tilelayer 293 | [L.map]: http://leafletjs.com/reference.html#map-usage 294 | [LatLngBounds]: http://leafletjs.com/reference.html#latlngbounds 295 | [Carto.CartoGroupBy]: https://github.com/CrestoneDigital/extjs-carto/blob/master/README.md#cartogroupbyjs 296 | [Carto.sublayer.SubLayerBase]: https://github.com/CrestoneDigital/extjs-carto/blob/master/README.md#sublayers 297 | [Ext.data.field.Field]: http://docs.sencha.com/extjs/6.2.1/classic/Ext.data.field.Field.html 298 | [Carto.layer.LayerGroup]: https://github.com/CrestoneDigital/extjs-carto/blob/master/README.md#layer-groups 299 | [Carto.mixin.DataContainingLayer]: https://github.com/CrestoneDigital/extjs-carto/blob/master/README.md#datacontaininglayerjs 300 | [Layer Demos]: https://github.com/CrestoneDigital/extjs-carto/blob/master/README.md#layer-demos 301 | [CartoCSS]: https://github.com/CrestoneDigital/extjs-carto/blob/master/README.md#cartocss 302 | [Carto.CartoStore]: https://github.com/CrestoneDigital/extjs-carto/blob/master/README.md#cartostorejs 303 | 304 | # Presentations 305 | 306 | ### [SlideShare - SenchaCon 2016: Integrating Geospatial Maps & Big Data Using CARTO via Ext JS Components](https://www.slideshare.net/senchainc/senchacon-2016-integrating-geospatial-maps-big-data-using-cartodb-via-ext-js-components-michael-giddens/1) 307 | [Video can be found here of the talk.](https://www.senchacon.com/videos-slides/#Top) 308 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /classic/Readme.md: -------------------------------------------------------------------------------- 1 | This classic-specific directory can include any (if not all) of the following directories: 2 | 3 | * overrides: Any classes in this directory will be automatically required and included in the classic build. 4 | In case any of these classes define an Ext JS override (using Ext.define with an "override" property), 5 | that override will in fact only be included in the build if the target class specified 6 | in the "override" property is also included. 7 | 8 | - sass: Any classic-specific style rules should reside in this package, following the same structure 9 | as the directory in the package root (see package.json for more information). 10 | 11 | - src: The classic-specific classes of this package should reside in this directory. -------------------------------------------------------------------------------- /examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrestoneDigital/extjs-carto/a67036b54c48717290eb6cfc996cd37644cdc46f/examples/.DS_Store -------------------------------------------------------------------------------- /examples/Readme.md: -------------------------------------------------------------------------------- 1 | # carto/examples 2 | 3 | This folder contains example applications demonstrating this package. Each of 4 | these applications will be built as part of the package build: 5 | 6 | cd /path/to/package 7 | sencha package build 8 | 9 | As applications, they can also be built individually: 10 | 11 | cd /path/to/package/examples/example-app 12 | sencha app build 13 | 14 | Or you can build all examples as a group: 15 | 16 | cd /path/to/package 17 | sencha ant examples 18 | 19 | The ideal location for the example builds to reside is the `"./build"` folder: 20 | 21 | /path/to/package/ 22 | src/ 23 | resources/ 24 | ... 25 | examples/ 26 | example-app/ 27 | other-example/ 28 | ... 29 | build/ 30 | resources/ 31 | examples/ 32 | example-app/ 33 | other-example/ 34 | 35 | This can be specified in the `".sencha/app/build.properties"` file for the 36 | example applications: 37 | 38 | build.dir=${package.build.dir}/examples/${app.name} 39 | -------------------------------------------------------------------------------- /examples/basicMap/basicMap-example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Basic Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/basicMap/basicMap-example1.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap' 6 | ]); 7 | 8 | 9 | /** 10 | * The most basic usage 11 | */ 12 | Ext.onReady(function () { 13 | Ext.QuickTips.init(); 14 | 15 | Ext.create('Ext.container.Viewport', { 16 | layout: 'fit', 17 | items: [{ 18 | xtype: "cartomap" 19 | }] 20 | }); 21 | 22 | }); 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/basicMap/basicMap-example2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Basic Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/basicMap/basicMap-example2.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap' 6 | ]); 7 | 8 | 9 | 10 | 11 | /** 12 | * 13 | * Basic map Centered on Japan using Japan ISO3166 code 14 | */ 15 | Ext.onReady(function () { 16 | Ext.QuickTips.init(); 17 | 18 | Ext.create('Ext.container.Viewport', { 19 | layout: 'fit', 20 | items: [{ 21 | xtype: "cartomap", 22 | center: 'jp' 23 | }] 24 | }); 25 | 26 | }); 27 | 28 | -------------------------------------------------------------------------------- /examples/basicMap/basicMap-example3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Basic Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/basicMap/basicMap-example3.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Carto.CartoStore' 7 | ]); 8 | 9 | /** 10 | * 11 | * Basic map Centered on US with a starter layer 12 | */ 13 | Ext.onReady(function () { 14 | Ext.QuickTips.init(); 15 | 16 | Ext.create('Ext.container.Viewport', { 17 | layout: 'fit', 18 | items: [{ 19 | xtype: "cartomap", 20 | center: 'us', 21 | layers: [{ 22 | subLayers: [{ 23 | store: { 24 | autoLoad: true, 25 | proxy: { 26 | username: 'extjscarto', 27 | table: 'petroleum_refineries' 28 | } 29 | } 30 | }] 31 | 32 | }] 33 | }] 34 | }); 35 | 36 | }); -------------------------------------------------------------------------------- /examples/basicMap/basicMap-example4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Basic Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/basicMap/basicMap-example4.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | 10 | var dataStore = Ext.create('Ext.data.Store',{ 11 | data: [{ 12 | name: 'Petroleum Refineries', 13 | value: 'petroleum_refineries', 14 | mapLayer: { 15 | layerId: 'petroleumLayer', 16 | subLayers: [{ 17 | store: { 18 | autoLoad: true, 19 | proxy: { 20 | username: 'extjscarto', 21 | table: 'petroleum_refineries' 22 | } 23 | } 24 | }] 25 | } 26 | }] 27 | }); 28 | 29 | 30 | var mapController = Ext.create('Ext.app.ViewController',{ 31 | onLayerAdd: function(combo, record, eOpts){ 32 | this.lookup('map').addLayer(record.data.mapLayer, function(){ 33 | console.log('mapLayerAdded'); 34 | }); 35 | this.lookup('removeButton').enable(); 36 | }, 37 | removeMapLayer: function(button, e, eOpts) { 38 | this.lookup('map').removeLayer('petroleumLayer', true); 39 | this.lookup('combo').reset(); 40 | button.disable(); 41 | } 42 | }); 43 | 44 | /** 45 | * 46 | * Basic map w/toolbar Centered on US. 47 | */ 48 | Ext.onReady(function () { 49 | Ext.QuickTips.init(); 50 | 51 | Ext.create('Ext.container.Viewport', { 52 | layout: 'fit', 53 | items: [{ 54 | xtype: 'panel', 55 | layout: 'fit', 56 | controller: mapController, 57 | items: [{ 58 | xtype: "cartomap", 59 | center: 'us', 60 | reference: 'map' 61 | }], 62 | tbar: [{ 63 | xtype: 'combobox', 64 | reference: 'combo', 65 | fieldLabel: 'Select Layer', 66 | displayField: 'name', 67 | valueField: 'value', 68 | store: dataStore, 69 | listeners: { 70 | select: 'onLayerAdd' 71 | }, 72 | width: 350, 73 | editable: false 74 | },{ 75 | xtype: 'button', 76 | text: 'Remove Layer', 77 | handler: 'removeMapLayer', 78 | disabled: true, 79 | reference: 'removeButton' 80 | }] 81 | }] 82 | }); 83 | }); -------------------------------------------------------------------------------- /examples/cartoAccount/cartoAccount-example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Carto Account Demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/cartoAccount/cartoAccount-example1.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Carto.CartoStore', 7 | 'Carto.CartoProxy', 8 | 'Carto.CartoBasemaps', 9 | 'Ext.data.Store' 10 | ]); 11 | 12 | var columnsToIgnore = ['cartodb_id', 'the_geom', 'the_geom_webmercator']; 13 | var numberTypes = ['double precision', 'integer', 'number']; 14 | 15 | var mapController = Ext.create('Ext.app.ViewController',{ 16 | reset: function(all) { 17 | if (all) { 18 | this.lookup('tableBox').clearValue(); 19 | this.getStore('tables').removeAll(); 20 | } 21 | this.lookup('fieldBox').clearValue(); 22 | this.lookup('numberFieldBox').clearValue(); 23 | this.getStore('columns').removeAll(); 24 | }, 25 | onSelectUsername: function(field, e) { 26 | var value = field.getValue(); 27 | if (value !== this.getViewModel().get('username')) { 28 | this.reset(true); 29 | this.getViewModel().set('username', value); 30 | this.getStore('tables').getProxy().setUsername(value); 31 | this.getStore('columns').getProxy().setUsername(value); 32 | this.getStore('tables').load(); 33 | } 34 | }, 35 | catchError: function(store, records, successful) { 36 | if (!successful) { 37 | Ext.Msg.alert('Error', 'There was a problem loading your tables. Please check your username.', Ext.emptyFn); 38 | } 39 | }, 40 | onSelectTable: function(combo, record) { 41 | var value = record.get('table_name'); 42 | this.reset(false); 43 | this.getViewModel().set('table', value); 44 | this.getStore('columns').getProxy().setTable(value); 45 | this.getStore('columns').load(); 46 | } 47 | }); 48 | 49 | Ext.onReady(function () { 50 | Ext.QuickTips.init(); 51 | 52 | Ext.create('Ext.container.Viewport', { 53 | layout: 'fit', 54 | items: [{ 55 | xtype: 'panel', 56 | layout: { 57 | type: 'vbox', 58 | align: 'center', 59 | pack: 'center' 60 | }, 61 | controller: mapController, 62 | viewModel: { 63 | stores: { 64 | tables: { 65 | storeId: 'tablesStore', 66 | sorters: 'table_name', 67 | proxy: { 68 | type: 'carto', 69 | mode: 'tables' 70 | }, 71 | listeners: { 72 | load: 'catchError' 73 | } 74 | }, 75 | columns: { 76 | storeId: 'columnsStore', 77 | sorters: 'column_name', 78 | proxy: { 79 | type: 'carto', 80 | mode: 'columns' 81 | }, 82 | filters: [ 83 | function(data) { 84 | return columnsToIgnore.indexOf(data.get('column_name')) === -1; 85 | } 86 | ] 87 | }, 88 | numberColumns: { 89 | source: '{columns}', 90 | filters: [ 91 | function(data) { 92 | return numberTypes.indexOf(data.get('column_type')) > -1; 93 | } 94 | ] 95 | } 96 | }, 97 | data: { 98 | username: null, 99 | table: null 100 | } 101 | }, 102 | defaults: { 103 | xtype: 'combobox', 104 | valueField: 'column_name', 105 | displayField: 'column_name', 106 | labelWidth: 200, 107 | editable: false 108 | }, 109 | items: [{ 110 | xtype: 'textfield', 111 | reference: 'usernameField', 112 | fieldLabel: 'Username', 113 | editable: true, 114 | listeners: { 115 | blur: 'onSelectUsername' 116 | } 117 | }, { 118 | reference: 'tableBox', 119 | valueField: 'table_name', 120 | displayField: 'table_name', 121 | listeners: { 122 | select: 'onSelectTable' 123 | }, 124 | bind: { 125 | fieldLabel: '{username}\'s tables', 126 | store: '{tables}' 127 | } 128 | }, { 129 | reference: 'fieldBox', 130 | bind: { 131 | fieldLabel: '{table}\'s fields', 132 | store: '{columns}', 133 | disabled: '{!table}' 134 | } 135 | }, { 136 | reference: 'numberFieldBox', 137 | queryMode: 'local', 138 | bind: { 139 | fieldLabel: '{table}\'s number fields', 140 | store: '{numberColumns}', 141 | disabled: '{!table}' 142 | } 143 | }] 144 | }] 145 | }); 146 | }); -------------------------------------------------------------------------------- /examples/chartMap/chartMap-example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ChartMap demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/chartMap/chartMap-example1.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Carto.CartoStore' 7 | ]); 8 | 9 | 10 | Ext.onReady(function () { 11 | Ext.QuickTips.init(); 12 | 13 | Ext.create('Ext.container.Viewport', { 14 | layout: 'fit', 15 | items: [{ 16 | xtype: 'panel', 17 | layout: 'border', 18 | viewModel: { 19 | data: { 20 | filterCombo: { 21 | selection: { 22 | author_gender: null 23 | } 24 | }, 25 | filterField: { 26 | value: '' 27 | } 28 | }, 29 | stores: { 30 | layer: { 31 | type: 'carto', 32 | storeId: 'layer', 33 | autoLoad: true, 34 | filters: [{ 35 | property: 'author_gender', 36 | value: '{filterCombo.selection.author_gender}', 37 | disableOnEmpty: true 38 | }, { 39 | property: 'text', 40 | value: '{filterField.value}', 41 | operator: 'regex', 42 | disableOnEmpty: true 43 | }], 44 | proxy: { 45 | username: 'extjscarto', 46 | table: 'starwars' 47 | } 48 | }, 49 | chart: { 50 | type: 'carto', 51 | storeId: 'chart', 52 | autoLoad: true, 53 | filters: [{ 54 | property: 'author_gender', 55 | value: '{filterCombo.selection.author_gender}', 56 | disableOnEmpty: true 57 | }, { 58 | property: 'text', 59 | value: '{filterField.value}', 60 | operator: 'regex', 61 | disableOnEmpty: true 62 | }], 63 | proxy: { 64 | groupBy: 'sentiment', 65 | username: 'extjscarto', 66 | table: 'starwars' 67 | } 68 | }, 69 | combo: { 70 | type: 'carto', 71 | storeId: 'combo', 72 | autoLoad: true, 73 | proxy: { 74 | groupBy: 'author_gender', 75 | username: 'extjscarto', 76 | table: 'starwars' 77 | } 78 | } 79 | } 80 | }, 81 | tbar: [{ 82 | xtype: 'combo', 83 | reference: 'filterCombo', 84 | fieldLabel: 'Author Gender', 85 | forceSelection: true, 86 | bind: { 87 | store: '{combo}' 88 | }, 89 | displayField: 'author_gender', 90 | valueField: 'author_gender' 91 | }, { 92 | xtype: 'textfield', 93 | reference: 'filterField', 94 | publishes: ['value'], 95 | fieldLabel: 'Keyword' 96 | }], 97 | items: [{ 98 | xtype: "cartomap", 99 | region: 'center', 100 | center: 'us', 101 | layers: [{ 102 | subLayers: [{ 103 | bind: '{layer}', 104 | interactivity: { 105 | enable: true, 106 | tooltip: { 107 | enable: true 108 | }, 109 | fields: ['text'] 110 | }, 111 | css: [ 112 | "#layer {", 113 | " marker-line-width: 1;", 114 | " marker-line-color: #FFF;", 115 | " marker-line-opacity: 1;", 116 | " marker-width: 7;", 117 | " marker-fill: gray;", 118 | " marker-fill-opacity: 0.9;", 119 | " marker-allow-overlap: true;", 120 | "}", 121 | "#layer [sentiment = 'pos'] {", 122 | " marker-fill: blue;", 123 | "}", 124 | "#layer [sentiment = 'neg'] {", 125 | " marker-fill: red;", 126 | "}" 127 | ] 128 | }] 129 | }] 130 | }, { 131 | xtype: 'cartesian', 132 | region: 'west', 133 | split: true, 134 | width: '30%', 135 | bind: '{chart}', 136 | axes: [{ 137 | type: 'numeric', 138 | position: 'left', 139 | title: { 140 | text: 'Number', 141 | fontSize: 15 142 | }, 143 | fields: 'cnt' 144 | }, { 145 | type: 'category', 146 | position: 'bottom', 147 | title: { 148 | text: 'Sentiment', 149 | fontSize: 15 150 | }, 151 | fields: 'sentiment' 152 | }], 153 | series: { 154 | type: 'bar', 155 | renderer: function(sprite, config, rendererData, index) { 156 | return { 157 | fillStyle: (index === 0) ? 'gray' : (index === 1) ? 'blue' : 'red' 158 | }; 159 | }, 160 | subStyle: { 161 | stroke: '#1F6D91' 162 | }, 163 | xField: 'sentiment', 164 | yField: 'cnt' 165 | } 166 | }] 167 | }] 168 | }); 169 | }); -------------------------------------------------------------------------------- /examples/fireMap/fireMap-example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | FireMap demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/fireMap/fireMap-example1.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | var dataTextStore = Ext.create('Ext.data.Store',{ 10 | data: [{ 11 | title: 'Federal Fire Occurrence', 12 | total: '694,294', 13 | natural: '287,674 natural', 14 | human: '380,984 human', 15 | fromYear: '1980', 16 | toYear: '2013' 17 | }] 18 | }); 19 | 20 | var txtTpl = new Ext.XTemplate( 21 | '', 22 | '

{title}

', 23 | '

Explore {total} ({natural}, {human}) fire records collected by Federal land management agencies for fires that occurred from {fromYear} through {toYear} in the United States.

', 24 | '
' 25 | ); 26 | 27 | var flag = false 28 | 29 | var dataStore = Ext.create('Ext.data.Store',{ 30 | data: [{ 31 | name: 'Fire Map', 32 | value: 0, 33 | mapLayer: { 34 | layerId: 'fireLayer', 35 | subLayers: [{ 36 | store: { 37 | autoLoad: true, 38 | proxy: { 39 | username: 'crestonedigital', 40 | table: 'wildfire' 41 | } 42 | }, 43 | css: [ 44 | '#wildfire{', 45 | 'marker-fill-opacity: 0.05;', 46 | 'marker-line-color: #FFF;', 47 | 'marker-line-width: 0.0;', 48 | 'marker-line-opacity: 1;', 49 | 'marker-placement: point;', 50 | 'marker-type: ellipse;', 51 | 'marker-width: 6;', 52 | 'marker-fill: #FF5C00;', 53 | 'marker-allow-overlap: true;', 54 | '}', 55 | '#wildfire [zoom <18]{', 56 | 'marker-fill-opacity: 0.7;', 57 | '}', 58 | '#wildfire [zoom <9]{', 59 | 'marker-fill-opacity: 0.4;', 60 | 'marker-width: 5;', 61 | '}', 62 | '#wildfire [zoom <8]{', 63 | 'marker-fill-opacity: 0.2;', 64 | 'marker-width: 4;', 65 | '}', 66 | '#wildfire [zoom <7]{', 67 | 'marker-fill-opacity: 0.08;', 68 | 'marker-width: 3;', 69 | '}', 70 | '#wildfire [zoom <6]{', 71 | 'marker-fill-opacity: 0.07;', 72 | 'marker-width: 2;', 73 | '}', 74 | '#wildfire [zoom <5]{', 75 | 'marker-width: 1;', 76 | '}' 77 | ].join(' ') 78 | }] 79 | } 80 | },{ 81 | name: 'Causes Map', 82 | value: 1, 83 | mapLayer: { 84 | layerId: 'causesLayer', 85 | subLayers: [{ 86 | store: { 87 | autoLoad: true, 88 | proxy: { 89 | username: 'crestonedigital', 90 | table: 'wildfire' 91 | } 92 | }, 93 | css: [ 94 | '#wildfire {'+ 95 | 'marker-fill-opacity: 0.9;'+ 96 | 'marker-line-color: #000;'+ 97 | 'marker-line-width: 0;'+ 98 | 'marker-line-opacity: 0;'+ 99 | 'marker-placement: point;'+ 100 | 'marker-type: ellipse;'+ 101 | 'marker-width: 6;'+ 102 | 'marker-allow-overlap: true;'+ 103 | '}'+ 104 | '#wildfire[cause="Human"] {'+ 105 | 'marker-fill: #1F78B4;'+ 106 | '}'+ 107 | '#wildfire[cause="Natural"] {'+ 108 | 'marker-fill: #B2DF8A;'+ 109 | '}'+ 110 | '#wildfire [zoom <18]{'+ 111 | 'marker-fill-opacity: 0.7;'+ 112 | '}'+ 113 | '#wildfire [zoom <9]{'+ 114 | 'marker-fill-opacity: 0.4;'+ 115 | 'marker-width: 5;'+ 116 | '}'+ 117 | '#wildfire [zoom <8]{'+ 118 | 'marker-fill-opacity: 0.2;'+ 119 | 'marker-width: 4;'+ 120 | '}'+ 121 | '#wildfire [zoom <7]{'+ 122 | 'marker-fill-opacity: 0.08;'+ 123 | 'marker-width: 3;'+ 124 | '}'+ 125 | '#wildfire [zoom <6]{'+ 126 | 'marker-fill-opacity: 0.07;'+ 127 | 'marker-width: 2;'+ 128 | '}'+ 129 | '#wildfire [zoom <5]{'+ 130 | 'marker-width: 1;'+ 131 | '}' 132 | ].join(' ') 133 | }] 134 | } 135 | }] 136 | }); 137 | 138 | 139 | var mapController = Ext.create('Ext.app.ViewController',{ 140 | onLayerAdd: function(tag, newRecord, oldRecord){ 141 | var idx; 142 | if (newRecord.length > oldRecord.length) { 143 | idx = this.getDiff(newRecord, oldRecord); 144 | this.lookup('map').addLayer(dataStore.data.items[newRecord[idx]].get('mapLayer')); 145 | } else { 146 | idx = this.getDiff(oldRecord, newRecord); 147 | this.lookup('map').removeLayer(dataStore.data.items[oldRecord[idx]].get('mapLayer').layerId, true); 148 | } 149 | }, 150 | 151 | getDiff: function(arr1, arr2) { 152 | for (var i = 0; i < arr1.length; i++) { 153 | if (arr2.indexOf(arr1[i]) === -1) { 154 | return i; 155 | } 156 | } 157 | return null; 158 | } 159 | }); 160 | 161 | /** 162 | * 163 | * Basic map w/toolbar Centered on US. 164 | */ 165 | Ext.onReady(function () { 166 | Ext.QuickTips.init(); 167 | 168 | Ext.create('Ext.container.Viewport', { 169 | layout: 'fit', 170 | items: [{ 171 | xtype: 'panel', 172 | layout: 'fit', 173 | controller: mapController, 174 | items: [{ 175 | xtype: "cartomap", 176 | center: 'us', 177 | reference: 'map', 178 | basemap: 'darkMatterLite' 179 | }], 180 | tbar: [{ 181 | xtype: 'tagfield', 182 | reference: 'layers', 183 | fieldLabel: 'Select Layer', 184 | displayField: 'name', 185 | valueField: 'value', 186 | store: dataStore, 187 | listeners: { 188 | change: 'onLayerAdd' 189 | }, 190 | width: 350, 191 | editable: false 192 | }] 193 | }] 194 | }); 195 | }); -------------------------------------------------------------------------------- /examples/fireMap/fireMap-example2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | FireMap demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /examples/fireMap/fireMap-example3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | FireMap demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /examples/fireMap/fireMap-example3.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | 10 | var mapController = Ext.create('Ext.app.ViewController',{ 11 | onLayerChange: function(segButton, value, oldValue){ 12 | var map = this.lookup('map'); 13 | if (oldValue) { 14 | map.removeLayer(map.getLayers().first(), true); 15 | } 16 | map.addLayer(value); 17 | map.getLayer('layer').setStore(this.getStore('fireLayer')); 18 | 19 | // var map = this.lookup('map'); 20 | // if (oldValue.length) { 21 | // map.removeLayer(map.getLayers().first(), true); 22 | // } 23 | // map.addLayer(value[0]); 24 | // map.getLayer('layer').setStore(this.getStore('fireLayer')); 25 | } 26 | }); 27 | 28 | /** 29 | * 30 | * Basic map w/toolbar Centered on US. 31 | */ 32 | Ext.onReady(function () { 33 | Ext.QuickTips.init(); 34 | 35 | Ext.create('Ext.container.Viewport', { 36 | layout: 'fit', 37 | items: [{ 38 | xtype: 'panel', 39 | layout: 'fit', 40 | controller: mapController, 41 | viewModel: { 42 | stores: { 43 | fireLayer: { 44 | type: 'carto', 45 | autoLoad: true, 46 | onlyTiles: true, 47 | proxy: { 48 | username: 'crestonedigital', 49 | table: 'wildfire' 50 | } 51 | } 52 | } 53 | }, 54 | items: [{ 55 | xtype: "cartomap", 56 | center: 'us', 57 | reference: 'map', 58 | basemap: 'darkMatterLite' 59 | }], 60 | tbar: [{ 61 | xtype: 'segmentedbutton', 62 | reference: 'cssButton', 63 | listeners: { 64 | change: 'onLayerChange' 65 | }, 66 | items: [{ 67 | text: 'Intensity', 68 | value: { 69 | subLayers: { 70 | layerId: 'layer', 71 | css: { 72 | type: 'intensity', 73 | value: { 74 | markerFillOpacity: 0.05, 75 | markerLineWidth: 0.0, 76 | markerWidth: 6, 77 | markerFill: '#FF5C00', 78 | case: [{ 79 | condition: 'zoom<18', 80 | markerFillOpacity: 0.7 81 | }, { 82 | condition: 'zoom<9', 83 | markerFillOpacity: 0.4, 84 | markerWidth: 5 85 | }, { 86 | condition: 'zoom<8', 87 | markerFillOpacity: 0.2, 88 | markerWidth: 4 89 | }, { 90 | condition: 'zoom<7', 91 | markerFillOpacity: 0.08, 92 | markerWidth: 3 93 | }, { 94 | condition: 'zoom<6', 95 | markerFillOpacity: 0.07, 96 | markerWidth: 2 97 | }, { 98 | condition: 'zoom<5', 99 | markerWidth: 1 100 | }] 101 | } 102 | } 103 | } 104 | }, 105 | pressed: true 106 | }, { 107 | text: 'Heatmap', 108 | value: { 109 | type: 'torque', 110 | layerId: 'layer', 111 | css: { 112 | type: 'heatmap' 113 | } 114 | } 115 | }] 116 | }] 117 | }] 118 | }); 119 | }); -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Grid Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example1.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Carto.CartoStore' 7 | ]); 8 | 9 | 10 | 11 | var mapController = Ext.create('Ext.app.ViewController',{ 12 | onSelect: function(rowmodel, record) { 13 | this.lookup('southGrid').ensureVisible(record); 14 | } 15 | }); 16 | 17 | /** 18 | * 19 | * Basic map w/toolbar Centered on US. 20 | */ 21 | Ext.onReady(function () { 22 | Ext.QuickTips.init(); 23 | 24 | Ext.create('Ext.container.Viewport', { 25 | layout: 'fit', 26 | items: [{ 27 | xtype: 'panel', 28 | layout: 'border', 29 | viewModel: { 30 | stores: { 31 | layer: { 32 | type: 'carto', 33 | autoLoad: true, 34 | proxy: { 35 | username: 'extjscarto', 36 | table: 'petroleum_refineries' 37 | } 38 | } 39 | } 40 | }, 41 | controller: mapController, 42 | items: [{ 43 | xtype: "cartomap", 44 | region: 'center', 45 | center: 'us', 46 | reference: 'map', 47 | bind: { 48 | selection: '{selectedValue}' 49 | }, 50 | basemap: 'darkMatterLite', 51 | layers: [{ 52 | subLayers: [{ 53 | css: { 54 | type: 'intensity', 55 | }, 56 | bind: '{layer}', 57 | interactivity: { 58 | enable: true, 59 | fields: [ 60 | 'site_name', 'company', 'state', 'total_oper' 61 | ], 62 | tooltip: { 63 | enable: true 64 | } 65 | } 66 | }] 67 | 68 | }] 69 | },{ 70 | xtype: 'grid', 71 | region: 'south', 72 | reference: 'southGrid', 73 | split: true, 74 | idProperty: 'cartodb_id', 75 | bind: { 76 | selection: '{selectedValue}', 77 | store: '{layer}' 78 | }, 79 | listeners: { 80 | select: 'onSelect' 81 | }, 82 | height: 350, 83 | columns: [{ 84 | text: 'Site Name', 85 | dataIndex: 'site_name', 86 | flex: 1 87 | },{ 88 | text: 'Company', 89 | dataIndex: 'company', 90 | flex: 1 91 | },{ 92 | text: 'State', 93 | dataIndex: 'state', 94 | flex: 1 95 | },{ 96 | text: 'Total Operation', 97 | dataIndex: 'total_oper', 98 | flex: 1 99 | }] 100 | }] 101 | }] 102 | }); 103 | }); -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Grid Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example2.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | Ext.onReady(function () { 10 | Ext.QuickTips.init(); 11 | 12 | Ext.create('Ext.container.Viewport', { 13 | layout: 'fit', 14 | items: [{ 15 | xtype: 'panel', 16 | layout: 'border', 17 | viewModel: { 18 | stores: { 19 | layer: { 20 | type: 'carto', 21 | autoLoad: true, 22 | proxy: { 23 | enableLatLng: true, 24 | username: 'extjscarto', 25 | table: 'petroleum_refineries' 26 | } 27 | } 28 | } 29 | }, 30 | items: [{ 31 | xtype: "cartomap", 32 | region: 'center', 33 | center: 'us', 34 | reference: 'map', 35 | bind: { 36 | selection: '{selectedValue}' 37 | }, 38 | selectedAction: ['panTo','placeMarker'], 39 | basemap: 'darkMatterLite', 40 | layers: [{ 41 | hidden: true, 42 | subLayers: [{ 43 | bind: '{layer}', 44 | interactivity: { 45 | enable: true, 46 | fields: [ 47 | 'site_name', 'company', 'state', 'total_oper' 48 | ] 49 | } 50 | }] 51 | 52 | }] 53 | },{ 54 | xtype: 'grid', 55 | region: 'south', 56 | reference: 'southGrid', 57 | split: true, 58 | idProperty: 'cartodb_id', 59 | bind: { 60 | selection: '{selectedValue}', 61 | store: '{layer}' 62 | }, 63 | height: 350, 64 | columns: [{ 65 | text: 'Site Name', 66 | dataIndex: 'site_name', 67 | flex: 1 68 | },{ 69 | text: 'Company', 70 | dataIndex: 'company', 71 | flex: 1 72 | },{ 73 | text: 'State', 74 | dataIndex: 'state', 75 | flex: 1 76 | },{ 77 | text: 'Total Operation', 78 | dataIndex: 'total_oper', 79 | flex: 1 80 | }] 81 | }, { 82 | xtype: 'container', 83 | reference: 'detailsPanel', 84 | padding: 10, 85 | width: '15%', 86 | region: 'east', 87 | split: true, 88 | tpl: ['

Site Name

', 89 | '

{site_name}

', 90 | '

Company

', 91 | '

{company}

', 92 | '

State

', 93 | '

{state}

', 94 | '

Number of Operations

', 95 | '

{total_oper}

'], 96 | bind: { 97 | data: '{selectedValue}' 98 | } 99 | }] 100 | }] 101 | }); 102 | }); -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Grid Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example3.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | 10 | 11 | var mapController = Ext.create('Ext.app.ViewController',{ 12 | onSelect: function(rowmodel, record) { 13 | this.lookup('southGrid').ensureVisible(record); 14 | } 15 | }); 16 | 17 | 18 | Ext.onReady(function () { 19 | Ext.QuickTips.init(); 20 | 21 | Ext.create('Ext.container.Viewport', { 22 | layout: 'fit', 23 | items: [{ 24 | xtype: 'panel', 25 | layout: 'border', 26 | viewModel: { 27 | stores: { 28 | layer: { 29 | storeId: 'layer1', 30 | type: 'carto', 31 | autoLoad: true, 32 | proxy: { 33 | enableLatLng: true, 34 | username: 'extjscarto', 35 | table: 'petroleum_refineries' 36 | } 37 | } 38 | } 39 | }, 40 | controller: mapController, 41 | tbar: { 42 | items: { 43 | xtype: 'checkboxfield', 44 | reference: 'lockToMapBox', 45 | boxLabel: 'Lock to Map' 46 | } 47 | }, 48 | items: [{ 49 | xtype: "cartomap", 50 | region: 'center', 51 | center: 'us', 52 | reference: 'map', 53 | bind: { 54 | selection: '{selectedValue}', 55 | mapLock: '{lockToMapBox.checked}' 56 | }, 57 | storesToLock: ['layer1'], 58 | basemap: 'darkMatterLite', 59 | layers: [{ 60 | subLayers: [{ 61 | bind: '{layer}', 62 | interactivity: { 63 | enable: true, 64 | fields: [ 65 | 'site_name', 'company', 'state', 'total_oper' 66 | ], 67 | tooltip: { 68 | enable: true 69 | } 70 | } 71 | }] 72 | }] 73 | },{ 74 | xtype: 'grid', 75 | region: 'south', 76 | reference: 'southGrid', 77 | split: true, 78 | idProperty: 'cartodb_id', 79 | bind: { 80 | selection: '{selectedValue}', 81 | store: '{layer}' 82 | }, 83 | listeners: { 84 | select: 'onSelect' 85 | }, 86 | height: 350, 87 | columns: [{ 88 | text: 'Site Name', 89 | dataIndex: 'site_name', 90 | flex: 1 91 | },{ 92 | text: 'Company', 93 | dataIndex: 'company', 94 | flex: 1 95 | },{ 96 | text: 'State', 97 | dataIndex: 'state', 98 | flex: 1 99 | },{ 100 | text: 'Total Operation', 101 | dataIndex: 'total_oper', 102 | flex: 1 103 | }] 104 | }] 105 | }] 106 | }); 107 | }); -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Grid Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example4.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | 10 | 11 | var mapController = Ext.create('Ext.app.ViewController',{ 12 | filterStore: function(combo, record){ 13 | this.getStore('layer').filter('city', record.get('city')); 14 | }, 15 | clearFilter: function(){ 16 | this.lookup('comboFilter').reset(); 17 | this.getStore('layer').clearFilter(); 18 | } 19 | }); 20 | 21 | Ext.onReady(function () { 22 | Ext.QuickTips.init(); 23 | 24 | Ext.create('Ext.container.Viewport', { 25 | layout: 'fit', 26 | items: [{ 27 | xtype: 'panel', 28 | layout: 'border', 29 | viewModel: { 30 | stores: { 31 | layer: { 32 | storeId: 'layer1', 33 | type: 'carto', 34 | autoLoad: true, 35 | proxy: { 36 | username: 'extjscarto', 37 | table: 'us_metro_stations' 38 | } 39 | }, 40 | combo: { 41 | type: 'carto', 42 | sorters: 'city', 43 | proxy: { 44 | username: 'extjscarto', 45 | table: 'us_metro_stations', 46 | groupBy: 'city' 47 | } 48 | } 49 | } 50 | }, 51 | controller: mapController, 52 | dockedItems: [{ 53 | xtype: 'toolbar', 54 | dock: 'top', 55 | items: [{ 56 | text: 'View Code', 57 | },{ 58 | xtype: 'combo', 59 | fieldLabel: "City Filters", 60 | reference: 'comboFilter', 61 | displayField: 'city', 62 | valueField: 'city', 63 | bind: { 64 | store: '{combo}' 65 | }, 66 | listeners: { 67 | select: 'filterStore' 68 | } 69 | },{ 70 | xtype: 'button', 71 | text: 'Clear Filter', 72 | handler: 'clearFilter' 73 | }] 74 | }], 75 | items: [{ 76 | xtype: "cartomap", 77 | region: 'center', 78 | center: 'us', 79 | reference: 'map', 80 | basemap: 'darkMatterLite', 81 | layers: [{ 82 | subLayers: [{ 83 | bind: '{layer}' 84 | }] 85 | }] 86 | },{ 87 | xtype: 'grid', 88 | region: 'south', 89 | reference: 'southGrid', 90 | split: true, 91 | height: 350, 92 | plugins: 'gridfilters', 93 | bind: { 94 | store: '{layer}' 95 | }, 96 | columns: [ 97 | { text: 'City', dataIndex: 'city', flex: 1, filter: { 98 | type: 'string', 99 | itemDefaults: { 100 | emptyText: 'Search for...' 101 | } 102 | } }, 103 | { text: 'Name', dataIndex: 'name', flex: 2 } 104 | ], 105 | }] 106 | }] 107 | }); 108 | }); -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Grid Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example5.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | 10 | 11 | var mapController = Ext.create('Ext.app.ViewController',{ 12 | filterStore: function(combo, record){ 13 | if (record) { 14 | this.getStore('layer').filter([{ 15 | property: 'city', 16 | value: record, 17 | operator: 'like' 18 | }]); 19 | } else { 20 | this.clearFilter(); 21 | } 22 | }, 23 | clearFilter: function(){ 24 | this.lookup('comboFilter').reset(); 25 | this.getStore('layer').clearFilter(); 26 | } 27 | }); 28 | 29 | Ext.onReady(function () { 30 | Ext.QuickTips.init(); 31 | 32 | Ext.create('Ext.container.Viewport', { 33 | layout: 'fit', 34 | items: [{ 35 | xtype: 'panel', 36 | layout: 'border', 37 | viewModel: { 38 | stores: { 39 | layer: { 40 | storeId: 'layer1', 41 | type: 'carto', 42 | autoLoad: true, 43 | proxy: { 44 | username: 'extjscarto', 45 | table: 'us_metro_stations' 46 | } 47 | }, 48 | combo: { 49 | type: 'carto', 50 | sorters: 'city', 51 | proxy: { 52 | username: 'extjscarto', 53 | table: 'us_metro_stations', 54 | groupBy: 'city' 55 | } 56 | } 57 | } 58 | }, 59 | controller: mapController, 60 | dockedItems: [{ 61 | xtype: 'toolbar', 62 | dock: 'top', 63 | items: [{ 64 | text: 'View Code', 65 | },{ 66 | xtype: 'combo', 67 | fieldLabel: "City Filters", 68 | reference: 'comboFilter', 69 | displayField: 'city', 70 | valueField: 'city', 71 | bind: { 72 | store: '{combo}' 73 | }, 74 | listeners: { 75 | change: 'filterStore' 76 | } 77 | },{ 78 | xtype: 'button', 79 | text: 'Clear Filter', 80 | handler: 'clearFilter' 81 | }] 82 | }], 83 | items: [{ 84 | xtype: "cartomap", 85 | region: 'center', 86 | center: 'us', 87 | reference: 'map', 88 | basemap: 'darkMatterLite', 89 | layers: [{ 90 | subLayers: [{ 91 | bind: '{layer}' 92 | }] 93 | }] 94 | },{ 95 | xtype: 'grid', 96 | region: 'south', 97 | reference: 'southGrid', 98 | split: true, 99 | height: 350, 100 | plugins: 'gridfilters', 101 | bind: { 102 | store: '{layer}' 103 | }, 104 | columns: [ 105 | { text: 'City', dataIndex: 'city', flex: 1, filter: { 106 | type: 'string', 107 | itemDefaults: { 108 | emptyText: 'Search for...' 109 | } 110 | } }, 111 | { text: 'Name', dataIndex: 'name', flex: 2 } 112 | ], 113 | }] 114 | }] 115 | }); 116 | }); -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Grid Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example6.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | 10 | 11 | var mapController = Ext.create('Ext.app.ViewController',{ 12 | filterStore: function(combo, record){ 13 | Ext.getStore('layer1').filter([{ 14 | property: 'sentiment', 15 | value: record.get('value') 16 | }]); 17 | }, 18 | clearFilter: function(){ 19 | this.lookup('comboFilter').reset(); 20 | Ext.getStore('layer1').clearFilter(); 21 | } 22 | }); 23 | 24 | Ext.onReady(function () { 25 | Ext.QuickTips.init(); 26 | 27 | Ext.create('Ext.container.Viewport', { 28 | layout: 'fit', 29 | items: [{ 30 | xtype: 'panel', 31 | layout: 'border', 32 | viewModel: { 33 | stores: { 34 | layer: { 35 | storeId: 'layer1', 36 | type: 'carto', 37 | autoLoad: true, 38 | pageSize: 20, 39 | proxy: { 40 | username: 'extjscarto', 41 | table: 'starwars', 42 | reader: { 43 | transform: { 44 | fn: function(data) { 45 | data.rows.forEach(function(item){ 46 | item.timestamp = new Date(item.timestamp/1000000); 47 | }.bind(this)); 48 | return data; 49 | } 50 | } 51 | } 52 | } 53 | }, 54 | combo: { 55 | data: [{ 56 | name: 'Negative', 57 | value: 'neg' 58 | },{ 59 | name: 'Postive', 60 | value: 'pos' 61 | }] 62 | } 63 | } 64 | }, 65 | controller: mapController, 66 | dockedItems: [{ 67 | xtype: 'toolbar', 68 | dock: 'top', 69 | items: [{ 70 | text: 'View Code', 71 | },{ 72 | xtype: 'combo', 73 | fieldLabel: "Sentiment Filter", 74 | reference: 'comboFilter', 75 | displayField: 'name', 76 | valueField: 'value', 77 | bind: { 78 | store: '{combo}' 79 | }, 80 | listeners: { 81 | select: 'filterStore' 82 | } 83 | },{ 84 | xtype: 'button', 85 | text: 'Clear Filter', 86 | handler: 'clearFilter' 87 | }] 88 | }], 89 | items: [{ 90 | xtype: "cartomap", 91 | region: 'center', 92 | center: 'us', 93 | reference: 'map', 94 | basemap: 'darkMatterLite', 95 | layers: [{ 96 | subLayers: [{ 97 | bind: '{layer}', 98 | css: { 99 | type: 'intensity' 100 | } 101 | }] 102 | }] 103 | },{ 104 | xtype: 'grid', 105 | region: 'south', 106 | reference: 'southGrid', 107 | split: true, 108 | height: 350, 109 | plugins: 'gridfilters', 110 | bind: { 111 | store: '{layer}' 112 | }, 113 | dockedItems: [{ 114 | xtype: 'pagingtoolbar', 115 | dock: 'bottom', 116 | bind: { 117 | store: '{layer}' 118 | }, 119 | displayInfo: true 120 | }], 121 | columns: [{ 122 | text: 'Author Handle', 123 | dataIndex: 'author_handle', 124 | flex: 2, 125 | filter: { 126 | type: 'string', 127 | itemDefaults: { 128 | emptyText: 'Search for...' 129 | } 130 | } 131 | },{ 132 | text: 'Author Gender', 133 | dataIndex: 'author_gender', 134 | flex: 1, 135 | filter: { 136 | type: 'string', 137 | itemDefaults: { 138 | emptyText: 'Search for...' 139 | } 140 | } 141 | },{ 142 | text: 'Followers', 143 | dataIndex: 'followers', 144 | flex: 1, 145 | filter: { 146 | type: 'number', 147 | itemDefaults: { 148 | emptyText: 'Search for...' 149 | } 150 | } 151 | },{ 152 | text: 'Sentiment', 153 | dataIndex: 'sentiment', 154 | flex: 1/2, 155 | filter: { 156 | type: 'string', 157 | itemDefaults: { 158 | emptyText: 'Search for...' 159 | } 160 | } 161 | },{ 162 | text: 'Text', 163 | dataIndex: 'text', 164 | flex: 3, 165 | filter: { 166 | type: 'string', 167 | itemDefaults: { 168 | emptyText: 'Search for...' 169 | } 170 | } 171 | }] 172 | }] 173 | }] 174 | }); 175 | }); -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example7.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Grid Map demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/gridMap/gridMap-example7.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | 10 | 11 | var mapController = Ext.create('Ext.app.ViewController',{ 12 | filterStore: function(combo, record){ 13 | Ext.getStore('layer1').filter([{ 14 | property: 'case_status', 15 | value: record.get('value'), 16 | operator: 'like' 17 | }]); 18 | }, 19 | clearFilter: function(){ 20 | this.lookup('comboFilter').reset(); 21 | Ext.getStore('layer1').clearFilter(); 22 | } 23 | }); 24 | 25 | Ext.onReady(function () { 26 | Ext.QuickTips.init(); 27 | 28 | Ext.create('Ext.container.Viewport', { 29 | layout: 'fit', 30 | items: [{ 31 | xtype: 'panel', 32 | layout: 'border', 33 | viewModel: { 34 | stores: { 35 | layer: { 36 | storeId: 'layer1', 37 | type: 'carto', 38 | autoLoad: true, 39 | proxy: { 40 | username: 'extjscarto', 41 | table: 'denver_service_requests', 42 | reader: { 43 | transform: { 44 | fn: function(data) { 45 | data.rows.forEach(function(item){ 46 | item.timestamp = new Date(item.timestamp/1000000); 47 | }.bind(this)); 48 | return data; 49 | } 50 | } 51 | } 52 | } 53 | }, 54 | combo: { 55 | data: [{ 56 | name: 'Open', 57 | value: 'Open' 58 | },{ 59 | name: 'Closed', 60 | value: 'Closed' 61 | }] 62 | } 63 | } 64 | }, 65 | controller: mapController, 66 | dockedItems: [{ 67 | xtype: 'toolbar', 68 | dock: 'top', 69 | items: [{ 70 | text: 'View Code', 71 | },{ 72 | xtype: 'combo', 73 | fieldLabel: "Case Filter", 74 | reference: 'comboFilter', 75 | displayField: 'name', 76 | valueField: 'value', 77 | bind: { 78 | store: '{combo}' 79 | }, 80 | listeners: { 81 | select: 'filterStore' 82 | } 83 | },{ 84 | xtype: 'button', 85 | text: 'Clear Filter', 86 | handler: 'clearFilter' 87 | }] 88 | }], 89 | items: [{ 90 | xtype: "cartomap", 91 | region: 'center', 92 | center: 'us', 93 | reference: 'map', 94 | basemap: 'darkMatterLite', 95 | maskWhileLoading: true, 96 | layers: [{ 97 | subLayers: [{ 98 | bind: '{layer}', 99 | css: { 100 | type: 'intensity' 101 | } 102 | }] 103 | }] 104 | },{ 105 | xtype: 'grid', 106 | region: 'south', 107 | reference: 'southGrid', 108 | split: true, 109 | height: 350, 110 | plugins: 'gridfilters', 111 | bind: { 112 | store: '{layer}' 113 | }, 114 | columns: [{ 115 | text: 'Agency', 116 | dataIndex: 'agency', 117 | flex: 2, 118 | filter: { 119 | type: 'string', 120 | itemDefaults: { 121 | emptyText: 'Search for...' 122 | } 123 | } 124 | },{ 125 | text: 'Case Summary', 126 | dataIndex: 'case_summa', 127 | flex: 1, 128 | filter: { 129 | type: 'string', 130 | itemDefaults: { 131 | emptyText: 'Search for...' 132 | } 133 | } 134 | },{ 135 | text: 'Case Status', 136 | dataIndex: 'case_status', 137 | flex: 1, 138 | filter: { 139 | type: 'string', 140 | itemDefaults: { 141 | emptyText: 'Search for...' 142 | } 143 | } 144 | },{ 145 | xtype:'datecolumn', 146 | format:'m-d-Y', 147 | text: 'Date Created', 148 | dataIndex: 'case_cre_1', 149 | flex: 1, 150 | filter: { 151 | type: 'date', 152 | itemDefaults: { 153 | emptyText: 'Search for...' 154 | } 155 | } 156 | }], 157 | }] 158 | }] 159 | }); 160 | }); -------------------------------------------------------------------------------- /examples/gridpanel/gridPanel-example3.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoProxy', 6 | 'Carto.CartoStore' 7 | ]); 8 | 9 | Ext.onReady(function () { 10 | Ext.QuickTips.init(); 11 | 12 | Ext.create('Carto.CartoStore', { 13 | storeId: 'metrostopsStore', 14 | proxy: { 15 | username: 'extjscarto', 16 | table: 'us_metro_stations' 17 | }, 18 | autoLoad: true 19 | }); 20 | 21 | Ext.create('Ext.container.Viewport', { 22 | layout: 'fit', 23 | items: [{ 24 | xtype: 'grid', 25 | title: 'United States - Metro Stops', 26 | store: Ext.data.StoreManager.lookup('metrostopsStore'), 27 | columns: [ 28 | { text: 'City', dataIndex: 'city', flex: 1 }, 29 | { text: 'Name', dataIndex: 'name', flex: 2 } 30 | ], 31 | /* Generic footer for reviewing example */ 32 | dockedItems: [{ 33 | xtype: 'toolbar', 34 | dock: 'top', 35 | items: [{ 36 | text: 'View Code', 37 | },{ 38 | xtype: 'combo', 39 | fieldLabel: "City Filters", 40 | displayField: 'name', 41 | valueField: 'value', 42 | store: Ext.create('Ext.data.Store', { 43 | data: [{ 44 | name: 'Atlanta', 45 | value: 'atlanta' 46 | },{ 47 | name: 'Boston', 48 | value: 'boston' 49 | }] 50 | }), 51 | listeners: { 52 | select: function(combo, record) { 53 | this.up('grid').store.filter('city', record.data.value); 54 | } 55 | } 56 | }] 57 | }] 58 | }] 59 | }); 60 | 61 | }); -------------------------------------------------------------------------------- /examples/gridpanel/gridpanel-example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GridPanel demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/gridpanel/gridpanel-example1.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoProxy' 6 | ]); 7 | 8 | Ext.onReady(function () { 9 | Ext.QuickTips.init(); 10 | 11 | Ext.create('Ext.data.Store', { 12 | storeId: 'metrostopsStore', 13 | remoteFilter: true, 14 | remoteSort: true, 15 | // sorters: 'city', 16 | sorters: [{ 17 | property: 'city', 18 | direction: 'ASC' 19 | }, 'name'], 20 | proxy: { 21 | type: 'carto', 22 | username: 'extjscarto', 23 | table: 'us_metro_stations' 24 | }, 25 | autoLoad: true 26 | }); 27 | 28 | Ext.create('Ext.container.Viewport', { 29 | layout: 'fit', 30 | items: [{ 31 | xtype: 'grid', 32 | title: 'United States - Metro Stops', 33 | store: Ext.data.StoreManager.lookup('metrostopsStore'), 34 | multiColumnSort: true, 35 | plugins: 'gridfilters', 36 | columns: [ 37 | { text: 'City', dataIndex: 'city', flex: 1, filter: 'number' }, 38 | { 39 | text: 'Name', 40 | dataIndex: 'name', 41 | flex: 2, 42 | filter: { 43 | type: 'string', 44 | itemDefaults: { 45 | emptyText: 'Search for...' 46 | } 47 | } 48 | } 49 | ], 50 | 51 | bbar: [{ 52 | xtype: 'pagingtoolbar', 53 | store: Ext.data.StoreManager.lookup('metrostopsStore'), 54 | displayInfo: true 55 | }], 56 | 57 | /* Generic footer for reviewing example */ 58 | dockedItems: [{ 59 | xtype: 'toolbar', 60 | dock: 'bottom', 61 | ui: 'dark', 62 | padding: 10, 63 | items: [{ 64 | text: 'View Code' 65 | }] 66 | }] 67 | }] 68 | }); 69 | 70 | }); -------------------------------------------------------------------------------- /examples/gridpanel/gridpanel-example2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GridPanel demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/gridpanel/gridpanel-example2.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoProxy' 6 | ]); 7 | 8 | Ext.onReady(function () { 9 | Ext.QuickTips.init(); 10 | 11 | Ext.create('Ext.data.Store', { 12 | storeId: 'metrostopsStore', 13 | proxy: { 14 | type: 'carto', 15 | username: 'extjscarto', 16 | table: 'us_metro_stations' 17 | }, 18 | autoLoad: true 19 | }); 20 | 21 | Ext.create('Ext.container.Viewport', { 22 | layout: 'fit', 23 | items: [{ 24 | xtype: 'grid', 25 | title: 'United States - Metro Stops', 26 | store: Ext.data.StoreManager.lookup('metrostopsStore'), 27 | columns: [ 28 | { text: 'City', dataIndex: 'city', flex: 1 }, 29 | { text: 'Name', dataIndex: 'name', flex: 2 } 30 | ], 31 | 32 | /* Generic footer for reviewing example */ 33 | dockedItems: [{ 34 | xtype: 'toolbar', 35 | dock: 'bottom', 36 | items: [{ 37 | text: 'View Code' 38 | }] 39 | }] 40 | }] 41 | }); 42 | 43 | }); -------------------------------------------------------------------------------- /examples/gridpanel/gridpanel-example3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GridPanel demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/layerDemo/layerDemo-example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Layer demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/layerDemo/layerDemo-example1.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | /** 10 | * 11 | * Layer Demo for different kinds of layers. 12 | */ 13 | Ext.onReady(function () { 14 | Ext.QuickTips.init(); 15 | 16 | Ext.create('Ext.container.Viewport', { 17 | layout: 'fit', 18 | items: [{ 19 | xtype: 'panel', 20 | layout: 'fit', 21 | controller: Ext.create('Ext.app.ViewController'), 22 | viewModel: { 23 | stores: { 24 | tweets: { 25 | type: 'carto', 26 | autoLoad: true, 27 | onlyTiles: true, 28 | filters: { 29 | property: 'longitude', 30 | value: -90, 31 | operator: '>' 32 | }, 33 | proxy: { 34 | username: 'crestonedigital', 35 | table: 'starwars' 36 | } 37 | }, 38 | coloradoZipCodes: { 39 | type: 'carto', 40 | autoLoad: true, 41 | onlyTiles: true, 42 | proxy: { 43 | username: 'crestonedigital', 44 | table: 'colorado_zipcodes' 45 | } 46 | }, 47 | oregonFires: { 48 | type: 'carto', 49 | autoLoad: true, 50 | onlyTiles: true, 51 | filters: { 52 | property: 'state', 53 | value: 'Oregon' 54 | }, 55 | proxy: { 56 | username: 'crestonedigital', 57 | table: 'wildfire' 58 | } 59 | } 60 | } 61 | }, 62 | items: [{ 63 | xtype: "cartomap", 64 | center: 'us', 65 | reference: 'map', 66 | basemap: 'darkMatterLite', 67 | layers: [{ 68 | type: 'torque', 69 | table: 'lac_hospitals_2011', 70 | username: 'crestonedigital', 71 | sql: 'SELECT * FROM lac_hospitals_2011', 72 | css: { 73 | type: 'torque' 74 | } 75 | }, { 76 | subLayers: [{ 77 | bind: '{tweets}' 78 | }, { 79 | bind: '{coloradoZipCodes}', 80 | css: { 81 | type: 'polygon' 82 | } 83 | }] 84 | }, { 85 | type: 'torque', 86 | bind: '{oregonFires}', 87 | css: { 88 | type: 'heatmap', 89 | value: { 90 | markerFillOpacity: .4, 91 | markerWidth: 25, 92 | case: null 93 | } 94 | } 95 | }] 96 | }] 97 | }] 98 | }); 99 | }); -------------------------------------------------------------------------------- /examples/playMap/playMap-example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Map Play Demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /examples/storeBinding/storeBinding-example1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Store Binding Demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /examples/storeBinding/storeBinding-example1.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | 'Carto.CartoMap', 6 | 'Ext.data.Store' 7 | ]); 8 | 9 | 10 | 11 | var mapController = Ext.create('Ext.app.ViewController',{ 12 | onSelect: function(rowmodel, record) { 13 | this.lookup('southGrid').ensureVisible(record); 14 | } 15 | }); 16 | 17 | /** 18 | * 19 | * Basic map w/toolbar Centered on US. 20 | */ 21 | Ext.onReady(function () { 22 | Ext.QuickTips.init(); 23 | 24 | Ext.create('Ext.container.Viewport', { 25 | layout: 'fit', 26 | items: [{ 27 | xtype: 'panel', 28 | layout: 'border', 29 | viewModel: { 30 | stores: { 31 | refineries: { 32 | type: 'carto', 33 | storeId: 'refineriesStore', 34 | autoLoad: true, 35 | proxy: { 36 | username: 'extjscarto', 37 | table: 'petroleum_refineries', 38 | enableLatLng: true 39 | } 40 | } 41 | } 42 | }, 43 | controller: mapController, 44 | items: [{ 45 | xtype: "cartomap", 46 | region: 'center', 47 | center: 'us', 48 | reference: 'map', 49 | bind: { 50 | selection: '{selectedValue}' 51 | }, 52 | selectedAction: 'panTo', 53 | basemap: 'darkMatterLite', 54 | layers: [{ 55 | subLayers: [{ 56 | subLayerId: 'intenseLayer', 57 | bind: { 58 | store: '{refineries}' 59 | }, 60 | css: { 61 | type: 'intensity' 62 | }, 63 | interactivity: { 64 | enable: true, 65 | fields: [ 66 | 'site_name', 'company', 'state', 'total_oper' 67 | ], 68 | tooltip: { 69 | enable: true 70 | } 71 | } 72 | }] 73 | 74 | }] 75 | }, { 76 | xtype: 'cartomap', 77 | region: 'east', 78 | width: '50%', 79 | bind: { 80 | selection: '{selectedValue}' 81 | }, 82 | layers: [{ 83 | subLayers: [{ 84 | subLayerId: 'normalLayer', 85 | bind: { 86 | store: '{refineries}' 87 | }, 88 | interactivity: { 89 | enable: true 90 | } 91 | }] 92 | }] 93 | }, { 94 | xtype: 'grid', 95 | region: 'south', 96 | reference: 'southGrid', 97 | split: true, 98 | idProperty: 'cartodb_id', 99 | bind: { 100 | store: '{refineries}', 101 | selection: '{selectedValue}' 102 | }, 103 | listeners: { 104 | select: 'onSelect' 105 | }, 106 | height: 350, 107 | columns: [{ 108 | text: 'Site Name', 109 | dataIndex: 'site_name', 110 | flex: 1 111 | },{ 112 | text: 'Company', 113 | dataIndex: 'company', 114 | flex: 1 115 | },{ 116 | text: 'State', 117 | dataIndex: 'state', 118 | flex: 1 119 | },{ 120 | text: 'Total Operation', 121 | dataIndex: 'total_oper', 122 | flex: 1 123 | }] 124 | }] 125 | }] 126 | }); 127 | }); -------------------------------------------------------------------------------- /examples/tornados/tornado-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tornado demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/tornados/tornado-example.js: -------------------------------------------------------------------------------- 1 | Ext.Loader.setConfig({enabled: true, disableCaching: true}); 2 | //Ext.Loader.setPath('Carto', '../../src/'); 3 | 4 | Ext.require([ 5 | // 'BarChart' 6 | ]); 7 | 8 | Ext.onReady(function () { 9 | // Ext.QuickTips.init(); 10 | 11 | Ext.create('Ext.data.Store', { 12 | storeId: 'tornadosStore', 13 | remoteFilter: true, 14 | remoteSort: true, 15 | // sorters: 'city', 16 | sorters: [{ 17 | property: 'st', 18 | direction: 'ASC' 19 | }], 20 | proxy: { 21 | type: 'carto', 22 | username: 'extjscarto', 23 | table: 'tornados' 24 | }, 25 | autoLoad: true 26 | }); 27 | 28 | 29 | // Ext.define('RoadExplorer.store.RoadData', { 30 | // extend: 'Ext.data.Store', 31 | // 32 | // alias: 'store.roadData', 33 | // 34 | // fields: ['name', 'value'], 35 | // data: [{ 36 | // name: 'Mon', 37 | // value: 39 38 | // }, { 39 | // name: 'Tues', 40 | // value: 22 41 | // }, { 42 | // name: 'Weds', 43 | // value: 14 44 | // }, { 45 | // name: 'Thurs', 46 | // value: 10 47 | // }, { 48 | // name: 'Fri', 49 | // value: 30 50 | // }, { 51 | // name: 'Sat', 52 | // value: 6 53 | // }, { 54 | // name: 'Sun', 55 | // value: 2 56 | // }], 57 | // 58 | // proxy: { 59 | // type: 'memory', 60 | // reader: { 61 | // type: 'json' 62 | // } 63 | // } 64 | // }); 65 | 66 | Ext.define('RoadExplorer.view.graph.BarChart', { 67 | extend: 'Ext.chart.CartesianChart', 68 | xtype: 'barChart', 69 | label: { 70 | display: 'insideStart', 71 | orientation: 'vertical' 72 | }, 73 | axes: [{ 74 | type: 'numeric', 75 | position: 'top', 76 | fields: 'mag' 77 | // fields: 'value' 78 | }, { 79 | type: 'category', 80 | position: 'left', 81 | fields: 'st' 82 | // fields: 'name' 83 | }], 84 | series: { 85 | type: 'bar', 86 | subStyle: { 87 | fill: ['#C8DCF1'], 88 | stroke: '#5CA6DB' 89 | }, 90 | xField: 'st', 91 | yField: 'mag', 92 | // xField: 'name', 93 | // yField: 'value', 94 | tooltip: { 95 | trackMouse: true, 96 | renderer: function (tooltip, record, item) { 97 | // tooltip.setHtml(item.record.get('name') + ': ' + item.record.get('value')); 98 | } 99 | } 100 | } 101 | }); 102 | 103 | Ext.create('Ext.container.Viewport', { 104 | layout: 'border', 105 | frame: true, 106 | bodyBorder: true, 107 | defaults: { 108 | collapsible: false, 109 | split: true, 110 | // bodyPadding: 10 111 | }, 112 | items: [{ 113 | title: 'United States - Tornados', 114 | region: 'center', 115 | // html: 'This is CenterPanel', 116 | headerPosition: 'top', 117 | xtype: 'barChart', 118 | // title: 'Crashes by Day of Week', 119 | flipXY: true, 120 | // store: { 121 | // type: 'roadData' 122 | // } 123 | store: Ext.data.StoreManager.lookup('tornadosStore') 124 | },{ 125 | title: 'East Panel', 126 | region: 'east', 127 | html: 'This is EastPanel', 128 | headerPosition: 'left', 129 | width: 400 130 | }] 131 | }); 132 | 133 | }); -------------------------------------------------------------------------------- /licenses/Readme.md: -------------------------------------------------------------------------------- 1 | # carto/licenses 2 | 3 | This folder contains the supported licenses for third-party use. 4 | -------------------------------------------------------------------------------- /modern/Readme.md: -------------------------------------------------------------------------------- 1 | This modern-specific directory can include any (if not all) of the following directories: 2 | 3 | * overrides: Any classes in this directory will be automatically required and included in the modern build. 4 | In case any of these classes define an Ext JS override (using Ext.define with an "override" property), 5 | that override will in fact only be included in the build if the target class specified 6 | in the "override" property is also included. 7 | 8 | - sass: Any modern-specific style rules should reside in this package, following the same structure 9 | as the directory in the package root (see package.json for more information). 10 | 11 | - src: The modern-specific classes of this package should reside in this directory. -------------------------------------------------------------------------------- /overrides/Readme.md: -------------------------------------------------------------------------------- 1 | # carto/overrides 2 | 3 | This folder contains overrides which will automatically be required by package users. 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | * The name of the package. 4 | */ 5 | "name": "carto", 6 | 7 | /** 8 | * Alternate names for this package. 9 | * 10 | * "alternateName": [], 11 | */ 12 | 13 | /** 14 | * The namespace of this package. 15 | * 16 | * As a general rule, all classes that belong to this package should be under this namespace 17 | * if multiple namespaces are part of this package, set this to "". 18 | */ 19 | "namespace": "carto", 20 | 21 | /** 22 | * The package type. 23 | * 24 | * Sencha Cmd understands the following types of packages: 25 | * - code : An arbitrary package of code for use by applications or other packages. 26 | * - theme : A package to be used as an application’s theme. 27 | * - locale : A package containing localization strings or locale-specific code. 28 | * - template : A package containing one or more templates. 29 | */ 30 | "type": "code", 31 | 32 | /** 33 | * The toolkit used by this theme (only for "theme" package type). 34 | * 35 | * Themes can specify the toolkit they apply to ("classic" or "modern"). 36 | * 37 | * "toolkit": "classic", 38 | */ 39 | "toolkit": "classic", 40 | 41 | /** 42 | * The author of the package. 43 | * 44 | * Required only if you are distributing this package through a Sencha Cmd repository, 45 | * in which case it should match the name you assign to your local package repository. 46 | */ 47 | "creator": "anonymous", 48 | 49 | /** 50 | * A summarized description of this package. 51 | */ 52 | "summary": "Short summary", 53 | 54 | /** 55 | * A detailed description of this package. 56 | */ 57 | "detailedDescription": "Long description of package", 58 | 59 | /** 60 | * The package version. 61 | * 62 | * Typically, changes to the package should come along with changes to the version. 63 | * This number should be in this format: d+(.d+)* 64 | */ 65 | "version": "1.0.0", 66 | 67 | /** 68 | * The version that users can transparently update from without requiring code changes. 69 | * 70 | * In addition the version property, packages can also indicate the degree to which 71 | * they are backward compatible using the compatVersion property. 72 | */ 73 | "compatVersion": "1.0.0", 74 | 75 | /** 76 | * Spec. version of this package.json file. 77 | * This is set automatically by Sencha Cmd when first generating this file 78 | */ 79 | "format": "1", 80 | 81 | /** 82 | * Additional resources used during theme slicing operations 83 | */ 84 | "slicer": { 85 | "js": [ 86 | { 87 | "path": "${package.dir}/sass/example/custom.js", 88 | "isWidgetManifest": true 89 | } 90 | ] 91 | }, 92 | 93 | /** 94 | * Controls the output directory. 95 | */ 96 | "output": "${package.dir}/build", 97 | 98 | /** 99 | * Indicates whether this is a locally developed package or downloaded form a repository. 100 | * Defaults to true on newly generated packages, should not be changed. 101 | */ 102 | "local": true, 103 | 104 | /** 105 | * The theme (package) this package will use (e.g., "ext-theme-neptune", etc.). 106 | * This is only needed if the built package will be used by a non-Cmd application. 107 | * 108 | * "theme": "ext-theme-classic", 109 | */ 110 | 111 | /** 112 | * Sass configuration properties. 113 | */ 114 | "sass" : { 115 | /** 116 | * The namespace to which this package's SASS corresponds. The default value of 117 | * "carto" means that the files in ./sass/src (and ./sass/var) match classes in 118 | * the carto" root namespace. In other words, "carto.panel.Panel" maps to 119 | * ./sass/src/panel/Panel.scss. 120 | * 121 | * To style classes from any namespace, set this to blank. If this is blank, 122 | * then to style "carto.panel.Panel" you would put SASS in 123 | * ./sass/src/carto/panel/Panel.scss. 124 | */ 125 | "namespace": "carto", 126 | 127 | /** 128 | * Comma-separated list of files or folders containing extra Sass. These 129 | * files are automatically included in the Sass compilation. By default this 130 | * is just "etc/all.scss" to allow import directives to control the order 131 | * other files are included. 132 | * 133 | * All "etc" files are included at the top of the Sass compilation in their 134 | * dependency order: 135 | * 136 | * +-------+---------+ 137 | * | | base | 138 | * | theme +---------+ 139 | * | | derived | 140 | * +-------+---------+ 141 | * | packages | (in package dependency order) 142 | * +-----------------+ 143 | * | application | 144 | * +-----------------+ 145 | */ 146 | "etc": [ 147 | "${package.dir}/sass/etc/all.scss" 148 | ], 149 | 150 | /** 151 | * Comma-separated list of folders containing Sass variable definitions 152 | * files. These file can also define Sass mixins for use by components. 153 | * 154 | * All "var" files are included after "etc" files in the Sass compilation in 155 | * dependency order: 156 | * 157 | * +-------+---------+ 158 | * | | base | 159 | * | theme +---------+ 160 | * | | derived | 161 | * +-------+---------+ 162 | * | packages | (in package dependency order) 163 | * +-----------------+ 164 | * | application | 165 | * +-----------------+ 166 | * 167 | * The "sass/var/all.scss" file is always included at the start of the var 168 | * block before any files associated with JavaScript classes. 169 | */ 170 | "var": [ 171 | "${package.dir}/sass/var" 172 | ], 173 | 174 | /** 175 | * Comma-separated list of folders containing Sass rule files. 176 | * 177 | * All "src" files are included after "var" files in the Sass compilation in 178 | * dependency order (the same order as "etc"): 179 | * 180 | * +-------+---------+ 181 | * | | base | 182 | * | theme +---------+ 183 | * | | derived | 184 | * +-------+---------+ 185 | * | packages | (in package dependency order) 186 | * +-----------------+ 187 | * | application | 188 | * +-----------------+ 189 | */ 190 | "src": [ 191 | "${package.dir}/sass/src" 192 | ] 193 | }, 194 | 195 | /** 196 | * This is the comma-separated list of folders where classes reside. These 197 | * classes must be explicitly required to be included in the build. 198 | */ 199 | "classpath": [ 200 | "${package.dir}/src" 201 | ], 202 | 203 | /** 204 | * Comma-separated string with the paths of directories or files to search. Any classes 205 | * declared in these locations will be automatically required and included in the build. 206 | * If any file defines an Ext JS override (using Ext.define with an "override" property), 207 | * that override will in fact only be included in the build if the target class specified 208 | * in the "override" property is also included. 209 | */ 210 | "overrides": [ 211 | "${package.dir}/overrides" 212 | ], 213 | 214 | "example": { 215 | /** 216 | * One or more folders that contain example applications for this package. 217 | */ 218 | "path": [ 219 | "${package.dir}/examples" 220 | ] 221 | 222 | /** 223 | * You can list apps specifically. 224 | * 225 | * "apps": [ 226 | * "demo1", 227 | * "demo2" 228 | * ] 229 | * 230 | * By default, all subfolders in the path are considered example applications. 231 | */ 232 | }, 233 | 234 | /** 235 | * The framework this package will use (i.e., "ext" or "touch"). 236 | * This is only needed if the built package will be used by a non-Cmd application. 237 | * 238 | * "framework": "ext", 239 | */ 240 | 241 | /** 242 | * Packages can require other packages in the same way that applications can require 243 | * packages. 244 | * 245 | * Can be specified as an array of package names or configuration objects. 246 | * 247 | * "requires": [ 248 | * "foo", 249 | * "bar@1.1-2.0", 250 | * { 251 | * "name": "baz" 252 | * "version": "1.5" 253 | * } 254 | * ] 255 | * 256 | * Can also be specified as an object: 257 | * 258 | * "requires": { 259 | * "foo": "2.2", 260 | * "bar": { 261 | * "minVersion": "1.1", 262 | * "version": "2.0" 263 | * } 264 | * } 265 | */ 266 | "requires": [] 267 | } 268 | -------------------------------------------------------------------------------- /resources/Readme.md: -------------------------------------------------------------------------------- 1 | # carto/resources 2 | 3 | This folder contains static resources (typically an `"images"` folder as well). 4 | -------------------------------------------------------------------------------- /sass/Readme.md: -------------------------------------------------------------------------------- 1 | # carto/sass 2 | 3 | This folder contains SASS files of various kinds, organized in sub-folders: 4 | 5 | carto/sass/etc 6 | carto/sass/src 7 | carto/sass/var 8 | -------------------------------------------------------------------------------- /sass/config.rb: -------------------------------------------------------------------------------- 1 | cur_dir = File.dirname(__FILE__) 2 | output_style = :nested 3 | -------------------------------------------------------------------------------- /sass/etc/Readme.md: -------------------------------------------------------------------------------- 1 | # carto/sass/etc 2 | 3 | This folder contains miscellaneous SASS files. Unlike `"carto/sass/etc"`, these files 4 | need to be used explicitly. 5 | -------------------------------------------------------------------------------- /sass/example/custom.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is generated as a starting point by Sencha Cmd - it will not be replaced or 3 | * updated by "sencha package upgrade". 4 | * 5 | * This file can be removed and the script tag in theme.html removed if this theme does 6 | * not need custom additional manifest or shortcut entries. These are documented in 7 | * ./packages/ext-theme-base/sass/example/render.js. 8 | */ 9 | 10 | //Ext.theme.addManifest(); 11 | 12 | //Ext.theme.addShortcuts(); 13 | -------------------------------------------------------------------------------- /sass/example/fashion.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Ext JS Theme Harness 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /sass/example/theme.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Ext JS Theme Harness 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /sass/src/Readme.md: -------------------------------------------------------------------------------- 1 | # carto/sass/src 2 | 3 | This folder contains SASS sources that mimic the component-class hierarchy. These files 4 | are gathered in to a build of the CSS based on classes that are used by the build. 5 | -------------------------------------------------------------------------------- /sass/var/Readme.md: -------------------------------------------------------------------------------- 1 | # carto/sass/var 2 | 3 | This folder contains variable declaration files named by their component class. 4 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CrestoneDigital/extjs-carto/a67036b54c48717290eb6cfc996cd37644cdc46f/src/.DS_Store -------------------------------------------------------------------------------- /src/AbstractLayer.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.AbstractLayer', { 2 | 3 | mixins: [ 4 | 'Ext.mixin.Inheritable', 5 | 'Ext.mixin.Observable', 6 | 'Ext.mixin.Bindable' 7 | ], 8 | 9 | config: { 10 | cartoLayer: null, 11 | hidden: false, 12 | table: '', 13 | username: '', 14 | mapZIndex: null 15 | }, 16 | 17 | isAbstractLayer: true, 18 | 19 | constructor: function(config) { 20 | config = config || {}; 21 | 22 | if (config.initialConfig) { 23 | config = config.initialConfig; 24 | } 25 | 26 | this.initialConfig = config; 27 | 28 | if (config.layerId) { 29 | this.setId(config.layerId); 30 | } 31 | 32 | this.getId(); 33 | this.initConfig(config); 34 | 35 | this.initBindable(); 36 | 37 | delete this.layerId; 38 | return this; 39 | }, 40 | 41 | beforeInitConfig: function() { 42 | this.mixins.observable.constructor.call(this); 43 | }, 44 | 45 | createCartoLayer: Ext.emptyFn, 46 | 47 | buildCartoLayer: Ext.emptyFn, 48 | 49 | updateCartoLayer: function(cartoLayer) { 50 | if (this.getHidden()) { 51 | cartoLayer.hide(); 52 | } 53 | }, 54 | 55 | updateHidden: function(hidden) { 56 | var cartoLayer = this.getCartoLayer(); 57 | if (cartoLayer) { 58 | if (hide) { 59 | cartoLayer.hide(); 60 | } else { 61 | cartoLayer.show(); 62 | } 63 | } 64 | }, 65 | 66 | getType: function() { 67 | var alias = this.alias; 68 | return alias ? alias[0].split('.')[1] : null; 69 | }, 70 | 71 | remove: function(destroy) { 72 | var cartoLayer = this.getCartoLayer(); 73 | if (cartoLayer) { 74 | cartoLayer.remove(); 75 | } 76 | if (destroy) { 77 | this.destroy(); 78 | } 79 | }, 80 | 81 | initInheritedState: function(inheritedState) { 82 | this.mixins.bindable.initInheritedState.call(this, inheritedState); 83 | }, 84 | 85 | doDestroy: Ext.emptyFn, 86 | 87 | destroy: function() { 88 | if (!this.hasListeners.beforedestroy || this.fireEvent('beforedestroy', this) !== false) { 89 | // isDestroying added for compat reasons 90 | this.isDestroying = this.destroying = true; 91 | 92 | this.doDestroy(); 93 | 94 | this.removeBindings(); 95 | 96 | this.destroyBindable(); 97 | 98 | // We need to defer clearing listeners until after doDestroy() completes, 99 | // to let the interested parties fire events until the very end. 100 | this.clearListeners(); 101 | 102 | // isDestroying added for compat reasons 103 | this.isDestroying = this.destroying = false; 104 | 105 | this.callParent(); // Ext.Base 106 | } 107 | } 108 | }); -------------------------------------------------------------------------------- /src/CartoBasemaps.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.CartoBasemaps',{ 2 | 3 | basemaps: [{ 4 | itemId: 'positronLite', 5 | name: 'Positron (lite)', 6 | url: 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', 7 | attribution: '© OpenStreetMap contributors, © CartoDB' 8 | },{ 9 | itemId: 'positron', 10 | name: 'Positron', 11 | url: 'https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png', 12 | attribution: '© OpenStreetMap contributors, © CartoDB' 13 | },{ 14 | itemId: 'positronLabelsBelow', 15 | name: 'Positron (labels below)', 16 | url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', 17 | attribution: '© OpenStreetMap contributors, © CartoDB' 18 | }, { 19 | itemId: 'darkMatterLabelsBelow', 20 | name: 'Dark Matter (labels below)', 21 | url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', 22 | attribution: '© OpenStreetMap contributors, © CartoDB' 23 | }, { 24 | itemId: 'darkMatter', 25 | name: 'Dark Matter', 26 | url: 'https://{s}.basemaps.cartocdn.com/dark_only_labels/{z}/{x}/{y}.png', 27 | attribution: '© OpenStreetMap contributors, © CartoDB' 28 | }, { 29 | itemId: 'darkMatterLite', 30 | name: 'Dark Matter (lite)', 31 | url: 'https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}.png', 32 | attribution: '© OpenStreetMap contributors, © CartoDB' 33 | }, { 34 | itemId: 'cartoWorldEco', 35 | name: 'CARTO World Eco', 36 | url: 'https://cartocdn_{s}.global.ssl.fastly.net/base-eco/{z}/{x}/{y}.png', 37 | attribution: '© OpenStreetMap contributors, © CartoDB' 38 | }, { 39 | itemId: 'cartoWorldFlatBlue', 40 | name: 'CARTO World Flat Blue', 41 | url: 'https://cartocdn_{s}.global.ssl.fastly.net/base-flatblue/{z}/{x}/{y}.png', 42 | attribution: '© OpenStreetMap contributors, © CartoDB' 43 | }, { 44 | itemId: 'cartoWorldMidnightCommander', 45 | name: 'CARTO World Midnight Commander', 46 | url: 'https://cartocdn_{s}.global.ssl.fastly.net/base-midnight/{z}/{x}/{y}.png', 47 | attribution: '© OpenStreetMap contributors, © CartoDB' 48 | }, { 49 | itemId: 'cartoAntique', 50 | name: 'CARTO Antique', 51 | url: 'https://cartocdn_{s}.global.ssl.fastly.net/base-antique/{z}/{x}/{y}.png', 52 | attribution: '© OpenStreetMap contributors, © CartoDB' 53 | /* New basemaps */ 54 | },{ 55 | itemId: 'toner', 56 | name: 'Toner', 57 | url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner-labels/{z}/{x}/{y}.png', 58 | attribution: '© OpenStreetMap contributors, © CartoDB' 59 | }, { 60 | itemId: 'tonerLabelsBelow', 61 | name: 'Toner (labels below)', 62 | url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}.png', 63 | attribution: '© OpenStreetMap contributors, © CartoDB' 64 | }, { 65 | itemId: 'tonerBackground', 66 | name: 'Toner Background', 67 | url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner-background/{z}/{x}/{y}.png', 68 | attribution: '© OpenStreetMap contributors, © CartoDB' 69 | }, { 70 | itemId: 'tonerLite', 71 | name: 'Toner Lite', 72 | url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png', 73 | attribution: '© OpenStreetMap contributors, © CartoDB' 74 | }, { 75 | itemId: 'tonerLines', 76 | name: 'Toner Lines', 77 | url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner-lines/{z}/{x}/{y}.png', 78 | attribution: '© OpenStreetMap contributors, © CartoDB' 79 | }, { 80 | itemId: 'tonerHybrid', 81 | name: 'Toner Hybrid', 82 | url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/toner-hybrid/{z}/{x}/{y}.png', 83 | attribution: '© OpenStreetMap contributors, © CartoDB' 84 | }, { 85 | itemId: 'watercolor', 86 | name: 'Watercolor', 87 | url: 'https://stamen-tiles-{s}.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png', 88 | attribution: '© OpenStreetMap contributors, © CartoDB' 89 | }], 90 | getBasemapById: function(itemId){ 91 | var basemap = null; 92 | this.basemaps.forEach(function(item){ 93 | if(item.itemId === itemId){ 94 | basemap = item; 95 | } 96 | }.bind(this)); 97 | if (basemap) { 98 | return basemap; 99 | } else { 100 | console.error("Unknown basemap '" + itemId + "'."); 101 | } 102 | } 103 | 104 | 105 | }); -------------------------------------------------------------------------------- /src/CartoDataModel.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.CartoDataModel', { 2 | extend: 'Ext.data.Model', 3 | idProperty: 'cartodb_id', 4 | fields: [ 5 | 'site_name', 'company', 'state', 'total_oper', 'cartodb_id' 6 | // 'corporatio', 'created_at', 7 | // 'dataperiod', 'source', 'the_geom', 'the_geom_webmercator', 'updated_at' 8 | ] 9 | }); -------------------------------------------------------------------------------- /src/CartoFilter.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.CartoFilter', { 2 | extend: 'Ext.util.Filter', 3 | 4 | config: { 5 | sql: '', 6 | negate: false 7 | }, 8 | 9 | initConfig: function(config) { 10 | this.callParent(arguments); 11 | if (!this.getSql() && !this.getFilterFn()) { 12 | this.createSql(); 13 | } 14 | }, 15 | 16 | createSql: function() { 17 | var me = this, 18 | property = me.getProperty(), 19 | value = me.getValue(), 20 | operator = me.getOperator() || '=', 21 | negate = me.getNegate(), 22 | caseSensitive = me.caseSensitive; 23 | 24 | if (property && value) { 25 | if (value instanceof RegExp) { 26 | operator = '~'; 27 | value = value.toString().slice(1); 28 | while (!value.endsWith('/')) { 29 | if (value.slice(-1) === 'i') { 30 | caseSensitive = false; 31 | } 32 | value = value.slice(0,-1); 33 | } 34 | if (!caseSensitive) { 35 | operator += '*'; 36 | } 37 | value = value.slice(0,-1); 38 | } else { 39 | switch(operator) { 40 | case 'like': 41 | case '<': 42 | case '<=': 43 | case '>': 44 | case '>=': 45 | case '=': 46 | case '!=': 47 | break; 48 | case 'lt': 49 | operator = '<'; 50 | break; 51 | case 'lte': 52 | operator = '<='; 53 | break; 54 | case 'gt': 55 | operator = '>'; 56 | break; 57 | case 'gte': 58 | operator = '>='; 59 | break; 60 | case 'eq': 61 | operator = '=' 62 | break; 63 | case 'in': 64 | if(Ext.isArray(value)) { 65 | var temp = value.slice(); 66 | for (var i = 0; i < temp.length; i++) temp[i] = this.wrap(temp[i]); 67 | property = 'ARRAY[' + property + ']'; 68 | operator = '<@'; 69 | value = 'ARRAY[' + temp + ']'; 70 | } 71 | break; 72 | case 'regex': 73 | var validRegExp = true; 74 | try { 75 | new RegExp(value); 76 | } catch (e) { 77 | validRegExp = false; 78 | } 79 | if (validRegExp) { 80 | operator = caseSensitive ? '~' : '~*'; 81 | } else { 82 | console.error("Invalid Regular Expression '" + value + "'. Skipping."); 83 | return; 84 | } 85 | break; 86 | default: 87 | console.warn("Unknown operator '" + operator + "'."); 88 | } 89 | } 90 | return (negate ? 'NOT ' : '') + property + operator + me.wrap(value); 91 | } 92 | } 93 | }); -------------------------------------------------------------------------------- /src/CartoGroupBy.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.CartoGroupBy', { 2 | isGroupBy: true, 3 | 4 | config: { 5 | fields: null, 6 | countName: 'cnt' 7 | }, 8 | 9 | constructor: function(config) { 10 | this.initConfig(config); 11 | }, 12 | 13 | initConfig: function(config) { 14 | this.decodeGroupBy(config); 15 | this.callParent(); 16 | }, 17 | 18 | /** 19 | * Adds a field to the `fields` config. 20 | * @param {Object} field 21 | */ 22 | addField: function(field) { 23 | var fields = this.getFields(), 24 | alreadyExists = false; 25 | field = this.decodeField(field); 26 | for (var i in fields) { 27 | if (fields[i].name === field.name) { 28 | alreadyExists = true; 29 | fields[i] = field; 30 | } 31 | } 32 | if (!alreadyExists) { 33 | fields.push(field); 34 | } 35 | this.setFields(fields); 36 | }, 37 | 38 | /** 39 | * Returns the comma-separated field's sql to be inserted in the SELECT statement. 40 | */ 41 | getSelectSql: function() { 42 | return Ext.pluck(this.getFields(), 'sql').join(',');; 43 | }, 44 | 45 | /** 46 | * Returns the comma-separated field's sql to be inserted in the GROUP BY statement.' 47 | */ 48 | getGroupBySql: function() { 49 | var sql = '', 50 | fields = this.getFields(); 51 | for (var i in fields) { 52 | sql += fields[i].aggregateType ? '' : fields[i].name + ','; 53 | } 54 | return sql.slice(0,-1); 55 | }, 56 | 57 | /** 58 | * Creates this from the given config. 59 | * @param {String/String[]/Object/Object[]} groupBy 60 | */ 61 | decodeGroupBy: function(groupBy) { 62 | if (!groupBy.fields) { 63 | groupBy = {fields: groupBy}; 64 | } 65 | var fields = Ext.isArray(groupBy.fields) ? groupBy.fields : [groupBy.fields], 66 | field; 67 | for (var i = 0; i < fields.length; i++) { 68 | fields[i] = this.decodeField(fields[i]); 69 | } 70 | this.setFields(fields); 71 | if (groupBy.countName) { 72 | this.setCountName(groupBy.countName); 73 | } 74 | }, 75 | 76 | /** 77 | * Creates the {@link Ext.data.field.Field} from the given config. 78 | * @param {String/Object/Ext.data.field.Field} field 79 | */ 80 | decodeField: function(field) { 81 | if (!field.isField) { 82 | field = new Ext.data.field.Field(field); 83 | } 84 | if (!field.sql) { 85 | field.sql = this.wrapAggregate(field) + (field.property ? ' AS ' + field.name : ''); 86 | } 87 | return field; 88 | }, 89 | 90 | wrapAggregate: function(field) { 91 | if (field.aggregateType) { 92 | field.aggregateType = field.aggregateType.toUpperCase(); 93 | if (this.allowedAggregateTypes.indexOf(field.aggregateType) === -1) { 94 | console.warn("Unknown aggregate type '" + field.aggregateType + "'. Skipping."); 95 | field.aggregateType = null; 96 | } else { 97 | return field.aggregateType + '(' + (field.property || field.name) + ')'; 98 | } 99 | } 100 | return field.property || field.name; 101 | }, 102 | 103 | allowedAggregateTypes: ['AVG', 'SUM', 'COUNT', 'MIN', 'MAX', 'STDDEV'] 104 | }); -------------------------------------------------------------------------------- /src/CartoProxy.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.CartoProxy', { 2 | extend: 'Ext.data.proxy.Ajax', 3 | alias: 'proxy.carto', 4 | 5 | requires: [ 6 | 'Carto.sql.CartoField', 7 | 'Carto.sql.CartoFrom', 8 | 'Carto.sql.CartoSql', 9 | 'Carto.sql.CartoTable', 10 | // 'Carto.util.SubLayerCollection' 11 | ], 12 | mixins: [ 13 | 'Carto.CartoSqlMixin' 14 | ], 15 | alternateClassName: ['Carto.CartoProxy.CartoAjax'], 16 | 17 | reader: { 18 | type: 'json', 19 | rootProperty: 'rows', 20 | totalProperty: 'total_rows' 21 | }, 22 | 23 | config: { 24 | url: "https://{{account}}.carto.com/api/v2/sql", 25 | apiKey: null, 26 | table: '', 27 | select: '', 28 | join: [], 29 | where: {}, 30 | groupBy: null, 31 | orderBy: '', 32 | username: '', 33 | mode: null, 34 | sqlCacheBuster: false, 35 | enableData: true, 36 | enableBounds: false, 37 | enableLatLng: false, 38 | limit: null, 39 | layers: null 40 | }, 41 | 42 | /** 43 | * @private 44 | * Copy any sorters, filters etc into the params so they can be sent over the wire 45 | */ 46 | getParams: function(operation) { 47 | if (!operation.isReadOperation) { 48 | return {}; 49 | } 50 | 51 | var me = this, 52 | params = {}, 53 | grouper = operation.getGrouper(), 54 | sorters = operation.getSorters(), 55 | filters = operation.getFilters(), 56 | page = operation.getPage(), 57 | start = operation.getStart(), 58 | limit = operation.getLimit(), 59 | simpleSortMode = me.getSimpleSortMode(), 60 | simpleGroupMode = me.getSimpleGroupMode(), 61 | pageParam = me.getPageParam(), 62 | startParam = me.getStartParam(), 63 | limitParam = me.getLimitParam(), 64 | groupParam = me.getGroupParam(), 65 | groupDirectionParam = me.getGroupDirectionParam(), 66 | sortParam = me.getSortParam(), 67 | filterParam = me.getFilterParam(), 68 | directionParam = me.getDirectionParam(), 69 | hasGroups, index; 70 | 71 | if (pageParam && page) { 72 | params[pageParam] = page; 73 | } 74 | 75 | if (startParam && (start || start === 0)) { 76 | params[startParam] = start; 77 | } 78 | 79 | if (limitParam && limit) { 80 | params[limitParam] = limit; 81 | } 82 | 83 | hasGroups = groupParam && grouper; 84 | if (hasGroups) { 85 | // Grouper is a subclass of sorter, so we can just use the sorter method 86 | if (simpleGroupMode) { 87 | params[groupParam] = grouper.getProperty(); 88 | params[groupDirectionParam] = grouper.getDirection(); 89 | } else { 90 | params[groupParam] = me.encodeSorters([grouper], true); 91 | } 92 | } 93 | 94 | if (sortParam && sorters && sorters.length > 0) { 95 | if (simpleSortMode) { 96 | index = 0; 97 | // Group will be included in sorters, so grab the next one 98 | if (sorters.length > 1 && hasGroups) { 99 | index = 1; 100 | } 101 | params[sortParam] = sorters[index].getProperty(); 102 | params[directionParam] = sorters[index].getDirection(); 103 | } else { 104 | params[sortParam] = me.encodeSorters(sorters); 105 | } 106 | 107 | } 108 | 109 | if (filterParam && filters && filters.length > 0) { 110 | // We do not want to send the filters as a parameter, as they will be added into the query 111 | params.filter = filters; 112 | } 113 | 114 | return params; 115 | }, 116 | 117 | joinTable: function(joinTable) { 118 | if (!joinTable.table.isCartoTable) { 119 | joinTable.table = Ext.create('Carto.sql.CartoTable', joinTable.table); 120 | } 121 | this.getJoin().push(joinTable); 122 | }, 123 | 124 | removeJoin: function(joinName) { 125 | var join = this.getJoin(), 126 | j; 127 | for (var i in join) { 128 | j = join[i]; 129 | if (j.table.getId() === joinName) { 130 | delete join.splice(i, 1); 131 | } 132 | } 133 | }, 134 | 135 | /** 136 | * Adds a field to the proxy's {@link Carto.CartoGroupBy}. This will create a groupBy object if one does not exist. 137 | * @param {Ext.data.field.Field/Object} field 138 | */ 139 | addGroupByField: function(field) { 140 | var groupBy = this.getGroupBy(); 141 | if (!groupBy) { 142 | groupBy = Ext.create('Carto.CartoGroupBy', field); 143 | } else { 144 | groupBy.addField(field); 145 | } 146 | this.setGroupBy(groupBy); 147 | }, 148 | 149 | addLayer: function(layer, load) { 150 | var table = this.getTable(), 151 | layers = this.getLayers(); 152 | if (table) { 153 | layer.setTable(table.getId()); 154 | } 155 | layer.setUsername(this.getUsername()); 156 | this.setLayers(layer); 157 | if (load && this._cachedSql) { 158 | layer.setSql(this._cachedSql); 159 | } 160 | }, 161 | 162 | setSql: function(sql) { 163 | this.sql = sql; 164 | }, 165 | 166 | /** 167 | * Generates a url based on a given Ext.data.Request object. By default, ServerProxy's buildUrl will add the 168 | * cache-buster param to the end of the url. Subclasses may need to perform additional modifications to the url. 169 | * @param {Ext.data.Request} request The request object 170 | * @return {String} The url 171 | */ 172 | buildUrl: function(request) { 173 | var url = this.getUrl(); 174 | if (this.useCartoDb) { 175 | url = "https://{{account}}.cartodb.com/api/v2/sql"; 176 | } 177 | url = url.replace(/{{account}}/, this.getUsername()); 178 | if (this.getNoCache()) { 179 | url = Ext.urlAppend(url, Ext.String.format("{0}={1}", this.getCacheString(), Ext.Date.now())); 180 | } 181 | return url; 182 | }, 183 | 184 | /** 185 | * Creates an {@link Ext.data.Request Request} object from {@link Ext.data.operation.Operation Operation}. 186 | * 187 | * This gets called from doRequest methods in subclasses of Server proxy. 188 | * 189 | * @param {Ext.data.operation.Operation} operation The operation to execute 190 | * @return {Ext.data.Request} The request object 191 | */ 192 | buildRequest: function(operation) { 193 | var me = this, 194 | layers = this.getLayers(), 195 | sqlParams = Ext.apply(me.getParams(operation), this.getCurrentConfig()), 196 | request, operationId, idParam, sql; 197 | switch (this.getMode()) { 198 | case 'tables': sql = this.getTablesSql; break; 199 | case 'columns': sql = this.getColumnsSql.replace(/{{table_name}}/g, this.getTable().getId()); break; 200 | default: sql = this.sql ? this.sqlFormatter(this.sql, sqlParams) : this.sqlBuilder(sqlParams); 201 | } 202 | var params = { 203 | q: sql 204 | }; 205 | if (this.getApiKey()) { 206 | params.api_key = this.getApiKey(); 207 | } 208 | if (layers) { 209 | sql = this.sql ? sql : this.sqlBuilder(sqlParams, {isMap: true}); 210 | if (sql !== me._cachedSql) { 211 | layers.each(function(layer) { 212 | layer.setSql(sql); 213 | }); 214 | } 215 | } 216 | me._cachedSql = sql; 217 | 218 | // Set up the entity id parameter according to the configured name. 219 | // This defaults to "id". But TreeStore has a "nodeParam" configuration which 220 | // specifies the id parameter name of the node being loaded. 221 | operationId = operation.getId(); 222 | idParam = me.getIdParam(); 223 | if (operationId !== undefined && params[idParam] === undefined) { 224 | params[idParam] = operationId; 225 | } 226 | request = new Ext.data.Request({ 227 | params: params, 228 | action: operation.getAction(), 229 | records: operation.getRecords(), 230 | url: operation.getUrl(), 231 | operation: operation, 232 | // this is needed by JsonSimlet in order to properly construct responses for 233 | // requests from this proxy 234 | proxy: me 235 | }); 236 | request.setUrl(me.buildUrl(request)); 237 | /* 238 | * Save the request on the Operation. Operations don't usually care about Request and Response data, but in the 239 | * ServerProxy and any of its subclasses we add both request and response as they may be useful for further processing 240 | */ 241 | operation.setRequest(request); 242 | return request; 243 | }, 244 | 245 | doRequest: function(operation) { 246 | var me = this, 247 | writer = me.getWriter(), 248 | request = me.buildRequest(operation), 249 | method = me.getMethod(request), 250 | jsonData, params; 251 | 252 | // EDIT 253 | // If the onlyTiles flag is enabled, then buildRequest has done all the work we needed done. 254 | if (operation.onlyTiles) { 255 | return null; 256 | } 257 | // END EDIT 258 | 259 | if (writer && operation.allowWrite()) { 260 | request = writer.write(request); 261 | } 262 | 263 | request.setConfig({ 264 | binary : me.getBinary(), 265 | headers : me.getHeaders(), 266 | timeout : me.getTimeout(), 267 | scope : me, 268 | callback : me.createRequestCallback(request, operation), 269 | method : method, 270 | useDefaultXhrHeader : me.getUseDefaultXhrHeader(), 271 | disableCaching : false // explicitly set it to false, ServerProxy handles caching 272 | }); 273 | 274 | if (method.toUpperCase() !== 'GET' && me.getParamsAsJson()) { 275 | params = request.getParams(); 276 | 277 | if (params) { 278 | jsonData = request.getJsonData(); 279 | if (jsonData) { 280 | jsonData = Ext.Object.merge({}, jsonData, params); 281 | } else { 282 | jsonData = params; 283 | } 284 | request.setJsonData(jsonData); 285 | request.setParams(undefined); 286 | } 287 | } 288 | 289 | if (me.getWithCredentials()) { 290 | request.setWithCredentials(true); 291 | request.setUsername(me.getUsername()); 292 | request.setPassword(me.getPassword()); 293 | } 294 | return me.sendRequest(request); 295 | }, 296 | 297 | applyLayers: function(layers, layerCollection) { 298 | if (!layerCollection) { 299 | layerCollection = Ext.create('Carto.util.LayerCollection'); 300 | } 301 | layerCollection.add(layers); 302 | return layerCollection; 303 | }, 304 | 305 | updateUsername: function(username) { 306 | var layers = this.getLayers(); 307 | if (layers) { 308 | layers.each(function(layer) { 309 | layer.setUsername(username); 310 | }.bind(this)); 311 | } 312 | }, 313 | 314 | applyTable: function(table) { 315 | if (table && !table.isCartoTable) { 316 | table = Ext.create('Carto.sql.CartoTable', table); 317 | } 318 | return table; 319 | }, 320 | 321 | updateTable: function(table) { 322 | var layers = this.getLayers(); 323 | if (table && layers) { 324 | layers.each(function(layer) { 325 | layer.setTable(table.getId()); 326 | }); 327 | } 328 | } 329 | 330 | }); -------------------------------------------------------------------------------- /src/CartoStore.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.CartoStore',{ 2 | extend: 'Ext.data.Store', 3 | alias: 'store.carto', 4 | requires: [ 5 | 'Carto.CartoProxy' 6 | ], 7 | 8 | isCartoStore: true, 9 | 10 | // listeners: { 11 | // filterchange: function(store, filters) { 12 | // var storeConfig = this.getProxy().getCurrentConfig(); 13 | // storeConfig.filter = []; 14 | // filters.forEach(function(item){ 15 | // storeConfig.filter.push({ 16 | // operator: (item._operator) ? item._operator : "like", 17 | // value: (item._convert) ? item._value.toLocaleDateString() :item._value, 18 | // property: item._property 19 | // }); 20 | // }.bind(this)); 21 | // // if(this._subLayer){ 22 | // // this._subLayer.setSQL(this.sqlBuilder(storeConfig)); 23 | // // } 24 | // if(this._layer){ 25 | // this._layer.setSQL(this.sqlBuilder(storeConfig)); 26 | // } 27 | // } 28 | // }, 29 | 30 | constructor: function(config) { 31 | var table = config.table; 32 | if (table) { 33 | config.select = { 34 | tables: [table] 35 | }; 36 | delete config.table; 37 | } 38 | this.callParent([config]); 39 | }, 40 | 41 | applySelect: function(select) { 42 | if (select && !select.isCartoSelect) { 43 | select = Ext.create('Carto.sql.CartoSelect', select); 44 | } 45 | return select; 46 | }, 47 | 48 | proxy: { 49 | type: 'carto' 50 | }, 51 | 52 | remoteFilter: true, 53 | remoteSort: true, 54 | 55 | config: { 56 | groupBy: null, 57 | distinct: false, 58 | applyFilterToLayer: true, 59 | onlyTiles: false 60 | }, 61 | 62 | // addSubLayerToProxy: function(subLayer) { 63 | // this.getProxy().addSubLayer(subLayer, this.autoLoad || this.isLoaded() || this.isLoading()); 64 | // }, 65 | 66 | addLayerToProxy: function(layer) { 67 | this.getProxy().addLayer(layer, this.autoLoad || this.isLoaded() || this.isLoading()); 68 | }, 69 | 70 | // getSubLayer: function() { 71 | // return this._subLayer; 72 | // }, 73 | 74 | privates: { 75 | setLoadOptions: function(options) { 76 | var me = this, 77 | groupBy = me.getGroupBy(), 78 | onlyTiles = me.getOnlyTiles(), 79 | distinct = me.getDistinct(); 80 | if (groupBy) { 81 | options.groupBy = groupBy; 82 | } 83 | if (onlyTiles) { 84 | options.onlyTiles = true; 85 | } 86 | me.callParent([options]); 87 | } 88 | } 89 | }); -------------------------------------------------------------------------------- /src/LayerManager.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.LayerManager', { 2 | 3 | // requires: [ 4 | // 'Carto.CartoLayerBase', 5 | // 'Carto.CartoLayerContainer', 6 | // 'Carto.CartoSubLayer', 7 | // 'Carto.CartoLayer' 8 | // ], 9 | 10 | singleton: true, 11 | 12 | lookupLayer: function(layer, defaultType) { 13 | if (!layer.isLayer) { 14 | if (!layer.type && layer.hasOwnProperty('subLayers')) { 15 | layer.type = 'layergroup'; 16 | } 17 | layer = Ext.Factory.layer(layer); 18 | } 19 | return layer; 20 | }, 21 | 22 | lookupSubLayer: function(subLayer, defaultType) { 23 | if (!subLayer.isSubLayer) { 24 | if (!subLayer.type && defaultType) { 25 | subLayer.type = defaultType; 26 | } 27 | subLayer = Ext.Factory.sublayer(subLayer, defaultType); 28 | } 29 | return subLayer; 30 | }, 31 | 32 | lookupCss: function(css) { 33 | if (!css) { 34 | return null; 35 | } 36 | if (Ext.isArray(css)) { 37 | css = css.join(''); 38 | } 39 | if (typeof css !== 'string' && !css.isCartoCss) { 40 | if (!css.type) { 41 | css = { 42 | type: 'shell', 43 | value: css 44 | } 45 | } 46 | css = Ext.Factory.cartocss(css); 47 | } 48 | return css; 49 | } 50 | }); -------------------------------------------------------------------------------- /src/LeafletFunctionsMixin.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.LeafletFunctionsMixin', { 2 | /** 3 | * @param {integer} lat 4 | * @param {integer} lng 5 | * @param {integer} zoom 6 | */ 7 | panTo: function(lat, lng, zoom) { 8 | this.getCartoMap().setView([lat,lng], zoom || 10); 9 | }, 10 | 11 | /** 12 | * @param {} bounds 13 | * @param {} options 14 | */ 15 | fitBounds: function(bounds, options) { 16 | this.getCartoMap().fitBounds(bounds, options); 17 | }, 18 | 19 | setZoom: function(zoom, options) { 20 | this.getCartoMap().setZoom(zoom, options); 21 | }, 22 | 23 | /** 24 | * @param {} num 25 | * @param {} options 26 | */ 27 | zoomIn: function(num, options) { 28 | this.getCartoMap().zoomIn(num, options); 29 | }, 30 | 31 | /** 32 | * @param {} num 33 | * @param {} options 34 | */ 35 | zoomOut: function(num, options) { 36 | this.getCartoMap().zoomOut(num, options); 37 | }, 38 | 39 | /** 40 | * @param {} latLngBounds 41 | */ 42 | setMaxBounds: function(latLngBounds) { 43 | this.getCartoMap().setMaxBounds(latLngBounds); 44 | }, 45 | 46 | /** 47 | */ 48 | remove: function() { 49 | this.getCartoMap().remove(); 50 | }, 51 | /** 52 | */ 53 | getCenter: function() { 54 | return this.getCartoMap().getCenter(); 55 | }, 56 | /** 57 | */ 58 | getZoom: function() { 59 | return this.getCartoMap().getZoom(); 60 | }, 61 | /** 62 | */ 63 | getMinZoom: function() { 64 | return this.getCartoMap().getMinZoom(); 65 | }, 66 | /** 67 | */ 68 | getMaxZoom: function() { 69 | return this.getCartoMap().getMaxZoom(); 70 | }, 71 | /** 72 | */ 73 | getBounds: function() { 74 | return this.getCartoMap().getBounds(); 75 | }, 76 | /** 77 | * @param {} latLngBounds 78 | * @param {} inside 79 | */ 80 | getBoundsZoom: function(latLngBounds, inside) { 81 | return this.getCartoMap().getBoundsZoom(latLngBounds, inside); 82 | }, 83 | /** 84 | */ 85 | getSize: function() { 86 | return this.getCartoMap().getSize(); 87 | }, 88 | /** 89 | */ 90 | getPixelBounds: function() { 91 | return this.getCartoMap().getPixelBounds(); 92 | }, 93 | /** 94 | */ 95 | getPixelOrigin: function() { 96 | return this.getCartoMap().getPixelOrigin(); 97 | } 98 | 99 | 100 | }); -------------------------------------------------------------------------------- /src/Readme.md: -------------------------------------------------------------------------------- 1 | # carto/src 2 | 3 | This folder contains source code that will automatically be added to the classpath when 4 | the package is used. 5 | -------------------------------------------------------------------------------- /src/css/Css.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.css.Css', { 2 | alias: 'cartocss.shell', 3 | 4 | mixins: [ 5 | 'Ext.mixin.Factoryable' 6 | ], 7 | 8 | factoryConfig: { 9 | type: 'cartocss', 10 | defaultType: 'shell' 11 | }, 12 | 13 | config: { 14 | value: {} 15 | }, 16 | 17 | isCartoCss: true, 18 | 19 | constructor: function(cfg) { 20 | this.initConfig(cfg); 21 | return this; 22 | }, 23 | 24 | applyValue: function(newValue, oldValue) { 25 | if (oldValue) { 26 | newValue = Ext.apply(oldValue, newValue); 27 | } 28 | return newValue; 29 | }, 30 | 31 | updateValue: function(value) { 32 | this.createCssString(); 33 | }, 34 | 35 | createCssString: function(obj) { 36 | var isCase = obj !== undefined, 37 | obj = isCase ? obj : this.getValue(), 38 | str = '', 39 | table, k, i; 40 | 41 | if (!obj) { 42 | return ''; 43 | } 44 | if (obj.Map) { 45 | str += this.createTorqueString(obj.Map); 46 | } 47 | if (isCase) { 48 | str += '[' + obj.condition + ']{'; 49 | } else { 50 | table = 'layer'; 51 | str += '#' + table + '{'; 52 | } 53 | for (k in obj) { 54 | if (k === 'case') { 55 | if (!Ext.isArray(obj[k])) { 56 | obj[k] = [obj[k]]; 57 | } 58 | for (i in obj[k]) { 59 | str += this.createCssString(obj[k][i]); 60 | } 61 | } else if (k === 'condition' || k === 'Map') { 62 | 63 | } else { 64 | str += this.parseCss(k) + ':' + obj[k] + ';'; 65 | } 66 | } 67 | str += '}'; 68 | if (!isCase) { 69 | this.cssString = str; 70 | } 71 | return str; 72 | }, 73 | 74 | createTorqueString: function(obj) { 75 | var str = '', 76 | k; 77 | if (obj) { 78 | str += 'Map{'; 79 | for (k in obj) { 80 | str += this.parseCss(k, true) + ':' + obj[k] + ';'; 81 | } 82 | str += '}'; 83 | } 84 | return str; 85 | }, 86 | 87 | set: function(attr, value, suppressed) { 88 | if (typeof attr === 'string') { 89 | if (value === undefined) { 90 | delete this.css[attr]; 91 | } else { 92 | this.css[attr] = value; 93 | } 94 | } else { 95 | for (var k in attr) { 96 | this.set(k, attr[k], true); 97 | } 98 | suppressed = value; 99 | } 100 | if (!suppressed) { 101 | this.createCssString(); 102 | } 103 | }, 104 | 105 | addCase: function(caseObj) { 106 | var css = this.css; 107 | if (!css.case) { 108 | css.case = []; 109 | } 110 | css.case.push(caseObj); 111 | this.css = css; 112 | this.createCssString(); 113 | }, 114 | 115 | removeCase: function(condition) { 116 | var cssCase = this.css.case; 117 | if (cssCase) { 118 | for (var i = 0; i < cssCase.length; i++) { 119 | if (cssCase[i].condition === condition) { 120 | cssCase.splice(i, 1); 121 | this.createCssString(); 122 | break; 123 | } 124 | } 125 | } 126 | }, 127 | 128 | getCssString: function() { 129 | return this.cssString; 130 | }, 131 | 132 | parseCss: function(str, prefix) { 133 | return (prefix ? '-' : '') + str.replace(this.cssRegex, this.replaceUppercase); 134 | }, 135 | 136 | replaceUppercase: function(str) { 137 | return '-' + str.toLowerCase(); 138 | }, 139 | 140 | cssRegex: /[A-Z]/g 141 | }); -------------------------------------------------------------------------------- /src/css/HeatMap.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.css.HeatMap', { 2 | extend: 'Carto.css.Css', 3 | alias: 'cartocss.heatmap', 4 | 5 | value: { 6 | Map: { 7 | torqueFrameCount: 1, 8 | torqueAnimationDuration: 10, 9 | torqueTimeAttribute: '"contrdated"', 10 | torqueAggregationFunction: '"count(cartodb_id)"', 11 | torqueResolution: 8, 12 | torqueDataAggregation: 'linear' 13 | }, 14 | 15 | imageFilters: 'colorize-alpha(blue, cyan, lightgreen, yellow , orange, red)', 16 | markerFile: 'url(http://s3.amazonaws.com/com.cartodb.assets.static/alphamarker.png)', 17 | markerFillOpacity: '0.4*[value]', 18 | markerWidth: 35, 19 | case: [{ 20 | condition: 'frame-offset=1', 21 | markerWidth: 37, 22 | markerFillOpacity: 0.2, 23 | }, { 24 | condition: 'frame-offset=2', 25 | markerWidth: 39, 26 | markerFillOpacity: 0.1 27 | }] 28 | } 29 | }); -------------------------------------------------------------------------------- /src/css/Intensity.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.css.Intensity', { 2 | extend: 'Carto.css.Css', 3 | alias: 'cartocss.intensity', 4 | 5 | value: { 6 | markerFill: '#FFCC00', 7 | markerWidth: '10', 8 | markerLineColor: '#FFF', 9 | markerLineWidth: '1', 10 | markerLineOpacity: '1', 11 | markerFillOpacity: '0.9', 12 | markerCompOp: 'multiply', 13 | markerType: 'ellipse', 14 | markerPlacement: 'point', 15 | markerAllowOverlap: true, 16 | markerClip: false, 17 | markerMultiPolicy: 'largest' 18 | } 19 | }); -------------------------------------------------------------------------------- /src/css/Line.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.css.Line', { 2 | extend: 'Carto.css.Css', 3 | alias: 'cartocss.line', 4 | 5 | value: { 6 | lineColor: '#FFF', 7 | lineWidth: '1', 8 | lineOpacity: '0.5', 9 | lineCompOp: 'soft-light' 10 | } 11 | }); -------------------------------------------------------------------------------- /src/css/Point.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.css.Point', { 2 | extend: 'Carto.css.Css', 3 | alias: 'cartocss.point', 4 | 5 | value: { 6 | markerLineColor: '#FFF', 7 | markerLineWidth: '1.5', 8 | markerLineOpacity: '1', 9 | markerFillOpacity: '0.9', 10 | markerPlacement: 'point', 11 | markerType: 'ellipse', 12 | markerFill: '#FF6600', 13 | markerWidth: '10', 14 | markerAllowOverlap: true 15 | } 16 | }); -------------------------------------------------------------------------------- /src/css/Polygon.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.css.Polygon', { 2 | extend: 'Carto.css.Css', 3 | alias: 'cartocss.polygon', 4 | 5 | value: { 6 | polygonFill: '#374C70', 7 | polygonOpacity: '0.9', 8 | polygonGamma: '0.5', 9 | lineColor: '#FFF', 10 | lineWidth: '1', 11 | lineOpacity: '0.5', 12 | lineCompOp: 'soft-light' 13 | } 14 | }); -------------------------------------------------------------------------------- /src/css/Torque.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.css.Torque', { 2 | extend: 'Carto.css.Css', 3 | alias: 'cartocss.torque', 4 | 5 | value: { 6 | Map: { 7 | torqueFrameCount: 256, 8 | torqueAnimationDuration: 30, 9 | torqueTimeAttribute: '"cartodb_id"', 10 | torqueAggregationFunction: '"count(cartodb_id)"', 11 | torqueResolution: 2, 12 | torqueDataAggregation: 'linear' 13 | }, 14 | 15 | compOp: 'lighter', 16 | markerFillOpacity: 0.9, 17 | markerLineColor: '#FFF', 18 | markerLineWidth: 0, 19 | markerLineOpacity: 1, 20 | markerType: 'ellipse', 21 | markerWidth: 6, 22 | markerFill: '#0F3B82', 23 | case: [{ 24 | condition: 'frame-offset=1', 25 | markerWidth: 8, 26 | markerFillOpacity: 0.45 27 | }, { 28 | condition: 'frame-offset=2', 29 | markerWidth: 10, 30 | markerFillOpacity: 0.225 31 | }] 32 | } 33 | }); -------------------------------------------------------------------------------- /src/css/TorqueCat.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.css.TorqueCat', { 2 | extend: 'Carto.css.Css', 3 | alias: 'cartocss.torquecat', 4 | 5 | // Coming Soon... 6 | value: { 7 | markerLineColor: '#FFF', 8 | markerLineWidth: '1.5', 9 | markerLineOpacity: '1', 10 | markerFillOpacity: '0.9', 11 | markerPlacement: 'point', 12 | markerType: 'ellipse', 13 | markerFill: '#FF6600', 14 | markerWidth: '10', 15 | markerAllowOverlap: true 16 | } 17 | }); -------------------------------------------------------------------------------- /src/layer/LayerBase.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.layer.LayerBase', { 2 | extend: 'Carto.AbstractLayer', 3 | 4 | mixins: [ 5 | 'Ext.mixin.Factoryable' 6 | ], 7 | 8 | isLayer: true, 9 | 10 | factoryConfig: { 11 | defaultType: 'cartodb', 12 | type: 'layer' 13 | }, 14 | 15 | config: { 16 | map: null 17 | }, 18 | 19 | getRefOwner: function() { 20 | return this.getMap(); 21 | } 22 | }); -------------------------------------------------------------------------------- /src/layer/LayerGroup.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.layer.LayerGroup', { 2 | extend: 'Carto.layer.LayerBase', 3 | alias: 'layer.layergroup', 4 | 5 | requires: [ 6 | 'Carto.util.SubLayerCollection' 7 | ], 8 | 9 | isLayerGroup: true, 10 | 11 | config: { 12 | subLayers: null 13 | }, 14 | 15 | createCartoSubLayer: function(subLayer) { 16 | if (this.isCreating) { 17 | return; 18 | } 19 | this.isCreating = true; 20 | if (this.getCartoLayer()) { 21 | this.getCartoLayer().addLayer(subLayer.buildCartoLayer()); 22 | } else if (this.allSubLayersReady()) { 23 | this.getMap().createCartoLayer(this); 24 | } 25 | delete this.isCreating; 26 | }, 27 | 28 | allSubLayersReady: function() { 29 | var subLayers = this.getSubLayers(), 30 | allReady = true; 31 | if (subLayers) { 32 | subLayers.each(function(subLayer) { 33 | if (!subLayer.isReadyToBuild()) { 34 | allReady = false; 35 | return false; 36 | } 37 | }); 38 | } else { 39 | allReady = false; 40 | } 41 | return allReady; 42 | }, 43 | 44 | buildCartoLayer: function() { 45 | var subLayerArr = [], 46 | subLayers = this.getSubLayers(), 47 | ret = { 48 | ext_id: this.getId(), 49 | user_name: this.getUsername(), 50 | tiler_domain: this.useCartoDb ? 'cartodb.com' : 'carto.com', 51 | type: this.getType(), 52 | sublayers: subLayerArr 53 | }; 54 | if (subLayers) { 55 | subLayers.each(function(subLayer) { 56 | subLayerArr.push(subLayer.buildCartoSubLayer()); 57 | }); 58 | } 59 | return ret; 60 | }, 61 | 62 | updateMap: function(map, oldMap) { 63 | var subLayers = this.getSubLayers(); 64 | if (subLayers && map) { 65 | map.addSubLayer(subLayers.getRange()); 66 | } 67 | }, 68 | 69 | updateCartoLayer: function(cartoLayer) { 70 | this.callParent(arguments); 71 | var subLayers = this.getSubLayers(); 72 | if (subLayers) { 73 | subLayers.each(function(subLayer, index) { 74 | subLayer.setCartoLayer(cartoLayer.getSubLayer(index)); 75 | }); 76 | } 77 | }, 78 | 79 | applySubLayers: function(subLayers, subLayerCollection) { 80 | var map = this.getMap(); 81 | if (!subLayerCollection) { 82 | subLayerCollection = Ext.create('Carto.util.SubLayerCollection', { 83 | owner: this 84 | }); 85 | } 86 | subLayers = subLayerCollection.add(subLayers); 87 | if (subLayers && map) { 88 | map.addLayer(subLayers); 89 | } 90 | return subLayerCollection; 91 | }, 92 | 93 | doDestroy: function() { 94 | var subLayers = this.getSubLayers(); 95 | if (subLayers) { 96 | subLayers.each(function(subLayer) { 97 | subLayer.destroy(); 98 | }); 99 | } 100 | } 101 | }); -------------------------------------------------------------------------------- /src/layer/Torque.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.layer.Torque', { 2 | extend: 'Carto.layer.LayerBase', 3 | alias: 'layer.torque', 4 | 5 | mixins: [ 6 | 'Carto.mixin.DataContainingLayer' 7 | ], 8 | 9 | defaultBindProperty: 'store', 10 | 11 | twoWayBindable: [ 12 | 'selection' 13 | ], 14 | 15 | create: function() { 16 | if (this.isReadyToBuild()) { 17 | this.getMap().createCartoLayer(this); 18 | } 19 | }, 20 | 21 | buildCartoLayer: function() { 22 | return { 23 | type: this.getType(), 24 | user_name: this.getUsername(), 25 | options: { 26 | ext_id: this.getId(), 27 | query: this.getSql(), 28 | cartocss: this.getCss(), 29 | table_name: this.getTable() 30 | } 31 | }; 32 | }, 33 | 34 | updateCartoLayer: function(cartoLayer) { 35 | this.callParent(arguments); 36 | this.mixins.dataContainingLayer.updateCartoLayer.call(this, cartoLayer); 37 | } 38 | }); -------------------------------------------------------------------------------- /src/mixin/DataContainingLayer.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.mixin.DataContainingLayer', { 2 | mixinId: 'dataContainingLayer', 3 | 4 | requires: [ 5 | 'Carto.css.Css', 6 | 'Carto.css.Point', 7 | 'Carto.css.Line', 8 | 'Carto.css.Polygon', 9 | 'Carto.css.Intensity', 10 | 'Carto.css.HeatMap', 11 | 'Carto.css.Torque', 12 | 'Carto.css.TorqueCat', 13 | 'Carto.LayerManager' 14 | ], 15 | 16 | isDataContainingLayer: true, 17 | 18 | config: { 19 | store: null, 20 | sql: '', 21 | css: { 22 | type: 'point' 23 | }, 24 | selection: null, 25 | interactivity: null 26 | }, 27 | 28 | isReadyToBuild: function() { 29 | return !!(this.getSql() && this.getCss()); 30 | }, 31 | 32 | updateSql: function(sql) { 33 | if (sql) { 34 | var cartoLayer = this.getCartoLayer(); 35 | if (cartoLayer) { 36 | cartoLayer.setSQL(sql); 37 | } else { 38 | this.create(); 39 | } 40 | } 41 | }, 42 | 43 | updateCartoLayer: function(cartoLayer) { 44 | var interactivity = this.getInteractivity(), 45 | tooltip; 46 | if (interactivity && interactivity.enable) { 47 | cartoLayer.setInteraction(true); 48 | cartoLayer.set({ 49 | interactivity: 'cartodb_id' + ((interactivity.fields) ? ',' + interactivity.fields.join(',') : '') 50 | }); 51 | tooltip = interactivity.tooltip; 52 | if(tooltip && tooltip.enable){ 53 | this.getMap().getCartoMap().viz.addOverlay({ 54 | type: 'tooltip', 55 | layer: cartoLayer, 56 | template: tooltip.html || this.createDefaultTooltip(tooltip.fields || interactivity.fields, tooltip.mood), 57 | position: tooltip.position || 'bottom|right', 58 | fields: [this.createFields(interactivity.fields)] 59 | }); 60 | } 61 | cartoLayer.on('featureClick', this.featureClick.bind(this)); 62 | cartoLayer.on('featureOver', this.featureOver.bind(this)); 63 | cartoLayer.on('featureOut', this.featureOut.bind(this)); 64 | } 65 | }, 66 | 67 | featureClick: function(e, latLng, point, record){ 68 | var selection = this.getRecord(record.cartodb_id); 69 | this.setSelection(selection); 70 | this.getLayer().getMap().setSelection(selection); 71 | if (this.hasListeners.itemclick) { 72 | this.fireEvent('itemclick', this, selection); 73 | } 74 | if (this.hasListeners.select) { 75 | this.fireEvent('select', this, selection); 76 | } 77 | }, 78 | 79 | featureOver: function() { 80 | if (!this._cursor && $('.leaflet-container').css('cursor') != 'pointer' ) { 81 | this._cursor = $('.leaflet-container').css('cursor'); 82 | } 83 | $('.leaflet-container').css('cursor','pointer'); 84 | }, 85 | 86 | featureOut: function() { 87 | $('.leaflet-container').css('cursor',this._cursor); 88 | }, 89 | 90 | createDefaultTooltip: function(fields, mood) { 91 | var html = '
'; 92 | for(var i = 0; i < fields.length; i++){ 93 | html += '

' + fields[i] + '

{{' + fields[i] + '}}

'; 94 | } 95 | return html + '
'; 96 | }, 97 | 98 | createFields: function(fields) { 99 | var obj = {}; 100 | for(var i = 0; i < fields.length; i++){ 101 | obj[fields[i]] = fields[i]; 102 | } 103 | return obj; 104 | }, 105 | 106 | getRecord: function(cartodb_id) { 107 | return this.getStore().findRecord('cartodb_id', cartodb_id); 108 | }, 109 | 110 | applyStore: function(store) { 111 | if (store) { 112 | store = Ext.StoreManager.lookup(store, 'carto'); 113 | // 114 | if (!store.isCartoStore) { 115 | Ext.raise('Carto Layers cannot have non-carto stores.'); 116 | } 117 | // 118 | } 119 | return store; 120 | }, 121 | 122 | updateStore: function(store) { 123 | if (store) { 124 | store.addLayerToProxy(this); 125 | } 126 | }, 127 | 128 | updateSelection: function(selection) { 129 | if (this.hasListeners.select) { 130 | this.fireEvent('select', this, selection); 131 | } 132 | }, 133 | 134 | setCssAttribute: function(attr, value, suppressed) { 135 | if (typeof attr !== 'string') { 136 | suppressed = value; 137 | } 138 | this.css.set(attr, value); 139 | if (!suppressed) { 140 | this.updateCss(this.css); 141 | } 142 | }, 143 | 144 | addCssCase: function(caseObj, suppressed) { 145 | this.css.addCase(caseObj); 146 | if (!suppressed) { 147 | this.updateCss(this.css); 148 | } 149 | }, 150 | 151 | removeCssCase: function(condition, suppressed) { 152 | this.css.removeCase(condition); 153 | if (!suppressed) { 154 | this.updateCss(this.css); 155 | } 156 | }, 157 | 158 | getCss: function() { 159 | var css = this.callParent(); 160 | if (css && typeof css !== 'string') { 161 | css = css.getCssString(); 162 | } 163 | return css; 164 | }, 165 | 166 | applyCss: function(css) { 167 | return Carto.LayerManager.lookupCss(css); 168 | }, 169 | 170 | updateCss: function(css) { 171 | if (css) { 172 | var cartoLayer = this.getCartoLayer(); 173 | if (cartoLayer) { 174 | cartoLayer.setCartoCSS(typeof css === 'string' ? css : css.getCssString()); 175 | } else { 176 | this.create(); 177 | } 178 | } 179 | } 180 | 181 | }); -------------------------------------------------------------------------------- /src/sql/CartoField.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.sql.CartoField', { 2 | extend: 'Carto.sql.CartoSql', 3 | 4 | isCartoField: true, 5 | 6 | // In honor of the original intent for these fields, keep it light 7 | 8 | property: null, 9 | sql: '', 10 | 11 | constructor: function(config) { 12 | this.callParent([config]); 13 | if (!this.sql) { 14 | this.createSql(); 15 | } 16 | }, 17 | 18 | createSql: function() { 19 | var name = this.getName(), 20 | property = this.getProperty(); 21 | this.sql = property ? property + ' AS ' + name : name; 22 | }, 23 | 24 | parseSql: function(sql) { 25 | var parseSql = this.stripEnds(sql).split(/\s/), 26 | len = parseSql.length; 27 | if (len > 1) { 28 | this.setAlias(parseSql[len-1]); 29 | } else { 30 | this.setName(parseSql[0]); 31 | } 32 | }, 33 | 34 | getProperty: function() { 35 | return this.property; 36 | }, 37 | 38 | getId: function() { 39 | return this.getAlias() || this.getName(); 40 | }, 41 | 42 | singleRegex: /^\w+$/, 43 | 44 | stripEnds: function(str) { 45 | return str.replace(/^\s+/, '').replace(/\s+$/, ''); 46 | } 47 | }); -------------------------------------------------------------------------------- /src/sql/CartoFrom.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.sql.CartoFrom', { 2 | extend: 'Carto.sql.CartoSql', 3 | 4 | requires: [ 5 | 'Carto.util.TableCollection' 6 | ], 7 | 8 | isCartoFrom: true, 9 | 10 | config: { 11 | tables: null 12 | }, 13 | 14 | decode: function(config) { 15 | if (!config.tables) { 16 | config = {tables: config}; 17 | } 18 | if (!Ext.isArray(config.tables)) { 19 | config.tables = [config.tables]; 20 | } 21 | return config; 22 | }, 23 | 24 | isMulti: function() { 25 | return this.getTables().length > 1; 26 | }, 27 | 28 | applyTables: function(tables, tableCollection) { 29 | if (!tableCollection) { 30 | tableCollection = Ext.create('Carto.util.TableCollection'); 31 | } 32 | tableCollection.add(tables); 33 | return tableCollection; 34 | }, 35 | 36 | createSql: function(sql) { 37 | this.setSql(this.getTables().getSql()); 38 | } 39 | }); -------------------------------------------------------------------------------- /src/sql/CartoSql.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.sql.CartoSql', { 2 | isCartoSql: true, 3 | 4 | config: { 5 | sql: '', 6 | hardcoded: false 7 | }, 8 | 9 | constructor: function(config) { 10 | this.initConfig(config); 11 | var sql = this.getSql(); 12 | if (sql) { 13 | this.setHardcoded(true); 14 | this.parseSql(sql); 15 | } else { 16 | this.createSql(); 17 | } 18 | return this; 19 | }, 20 | 21 | initConfig: function(config) { 22 | config = this.decode(config); 23 | return this.callParent([config]); 24 | }, 25 | 26 | parseSql: Ext.emptyFn, 27 | createSql: Ext.emptyFn, 28 | 29 | decode: function(config) { 30 | return config; 31 | }, 32 | 33 | stripEnds: function(str) { 34 | return str.replace(/^\s+/, '').replace(/\s+$/, ''); 35 | } 36 | }); -------------------------------------------------------------------------------- /src/sql/CartoTable.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.sql.CartoTable', { 2 | extend: 'Carto.sql.CartoSql', 3 | 4 | isCartoTable: true, 5 | 6 | config: { 7 | name: '', 8 | alias: '' 9 | }, 10 | 11 | decode: function(config) { 12 | if (typeof config === 'string') { 13 | if (/\s/.test(this.stripEnds(config))) { 14 | config = {sql: config}; 15 | } else { 16 | config = {name: config}; 17 | } 18 | } 19 | return config; 20 | }, 21 | 22 | createSql: function() { 23 | var name = this.getName(), 24 | alias = this.getAlias(); 25 | this.setSql(name + (alias ? ' AS ' + alias : '')); 26 | }, 27 | 28 | parseSql: function(sql) { 29 | var parseSql = this.stripEnds(sql).split(/\s/), 30 | len = parseSql.length; 31 | if (len > 1) { 32 | this.setAlias(parseSql[len-1]); 33 | } else { 34 | this.setName(parseSql[0]); 35 | } 36 | }, 37 | 38 | getId: function() { 39 | return this.getAlias() || this.getName(); 40 | } 41 | }); -------------------------------------------------------------------------------- /src/sublayer/CartoDb.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.sublayer.CartoDb', { 2 | extend: 'Carto.sublayer.SubLayerBase', 3 | alias: 'sublayer.cartodb', 4 | 5 | buildCartoSubLayer: function() { 6 | return { 7 | type: this.getType(), 8 | sql: this.getSql(), 9 | cartocss: this.getCss() 10 | }; 11 | } 12 | }); -------------------------------------------------------------------------------- /src/sublayer/SubLayerBase.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.sublayer.SubLayerBase', { 2 | extend: 'Carto.AbstractLayer', 3 | 4 | mixins: [ 5 | 'Carto.mixin.DataContainingLayer', 6 | 'Ext.mixin.Factoryable' 7 | ], 8 | 9 | isSubLayer: true, 10 | 11 | defaultBindProperty: 'store', 12 | 13 | twoWayBindable: [ 14 | 'selection' 15 | ], 16 | 17 | factoryConfig: { 18 | defaultType: 'cartodb', 19 | type: 'sublayer' 20 | }, 21 | 22 | config: { 23 | layer: null 24 | }, 25 | 26 | create: function() { 27 | if (this.isReadyToBuild()) { 28 | this.getLayer().createCartoSubLayer(this); 29 | } 30 | }, 31 | 32 | updateUsername: function(username, oldUsername) { 33 | var layer = this.getLayer(); 34 | if (username && layer) { 35 | layer.setUsername(username); 36 | } 37 | }, 38 | 39 | updateLayer: function(layer, oldLayer) { 40 | if (layer) { 41 | var username = this.getUsername(); 42 | if (username) { 43 | layer.setUsername(username); 44 | } 45 | } 46 | }, 47 | 48 | updateCartoLayer: function(cartoLayer) { 49 | this.callParent(arguments); 50 | this.mixins.dataContainingLayer.updateCartoLayer.call(this, cartoLayer); 51 | }, 52 | 53 | getRefOwner: function() { 54 | return this.getLayer(); 55 | }, 56 | 57 | getMap: function() { 58 | return this.getLayer().getMap(); 59 | } 60 | }); -------------------------------------------------------------------------------- /src/util/LayerCollection.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.util.LayerCollection', { 2 | extend: 'Ext.util.Collection', 3 | 4 | requires: [ 5 | 'Carto.LayerManager', 6 | 'Carto.layer.LayerGroup', 7 | 'Carto.layer.Torque' 8 | ], 9 | 10 | isLayerCollection: true, 11 | 12 | constructor: function(config) { 13 | this.callParent([config]); 14 | this.setDecoder(this.decodeLayer); 15 | }, 16 | 17 | decodeLayer: function(layer) { 18 | var owner = this.getOwner(); 19 | if (!layer.isLayer && owner && owner.isMap) { 20 | layer.map = owner; 21 | } 22 | return Carto.LayerManager.lookupLayer(layer); 23 | }, 24 | 25 | getOwner: function() { 26 | return this.owner; 27 | } 28 | }); -------------------------------------------------------------------------------- /src/util/SubLayerCollection.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.util.SubLayerCollection', { 2 | extend: 'Ext.util.Collection', 3 | 4 | requires: [ 5 | 'Carto.LayerManager', 6 | 'Carto.sublayer.CartoDb' 7 | ], 8 | 9 | isSubLayerCollection: true, 10 | 11 | constructor: function(config) { 12 | this.callParent([config]); 13 | this.setDecoder(this.decodeSubLayer); 14 | }, 15 | 16 | decodeSubLayer: function(subLayer) { 17 | var owner = this.getOwner(); 18 | if (!subLayer.isSubLayer && owner && owner.isLayer) { 19 | subLayer.layer = owner; 20 | } 21 | return Carto.LayerManager.lookupSubLayer(subLayer, 'cartodb'); 22 | }, 23 | 24 | getOwner: function() { 25 | return this.owner; 26 | } 27 | }); -------------------------------------------------------------------------------- /src/util/TableCollection.js: -------------------------------------------------------------------------------- 1 | Ext.define('Carto.util.TableCollection', { 2 | extend: 'Ext.util.Collection', 3 | 4 | requires: [ 5 | 'Carto.sql.CartoTable' 6 | ], 7 | 8 | isTableCollection: true, 9 | 10 | constructor: function(config) { 11 | this.callParent([config]); 12 | this.setDecoder(this.decodeTable); 13 | }, 14 | 15 | decodeTable: function(table) { 16 | if (!table.isCartoTable) { 17 | table = new Carto.sql.CartoTable(table); 18 | } 19 | return table; 20 | }, 21 | 22 | getSql: function() { 23 | var sql = ''; 24 | this.items.forEach(function(item) { 25 | sql += item.getSql() + ','; 26 | }); 27 | return sql.slice(0,-1); 28 | } 29 | }); --------------------------------------------------------------------------------