├── .editorconfig ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .jshintrc ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── UPGRADE.md ├── bower.json ├── examples ├── advanced │ ├── README.txt │ ├── add_cities_on_map_by_double_click.html │ ├── afterInit_extend_raphael_paper.html │ ├── dataviz_example.html │ ├── eventHandlers_display_information_about_plotted_cities.html │ ├── eventHandlers_option_and_update_event_refresh_onclick.html │ ├── import_from_json.html │ ├── import_from_json_file.json │ ├── initial_zoom_level_on_a_specific_position.html │ ├── legend_show_hide.html │ ├── links_between_plotted_cities.html │ ├── map_focused_on_a_specific_area.html │ ├── multiple_instances.html │ ├── multiple_legends_plotted_cities.html │ ├── range_selection_areas.html │ ├── range_selection_plotted_cities.html │ ├── transformations_on_svg_plots.html │ ├── update_event_for_refreshing_elements.html │ ├── updates_on_links_performed.html │ ├── zoom_event_on_specific_area.html │ └── zoom_on_click.html └── basic │ ├── README.txt │ ├── horizontal_legend.html │ ├── href_areas_plotted_cities.html │ ├── legendSpecificAttrs_option.html │ ├── legend_SVG_paths.html │ ├── legend_areas.html │ ├── legend_areas_one_item_activated_at_a_time.html │ ├── legend_images.html │ ├── legend_plotted_cities.html │ ├── legend_plotted_cities_areas.html │ ├── legend_slices_fixed_values.html │ ├── minimal_example.html │ ├── multiple_projections.html │ ├── plotted_cities_areas.html │ └── zoom_features.html ├── js ├── jquery.mapael.js ├── jquery.mapael.min.js └── maps │ ├── README.txt │ ├── france_departments.js │ ├── france_departments.min.js │ ├── usa_states.js │ ├── usa_states.min.js │ ├── world_countries.js │ ├── world_countries.min.js │ ├── world_countries_mercator.js │ ├── world_countries_mercator.min.js │ ├── world_countries_miller.js │ └── world_countries_miller.min.js ├── package-lock.json ├── package.json └── test ├── const.js ├── index.html ├── marker.png ├── test-areas.js ├── test-basic.js ├── test-options.js ├── test-plots.js └── test-range.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | Before submitting a new issue, please search on the issue tracker first (https://github.com/neveldo/jQuery-Mapael/issues) 3 | 4 | 5 | ## Description 6 | 7 | 8 | 9 | ## Expected Behavior 10 | 11 | 12 | 13 | ## Current Behavior 14 | 15 | 16 | 17 | ## Environment 18 | 19 | * Mapael version: 20 | * Raphael version: 21 | * Browser Name and version: 22 | * Operating System and version (desktop or mobile): 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | Hey! Thanks for submitting a pull request! 3 | 4 | 5 | Are you adding a new map? Additionnal maps shall be added to the mapael-maps repository (https://github.com/neveldo/mapael-maps) 6 | 7 | 8 | Before submitting, please check the existing Pull Requests (https://github.com/neveldo/jQuery-Mapael/pulls). 9 | 10 | For new feature, please provide a working example (e.g. using JSFiddle https://jsfiddle.net/) 11 | 12 | For more information, see the `CONTRIBUTING` guide. 13 | 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .fuse_hidden* 3 | .idea 4 | /node_modules 5 | /bower_components -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 3, 3 | "jquery": true, 4 | "browser": true, 5 | 6 | "devel": true, 7 | "undef": true, 8 | "unused": true, 9 | "nonbsp": true, 10 | "latedef": true, 11 | "noarg": true, 12 | "eqeqeq": true, 13 | "forin": true, 14 | "freeze": true, 15 | "nocomma": true, 16 | "nonew": true, 17 | 18 | "globals": { 19 | "define": true, 20 | "require": true, 21 | "module": true, 22 | "exports": true, 23 | "Raphael": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4.1" 4 | before_script: 5 | - npm install -g grunt-cli -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | You want to contribute to Mapael? That's great, first of all, thank you ! 4 | 5 | There are several ways you can contribute : 6 | 7 | - **Wanna give a little hand?** Go to the [Issues](https://github.com/neveldo/jQuery-Mapael/issues) list and start helping people! 8 | 9 | - **Found a bug?** Submit a [bug report](https://github.com/neveldo/jQuery-Mapael/issues) and describe your problem. 10 | 11 | - **Add a new map** You can share your Map by submitting a Pull Request on the [mapael-maps repository](https://github.com/neveldo/mapael-maps). 12 | 13 | - **Improve the documentation** The mapael documentation can be improved by submitting a Pull Request on the [mapael-documentation repository](https://github.com/neveldo/mapael-documentation). 14 | 15 | - **Know how to resolve a bug / Want to add a feature?** Submit a Pull Request (*PR*). Your code will be reviewed and merged into Mapael (see link 2 below) 16 | 17 | - **You want to help, but don't know what to do?** Check the [TODO list](https://github.com/neveldo/jQuery-Mapael/wiki/TODO-list) for features/issues we need/are working on. 18 | 19 | Here are some readings: 20 | 21 | --- 22 | 23 | # Dev information 24 | 25 | ## Cloning the repository 26 | 27 | Before making any modification to Mapael, you will need your own Mapael fork! 28 | 29 | Here are some reading to get a local Mapael: 30 | 1. 31 | 1. 32 | 33 | ## Environment 34 | 35 | Mapael uses [NPM](https://www.npmjs.com/) to manage package dependencies 36 | and [Grunt](https://gruntjs.com/) to run development tasks. 37 | 38 | After cloning locally the Mapael repository, run this command-line: 39 | ``` 40 | npm install 41 | ``` 42 | 43 | Then you will be able to run all related Grunt tasks. 44 | 45 | ## Code quality 46 | 47 | Mapael uses [JSHint](http://jshint.com/about/) to check code quality. 48 | The rules are [explained in the Wiki](https://github.com/neveldo/jQuery-Mapael/wiki/JSHint). 49 | 50 | You can run this check with the following command-line: 51 | ``` 52 | grunt jshint 53 | ``` 54 | 55 | ## Test suite 56 | 57 | There is a test suite in the `/test` folder, power by [QUnit](http://qunitjs.com/). 58 | While not broken, it is, however, very light. We sadly don't have the time to expand it for now. 59 | 60 | When submitting a new PR, it is not expected from you to add any tests. 61 | But if you feel like you can, please do so. 62 | 63 | You can run this check with the following command-line 64 | (note: it will run JSHint, then the Test Suite): 65 | ``` 66 | grunt test 67 | ``` 68 | 69 | ## Build (minimified version) 70 | 71 | Mapael is distributed as a minified file for production (`jquery.mapael.min.js`). 72 | [UglifyJS](http://lisperator.net/uglifyjs/) is used for this operation. 73 | 74 | You can build it with the following command-line 75 | (note: it will run JSHint, then build the minimified files): 76 | ``` 77 | grunt build 78 | ``` 79 | 80 | When submitting a new PR, it is not expected from you to provide the minified version. 81 | This version is usually generated by maintainers before tagging a new release. 82 | 83 | ## Continuous Integration (CI) 84 | 85 | When submitting a new PR, you will see that [Travis](https://travis-ci.org/) (the CI tool) 86 | will automatically run some tests on your code. It performs two tests: 87 | 1. Run JSHint to check code quality 88 | 2. Run the Test Suite to check regression 89 | 90 | You will be able to check the result then, and perform adjustements if necessary 91 | (by pushing a new commit to the branch). 92 | 93 | These two tests are expected to pass when submitting a new PR. 94 | Please check your code so 95 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | jshint: { 4 | options: { 5 | jshintrc: '.jshintrc' 6 | }, 7 | all: ['js/**/*.js', '!js/**/*.min.js'] 8 | }, 9 | uglify: { 10 | options: { 11 | compress: true, 12 | mangle: true, 13 | preserveComments: 'some', 14 | report: 'gzip' 15 | }, 16 | build: { 17 | files: [ 18 | { 19 | expand: true, // Enable dynamic expansion. 20 | src: ['js/**/*.js', '!js/**/*.min.js'], 21 | ext: '.min.js', // Dest filepaths will have this extension. 22 | extDot: 'last' // Extensions in filenames begin after the last dot 23 | } 24 | ] 25 | } 26 | }, 27 | qunit: { 28 | all: { 29 | options: { 30 | urls: ['test/index.html'] 31 | } 32 | } 33 | } 34 | }); 35 | 36 | grunt.loadNpmTasks('grunt-contrib-jshint'); 37 | grunt.loadNpmTasks('grunt-contrib-qunit'); 38 | grunt.loadNpmTasks('grunt-contrib-uglify'); 39 | 40 | grunt.registerTask('test', ['jshint', 'qunit']); 41 | grunt.registerTask('build', ['uglify']); 42 | grunt.registerTask('default', ['test', 'build']); 43 | }; 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Vincent Brouté 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jQuery Mapael - Dynamic vector maps 2 | 3 | [![Build Status](https://travis-ci.org/neveldo/jQuery-Mapael.svg?branch=master)](https://travis-ci.org/neveldo/jQuery-Mapael) 4 | [![CDNJS](https://img.shields.io/cdnjs/v/jquery-mapael.svg)](https://cdnjs.com/libraries/jquery-mapael) 5 | 6 | ⚠️ Important note : I do not maintain jQuery Mapael anymore. However, feel free to submit a pull request if you need a bugfix or a security fix. More information : *[Ending an Open Source project (Mapael)](https://www.vincentbroute.fr/blog/ending-an-open-source-project-mapael/)*. 7 | 8 | The complete documentation is available on [Mapael website](https://www.vincentbroute.fr/mapael) (repository: ['neveldo/mapael-documentation'](https://github.com/neveldo/mapael-documentation)). 9 | 10 | Additional maps are stored in the repository ['neveldo/mapael-maps'](https://github.com/neveldo/mapael-maps). 11 | 12 | The documentation of Raphael.js is available [here](http://dmitrybaranovskiy.github.io/raphael/reference.html) ([mirror](https://www.vincentbroute.fr/mapael/raphael-js-documentation/)). 13 | 14 | ## Overview 15 | 16 | jQuery Mapael is a [jQuery](http://jquery.com/) plugin based on [raphael.js](http://raphaeljs.com/) that allows you to display dynamic vector maps. 17 | 18 | For example, with Mapael, you can display a map of the world with clickable countries. You can also build simple dataviz by setting some parameters in order to automatically set a color depending on a value to each area of your map and display the associated legend. Moreover, you can plot cities on the map with circles, squares or images by their latitude and longitude. Many more options are available, read the documentation in order to get a complete overview of mapael abilities. 19 | 20 | Mapael supports all modern browsers and Internet Explorer 9+. For older versions of IE, you can load jQuery 1.11.x and Raphael.js 2.1.2 as dependencies, most of the jQuery Mapael features should work fine. 21 | 22 | ![Dataviz example](https://www.vincentbroute.fr/mapael/assets/img/world-example.png) 23 | 24 | [See this example !](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/dataviz_example.html) 25 | 26 | ## Key features 27 | 28 | * based on **jQuery and raphael.js**. And optionally based on jQuery mousewheel for the zoom on mousewheel feature. 29 | * **Interactive.** Set href, tooltip, add events and many more on the elements of your map. 30 | * **Plottable cities** Cities can be plotted on the map with circles, squares, images or SVG paths by their latitude and longitude 31 | * **Areas and plotted points colorization with legends.** Mapael automatically sets attributes like color and size to each area and plotted point displayed on map and generates an interactive legend in order to build pretty dataviz 32 | * **Links between cities.** You can draw links between the cities of the map. 33 | * **Easy to add new maps.** Build your own maps based on SVG paths 34 | * **SEO-friendly.** An alternative content can be set for non-JS users and web crawlers 35 | * **Resizable** Maps are easily resizable. 36 | * **Zoom** Zoom and panning abilities (also on mobile devices). 37 | 38 | ## Installation 39 | 40 | ### Directly in your page 41 | 42 | **Note on dependencies**: [jQuery](http://jquery.com/) and [Raphael](http://raphaeljs.com) 43 | (and [Mousewheel](https://github.com/jquery/jquery-mousewheel), if needed) 44 | must be loaded **before** Mapael in order to work properly. 45 | 46 | **Note on maps**: map files must be loaded **after** Mapael in order to work properly. 47 | 48 | #### Using CDN 49 | 50 | Include in your project page one of these tags: 51 | ```html 52 | 53 | 54 | ``` 55 | 56 | #### Using self-hosted 57 | 58 | Download the [latest version](https://github.com/neveldo/jQuery-Mapael/releases/tag/2.2.0) 59 | and extract `jquery.mapael.min.js` in your project. 60 | 61 | Then, add the script to your page (update the path as needed): 62 | ```html 63 | 64 | ``` 65 | 66 | ### Using a package manager 67 | 68 | #### NPM / Yarn 69 | 70 | In your project root, run either commandline: 71 | ```text 72 | npm i --save jquery-mapael 73 | yarn add jquery-mapael 74 | ``` 75 | 76 | However, if you don't need the optional Mousewheel feature (for Zoom feature), 77 | then you can use the `--no-optional` flag to skip optional dependencies. 78 | 79 | Use either: 80 | ```text 81 | npm i --no-optional jquery-mapael 82 | yarn add --no-optional jquery-mapael 83 | ``` 84 | 85 | Then in your application: 86 | ```js 87 | require('jquery-mapael'); 88 | ``` 89 | Or, in ES6: 90 | ```js 91 | import 'jquery-mapael'; 92 | ``` 93 | 94 | #### Bower 95 | 96 | In your project root, run: 97 | ```text 98 | bower install jquery-mapael --save 99 | ``` 100 | 101 | ## Basic code example 102 | 103 | Here is the simplest example that shows how to display an empty map of the world : 104 | 105 | **HTML :** 106 | ```html 107 |
108 |
Alternative content
109 |
110 | ``` 111 | 112 | **JS :** 113 | ```js 114 | $(".container").mapael({ 115 | map : { 116 | name : "world_countries" 117 | } 118 | }); 119 | ``` 120 | 121 | ## Examples 122 | 123 | **Basic** 124 | 125 | * [Minimal example](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/minimal_example.html) 126 | * [Map with some custom plotted cities and areas](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/plotted_cities_areas.html) 127 | * [Map with zoom-in, zoom-out, zoom-reset buttons and zoom on mousewheel feature](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/zoom_features.html) 128 | * [Map with a legend for areas](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/legend_areas.html) 129 | * [Map with a legend for plotted cities](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/legend_plotted_cities.html) 130 | * [Map with a legend where slices are specified with a fixed value instead of min and max values](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/legend_slices_fixed_values.html) 131 | * [Map with a legend for images](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/legend_images.html) 132 | * [Map with SVG paths defined through the legend to plot some cities](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/legend_SVG_paths.html) 133 | * [Map with a legend for areas (only one item from the legend activated at a time.html)](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/legend_areas_one_item_activated_at_a_time.html) 134 | * [Map with a legend for plotted cities and areas](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/legend_plotted_cities_areas.html) 135 | * [Use legendSpecificAttrs option to apply specific attributes to the legend elements](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/legendSpecificAttrs_option.html) 136 | * [Map with an horizontal legend for plotted cities and areas](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/horizontal_legend.html) 137 | * [Map with href on areas and plotted cities](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/href_areas_plotted_cities.html) 138 | * [Multiple projection example (Equirectangular, Mercator and Miller.html)](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/basic/multiple_projections.html) 139 | 140 | **Advanced** 141 | 142 | * [Map with links between the plotted cities](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/links_between_plotted_cities.html) 143 | * [Map with some updates on links performed](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/updates_on_links_performed.html) 144 | * [Map with multiple plotted cities legends that handle different criteria](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/multiple_legends_plotted_cities.html) 145 | * [Trigger an 'update' event for refreshing elements](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/update_event_for_refreshing_elements.html) 146 | * [Use the 'eventHandlers' option and the 'update' event for refreshing areas when the user click on them](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/eventHandlers_option_and_update_event_refresh_onclick.html) 147 | * [Use 'zoom' event in order to zoom on specific areas of the map](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/zoom_event_on_specific_area.html) 148 | * [Use 'zoom.init' option in order to set an initial zoom level on a specific position](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/initial_zoom_level_on_a_specific_position.html) 149 | * [Use 'afterInit' option to extend the Raphael paper](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/afterInit_extend_raphael_paper.html) 150 | * [Use the 'eventHandlers' option to display information about plotted cities in a div on mouseover](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/eventHandlers_display_information_about_plotted_cities.html) 151 | * [Dataviz example : population of countries and cities by year](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/dataviz_example.html) 152 | * [Importing data from JSON (French railway station for passengers.html)](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/import_from_json.html) 153 | * [Show or hide the legends through the 'update' event and the 'setLegendElemsState' option.](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/legend_show_hide.html) 154 | * [Multiple instances of Mapael on the same page with overriden default options](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/multiple_instances.html) 155 | * [Map with a range selection for areas](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/range_selection_areas.html) 156 | * [Map with a range selection for plotted cities](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/range_selection_plotted_cities.html) 157 | * [Zoom on click example](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/zoom_on_click.html) 158 | * [Map with some transformations performed on SVG plotted points](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/transformations_on_svg_plots.html) 159 | * [Allow the user to add some cities by double-clicking on the map](https://rawgit.com/neveldo/jQuery-Mapael/master/examples/advanced/add_cities_on_map_by_double_click.html) 160 | 161 | ## Contributing 162 | 163 | Want to contribute? See the [CONTRIBUTING](https://github.com/neveldo/jQuery-Mapael/blob/master/CONTRIBUTING.md) file. 164 | 165 | ## License 166 | 167 | Copyright (C) 2013-2022 [Vincent Brouté](https://www.vincentbroute.fr) 168 | 169 | jQuery Mapael is licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php). 170 | 171 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 172 | 173 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 174 | 175 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 176 | -------------------------------------------------------------------------------- /UPGRADE.md: -------------------------------------------------------------------------------- 1 | # Upgrading Mapael 2 | 3 | ## From 1.1.0 to 2.0.0 4 | 5 | ### A. Change your `update` event trigger ([#105](https://github.com/neveldo/jQuery-Mapael/issues/105)) 6 | The `update` event has a new signature. 7 | It now accepts a single object containing all the options. 8 | 9 | `opt.resetPlots` and `opt.resetAreas` were removed in favor of a new `options.replaceOptions` 10 | 11 | **Old signature:** 12 | ```javascript 13 | var updatedOptions = {}; 14 | var newPlots = {}; 15 | var deletedPlots = []; 16 | var opt = { 17 | animDuration: 0, 18 | resetPlots: false, 19 | resetAreas: false, 20 | afterUpdate: function(){}, 21 | newLinks: {} 22 | deletedLinks: [] 23 | }; 24 | $(".container").trigger('update', [updatedOptions, newPlots, deletedPlots, opt]); 25 | ``` 26 | **New signature:** 27 | ```javascript 28 | var options = { 29 | mapOptions: {}, // was updatedOptions 30 | replaceOptions: false // replace opt.resetPlots/resetAreas: whether mapsOptions should entirely replace current map options, or just extend it, 31 | newPlots: {}, // was newPlots 32 | newLinks: {}, // was opt.newLinks 33 | deletePlotKeys: [], // was deletedPlots 34 | deleteLinkKeys: [], // was opt.deletedLinks 35 | setLegendElemsState: true, // is new 36 | animDuration: 0, // was opt.animDuration 37 | afterUpdate: function(){} // was opt.afterUpdate 38 | }; 39 | $(".container").trigger('update', [options]); 40 | ``` 41 | 42 | ### B. Behavior modification for legend slices ([#84](https://github.com/neveldo/jQuery-Mapael/issues/84)) 43 | The behavior has changed regarding the slices `max` value for legends: it is now inclusive like the `min` value. 44 | 45 | **Old behavior:** 46 | ``` 47 | slices[].min <= value < slices[].max 48 | ``` 49 | 50 | **New behavior:** 51 | ``` 52 | slices[].min <= value <= slices[].max 53 | ``` 54 | 55 | ### C. New architecture ([#117](https://github.com/neveldo/jQuery-Mapael/issues/117)) 56 | Mapael version 2.0.0 introduces a new architecture. 57 | 58 | **Before**, the *unique* Mapael object was stored directly inside `$.fn.mapael` and accessible here. 59 | The current Mapael instance of each map was not accessible. 60 | 61 | **After**, you have: 62 | - in `$.mapael`: the Mapael *prototype* (this is *not* an instance of mapael, this is only the prototype) 63 | - in `$.fn.mapael`: the DOM attachment method (this is only a wrapper to attach mapael to the element by creating a mapael instance). 64 | - in each DOM container data: the current instance of Mapael (accessible through `$(".mapcontainer").data("mapael")`) 65 | - The zoom data are no longer accessible through `$('.mapcontainer').data('zoomLevel');` for instance. They are now stored in `$(".mapcontainer").data("mapael").zoomData.zoomLevel` for instance. 66 | 67 | These internal changes have some external impacts: 68 | 69 | #### C.1. For your maps: extend `$.mapael` instead of `$.fn.mapael` 70 | Extending `$.fn.mapael` is deprecated as of Mapael version 2.0.0 and support will be removed in future version. 71 | 72 | A warning message is logged in the console at runtime for maps extending `$.fn.mapael`. 73 | 74 | The best way would be to update your map in the [mapael-maps repository](https://github.com/neveldo/mapael-maps). 75 | 76 | #### C.2. New way to override the default behavior 77 | Basically, you need to modify the prototype inside `$.mapael` instead of the old `$.fn.mapael`. 78 | 79 | **Before:** 80 | - override the default options: `$.fn.mapael.defaultOptions = {}` 81 | - override a method: `$.fn.mapael.tooltip = function() {}` 82 | 83 | **After:** 84 | - override the default options: `$.mapael.prototype.defaultOptions = {...}` 85 | - override a method: `$.mapael.prototype.setTooltip = function(...) {...}` 86 | 87 | Additional note: use `$.mapael.prototype.setTooltip.call(this, ...)` to call original behavior. 88 | 89 | ### D. New Zoom buttons functionnality ([#166](https://github.com/neveldo/jQuery-Mapael/issues/166)) 90 | The zoom buttons are more curstomizable! Also, a reset buttons is now available by default. 91 | 92 | **Old options:** 93 | ```javascript 94 | zoom: { 95 | enabled: false, 96 | maxLevel: 10, 97 | step: 0.25, 98 | mousewheel: true, 99 | /* Old options */ 100 | zoomIncssClass: "zoomIn", 101 | zoomOutcssClass: "zoomOut", 102 | /* - */ 103 | touch: true, 104 | animDuration: 200, 105 | animEasing: "linear" 106 | } 107 | ``` 108 | 109 | **New options:** 110 | ```javascript 111 | zoom: { 112 | enabled: false, 113 | maxLevel: 10, 114 | step: 0.25, 115 | mousewheel: true, 116 | touch: true, 117 | animDuration: 200, 118 | animEasing: "linear", 119 | /* New options */ 120 | buttons: { 121 | "reset": { 122 | cssClass: "zoomButton zoomReset", 123 | content: "•", // bullet sign 124 | title: "Reset zoom" 125 | }, 126 | "in": { 127 | cssClass: "zoomButton zoomIn", 128 | content: "+", 129 | title: "Zoom in" 130 | }, 131 | "out": { 132 | cssClass: "zoomButton zoomOut", 133 | content: "−", // minus sign 134 | title: "Zoom out" 135 | } 136 | } 137 | } 138 | ``` 139 | 140 | ### E. Updated the CSS position of the tooltip 141 | 142 | In the CSS file related to mapael maps, the tooltip position should now be 'absolute' instead of 'fixed'. 143 | 144 | **Old style:** 145 | ```css 146 | .mapael .mapTooltip { 147 | position: fixed; 148 | } 149 | ``` 150 | **New style:** 151 | ```css 152 | .mapael .mapTooltip { 153 | position: absolute; 154 | } 155 | ``` -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-mapael", 3 | "version": "2.2.0", 4 | "main": "./js/jquery.mapael.js", 5 | "description": "jQuery Mapael is a jQuery plugin based on raphael.js that allows you to display dynamic vector maps.", 6 | "license": "MIT", 7 | "ignore": [ 8 | ".*", 9 | "*.json", 10 | "*.md", 11 | "*.txt", 12 | "Gruntfile.js", 13 | "test", 14 | "examples", 15 | "!LICENSE", 16 | "!CHANGELOG.md" 17 | ], 18 | "dependencies": { 19 | "raphael": "^2.2", 20 | "jquery": "^3.0", 21 | "jquery-mousewheel": "^3.1" 22 | }, 23 | "devDependencies": { 24 | "grunt": "^1.0", 25 | "grunt-contrib-jshint": "^1.0", 26 | "grunt-contrib-qunit": "^1.2", 27 | "grunt-contrib-uglify": "^2.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/advanced/README.txt: -------------------------------------------------------------------------------- 1 | Advanced examples: special Javascript processing needed. 2 | -------------------------------------------------------------------------------- /examples/advanced/add_cities_on_map_by_double_click.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Allow the user to add some cities by double-clicking on the map 6 | 84 | 85 | 86 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 128 | 129 | 130 | 131 | 132 | 133 |
134 |

Allow the user to add some cities by double-clicking on the map

135 | 136 |
137 |
138 | Alternative content for the map 139 |
140 |
141 | 142 |

All example for jQuery Mapael are available here.

143 |
144 | 145 | -------------------------------------------------------------------------------- /examples/advanced/afterInit_extend_raphael_paper.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Use 'afterInit' option to extend the Raphael paper 6 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 74 | 75 | 76 | 77 | 78 |
79 | 80 |

Use 'afterInit' option to extend the Raphael paper

81 |
82 |
83 | Alternative content for the map 84 |
85 |
86 |

All example for jQuery Mapael are available here.

87 | 88 |
89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /examples/advanced/eventHandlers_display_information_about_plotted_cities.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Use the 'eventHandlers' option to display information about plotted cities in a div on mouseover 6 | 54 | 55 | 56 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 139 | 140 | 141 | 142 | 143 |
144 | 145 |

Use the 'eventHandlers' option to display information about plotted cities in a div on mouseover

146 | 147 |
148 | Move your cursor over the plots on the map in order to show information in this div.
149 |
150 |
151 | Alternative content for the map 152 |
153 |
154 | 155 |

All example for jQuery Mapael are available here.

156 | 157 |
158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /examples/advanced/eventHandlers_option_and_update_event_refresh_onclick.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Use the 'eventHandlers' option and the 'update' event for refreshing areas when the user click on 6 | them 7 | 84 | 85 | 86 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 184 | 185 | 186 | 187 | 188 |
189 | 190 |

Use the 'eventHandlers' option and the 'update' event for refreshing areas when the user click on them

191 | 192 |
193 |
Alternative content for the map 194 | 195 |
196 |
197 | 198 |

All example for jQuery Mapael are available here.

199 | 200 |
201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /examples/advanced/import_from_json.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Minimal example 6 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 124 | 125 | 126 | 127 | 128 |
129 | 130 |

Importing data from JSON

131 | 132 |

French railway station for passengers

133 | 134 |

Category: national stations (above 250 000 annual visitors) as at 20th of November, 2015

135 | 136 |

137 | JSON data are taken from SNCF Open Data website. 138 |

139 | 140 |
141 |
142 | Alternative content for the map 143 |
144 |
145 | 146 |

All example for jQuery Mapael are available here.

147 | 148 |
149 | 150 | 151 | -------------------------------------------------------------------------------- /examples/advanced/initial_zoom_level_on_a_specific_position.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Use 'zoom.init' option in order to set an initial zoom level on a specific position 6 | 88 | 89 | 90 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 125 | 126 | 127 | 128 | 129 |
130 | 131 |

Use 'zoom.init' option in order to set an initial zoom level on a specific position

132 | 133 |
134 |
135 | Alternative content for the map 136 |
137 |
138 | 139 |

All example for jQuery Mapael are available here.

140 | 141 |
142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /examples/advanced/links_between_plotted_cities.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Map with links between the plotted cities 6 | 45 | 46 | 47 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 241 | 242 | 243 | 244 | 245 |
246 | 247 |

Map with links between the plotted cities

248 | 249 |
250 |
251 | Alternative content for the map 252 |
253 |
254 | 255 |

All example for jQuery Mapael are available here.

256 | 257 |
258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /examples/advanced/multiple_legends_plotted_cities.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Map with multiple plotted cities legends that handle different criteria 6 | 48 | 49 | 50 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 237 | 238 | 239 | 240 | 241 |
242 | 243 |

Map with multiple plotted cities legends that handle different criteria

244 | 245 |
246 |
247 |
248 | Alternative content for the legend 249 |
250 |
251 | Alternative content for the legend2 252 |
253 |
254 |
255 |
256 | Alternative content for the map 257 |
258 | 259 |
260 | 261 |

All example for jQuery Mapael are available here.

262 | 263 |
264 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /examples/advanced/transformations_on_svg_plots.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Map with some transformations performed on SVG plotted points 6 | 86 | 87 | 88 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 213 | 214 | 215 | 216 | 217 |
218 | 219 |

Map with some transformations performed on SVG plotted points

220 | 221 |
222 |
223 | Alternative content for the map 224 |
225 |
226 | Alternative content for the legend 227 |
228 | 229 |
230 | 231 |

All example for jQuery Mapael are available here.

232 | 233 |
234 | 235 | 236 | 237 | -------------------------------------------------------------------------------- /examples/advanced/update_event_for_refreshing_elements.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Trigger an 'update' event for refreshing elements 6 | 85 | 86 | 87 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 220 | 221 | 222 | 223 | 224 |
225 | 226 |

Trigger an 'update' event for refreshing elements

227 | 228 |
229 | 230 | 231 |
232 | Alternative content for the map 233 |
234 |
235 | 236 |

All example for jQuery Mapael are available here.

237 | 238 |
239 | 240 | 241 | 242 | -------------------------------------------------------------------------------- /examples/advanced/updates_on_links_performed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Map with some updates on links performed 6 | 83 | 84 | 85 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 183 | 184 | 185 | 186 | 187 |
188 | 189 |

Map with some updates on links performed

190 | 191 |
192 | 193 | 194 |
195 | Alternative content for the map 196 |
197 |
198 | 199 |

All example for jQuery Mapael are available here.

200 | 201 |
202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /examples/advanced/zoom_event_on_specific_area.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Use 'zoom' event in order to zoom on specific areas of the map 6 | 87 | 88 | 89 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 156 | 157 | 158 | 159 | 160 |
161 | 162 |

Use 'zoom' event in order to zoom on specific coordinate, plot or area

163 | 164 | 165 | 166 | 167 | You can also click on an area directly. 168 | 169 |
170 |
171 | Alternative content for the map 172 |
173 |
174 | 175 |

All example for jQuery Mapael are available here.

176 | 177 |
178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /examples/basic/README.txt: -------------------------------------------------------------------------------- 1 | Basic examples: no additional Javascript needed to make it work. 2 | -------------------------------------------------------------------------------- /examples/basic/href_areas_plotted_cities.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Map with href on areas and plotted cities 6 | 83 | 84 | 85 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 213 | 214 | 215 | 216 | 217 |
218 | 219 |

Map with href on areas and plotted cities

220 | 221 |
222 |
223 | Alternative content for the map 224 |
225 |
226 | 227 |

All example for jQuery Mapael are available here.

228 | 229 |
230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /examples/basic/legend_SVG_paths.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Map with SVG paths defined through the legend to plot some cities 6 | 86 | 87 | 88 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 201 | 202 | 203 | 204 | 205 |
206 | 207 |

Map with SVG paths defined through the legend to plot some cities

208 | 209 |
210 |
211 | Alternative content for the map 212 |
213 |
214 | Alternative content for the legend 215 |
216 | 217 |
218 | 219 |

All example for jQuery Mapael are available here.

220 | 221 |
222 | 223 | 224 | 225 | 226 | -------------------------------------------------------------------------------- /examples/basic/legend_images.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Map with a legend for images 6 | 47 | 48 | 49 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 157 | 158 | 159 | 160 | 161 |
162 | 163 |

Map with a legend for images

164 | 165 |
166 |
167 | Alternative content for the map 168 |
169 |
170 | Alternative content for the legend 171 |
172 | 173 |
174 | 175 |

All example for jQuery Mapael are available here.

176 | 177 |
178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /examples/basic/legend_slices_fixed_values.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Map with a legend where slices are specified with a fixed value instead of min and max values 6 | 45 | 46 | 47 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 147 | 148 | 149 | 150 | 151 |
152 | 153 |

Map with a legend where slices are specified with a fixed value instead of min and max values

154 | 155 |
156 |
157 | Alternative content for the map 158 |
159 |
160 | Alternative content for the legend 161 |
162 |
163 | 164 |

All example for jQuery Mapael are available here.

165 | 166 |
167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /examples/basic/minimal_example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Minimal example 6 | 23 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 47 |
48 | 49 |

Minimal example

50 | 51 |
52 |
53 | Alternative content for the map 54 |
55 |
56 | 57 |

All example for jQuery Mapael are available here.

58 | 59 |
60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /examples/basic/multiple_projections.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Multiple projection example 6 | 41 | 42 | 43 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 186 | 187 | 188 | 189 | 190 |
191 | 192 |

Multiple projection example

193 | 194 |

Equirectangular projection

195 |
196 |
197 | Alternative content for the map 198 |
199 |
200 | 201 |

Mercator projection

202 |
203 |
204 | Alternative content for the map 205 |
206 |
207 | 208 |

Miller projection

209 |
210 |
211 | Alternative content for the map 212 |
213 |
214 | 215 |

All example for jQuery Mapael are available here.

216 | 217 |
218 | 219 | 220 | 221 | 222 | -------------------------------------------------------------------------------- /examples/basic/plotted_cities_areas.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Map with some custom plotted cities and areas 6 | 45 | 46 | 47 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 209 | 210 | 211 | 212 | 213 |
214 | 215 |

Map with some custom plotted cities and areas

216 | 217 |
218 |
219 | Alternative content for the map 220 |
221 |
222 | 223 |

All example for jQuery Mapael are available here.

224 | 225 |
226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /examples/basic/zoom_features.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Map with zoom-in, zoom-out buttons and zoom on mousewheel 6 | 85 | 86 | 87 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 244 | 245 | 246 | 247 | 248 | 249 |
250 |

Map with zoom-in, zoom-out buttons and zoom on mousewheel

251 | 252 |
253 |
254 | Alternative content for the map 255 |
256 |
257 | 258 |

All example for jQuery Mapael are available here.

259 |
260 | 261 | -------------------------------------------------------------------------------- /js/maps/README.txt: -------------------------------------------------------------------------------- 1 | Additional maps are stored in the repository neveldo/mapael-maps 2 | 3 | Full link: https://github.com/neveldo/mapael-maps 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-mapael", 3 | "version": "2.2.0", 4 | "description": "jQuery Mapael is a jQuery plugin based on raphael.js that allows you to display dynamic vector maps.", 5 | "homepage": "https://www.vincentbroute.fr/mapael/", 6 | "main": "./js/jquery.mapael.js", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/neveldo/jQuery-Mapael.git" 10 | }, 11 | "author": "Vincent Brouté (https://www.vincentbroute.fr/)", 12 | "license": "MIT", 13 | "bugs": { 14 | "url": "https://github.com/neveldo/jQuery-Mapael/issues" 15 | }, 16 | "keywords": [ 17 | "jquery", 18 | "map", 19 | "vector", 20 | "svg", 21 | "dataviz", 22 | "dynamic", 23 | "jquery-plugin", 24 | "browser" 25 | ], 26 | "dependencies": { 27 | "jquery": "^3.0 || ^2.0 || ^1.0", 28 | "raphael": "^2.2.0 || ^2.1.1" 29 | }, 30 | "peerDependencies": { 31 | "jquery": "^3.0 || ^2.0 || ^1.0" 32 | }, 33 | "optionalDependencies": { 34 | "jquery-mousewheel": "^3.1" 35 | }, 36 | "devDependencies": { 37 | "grunt": "^1.0", 38 | "grunt-contrib-jshint": "^1.1", 39 | "grunt-contrib-qunit": "^1.2", 40 | "grunt-contrib-uglify": "^2.0" 41 | }, 42 | "files": [ 43 | "js/" 44 | ], 45 | "scripts": { 46 | "test": "grunt test" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/const.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Unit Test for Mapael 3 | * 4 | * Constants 5 | */ 6 | 7 | CST_NB_OF_FRANCE_DPTMT = 96; 8 | CST_MAP_MAX_WIDTH = 800; 9 | CST_MAP_MAX_HEIGHT = 834.8948306319708; // Calculated 10 | 11 | CST_MOUSEOVER_TIMEOUT_MS = 300; // 120 in code 12 | 13 | CST_NB_OF_HOVER_CHECK = CST_NB_OF_FRANCE_DPTMT / 6 ; // We wont check all dptmt as it takes lot of times 14 | 15 | // Options for module 16 | CST_MODULE_OPTS = { 17 | beforeEach: function() { 18 | this.$map = $(".mapcontainer"); 19 | }, 20 | afterEach: function() { 21 | if (this.$map && this.$map.data) { 22 | var mapael = this.$map.data('mapael'); 23 | if (mapael) { 24 | mapael.destroy(); 25 | } 26 | } 27 | } 28 | }; 29 | 30 | CST_MAPCONF_NOANIMDURATION = { 31 | map : { 32 | defaultArea : { 33 | attrsHover : { 34 | animDuration : 0 35 | }, 36 | text : { 37 | attrsHover : { 38 | animDuration : 0 39 | } 40 | } 41 | }, 42 | defaultPlot : { 43 | attrsHover : { 44 | animDuration : 0 45 | }, 46 | text : { 47 | attrsHover : { 48 | animDuration : 0 49 | } 50 | } 51 | }, 52 | defaultLink : { 53 | attrsHover : { 54 | animDuration : 0 55 | }, 56 | text : { 57 | attrsHover : { 58 | animDuration : 0 59 | } 60 | } 61 | }, 62 | zoom : { 63 | animDuration : 0 64 | } 65 | } 66 | }; 67 | 68 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mapael Unit Testing 6 | 7 | 8 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
49 |
50 |
51 |
52 |
53 | Alternative content for the map 54 |
55 |
56 | Alternative content for the legend 57 |
58 |
59 | Alternative content for the legend 60 |
61 |
62 |
63 |
64 | 65 | 66 | -------------------------------------------------------------------------------- /test/marker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neveldo/jQuery-Mapael/f27c7dffe28284cff213c42fcfc2f4ee2b96481b/test/marker.png -------------------------------------------------------------------------------- /test/test-areas.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Unit Test for Mapael 3 | * Module: Areas 4 | * 5 | * Here are tested: 6 | * - options.map.defaultArea 7 | * - options.map.areas 8 | */ 9 | $(function() { 10 | 11 | QUnit.module("Areas", CST_MODULE_OPTS); 12 | 13 | QUnit.test("defaultArea option override", function(assert) { 14 | var self = this; 15 | var mouseover_async_done = assert.async(CST_NB_OF_HOVER_CHECK); 16 | 17 | var CST_DEFAULTAREA = { 18 | attrs: { 19 | fill: "#f4f4e8", 20 | stroke: "#ced8d0" 21 | }, 22 | attrsHover: { 23 | fill: "#a4e100", 24 | stroke: "#aaaaaa" 25 | }, 26 | text: { 27 | attrs: { 28 | fill: "#505444" 29 | }, 30 | attrsHover: { 31 | fill: "#000" 32 | } 33 | } 34 | }; 35 | 36 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 37 | map: { 38 | name: "france_departments", 39 | defaultArea: CST_DEFAULTAREA 40 | } 41 | })); 42 | 43 | assert.ok(self.$map.find(".map svg")[0], "Map created" ); 44 | 45 | var counter = 0; 46 | self.$map.find("svg path").slice(0, CST_NB_OF_HOVER_CHECK).each(function(id, elem) { 47 | var $elem = $(elem); 48 | var data_id = $elem.attr("data-id"); 49 | assert.equal($elem.attr("fill"), CST_DEFAULTAREA.attrs.fill, "Check overriden fill before mouseover for " + data_id); 50 | assert.equal($elem.attr("stroke"), CST_DEFAULTAREA.attrs.stroke, "Check overriden stroke before mouseover for " + data_id); 51 | 52 | setTimeout(function() { 53 | $elem.trigger("mouseover"); 54 | setTimeout(function() { 55 | assert.equal($elem.attr("fill"), CST_DEFAULTAREA.attrsHover.fill, "Check overriden hover fill after mouseover for " + data_id); 56 | assert.equal($elem.attr("stroke"), CST_DEFAULTAREA.attrsHover.stroke, "Check overriden hover stroke after mouseover for " + data_id); 57 | 58 | $elem.trigger("mouseout"); 59 | setTimeout(function() { 60 | assert.equal($elem.attr("fill"), CST_DEFAULTAREA.attrs.fill, "Check overriden fill after mouseout for " + data_id); 61 | mouseover_async_done(); 62 | }, CST_MOUSEOVER_TIMEOUT_MS); 63 | }, CST_MOUSEOVER_TIMEOUT_MS); 64 | }, counter * (CST_MOUSEOVER_TIMEOUT_MS * 2)); 65 | counter++; 66 | }); 67 | }); 68 | 69 | QUnit.test("Area custom option override", function(assert) { 70 | var self = this; 71 | var mouseover_async_done = assert.async(2); 72 | var text_mouseover_async_done = assert.async(); 73 | 74 | var CST_CUSTOMAREA = { 75 | "department-56": { 76 | text: { 77 | content: "TEXT_department-56", 78 | attrs: {"font-size": 5}, 79 | attrsHover: {"font-size": 20} 80 | }, 81 | tooltip: {content: "TOOLTIP_department-56"} 82 | }, 83 | "department-21": { 84 | attrs: { 85 | fill: "#488402" 86 | }, 87 | attrsHover: { 88 | fill: "#a4e100" 89 | } 90 | }, 91 | "department-74": { 92 | text: { 93 | content: "TEXT_department-74", 94 | position:"top", 95 | margin:0 96 | }, 97 | href: "http://path.to.74.com", 98 | target: "_blank" 99 | } 100 | }; 101 | 102 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 103 | map: { 104 | name: "france_departments" 105 | }, 106 | areas: CST_CUSTOMAREA 107 | })); 108 | 109 | assert.ok(self.$map.find(".map svg")[0], "Map created" ); 110 | 111 | var $text_56 = self.$map.find(".map svg text[data-id='department-56']"); 112 | var $text_74 = self.$map.find(".map svg text[data-id='department-74']"); 113 | 114 | assert.ok($text_56[0], "Text created for department-56" ); 115 | assert.equal($text_56.attr("font-size"), CST_CUSTOMAREA["department-56"].text.attrs["font-size"] + "px", "Font-size ok for department-56" ); 116 | $text_56.trigger("mouseover"); 117 | setTimeout(function() { 118 | assert.equal($text_56.attr("font-size"), CST_CUSTOMAREA["department-56"].text.attrsHover["font-size"] + "px", "Font-size hover ok for department-56" ); 119 | text_mouseover_async_done(); 120 | 121 | assert.ok($text_74[0], "Text created for department-74" ); 122 | 123 | var counter = 0; 124 | self.$map.find("svg path").each(function(id, elem) { 125 | var $elem = $(elem); 126 | var data_id = $elem.attr("data-id"); 127 | 128 | if (data_id === "department-21") { 129 | assert.equal($elem.attr("fill"), CST_CUSTOMAREA[data_id].attrs.fill, "Check special overriden fill before mouseover for " + data_id); 130 | } else if (data_id === "department-74") { 131 | /* Can't check more than that since href and target values are handled by onClick event... */ 132 | } 133 | 134 | if ((data_id === "department-21") || (data_id === "department-56")) { 135 | setTimeout(function () { 136 | $elem.trigger("mouseover"); 137 | $elem.trigger("mousemove"); 138 | setTimeout(function () { 139 | if (data_id === "department-21") { 140 | assert.equal($elem.attr("fill"), CST_CUSTOMAREA[data_id].attrsHover.fill, "Check special overriden hover fill after mouseover for " + data_id); 141 | } else if (data_id === "department-56") { 142 | assert.ok(self.$map.find(".map .mapTooltip").is(":visible"), "Check tooltip visible for " + data_id); 143 | assert.equal(self.$map.find(".map .mapTooltip").html(), CST_CUSTOMAREA[data_id].tooltip.content, "Check special tooltip content for " + data_id); 144 | } 145 | 146 | $elem.trigger("mouseout"); 147 | setTimeout(function () { 148 | if (data_id === "department-21") { 149 | assert.equal($elem.attr("fill"), CST_CUSTOMAREA[data_id].attrs.fill, "Check special overriden fill after mouseout for " + data_id); 150 | } else if (data_id === "department-56") { 151 | assert.ok(self.$map.find(".map .mapTooltip").is(":hidden"), "Check tooltip hidden after mouseout for " + data_id); 152 | } 153 | 154 | mouseover_async_done(); 155 | }, CST_MOUSEOVER_TIMEOUT_MS); 156 | }, CST_MOUSEOVER_TIMEOUT_MS); 157 | }, counter * (CST_MOUSEOVER_TIMEOUT_MS * 2)); 158 | counter++; 159 | } 160 | }); 161 | }, CST_MOUSEOVER_TIMEOUT_MS); 162 | }); 163 | 164 | }); 165 | -------------------------------------------------------------------------------- /test/test-basic.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Unit Test for Mapael 3 | * Module: Basic 4 | * 5 | * Here are tested: 6 | * - Basic map creation/destruction 7 | * - Basic map interaction 8 | * - options.map.name 9 | */ 10 | $(function() { 11 | 12 | QUnit.module("Basic", CST_MODULE_OPTS); 13 | 14 | QUnit.test("Default instance creation", function(assert) { 15 | var self = this; 16 | 17 | /* Create the basic map! */ 18 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 19 | map: { 20 | name: "france_departments" 21 | } 22 | })); 23 | 24 | /* Some basic checks */ 25 | assert.ok(self.$map.find(".map svg")[0], "SVG map created" ); 26 | assert.ok(self.$map.find(".map svg path")[0], "Path in SVG map" ); 27 | assert.equal(self.$map.find(".map svg path").length, CST_NB_OF_FRANCE_DPTMT, "All France department drawn" ); 28 | assert.equal(self.$map.find(".map svg").attr("width"), CST_MAP_MAX_WIDTH, "Check map width size" ); 29 | assert.equal(self.$map.find(".map svg").attr("height"), CST_MAP_MAX_HEIGHT, "Check map height size" ); 30 | assert.ok(self.$map.hasClass("mapael"), "Has mapael class" ); 31 | assert.ok(typeof self.$map.data("mapael") === "object", "Has mapael data" ); 32 | assert.ok(self.$map.find(".map .mapTooltip")[0], "Has tooltip div" ); 33 | 34 | }); 35 | 36 | QUnit.test("Instance destruction", function(assert) { 37 | var self = this; 38 | 39 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 40 | map: { name: "france_departments" } 41 | })); 42 | 43 | assert.ok(self.$map.find("svg")[0], "Map existing" ); 44 | 45 | self.$map.data("mapael").destroy(); 46 | 47 | assert.notOk(self.$map.find(".map svg")[0], "SVG map not created" ); 48 | assert.notOk(self.$map.hasClass("mapael"), "Has not mapael class" ); 49 | assert.notOk(typeof self.$map.data("mapael") === "object", "Has not mapael data" ); 50 | assert.notOk(self.$map.find(".map .mapTooltip")[0], "Has not tooltip div" ); 51 | }); 52 | 53 | QUnit.test("Instance creation: existing map", function(assert) { 54 | var self = this; 55 | 56 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 57 | map: { name: "france_departments" } 58 | })); 59 | 60 | assert.ok(self.$map.find("svg")[0], "First map existing" ); 61 | 62 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 63 | map: { name: "france_departments" } 64 | })); 65 | 66 | assert.ok(self.$map.find("svg")[0], "Second map existing" ); 67 | }); 68 | 69 | QUnit.test("Creation fail: wrong map", function(assert) { 70 | var self = this; 71 | 72 | /* Error if wrong map name */ 73 | assert.throws(function(){ 74 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 75 | map: { name: "not_existing_map" } 76 | })); 77 | }, "Throw error" ); 78 | 79 | assert.notOk(self.$map.find("svg")[0], "Map not existing" ); 80 | 81 | }); 82 | 83 | QUnit.test("Creation fail: hidden map", function(assert) { 84 | var self = this; 85 | 86 | $(".container").hide(); 87 | 88 | /* Error if map is hidden */ 89 | assert.throws(function(){ 90 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 91 | map: { name: "france_departments" } 92 | })); 93 | }, "Throw error" ); 94 | 95 | assert.notOk(self.$map.find("svg")[0], "Map not existing" ); 96 | 97 | }); 98 | 99 | QUnit.test("Mouseover", function(assert) { 100 | var self = this; 101 | var mouseover_async_done = assert.async(CST_NB_OF_HOVER_CHECK); 102 | 103 | /* Create the map */ 104 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 105 | map: { 106 | name: "france_departments" 107 | } 108 | })); 109 | 110 | /* mouseover event check (background changement) */ 111 | var default_fill = self.$map.find("svg path:first").attr("fill"); 112 | var counter = 0; 113 | self.$map.find("svg path").slice(0, CST_NB_OF_HOVER_CHECK).each(function(id, elem) { 114 | var $elem = $(elem); 115 | setTimeout(function() { 116 | $elem.trigger("mouseover"); 117 | setTimeout(function() { 118 | var new_fill = $elem.attr("fill"); 119 | assert.notEqual(default_fill, new_fill, "Check new background" ); 120 | assert.ok(self.$map.find(".map .mapTooltip").is( ":hidden" ), "Check tooltip hidden" ); 121 | 122 | $elem.trigger("mouseout"); 123 | setTimeout(function() { 124 | var new_fill = $elem.attr("fill"); 125 | assert.equal(new_fill, default_fill, "Check old background" ); 126 | mouseover_async_done(); 127 | }, CST_MOUSEOVER_TIMEOUT_MS); 128 | }, CST_MOUSEOVER_TIMEOUT_MS); 129 | }, counter * (CST_MOUSEOVER_TIMEOUT_MS * 2)); 130 | counter++; 131 | }); 132 | 133 | }); 134 | 135 | QUnit.test("Responsive", function(assert) { 136 | var self = this; 137 | var responsive_async_done = assert.async(); 138 | 139 | /* Create the map */ 140 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 141 | map: { 142 | name: "france_departments" 143 | } 144 | })); 145 | 146 | /* Responsive checks */ 147 | self.$map.width(CST_MAP_MAX_WIDTH/2); 148 | $(window).trigger('resize'); 149 | setTimeout(function() { 150 | var $svg = self.$map.find(".map svg"); 151 | assert.equal($svg.attr("width"), CST_MAP_MAX_WIDTH/2, "Check new map width size" ); 152 | assert.equal($svg.attr("height"), CST_MAP_MAX_HEIGHT/2, "Check new map height size" ); 153 | 154 | self.$map.width(CST_MAP_MAX_WIDTH); 155 | $(window).trigger('resize'); 156 | setTimeout(function() { 157 | var $svg = self.$map.find(".map svg"); 158 | assert.equal($svg.attr("width"), CST_MAP_MAX_WIDTH, "Check old map width size" ); 159 | assert.equal($svg.attr("height"), CST_MAP_MAX_HEIGHT, "Check old map height size" ); 160 | responsive_async_done(); 161 | }, 500); 162 | }, 500); 163 | 164 | }); 165 | 166 | }); 167 | -------------------------------------------------------------------------------- /test/test-options.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Unit Test for Mapael 3 | * Module: Options 4 | * 5 | * Here are tested: 6 | * - options.map.width 7 | * - options.map.beforeInit 8 | * - options.map.afterInit 9 | * - options.map.cssClass 10 | * - options.map.tooltip 11 | */ 12 | $(function() { 13 | 14 | QUnit.module("Options", CST_MODULE_OPTS); 15 | 16 | QUnit.test("Force width", function(assert) { 17 | var self = this; 18 | var responsive_async_done = assert.async(); 19 | 20 | /* Create the map */ 21 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 22 | map: { 23 | name: "france_departments", 24 | width:CST_MAP_MAX_WIDTH/2 25 | } 26 | })); 27 | 28 | var $svg = self.$map.find(".map svg"); 29 | 30 | assert.equal($svg.attr("width"), CST_MAP_MAX_WIDTH/2, "Check map fixed width size" ); 31 | assert.equal($svg.attr("height"), CST_MAP_MAX_HEIGHT/2, "Check map fixed height size" ); 32 | 33 | /* Responsive checks */ 34 | self.$map.width(CST_MAP_MAX_WIDTH/4); 35 | $(window).trigger('resize'); 36 | setTimeout(function() { 37 | var $svg = self.$map.find(".map svg"); 38 | assert.equal($svg.attr("width"), CST_MAP_MAX_WIDTH/2, "Check fixed map width size after resize" ); 39 | assert.equal($svg.attr("height"), CST_MAP_MAX_HEIGHT/2, "Check fixed map height size after resize" ); 40 | 41 | responsive_async_done(); 42 | }, 500); 43 | 44 | }); 45 | 46 | QUnit.test("Different map cssClass", function(assert) { 47 | var self = this; 48 | var new_classname = "DIFFERENT_CLASSNAME"; 49 | 50 | self.$map.find(".map").attr("class", "").addClass(new_classname); 51 | 52 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 53 | map: { 54 | name: "france_departments", 55 | cssClass: new_classname 56 | } 57 | })); 58 | 59 | assert.ok($("." + new_classname + " svg")[0], "Map created" ); 60 | 61 | }); 62 | 63 | QUnit.test("Wrong map cssClass", function(assert) { 64 | var self = this; 65 | assert.throws(function(){ 66 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 67 | map: { 68 | name: "france_departments", 69 | cssClass: "NOT_EXISTING" 70 | } 71 | })); 72 | }, "Throw error" ); 73 | 74 | assert.notOk(self.$map.find("svg")[0], "Container not existing" ); 75 | }); 76 | 77 | QUnit.test("Check callbacks", function(assert) { 78 | var self = this; 79 | var beforeInit_spy = sinon.spy(); 80 | var afterInit_spy = sinon.spy(); 81 | 82 | /* Create the map */ 83 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 84 | map: { 85 | name: "france_departments", 86 | beforeInit:beforeInit_spy, 87 | afterInit:afterInit_spy 88 | } 89 | })); 90 | 91 | assert.ok(beforeInit_spy.calledOnce, "beforeInit call"); 92 | assert.ok(afterInit_spy.calledOnce, "afterInit call"); 93 | 94 | }); 95 | 96 | QUnit.test("Tooltip options", function(assert) { 97 | var self = this; 98 | var tooltip_async_done = assert.async(); 99 | var tooltip_class = "TOOLTIP_CLASSNAME"; 100 | var additional_prop = { 101 | "border-left-width": "5px", 102 | "border-left-style": "solid", 103 | "border-left-color": "rgb(0, 255, 0)" 104 | }; 105 | 106 | $('
').addClass(tooltip_class).appendTo('.container'); 107 | 108 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 109 | map: { 110 | name: "france_departments", 111 | tooltip: { 112 | cssClass: tooltip_class, 113 | css: additional_prop 114 | } 115 | }, 116 | areas:{ 117 | "department-56": { 118 | tooltip: {content: "TOOLTIP_department-56"} 119 | } 120 | } 121 | })); 122 | 123 | assert.ok($("." + tooltip_class)[0], "Tooltip created" ); 124 | assert.ok(self.$map.find(".map > ." + tooltip_class)[0], "Tooltip created in target" ); 125 | 126 | $("path[data-id='department-56']").trigger("mouseover"); 127 | 128 | setTimeout(function() { 129 | $.each(additional_prop, function(propertyName, value){ 130 | assert.equal($("." + tooltip_class).css(propertyName), value, "CSS property " + propertyName + " added"); 131 | }); 132 | tooltip_async_done(); 133 | }, 500); 134 | }); 135 | 136 | }); 137 | -------------------------------------------------------------------------------- /test/test-plots.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Unit Test for Mapael 3 | * Module: Plots 4 | * 5 | * Here are tested: 6 | * - options.map.defaultPlot 7 | * - options.map.plots 8 | */ 9 | $(function() { 10 | 11 | QUnit.module("Plots", CST_MODULE_OPTS); 12 | 13 | QUnit.test("Test adding Image plot", function(assert) { 14 | var self = this; 15 | 16 | var CST_PLOTS = { 17 | // Image plot 18 | 'paris': { 19 | type: "image", 20 | url: "./marker.png", 21 | width: 12, 22 | height: 40, 23 | latitude: 48.86, 24 | longitude: 2.3444, 25 | attrs: { 26 | opacity: 0.5 27 | }, 28 | attrsHover: { 29 | transform: "s1.5" 30 | } 31 | } 32 | }; 33 | 34 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 35 | map: { 36 | name: "france_departments" 37 | }, 38 | plots: CST_PLOTS 39 | })); 40 | 41 | var $plot_paris = self.$map.find(".map svg image[data-id='paris']"); 42 | 43 | /* PARIS PLOT */ 44 | assert.ok($plot_paris[0], "Paris plot: created"); 45 | assert.equal($plot_paris.attr("href"), CST_PLOTS["paris"].url,"Paris plot: URL ok"); 46 | assert.equal($plot_paris.attr("width"), CST_PLOTS["paris"].width,"Paris plot: width ok"); 47 | assert.equal($plot_paris.attr("height"), CST_PLOTS["paris"].height,"Paris plot: height ok"); 48 | assert.equal($plot_paris.attr("opacity"), CST_PLOTS["paris"].attrs.opacity,"Paris plot: opacity ok"); 49 | 50 | }); 51 | 52 | 53 | QUnit.test("Test adding SVG plots", function(assert) { 54 | var self = this; 55 | 56 | var CST_PLOTS = { 57 | // SVG plot 58 | 'limoge': { 59 | type: "svg", 60 | path: "M 24.267286,27.102843 15.08644,22.838269 6.3686216,27.983579 7.5874348,17.934248 0,11.2331 9.9341158,9.2868473 13.962641,0 l 4.920808,8.8464793 10.077199,0.961561 -6.892889,7.4136777 z", 61 | latitude: 45.8188276, 62 | longitude: 1.1060351, 63 | attrs: { 64 | opacity: 0.9 65 | } 66 | } 67 | }; 68 | 69 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 70 | map: { 71 | name: "france_departments" 72 | }, 73 | plots: CST_PLOTS 74 | })); 75 | 76 | var $plot_limoge = self.$map.find(".map svg path[data-id='limoge']"); 77 | 78 | /* LIMOGE PLOT */ 79 | assert.ok($plot_limoge[0], "limoge plot: created"); 80 | // Not working: path seems to be modified ? 81 | // assert.equal($plot_limoge.attr("d"), CST_PLOTS["limoge"].path.replace(/\s/g, ''),"limoge plot: Path ok"); 82 | assert.equal($plot_limoge.attr("opacity"), CST_PLOTS["limoge"].attrs.opacity,"limoge plot: opacity ok"); 83 | 84 | }); 85 | 86 | 87 | QUnit.test("Test adding Cicle plots", function(assert) { 88 | var self = this; 89 | 90 | var CST_PLOTS = { 91 | // Circle plot 92 | 'lyon': { 93 | type: "circle", 94 | size: 50, 95 | latitude: 45.758888888889, 96 | longitude: 4.8413888888889 97 | }, 98 | 'bordeaux': { 99 | type: "circle", 100 | size: 30, 101 | latitude: 44.834763, 102 | longitude: -0.580991 103 | } 104 | }; 105 | 106 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 107 | map: { 108 | name: "france_departments" 109 | }, 110 | plots: CST_PLOTS 111 | })); 112 | 113 | var $plot_lyon = self.$map.find(".map svg circle[data-id='lyon']"); 114 | var $plot_bordeaux = self.$map.find(".map svg circle[data-id='bordeaux']"); 115 | 116 | /* LYON PLOT */ 117 | assert.ok($plot_lyon[0], "lyon plot: created"); 118 | assert.equal($plot_lyon.attr("r"), CST_PLOTS["lyon"].size / 2,"lyon plot: Rayon ok"); 119 | 120 | /* BORDEAUX PLOT */ 121 | assert.ok($plot_bordeaux[0], "bordeaux plot: created"); 122 | assert.equal($plot_bordeaux.attr("r"), CST_PLOTS["bordeaux"].size / 2,"bordeaux plot: Rayon ok"); 123 | 124 | }); 125 | 126 | 127 | QUnit.test("Test adding Square plots", function(assert) { 128 | var self = this; 129 | 130 | var CST_PLOTS = { 131 | // Square plot 132 | 'rennes': { 133 | type: "square", 134 | size: 20, 135 | latitude: 48.114166666667, 136 | longitude: -1.6808333333333 137 | } 138 | }; 139 | 140 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 141 | map: { 142 | name: "france_departments" 143 | }, 144 | plots: CST_PLOTS 145 | })); 146 | 147 | var $plot_rennes = self.$map.find(".map svg rect[data-id='rennes']"); 148 | 149 | /* RENNES PLOT */ 150 | assert.ok($plot_rennes[0], "rennes plot: created"); 151 | assert.equal($plot_rennes.attr("width"), CST_PLOTS["rennes"].size,"rennes plot: width ok"); 152 | assert.equal($plot_rennes.attr("height"), CST_PLOTS["rennes"].size,"rennes plot: height ok"); 153 | 154 | }); 155 | 156 | 157 | QUnit.test("Test adding X,Y plots", function(assert) { 158 | var self = this; 159 | 160 | var CST_PLOTS = { 161 | // Plot positioned by x and y instead of latitude, longitude 162 | 'plotxy': { 163 | x: 300, 164 | y: 200 165 | } 166 | }; 167 | 168 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 169 | map: { 170 | name: "france_departments" 171 | }, 172 | plots: CST_PLOTS 173 | })); 174 | 175 | var $plot_plotxy = self.$map.find(".map svg circle[data-id='plotxy']"); 176 | 177 | /* PLOTXY PLOT */ 178 | assert.ok($plot_plotxy[0], "plotxy plot: created"); 179 | assert.equal($plot_plotxy.attr("cx"), CST_PLOTS["plotxy"].x,"plotxy plot: X ok"); 180 | assert.equal($plot_plotxy.attr("cy"), CST_PLOTS["plotxy"].y,"plotxy plot: Y ok"); 181 | 182 | }); 183 | 184 | 185 | QUnit.test("Test adding plots with text", function(assert) { 186 | var self = this; 187 | 188 | var CST_PLOTS = { 189 | // Circle plot 190 | 'lyon': { 191 | type: "circle", 192 | size: 50, 193 | latitude: 45.758888888889, 194 | longitude: 4.8413888888889, 195 | tooltip: {content: "City : Lyon
Rhône-Alpes"}, 196 | text: {content: "Lyon"} 197 | }, 198 | // Square plot 199 | 'rennes': { 200 | type: "square", 201 | size: 20, 202 | latitude: 48.114166666667, 203 | longitude: -1.6808333333333, 204 | tooltip: {content: "City : Rennes
Bretagne"}, 205 | text: {content: "Rennes"} 206 | }, 207 | // Plot positioned by x and y instead of latitude, longitude 208 | 'plotxy': { 209 | x: 300, 210 | y: 200, 211 | text: { 212 | content: "My plot" 213 | , position: "bottom" 214 | , attrs: {"font-size": 10, fill: "#004a9b", opacity: 0.6} 215 | , attrsHover: {fill: "#004a9b", opacity: 1} 216 | }, 217 | }, 218 | 'bordeaux': { 219 | type: "circle", 220 | size: 30, 221 | latitude: 44.834763, 222 | longitude: -0.580991, 223 | text: { 224 | content: "33", 225 | position: "inner", 226 | attrs: { 227 | "font-size": 16, 228 | "font-weight": "bold", 229 | fill: "#ffffff" 230 | }, 231 | attrsHover: { 232 | "font-size": 16, 233 | "font-weight": "bold", 234 | fill: "#ffffff" 235 | } 236 | } 237 | } 238 | }; 239 | 240 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 241 | map: { 242 | name: "france_departments" 243 | }, 244 | plots: CST_PLOTS 245 | })); 246 | 247 | var $plot_lyon = self.$map.find(".map svg circle[data-id='lyon']"); 248 | var $plot_rennes = self.$map.find(".map svg rect[data-id='rennes']"); 249 | var $plot_plotxy = self.$map.find(".map svg circle[data-id='plotxy']"); 250 | var $plot_bordeaux = self.$map.find(".map svg circle[data-id='bordeaux']"); 251 | 252 | var $plot_txt_lyon = self.$map.find(".map svg text[data-id='lyon']"); 253 | var $plot_txt_rennes = self.$map.find(".map svg text[data-id='rennes']"); 254 | var $plot_txt_plotxy = self.$map.find(".map svg text[data-id='plotxy']"); 255 | var $plot_txt_bordeaux = self.$map.find(".map svg text[data-id='bordeaux']"); 256 | 257 | /* LYON PLOT TEXT */ 258 | assert.ok($plot_txt_lyon[0], "lyon text: created"); 259 | assert.equal($("tspan", $plot_txt_lyon).text(), CST_PLOTS["lyon"].text.content, "lyon text: content ok"); 260 | 261 | /* RENNES PLOT TEXT */ 262 | assert.ok($plot_txt_rennes[0], "rennes text: created"); 263 | assert.equal($("tspan", $plot_txt_rennes).text(), CST_PLOTS["rennes"].text.content, "rennes text: content ok"); 264 | 265 | /* PLOTXY PLOT TEXT */ 266 | assert.ok($plot_txt_plotxy[0], "plotxy text: created"); 267 | assert.equal($("tspan", $plot_txt_plotxy).text(), CST_PLOTS["plotxy"].text.content, "plotxy text: content ok"); 268 | assert.equal($plot_txt_plotxy.attr("font-size"), CST_PLOTS["plotxy"].text.attrs["font-size"] + "px","plotxy text: font-size ok"); 269 | assert.equal($plot_txt_plotxy.attr("fill"), CST_PLOTS["plotxy"].text.attrs["fill"],"plotxy text: fill ok"); 270 | assert.equal($plot_txt_plotxy.attr("opacity"), CST_PLOTS["plotxy"].text.attrs["opacity"],"plotxy text: opacity ok"); 271 | 272 | /* BORDEAUX PLOT TEXT */ 273 | assert.ok($plot_txt_bordeaux[0], "bordeaux text: created"); 274 | assert.equal($("tspan", $plot_txt_bordeaux).text(), CST_PLOTS["bordeaux"].text.content, "bordeaux text: content ok"); 275 | assert.equal($plot_txt_bordeaux.attr("font-size"), CST_PLOTS["bordeaux"].text.attrs["font-size"] + "px","bordeaux text: font-size ok"); 276 | assert.equal($plot_txt_bordeaux.attr("font-weight"), CST_PLOTS["bordeaux"].text.attrs["font-weight"],"bordeaux text: font-weight ok"); 277 | assert.equal($plot_txt_bordeaux.attr("fill"), CST_PLOTS["bordeaux"].text.attrs["fill"],"bordeaux text: fill ok"); 278 | 279 | }); 280 | 281 | }); 282 | -------------------------------------------------------------------------------- /test/test-range.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Unit Test for Mapael 3 | * Module: Range event 4 | * 5 | * Here are tested: 6 | * - showElementsInRange trigger event 7 | */ 8 | $(function() { 9 | 10 | QUnit.module("Range event", CST_MODULE_OPTS); 11 | 12 | QUnit.test("Check callback", function(assert) { 13 | var self = this; 14 | 15 | /* Create the map */ 16 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 17 | map: { 18 | name: "france_departments" 19 | } 20 | })); 21 | 22 | var opt = { 23 | afterShowRange: sinon.spy() 24 | }; 25 | 26 | self.$map.trigger("showElementsInRange", [opt]); 27 | 28 | assert.ok(opt.afterShowRange.calledOnce, "afterShowRange call"); 29 | 30 | }); 31 | 32 | QUnit.test("Range test for plots", function(assert) { 33 | var self = this; 34 | self.$map.mapael($.extend(true, {}, CST_MAPCONF_NOANIMDURATION, { 35 | map: { 36 | name: "france_departments" 37 | }, 38 | plots: { 39 | "p1": { 40 | value: "0", 41 | latitude: 1, 42 | longitude: 1 43 | }, 44 | "p2": { 45 | value: "10", 46 | latitude: 2, 47 | longitude: 2 48 | }, 49 | "p3": { 50 | value: ["50", "10"], 51 | latitude: 3, 52 | longitude: 3 53 | }, 54 | "p4": { 55 | value: "5000", 56 | latitude: 4, 57 | longitude: 4 58 | }, 59 | "p5": { 60 | value: "-50", 61 | latitude: 5, 62 | longitude: 5 63 | } 64 | } 65 | })); 66 | 67 | var opt = { 68 | animDuration: 0, 69 | hiddenOpacity: 0.1, 70 | ranges: { 71 | plot: {} 72 | } 73 | }; 74 | 75 | var $p1 = self.$map.find(".map svg [data-id='p1']"); 76 | var $p2 = self.$map.find(".map svg [data-id='p2']"); 77 | var $p3 = self.$map.find(".map svg [data-id='p3']"); 78 | var $p4 = self.$map.find(".map svg [data-id='p4']"); 79 | var $p5 = self.$map.find(".map svg [data-id='p5']"); 80 | 81 | // No range 82 | opt.ranges.plot = {}; 83 | self.$map.trigger("showElementsInRange", [opt]); 84 | assert.ok($p1.attr("opacity") === undefined && $p1.css('display') !== 'none', "No range, p1 visible"); 85 | assert.ok($p2.attr("opacity") === undefined && $p2.css('display') !== 'none', "No range, p2 visible"); 86 | assert.ok($p3.attr("opacity") === undefined && $p3.css('display') !== 'none', "No range, p3 visible"); 87 | assert.ok($p4.attr("opacity") === undefined && $p4.css('display') !== 'none', "No range, p4 visible"); 88 | assert.ok($p5.attr("opacity") === undefined && $p5.css('display') !== 'none', "No range, p5 visible"); 89 | 90 | // Check for min = 10000 91 | opt.ranges.plot = {min: 10000}; 92 | self.$map.trigger("showElementsInRange", [opt]); 93 | assert.ok(parseFloat($p1.attr("opacity")) === 0.1 && $p1.css('display') !== 'none', "Min = 1000, p1 opacity"); 94 | assert.ok(parseFloat($p2.attr("opacity")) === 0.1 && $p2.css('display') !== 'none', "Min = 1000, p2 opacity"); 95 | assert.ok(parseFloat($p3.attr("opacity")) === 0.1 && $p3.css('display') !== 'none', "Min = 1000, p3 opacity"); 96 | assert.ok(parseFloat($p4.attr("opacity")) === 0.1 && $p4.css('display') !== 'none', "Min = 1000, p4 opacity"); 97 | assert.ok(parseFloat($p5.attr("opacity")) === 0.1 && $p5.css('display') !== 'none', "Min = 1000, p5 opacity"); 98 | 99 | // Check for min = 0 100 | opt.ranges.plot = {min: 0}; 101 | self.$map.trigger("showElementsInRange", [opt]); 102 | assert.ok(parseFloat($p1.attr("opacity")) === 1 && $p1.css('display') !== 'none', "Min = 0, p1 opacity"); 103 | assert.ok(parseFloat($p2.attr("opacity")) === 1 && $p2.css('display') !== 'none', "Min = 0, p2 opacity"); 104 | assert.ok(parseFloat($p3.attr("opacity")) === 1 && $p3.css('display') !== 'none', "Min = 0, p3 opacity"); 105 | assert.ok(parseFloat($p4.attr("opacity")) === 1 && $p4.css('display') !== 'none', "Min = 0, p4 opacity"); 106 | assert.ok(parseFloat($p5.attr("opacity")) === 0.1 && $p5.css('display') !== 'none', "Min = 0, p5 opacity"); 107 | 108 | // Check for min = 50 109 | opt.ranges.plot = {min: 50}; 110 | self.$map.trigger("showElementsInRange", [opt]); 111 | assert.ok(parseFloat($p1.attr("opacity")) === 0.1 && $p1.css('display') !== 'none', "Min = 50, p1 opacity"); 112 | assert.ok(parseFloat($p2.attr("opacity")) === 0.1 && $p2.css('display') !== 'none', "Min = 50, p2 opacity"); 113 | assert.ok(parseFloat($p3.attr("opacity")) === 1 && $p3.css('display') !== 'none', "Min = 50, p3 opacity"); 114 | assert.ok(parseFloat($p4.attr("opacity")) === 1 && $p4.css('display') !== 'none', "Min = 50, p4 opacity"); 115 | assert.ok(parseFloat($p5.attr("opacity")) === 0.1 && $p5.css('display') !== 'none', "Min = 50, p5 opacity"); 116 | 117 | // Check for min = 5000 118 | opt.ranges.plot = {max: 5000}; 119 | self.$map.trigger("showElementsInRange", [opt]); 120 | assert.ok(parseFloat($p1.attr("opacity")) === 1 && $p1.css('display') !== 'none', "Max = 5000, p1 opacity"); 121 | assert.ok(parseFloat($p2.attr("opacity")) === 1 && $p2.css('display') !== 'none', "Max = 5000, p2 opacity"); 122 | assert.ok(parseFloat($p3.attr("opacity")) === 1 && $p3.css('display') !== 'none', "Max = 5000, p3 opacity"); 123 | assert.ok(parseFloat($p4.attr("opacity")) === 1 && $p4.css('display') !== 'none', "Max = 5000, p4 opacity"); 124 | assert.ok(parseFloat($p5.attr("opacity")) === 1 && $p5.css('display') !== 'none', "Max = 5000, p5 opacity"); 125 | 126 | // Check for max = 500000 127 | opt.ranges.plot = {max: 500000}; 128 | self.$map.trigger("showElementsInRange", [opt]); 129 | assert.ok(parseFloat($p1.attr("opacity")) === 1 && $p1.css('display') !== 'none', "Max = 500000, p1 opacity"); 130 | assert.ok(parseFloat($p2.attr("opacity")) === 1 && $p2.css('display') !== 'none', "Max = 500000, p2 opacity"); 131 | assert.ok(parseFloat($p3.attr("opacity")) === 1 && $p3.css('display') !== 'none', "Max = 500000, p3 opacity"); 132 | assert.ok(parseFloat($p4.attr("opacity")) === 1 && $p4.css('display') !== 'none', "Max = 500000, p4 opacity"); 133 | assert.ok(parseFloat($p5.attr("opacity")) === 1 && $p5.css('display') !== 'none', "Max = 500000, p5 opacity"); 134 | 135 | // Check for max = -49 136 | opt.ranges.plot = {max: -49}; 137 | self.$map.trigger("showElementsInRange", [opt]); 138 | assert.ok(parseFloat($p1.attr("opacity")) === 0.1 && $p1.css('display') !== 'none', "Max = -49, p1 opacity"); 139 | assert.ok(parseFloat($p2.attr("opacity")) === 0.1 && $p2.css('display') !== 'none', "Max = -49, p2 opacity"); 140 | assert.ok(parseFloat($p3.attr("opacity")) === 0.1 && $p3.css('display') !== 'none', "Max = -49, p3 opacity"); 141 | assert.ok(parseFloat($p4.attr("opacity")) === 0.1 && $p4.css('display') !== 'none', "Max = -49, p4 opacity"); 142 | assert.ok(parseFloat($p5.attr("opacity")) === 1 && $p5.css('display') !== 'none', "Max = -49, p5 opacity"); 143 | 144 | // Check for min: 25, max: 65 145 | opt.ranges.plot = {min: 25, max: 65}; 146 | self.$map.trigger("showElementsInRange", [opt]); 147 | assert.ok(parseFloat($p1.attr("opacity")) === 0.1 && $p1.css('display') !== 'none', "Range(25, 65), p1 opacity"); 148 | assert.ok(parseFloat($p2.attr("opacity")) === 0.1 && $p2.css('display') !== 'none', "Range(25, 65), p2 opacity"); 149 | assert.ok(parseFloat($p3.attr("opacity")) === 1 && $p3.css('display') !== 'none', "Range(25, 65), p3 opacity"); 150 | assert.ok(parseFloat($p4.attr("opacity")) === 0.1 && $p4.css('display') !== 'none', "Range(25, 65), p4 opacity"); 151 | assert.ok(parseFloat($p5.attr("opacity")) === 0.1 && $p5.css('display') !== 'none', "Range(25, 65), p5 opacity"); 152 | 153 | // Check for range with unknown index (no modification of current opacity) 154 | opt.ranges.plot = {4:{min: 25, max: 65}}; 155 | self.$map.trigger("showElementsInRange", [opt]); 156 | assert.ok(parseFloat($p1.attr("opacity")) === 0.1 && $p1.css('display') !== 'none', "Unknown index, p1 opacity"); 157 | assert.ok(parseFloat($p2.attr("opacity")) === 0.1 && $p2.css('display') !== 'none', "Unknown index, p2 opacity"); 158 | assert.ok(parseFloat($p3.attr("opacity")) === 1 && $p3.css('display') !== 'none', "Unknown index, p3 opacity"); 159 | assert.ok(parseFloat($p4.attr("opacity")) === 0.1 && $p4.css('display') !== 'none', "Unknown index, p4 opacity"); 160 | assert.ok(parseFloat($p5.attr("opacity")) === 0.1 && $p5.css('display') !== 'none', "Unknown index, p5 opacity"); 161 | 162 | // Check for range with known different index (p3 is the only one with two indexes) 163 | opt.ranges.plot = { 164 | 0:{min: -200}, // shows all except p3 165 | 1:{min: 11} // hide p3 166 | }; 167 | self.$map.trigger("showElementsInRange", [opt]); 168 | assert.ok(parseFloat($p1.attr("opacity")) === 1 && $p1.css('display') !== 'none', "2 differents indexes, p1 opacity"); 169 | assert.ok(parseFloat($p2.attr("opacity")) === 1 && $p2.css('display') !== 'none', "2 differents indexes, p2 opacity"); 170 | assert.ok(parseFloat($p3.attr("opacity")) === 0.1 && $p3.css('display') !== 'none', "2 differents indexes, p3 opacity"); 171 | assert.ok(parseFloat($p4.attr("opacity")) === 1 && $p4.css('display') !== 'none', "2 differents indexes, p4 opacity"); 172 | assert.ok(parseFloat($p5.attr("opacity")) === 1 && $p5.css('display') !== 'none', "2 differents indexes, p5 opacity"); 173 | 174 | // Check for range with 2nd index set 175 | opt.ranges.plot = { 176 | 1:{min: 0} 177 | }; 178 | self.$map.trigger("showElementsInRange", [opt]); 179 | assert.ok(parseFloat($p1.attr("opacity")) === 1 && $p1.css('display') !== 'none', "2nd index set, p1 opacity"); 180 | assert.ok(parseFloat($p2.attr("opacity")) === 1 && $p2.css('display') !== 'none', "2nd index set, p2 opacity"); 181 | assert.ok(parseFloat($p3.attr("opacity")) === 1 && $p3.css('display') !== 'none', "2nd index set, p3 opacity"); 182 | assert.ok(parseFloat($p4.attr("opacity")) === 1 && $p4.css('display') !== 'none', "2nd index set, p4 opacity"); 183 | assert.ok(parseFloat($p5.attr("opacity")) === 1 && $p5.css('display') !== 'none', "2nd index set, p5 opacity"); 184 | 185 | // Check for no range, but range for area (no modification of current opacity) 186 | opt.ranges.plot = {}; 187 | opt.ranges.area = {min:-1000}; 188 | opt.ranges.link = {max:2000}; 189 | self.$map.trigger("showElementsInRange", [opt]); 190 | assert.ok(parseFloat($p1.attr("opacity")) === 1 && $p1.css('display') !== 'none', "No range + area, p1 opacity"); 191 | assert.ok(parseFloat($p2.attr("opacity")) === 1 && $p2.css('display') !== 'none', "No range + area, p2 opacity"); 192 | assert.ok(parseFloat($p3.attr("opacity")) === 1 && $p3.css('display') !== 'none', "No range + area, p3 opacity"); 193 | assert.ok(parseFloat($p4.attr("opacity")) === 1 && $p4.css('display') !== 'none', "No range + area, p4 opacity"); 194 | assert.ok(parseFloat($p5.attr("opacity")) === 1 && $p5.css('display') !== 'none', "No range + area, p5 opacity"); 195 | 196 | // Check for min = 20000 with hiddenOpacity set to 0 197 | opt.ranges.plot = {min: 20000}; 198 | opt.hiddenOpacity = 0; 199 | self.$map.trigger("showElementsInRange", [opt]); 200 | assert.ok(parseFloat($p1.attr("opacity")) === 0 && $p1.css('display') === 'none', "Min = 20000, hiddenOpacity 0, p1 opacity"); 201 | assert.ok(parseFloat($p2.attr("opacity")) === 0 && $p2.css('display') === 'none', "Min = 20000, hiddenOpacity 0, p2 opacity"); 202 | assert.ok(parseFloat($p3.attr("opacity")) === 0 && $p3.css('display') === 'none', "Min = 20000, hiddenOpacity 0, p3 opacity"); 203 | assert.ok(parseFloat($p4.attr("opacity")) === 0 && $p4.css('display') === 'none', "Min = 20000, hiddenOpacity 0, p4 opacity"); 204 | assert.ok(parseFloat($p5.attr("opacity")) === 0 && $p5.css('display') === 'none', "Min = 20000, hiddenOpacity 0, p5 opacity"); 205 | 206 | // Check for min = -1000 with hiddenOpacity set to 0 207 | opt.ranges.plot = {min: -1000}; 208 | self.$map.trigger("showElementsInRange", [opt]); 209 | assert.ok(parseFloat($p1.attr("opacity")) === 1 && $p1.css('display') !== 'none', "Min = -1000, hiddenOpacity 0, p1 opacity"); 210 | assert.ok(parseFloat($p2.attr("opacity")) === 1 && $p2.css('display') !== 'none', "Min = -1000, hiddenOpacity 0, p2 opacity"); 211 | assert.ok(parseFloat($p3.attr("opacity")) === 1 && $p3.css('display') !== 'none', "Min = -1000, hiddenOpacity 0, p3 opacity"); 212 | assert.ok(parseFloat($p4.attr("opacity")) === 1 && $p4.css('display') !== 'none', "Min = -1000, hiddenOpacity 0, p4 opacity"); 213 | assert.ok(parseFloat($p5.attr("opacity")) === 1 && $p5.css('display') !== 'none', "Min = -1000, hiddenOpacity 0, p5 opacity"); 214 | 215 | }); 216 | 217 | }); 218 | --------------------------------------------------------------------------------