diff --git a/.gitignore b/.gitignore index b54acc08af4..098c43737c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules .aws-config.json -dist \ No newline at end of file +dist +web.config \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index a4a1bfe2b4a..00000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,19 +0,0 @@ -If you have a bugfix or new feature that you would like to contribute to Kibana, please **find or open an issue about it before you start working on it.** Talk about what you would like to do. It may be that somebody is already working on it, or that there are particular issues that you should know about before implementing the change. - -We enjoy working with contributors to get their code accepted. There are many approaches to fixing a problem and it is important to find the best approach before writing too much code. - -The process for contributing to any of the Elasticsearch repositories is similar. - -1. Sign the contributor license agreement -Please make sure you have signed the [Contributor License Agreement](http://www.elasticsearch.org/contributor-agreement/). We are not asking you to assign copyright to us, but to give us the right to distribute your code without restriction. We ask this of all contributors in order to assure our users of the origin and continuing existence of the code. You only need to sign the CLA once. - -2. Run the grunt build process and ensure it completes without errors with your changes. - -3. Rebase your changes -Update your local repository with the most recent code from the main Kibana repository, and rebase your branch on top of the latest master branch. We prefer your changes to be squashed into a single commit. - -4. Submit a pull request -Push your local changes to your forked copy of the repository and submit a pull request. In the pull request, describe what your changes do and mention the number of the issue where discussion has taken place, eg “Closes #123″. - -Then sit back and wait. There will probably be discussion about the pull request and, if any changes are needed, we would love to work with you to get your pull request merged into Kibana. - diff --git a/README.md b/README.md index 88716ef416b..acb42db4a3f 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,4 @@ -# Kibana +# Grafana -__NOTE__: You have reached the Kibana 3 repository. -Kibana 3 is a completely new version of Kibana written entirely in HTML and Javascript. You can find -the Kibana 2 repository at [https://github.com/rashidkpc/Kibana](https://github.com/rashidkpc/Kibana) +Experimenting with a a custom graph dashboard based on [kibana](https://github.com/elasticsearch/kibana). -More information about Kibana 3 can be found at [http://www.elasticsearch.org/overview/kibana/](http://www.elasticsearch.org/overview/kibana/) - -## Overview - -Kibana is an open source (Apache Licensed), browser based analytics and search interface to Logstash -and other timestamped data sets stored in ElasticSearch. With those in place Kibana is a snap to -setup and start using (seriously). Kibana strives to be easy to get started with, while also being -flexible and powerful - -### Requirements -* A modern web browser. The latest version of Chrome, Safari and Firefox have all been tested to -work. IE9 and greater should work. IE8 does not. -* A webserver. No extensions are required, as long as it can serve plain html it will work -* A browser reachable Elasticsearch server. Port 9200 must be open, or a proxy configured to allow -access to it. - -### Installation - -1. Download and extract [http://download.elasticsearch.org/kibana/kibana/kibana-latest.zip](http://download.elasticsearch.org/kibana/kibana/kibana-latest.zip) to your webserver. -2. Edit config.js in your deployed directory to point to your elasticsearch server. This should __not be -http://localhost:9200__, but rather the fully qualified domain name of your elasticsearch server. -The url entered here _must be reachable_ by your browser. -3. Point your browser at your installation. If you're using Logstash with the default indexing -configuration the included Kibana logstash interface should work nicely. - -### FAQ -__Q__: Why doesnt it work? I have http://localhost:9200 in my config.js, my webserver and elasticsearch -server are on the same machine -__A__: Kibana 3 does not work like previous versions of Kibana. To ease deployment, the server side -component has been eliminated. Thus __the browser connects directly to Elasticsearch__. The default -config.js setup works for the webserver+Elasticsearch on the same machine scenario. Do not set it -to http://localhost:9200 unless your browser and elasticsearch are on the same machine - -__Q__: How do I secure this? I don't want to leave 9200 open. -__A__: A simple nginx virtual host and proxy configuration can be found in the sample/nginx.conf - -### Support - -If you have questions or comments the best place to reach me is #logstash or #elasticsearch on irc.freenode.net - -### Contributing - -Please see [CONTRIBUTING.md](https://github.com/elasticsearch/kibana/blob/master/CONTRIBUTING.md). -If you have a bugfix or new feature that you would like to contribute to Kibana, **please find or open an issue -about it first.** diff --git a/docs/kibana/configuration/config.js.asciidoc b/docs/kibana/configuration/config.js.asciidoc deleted file mode 100644 index 2147c29a42c..00000000000 --- a/docs/kibana/configuration/config.js.asciidoc +++ /dev/null @@ -1,29 +0,0 @@ -== Configuration == -config.js is where you will find the core Kibana configuration. This file contains parameter that -must be set before kibana is run for the first time. -// src/config.js:1 - -=== Parameters === -// src/config.js:10 - -==== elasticsearch ==== - -The URL to your elasticsearch server. You almost certainly don't -want +http://localhost:9200+ here. Even if Kibana and Elasticsearch are on -the same host. By default this will attempt to reach ES at the same host you have -elasticsearch installed on. You probably want to set it to the FQDN of your -elasticsearch host -// src/config.js:15 - -==== kibana-int ==== - -The default ES index to use for storing Kibana specific object -such as stored dashboards -// src/config.js:26 - -==== panel_name ==== - -An array of panel modules available. Panels will only be loaded when they are defined in the -dashboard, but this list is used in the "add panel" interface. -// src/config.js:34 - diff --git a/docs/kibana/index.asciidoc b/docs/kibana/index.asciidoc deleted file mode 100644 index 4e98149e15d..00000000000 --- a/docs/kibana/index.asciidoc +++ /dev/null @@ -1,18 +0,0 @@ -= Kibana - -// Why can't I have a preamble here? - -== Introduction - -Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for -ElasticSearch. Kibana is a snap to setup and start using. Written entirely in HTML and Javascript -it requires only a plain webserver, Kibana requires no fancy server side components. -Kibana strives to be easy to get started with, while also being flexible and powerful, just like -Elasticsearch. - -include::configuration/config.js.asciidoc[] - -include::panels.asciidoc[] - -// src/app/controllers/dash.js:1 - diff --git a/docs/kibana/panels.asciidoc b/docs/kibana/panels.asciidoc deleted file mode 100644 index a8c4c9bb3dc..00000000000 --- a/docs/kibana/panels.asciidoc +++ /dev/null @@ -1,64 +0,0 @@ -[[panels]] -= Panels - -[partintro] --- -*Kibana* dashboards are made up of blocks called +panels+. Panels are organized into rows -and can serve many purposes, though most are designed to provide the results of a query or -multiple queries as a visualization. Other panels may show collections of documents or -allow you to insert instructions for your users. - -Panels can be configured easily via the Kibana web interface. For more advanced usage, such -as templated or scripted dashboards, documentation of panel properties is available in this -section. You may find settings here which are not exposed via the web interface. - -Each panel type has its own properties, hover there are several that are shared. - -// src/app/controllers/row.js:61 - -span:: A number, 1-12, that describes the width of the panel. -// src/app/controllers/row.js:87 - -editable:: Enable or disable the edit button the the panel -// src/app/controllers/row.js:91 - -type:: The type of panel this object contains. Each panel type will require additional -properties. See the panel types list to the right. -// src/app/controllers/row.js:95 - --- -// src/app/controllers/row.js:103 - -include::panels/bettermap.asciidoc[] -// src/app/panels/bettermap/module.js:1 - -include::panels/column.asciidoc[] -// src/app/panels/column/module.js:1 - -include::panels/histogram.asciidoc[] -// src/app/panels/histogram/module.js:1 - -include::panels/hits.asciidoc[] -// src/app/panels/hits/module.js:1 - -include::panels/map.asciidoc[] -// src/app/panels/map/module.js:1 - -include::panels/pie.asciidoc[] -// src/app/panels/pie/module.js:1 - -include::panels/sparklines.asciidoc[] -// src/app/panels/sparklines/module.js:1 - -include::panels/table.asciidoc[] -// src/app/panels/table/module.js:1 - -include::panels/terms.asciidoc[] -// src/app/panels/terms/module.js:1 - -include::panels/text.asciidoc[] -// src/app/panels/text/module.js:1 - -include::panels/trends.asciidoc[] -// src/app/panels/trends/module.js:1 - diff --git a/docs/kibana/panels/bettermap.asciidoc b/docs/kibana/panels/bettermap.asciidoc deleted file mode 100644 index 8d13f7c0cfc..00000000000 --- a/docs/kibana/panels/bettermap.asciidoc +++ /dev/null @@ -1,36 +0,0 @@ -== Bettermap -Status: *Experimental* - -Bettermap is called bettermap for lack of a better name. Bettermap uses geographic coordinates to -create clusters of markers on map and shade them orange, yellow and green depending on the -density of the cluster. - -To drill down, click on a cluster. The map will be zoomed and the cluster broken into smaller cluster. -When it no longer makes visual sense to cluster, individual markers will be displayed. Hover over -a marker to see the tooltip value/ - -IMPORTANT: bettermap requires an internet connection to download its map panels. -// src/app/panels/bettermap/module.js:5 - -=== Parameters - -field:: The field that contains the coordinates, in geojson format. GeoJSON is -+[longitude,latitude]+ in an array. This is different from most implementations, which use -latitude, longitude. -// src/app/panels/bettermap/module.js:62 - -size:: The number of documents to use when drawing the map -// src/app/panels/bettermap/module.js:70 - -spyable:: Should the `inspect` icon be shown? -// src/app/panels/bettermap/module.js:74 - -tooltip:: Which field to use for the tooltip when hovering over a marker -// src/app/panels/bettermap/module.js:78 - -==== Queries -queries object:: This object describes the queries to use on this panel. -queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ -queries.ids::: In +selected+ mode, which query ids are selected. -// src/app/panels/bettermap/module.js:82 - diff --git a/docs/kibana/panels/column.asciidoc b/docs/kibana/panels/column.asciidoc deleted file mode 100644 index 643d50c4aad..00000000000 --- a/docs/kibana/panels/column.asciidoc +++ /dev/null @@ -1,14 +0,0 @@ -== Column -Status: *Stable* - -A pseudo panel that lets you add other panels to be arranged in a column with defined heights. -While the column panel is stable, it does have many limitations, including the inability to drag -and drop panels within its borders. It may be removed in a future release. - -// src/app/panels/column/module.js:5 - -=== Parameters - -panel:: An array of panel objects -// src/app/panels/column/module.js:36 - diff --git a/docs/kibana/panels/histogram.asciidoc b/docs/kibana/panels/histogram.asciidoc deleted file mode 100644 index d2d7d1951fb..00000000000 --- a/docs/kibana/panels/histogram.asciidoc +++ /dev/null @@ -1,129 +0,0 @@ -== Histogram -Status: *Stable* - -The histogram panel allow for the display of time charts. It includes several modes and tranformations -to display event counts, mean, min, max and total of numeric fields, and derivatives of counter -fields. - -// src/app/panels/histogram/module.js:5 - -=== Parameters -==== Axis options -mode:: Value to use for the y-axis. For all modes other than count, +value_field+ must be -defined. Possible values: count, mean, max, min, total. -// src/app/panels/histogram/module.js:65 - -time_field:: x-axis field. This must be defined as a date type in Elasticsearch. -// src/app/panels/histogram/module.js:72 - -value_field:: y-axis field if +mode+ is set to mean, max, min or total. Must be numeric. -// src/app/panels/histogram/module.js:76 - -x-axis:: Show the x-axis -// src/app/panels/histogram/module.js:80 - -y-axis:: Show the y-axis -// src/app/panels/histogram/module.js:84 - -scale:: Scale the y-axis by this factor -// src/app/panels/histogram/module.js:88 - -y_format:: 'none','bytes','short ' -// src/app/panels/histogram/module.js:92 - -==== Annotations -annotate object:: A query can be specified, the results of which will be displayed as markers on -the chart. For example, for noting code deploys. -annotate.enable::: Should annotations, aka markers, be shown? -annotate.query::: Lucene query_string syntax query to use for markers. -annotate.size::: Max number of markers to show -annotate.field::: Field from documents to show -annotate.sort::: Sort array in format [field,order], For example [`@timestamp',`desc'] -// src/app/panels/histogram/module.js:115 - -==== Interval options -auto_int:: Automatically scale intervals? -// src/app/panels/histogram/module.js:132 - -resolution:: If auto_int is true, shoot for this many bars. -// src/app/panels/histogram/module.js:137 - -interval:: If auto_int is set to false, use this as the interval. -// src/app/panels/histogram/module.js:141 - -interval:: Array of possible intervals in the *View* selector. Example [`auto',`1s',`5m',`3h'] -// src/app/panels/histogram/module.js:145 - -==== Drawing options -lines:: Show line chart -// src/app/panels/histogram/module.js:149 - -fill:: Area fill factor for line charts, 1-10 -// src/app/panels/histogram/module.js:154 - -linewidth:: Weight of lines in pixels -// src/app/panels/histogram/module.js:158 - -points:: Show points on chart -// src/app/panels/histogram/module.js:162 - -pointradius:: Size of points in pixels -// src/app/panels/histogram/module.js:166 - -bars:: Show bars on chart -// src/app/panels/histogram/module.js:170 - -stack:: Stack multiple series -// src/app/panels/histogram/module.js:174 - -spyable:: Show inspect icon -// src/app/panels/histogram/module.js:178 - -zoomlinks:: Show `Zoom Out' link -// src/app/panels/histogram/module.js:182 - -options:: Show quick view options section -// src/app/panels/histogram/module.js:186 - -legend:: Display the legond -// src/app/panels/histogram/module.js:190 - -show_query:: If no alias is set, should the query be displayed? -// src/app/panels/histogram/module.js:194 - -interactive:: Enable click-and-drag to zoom functionality -// src/app/panels/histogram/module.js:198 - -legend_counts:: Show counts in legend -// src/app/panels/histogram/module.js:202 - -==== Transformations -timezone:: Correct for browser timezone?. Valid values: browser, utc -// src/app/panels/histogram/module.js:206 - -percentage:: Show the y-axis as a percentage of the axis total. Only makes sense for multiple -queries -// src/app/panels/histogram/module.js:211 - -zerofill:: Improves the accuracy of line charts at a small performance cost. -// src/app/panels/histogram/module.js:216 - -derivative:: Show each point on the x-axis as the change from the previous point -// src/app/panels/histogram/module.js:220 - -tooltip object:: -tooltip.value_type::: Individual or cumulative controls how tooltips are display on stacked charts -tooltip.query_as_alias::: If no alias is set, should the query be displayed? -// src/app/panels/histogram/module.js:224 - -grid object:: Min and max y-axis values -grid.min::: Minimum y-axis value -grid.max::: Maximum y-axis value -// src/app/panels/histogram/module.js:96 - -==== Queries -queries object:: This object describes the queries to use on this panel. -queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ -queries.ids::: In +selected+ mode, which query ids are selected. -// src/app/panels/histogram/module.js:105 - diff --git a/docs/kibana/panels/hits.asciidoc b/docs/kibana/panels/hits.asciidoc deleted file mode 100644 index 0a25543e465..00000000000 --- a/docs/kibana/panels/hits.asciidoc +++ /dev/null @@ -1,37 +0,0 @@ -== Hits -Status: *Stable* - -The hits panel displays the number of hits for each of the queries on the dashboard in a -configurable format specified by the `chart' property. - -// src/app/panels/hits/module.js:5 - -=== Parameters - -arrangement:: The arrangement of the legend. horizontal or vertical -// src/app/panels/hits/module.js:49 - -chart:: bar, pie or none -// src/app/panels/hits/module.js:55 - -counter_pos:: The position of the legend, above or below -// src/app/panels/hits/module.js:59 - -donut:: If the chart is set to pie, setting donut to true will draw a hole in the midle of it -// src/app/panels/hits/module.js:63 - -tilt:: If the chart is set to pie, setting tilt to true will tilt it back into an oval -// src/app/panels/hits/module.js:67 - -labels:: If the chart is set to pie, setting labels to true will draw labels in the slices -// src/app/panels/hits/module.js:71 - -spyable:: Setting spyable to false disables the inspect icon. -// src/app/panels/hits/module.js:75 - -==== Queries -queries object:: This object describes the queries to use on this panel. -queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ -queries.ids::: In +selected+ mode, which query ids are selected. -// src/app/panels/hits/module.js:79 - diff --git a/docs/kibana/panels/map.asciidoc b/docs/kibana/panels/map.asciidoc deleted file mode 100644 index 5fd7faeb578..00000000000 --- a/docs/kibana/panels/map.asciidoc +++ /dev/null @@ -1,32 +0,0 @@ -== Map -Status: *Stable* - -The map panel translates 2 letter country or state codes into shaded regions on a map. Currently -available maps are world, usa and europe. - -// src/app/panels/map/module.js:5 - -=== Parameters - -map:: Map to display. world, usa, europe -// src/app/panels/map/module.js:48 - -colors:: An array of colors to use to shade the map. If 2 colors are specified, shades -between them will be used. For example [`#A0E2E2', `#265656'] -// src/app/panels/map/module.js:54 - -size:: Max number of regions to shade -// src/app/panels/map/module.js:59 - -exclude:: exclude this array of regions. For example [`US',`BR',`IN'] -// src/app/panels/map/module.js:63 - -spyable:: Setting spyable to false disables the inspect icon. -// src/app/panels/map/module.js:67 - -==== Queries -queries object:: This object describes the queries to use on this panel. -queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ -queries.ids::: In +selected+ mode, which query ids are selected. -// src/app/panels/map/module.js:71 - diff --git a/docs/kibana/panels/pie.asciidoc b/docs/kibana/panels/pie.asciidoc deleted file mode 100644 index b1ec93e511f..00000000000 --- a/docs/kibana/panels/pie.asciidoc +++ /dev/null @@ -1,50 +0,0 @@ -== Pie -Status: *Deprecated* - -The pie panel has been largely replaced by the +terms+ panel. It exists for backwards compatibility -for now, but will be removed in a future release - -// src/app/panels/pie/module.js:5 - -=== Parameters - -mode:: terms or goal. Terms mode finds the top N most popular terms, Goal mode display -progress towards a fix goal in terms of documents matched -// src/app/panels/pie/module.js:48 - -size:: The max number of results to display in +terms+ mode. -// src/app/panels/pie/module.js:55 - -exclude:: Exclude these terms in terms mode -// src/app/panels/pie/module.js:59 - -donut:: Draw a hole in the middle of the pie, creating a tasty donut. -// src/app/panels/pie/module.js:63 - -tilt:: Tilt the pie back into an oval shape -// src/app/panels/pie/module.js:67 - -legend:: The location of the legend, above, below or none -// src/app/panels/pie/module.js:71 - -labels:: Set to false to disable drawing labels inside the pie slices -// src/app/panels/pie/module.js:75 - -spyable:: Set to false to disable the inspect function. -// src/app/panels/pie/module.js:79 - -==== Query - -query object:: This confusingly named object has properties to set the terms mode field, -and the fixed goal for the goal mode -query.field::: the field to facet on in terms mode -query.goal::: the fixed goal for goal mode -// src/app/panels/pie/module.js:83 - -==== Queries - -queries object:: This object describes the queries to use on this panel. -queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ -queries.ids::: In +selected+ mode, which query ids are selected. -// src/app/panels/pie/module.js:92 - diff --git a/docs/kibana/panels/sparklines.asciidoc b/docs/kibana/panels/sparklines.asciidoc deleted file mode 100644 index a26f0bb7abb..00000000000 --- a/docs/kibana/panels/sparklines.asciidoc +++ /dev/null @@ -1,32 +0,0 @@ -== Sparklines -Status: *Experimental* - -The sparklines panel shows tiny time charts. The purpose of these is not to give an exact value, -but rather to show the shape of the time series in a compact manner - -// src/app/panels/sparklines/module.js:5 - -=== Parameters -mode:: Value to use for the y-axis. For all modes other than count, +value_field+ must be -defined. Possible values: count, mean, max, min, total. -// src/app/panels/sparklines/module.js:56 - -time_field:: x-axis field. This must be defined as a date type in Elasticsearch. -// src/app/panels/sparklines/module.js:62 - -value_field:: y-axis field if +mode+ is set to mean, max, min or total. Must be numeric. -// src/app/panels/sparklines/module.js:66 - -interval:: Sparkline intervals are computed automatically as long as there is a time filter -present. In the absence of a time filter, use this interval. -// src/app/panels/sparklines/module.js:70 - -spyable:: Show inspect icon -// src/app/panels/sparklines/module.js:75 - -==== Queries -queries object:: This object describes the queries to use on this panel. -queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ -queries.ids::: In +selected+ mode, which query ids are selected. -// src/app/panels/sparklines/module.js:79 - diff --git a/docs/kibana/panels/table.asciidoc b/docs/kibana/panels/table.asciidoc deleted file mode 100644 index 85a8c1a360d..00000000000 --- a/docs/kibana/panels/table.asciidoc +++ /dev/null @@ -1,69 +0,0 @@ -== table -Status: *Stable* - -The table panel contains a sortable, pagable view of documents that. It can be arranged into -defined columns and offers several interactions, such as performing adhoc terms aggregations. - -// src/app/panels/table/module.js:5 - -=== Parameters - -size:: The number of hits to show per page -// src/app/panels/table/module.js:53 - -pages:: The number of pages available -// src/app/panels/table/module.js:59 - -offset:: The current page -// src/app/panels/table/module.js:63 - -sort:: An array describing the sort order of the table. For example [`@timestamp',`desc'] -// src/app/panels/table/module.js:67 - -overflow:: The css overflow property. `min-height' (expand) or `auto' (scroll) -// src/app/panels/table/module.js:71 - -fields:: the fields used a columns of the table, in an array. -// src/app/panels/table/module.js:75 - -highlight:: The fields on which to highlight, in an array -// src/app/panels/table/module.js:79 - -sortable:: Set sortable to false to disable sorting -// src/app/panels/table/module.js:83 - -header:: Set to false to hide the table column names -// src/app/panels/table/module.js:87 - -paging:: Set to false to hide the paging controls of the table -// src/app/panels/table/module.js:91 - -field_list:: Set to false to hide the list of fields. The user will be able to expand it, -but it will be hidden by default -// src/app/panels/table/module.js:95 - -all_fields:: Set to true to show all fields in the mapping, not just the current fields in -the table. -// src/app/panels/table/module.js:100 - -trimFactor:: The trim factor is the length at which to truncate fields takinging into -consideration the number of columns in the table. For example, a trimFactor of 100, with 5 -columns in the table, would trim each column at 20 character. The entirety of the field is -still available in the expanded view of the event. -// src/app/panels/table/module.js:105 - -localTime:: Set to true to adjust the timeField to the browser's local time -// src/app/panels/table/module.js:112 - -timeField:: If localTime is set to true, this field will be adjusted to the browsers local time -// src/app/panels/table/module.js:116 - -spyable:: Set to false to disable the inspect icon -// src/app/panels/table/module.js:120 - -==== Queries -queries object:: This object describes the queries to use on this panel. -queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ -queries.ids::: In +selected+ mode, which query ids are selected. -// src/app/panels/table/module.js:124 - diff --git a/docs/kibana/panels/terms.asciidoc b/docs/kibana/panels/terms.asciidoc deleted file mode 100644 index c20caf59078..00000000000 --- a/docs/kibana/panels/terms.asciidoc +++ /dev/null @@ -1,56 +0,0 @@ -== terms -Status: *Stable* - -A table, bar chart or pie chart based on the results of an Elasticsearch terms facet. - -// src/app/panels/terms/module.js:5 - -=== Parameters - -field:: The field on which to computer the facet -// src/app/panels/terms/module.js:45 - -exclude:: terms to exclude from the results -// src/app/panels/terms/module.js:51 - -missing:: Set to false to disable the display of a counter showing how much results are -missing the field -// src/app/panels/terms/module.js:55 - -other:: Set to false to disable the display of a counter representing the aggregate of all -values outside of the scope of your +size+ property -// src/app/panels/terms/module.js:60 - -size:: Show this many terms -// src/app/panels/terms/module.js:65 - -order:: count, term, reverse_count or reverse_term -// src/app/panels/terms/module.js:69 - -donut:: In pie chart mode, draw a hole in the middle of the pie to make a tasty donut. -// src/app/panels/terms/module.js:74 - -tilt:: In pie chart mode, tilt the chart back to appear as more of an oval shape -// src/app/panels/terms/module.js:78 - -lables:: In pie chart mode, draw labels in the pie slices -// src/app/panels/terms/module.js:82 - -arrangement:: In bar or pie mode, arrangement of the legend. horizontal or vertical -// src/app/panels/terms/module.js:86 - -chart:: table, bar or pie -// src/app/panels/terms/module.js:90 - -counter_pos:: The location of the legend in respect to the chart, above or below. -// src/app/panels/terms/module.js:94 - -spyable:: Set spyable to false to disable the inspect button -// src/app/panels/terms/module.js:98 - -==== Queries -queries object:: This object describes the queries to use on this panel. -queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ -queries.ids::: In +selected+ mode, which query ids are selected. -// src/app/panels/terms/module.js:102 - diff --git a/docs/kibana/panels/text.asciidoc b/docs/kibana/panels/text.asciidoc deleted file mode 100644 index da8cfb69cd1..00000000000 --- a/docs/kibana/panels/text.asciidoc +++ /dev/null @@ -1,16 +0,0 @@ -== text -Status: *Stable* - -The text panel is used for displaying static text formated as markdown, sanitized html or as plain -text. - -// src/app/panels/text/module.js:5 - -=== Parameters - -mode:: `html', `markdown' or `text' -// src/app/panels/text/module.js:33 - -content:: The content of your panel, written in the mark up specified in +mode+ -// src/app/panels/text/module.js:39 - diff --git a/docs/kibana/panels/trends.asciidoc b/docs/kibana/panels/trends.asciidoc deleted file mode 100644 index ce90c34730b..00000000000 --- a/docs/kibana/panels/trends.asciidoc +++ /dev/null @@ -1,27 +0,0 @@ -== trends -Status: *Beta* - -A stock-ticker style representation of how queries are moving over time. For example, if the -time is 1:10pm, your time picker was set to "Last 10m", and the "Time Ago" parameter was set to -"1h", the panel would show how much the query results have changed since 12:00-12:10pm - -// src/app/panels/trends/module.js:5 - -=== Parameters - -ago:: A date math formatted string describing the relative time period to compare the -queries to. -// src/app/panels/trends/module.js:49 - -arrangement:: `horizontal' or `vertical' -// src/app/panels/trends/module.js:56 - -spyable:: Set to false to disable the inspect icon -// src/app/panels/trends/module.js:60 - -==== Queries -queries object:: This object describes the queries to use on this panel. -queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ -queries.ids::: In +selected+ mode, which query ids are selected. -// src/app/panels/trends/module.js:64 - diff --git a/package.json b/package.json index d58807e4ec9..336311a01ce 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "devDependencies": { "rjs-build-analysis": "0.0.3", "grunt": "~0.4.0", - "grunt-s3": "~0.2.0-alpha.2", "grunt-ngmin": "0.0.3", "grunt-contrib": "~0.8.0", "grunt-contrib-less": "~0.7.0", @@ -29,8 +28,7 @@ "grunt-contrib-uglify": "~0.2.4", "load-grunt-tasks": "~0.2.0", "glob": "~3.2.7", - "grunt-contrib-connect": "~0.5.0", - "grunt-scratchy": "git://github.com/rashidkpc/grunt-scratchy.git" + "grunt-contrib-connect": "~0.5.0" }, "license": "Apache License" } diff --git a/src/app/dashboards/default.json b/src/app/dashboards/default.json index ea0ed6ef516..1ae0542e4a4 100644 --- a/src/app/dashboards/default.json +++ b/src/app/dashboards/default.json @@ -24,8 +24,8 @@ "rows": [ { "title": "Intro", - "height": "450px", - "editable": false, + "height": "150px", + "editable": true, "collapse": false, "collapsable": false, "panels": [ @@ -38,7 +38,7 @@ ], "type": "text", "mode": "markdown", - "content": "![kibana](img/kibana.png) \n\n##### Did you just upgrade? Not expecting this screen?\nIf you were using the old default page you might not be expecting this screen. I understand, change can be awkward. Let me explain. \n\n##### Setting a global default dashboard\nKibana has always shipped with an interface for Logstash, still does! You can access it [here](index.html#dashboard/file/logstash.json). However, if you want to make it your default again, all you need to do is rename a file!\nIn your Kibana installation directory: \n\nRename *logstash.json* to *default.json* and refresh. Should be all set.\n\n##### But wait, there's more!\nIn fact, you can add any exported dashboard to that directory and access it as *http://YOUR-HOST -HERE/index.html#dashboard/file/YOUR-DASHBOARD.json*. Neat trick eh?", + "content": "hej!", "style": {}, "title": "", "status": "Stable" @@ -46,21 +46,17 @@ { "error": false, "span": 8, - "editable": false, + "editable": true, "group": [ "default" ], - "type": "text", - "mode": "markdown", - "content": "### Welcome to Kibana. \nGlad you could make it. Happy to have you here! Lets get started, shall we?\n##### Requirements\n* **A good browser.** \n The latest version of Chrome or Firefox is recommended. Safari (latest version) and Internet Explorer 9 and above are also supported.\n* **A webserver.** \n Just somewhere to host the HTML and Javascript. Basically any webserver will work.\n* **Elasticsearch** \n 0.20.5 or above. Kibana will soon move to requiring Elasticsearch 0.90 or above, so upgrading is recommended.\n\n##### Configuration\nIf Kibana and Elasticsearch are on the same host, and you're using the default Elasticsearch port, then you're all set. Kibana is configured to use that setup by default! \n\nIf not, you need to edit *config.js* and set the *elasticsearch* parameter with the URL (including port, probably 9200) of your Elasticsearch server. The host part should be the entire, fully qualified domain name, or IP, **not localhost**.\n#### Are you a Logstash User?\n+ **YES** - Great! We have a prebuilt dashboard: [(Logstash Dashboard)](index.html#/dashboard/file/logstash.json). See the note to the right about making it your global default \n\n+ **NO** - Hey, no problem, you just have a bit of setup to do. You have a few choices: \n\n 1. [Sample Dashboard](index.html#/dashboard/file/guided.json) *I don't have much data yet, please extract some basics for me* \n 2. [Unconfigured Dashboard](index.html#/dashboard/file/noted.json) *I have a lot of data and I don't want Kibana to query it at once*\n 3. [Blank Dashboard](index.html#/dashboard/file/blank.json) *I'm comfortable figuring it out on my own*", - "style": {}, - "status": "Stable" + "type": "graph" } ], - "notice": false + "notice": true } ], - "editable": false, + "editable": true, "index": { "interval": "none", "pattern": "[logstash-]YYYY.MM.DD", @@ -71,7 +67,38 @@ "failover": false, "panel_hints": true, "pulldowns": [], - "nav": [], + "nav": [ + { + "type": "timepicker", + "collapse": false, + "notice": false, + "status": "Stable", + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ], + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "timefield": "@timestamp" + } + ], "loader": { "save_gist": false, "save_elasticsearch": true, diff --git a/src/app/panels/bettermap/editor.html b/src/app/panels/bettermap/editor.html deleted file mode 100644 index bcbd304d3d5..00000000000 --- a/src/app/panels/bettermap/editor.html +++ /dev/null @@ -1,17 +0,0 @@ -
-
-
-
Coordinate Field geoJSON array! Long,Lat NOT Lat,Long
- -
-
-
-
-
Tooltip Field
- -
-
-
Max Points
- -
-
diff --git a/src/app/panels/bettermap/leaflet/images/layers-2x.png b/src/app/panels/bettermap/leaflet/images/layers-2x.png deleted file mode 100644 index a2cf7f9efef..00000000000 Binary files a/src/app/panels/bettermap/leaflet/images/layers-2x.png and /dev/null differ diff --git a/src/app/panels/bettermap/leaflet/images/layers.png b/src/app/panels/bettermap/leaflet/images/layers.png deleted file mode 100644 index bca0a0e4296..00000000000 Binary files a/src/app/panels/bettermap/leaflet/images/layers.png and /dev/null differ diff --git a/src/app/panels/bettermap/leaflet/images/marker-icon-2x.png b/src/app/panels/bettermap/leaflet/images/marker-icon-2x.png deleted file mode 100644 index 0015b6495fa..00000000000 Binary files a/src/app/panels/bettermap/leaflet/images/marker-icon-2x.png and /dev/null differ diff --git a/src/app/panels/bettermap/leaflet/images/marker-icon.png b/src/app/panels/bettermap/leaflet/images/marker-icon.png deleted file mode 100644 index e2e9f757f51..00000000000 Binary files a/src/app/panels/bettermap/leaflet/images/marker-icon.png and /dev/null differ diff --git a/src/app/panels/bettermap/leaflet/images/marker-shadow.png b/src/app/panels/bettermap/leaflet/images/marker-shadow.png deleted file mode 100644 index d1e773c715a..00000000000 Binary files a/src/app/panels/bettermap/leaflet/images/marker-shadow.png and /dev/null differ diff --git a/src/app/panels/bettermap/leaflet/leaflet-src.js b/src/app/panels/bettermap/leaflet/leaflet-src.js deleted file mode 100644 index 9905530fab9..00000000000 --- a/src/app/panels/bettermap/leaflet/leaflet-src.js +++ /dev/null @@ -1,8724 +0,0 @@ -/* - Leaflet, a JavaScript library for mobile-friendly interactive maps. http://leafletjs.com - (c) 2010-2013, Vladimir Agafonkin, CloudMade -*/ -(function (window, document, undefined) { -var oldL = window.L, - L = {}; - -L.version = '0.6-dev'; - -// define Leaflet for Node module pattern loaders, including Browserify -if (typeof module === 'object' && typeof module.exports === 'object') { - module.exports = L; - -// define Leaflet as an AMD module -} else if (typeof define === 'function' && define.amd) { - define(L); -} - -// define Leaflet as a global L variable, saving the original L to restore later if needed - -L.noConflict = function () { - window.L = oldL; - return this; -}; - -window.L = L; - - -/* - * L.Util contains various utility functions used throughout Leaflet code. - */ - -L.Util = { - extend: function (dest) { // (Object[, Object, ...]) -> - var sources = Array.prototype.slice.call(arguments, 1), - i, j, len, src; - - for (j = 0, len = sources.length; j < len; j++) { - src = sources[j] || {}; - for (i in src) { - if (src.hasOwnProperty(i)) { - dest[i] = src[i]; - } - } - } - return dest; - }, - - bind: function (fn, obj) { // (Function, Object) -> Function - var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null; - return function () { - return fn.apply(obj, args || arguments); - }; - }, - - stamp: (function () { - var lastId = 0, - key = '_leaflet_id'; - return function (obj) { - obj[key] = obj[key] || ++lastId; - return obj[key]; - }; - }()), - - invokeEach: function (obj, method, context) { - var i, args; - - if (typeof obj === 'object') { - args = Array.prototype.slice.call(arguments, 3); - - for (i in obj) { - method.apply(context, [i, obj[i]].concat(args)); - } - return true; - } - - return false; - }, - - limitExecByInterval: function (fn, time, context) { - var lock, execOnUnlock; - - return function wrapperFn() { - var args = arguments; - - if (lock) { - execOnUnlock = true; - return; - } - - lock = true; - - setTimeout(function () { - lock = false; - - if (execOnUnlock) { - wrapperFn.apply(context, args); - execOnUnlock = false; - } - }, time); - - fn.apply(context, args); - }; - }, - - falseFn: function () { - return false; - }, - - formatNum: function (num, digits) { - var pow = Math.pow(10, digits || 5); - return Math.round(num * pow) / pow; - }, - - trim: function (str) { - return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); - }, - - splitWords: function (str) { - return L.Util.trim(str).split(/\s+/); - }, - - setOptions: function (obj, options) { - obj.options = L.extend({}, obj.options, options); - return obj.options; - }, - - getParamString: function (obj, existingUrl, uppercase) { - var params = []; - for (var i in obj) { - params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); - } - return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); - }, - - template: function (str, data) { - return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) { - var value = data[key]; - if (value === undefined) { - throw new Error('No value provided for variable ' + str); - } else if (typeof value === 'function') { - value = value(data); - } - return value; - }); - }, - - isArray: function (obj) { - return (Object.prototype.toString.call(obj) === '[object Array]'); - }, - - emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' -}; - -(function () { - - // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/ - - function getPrefixed(name) { - var i, fn, - prefixes = ['webkit', 'moz', 'o', 'ms']; - - for (i = 0; i < prefixes.length && !fn; i++) { - fn = window[prefixes[i] + name]; - } - - return fn; - } - - var lastTime = 0; - - function timeoutDefer(fn) { - var time = +new Date(), - timeToCall = Math.max(0, 16 - (time - lastTime)); - - lastTime = time + timeToCall; - return window.setTimeout(fn, timeToCall); - } - - var requestFn = window.requestAnimationFrame || - getPrefixed('RequestAnimationFrame') || timeoutDefer; - - var cancelFn = window.cancelAnimationFrame || - getPrefixed('CancelAnimationFrame') || - getPrefixed('CancelRequestAnimationFrame') || - function (id) { window.clearTimeout(id); }; - - - L.Util.requestAnimFrame = function (fn, context, immediate, element) { - fn = L.bind(fn, context); - - if (immediate && requestFn === timeoutDefer) { - fn(); - } else { - return requestFn.call(window, fn, element); - } - }; - - L.Util.cancelAnimFrame = function (id) { - if (id) { - cancelFn.call(window, id); - } - }; - -}()); - -// shortcuts for most used utility functions -L.extend = L.Util.extend; -L.bind = L.Util.bind; -L.stamp = L.Util.stamp; -L.setOptions = L.Util.setOptions; - - -/* - * L.Class powers the OOP facilities of the library. - * Thanks to John Resig and Dean Edwards for inspiration! - */ - -L.Class = function () {}; - -L.Class.extend = function (props) { - - // extended class with the new prototype - var NewClass = function () { - - // call the constructor - if (this.initialize) { - this.initialize.apply(this, arguments); - } - - // call all constructor hooks - if (this._initHooks) { - this.callInitHooks(); - } - }; - - // instantiate class without calling constructor - var F = function () {}; - F.prototype = this.prototype; - - var proto = new F(); - proto.constructor = NewClass; - - NewClass.prototype = proto; - - //inherit parent's statics - for (var i in this) { - if (this.hasOwnProperty(i) && i !== 'prototype') { - NewClass[i] = this[i]; - } - } - - // mix static properties into the class - if (props.statics) { - L.extend(NewClass, props.statics); - delete props.statics; - } - - // mix includes into the prototype - if (props.includes) { - L.Util.extend.apply(null, [proto].concat(props.includes)); - delete props.includes; - } - - // merge options - if (props.options && proto.options) { - props.options = L.extend({}, proto.options, props.options); - } - - // mix given properties into the prototype - L.extend(proto, props); - - proto._initHooks = []; - - var parent = this; - // jshint camelcase: false - NewClass.__super__ = parent.prototype; - - // add method for calling all hooks - proto.callInitHooks = function () { - - if (this._initHooksCalled) { return; } - - if (parent.prototype.callInitHooks) { - parent.prototype.callInitHooks.call(this); - } - - this._initHooksCalled = true; - - for (var i = 0, len = proto._initHooks.length; i < len; i++) { - proto._initHooks[i].call(this); - } - }; - - return NewClass; -}; - - -// method for adding properties to prototype -L.Class.include = function (props) { - L.extend(this.prototype, props); -}; - -// merge new default options to the Class -L.Class.mergeOptions = function (options) { - L.extend(this.prototype.options, options); -}; - -// add a constructor hook -L.Class.addInitHook = function (fn) { // (Function) || (String, args...) - var args = Array.prototype.slice.call(arguments, 1); - - var init = typeof fn === 'function' ? fn : function () { - this[fn].apply(this, args); - }; - - this.prototype._initHooks = this.prototype._initHooks || []; - this.prototype._initHooks.push(init); -}; - - -/* - * L.Mixin.Events is used to add custom events functionality to Leaflet classes. - */ - -var eventsKey = '_leaflet_events'; - -L.Mixin = {}; - -L.Mixin.Events = { - - addEventListener: function (types, fn, context) { // (String, Function[, Object]) or (Object[, Object]) - - // types can be a map of types/handlers - if (L.Util.invokeEach(types, this.addEventListener, this, fn, context)) { return this; } - - var events = this[eventsKey] = this[eventsKey] || {}, - contextId = context && L.stamp(context), - i, len, event, type, indexKey, indexLenKey, typeIndex; - - // types can be a string of space-separated words - types = L.Util.splitWords(types); - - for (i = 0, len = types.length; i < len; i++) { - event = { - action: fn, - context: context || this - }; - type = types[i]; - - if (context) { - // store listeners of a particular context in a separate hash (if it has an id) - // gives a major performance boost when removing thousands of map layers - - indexKey = type + '_idx'; - indexLenKey = indexKey + '_len'; - - typeIndex = events[indexKey] = events[indexKey] || {}; - - if (!typeIndex[contextId]) { - typeIndex[contextId] = []; - - // keep track of the number of keys in the index to quickly check if it's empty - events[indexLenKey] = (events[indexLenKey] || 0) + 1; - } - - typeIndex[contextId].push(event); - - - } else { - events[type] = events[type] || []; - events[type].push(event); - } - } - - return this; - }, - - hasEventListeners: function (type) { // (String) -> Boolean - var events = this[eventsKey]; - return !!events && ((type in events && events[type].length > 0) || - (type + '_idx' in events && events[type + '_idx_len'] > 0)); - }, - - removeEventListener: function (types, fn, context) { // ([String, Function, Object]) or (Object[, Object]) - - if (!this[eventsKey]) { - return this; - } - - if (!types) { - return this.clearAllEventListeners(); - } - - if (L.Util.invokeEach(types, this.removeEventListener, this, fn, context)) { return this; } - - var events = this[eventsKey], - contextId = context && L.stamp(context), - i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed; - - types = L.Util.splitWords(types); - - for (i = 0, len = types.length; i < len; i++) { - type = types[i]; - indexKey = type + '_idx'; - indexLenKey = indexKey + '_len'; - - typeIndex = events[indexKey]; - - if (!fn) { - // clear all listeners for a type if function isn't specified - delete events[type]; - delete events[indexKey]; - - } else { - listeners = context && typeIndex ? typeIndex[contextId] : events[type]; - - if (listeners) { - for (j = listeners.length - 1; j >= 0; j--) { - if ((listeners[j].action === fn) && (!context || (listeners[j].context === context))) { - removed = listeners.splice(j, 1); - // set the old action to a no-op, because it is possible - // that the listener is being iterated over as part of a dispatch - removed[0].action = L.Util.falseFn; - } - } - - if (context && typeIndex && (listeners.length === 0)) { - delete typeIndex[contextId]; - events[indexLenKey]--; - } - } - } - } - - return this; - }, - - clearAllEventListeners: function () { - delete this[eventsKey]; - return this; - }, - - fireEvent: function (type, data) { // (String[, Object]) - if (!this.hasEventListeners(type)) { - return this; - } - - var event = L.Util.extend({}, data, { type: type, target: this }); - - var events = this[eventsKey], - listeners, i, len, typeIndex, contextId; - - if (events[type]) { - // make sure adding/removing listeners inside other listeners won't cause infinite loop - listeners = events[type].slice(); - - for (i = 0, len = listeners.length; i < len; i++) { - listeners[i].action.call(listeners[i].context || this, event); - } - } - - // fire event for the context-indexed listeners as well - typeIndex = events[type + '_idx']; - - for (contextId in typeIndex) { - listeners = typeIndex[contextId].slice(); - - if (listeners) { - for (i = 0, len = listeners.length; i < len; i++) { - listeners[i].action.call(listeners[i].context || this, event); - } - } - } - - return this; - }, - - addOneTimeEventListener: function (types, fn, context) { - - if (L.Util.invokeEach(types, this.addOneTimeEventListener, this, fn, context)) { return this; } - - var handler = L.bind(function () { - this - .removeEventListener(types, fn, context) - .removeEventListener(types, handler, context); - }, this); - - return this - .addEventListener(types, fn, context) - .addEventListener(types, handler, context); - } -}; - -L.Mixin.Events.on = L.Mixin.Events.addEventListener; -L.Mixin.Events.off = L.Mixin.Events.removeEventListener; -L.Mixin.Events.once = L.Mixin.Events.addOneTimeEventListener; -L.Mixin.Events.fire = L.Mixin.Events.fireEvent; - - -/* - * L.Browser handles different browser and feature detections for internal Leaflet use. - */ - -(function () { - - var ie = !!window.ActiveXObject, - ie6 = ie && !window.XMLHttpRequest, - ie7 = ie && !document.querySelector, - ielt9 = ie && !document.addEventListener, - - // terrible browser detection to work around Safari / iOS / Android browser bugs - ua = navigator.userAgent.toLowerCase(), - webkit = ua.indexOf('webkit') !== -1, - chrome = ua.indexOf('chrome') !== -1, - phantomjs = ua.indexOf('phantom') !== -1, - android = ua.indexOf('android') !== -1, - android23 = ua.search('android [23]') !== -1, - - mobile = typeof orientation !== undefined + '', - msTouch = window.navigator && window.navigator.msPointerEnabled && - window.navigator.msMaxTouchPoints, - retina = ('devicePixelRatio' in window && window.devicePixelRatio > 1) || - ('matchMedia' in window && window.matchMedia('(min-resolution:144dpi)') && - window.matchMedia('(min-resolution:144dpi)').matches), - - doc = document.documentElement, - ie3d = ie && ('transition' in doc.style), - webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()), - gecko3d = 'MozPerspective' in doc.style, - opera3d = 'OTransition' in doc.style, - any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d || opera3d) && !phantomjs; - - - // PhantomJS has 'ontouchstart' in document.documentElement, but doesn't actually support touch. - // https://github.com/Leaflet/Leaflet/pull/1434#issuecomment-13843151 - - var touch = !window.L_NO_TOUCH && !phantomjs && (function () { - - var startName = 'ontouchstart'; - - // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.MsTouch) or WebKit, etc. - if (msTouch || (startName in doc)) { - return true; - } - - // Firefox/Gecko - var div = document.createElement('div'), - supported = false; - - if (!div.setAttribute) { - return false; - } - div.setAttribute(startName, 'return;'); - - if (typeof div[startName] === 'function') { - supported = true; - } - - div.removeAttribute(startName); - div = null; - - return supported; - }()); - - - L.Browser = { - ie: ie, - ie6: ie6, - ie7: ie7, - ielt9: ielt9, - webkit: webkit, - - android: android, - android23: android23, - - chrome: chrome, - - ie3d: ie3d, - webkit3d: webkit3d, - gecko3d: gecko3d, - opera3d: opera3d, - any3d: any3d, - - mobile: mobile, - mobileWebkit: mobile && webkit, - mobileWebkit3d: mobile && webkit3d, - mobileOpera: mobile && window.opera, - - touch: touch, - msTouch: msTouch, - - retina: retina - }; - -}()); - - -/* - * L.Point represents a point with x and y coordinates. - */ - -L.Point = function (/*Number*/ x, /*Number*/ y, /*Boolean*/ round) { - this.x = (round ? Math.round(x) : x); - this.y = (round ? Math.round(y) : y); -}; - -L.Point.prototype = { - - clone: function () { - return new L.Point(this.x, this.y); - }, - - // non-destructive, returns a new point - add: function (point) { - return this.clone()._add(L.point(point)); - }, - - // destructive, used directly for performance in situations where it's safe to modify existing point - _add: function (point) { - this.x += point.x; - this.y += point.y; - return this; - }, - - subtract: function (point) { - return this.clone()._subtract(L.point(point)); - }, - - _subtract: function (point) { - this.x -= point.x; - this.y -= point.y; - return this; - }, - - divideBy: function (num) { - return this.clone()._divideBy(num); - }, - - _divideBy: function (num) { - this.x /= num; - this.y /= num; - return this; - }, - - multiplyBy: function (num) { - return this.clone()._multiplyBy(num); - }, - - _multiplyBy: function (num) { - this.x *= num; - this.y *= num; - return this; - }, - - round: function () { - return this.clone()._round(); - }, - - _round: function () { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; - }, - - floor: function () { - return this.clone()._floor(); - }, - - _floor: function () { - this.x = Math.floor(this.x); - this.y = Math.floor(this.y); - return this; - }, - - distanceTo: function (point) { - point = L.point(point); - - var x = point.x - this.x, - y = point.y - this.y; - - return Math.sqrt(x * x + y * y); - }, - - equals: function (point) { - point = L.point(point); - - return point.x === this.x && - point.y === this.y; - }, - - contains: function (point) { - point = L.point(point); - - return Math.abs(point.x) <= Math.abs(this.x) && - Math.abs(point.y) <= Math.abs(this.y); - }, - - toString: function () { - return 'Point(' + - L.Util.formatNum(this.x) + ', ' + - L.Util.formatNum(this.y) + ')'; - } -}; - -L.point = function (x, y, round) { - if (x instanceof L.Point) { - return x; - } - if (L.Util.isArray(x)) { - return new L.Point(x[0], x[1]); - } - if (x === undefined || x === null) { - return x; - } - return new L.Point(x, y, round); -}; - - -/* - * L.Bounds represents a rectangular area on the screen in pixel coordinates. - */ - -L.Bounds = function (a, b) { //(Point, Point) or Point[] - if (!a) { return; } - - var points = b ? [a, b] : a; - - for (var i = 0, len = points.length; i < len; i++) { - this.extend(points[i]); - } -}; - -L.Bounds.prototype = { - // extend the bounds to contain the given point - extend: function (point) { // (Point) - point = L.point(point); - - if (!this.min && !this.max) { - this.min = point.clone(); - this.max = point.clone(); - } else { - this.min.x = Math.min(point.x, this.min.x); - this.max.x = Math.max(point.x, this.max.x); - this.min.y = Math.min(point.y, this.min.y); - this.max.y = Math.max(point.y, this.max.y); - } - return this; - }, - - getCenter: function (round) { // (Boolean) -> Point - return new L.Point( - (this.min.x + this.max.x) / 2, - (this.min.y + this.max.y) / 2, round); - }, - - getBottomLeft: function () { // -> Point - return new L.Point(this.min.x, this.max.y); - }, - - getTopRight: function () { // -> Point - return new L.Point(this.max.x, this.min.y); - }, - - getSize: function () { - return this.max.subtract(this.min); - }, - - contains: function (obj) { // (Bounds) or (Point) -> Boolean - var min, max; - - if (typeof obj[0] === 'number' || obj instanceof L.Point) { - obj = L.point(obj); - } else { - obj = L.bounds(obj); - } - - if (obj instanceof L.Bounds) { - min = obj.min; - max = obj.max; - } else { - min = max = obj; - } - - return (min.x >= this.min.x) && - (max.x <= this.max.x) && - (min.y >= this.min.y) && - (max.y <= this.max.y); - }, - - intersects: function (bounds) { // (Bounds) -> Boolean - bounds = L.bounds(bounds); - - var min = this.min, - max = this.max, - min2 = bounds.min, - max2 = bounds.max, - xIntersects = (max2.x >= min.x) && (min2.x <= max.x), - yIntersects = (max2.y >= min.y) && (min2.y <= max.y); - - return xIntersects && yIntersects; - }, - - isValid: function () { - return !!(this.min && this.max); - } -}; - -L.bounds = function (a, b) { // (Bounds) or (Point, Point) or (Point[]) - if (!a || a instanceof L.Bounds) { - return a; - } - return new L.Bounds(a, b); -}; - - -/* - * L.Transformation is an utility class to perform simple point transformations through a 2d-matrix. - */ - -L.Transformation = function (a, b, c, d) { - this._a = a; - this._b = b; - this._c = c; - this._d = d; -}; - -L.Transformation.prototype = { - transform: function (point, scale) { // (Point, Number) -> Point - return this._transform(point.clone(), scale); - }, - - // destructive transform (faster) - _transform: function (point, scale) { - scale = scale || 1; - point.x = scale * (this._a * point.x + this._b); - point.y = scale * (this._c * point.y + this._d); - return point; - }, - - untransform: function (point, scale) { - scale = scale || 1; - return new L.Point( - (point.x / scale - this._b) / this._a, - (point.y / scale - this._d) / this._c); - } -}; - - -/* - * L.DomUtil contains various utility functions for working with DOM. - */ - -L.DomUtil = { - get: function (id) { - return (typeof id === 'string' ? document.getElementById(id) : id); - }, - - getStyle: function (el, style) { - - var value = el.style[style]; - - if (!value && el.currentStyle) { - value = el.currentStyle[style]; - } - - if ((!value || value === 'auto') && document.defaultView) { - var css = document.defaultView.getComputedStyle(el, null); - value = css ? css[style] : null; - } - - return value === 'auto' ? null : value; - }, - - getViewportOffset: function (element) { - - var top = 0, - left = 0, - el = element, - docBody = document.body, - docEl = document.documentElement, - pos, - ie7 = L.Browser.ie7; - - do { - top += el.offsetTop || 0; - left += el.offsetLeft || 0; - - //add borders - top += parseInt(L.DomUtil.getStyle(el, 'borderTopWidth'), 10) || 0; - left += parseInt(L.DomUtil.getStyle(el, 'borderLeftWidth'), 10) || 0; - - pos = L.DomUtil.getStyle(el, 'position'); - - if (el.offsetParent === docBody && pos === 'absolute') { break; } - - if (pos === 'fixed') { - top += docBody.scrollTop || docEl.scrollTop || 0; - left += docBody.scrollLeft || docEl.scrollLeft || 0; - break; - } - - if (pos === 'relative' && !el.offsetLeft) { - var width = L.DomUtil.getStyle(el, 'width'), - maxWidth = L.DomUtil.getStyle(el, 'max-width'), - r = el.getBoundingClientRect(); - - if (width !== 'none' || maxWidth !== 'none') { - left += r.left + el.clientLeft; - } - - //calculate full y offset since we're breaking out of the loop - top += r.top + (docBody.scrollTop || docEl.scrollTop || 0); - - break; - } - - el = el.offsetParent; - - } while (el); - - el = element; - - do { - if (el === docBody) { break; } - - top -= el.scrollTop || 0; - left -= el.scrollLeft || 0; - - // webkit (and ie <= 7) handles RTL scrollLeft different to everyone else - // https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/style/bidi.js - if (!L.DomUtil.documentIsLtr() && (L.Browser.webkit || ie7)) { - left += el.scrollWidth - el.clientWidth; - - // ie7 shows the scrollbar by default and provides clientWidth counting it, so we - // need to add it back in if it is visible; scrollbar is on the left as we are RTL - if (ie7 && L.DomUtil.getStyle(el, 'overflow-y') !== 'hidden' && - L.DomUtil.getStyle(el, 'overflow') !== 'hidden') { - left += 17; - } - } - - el = el.parentNode; - } while (el); - - return new L.Point(left, top); - }, - - documentIsLtr: function () { - if (!L.DomUtil._docIsLtrCached) { - L.DomUtil._docIsLtrCached = true; - L.DomUtil._docIsLtr = L.DomUtil.getStyle(document.body, 'direction') === 'ltr'; - } - return L.DomUtil._docIsLtr; - }, - - create: function (tagName, className, container) { - - var el = document.createElement(tagName); - el.className = className; - - if (container) { - container.appendChild(el); - } - - return el; - }, - - disableTextSelection: function () { - if (document.selection && document.selection.empty) { - document.selection.empty(); - } - if (!this._onselectstart) { - this._onselectstart = document.onselectstart || null; - document.onselectstart = L.Util.falseFn; - } - }, - - enableTextSelection: function () { - if (document.onselectstart === L.Util.falseFn) { - document.onselectstart = this._onselectstart; - this._onselectstart = null; - } - }, - - hasClass: function (el, name) { - return (el.className.length > 0) && - new RegExp('(^|\\s)' + name + '(\\s|$)').test(el.className); - }, - - addClass: function (el, name) { - if (!L.DomUtil.hasClass(el, name)) { - el.className += (el.className ? ' ' : '') + name; - } - }, - - removeClass: function (el, name) { - el.className = L.Util.trim((' ' + el.className + ' ').replace(' ' + name + ' ', ' ')); - }, - - setOpacity: function (el, value) { - - if ('opacity' in el.style) { - el.style.opacity = value; - - } else if ('filter' in el.style) { - - var filter = false, - filterName = 'DXImageTransform.Microsoft.Alpha'; - - // filters collection throws an error if we try to retrieve a filter that doesn't exist - try { - filter = el.filters.item(filterName); - } catch (e) { - // don't set opacity to 1 if we haven't already set an opacity, - // it isn't needed and breaks transparent pngs. - if (value === 1) { return; } - } - - value = Math.round(value * 100); - - if (filter) { - filter.Enabled = (value !== 100); - filter.Opacity = value; - } else { - el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')'; - } - } - }, - - testProp: function (props) { - - var style = document.documentElement.style; - - for (var i = 0; i < props.length; i++) { - if (props[i] in style) { - return props[i]; - } - } - return false; - }, - - getTranslateString: function (point) { - // on WebKit browsers (Chrome/Safari/iOS Safari/Android) using translate3d instead of translate - // makes animation smoother as it ensures HW accel is used. Firefox 13 doesn't care - // (same speed either way), Opera 12 doesn't support translate3d - - var is3d = L.Browser.webkit3d, - open = 'translate' + (is3d ? '3d' : '') + '(', - close = (is3d ? ',0' : '') + ')'; - - return open + point.x + 'px,' + point.y + 'px' + close; - }, - - getScaleString: function (scale, origin) { - - var preTranslateStr = L.DomUtil.getTranslateString(origin.add(origin.multiplyBy(-1 * scale))), - scaleStr = ' scale(' + scale + ') '; - - return preTranslateStr + scaleStr; - }, - - setPosition: function (el, point, disable3D) { // (HTMLElement, Point[, Boolean]) - - // jshint camelcase: false - el._leaflet_pos = point; - - if (!disable3D && L.Browser.any3d) { - el.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(point); - - // workaround for Android 2/3 stability (https://github.com/CloudMade/Leaflet/issues/69) - if (L.Browser.mobileWebkit3d) { - el.style.WebkitBackfaceVisibility = 'hidden'; - } - } else { - el.style.left = point.x + 'px'; - el.style.top = point.y + 'px'; - } - }, - - getPosition: function (el) { - // this method is only used for elements previously positioned using setPosition, - // so it's safe to cache the position for performance - - // jshint camelcase: false - return el._leaflet_pos; - } -}; - - -// prefix style property names - -L.DomUtil.TRANSFORM = L.DomUtil.testProp( - ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']); - -// webkitTransition comes first because some browser versions that drop vendor prefix don't do -// the same for the transitionend event, in particular the Android 4.1 stock browser - -L.DomUtil.TRANSITION = L.DomUtil.testProp( - ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); - -L.DomUtil.TRANSITION_END = - L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ? - L.DomUtil.TRANSITION + 'End' : 'transitionend'; - - -/* - * L.LatLng represents a geographical point with latitude and longitude coordinates. - */ - -L.LatLng = function (rawLat, rawLng) { // (Number, Number) - var lat = parseFloat(rawLat), - lng = parseFloat(rawLng); - - if (isNaN(lat) || isNaN(lng)) { - throw new Error('Invalid LatLng object: (' + rawLat + ', ' + rawLng + ')'); - } - - this.lat = lat; - this.lng = lng; -}; - -L.extend(L.LatLng, { - DEG_TO_RAD: Math.PI / 180, - RAD_TO_DEG: 180 / Math.PI, - MAX_MARGIN: 1.0E-9 // max margin of error for the "equals" check -}); - -L.LatLng.prototype = { - equals: function (obj) { // (LatLng) -> Boolean - if (!obj) { return false; } - - obj = L.latLng(obj); - - var margin = Math.max( - Math.abs(this.lat - obj.lat), - Math.abs(this.lng - obj.lng)); - - return margin <= L.LatLng.MAX_MARGIN; - }, - - toString: function (precision) { // (Number) -> String - return 'LatLng(' + - L.Util.formatNum(this.lat, precision) + ', ' + - L.Util.formatNum(this.lng, precision) + ')'; - }, - - // Haversine distance formula, see http://en.wikipedia.org/wiki/Haversine_formula - // TODO move to projection code, LatLng shouldn't know about Earth - distanceTo: function (other) { // (LatLng) -> Number - other = L.latLng(other); - - var R = 6378137, // earth radius in meters - d2r = L.LatLng.DEG_TO_RAD, - dLat = (other.lat - this.lat) * d2r, - dLon = (other.lng - this.lng) * d2r, - lat1 = this.lat * d2r, - lat2 = other.lat * d2r, - sin1 = Math.sin(dLat / 2), - sin2 = Math.sin(dLon / 2); - - var a = sin1 * sin1 + sin2 * sin2 * Math.cos(lat1) * Math.cos(lat2); - - return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - }, - - wrap: function (a, b) { // (Number, Number) -> LatLng - var lng = this.lng; - - a = a || -180; - b = b || 180; - - lng = (lng + b) % (b - a) + (lng < a || lng === b ? b : a); - - return new L.LatLng(this.lat, lng); - } -}; - -L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Number) - if (a instanceof L.LatLng) { - return a; - } - if (L.Util.isArray(a)) { - return new L.LatLng(a[0], a[1]); - } - if (a === undefined || a === null) { - return a; - } - if (typeof a === 'object' && 'lat' in a) { - return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon); - } - return new L.LatLng(a, b); -}; - - - -/* - * L.LatLngBounds represents a rectangular area on the map in geographical coordinates. - */ - -L.LatLngBounds = function (southWest, northEast) { // (LatLng, LatLng) or (LatLng[]) - if (!southWest) { return; } - - var latlngs = northEast ? [southWest, northEast] : southWest; - - for (var i = 0, len = latlngs.length; i < len; i++) { - this.extend(latlngs[i]); - } -}; - -L.LatLngBounds.prototype = { - // extend the bounds to contain the given point or bounds - extend: function (obj) { // (LatLng) or (LatLngBounds) - if (!obj) { return this; } - - if (typeof obj[0] === 'number' || typeof obj[0] === 'string' || obj instanceof L.LatLng) { - obj = L.latLng(obj); - } else { - obj = L.latLngBounds(obj); - } - - if (obj instanceof L.LatLng) { - if (!this._southWest && !this._northEast) { - this._southWest = new L.LatLng(obj.lat, obj.lng); - this._northEast = new L.LatLng(obj.lat, obj.lng); - } else { - this._southWest.lat = Math.min(obj.lat, this._southWest.lat); - this._southWest.lng = Math.min(obj.lng, this._southWest.lng); - - this._northEast.lat = Math.max(obj.lat, this._northEast.lat); - this._northEast.lng = Math.max(obj.lng, this._northEast.lng); - } - } else if (obj instanceof L.LatLngBounds) { - this.extend(obj._southWest); - this.extend(obj._northEast); - } - return this; - }, - - // extend the bounds by a percentage - pad: function (bufferRatio) { // (Number) -> LatLngBounds - var sw = this._southWest, - ne = this._northEast, - heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio, - widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio; - - return new L.LatLngBounds( - new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer), - new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)); - }, - - getCenter: function () { // -> LatLng - return new L.LatLng( - (this._southWest.lat + this._northEast.lat) / 2, - (this._southWest.lng + this._northEast.lng) / 2); - }, - - getSouthWest: function () { - return this._southWest; - }, - - getNorthEast: function () { - return this._northEast; - }, - - getNorthWest: function () { - return new L.LatLng(this.getNorth(), this.getWest()); - }, - - getSouthEast: function () { - return new L.LatLng(this.getSouth(), this.getEast()); - }, - - getWest: function () { - return this._southWest.lng; - }, - - getSouth: function () { - return this._southWest.lat; - }, - - getEast: function () { - return this._northEast.lng; - }, - - getNorth: function () { - return this._northEast.lat; - }, - - contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean - if (typeof obj[0] === 'number' || obj instanceof L.LatLng) { - obj = L.latLng(obj); - } else { - obj = L.latLngBounds(obj); - } - - var sw = this._southWest, - ne = this._northEast, - sw2, ne2; - - if (obj instanceof L.LatLngBounds) { - sw2 = obj.getSouthWest(); - ne2 = obj.getNorthEast(); - } else { - sw2 = ne2 = obj; - } - - return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && - (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); - }, - - intersects: function (bounds) { // (LatLngBounds) - bounds = L.latLngBounds(bounds); - - var sw = this._southWest, - ne = this._northEast, - sw2 = bounds.getSouthWest(), - ne2 = bounds.getNorthEast(), - - latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat), - lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng); - - return latIntersects && lngIntersects; - }, - - toBBoxString: function () { - return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(','); - }, - - equals: function (bounds) { // (LatLngBounds) - if (!bounds) { return false; } - - bounds = L.latLngBounds(bounds); - - return this._southWest.equals(bounds.getSouthWest()) && - this._northEast.equals(bounds.getNorthEast()); - }, - - isValid: function () { - return !!(this._southWest && this._northEast); - } -}; - -//TODO International date line? - -L.latLngBounds = function (a, b) { // (LatLngBounds) or (LatLng, LatLng) - if (!a || a instanceof L.LatLngBounds) { - return a; - } - return new L.LatLngBounds(a, b); -}; - - -/* - * L.Projection contains various geographical projections used by CRS classes. - */ - -L.Projection = {}; - - -/* - * Spherical Mercator is the most popular map projection, used by EPSG:3857 CRS used by default. - */ - -L.Projection.SphericalMercator = { - MAX_LATITUDE: 85.0511287798, - - project: function (latlng) { // (LatLng) -> Point - var d = L.LatLng.DEG_TO_RAD, - max = this.MAX_LATITUDE, - lat = Math.max(Math.min(max, latlng.lat), -max), - x = latlng.lng * d, - y = lat * d; - - y = Math.log(Math.tan((Math.PI / 4) + (y / 2))); - - return new L.Point(x, y); - }, - - unproject: function (point) { // (Point, Boolean) -> LatLng - var d = L.LatLng.RAD_TO_DEG, - lng = point.x * d, - lat = (2 * Math.atan(Math.exp(point.y)) - (Math.PI / 2)) * d; - - return new L.LatLng(lat, lng); - } -}; - - -/* - * Simple equirectangular (Plate Carree) projection, used by CRS like EPSG:4326 and Simple. - */ - -L.Projection.LonLat = { - project: function (latlng) { - return new L.Point(latlng.lng, latlng.lat); - }, - - unproject: function (point) { - return new L.LatLng(point.y, point.x); - } -}; - - -/* - * L.CRS is a base object for all defined CRS (Coordinate Reference Systems) in Leaflet. - */ - -L.CRS = { - latLngToPoint: function (latlng, zoom) { // (LatLng, Number) -> Point - var projectedPoint = this.projection.project(latlng), - scale = this.scale(zoom); - - return this.transformation._transform(projectedPoint, scale); - }, - - pointToLatLng: function (point, zoom) { // (Point, Number[, Boolean]) -> LatLng - var scale = this.scale(zoom), - untransformedPoint = this.transformation.untransform(point, scale); - - return this.projection.unproject(untransformedPoint); - }, - - project: function (latlng) { - return this.projection.project(latlng); - }, - - scale: function (zoom) { - return 256 * Math.pow(2, zoom); - } -}; - - -/* - * A simple CRS that can be used for flat non-Earth maps like panoramas or game maps. - */ - -L.CRS.Simple = L.extend({}, L.CRS, { - projection: L.Projection.LonLat, - transformation: new L.Transformation(1, 0, -1, 0), - - scale: function (zoom) { - return Math.pow(2, zoom); - } -}); - - -/* - * L.CRS.EPSG3857 (Spherical Mercator) is the most common CRS for web mapping - * and is used by Leaflet by default. - */ - -L.CRS.EPSG3857 = L.extend({}, L.CRS, { - code: 'EPSG:3857', - - projection: L.Projection.SphericalMercator, - transformation: new L.Transformation(0.5 / Math.PI, 0.5, -0.5 / Math.PI, 0.5), - - project: function (latlng) { // (LatLng) -> Point - var projectedPoint = this.projection.project(latlng), - earthRadius = 6378137; - return projectedPoint.multiplyBy(earthRadius); - } -}); - -L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, { - code: 'EPSG:900913' -}); - - -/* - * L.CRS.EPSG4326 is a CRS popular among advanced GIS specialists. - */ - -L.CRS.EPSG4326 = L.extend({}, L.CRS, { - code: 'EPSG:4326', - - projection: L.Projection.LonLat, - transformation: new L.Transformation(1 / 360, 0.5, -1 / 360, 0.5) -}); - - -/* - * L.Map is the central class of the API - it is used to create a map. - */ - -L.Map = L.Class.extend({ - - includes: L.Mixin.Events, - - options: { - crs: L.CRS.EPSG3857, - - /* - center: LatLng, - zoom: Number, - layers: Array, - */ - - fadeAnimation: L.DomUtil.TRANSITION && !L.Browser.android23, - trackResize: true, - markerZoomAnimation: L.DomUtil.TRANSITION && L.Browser.any3d - }, - - initialize: function (id, options) { // (HTMLElement or String, Object) - options = L.setOptions(this, options); - - this._initContainer(id); - this._initLayout(); - this._initEvents(); - - if (options.maxBounds) { - this.setMaxBounds(options.maxBounds); - } - - if (options.center && options.zoom !== undefined) { - this.setView(L.latLng(options.center), options.zoom, {reset: true}); - } - - this._initLayers(options.layers); - - this._handlers = []; - - this.callInitHooks(); - }, - - - // public methods that modify map state - - // replaced by animation-powered implementation in Map.PanAnimation.js - setView: function (center, zoom) { - this._resetView(L.latLng(center), this._limitZoom(zoom)); - return this; - }, - - setZoom: function (zoom, options) { - return this.setView(this.getCenter(), zoom, {zoom: options}); - }, - - zoomIn: function (delta, options) { - return this.setZoom(this._zoom + (delta || 1), options); - }, - - zoomOut: function (delta, options) { - return this.setZoom(this._zoom - (delta || 1), options); - }, - - setZoomAround: function (latlng, zoom, options) { - var scale = this.getZoomScale(zoom), - viewHalf = this.getSize().divideBy(2), - containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng), - - centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale), - newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset)); - - return this.setView(newCenter, zoom, {zoom: options}); - }, - - fitBounds: function (bounds, options) { - - options = options || {}; - bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds); - - var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]), - paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]), - - zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR)), - paddingOffset = paddingBR.subtract(paddingTL).divideBy(2), - - swPoint = this.project(bounds.getSouthWest(), zoom), - nePoint = this.project(bounds.getNorthEast(), zoom), - center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom); - - return this.setView(center, zoom, options); - }, - - fitWorld: function (options) { - return this.fitBounds([[-90, -180], [90, 180]], options); - }, - - panTo: function (center, options) { // (LatLng) - return this.setView(center, this._zoom, {pan: options}); - }, - - panBy: function (offset) { // (Point) - // replaced with animated panBy in Map.Animation.js - this.fire('movestart'); - - this._rawPanBy(L.point(offset)); - - this.fire('move'); - return this.fire('moveend'); - }, - - setMaxBounds: function (bounds) { - bounds = L.latLngBounds(bounds); - - this.options.maxBounds = bounds; - - if (!bounds) { - this._boundsMinZoom = null; - this.off('moveend', this._panInsideMaxBounds, this); - return this; - } - - var minZoom = this.getBoundsZoom(bounds, true); - - this._boundsMinZoom = minZoom; - - if (this._loaded) { - if (this._zoom < minZoom) { - this.setView(bounds.getCenter(), minZoom); - } else { - this.panInsideBounds(bounds); - } - } - - this.on('moveend', this._panInsideMaxBounds, this); - - return this; - }, - - panInsideBounds: function (bounds) { - bounds = L.latLngBounds(bounds); - - var viewBounds = this.getPixelBounds(), - viewSw = viewBounds.getBottomLeft(), - viewNe = viewBounds.getTopRight(), - sw = this.project(bounds.getSouthWest()), - ne = this.project(bounds.getNorthEast()), - dx = 0, - dy = 0; - - if (viewNe.y < ne.y) { // north - dy = Math.ceil(ne.y - viewNe.y); - } - if (viewNe.x > ne.x) { // east - dx = Math.floor(ne.x - viewNe.x); - } - if (viewSw.y > sw.y) { // south - dy = Math.floor(sw.y - viewSw.y); - } - if (viewSw.x < sw.x) { // west - dx = Math.ceil(sw.x - viewSw.x); - } - - if (dx || dy) { - return this.panBy([dx, dy]); - } - - return this; - }, - - addLayer: function (layer) { - // TODO method is too big, refactor - - var id = L.stamp(layer); - - if (this._layers[id]) { return this; } - - this._layers[id] = layer; - - // TODO getMaxZoom, getMinZoom in ILayer (instead of options) - if (layer.options && (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom))) { - this._zoomBoundLayers[id] = layer; - this._updateZoomLevels(); - } - - // TODO looks ugly, refactor!!! - if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) { - this._tileLayersNum++; - this._tileLayersToLoad++; - layer.on('load', this._onTileLayerLoad, this); - } - - if (this._loaded) { - this._layerAdd(layer); - } - - return this; - }, - - removeLayer: function (layer) { - var id = L.stamp(layer); - - if (!this._layers[id]) { return; } - - if (this._loaded) { - layer.onRemove(this); - this.fire('layerremove', {layer: layer}); - } - - delete this._layers[id]; - if (this._zoomBoundLayers[id]) { - delete this._zoomBoundLayers[id]; - this._updateZoomLevels(); - } - - // TODO looks ugly, refactor - if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) { - this._tileLayersNum--; - this._tileLayersToLoad--; - layer.off('load', this._onTileLayerLoad, this); - } - - return this; - }, - - hasLayer: function (layer) { - if (!layer) { return false; } - - return (L.stamp(layer) in this._layers); - }, - - eachLayer: function (method, context) { - for (var i in this._layers) { - method.call(context, this._layers[i]); - } - return this; - }, - - invalidateSize: function (animate) { - var oldSize = this.getSize(); - - this._sizeChanged = true; - - if (this.options.maxBounds) { - this.setMaxBounds(this.options.maxBounds); - } - - if (!this._loaded) { return this; } - - var newSize = this.getSize(), - offset = oldSize.subtract(newSize).divideBy(2).round(); - - if ((offset.x !== 0) || (offset.y !== 0)) { - if (animate === true) { - this.panBy(offset); - } else { - this._rawPanBy(offset); - - this.fire('move'); - - clearTimeout(this._sizeTimer); - this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200); - } - this.fire('resize', { - oldSize: oldSize, - newSize: newSize - }); - } - return this; - }, - - // TODO handler.addTo - addHandler: function (name, HandlerClass) { - if (!HandlerClass) { return; } - - var handler = this[name] = new HandlerClass(this); - - this._handlers.push(handler); - - if (this.options[name]) { - handler.enable(); - } - - return this; - }, - - remove: function () { - if (this._loaded) { - this.fire('unload'); - } - - this._initEvents('off'); - - delete this._container._leaflet; - - this._clearPanes(); - if (this._clearControlPos) { - this._clearControlPos(); - } - - this._clearHandlers(); - - return this; - }, - - - // public methods for getting map state - - getCenter: function () { // (Boolean) -> LatLng - this._checkIfLoaded(); - - if (!this._moved()) { - return this._initialCenter; - } - return this.layerPointToLatLng(this._getCenterLayerPoint()); - }, - - getZoom: function () { - return this._zoom; - }, - - getBounds: function () { - var bounds = this.getPixelBounds(), - sw = this.unproject(bounds.getBottomLeft()), - ne = this.unproject(bounds.getTopRight()); - - return new L.LatLngBounds(sw, ne); - }, - - getMinZoom: function () { - var z1 = this.options.minZoom || 0, - z2 = this._layersMinZoom || 0, - z3 = this._boundsMinZoom || 0; - - return Math.max(z1, z2, z3); - }, - - getMaxZoom: function () { - var z1 = this.options.maxZoom === undefined ? Infinity : this.options.maxZoom, - z2 = this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom; - - return Math.min(z1, z2); - }, - - getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number - bounds = L.latLngBounds(bounds); - - var zoom = this.getMinZoom() - (inside ? 1 : 0), - maxZoom = this.getMaxZoom(), - size = this.getSize(), - - nw = bounds.getNorthWest(), - se = bounds.getSouthEast(), - - zoomNotFound = true, - boundsSize; - - padding = L.point(padding || [0, 0]); - - do { - zoom++; - boundsSize = this.project(se, zoom).subtract(this.project(nw, zoom)).add(padding); - zoomNotFound = !inside ? size.contains(boundsSize) : boundsSize.x < size.x || boundsSize.y < size.y; - - } while (zoomNotFound && zoom <= maxZoom); - - if (zoomNotFound && inside) { - return null; - } - - return inside ? zoom : zoom - 1; - }, - - getSize: function () { - if (!this._size || this._sizeChanged) { - this._size = new L.Point( - this._container.clientWidth, - this._container.clientHeight); - - this._sizeChanged = false; - } - return this._size.clone(); - }, - - getPixelBounds: function () { - var topLeftPoint = this._getTopLeftPoint(); - return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize())); - }, - - getPixelOrigin: function () { - this._checkIfLoaded(); - return this._initialTopLeftPoint; - }, - - getPanes: function () { - return this._panes; - }, - - getContainer: function () { - return this._container; - }, - - - // TODO replace with universal implementation after refactoring projections - - getZoomScale: function (toZoom) { - var crs = this.options.crs; - return crs.scale(toZoom) / crs.scale(this._zoom); - }, - - getScaleZoom: function (scale) { - return this._zoom + (Math.log(scale) / Math.LN2); - }, - - - // conversion methods - - project: function (latlng, zoom) { // (LatLng[, Number]) -> Point - zoom = zoom === undefined ? this._zoom : zoom; - return this.options.crs.latLngToPoint(L.latLng(latlng), zoom); - }, - - unproject: function (point, zoom) { // (Point[, Number]) -> LatLng - zoom = zoom === undefined ? this._zoom : zoom; - return this.options.crs.pointToLatLng(L.point(point), zoom); - }, - - layerPointToLatLng: function (point) { // (Point) - var projectedPoint = L.point(point).add(this.getPixelOrigin()); - return this.unproject(projectedPoint); - }, - - latLngToLayerPoint: function (latlng) { // (LatLng) - var projectedPoint = this.project(L.latLng(latlng))._round(); - return projectedPoint._subtract(this.getPixelOrigin()); - }, - - containerPointToLayerPoint: function (point) { // (Point) - return L.point(point).subtract(this._getMapPanePos()); - }, - - layerPointToContainerPoint: function (point) { // (Point) - return L.point(point).add(this._getMapPanePos()); - }, - - containerPointToLatLng: function (point) { - var layerPoint = this.containerPointToLayerPoint(L.point(point)); - return this.layerPointToLatLng(layerPoint); - }, - - latLngToContainerPoint: function (latlng) { - return this.layerPointToContainerPoint(this.latLngToLayerPoint(L.latLng(latlng))); - }, - - mouseEventToContainerPoint: function (e) { // (MouseEvent) - return L.DomEvent.getMousePosition(e, this._container); - }, - - mouseEventToLayerPoint: function (e) { // (MouseEvent) - return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e)); - }, - - mouseEventToLatLng: function (e) { // (MouseEvent) - return this.layerPointToLatLng(this.mouseEventToLayerPoint(e)); - }, - - - // map initialization methods - - _initContainer: function (id) { - var container = this._container = L.DomUtil.get(id); - - if (!container) { - throw new Error('Map container not found.'); - } else if (container._leaflet) { - throw new Error('Map container is already initialized.'); - } - - container._leaflet = true; - }, - - _initLayout: function () { - var container = this._container; - - L.DomUtil.addClass(container, 'leaflet-container' + - (L.Browser.touch ? ' leaflet-touch' : '') + - (L.Browser.retina ? ' leaflet-retina' : '') + - (this.options.fadeAnimation ? ' leaflet-fade-anim' : '')); - - var position = L.DomUtil.getStyle(container, 'position'); - - if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') { - container.style.position = 'relative'; - } - - this._initPanes(); - - if (this._initControlPos) { - this._initControlPos(); - } - }, - - _initPanes: function () { - var panes = this._panes = {}; - - this._mapPane = panes.mapPane = this._createPane('leaflet-map-pane', this._container); - - this._tilePane = panes.tilePane = this._createPane('leaflet-tile-pane', this._mapPane); - panes.objectsPane = this._createPane('leaflet-objects-pane', this._mapPane); - panes.shadowPane = this._createPane('leaflet-shadow-pane'); - panes.overlayPane = this._createPane('leaflet-overlay-pane'); - panes.markerPane = this._createPane('leaflet-marker-pane'); - panes.popupPane = this._createPane('leaflet-popup-pane'); - - var zoomHide = ' leaflet-zoom-hide'; - - if (!this.options.markerZoomAnimation) { - L.DomUtil.addClass(panes.markerPane, zoomHide); - L.DomUtil.addClass(panes.shadowPane, zoomHide); - L.DomUtil.addClass(panes.popupPane, zoomHide); - } - }, - - _createPane: function (className, container) { - return L.DomUtil.create('div', className, container || this._panes.objectsPane); - }, - - _clearPanes: function () { - this._container.removeChild(this._mapPane); - }, - - _initLayers: function (layers) { - layers = layers ? (L.Util.isArray(layers) ? layers : [layers]) : []; - - this._layers = {}; - this._zoomBoundLayers = {}; - this._tileLayersNum = 0; - - var i, len; - - for (i = 0, len = layers.length; i < len; i++) { - this.addLayer(layers[i]); - } - }, - - - // private methods that modify map state - - _resetView: function (center, zoom, preserveMapOffset, afterZoomAnim) { - - var zoomChanged = (this._zoom !== zoom); - - if (!afterZoomAnim) { - this.fire('movestart'); - - if (zoomChanged) { - this.fire('zoomstart'); - } - } - - this._zoom = zoom; - this._initialCenter = center; - - this._initialTopLeftPoint = this._getNewTopLeftPoint(center); - - if (!preserveMapOffset) { - L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0)); - } else { - this._initialTopLeftPoint._add(this._getMapPanePos()); - } - - this._tileLayersToLoad = this._tileLayersNum; - - var loading = !this._loaded; - this._loaded = true; - - if (loading) { - this.fire('load'); - this.eachLayer(this._layerAdd, this); - } - - this.fire('viewreset', {hard: !preserveMapOffset}); - - this.fire('move'); - - if (zoomChanged || afterZoomAnim) { - this.fire('zoomend'); - } - - this.fire('moveend', {hard: !preserveMapOffset}); - }, - - _rawPanBy: function (offset) { - L.DomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset)); - }, - - _getZoomSpan: function () { - return this.getMaxZoom() - this.getMinZoom(); - }, - - _updateZoomLevels: function () { - var i, - minZoom = Infinity, - maxZoom = -Infinity, - oldZoomSpan = this._getZoomSpan(); - - for (i in this._zoomBoundLayers) { - var layer = this._zoomBoundLayers[i]; - if (!isNaN(layer.options.minZoom)) { - minZoom = Math.min(minZoom, layer.options.minZoom); - } - if (!isNaN(layer.options.maxZoom)) { - maxZoom = Math.max(maxZoom, layer.options.maxZoom); - } - } - - if (i === undefined) { // we have no tilelayers - this._layersMaxZoom = this._layersMinZoom = undefined; - } else { - this._layersMaxZoom = maxZoom; - this._layersMinZoom = minZoom; - } - - if (oldZoomSpan !== this._getZoomSpan()) { - this.fire('zoomlevelschange'); - } - }, - - _panInsideMaxBounds: function () { - this.panInsideBounds(this.options.maxBounds); - }, - - _checkIfLoaded: function () { - if (!this._loaded) { - throw new Error('Set map center and zoom first.'); - } - }, - - // map events - - _initEvents: function (onOff) { - if (!L.DomEvent) { return; } - - onOff = onOff || 'on'; - - L.DomEvent[onOff](this._container, 'click', this._onMouseClick, this); - - var events = ['dblclick', 'mousedown', 'mouseup', 'mouseenter', - 'mouseleave', 'mousemove', 'contextmenu'], - i, len; - - for (i = 0, len = events.length; i < len; i++) { - L.DomEvent[onOff](this._container, events[i], this._fireMouseEvent, this); - } - - if (this.options.trackResize) { - L.DomEvent[onOff](window, 'resize', this._onResize, this); - } - }, - - _onResize: function () { - L.Util.cancelAnimFrame(this._resizeRequest); - this._resizeRequest = L.Util.requestAnimFrame( - this.invalidateSize, this, false, this._container); - }, - - _onMouseClick: function (e) { - if (!this._loaded || (this.dragging && this.dragging.moved())) { return; } - - this.fire('preclick'); - this._fireMouseEvent(e); - }, - - _fireMouseEvent: function (e) { - if (!this._loaded) { return; } - - var type = e.type; - - type = (type === 'mouseenter' ? 'mouseover' : (type === 'mouseleave' ? 'mouseout' : type)); - - if (!this.hasEventListeners(type)) { return; } - - if (type === 'contextmenu') { - L.DomEvent.preventDefault(e); - } - - var containerPoint = this.mouseEventToContainerPoint(e), - layerPoint = this.containerPointToLayerPoint(containerPoint), - latlng = this.layerPointToLatLng(layerPoint); - - this.fire(type, { - latlng: latlng, - layerPoint: layerPoint, - containerPoint: containerPoint, - originalEvent: e - }); - }, - - _onTileLayerLoad: function () { - this._tileLayersToLoad--; - if (this._tileLayersNum && !this._tileLayersToLoad) { - this.fire('tilelayersload'); - } - }, - - _clearHandlers: function () { - for (var i = 0, len = this._handlers.length; i < len; i++) { - this._handlers[i].disable(); - } - }, - - whenReady: function (callback, context) { - if (this._loaded) { - callback.call(context || this, this); - } else { - this.on('load', callback, context); - } - return this; - }, - - _layerAdd: function (layer) { - layer.onAdd(this); - this.fire('layeradd', {layer: layer}); - }, - - - // private methods for getting map state - - _getMapPanePos: function () { - return L.DomUtil.getPosition(this._mapPane); - }, - - _moved: function () { - var pos = this._getMapPanePos(); - return pos && !pos.equals([0, 0]); - }, - - _getTopLeftPoint: function () { - return this.getPixelOrigin().subtract(this._getMapPanePos()); - }, - - _getNewTopLeftPoint: function (center, zoom) { - var viewHalf = this.getSize()._divideBy(2); - // TODO round on display, not calculation to increase precision? - return this.project(center, zoom)._subtract(viewHalf)._round(); - }, - - _latLngToNewLayerPoint: function (latlng, newZoom, newCenter) { - var topLeft = this._getNewTopLeftPoint(newCenter, newZoom).add(this._getMapPanePos()); - return this.project(latlng, newZoom)._subtract(topLeft); - }, - - // layer point of the current center - _getCenterLayerPoint: function () { - return this.containerPointToLayerPoint(this.getSize()._divideBy(2)); - }, - - // offset of the specified place to the current center in pixels - _getCenterOffset: function (latlng) { - return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint()); - }, - - _limitZoom: function (zoom) { - var min = this.getMinZoom(), - max = this.getMaxZoom(); - - return Math.max(min, Math.min(max, zoom)); - } -}); - -L.map = function (id, options) { - return new L.Map(id, options); -}; - - -/* - * Mercator projection that takes into account that the Earth is not a perfect sphere. - * Less popular than spherical mercator; used by projections like EPSG:3395. - */ - -L.Projection.Mercator = { - MAX_LATITUDE: 85.0840591556, - - R_MINOR: 6356752.3142, - R_MAJOR: 6378137, - - project: function (latlng) { // (LatLng) -> Point - var d = L.LatLng.DEG_TO_RAD, - max = this.MAX_LATITUDE, - lat = Math.max(Math.min(max, latlng.lat), -max), - r = this.R_MAJOR, - r2 = this.R_MINOR, - x = latlng.lng * d * r, - y = lat * d, - tmp = r2 / r, - eccent = Math.sqrt(1.0 - tmp * tmp), - con = eccent * Math.sin(y); - - con = Math.pow((1 - con) / (1 + con), eccent * 0.5); - - var ts = Math.tan(0.5 * ((Math.PI * 0.5) - y)) / con; - y = -r2 * Math.log(ts); - - return new L.Point(x, y); - }, - - unproject: function (point) { // (Point, Boolean) -> LatLng - var d = L.LatLng.RAD_TO_DEG, - r = this.R_MAJOR, - r2 = this.R_MINOR, - lng = point.x * d / r, - tmp = r2 / r, - eccent = Math.sqrt(1 - (tmp * tmp)), - ts = Math.exp(- point.y / r2), - phi = (Math.PI / 2) - 2 * Math.atan(ts), - numIter = 15, - tol = 1e-7, - i = numIter, - dphi = 0.1, - con; - - while ((Math.abs(dphi) > tol) && (--i > 0)) { - con = eccent * Math.sin(phi); - dphi = (Math.PI / 2) - 2 * Math.atan(ts * - Math.pow((1.0 - con) / (1.0 + con), 0.5 * eccent)) - phi; - phi += dphi; - } - - return new L.LatLng(phi * d, lng); - } -}; - - - -L.CRS.EPSG3395 = L.extend({}, L.CRS, { - code: 'EPSG:3395', - - projection: L.Projection.Mercator, - - transformation: (function () { - var m = L.Projection.Mercator, - r = m.R_MAJOR, - r2 = m.R_MINOR; - - return new L.Transformation(0.5 / (Math.PI * r), 0.5, -0.5 / (Math.PI * r2), 0.5); - }()) -}); - - -/* - * L.TileLayer is used for standard xyz-numbered tile layers. - */ - -L.TileLayer = L.Class.extend({ - includes: L.Mixin.Events, - - options: { - minZoom: 0, - maxZoom: 18, - tileSize: 256, - subdomains: 'abc', - errorTileUrl: '', - attribution: '', - zoomOffset: 0, - opacity: 1, - /* (undefined works too) - zIndex: null, - tms: false, - continuousWorld: false, - noWrap: false, - zoomReverse: false, - detectRetina: false, - reuseTiles: false, - bounds: false, - */ - unloadInvisibleTiles: L.Browser.mobile, - updateWhenIdle: L.Browser.mobile - }, - - initialize: function (url, options) { - options = L.setOptions(this, options); - - // detecting retina displays, adjusting tileSize and zoom levels - if (options.detectRetina && L.Browser.retina && options.maxZoom > 0) { - - options.tileSize = Math.floor(options.tileSize / 2); - options.zoomOffset++; - - if (options.minZoom > 0) { - options.minZoom--; - } - this.options.maxZoom--; - } - - if (options.bounds) { - options.bounds = L.latLngBounds(options.bounds); - } - - this._url = url; - - var subdomains = this.options.subdomains; - - if (typeof subdomains === 'string') { - this.options.subdomains = subdomains.split(''); - } - }, - - onAdd: function (map) { - this._map = map; - this._animated = map.options.zoomAnimation && L.Browser.any3d; - - // create a container div for tiles - this._initContainer(); - - // create an image to clone for tiles - this._createTileProto(); - - // set up events - map.on({ - 'viewreset': this._reset, - 'moveend': this._update - }, this); - - if (this._animated) { - map.on({ - 'zoomanim': this._animateZoom, - 'zoomend': this._endZoomAnim - }, this); - } - - if (!this.options.updateWhenIdle) { - this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this); - map.on('move', this._limitedUpdate, this); - } - - this._reset(); - this._update(); - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - onRemove: function (map) { - this._container.parentNode.removeChild(this._container); - - map.off({ - 'viewreset': this._reset, - 'moveend': this._update - }, this); - - if (this._animated) { - map.off({ - 'zoomanim': this._animateZoom, - 'zoomend': this._endZoomAnim - }, this); - } - - if (!this.options.updateWhenIdle) { - map.off('move', this._limitedUpdate, this); - } - - this._container = null; - this._map = null; - }, - - bringToFront: function () { - var pane = this._map._panes.tilePane; - - if (this._container) { - pane.appendChild(this._container); - this._setAutoZIndex(pane, Math.max); - } - - return this; - }, - - bringToBack: function () { - var pane = this._map._panes.tilePane; - - if (this._container) { - pane.insertBefore(this._container, pane.firstChild); - this._setAutoZIndex(pane, Math.min); - } - - return this; - }, - - getAttribution: function () { - return this.options.attribution; - }, - - getContainer: function () { - return this._container; - }, - - setOpacity: function (opacity) { - this.options.opacity = opacity; - - if (this._map) { - this._updateOpacity(); - } - - return this; - }, - - setZIndex: function (zIndex) { - this.options.zIndex = zIndex; - this._updateZIndex(); - - return this; - }, - - setUrl: function (url, noRedraw) { - this._url = url; - - if (!noRedraw) { - this.redraw(); - } - - return this; - }, - - redraw: function () { - if (this._map) { - this._reset({hard: true}); - this._update(); - } - return this; - }, - - _updateZIndex: function () { - if (this._container && this.options.zIndex !== undefined) { - this._container.style.zIndex = this.options.zIndex; - } - }, - - _setAutoZIndex: function (pane, compare) { - - var layers = pane.children, - edgeZIndex = -compare(Infinity, -Infinity), // -Infinity for max, Infinity for min - zIndex, i, len; - - for (i = 0, len = layers.length; i < len; i++) { - - if (layers[i] !== this._container) { - zIndex = parseInt(layers[i].style.zIndex, 10); - - if (!isNaN(zIndex)) { - edgeZIndex = compare(edgeZIndex, zIndex); - } - } - } - - this.options.zIndex = this._container.style.zIndex = - (isFinite(edgeZIndex) ? edgeZIndex : 0) + compare(1, -1); - }, - - _updateOpacity: function () { - var i, - tiles = this._tiles; - - if (L.Browser.ielt9) { - for (i in tiles) { - L.DomUtil.setOpacity(tiles[i], this.options.opacity); - } - } else { - L.DomUtil.setOpacity(this._container, this.options.opacity); - } - - // stupid webkit hack to force redrawing of tiles - if (L.Browser.webkit) { - for (i in tiles) { - tiles[i].style.webkitTransform += ' translate(0,0)'; - } - } - }, - - _initContainer: function () { - var tilePane = this._map._panes.tilePane; - - if (!this._container) { - this._container = L.DomUtil.create('div', 'leaflet-layer'); - - this._updateZIndex(); - - if (this._animated) { - var className = 'leaflet-tile-container leaflet-zoom-animated'; - - this._bgBuffer = L.DomUtil.create('div', className, this._container); - this._bgBuffer.style.zIndex = 1; - - this._tileContainer = L.DomUtil.create('div', className, this._container); - this._tileContainer.style.zIndex = 2; - - } else { - this._tileContainer = this._container; - } - - tilePane.appendChild(this._container); - - if (this.options.opacity < 1) { - this._updateOpacity(); - } - } - }, - - _reset: function (e) { - for (var key in this._tiles) { - this.fire('tileunload', {tile: this._tiles[key]}); - } - - this._tiles = {}; - this._tilesToLoad = 0; - - if (this.options.reuseTiles) { - this._unusedTiles = []; - } - - this._tileContainer.innerHTML = ''; - - if (this._animated && e && e.hard) { - this._clearBgBuffer(); - } - - this._initContainer(); - }, - - _update: function () { - - if (!this._map) { return; } - - var bounds = this._map.getPixelBounds(), - zoom = this._map.getZoom(), - tileSize = this.options.tileSize; - - if (zoom > this.options.maxZoom || zoom < this.options.minZoom) { - return; - } - - var tileBounds = L.bounds( - bounds.min.divideBy(tileSize)._floor(), - bounds.max.divideBy(tileSize)._floor()); - - this._addTilesFromCenterOut(tileBounds); - - if (this.options.unloadInvisibleTiles || this.options.reuseTiles) { - this._removeOtherTiles(tileBounds); - } - }, - - _addTilesFromCenterOut: function (bounds) { - var queue = [], - center = bounds.getCenter(); - - var j, i, point; - - for (j = bounds.min.y; j <= bounds.max.y; j++) { - for (i = bounds.min.x; i <= bounds.max.x; i++) { - point = new L.Point(i, j); - - if (this._tileShouldBeLoaded(point)) { - queue.push(point); - } - } - } - - var tilesToLoad = queue.length; - - if (tilesToLoad === 0) { return; } - - // load tiles in order of their distance to center - queue.sort(function (a, b) { - return a.distanceTo(center) - b.distanceTo(center); - }); - - var fragment = document.createDocumentFragment(); - - // if its the first batch of tiles to load - if (!this._tilesToLoad) { - this.fire('loading'); - } - - this._tilesToLoad += tilesToLoad; - - for (i = 0; i < tilesToLoad; i++) { - this._addTile(queue[i], fragment); - } - - this._tileContainer.appendChild(fragment); - }, - - _tileShouldBeLoaded: function (tilePoint) { - if ((tilePoint.x + ':' + tilePoint.y) in this._tiles) { - return false; // already loaded - } - - var options = this.options; - - if (!options.continuousWorld) { - var limit = this._getWrapTileNum(); - - // don't load if exceeds world bounds - if ((options.noWrap && (tilePoint.x < 0 || tilePoint.x >= limit)) || - tilePoint.y < 0 || tilePoint.y >= limit) { return false; } - } - - if (options.bounds) { - var tileSize = options.tileSize, - nwPoint = tilePoint.multiplyBy(tileSize), - sePoint = nwPoint.add([tileSize, tileSize]), - nw = this._map.unproject(nwPoint), - se = this._map.unproject(sePoint); - - // TODO temporary hack, will be removed after refactoring projections - // https://github.com/Leaflet/Leaflet/issues/1618 - if (!options.continuousWorld && !options.noWrap) { - nw = nw.wrap(); - se = se.wrap(); - } - - if (!options.bounds.intersects([nw, se])) { return false; } - } - - return true; - }, - - _removeOtherTiles: function (bounds) { - var kArr, x, y, key; - - for (key in this._tiles) { - kArr = key.split(':'); - x = parseInt(kArr[0], 10); - y = parseInt(kArr[1], 10); - - // remove tile if it's out of bounds - if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) { - this._removeTile(key); - } - } - }, - - _removeTile: function (key) { - var tile = this._tiles[key]; - - this.fire('tileunload', {tile: tile, url: tile.src}); - - if (this.options.reuseTiles) { - L.DomUtil.removeClass(tile, 'leaflet-tile-loaded'); - this._unusedTiles.push(tile); - - } else if (tile.parentNode === this._tileContainer) { - this._tileContainer.removeChild(tile); - } - - // for https://github.com/CloudMade/Leaflet/issues/137 - if (!L.Browser.android) { - tile.onload = null; - tile.src = L.Util.emptyImageUrl; - } - - delete this._tiles[key]; - }, - - _addTile: function (tilePoint, container) { - var tilePos = this._getTilePos(tilePoint); - - // get unused tile - or create a new tile - var tile = this._getTile(); - - /* - Chrome 20 layouts much faster with top/left (verify with timeline, frames) - Android 4 browser has display issues with top/left and requires transform instead - Android 2 browser requires top/left or tiles disappear on load or first drag - (reappear after zoom) https://github.com/CloudMade/Leaflet/issues/866 - (other browsers don't currently care) - see debug/hacks/jitter.html for an example - */ - L.DomUtil.setPosition(tile, tilePos, L.Browser.chrome || L.Browser.android23); - - this._tiles[tilePoint.x + ':' + tilePoint.y] = tile; - - this._loadTile(tile, tilePoint); - - if (tile.parentNode !== this._tileContainer) { - container.appendChild(tile); - } - }, - - _getZoomForUrl: function () { - - var options = this.options, - zoom = this._map.getZoom(); - - if (options.zoomReverse) { - zoom = options.maxZoom - zoom; - } - - return zoom + options.zoomOffset; - }, - - _getTilePos: function (tilePoint) { - var origin = this._map.getPixelOrigin(), - tileSize = this.options.tileSize; - - return tilePoint.multiplyBy(tileSize).subtract(origin); - }, - - // image-specific code (override to implement e.g. Canvas or SVG tile layer) - - getTileUrl: function (tilePoint) { - return L.Util.template(this._url, L.extend({ - s: this._getSubdomain(tilePoint), - z: tilePoint.z, - x: tilePoint.x, - y: tilePoint.y - }, this.options)); - }, - - _getWrapTileNum: function () { - // TODO refactor, limit is not valid for non-standard projections - return Math.pow(2, this._getZoomForUrl()); - }, - - _adjustTilePoint: function (tilePoint) { - - var limit = this._getWrapTileNum(); - - // wrap tile coordinates - if (!this.options.continuousWorld && !this.options.noWrap) { - tilePoint.x = ((tilePoint.x % limit) + limit) % limit; - } - - if (this.options.tms) { - tilePoint.y = limit - tilePoint.y - 1; - } - - tilePoint.z = this._getZoomForUrl(); - }, - - _getSubdomain: function (tilePoint) { - var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length; - return this.options.subdomains[index]; - }, - - _createTileProto: function () { - var img = this._tileImg = L.DomUtil.create('img', 'leaflet-tile'); - img.style.width = img.style.height = this.options.tileSize + 'px'; - img.galleryimg = 'no'; - }, - - _getTile: function () { - if (this.options.reuseTiles && this._unusedTiles.length > 0) { - var tile = this._unusedTiles.pop(); - this._resetTile(tile); - return tile; - } - return this._createTile(); - }, - - // Override if data stored on a tile needs to be cleaned up before reuse - _resetTile: function (/*tile*/) {}, - - _createTile: function () { - var tile = this._tileImg.cloneNode(false); - tile.onselectstart = tile.onmousemove = L.Util.falseFn; - - if (L.Browser.ielt9 && this.options.opacity !== undefined) { - L.DomUtil.setOpacity(tile, this.options.opacity); - } - return tile; - }, - - _loadTile: function (tile, tilePoint) { - tile._layer = this; - tile.onload = this._tileOnLoad; - tile.onerror = this._tileOnError; - - this._adjustTilePoint(tilePoint); - tile.src = this.getTileUrl(tilePoint); - }, - - _tileLoaded: function () { - this._tilesToLoad--; - if (!this._tilesToLoad) { - this.fire('load'); - - if (this._animated) { - // clear scaled tiles after all new tiles are loaded (for performance) - clearTimeout(this._clearBgBufferTimer); - this._clearBgBufferTimer = setTimeout(L.bind(this._clearBgBuffer, this), 500); - } - } - }, - - _tileOnLoad: function () { - var layer = this._layer; - - //Only if we are loading an actual image - if (this.src !== L.Util.emptyImageUrl) { - L.DomUtil.addClass(this, 'leaflet-tile-loaded'); - - layer.fire('tileload', { - tile: this, - url: this.src - }); - } - - layer._tileLoaded(); - }, - - _tileOnError: function () { - var layer = this._layer; - - layer.fire('tileerror', { - tile: this, - url: this.src - }); - - var newUrl = layer.options.errorTileUrl; - if (newUrl) { - this.src = newUrl; - } - - layer._tileLoaded(); - } -}); - -L.tileLayer = function (url, options) { - return new L.TileLayer(url, options); -}; - - -/* - * L.TileLayer.WMS is used for putting WMS tile layers on the map. - */ - -L.TileLayer.WMS = L.TileLayer.extend({ - - defaultWmsParams: { - service: 'WMS', - request: 'GetMap', - version: '1.1.1', - layers: '', - styles: '', - format: 'image/jpeg', - transparent: false - }, - - initialize: function (url, options) { // (String, Object) - - this._url = url; - - var wmsParams = L.extend({}, this.defaultWmsParams), - tileSize = options.tileSize || this.options.tileSize; - - if (options.detectRetina && L.Browser.retina) { - wmsParams.width = wmsParams.height = tileSize * 2; - } else { - wmsParams.width = wmsParams.height = tileSize; - } - - for (var i in options) { - // all keys that are not TileLayer options go to WMS params - if (!this.options.hasOwnProperty(i)) { - wmsParams[i] = options[i]; - } - } - - this.wmsParams = wmsParams; - - L.setOptions(this, options); - }, - - onAdd: function (map) { - - var projectionKey = parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs'; - this.wmsParams[projectionKey] = map.options.crs.code; - - L.TileLayer.prototype.onAdd.call(this, map); - }, - - getTileUrl: function (tilePoint, zoom) { // (Point, Number) -> String - - var map = this._map, - crs = map.options.crs, - tileSize = this.options.tileSize, - - nwPoint = tilePoint.multiplyBy(tileSize), - sePoint = nwPoint.add([tileSize, tileSize]), - - nw = crs.project(map.unproject(nwPoint, zoom)), - se = crs.project(map.unproject(sePoint, zoom)), - - bbox = [nw.x, se.y, se.x, nw.y].join(','), - - url = L.Util.template(this._url, {s: this._getSubdomain(tilePoint)}); - - return url + L.Util.getParamString(this.wmsParams, url, true) + '&BBOX=' + bbox; - }, - - setParams: function (params, noRedraw) { - - L.extend(this.wmsParams, params); - - if (!noRedraw) { - this.redraw(); - } - - return this; - } -}); - -L.tileLayer.wms = function (url, options) { - return new L.TileLayer.WMS(url, options); -}; - - -/* - * L.TileLayer.Canvas is a class that you can use as a base for creating - * dynamically drawn Canvas-based tile layers. - */ - -L.TileLayer.Canvas = L.TileLayer.extend({ - options: { - async: false - }, - - initialize: function (options) { - L.setOptions(this, options); - }, - - redraw: function () { - for (var i in this._tiles) { - this._redrawTile(this._tiles[i]); - } - return this; - }, - - _redrawTile: function (tile) { - this.drawTile(tile, tile._tilePoint, this._map._zoom); - }, - - _createTileProto: function () { - var proto = this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile'); - proto.width = proto.height = this.options.tileSize; - }, - - _createTile: function () { - var tile = this._canvasProto.cloneNode(false); - tile.onselectstart = tile.onmousemove = L.Util.falseFn; - return tile; - }, - - _loadTile: function (tile, tilePoint) { - tile._layer = this; - tile._tilePoint = tilePoint; - - this._redrawTile(tile); - - if (!this.options.async) { - this.tileDrawn(tile); - } - }, - - drawTile: function (/*tile, tilePoint*/) { - // override with rendering code - }, - - tileDrawn: function (tile) { - this._tileOnLoad.call(tile); - } -}); - - -L.tileLayer.canvas = function (options) { - return new L.TileLayer.Canvas(options); -}; - - -/* - * L.ImageOverlay is used to overlay images over the map (to specific geographical bounds). - */ - -L.ImageOverlay = L.Class.extend({ - includes: L.Mixin.Events, - - options: { - opacity: 1 - }, - - initialize: function (url, bounds, options) { // (String, LatLngBounds, Object) - this._url = url; - this._bounds = L.latLngBounds(bounds); - - L.setOptions(this, options); - }, - - onAdd: function (map) { - this._map = map; - - if (!this._image) { - this._initImage(); - } - - map._panes.overlayPane.appendChild(this._image); - - map.on('viewreset', this._reset, this); - - if (map.options.zoomAnimation && L.Browser.any3d) { - map.on('zoomanim', this._animateZoom, this); - } - - this._reset(); - }, - - onRemove: function (map) { - map.getPanes().overlayPane.removeChild(this._image); - - map.off('viewreset', this._reset, this); - - if (map.options.zoomAnimation) { - map.off('zoomanim', this._animateZoom, this); - } - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - setOpacity: function (opacity) { - this.options.opacity = opacity; - this._updateOpacity(); - return this; - }, - - // TODO remove bringToFront/bringToBack duplication from TileLayer/Path - bringToFront: function () { - if (this._image) { - this._map._panes.overlayPane.appendChild(this._image); - } - return this; - }, - - bringToBack: function () { - var pane = this._map._panes.overlayPane; - if (this._image) { - pane.insertBefore(this._image, pane.firstChild); - } - return this; - }, - - _initImage: function () { - this._image = L.DomUtil.create('img', 'leaflet-image-layer'); - - if (this._map.options.zoomAnimation && L.Browser.any3d) { - L.DomUtil.addClass(this._image, 'leaflet-zoom-animated'); - } else { - L.DomUtil.addClass(this._image, 'leaflet-zoom-hide'); - } - - this._updateOpacity(); - - //TODO createImage util method to remove duplication - L.extend(this._image, { - galleryimg: 'no', - onselectstart: L.Util.falseFn, - onmousemove: L.Util.falseFn, - onload: L.bind(this._onImageLoad, this), - src: this._url - }); - }, - - _animateZoom: function (e) { - var map = this._map, - image = this._image, - scale = map.getZoomScale(e.zoom), - nw = this._bounds.getNorthWest(), - se = this._bounds.getSouthEast(), - - topLeft = map._latLngToNewLayerPoint(nw, e.zoom, e.center), - size = map._latLngToNewLayerPoint(se, e.zoom, e.center)._subtract(topLeft), - origin = topLeft._add(size._multiplyBy((1 / 2) * (1 - 1 / scale))); - - image.style[L.DomUtil.TRANSFORM] = - L.DomUtil.getTranslateString(origin) + ' scale(' + scale + ') '; - }, - - _reset: function () { - var image = this._image, - topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()), - size = this._map.latLngToLayerPoint(this._bounds.getSouthEast())._subtract(topLeft); - - L.DomUtil.setPosition(image, topLeft); - - image.style.width = size.x + 'px'; - image.style.height = size.y + 'px'; - }, - - _onImageLoad: function () { - this.fire('load'); - }, - - _updateOpacity: function () { - L.DomUtil.setOpacity(this._image, this.options.opacity); - } -}); - -L.imageOverlay = function (url, bounds, options) { - return new L.ImageOverlay(url, bounds, options); -}; - - -/* - * L.Icon is an image-based icon class that you can use with L.Marker for custom markers. - */ - -L.Icon = L.Class.extend({ - options: { - /* - iconUrl: (String) (required) - iconRetinaUrl: (String) (optional, used for retina devices if detected) - iconSize: (Point) (can be set through CSS) - iconAnchor: (Point) (centered by default, can be set in CSS with negative margins) - popupAnchor: (Point) (if not specified, popup opens in the anchor point) - shadowUrl: (Point) (no shadow by default) - shadowRetinaUrl: (String) (optional, used for retina devices if detected) - shadowSize: (Point) - shadowAnchor: (Point) - */ - className: '' - }, - - initialize: function (options) { - L.setOptions(this, options); - }, - - createIcon: function (oldIcon) { - return this._createIcon('icon', oldIcon); - }, - - createShadow: function (oldIcon) { - return this._createIcon('shadow', oldIcon); - }, - - _createIcon: function (name, oldIcon) { - var src = this._getIconUrl(name); - - if (!src) { - if (name === 'icon') { - throw new Error('iconUrl not set in Icon options (see the docs).'); - } - return null; - } - - var img; - if (!oldIcon || oldIcon.tagName !== 'IMG') { - img = this._createImg(src); - } else { - img = this._createImg(src, oldIcon); - } - this._setIconStyles(img, name); - - return img; - }, - - _setIconStyles: function (img, name) { - var options = this.options, - size = L.point(options[name + 'Size']), - anchor; - - if (name === 'shadow') { - anchor = L.point(options.shadowAnchor || options.iconAnchor); - } else { - anchor = L.point(options.iconAnchor); - } - - if (!anchor && size) { - anchor = size.divideBy(2, true); - } - - img.className = 'leaflet-marker-' + name + ' ' + options.className; - - if (anchor) { - img.style.marginLeft = (-anchor.x) + 'px'; - img.style.marginTop = (-anchor.y) + 'px'; - } - - if (size) { - img.style.width = size.x + 'px'; - img.style.height = size.y + 'px'; - } - }, - - _createImg: function (src, el) { - - if (!L.Browser.ie6) { - if (!el) { - el = document.createElement('img'); - } - el.src = src; - } else { - if (!el) { - el = document.createElement('div'); - } - el.style.filter = - 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")'; - } - return el; - }, - - _getIconUrl: function (name) { - if (L.Browser.retina && this.options[name + 'RetinaUrl']) { - return this.options[name + 'RetinaUrl']; - } - return this.options[name + 'Url']; - } -}); - -L.icon = function (options) { - return new L.Icon(options); -}; - - -/* - * L.Icon.Default is the blue marker icon used by default in Leaflet. - */ - -L.Icon.Default = L.Icon.extend({ - - options: { - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], - - shadowSize: [41, 41] - }, - - _getIconUrl: function (name) { - var key = name + 'Url'; - - if (this.options[key]) { - return this.options[key]; - } - - if (L.Browser.retina && name === 'icon') { - name += '-2x'; - } - - var path = L.Icon.Default.imagePath; - - if (!path) { - throw new Error('Couldn\'t autodetect L.Icon.Default.imagePath, set it manually.'); - } - - return path + '/marker-' + name + '.png'; - } -}); - -L.Icon.Default.imagePath = (function () { - var scripts = document.getElementsByTagName('script'), - leafletRe = /[\/^]leaflet[\-\._]?([\w\-\._]*)\.js\??/; - - var i, len, src, matches, path; - - for (i = 0, len = scripts.length; i < len; i++) { - src = scripts[i].src; - matches = src.match(leafletRe); - - if (matches) { - path = src.split(leafletRe)[0]; - return (path ? path + '/' : '') + 'images'; - } - } -}()); - - -/* - * L.Marker is used to display clickable/draggable icons on the map. - */ - -L.Marker = L.Class.extend({ - - includes: L.Mixin.Events, - - options: { - icon: new L.Icon.Default(), - title: '', - clickable: true, - draggable: false, - zIndexOffset: 0, - opacity: 1, - riseOnHover: false, - riseOffset: 250 - }, - - initialize: function (latlng, options) { - L.setOptions(this, options); - this._latlng = L.latLng(latlng); - }, - - onAdd: function (map) { - this._map = map; - - map.on('viewreset', this.update, this); - - this._initIcon(); - this.update(); - - if (map.options.zoomAnimation && map.options.markerZoomAnimation) { - map.on('zoomanim', this._animateZoom, this); - } - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - onRemove: function (map) { - if (this.dragging) { - this.dragging.disable(); - } - - this._removeIcon(); - - this.fire('remove'); - - map.off({ - 'viewreset': this.update, - 'zoomanim': this._animateZoom - }, this); - - this._map = null; - }, - - getLatLng: function () { - return this._latlng; - }, - - setLatLng: function (latlng) { - this._latlng = L.latLng(latlng); - - this.update(); - - return this.fire('move', { latlng: this._latlng }); - }, - - setZIndexOffset: function (offset) { - this.options.zIndexOffset = offset; - this.update(); - - return this; - }, - - setIcon: function (icon) { - - this.options.icon = icon; - - if (this._map) { - this._initIcon(); - this.update(); - } - - return this; - }, - - update: function () { - if (this._icon) { - var pos = this._map.latLngToLayerPoint(this._latlng).round(); - this._setPos(pos); - } - - return this; - }, - - _initIcon: function () { - var options = this.options, - map = this._map, - animation = (map.options.zoomAnimation && map.options.markerZoomAnimation), - classToAdd = animation ? 'leaflet-zoom-animated' : 'leaflet-zoom-hide', - needOpacityUpdate = false; - - var reuseIcon = this._icon; - if (!reuseIcon) { - this._icon = options.icon.createIcon(); - } else { - var newIcon = options.icon.createIcon(this._icon); - - //If the icon isn't being reused, remove the old one - if (newIcon !== this._icon) { - this._removeIcon(); - - this._icon = newIcon; - reuseIcon = false; - } - } - - if (options.title) { - this._icon.title = options.title; - } - - this._initInteraction(); - needOpacityUpdate = (options.opacity < 1); - - L.DomUtil.addClass(this._icon, classToAdd); - - if (options.riseOnHover) { - L.DomEvent - .on(this._icon, 'mouseover', this._bringToFront, this) - .on(this._icon, 'mouseout', this._resetZIndex, this); - } - - var reuseShadow = this._shadow; - if (!reuseShadow) { - this._shadow = options.icon.createShadow(); - - if (this._shadow) { - L.DomUtil.addClass(this._shadow, classToAdd); - needOpacityUpdate = (options.opacity < 1); - } - } else { - this._shadow = options.icon.createShadow(this._shadow); - } - - if (needOpacityUpdate) { - this._updateOpacity(); - } - - var panes = this._map._panes; - - if (!reuseIcon) { - panes.markerPane.appendChild(this._icon); - } - - if (this._shadow && !reuseShadow) { - panes.shadowPane.appendChild(this._shadow); - } - }, - - _removeIcon: function () { - var panes = this._map._panes; - - if (this.options.riseOnHover) { - L.DomEvent - .off(this._icon, 'mouseover', this._bringToFront) - .off(this._icon, 'mouseout', this._resetZIndex); - } - - panes.markerPane.removeChild(this._icon); - - if (this._shadow) { - panes.shadowPane.removeChild(this._shadow); - } - - this._icon = this._shadow = null; - }, - - _setPos: function (pos) { - L.DomUtil.setPosition(this._icon, pos); - - if (this._shadow) { - L.DomUtil.setPosition(this._shadow, pos); - } - - this._zIndex = pos.y + this.options.zIndexOffset; - - this._resetZIndex(); - }, - - _updateZIndex: function (offset) { - this._icon.style.zIndex = this._zIndex + offset; - }, - - _animateZoom: function (opt) { - var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center); - - this._setPos(pos); - }, - - _initInteraction: function () { - - if (!this.options.clickable) { return; } - - // TODO refactor into something shared with Map/Path/etc. to DRY it up - - var icon = this._icon, - events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu']; - - L.DomUtil.addClass(icon, 'leaflet-clickable'); - L.DomEvent.on(icon, 'click', this._onMouseClick, this); - - for (var i = 0; i < events.length; i++) { - L.DomEvent.on(icon, events[i], this._fireMouseEvent, this); - } - - if (L.Handler.MarkerDrag) { - this.dragging = new L.Handler.MarkerDrag(this); - - if (this.options.draggable) { - this.dragging.enable(); - } - } - }, - - _onMouseClick: function (e) { - var wasDragged = this.dragging && this.dragging.moved(); - - if (this.hasEventListeners(e.type) || wasDragged) { - L.DomEvent.stopPropagation(e); - } - - if (wasDragged) { return; } - - if ((!this.dragging || !this.dragging._enabled) && this._map.dragging && this._map.dragging.moved()) { return; } - - this.fire(e.type, { - originalEvent: e, - latlng: this._latlng - }); - }, - - _fireMouseEvent: function (e) { - - this.fire(e.type, { - originalEvent: e, - latlng: this._latlng - }); - - // TODO proper custom event propagation - // this line will always be called if marker is in a FeatureGroup - if (e.type === 'contextmenu' && this.hasEventListeners(e.type)) { - L.DomEvent.preventDefault(e); - } - if (e.type !== 'mousedown') { - L.DomEvent.stopPropagation(e); - } - }, - - setOpacity: function (opacity) { - this.options.opacity = opacity; - if (this._map) { - this._updateOpacity(); - } - }, - - _updateOpacity: function () { - L.DomUtil.setOpacity(this._icon, this.options.opacity); - if (this._shadow) { - L.DomUtil.setOpacity(this._shadow, this.options.opacity); - } - }, - - _bringToFront: function () { - this._updateZIndex(this.options.riseOffset); - }, - - _resetZIndex: function () { - this._updateZIndex(0); - } -}); - -L.marker = function (latlng, options) { - return new L.Marker(latlng, options); -}; - - -/* - * L.DivIcon is a lightweight HTML-based icon class (as opposed to the image-based L.Icon) - * to use with L.Marker. - */ - -L.DivIcon = L.Icon.extend({ - options: { - iconSize: [12, 12], // also can be set through CSS - /* - iconAnchor: (Point) - popupAnchor: (Point) - html: (String) - bgPos: (Point) - */ - className: 'leaflet-div-icon', - html: false - }, - - createIcon: function (oldIcon) { - var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'), - options = this.options; - - if (options.html !== false) { - div.innerHTML = options.html; - } else { - div.innerHTML = ''; - } - - if (options.bgPos) { - div.style.backgroundPosition = - (-options.bgPos.x) + 'px ' + (-options.bgPos.y) + 'px'; - } - - this._setIconStyles(div, 'icon'); - return div; - }, - - createShadow: function () { - return null; - } -}); - -L.divIcon = function (options) { - return new L.DivIcon(options); -}; - - -/* - * L.Popup is used for displaying popups on the map. - */ - -L.Map.mergeOptions({ - closePopupOnClick: true -}); - -L.Popup = L.Class.extend({ - includes: L.Mixin.Events, - - options: { - minWidth: 50, - maxWidth: 300, - maxHeight: null, - autoPan: true, - closeButton: true, - offset: [0, 7], - autoPanPadding: [5, 5], - keepInView: false, - className: '', - zoomAnimation: true - }, - - initialize: function (options, source) { - L.setOptions(this, options); - - this._source = source; - this._animated = L.Browser.any3d && this.options.zoomAnimation; - }, - - onAdd: function (map) { - this._map = map; - - if (!this._container) { - this._initLayout(); - } - this._updateContent(); - - var animFade = map.options.fadeAnimation; - - if (animFade) { - L.DomUtil.setOpacity(this._container, 0); - } - map._panes.popupPane.appendChild(this._container); - - map.on(this._getEvents(), this); - - this._update(); - - if (animFade) { - L.DomUtil.setOpacity(this._container, 1); - } - - this.fire('open'); - - map.fire('popupopen', {popup: this}); - - if (this._source) { - this._source.fire('popupopen', {popup: this}); - } - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - openOn: function (map) { - map.openPopup(this); - return this; - }, - - onRemove: function (map) { - map._panes.popupPane.removeChild(this._container); - - L.Util.falseFn(this._container.offsetWidth); // force reflow - - map.off(this._getEvents(), this); - - if (map.options.fadeAnimation) { - L.DomUtil.setOpacity(this._container, 0); - } - - this._map = null; - - this.fire('close'); - - map.fire('popupclose', {popup: this}); - - if (this._source) { - this._source.fire('popupclose', {popup: this}); - } - }, - - setLatLng: function (latlng) { - this._latlng = L.latLng(latlng); - this._update(); - return this; - }, - - setContent: function (content) { - this._content = content; - this._update(); - return this; - }, - - _getEvents: function () { - var events = { - viewreset: this._updatePosition - }; - - if (this._animated) { - events.zoomanim = this._zoomAnimation; - } - if ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) { - events.preclick = this._close; - } - if (this.options.keepInView) { - events.moveend = this._adjustPan; - } - - return events; - }, - - _close: function () { - if (this._map) { - this._map.closePopup(this); - } - }, - - _initLayout: function () { - var prefix = 'leaflet-popup', - containerClass = prefix + ' ' + this.options.className + ' leaflet-zoom-' + - (this._animated ? 'animated' : 'hide'), - container = this._container = L.DomUtil.create('div', containerClass), - closeButton; - - if (this.options.closeButton) { - closeButton = this._closeButton = - L.DomUtil.create('a', prefix + '-close-button', container); - closeButton.href = '#close'; - closeButton.innerHTML = '×'; - L.DomEvent.disableClickPropagation(closeButton); - - L.DomEvent.on(closeButton, 'click', this._onCloseButtonClick, this); - } - - var wrapper = this._wrapper = - L.DomUtil.create('div', prefix + '-content-wrapper', container); - L.DomEvent.disableClickPropagation(wrapper); - - this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper); - L.DomEvent.on(this._contentNode, 'mousewheel', L.DomEvent.stopPropagation); - L.DomEvent.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation); - this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container); - this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer); - }, - - _update: function () { - if (!this._map) { return; } - - this._container.style.visibility = 'hidden'; - - this._updateContent(); - this._updateLayout(); - this._updatePosition(); - - this._container.style.visibility = ''; - - this._adjustPan(); - }, - - _updateContent: function () { - if (!this._content) { return; } - - if (typeof this._content === 'string') { - this._contentNode.innerHTML = this._content; - } else { - while (this._contentNode.hasChildNodes()) { - this._contentNode.removeChild(this._contentNode.firstChild); - } - this._contentNode.appendChild(this._content); - } - this.fire('contentupdate'); - }, - - _updateLayout: function () { - var container = this._contentNode, - style = container.style; - - style.width = ''; - style.whiteSpace = 'nowrap'; - - var width = container.offsetWidth; - width = Math.min(width, this.options.maxWidth); - width = Math.max(width, this.options.minWidth); - - style.width = (width + 1) + 'px'; - style.whiteSpace = ''; - - style.height = ''; - - var height = container.offsetHeight, - maxHeight = this.options.maxHeight, - scrolledClass = 'leaflet-popup-scrolled'; - - if (maxHeight && height > maxHeight) { - style.height = maxHeight + 'px'; - L.DomUtil.addClass(container, scrolledClass); - } else { - L.DomUtil.removeClass(container, scrolledClass); - } - - this._containerWidth = this._container.offsetWidth; - }, - - _updatePosition: function () { - if (!this._map) { return; } - - var pos = this._map.latLngToLayerPoint(this._latlng), - animated = this._animated, - offset = L.point(this.options.offset); - - if (animated) { - L.DomUtil.setPosition(this._container, pos); - } - - this._containerBottom = -offset.y - (animated ? 0 : pos.y); - this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x + (animated ? 0 : pos.x); - - // bottom position the popup in case the height of the popup changes (images loading etc) - this._container.style.bottom = this._containerBottom + 'px'; - this._container.style.left = this._containerLeft + 'px'; - }, - - _zoomAnimation: function (opt) { - var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center); - - L.DomUtil.setPosition(this._container, pos); - }, - - _adjustPan: function () { - if (!this.options.autoPan) { return; } - - var map = this._map, - containerHeight = this._container.offsetHeight, - containerWidth = this._containerWidth, - - layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom); - - if (this._animated) { - layerPos._add(L.DomUtil.getPosition(this._container)); - } - - var containerPos = map.layerPointToContainerPoint(layerPos), - padding = L.point(this.options.autoPanPadding), - size = map.getSize(), - dx = 0, - dy = 0; - - if (containerPos.x + containerWidth > size.x) { // right - dx = containerPos.x + containerWidth - size.x + padding.x; - } - if (containerPos.x - dx < 0) { // left - dx = containerPos.x - padding.x; - } - if (containerPos.y + containerHeight > size.y) { // bottom - dy = containerPos.y + containerHeight - size.y + padding.y; - } - if (containerPos.y - dy < 0) { // top - dy = containerPos.y - padding.y; - } - - if (dx || dy) { - map - .fire('autopanstart') - .panBy([dx, dy]); - } - }, - - _onCloseButtonClick: function (e) { - this._close(); - L.DomEvent.stop(e); - } -}); - -L.popup = function (options, source) { - return new L.Popup(options, source); -}; - - -L.Map.include({ - openPopup: function (popup, latlng, options) { // (Popup) or (String || HTMLElement, LatLng[, Object]) - this.closePopup(); - - if (!(popup instanceof L.Popup)) { - var content = popup; - - popup = new L.Popup(options) - .setLatLng(latlng) - .setContent(content); - } - - this._popup = popup; - return this.addLayer(popup); - }, - - closePopup: function (popup) { - if (!popup || popup === this._popup) { - popup = this._popup; - this._popup = null; - } - if (popup) { - this.removeLayer(popup); - } - return this; - } -}); - - -/* - * Popup extension to L.Marker, adding popup-related methods. - */ - -L.Marker.include({ - openPopup: function () { - if (this._popup && this._map && !this._map.hasLayer(this._popup)) { - this._popup.setLatLng(this._latlng); - this._map.openPopup(this._popup); - } - - return this; - }, - - closePopup: function () { - if (this._popup) { - this._popup._close(); - } - return this; - }, - - bindPopup: function (content, options) { - var anchor = L.point(this.options.icon.options.popupAnchor || [0, 0]); - - anchor = anchor.add(L.Popup.prototype.options.offset); - - if (options && options.offset) { - anchor = anchor.add(options.offset); - } - - options = L.extend({offset: anchor}, options); - - if (!this._popup) { - this - .on('click', this.openPopup, this) - .on('remove', this.closePopup, this) - .on('move', this._movePopup, this); - } - - if (content instanceof L.Popup) { - L.setOptions(content, options); - this._popup = content; - } else { - this._popup = new L.Popup(options, this) - .setContent(content); - } - - return this; - }, - - setPopupContent: function (content) { - if (this._popup) { - this._popup.setContent(content); - } - return this; - }, - - unbindPopup: function () { - if (this._popup) { - this._popup = null; - this - .off('click', this.openPopup) - .off('remove', this.closePopup) - .off('move', this._movePopup); - } - return this; - }, - - _movePopup: function (e) { - this._popup.setLatLng(e.latlng); - } -}); - - -/* - * L.LayerGroup is a class to combine several layers into one so that - * you can manipulate the group (e.g. add/remove it) as one layer. - */ - -L.LayerGroup = L.Class.extend({ - initialize: function (layers) { - this._layers = {}; - - var i, len; - - if (layers) { - for (i = 0, len = layers.length; i < len; i++) { - this.addLayer(layers[i]); - } - } - }, - - addLayer: function (layer) { - var id = this.getLayerId(layer); - - this._layers[id] = layer; - - if (this._map) { - this._map.addLayer(layer); - } - - return this; - }, - - removeLayer: function (layer) { - var id = layer in this._layers ? layer : this.getLayerId(layer); - - if (this._map && this._layers[id]) { - this._map.removeLayer(this._layers[id]); - } - - delete this._layers[id]; - - return this; - }, - - hasLayer: function (layer) { - if (!layer) { return false; } - - return (layer in this._layers || this.getLayerId(layer) in this._layers); - }, - - clearLayers: function () { - this.eachLayer(this.removeLayer, this); - return this; - }, - - invoke: function (methodName) { - var args = Array.prototype.slice.call(arguments, 1), - i, layer; - - for (i in this._layers) { - layer = this._layers[i]; - - if (layer[methodName]) { - layer[methodName].apply(layer, args); - } - } - - return this; - }, - - onAdd: function (map) { - this._map = map; - this.eachLayer(map.addLayer, map); - }, - - onRemove: function (map) { - this.eachLayer(map.removeLayer, map); - this._map = null; - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - eachLayer: function (method, context) { - for (var i in this._layers) { - method.call(context, this._layers[i]); - } - return this; - }, - - getLayer: function (id) { - return this._layers[id]; - }, - - getLayers: function () { - var layers = []; - - for (var i in this._layers) { - layers.push(this._layers[i]); - } - return layers; - }, - - setZIndex: function (zIndex) { - return this.invoke('setZIndex', zIndex); - }, - - getLayerId: function (layer) { - return L.stamp(layer); - } -}); - -L.layerGroup = function (layers) { - return new L.LayerGroup(layers); -}; - - -/* - * L.FeatureGroup extends L.LayerGroup by introducing mouse events and additional methods - * shared between a group of interactive layers (like vectors or markers). - */ - -L.FeatureGroup = L.LayerGroup.extend({ - includes: L.Mixin.Events, - - statics: { - EVENTS: 'click dblclick mouseover mouseout mousemove contextmenu' - }, - - addLayer: function (layer) { - if (this.hasLayer(layer)) { - return this; - } - - layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this); - - L.LayerGroup.prototype.addLayer.call(this, layer); - - if (this._popupContent && layer.bindPopup) { - layer.bindPopup(this._popupContent, this._popupOptions); - } - - return this.fire('layeradd', {layer: layer}); - }, - - removeLayer: function (layer) { - if (layer in this._layers) { - layer = this._layers[layer]; - } - - layer.off(L.FeatureGroup.EVENTS, this._propagateEvent, this); - - L.LayerGroup.prototype.removeLayer.call(this, layer); - - if (this._popupContent) { - this.invoke('unbindPopup'); - } - - return this.fire('layerremove', {layer: layer}); - }, - - bindPopup: function (content, options) { - this._popupContent = content; - this._popupOptions = options; - return this.invoke('bindPopup', content, options); - }, - - setStyle: function (style) { - return this.invoke('setStyle', style); - }, - - bringToFront: function () { - return this.invoke('bringToFront'); - }, - - bringToBack: function () { - return this.invoke('bringToBack'); - }, - - getBounds: function () { - var bounds = new L.LatLngBounds(); - - this.eachLayer(function (layer) { - bounds.extend(layer instanceof L.Marker ? layer.getLatLng() : layer.getBounds()); - }); - - return bounds; - }, - - _propagateEvent: function (e) { - if (!e.layer) { - e.layer = e.target; - } - e.target = this; - - this.fire(e.type, e); - } -}); - -L.featureGroup = function (layers) { - return new L.FeatureGroup(layers); -}; - - -/* - * L.Path is a base class for rendering vector paths on a map. Inherited by Polyline, Circle, etc. - */ - -L.Path = L.Class.extend({ - includes: [L.Mixin.Events], - - statics: { - // how much to extend the clip area around the map view - // (relative to its size, e.g. 0.5 is half the screen in each direction) - // set it so that SVG element doesn't exceed 1280px (vectors flicker on dragend if it is) - CLIP_PADDING: L.Browser.mobile ? - Math.max(0, Math.min(0.5, - (1280 / Math.max(window.innerWidth, window.innerHeight) - 1) / 2)) : 0.5 - }, - - options: { - stroke: true, - color: '#0033ff', - dashArray: null, - weight: 5, - opacity: 0.5, - - fill: false, - fillColor: null, //same as color by default - fillOpacity: 0.2, - - clickable: true - }, - - initialize: function (options) { - L.setOptions(this, options); - }, - - onAdd: function (map) { - this._map = map; - - if (!this._container) { - this._initElements(); - this._initEvents(); - } - - this.projectLatlngs(); - this._updatePath(); - - if (this._container) { - this._map._pathRoot.appendChild(this._container); - } - - this.fire('add'); - - map.on({ - 'viewreset': this.projectLatlngs, - 'moveend': this._updatePath - }, this); - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - onRemove: function (map) { - map._pathRoot.removeChild(this._container); - - // Need to fire remove event before we set _map to null as the event hooks might need the object - this.fire('remove'); - this._map = null; - - if (L.Browser.vml) { - this._container = null; - this._stroke = null; - this._fill = null; - } - - map.off({ - 'viewreset': this.projectLatlngs, - 'moveend': this._updatePath - }, this); - }, - - projectLatlngs: function () { - // do all projection stuff here - }, - - setStyle: function (style) { - L.setOptions(this, style); - - if (this._container) { - this._updateStyle(); - } - - return this; - }, - - redraw: function () { - if (this._map) { - this.projectLatlngs(); - this._updatePath(); - } - return this; - } -}); - -L.Map.include({ - _updatePathViewport: function () { - var p = L.Path.CLIP_PADDING, - size = this.getSize(), - panePos = L.DomUtil.getPosition(this._mapPane), - min = panePos.multiplyBy(-1)._subtract(size.multiplyBy(p)._round()), - max = min.add(size.multiplyBy(1 + p * 2)._round()); - - this._pathViewport = new L.Bounds(min, max); - } -}); - - -/* - * Extends L.Path with SVG-specific rendering code. - */ - -L.Path.SVG_NS = 'http://www.w3.org/2000/svg'; - -L.Browser.svg = !!(document.createElementNS && document.createElementNS(L.Path.SVG_NS, 'svg').createSVGRect); - -L.Path = L.Path.extend({ - statics: { - SVG: L.Browser.svg - }, - - bringToFront: function () { - var root = this._map._pathRoot, - path = this._container; - - if (path && root.lastChild !== path) { - root.appendChild(path); - } - return this; - }, - - bringToBack: function () { - var root = this._map._pathRoot, - path = this._container, - first = root.firstChild; - - if (path && first !== path) { - root.insertBefore(path, first); - } - return this; - }, - - getPathString: function () { - // form path string here - }, - - _createElement: function (name) { - return document.createElementNS(L.Path.SVG_NS, name); - }, - - _initElements: function () { - this._map._initPathRoot(); - this._initPath(); - this._initStyle(); - }, - - _initPath: function () { - this._container = this._createElement('g'); - - this._path = this._createElement('path'); - this._container.appendChild(this._path); - }, - - _initStyle: function () { - if (this.options.stroke) { - this._path.setAttribute('stroke-linejoin', 'round'); - this._path.setAttribute('stroke-linecap', 'round'); - } - if (this.options.fill) { - this._path.setAttribute('fill-rule', 'evenodd'); - } - if (this.options.pointerEvents) { - this._path.setAttribute('pointer-events', this.options.pointerEvents); - } - if (!this.options.clickable && !this.options.pointerEvents) { - this._path.setAttribute('pointer-events', 'none'); - } - this._updateStyle(); - }, - - _updateStyle: function () { - if (this.options.stroke) { - this._path.setAttribute('stroke', this.options.color); - this._path.setAttribute('stroke-opacity', this.options.opacity); - this._path.setAttribute('stroke-width', this.options.weight); - if (this.options.dashArray) { - this._path.setAttribute('stroke-dasharray', this.options.dashArray); - } else { - this._path.removeAttribute('stroke-dasharray'); - } - } else { - this._path.setAttribute('stroke', 'none'); - } - if (this.options.fill) { - this._path.setAttribute('fill', this.options.fillColor || this.options.color); - this._path.setAttribute('fill-opacity', this.options.fillOpacity); - } else { - this._path.setAttribute('fill', 'none'); - } - }, - - _updatePath: function () { - var str = this.getPathString(); - if (!str) { - // fix webkit empty string parsing bug - str = 'M0 0'; - } - this._path.setAttribute('d', str); - }, - - // TODO remove duplication with L.Map - _initEvents: function () { - if (this.options.clickable) { - if (L.Browser.svg || !L.Browser.vml) { - this._path.setAttribute('class', 'leaflet-clickable'); - } - - L.DomEvent.on(this._container, 'click', this._onMouseClick, this); - - var events = ['dblclick', 'mousedown', 'mouseover', - 'mouseout', 'mousemove', 'contextmenu']; - for (var i = 0; i < events.length; i++) { - L.DomEvent.on(this._container, events[i], this._fireMouseEvent, this); - } - } - }, - - _onMouseClick: function (e) { - if (this._map.dragging && this._map.dragging.moved()) { return; } - - this._fireMouseEvent(e); - }, - - _fireMouseEvent: function (e) { - if (!this.hasEventListeners(e.type)) { return; } - - var map = this._map, - containerPoint = map.mouseEventToContainerPoint(e), - layerPoint = map.containerPointToLayerPoint(containerPoint), - latlng = map.layerPointToLatLng(layerPoint); - - this.fire(e.type, { - latlng: latlng, - layerPoint: layerPoint, - containerPoint: containerPoint, - originalEvent: e - }); - - if (e.type === 'contextmenu') { - L.DomEvent.preventDefault(e); - } - if (e.type !== 'mousemove') { - L.DomEvent.stopPropagation(e); - } - } -}); - -L.Map.include({ - _initPathRoot: function () { - if (!this._pathRoot) { - this._pathRoot = L.Path.prototype._createElement('svg'); - this._panes.overlayPane.appendChild(this._pathRoot); - - if (this.options.zoomAnimation && L.Browser.any3d) { - this._pathRoot.setAttribute('class', ' leaflet-zoom-animated'); - - this.on({ - 'zoomanim': this._animatePathZoom, - 'zoomend': this._endPathZoom - }); - } else { - this._pathRoot.setAttribute('class', ' leaflet-zoom-hide'); - } - - this.on('moveend', this._updateSvgViewport); - this._updateSvgViewport(); - } - }, - - _animatePathZoom: function (e) { - var scale = this.getZoomScale(e.zoom), - offset = this._getCenterOffset(e.center)._multiplyBy(-scale)._add(this._pathViewport.min); - - this._pathRoot.style[L.DomUtil.TRANSFORM] = - L.DomUtil.getTranslateString(offset) + ' scale(' + scale + ') '; - - this._pathZooming = true; - }, - - _endPathZoom: function () { - this._pathZooming = false; - }, - - _updateSvgViewport: function () { - - if (this._pathZooming) { - // Do not update SVGs while a zoom animation is going on otherwise the animation will break. - // When the zoom animation ends we will be updated again anyway - // This fixes the case where you do a momentum move and zoom while the move is still ongoing. - return; - } - - this._updatePathViewport(); - - var vp = this._pathViewport, - min = vp.min, - max = vp.max, - width = max.x - min.x, - height = max.y - min.y, - root = this._pathRoot, - pane = this._panes.overlayPane; - - // Hack to make flicker on drag end on mobile webkit less irritating - if (L.Browser.mobileWebkit) { - pane.removeChild(root); - } - - L.DomUtil.setPosition(root, min); - root.setAttribute('width', width); - root.setAttribute('height', height); - root.setAttribute('viewBox', [min.x, min.y, width, height].join(' ')); - - if (L.Browser.mobileWebkit) { - pane.appendChild(root); - } - } -}); - - -/* - * Popup extension to L.Path (polylines, polygons, circles), adding popup-related methods. - */ - -L.Path.include({ - - bindPopup: function (content, options) { - - if (content instanceof L.Popup) { - this._popup = content; - } else { - if (!this._popup || options) { - this._popup = new L.Popup(options, this); - } - this._popup.setContent(content); - } - - if (!this._popupHandlersAdded) { - this - .on('click', this._openPopup, this) - .on('remove', this.closePopup, this); - - this._popupHandlersAdded = true; - } - - return this; - }, - - unbindPopup: function () { - if (this._popup) { - this._popup = null; - this - .off('click', this._openPopup) - .off('remove', this.closePopup); - - this._popupHandlersAdded = false; - } - return this; - }, - - openPopup: function (latlng) { - - if (this._popup) { - // open the popup from one of the path's points if not specified - latlng = latlng || this._latlng || - this._latlngs[Math.floor(this._latlngs.length / 2)]; - - this._openPopup({latlng: latlng}); - } - - return this; - }, - - closePopup: function () { - if (this._popup) { - this._popup._close(); - } - return this; - }, - - _openPopup: function (e) { - this._popup.setLatLng(e.latlng); - this._map.openPopup(this._popup); - } -}); - - -/* - * Vector rendering for IE6-8 through VML. - * Thanks to Dmitry Baranovsky and his Raphael library for inspiration! - */ - -L.Browser.vml = !L.Browser.svg && (function () { - try { - var div = document.createElement('div'); - div.innerHTML = ''; - - var shape = div.firstChild; - shape.style.behavior = 'url(#default#VML)'; - - return shape && (typeof shape.adj === 'object'); - - } catch (e) { - return false; - } -}()); - -L.Path = L.Browser.svg || !L.Browser.vml ? L.Path : L.Path.extend({ - statics: { - VML: true, - CLIP_PADDING: 0.02 - }, - - _createElement: (function () { - try { - document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml'); - return function (name) { - return document.createElement(''); - }; - } catch (e) { - return function (name) { - return document.createElement( - '<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">'); - }; - } - }()), - - _initPath: function () { - var container = this._container = this._createElement('shape'); - L.DomUtil.addClass(container, 'leaflet-vml-shape'); - if (this.options.clickable) { - L.DomUtil.addClass(container, 'leaflet-clickable'); - } - container.coordsize = '1 1'; - - this._path = this._createElement('path'); - container.appendChild(this._path); - - this._map._pathRoot.appendChild(container); - }, - - _initStyle: function () { - this._updateStyle(); - }, - - _updateStyle: function () { - var stroke = this._stroke, - fill = this._fill, - options = this.options, - container = this._container; - - container.stroked = options.stroke; - container.filled = options.fill; - - if (options.stroke) { - if (!stroke) { - stroke = this._stroke = this._createElement('stroke'); - stroke.endcap = 'round'; - container.appendChild(stroke); - } - stroke.weight = options.weight + 'px'; - stroke.color = options.color; - stroke.opacity = options.opacity; - - if (options.dashArray) { - stroke.dashStyle = options.dashArray instanceof Array ? - options.dashArray.join(' ') : - options.dashArray.replace(/( *, *)/g, ' '); - } else { - stroke.dashStyle = ''; - } - - } else if (stroke) { - container.removeChild(stroke); - this._stroke = null; - } - - if (options.fill) { - if (!fill) { - fill = this._fill = this._createElement('fill'); - container.appendChild(fill); - } - fill.color = options.fillColor || options.color; - fill.opacity = options.fillOpacity; - - } else if (fill) { - container.removeChild(fill); - this._fill = null; - } - }, - - _updatePath: function () { - var style = this._container.style; - - style.display = 'none'; - this._path.v = this.getPathString() + ' '; // the space fixes IE empty path string bug - style.display = ''; - } -}); - -L.Map.include(L.Browser.svg || !L.Browser.vml ? {} : { - _initPathRoot: function () { - if (this._pathRoot) { return; } - - var root = this._pathRoot = document.createElement('div'); - root.className = 'leaflet-vml-container'; - this._panes.overlayPane.appendChild(root); - - this.on('moveend', this._updatePathViewport); - this._updatePathViewport(); - } -}); - - -/* - * Vector rendering for all browsers that support canvas. - */ - -L.Browser.canvas = (function () { - return !!document.createElement('canvas').getContext; -}()); - -L.Path = (L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? L.Path : L.Path.extend({ - statics: { - //CLIP_PADDING: 0.02, // not sure if there's a need to set it to a small value - CANVAS: true, - SVG: false - }, - - redraw: function () { - if (this._map) { - this.projectLatlngs(); - this._requestUpdate(); - } - return this; - }, - - setStyle: function (style) { - L.setOptions(this, style); - - if (this._map) { - this._updateStyle(); - this._requestUpdate(); - } - return this; - }, - - onRemove: function (map) { - map - .off('viewreset', this.projectLatlngs, this) - .off('moveend', this._updatePath, this); - - if (this.options.clickable) { - this._map.off('click', this._onClick, this); - this._map.off('mousemove', this._onMouseMove, this); - } - - this._requestUpdate(); - - this._map = null; - }, - - _requestUpdate: function () { - if (this._map && !L.Path._updateRequest) { - L.Path._updateRequest = L.Util.requestAnimFrame(this._fireMapMoveEnd, this._map); - } - }, - - _fireMapMoveEnd: function () { - L.Path._updateRequest = null; - this.fire('moveend'); - }, - - _initElements: function () { - this._map._initPathRoot(); - this._ctx = this._map._canvasCtx; - }, - - _updateStyle: function () { - var options = this.options; - - if (options.stroke) { - this._ctx.lineWidth = options.weight; - this._ctx.strokeStyle = options.color; - } - if (options.fill) { - this._ctx.fillStyle = options.fillColor || options.color; - } - }, - - _drawPath: function () { - var i, j, len, len2, point, drawMethod; - - this._ctx.beginPath(); - - for (i = 0, len = this._parts.length; i < len; i++) { - for (j = 0, len2 = this._parts[i].length; j < len2; j++) { - point = this._parts[i][j]; - drawMethod = (j === 0 ? 'move' : 'line') + 'To'; - - this._ctx[drawMethod](point.x, point.y); - } - // TODO refactor ugly hack - if (this instanceof L.Polygon) { - this._ctx.closePath(); - } - } - }, - - _checkIfEmpty: function () { - return !this._parts.length; - }, - - _updatePath: function () { - if (this._checkIfEmpty()) { return; } - - var ctx = this._ctx, - options = this.options; - - this._drawPath(); - ctx.save(); - this._updateStyle(); - - if (options.fill) { - ctx.globalAlpha = options.fillOpacity; - ctx.fill(); - } - - if (options.stroke) { - ctx.globalAlpha = options.opacity; - ctx.stroke(); - } - - ctx.restore(); - - // TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature - }, - - _initEvents: function () { - if (this.options.clickable) { - // TODO dblclick - this._map.on('mousemove', this._onMouseMove, this); - this._map.on('click', this._onClick, this); - } - }, - - _onClick: function (e) { - if (this._containsPoint(e.layerPoint)) { - this.fire('click', e); - } - }, - - _onMouseMove: function (e) { - if (!this._map || this._map._animatingZoom) { return; } - - // TODO don't do on each move - if (this._containsPoint(e.layerPoint)) { - this._ctx.canvas.style.cursor = 'pointer'; - this._mouseInside = true; - this.fire('mouseover', e); - - } else if (this._mouseInside) { - this._ctx.canvas.style.cursor = ''; - this._mouseInside = false; - this.fire('mouseout', e); - } - } -}); - -L.Map.include((L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? {} : { - _initPathRoot: function () { - var root = this._pathRoot, - ctx; - - if (!root) { - root = this._pathRoot = document.createElement('canvas'); - root.style.position = 'absolute'; - ctx = this._canvasCtx = root.getContext('2d'); - - ctx.lineCap = 'round'; - ctx.lineJoin = 'round'; - - this._panes.overlayPane.appendChild(root); - - if (this.options.zoomAnimation) { - this._pathRoot.className = 'leaflet-zoom-animated'; - this.on('zoomanim', this._animatePathZoom); - this.on('zoomend', this._endPathZoom); - } - this.on('moveend', this._updateCanvasViewport); - this._updateCanvasViewport(); - } - }, - - _updateCanvasViewport: function () { - // don't redraw while zooming. See _updateSvgViewport for more details - if (this._pathZooming) { return; } - this._updatePathViewport(); - - var vp = this._pathViewport, - min = vp.min, - size = vp.max.subtract(min), - root = this._pathRoot; - - //TODO check if this works properly on mobile webkit - L.DomUtil.setPosition(root, min); - root.width = size.x; - root.height = size.y; - root.getContext('2d').translate(-min.x, -min.y); - } -}); - - -/* - * L.LineUtil contains different utility functions for line segments - * and polylines (clipping, simplification, distances, etc.) - */ - -/*jshint bitwise:false */ // allow bitwise oprations for this file - -L.LineUtil = { - - // Simplify polyline with vertex reduction and Douglas-Peucker simplification. - // Improves rendering performance dramatically by lessening the number of points to draw. - - simplify: function (/*Point[]*/ points, /*Number*/ tolerance) { - if (!tolerance || !points.length) { - return points.slice(); - } - - var sqTolerance = tolerance * tolerance; - - // stage 1: vertex reduction - points = this._reducePoints(points, sqTolerance); - - // stage 2: Douglas-Peucker simplification - points = this._simplifyDP(points, sqTolerance); - - return points; - }, - - // distance from a point to a segment between two points - pointToSegmentDistance: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { - return Math.sqrt(this._sqClosestPointOnSegment(p, p1, p2, true)); - }, - - closestPointOnSegment: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { - return this._sqClosestPointOnSegment(p, p1, p2); - }, - - // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm - _simplifyDP: function (points, sqTolerance) { - - var len = points.length, - ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array, - markers = new ArrayConstructor(len); - - markers[0] = markers[len - 1] = 1; - - this._simplifyDPStep(points, markers, sqTolerance, 0, len - 1); - - var i, - newPoints = []; - - for (i = 0; i < len; i++) { - if (markers[i]) { - newPoints.push(points[i]); - } - } - - return newPoints; - }, - - _simplifyDPStep: function (points, markers, sqTolerance, first, last) { - - var maxSqDist = 0, - index, i, sqDist; - - for (i = first + 1; i <= last - 1; i++) { - sqDist = this._sqClosestPointOnSegment(points[i], points[first], points[last], true); - - if (sqDist > maxSqDist) { - index = i; - maxSqDist = sqDist; - } - } - - if (maxSqDist > sqTolerance) { - markers[index] = 1; - - this._simplifyDPStep(points, markers, sqTolerance, first, index); - this._simplifyDPStep(points, markers, sqTolerance, index, last); - } - }, - - // reduce points that are too close to each other to a single point - _reducePoints: function (points, sqTolerance) { - var reducedPoints = [points[0]]; - - for (var i = 1, prev = 0, len = points.length; i < len; i++) { - if (this._sqDist(points[i], points[prev]) > sqTolerance) { - reducedPoints.push(points[i]); - prev = i; - } - } - if (prev < len - 1) { - reducedPoints.push(points[len - 1]); - } - return reducedPoints; - }, - - // Cohen-Sutherland line clipping algorithm. - // Used to avoid rendering parts of a polyline that are not currently visible. - - clipSegment: function (a, b, bounds, useLastCode) { - var codeA = useLastCode ? this._lastCode : this._getBitCode(a, bounds), - codeB = this._getBitCode(b, bounds), - - codeOut, p, newCode; - - // save 2nd code to avoid calculating it on the next segment - this._lastCode = codeB; - - while (true) { - // if a,b is inside the clip window (trivial accept) - if (!(codeA | codeB)) { - return [a, b]; - // if a,b is outside the clip window (trivial reject) - } else if (codeA & codeB) { - return false; - // other cases - } else { - codeOut = codeA || codeB; - p = this._getEdgeIntersection(a, b, codeOut, bounds); - newCode = this._getBitCode(p, bounds); - - if (codeOut === codeA) { - a = p; - codeA = newCode; - } else { - b = p; - codeB = newCode; - } - } - } - }, - - _getEdgeIntersection: function (a, b, code, bounds) { - var dx = b.x - a.x, - dy = b.y - a.y, - min = bounds.min, - max = bounds.max; - - if (code & 8) { // top - return new L.Point(a.x + dx * (max.y - a.y) / dy, max.y); - } else if (code & 4) { // bottom - return new L.Point(a.x + dx * (min.y - a.y) / dy, min.y); - } else if (code & 2) { // right - return new L.Point(max.x, a.y + dy * (max.x - a.x) / dx); - } else if (code & 1) { // left - return new L.Point(min.x, a.y + dy * (min.x - a.x) / dx); - } - }, - - _getBitCode: function (/*Point*/ p, bounds) { - var code = 0; - - if (p.x < bounds.min.x) { // left - code |= 1; - } else if (p.x > bounds.max.x) { // right - code |= 2; - } - if (p.y < bounds.min.y) { // bottom - code |= 4; - } else if (p.y > bounds.max.y) { // top - code |= 8; - } - - return code; - }, - - // square distance (to avoid unnecessary Math.sqrt calls) - _sqDist: function (p1, p2) { - var dx = p2.x - p1.x, - dy = p2.y - p1.y; - return dx * dx + dy * dy; - }, - - // return closest point on segment or distance to that point - _sqClosestPointOnSegment: function (p, p1, p2, sqDist) { - var x = p1.x, - y = p1.y, - dx = p2.x - x, - dy = p2.y - y, - dot = dx * dx + dy * dy, - t; - - if (dot > 0) { - t = ((p.x - x) * dx + (p.y - y) * dy) / dot; - - if (t > 1) { - x = p2.x; - y = p2.y; - } else if (t > 0) { - x += dx * t; - y += dy * t; - } - } - - dx = p.x - x; - dy = p.y - y; - - return sqDist ? dx * dx + dy * dy : new L.Point(x, y); - } -}; - - -/* - * L.Polyline is used to display polylines on a map. - */ - -L.Polyline = L.Path.extend({ - initialize: function (latlngs, options) { - L.Path.prototype.initialize.call(this, options); - - this._latlngs = this._convertLatLngs(latlngs); - }, - - options: { - // how much to simplify the polyline on each zoom level - // more = better performance and smoother look, less = more accurate - smoothFactor: 1.0, - noClip: false - }, - - projectLatlngs: function () { - this._originalPoints = []; - - for (var i = 0, len = this._latlngs.length; i < len; i++) { - this._originalPoints[i] = this._map.latLngToLayerPoint(this._latlngs[i]); - } - }, - - getPathString: function () { - for (var i = 0, len = this._parts.length, str = ''; i < len; i++) { - str += this._getPathPartStr(this._parts[i]); - } - return str; - }, - - getLatLngs: function () { - return this._latlngs; - }, - - setLatLngs: function (latlngs) { - this._latlngs = this._convertLatLngs(latlngs); - return this.redraw(); - }, - - addLatLng: function (latlng) { - this._latlngs.push(L.latLng(latlng)); - return this.redraw(); - }, - - spliceLatLngs: function () { // (Number index, Number howMany) - var removed = [].splice.apply(this._latlngs, arguments); - this._convertLatLngs(this._latlngs, true); - this.redraw(); - return removed; - }, - - closestLayerPoint: function (p) { - var minDistance = Infinity, parts = this._parts, p1, p2, minPoint = null; - - for (var j = 0, jLen = parts.length; j < jLen; j++) { - var points = parts[j]; - for (var i = 1, len = points.length; i < len; i++) { - p1 = points[i - 1]; - p2 = points[i]; - var sqDist = L.LineUtil._sqClosestPointOnSegment(p, p1, p2, true); - if (sqDist < minDistance) { - minDistance = sqDist; - minPoint = L.LineUtil._sqClosestPointOnSegment(p, p1, p2); - } - } - } - if (minPoint) { - minPoint.distance = Math.sqrt(minDistance); - } - return minPoint; - }, - - getBounds: function () { - return new L.LatLngBounds(this.getLatLngs()); - }, - - _convertLatLngs: function (latlngs, overwrite) { - var i, len, target = overwrite ? latlngs : []; - - for (i = 0, len = latlngs.length; i < len; i++) { - if (L.Util.isArray(latlngs[i]) && typeof latlngs[i][0] !== 'number') { - return; - } - target[i] = L.latLng(latlngs[i]); - } - return target; - }, - - _initEvents: function () { - L.Path.prototype._initEvents.call(this); - }, - - _getPathPartStr: function (points) { - var round = L.Path.VML; - - for (var j = 0, len2 = points.length, str = '', p; j < len2; j++) { - p = points[j]; - if (round) { - p._round(); - } - str += (j ? 'L' : 'M') + p.x + ' ' + p.y; - } - return str; - }, - - _clipPoints: function () { - var points = this._originalPoints, - len = points.length, - i, k, segment; - - if (this.options.noClip) { - this._parts = [points]; - return; - } - - this._parts = []; - - var parts = this._parts, - vp = this._map._pathViewport, - lu = L.LineUtil; - - for (i = 0, k = 0; i < len - 1; i++) { - segment = lu.clipSegment(points[i], points[i + 1], vp, i); - if (!segment) { - continue; - } - - parts[k] = parts[k] || []; - parts[k].push(segment[0]); - - // if segment goes out of screen, or it's the last one, it's the end of the line part - if ((segment[1] !== points[i + 1]) || (i === len - 2)) { - parts[k].push(segment[1]); - k++; - } - } - }, - - // simplify each clipped part of the polyline - _simplifyPoints: function () { - var parts = this._parts, - lu = L.LineUtil; - - for (var i = 0, len = parts.length; i < len; i++) { - parts[i] = lu.simplify(parts[i], this.options.smoothFactor); - } - }, - - _updatePath: function () { - if (!this._map) { return; } - - this._clipPoints(); - this._simplifyPoints(); - - L.Path.prototype._updatePath.call(this); - } -}); - -L.polyline = function (latlngs, options) { - return new L.Polyline(latlngs, options); -}; - - -/* - * L.PolyUtil contains utility functions for polygons (clipping, etc.). - */ - -/*jshint bitwise:false */ // allow bitwise operations here - -L.PolyUtil = {}; - -/* - * Sutherland-Hodgeman polygon clipping algorithm. - * Used to avoid rendering parts of a polygon that are not currently visible. - */ -L.PolyUtil.clipPolygon = function (points, bounds) { - var clippedPoints, - edges = [1, 4, 2, 8], - i, j, k, - a, b, - len, edge, p, - lu = L.LineUtil; - - for (i = 0, len = points.length; i < len; i++) { - points[i]._code = lu._getBitCode(points[i], bounds); - } - - // for each edge (left, bottom, right, top) - for (k = 0; k < 4; k++) { - edge = edges[k]; - clippedPoints = []; - - for (i = 0, len = points.length, j = len - 1; i < len; j = i++) { - a = points[i]; - b = points[j]; - - // if a is inside the clip window - if (!(a._code & edge)) { - // if b is outside the clip window (a->b goes out of screen) - if (b._code & edge) { - p = lu._getEdgeIntersection(b, a, edge, bounds); - p._code = lu._getBitCode(p, bounds); - clippedPoints.push(p); - } - clippedPoints.push(a); - - // else if b is inside the clip window (a->b enters the screen) - } else if (!(b._code & edge)) { - p = lu._getEdgeIntersection(b, a, edge, bounds); - p._code = lu._getBitCode(p, bounds); - clippedPoints.push(p); - } - } - points = clippedPoints; - } - - return points; -}; - - -/* - * L.Polygon is used to display polygons on a map. - */ - -L.Polygon = L.Polyline.extend({ - options: { - fill: true - }, - - initialize: function (latlngs, options) { - var i, len, hole; - - L.Polyline.prototype.initialize.call(this, latlngs, options); - - if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) { - this._latlngs = this._convertLatLngs(latlngs[0]); - this._holes = latlngs.slice(1); - - for (i = 0, len = this._holes.length; i < len; i++) { - hole = this._holes[i] = this._convertLatLngs(this._holes[i]); - if (hole[0].equals(hole[hole.length - 1])) { - hole.pop(); - } - } - } - - // filter out last point if its equal to the first one - latlngs = this._latlngs; - - if (latlngs.length >= 2 && latlngs[0].equals(latlngs[latlngs.length - 1])) { - latlngs.pop(); - } - }, - - projectLatlngs: function () { - L.Polyline.prototype.projectLatlngs.call(this); - - // project polygon holes points - // TODO move this logic to Polyline to get rid of duplication - this._holePoints = []; - - if (!this._holes) { return; } - - var i, j, len, len2; - - for (i = 0, len = this._holes.length; i < len; i++) { - this._holePoints[i] = []; - - for (j = 0, len2 = this._holes[i].length; j < len2; j++) { - this._holePoints[i][j] = this._map.latLngToLayerPoint(this._holes[i][j]); - } - } - }, - - _clipPoints: function () { - var points = this._originalPoints, - newParts = []; - - this._parts = [points].concat(this._holePoints); - - if (this.options.noClip) { return; } - - for (var i = 0, len = this._parts.length; i < len; i++) { - var clipped = L.PolyUtil.clipPolygon(this._parts[i], this._map._pathViewport); - if (clipped.length) { - newParts.push(clipped); - } - } - - this._parts = newParts; - }, - - _getPathPartStr: function (points) { - var str = L.Polyline.prototype._getPathPartStr.call(this, points); - return str + (L.Browser.svg ? 'z' : 'x'); - } -}); - -L.polygon = function (latlngs, options) { - return new L.Polygon(latlngs, options); -}; - - -/* - * Contains L.MultiPolyline and L.MultiPolygon layers. - */ - -(function () { - function createMulti(Klass) { - - return L.FeatureGroup.extend({ - - initialize: function (latlngs, options) { - this._layers = {}; - this._options = options; - this.setLatLngs(latlngs); - }, - - setLatLngs: function (latlngs) { - var i = 0, - len = latlngs.length; - - this.eachLayer(function (layer) { - if (i < len) { - layer.setLatLngs(latlngs[i++]); - } else { - this.removeLayer(layer); - } - }, this); - - while (i < len) { - this.addLayer(new Klass(latlngs[i++], this._options)); - } - - return this; - } - }); - } - - L.MultiPolyline = createMulti(L.Polyline); - L.MultiPolygon = createMulti(L.Polygon); - - L.multiPolyline = function (latlngs, options) { - return new L.MultiPolyline(latlngs, options); - }; - - L.multiPolygon = function (latlngs, options) { - return new L.MultiPolygon(latlngs, options); - }; -}()); - - -/* - * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object. - */ - -L.Rectangle = L.Polygon.extend({ - initialize: function (latLngBounds, options) { - L.Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options); - }, - - setBounds: function (latLngBounds) { - this.setLatLngs(this._boundsToLatLngs(latLngBounds)); - }, - - _boundsToLatLngs: function (latLngBounds) { - latLngBounds = L.latLngBounds(latLngBounds); - return [ - latLngBounds.getSouthWest(), - latLngBounds.getNorthWest(), - latLngBounds.getNorthEast(), - latLngBounds.getSouthEast() - ]; - } -}); - -L.rectangle = function (latLngBounds, options) { - return new L.Rectangle(latLngBounds, options); -}; - - -/* - * L.Circle is a circle overlay (with a certain radius in meters). - */ - -L.Circle = L.Path.extend({ - initialize: function (latlng, radius, options) { - L.Path.prototype.initialize.call(this, options); - - this._latlng = L.latLng(latlng); - this._mRadius = radius; - }, - - options: { - fill: true - }, - - setLatLng: function (latlng) { - this._latlng = L.latLng(latlng); - return this.redraw(); - }, - - setRadius: function (radius) { - this._mRadius = radius; - return this.redraw(); - }, - - projectLatlngs: function () { - var lngRadius = this._getLngRadius(), - latlng = this._latlng, - pointLeft = this._map.latLngToLayerPoint([latlng.lat, latlng.lng - lngRadius]); - - this._point = this._map.latLngToLayerPoint(latlng); - this._radius = Math.max(this._point.x - pointLeft.x, 1); - }, - - getBounds: function () { - var lngRadius = this._getLngRadius(), - latRadius = (this._mRadius / 40075017) * 360, - latlng = this._latlng; - - return new L.LatLngBounds( - [latlng.lat - latRadius, latlng.lng - lngRadius], - [latlng.lat + latRadius, latlng.lng + lngRadius]); - }, - - getLatLng: function () { - return this._latlng; - }, - - getPathString: function () { - var p = this._point, - r = this._radius; - - if (this._checkIfEmpty()) { - return ''; - } - - if (L.Browser.svg) { - return 'M' + p.x + ',' + (p.y - r) + - 'A' + r + ',' + r + ',0,1,1,' + - (p.x - 0.1) + ',' + (p.y - r) + ' z'; - } else { - p._round(); - r = Math.round(r); - return 'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r + ' 0,' + (65535 * 360); - } - }, - - getRadius: function () { - return this._mRadius; - }, - - // TODO Earth hardcoded, move into projection code! - - _getLatRadius: function () { - return (this._mRadius / 40075017) * 360; - }, - - _getLngRadius: function () { - return this._getLatRadius() / Math.cos(L.LatLng.DEG_TO_RAD * this._latlng.lat); - }, - - _checkIfEmpty: function () { - if (!this._map) { - return false; - } - var vp = this._map._pathViewport, - r = this._radius, - p = this._point; - - return p.x - r > vp.max.x || p.y - r > vp.max.y || - p.x + r < vp.min.x || p.y + r < vp.min.y; - } -}); - -L.circle = function (latlng, radius, options) { - return new L.Circle(latlng, radius, options); -}; - - -/* - * L.CircleMarker is a circle overlay with a permanent pixel radius. - */ - -L.CircleMarker = L.Circle.extend({ - options: { - radius: 10, - weight: 2 - }, - - initialize: function (latlng, options) { - L.Circle.prototype.initialize.call(this, latlng, null, options); - this._radius = this.options.radius; - }, - - projectLatlngs: function () { - this._point = this._map.latLngToLayerPoint(this._latlng); - }, - - _updateStyle : function () { - L.Circle.prototype._updateStyle.call(this); - this.setRadius(this.options.radius); - }, - - setRadius: function (radius) { - this.options.radius = this._radius = radius; - return this.redraw(); - } -}); - -L.circleMarker = function (latlng, options) { - return new L.CircleMarker(latlng, options); -}; - - -/* - * Extends L.Polyline to be able to manually detect clicks on Canvas-rendered polylines. - */ - -L.Polyline.include(!L.Path.CANVAS ? {} : { - _containsPoint: function (p, closed) { - var i, j, k, len, len2, dist, part, - w = this.options.weight / 2; - - if (L.Browser.touch) { - w += 10; // polyline click tolerance on touch devices - } - - for (i = 0, len = this._parts.length; i < len; i++) { - part = this._parts[i]; - for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { - if (!closed && (j === 0)) { - continue; - } - - dist = L.LineUtil.pointToSegmentDistance(p, part[k], part[j]); - - if (dist <= w) { - return true; - } - } - } - return false; - } -}); - - -/* - * Extends L.Polygon to be able to manually detect clicks on Canvas-rendered polygons. - */ - -L.Polygon.include(!L.Path.CANVAS ? {} : { - _containsPoint: function (p) { - var inside = false, - part, p1, p2, - i, j, k, - len, len2; - - // TODO optimization: check if within bounds first - - if (L.Polyline.prototype._containsPoint.call(this, p, true)) { - // click on polygon border - return true; - } - - // ray casting algorithm for detecting if point is in polygon - - for (i = 0, len = this._parts.length; i < len; i++) { - part = this._parts[i]; - - for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { - p1 = part[j]; - p2 = part[k]; - - if (((p1.y > p.y) !== (p2.y > p.y)) && - (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) { - inside = !inside; - } - } - } - - return inside; - } -}); - - -/* - * Extends L.Circle with Canvas-specific code. - */ - -L.Circle.include(!L.Path.CANVAS ? {} : { - _drawPath: function () { - var p = this._point; - this._ctx.beginPath(); - this._ctx.arc(p.x, p.y, this._radius, 0, Math.PI * 2, false); - }, - - _containsPoint: function (p) { - var center = this._point, - w2 = this.options.stroke ? this.options.weight / 2 : 0; - - return (p.distanceTo(center) <= this._radius + w2); - } -}); - - -/* - * CircleMarker canvas specific drawing parts. - */ - -L.CircleMarker.include(!L.Path.CANVAS ? {} : { - _updateStyle: function () { - L.Path.prototype._updateStyle.call(this); - } -}); - - -/* - * L.GeoJSON turns any GeoJSON data into a Leaflet layer. - */ - -L.GeoJSON = L.FeatureGroup.extend({ - - initialize: function (geojson, options) { - L.setOptions(this, options); - - this._layers = {}; - - if (geojson) { - this.addData(geojson); - } - }, - - addData: function (geojson) { - var features = L.Util.isArray(geojson) ? geojson : geojson.features, - i, len; - - if (features) { - for (i = 0, len = features.length; i < len; i++) { - // Only add this if geometry or geometries are set and not null - if (features[i].geometries || features[i].geometry || features[i].features) { - this.addData(features[i]); - } - } - return this; - } - - var options = this.options; - - if (options.filter && !options.filter(geojson)) { return; } - - var layer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng); - layer.feature = geojson; - - layer.defaultOptions = layer.options; - this.resetStyle(layer); - - if (options.onEachFeature) { - options.onEachFeature(geojson, layer); - } - - return this.addLayer(layer); - }, - - resetStyle: function (layer) { - var style = this.options.style; - if (style) { - // reset any custom styles - L.Util.extend(layer.options, layer.defaultOptions); - - this._setLayerStyle(layer, style); - } - }, - - setStyle: function (style) { - this.eachLayer(function (layer) { - this._setLayerStyle(layer, style); - }, this); - }, - - _setLayerStyle: function (layer, style) { - if (typeof style === 'function') { - style = style(layer.feature); - } - if (layer.setStyle) { - layer.setStyle(style); - } - } -}); - -L.extend(L.GeoJSON, { - geometryToLayer: function (geojson, pointToLayer, coordsToLatLng) { - var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson, - coords = geometry.coordinates, - layers = [], - latlng, latlngs, i, len, layer; - - coordsToLatLng = coordsToLatLng || this.coordsToLatLng; - - switch (geometry.type) { - case 'Point': - latlng = coordsToLatLng(coords); - return pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng); - - case 'MultiPoint': - for (i = 0, len = coords.length; i < len; i++) { - latlng = coordsToLatLng(coords[i]); - layer = pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng); - layers.push(layer); - } - return new L.FeatureGroup(layers); - - case 'LineString': - latlngs = this.coordsToLatLngs(coords, 0, coordsToLatLng); - return new L.Polyline(latlngs); - - case 'Polygon': - latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng); - return new L.Polygon(latlngs); - - case 'MultiLineString': - latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng); - return new L.MultiPolyline(latlngs); - - case 'MultiPolygon': - latlngs = this.coordsToLatLngs(coords, 2, coordsToLatLng); - return new L.MultiPolygon(latlngs); - - case 'GeometryCollection': - for (i = 0, len = geometry.geometries.length; i < len; i++) { - - layer = this.geometryToLayer({ - geometry: geometry.geometries[i], - type: 'Feature', - properties: geojson.properties - }, pointToLayer); - - layers.push(layer); - } - return new L.FeatureGroup(layers); - - default: - throw new Error('Invalid GeoJSON object.'); - } - }, - - coordsToLatLng: function (coords) { // (Array[, Boolean]) -> LatLng - return new L.LatLng(coords[1], coords[0]); - }, - - coordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) { // (Array[, Number, Function]) -> Array - var latlng, i, len, - latlngs = []; - - for (i = 0, len = coords.length; i < len; i++) { - latlng = levelsDeep ? - this.coordsToLatLngs(coords[i], levelsDeep - 1, coordsToLatLng) : - (coordsToLatLng || this.coordsToLatLng)(coords[i]); - - latlngs.push(latlng); - } - - return latlngs; - }, - - latLngToCoords: function (latLng) { - return [latLng.lng, latLng.lat]; - }, - - latLngsToCoords: function (latLngs) { - var coords = []; - - for (var i = 0, len = latLngs.length; i < len; i++) { - coords.push(L.GeoJSON.latLngToCoords(latLngs[i])); - } - - return coords; - } -}); - -L.Marker.include({ - toGeoJSON: function () { - return { - type: 'Point', - coordinates: L.GeoJSON.latLngToCoords(this.getLatLng()) - }; - } -}); - -L.Polyline.include({ - toGeoJSON: function () { - return { - type: 'LineString', - coordinates: L.GeoJSON.latLngsToCoords(this.getLatLngs()) - }; - } -}); - -L.Polygon.include({ - toGeoJSON: function () { - var coords = [L.GeoJSON.latLngsToCoords(this.getLatLngs())], - i, len, hole; - - coords[0].push(coords[0][0]); - - if (this._holes) { - for (i = 0, len = this._holes.length; i < len; i++) { - hole = L.GeoJSON.latLngsToCoords(this._holes[i]); - hole.push(hole[0]); - coords.push(hole); - } - } - - return { - type: 'Polygon', - coordinates: coords - }; - } -}); - -(function () { - function includeMulti(Klass, type) { - Klass.include({ - toGeoJSON: function () { - var coords = []; - - this.eachLayer(function (layer) { - coords.push(layer.toGeoJSON().coordinates); - }); - - return { - type: type, - coordinates: coords - }; - } - }); - } - - includeMulti(L.MultiPolyline, 'MultiLineString'); - includeMulti(L.MultiPolygon, 'MultiPolygon'); -}()); - -L.LayerGroup.include({ - toGeoJSON: function () { - var geoms = []; - - this.eachLayer(function (layer) { - if (layer.toGeoJSON) { - geoms.push(layer.toGeoJSON()); - } - }); - - return { - type: 'GeometryCollection', - geometries: geoms - }; - } -}); - -L.geoJson = function (geojson, options) { - return new L.GeoJSON(geojson, options); -}; - - -/* - * L.DomEvent contains functions for working with DOM events. - */ - -L.DomEvent = { - /* inspired by John Resig, Dean Edwards and YUI addEvent implementations */ - addListener: function (obj, type, fn, context) { // (HTMLElement, String, Function[, Object]) - - var id = L.stamp(fn), - key = '_leaflet_' + type + id, - handler, originalHandler, newType; - - if (obj[key]) { return this; } - - handler = function (e) { - return fn.call(context || obj, e || L.DomEvent._getEvent()); - }; - - if (L.Browser.msTouch && type.indexOf('touch') === 0) { - return this.addMsTouchListener(obj, type, handler, id); - } - if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener) { - this.addDoubleTapListener(obj, handler, id); - } - - if ('addEventListener' in obj) { - - if (type === 'mousewheel') { - obj.addEventListener('DOMMouseScroll', handler, false); - obj.addEventListener(type, handler, false); - - } else if ((type === 'mouseenter') || (type === 'mouseleave')) { - - originalHandler = handler; - newType = (type === 'mouseenter' ? 'mouseover' : 'mouseout'); - - handler = function (e) { - if (!L.DomEvent._checkMouse(obj, e)) { return; } - return originalHandler(e); - }; - - obj.addEventListener(newType, handler, false); - - } else if (type === 'click' && L.Browser.android) { - originalHandler = handler; - handler = function (e) { - return L.DomEvent._filterClick(e, originalHandler); - }; - - obj.addEventListener(type, handler, false); - } else { - obj.addEventListener(type, handler, false); - } - - } else if ('attachEvent' in obj) { - obj.attachEvent('on' + type, handler); - } - - obj[key] = handler; - - return this; - }, - - removeListener: function (obj, type, fn) { // (HTMLElement, String, Function) - - var id = L.stamp(fn), - key = '_leaflet_' + type + id, - handler = obj[key]; - - if (!handler) { return this; } - - if (L.Browser.msTouch && type.indexOf('touch') === 0) { - this.removeMsTouchListener(obj, type, id); - } else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) { - this.removeDoubleTapListener(obj, id); - - } else if ('removeEventListener' in obj) { - - if (type === 'mousewheel') { - obj.removeEventListener('DOMMouseScroll', handler, false); - obj.removeEventListener(type, handler, false); - - } else if ((type === 'mouseenter') || (type === 'mouseleave')) { - obj.removeEventListener((type === 'mouseenter' ? 'mouseover' : 'mouseout'), handler, false); - } else { - obj.removeEventListener(type, handler, false); - } - } else if ('detachEvent' in obj) { - obj.detachEvent('on' + type, handler); - } - - obj[key] = null; - - return this; - }, - - stopPropagation: function (e) { - - if (e.stopPropagation) { - e.stopPropagation(); - } else { - e.cancelBubble = true; - } - return this; - }, - - disableClickPropagation: function (el) { - - var stop = L.DomEvent.stopPropagation; - - for (var i = L.Draggable.START.length - 1; i >= 0; i--) { - L.DomEvent.addListener(el, L.Draggable.START[i], stop); - } - - return L.DomEvent - .addListener(el, 'click', stop) - .addListener(el, 'dblclick', stop); - }, - - preventDefault: function (e) { - - if (e.preventDefault) { - e.preventDefault(); - } else { - e.returnValue = false; - } - return this; - }, - - stop: function (e) { - return L.DomEvent.preventDefault(e).stopPropagation(e); - }, - - getMousePosition: function (e, container) { - - var body = document.body, - docEl = document.documentElement, - x = e.pageX ? e.pageX : e.clientX + body.scrollLeft + docEl.scrollLeft, - y = e.pageY ? e.pageY : e.clientY + body.scrollTop + docEl.scrollTop, - pos = new L.Point(x, y); - - return (container ? pos._subtract(L.DomUtil.getViewportOffset(container)) : pos); - }, - - getWheelDelta: function (e) { - - var delta = 0; - - if (e.wheelDelta) { - delta = e.wheelDelta / 120; - } - if (e.detail) { - delta = -e.detail / 3; - } - return delta; - }, - - // check if element really left/entered the event target (for mouseenter/mouseleave) - _checkMouse: function (el, e) { - - var related = e.relatedTarget; - - if (!related) { return true; } - - try { - while (related && (related !== el)) { - related = related.parentNode; - } - } catch (err) { - return false; - } - return (related !== el); - }, - - _getEvent: function () { // evil magic for IE - /*jshint noarg:false */ - var e = window.event; - if (!e) { - var caller = arguments.callee.caller; - while (caller) { - e = caller['arguments'][0]; - if (e && window.Event === e.constructor) { - break; - } - caller = caller.caller; - } - } - return e; - }, - - // this solves a bug in Android WebView where a single touch triggers two click events. - _filterClick: function (e, handler) { - var timeStamp = (e.timeStamp || e.originalEvent.timeStamp); - var elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick); - - // are they closer together than 400ms yet more than 100ms? - // Android typically triggers them ~300ms apart while multiple listeners - // on the same event should be triggered far faster. - - if (elapsed && elapsed > 100 && elapsed < 400) { - L.DomEvent.stop(e); - return; - } - L.DomEvent._lastClick = timeStamp; - - return handler(e); - } -}; - -L.DomEvent.on = L.DomEvent.addListener; -L.DomEvent.off = L.DomEvent.removeListener; - - -/* - * L.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too. - */ - -L.Draggable = L.Class.extend({ - includes: L.Mixin.Events, - - statics: { - START: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'], - END: { - mousedown: 'mouseup', - touchstart: 'touchend', - MSPointerDown: 'touchend' - }, - MOVE: { - mousedown: 'mousemove', - touchstart: 'touchmove', - MSPointerDown: 'touchmove' - }, - TAP_TOLERANCE: 15 - }, - - initialize: function (element, dragStartTarget, longPress) { - this._element = element; - this._dragStartTarget = dragStartTarget || element; - this._longPress = longPress && !L.Browser.msTouch; - }, - - enable: function () { - if (this._enabled) { return; } - - for (var i = L.Draggable.START.length - 1; i >= 0; i--) { - L.DomEvent.on(this._dragStartTarget, L.Draggable.START[i], this._onDown, this); - } - - this._enabled = true; - }, - - disable: function () { - if (!this._enabled) { return; } - - for (var i = L.Draggable.START.length - 1; i >= 0; i--) { - L.DomEvent.off(this._dragStartTarget, L.Draggable.START[i], this._onDown, this); - } - - this._enabled = false; - this._moved = false; - }, - - _onDown: function (e) { - if (e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; } - - L.DomEvent - .preventDefault(e) - .stopPropagation(e); - - if (L.Draggable._disabled) { return; } - - this._simulateClick = true; - - var touchesNum = (e.touches && e.touches.length) || 0; - - // don't simulate click or track longpress if more than 1 touch - if (touchesNum > 1) { - this._simulateClick = false; - clearTimeout(this._longPressTimeout); - return; - } - - var first = touchesNum === 1 ? e.touches[0] : e, - el = first.target; - - // if touching a link, highlight it - if (L.Browser.touch && el.tagName.toLowerCase() === 'a') { - L.DomUtil.addClass(el, 'leaflet-active'); - } - - this._moved = false; - - if (this._moving) { return; } - - this._startPoint = new L.Point(first.clientX, first.clientY); - this._startPos = this._newPos = L.DomUtil.getPosition(this._element); - - // touch contextmenu event emulation - if (touchesNum === 1 && L.Browser.touch && this._longPress) { - - this._longPressTimeout = setTimeout(L.bind(function () { - var dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0; - - if (dist < L.Draggable.TAP_TOLERANCE) { - this._simulateClick = false; - this._onUp(); - this._simulateEvent('contextmenu', first); - } - }, this), 1000); - } - - L.DomEvent - .on(document, L.Draggable.MOVE[e.type], this._onMove, this) - .on(document, L.Draggable.END[e.type], this._onUp, this); - }, - - _onMove: function (e) { - if (e.touches && e.touches.length > 1) { return; } - - var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e), - newPoint = new L.Point(first.clientX, first.clientY), - offset = newPoint.subtract(this._startPoint); - - if (!offset.x && !offset.y) { return; } - - L.DomEvent.preventDefault(e); - - if (!this._moved) { - this.fire('dragstart'); - - this._moved = true; - this._startPos = L.DomUtil.getPosition(this._element).subtract(offset); - - if (!L.Browser.touch) { - L.DomUtil.disableTextSelection(); - L.DomUtil.addClass(document.body, 'leaflet-dragging'); - } - } - - this._newPos = this._startPos.add(offset); - this._moving = true; - - L.Util.cancelAnimFrame(this._animRequest); - this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget); - }, - - _updatePosition: function () { - this.fire('predrag'); - L.DomUtil.setPosition(this._element, this._newPos); - this.fire('drag'); - }, - - _onUp: function (e) { - var first, el, dist, simulateClickTouch, i; - - clearTimeout(this._longPressTimeout); - - if (this._simulateClick && e.changedTouches) { - - dist = (this._newPos && this._newPos.distanceTo(this._startPos)) || 0; - first = e.changedTouches[0]; - el = first.target; - - if (el.tagName.toLowerCase() === 'a') { - L.DomUtil.removeClass(el, 'leaflet-active'); - } - - // simulate click if the touch didn't move too much - if (dist < L.Draggable.TAP_TOLERANCE) { - simulateClickTouch = true; - } - } - - if (!L.Browser.touch) { - L.DomUtil.enableTextSelection(); - L.DomUtil.removeClass(document.body, 'leaflet-dragging'); - } - - for (i in L.Draggable.MOVE) { - L.DomEvent - .off(document, L.Draggable.MOVE[i], this._onMove) - .off(document, L.Draggable.END[i], this._onUp); - } - - if (this._moved) { - // ensure drag is not fired after dragend - L.Util.cancelAnimFrame(this._animRequest); - - this.fire('dragend'); - } - - this._moving = false; - - if (simulateClickTouch) { - this._moved = false; - this._simulateEvent('click', first); - } - }, - - _simulateEvent: function (type, e) { - var simulatedEvent = document.createEvent('MouseEvents'); - - simulatedEvent.initMouseEvent( - type, true, true, window, 1, - e.screenX, e.screenY, - e.clientX, e.clientY, - false, false, false, false, 0, null); - - e.target.dispatchEvent(simulatedEvent); - } -}); - - -/* - L.Handler is a base class for handler classes that are used internally to inject - interaction features like dragging to classes like Map and Marker. -*/ - -L.Handler = L.Class.extend({ - initialize: function (map) { - this._map = map; - }, - - enable: function () { - if (this._enabled) { return; } - - this._enabled = true; - this.addHooks(); - }, - - disable: function () { - if (!this._enabled) { return; } - - this._enabled = false; - this.removeHooks(); - }, - - enabled: function () { - return !!this._enabled; - } -}); - - -/* - * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default. - */ - -L.Map.mergeOptions({ - dragging: true, - - inertia: !L.Browser.android23, - inertiaDeceleration: 3400, // px/s^2 - inertiaMaxSpeed: Infinity, // px/s - inertiaThreshold: L.Browser.touch ? 32 : 18, // ms - easeLinearity: 0.25, - - longPress: true, - - // TODO refactor, move to CRS - worldCopyJump: false -}); - -L.Map.Drag = L.Handler.extend({ - addHooks: function () { - if (!this._draggable) { - var map = this._map; - - this._draggable = new L.Draggable(map._mapPane, map._container, map.options.longPress); - - this._draggable.on({ - 'dragstart': this._onDragStart, - 'drag': this._onDrag, - 'dragend': this._onDragEnd - }, this); - - if (map.options.worldCopyJump) { - this._draggable.on('predrag', this._onPreDrag, this); - map.on('viewreset', this._onViewReset, this); - } - } - this._draggable.enable(); - }, - - removeHooks: function () { - this._draggable.disable(); - }, - - moved: function () { - return this._draggable && this._draggable._moved; - }, - - _onDragStart: function () { - var map = this._map; - - if (map._panAnim) { - map._panAnim.stop(); - } - - map - .fire('movestart') - .fire('dragstart'); - - if (map.options.inertia) { - this._positions = []; - this._times = []; - } - }, - - _onDrag: function () { - if (this._map.options.inertia) { - var time = this._lastTime = +new Date(), - pos = this._lastPos = this._draggable._newPos; - - this._positions.push(pos); - this._times.push(time); - - if (time - this._times[0] > 200) { - this._positions.shift(); - this._times.shift(); - } - } - - this._map - .fire('move') - .fire('drag'); - }, - - _onViewReset: function () { - // TODO fix hardcoded Earth values - var pxCenter = this._map.getSize()._divideBy(2), - pxWorldCenter = this._map.latLngToLayerPoint([0, 0]); - - this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x; - this._worldWidth = this._map.project([0, 180]).x; - }, - - _onPreDrag: function () { - // TODO refactor to be able to adjust map pane position after zoom - var worldWidth = this._worldWidth, - halfWidth = Math.round(worldWidth / 2), - dx = this._initialWorldOffset, - x = this._draggable._newPos.x, - newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx, - newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx, - newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2; - - this._draggable._newPos.x = newX; - }, - - _onDragEnd: function () { - var map = this._map, - options = map.options, - delay = +new Date() - this._lastTime, - - noInertia = !options.inertia || delay > options.inertiaThreshold || !this._positions[0]; - - map.fire('dragend'); - - if (noInertia) { - map.fire('moveend'); - - } else { - - var direction = this._lastPos.subtract(this._positions[0]), - duration = (this._lastTime + delay - this._times[0]) / 1000, - ease = options.easeLinearity, - - speedVector = direction.multiplyBy(ease / duration), - speed = speedVector.distanceTo([0, 0]), - - limitedSpeed = Math.min(options.inertiaMaxSpeed, speed), - limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed), - - decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease), - offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round(); - - if (!offset.x || !offset.y) { - map.fire('moveend'); - - } else { - L.Util.requestAnimFrame(function () { - map.panBy(offset, { - duration: decelerationDuration, - easeLinearity: ease, - noMoveStart: true - }); - }); - } - } - } -}); - -L.Map.addInitHook('addHandler', 'dragging', L.Map.Drag); - - -/* - * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default. - */ - -L.Map.mergeOptions({ - doubleClickZoom: true -}); - -L.Map.DoubleClickZoom = L.Handler.extend({ - addHooks: function () { - this._map.on('dblclick', this._onDoubleClick); - }, - - removeHooks: function () { - this._map.off('dblclick', this._onDoubleClick); - }, - - _onDoubleClick: function (e) { - this.setZoomAround(e.containerPoint, this._zoom + 1); - } -}); - -L.Map.addInitHook('addHandler', 'doubleClickZoom', L.Map.DoubleClickZoom); - - -/* - * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map. - */ - -L.Map.mergeOptions({ - scrollWheelZoom: true -}); - -L.Map.ScrollWheelZoom = L.Handler.extend({ - addHooks: function () { - L.DomEvent.on(this._map._container, 'mousewheel', this._onWheelScroll, this); - this._delta = 0; - }, - - removeHooks: function () { - L.DomEvent.off(this._map._container, 'mousewheel', this._onWheelScroll); - }, - - _onWheelScroll: function (e) { - var delta = L.DomEvent.getWheelDelta(e); - - this._delta += delta; - this._lastMousePos = this._map.mouseEventToContainerPoint(e); - - if (!this._startTime) { - this._startTime = +new Date(); - } - - var left = Math.max(40 - (+new Date() - this._startTime), 0); - - clearTimeout(this._timer); - this._timer = setTimeout(L.bind(this._performZoom, this), left); - - L.DomEvent.preventDefault(e); - L.DomEvent.stopPropagation(e); - }, - - _performZoom: function () { - var map = this._map, - delta = this._delta, - zoom = map.getZoom(); - - delta = delta > 0 ? Math.ceil(delta) : Math.floor(delta); - delta = Math.max(Math.min(delta, 4), -4); - delta = map._limitZoom(zoom + delta) - zoom; - - this._delta = 0; - this._startTime = null; - - if (!delta) { return; } - - map.setZoomAround(this._lastMousePos, zoom + delta); - } -}); - -L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom); - - -/* - * Extends the event handling code with double tap support for mobile browsers. - */ - -L.extend(L.DomEvent, { - - _touchstart: L.Browser.msTouch ? 'MSPointerDown' : 'touchstart', - _touchend: L.Browser.msTouch ? 'MSPointerUp' : 'touchend', - - // inspired by Zepto touch code by Thomas Fuchs - addDoubleTapListener: function (obj, handler, id) { - var last, - doubleTap = false, - delay = 250, - touch, - pre = '_leaflet_', - touchstart = this._touchstart, - touchend = this._touchend, - trackedTouches = []; - - function onTouchStart(e) { - var count; - - if (L.Browser.msTouch) { - trackedTouches.push(e.pointerId); - count = trackedTouches.length; - } else { - count = e.touches.length; - } - if (count > 1) { - return; - } - - var now = Date.now(), - delta = now - (last || now); - - touch = e.touches ? e.touches[0] : e; - doubleTap = (delta > 0 && delta <= delay); - last = now; - } - - function onTouchEnd(e) { - if (L.Browser.msTouch) { - var idx = trackedTouches.indexOf(e.pointerId); - if (idx === -1) { - return; - } - trackedTouches.splice(idx, 1); - } - - if (doubleTap) { - if (L.Browser.msTouch) { - // work around .type being readonly with MSPointer* events - var newTouch = { }, - prop; - - // jshint forin:false - for (var i in touch) { - prop = touch[i]; - if (typeof prop === 'function') { - newTouch[i] = prop.bind(touch); - } else { - newTouch[i] = prop; - } - } - touch = newTouch; - } - touch.type = 'dblclick'; - handler(touch); - last = null; - } - } - obj[pre + touchstart + id] = onTouchStart; - obj[pre + touchend + id] = onTouchEnd; - - // on msTouch we need to listen on the document, otherwise a drag starting on the map and moving off screen - // will not come through to us, so we will lose track of how many touches are ongoing - var endElement = L.Browser.msTouch ? document.documentElement : obj; - - obj.addEventListener(touchstart, onTouchStart, false); - endElement.addEventListener(touchend, onTouchEnd, false); - - if (L.Browser.msTouch) { - endElement.addEventListener('MSPointerCancel', onTouchEnd, false); - } - - return this; - }, - - removeDoubleTapListener: function (obj, id) { - var pre = '_leaflet_'; - - obj.removeEventListener(this._touchstart, obj[pre + this._touchstart + id], false); - (L.Browser.msTouch ? document.documentElement : obj).removeEventListener( - this._touchend, obj[pre + this._touchend + id], false); - - if (L.Browser.msTouch) { - document.documentElement.removeEventListener('MSPointerCancel', obj[pre + this._touchend + id], false); - } - - return this; - } -}); - - -/* - * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices. - */ - -L.extend(L.DomEvent, { - - _msTouches: [], - _msDocumentListener: false, - - // Provides a touch events wrapper for msPointer events. - // Based on changes by veproza https://github.com/CloudMade/Leaflet/pull/1019 - - addMsTouchListener: function (obj, type, handler, id) { - - switch (type) { - case 'touchstart': - return this.addMsTouchListenerStart(obj, type, handler, id); - case 'touchend': - return this.addMsTouchListenerEnd(obj, type, handler, id); - case 'touchmove': - return this.addMsTouchListenerMove(obj, type, handler, id); - default: - throw 'Unknown touch event type'; - } - }, - - addMsTouchListenerStart: function (obj, type, handler, id) { - var pre = '_leaflet_', - touches = this._msTouches; - - var cb = function (e) { - - var alreadyInArray = false; - for (var i = 0; i < touches.length; i++) { - if (touches[i].pointerId === e.pointerId) { - alreadyInArray = true; - break; - } - } - if (!alreadyInArray) { - touches.push(e); - } - - e.touches = touches.slice(); - e.changedTouches = [e]; - - handler(e); - }; - - obj[pre + 'touchstart' + id] = cb; - obj.addEventListener('MSPointerDown', cb, false); - - // need to also listen for end events to keep the _msTouches list accurate - // this needs to be on the body and never go away - if (!this._msDocumentListener) { - var internalCb = function (e) { - for (var i = 0; i < touches.length; i++) { - if (touches[i].pointerId === e.pointerId) { - touches.splice(i, 1); - break; - } - } - }; - //We listen on the documentElement as any drags that end by moving the touch off the screen get fired there - document.documentElement.addEventListener('MSPointerUp', internalCb, false); - document.documentElement.addEventListener('MSPointerCancel', internalCb, false); - - this._msDocumentListener = true; - } - - return this; - }, - - addMsTouchListenerMove: function (obj, type, handler, id) { - var pre = '_leaflet_', - touches = this._msTouches; - - function cb(e) { - - // don't fire touch moves when mouse isn't down - if (e.pointerType === e.MSPOINTER_TYPE_MOUSE && e.buttons === 0) { return; } - - for (var i = 0; i < touches.length; i++) { - if (touches[i].pointerId === e.pointerId) { - touches[i] = e; - break; - } - } - - e.touches = touches.slice(); - e.changedTouches = [e]; - - handler(e); - } - - obj[pre + 'touchmove' + id] = cb; - obj.addEventListener('MSPointerMove', cb, false); - - return this; - }, - - addMsTouchListenerEnd: function (obj, type, handler, id) { - var pre = '_leaflet_', - touches = this._msTouches; - - var cb = function (e) { - for (var i = 0; i < touches.length; i++) { - if (touches[i].pointerId === e.pointerId) { - touches.splice(i, 1); - break; - } - } - - e.touches = touches.slice(); - e.changedTouches = [e]; - - handler(e); - }; - - obj[pre + 'touchend' + id] = cb; - obj.addEventListener('MSPointerUp', cb, false); - obj.addEventListener('MSPointerCancel', cb, false); - - return this; - }, - - removeMsTouchListener: function (obj, type, id) { - var pre = '_leaflet_', - cb = obj[pre + type + id]; - - switch (type) { - case 'touchstart': - obj.removeEventListener('MSPointerDown', cb, false); - break; - case 'touchmove': - obj.removeEventListener('MSPointerMove', cb, false); - break; - case 'touchend': - obj.removeEventListener('MSPointerUp', cb, false); - obj.removeEventListener('MSPointerCancel', cb, false); - break; - } - - return this; - } -}); - - -/* - * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers. - */ - -L.Map.mergeOptions({ - touchZoom: L.Browser.touch && !L.Browser.android23 -}); - -L.Map.TouchZoom = L.Handler.extend({ - addHooks: function () { - L.DomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this); - }, - - removeHooks: function () { - L.DomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this); - }, - - _onTouchStart: function (e) { - var map = this._map; - - if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; } - - var p1 = map.mouseEventToLayerPoint(e.touches[0]), - p2 = map.mouseEventToLayerPoint(e.touches[1]), - viewCenter = map._getCenterLayerPoint(); - - this._startCenter = p1.add(p2)._divideBy(2); - this._startDist = p1.distanceTo(p2); - - this._moved = false; - this._zooming = true; - - this._centerOffset = viewCenter.subtract(this._startCenter); - - if (map._panAnim) { - map._panAnim.stop(); - } - - L.DomEvent - .on(document, 'touchmove', this._onTouchMove, this) - .on(document, 'touchend', this._onTouchEnd, this); - - L.DomEvent.preventDefault(e); - }, - - _onTouchMove: function (e) { - var map = this._map; - - if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; } - - var p1 = map.mouseEventToLayerPoint(e.touches[0]), - p2 = map.mouseEventToLayerPoint(e.touches[1]); - - this._scale = p1.distanceTo(p2) / this._startDist; - this._delta = p1._add(p2)._divideBy(2)._subtract(this._startCenter); - - if (this._scale === 1) { return; } - - if (!this._moved) { - L.DomUtil.addClass(map._mapPane, 'leaflet-touching'); - - map - .fire('movestart') - .fire('zoomstart'); - - this._moved = true; - } - - L.Util.cancelAnimFrame(this._animRequest); - this._animRequest = L.Util.requestAnimFrame( - this._updateOnMove, this, true, this._map._container); - - L.DomEvent.preventDefault(e); - }, - - _updateOnMove: function () { - var map = this._map, - origin = this._getScaleOrigin(), - center = map.layerPointToLatLng(origin), - zoom = map.getScaleZoom(this._scale); - - map._animateZoom(center, zoom, this._startCenter, this._scale, this._delta); - }, - - _onTouchEnd: function () { - if (!this._moved || !this._zooming) { - this._zooming = false; - return; - } - - var map = this._map; - - this._zooming = false; - L.DomUtil.removeClass(map._mapPane, 'leaflet-touching'); - L.Util.cancelAnimFrame(this._animRequest); - - L.DomEvent - .off(document, 'touchmove', this._onTouchMove) - .off(document, 'touchend', this._onTouchEnd); - - var origin = this._getScaleOrigin(), - center = map.layerPointToLatLng(origin), - - oldZoom = map.getZoom(), - floatZoomDelta = map.getScaleZoom(this._scale) - oldZoom, - roundZoomDelta = (floatZoomDelta > 0 ? - Math.ceil(floatZoomDelta) : Math.floor(floatZoomDelta)), - - zoom = map._limitZoom(oldZoom + roundZoomDelta), - scale = map.getZoomScale(zoom) / this._scale; - - map._animateZoom(center, zoom, origin, scale); - }, - - _getScaleOrigin: function () { - var centerOffset = this._centerOffset.subtract(this._delta).divideBy(this._scale); - return this._startCenter.add(centerOffset); - } -}); - -L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom); - - -/* - * L.Handler.ShiftDragZoom is used to add shift-drag zoom interaction to the map - * (zoom to a selected bounding box), enabled by default. - */ - -L.Map.mergeOptions({ - boxZoom: true -}); - -L.Map.BoxZoom = L.Handler.extend({ - initialize: function (map) { - this._map = map; - this._container = map._container; - this._pane = map._panes.overlayPane; - }, - - addHooks: function () { - L.DomEvent.on(this._container, 'mousedown', this._onMouseDown, this); - }, - - removeHooks: function () { - L.DomEvent.off(this._container, 'mousedown', this._onMouseDown); - }, - - _onMouseDown: function (e) { - if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; } - - L.DomUtil.disableTextSelection(); - - this._startLayerPoint = this._map.mouseEventToLayerPoint(e); - - this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._pane); - L.DomUtil.setPosition(this._box, this._startLayerPoint); - - //TODO refactor: move cursor to styles - this._container.style.cursor = 'crosshair'; - - L.DomEvent - .on(document, 'mousemove', this._onMouseMove, this) - .on(document, 'mouseup', this._onMouseUp, this) - .on(document, 'keydown', this._onKeyDown, this) - .preventDefault(e); - - this._map.fire('boxzoomstart'); - }, - - _onMouseMove: function (e) { - var startPoint = this._startLayerPoint, - box = this._box, - - layerPoint = this._map.mouseEventToLayerPoint(e), - offset = layerPoint.subtract(startPoint), - - newPos = new L.Point( - Math.min(layerPoint.x, startPoint.x), - Math.min(layerPoint.y, startPoint.y)); - - L.DomUtil.setPosition(box, newPos); - - // TODO refactor: remove hardcoded 4 pixels - box.style.width = (Math.max(0, Math.abs(offset.x) - 4)) + 'px'; - box.style.height = (Math.max(0, Math.abs(offset.y) - 4)) + 'px'; - }, - - _finish: function () { - this._pane.removeChild(this._box); - this._container.style.cursor = ''; - - L.DomUtil.enableTextSelection(); - - L.DomEvent - .off(document, 'mousemove', this._onMouseMove) - .off(document, 'mouseup', this._onMouseUp) - .off(document, 'keydown', this._onKeyDown); - }, - - _onMouseUp: function (e) { - - this._finish(); - - var map = this._map, - layerPoint = map.mouseEventToLayerPoint(e); - - if (this._startLayerPoint.equals(layerPoint)) { return; } - - var bounds = new L.LatLngBounds( - map.layerPointToLatLng(this._startLayerPoint), - map.layerPointToLatLng(layerPoint)); - - map.fitBounds(bounds); - - map.fire('boxzoomend', { - boxZoomBounds: bounds - }); - }, - - _onKeyDown: function (e) { - if (e.keyCode === 27) { - this._finish(); - } - } -}); - -L.Map.addInitHook('addHandler', 'boxZoom', L.Map.BoxZoom); - - -/* - * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default. - */ - -L.Map.mergeOptions({ - keyboard: true, - keyboardPanOffset: 80, - keyboardZoomOffset: 1 -}); - -L.Map.Keyboard = L.Handler.extend({ - - keyCodes: { - left: [37], - right: [39], - down: [40], - up: [38], - zoomIn: [187, 107, 61], - zoomOut: [189, 109, 173] - }, - - initialize: function (map) { - this._map = map; - - this._setPanOffset(map.options.keyboardPanOffset); - this._setZoomOffset(map.options.keyboardZoomOffset); - }, - - addHooks: function () { - var container = this._map._container; - - // make the container focusable by tabbing - if (container.tabIndex === -1) { - container.tabIndex = '0'; - } - - L.DomEvent - .on(container, 'focus', this._onFocus, this) - .on(container, 'blur', this._onBlur, this) - .on(container, 'mousedown', this._onMouseDown, this); - - this._map - .on('focus', this._addHooks, this) - .on('blur', this._removeHooks, this); - }, - - removeHooks: function () { - this._removeHooks(); - - var container = this._map._container; - - L.DomEvent - .off(container, 'focus', this._onFocus, this) - .off(container, 'blur', this._onBlur, this) - .off(container, 'mousedown', this._onMouseDown, this); - - this._map - .off('focus', this._addHooks, this) - .off('blur', this._removeHooks, this); - }, - - _onMouseDown: function () { - if (this._focused) { return; } - - var body = document.body, - docEl = document.documentElement, - top = body.scrollTop || docEl.scrollTop, - left = body.scrollTop || docEl.scrollLeft; - - this._map._container.focus(); - - window.scrollTo(left, top); - }, - - _onFocus: function () { - this._focused = true; - this._map.fire('focus'); - }, - - _onBlur: function () { - this._focused = false; - this._map.fire('blur'); - }, - - _setPanOffset: function (pan) { - var keys = this._panKeys = {}, - codes = this.keyCodes, - i, len; - - for (i = 0, len = codes.left.length; i < len; i++) { - keys[codes.left[i]] = [-1 * pan, 0]; - } - for (i = 0, len = codes.right.length; i < len; i++) { - keys[codes.right[i]] = [pan, 0]; - } - for (i = 0, len = codes.down.length; i < len; i++) { - keys[codes.down[i]] = [0, pan]; - } - for (i = 0, len = codes.up.length; i < len; i++) { - keys[codes.up[i]] = [0, -1 * pan]; - } - }, - - _setZoomOffset: function (zoom) { - var keys = this._zoomKeys = {}, - codes = this.keyCodes, - i, len; - - for (i = 0, len = codes.zoomIn.length; i < len; i++) { - keys[codes.zoomIn[i]] = zoom; - } - for (i = 0, len = codes.zoomOut.length; i < len; i++) { - keys[codes.zoomOut[i]] = -zoom; - } - }, - - _addHooks: function () { - L.DomEvent.on(document, 'keydown', this._onKeyDown, this); - }, - - _removeHooks: function () { - L.DomEvent.off(document, 'keydown', this._onKeyDown, this); - }, - - _onKeyDown: function (e) { - var key = e.keyCode, - map = this._map; - - if (key in this._panKeys) { - map.panBy(this._panKeys[key]); - - if (map.options.maxBounds) { - map.panInsideBounds(map.options.maxBounds); - } - - } else if (key in this._zoomKeys) { - map.setZoom(map.getZoom() + this._zoomKeys[key]); - - } else { - return; - } - - L.DomEvent.stop(e); - } -}); - -L.Map.addInitHook('addHandler', 'keyboard', L.Map.Keyboard); - - -/* - * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable. - */ - -L.Handler.MarkerDrag = L.Handler.extend({ - initialize: function (marker) { - this._marker = marker; - }, - - addHooks: function () { - var icon = this._marker._icon; - if (!this._draggable) { - this._draggable = new L.Draggable(icon, icon); - } - - this._draggable - .on('dragstart', this._onDragStart, this) - .on('drag', this._onDrag, this) - .on('dragend', this._onDragEnd, this); - this._draggable.enable(); - }, - - removeHooks: function () { - this._draggable - .off('dragstart', this._onDragStart) - .off('drag', this._onDrag) - .off('dragend', this._onDragEnd); - - this._draggable.disable(); - }, - - moved: function () { - return this._draggable && this._draggable._moved; - }, - - _onDragStart: function () { - this._marker - .closePopup() - .fire('movestart') - .fire('dragstart'); - }, - - _onDrag: function () { - var marker = this._marker, - shadow = marker._shadow, - iconPos = L.DomUtil.getPosition(marker._icon), - latlng = marker._map.layerPointToLatLng(iconPos); - - // update shadow position - if (shadow) { - L.DomUtil.setPosition(shadow, iconPos); - } - - marker._latlng = latlng; - - marker - .fire('move', {latlng: latlng}) - .fire('drag'); - }, - - _onDragEnd: function () { - this._marker - .fire('moveend') - .fire('dragend'); - } -}); - - -/* - * L.Control is a base class for implementing map controls. Handles positioning. - * All other controls extend from this class. - */ - -L.Control = L.Class.extend({ - options: { - position: 'topright' - }, - - initialize: function (options) { - L.setOptions(this, options); - }, - - getPosition: function () { - return this.options.position; - }, - - setPosition: function (position) { - var map = this._map; - - if (map) { - map.removeControl(this); - } - - this.options.position = position; - - if (map) { - map.addControl(this); - } - - return this; - }, - - getContainer: function () { - return this._container; - }, - - addTo: function (map) { - this._map = map; - - var container = this._container = this.onAdd(map), - pos = this.getPosition(), - corner = map._controlCorners[pos]; - - L.DomUtil.addClass(container, 'leaflet-control'); - - if (pos.indexOf('bottom') !== -1) { - corner.insertBefore(container, corner.firstChild); - } else { - corner.appendChild(container); - } - - return this; - }, - - removeFrom: function (map) { - var pos = this.getPosition(), - corner = map._controlCorners[pos]; - - corner.removeChild(this._container); - this._map = null; - - if (this.onRemove) { - this.onRemove(map); - } - - return this; - } -}); - -L.control = function (options) { - return new L.Control(options); -}; - - -// adds control-related methods to L.Map - -L.Map.include({ - addControl: function (control) { - control.addTo(this); - return this; - }, - - removeControl: function (control) { - control.removeFrom(this); - return this; - }, - - _initControlPos: function () { - var corners = this._controlCorners = {}, - l = 'leaflet-', - container = this._controlContainer = - L.DomUtil.create('div', l + 'control-container', this._container); - - function createCorner(vSide, hSide) { - var className = l + vSide + ' ' + l + hSide; - - corners[vSide + hSide] = L.DomUtil.create('div', className, container); - } - - createCorner('top', 'left'); - createCorner('top', 'right'); - createCorner('bottom', 'left'); - createCorner('bottom', 'right'); - }, - - _clearControlPos: function () { - this._container.removeChild(this._controlContainer); - } -}); - - -/* - * L.Control.Zoom is used for the default zoom buttons on the map. - */ - -L.Control.Zoom = L.Control.extend({ - options: { - position: 'topleft' - }, - - onAdd: function (map) { - var zoomName = 'leaflet-control-zoom', - container = L.DomUtil.create('div', zoomName + ' leaflet-bar'); - - this._map = map; - - this._zoomInButton = this._createButton( - '+', 'Zoom in', zoomName + '-in', container, this._zoomIn, this); - this._zoomOutButton = this._createButton( - '-', 'Zoom out', zoomName + '-out', container, this._zoomOut, this); - - map.on('zoomend zoomlevelschange', this._updateDisabled, this); - - return container; - }, - - onRemove: function (map) { - map.off('zoomend zoomlevelschange', this._updateDisabled, this); - }, - - _zoomIn: function (e) { - this._map.zoomIn(e.shiftKey ? 3 : 1); - }, - - _zoomOut: function (e) { - this._map.zoomOut(e.shiftKey ? 3 : 1); - }, - - _createButton: function (html, title, className, container, fn, context) { - var link = L.DomUtil.create('a', className, container); - link.innerHTML = html; - link.href = '#'; - link.title = title; - - var stop = L.DomEvent.stopPropagation; - - L.DomEvent - .on(link, 'click', stop) - .on(link, 'mousedown', stop) - .on(link, 'dblclick', stop) - .on(link, 'click', L.DomEvent.preventDefault) - .on(link, 'click', fn, context); - - return link; - }, - - _updateDisabled: function () { - var map = this._map, - className = 'leaflet-disabled'; - - L.DomUtil.removeClass(this._zoomInButton, className); - L.DomUtil.removeClass(this._zoomOutButton, className); - - if (map._zoom === map.getMinZoom()) { - L.DomUtil.addClass(this._zoomOutButton, className); - } - if (map._zoom === map.getMaxZoom()) { - L.DomUtil.addClass(this._zoomInButton, className); - } - } -}); - -L.Map.mergeOptions({ - zoomControl: true -}); - -L.Map.addInitHook(function () { - if (this.options.zoomControl) { - this.zoomControl = new L.Control.Zoom(); - this.addControl(this.zoomControl); - } -}); - -L.control.zoom = function (options) { - return new L.Control.Zoom(options); -}; - - - -/* - * L.Control.Attribution is used for displaying attribution on the map (added by default). - */ - -L.Control.Attribution = L.Control.extend({ - options: { - position: 'bottomright', - prefix: 'Leaflet' - }, - - initialize: function (options) { - L.setOptions(this, options); - - this._attributions = {}; - }, - - onAdd: function (map) { - this._container = L.DomUtil.create('div', 'leaflet-control-attribution'); - L.DomEvent.disableClickPropagation(this._container); - - map - .on('layeradd', this._onLayerAdd, this) - .on('layerremove', this._onLayerRemove, this); - - this._update(); - - return this._container; - }, - - onRemove: function (map) { - map - .off('layeradd', this._onLayerAdd) - .off('layerremove', this._onLayerRemove); - - }, - - setPrefix: function (prefix) { - this.options.prefix = prefix; - this._update(); - return this; - }, - - addAttribution: function (text) { - if (!text) { return; } - - if (!this._attributions[text]) { - this._attributions[text] = 0; - } - this._attributions[text]++; - - this._update(); - - return this; - }, - - removeAttribution: function (text) { - if (!text) { return; } - - if (this._attributions[text]) { - this._attributions[text]--; - this._update(); - } - - return this; - }, - - _update: function () { - if (!this._map) { return; } - - var attribs = []; - - for (var i in this._attributions) { - if (this._attributions[i]) { - attribs.push(i); - } - } - - var prefixAndAttribs = []; - - if (this.options.prefix) { - prefixAndAttribs.push(this.options.prefix); - } - if (attribs.length) { - prefixAndAttribs.push(attribs.join(', ')); - } - - this._container.innerHTML = prefixAndAttribs.join(' | '); - }, - - _onLayerAdd: function (e) { - if (e.layer.getAttribution) { - this.addAttribution(e.layer.getAttribution()); - } - }, - - _onLayerRemove: function (e) { - if (e.layer.getAttribution) { - this.removeAttribution(e.layer.getAttribution()); - } - } -}); - -L.Map.mergeOptions({ - attributionControl: true -}); - -L.Map.addInitHook(function () { - if (this.options.attributionControl) { - this.attributionControl = (new L.Control.Attribution()).addTo(this); - } -}); - -L.control.attribution = function (options) { - return new L.Control.Attribution(options); -}; - - -/* - * L.Control.Scale is used for displaying metric/imperial scale on the map. - */ - -L.Control.Scale = L.Control.extend({ - options: { - position: 'bottomleft', - maxWidth: 100, - metric: true, - imperial: true, - updateWhenIdle: false - }, - - onAdd: function (map) { - this._map = map; - - var className = 'leaflet-control-scale', - container = L.DomUtil.create('div', className), - options = this.options; - - this._addScales(options, className, container); - - map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this); - map.whenReady(this._update, this); - - return container; - }, - - onRemove: function (map) { - map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this); - }, - - _addScales: function (options, className, container) { - if (options.metric) { - this._mScale = L.DomUtil.create('div', className + '-line', container); - } - if (options.imperial) { - this._iScale = L.DomUtil.create('div', className + '-line', container); - } - }, - - _update: function () { - var bounds = this._map.getBounds(), - centerLat = bounds.getCenter().lat, - halfWorldMeters = 6378137 * Math.PI * Math.cos(centerLat * Math.PI / 180), - dist = halfWorldMeters * (bounds.getNorthEast().lng - bounds.getSouthWest().lng) / 180, - - size = this._map.getSize(), - options = this.options, - maxMeters = 0; - - if (size.x > 0) { - maxMeters = dist * (options.maxWidth / size.x); - } - - this._updateScales(options, maxMeters); - }, - - _updateScales: function (options, maxMeters) { - if (options.metric && maxMeters) { - this._updateMetric(maxMeters); - } - - if (options.imperial && maxMeters) { - this._updateImperial(maxMeters); - } - }, - - _updateMetric: function (maxMeters) { - var meters = this._getRoundNum(maxMeters); - - this._mScale.style.width = this._getScaleWidth(meters / maxMeters) + 'px'; - this._mScale.innerHTML = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km'; - }, - - _updateImperial: function (maxMeters) { - var maxFeet = maxMeters * 3.2808399, - scale = this._iScale, - maxMiles, miles, feet; - - if (maxFeet > 5280) { - maxMiles = maxFeet / 5280; - miles = this._getRoundNum(maxMiles); - - scale.style.width = this._getScaleWidth(miles / maxMiles) + 'px'; - scale.innerHTML = miles + ' mi'; - - } else { - feet = this._getRoundNum(maxFeet); - - scale.style.width = this._getScaleWidth(feet / maxFeet) + 'px'; - scale.innerHTML = feet + ' ft'; - } - }, - - _getScaleWidth: function (ratio) { - return Math.round(this.options.maxWidth * ratio) - 10; - }, - - _getRoundNum: function (num) { - var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1), - d = num / pow10; - - d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : 1; - - return pow10 * d; - } -}); - -L.control.scale = function (options) { - return new L.Control.Scale(options); -}; - - -/* - * L.Control.Layers is a control to allow users to switch between different layers on the map. - */ - -L.Control.Layers = L.Control.extend({ - options: { - collapsed: true, - position: 'topright', - autoZIndex: true - }, - - initialize: function (baseLayers, overlays, options) { - L.setOptions(this, options); - - this._layers = {}; - this._lastZIndex = 0; - this._handlingClick = false; - - for (var i in baseLayers) { - this._addLayer(baseLayers[i], i); - } - - for (i in overlays) { - this._addLayer(overlays[i], i, true); - } - }, - - onAdd: function (map) { - this._initLayout(); - this._update(); - - map - .on('layeradd', this._onLayerChange, this) - .on('layerremove', this._onLayerChange, this); - - return this._container; - }, - - onRemove: function (map) { - map - .off('layeradd', this._onLayerChange) - .off('layerremove', this._onLayerChange); - }, - - addBaseLayer: function (layer, name) { - this._addLayer(layer, name); - this._update(); - return this; - }, - - addOverlay: function (layer, name) { - this._addLayer(layer, name, true); - this._update(); - return this; - }, - - removeLayer: function (layer) { - var id = L.stamp(layer); - delete this._layers[id]; - this._update(); - return this; - }, - - _initLayout: function () { - var className = 'leaflet-control-layers', - container = this._container = L.DomUtil.create('div', className); - - //Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released - container.setAttribute('aria-haspopup', true); - - if (!L.Browser.touch) { - L.DomEvent.disableClickPropagation(container); - L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation); - } else { - L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation); - } - - var form = this._form = L.DomUtil.create('form', className + '-list'); - - if (this.options.collapsed) { - L.DomEvent - .on(container, 'mouseover', this._expand, this) - .on(container, 'mouseout', this._collapse, this); - - var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container); - link.href = '#'; - link.title = 'Layers'; - - if (L.Browser.touch) { - L.DomEvent - .on(link, 'click', L.DomEvent.stopPropagation) - .on(link, 'click', L.DomEvent.preventDefault) - .on(link, 'click', this._expand, this); - } - else { - L.DomEvent.on(link, 'focus', this._expand, this); - } - - this._map.on('movestart', this._collapse, this); - // TODO keyboard accessibility - } else { - this._expand(); - } - - this._baseLayersList = L.DomUtil.create('div', className + '-base', form); - this._separator = L.DomUtil.create('div', className + '-separator', form); - this._overlaysList = L.DomUtil.create('div', className + '-overlays', form); - - container.appendChild(form); - }, - - _addLayer: function (layer, name, overlay) { - var id = L.stamp(layer); - - this._layers[id] = { - layer: layer, - name: name, - overlay: overlay - }; - - if (this.options.autoZIndex && layer.setZIndex) { - this._lastZIndex++; - layer.setZIndex(this._lastZIndex); - } - }, - - _update: function () { - if (!this._container) { - return; - } - - this._baseLayersList.innerHTML = ''; - this._overlaysList.innerHTML = ''; - - var baseLayersPresent = false, - overlaysPresent = false, - i, obj; - - for (i in this._layers) { - obj = this._layers[i]; - this._addItem(obj); - overlaysPresent = overlaysPresent || obj.overlay; - baseLayersPresent = baseLayersPresent || !obj.overlay; - } - - this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none'; - }, - - _onLayerChange: function (e) { - var id = L.stamp(e.layer); - - if (this._layers[id] && !this._handlingClick) { - this._update(); - } - }, - - // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe) - _createRadioElement: function (name, checked) { - - var radioHtml = ' this.options.zoomAnimationThreshold) { return false; } - - // offset is the pixel coords of the zoom origin relative to the current center - var scale = this.getZoomScale(zoom), - offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale), - origin = this._getCenterLayerPoint()._add(offset); - - // don't animate if the zoom origin isn't within one screen from the current center, unless forced - if (options.animate !== true && !this.getSize().contains(offset)) { return false; } - - this - .fire('movestart') - .fire('zoomstart'); - - this._animateZoom(center, zoom, origin, scale); - - return true; - }, - - _animateZoom: function (center, zoom, origin, scale, delta) { - - this._animatingZoom = true; - - // put transform transition on all layers with leaflet-zoom-animated class - L.DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim'); - - // remember what center/zoom to set after animation - this._animateToCenter = center; - this._animateToZoom = zoom; - - // disable any dragging during animation - if (L.Draggable) { - L.Draggable._disabled = true; - } - - this.fire('zoomanim', { - center: center, - zoom: zoom, - origin: origin, - scale: scale, - delta: delta - }); - }, - - _onZoomTransitionEnd: function () { - - this._animatingZoom = false; - - L.DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim'); - - this._resetView(this._animateToCenter, this._animateToZoom, true, true); - - if (L.Draggable) { - L.Draggable._disabled = false; - } - } -}); - - -/* - Zoom animation logic for L.TileLayer. -*/ - -L.TileLayer.include({ - _animateZoom: function (e) { - var firstFrame = false; - - if (!this._animating) { - this._animating = true; - firstFrame = true; - } - - if (firstFrame) { - this._prepareBgBuffer(); - } - - var bg = this._bgBuffer; - - if (firstFrame) { - //prevent bg buffer from clearing right after zoom - clearTimeout(this._clearBgBufferTimer); - - // hack to make sure transform is updated before running animation - L.Util.falseFn(bg.offsetWidth); - } - - var transform = L.DomUtil.TRANSFORM, - initialTransform = e.delta ? L.DomUtil.getTranslateString(e.delta) : bg.style[transform]; - - bg.style[transform] = initialTransform + ' ' + L.DomUtil.getScaleString(e.scale, e.origin); - }, - - _endZoomAnim: function () { - var front = this._tileContainer, - bg = this._bgBuffer; - - front.style.visibility = ''; - front.style.zIndex = 2; - - bg.style.zIndex = 1; - - // force reflow - L.Util.falseFn(bg.offsetWidth); - - this._animating = false; - }, - - _clearBgBuffer: function () { - var map = this._map; - - if (map && !map._animatingZoom && !map.touchZoom._zooming) { - this._bgBuffer.innerHTML = ''; - this._bgBuffer.style[L.DomUtil.TRANSFORM] = ''; - } - }, - - _prepareBgBuffer: function () { - - var front = this._tileContainer, - bg = this._bgBuffer; - - // if foreground layer doesn't have many tiles but bg layer does, - // keep the existing bg layer and just zoom it some more - - var bgLoaded = this._getLoadedTilesPercentage(bg), - frontLoaded = this._getLoadedTilesPercentage(front); - - if (bg && bgLoaded > 0.5 && frontLoaded < 0.5) { - - front.style.visibility = 'hidden'; - this._stopLoadingImages(front); - return; - } - - // prepare the buffer to become the front tile pane - bg.style.visibility = 'hidden'; - bg.style[L.DomUtil.TRANSFORM] = ''; - - // switch out the current layer to be the new bg layer (and vice-versa) - this._tileContainer = bg; - bg = this._bgBuffer = front; - - this._stopLoadingImages(bg); - }, - - _getLoadedTilesPercentage: function (container) { - var tiles = container.getElementsByTagName('img'), - i, len, count = 0; - - for (i = 0, len = tiles.length; i < len; i++) { - if (tiles[i].complete) { - count++; - } - } - return count / len; - }, - - // stops loading all tiles in the background layer - _stopLoadingImages: function (container) { - var tiles = Array.prototype.slice.call(container.getElementsByTagName('img')), - i, len, tile; - - for (i = 0, len = tiles.length; i < len; i++) { - tile = tiles[i]; - - if (!tile.complete) { - tile.onload = L.Util.falseFn; - tile.onerror = L.Util.falseFn; - tile.src = L.Util.emptyImageUrl; - - tile.parentNode.removeChild(tile); - } - } - } -}); - - -/* - * Provides L.Map with convenient shortcuts for using browser geolocation features. - */ - -L.Map.include({ - _defaultLocateOptions: { - watch: false, - setView: false, - maxZoom: Infinity, - timeout: 10000, - maximumAge: 0, - enableHighAccuracy: false - }, - - locate: function (/*Object*/ options) { - - options = this._locateOptions = L.extend(this._defaultLocateOptions, options); - - if (!navigator.geolocation) { - this._handleGeolocationError({ - code: 0, - message: 'Geolocation not supported.' - }); - return this; - } - - var onResponse = L.bind(this._handleGeolocationResponse, this), - onError = L.bind(this._handleGeolocationError, this); - - if (options.watch) { - this._locationWatchId = - navigator.geolocation.watchPosition(onResponse, onError, options); - } else { - navigator.geolocation.getCurrentPosition(onResponse, onError, options); - } - return this; - }, - - stopLocate: function () { - if (navigator.geolocation) { - navigator.geolocation.clearWatch(this._locationWatchId); - } - if (this._locateOptions) { - this._locateOptions.setView = false; - } - return this; - }, - - _handleGeolocationError: function (error) { - var c = error.code, - message = error.message || - (c === 1 ? 'permission denied' : - (c === 2 ? 'position unavailable' : 'timeout')); - - if (this._locateOptions.setView && !this._loaded) { - this.fitWorld(); - } - - this.fire('locationerror', { - code: c, - message: 'Geolocation error: ' + message + '.' - }); - }, - - _handleGeolocationResponse: function (pos) { - var lat = pos.coords.latitude, - lng = pos.coords.longitude, - latlng = new L.LatLng(lat, lng), - - latAccuracy = 180 * pos.coords.accuracy / 40075017, - lngAccuracy = latAccuracy / Math.cos(L.LatLng.DEG_TO_RAD * lat), - - bounds = L.latLngBounds( - [lat - latAccuracy, lng - lngAccuracy], - [lat + latAccuracy, lng + lngAccuracy]), - - options = this._locateOptions; - - if (options.setView) { - var zoom = Math.min(this.getBoundsZoom(bounds), options.maxZoom); - this.setView(latlng, zoom); - } - - var event = L.extend({ - latlng: latlng, - bounds: bounds - }, pos.coords); - - this.fire('locationfound', event); - } -}); - - -}(window, document)); \ No newline at end of file diff --git a/src/app/panels/bettermap/leaflet/leaflet.css b/src/app/panels/bettermap/leaflet/leaflet.css deleted file mode 100644 index ddb7e6b8b09..00000000000 --- a/src/app/panels/bettermap/leaflet/leaflet.css +++ /dev/null @@ -1,463 +0,0 @@ -/* required styles */ - -.leaflet-map-pane, -.leaflet-tile, -.leaflet-marker-icon, -.leaflet-marker-shadow, -.leaflet-tile-pane, -.leaflet-tile-container, -.leaflet-overlay-pane, -.leaflet-shadow-pane, -.leaflet-marker-pane, -.leaflet-popup-pane, -.leaflet-overlay-pane svg, -.leaflet-zoom-box, -.leaflet-image-layer, -.leaflet-layer { - position: absolute; - left: 0; - top: 0; - } -.leaflet-container { - overflow: hidden; - -ms-touch-action: none; - } -.leaflet-tile, -.leaflet-marker-icon, -.leaflet-marker-shadow { - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - -webkit-user-drag: none; - } -.leaflet-marker-icon, -.leaflet-marker-shadow { - display: block; - } -/* map is broken in FF if you have max-width: 100% on tiles */ -.leaflet-container img { - max-width: none !important; - } -/* stupid Android 2 doesn't understand "max-width: none" properly */ -.leaflet-container img.leaflet-image-layer { - max-width: 15000px !important; - } -.leaflet-tile { - filter: inherit; - visibility: hidden; - } -.leaflet-tile-loaded { - visibility: inherit; - } -.leaflet-zoom-box { - width: 0; - height: 0; - } - -.leaflet-tile-pane { z-index: 2; } -.leaflet-objects-pane { z-index: 3; } -.leaflet-overlay-pane { z-index: 4; } -.leaflet-shadow-pane { z-index: 5; } -.leaflet-marker-pane { z-index: 6; } -.leaflet-popup-pane { z-index: 7; } - - -/* control positioning */ - -.leaflet-control { - position: relative; - z-index: 7; - pointer-events: auto; - } -.leaflet-top, -.leaflet-bottom { - position: absolute; - z-index: 1000; - pointer-events: none; - } -.leaflet-top { - top: 0; - } -.leaflet-right { - right: 0; - } -.leaflet-bottom { - bottom: 0; - } -.leaflet-left { - left: 0; - } -.leaflet-control { - float: left; - clear: both; - } -.leaflet-right .leaflet-control { - float: right; - } -.leaflet-top .leaflet-control { - margin-top: 10px; - } -.leaflet-bottom .leaflet-control { - margin-bottom: 10px; - } -.leaflet-left .leaflet-control { - margin-left: 10px; - } -.leaflet-right .leaflet-control { - margin-right: 10px; - } - - -/* zoom and fade animations */ - -.leaflet-fade-anim .leaflet-tile, -.leaflet-fade-anim .leaflet-popup { - opacity: 0; - -webkit-transition: opacity 0.2s linear; - -moz-transition: opacity 0.2s linear; - -o-transition: opacity 0.2s linear; - transition: opacity 0.2s linear; - } -.leaflet-fade-anim .leaflet-tile-loaded, -.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { - opacity: 1; - } - -.leaflet-zoom-anim .leaflet-zoom-animated { - -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); - -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); - -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1); - transition: transform 0.25s cubic-bezier(0,0,0.25,1); - } -.leaflet-zoom-anim .leaflet-tile, -.leaflet-pan-anim .leaflet-tile, -.leaflet-touching .leaflet-zoom-animated { - -webkit-transition: none; - -moz-transition: none; - -o-transition: none; - transition: none; - } - -.leaflet-zoom-anim .leaflet-zoom-hide { - visibility: hidden; - } - - -/* cursors */ - -.leaflet-clickable { - cursor: pointer; - } -.leaflet-container { - cursor: -webkit-grab; - cursor: -moz-grab; - } -.leaflet-popup-pane, -.leaflet-control { - cursor: auto; - } -.leaflet-dragging, -.leaflet-dragging .leaflet-clickable, -.leaflet-dragging .leaflet-container { - cursor: move; - cursor: -webkit-grabbing; - cursor: -moz-grabbing; - } - - -/* visual tweaks */ - -.leaflet-container { - background: #ddd; - outline: 0; - } -.leaflet-container a { - color: #0078A8; - } -.leaflet-container a.leaflet-active { - outline: 2px solid orange; - } -.leaflet-zoom-box { - border: 2px dotted #05f; - background: white; - opacity: 0.5; - } - - -/* general typography */ -.leaflet-container { - font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; - } - - -/* general toolbar styles */ - -.leaflet-bar { - box-shadow: 0 1px 7px rgba(0,0,0,0.65); - -webkit-border-radius: 4px; - border-radius: 4px; - } -.leaflet-bar a { - background-color: #fff; - border-bottom: 1px solid #ccc; - width: 26px; - height: 26px; - line-height: 26px; - display: block; - text-align: center; - text-decoration: none; - color: black; - } -.leaflet-bar a, -.leaflet-control-layers-toggle { - background-position: 50% 50%; - background-repeat: no-repeat; - display: block; - } -.leaflet-bar a:hover { - background-color: #f4f4f4; - } -.leaflet-bar a:first-child { - -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - } -.leaflet-bar a:last-child { - -webkit-border-bottom-left-radius: 4px; - border-bottom-left-radius: 4px; - -webkit-border-bottom-right-radius: 4px; - border-bottom-right-radius: 4px; - border-bottom: none; - } -.leaflet-bar a.leaflet-disabled { - cursor: default; - background-color: #f4f4f4; - color: #bbb; - } - -.leaflet-touch .leaflet-bar { - -webkit-border-radius: 10px; - border-radius: 10px; - } -.leaflet-touch .leaflet-bar a { - width: 30px; - height: 30px; - } -.leaflet-touch .leaflet-bar a:first-child { - -webkit-border-top-left-radius: 7px; - border-top-left-radius: 7px; - -webkit-border-top-right-radius: 7px; - border-top-right-radius: 7px; - } -.leaflet-touch .leaflet-bar a:last-child { - -webkit-border-bottom-left-radius: 7px; - border-bottom-left-radius: 7px; - -webkit-border-bottom-right-radius: 7px; - border-bottom-right-radius: 7px; - border-bottom: none; - } - - -/* zoom control */ - -.leaflet-control-zoom-in { - font: bold 18px 'Lucida Console', Monaco, monospace; - } -.leaflet-control-zoom-out { - font: bold 22px 'Lucida Console', Monaco, monospace; - } - -.leaflet-touch .leaflet-control-zoom-in { - font-size: 22px; - line-height: 30px; - } -.leaflet-touch .leaflet-control-zoom-out { - font-size: 28px; - line-height: 30px; - } - - -/* layers control */ - -.leaflet-control-layers { - box-shadow: 0 1px 7px rgba(0,0,0,0.4); - background: #f8f8f9; - -webkit-border-radius: 5px; - border-radius: 5px; - } -.leaflet-control-layers-toggle { - background-image: url(images/layers.png); - width: 36px; - height: 36px; - } -.leaflet-retina .leaflet-control-layers-toggle { - background-image: url(images/layers-2x.png); - background-size: 26px 26px; - } -.leaflet-touch .leaflet-control-layers-toggle { - width: 44px; - height: 44px; - } -.leaflet-control-layers .leaflet-control-layers-list, -.leaflet-control-layers-expanded .leaflet-control-layers-toggle { - display: none; - } -.leaflet-control-layers-expanded .leaflet-control-layers-list { - display: block; - position: relative; - } -.leaflet-control-layers-expanded { - padding: 6px 10px 6px 6px; - color: #333; - background: #fff; - } -.leaflet-control-layers-selector { - margin-top: 2px; - position: relative; - top: 1px; - } -.leaflet-control-layers label { - display: block; - } -.leaflet-control-layers-separator { - height: 0; - border-top: 1px solid #ddd; - margin: 5px -10px 5px -6px; - } - - -/* attribution and scale controls */ - -.leaflet-container .leaflet-control-attribution { - background-color: rgba(255, 255, 255, 0.7); - box-shadow: 0 0 5px #bbb; - margin: 0; - } -.leaflet-control-attribution, -.leaflet-control-scale-line { - padding: 0 5px; - color: #333; - } -.leaflet-container .leaflet-control-attribution, -.leaflet-container .leaflet-control-scale { - font-size: 11px; - } -.leaflet-left .leaflet-control-scale { - margin-left: 5px; - } -.leaflet-bottom .leaflet-control-scale { - margin-bottom: 5px; - } -.leaflet-control-scale-line { - border: 2px solid #777; - border-top: none; - color: black; - line-height: 1.1; - padding: 2px 5px 1px; - font-size: 11px; - text-shadow: 1px 1px 1px #fff; - background-color: rgba(255, 255, 255, 0.5); - box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.2); - white-space: nowrap; - overflow: hidden; - } -.leaflet-control-scale-line:not(:first-child) { - border-top: 2px solid #777; - border-bottom: none; - margin-top: -2px; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - } -.leaflet-control-scale-line:not(:first-child):not(:last-child) { - border-bottom: 2px solid #777; - } - -.leaflet-touch .leaflet-control-attribution, -.leaflet-touch .leaflet-control-layers, -.leaflet-touch .leaflet-control-zoom { - box-shadow: none; - } -.leaflet-touch .leaflet-control-layers, -.leaflet-touch .leaflet-control-zoom { - border: 4px solid rgba(0,0,0,0.3); - } - - -/* popup */ - -.leaflet-popup { - position: absolute; - text-align: center; - } -.leaflet-popup-content-wrapper { - padding: 1px; - text-align: left; - -webkit-border-radius: 12px; - border-radius: 12px; - } -.leaflet-popup-content { - margin: 13px 19px; - line-height: 1.4; - } -.leaflet-popup-content p { - margin: 18px 0; - } -.leaflet-popup-tip-container { - margin: 0 auto; - width: 40px; - height: 20px; - position: relative; - overflow: hidden; - } -.leaflet-popup-tip { - width: 17px; - height: 17px; - padding: 1px; - - margin: -10px auto 0; - - -webkit-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -ms-transform: rotate(45deg); - -o-transform: rotate(45deg); - transform: rotate(45deg); - } -.leaflet-popup-content-wrapper, .leaflet-popup-tip { - background: white; - - box-shadow: 0 3px 14px rgba(0,0,0,0.4); - } -.leaflet-container a.leaflet-popup-close-button { - position: absolute; - top: 0; - right: 0; - padding: 4px 4px 0 0; - text-align: center; - width: 18px; - height: 14px; - font: 16px/14px Tahoma, Verdana, sans-serif; - color: #c3c3c3; - text-decoration: none; - font-weight: bold; - background: transparent; - } -.leaflet-container a.leaflet-popup-close-button:hover { - color: #999; - } -.leaflet-popup-scrolled { - overflow: auto; - border-bottom: 1px solid #ddd; - border-top: 1px solid #ddd; - } - - -/* div icon */ - -.leaflet-div-icon { - background: #fff; - border: 1px solid #666; - } -.leaflet-editing-icon { - -webkit-border-radius: 2px; - border-radius: 2px; - } diff --git a/src/app/panels/bettermap/leaflet/leaflet.ie.css b/src/app/panels/bettermap/leaflet/leaflet.ie.css deleted file mode 100644 index 14b84b691e9..00000000000 --- a/src/app/panels/bettermap/leaflet/leaflet.ie.css +++ /dev/null @@ -1,51 +0,0 @@ -.leaflet-vml-shape { - width: 1px; - height: 1px; - } -.lvml { - behavior: url(#default#VML); - display: inline-block; - position: absolute; - } - -.leaflet-control { - display: inline; - } - -.leaflet-popup-tip { - width: 21px; - _width: 27px; - margin: 0 auto; - _margin-top: -3px; - - filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); - -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; - } -.leaflet-popup-tip-container { - margin-top: -1px; - } -.leaflet-popup-content-wrapper, .leaflet-popup-tip { - border: 1px solid #999; - } -.leaflet-popup-content-wrapper { - zoom: 1; - } - -.leaflet-control-zoom, -.leaflet-control-layers { - border: 3px solid #999; - } -.leaflet-control-layers-toggle { - } -.leaflet-control-attribution, -.leaflet-control-layers, -.leaflet-control-scale-line { - background: white; - } -.leaflet-zoom-box { - filter: alpha(opacity=50); - } -.leaflet-control-attribution { - border-top: 1px solid #bbb; - border-left: 1px solid #bbb; - } diff --git a/src/app/panels/bettermap/leaflet/leaflet.js b/src/app/panels/bettermap/leaflet/leaflet.js deleted file mode 100644 index a343bd38642..00000000000 --- a/src/app/panels/bettermap/leaflet/leaflet.js +++ /dev/null @@ -1,8 +0,0 @@ -/* - Leaflet, a JavaScript library for mobile-friendly interactive maps. http://leafletjs.com - (c) 2010-2013, Vladimir Agafonkin, CloudMade -*/ -!function(t,e,i){var n=t.L,o={};o.version="0.6-dev","object"==typeof module&&"object"==typeof module.exports?module.exports=o:"function"==typeof define&&define.amd&&define("leaflet",[],function(){return o}),o.noConflict=function(){return t.L=n,this},t.L=o,o.Util={extend:function(t){var e,i,n,o,s=Array.prototype.slice.call(arguments,1);for(i=0,n=s.length;n>i;i++){o=s[i]||{};for(e in o)o.hasOwnProperty(e)&&(t[e]=o[e])}return t},bind:function(t,e){var i=arguments.length>2?Array.prototype.slice.call(arguments,2):null;return function(){return t.apply(e,i||arguments)}},stamp:function(){var t=0,e="_leaflet_id";return function(i){return i[e]=i[e]||++t,i[e]}}(),invokeEach:function(t,e,i){var n,o;if("object"==typeof t){o=Array.prototype.slice.call(arguments,3);for(n in t)e.apply(i,[n,t[n]].concat(o));return!0}return!1},limitExecByInterval:function(t,e,i){var n,o;return function s(){var a=arguments;return n?(o=!0,void 0):(n=!0,setTimeout(function(){n=!1,o&&(s.apply(i,a),o=!1)},e),t.apply(i,a),void 0)}},falseFn:function(){return!1},formatNum:function(t,e){var i=Math.pow(10,e||5);return Math.round(t*i)/i},trim:function(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")},splitWords:function(t){return o.Util.trim(t).split(/\s+/)},setOptions:function(t,e){return t.options=o.extend({},t.options,e),t.options},getParamString:function(t,e,i){var n=[];for(var o in t)n.push(encodeURIComponent(i?o.toUpperCase():o)+"="+encodeURIComponent(t[o]));return(e&&-1!==e.indexOf("?")?"&":"?")+n.join("&")},template:function(t,e){return t.replace(/\{ *([\w_]+) *\}/g,function(t,n){var o=e[n];if(o===i)throw new Error("No value provided for variable "+t);return"function"==typeof o&&(o=o(e)),o})},isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)},emptyImageUrl:"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="},function(){function e(e){var i,n,o=["webkit","moz","o","ms"];for(i=0;it;t++)n._initHooks[t].call(this)}},e},o.Class.include=function(t){o.extend(this.prototype,t)},o.Class.mergeOptions=function(t){o.extend(this.prototype.options,t)},o.Class.addInitHook=function(t){var e=Array.prototype.slice.call(arguments,1),i="function"==typeof t?t:function(){this[t].apply(this,e)};this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(i)};var s="_leaflet_events";o.Mixin={},o.Mixin.Events={addEventListener:function(t,e,i){if(o.Util.invokeEach(t,this.addEventListener,this,e,i))return this;var n,a,r,h,l,u,c,d=this[s]=this[s]||{},_=i&&o.stamp(i);for(t=o.Util.splitWords(t),n=0,a=t.length;a>n;n++)r={action:e,context:i||this},h=t[n],i?(l=h+"_idx",u=l+"_len",c=d[l]=d[l]||{},c[_]||(c[_]=[],d[u]=(d[u]||0)+1),c[_].push(r)):(d[h]=d[h]||[],d[h].push(r));return this},hasEventListeners:function(t){var e=this[s];return!!e&&(t in e&&e[t].length>0||t+"_idx"in e&&e[t+"_idx_len"]>0)},removeEventListener:function(t,e,i){if(!this[s])return this;if(!t)return this.clearAllEventListeners();if(o.Util.invokeEach(t,this.removeEventListener,this,e,i))return this;var n,a,r,h,l,u,c,d,_,p=this[s],m=i&&o.stamp(i);for(t=o.Util.splitWords(t),n=0,a=t.length;a>n;n++)if(r=t[n],u=r+"_idx",c=u+"_len",d=p[u],e){if(h=i&&d?d[m]:p[r]){for(l=h.length-1;l>=0;l--)h[l].action!==e||i&&h[l].context!==i||(_=h.splice(l,1),_[0].action=o.Util.falseFn);i&&d&&0===h.length&&(delete d[m],p[c]--)}}else delete p[r],delete p[u];return this},clearAllEventListeners:function(){return delete this[s],this},fireEvent:function(t,e){if(!this.hasEventListeners(t))return this;var i,n,a,r,h,l=o.Util.extend({},e,{type:t,target:this}),u=this[s];if(u[t])for(i=u[t].slice(),n=0,a=i.length;a>n;n++)i[n].action.call(i[n].context||this,l);r=u[t+"_idx"];for(h in r)if(i=r[h].slice())for(n=0,a=i.length;a>n;n++)i[n].action.call(i[n].context||this,l);return this},addOneTimeEventListener:function(t,e,i){if(o.Util.invokeEach(t,this.addOneTimeEventListener,this,e,i))return this;var n=o.bind(function(){this.removeEventListener(t,e,i).removeEventListener(t,n,i)},this);return this.addEventListener(t,e,i).addEventListener(t,n,i)}},o.Mixin.Events.on=o.Mixin.Events.addEventListener,o.Mixin.Events.off=o.Mixin.Events.removeEventListener,o.Mixin.Events.once=o.Mixin.Events.addOneTimeEventListener,o.Mixin.Events.fire=o.Mixin.Events.fireEvent,function(){var n=!!t.ActiveXObject,s=n&&!t.XMLHttpRequest,a=n&&!e.querySelector,r=n&&!e.addEventListener,h=navigator.userAgent.toLowerCase(),l=-1!==h.indexOf("webkit"),u=-1!==h.indexOf("chrome"),c=-1!==h.indexOf("phantom"),d=-1!==h.indexOf("android"),_=-1!==h.search("android [23]"),p=typeof orientation!=i+"",m=t.navigator&&t.navigator.msPointerEnabled&&t.navigator.msMaxTouchPoints,f="devicePixelRatio"in t&&t.devicePixelRatio>1||"matchMedia"in t&&t.matchMedia("(min-resolution:144dpi)")&&t.matchMedia("(min-resolution:144dpi)").matches,g=e.documentElement,v=n&&"transition"in g.style,y="WebKitCSSMatrix"in t&&"m11"in new t.WebKitCSSMatrix,L="MozPerspective"in g.style,P="OTransition"in g.style,x=!t.L_DISABLE_3D&&(v||y||L||P)&&!c,w=!t.L_NO_TOUCH&&!c&&function(){var t="ontouchstart";if(m||t in g)return!0;var i=e.createElement("div"),n=!1;return i.setAttribute?(i.setAttribute(t,"return;"),"function"==typeof i[t]&&(n=!0),i.removeAttribute(t),i=null,n):!1}();o.Browser={ie:n,ie6:s,ie7:a,ielt9:r,webkit:l,android:d,android23:_,chrome:u,ie3d:v,webkit3d:y,gecko3d:L,opera3d:P,any3d:x,mobile:p,mobileWebkit:p&&l,mobileWebkit3d:p&&y,mobileOpera:p&&t.opera,touch:w,msTouch:m,retina:f}}(),o.Point=function(t,e,i){this.x=i?Math.round(t):t,this.y=i?Math.round(e):e},o.Point.prototype={clone:function(){return new o.Point(this.x,this.y)},add:function(t){return this.clone()._add(o.point(t))},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(o.point(t))},_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t){return this.clone()._divideBy(t)},_divideBy:function(t){return this.x/=t,this.y/=t,this},multiplyBy:function(t){return this.clone()._multiplyBy(t)},_multiplyBy:function(t){return this.x*=t,this.y*=t,this},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},distanceTo:function(t){t=o.point(t);var e=t.x-this.x,i=t.y-this.y;return Math.sqrt(e*e+i*i)},equals:function(t){return t=o.point(t),t.x===this.x&&t.y===this.y},contains:function(t){return t=o.point(t),Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y)},toString:function(){return"Point("+o.Util.formatNum(this.x)+", "+o.Util.formatNum(this.y)+")"}},o.point=function(t,e,n){return t instanceof o.Point?t:o.Util.isArray(t)?new o.Point(t[0],t[1]):t===i||null===t?t:new o.Point(t,e,n)},o.Bounds=function(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;o>n;n++)this.extend(i[n])},o.Bounds.prototype={extend:function(t){return t=o.point(t),this.min||this.max?(this.min.x=Math.min(t.x,this.min.x),this.max.x=Math.max(t.x,this.max.x),this.min.y=Math.min(t.y,this.min.y),this.max.y=Math.max(t.y,this.max.y)):(this.min=t.clone(),this.max=t.clone()),this},getCenter:function(t){return new o.Point((this.min.x+this.max.x)/2,(this.min.y+this.max.y)/2,t)},getBottomLeft:function(){return new o.Point(this.min.x,this.max.y)},getTopRight:function(){return new o.Point(this.max.x,this.min.y)},getSize:function(){return this.max.subtract(this.min)},contains:function(t){var e,i;return t="number"==typeof t[0]||t instanceof o.Point?o.point(t):o.bounds(t),t instanceof o.Bounds?(e=t.min,i=t.max):e=i=t,e.x>=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=o.bounds(t);var e=this.min,i=this.max,n=t.min,s=t.max,a=s.x>=e.x&&n.x<=i.x,r=s.y>=e.y&&n.y<=i.y;return a&&r},isValid:function(){return!(!this.min||!this.max)}},o.bounds=function(t,e){return!t||t instanceof o.Bounds?t:new o.Bounds(t,e)},o.Transformation=function(t,e,i,n){this._a=t,this._b=e,this._c=i,this._d=n},o.Transformation.prototype={transform:function(t,e){return this._transform(t.clone(),e)},_transform:function(t,e){return e=e||1,t.x=e*(this._a*t.x+this._b),t.y=e*(this._c*t.y+this._d),t},untransform:function(t,e){return e=e||1,new o.Point((t.x/e-this._b)/this._a,(t.y/e-this._d)/this._c)}},o.DomUtil={get:function(t){return"string"==typeof t?e.getElementById(t):t},getStyle:function(t,i){var n=t.style[i];if(!n&&t.currentStyle&&(n=t.currentStyle[i]),(!n||"auto"===n)&&e.defaultView){var o=e.defaultView.getComputedStyle(t,null);n=o?o[i]:null}return"auto"===n?null:n},getViewportOffset:function(t){var i,n=0,s=0,a=t,r=e.body,h=e.documentElement,l=o.Browser.ie7;do{if(n+=a.offsetTop||0,s+=a.offsetLeft||0,n+=parseInt(o.DomUtil.getStyle(a,"borderTopWidth"),10)||0,s+=parseInt(o.DomUtil.getStyle(a,"borderLeftWidth"),10)||0,i=o.DomUtil.getStyle(a,"position"),a.offsetParent===r&&"absolute"===i)break;if("fixed"===i){n+=r.scrollTop||h.scrollTop||0,s+=r.scrollLeft||h.scrollLeft||0;break}if("relative"===i&&!a.offsetLeft){var u=o.DomUtil.getStyle(a,"width"),c=o.DomUtil.getStyle(a,"max-width"),d=a.getBoundingClientRect();("none"!==u||"none"!==c)&&(s+=d.left+a.clientLeft),n+=d.top+(r.scrollTop||h.scrollTop||0);break}a=a.offsetParent}while(a);a=t;do{if(a===r)break;n-=a.scrollTop||0,s-=a.scrollLeft||0,o.DomUtil.documentIsLtr()||!o.Browser.webkit&&!l||(s+=a.scrollWidth-a.clientWidth,l&&"hidden"!==o.DomUtil.getStyle(a,"overflow-y")&&"hidden"!==o.DomUtil.getStyle(a,"overflow")&&(s+=17)),a=a.parentNode}while(a);return new o.Point(s,n)},documentIsLtr:function(){return o.DomUtil._docIsLtrCached||(o.DomUtil._docIsLtrCached=!0,o.DomUtil._docIsLtr="ltr"===o.DomUtil.getStyle(e.body,"direction")),o.DomUtil._docIsLtr},create:function(t,i,n){var o=e.createElement(t);return o.className=i,n&&n.appendChild(o),o},disableTextSelection:function(){e.selection&&e.selection.empty&&e.selection.empty(),this._onselectstart||(this._onselectstart=e.onselectstart||null,e.onselectstart=o.Util.falseFn)},enableTextSelection:function(){e.onselectstart===o.Util.falseFn&&(e.onselectstart=this._onselectstart,this._onselectstart=null)},hasClass:function(t,e){return t.className.length>0&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(t.className)},addClass:function(t,e){o.DomUtil.hasClass(t,e)||(t.className+=(t.className?" ":"")+e)},removeClass:function(t,e){t.className=o.Util.trim((" "+t.className+" ").replace(" "+e+" "," "))},setOpacity:function(t,e){if("opacity"in t.style)t.style.opacity=e;else if("filter"in t.style){var i=!1,n="DXImageTransform.Microsoft.Alpha";try{i=t.filters.item(n)}catch(o){if(1===e)return}e=Math.round(100*e),i?(i.Enabled=100!==e,i.Opacity=e):t.style.filter+=" progid:"+n+"(opacity="+e+")"}},testProp:function(t){for(var i=e.documentElement.style,n=0;ni||i===e?e:t),new o.LatLng(this.lat,i)}},o.latLng=function(t,e){return t instanceof o.LatLng?t:o.Util.isArray(t)?new o.LatLng(t[0],t[1]):t===i||null===t?t:"object"==typeof t&&"lat"in t?new o.LatLng(t.lat,"lng"in t?t.lng:t.lon):new o.LatLng(t,e)},o.LatLngBounds=function(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;o>n;n++)this.extend(i[n])},o.LatLngBounds.prototype={extend:function(t){return t?(t="number"==typeof t[0]||"string"==typeof t[0]||t instanceof o.LatLng?o.latLng(t):o.latLngBounds(t),t instanceof o.LatLng?this._southWest||this._northEast?(this._southWest.lat=Math.min(t.lat,this._southWest.lat),this._southWest.lng=Math.min(t.lng,this._southWest.lng),this._northEast.lat=Math.max(t.lat,this._northEast.lat),this._northEast.lng=Math.max(t.lng,this._northEast.lng)):(this._southWest=new o.LatLng(t.lat,t.lng),this._northEast=new o.LatLng(t.lat,t.lng)):t instanceof o.LatLngBounds&&(this.extend(t._southWest),this.extend(t._northEast)),this):this},pad:function(t){var e=this._southWest,i=this._northEast,n=Math.abs(e.lat-i.lat)*t,s=Math.abs(e.lng-i.lng)*t;return new o.LatLngBounds(new o.LatLng(e.lat-n,e.lng-s),new o.LatLng(i.lat+n,i.lng+s))},getCenter:function(){return new o.LatLng((this._southWest.lat+this._northEast.lat)/2,(this._southWest.lng+this._northEast.lng)/2)},getSouthWest:function(){return this._southWest},getNorthEast:function(){return this._northEast},getNorthWest:function(){return new o.LatLng(this.getNorth(),this.getWest())},getSouthEast:function(){return new o.LatLng(this.getSouth(),this.getEast())},getWest:function(){return this._southWest.lng},getSouth:function(){return this._southWest.lat},getEast:function(){return this._northEast.lng},getNorth:function(){return this._northEast.lat},contains:function(t){t="number"==typeof t[0]||t instanceof o.LatLng?o.latLng(t):o.latLngBounds(t);var e,i,n=this._southWest,s=this._northEast;return t instanceof o.LatLngBounds?(e=t.getSouthWest(),i=t.getNorthEast()):e=i=t,e.lat>=n.lat&&i.lat<=s.lat&&e.lng>=n.lng&&i.lng<=s.lng},intersects:function(t){t=o.latLngBounds(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),s=t.getNorthEast(),a=s.lat>=e.lat&&n.lat<=i.lat,r=s.lng>=e.lng&&n.lng<=i.lng;return a&&r},toBBoxString:function(){return[this.getWest(),this.getSouth(),this.getEast(),this.getNorth()].join(",")},equals:function(t){return t?(t=o.latLngBounds(t),this._southWest.equals(t.getSouthWest())&&this._northEast.equals(t.getNorthEast())):!1},isValid:function(){return!(!this._southWest||!this._northEast)}},o.latLngBounds=function(t,e){return!t||t instanceof o.LatLngBounds?t:new o.LatLngBounds(t,e)},o.Projection={},o.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(t){var e=o.LatLng.DEG_TO_RAD,i=this.MAX_LATITUDE,n=Math.max(Math.min(i,t.lat),-i),s=t.lng*e,a=n*e;return a=Math.log(Math.tan(Math.PI/4+a/2)),new o.Point(s,a)},unproject:function(t){var e=o.LatLng.RAD_TO_DEG,i=t.x*e,n=(2*Math.atan(Math.exp(t.y))-Math.PI/2)*e;return new o.LatLng(n,i)}},o.Projection.LonLat={project:function(t){return new o.Point(t.lng,t.lat)},unproject:function(t){return new o.LatLng(t.y,t.x)}},o.CRS={latLngToPoint:function(t,e){var i=this.projection.project(t),n=this.scale(e);return this.transformation._transform(i,n)},pointToLatLng:function(t,e){var i=this.scale(e),n=this.transformation.untransform(t,i);return this.projection.unproject(n)},project:function(t){return this.projection.project(t)},scale:function(t){return 256*Math.pow(2,t)}},o.CRS.Simple=o.extend({},o.CRS,{projection:o.Projection.LonLat,transformation:new o.Transformation(1,0,-1,0),scale:function(t){return Math.pow(2,t)}}),o.CRS.EPSG3857=o.extend({},o.CRS,{code:"EPSG:3857",projection:o.Projection.SphericalMercator,transformation:new o.Transformation(.5/Math.PI,.5,-.5/Math.PI,.5),project:function(t){var e=this.projection.project(t),i=6378137;return e.multiplyBy(i)}}),o.CRS.EPSG900913=o.extend({},o.CRS.EPSG3857,{code:"EPSG:900913"}),o.CRS.EPSG4326=o.extend({},o.CRS,{code:"EPSG:4326",projection:o.Projection.LonLat,transformation:new o.Transformation(1/360,.5,-1/360,.5)}),o.Map=o.Class.extend({includes:o.Mixin.Events,options:{crs:o.CRS.EPSG3857,fadeAnimation:o.DomUtil.TRANSITION&&!o.Browser.android23,trackResize:!0,markerZoomAnimation:o.DomUtil.TRANSITION&&o.Browser.any3d},initialize:function(t,e){e=o.setOptions(this,e),this._initContainer(t),this._initLayout(),this._initEvents(),e.maxBounds&&this.setMaxBounds(e.maxBounds),e.center&&e.zoom!==i&&this.setView(o.latLng(e.center),e.zoom,{reset:!0}),this._initLayers(e.layers),this._handlers=[],this.callInitHooks()},setView:function(t,e){return this._resetView(o.latLng(t),this._limitZoom(e)),this},setZoom:function(t,e){return this.setView(this.getCenter(),t,{zoom:e})},zoomIn:function(t,e){return this.setZoom(this._zoom+(t||1),e)},zoomOut:function(t,e){return this.setZoom(this._zoom-(t||1),e)},setZoomAround:function(t,e,i){var n=this.getZoomScale(e),s=this.getSize().divideBy(2),a=t instanceof o.Point?t:this.latLngToContainerPoint(t),r=a.subtract(s).multiplyBy(1-1/n),h=this.containerPointToLatLng(s.add(r));return this.setView(h,e,{zoom:i})},fitBounds:function(t,e){e=e||{},t=t.getBounds?t.getBounds():o.latLngBounds(t);var i=o.point(e.paddingTopLeft||e.padding||[0,0]),n=o.point(e.paddingBottomRight||e.padding||[0,0]),s=this.getBoundsZoom(t,!1,i.add(n)),a=n.subtract(i).divideBy(2),r=this.project(t.getSouthWest(),s),h=this.project(t.getNorthEast(),s),l=this.unproject(r.add(h).divideBy(2).add(a),s);return this.setView(l,s,e)},fitWorld:function(t){return this.fitBounds([[-90,-180],[90,180]],t)},panTo:function(t,e){return this.setView(t,this._zoom,{pan:e})},panBy:function(t){return this.fire("movestart"),this._rawPanBy(o.point(t)),this.fire("move"),this.fire("moveend")},setMaxBounds:function(t){if(t=o.latLngBounds(t),this.options.maxBounds=t,!t)return this._boundsMinZoom=null,this.off("moveend",this._panInsideMaxBounds,this),this;var e=this.getBoundsZoom(t,!0);return this._boundsMinZoom=e,this._loaded&&(this._zooma.x&&(r=Math.floor(a.x-n.x)),i.y>s.y&&(h=Math.floor(s.y-i.y)),i.x=s);return u&&e?null:e?s:s-1},getSize:function(){return(!this._size||this._sizeChanged)&&(this._size=new o.Point(this._container.clientWidth,this._container.clientHeight),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(){var t=this._getTopLeftPoint();return new o.Bounds(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._initialTopLeftPoint},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t){var e=this.options.crs;return e.scale(t)/e.scale(this._zoom)},getScaleZoom:function(t){return this._zoom+Math.log(t)/Math.LN2},project:function(t,e){return e=e===i?this._zoom:e,this.options.crs.latLngToPoint(o.latLng(t),e)},unproject:function(t,e){return e=e===i?this._zoom:e,this.options.crs.pointToLatLng(o.point(t),e)},layerPointToLatLng:function(t){var e=o.point(t).add(this.getPixelOrigin());return this.unproject(e)},latLngToLayerPoint:function(t){var e=this.project(o.latLng(t))._round();return e._subtract(this.getPixelOrigin())},containerPointToLayerPoint:function(t){return o.point(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return o.point(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var e=this.containerPointToLayerPoint(o.point(t));return this.layerPointToLatLng(e)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(o.latLng(t)))},mouseEventToContainerPoint:function(t){return o.DomEvent.getMousePosition(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var e=this._container=o.DomUtil.get(t);if(!e)throw new Error("Map container not found.");if(e._leaflet)throw new Error("Map container is already initialized.");e._leaflet=!0},_initLayout:function(){var t=this._container;o.DomUtil.addClass(t,"leaflet-container"+(o.Browser.touch?" leaflet-touch":"")+(o.Browser.retina?" leaflet-retina":"")+(this.options.fadeAnimation?" leaflet-fade-anim":""));var e=o.DomUtil.getStyle(t,"position");"absolute"!==e&&"relative"!==e&&"fixed"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._mapPane=t.mapPane=this._createPane("leaflet-map-pane",this._container),this._tilePane=t.tilePane=this._createPane("leaflet-tile-pane",this._mapPane),t.objectsPane=this._createPane("leaflet-objects-pane",this._mapPane),t.shadowPane=this._createPane("leaflet-shadow-pane"),t.overlayPane=this._createPane("leaflet-overlay-pane"),t.markerPane=this._createPane("leaflet-marker-pane"),t.popupPane=this._createPane("leaflet-popup-pane");var e=" leaflet-zoom-hide";this.options.markerZoomAnimation||(o.DomUtil.addClass(t.markerPane,e),o.DomUtil.addClass(t.shadowPane,e),o.DomUtil.addClass(t.popupPane,e))},_createPane:function(t,e){return o.DomUtil.create("div",t,e||this._panes.objectsPane)},_clearPanes:function(){this._container.removeChild(this._mapPane)},_initLayers:function(t){t=t?o.Util.isArray(t)?t:[t]:[],this._layers={},this._zoomBoundLayers={},this._tileLayersNum=0;var e,i;for(e=0,i=t.length;i>e;e++)this.addLayer(t[e])},_resetView:function(t,e,i,n){var s=this._zoom!==e;n||(this.fire("movestart"),s&&this.fire("zoomstart")),this._zoom=e,this._initialCenter=t,this._initialTopLeftPoint=this._getNewTopLeftPoint(t),i?this._initialTopLeftPoint._add(this._getMapPanePos()):o.DomUtil.setPosition(this._mapPane,new o.Point(0,0)),this._tileLayersToLoad=this._tileLayersNum;var a=!this._loaded;this._loaded=!0,a&&(this.fire("load"),this.eachLayer(this._layerAdd,this)),this.fire("viewreset",{hard:!i}),this.fire("move"),(s||n)&&this.fire("zoomend"),this.fire("moveend",{hard:!i})},_rawPanBy:function(t){o.DomUtil.setPosition(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_updateZoomLevels:function(){var t,e=1/0,n=-1/0,o=this._getZoomSpan();for(t in this._zoomBoundLayers){var s=this._zoomBoundLayers[t];isNaN(s.options.minZoom)||(e=Math.min(e,s.options.minZoom)),isNaN(s.options.maxZoom)||(n=Math.max(n,s.options.maxZoom))}t===i?this._layersMaxZoom=this._layersMinZoom=i:(this._layersMaxZoom=n,this._layersMinZoom=e),o!==this._getZoomSpan()&&this.fire("zoomlevelschange")},_panInsideMaxBounds:function(){this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(e){if(o.DomEvent){e=e||"on",o.DomEvent[e](this._container,"click",this._onMouseClick,this);var i,n,s=["dblclick","mousedown","mouseup","mouseenter","mouseleave","mousemove","contextmenu"];for(i=0,n=s.length;n>i;i++)o.DomEvent[e](this._container,s[i],this._fireMouseEvent,this);this.options.trackResize&&o.DomEvent[e](t,"resize",this._onResize,this)}},_onResize:function(){o.Util.cancelAnimFrame(this._resizeRequest),this._resizeRequest=o.Util.requestAnimFrame(this.invalidateSize,this,!1,this._container)},_onMouseClick:function(t){!this._loaded||this.dragging&&this.dragging.moved()||(this.fire("preclick"),this._fireMouseEvent(t))},_fireMouseEvent:function(t){if(this._loaded){var e=t.type;if(e="mouseenter"===e?"mouseover":"mouseleave"===e?"mouseout":e,this.hasEventListeners(e)){"contextmenu"===e&&o.DomEvent.preventDefault(t);var i=this.mouseEventToContainerPoint(t),n=this.containerPointToLayerPoint(i),s=this.layerPointToLatLng(n);this.fire(e,{latlng:s,layerPoint:n,containerPoint:i,originalEvent:t})}}},_onTileLayerLoad:function(){this._tileLayersToLoad--,this._tileLayersNum&&!this._tileLayersToLoad&&this.fire("tilelayersload")},_clearHandlers:function(){for(var t=0,e=this._handlers.length;e>t;t++)this._handlers[t].disable()},whenReady:function(t,e){return this._loaded?t.call(e||this,this):this.on("load",t,e),this},_layerAdd:function(t){t.onAdd(this),this.fire("layeradd",{layer:t})},_getMapPanePos:function(){return o.DomUtil.getPosition(this._mapPane)},_moved:function(){var t=this._getMapPanePos();return t&&!t.equals([0,0])},_getTopLeftPoint:function(){return this.getPixelOrigin().subtract(this._getMapPanePos())},_getNewTopLeftPoint:function(t,e){var i=this.getSize()._divideBy(2);return this.project(t,e)._subtract(i)._round()},_latLngToNewLayerPoint:function(t,e,i){var n=this._getNewTopLeftPoint(i,e).add(this._getMapPanePos());return this.project(t,e)._subtract(n)},_getCenterLayerPoint:function(){return this.containerPointToLayerPoint(this.getSize()._divideBy(2))},_getCenterOffset:function(t){return this.latLngToLayerPoint(t).subtract(this._getCenterLayerPoint())},_limitZoom:function(t){var e=this.getMinZoom(),i=this.getMaxZoom();return Math.max(e,Math.min(i,t))}}),o.map=function(t,e){return new o.Map(t,e)},o.Projection.Mercator={MAX_LATITUDE:85.0840591556,R_MINOR:6356752.3142,R_MAJOR:6378137,project:function(t){var e=o.LatLng.DEG_TO_RAD,i=this.MAX_LATITUDE,n=Math.max(Math.min(i,t.lat),-i),s=this.R_MAJOR,a=this.R_MINOR,r=t.lng*e*s,h=n*e,l=a/s,u=Math.sqrt(1-l*l),c=u*Math.sin(h);c=Math.pow((1-c)/(1+c),.5*u);var d=Math.tan(.5*(.5*Math.PI-h))/c;return h=-a*Math.log(d),new o.Point(r,h)},unproject:function(t){for(var e,i=o.LatLng.RAD_TO_DEG,n=this.R_MAJOR,s=this.R_MINOR,a=t.x*i/n,r=s/n,h=Math.sqrt(1-r*r),l=Math.exp(-t.y/s),u=Math.PI/2-2*Math.atan(l),c=15,d=1e-7,_=c,p=.1;Math.abs(p)>d&&--_>0;)e=h*Math.sin(u),p=Math.PI/2-2*Math.atan(l*Math.pow((1-e)/(1+e),.5*h))-u,u+=p;return new o.LatLng(u*i,a)}},o.CRS.EPSG3395=o.extend({},o.CRS,{code:"EPSG:3395",projection:o.Projection.Mercator,transformation:function(){var t=o.Projection.Mercator,e=t.R_MAJOR,i=t.R_MINOR;return new o.Transformation(.5/(Math.PI*e),.5,-.5/(Math.PI*i),.5)}()}),o.TileLayer=o.Class.extend({includes:o.Mixin.Events,options:{minZoom:0,maxZoom:18,tileSize:256,subdomains:"abc",errorTileUrl:"",attribution:"",zoomOffset:0,opacity:1,unloadInvisibleTiles:o.Browser.mobile,updateWhenIdle:o.Browser.mobile},initialize:function(t,e){e=o.setOptions(this,e),e.detectRetina&&o.Browser.retina&&e.maxZoom>0&&(e.tileSize=Math.floor(e.tileSize/2),e.zoomOffset++,e.minZoom>0&&e.minZoom--,this.options.maxZoom--),e.bounds&&(e.bounds=o.latLngBounds(e.bounds)),this._url=t;var i=this.options.subdomains;"string"==typeof i&&(this.options.subdomains=i.split(""))},onAdd:function(t){this._map=t,this._animated=t.options.zoomAnimation&&o.Browser.any3d,this._initContainer(),this._createTileProto(),t.on({viewreset:this._reset,moveend:this._update},this),this._animated&&t.on({zoomanim:this._animateZoom,zoomend:this._endZoomAnim},this),this.options.updateWhenIdle||(this._limitedUpdate=o.Util.limitExecByInterval(this._update,150,this),t.on("move",this._limitedUpdate,this)),this._reset(),this._update()},addTo:function(t){return t.addLayer(this),this},onRemove:function(t){this._container.parentNode.removeChild(this._container),t.off({viewreset:this._reset,moveend:this._update},this),this._animated&&t.off({zoomanim:this._animateZoom,zoomend:this._endZoomAnim},this),this.options.updateWhenIdle||t.off("move",this._limitedUpdate,this),this._container=null,this._map=null -},bringToFront:function(){var t=this._map._panes.tilePane;return this._container&&(t.appendChild(this._container),this._setAutoZIndex(t,Math.max)),this},bringToBack:function(){var t=this._map._panes.tilePane;return this._container&&(t.insertBefore(this._container,t.firstChild),this._setAutoZIndex(t,Math.min)),this},getAttribution:function(){return this.options.attribution},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},setUrl:function(t,e){return this._url=t,e||this.redraw(),this},redraw:function(){return this._map&&(this._reset({hard:!0}),this._update()),this},_updateZIndex:function(){this._container&&this.options.zIndex!==i&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t,e){var i,n,o,s=t.children,a=-e(1/0,-1/0);for(n=0,o=s.length;o>n;n++)s[n]!==this._container&&(i=parseInt(s[n].style.zIndex,10),isNaN(i)||(a=e(a,i)));this.options.zIndex=this._container.style.zIndex=(isFinite(a)?a:0)+e(1,-1)},_updateOpacity:function(){var t,e=this._tiles;if(o.Browser.ielt9)for(t in e)o.DomUtil.setOpacity(e[t],this.options.opacity);else o.DomUtil.setOpacity(this._container,this.options.opacity);if(o.Browser.webkit)for(t in e)e[t].style.webkitTransform+=" translate(0,0)"},_initContainer:function(){var t=this._map._panes.tilePane;if(!this._container){if(this._container=o.DomUtil.create("div","leaflet-layer"),this._updateZIndex(),this._animated){var e="leaflet-tile-container leaflet-zoom-animated";this._bgBuffer=o.DomUtil.create("div",e,this._container),this._bgBuffer.style.zIndex=1,this._tileContainer=o.DomUtil.create("div",e,this._container),this._tileContainer.style.zIndex=2}else this._tileContainer=this._container;t.appendChild(this._container),this.options.opacity<1&&this._updateOpacity()}},_reset:function(t){for(var e in this._tiles)this.fire("tileunload",{tile:this._tiles[e]});this._tiles={},this._tilesToLoad=0,this.options.reuseTiles&&(this._unusedTiles=[]),this._tileContainer.innerHTML="",this._animated&&t&&t.hard&&this._clearBgBuffer(),this._initContainer()},_update:function(){if(this._map){var t=this._map.getPixelBounds(),e=this._map.getZoom(),i=this.options.tileSize;if(!(e>this.options.maxZoom||en;n++)this._addTile(a[n],l);this._tileContainer.appendChild(l)}},_tileShouldBeLoaded:function(t){if(t.x+":"+t.y in this._tiles)return!1;var e=this.options;if(!e.continuousWorld){var i=this._getWrapTileNum();if(e.noWrap&&(t.x<0||t.x>=i)||t.y<0||t.y>=i)return!1}if(e.bounds){var n=e.tileSize,o=t.multiplyBy(n),s=o.add([n,n]),a=this._map.unproject(o),r=this._map.unproject(s);if(e.continuousWorld||e.noWrap||(a=a.wrap(),r=r.wrap()),!e.bounds.intersects([a,r]))return!1}return!0},_removeOtherTiles:function(t){var e,i,n,o;for(o in this._tiles)e=o.split(":"),i=parseInt(e[0],10),n=parseInt(e[1],10),(it.max.x||nt.max.y)&&this._removeTile(o)},_removeTile:function(t){var e=this._tiles[t];this.fire("tileunload",{tile:e,url:e.src}),this.options.reuseTiles?(o.DomUtil.removeClass(e,"leaflet-tile-loaded"),this._unusedTiles.push(e)):e.parentNode===this._tileContainer&&this._tileContainer.removeChild(e),o.Browser.android||(e.onload=null,e.src=o.Util.emptyImageUrl),delete this._tiles[t]},_addTile:function(t,e){var i=this._getTilePos(t),n=this._getTile();o.DomUtil.setPosition(n,i,o.Browser.chrome||o.Browser.android23),this._tiles[t.x+":"+t.y]=n,this._loadTile(n,t),n.parentNode!==this._tileContainer&&e.appendChild(n)},_getZoomForUrl:function(){var t=this.options,e=this._map.getZoom();return t.zoomReverse&&(e=t.maxZoom-e),e+t.zoomOffset},_getTilePos:function(t){var e=this._map.getPixelOrigin(),i=this.options.tileSize;return t.multiplyBy(i).subtract(e)},getTileUrl:function(t){return o.Util.template(this._url,o.extend({s:this._getSubdomain(t),z:t.z,x:t.x,y:t.y},this.options))},_getWrapTileNum:function(){return Math.pow(2,this._getZoomForUrl())},_adjustTilePoint:function(t){var e=this._getWrapTileNum();this.options.continuousWorld||this.options.noWrap||(t.x=(t.x%e+e)%e),this.options.tms&&(t.y=e-t.y-1),t.z=this._getZoomForUrl()},_getSubdomain:function(t){var e=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[e]},_createTileProto:function(){var t=this._tileImg=o.DomUtil.create("img","leaflet-tile");t.style.width=t.style.height=this.options.tileSize+"px",t.galleryimg="no"},_getTile:function(){if(this.options.reuseTiles&&this._unusedTiles.length>0){var t=this._unusedTiles.pop();return this._resetTile(t),t}return this._createTile()},_resetTile:function(){},_createTile:function(){var t=this._tileImg.cloneNode(!1);return t.onselectstart=t.onmousemove=o.Util.falseFn,o.Browser.ielt9&&this.options.opacity!==i&&o.DomUtil.setOpacity(t,this.options.opacity),t},_loadTile:function(t,e){t._layer=this,t.onload=this._tileOnLoad,t.onerror=this._tileOnError,this._adjustTilePoint(e),t.src=this.getTileUrl(e)},_tileLoaded:function(){this._tilesToLoad--,this._tilesToLoad||(this.fire("load"),this._animated&&(clearTimeout(this._clearBgBufferTimer),this._clearBgBufferTimer=setTimeout(o.bind(this._clearBgBuffer,this),500)))},_tileOnLoad:function(){var t=this._layer;this.src!==o.Util.emptyImageUrl&&(o.DomUtil.addClass(this,"leaflet-tile-loaded"),t.fire("tileload",{tile:this,url:this.src})),t._tileLoaded()},_tileOnError:function(){var t=this._layer;t.fire("tileerror",{tile:this,url:this.src});var e=t.options.errorTileUrl;e&&(this.src=e),t._tileLoaded()}}),o.tileLayer=function(t,e){return new o.TileLayer(t,e)},o.TileLayer.WMS=o.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(t,e){this._url=t;var i=o.extend({},this.defaultWmsParams),n=e.tileSize||this.options.tileSize;i.width=i.height=e.detectRetina&&o.Browser.retina?2*n:n;for(var s in e)this.options.hasOwnProperty(s)||(i[s]=e[s]);this.wmsParams=i,o.setOptions(this,e)},onAdd:function(t){var e=parseFloat(this.wmsParams.version)>=1.3?"crs":"srs";this.wmsParams[e]=t.options.crs.code,o.TileLayer.prototype.onAdd.call(this,t)},getTileUrl:function(t,e){var i=this._map,n=i.options.crs,s=this.options.tileSize,a=t.multiplyBy(s),r=a.add([s,s]),h=n.project(i.unproject(a,e)),l=n.project(i.unproject(r,e)),u=[h.x,l.y,l.x,h.y].join(","),c=o.Util.template(this._url,{s:this._getSubdomain(t)});return c+o.Util.getParamString(this.wmsParams,c,!0)+"&BBOX="+u},setParams:function(t,e){return o.extend(this.wmsParams,t),e||this.redraw(),this}}),o.tileLayer.wms=function(t,e){return new o.TileLayer.WMS(t,e)},o.TileLayer.Canvas=o.TileLayer.extend({options:{async:!1},initialize:function(t){o.setOptions(this,t)},redraw:function(){for(var t in this._tiles)this._redrawTile(this._tiles[t]);return this},_redrawTile:function(t){this.drawTile(t,t._tilePoint,this._map._zoom)},_createTileProto:function(){var t=this._canvasProto=o.DomUtil.create("canvas","leaflet-tile");t.width=t.height=this.options.tileSize},_createTile:function(){var t=this._canvasProto.cloneNode(!1);return t.onselectstart=t.onmousemove=o.Util.falseFn,t},_loadTile:function(t,e){t._layer=this,t._tilePoint=e,this._redrawTile(t),this.options.async||this.tileDrawn(t)},drawTile:function(){},tileDrawn:function(t){this._tileOnLoad.call(t)}}),o.tileLayer.canvas=function(t){return new o.TileLayer.Canvas(t)},o.ImageOverlay=o.Class.extend({includes:o.Mixin.Events,options:{opacity:1},initialize:function(t,e,i){this._url=t,this._bounds=o.latLngBounds(e),o.setOptions(this,i)},onAdd:function(t){this._map=t,this._image||this._initImage(),t._panes.overlayPane.appendChild(this._image),t.on("viewreset",this._reset,this),t.options.zoomAnimation&&o.Browser.any3d&&t.on("zoomanim",this._animateZoom,this),this._reset()},onRemove:function(t){t.getPanes().overlayPane.removeChild(this._image),t.off("viewreset",this._reset,this),t.options.zoomAnimation&&t.off("zoomanim",this._animateZoom,this)},addTo:function(t){return t.addLayer(this),this},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},bringToFront:function(){return this._image&&this._map._panes.overlayPane.appendChild(this._image),this},bringToBack:function(){var t=this._map._panes.overlayPane;return this._image&&t.insertBefore(this._image,t.firstChild),this},_initImage:function(){this._image=o.DomUtil.create("img","leaflet-image-layer"),this._map.options.zoomAnimation&&o.Browser.any3d?o.DomUtil.addClass(this._image,"leaflet-zoom-animated"):o.DomUtil.addClass(this._image,"leaflet-zoom-hide"),this._updateOpacity(),o.extend(this._image,{galleryimg:"no",onselectstart:o.Util.falseFn,onmousemove:o.Util.falseFn,onload:o.bind(this._onImageLoad,this),src:this._url})},_animateZoom:function(t){var e=this._map,i=this._image,n=e.getZoomScale(t.zoom),s=this._bounds.getNorthWest(),a=this._bounds.getSouthEast(),r=e._latLngToNewLayerPoint(s,t.zoom,t.center),h=e._latLngToNewLayerPoint(a,t.zoom,t.center)._subtract(r),l=r._add(h._multiplyBy(.5*(1-1/n)));i.style[o.DomUtil.TRANSFORM]=o.DomUtil.getTranslateString(l)+" scale("+n+") "},_reset:function(){var t=this._image,e=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),i=this._map.latLngToLayerPoint(this._bounds.getSouthEast())._subtract(e);o.DomUtil.setPosition(t,e),t.style.width=i.x+"px",t.style.height=i.y+"px"},_onImageLoad:function(){this.fire("load")},_updateOpacity:function(){o.DomUtil.setOpacity(this._image,this.options.opacity)}}),o.imageOverlay=function(t,e,i){return new o.ImageOverlay(t,e,i)},o.Icon=o.Class.extend({options:{className:""},initialize:function(t){o.setOptions(this,t)},createIcon:function(t){return this._createIcon("icon",t)},createShadow:function(t){return this._createIcon("shadow",t)},_createIcon:function(t,e){var i=this._getIconUrl(t);if(!i){if("icon"===t)throw new Error("iconUrl not set in Icon options (see the docs).");return null}var n;return n=e&&"IMG"===e.tagName?this._createImg(i,e):this._createImg(i),this._setIconStyles(n,t),n},_setIconStyles:function(t,e){var i,n=this.options,s=o.point(n[e+"Size"]);i="shadow"===e?o.point(n.shadowAnchor||n.iconAnchor):o.point(n.iconAnchor),!i&&s&&(i=s.divideBy(2,!0)),t.className="leaflet-marker-"+e+" "+n.className,i&&(t.style.marginLeft=-i.x+"px",t.style.marginTop=-i.y+"px"),s&&(t.style.width=s.x+"px",t.style.height=s.y+"px")},_createImg:function(t,i){return o.Browser.ie6?(i||(i=e.createElement("div")),i.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="'+t+'")'):(i||(i=e.createElement("img")),i.src=t),i},_getIconUrl:function(t){return o.Browser.retina&&this.options[t+"RetinaUrl"]?this.options[t+"RetinaUrl"]:this.options[t+"Url"]}}),o.icon=function(t){return new o.Icon(t)},o.Icon.Default=o.Icon.extend({options:{iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],shadowSize:[41,41]},_getIconUrl:function(t){var e=t+"Url";if(this.options[e])return this.options[e];o.Browser.retina&&"icon"===t&&(t+="-2x");var i=o.Icon.Default.imagePath;if(!i)throw new Error("Couldn't autodetect L.Icon.Default.imagePath, set it manually.");return i+"/marker-"+t+".png"}}),o.Icon.Default.imagePath=function(){var t,i,n,o,s,a=e.getElementsByTagName("script"),r=/[\/^]leaflet[\-\._]?([\w\-\._]*)\.js\??/;for(t=0,i=a.length;i>t;t++)if(n=a[t].src,o=n.match(r))return s=n.split(r)[0],(s?s+"/":"")+"images"}(),o.Marker=o.Class.extend({includes:o.Mixin.Events,options:{icon:new o.Icon.Default,title:"",clickable:!0,draggable:!1,zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250},initialize:function(t,e){o.setOptions(this,e),this._latlng=o.latLng(t)},onAdd:function(t){this._map=t,t.on("viewreset",this.update,this),this._initIcon(),this.update(),t.options.zoomAnimation&&t.options.markerZoomAnimation&&t.on("zoomanim",this._animateZoom,this)},addTo:function(t){return t.addLayer(this),this},onRemove:function(t){this.dragging&&this.dragging.disable(),this._removeIcon(),this.fire("remove"),t.off({viewreset:this.update,zoomanim:this._animateZoom},this),this._map=null},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=o.latLng(t),this.update(),this.fire("move",{latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update(),this},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this},update:function(){if(this._icon){var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t)}return this},_initIcon:function(){var t=this.options,e=this._map,i=e.options.zoomAnimation&&e.options.markerZoomAnimation,n=i?"leaflet-zoom-animated":"leaflet-zoom-hide",s=!1,a=this._icon;if(a){var r=t.icon.createIcon(this._icon);r!==this._icon&&(this._removeIcon(),this._icon=r,a=!1)}else this._icon=t.icon.createIcon();t.title&&(this._icon.title=t.title),this._initInteraction(),s=t.opacity<1,o.DomUtil.addClass(this._icon,n),t.riseOnHover&&o.DomEvent.on(this._icon,"mouseover",this._bringToFront,this).on(this._icon,"mouseout",this._resetZIndex,this);var h=this._shadow;h?this._shadow=t.icon.createShadow(this._shadow):(this._shadow=t.icon.createShadow(),this._shadow&&(o.DomUtil.addClass(this._shadow,n),s=t.opacity<1)),s&&this._updateOpacity();var l=this._map._panes;a||l.markerPane.appendChild(this._icon),this._shadow&&!h&&l.shadowPane.appendChild(this._shadow)},_removeIcon:function(){var t=this._map._panes;this.options.riseOnHover&&o.DomEvent.off(this._icon,"mouseover",this._bringToFront).off(this._icon,"mouseout",this._resetZIndex),t.markerPane.removeChild(this._icon),this._shadow&&t.shadowPane.removeChild(this._shadow),this._icon=this._shadow=null},_setPos:function(t){o.DomUtil.setPosition(this._icon,t),this._shadow&&o.DomUtil.setPosition(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon.style.zIndex=this._zIndex+t},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);this._setPos(e)},_initInteraction:function(){if(this.options.clickable){var t=this._icon,e=["dblclick","mousedown","mouseover","mouseout","contextmenu"];o.DomUtil.addClass(t,"leaflet-clickable"),o.DomEvent.on(t,"click",this._onMouseClick,this);for(var i=0;is?(e.height=s+"px",o.DomUtil.addClass(t,a)):o.DomUtil.removeClass(t,a),this._containerWidth=this._container.offsetWidth},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),e=this._animated,i=o.point(this.options.offset);e&&o.DomUtil.setPosition(this._container,t),this._containerBottom=-i.y-(e?0:t.y),this._containerLeft=-Math.round(this._containerWidth/2)+i.x+(e?0:t.x),this._container.style.bottom=this._containerBottom+"px",this._container.style.left=this._containerLeft+"px"}},_zoomAnimation:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);o.DomUtil.setPosition(this._container,e)},_adjustPan:function(){if(this.options.autoPan){var t=this._map,e=this._container.offsetHeight,i=this._containerWidth,n=new o.Point(this._containerLeft,-e-this._containerBottom);this._animated&&n._add(o.DomUtil.getPosition(this._container));var s=t.layerPointToContainerPoint(n),a=o.point(this.options.autoPanPadding),r=t.getSize(),h=0,l=0;s.x+i>r.x&&(h=s.x+i-r.x+a.x),s.x-h<0&&(h=s.x-a.x),s.y+e>r.y&&(l=s.y+e-r.y+a.y),s.y-l<0&&(l=s.y-a.y),(h||l)&&t.fire("autopanstart").panBy([h,l])}},_onCloseButtonClick:function(t){this._close(),o.DomEvent.stop(t)}}),o.popup=function(t,e){return new o.Popup(t,e)},o.Map.include({openPopup:function(t,e,i){if(this.closePopup(),!(t instanceof o.Popup)){var n=t;t=new o.Popup(i).setLatLng(e).setContent(n)}return this._popup=t,this.addLayer(t)},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),o.Marker.include({openPopup:function(){return this._popup&&this._map&&!this._map.hasLayer(this._popup)&&(this._popup.setLatLng(this._latlng),this._map.openPopup(this._popup)),this},closePopup:function(){return this._popup&&this._popup._close(),this},bindPopup:function(t,e){var i=o.point(this.options.icon.options.popupAnchor||[0,0]);return i=i.add(o.Popup.prototype.options.offset),e&&e.offset&&(i=i.add(e.offset)),e=o.extend({offset:i},e),this._popup||this.on("click",this.openPopup,this).on("remove",this.closePopup,this).on("move",this._movePopup,this),t instanceof o.Popup?(o.setOptions(t,e),this._popup=t):this._popup=new o.Popup(e,this).setContent(t),this},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},unbindPopup:function(){return this._popup&&(this._popup=null,this.off("click",this.openPopup).off("remove",this.closePopup).off("move",this._movePopup)),this},_movePopup:function(t){this._popup.setLatLng(t.latlng)}}),o.LayerGroup=o.Class.extend({initialize:function(t){this._layers={};var e,i;if(t)for(e=0,i=t.length;i>e;e++)this.addLayer(t[e])},addLayer:function(t){var e=this.getLayerId(t);return this._layers[e]=t,this._map&&this._map.addLayer(t),this},removeLayer:function(t){var e=t in this._layers?t:this.getLayerId(t);return this._map&&this._layers[e]&&this._map.removeLayer(this._layers[e]),delete this._layers[e],this},hasLayer:function(t){return t?t in this._layers||this.getLayerId(t)in this._layers:!1},clearLayers:function(){return this.eachLayer(this.removeLayer,this),this},invoke:function(t){var e,i,n=Array.prototype.slice.call(arguments,1);for(e in this._layers)i=this._layers[e],i[t]&&i[t].apply(i,n);return this},onAdd:function(t){this._map=t,this.eachLayer(t.addLayer,t)},onRemove:function(t){this.eachLayer(t.removeLayer,t),this._map=null},addTo:function(t){return t.addLayer(this),this},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},getLayer:function(t){return this._layers[t]},getLayers:function(){var t=[];for(var e in this._layers)t.push(this._layers[e]);return t},setZIndex:function(t){return this.invoke("setZIndex",t)},getLayerId:function(t){return o.stamp(t)}}),o.layerGroup=function(t){return new o.LayerGroup(t)},o.FeatureGroup=o.LayerGroup.extend({includes:o.Mixin.Events,statics:{EVENTS:"click dblclick mouseover mouseout mousemove contextmenu"},addLayer:function(t){return this.hasLayer(t)?this:(t.on(o.FeatureGroup.EVENTS,this._propagateEvent,this),o.LayerGroup.prototype.addLayer.call(this,t),this._popupContent&&t.bindPopup&&t.bindPopup(this._popupContent,this._popupOptions),this.fire("layeradd",{layer:t}))},removeLayer:function(t){return t in this._layers&&(t=this._layers[t]),t.off(o.FeatureGroup.EVENTS,this._propagateEvent,this),o.LayerGroup.prototype.removeLayer.call(this,t),this._popupContent&&this.invoke("unbindPopup"),this.fire("layerremove",{layer:t})},bindPopup:function(t,e){return this._popupContent=t,this._popupOptions=e,this.invoke("bindPopup",t,e)},setStyle:function(t){return this.invoke("setStyle",t)},bringToFront:function(){return this.invoke("bringToFront")},bringToBack:function(){return this.invoke("bringToBack")},getBounds:function(){var t=new o.LatLngBounds;return this.eachLayer(function(e){t.extend(e instanceof o.Marker?e.getLatLng():e.getBounds())}),t},_propagateEvent:function(t){t.layer||(t.layer=t.target),t.target=this,this.fire(t.type,t)}}),o.featureGroup=function(t){return new o.FeatureGroup(t)},o.Path=o.Class.extend({includes:[o.Mixin.Events],statics:{CLIP_PADDING:o.Browser.mobile?Math.max(0,Math.min(.5,(1280/Math.max(t.innerWidth,t.innerHeight)-1)/2)):.5},options:{stroke:!0,color:"#0033ff",dashArray:null,weight:5,opacity:.5,fill:!1,fillColor:null,fillOpacity:.2,clickable:!0},initialize:function(t){o.setOptions(this,t)},onAdd:function(t){this._map=t,this._container||(this._initElements(),this._initEvents()),this.projectLatlngs(),this._updatePath(),this._container&&this._map._pathRoot.appendChild(this._container),this.fire("add"),t.on({viewreset:this.projectLatlngs,moveend:this._updatePath},this)},addTo:function(t){return t.addLayer(this),this},onRemove:function(t){t._pathRoot.removeChild(this._container),this.fire("remove"),this._map=null,o.Browser.vml&&(this._container=null,this._stroke=null,this._fill=null),t.off({viewreset:this.projectLatlngs,moveend:this._updatePath},this)},projectLatlngs:function(){},setStyle:function(t){return o.setOptions(this,t),this._container&&this._updateStyle(),this},redraw:function(){return this._map&&(this.projectLatlngs(),this._updatePath()),this}}),o.Map.include({_updatePathViewport:function(){var t=o.Path.CLIP_PADDING,e=this.getSize(),i=o.DomUtil.getPosition(this._mapPane),n=i.multiplyBy(-1)._subtract(e.multiplyBy(t)._round()),s=n.add(e.multiplyBy(1+2*t)._round());this._pathViewport=new o.Bounds(n,s)}}),o.Path.SVG_NS="http://www.w3.org/2000/svg",o.Browser.svg=!(!e.createElementNS||!e.createElementNS(o.Path.SVG_NS,"svg").createSVGRect),o.Path=o.Path.extend({statics:{SVG:o.Browser.svg},bringToFront:function(){var t=this._map._pathRoot,e=this._container;return e&&t.lastChild!==e&&t.appendChild(e),this},bringToBack:function(){var t=this._map._pathRoot,e=this._container,i=t.firstChild;return e&&i!==e&&t.insertBefore(e,i),this},getPathString:function(){},_createElement:function(t){return e.createElementNS(o.Path.SVG_NS,t)},_initElements:function(){this._map._initPathRoot(),this._initPath(),this._initStyle()},_initPath:function(){this._container=this._createElement("g"),this._path=this._createElement("path"),this._container.appendChild(this._path)},_initStyle:function(){this.options.stroke&&(this._path.setAttribute("stroke-linejoin","round"),this._path.setAttribute("stroke-linecap","round")),this.options.fill&&this._path.setAttribute("fill-rule","evenodd"),this.options.pointerEvents&&this._path.setAttribute("pointer-events",this.options.pointerEvents),this.options.clickable||this.options.pointerEvents||this._path.setAttribute("pointer-events","none"),this._updateStyle()},_updateStyle:function(){this.options.stroke?(this._path.setAttribute("stroke",this.options.color),this._path.setAttribute("stroke-opacity",this.options.opacity),this._path.setAttribute("stroke-width",this.options.weight),this.options.dashArray?this._path.setAttribute("stroke-dasharray",this.options.dashArray):this._path.removeAttribute("stroke-dasharray")):this._path.setAttribute("stroke","none"),this.options.fill?(this._path.setAttribute("fill",this.options.fillColor||this.options.color),this._path.setAttribute("fill-opacity",this.options.fillOpacity)):this._path.setAttribute("fill","none")},_updatePath:function(){var t=this.getPathString();t||(t="M0 0"),this._path.setAttribute("d",t)},_initEvents:function(){if(this.options.clickable){(o.Browser.svg||!o.Browser.vml)&&this._path.setAttribute("class","leaflet-clickable"),o.DomEvent.on(this._container,"click",this._onMouseClick,this);for(var t=["dblclick","mousedown","mouseover","mouseout","mousemove","contextmenu"],e=0;e';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(n){return!1}}(),o.Path=o.Browser.svg||!o.Browser.vml?o.Path:o.Path.extend({statics:{VML:!0,CLIP_PADDING:.02},_createElement:function(){try{return e.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(t){return e.createElement("')}}catch(t){return function(t){return e.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_initPath:function(){var t=this._container=this._createElement("shape");o.DomUtil.addClass(t,"leaflet-vml-shape"),this.options.clickable&&o.DomUtil.addClass(t,"leaflet-clickable"),t.coordsize="1 1",this._path=this._createElement("path"),t.appendChild(this._path),this._map._pathRoot.appendChild(t)},_initStyle:function(){this._updateStyle()},_updateStyle:function(){var t=this._stroke,e=this._fill,i=this.options,n=this._container;n.stroked=i.stroke,n.filled=i.fill,i.stroke?(t||(t=this._stroke=this._createElement("stroke"),t.endcap="round",n.appendChild(t)),t.weight=i.weight+"px",t.color=i.color,t.opacity=i.opacity,t.dashStyle=i.dashArray?i.dashArray instanceof Array?i.dashArray.join(" "):i.dashArray.replace(/( *, *)/g," "):""):t&&(n.removeChild(t),this._stroke=null),i.fill?(e||(e=this._fill=this._createElement("fill"),n.appendChild(e)),e.color=i.fillColor||i.color,e.opacity=i.fillOpacity):e&&(n.removeChild(e),this._fill=null) -},_updatePath:function(){var t=this._container.style;t.display="none",this._path.v=this.getPathString()+" ",t.display=""}}),o.Map.include(o.Browser.svg||!o.Browser.vml?{}:{_initPathRoot:function(){if(!this._pathRoot){var t=this._pathRoot=e.createElement("div");t.className="leaflet-vml-container",this._panes.overlayPane.appendChild(t),this.on("moveend",this._updatePathViewport),this._updatePathViewport()}}}),o.Browser.canvas=function(){return!!e.createElement("canvas").getContext}(),o.Path=o.Path.SVG&&!t.L_PREFER_CANVAS||!o.Browser.canvas?o.Path:o.Path.extend({statics:{CANVAS:!0,SVG:!1},redraw:function(){return this._map&&(this.projectLatlngs(),this._requestUpdate()),this},setStyle:function(t){return o.setOptions(this,t),this._map&&(this._updateStyle(),this._requestUpdate()),this},onRemove:function(t){t.off("viewreset",this.projectLatlngs,this).off("moveend",this._updatePath,this),this.options.clickable&&(this._map.off("click",this._onClick,this),this._map.off("mousemove",this._onMouseMove,this)),this._requestUpdate(),this._map=null},_requestUpdate:function(){this._map&&!o.Path._updateRequest&&(o.Path._updateRequest=o.Util.requestAnimFrame(this._fireMapMoveEnd,this._map))},_fireMapMoveEnd:function(){o.Path._updateRequest=null,this.fire("moveend")},_initElements:function(){this._map._initPathRoot(),this._ctx=this._map._canvasCtx},_updateStyle:function(){var t=this.options;t.stroke&&(this._ctx.lineWidth=t.weight,this._ctx.strokeStyle=t.color),t.fill&&(this._ctx.fillStyle=t.fillColor||t.color)},_drawPath:function(){var t,e,i,n,s,a;for(this._ctx.beginPath(),t=0,i=this._parts.length;i>t;t++){for(e=0,n=this._parts[t].length;n>e;e++)s=this._parts[t][e],a=(0===e?"move":"line")+"To",this._ctx[a](s.x,s.y);this instanceof o.Polygon&&this._ctx.closePath()}},_checkIfEmpty:function(){return!this._parts.length},_updatePath:function(){if(!this._checkIfEmpty()){var t=this._ctx,e=this.options;this._drawPath(),t.save(),this._updateStyle(),e.fill&&(t.globalAlpha=e.fillOpacity,t.fill()),e.stroke&&(t.globalAlpha=e.opacity,t.stroke()),t.restore()}},_initEvents:function(){this.options.clickable&&(this._map.on("mousemove",this._onMouseMove,this),this._map.on("click",this._onClick,this))},_onClick:function(t){this._containsPoint(t.layerPoint)&&this.fire("click",t)},_onMouseMove:function(t){this._map&&!this._map._animatingZoom&&(this._containsPoint(t.layerPoint)?(this._ctx.canvas.style.cursor="pointer",this._mouseInside=!0,this.fire("mouseover",t)):this._mouseInside&&(this._ctx.canvas.style.cursor="",this._mouseInside=!1,this.fire("mouseout",t)))}}),o.Map.include(o.Path.SVG&&!t.L_PREFER_CANVAS||!o.Browser.canvas?{}:{_initPathRoot:function(){var t,i=this._pathRoot;i||(i=this._pathRoot=e.createElement("canvas"),i.style.position="absolute",t=this._canvasCtx=i.getContext("2d"),t.lineCap="round",t.lineJoin="round",this._panes.overlayPane.appendChild(i),this.options.zoomAnimation&&(this._pathRoot.className="leaflet-zoom-animated",this.on("zoomanim",this._animatePathZoom),this.on("zoomend",this._endPathZoom)),this.on("moveend",this._updateCanvasViewport),this._updateCanvasViewport())},_updateCanvasViewport:function(){if(!this._pathZooming){this._updatePathViewport();var t=this._pathViewport,e=t.min,i=t.max.subtract(e),n=this._pathRoot;o.DomUtil.setPosition(n,e),n.width=i.x,n.height=i.y,n.getContext("2d").translate(-e.x,-e.y)}}}),o.LineUtil={simplify:function(t,e){if(!e||!t.length)return t.slice();var i=e*e;return t=this._reducePoints(t,i),t=this._simplifyDP(t,i)},pointToSegmentDistance:function(t,e,i){return Math.sqrt(this._sqClosestPointOnSegment(t,e,i,!0))},closestPointOnSegment:function(t,e,i){return this._sqClosestPointOnSegment(t,e,i)},_simplifyDP:function(t,e){var n=t.length,o=typeof Uint8Array!=i+""?Uint8Array:Array,s=new o(n);s[0]=s[n-1]=1,this._simplifyDPStep(t,s,e,0,n-1);var a,r=[];for(a=0;n>a;a++)s[a]&&r.push(t[a]);return r},_simplifyDPStep:function(t,e,i,n,o){var s,a,r,h=0;for(a=n+1;o-1>=a;a++)r=this._sqClosestPointOnSegment(t[a],t[n],t[o],!0),r>h&&(s=a,h=r);h>i&&(e[s]=1,this._simplifyDPStep(t,e,i,n,s),this._simplifyDPStep(t,e,i,s,o))},_reducePoints:function(t,e){for(var i=[t[0]],n=1,o=0,s=t.length;s>n;n++)this._sqDist(t[n],t[o])>e&&(i.push(t[n]),o=n);return s-1>o&&i.push(t[s-1]),i},clipSegment:function(t,e,i,n){var o,s,a,r=n?this._lastCode:this._getBitCode(t,i),h=this._getBitCode(e,i);for(this._lastCode=h;;){if(!(r|h))return[t,e];if(r&h)return!1;o=r||h,s=this._getEdgeIntersection(t,e,o,i),a=this._getBitCode(s,i),o===r?(t=s,r=a):(e=s,h=a)}},_getEdgeIntersection:function(t,e,i,n){var s=e.x-t.x,a=e.y-t.y,r=n.min,h=n.max;return 8&i?new o.Point(t.x+s*(h.y-t.y)/a,h.y):4&i?new o.Point(t.x+s*(r.y-t.y)/a,r.y):2&i?new o.Point(h.x,t.y+a*(h.x-t.x)/s):1&i?new o.Point(r.x,t.y+a*(r.x-t.x)/s):void 0},_getBitCode:function(t,e){var i=0;return t.xe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i},_sqDist:function(t,e){var i=e.x-t.x,n=e.y-t.y;return i*i+n*n},_sqClosestPointOnSegment:function(t,e,i,n){var s,a=e.x,r=e.y,h=i.x-a,l=i.y-r,u=h*h+l*l;return u>0&&(s=((t.x-a)*h+(t.y-r)*l)/u,s>1?(a=i.x,r=i.y):s>0&&(a+=h*s,r+=l*s)),h=t.x-a,l=t.y-r,n?h*h+l*l:new o.Point(a,r)}},o.Polyline=o.Path.extend({initialize:function(t,e){o.Path.prototype.initialize.call(this,e),this._latlngs=this._convertLatLngs(t)},options:{smoothFactor:1,noClip:!1},projectLatlngs:function(){this._originalPoints=[];for(var t=0,e=this._latlngs.length;e>t;t++)this._originalPoints[t]=this._map.latLngToLayerPoint(this._latlngs[t])},getPathString:function(){for(var t=0,e=this._parts.length,i="";e>t;t++)i+=this._getPathPartStr(this._parts[t]);return i},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._latlngs=this._convertLatLngs(t),this.redraw()},addLatLng:function(t){return this._latlngs.push(o.latLng(t)),this.redraw()},spliceLatLngs:function(){var t=[].splice.apply(this._latlngs,arguments);return this._convertLatLngs(this._latlngs,!0),this.redraw(),t},closestLayerPoint:function(t){for(var e,i,n=1/0,s=this._parts,a=null,r=0,h=s.length;h>r;r++)for(var l=s[r],u=1,c=l.length;c>u;u++){e=l[u-1],i=l[u];var d=o.LineUtil._sqClosestPointOnSegment(t,e,i,!0);n>d&&(n=d,a=o.LineUtil._sqClosestPointOnSegment(t,e,i))}return a&&(a.distance=Math.sqrt(n)),a},getBounds:function(){return new o.LatLngBounds(this.getLatLngs())},_convertLatLngs:function(t,e){var i,n,s=e?t:[];for(i=0,n=t.length;n>i;i++){if(o.Util.isArray(t[i])&&"number"!=typeof t[i][0])return;s[i]=o.latLng(t[i])}return s},_initEvents:function(){o.Path.prototype._initEvents.call(this)},_getPathPartStr:function(t){for(var e,i=o.Path.VML,n=0,s=t.length,a="";s>n;n++)e=t[n],i&&e._round(),a+=(n?"L":"M")+e.x+" "+e.y;return a},_clipPoints:function(){var t,e,i,n=this._originalPoints,s=n.length;if(this.options.noClip)return this._parts=[n],void 0;this._parts=[];var a=this._parts,r=this._map._pathViewport,h=o.LineUtil;for(t=0,e=0;s-1>t;t++)i=h.clipSegment(n[t],n[t+1],r,t),i&&(a[e]=a[e]||[],a[e].push(i[0]),(i[1]!==n[t+1]||t===s-2)&&(a[e].push(i[1]),e++))},_simplifyPoints:function(){for(var t=this._parts,e=o.LineUtil,i=0,n=t.length;n>i;i++)t[i]=e.simplify(t[i],this.options.smoothFactor)},_updatePath:function(){this._map&&(this._clipPoints(),this._simplifyPoints(),o.Path.prototype._updatePath.call(this))}}),o.polyline=function(t,e){return new o.Polyline(t,e)},o.PolyUtil={},o.PolyUtil.clipPolygon=function(t,e){var i,n,s,a,r,h,l,u,c,d=[1,4,2,8],_=o.LineUtil;for(n=0,l=t.length;l>n;n++)t[n]._code=_._getBitCode(t[n],e);for(a=0;4>a;a++){for(u=d[a],i=[],n=0,l=t.length,s=l-1;l>n;s=n++)r=t[n],h=t[s],r._code&u?h._code&u||(c=_._getEdgeIntersection(h,r,u,e),c._code=_._getBitCode(c,e),i.push(c)):(h._code&u&&(c=_._getEdgeIntersection(h,r,u,e),c._code=_._getBitCode(c,e),i.push(c)),i.push(r));t=i}return t},o.Polygon=o.Polyline.extend({options:{fill:!0},initialize:function(t,e){var i,n,s;if(o.Polyline.prototype.initialize.call(this,t,e),t&&o.Util.isArray(t[0])&&"number"!=typeof t[0][0])for(this._latlngs=this._convertLatLngs(t[0]),this._holes=t.slice(1),i=0,n=this._holes.length;n>i;i++)s=this._holes[i]=this._convertLatLngs(this._holes[i]),s[0].equals(s[s.length-1])&&s.pop();t=this._latlngs,t.length>=2&&t[0].equals(t[t.length-1])&&t.pop()},projectLatlngs:function(){if(o.Polyline.prototype.projectLatlngs.call(this),this._holePoints=[],this._holes){var t,e,i,n;for(t=0,i=this._holes.length;i>t;t++)for(this._holePoints[t]=[],e=0,n=this._holes[t].length;n>e;e++)this._holePoints[t][e]=this._map.latLngToLayerPoint(this._holes[t][e])}},_clipPoints:function(){var t=this._originalPoints,e=[];if(this._parts=[t].concat(this._holePoints),!this.options.noClip){for(var i=0,n=this._parts.length;n>i;i++){var s=o.PolyUtil.clipPolygon(this._parts[i],this._map._pathViewport);s.length&&e.push(s)}this._parts=e}},_getPathPartStr:function(t){var e=o.Polyline.prototype._getPathPartStr.call(this,t);return e+(o.Browser.svg?"z":"x")}}),o.polygon=function(t,e){return new o.Polygon(t,e)},function(){function t(t){return o.FeatureGroup.extend({initialize:function(t,e){this._layers={},this._options=e,this.setLatLngs(t)},setLatLngs:function(e){var i=0,n=e.length;for(this.eachLayer(function(t){n>i?t.setLatLngs(e[i++]):this.removeLayer(t)},this);n>i;)this.addLayer(new t(e[i++],this._options));return this}})}o.MultiPolyline=t(o.Polyline),o.MultiPolygon=t(o.Polygon),o.multiPolyline=function(t,e){return new o.MultiPolyline(t,e)},o.multiPolygon=function(t,e){return new o.MultiPolygon(t,e)}}(),o.Rectangle=o.Polygon.extend({initialize:function(t,e){o.Polygon.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return t=o.latLngBounds(t),[t.getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}}),o.rectangle=function(t,e){return new o.Rectangle(t,e)},o.Circle=o.Path.extend({initialize:function(t,e,i){o.Path.prototype.initialize.call(this,i),this._latlng=o.latLng(t),this._mRadius=e},options:{fill:!0},setLatLng:function(t){return this._latlng=o.latLng(t),this.redraw()},setRadius:function(t){return this._mRadius=t,this.redraw()},projectLatlngs:function(){var t=this._getLngRadius(),e=this._latlng,i=this._map.latLngToLayerPoint([e.lat,e.lng-t]);this._point=this._map.latLngToLayerPoint(e),this._radius=Math.max(this._point.x-i.x,1)},getBounds:function(){var t=this._getLngRadius(),e=360*(this._mRadius/40075017),i=this._latlng;return new o.LatLngBounds([i.lat-e,i.lng-t],[i.lat+e,i.lng+t])},getLatLng:function(){return this._latlng},getPathString:function(){var t=this._point,e=this._radius;return this._checkIfEmpty()?"":o.Browser.svg?"M"+t.x+","+(t.y-e)+"A"+e+","+e+",0,1,1,"+(t.x-.1)+","+(t.y-e)+" z":(t._round(),e=Math.round(e),"AL "+t.x+","+t.y+" "+e+","+e+" 0,"+23592600)},getRadius:function(){return this._mRadius},_getLatRadius:function(){return 360*(this._mRadius/40075017)},_getLngRadius:function(){return this._getLatRadius()/Math.cos(o.LatLng.DEG_TO_RAD*this._latlng.lat)},_checkIfEmpty:function(){if(!this._map)return!1;var t=this._map._pathViewport,e=this._radius,i=this._point;return i.x-e>t.max.x||i.y-e>t.max.y||i.x+ei;i++)for(l=this._parts[i],n=0,r=l.length,s=r-1;r>n;s=n++)if((e||0!==n)&&(h=o.LineUtil.pointToSegmentDistance(t,l[s],l[n]),u>=h))return!0;return!1}}:{}),o.Polygon.include(o.Path.CANVAS?{_containsPoint:function(t){var e,i,n,s,a,r,h,l,u=!1;if(o.Polyline.prototype._containsPoint.call(this,t,!0))return!0;for(s=0,h=this._parts.length;h>s;s++)for(e=this._parts[s],a=0,l=e.length,r=l-1;l>a;r=a++)i=e[a],n=e[r],i.y>t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(u=!u);return u}}:{}),o.Circle.include(o.Path.CANVAS?{_drawPath:function(){var t=this._point;this._ctx.beginPath(),this._ctx.arc(t.x,t.y,this._radius,0,2*Math.PI,!1)},_containsPoint:function(t){var e=this._point,i=this.options.stroke?this.options.weight/2:0;return t.distanceTo(e)<=this._radius+i}}:{}),o.CircleMarker.include(o.Path.CANVAS?{_updateStyle:function(){o.Path.prototype._updateStyle.call(this)}}:{}),o.GeoJSON=o.FeatureGroup.extend({initialize:function(t,e){o.setOptions(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n=o.Util.isArray(t)?t:t.features;if(n){for(e=0,i=n.length;i>e;e++)(n[e].geometries||n[e].geometry||n[e].features)&&this.addData(n[e]);return this}var s=this.options;if(!s.filter||s.filter(t)){var a=o.GeoJSON.geometryToLayer(t,s.pointToLayer,s.coordsToLatLng);return a.feature=t,a.defaultOptions=a.options,this.resetStyle(a),s.onEachFeature&&s.onEachFeature(t,a),this.addLayer(a)}},resetStyle:function(t){var e=this.options.style;e&&(o.Util.extend(t.options,t.defaultOptions),this._setLayerStyle(t,e))},setStyle:function(t){this.eachLayer(function(e){this._setLayerStyle(e,t)},this)},_setLayerStyle:function(t,e){"function"==typeof e&&(e=e(t.feature)),t.setStyle&&t.setStyle(e)}}),o.extend(o.GeoJSON,{geometryToLayer:function(t,e,i){var n,s,a,r,h,l="Feature"===t.type?t.geometry:t,u=l.coordinates,c=[];switch(i=i||this.coordsToLatLng,l.type){case"Point":return n=i(u),e?e(t,n):new o.Marker(n);case"MultiPoint":for(a=0,r=u.length;r>a;a++)n=i(u[a]),h=e?e(t,n):new o.Marker(n),c.push(h);return new o.FeatureGroup(c);case"LineString":return s=this.coordsToLatLngs(u,0,i),new o.Polyline(s);case"Polygon":return s=this.coordsToLatLngs(u,1,i),new o.Polygon(s);case"MultiLineString":return s=this.coordsToLatLngs(u,1,i),new o.MultiPolyline(s);case"MultiPolygon":return s=this.coordsToLatLngs(u,2,i),new o.MultiPolygon(s);case"GeometryCollection":for(a=0,r=l.geometries.length;r>a;a++)h=this.geometryToLayer({geometry:l.geometries[a],type:"Feature",properties:t.properties},e),c.push(h);return new o.FeatureGroup(c);default:throw new Error("Invalid GeoJSON object.")}},coordsToLatLng:function(t){return new o.LatLng(t[1],t[0])},coordsToLatLngs:function(t,e,i){var n,o,s,a=[];for(o=0,s=t.length;s>o;o++)n=e?this.coordsToLatLngs(t[o],e-1,i):(i||this.coordsToLatLng)(t[o]),a.push(n);return a},latLngToCoords:function(t){return[t.lng,t.lat]},latLngsToCoords:function(t){for(var e=[],i=0,n=t.length;n>i;i++)e.push(o.GeoJSON.latLngToCoords(t[i]));return e}}),o.Marker.include({toGeoJSON:function(){return{type:"Point",coordinates:o.GeoJSON.latLngToCoords(this.getLatLng())}}}),o.Polyline.include({toGeoJSON:function(){return{type:"LineString",coordinates:o.GeoJSON.latLngsToCoords(this.getLatLngs())}}}),o.Polygon.include({toGeoJSON:function(){var t,e,i,n=[o.GeoJSON.latLngsToCoords(this.getLatLngs())];if(n[0].push(n[0][0]),this._holes)for(t=0,e=this._holes.length;e>t;t++)i=o.GeoJSON.latLngsToCoords(this._holes[t]),i.push(i[0]),n.push(i);return{type:"Polygon",coordinates:n}}}),function(){function t(t,e){t.include({toGeoJSON:function(){var t=[];return this.eachLayer(function(e){t.push(e.toGeoJSON().coordinates)}),{type:e,coordinates:t}}})}t(o.MultiPolyline,"MultiLineString"),t(o.MultiPolygon,"MultiPolygon")}(),o.LayerGroup.include({toGeoJSON:function(){var t=[];return this.eachLayer(function(e){e.toGeoJSON&&t.push(e.toGeoJSON())}),{type:"GeometryCollection",geometries:t}}}),o.geoJson=function(t,e){return new o.GeoJSON(t,e)},o.DomEvent={addListener:function(t,e,i,n){var s,a,r,h=o.stamp(i),l="_leaflet_"+e+h;return t[l]?this:(s=function(e){return i.call(n||t,e||o.DomEvent._getEvent())},o.Browser.msTouch&&0===e.indexOf("touch")?this.addMsTouchListener(t,e,s,h):(o.Browser.touch&&"dblclick"===e&&this.addDoubleTapListener&&this.addDoubleTapListener(t,s,h),"addEventListener"in t?"mousewheel"===e?(t.addEventListener("DOMMouseScroll",s,!1),t.addEventListener(e,s,!1)):"mouseenter"===e||"mouseleave"===e?(a=s,r="mouseenter"===e?"mouseover":"mouseout",s=function(e){return o.DomEvent._checkMouse(t,e)?a(e):void 0},t.addEventListener(r,s,!1)):"click"===e&&o.Browser.android?(a=s,s=function(t){return o.DomEvent._filterClick(t,a)},t.addEventListener(e,s,!1)):t.addEventListener(e,s,!1):"attachEvent"in t&&t.attachEvent("on"+e,s),t[l]=s,this))},removeListener:function(t,e,i){var n=o.stamp(i),s="_leaflet_"+e+n,a=t[s];return a?(o.Browser.msTouch&&0===e.indexOf("touch")?this.removeMsTouchListener(t,e,n):o.Browser.touch&&"dblclick"===e&&this.removeDoubleTapListener?this.removeDoubleTapListener(t,n):"removeEventListener"in t?"mousewheel"===e?(t.removeEventListener("DOMMouseScroll",a,!1),t.removeEventListener(e,a,!1)):"mouseenter"===e||"mouseleave"===e?t.removeEventListener("mouseenter"===e?"mouseover":"mouseout",a,!1):t.removeEventListener(e,a,!1):"detachEvent"in t&&t.detachEvent("on"+e,a),t[s]=null,this):this},stopPropagation:function(t){return t.stopPropagation?t.stopPropagation():t.cancelBubble=!0,this},disableClickPropagation:function(t){for(var e=o.DomEvent.stopPropagation,i=o.Draggable.START.length-1;i>=0;i--)o.DomEvent.addListener(t,o.Draggable.START[i],e);return o.DomEvent.addListener(t,"click",e).addListener(t,"dblclick",e)},preventDefault:function(t){return t.preventDefault?t.preventDefault():t.returnValue=!1,this},stop:function(t){return o.DomEvent.preventDefault(t).stopPropagation(t)},getMousePosition:function(t,i){var n=e.body,s=e.documentElement,a=t.pageX?t.pageX:t.clientX+n.scrollLeft+s.scrollLeft,r=t.pageY?t.pageY:t.clientY+n.scrollTop+s.scrollTop,h=new o.Point(a,r);return i?h._subtract(o.DomUtil.getViewportOffset(i)):h},getWheelDelta:function(t){var e=0;return t.wheelDelta&&(e=t.wheelDelta/120),t.detail&&(e=-t.detail/3),e},_checkMouse:function(t,e){var i=e.relatedTarget;if(!i)return!0;try{for(;i&&i!==t;)i=i.parentNode}catch(n){return!1}return i!==t},_getEvent:function(){var e=t.event;if(!e)for(var i=arguments.callee.caller;i&&(e=i.arguments[0],!e||t.Event!==e.constructor);)i=i.caller;return e},_filterClick:function(t,e){var i=t.timeStamp||t.originalEvent.timeStamp,n=o.DomEvent._lastClick&&i-o.DomEvent._lastClick;return n&&n>100&&400>n?(o.DomEvent.stop(t),void 0):(o.DomEvent._lastClick=i,e(t))}},o.DomEvent.on=o.DomEvent.addListener,o.DomEvent.off=o.DomEvent.removeListener,o.Draggable=o.Class.extend({includes:o.Mixin.Events,statics:{START:o.Browser.touch?["touchstart","mousedown"]:["mousedown"],END:{mousedown:"mouseup",touchstart:"touchend",MSPointerDown:"touchend"},MOVE:{mousedown:"mousemove",touchstart:"touchmove",MSPointerDown:"touchmove"},TAP_TOLERANCE:15},initialize:function(t,e,i){this._element=t,this._dragStartTarget=e||t,this._longPress=i&&!o.Browser.msTouch},enable:function(){if(!this._enabled){for(var t=o.Draggable.START.length-1;t>=0;t--)o.DomEvent.on(this._dragStartTarget,o.Draggable.START[t],this._onDown,this);this._enabled=!0}},disable:function(){if(this._enabled){for(var t=o.Draggable.START.length-1;t>=0;t--)o.DomEvent.off(this._dragStartTarget,o.Draggable.START[t],this._onDown,this);this._enabled=!1,this._moved=!1}},_onDown:function(t){if(!t.shiftKey&&(1===t.which||1===t.button||t.touches)&&(o.DomEvent.preventDefault(t).stopPropagation(t),!o.Draggable._disabled)){this._simulateClick=!0;var i=t.touches&&t.touches.length||0;if(i>1)return this._simulateClick=!1,clearTimeout(this._longPressTimeout),void 0;var n=1===i?t.touches[0]:t,s=n.target;o.Browser.touch&&"a"===s.tagName.toLowerCase()&&o.DomUtil.addClass(s,"leaflet-active"),this._moved=!1,this._moving||(this._startPoint=new o.Point(n.clientX,n.clientY),this._startPos=this._newPos=o.DomUtil.getPosition(this._element),1===i&&o.Browser.touch&&this._longPress&&(this._longPressTimeout=setTimeout(o.bind(function(){var t=this._newPos&&this._newPos.distanceTo(this._startPos)||0;t1)){var i=t.touches&&1===t.touches.length?t.touches[0]:t,n=new o.Point(i.clientX,i.clientY),s=n.subtract(this._startPoint);(s.x||s.y)&&(o.DomEvent.preventDefault(t),this._moved||(this.fire("dragstart"),this._moved=!0,this._startPos=o.DomUtil.getPosition(this._element).subtract(s),o.Browser.touch||(o.DomUtil.disableTextSelection(),o.DomUtil.addClass(e.body,"leaflet-dragging"))),this._newPos=this._startPos.add(s),this._moving=!0,o.Util.cancelAnimFrame(this._animRequest),this._animRequest=o.Util.requestAnimFrame(this._updatePosition,this,!0,this._dragStartTarget))}},_updatePosition:function(){this.fire("predrag"),o.DomUtil.setPosition(this._element,this._newPos),this.fire("drag")},_onUp:function(t){var i,n,s,a,r;clearTimeout(this._longPressTimeout),this._simulateClick&&t.changedTouches&&(s=this._newPos&&this._newPos.distanceTo(this._startPos)||0,i=t.changedTouches[0],n=i.target,"a"===n.tagName.toLowerCase()&&o.DomUtil.removeClass(n,"leaflet-active"),s200&&(this._positions.shift(),this._times.shift())}this._map.fire("move").fire("drag")},_onViewReset:function(){var t=this._map.getSize()._divideBy(2),e=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=e.subtract(t).x,this._worldWidth=this._map.project([0,180]).x},_onPreDrag:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,s=(n+e+i)%t-e-i,a=Math.abs(o+i)e.inertiaThreshold||!this._positions[0];if(t.fire("dragend"),n)t.fire("moveend");else{var s=this._lastPos.subtract(this._positions[0]),a=(this._lastTime+i-this._times[0])/1e3,r=e.easeLinearity,h=s.multiplyBy(r/a),l=h.distanceTo([0,0]),u=Math.min(e.inertiaMaxSpeed,l),c=h.multiplyBy(u/l),d=u/(e.inertiaDeceleration*r),_=c.multiplyBy(-d/2).round();_.x&&_.y?o.Util.requestAnimFrame(function(){t.panBy(_,{duration:d,easeLinearity:r,noMoveStart:!0})}):t.fire("moveend")}}}),o.Map.addInitHook("addHandler","dragging",o.Map.Drag),o.Map.mergeOptions({doubleClickZoom:!0}),o.Map.DoubleClickZoom=o.Handler.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick)},_onDoubleClick:function(t){this.setZoomAround(t.containerPoint,this._zoom+1)}}),o.Map.addInitHook("addHandler","doubleClickZoom",o.Map.DoubleClickZoom),o.Map.mergeOptions({scrollWheelZoom:!0}),o.Map.ScrollWheelZoom=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,"mousewheel",this._onWheelScroll,this),this._delta=0},removeHooks:function(){o.DomEvent.off(this._map._container,"mousewheel",this._onWheelScroll)},_onWheelScroll:function(t){var e=o.DomEvent.getWheelDelta(t);this._delta+=e,this._lastMousePos=this._map.mouseEventToContainerPoint(t),this._startTime||(this._startTime=+new Date);var i=Math.max(40-(+new Date-this._startTime),0);clearTimeout(this._timer),this._timer=setTimeout(o.bind(this._performZoom,this),i),o.DomEvent.preventDefault(t),o.DomEvent.stopPropagation(t)},_performZoom:function(){var t=this._map,e=this._delta,i=t.getZoom();e=e>0?Math.ceil(e):Math.floor(e),e=Math.max(Math.min(e,4),-4),e=t._limitZoom(i+e)-i,this._delta=0,this._startTime=null,e&&t.setZoomAround(this._lastMousePos,i+e)}}),o.Map.addInitHook("addHandler","scrollWheelZoom",o.Map.ScrollWheelZoom),o.extend(o.DomEvent,{_touchstart:o.Browser.msTouch?"MSPointerDown":"touchstart",_touchend:o.Browser.msTouch?"MSPointerUp":"touchend",addDoubleTapListener:function(t,i,n){function s(t){var e;if(o.Browser.msTouch?(p.push(t.pointerId),e=p.length):e=t.touches.length,!(e>1)){var i=Date.now(),n=i-(r||i);h=t.touches?t.touches[0]:t,l=n>0&&u>=n,r=i}}function a(t){if(o.Browser.msTouch){var e=p.indexOf(t.pointerId);if(-1===e)return;p.splice(e,1)}if(l){if(o.Browser.msTouch){var n,s={};for(var a in h)n=h[a],s[a]="function"==typeof n?n.bind(h):n;h=s}h.type="dblclick",i(h),r=null}}var r,h,l=!1,u=250,c="_leaflet_",d=this._touchstart,_=this._touchend,p=[];t[c+d+n]=s,t[c+_+n]=a;var m=o.Browser.msTouch?e.documentElement:t;return t.addEventListener(d,s,!1),m.addEventListener(_,a,!1),o.Browser.msTouch&&m.addEventListener("MSPointerCancel",a,!1),this},removeDoubleTapListener:function(t,i){var n="_leaflet_";return t.removeEventListener(this._touchstart,t[n+this._touchstart+i],!1),(o.Browser.msTouch?e.documentElement:t).removeEventListener(this._touchend,t[n+this._touchend+i],!1),o.Browser.msTouch&&e.documentElement.removeEventListener("MSPointerCancel",t[n+this._touchend+i],!1),this}}),o.extend(o.DomEvent,{_msTouches:[],_msDocumentListener:!1,addMsTouchListener:function(t,e,i,n){switch(e){case"touchstart":return this.addMsTouchListenerStart(t,e,i,n);case"touchend":return this.addMsTouchListenerEnd(t,e,i,n);case"touchmove":return this.addMsTouchListenerMove(t,e,i,n);default:throw"Unknown touch event type"}},addMsTouchListenerStart:function(t,i,n,o){var s="_leaflet_",a=this._msTouches,r=function(t){for(var e=!1,i=0;i0?Math.ceil(a):Math.floor(a),h=t._limitZoom(s+r),l=t.getZoomScale(h)/this._scale;t._animateZoom(n,h,i,l)},_getScaleOrigin:function(){var t=this._centerOffset.subtract(this._delta).divideBy(this._scale);return this._startCenter.add(t)}}),o.Map.addInitHook("addHandler","touchZoom",o.Map.TouchZoom),o.Map.mergeOptions({boxZoom:!0}),o.Map.BoxZoom=o.Handler.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane},addHooks:function(){o.DomEvent.on(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){o.DomEvent.off(this._container,"mousedown",this._onMouseDown)},_onMouseDown:function(t){return!t.shiftKey||1!==t.which&&1!==t.button?!1:(o.DomUtil.disableTextSelection(),this._startLayerPoint=this._map.mouseEventToLayerPoint(t),this._box=o.DomUtil.create("div","leaflet-zoom-box",this._pane),o.DomUtil.setPosition(this._box,this._startLayerPoint),this._container.style.cursor="crosshair",o.DomEvent.on(e,"mousemove",this._onMouseMove,this).on(e,"mouseup",this._onMouseUp,this).on(e,"keydown",this._onKeyDown,this).preventDefault(t),this._map.fire("boxzoomstart"),void 0)},_onMouseMove:function(t){var e=this._startLayerPoint,i=this._box,n=this._map.mouseEventToLayerPoint(t),s=n.subtract(e),a=new o.Point(Math.min(n.x,e.x),Math.min(n.y,e.y));o.DomUtil.setPosition(i,a),i.style.width=Math.max(0,Math.abs(s.x)-4)+"px",i.style.height=Math.max(0,Math.abs(s.y)-4)+"px" -},_finish:function(){this._pane.removeChild(this._box),this._container.style.cursor="",o.DomUtil.enableTextSelection(),o.DomEvent.off(e,"mousemove",this._onMouseMove).off(e,"mouseup",this._onMouseUp).off(e,"keydown",this._onKeyDown)},_onMouseUp:function(t){this._finish();var e=this._map,i=e.mouseEventToLayerPoint(t);if(!this._startLayerPoint.equals(i)){var n=new o.LatLngBounds(e.layerPointToLatLng(this._startLayerPoint),e.layerPointToLatLng(i));e.fitBounds(n),e.fire("boxzoomend",{boxZoomBounds:n})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}}),o.Map.addInitHook("addHandler","boxZoom",o.Map.BoxZoom),o.Map.mergeOptions({keyboard:!0,keyboardPanOffset:80,keyboardZoomOffset:1}),o.Map.Keyboard=o.Handler.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61],zoomOut:[189,109,173]},initialize:function(t){this._map=t,this._setPanOffset(t.options.keyboardPanOffset),this._setZoomOffset(t.options.keyboardZoomOffset)},addHooks:function(){var t=this._map._container;-1===t.tabIndex&&(t.tabIndex="0"),o.DomEvent.on(t,"focus",this._onFocus,this).on(t,"blur",this._onBlur,this).on(t,"mousedown",this._onMouseDown,this),this._map.on("focus",this._addHooks,this).on("blur",this._removeHooks,this)},removeHooks:function(){this._removeHooks();var t=this._map._container;o.DomEvent.off(t,"focus",this._onFocus,this).off(t,"blur",this._onBlur,this).off(t,"mousedown",this._onMouseDown,this),this._map.off("focus",this._addHooks,this).off("blur",this._removeHooks,this)},_onMouseDown:function(){if(!this._focused){var i=e.body,n=e.documentElement,o=i.scrollTop||n.scrollTop,s=i.scrollTop||n.scrollLeft;this._map._container.focus(),t.scrollTo(s,o)}},_onFocus:function(){this._focused=!0,this._map.fire("focus")},_onBlur:function(){this._focused=!1,this._map.fire("blur")},_setPanOffset:function(t){var e,i,n=this._panKeys={},o=this.keyCodes;for(e=0,i=o.left.length;i>e;e++)n[o.left[e]]=[-1*t,0];for(e=0,i=o.right.length;i>e;e++)n[o.right[e]]=[t,0];for(e=0,i=o.down.length;i>e;e++)n[o.down[e]]=[0,t];for(e=0,i=o.up.length;i>e;e++)n[o.up[e]]=[0,-1*t]},_setZoomOffset:function(t){var e,i,n=this._zoomKeys={},o=this.keyCodes;for(e=0,i=o.zoomIn.length;i>e;e++)n[o.zoomIn[e]]=t;for(e=0,i=o.zoomOut.length;i>e;e++)n[o.zoomOut[e]]=-t},_addHooks:function(){o.DomEvent.on(e,"keydown",this._onKeyDown,this)},_removeHooks:function(){o.DomEvent.off(e,"keydown",this._onKeyDown,this)},_onKeyDown:function(t){var e=t.keyCode,i=this._map;if(e in this._panKeys)i.panBy(this._panKeys[e]),i.options.maxBounds&&i.panInsideBounds(i.options.maxBounds);else{if(!(e in this._zoomKeys))return;i.setZoom(i.getZoom()+this._zoomKeys[e])}o.DomEvent.stop(t)}}),o.Map.addInitHook("addHandler","keyboard",o.Map.Keyboard),o.Handler.MarkerDrag=o.Handler.extend({initialize:function(t){this._marker=t},addHooks:function(){var t=this._marker._icon;this._draggable||(this._draggable=new o.Draggable(t,t)),this._draggable.on("dragstart",this._onDragStart,this).on("drag",this._onDrag,this).on("dragend",this._onDragEnd,this),this._draggable.enable()},removeHooks:function(){this._draggable.off("dragstart",this._onDragStart).off("drag",this._onDrag).off("dragend",this._onDragEnd),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},_onDragStart:function(){this._marker.closePopup().fire("movestart").fire("dragstart")},_onDrag:function(){var t=this._marker,e=t._shadow,i=o.DomUtil.getPosition(t._icon),n=t._map.layerPointToLatLng(i);e&&o.DomUtil.setPosition(e,i),t._latlng=n,t.fire("move",{latlng:n}).fire("drag")},_onDragEnd:function(){this._marker.fire("moveend").fire("dragend")}}),o.Control=o.Class.extend({options:{position:"topright"},initialize:function(t){o.setOptions(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),n=t._controlCorners[i];return o.DomUtil.addClass(e,"leaflet-control"),-1!==i.indexOf("bottom")?n.insertBefore(e,n.firstChild):n.appendChild(e),this},removeFrom:function(t){var e=this.getPosition(),i=t._controlCorners[e];return i.removeChild(this._container),this._map=null,this.onRemove&&this.onRemove(t),this}}),o.control=function(t){return new o.Control(t)},o.Map.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.removeFrom(this),this},_initControlPos:function(){function t(t,s){var a=i+t+" "+i+s;e[t+s]=o.DomUtil.create("div",a,n)}var e=this._controlCorners={},i="leaflet-",n=this._controlContainer=o.DomUtil.create("div",i+"control-container",this._container);t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){this._container.removeChild(this._controlContainer)}}),o.Control.Zoom=o.Control.extend({options:{position:"topleft"},onAdd:function(t){var e="leaflet-control-zoom",i=o.DomUtil.create("div",e+" leaflet-bar");return this._map=t,this._zoomInButton=this._createButton("+","Zoom in",e+"-in",i,this._zoomIn,this),this._zoomOutButton=this._createButton("-","Zoom out",e+"-out",i,this._zoomOut,this),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},_zoomIn:function(t){this._map.zoomIn(t.shiftKey?3:1)},_zoomOut:function(t){this._map.zoomOut(t.shiftKey?3:1)},_createButton:function(t,e,i,n,s,a){var r=o.DomUtil.create("a",i,n);r.innerHTML=t,r.href="#",r.title=e;var h=o.DomEvent.stopPropagation;return o.DomEvent.on(r,"click",h).on(r,"mousedown",h).on(r,"dblclick",h).on(r,"click",o.DomEvent.preventDefault).on(r,"click",s,a),r},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";o.DomUtil.removeClass(this._zoomInButton,e),o.DomUtil.removeClass(this._zoomOutButton,e),t._zoom===t.getMinZoom()&&o.DomUtil.addClass(this._zoomOutButton,e),t._zoom===t.getMaxZoom()&&o.DomUtil.addClass(this._zoomInButton,e)}}),o.Map.mergeOptions({zoomControl:!0}),o.Map.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new o.Control.Zoom,this.addControl(this.zoomControl))}),o.control.zoom=function(t){return new o.Control.Zoom(t)},o.Control.Attribution=o.Control.extend({options:{position:"bottomright",prefix:'Leaflet'},initialize:function(t){o.setOptions(this,t),this._attributions={}},onAdd:function(t){return this._container=o.DomUtil.create("div","leaflet-control-attribution"),o.DomEvent.disableClickPropagation(this._container),t.on("layeradd",this._onLayerAdd,this).on("layerremove",this._onLayerRemove,this),this._update(),this._container},onRemove:function(t){t.off("layeradd",this._onLayerAdd).off("layerremove",this._onLayerRemove)},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):void 0},removeAttribution:function(t){return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):void 0},_update:function(){if(this._map){var t=[];for(var e in this._attributions)this._attributions[e]&&t.push(e);var i=[];this.options.prefix&&i.push(this.options.prefix),t.length&&i.push(t.join(", ")),this._container.innerHTML=i.join(" | ")}},_onLayerAdd:function(t){t.layer.getAttribution&&this.addAttribution(t.layer.getAttribution())},_onLayerRemove:function(t){t.layer.getAttribution&&this.removeAttribution(t.layer.getAttribution())}}),o.Map.mergeOptions({attributionControl:!0}),o.Map.addInitHook(function(){this.options.attributionControl&&(this.attributionControl=(new o.Control.Attribution).addTo(this))}),o.control.attribution=function(t){return new o.Control.Attribution(t)},o.Control.Scale=o.Control.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0,updateWhenIdle:!1},onAdd:function(t){this._map=t;var e="leaflet-control-scale",i=o.DomUtil.create("div",e),n=this.options;return this._addScales(n,e,i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=o.DomUtil.create("div",e+"-line",i)),t.imperial&&(this._iScale=o.DomUtil.create("div",e+"-line",i))},_update:function(){var t=this._map.getBounds(),e=t.getCenter().lat,i=6378137*Math.PI*Math.cos(e*Math.PI/180),n=i*(t.getNorthEast().lng-t.getSouthWest().lng)/180,o=this._map.getSize(),s=this.options,a=0;o.x>0&&(a=n*(s.maxWidth/o.x)),this._updateScales(s,a)},_updateScales:function(t,e){t.metric&&e&&this._updateMetric(e),t.imperial&&e&&this._updateImperial(e)},_updateMetric:function(t){var e=this._getRoundNum(t);this._mScale.style.width=this._getScaleWidth(e/t)+"px",this._mScale.innerHTML=1e3>e?e+" m":e/1e3+" km"},_updateImperial:function(t){var e,i,n,o=3.2808399*t,s=this._iScale;o>5280?(e=o/5280,i=this._getRoundNum(e),s.style.width=this._getScaleWidth(i/e)+"px",s.innerHTML=i+" mi"):(n=this._getRoundNum(o),s.style.width=this._getScaleWidth(n/o)+"px",s.innerHTML=n+" ft")},_getScaleWidth:function(t){return Math.round(this.options.maxWidth*t)-10},_getRoundNum:function(t){var e=Math.pow(10,(Math.floor(t)+"").length-1),i=t/e;return i=i>=10?10:i>=5?5:i>=3?3:i>=2?2:1,e*i}}),o.control.scale=function(t){return new o.Control.Scale(t)},o.Control.Layers=o.Control.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0},initialize:function(t,e,i){o.setOptions(this,i),this._layers={},this._lastZIndex=0,this._handlingClick=!1;for(var n in t)this._addLayer(t[n],n);for(n in e)this._addLayer(e[n],n,!0)},onAdd:function(t){return this._initLayout(),this._update(),t.on("layeradd",this._onLayerChange,this).on("layerremove",this._onLayerChange,this),this._container},onRemove:function(t){t.off("layeradd",this._onLayerChange).off("layerremove",this._onLayerChange)},addBaseLayer:function(t,e){return this._addLayer(t,e),this._update(),this},addOverlay:function(t,e){return this._addLayer(t,e,!0),this._update(),this},removeLayer:function(t){var e=o.stamp(t);return delete this._layers[e],this._update(),this},_initLayout:function(){var t="leaflet-control-layers",e=this._container=o.DomUtil.create("div",t);e.setAttribute("aria-haspopup",!0),o.Browser.touch?o.DomEvent.on(e,"click",o.DomEvent.stopPropagation):(o.DomEvent.disableClickPropagation(e),o.DomEvent.on(e,"mousewheel",o.DomEvent.stopPropagation));var i=this._form=o.DomUtil.create("form",t+"-list");if(this.options.collapsed){o.DomEvent.on(e,"mouseover",this._expand,this).on(e,"mouseout",this._collapse,this);var n=this._layersLink=o.DomUtil.create("a",t+"-toggle",e);n.href="#",n.title="Layers",o.Browser.touch?o.DomEvent.on(n,"click",o.DomEvent.stopPropagation).on(n,"click",o.DomEvent.preventDefault).on(n,"click",this._expand,this):o.DomEvent.on(n,"focus",this._expand,this),this._map.on("movestart",this._collapse,this)}else this._expand();this._baseLayersList=o.DomUtil.create("div",t+"-base",i),this._separator=o.DomUtil.create("div",t+"-separator",i),this._overlaysList=o.DomUtil.create("div",t+"-overlays",i),e.appendChild(i)},_addLayer:function(t,e,i){var n=o.stamp(t);this._layers[n]={layer:t,name:e,overlay:i},this.options.autoZIndex&&t.setZIndex&&(this._lastZIndex++,t.setZIndex(this._lastZIndex))},_update:function(){if(this._container){this._baseLayersList.innerHTML="",this._overlaysList.innerHTML="";var t,e,i=!1,n=!1;for(t in this._layers)e=this._layers[t],this._addItem(e),n=n||e.overlay,i=i||!e.overlay;this._separator.style.display=n&&i?"":"none"}},_onLayerChange:function(t){var e=o.stamp(t.layer);this._layers[e]&&!this._handlingClick&&this._update()},_createRadioElement:function(t,i){var n='t;t++)e=o[t],i=this._layers[e.layerId],e.checked&&!this._map.hasLayer(i.layer)?(this._map.addLayer(i.layer),i.overlay?this._map.fire("overlayadd",{layer:i}):n=i.layer):!e.checked&&this._map.hasLayer(i.layer)&&(this._map.removeLayer(i.layer),this._map.fire("overlayremove",{layer:i}));n&&(this._map.setZoom(this._map.getZoom()),this._map.fire("baselayerchange",{layer:n})),this._handlingClick=!1},_expand:function(){o.DomUtil.addClass(this._container,"leaflet-control-layers-expanded")},_collapse:function(){this._container.className=this._container.className.replace(" leaflet-control-layers-expanded","")}}),o.control.layers=function(t,e,i){return new o.Control.Layers(t,e,i)},o.PosAnimation=o.Class.extend({includes:o.Mixin.Events,run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._newPos=e,this.fire("start"),t.style[o.DomUtil.TRANSITION]="all "+(i||.25)+"s cubic-bezier(0,0,"+(n||.5)+",1)",o.DomEvent.on(t,o.DomUtil.TRANSITION_END,this._onTransitionEnd,this),o.DomUtil.setPosition(t,e),o.Util.falseFn(t.offsetWidth),this._stepTimer=setInterval(o.bind(this._onStep,this),50)},stop:function(){this._inProgress&&(o.DomUtil.setPosition(this._el,this._getPos()),this._onTransitionEnd(),o.Util.falseFn(this._el.offsetWidth))},_onStep:function(){this._el._leaflet_pos=this._getPos(),this.fire("step")},_transformRe:/([-+]?(?:\d*\.)?\d+)\D*, ([-+]?(?:\d*\.)?\d+)\D*\)/,_getPos:function(){var e,i,n,s=this._el,a=t.getComputedStyle(s);return o.Browser.any3d?(n=a[o.DomUtil.TRANSFORM].match(this._transformRe),e=parseFloat(n[1]),i=parseFloat(n[2])):(e=parseFloat(a.left),i=parseFloat(a.top)),new o.Point(e,i,!0)},_onTransitionEnd:function(){o.DomEvent.off(this._el,o.DomUtil.TRANSITION_END,this._onTransitionEnd,this),this._inProgress&&(this._inProgress=!1,this._el.style[o.DomUtil.TRANSITION]="",this._el._leaflet_pos=this._newPos,clearInterval(this._stepTimer),this.fire("step").fire("end"))}}),o.Map.include({setView:function(t,e,n){if(e=this._limitZoom(e),t=o.latLng(t),n=n||{},this._panAnim&&this._panAnim.stop(),this._loaded&&!n.reset&&n!==!0){n.animate!==i&&(n.zoom=o.extend({animate:n.animate},n.zoom),n.pan=o.extend({animate:n.animate},n.pan));var s=this._zoom!==e?this._tryAnimatedZoom&&this._tryAnimatedZoom(t,e,n.zoom):this._tryAnimatedPan(t,n.pan);if(s)return clearTimeout(this._sizeTimer),this}return this._resetView(t,e),this},panBy:function(t,e){if(t=o.point(t).round(),e=e||{},!t.x&&!t.y)return this;if(this._panAnim||(this._panAnim=new o.PosAnimation,this._panAnim.on({step:this._onPanTransitionStep,end:this._onPanTransitionEnd},this)),e.noMoveStart||this.fire("movestart"),e.animate!==!1){o.DomUtil.addClass(this._mapPane,"leaflet-pan-anim");var i=this._getMapPanePos().subtract(t);this._panAnim.run(this._mapPane,i,e.duration||.25,e.easeLinearity)}else this._rawPanBy(t),this.fire("move").fire("moveend");return this},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){o.DomUtil.removeClass(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,e){var i=this._getCenterOffset(t)._floor();return(e&&e.animate)===!0||this.getSize().contains(i)?(this.panBy(i,e),!0):!1}}),o.PosAnimation=o.DomUtil.TRANSITION?o.PosAnimation:o.PosAnimation.extend({run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=i||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=o.DomUtil.getPosition(t),this._offset=e.subtract(this._startPos),this._startTime=+new Date,this.fire("start"),this._animate()},stop:function(){this._inProgress&&(this._step(),this._complete())},_animate:function(){this._animId=o.Util.requestAnimFrame(this._animate,this),this._step()},_step:function(){var t=+new Date-this._startTime,e=1e3*this._duration;e>t?this._runFrame(this._easeOut(t/e)):(this._runFrame(1),this._complete())},_runFrame:function(t){var e=this._startPos.add(this._offset.multiplyBy(t));o.DomUtil.setPosition(this._el,e),this.fire("step")},_complete:function(){o.Util.cancelAnimFrame(this._animId),this._inProgress=!1,this.fire("end")},_easeOut:function(t){return 1-Math.pow(1-t,this._easeOutPower)}}),o.Map.mergeOptions({zoomAnimation:!0,zoomAnimationThreshold:4}),o.DomUtil.TRANSITION&&o.Map.addInitHook(function(){o.DomEvent.on(this._mapPane,o.DomUtil.TRANSITION_END,this._catchTransitionEnd,this)}),o.Map.include(o.DomUtil.TRANSITION?{_catchTransitionEnd:function(){this._animatingZoom&&this._onZoomTransitionEnd()},_tryAnimatedZoom:function(t,e,i){if(this._animatingZoom)return!0;if(i=i||{},!this.options.zoomAnimation||i.animate===!1||!o.DomUtil.TRANSITION||o.Browser.android23||o.Browser.mobileOpera||Math.abs(e-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),s=this._getCenterOffset(t)._divideBy(1-1/n),a=this._getCenterLayerPoint()._add(s);return i.animate===!0||this.getSize().contains(s)?(this.fire("movestart").fire("zoomstart"),this._animateZoom(t,e,a,n),!0):!1},_animateZoom:function(t,e,i,n,s){this._animatingZoom=!0,o.DomUtil.addClass(this._mapPane,"leaflet-zoom-anim"),this._animateToCenter=t,this._animateToZoom=e,o.Draggable&&(o.Draggable._disabled=!0),this.fire("zoomanim",{center:t,zoom:e,origin:i,scale:n,delta:s})},_onZoomTransitionEnd:function(){this._animatingZoom=!1,o.DomUtil.removeClass(this._mapPane,"leaflet-zoom-anim"),this._resetView(this._animateToCenter,this._animateToZoom,!0,!0),o.Draggable&&(o.Draggable._disabled=!1)}}:{}),o.TileLayer.include({_animateZoom:function(t){var e=!1;this._animating||(this._animating=!0,e=!0),e&&this._prepareBgBuffer();var i=this._bgBuffer;e&&(clearTimeout(this._clearBgBufferTimer),o.Util.falseFn(i.offsetWidth));var n=o.DomUtil.TRANSFORM,s=t.delta?o.DomUtil.getTranslateString(t.delta):i.style[n];i.style[n]=s+" "+o.DomUtil.getScaleString(t.scale,t.origin)},_endZoomAnim:function(){var t=this._tileContainer,e=this._bgBuffer;t.style.visibility="",t.style.zIndex=2,e.style.zIndex=1,o.Util.falseFn(e.offsetWidth),this._animating=!1},_clearBgBuffer:function(){var t=this._map;!t||t._animatingZoom||t.touchZoom._zooming||(this._bgBuffer.innerHTML="",this._bgBuffer.style[o.DomUtil.TRANSFORM]="")},_prepareBgBuffer:function(){var t=this._tileContainer,e=this._bgBuffer,i=this._getLoadedTilesPercentage(e),n=this._getLoadedTilesPercentage(t);return e&&i>.5&&.5>n?(t.style.visibility="hidden",this._stopLoadingImages(t),void 0):(e.style.visibility="hidden",e.style[o.DomUtil.TRANSFORM]="",this._tileContainer=e,e=this._bgBuffer=t,this._stopLoadingImages(e),void 0)},_getLoadedTilesPercentage:function(t){var e,i,n=t.getElementsByTagName("img"),o=0;for(e=0,i=n.length;i>e;e++)n[e].complete&&o++;return o/i},_stopLoadingImages:function(t){var e,i,n,s=Array.prototype.slice.call(t.getElementsByTagName("img"));for(e=0,i=s.length;i>e;e++)n=s[e],n.complete||(n.onload=o.Util.falseFn,n.onerror=o.Util.falseFn,n.src=o.Util.emptyImageUrl,n.parentNode.removeChild(n))}}),o.Map.include({_defaultLocateOptions:{watch:!1,setView:!1,maxZoom:1/0,timeout:1e4,maximumAge:0,enableHighAccuracy:!1},locate:function(t){if(t=this._locateOptions=o.extend(this._defaultLocateOptions,t),!navigator.geolocation)return this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this;var e=o.bind(this._handleGeolocationResponse,this),i=o.bind(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e=t.code,i=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+i+"."})},_handleGeolocationResponse:function(t){var e=t.coords.latitude,i=t.coords.longitude,n=new o.LatLng(e,i),s=180*t.coords.accuracy/40075017,a=s/Math.cos(o.LatLng.DEG_TO_RAD*e),r=o.latLngBounds([e-s,i-a],[e+s,i+a]),h=this._locateOptions;if(h.setView){var l=Math.min(this.getBoundsZoom(r),h.maxZoom);this.setView(n,l)}var u=o.extend({latlng:n,bounds:r},t.coords);this.fire("locationfound",u)}})}(window,document); \ No newline at end of file diff --git a/src/app/panels/bettermap/leaflet/plugins.css b/src/app/panels/bettermap/leaflet/plugins.css deleted file mode 100644 index ba2c7c405ac..00000000000 --- a/src/app/panels/bettermap/leaflet/plugins.css +++ /dev/null @@ -1,75 +0,0 @@ -.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow { - -webkit-transition: -webkit-transform 0.2s ease-out, opacity 0.2s ease-in; - -moz-transition: -moz-transform 0.2s ease-out, opacity 0.2s ease-in; - -o-transition: -o-transform 0.2s ease-out, opacity 0.2s ease-in; - transition: transform 0.2s ease-out, opacity 0.2s ease-in; - } -.marker-cluster-small { - background-color: rgba(181, 226, 140, 0.6); - } -.marker-cluster-small div { - background-color: rgba(110, 204, 57, 0.6); - } - -.marker-cluster-medium { - background-color: rgba(241, 211, 87, 0.6); - } -.marker-cluster-medium div { - background-color: rgba(240, 194, 12, 0.6); - } - -.marker-cluster-large { - background-color: rgba(253, 156, 115, 0.6); - } -.marker-cluster-large div { - background-color: rgba(241, 128, 23, 0.6); - } - -.marker-cluster { - background-clip: padding-box; - border-radius: 20px; - } -.marker-cluster div { - width: 30px; - height: 30px; - margin-left: 5px; - margin-top: 5px; - - text-align: center; - border-radius: 15px; - font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif; - } -.marker-cluster span { - line-height: 30px; - } - -.leaflet-label { - background: #1f1f1f; - background-clip: padding-box; - border-radius: 4px; - border-style: solid; - border-width: 0px; - display: block; - font-weight: 200; - font-size: 11pt; - padding: 5px; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - white-space: nowrap; - z-index: 99999 !important; -} - -.leaflet-label:before { - border-right: 6px solid black; - border-right-color: inherit; - border-top: 6px solid transparent; - border-bottom: 6px solid transparent; - content: ""; - position: absolute; - top: 5px; - left: -10px; - display: none; -} \ No newline at end of file diff --git a/src/app/panels/bettermap/leaflet/plugins.js b/src/app/panels/bettermap/leaflet/plugins.js deleted file mode 100644 index 81f6e444da4..00000000000 --- a/src/app/panels/bettermap/leaflet/plugins.js +++ /dev/null @@ -1,16 +0,0 @@ -/* - Leaflet.markercluster, Provides Beautiful Animated Marker Clustering functionality for Leaflet, a JS library for interactive maps. - https://github.com/Leaflet/Leaflet.markercluster - (c) 2012-2013, Dave Leaver, smartrak -*/ -!function(t,e){L.MarkerClusterGroup=L.FeatureGroup.extend({options:{maxClusterRadius:80,iconCreateFunction:null,spiderfyOnMaxZoom:!0,showCoverageOnHover:!0,zoomToBoundsOnClick:!0,singleMarkerMode:!1,disableClusteringAtZoom:null,removeOutsideVisibleBounds:!0,animateAddingMarkers:!1,spiderfyDistanceMultiplier:1,polygonOptions:{}},initialize:function(t){L.Util.setOptions(this,t),this.options.iconCreateFunction||(this.options.iconCreateFunction=this._defaultIconCreateFunction),L.FeatureGroup.prototype.initialize.call(this,[]),this._inZoomAnimation=0,this._needsClustering=[],this._needsRemoving=[],this._currentShownBounds=null},addLayer:function(t){if(t instanceof L.LayerGroup){var e=[];for(var i in t._layers)e.push(t._layers[i]);return this.addLayers(e)}if(!this._map)return this._needsClustering.push(t),this;if(this.hasLayer(t))return this;this._unspiderfy&&this._unspiderfy(),this._addLayer(t,this._maxZoom);var n=t,r=this._map.getZoom();if(t.__parent)for(;n.__parent._zoom>=r;)n=n.__parent;return this._currentShownBounds.contains(n.getLatLng())&&(this.options.animateAddingMarkers?this._animationAddLayer(t,n):this._animationAddLayerNonAnimated(t,n)),this},removeLayer:function(t){return this._map?t.__parent?(this._unspiderfy&&(this._unspiderfy(),this._unspiderfyLayer(t)),this._removeLayer(t,!0),(t._icon||t._container)&&(L.FeatureGroup.prototype.removeLayer.call(this,t),t.setOpacity&&t.setOpacity(1)),this):this:(!this._arraySplice(this._needsClustering,t)&&this.hasLayer(t)&&this._needsRemoving.push(t),this)},addLayers:function(t){var e,i,n;if(!this._map)return this._needsClustering=this._needsClustering.concat(t),this;for(e=0,i=t.length;i>e;e++)if(n=t[e],!this.hasLayer(n)&&(this._addLayer(n,this._maxZoom),n.__parent&&2===n.__parent.getChildCount())){var r=n.__parent.getAllChildMarkers(),s=r[0]===n?r[1]:r[0];L.FeatureGroup.prototype.removeLayer.call(this,s)}for(e in this._layers)n=this._layers[e],n instanceof L.MarkerCluster&&n._iconNeedsUpdate&&n._updateIcon();return this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds),this},removeLayers:function(t){var e,i,n;if(!this._map){for(e=0,i=t.length;i>e;e++)this._arraySplice(this._needsClustering,t[e]);return this}for(e=0,i=t.length;i>e;e++)n=t[e],n.__parent&&(this._removeLayer(n,!0,!0),n._icon&&(L.FeatureGroup.prototype.removeLayer.call(this,n),n.setOpacity(1)));this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds);for(e in this._layers)n=this._layers[e],n instanceof L.MarkerCluster&&n._updateIcon();return this},clearLayers:function(){this._map||(this._needsClustering=[],delete this._gridClusters,delete this._gridUnclustered),this._noanimationUnspiderfy&&this._noanimationUnspiderfy();for(var t in this._layers)L.FeatureGroup.prototype.removeLayer.call(this,this._layers[t]);return this.eachLayer(function(t){delete t.__parent}),this._map&&this._generateInitialClusters(),this},getBounds:function(){var t=new L.LatLngBounds;if(this._topClusterLevel)t.extend(this._topClusterLevel._bounds);else for(var e=this._needsClustering.length-1;e>=0;e--)t.extend(this._needsClustering[e].getLatLng());return t},eachLayer:function(t,e){var i,n=this._needsClustering.slice();for(this._topClusterLevel&&this._topClusterLevel.getAllChildMarkers(n),i=n.length-1;i>=0;i--)t.call(e,n[i])},hasLayer:function(t){if(!t||t._noHas)return!1;var e,i=this._needsClustering;for(e=i.length-1;e>=0;e--)if(i[e]===t)return!0;for(i=this._needsRemoving,e=i.length-1;e>=0;e--)if(i[e]===t)return!1;return!(!t.__parent||t.__parent._group!==this)},zoomToShowLayer:function(t,e){var i=function(){if((t._icon||t.__parent._icon)&&!this._inZoomAnimation)if(this._map.off("moveend",i,this),this.off("animationend",i,this),t._icon)e();else if(t.__parent._icon){var n=function(){this.off("spiderfied",n,this),e()};this.on("spiderfied",n,this),t.__parent.spiderfy()}};t._icon?e():t.__parent._zoome;e++)n=this._needsRemoving[e],this._removeLayer(n);for(this._needsRemoving=[],e=0,i=this._needsClustering.length;i>e;e++)n=this._needsClustering[e],n.__parent||this._addLayer(n,this._maxZoom);this._needsClustering=[],this._map.on("zoomend",this._zoomEnd,this),this._map.on("moveend",this._moveEnd,this),this._spiderfierOnAdd&&this._spiderfierOnAdd(),this._bindEvents(),this._zoom=this._map.getZoom(),this._currentShownBounds=this._getExpandedVisibleBounds(),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds)},onRemove:function(t){t.off("zoomend",this._zoomEnd,this),t.off("moveend",this._moveEnd,this),this._unbindEvents(),this._map._mapPane.className=this._map._mapPane.className.replace(" leaflet-cluster-anim",""),this._spiderfierOnRemove&&this._spiderfierOnRemove();for(var e in this._layers)L.FeatureGroup.prototype.removeLayer.call(this,this._layers[e]);this._map=null},_arraySplice:function(t,e){for(var i=t.length-1;i>=0;i--)if(t[i]===e)return t.splice(i,1),!0},_removeLayer:function(t,e,i){var n=this._gridClusters,r=this._gridUnclustered,s=this._map;if(e)for(var o=this._maxZoom;o>=0&&r[o].removeObject(t,s.project(t.getLatLng(),o));o--);var a,l=t.__parent,_=l._markers;for(this._arraySplice(_,t);l&&(l._childCount--,!(l._zoom<0));)e&&l._childCount<=1?(a=l._markers[0]===t?l._markers[1]:l._markers[0],n[l._zoom].removeObject(l,s.project(l._cLatLng,l._zoom)),r[l._zoom].addObject(a,s.project(a.getLatLng(),l._zoom)),this._arraySplice(l.__parent._childClusters,l),l.__parent._markers.push(a),a.__parent=l.__parent,l._icon&&(L.FeatureGroup.prototype.removeLayer.call(this,l),i||(a._noHas=!0,L.FeatureGroup.prototype.addLayer.call(this,a),delete a._noHas))):(l._recalculateBounds(),i&&l._icon||l._updateIcon()),l=l.__parent;delete t.__parent},_propagateEvent:function(t){t.target instanceof L.MarkerCluster&&(t.type="cluster"+t.type),L.FeatureGroup.prototype._propagateEvent.call(this,t)},_defaultIconCreateFunction:function(t){var e=t.getChildCount(),i=" marker-cluster-";return i+=10>e?"small":100>e?"medium":"large",new L.DivIcon({html:"
"+e+"
",className:"marker-cluster"+i,iconSize:new L.Point(40,40)})},_bindEvents:function(){var t=null,e=this._map,i=this.options.spiderfyOnMaxZoom,n=this.options.showCoverageOnHover,r=this.options.zoomToBoundsOnClick;(i||r)&&this.on("clusterclick",function(t){e.getMaxZoom()===e.getZoom()?i&&t.layer.spiderfy():r&&t.layer.zoomToBounds()},this),n&&(this.on("clustermouseover",function(i){this._inZoomAnimation||(t&&e.removeLayer(t),i.layer.getChildCount()>2&&i.layer!==this._spiderfied&&(t=new L.Polygon(i.layer.getConvexHull(),this.options.polygonOptions),e.addLayer(t)))},this),this.on("clustermouseout",function(){t&&(e.removeLayer(t),t=null)},this),e.on("zoomend",function(){t&&(e.removeLayer(t),t=null)},this),e.on("layerremove",function(i){t&&i.layer===this&&(e.removeLayer(t),t=null)},this))},_unbindEvents:function(){var t=this.options.spiderfyOnMaxZoom,e=this.options.showCoverageOnHover,i=this.options.zoomToBoundsOnClick,n=this._map;(t||i)&&this.off("clusterclick",null,this),e&&(this.off("clustermouseover",null,this),this.off("clustermouseout",null,this),n.off("zoomend",null,this),n.off("layerremove",null,this))},_zoomEnd:function(){this._map&&(this._mergeSplitClusters(),this._zoom=this._map._zoom,this._currentShownBounds=this._getExpandedVisibleBounds())},_moveEnd:function(){if(!this._inZoomAnimation){var t=this._getExpandedVisibleBounds();this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,this._zoom,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,t),this._currentShownBounds=t}},_generateInitialClusters:function(){var t=this._map.getMaxZoom(),e=this.options.maxClusterRadius;this.options.disableClusteringAtZoom&&(t=this.options.disableClusteringAtZoom-1),this._maxZoom=t,this._gridClusters={},this._gridUnclustered={};for(var i=t;i>=0;i--)this._gridClusters[i]=new L.DistanceGrid(e),this._gridUnclustered[i]=new L.DistanceGrid(e);this._topClusterLevel=new L.MarkerCluster(this,-1)},_addLayer:function(t,e){var i,n,r=this._gridClusters,s=this._gridUnclustered;for(this.options.singleMarkerMode&&(t.options.icon=this.options.iconCreateFunction({getChildCount:function(){return 1},getAllChildMarkers:function(){return[t]}}));e>=0;e--){i=this._map.project(t.getLatLng(),e);var o=r[e].getNearObject(i);if(o)return o._addChild(t),t.__parent=o,void 0;if(o=s[e].getNearObject(i)){var a=o.__parent;a&&this._removeLayer(o,!1);var l=new L.MarkerCluster(this,e,o,t);r[e].addObject(l,this._map.project(l._cLatLng,e)),o.__parent=l,t.__parent=l;var _=l;for(n=e-1;n>a._zoom;n--)_=new L.MarkerCluster(this,n,_),r[n].addObject(_,this._map.project(o.getLatLng(),n));for(a._addChild(_),n=e;n>=0&&s[n].removeObject(o,this._map.project(o.getLatLng(),n));n--);return}s[e].addObject(t,i)}this._topClusterLevel._addChild(t),t.__parent=this._topClusterLevel},_mergeSplitClusters:function(){this._zoomthis._map._zoom?(this._animationStart(),this._animationZoomOut(this._zoom,this._map._zoom)):this._moveEnd()},_getExpandedVisibleBounds:function(){if(!this.options.removeOutsideVisibleBounds)return this.getBounds();var t=this._map,e=t.getBounds(),i=e._southWest,n=e._northEast,r=L.Browser.mobile?0:Math.abs(i.lat-n.lat),s=L.Browser.mobile?0:Math.abs(i.lng-n.lng);return new L.LatLngBounds(new L.LatLng(i.lat-r,i.lng-s,!0),new L.LatLng(n.lat+r,n.lng+s,!0))},_animationAddLayerNonAnimated:function(t,e){if(e===t)t._noHas=!0,L.FeatureGroup.prototype.addLayer.call(this,t),delete t._noHas;else if(2===e._childCount){e._addToMap();var i=e.getAllChildMarkers();L.FeatureGroup.prototype.removeLayer.call(this,i[0]),L.FeatureGroup.prototype.removeLayer.call(this,i[1])}else e._updateIcon()}}),L.MarkerClusterGroup.include(L.DomUtil.TRANSITION?{_animationStart:function(){this._map._mapPane.className+=" leaflet-cluster-anim",this._inZoomAnimation++},_animationEnd:function(){this._map&&(this._map._mapPane.className=this._map._mapPane.className.replace(" leaflet-cluster-anim","")),this._inZoomAnimation--,this.fire("animationend")},_animationZoomIn:function(t,e){var i,n=this,r=this._getExpandedVisibleBounds();this._topClusterLevel._recursively(r,t,0,function(s){var o,a=s._latlng,l=s._markers;for(s._isSingleParent()&&t+1===e?(L.FeatureGroup.prototype.removeLayer.call(n,s),s._recursivelyAddChildrenToMap(null,e,r)):(s.setOpacity(0),s._recursivelyAddChildrenToMap(a,e,r)),i=l.length-1;i>=0;i--)o=l[i],r.contains(o._latlng)||L.FeatureGroup.prototype.removeLayer.call(n,o)}),this._forceLayout();var s,o;n._topClusterLevel._recursivelyBecomeVisible(r,e);for(s in n._layers)o=n._layers[s],o instanceof L.MarkerCluster||!o._icon||o.setOpacity(1);n._topClusterLevel._recursively(r,t,e,function(t){t._recursivelyRestoreChildPositions(e)}),setTimeout(function(){n._topClusterLevel._recursively(r,t,0,function(t){L.FeatureGroup.prototype.removeLayer.call(n,t),t.setOpacity(1)}),n._animationEnd()},200)},_animationZoomOut:function(t,e){this._animationZoomOutSingle(this._topClusterLevel,t-1,e),this._topClusterLevel._recursivelyAddChildrenToMap(null,e,this._getExpandedVisibleBounds()),this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t,this._getExpandedVisibleBounds())},_animationZoomOutSingle:function(t,e,i){var n=this._getExpandedVisibleBounds();t._recursivelyAnimateChildrenInAndAddSelfToMap(n,e+1,i);var r=this;this._forceLayout(),t._recursivelyBecomeVisible(n,i),setTimeout(function(){if(1===t._childCount){var s=t._markers[0];s.setLatLng(s.getLatLng()),s.setOpacity(1)}else t._recursively(n,i,0,function(t){t._recursivelyRemoveChildrenFromMap(n,e+1)});r._animationEnd()},200)},_animationAddLayer:function(t,e){var i=this;t._noHas=!0,L.FeatureGroup.prototype.addLayer.call(this,t),delete t._noHas,e!==t&&(e._childCount>2?(e._updateIcon(),this._forceLayout(),this._animationStart(),t._setPos(this._map.latLngToLayerPoint(e.getLatLng())),t.setOpacity(0),setTimeout(function(){L.FeatureGroup.prototype.removeLayer.call(i,t),t.setOpacity(1),i._animationEnd()},200)):(this._forceLayout(),i._animationStart(),i._animationZoomOutSingle(e,this._map.getMaxZoom(),this._map.getZoom())))},_forceLayout:function(){L.Util.falseFn(e.body.offsetWidth)}}:{_animationStart:function(){},_animationZoomIn:function(t,e){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,e,this._getExpandedVisibleBounds())},_animationZoomOut:function(t,e){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,e,this._getExpandedVisibleBounds())},_animationAddLayer:function(t,e){this._animationAddLayerNonAnimated(t,e)}}),L.markerClusterGroup=function(t){return new L.MarkerClusterGroup(t)},L.MarkerCluster=L.Marker.extend({initialize:function(t,e,i,n){L.Marker.prototype.initialize.call(this,i?i._cLatLng||i.getLatLng():new L.LatLng(0,0),{icon:this}),this._group=t,this._zoom=e,this._markers=[],this._childClusters=[],this._childCount=0,this._iconNeedsUpdate=!0,this._bounds=new L.LatLngBounds,i&&this._addChild(i),n&&this._addChild(n)},getAllChildMarkers:function(t){t=t||[];for(var e=this._childClusters.length-1;e>=0;e--)this._childClusters[e].getAllChildMarkers(t);for(var i=this._markers.length-1;i>=0;i--)t.push(this._markers[i]);return t},getChildCount:function(){return this._childCount},zoomToBounds:function(){this._group._map.fitBounds(this._bounds)},getBounds:function(){var t=new L.LatLngBounds;return t.extend(this._bounds),t},_updateIcon:function(){this._iconNeedsUpdate=!0,this._icon&&this.setIcon(this)},createIcon:function(){return this._iconNeedsUpdate&&(this._iconObj=this._group.options.iconCreateFunction(this),this._iconNeedsUpdate=!1),this._iconObj.createIcon()},createShadow:function(){return this._iconObj.createShadow()},_addChild:function(t,e){this._iconNeedsUpdate=!0,this._expandBounds(t),t instanceof L.MarkerCluster?(e||(this._childClusters.push(t),t.__parent=this),this._childCount+=t._childCount):(e||this._markers.push(t),this._childCount++),this.__parent&&this.__parent._addChild(t,!0)},_expandBounds:function(t){var e,i=t._wLatLng||t._latlng;t instanceof L.MarkerCluster?(this._bounds.extend(t._bounds),e=t._childCount):(this._bounds.extend(i),e=1),this._cLatLng||(this._cLatLng=t._cLatLng||i);var n=this._childCount+e;this._wLatLng?(this._wLatLng.lat=(i.lat*e+this._wLatLng.lat*this._childCount)/n,this._wLatLng.lng=(i.lng*e+this._wLatLng.lng*this._childCount)/n):this._latlng=this._wLatLng=new L.LatLng(i.lat,i.lng)},_addToMap:function(t){t&&(this._backupLatlng=this._latlng,this.setLatLng(t)),this._noHas=!0,L.FeatureGroup.prototype.addLayer.call(this._group,this),delete this._noHas},_recursivelyAnimateChildrenIn:function(t,e,i){this._recursively(t,0,i-1,function(t){var i,n,r=t._markers;for(i=r.length-1;i>=0;i--)n=r[i],n._icon&&(n._setPos(e),n.setOpacity(0))},function(t){var i,n,r=t._childClusters;for(i=r.length-1;i>=0;i--)n=r[i],n._icon&&(n._setPos(e),n.setOpacity(0))})},_recursivelyAnimateChildrenInAndAddSelfToMap:function(t,e,i){this._recursively(t,i,0,function(n){n._recursivelyAnimateChildrenIn(t,n._group._map.latLngToLayerPoint(n.getLatLng()).round(),e),n._isSingleParent()&&e-1===i?(n.setOpacity(1),n._recursivelyRemoveChildrenFromMap(t,e)):n.setOpacity(0),n._addToMap()})},_recursivelyBecomeVisible:function(t,e){this._recursively(t,0,e,null,function(t){t.setOpacity(1)})},_recursivelyAddChildrenToMap:function(t,e,i){this._recursively(i,-1,e,function(n){if(e!==n._zoom)for(var r=n._markers.length-1;r>=0;r--){var s=n._markers[r];i.contains(s._latlng)&&(t&&(s._backupLatlng=s.getLatLng(),s.setLatLng(t),s.setOpacity&&s.setOpacity(0)),s._noHas=!0,L.FeatureGroup.prototype.addLayer.call(n._group,s),delete s._noHas)}},function(e){e._addToMap(t)})},_recursivelyRestoreChildPositions:function(t){for(var e=this._markers.length-1;e>=0;e--){var i=this._markers[e];i._backupLatlng&&(i.setLatLng(i._backupLatlng),delete i._backupLatlng)}if(t-1===this._zoom)for(var n=this._childClusters.length-1;n>=0;n--)this._childClusters[n]._restorePosition();else for(var r=this._childClusters.length-1;r>=0;r--)this._childClusters[r]._recursivelyRestoreChildPositions(t)},_restorePosition:function(){this._backupLatlng&&(this.setLatLng(this._backupLatlng),delete this._backupLatlng)},_recursivelyRemoveChildrenFromMap:function(t,e,i){var n,r;this._recursively(t,-1,e-1,function(t){for(r=t._markers.length-1;r>=0;r--)n=t._markers[r],i&&i.contains(n._latlng)||(L.FeatureGroup.prototype.removeLayer.call(t._group,n),n.setOpacity&&n.setOpacity(1))},function(t){for(r=t._childClusters.length-1;r>=0;r--)n=t._childClusters[r],i&&i.contains(n._latlng)||((!L.FeatureGroup.prototype.hasLayer||L.FeatureGroup.prototype.hasLayer.call(t._group,n))&&L.FeatureGroup.prototype.removeLayer.call(t._group,n),n.setOpacity&&n.setOpacity(1))})},_recursively:function(t,e,i,n,r){var s,o,a=this._childClusters,l=this._zoom;if(e>l)for(s=a.length-1;s>=0;s--)o=a[s],t.intersects(o._bounds)&&o._recursively(t,e,i,n,r);else if(n&&n(this),r&&this._zoom===i&&r(this),i>l)for(s=a.length-1;s>=0;s--)o=a[s],t.intersects(o._bounds)&&o._recursively(t,e,i,n,r)},_recalculateBounds:function(){var t,e=this._markers,i=this._childClusters;for(this._bounds=new L.LatLngBounds,delete this._wLatLng,t=e.length-1;t>=0;t--)this._expandBounds(e[t]);for(t=i.length-1;t>=0;t--)this._expandBounds(i[t])},_isSingleParent:function(){return this._childClusters.length>0&&this._childClusters[0]._childCount===this._childCount}}),L.DistanceGrid=function(t){this._cellSize=t,this._sqCellSize=t*t,this._grid={},this._objectPoint={}},L.DistanceGrid.prototype={addObject:function(t,e){var i=this._getCoord(e.x),n=this._getCoord(e.y),r=this._grid,s=r[n]=r[n]||{},o=s[i]=s[i]||[],a=L.Util.stamp(t);this._objectPoint[a]=e,o.push(t)},updateObject:function(t,e){this.removeObject(t),this.addObject(t,e)},removeObject:function(t,e){var i,n,r=this._getCoord(e.x),s=this._getCoord(e.y),o=this._grid,a=o[s]=o[s]||{},l=a[r]=a[r]||[];for(delete this._objectPoint[L.Util.stamp(t)],i=0,n=l.length;n>i;i++)if(l[i]===t)return l.splice(i,1),1===n&&delete a[r],!0},eachObject:function(t,e){var i,n,r,s,o,a,l,_=this._grid;for(i in _){o=_[i];for(n in o)for(a=o[n],r=0,s=a.length;s>r;r++)l=t.call(e,a[r]),l&&(r--,s--)}},getNearObject:function(t){var e,i,n,r,s,o,a,l,_=this._getCoord(t.x),h=this._getCoord(t.y),u=this._objectPoint,d=this._sqCellSize,p=null;for(e=h-1;h+1>=e;e++)if(r=this._grid[e])for(i=_-1;_+1>=i;i++)if(s=r[i])for(n=0,o=s.length;o>n;n++)a=s[n],l=this._sqDist(u[L.Util.stamp(a)],t),d>l&&(d=l,p=a);return p},_getCoord:function(t){return Math.floor(t/this._cellSize)},_sqDist:function(t,e){var i=e.x-t.x,n=e.y-t.y;return i*i+n*n}},function(){L.QuickHull={getDistant:function(t,e){var i=e[1].lat-e[0].lat,n=e[0].lng-e[1].lng;return n*(t.lat-e[0].lat)+i*(t.lng-e[0].lng)},findMostDistantPointFromBaseLine:function(t,e){var i,n,r,s=0,o=null,a=[];for(i=e.length-1;i>=0;i--)n=e[i],r=this.getDistant(n,t),r>0&&(a.push(n),r>s&&(s=r,o=n));return{maxPoint:o,newPoints:a}},buildConvexHull:function(t,e){var i=[],n=this.findMostDistantPointFromBaseLine(t,e);return n.maxPoint?(i=i.concat(this.buildConvexHull([t[0],n.maxPoint],n.newPoints)),i=i.concat(this.buildConvexHull([n.maxPoint,t[1]],n.newPoints))):[t]},getConvexHull:function(t){var e,i=!1,n=!1,r=null,s=null;for(e=t.length-1;e>=0;e--){var o=t[e];(i===!1||o.lat>i)&&(r=o,i=o.lat),(n===!1||o.lat=0;i--)e=n[i].getLatLng(),r.push(e);for(t=L.QuickHull.getConvexHull(r),i=t.length-1;i>=0;i--)s.push(t[i][0]);return s}}),L.MarkerCluster.include({_2PI:2*Math.PI,_circleFootSeparation:25,_circleStartAngle:Math.PI/6,_spiralFootSeparation:28,_spiralLengthStart:11,_spiralLengthFactor:5,_circleSpiralSwitchover:9,spiderfy:function(){if(this._group._spiderfied!==this&&!this._group._inZoomAnimation){var t,e=this.getAllChildMarkers(),i=this._group,n=i._map,r=n.latLngToLayerPoint(this._latlng);this._group._unspiderfy(),this._group._spiderfied=this,e.length>=this._circleSpiralSwitchover?t=this._generatePointsSpiral(e.length,r):(r.y+=10,t=this._generatePointsCircle(e.length,r)),this._animationSpiderfy(e,t)}},unspiderfy:function(t){this._group._inZoomAnimation||(this._animationUnspiderfy(t),this._group._spiderfied=null)},_generatePointsCircle:function(t,e){var i,n,r=this._group.options.spiderfyDistanceMultiplier*this._circleFootSeparation*(2+t),s=r/this._2PI,o=this._2PI/t,a=[];for(a.length=t,i=t-1;i>=0;i--)n=this._circleStartAngle+i*o,a[i]=new L.Point(e.x+s*Math.cos(n),e.y+s*Math.sin(n))._round();return a},_generatePointsSpiral:function(t,e){var i,n=this._group.options.spiderfyDistanceMultiplier*this._spiralLengthStart,r=this._group.options.spiderfyDistanceMultiplier*this._spiralFootSeparation,s=this._group.options.spiderfyDistanceMultiplier*this._spiralLengthFactor,o=0,a=[];for(a.length=t,i=t-1;i>=0;i--)o+=r/n+5e-4*i,a[i]=new L.Point(e.x+n*Math.cos(o),e.y+n*Math.sin(o))._round(),n+=this._2PI*s/o;return a},_noanimationUnspiderfy:function(){var t,e,i=this._group,n=i._map,r=this.getAllChildMarkers();for(this.setOpacity(1),e=r.length-1;e>=0;e--)t=r[e],L.FeatureGroup.prototype.removeLayer.call(i,t),t._preSpiderfyLatlng&&(t.setLatLng(t._preSpiderfyLatlng),delete t._preSpiderfyLatlng),t.setZIndexOffset(0),t._spiderLeg&&(n.removeLayer(t._spiderLeg),delete t._spiderLeg)}}),L.MarkerCluster.include(L.DomUtil.TRANSITION?{SVG_ANIMATION:function(){return e.createElementNS("http://www.w3.org/2000/svg","animate").toString().indexOf("SVGAnimate")>-1}(),_animationSpiderfy:function(t,i){var n,r,s,o,a=this,l=this._group,_=l._map,h=_.latLngToLayerPoint(this._latlng);for(n=t.length-1;n>=0;n--)r=t[n],r.setZIndexOffset(1e6),r.setOpacity(0),r._noHas=!0,L.FeatureGroup.prototype.addLayer.call(l,r),delete r._noHas,r._setPos(h);l._forceLayout(),l._animationStart();var u=L.Path.SVG?0:.3,d=L.Path.SVG_NS;for(n=t.length-1;n>=0;n--)if(o=_.layerPointToLatLng(i[n]),r=t[n],r._preSpiderfyLatlng=r._latlng,r.setLatLng(o),r.setOpacity(1),s=new L.Polyline([a._latlng,o],{weight:1.5,color:"#222",opacity:u}),_.addLayer(s),r._spiderLeg=s,L.Path.SVG&&this.SVG_ANIMATION){var p=s._path.getTotalLength();s._path.setAttribute("stroke-dasharray",p+","+p);var c=e.createElementNS(d,"animate");c.setAttribute("attributeName","stroke-dashoffset"),c.setAttribute("begin","indefinite"),c.setAttribute("from",p),c.setAttribute("to",0),c.setAttribute("dur",.25),s._path.appendChild(c),c.beginElement(),c=e.createElementNS(d,"animate"),c.setAttribute("attributeName","stroke-opacity"),c.setAttribute("attributeName","stroke-opacity"),c.setAttribute("begin","indefinite"),c.setAttribute("from",0),c.setAttribute("to",.5),c.setAttribute("dur",.25),s._path.appendChild(c),c.beginElement()}if(a.setOpacity(.3),L.Path.SVG)for(this._group._forceLayout(),n=t.length-1;n>=0;n--)r=t[n]._spiderLeg,r.options.opacity=.5,r._path.setAttribute("stroke-opacity",.5);setTimeout(function(){l._animationEnd(),l.fire("spiderfied")},200)},_animationUnspiderfy:function(t){var e,i,n,r=this._group,s=r._map,o=t?s._latLngToNewLayerPoint(this._latlng,t.zoom,t.center):s.latLngToLayerPoint(this._latlng),a=this.getAllChildMarkers(),l=L.Path.SVG&&this.SVG_ANIMATION;for(r._animationStart(),this.setOpacity(1),i=a.length-1;i>=0;i--)e=a[i],e._preSpiderfyLatlng&&(e.setLatLng(e._preSpiderfyLatlng),delete e._preSpiderfyLatlng,e._setPos(o),e.setOpacity(0),l&&(n=e._spiderLeg._path.childNodes[0],n.setAttribute("to",n.getAttribute("from")),n.setAttribute("from",0),n.beginElement(),n=e._spiderLeg._path.childNodes[1],n.setAttribute("from",.5),n.setAttribute("to",0),n.setAttribute("stroke-opacity",0),n.beginElement(),e._spiderLeg._path.setAttribute("stroke-opacity",0)));setTimeout(function(){var t=0;for(i=a.length-1;i>=0;i--)e=a[i],e._spiderLeg&&t++;for(i=a.length-1;i>=0;i--)e=a[i],e._spiderLeg&&(e.setOpacity(1),e.setZIndexOffset(0),t>1&&L.FeatureGroup.prototype.removeLayer.call(r,e),s.removeLayer(e._spiderLeg),delete e._spiderLeg);r._animationEnd()},200)}}:{_animationSpiderfy:function(t,e){var i,n,r,s,o=this._group,a=o._map;for(i=t.length-1;i>=0;i--)s=a.layerPointToLatLng(e[i]),n=t[i],n._preSpiderfyLatlng=n._latlng,n.setLatLng(s),n.setZIndexOffset(1e6),L.FeatureGroup.prototype.addLayer.call(o,n),r=new L.Polyline([this._latlng,s],{weight:1.5,color:"#222"}),a.addLayer(r),n._spiderLeg=r;this.setOpacity(.3),o.fire("spiderfied")},_animationUnspiderfy:function(){this._noanimationUnspiderfy()}}),L.MarkerClusterGroup.include({_spiderfied:null,_spiderfierOnAdd:function(){this._map.on("click",this._unspiderfyWrapper,this),this._map.options.zoomAnimation?this._map.on("zoomstart",this._unspiderfyZoomStart,this):this._map.on("zoomend",this._unspiderfyWrapper,this),L.Path.SVG&&!L.Browser.touch&&this._map._initPathRoot()},_spiderfierOnRemove:function(){this._map.off("click",this._unspiderfyWrapper,this),this._map.off("zoomstart",this._unspiderfyZoomStart,this),this._map.off("zoomanim",this._unspiderfyZoomAnim,this),this._unspiderfy()},_unspiderfyZoomStart:function(){this._map&&this._map.on("zoomanim",this._unspiderfyZoomAnim,this)},_unspiderfyZoomAnim:function(t){L.DomUtil.hasClass(this._map._mapPane,"leaflet-touching")||(this._map.off("zoomanim",this._unspiderfyZoomAnim,this),this._unspiderfy(t))},_unspiderfyWrapper:function(){this._unspiderfy()},_unspiderfy:function(t){this._spiderfied&&this._spiderfied.unspiderfy(t)},_noanimationUnspiderfy:function(){this._spiderfied&&this._spiderfied._noanimationUnspiderfy()},_unspiderfyLayer:function(t){t._spiderLeg&&(L.FeatureGroup.prototype.removeLayer.call(this,t),t.setOpacity(1),t.setZIndexOffset(0),this._map.removeLayer(t._spiderLeg),delete t._spiderLeg)}})}(window,document); - -/* - Leaflet.label, a plugin that adds labels to markers and vectors for Leaflet powered maps. - (c) 2012-2013, Jacob Toye, Smartrak - - https://github.com/Leaflet/Leaflet.label - http://leafletjs.com - https://github.com/jacobtoye -*/ -(function(){L.labelVersion="0.1.4-dev",L.Label=L.Popup.extend({options:{autoPan:!1,className:"",closePopupOnClick:!1,noHide:!1,offset:new L.Point(12,-15),opacity:1},onAdd:function(t){this._map=t,this._pane=this._source instanceof L.Marker?t._panes.markerPane:t._panes.popupPane,this._container||this._initLayout(),this._updateContent();var e=t.options.fadeAnimation;e&&L.DomUtil.setOpacity(this._container,0),this._pane.appendChild(this._container),t.on("viewreset",this._updatePosition,this),this._animated&&t.on("zoomanim",this._zoomAnimation,this),L.Browser.touch&&!this.options.noHide&&L.DomEvent.on(this._container,"click",this.close,this),this._update(),this.setOpacity(this.options.opacity)},onRemove:function(t){this._pane.removeChild(this._container),L.Util.falseFn(this._container.offsetWidth),t.off({viewreset:this._updatePosition,zoomanim:this._zoomAnimation},this),t.options.fadeAnimation&&L.DomUtil.setOpacity(this._container,0),this._map=null},close:function(){var t=this._map;t&&(L.Browser.touch&&!this.options.noHide&&L.DomEvent.off(this._container,"click",this.close),t._label=null,t.removeLayer(this))},updateZIndex:function(t){this._zIndex=t,this._container&&this._zIndex&&(this._container.style.zIndex=t)},setOpacity:function(t){this.options.opacity=t,this._container&&L.DomUtil.setOpacity(this._container,t)},_initLayout:function(){this._container=L.DomUtil.create("div","leaflet-label "+this.options.className+" leaflet-zoom-animated"),this.updateZIndex(this._zIndex)},_updateContent:function(){this._content&&"string"==typeof this._content&&(this._container.innerHTML=this._content)},_updateLayout:function(){},_updatePosition:function(){var t=this._map.latLngToLayerPoint(this._latlng);this._setPosition(t)},_setPosition:function(t){t=t.add(this.options.offset),L.DomUtil.setPosition(this._container,t)},_zoomAnimation:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);this._setPosition(e)}}),L.Icon.Default.mergeOptions({labelAnchor:new L.Point(9,-20)}),L.Marker.mergeOptions({icon:new L.Icon.Default}),L.Marker.include({showLabel:function(){return this._label&&this._map&&(this._label.setLatLng(this._latlng),this._map.showLabel(this._label)),this},hideLabel:function(){return this._label&&this._label.close(),this},setLabelNoHide:function(t){this._labelNoHide!==t&&(this._labelNoHide=t,t?(this._removeLabelRevealHandlers(),this.showLabel()):(this._addLabelRevealHandlers(),this.hideLabel()))},bindLabel:function(t,e){var i=L.point(this.options.icon.options.labelAnchor)||new L.Point(0,0);return i=i.add(L.Label.prototype.options.offset),e&&e.offset&&(i=i.add(e.offset)),e=L.Util.extend({offset:i},e),this._labelNoHide=e.noHide,this._label||(this._labelNoHide||this._addLabelRevealHandlers(),this.on("remove",this.hideLabel,this).on("move",this._moveLabel,this),this._hasLabelHandlers=!0),this._label=new L.Label(e,this).setContent(t),this},unbindLabel:function(){return this._label&&(this.hideLabel(),this._label=null,this._hasLabelHandlers&&(this._labelNoHide||this._removeLabelRevealHandlers(),this.off("remove",this.hideLabel,this).off("move",this._moveLabel,this)),this._hasLabelHandlers=!1),this},updateLabelContent:function(t){this._label&&this._label.setContent(t)},_addLabelRevealHandlers:function(){this.on("mouseover",this.showLabel,this).on("mouseout",this.hideLabel,this),L.Browser.touch&&this.on("click",this.showLabel,this)},_removeLabelRevealHandlers:function(){this.off("mouseover",this.showLabel,this).off("mouseout",this.hideLabel,this).off("remove",this.hideLabel,this).off("move",this._moveLabel,this),L.Browser.touch&&this.off("click",this.showLabel,this)},_moveLabel:function(t){this._label.setLatLng(t.latlng)},_originalUpdateZIndex:L.Marker.prototype._updateZIndex,_updateZIndex:function(t){var e=this._zIndex+t;this._originalUpdateZIndex(t),this._label&&this._label.updateZIndex(e)},_originalSetOpacity:L.Marker.prototype.setOpacity,setOpacity:function(t,e){this.options.labelHasSemiTransparency=e,this._originalSetOpacity(t)},_originalUpdateOpacity:L.Marker.prototype._updateOpacity,_updateOpacity:function(){var t=0===this.options.opacity?0:1;this._originalUpdateOpacity(),this._label&&this._label.setOpacity(this.options.labelHasSemiTransparency?this.options.opacity:t)}}),L.Path.include({bindLabel:function(t,e){return this._label&&this._label.options===e||(this._label=new L.Label(e,this)),this._label.setContent(t),this._showLabelAdded||(this.on("mouseover",this._showLabel,this).on("mousemove",this._moveLabel,this).on("mouseout remove",this._hideLabel,this),L.Browser.touch&&this.on("click",this._showLabel,this),this._showLabelAdded=!0),this},unbindLabel:function(){return this._label&&(this._hideLabel(),this._label=null,this._showLabelAdded=!1,this.off("mouseover",this._showLabel,this).off("mousemove",this._moveLabel,this).off("mouseout remove",this._hideLabel,this)),this},updateLabelContent:function(t){this._label&&this._label.setContent(t)},_showLabel:function(t){this._label.setLatLng(t.latlng),this._map.showLabel(this._label)},_moveLabel:function(t){this._label.setLatLng(t.latlng)},_hideLabel:function(){this._label.close()}}),L.Map.include({showLabel:function(t){return this._label=t,this.addLayer(t)}}),L.FeatureGroup.include({clearLayers:function(){return this.unbindLabel(),this.eachLayer(this.removeLayer,this),this},bindLabel:function(t,e){return this.invoke("bindLabel",t,e)},unbindLabel:function(){return this.invoke("unbindLabel")},updateLabelContent:function(t){this.invoke("updateLabelContent",t)}})})(this,document); \ No newline at end of file diff --git a/src/app/panels/bettermap/module.css b/src/app/panels/bettermap/module.css deleted file mode 100644 index b0e09690095..00000000000 --- a/src/app/panels/bettermap/module.css +++ /dev/null @@ -1,4 +0,0 @@ -/** custom additions **/ -.leaflet-marker-icon { - color: #333; -} \ No newline at end of file diff --git a/src/app/panels/bettermap/module.html b/src/app/panels/bettermap/module.html deleted file mode 100644 index a006d0d7839..00000000000 --- a/src/app/panels/bettermap/module.html +++ /dev/null @@ -1,6 +0,0 @@ -
- -
-
-
-
\ No newline at end of file diff --git a/src/app/panels/bettermap/module.js b/src/app/panels/bettermap/module.js deleted file mode 100644 index d1cfd14450e..00000000000 --- a/src/app/panels/bettermap/module.js +++ /dev/null @@ -1,268 +0,0 @@ -/** @scratch /panels/5 - * include::panels/bettermap.asciidoc[] - */ - -/** @scratch /panels/bettermap/0 - * == Bettermap - * Status: *Experimental* - * - * Bettermap is called bettermap for lack of a better name. Bettermap uses geographic coordinates to - * create clusters of markers on map and shade them orange, yellow and green depending on the - * density of the cluster. - * - * To drill down, click on a cluster. The map will be zoomed and the cluster broken into smaller cluster. - * When it no longer makes visual sense to cluster, individual markers will be displayed. Hover over - * a marker to see the tooltip value/ - * - * IMPORTANT: bettermap requires an internet connection to download its map panels. - */ -define([ - 'angular', - 'app', - 'underscore', - './leaflet/leaflet-src', - 'require', - - 'css!./module.css', - 'css!./leaflet/leaflet.css', - 'css!./leaflet/plugins.css' -], -function (angular, app, _, L, localRequire) { - 'use strict'; - - var module = angular.module('kibana.panels.bettermap', []); - app.useModule(module); - - module.controller('bettermap', function($scope, querySrv, dashboard, filterSrv) { - $scope.panelMeta = { - editorTabs : [ - { - title: 'Queries', - src: 'app/partials/querySelect.html' - } - ], - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], - status : "Experimental", - description : "Displays geo points in clustered groups on a map. The cavaet for this panel is"+ - " that, for better or worse, it does NOT use the terms facet and it does query "+ - "sequentially. This however means that it transfers more data and is generally heavier to"+ - " compute, while showing less actual data. If you have a time filter, it will attempt to"+ - " show to most recent points in your search, up to your defined limit" - }; - - // Set and populate defaults - var _d = { - /** @scratch /panels/bettermap/3 - * === Parameters - * - * field:: The field that contains the coordinates, in geojson format. GeoJSON is - * +[longitude,latitude]+ in an array. This is different from most implementations, which use - * latitude, longitude. - */ - field : null, - /** @scratch /panels/bettermap/5 - * size:: The number of documents to use when drawing the map - */ - size : 1000, - /** @scratch /panels/bettermap/5 - * spyable:: Should the `inspect` icon be shown? - */ - spyable : true, - /** @scratch /panels/bettermap/5 - * tooltip:: Which field to use for the tooltip when hovering over a marker - */ - tooltip : "_id", - /** @scratch /panels/bettermap/5 - * ==== Queries - * queries object:: This object describes the queries to use on this panel. - * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ - * queries.ids::: In +selected+ mode, which query ids are selected. - */ - queries : { - mode : 'all', - ids : [] - }, - }; - - _.defaults($scope.panel,_d); - - // inorder to use relative paths in require calls, require needs a context to run. Without - // setting this property the paths would be relative to the app not this context/file. - $scope.requireContext = localRequire; - - $scope.init = function() { - $scope.$on('refresh',function(){ - $scope.get_data(); - }); - $scope.get_data(); - }; - - $scope.get_data = function(segment,query_id) { - $scope.require(['./leaflet/plugins'], function () { - $scope.panel.error = false; - - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - - if(_.isUndefined($scope.panel.field)) { - $scope.panel.error = "Please select a field that contains geo point in [lon,lat] format"; - return; - } - - // Determine the field to sort on - var timeField = _.uniq(_.pluck(filterSrv.getByType('time'),'field')); - if(timeField.length > 1) { - $scope.panel.error = "Time field must be consistent amongst time filters"; - } else if(timeField.length === 0) { - timeField = null; - } else { - timeField = timeField[0]; - } - - var _segment = _.isUndefined(segment) ? 0 : segment; - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - var queries = querySrv.getQueryObjs($scope.panel.queries.ids); - - var boolQuery = $scope.ejs.BoolQuery(); - _.each(queries,function(q) { - boolQuery = boolQuery.should(querySrv.toEjsObj(q)); - }); - - var request = $scope.ejs.Request().indices(dashboard.indices[_segment]) - .query($scope.ejs.FilteredQuery( - boolQuery, - filterSrv.getBoolFilter(filterSrv.ids).must($scope.ejs.ExistsFilter($scope.panel.field)) - )) - .fields([$scope.panel.field,$scope.panel.tooltip]) - .size($scope.panel.size); - - if(!_.isNull(timeField)) { - request = request.sort(timeField,'desc'); - } - - $scope.populate_modal(request); - - var results = request.doSearch(); - - // Populate scope when we have results - results.then(function(results) { - $scope.panelMeta.loading = false; - - if(_segment === 0) { - $scope.hits = 0; - $scope.data = []; - query_id = $scope.query_id = new Date().getTime(); - } - - // Check for error and abort if found - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error); - return; - } - - // Check that we're still on the same query, if not stop - if($scope.query_id === query_id) { - - // Keep only what we need for the set - $scope.data = $scope.data.slice(0,$scope.panel.size).concat(_.map(results.hits.hits, function(hit) { - return { - coordinates : new L.LatLng(hit.fields[$scope.panel.field][1],hit.fields[$scope.panel.field][0]), - tooltip : hit.fields[$scope.panel.tooltip] - }; - })); - - } else { - return; - } - - $scope.$emit('draw'); - - // Get $size results then stop querying - if($scope.data.length < $scope.panel.size && _segment+1 < dashboard.indices.length) { - $scope.get_data(_segment+1,$scope.query_id); - } - - }); - }); - }; - - $scope.populate_modal = function(request) { - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - }; - - }); - - module.directive('bettermap', function() { - return { - restrict: 'A', - link: function(scope, elem, attrs) { - - elem.html('
'); - - // Receive render events - scope.$on('draw',function(){ - render_panel(); - }); - - scope.$on('render', function(){ - if(!_.isUndefined(map)) { - map.invalidateSize(); - map.getPanes(); - } - }); - - var map, layerGroup; - - function render_panel() { - scope.require(['./leaflet/plugins'], function () { - scope.panelMeta.loading = false; - L.Icon.Default.imagePath = 'app/panels/bettermap/leaflet/images'; - if(_.isUndefined(map)) { - map = L.map(attrs.id, { - scrollWheelZoom: false, - center: [40, -86], - zoom: 10 - }); - - // This could be made configurable? - L.tileLayer('http://{s}.tile.cloudmade.com/57cbb6ca8cac418dbb1a402586df4528/22677/256/{z}/{x}/{y}.png', { - maxZoom: 18, - minZoom: 2 - }).addTo(map); - layerGroup = new L.MarkerClusterGroup({maxClusterRadius:30}); - } else { - layerGroup.clearLayers(); - } - - var markerList = []; - - _.each(scope.data, function(p) { - if(!_.isUndefined(p.tooltip) && p.tooltip !== '') { - markerList.push(L.marker(p.coordinates).bindLabel(p.tooltip)); - } else { - markerList.push(L.marker(p.coordinates)); - } - }); - - layerGroup.addLayers(markerList); - - layerGroup.addTo(map); - - map.fitBounds(_.pluck(scope.data,'coordinates')); - }); - } - } - }; - }); - -}); diff --git a/src/app/panels/dashcontrol/editor.html b/src/app/panels/dashcontrol/editor.html deleted file mode 100644 index 8faf8151c69..00000000000 --- a/src/app/panels/dashcontrol/editor.html +++ /dev/null @@ -1,44 +0,0 @@ -
-
Allow saving to
-
-
- -
-
- -
-
- -
-
- -
-
-
Allow loading from
-
-
- -
-
- -
-
- -
-
- -
-
-
Sharing
-
-
- -
-
- -
-
- -
-
-
\ No newline at end of file diff --git a/src/app/panels/dashcontrol/load.html b/src/app/panels/dashcontrol/load.html deleted file mode 100644 index 29afae124be..00000000000 --- a/src/app/panels/dashcontrol/load.html +++ /dev/null @@ -1,40 +0,0 @@ -
- × -

Load

-
-
Local File
-
-
-
-
-
-
Gist Enter a gist number or url
-
-
- -
Dashboards in gist:{{gist.url | gistid}} click to load
-
No gist dashboards found
- - - - -
{{file.title}}
-
-
-
-
Elasticsearch
-
- - -
-
Elasticsearch stored dashboards
-
No dashboards matching your query found
- - - - - - -
{{row._id}}
-
-
diff --git a/src/app/panels/dashcontrol/module.html b/src/app/panels/dashcontrol/module.html deleted file mode 100644 index 6ea3aec639c..00000000000 --- a/src/app/panels/dashcontrol/module.html +++ /dev/null @@ -1,6 +0,0 @@ -
- - - - -
\ No newline at end of file diff --git a/src/app/panels/dashcontrol/module.js b/src/app/panels/dashcontrol/module.js deleted file mode 100644 index fb10bbf5c7c..00000000000 --- a/src/app/panels/dashcontrol/module.js +++ /dev/null @@ -1,198 +0,0 @@ -/* - ## Dashcontrol - - ### Parameters - * save - ** gist :: Allow saving to gist. Requires registering an oauth domain with Github - ** elasticsearch :: Allow saving to a special Kibana index within Elasticsearch - ** local :: Allow saving to local file - * load - ** gist :: Allow loading from gists - ** elasticsearch :: Allow searching and loading of elasticsearch saved dashboards - ** local :: Allow loading of dashboards from Elasticsearch - * hide_control :: Upon save, hide this panel - * elasticsearch_size :: show this many dashboards under the ES section in the load drop down - * temp :: Allow saving of temp dashboards - * ttl :: Enable setting ttl. - * temp_ttl :: How long should temp dashboards persist -*/ -define([ - 'angular', - 'app', - 'underscore' -], -function(angular, app, _) { - 'use strict'; - - var module = angular.module('kibana.panels.dashcontrol', []); - app.useModule(module); - - module.controller('dashcontrol', function($scope, $http, timer, dashboard, alertSrv) { - $scope.panelMeta = { - status : "Deprecated", - description : "This panel has been moved to the navigation bar. See the dashboard setting editor to configure it." - }; - - $scope.panel = $scope.panel || {}; - // Set and populate defaults - var _d = { - save : { - gist: false, - elasticsearch: true, - local: true, - 'default': true - }, - load : { - gist: true, - elasticsearch: true, - local: true - }, - hide_control: false, - elasticsearch_size: 20, - temp: true, - ttl_enable: true, - temp_ttl: '30d' - }; - _.defaults($scope.panel,_d); - - $scope.init = function() { - $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; - $scope.gist = {}; - $scope.elasticsearch = {}; - }; - - $scope.set_default = function() { - if(dashboard.set_default()) { - alertSrv.set('Local Default Set',dashboard.current.title+' has been set as your local default','success',5000); - } else { - alertSrv.set('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000); - } - }; - - $scope.purge_default = function() { - if(dashboard.purge_default()) { - alertSrv.set('Local Default Clear','Your local default dashboard has been cleared','success',5000); - } else { - alertSrv.set('Incompatible Browser','Sorry, your browser is too old for this feature','error',5000); - } - }; - - $scope.elasticsearch_save = function(type,ttl) { - dashboard.elasticsearch_save( - type, - ($scope.elasticsearch.title || dashboard.current.title), - ($scope.panel.ttl_enable ? ttl : false) - ).then( - function(result) { - if(!_.isUndefined(result._id)) { - alertSrv.set('Dashboard Saved','This dashboard has been saved to Elasticsearch as "' + - result._id + '"','success',5000); - if(type === 'temp') { - $scope.share = dashboard.share_link(dashboard.current.title,'temp',result._id); - } - } else { - alertSrv.set('Save failed','Dashboard could not be saved to Elasticsearch','error',5000); - } - }); - }; - - $scope.elasticsearch_delete = function(id) { - dashboard.elasticsearch_delete(id).then( - function(result) { - if(!_.isUndefined(result)) { - if(result.found) { - alertSrv.set('Dashboard Deleted',id+' has been deleted','success',5000); - // Find the deleted dashboard in the cached list and remove it - var toDelete = _.where($scope.elasticsearch.dashboards,{_id:id})[0]; - $scope.elasticsearch.dashboards = _.without($scope.elasticsearch.dashboards,toDelete); - } else { - alertSrv.set('Dashboard Not Found','Could not find '+id+' in Elasticsearch','warning',5000); - } - } else { - alertSrv.set('Dashboard Not Deleted','An error occurred deleting the dashboard','error',5000); - } - } - ); - }; - - $scope.elasticsearch_dblist = function(query) { - dashboard.elasticsearch_list(query,$scope.panel.elasticsearch_size).then( - function(result) { - if(!_.isUndefined(result.hits)) { - $scope.panel.error = false; - $scope.hits = result.hits.total; - $scope.elasticsearch.dashboards = result.hits.hits; - } - }); - }; - - $scope.save_gist = function() { - dashboard.save_gist($scope.gist.title).then( - function(link) { - if(!_.isUndefined(link)) { - $scope.gist.last = link; - alertSrv.set('Gist saved','You will be able to access your exported dashboard file at '+ - ''+link+' in a moment','success'); - } else { - alertSrv.set('Save failed','Gist could not be saved','error',5000); - } - }); - }; - - $scope.gist_dblist = function(id) { - dashboard.gist_list(id).then( - function(files) { - if(files && files.length > 0) { - $scope.gist.files = files; - } else { - alertSrv.set('Gist Failed','Could not retrieve dashboard list from gist','error',5000); - } - }); - }; - }); - - module.directive('dashUpload', function(timer, dashboard, alertSrv){ - return { - restrict: 'A', - link: function(scope) { - function file_selected(evt) { - var files = evt.target.files; // FileList object - - // unused.. var output = []; // files is a FileList of File objects. List some properties. - var readerOnload = function() { - return function(e) { - dashboard.dash_load(JSON.parse(e.target.result)); - scope.$apply(); - }; - }; - for (var i = 0, f; f = files[i]; i++) { - var reader = new FileReader(); - reader.onload = (readerOnload)(f); - reader.readAsText(f); - } - } - - // Check for the various File API support. - if (window.File && window.FileReader && window.FileList && window.Blob) { - // Something - document.getElementById('dashupload').addEventListener('change', file_selected, false); - } else { - alertSrv.set('Oops','Sorry, the HTML5 File APIs are not fully supported in this browser.','error'); - } - } - }; - }); - - module.filter('gistid', function() { - var gist_pattern = /(\d{5,})|([a-z0-9]{10,})|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; - return function(input) { - //return input+"boners" - if(!(_.isUndefined(input))) { - var output = input.match(gist_pattern); - if(!_.isNull(output) && !_.isUndefined(output)) { - return output[0].replace(/.*\//, ''); - } - } - }; - }); -}); \ No newline at end of file diff --git a/src/app/panels/dashcontrol/save.html b/src/app/panels/dashcontrol/save.html deleted file mode 100644 index 2879c4a0999..00000000000 --- a/src/app/panels/dashcontrol/save.html +++ /dev/null @@ -1,30 +0,0 @@ -
- × -

Save

- - -
-
Gist
-
- - -

- Last gist: {{gist.last}} -
-
-
Elasticsearch
-
- - -
-
-
\ No newline at end of file diff --git a/src/app/panels/dashcontrol/share.html b/src/app/panels/dashcontrol/share.html deleted file mode 100644 index d542c2c1303..00000000000 --- a/src/app/panels/dashcontrol/share.html +++ /dev/null @@ -1,11 +0,0 @@ - - - \ No newline at end of file diff --git a/src/app/panels/derivequeries/editor.html b/src/app/panels/derivequeries/editor.html deleted file mode 100644 index 281c6866c37..00000000000 --- a/src/app/panels/derivequeries/editor.html +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/src/app/panels/derivequeries/module.html b/src/app/panels/derivequeries/module.html deleted file mode 100644 index 58e96a13b14..00000000000 --- a/src/app/panels/derivequeries/module.html +++ /dev/null @@ -1,3 +0,0 @@ -
-

This panel has been removed and replaced with the new topN query type. Click the colored dot associated with a query to configure the, much improved, equivilent of a derived query.

-
\ No newline at end of file diff --git a/src/app/panels/derivequeries/module.js b/src/app/panels/derivequeries/module.js deleted file mode 100644 index 50c338b3f29..00000000000 --- a/src/app/panels/derivequeries/module.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - ## Derivequeries - - ### Parameters - * label :: The label to stick over the field - * query :: A string to use as a filter for the terms facet - * field :: the field to facet on - * rest :: include a filter that matches all other terms, - * size :: how many queries to generate - * fields :: a list of fields known to us - * query_mode :: how to create query - -*/ -define([ - 'angular', - 'app', - 'underscore' -], -function (angular, app, _) { - 'use strict'; - - var module = angular.module('kibana.panels.derivequeries', []); - app.useModule(module); - - module.controller('derivequeries', function($scope) { - $scope.panelMeta = { - status : "Deprecated", - description : "This panel has been replaced with the 'topN' mode in the query pull down." - }; - - // Set and populate defaults - var _d = { - loading : false, - label : "Search", - query : "*", - ids : [], - field : '_type', - fields : [], - spyable : true, - rest : false, - size : 5, - mode : 'terms only', - exclude : [], - history : [], - remember: 10 // max: 100, angular strap can't take a variable for items param - }; - _.defaults($scope.panel,_d); - - $scope.init = function() { - $scope.editing = false; - }; - }); -}); \ No newline at end of file diff --git a/src/app/panels/fields/editor.html b/src/app/panels/fields/editor.html deleted file mode 100644 index 42ddee0315e..00000000000 --- a/src/app/panels/fields/editor.html +++ /dev/null @@ -1,10 +0,0 @@ -
-
Popup Position
- -
-
List Arrangement
- -
-
Font Size
- -
diff --git a/src/app/panels/fields/micropanel.html b/src/app/panels/fields/micropanel.html deleted file mode 100644 index 767c8fd359d..00000000000 --- a/src/app/panels/fields/micropanel.html +++ /dev/null @@ -1,25 +0,0 @@ -× -

- Micro Analysis of {{micropanel.field}} - - -
{{micropanel.count}} events in the table set -

- - - - - - - - - - - - - -
{{micropanel.field}}ActionIn set
{{{true: "__blank__",false:field[0]}[field[0] == ""]}} - - - {{field[1]}}
-{{field}} ({{Math.round((count / micropanel.count) * 100)}}%), \ No newline at end of file diff --git a/src/app/panels/fields/module.html b/src/app/panels/fields/module.html deleted file mode 100644 index 79b6f4c08ce..00000000000 --- a/src/app/panels/fields/module.html +++ /dev/null @@ -1,3 +0,0 @@ -
-

The 'fields' panel is deprecated.

The table panel now integrates a field selector. -
\ No newline at end of file diff --git a/src/app/panels/fields/module.js b/src/app/panels/fields/module.js deleted file mode 100644 index d2095cc8ac3..00000000000 --- a/src/app/panels/fields/module.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - ## Fields (DEPRECATED) -*/ -define([ - 'angular', - 'app', - 'underscore' -], -function (angular, app, _) { - 'use strict'; - - var module = angular.module('kibana.panels.fields', []); - app.useModule(module); - - module.controller('fields', function($scope) { - - $scope.panelMeta = { - status : "Deprecated", - description : "You should not use this table, it does not work anymore. The table panel now"+ - "integrates a field selector. This module will soon be removed." - }; - - - // Set and populate defaults - var _d = { - style : {}, - arrange : 'vertical', - micropanel_position : 'right', - }; - _.defaults($scope.panel,_d); - - $scope.init = function() { - // Place holder until I remove this - }; - - }); -}); \ No newline at end of file diff --git a/src/app/panels/filtering/editor.html b/src/app/panels/filtering/editor.html deleted file mode 100644 index 3100415c7f2..00000000000 --- a/src/app/panels/filtering/editor.html +++ /dev/null @@ -1,7 +0,0 @@ -
-
-
- No options here -
-
-
\ No newline at end of file diff --git a/src/app/panels/filtering/meta.html b/src/app/panels/filtering/meta.html deleted file mode 100644 index 8af862ff5bf..00000000000 --- a/src/app/panels/filtering/meta.html +++ /dev/null @@ -1,15 +0,0 @@ -
- - × -
Query Alias
-
- -
- -
-
-
\ No newline at end of file diff --git a/src/app/panels/filtering/module.html b/src/app/panels/filtering/module.html deleted file mode 100644 index a0a0a677a94..00000000000 --- a/src/app/panels/filtering/module.html +++ /dev/null @@ -1,90 +0,0 @@ -
- - -
- -
No filters available
-
-
-
- {{filterSrv.list[id].type}} - - {{filterSrv.list[id].mandate}} - - - {{filterSrv.list[id].mandate}} - - - - - - - - - -
- -
-
    -
  • - {{key}} : {{value}} -
  • -
-
-
-
    -
  • - {{key}} : -
  • -
-
- - -
-
-
- -
-
\ No newline at end of file diff --git a/src/app/panels/filtering/module.js b/src/app/panels/filtering/module.js deleted file mode 100644 index aaa2fc9c804..00000000000 --- a/src/app/panels/filtering/module.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - - ## filtering - -*/ -define([ - 'angular', - 'app', - 'underscore' -], -function (angular, app, _) { - 'use strict'; - - var module = angular.module('kibana.panels.filtering', []); - app.useModule(module); - - module.controller('filtering', function($scope, filterSrv, $rootScope, dashboard) { - - $scope.panelMeta = { - status : "Stable", - description : "A controllable list of all filters currently applied to the dashboard. You "+ - "almost certainly want one of these on your dashboard somewhere." - }; - - // Set and populate defaults - var _d = { - }; - _.defaults($scope.panel,_d); - - $scope.$on('filter', function() { - $scope.row.notice = true; - }); - - $scope.init = function() { - $scope.filterSrv = filterSrv; - }; - - $scope.remove = function(id) { - filterSrv.remove(id); - }; - - // This function should be moved to the service - $scope.toggle = function(id) { - filterSrv.list[id].active = !filterSrv.list[id].active; - dashboard.refresh(); - }; - - $scope.add = function(query) { - query = query || '*'; - filterSrv.set({ - editing : true, - type : 'querystring', - query : query, - mandate : 'must' - },undefined,true); - }; - - $scope.refresh = function() { - dashboard.refresh(); - }; - - $scope.render = function() { - $rootScope.$broadcast('render'); - }; - - $scope.show_key = function(key) { - return !_.contains(['type','id','alias','mandate','active','editing'],key); - }; - - $scope.isEditable = function(filter) { - var uneditable = ['time']; - if(_.contains(uneditable,filter.type)) { - return false; - } else { - return true; - } - }; - - }); -}); \ No newline at end of file diff --git a/src/app/panels/graph/editor.html b/src/app/panels/graph/editor.html new file mode 100644 index 00000000000..6e195172926 --- /dev/null +++ b/src/app/panels/graph/editor.html @@ -0,0 +1,11 @@ +
+
+
+ + +
+
+ + + +
\ No newline at end of file diff --git a/src/app/panels/graph/module.html b/src/app/panels/graph/module.html new file mode 100644 index 00000000000..74c795949be --- /dev/null +++ b/src/app/panels/graph/module.html @@ -0,0 +1,9 @@ +
+

{{saySomething}}

+ +
    +
  • {{panel.graphiteUrl}}
  • +
  • {{panel.targets}}
  • +
+ +
\ No newline at end of file diff --git a/src/app/panels/graph/module.js b/src/app/panels/graph/module.js new file mode 100644 index 00000000000..df4beaf17b0 --- /dev/null +++ b/src/app/panels/graph/module.js @@ -0,0 +1,43 @@ +/** @scratch /panels/5 + * include::panels/text.asciidoc[] + */ + +/** @scratch /panels/text/0 + * == text + * Status: *Stable* + * + * The text panel is used for displaying static text formated as markdown, sanitized html or as plain + * text. + * + */ +define([ + 'angular', + 'app', + 'underscore' +], +function (angular, app, _) { + 'use strict'; + + var module = angular.module('kibana.panels.graph', []); + app.useModule(module); + + module.controller('graph', function($scope) { + $scope.panelMeta = { + status : "Unstable", + description : "A graphite graph module" + }; + + // Set and populate defaults + var _d = { + }; + + _.defaults($scope.panel,_d); + + $scope.init = function() { + $scope.ready = false; + $scope.saySomething = "something!"; + }; + + }); + +}); \ No newline at end of file diff --git a/src/app/panels/histogram/editor.html b/src/app/panels/histogram/editor.html deleted file mode 100644 index 15490701bb4..00000000000 --- a/src/app/panels/histogram/editor.html +++ /dev/null @@ -1,48 +0,0 @@ -
-
-
Values
-
- - -
-
- - -
-
-
-
Transform Series
-
- - -
-
- -
-
- -
-
-
-
Time Options
-
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
\ No newline at end of file diff --git a/src/app/panels/histogram/interval.js b/src/app/panels/histogram/interval.js deleted file mode 100644 index 673371fcf4c..00000000000 --- a/src/app/panels/histogram/interval.js +++ /dev/null @@ -1,57 +0,0 @@ -define([ - 'kbn' -], -function (kbn) { - 'use strict'; - - /** - * manages the interval logic - * @param {[type]} interval_string An interval string in the format '1m', '1y', etc - */ - function Interval(interval_string) { - this.string = interval_string; - - var info = kbn.describe_interval(interval_string); - this.type = info.type; - this.ms = info.sec * 1000 * info.count; - - // does the length of the interval change based on the current time? - if (this.type === 'y' || this.type === 'M') { - // we will just modify this time object rather that create a new one constantly - this.get = this.get_complex; - this.date = new Date(0); - } else { - this.get = this.get_simple; - } - } - - Interval.prototype = { - toString: function () { - return this.string; - }, - after: function(current_ms) { - return this.get(current_ms, 1); - }, - before: function (current_ms) { - return this.get(current_ms, -1); - }, - get_complex: function (current, delta) { - this.date.setTime(current); - switch(this.type) { - case 'M': - this.date.setUTCMonth(this.date.getUTCMonth() + delta); - break; - case 'y': - this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); - break; - } - return this.date.getTime(); - }, - get_simple: function (current, delta) { - return current + (delta * this.ms); - } - }; - - return Interval; - -}); \ No newline at end of file diff --git a/src/app/panels/histogram/module.html b/src/app/panels/histogram/module.html deleted file mode 100644 index 20ca4732d93..00000000000 --- a/src/app/panels/histogram/module.html +++ /dev/null @@ -1,99 +0,0 @@ -
- -
- - - View - |  - - - - Zoom Out |  - - - - - {{series.info.alias || series.info.query}} - {{series.info.alias}} - ({{series.hits}}) - - - change in {{panel.value_field}} {{panel.mode}} per {{panel.interval}}1s | ({{hits}} hits) -
-
- -
- -
-
- -
-
- -
-
- -
- -
-
- -
- -
-
- - - -
-
-
-
\ No newline at end of file diff --git a/src/app/panels/histogram/module.js b/src/app/panels/histogram/module.js deleted file mode 100644 index 720ca36fb6f..00000000000 --- a/src/app/panels/histogram/module.js +++ /dev/null @@ -1,764 +0,0 @@ -/** @scratch /panels/5 - * include::panels/histogram.asciidoc[] - */ - -/** @scratch /panels/histogram/0 - * == Histogram - * Status: *Stable* - * - * The histogram panel allow for the display of time charts. It includes several modes and tranformations - * to display event counts, mean, min, max and total of numeric fields, and derivatives of counter - * fields. - * - */ -define([ - 'angular', - 'app', - 'jquery', - 'underscore', - 'kbn', - 'moment', - './timeSeries', - 'jquery.flot', - 'jquery.flot.events', - 'jquery.flot.selection', - 'jquery.flot.time', - 'jquery.flot.byte', - 'jquery.flot.stack', - 'jquery.flot.stackpercent' -], -function (angular, app, $, _, kbn, moment, timeSeries) { - - 'use strict'; - - var module = angular.module('kibana.panels.histogram', []); - app.useModule(module); - - module.controller('histogram', function($scope, querySrv, dashboard, filterSrv) { - $scope.panelMeta = { - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], - editorTabs : [ - { - title:'Style', - src:'app/panels/histogram/styleEditor.html' - }, - { - title:'Queries', - src:'app/panels/histogram/queriesEditor.html' - }, - ], - status : "Stable", - description : "A bucketed time series chart of the current query or queries. Uses the "+ - "Elasticsearch date_histogram facet. If using time stamped indices this panel will query"+ - " them sequentially to attempt to apply the lighest possible load to your Elasticsearch cluster" - }; - - // Set and populate defaults - var _d = { - /** @scratch /panels/histogram/3 - * === Parameters - * ==== Axis options - * mode:: Value to use for the y-axis. For all modes other than count, +value_field+ must be - * defined. Possible values: count, mean, max, min, total. - */ - mode : 'count', - /** @scratch /panels/histogram/3 - * time_field:: x-axis field. This must be defined as a date type in Elasticsearch. - */ - time_field : '@timestamp', - /** @scratch /panels/histogram/3 - * value_field:: y-axis field if +mode+ is set to mean, max, min or total. Must be numeric. - */ - value_field : null, - /** @scratch /panels/histogram/3 - * x-axis:: Show the x-axis - */ - 'x-axis' : true, - /** @scratch /panels/histogram/3 - * y-axis:: Show the y-axis - */ - 'y-axis' : true, - /** @scratch /panels/histogram/3 - * scale:: Scale the y-axis by this factor - */ - scale : 1, - /** @scratch /panels/histogram/3 - * y_format:: 'none','bytes','short ' - */ - y_format : 'none', - /** @scratch /panels/histogram/5 - * grid object:: Min and max y-axis values - * grid.min::: Minimum y-axis value - * grid.max::: Maximum y-axis value - */ - grid : { - max: null, - min: 0 - }, - /** @scratch /panels/histogram/5 - * ==== Queries - * queries object:: This object describes the queries to use on this panel. - * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ - * queries.ids::: In +selected+ mode, which query ids are selected. - */ - queries : { - mode : 'all', - ids : [] - }, - /** @scratch /panels/histogram/3 - * ==== Annotations - * annotate object:: A query can be specified, the results of which will be displayed as markers on - * the chart. For example, for noting code deploys. - * annotate.enable::: Should annotations, aka markers, be shown? - * annotate.query::: Lucene query_string syntax query to use for markers. - * annotate.size::: Max number of markers to show - * annotate.field::: Field from documents to show - * annotate.sort::: Sort array in format [field,order], For example [`@timestamp',`desc'] - */ - annotate : { - enable : false, - query : "*", - size : 20, - field : '_type', - sort : ['_score','desc'] - }, - /** @scratch /panels/histogram/3 - * ==== Interval options - * auto_int:: Automatically scale intervals? - */ - auto_int : true, - /** @scratch /panels/histogram/3 - * resolution:: If auto_int is true, shoot for this many bars. - */ - resolution : 100, - /** @scratch /panels/histogram/3 - * interval:: If auto_int is set to false, use this as the interval. - */ - interval : '5m', - /** @scratch /panels/histogram/3 - * interval:: Array of possible intervals in the *View* selector. Example [`auto',`1s',`5m',`3h'] - */ - intervals : ['auto','1s','1m','5m','10m','30m','1h','3h','12h','1d','1w','1y'], - /** @scratch /panels/histogram/3 - * ==== Drawing options - * lines:: Show line chart - */ - lines : false, - /** @scratch /panels/histogram/3 - * fill:: Area fill factor for line charts, 1-10 - */ - fill : 0, - /** @scratch /panels/histogram/3 - * linewidth:: Weight of lines in pixels - */ - linewidth : 3, - /** @scratch /panels/histogram/3 - * points:: Show points on chart - */ - points : false, - /** @scratch /panels/histogram/3 - * pointradius:: Size of points in pixels - */ - pointradius : 5, - /** @scratch /panels/histogram/3 - * bars:: Show bars on chart - */ - bars : true, - /** @scratch /panels/histogram/3 - * stack:: Stack multiple series - */ - stack : true, - /** @scratch /panels/histogram/3 - * spyable:: Show inspect icon - */ - spyable : true, - /** @scratch /panels/histogram/3 - * zoomlinks:: Show `Zoom Out' link - */ - zoomlinks : true, - /** @scratch /panels/histogram/3 - * options:: Show quick view options section - */ - options : true, - /** @scratch /panels/histogram/3 - * legend:: Display the legond - */ - legend : true, - /** @scratch /panels/histogram/3 - * show_query:: If no alias is set, should the query be displayed? - */ - show_query : true, - /** @scratch /panels/histogram/3 - * interactive:: Enable click-and-drag to zoom functionality - */ - interactive : true, - /** @scratch /panels/histogram/3 - * legend_counts:: Show counts in legend - */ - legend_counts : true, - /** @scratch /panels/histogram/3 - * ==== Transformations - * timezone:: Correct for browser timezone?. Valid values: browser, utc - */ - timezone : 'browser', // browser or utc - /** @scratch /panels/histogram/3 - * percentage:: Show the y-axis as a percentage of the axis total. Only makes sense for multiple - * queries - */ - percentage : false, - /** @scratch /panels/histogram/3 - * zerofill:: Improves the accuracy of line charts at a small performance cost. - */ - zerofill : true, - /** @scratch /panels/histogram/3 - * derivative:: Show each point on the x-axis as the change from the previous point - */ - derivative : false, - /** @scratch /panels/histogram/3 - * tooltip object:: - * tooltip.value_type::: Individual or cumulative controls how tooltips are display on stacked charts - * tooltip.query_as_alias::: If no alias is set, should the query be displayed? - */ - tooltip : { - value_type: 'cumulative', - query_as_alias: true - } - }; - - _.defaults($scope.panel,_d); - _.defaults($scope.panel.tooltip,_d.tooltip); - _.defaults($scope.panel.annotate,_d.annotate); - _.defaults($scope.panel.grid,_d.grid); - - - - $scope.init = function() { - // Hide view options by default - $scope.options = false; - $scope.$on('refresh',function(){ - $scope.get_data(); - }); - - // Always show the query if an alias isn't set. Users can set an alias if the query is too - // long - $scope.panel.tooltip.query_as_alias = true; - - $scope.get_data(); - - }; - - $scope.set_interval = function(interval) { - if(interval !== 'auto') { - $scope.panel.auto_int = false; - $scope.panel.interval = interval; - } else { - $scope.panel.auto_int = true; - } - }; - - $scope.interval_label = function(interval) { - return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; - }; - - /** - * The time range effecting the panel - * @return {[type]} [description] - */ - $scope.get_time_range = function () { - var range = $scope.range = filterSrv.timeRange('last'); - return range; - }; - - $scope.get_interval = function () { - var interval = $scope.panel.interval, - range; - if ($scope.panel.auto_int) { - range = $scope.get_time_range(); - if (range) { - interval = kbn.secondsToHms( - kbn.calculate_interval(range.from, range.to, $scope.panel.resolution, 0) / 1000 - ); - } - } - $scope.panel.interval = interval || '10m'; - return $scope.panel.interval; - }; - - /** - * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies - * need to be consulted (like timestamped logstash indicies) - * - * The results of this function are stored on the scope's data property. This property will be an - * array of objects with the properties info, time_series, and hits. These objects are used in the - * render_panel function to create the historgram. - * - * @param {number} segment The segment count, (0 based) - * @param {number} query_id The id of the query, generated on the first run and passed back when - * this call is made recursively for more segments - */ - $scope.get_data = function(segment, query_id) { - var - _range, - _interval, - request, - queries, - results; - - if (_.isUndefined(segment)) { - segment = 0; - } - delete $scope.panel.error; - - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - _range = $scope.get_time_range(); - _interval = $scope.get_interval(_range); - - if ($scope.panel.auto_int) { - $scope.panel.interval = kbn.secondsToHms( - kbn.calculate_interval(_range.from,_range.to,$scope.panel.resolution,0)/1000); - } - - $scope.panelMeta.loading = true; - request = $scope.ejs.Request().indices(dashboard.indices[segment]); - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - - queries = querySrv.getQueryObjs($scope.panel.queries.ids); - - // Build the query - _.each(queries, function(q) { - var query = $scope.ejs.FilteredQuery( - querySrv.toEjsObj(q), - filterSrv.getBoolFilter(filterSrv.ids) - ); - - var facet = $scope.ejs.DateHistogramFacet(q.id); - - if($scope.panel.mode === 'count') { - facet = facet.field($scope.panel.time_field).global(true); - } else { - if(_.isNull($scope.panel.value_field)) { - $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; - return; - } - facet = facet.keyField($scope.panel.time_field).valueField($scope.panel.value_field).global(true); - } - facet = facet.interval(_interval).facetFilter($scope.ejs.QueryFilter(query)); - request = request.facet(facet) - .size($scope.panel.annotate.enable ? $scope.panel.annotate.size : 0); - }); - - if($scope.panel.annotate.enable) { - var query = $scope.ejs.FilteredQuery( - $scope.ejs.QueryStringQuery($scope.panel.annotate.query || '*'), - filterSrv.getBoolFilter(filterSrv.idsByType('time')) - ); - request = request.query(query); - - // This is a hack proposed by @boaz to work around the fact that we can't get - // to field data values directly, and we need timestamps as normalized longs - request = request.sort([ - $scope.ejs.Sort($scope.panel.annotate.sort[0]).order($scope.panel.annotate.sort[1]), - $scope.ejs.Sort($scope.panel.time_field).desc() - ]); - } - - // Populate the inspector panel - $scope.populate_modal(request); - - // Then run it - results = request.doSearch(); - - // Populate scope when we have results - results.then(function(results) { - - $scope.panelMeta.loading = false; - if(segment === 0) { - $scope.hits = 0; - $scope.data = []; - $scope.annotations = []; - query_id = $scope.query_id = new Date().getTime(); - } - - // Check for error and abort if found - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error); - return; - } - - // Make sure we're still on the same query/queries - if($scope.query_id === query_id) { - - var i = 0, - time_series, - hits; - - _.each(queries, function(q) { - var query_results = results.facets[q.id]; - // we need to initialize the data variable on the first run, - // and when we are working on the first segment of the data. - if(_.isUndefined($scope.data[i]) || segment === 0) { - var tsOpts = { - interval: _interval, - start_date: _range && _range.from, - end_date: _range && _range.to, - fill_style: $scope.panel.derivative ? 'null' : 'minimal' - }; - time_series = new timeSeries.ZeroFilled(tsOpts); - hits = 0; - } else { - time_series = $scope.data[i].time_series; - hits = $scope.data[i].hits; - } - - // push each entry into the time series, while incrementing counters - _.each(query_results.entries, function(entry) { - time_series.addValue(entry.time, entry[$scope.panel.mode]); - hits += entry.count; // The series level hits counter - $scope.hits += entry.count; // Entire dataset level hits counter - }); - $scope.data[i] = { - info: q, - time_series: time_series, - hits: hits - }; - - i++; - }); - - if($scope.panel.annotate.enable) { - $scope.annotations = $scope.annotations.concat(_.map(results.hits.hits, function(hit) { - var _p = _.omit(hit,'_source','sort','_score'); - var _h = _.extend(kbn.flatten_json(hit._source),_p); - return { - min: hit.sort[1], - max: hit.sort[1], - eventType: "annotation", - title: null, - description: " "+ - _h[$scope.panel.annotate.field]+"
"+ - moment(hit.sort[1]).format('YYYY-MM-DD HH:mm:ss'), - score: hit.sort[0] - }; - })); - // Sort the data - $scope.annotations = _.sortBy($scope.annotations, function(v){ - // Sort in reverse - return v.score*($scope.panel.annotate.sort[1] === 'desc' ? -1 : 1); - }); - // And slice to the right size - $scope.annotations = $scope.annotations.slice(0,$scope.panel.annotate.size); - } - - // Tell the histogram directive to render. - $scope.$emit('render'); - - // If we still have segments left, get them - if(segment < dashboard.indices.length-1) { - $scope.get_data(segment+1,query_id); - } - } - }); - }; - - // function $scope.zoom - // factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan - $scope.zoom = function(factor) { - var _range = filterSrv.timeRange('last'); - var _timespan = (_range.to.valueOf() - _range.from.valueOf()); - var _center = _range.to.valueOf() - _timespan/2; - - var _to = (_center + (_timespan*factor)/2); - var _from = (_center - (_timespan*factor)/2); - - // If we're not already looking into the future, don't. - if(_to > Date.now() && _range.to < Date.now()) { - var _offset = _to - Date.now(); - _from = _from - _offset; - _to = Date.now(); - } - - if(factor > 1) { - filterSrv.removeByType('time'); - } - filterSrv.set({ - type:'time', - from:moment.utc(_from).toDate(), - to:moment.utc(_to).toDate(), - field:$scope.panel.time_field - }); - }; - - // I really don't like this function, too much dom manip. Break out into directive? - $scope.populate_modal = function(request) { - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - }; - - $scope.set_refresh = function (state) { - $scope.refresh = state; - }; - - $scope.close_edit = function() { - if($scope.refresh) { - $scope.get_data(); - } - $scope.refresh = false; - $scope.$emit('render'); - }; - - $scope.render = function() { - $scope.$emit('render'); - }; - - }); - - module.directive('histogramChart', function(dashboard, filterSrv) { - return { - restrict: 'A', - template: '
', - link: function(scope, elem) { - - // Receive render events - scope.$on('render',function(){ - render_panel(); - }); - - // Re-render if the window is resized - angular.element(window).bind('resize', function(){ - render_panel(); - }); - - var scale = function(series,factor) { - return _.map(series,function(p) { - return [p[0],p[1]*factor]; - }); - }; - - var scaleSeconds = function(series,interval) { - return _.map(series,function(p) { - return [p[0],p[1]/kbn.interval_to_seconds(interval)]; - }); - }; - - var derivative = function(series) { - return _.map(series, function(p,i) { - var _v; - if(i === 0 || p[1] === null) { - _v = [p[0],null]; - } else { - _v = series[i-1][1] === null ? [p[0],null] : [p[0],p[1]-(series[i-1][1])]; - } - return _v; - }); - }; - - // Function for rendering panel - function render_panel() { - // IE doesn't work without this - elem.css({height:scope.panel.height || scope.row.height}); - - // Populate from the query service - try { - _.each(scope.data, function(series) { - series.label = series.info.alias; - series.color = series.info.color; - }); - } catch(e) {return;} - - // Set barwidth based on specified interval - var barwidth = kbn.interval_to_ms(scope.panel.interval); - - var stack = scope.panel.stack ? true : null; - - // Populate element - try { - var options = { - legend: { show: false }, - series: { - stackpercent: scope.panel.stack ? scope.panel.percentage : false, - stack: scope.panel.percentage ? null : stack, - lines: { - show: scope.panel.lines, - // Silly, but fixes bug in stacked percentages - fill: scope.panel.fill === 0 ? 0.001 : scope.panel.fill/10, - lineWidth: scope.panel.linewidth, - steps: false - }, - bars: { - show: scope.panel.bars, - fill: 1, - barWidth: barwidth/1.5, - zero: false, - lineWidth: 0 - }, - points: { - show: scope.panel.points, - fill: 1, - fillColor: false, - radius: scope.panel.pointradius - }, - shadowSize: 1 - }, - yaxis: { - show: scope.panel['y-axis'], - min: scope.panel.grid.min, - max: scope.panel.percentage && scope.panel.stack ? 100 : scope.panel.grid.max - }, - xaxis: { - timezone: scope.panel.timezone, - show: scope.panel['x-axis'], - mode: "time", - min: _.isUndefined(scope.range.from) ? null : scope.range.from.getTime(), - max: _.isUndefined(scope.range.to) ? null : scope.range.to.getTime(), - timeformat: time_format(scope.panel.interval), - label: "Datetime", - ticks: elem.width()/100 - }, - grid: { - backgroundColor: null, - borderWidth: 0, - hoverable: true, - color: '#c8c8c8' - } - }; - - if(scope.panel.y_format === 'bytes') { - options.yaxis.mode = "byte"; - } - - if(scope.panel.y_format === 'short') { - options.yaxis.tickFormatter = function(val) { - return kbn.shortFormat(val,0); - }; - } - - if(scope.panel.annotate.enable) { - options.events = { - levels: 1, - data: scope.annotations, - types: { - 'annotation': { - level: 1, - icon: { - icon: "icon-tag icon-flip-vertical", - size: 20, - color: "#222", - outline: "#bbb" - } - } - } - //xaxis: int // the x axis to attach events to - }; - } - - if(scope.panel.interactive) { - options.selection = { mode: "x", color: '#666' }; - } - - // when rendering stacked bars, we need to ensure each point that has data is zero-filled - // so that the stacking happens in the proper order - var required_times = []; - if (scope.data.length > 1) { - required_times = Array.prototype.concat.apply([], _.map(scope.data, function (query) { - return query.time_series.getOrderedTimes(); - })); - required_times = _.uniq(required_times.sort(function (a, b) { - // decending numeric sort - return a-b; - }), true); - } - - - for (var i = 0; i < scope.data.length; i++) { - var _d = scope.data[i].time_series.getFlotPairs(required_times); - if(scope.panel.derivative) { - _d = derivative(_d); - } - if(scope.panel.scale !== 1) { - _d = scale(_d,scope.panel.scale); - } - if(scope.panel.scaleSeconds) { - _d = scaleSeconds(_d,scope.panel.interval); - } - scope.data[i].data = _d; - } - - scope.plot = $.plot(elem, scope.data, options); - - } catch(e) { - // Nothing to do here - } - } - - function time_format(interval) { - var _int = kbn.interval_to_seconds(interval); - if(_int >= 2628000) { - return "%Y-%m"; - } - if(_int >= 86400) { - return "%Y-%m-%d"; - } - if(_int >= 60) { - return "%H:%M
%m-%d"; - } - - return "%H:%M:%S"; - } - - var $tooltip = $('
'); - elem.bind("plothover", function (event, pos, item) { - var group, value, timestamp; - if (item) { - if (item.series.info.alias || scope.panel.tooltip.query_as_alias) { - group = '' + - '' + ' ' + - (item.series.info.alias || item.series.info.query)+ - '
'; - } else { - group = kbn.query_color_dot(item.series.color, 15) + ' '; - } - value = (scope.panel.stack && scope.panel.tooltip.value_type === 'individual') ? - item.datapoint[1] - item.datapoint[2] : - item.datapoint[1]; - if(scope.panel.y_format === 'bytes') { - value = kbn.byteFormat(value,2); - } - if(scope.panel.y_format === 'short') { - value = kbn.shortFormat(value,2); - } - timestamp = scope.panel.timezone === 'browser' ? - moment(item.datapoint[0]).format('YYYY-MM-DD HH:mm:ss') : - moment.utc(item.datapoint[0]).format('YYYY-MM-DD HH:mm:ss'); - $tooltip - .html( - group + value + " @ " + timestamp - ) - .place_tt(pos.pageX, pos.pageY); - } else { - $tooltip.detach(); - } - }); - - elem.bind("plotselected", function (event, ranges) { - filterSrv.set({ - type : 'time', - from : moment.utc(ranges.xaxis.from).toDate(), - to : moment.utc(ranges.xaxis.to).toDate(), - field : scope.panel.time_field - }); - }); - } - }; - }); - -}); diff --git a/src/app/panels/histogram/queriesEditor.html b/src/app/panels/histogram/queriesEditor.html deleted file mode 100644 index 414de272ef8..00000000000 --- a/src/app/panels/histogram/queriesEditor.html +++ /dev/null @@ -1,43 +0,0 @@ -

Charted

-
- -
-

Markers

- -
- Here you can specify a query to be plotted on your chart as a marker. Hovering over a marker will display the field you specify below. If more documents are found than the limit you set, they will be scored by Elasticsearch and events that best match your query will be displayed. -
- -

-

- - -
-
- - -
-
- - -
-
- - -
-
- - - -
-
diff --git a/src/app/panels/histogram/styleEditor.html b/src/app/panels/histogram/styleEditor.html deleted file mode 100644 index 874a22640b5..00000000000 --- a/src/app/panels/histogram/styleEditor.html +++ /dev/null @@ -1,88 +0,0 @@ -
-
-
Chart Options
-
- -
-
- -
-
- -
-
- -
-
-
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
Multiple Series
-
- -
-
- - -
-
- - -
-
-
- -
-
-
Header
-
- -
-
- -
-
-
-
Legend
-
- -
-
- -
-
- -
-
- -
-
Grid
-
- - -
-
- - -
-
- -
diff --git a/src/app/panels/histogram/timeSeries.js b/src/app/panels/histogram/timeSeries.js deleted file mode 100644 index 8885e734371..00000000000 --- a/src/app/panels/histogram/timeSeries.js +++ /dev/null @@ -1,216 +0,0 @@ -define([ - 'underscore', - './interval' -], -function (_, Interval) { - 'use strict'; - - var ts = {}; - - // map compatable parseInt - function base10Int(val) { - return parseInt(val, 10); - } - - // trim the ms off of a time, but return it with empty ms. - function getDatesTime(date) { - return Math.floor(date.getTime() / 1000)*1000; - } - - /** - * Certain graphs require 0 entries to be specified for them to render - * properly (like the line graph). So with this we will caluclate all of - * the expected time measurements, and fill the missing ones in with 0 - * @param {object} opts An object specifying some/all of the options - * - * OPTIONS: - * @opt {string} interval The interval notion describing the expected spacing between - * each data point. - * @opt {date} start_date (optional) The start point for the time series, setting this and the - * end_date will ensure that the series streches to resemble the entire - * expected result - * @opt {date} end_date (optional) The end point for the time series, see start_date - * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill - * the series. - */ - ts.ZeroFilled = function (opts) { - opts = _.defaults(opts, { - interval: '10m', - start_date: null, - end_date: null, - fill_style: 'minimal' - }); - - // the expected differenece between readings. - this.interval = new Interval(opts.interval); - - // will keep all values here, keyed by their time - this._data = {}; - this.start_time = opts.start_date && getDatesTime(opts.start_date); - this.end_time = opts.end_date && getDatesTime(opts.end_date); - this.opts = opts; - }; - - /** - * Add a row - * @param {int} time The time for the value, in - * @param {any} value The value at this time - */ - ts.ZeroFilled.prototype.addValue = function (time, value) { - if (time instanceof Date) { - time = getDatesTime(time); - } else { - time = base10Int(time); - } - if (!isNaN(time)) { - this._data[time] = (_.isUndefined(value) ? 0 : value); - } - this._cached_times = null; - }; - - /** - * Get an array of the times that have been explicitly set in the series - * @param {array} include (optional) list of timestamps to include in the response - * @return {array} An array of integer times. - */ - ts.ZeroFilled.prototype.getOrderedTimes = function (include) { - var times = _.map(_.keys(this._data), base10Int); - if (_.isArray(include)) { - times = times.concat(include); - } - return _.uniq(times.sort(function (a, b) { - // decending numeric sort - return a - b; - }), true); - }; - - /** - * return the rows in the format: - * [ [time, value], [time, value], ... ] - * - * Heavy lifting is done by _get(Min|Default|All)FlotPairs() - * @param {array} required_times An array of timestamps that must be in the resulting pairs - * @return {array} - */ - ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { - var times = this.getOrderedTimes(required_times), - strategy, - pairs; - - if(this.opts.fill_style === 'all') { - strategy = this._getAllFlotPairs; - } else if(this.opts.fill_style === 'null') { - strategy = this._getNullFlotPairs; - } else { - strategy = this._getMinFlotPairs; - } - - pairs = _.reduce( - times, // what - strategy, // how - [], // where - this // context - ); - - // if the first or last pair is inside either the start or end time, - // add those times to the series with null values so the graph will stretch to contain them. - // Removing, flot 0.8.1's max/min params satisfy this - /* - if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { - pairs.unshift([this.start_time, null]); - } - if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { - pairs.push([this.end_time, null]); - } - */ - - return pairs; - }; - - /** - * ** called as a reduce stragegy in getFlotPairs() ** - * Fill zero's on either side of the current time, unless there is already a measurement there or - * we are looking at an edge. - * @return {array} An array of points to plot with flot - */ - ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { - var next, expected_next, prev, expected_prev; - - // check for previous measurement - if (i > 0) { - prev = times[i - 1]; - expected_prev = this.interval.before(time); - if (prev < expected_prev) { - result.push([expected_prev, 0]); - } - } - - // add the current time - result.push([ time, this._data[time] || 0]); - - // check for next measurement - if (times.length > i) { - next = times[i + 1]; - expected_next = this.interval.after(time); - if (next > expected_next) { - result.push([expected_next, 0]); - } - } - - return result; - }; - - /** - * ** called as a reduce stragegy in getFlotPairs() ** - * Fill zero's to the right of each time, until the next measurement is reached or we are at the - * last measurement - * @return {array} An array of points to plot with flot - */ - ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { - var next, expected_next; - - result.push([ times[i], this._data[times[i]] || 0 ]); - next = times[i + 1]; - expected_next = this.interval.after(time); - for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { - result.push([expected_next, 0]); - } - - return result; - }; - - /** - * ** called as a reduce stragegy in getFlotPairs() ** - * Same as min, but fills with nulls - * @return {array} An array of points to plot with flot - */ - ts.ZeroFilled.prototype._getNullFlotPairs = function (result, time, i, times) { - var next, expected_next, prev, expected_prev; - - // check for previous measurement - if (i > 0) { - prev = times[i - 1]; - expected_prev = this.interval.before(time); - if (prev < expected_prev) { - result.push([expected_prev, null]); - } - } - - // add the current time - result.push([ time, this._data[time] || null]); - - // check for next measurement - if (times.length > i) { - next = times[i + 1]; - expected_next = this.interval.after(time); - if (next > expected_next) { - result.push([expected_next, null]); - } - } - - return result; - }; - - - return ts; -}); \ No newline at end of file diff --git a/src/app/panels/hits/editor.html b/src/app/panels/hits/editor.html deleted file mode 100644 index 8e113bfaf04..00000000000 --- a/src/app/panels/hits/editor.html +++ /dev/null @@ -1,29 +0,0 @@ -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
- -
-
- -
-
-
diff --git a/src/app/panels/hits/module.html b/src/app/panels/hits/module.html deleted file mode 100644 index 92283dbab8c..00000000000 --- a/src/app/panels/hits/module.html +++ /dev/null @@ -1,44 +0,0 @@ -
-
- - - - - -
{{query.info.alias}}{{query.data[0][1]}}
- - -
- {{query.info.alias}} ({{query.data[0][1]}}) -

- -
- -
- -
- -
- - - - - -
{{query.info.alias}}{{query.data[0][1]}}
- - -
- {{query.info.alias}} ({{query.data[0][1]}}) -

- -
- -
{{hits}}
- - -
- {{query.info.alias}} ({{query.hits}}) -
-

- -
\ No newline at end of file diff --git a/src/app/panels/hits/module.js b/src/app/panels/hits/module.js deleted file mode 100644 index 53e1fba8f6c..00000000000 --- a/src/app/panels/hits/module.js +++ /dev/null @@ -1,295 +0,0 @@ -/** @scratch /panels/5 - * include::panels/hits.asciidoc[] - */ - -/** @scratch /panels/hits/0 - * == Hits - * Status: *Stable* - * - * The hits panel displays the number of hits for each of the queries on the dashboard in a - * configurable format specified by the `chart' property. - * - */ -define([ - 'angular', - 'app', - 'underscore', - 'jquery', - 'kbn', - - 'jquery.flot', - 'jquery.flot.pie' -], function (angular, app, _, $, kbn) { - 'use strict'; - - var module = angular.module('kibana.panels.hits', []); - app.useModule(module); - - module.controller('hits', function($scope, querySrv, dashboard, filterSrv) { - $scope.panelMeta = { - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], - editorTabs : [ - {title:'Queries', src:'app/partials/querySelect.html'} - ], - status : "Stable", - description : "The total hits for a query or set of queries. Can be a pie chart, bar chart, "+ - "list, or absolute total of all queries combined" - }; - - // Set and populate defaults - var _d = { - style : { "font-size": '10pt'}, - /** @scratch /panels/hits/3 - * === Parameters - * - * arrangement:: The arrangement of the legend. horizontal or vertical - */ - arrangement : 'horizontal', - /** @scratch /panels/hits/3 - * chart:: bar, pie or none - */ - chart : 'bar', - /** @scratch /panels/hits/3 - * counter_pos:: The position of the legend, above or below - */ - counter_pos : 'above', - /** @scratch /panels/hits/3 - * donut:: If the chart is set to pie, setting donut to true will draw a hole in the midle of it - */ - donut : false, - /** @scratch /panels/hits/3 - * tilt:: If the chart is set to pie, setting tilt to true will tilt it back into an oval - */ - tilt : false, - /** @scratch /panels/hits/3 - * labels:: If the chart is set to pie, setting labels to true will draw labels in the slices - */ - labels : true, - /** @scratch /panels/hits/3 - * spyable:: Setting spyable to false disables the inspect icon. - */ - spyable : true, - /** @scratch /panels/hits/5 - * ==== Queries - * queries object:: This object describes the queries to use on this panel. - * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ - * queries.ids::: In +selected+ mode, which query ids are selected. - */ - queries : { - mode : 'all', - ids : [] - }, - }; - _.defaults($scope.panel,_d); - - $scope.init = function () { - $scope.hits = 0; - - $scope.$on('refresh',function(){ - $scope.get_data(); - }); - $scope.get_data(); - - }; - - $scope.get_data = function(segment,query_id) { - delete $scope.panel.error; - $scope.panelMeta.loading = true; - - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - - var _segment = _.isUndefined(segment) ? 0 : segment; - var request = $scope.ejs.Request().indices(dashboard.indices[_segment]); - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - var queries = querySrv.getQueryObjs($scope.panel.queries.ids); - - // Build the question part of the query - _.each(queries, function(q) { - var _q = $scope.ejs.FilteredQuery( - querySrv.toEjsObj(q), - filterSrv.getBoolFilter(filterSrv.ids)); - - request = request - .facet($scope.ejs.QueryFacet(q.id) - .query(_q) - ).size(0); - }); - - // Populate the inspector panel - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - - // Then run it - var results = request.doSearch(); - - // Populate scope when we have results - results.then(function(results) { - $scope.panelMeta.loading = false; - if(_segment === 0) { - $scope.hits = 0; - $scope.data = []; - query_id = $scope.query_id = new Date().getTime(); - } - - // Check for error and abort if found - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error); - return; - } - - // Make sure we're still on the same query/queries - if($scope.query_id === query_id) { - var i = 0; - _.each(queries, function(q) { - var v = results.facets[q.id]; - var hits = _.isUndefined($scope.data[i]) || _segment === 0 ? - v.count : $scope.data[i].hits+v.count; - $scope.hits += v.count; - - // Create series - $scope.data[i] = { - info: q, - id: q.id, - hits: hits, - data: [[i,hits]] - }; - - i++; - }); - $scope.$emit('render'); - if(_segment < dashboard.indices.length-1) { - $scope.get_data(_segment+1,query_id); - } - - } - }); - }; - - $scope.set_refresh = function (state) { - $scope.refresh = state; - }; - - $scope.close_edit = function() { - if($scope.refresh) { - $scope.get_data(); - } - $scope.refresh = false; - $scope.$emit('render'); - }; - }); - - - module.directive('hitsChart', function(querySrv) { - return { - restrict: 'A', - link: function(scope, elem) { - - // Receive render events - scope.$on('render',function(){ - render_panel(); - }); - - // Re-render if the window is resized - angular.element(window).bind('resize', function(){ - render_panel(); - }); - - // Function for rendering panel - function render_panel() { - // IE doesn't work without this - elem.css({height:scope.panel.height||scope.row.height}); - - try { - _.each(scope.data,function(series) { - series.label = series.info.alias; - series.color = series.info.color; - }); - } catch(e) {return;} - - // Populate element - try { - // Add plot to scope so we can build out own legend - if(scope.panel.chart === 'bar') { - scope.plot = $.plot(elem, scope.data, { - legend: { show: false }, - series: { - lines: { show: false, }, - bars: { show: true, fill: 1, barWidth: 0.8, horizontal: false }, - shadowSize: 1 - }, - yaxis: { show: true, min: 0, color: "#c8c8c8" }, - xaxis: { show: false }, - grid: { - borderWidth: 0, - borderColor: '#eee', - color: "#eee", - hoverable: true, - }, - colors: querySrv.colors - }); - } - if(scope.panel.chart === 'pie') { - scope.plot = $.plot(elem, scope.data, { - legend: { show: false }, - series: { - pie: { - innerRadius: scope.panel.donut ? 0.4 : 0, - tilt: scope.panel.tilt ? 0.45 : 1, - radius: 1, - show: true, - combine: { - color: '#999', - label: 'The Rest' - }, - stroke: { - width: 0 - }, - label: { - show: scope.panel.labels, - radius: 2/3, - formatter: function(label, series){ - return '
'+ - label+'
'+Math.round(series.percent)+'%
'; - }, - threshold: 0.1 - } - } - }, - //grid: { hoverable: true, clickable: true }, - grid: { hoverable: true, clickable: true }, - colors: querySrv.colors - }); - } - } catch(e) { - elem.text(e); - } - } - - var $tooltip = $('
'); - elem.bind("plothover", function (event, pos, item) { - if (item) { - var value = scope.panel.chart === 'bar' ? - item.datapoint[1] : item.datapoint[1][0][1]; - $tooltip - .html(kbn.query_color_dot(item.series.color, 20) + ' ' + value.toFixed(0)) - .place_tt(pos.pageX, pos.pageY); - } else { - $tooltip.remove(); - } - }); - - } - }; - }); -}); \ No newline at end of file diff --git a/src/app/panels/map/editor.html b/src/app/panels/map/editor.html deleted file mode 100644 index 95f2912e33f..00000000000 --- a/src/app/panels/map/editor.html +++ /dev/null @@ -1,15 +0,0 @@ -
-
-
-
Field 2 letter country or state code
- -
-
-
-
Max Maximum countries to plot
- -
-
Map
- -
-
diff --git a/src/app/panels/map/lib/jquery.jvectormap.min.js b/src/app/panels/map/lib/jquery.jvectormap.min.js deleted file mode 100644 index ea54476f292..00000000000 --- a/src/app/panels/map/lib/jquery.jvectormap.min.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * jVectorMap version 1.2.2 - * - * Copyright 2011-2013, Kirill Lebedev - * Licensed under the MIT license. - * - */(function(e){var t={set:{colors:1,values:1,backgroundColor:1,scaleColors:1,normalizeFunction:1,focus:1},get:{selectedRegions:1,selectedMarkers:1,mapObject:1,regionName:1}};e.fn.vectorMap=function(e){var n,r,i,n=this.children(".jvectormap-container").data("mapObject");if(e==="addMap")jvm.WorldMap.maps[arguments[1]]=arguments[2];else{if(!(e!=="set"&&e!=="get"||!t[e][arguments[1]]))return r=arguments[1].charAt(0).toUpperCase()+arguments[1].substr(1),n[e+r].apply(n,Array.prototype.slice.call(arguments,2));e=e||{},e.container=this,n=new jvm.WorldMap(e)}return this}})(jQuery),function(e){function r(t){var n=t||window.event,r=[].slice.call(arguments,1),i=0,s=!0,o=0,u=0;return t=e.event.fix(n),t.type="mousewheel",n.wheelDelta&&(i=n.wheelDelta/120),n.detail&&(i=-n.detail/3),u=i,n.axis!==undefined&&n.axis===n.HORIZONTAL_AXIS&&(u=0,o=-1*i),n.wheelDeltaY!==undefined&&(u=n.wheelDeltaY/120),n.wheelDeltaX!==undefined&&(o=-1*n.wheelDeltaX/120),r.unshift(t,i,o,u),(e.event.dispatch||e.event.handle).apply(this,r)}var t=["DOMMouseScroll","mousewheel"];if(e.event.fixHooks)for(var n=t.length;n;)e.event.fixHooks[t[--n]]=e.event.mouseHooks;e.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var e=t.length;e;)this.addEventListener(t[--e],r,!1);else this.onmousewheel=r},teardown:function(){if(this.removeEventListener)for(var e=t.length;e;)this.removeEventListener(t[--e],r,!1);else this.onmousewheel=null}},e.fn.extend({mousewheel:function(e){return e?this.bind("mousewheel",e):this.trigger("mousewheel")},unmousewheel:function(e){return this.unbind("mousewheel",e)}})}(jQuery);var jvm={inherits:function(e,t){function n(){}n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e,e.parentClass=t},mixin:function(e,t){var n;for(n in t.prototype)t.prototype.hasOwnProperty(n)&&(e.prototype[n]=t.prototype[n])},min:function(e){var t=Number.MAX_VALUE,n;if(e instanceof Array)for(n=0;nt&&(t=e[n]);else for(n in e)e[n]>t&&(t=e[n]);return t},keys:function(e){var t=[],n;for(n in e)t.push(n);return t},values:function(e){var t=[],n,r;for(r=0;r')}}catch(e){jvm.VMLElement.prototype.createElement=function(e){return document.createElement("<"+e+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}document.createStyleSheet().addRule(".rvml","behavior:url(#default#VML)"),jvm.VMLElement.VMLInitialized=!0},jvm.VMLElement.prototype.getElementCtr=function(e){return jvm["VML"+e]},jvm.VMLElement.prototype.addClass=function(e){jvm.$(this.node).addClass(e)},jvm.VMLElement.prototype.applyAttr=function(e,t){this.node[e]=t},jvm.VMLElement.prototype.getBBox=function(){var e=jvm.$(this.node);return{x:e.position().left/this.canvas.scale,y:e.position().top/this.canvas.scale,width:e.width()/this.canvas.scale,height:e.height()/this.canvas.scale}},jvm.VMLGroupElement=function(){jvm.VMLGroupElement.parentClass.call(this,"group"),this.node.style.left="0px",this.node.style.top="0px",this.node.coordorigin="0 0"},jvm.inherits(jvm.VMLGroupElement,jvm.VMLElement),jvm.VMLGroupElement.prototype.add=function(e){this.node.appendChild(e.node)},jvm.VMLCanvasElement=function(e,t,n){this.classPrefix="VML",jvm.VMLCanvasElement.parentClass.call(this,"group"),jvm.AbstractCanvasElement.apply(this,arguments),this.node.style.position="absolute"},jvm.inherits(jvm.VMLCanvasElement,jvm.VMLElement),jvm.mixin(jvm.VMLCanvasElement,jvm.AbstractCanvasElement),jvm.VMLCanvasElement.prototype.setSize=function(e,t){var n,r,i,s;this.width=e,this.height=t,this.node.style.width=e+"px",this.node.style.height=t+"px",this.node.coordsize=e+" "+t,this.node.coordorigin="0 0";if(this.rootElement){n=this.rootElement.node.getElementsByTagName("shape");for(i=0,s=n.length;i=0)e-=t[i],i++;return i==this.scale.length-1?e=this.vectorToNum(this.scale[i]):e=this.vectorToNum(this.vectorAdd(this.scale[i],this.vectorMult(this.vectorSubtract(this.scale[i+1],this.scale[i]),e/t[i]))),e},vectorToNum:function(e){var t=0,n;for(n=0;nt&&(t=e[i]),r0?1:e<0?-1:e},mill:function(e,t,n){return{x:this.radius*(t-n)*this.radDeg,y:-this.radius*Math.log(Math.tan((45+.4*e)*this.radDeg))/.8}},mill_inv:function(e,t,n){return{lat:(2.5*Math.atan(Math.exp(.8*t/this.radius))-5*Math.PI/8)*this.degRad,lng:(n*this.radDeg+e/this.radius)*this.degRad}},merc:function(e,t,n){return{x:this.radius*(t-n)*this.radDeg,y:-this.radius*Math.log(Math.tan(Math.PI/4+e*Math.PI/360))}},merc_inv:function(e,t,n){return{lat:(2*Math.atan(Math.exp(t/this.radius))-Math.PI/2)*this.degRad,lng:(n*this.radDeg+e/this.radius)*this.degRad}},aea:function(e,t,n){var r=0,i=n*this.radDeg,s=29.5*this.radDeg,o=45.5*this.radDeg,u=e*this.radDeg,a=t*this.radDeg,f=(Math.sin(s)+Math.sin(o))/2,l=Math.cos(s)*Math.cos(s)+2*f*Math.sin(s),c=f*(a-i),h=Math.sqrt(l-2*f*Math.sin(u))/f,p=Math.sqrt(l-2*f*Math.sin(r))/f;return{x:h*Math.sin(c)*this.radius,y:-(p-h*Math.cos(c))*this.radius}},aea_inv:function(e,t,n){var r=e/this.radius,i=t/this.radius,s=0,o=n*this.radDeg,u=29.5*this.radDeg,a=45.5*this.radDeg,f=(Math.sin(u)+Math.sin(a))/2,l=Math.cos(u)*Math.cos(u)+2*f*Math.sin(u),c=Math.sqrt(l-2*f*Math.sin(s))/f,h=Math.sqrt(r*r+(c-i)*(c-i)),p=Math.atan(r/(c-i));return{lat:Math.asin((l-h*h*f*f)/(2*f))*this.degRad,lng:(o+p/f)*this.degRad}},lcc:function(e,t,n){var r=0,i=n*this.radDeg,s=t*this.radDeg,o=33*this.radDeg,u=45*this.radDeg,a=e*this.radDeg,f=Math.log(Math.cos(o)*(1/Math.cos(u)))/Math.log(Math.tan(Math.PI/4+u/2)*(1/Math.tan(Math.PI/4+o/2))),l=Math.cos(o)*Math.pow(Math.tan(Math.PI/4+o/2),f)/f,c=l*Math.pow(1/Math.tan(Math.PI/4+a/2),f),h=l*Math.pow(1/Math.tan(Math.PI/4+r/2),f);return{x:c*Math.sin(f*(s-i))*this.radius,y:-(h-c*Math.cos(f*(s-i)))*this.radius}},lcc_inv:function(e,t,n){var r=e/this.radius,i=t/this.radius,s=0,o=n*this.radDeg,u=33*this.radDeg,a=45*this.radDeg,f=Math.log(Math.cos(u)*(1/Math.cos(a)))/Math.log(Math.tan(Math.PI/4+a/2)*(1/Math.tan(Math.PI/4+u/2))),l=Math.cos(u)*Math.pow(Math.tan(Math.PI/4+u/2),f)/f,c=l*Math.pow(1/Math.tan(Math.PI/4+s/2),f),h=this.sgn(f)*Math.sqrt(r*r+(c-i)*(c-i)),p=Math.atan(r/(c-i));return{lat:(2*Math.atan(Math.pow(l/h,1/f))-Math.PI/2)*this.degRad,lng:(o+p/f)*this.degRad}}},jvm.WorldMap=function(e){var t=this,n;this.params=jvm.$.extend(!0,{},jvm.WorldMap.defaultParams,e);if(!jvm.WorldMap.maps[this.params.map])throw new Error("Attempt to use map which was not loaded: "+this.params.map);this.mapData=jvm.WorldMap.maps[this.params.map],this.markers={},this.regions={},this.regionsColors={},this.regionsData={},this.container=jvm.$("
").css({width:"100%",height:"100%"}).addClass("jvectormap-container"),this.params.container.append(this.container),this.container.data("mapObject",this),this.container.css({position:"relative",overflow:"hidden"}),this.defaultWidth=this.mapData.width,this.defaultHeight=this.mapData.height,this.setBackgroundColor(this.params.backgroundColor),this.onResize=function(){t.setSize()},jvm.$(window).resize(this.onResize);for(n in jvm.WorldMap.apiEvents)this.params[n]&&this.container.bind(jvm.WorldMap.apiEvents[n]+".jvectormap",this.params[n]);this.canvas=new jvm.VectorCanvas(this.container[0],this.width,this.height),"ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch?this.params.bindTouchEvents&&this.bindContainerTouchEvents():this.bindContainerEvents(),this.bindElementEvents(),this.createLabel(),this.params.zoomButtons&&this.bindZoomButtons(),this.createRegions(),this.createMarkers(this.params.markers||{}),this.setSize(),this.params.focusOn&&(typeof this.params.focusOn=="object"?this.setFocus.call(this,this.params.focusOn.scale,this.params.focusOn.x,this.params.focusOn.y):this.setFocus.call(this,this.params.focusOn)),this.params.selectedRegions&&this.setSelectedRegions(this.params.selectedRegions),this.params.selectedMarkers&&this.setSelectedMarkers(this.params.selectedMarkers),this.params.series&&this.createSeries()},jvm.WorldMap.prototype={transX:0,transY:0,scale:1,baseTransX:0,baseTransY:0,baseScale:1,width:0,height:0,setBackgroundColor:function(e){this.container.css("background-color",e)},resize:function(){var e=this.baseScale;this.width/this.height>this.defaultWidth/this.defaultHeight?(this.baseScale=this.height/this.defaultHeight,this.baseTransX=Math.abs(this.width-this.defaultWidth*this.baseScale)/(2*this.baseScale)):(this.baseScale=this.width/this.defaultWidth,this.baseTransY=Math.abs(this.height-this.defaultHeight*this.baseScale)/(2*this.baseScale)),this.scale*=this.baseScale/e,this.transX*=this.baseScale/e,this.transY*=this.baseScale/e},setSize:function(){this.width=this.container.width(),this.height=this.container.height(),this.resize(),this.canvas.setSize(this.width,this.height),this.applyTransform()},reset:function(){var e,t;for(e in this.series)for(t=0;tt?this.transY=t:this.transYe?this.transX=e:this.transXf[1].pageX?s=f[1].pageX+(f[0].pageX-f[1].pageX)/2:s=f[0].pageX+(f[1].pageX-f[0].pageX)/2,f[0].pageY>f[1].pageY?o=f[1].pageY+(f[0].pageY-f[1].pageY)/2:o=f[0].pageY+(f[1].pageY-f[0].pageY)/2,s-=l.left,o-=l.top,e=n.scale,t=Math.sqrt(Math.pow(f[0].pageX-f[1].pageX,2)+Math.pow(f[0].pageY-f[1].pageY,2)))),u=f.length};jvm.$(this.container).bind("touchstart",a),jvm.$(this.container).bind("touchmove",a)},bindElementEvents:function(){var e=this,t;this.container.mousemove(function(){t=!0}),this.container.delegate("[class~='jvectormap-element']","mouseover mouseout",function(t){var n=this,r=jvm.$(this).attr("class").baseVal?jvm.$(this).attr("class").baseVal:jvm.$(this).attr("class"),i=r.indexOf("jvectormap-region")===-1?"marker":"region",s=i=="region"?jvm.$(this).attr("data-code"):jvm.$(this).attr("data-index"),o=i=="region"?e.regions[s].element:e.markers[s].element,u=i=="region"?e.mapData.paths[s].name:e.markers[s].config.name||"",a=jvm.$.Event(i+"LabelShow.jvectormap"),f=jvm.$.Event(i+"Over.jvectormap");t.type=="mouseover"?(e.container.trigger(f,[s]),f.isDefaultPrevented()||o.setHovered(!0),e.label.text(u),e.container.trigger(a,[e.label,s]),a.isDefaultPrevented()||(e.label.show(),e.labelWidth=e.label.width(),e.labelHeight=e.label.height())):(o.setHovered(!1),e.label.hide(),e.container.trigger(i+"Out.jvectormap",[s]))}),this.container.delegate("[class~='jvectormap-element']","mousedown",function(e){t=!1}),this.container.delegate("[class~='jvectormap-element']","mouseup",function(n){var r=this,i=jvm.$(this).attr("class").baseVal?jvm.$(this).attr("class").baseVal:jvm.$(this).attr("class"),s=i.indexOf("jvectormap-region")===-1?"marker":"region",o=s=="region"?jvm.$(this).attr("data-code"):jvm.$(this).attr("data-index"),u=jvm.$.Event(s+"Click.jvectormap"),a=s=="region"?e.regions[o].element:e.markers[o].element;if(!t){e.container.trigger(u,[o]);if(s==="region"&&e.params.regionsSelectable||s==="marker"&&e.params.markersSelectable)u.isDefaultPrevented()||(e.params[s+"sSelectableOne"]&&e.clearSelected(s+"s"),a.setSelected(!a.isSelected))}})},bindZoomButtons:function(){var e=this;jvm.$("
").addClass("jvectormap-zoomin").text("+").appendTo(this.container),jvm.$("
").addClass("jvectormap-zoomout").html("−").appendTo(this.container),this.container.find(".jvectormap-zoomin").click(function(){e.setScale(e.scale*e.params.zoomStep,e.width/2,e.height/2)}),this.container.find(".jvectormap-zoomout").click(function(){e.setScale(e.scale/e.params.zoomStep,e.width/2,e.height/2)})},createLabel:function(){var e=this;this.label=jvm.$("
").addClass("jvectormap-label").appendTo(jvm.$("body")),this.container.mousemove(function(t){var n=t.pageX-15-e.labelWidth,r=t.pageY-15-e.labelHeight;n<5&&(n=t.pageX+15),r<5&&(r=t.pageY+15),e.label.is(":visible")&&e.label.css({left:n,top:r})})},setScale:function(e,t,n,r){var i,s=jvm.$.Event("zoom.jvectormap");e>this.params.zoomMax*this.baseScale?e=this.params.zoomMax*this.baseScale:eu[0].x&&au[0].y&&fi[0].x&&ei[0].y&&t - -
-
\ No newline at end of file diff --git a/src/app/panels/map/module.js b/src/app/panels/map/module.js deleted file mode 100644 index 4bd58e5e83f..00000000000 --- a/src/app/panels/map/module.js +++ /dev/null @@ -1,206 +0,0 @@ -/** @scratch /panels/5 - * include::panels/map.asciidoc[] - */ - -/** @scratch /panels/map/0 - * == Map - * Status: *Stable* - * - * The map panel translates 2 letter country or state codes into shaded regions on a map. Currently - * available maps are world, usa and europe. - * - */ -define([ - 'angular', - 'app', - 'underscore', - 'jquery', - 'config', - './lib/jquery.jvectormap.min' -], -function (angular, app, _, $) { - 'use strict'; - - var module = angular.module('kibana.panels.map', []); - app.useModule(module); - - module.controller('map', function($scope, $rootScope, querySrv, dashboard, filterSrv) { - $scope.panelMeta = { - editorTabs : [ - {title:'Queries', src:'app/partials/querySelect.html'} - ], - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], - status : "Stable", - description : "Displays a map of shaded regions using a field containing a 2 letter country "+ - ", or US state, code. Regions with more hit are shaded darker. Node that this does use the"+ - " Elasticsearch terms facet, so it is important that you set it to the correct field." - }; - - // Set and populate defaults - var _d = { - /** @scratch /panels/map/3 - * === Parameters - * - * map:: Map to display. world, usa, europe - */ - map : "world", - /** @scratch /panels/map/3 - * colors:: An array of colors to use to shade the map. If 2 colors are specified, shades - * between them will be used. For example [`#A0E2E2', `#265656'] - */ - colors : ['#A0E2E2', '#265656'], - /** @scratch /panels/map/3 - * size:: Max number of regions to shade - */ - size : 100, - /** @scratch /panels/map/3 - * exclude:: exclude this array of regions. For example [`US',`BR',`IN'] - */ - exclude : [], - /** @scratch /panels/map/3 - * spyable:: Setting spyable to false disables the inspect icon. - */ - spyable : true, - /** @scratch /panels/map/5 - * ==== Queries - * queries object:: This object describes the queries to use on this panel. - * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ - * queries.ids::: In +selected+ mode, which query ids are selected. - */ - queries : { - mode : 'all', - ids : [] - } - }; - _.defaults($scope.panel,_d); - - $scope.init = function() { - $scope.$on('refresh',function(){$scope.get_data();}); - $scope.get_data(); - }; - - $scope.get_data = function() { - - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - $scope.panelMeta.loading = true; - - - var request, - boolQuery, - queries; - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - request = $scope.ejs.Request().indices(dashboard.indices); - queries = querySrv.getQueryObjs($scope.panel.queries.ids); - - boolQuery = $scope.ejs.BoolQuery(); - _.each(queries,function(q) { - boolQuery = boolQuery.should(querySrv.toEjsObj(q)); - }); - - // Then the insert into facet and make the request - request = request - .facet($scope.ejs.TermsFacet('map') - .field($scope.panel.field) - .size($scope.panel.size) - .exclude($scope.panel.exclude) - .facetFilter($scope.ejs.QueryFilter( - $scope.ejs.FilteredQuery( - boolQuery, - filterSrv.getBoolFilter(filterSrv.ids) - )))).size(0); - - $scope.populate_modal(request); - - var results = request.doSearch(); - - // Populate scope when we have results - results.then(function(results) { - $scope.panelMeta.loading = false; - $scope.hits = results.hits.total; - $scope.data = {}; - _.each(results.facets.map.terms, function(v) { - $scope.data[v.term.toUpperCase()] = v.count; - }); - $scope.$emit('render'); - }); - }; - - // I really don't like this function, too much dom manip. Break out into directive? - $scope.populate_modal = function(request) { - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - }; - - $scope.build_search = function(field,value) { - filterSrv.set({type:'querystring',mandate:'must',query:field+":"+value}); - }; - - }); - - - module.directive('map', function() { - return { - restrict: 'A', - link: function(scope, elem) { - - elem.html('
'); - - // Receive render events - scope.$on('render',function(){ - render_panel(); - }); - - // Or if the window is resized - angular.element(window).bind('resize', function(){ - render_panel(); - }); - - function render_panel() { - elem.text(''); - $('.jvectormap-zoomin,.jvectormap-zoomout,.jvectormap-label').remove(); - require(['./panels/map/lib/map.'+scope.panel.map], function () { - elem.vectorMap({ - map: scope.panel.map, - regionStyle: {initial: {fill: '#8c8c8c'}}, - zoomOnScroll: false, - backgroundColor: null, - series: { - regions: [{ - values: scope.data, - scale: scope.panel.colors, - normalizeFunction: 'polynomial' - }] - }, - onRegionLabelShow: function(event, label, code){ - elem.children('.map-legend').show(); - var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code]; - elem.children('.map-legend').text(label.text() + ": " + count); - }, - onRegionOut: function() { - $('.map-legend').hide(); - }, - onRegionClick: function(event, code) { - var count = _.isUndefined(scope.data[code]) ? 0 : scope.data[code]; - if (count !== 0) { - scope.build_search(scope.panel.field,code); - } - } - }); - elem.prepend(''); - $('.map-legend').hide(); - }); - } - } - }; - }); -}); \ No newline at end of file diff --git a/src/app/panels/pie/editor.html b/src/app/panels/pie/editor.html deleted file mode 100644 index f1de354d177..00000000000 --- a/src/app/panels/pie/editor.html +++ /dev/null @@ -1,49 +0,0 @@ -
-
-
- - -
-
-
-
-
- - -
-
- - -
-
- - -
-
-
-
-
-
-
- - -
-
-
-
-
-
-
- -
-
- -
-
- -
-
- - -
-
\ No newline at end of file diff --git a/src/app/panels/pie/module.html b/src/app/panels/pie/module.html deleted file mode 100644 index 3ae47964c25..00000000000 --- a/src/app/panels/pie/module.html +++ /dev/null @@ -1,15 +0,0 @@ -
- -
- {{query.label}} ({{query.data[0][1]}}) -

-
- -
- -
- {{query.label}} ({{query.data[0][1]}}) -
-
\ No newline at end of file diff --git a/src/app/panels/pie/module.js b/src/app/panels/pie/module.js deleted file mode 100644 index d70009f1c49..00000000000 --- a/src/app/panels/pie/module.js +++ /dev/null @@ -1,334 +0,0 @@ -/** @scratch /panels/5 - * include::panels/pie.asciidoc[] - */ - -/** @scratch /panels/pie/0 - * == Pie - * Status: *Deprecated* - * - * The pie panel has been largely replaced by the +terms+ panel. It exists for backwards compatibility - * for now, but will be removed in a future release - * - */ -define([ - 'angular', - 'app', - 'underscore', - 'jquery', - 'kbn', - 'config' -], function (angular, app, _, $, kbn) { - 'use strict'; - - var module = angular.module('kibana.panels.pie', []); - app.useModule(module); - - module.controller('pie', function($scope, $rootScope, querySrv, dashboard, filterSrv) { - - $scope.panelMeta = { - editorTabs : [ - {title:'Queries', src:'app/partials/querySelect.html'} - ], - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], - status : "Deprecated", - description : "Uses an Elasticsearch terms facet to create a pie chart. You should really only"+ - " point this at not_analyzed fields for that reason. This panel is going away soon, it has"+ - " been replaced by the terms panel. Please use that one instead." - }; - - // Set and populate defaults - var _d = { - /** @scratch /panels/pie/3 - * === Parameters - * - * mode:: terms or goal. Terms mode finds the top N most popular terms, Goal mode display - * progress towards a fix goal in terms of documents matched - */ - mode : "terms", - /** @scratch /panels/pie/3 - * size:: The max number of results to display in +terms+ mode. - */ - size : 10, - /** @scratch /panels/pie/3 - * exclude:: Exclude these terms in terms mode - */ - exclude : [], - /** @scratch /panels/pie/3 - * donut:: Draw a hole in the middle of the pie, creating a tasty donut. - */ - donut : false, - /** @scratch /panels/pie/3 - * tilt:: Tilt the pie back into an oval shape - */ - tilt : false, - /** @scratch /panels/pie/3 - * legend:: The location of the legend, above, below or none - */ - legend : "above", - /** @scratch /panels/pie/3 - * labels:: Set to false to disable drawing labels inside the pie slices - */ - labels : true, - /** @scratch /panels/pie/3 - * spyable:: Set to false to disable the inspect function. - */ - spyable : true, - /** @scratch /panels/pie/3 - * ==== Query - * - * query object:: This confusingly named object has properties to set the terms mode field, - * and the fixed goal for the goal mode - * query.field::: the field to facet on in terms mode - * query.goal::: the fixed goal for goal mode - */ - query : { field:"_type", goal: 100}, - /** @scratch /panels/pie/5 - * ==== Queries - * - * queries object:: This object describes the queries to use on this panel. - * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ - * queries.ids::: In +selected+ mode, which query ids are selected. - */ - queries : { - mode : 'all', - ids : [] - }, - default_field : '_type', - - }; - _.defaults($scope.panel,_d); - - $scope.init = function() { - $scope.$on('refresh',function(){$scope.get_data();}); - $scope.get_data(); - }; - - $scope.set_mode = function(mode) { - switch(mode) - { - case 'terms': - $scope.panel.query = {field:"_all"}; - break; - case 'goal': - $scope.panel.query = {goal:100}; - break; - } - }; - - $scope.set_refresh = function (state) { - $scope.refresh = state; - }; - - $scope.close_edit = function() { - if($scope.refresh) { - $scope.get_data(); - } - $scope.refresh = false; - $scope.$emit('render'); - }; - - $scope.get_data = function() { - - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - - - $scope.panelMeta.loading = true; - var request = $scope.ejs.Request().indices(dashboard.indices); - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - var queries = querySrv.getQueryObjs($scope.panel.queries.ids); - - // This could probably be changed to a BoolFilter - var boolQuery = $scope.ejs.BoolQuery(); - _.each(queries,function(q) { - boolQuery = boolQuery.should(querySrv.toEjsObj(q)); - }); - - var results; - - // Terms mode - if ($scope.panel.mode === "terms") { - request = request - .facet($scope.ejs.TermsFacet('pie') - .field($scope.panel.query.field || $scope.panel.default_field) - .size($scope.panel.size) - .exclude($scope.panel.exclude) - .facetFilter($scope.ejs.QueryFilter( - $scope.ejs.FilteredQuery( - boolQuery, - filterSrv.getBoolFilter(filterSrv.ids) - )))).size(0); - - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - - results = request.doSearch(); - - // Populate scope when we have results - results.then(function(results) { - $scope.panelMeta.loading = false; - $scope.hits = results.hits.total; - $scope.data = []; - var k = 0; - _.each(results.facets.pie.terms, function(v) { - var slice = { label : v.term, data : v.count }; - $scope.data.push(); - $scope.data.push(slice); - k = k + 1; - }); - $scope.$emit('render'); - }); - // Goal mode - } else { - request = request - .query(boolQuery) - .filter(filterSrv.getBoolFilter(filterSrv.ids)) - .size(0); - - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - - results = request.doSearch(); - - results.then(function(results) { - $scope.panelMeta.loading = false; - var complete = results.hits.total; - var remaining = $scope.panel.query.goal - complete; - $scope.data = [ - { label : 'Complete', data : complete, color: '#BF6730' }, - { data : remaining, color: '#e2d0c4' } - ]; - $scope.$emit('render'); - }); - } - }; - - }); - - module.directive('pie', function(querySrv, filterSrv) { - return { - restrict: 'A', - link: function(scope, elem) { - - elem.html('
'); - - // Receive render events - scope.$on('render',function(){ - render_panel(); - }); - - // Or if the window is resized - angular.element(window).bind('resize', function(){ - render_panel(); - }); - - // Function for rendering panel - function render_panel() { - // IE doesn't work without this - elem.css({height:scope.panel.height||scope.row.height}); - - var label; - - if(scope.panel.mode === 'goal') { - label = { - show: scope.panel.labels, - radius: 0, - formatter: function(label, series){ - var font = parseInt(scope.row.height.replace('px',''),10)/8 + String('px'); - if(!(_.isUndefined(label))) { - return '
'+ - Math.round(series.percent)+'%
'; - } else { - return ''; - } - }, - }; - } else { - label = { - show: scope.panel.labels, - radius: 2/3, - formatter: function(label, series){ - return '
'+ - label+'
'+Math.round(series.percent)+'%
'; - }, - threshold: 0.1 - }; - } - - var pie = { - series: { - pie: { - innerRadius: scope.panel.donut ? 0.45 : 0, - tilt: scope.panel.tilt ? 0.45 : 1, - radius: 1, - show: true, - combine: { - color: '#999', - label: 'The Rest' - }, - label: label, - stroke: { - width: 0 - } - } - }, - //grid: { hoverable: true, clickable: true }, - grid: { - backgroundColor: null, - hoverable: true, - clickable: true - }, - legend: { show: false }, - colors: querySrv.colors - }; - - // Populate legend - if(elem.is(":visible")){ - require(['jquery.flot.pie'], function(){ - scope.legend = $.plot(elem, scope.data, pie).getData(); - if(!scope.$$phase) { - scope.$apply(); - } - }); - } - - } - - elem.bind('plotclick', function (event, pos, object) { - if (!object) { - return; - } - if(scope.panel.mode === 'terms') { - filterSrv.set({type:'terms',field:scope.panel.query.field,value:object.series.label}); - } - }); - - var $tooltip = $('
'); - elem.bind('plothover', function (event, pos, item) { - if (item) { - $tooltip - .html([ - kbn.query_color_dot(item.series.color, 15), - (item.series.label || ''), - parseFloat(item.series.percent).toFixed(1) + '%' - ].join(' ')) - .place_tt(pos.pageX, pos.pageY, { - offset: 10 - }); - } else { - $tooltip.remove(); - } - }); - - } - }; - }); -}); \ No newline at end of file diff --git a/src/app/panels/query/editor.html b/src/app/panels/query/editor.html deleted file mode 100644 index 3100415c7f2..00000000000 --- a/src/app/panels/query/editor.html +++ /dev/null @@ -1,7 +0,0 @@ -
-
-
- No options here -
-
-
\ No newline at end of file diff --git a/src/app/panels/query/editors/lucene.html b/src/app/panels/query/editors/lucene.html deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/app/panels/query/editors/regex.html b/src/app/panels/query/editors/regex.html deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/app/panels/query/editors/topN.html b/src/app/panels/query/editors/topN.html deleted file mode 100644 index 71496541906..00000000000 --- a/src/app/panels/query/editors/topN.html +++ /dev/null @@ -1,12 +0,0 @@ -
-
- -

-
- -

-
- -

diff --git a/src/app/panels/query/help/lucene.html b/src/app/panels/query/help/lucene.html deleted file mode 100644 index 9e860e97d47..00000000000 --- a/src/app/panels/query/help/lucene.html +++ /dev/null @@ -1,30 +0,0 @@ -The lucene query type uses LUCENE query string syntax to find matching documents or events within Elasticsearch. - -

Examples

-
    -
  • - status field contains active -

    status:active
  • -
  • - title field contains quick or brown -

    title:(quick brown)
  • -
  • - author field contains the exact phrase "john smith" -

    author:"John Smith"
  • -
- -

Wildcard searches can be run on individual terms, using ? to replace -a single character, and * to replace zero or more characters:

-
qu?ck bro*
- -
    -
  • - Numbers 1..5 -

    count:[1 TO 5]
  • -
  • - Tags between alpha and omega, excluding alpha and omega: -

    tag:{alpha TO omega}
  • -
  • - Numbers from 10 upwards -

    count:[10 TO *]
  • -
diff --git a/src/app/panels/query/help/regex.html b/src/app/panels/query/help/regex.html deleted file mode 100644 index 8e38ab96fe2..00000000000 --- a/src/app/panels/query/help/regex.html +++ /dev/null @@ -1,10 +0,0 @@ -The regex query allows you to use regular expressions to match terms in the _all field. - -A detailed overview of lucene's regex engine is available here: Regular expressions in Elasticsearch - -
A note on anchoring
-Lucene’s patterns are always anchored. The pattern provided must match the entire string. For string "abcde": -

-ab.* will match
-abcd will not match
- diff --git a/src/app/panels/query/help/topN.html b/src/app/panels/query/help/topN.html deleted file mode 100644 index 9fc7c3aa8e0..00000000000 --- a/src/app/panels/query/help/topN.html +++ /dev/null @@ -1,14 +0,0 @@ -The topN query uses an Elasticsearch terms facet to find the most common terms in a field and build queries from the result. The topN query uses LUCENE query string syntax - -

Parameters

-
    -
  • - Field / The field to facet on. Fields with a large number of unique terms will use more memory to calculate. -
  • -
  • - Count / How many queries to generate. The resulting queries will use brightness variations on the original query's color for their own. -
  • -
  • - Union / The relation the generated queries have to the original. For example, if your field was set to 'extension', your original query was "user:B.Awesome" and your union was AND. Kibana might generate the following example query: extension:"html" AND (user:B.Awesome) -
  • -
\ No newline at end of file diff --git a/src/app/panels/query/helpModal.html b/src/app/panels/query/helpModal.html deleted file mode 100644 index 3cbbf8cdf7a..00000000000 --- a/src/app/panels/query/helpModal.html +++ /dev/null @@ -1,12 +0,0 @@ - - - \ No newline at end of file diff --git a/src/app/panels/query/meta.html b/src/app/panels/query/meta.html deleted file mode 100644 index a35d0022b00..00000000000 --- a/src/app/panels/query/meta.html +++ /dev/null @@ -1,34 +0,0 @@ -
- - - -
-   About the {{querySrv.list[id].type}} query - -
- - - -
- -
- - -
-
- -
- - -
- Deactivate - Pin - -
-
\ No newline at end of file diff --git a/src/app/panels/query/module.html b/src/app/panels/query/module.html deleted file mode 100644 index 3ae1d0c6bdb..00000000000 --- a/src/app/panels/query/module.html +++ /dev/null @@ -1,30 +0,0 @@ -
-
- -
-
- Pinned - - - - {{querySrv.list[id].alias || querySrv.list[id].query}} - -
- - - - -
\ No newline at end of file diff --git a/src/app/panels/query/module.js b/src/app/panels/query/module.js deleted file mode 100644 index b622ee6403a..00000000000 --- a/src/app/panels/query/module.js +++ /dev/null @@ -1,117 +0,0 @@ -/* - - ## query - - ### Parameters - * query :: A string or an array of querys. String if multi is off, array if it is on - This should be fixed, it should always be an array even if its only - one element -*/ -define([ - 'angular', - 'app', - 'underscore', - - 'css!./query.css' -], function (angular, app, _) { - 'use strict'; - - var module = angular.module('kibana.panels.query', []); - app.useModule(module); - - module.controller('query', function($scope, querySrv, $rootScope, dashboard, $q, $modal) { - $scope.panelMeta = { - status : "Stable", - description : "Manage all of the queries on the dashboard. You almost certainly need one of "+ - "these somewhere. This panel allows you to add, remove, label, pin and color queries" - }; - - // Set and populate defaults - var _d = { - query : "*", - pinned : true, - history : [], - remember: 10 // max: 100, angular strap can't take a variable for items param - }; - _.defaults($scope.panel,_d); - - $scope.querySrv = querySrv; - - // A list of query types for the query config popover - $scope.queryTypes = _.map(querySrv.queryTypes, function(v,k) { - return { - name:k, - require:v.require - }; - }); - - var queryHelpModal = $modal({ - template: './app/panels/query/helpModal.html', - persist: true, - show: false, - scope: $scope, - }); - - $scope.init = function() { - }; - - $scope.refresh = function() { - update_history(_.pluck($scope.querySrv.list,'query')); - dashboard.refresh(); - }; - - $scope.render = function() { - $rootScope.$broadcast('render'); - }; - - $scope.toggle_pin = function(id) { - querySrv.list[id].pin = querySrv.list[id].pin ? false : true; - }; - - $scope.queryIcon = function(type) { - return querySrv.queryTypes[type].icon; - }; - - $scope.queryConfig = function(type) { - return "./app/panels/query/editors/"+(type||'lucene')+".html"; - }; - - $scope.queryHelpPath = function(type) { - return "./app/panels/query/help/"+(type||'lucene')+".html"; - }; - - $scope.queryHelp = function(type) { - $scope.help = { - type: type - }; - $q.when(queryHelpModal).then(function(modalEl) { - modalEl.modal('show'); - }); - }; - - $scope.typeChange = function(q) { - var _nq = { - id : q.id, - type : q.type, - query: q.query, - alias: q.alias, - color: q.color - }; - querySrv.list[_nq.id] = querySrv.defaults(_nq); - }; - - var update_history = function(query) { - if($scope.panel.remember > 0) { - $scope.panel.history = _.union(query.reverse(),$scope.panel.history); - var _length = $scope.panel.history.length; - if(_length > $scope.panel.remember) { - $scope.panel.history = $scope.panel.history.slice(0,$scope.panel.remember); - } - } - }; - - $scope.init(); - - }); - -}); \ No newline at end of file diff --git a/src/app/panels/query/query.css b/src/app/panels/query/query.css deleted file mode 100644 index 1b0db0ca3a0..00000000000 --- a/src/app/panels/query/query.css +++ /dev/null @@ -1,47 +0,0 @@ -.short-query { - display:inline-block; - margin-right: 10px; -} -.short-query input.search-query { - width: 280px; -} -.begin-query { - position:absolute; - left:13px; - top:5px; -} -.end-query { - position:absolute; - right:15px; - top:5px; -} -.panel-query { - padding-left: 35px !important; - height: 31px !important; - -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ - -moz-box-sizing: border-box; /* Firefox, other Gecko */ - box-sizing: border-box; /* Opera/IE 8+ */ -} - -.query-disabled { - opacity: 0.3; -} - -.form-search:hover .has-remove { - padding-left: 50px !important; -} -.remove-query { - opacity: 0; -} -.last-query { - padding-right: 45px !important; -} -.form-search:hover .remove-query { - opacity: 1; -} -.query-panel .pins { - text-decoration: underline; -} -.query-panel .pinned { - margin-right: 5px; -} \ No newline at end of file diff --git a/src/app/panels/sparklines/editor.html b/src/app/panels/sparklines/editor.html deleted file mode 100644 index 65fc07eb7f5..00000000000 --- a/src/app/panels/sparklines/editor.html +++ /dev/null @@ -1,23 +0,0 @@ -
-
-
Values
-
- - -
-
- - -
-
- - -
-
-
-
Transform Series
-
- -
-
-
\ No newline at end of file diff --git a/src/app/panels/sparklines/interval.js b/src/app/panels/sparklines/interval.js deleted file mode 100644 index 673371fcf4c..00000000000 --- a/src/app/panels/sparklines/interval.js +++ /dev/null @@ -1,57 +0,0 @@ -define([ - 'kbn' -], -function (kbn) { - 'use strict'; - - /** - * manages the interval logic - * @param {[type]} interval_string An interval string in the format '1m', '1y', etc - */ - function Interval(interval_string) { - this.string = interval_string; - - var info = kbn.describe_interval(interval_string); - this.type = info.type; - this.ms = info.sec * 1000 * info.count; - - // does the length of the interval change based on the current time? - if (this.type === 'y' || this.type === 'M') { - // we will just modify this time object rather that create a new one constantly - this.get = this.get_complex; - this.date = new Date(0); - } else { - this.get = this.get_simple; - } - } - - Interval.prototype = { - toString: function () { - return this.string; - }, - after: function(current_ms) { - return this.get(current_ms, 1); - }, - before: function (current_ms) { - return this.get(current_ms, -1); - }, - get_complex: function (current, delta) { - this.date.setTime(current); - switch(this.type) { - case 'M': - this.date.setUTCMonth(this.date.getUTCMonth() + delta); - break; - case 'y': - this.date.setUTCFullYear(this.date.getUTCFullYear() + delta); - break; - } - return this.date.getTime(); - }, - get_simple: function (current, delta) { - return current + (delta * this.ms); - } - }; - - return Interval; - -}); \ No newline at end of file diff --git a/src/app/panels/sparklines/module.html b/src/app/panels/sparklines/module.html deleted file mode 100644 index e34701cabb8..00000000000 --- a/src/app/panels/sparklines/module.html +++ /dev/null @@ -1,10 +0,0 @@ -
-
- - -
- {{series.info.alias}}
-
-
- -
\ No newline at end of file diff --git a/src/app/panels/sparklines/module.js b/src/app/panels/sparklines/module.js deleted file mode 100644 index d0fce1ee3e7..00000000000 --- a/src/app/panels/sparklines/module.js +++ /dev/null @@ -1,386 +0,0 @@ -/** @scratch /panels/5 - * include::panels/sparklines.asciidoc[] - */ - -/** @scratch /panels/sparklines/0 - * == Sparklines - * Status: *Experimental* - * - * The sparklines panel shows tiny time charts. The purpose of these is not to give an exact value, - * but rather to show the shape of the time series in a compact manner - * - */ -define([ - 'angular', - 'app', - 'jquery', - 'underscore', - 'kbn', - 'moment', - './timeSeries', - - 'jquery.flot', - 'jquery.flot.time' -], -function (angular, app, $, _, kbn, moment, timeSeries) { - - 'use strict'; - - var module = angular.module('kibana.panels.sparklines', []); - app.useModule(module); - - module.controller('sparklines', function($scope, querySrv, dashboard, filterSrv) { - $scope.panelMeta = { - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], - editorTabs : [ - { - title:'Queries', - src:'app/partials/querySelect.html' - } - ], - status : "Experimental", - description : "Sparklines are tiny, simple, time series charts, shown seperately. Because "+ - "sparklines are unclutted by grids, axis markers and colors, they are perfect for spotting"+ - " change in a series" - }; - - // Set and populate defaults - var _d = { - /** @scratch /panels/sparklines/3 - * === Parameters - * mode:: Value to use for the y-axis. For all modes other than count, +value_field+ must be - * defined. Possible values: count, mean, max, min, total. - */ - mode : 'count', - /** @scratch /panels/sparklines/3 - * time_field:: x-axis field. This must be defined as a date type in Elasticsearch. - */ - time_field : '@timestamp', - /** @scratch /panels/sparklines/3 - * value_field:: y-axis field if +mode+ is set to mean, max, min or total. Must be numeric. - */ - value_field : null, - /** @scratch /panels/sparklines/3 - * interval:: Sparkline intervals are computed automatically as long as there is a time filter - * present. In the absence of a time filter, use this interval. - */ - interval : '5m', - /** @scratch /panels/sparklines/3 - * spyable:: Show inspect icon - */ - spyable : true, - /** @scratch /panels/sparklines/5 - * ==== Queries - * queries object:: This object describes the queries to use on this panel. - * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ - * queries.ids::: In +selected+ mode, which query ids are selected. - */ - queries : { - mode : 'all', - ids : [] - }, - }; - - _.defaults($scope.panel,_d); - - $scope.init = function() { - - $scope.$on('refresh',function(){ - $scope.get_data(); - }); - - $scope.get_data(); - - }; - - $scope.interval_label = function(interval) { - return $scope.panel.auto_int && interval === $scope.panel.interval ? interval+" (auto)" : interval; - }; - - /** - * The time range effecting the panel - * @return {[type]} [description] - */ - $scope.get_time_range = function () { - var range = $scope.range = filterSrv.timeRange('last'); - return range; - }; - - $scope.get_interval = function () { - var interval = $scope.panel.interval, - range; - range = $scope.get_time_range(); - if (range) { - interval = kbn.secondsToHms( - kbn.calculate_interval(range.from, range.to, 10, 0) / 1000 - ); - } - $scope.panel.interval = interval || '10m'; - return $scope.panel.interval; - }; - - /** - * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies - * need to be consulted (like timestamped logstash indicies) - * - * The results of this function are stored on the scope's data property. This property will be an - * array of objects with the properties info, time_series, and hits. These objects are used in the - * render_panel function to create the historgram. - * - * @param {number} segment The segment count, (0 based) - * @param {number} query_id The id of the query, generated on the first run and passed back when - * this call is made recursively for more segments - */ - $scope.get_data = function(segment, query_id) { - var - _range, - _interval, - request, - queries, - results; - - if (_.isUndefined(segment)) { - segment = 0; - } - delete $scope.panel.error; - - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - _range = $scope.get_time_range(); - _interval = $scope.get_interval(_range); - - $scope.panelMeta.loading = true; - request = $scope.ejs.Request().indices(dashboard.indices[segment]); - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - - queries = querySrv.getQueryObjs($scope.panel.queries.ids); - - // Build the query - _.each(queries, function(q) { - var query = $scope.ejs.FilteredQuery( - querySrv.toEjsObj(q), - filterSrv.getBoolFilter(filterSrv.ids) - ); - - var facet = $scope.ejs.DateHistogramFacet(q.id); - - if($scope.panel.mode === 'count') { - facet = facet.field($scope.panel.time_field).global(true); - } else { - if(_.isNull($scope.panel.value_field)) { - $scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified"; - return; - } - facet = facet.keyField($scope.panel.time_field).valueField($scope.panel.value_field); - } - facet = facet.interval(_interval).facetFilter($scope.ejs.QueryFilter(query)); - request = request.facet(facet) - .size(0); - }); - - // Populate the inspector panel - $scope.populate_modal(request); - - // Then run it - results = request.doSearch(); - - // Populate scope when we have results - results.then(function(results) { - - $scope.panelMeta.loading = false; - if(segment === 0) { - $scope.hits = 0; - $scope.data = []; - query_id = $scope.query_id = new Date().getTime(); - } - - // Check for error and abort if found - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error); - return; - } - - // Make sure we're still on the same query/queries - if($scope.query_id === query_id) { - - var i = 0, - time_series, - hits; - - _.each(queries, function(q) { - var query_results = results.facets[q.id]; - // we need to initialize the data variable on the first run, - // and when we are working on the first segment of the data. - if(_.isUndefined($scope.data[i]) || segment === 0) { - var tsOpts = { - interval: _interval, - start_date: _range && _range.from, - end_date: _range && _range.to, - fill_style: 'minimal' - }; - time_series = new timeSeries.ZeroFilled(tsOpts); - hits = 0; - } else { - time_series = $scope.data[i].time_series; - hits = $scope.data[i].hits; - } - - // push each entry into the time series, while incrementing counters - _.each(query_results.entries, function(entry) { - time_series.addValue(entry.time, entry[$scope.panel.mode]); - hits += entry.count; // The series level hits counter - $scope.hits += entry.count; // Entire dataset level hits counter - }); - $scope.data[i] = { - info: q, - range: $scope.range, - time_series: time_series, - hits: hits - }; - - i++; - }); - - // If we still have segments left, get them - if(segment < dashboard.indices.length-1) { - $scope.get_data(segment+1,query_id); - } - } - }); - }; - - // I really don't like this function, too much dom manip. Break out into directive? - $scope.populate_modal = function(request) { - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - }; - - $scope.set_refresh = function (state) { - $scope.refresh = state; - }; - - $scope.close_edit = function() { - if($scope.refresh) { - $scope.get_data(); - } - $scope.refresh = false; - }; - - }); - - module.directive('sparklinesChart', function() { - return { - restrict: 'A', - scope: { - series: '=', - panel: '=' - }, - template: '
', - link: function(scope, elem) { - - // Receive render events - scope.$watch('series',function(){ - render_panel(); - }); - - // Re-render if the window is resized - angular.element(window).bind('resize', function(){ - render_panel(); - }); - - var derivative = function(series) { - return _.map(series, function(p,i) { - var _v; - if(i === 0 || p[1] === null) { - _v = [p[0],null]; - } else { - _v = series[i-1][1] === null ? [p[0],null] : [p[0],p[1]-(series[i-1][1])]; - } - return _v; - }); - }; - - // Function for rendering panel - function render_panel() { - // IE doesn't work without this - elem.css({height:"30px",width:"100px"}); - - // Populate element - //try { - var options = { - legend: { show: false }, - series: { - lines: { - show: true, - // Silly, but fixes bug in stacked percentages - fill: 0, - lineWidth: 2, - steps: false - }, - points: { radius:2 }, - shadowSize: 1 - }, - yaxis: { - show: false - }, - xaxis: { - show: false, - mode: "time", - min: _.isUndefined(scope.series.range.from) ? null : scope.series.range.from.getTime(), - max: _.isUndefined(scope.series.range.to) ? null : scope.series.range.to.getTime() - }, - grid: { - hoverable: false, - show: false - } - }; - // when rendering stacked bars, we need to ensure each point that has data is zero-filled - // so that the stacking happens in the proper order - var required_times = []; - required_times = scope.series.time_series.getOrderedTimes(); - required_times = _.uniq(required_times.sort(function (a, b) { - // decending numeric sort - return a-b; - }), true); - - var _d = { - data : scope.panel.derivative ? - derivative(scope.series.time_series.getFlotPairs(required_times)) : - scope.series.time_series.getFlotPairs(required_times), - label : scope.series.info.alias, - color : elem.css('color'), - }; - - $.plot(elem, [_d], options); - - //} catch(e) { - // console.log(e); - //} - } - - var $tooltip = $('
'); - elem.bind("plothover", function (event, pos, item) { - if (item) { - $tooltip - .html( - item.datapoint[1] + " @ " + moment(item.datapoint[0]).format('YYYY-MM-DD HH:mm:ss') - ) - .place_tt(pos.pageX, pos.pageY); - } else { - $tooltip.detach(); - } - }); - } - }; - }); - -}); diff --git a/src/app/panels/sparklines/timeSeries.js b/src/app/panels/sparklines/timeSeries.js deleted file mode 100644 index 8885e734371..00000000000 --- a/src/app/panels/sparklines/timeSeries.js +++ /dev/null @@ -1,216 +0,0 @@ -define([ - 'underscore', - './interval' -], -function (_, Interval) { - 'use strict'; - - var ts = {}; - - // map compatable parseInt - function base10Int(val) { - return parseInt(val, 10); - } - - // trim the ms off of a time, but return it with empty ms. - function getDatesTime(date) { - return Math.floor(date.getTime() / 1000)*1000; - } - - /** - * Certain graphs require 0 entries to be specified for them to render - * properly (like the line graph). So with this we will caluclate all of - * the expected time measurements, and fill the missing ones in with 0 - * @param {object} opts An object specifying some/all of the options - * - * OPTIONS: - * @opt {string} interval The interval notion describing the expected spacing between - * each data point. - * @opt {date} start_date (optional) The start point for the time series, setting this and the - * end_date will ensure that the series streches to resemble the entire - * expected result - * @opt {date} end_date (optional) The end point for the time series, see start_date - * @opt {string} fill_style Either "minimal", or "all" describing the strategy used to zero-fill - * the series. - */ - ts.ZeroFilled = function (opts) { - opts = _.defaults(opts, { - interval: '10m', - start_date: null, - end_date: null, - fill_style: 'minimal' - }); - - // the expected differenece between readings. - this.interval = new Interval(opts.interval); - - // will keep all values here, keyed by their time - this._data = {}; - this.start_time = opts.start_date && getDatesTime(opts.start_date); - this.end_time = opts.end_date && getDatesTime(opts.end_date); - this.opts = opts; - }; - - /** - * Add a row - * @param {int} time The time for the value, in - * @param {any} value The value at this time - */ - ts.ZeroFilled.prototype.addValue = function (time, value) { - if (time instanceof Date) { - time = getDatesTime(time); - } else { - time = base10Int(time); - } - if (!isNaN(time)) { - this._data[time] = (_.isUndefined(value) ? 0 : value); - } - this._cached_times = null; - }; - - /** - * Get an array of the times that have been explicitly set in the series - * @param {array} include (optional) list of timestamps to include in the response - * @return {array} An array of integer times. - */ - ts.ZeroFilled.prototype.getOrderedTimes = function (include) { - var times = _.map(_.keys(this._data), base10Int); - if (_.isArray(include)) { - times = times.concat(include); - } - return _.uniq(times.sort(function (a, b) { - // decending numeric sort - return a - b; - }), true); - }; - - /** - * return the rows in the format: - * [ [time, value], [time, value], ... ] - * - * Heavy lifting is done by _get(Min|Default|All)FlotPairs() - * @param {array} required_times An array of timestamps that must be in the resulting pairs - * @return {array} - */ - ts.ZeroFilled.prototype.getFlotPairs = function (required_times) { - var times = this.getOrderedTimes(required_times), - strategy, - pairs; - - if(this.opts.fill_style === 'all') { - strategy = this._getAllFlotPairs; - } else if(this.opts.fill_style === 'null') { - strategy = this._getNullFlotPairs; - } else { - strategy = this._getMinFlotPairs; - } - - pairs = _.reduce( - times, // what - strategy, // how - [], // where - this // context - ); - - // if the first or last pair is inside either the start or end time, - // add those times to the series with null values so the graph will stretch to contain them. - // Removing, flot 0.8.1's max/min params satisfy this - /* - if (this.start_time && (pairs.length === 0 || pairs[0][0] > this.start_time)) { - pairs.unshift([this.start_time, null]); - } - if (this.end_time && (pairs.length === 0 || pairs[pairs.length - 1][0] < this.end_time)) { - pairs.push([this.end_time, null]); - } - */ - - return pairs; - }; - - /** - * ** called as a reduce stragegy in getFlotPairs() ** - * Fill zero's on either side of the current time, unless there is already a measurement there or - * we are looking at an edge. - * @return {array} An array of points to plot with flot - */ - ts.ZeroFilled.prototype._getMinFlotPairs = function (result, time, i, times) { - var next, expected_next, prev, expected_prev; - - // check for previous measurement - if (i > 0) { - prev = times[i - 1]; - expected_prev = this.interval.before(time); - if (prev < expected_prev) { - result.push([expected_prev, 0]); - } - } - - // add the current time - result.push([ time, this._data[time] || 0]); - - // check for next measurement - if (times.length > i) { - next = times[i + 1]; - expected_next = this.interval.after(time); - if (next > expected_next) { - result.push([expected_next, 0]); - } - } - - return result; - }; - - /** - * ** called as a reduce stragegy in getFlotPairs() ** - * Fill zero's to the right of each time, until the next measurement is reached or we are at the - * last measurement - * @return {array} An array of points to plot with flot - */ - ts.ZeroFilled.prototype._getAllFlotPairs = function (result, time, i, times) { - var next, expected_next; - - result.push([ times[i], this._data[times[i]] || 0 ]); - next = times[i + 1]; - expected_next = this.interval.after(time); - for(; times.length > i && next > expected_next; expected_next = this.interval.after(expected_next)) { - result.push([expected_next, 0]); - } - - return result; - }; - - /** - * ** called as a reduce stragegy in getFlotPairs() ** - * Same as min, but fills with nulls - * @return {array} An array of points to plot with flot - */ - ts.ZeroFilled.prototype._getNullFlotPairs = function (result, time, i, times) { - var next, expected_next, prev, expected_prev; - - // check for previous measurement - if (i > 0) { - prev = times[i - 1]; - expected_prev = this.interval.before(time); - if (prev < expected_prev) { - result.push([expected_prev, null]); - } - } - - // add the current time - result.push([ time, this._data[time] || null]); - - // check for next measurement - if (times.length > i) { - next = times[i + 1]; - expected_next = this.interval.after(time); - if (next > expected_next) { - result.push([expected_next, null]); - } - } - - return result; - }; - - - return ts; -}); \ No newline at end of file diff --git a/src/app/panels/table/editor.html b/src/app/panels/table/editor.html deleted file mode 100644 index 9b5f26e7b3e..00000000000 --- a/src/app/panels/table/editor.html +++ /dev/null @@ -1,49 +0,0 @@ -
-
-
Columns
-
- - -

- {{field}} -
-
-
Hightlighted Fields
-
- - -

- {{field}} -
-
- -
-
-
Options
-
-
Header
-
-
-
Sorting
-
-
-
Sort
- - -
-
Font Size
- -
-
-
Trim Factor Trim fields to this long divided by # of rows. Requires data refresh.
- -
-
-
Local Time Adjust time field to browser's local time
-
-
-
Time Field
- -
-
-
\ No newline at end of file diff --git a/src/app/panels/table/micropanel.html b/src/app/panels/table/micropanel.html deleted file mode 100644 index bb256627591..00000000000 --- a/src/app/panels/table/micropanel.html +++ /dev/null @@ -1,62 +0,0 @@ -× - - - - - Micro Analysis of {{micropanel.field}} - - as - Groups / - Singles - - - - - - - - - - - - - - - -
{{micropanel.field}}ActionCount / {{micropanel.count}} events
{{{true: "__blank__", false:field[0] }[field[0] == '' || field[0] == undefined]|tableTruncate:panel.trimFactor:3}} - - - - -
- {{field[1]}} -
-
-
-
-
- {{field.name}} ({{Math.round((field.count / micropanel.count) * 100)}}%), - More -
-
-
-
- - Terms - - - -
- -
-
\ No newline at end of file diff --git a/src/app/panels/table/modal.html b/src/app/panels/table/modal.html deleted file mode 100644 index 713d36175fe..00000000000 --- a/src/app/panels/table/modal.html +++ /dev/null @@ -1,45 +0,0 @@ - - - \ No newline at end of file diff --git a/src/app/panels/table/module.html b/src/app/panels/table/module.html deleted file mode 100644 index 9913c3f00c5..00000000000 --- a/src/app/panels/table/module.html +++ /dev/null @@ -1,124 +0,0 @@ -
- - -
-
- -
-
- -
-
- - -
-
- {{panel.offset}} to {{panel.offset + data.slice(panel.offset,panel.offset+panel.size).length}} - of {{data.length}} available for paging -
-
- -
-
- - - - - - - - - - - - - - - -
_source (select columns from the list to the left) - - - - {{field}} - - - {{field}} - -
- - -
- - View: - Table / - JSON / - Raw - - - - - - - - - - - - - - -
FieldActionValue
- - - -
-

-              

-            
-
-
- - -
-
- {{panel.offset}} to {{panel.offset + data.slice(panel.offset,panel.offset+panel.size).length}} - of {{data.length}} available for paging -
-
- -
-
-
-
-
\ No newline at end of file diff --git a/src/app/panels/table/module.js b/src/app/panels/table/module.js deleted file mode 100644 index ed21487efb5..00000000000 --- a/src/app/panels/table/module.js +++ /dev/null @@ -1,493 +0,0 @@ -/** @scratch /panels/5 - * include::panels/table.asciidoc[] - */ - -/** @scratch /panels/table/0 - * == table - * Status: *Stable* - * - * The table panel contains a sortable, pagable view of documents that. It can be arranged into - * defined columns and offers several interactions, such as performing adhoc terms aggregations. - * - */ -define([ - 'angular', - 'app', - 'underscore', - 'kbn', - 'moment', -], -function (angular, app, _, kbn, moment) { - 'use strict'; - - var module = angular.module('kibana.panels.table', []); - app.useModule(module); - - module.controller('table', function($rootScope, $scope, $modal, $q, $compile, fields, querySrv, dashboard, filterSrv) { - $scope.panelMeta = { - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], - editorTabs : [ - { - title:'Paging', - src: 'app/panels/table/pagination.html' - }, - { - title:'Queries', - src: 'app/partials/querySelect.html' - } - ], - status: "Stable", - description: "A paginated table of records matching your query or queries. Click on a row to "+ - "expand it and review all of the fields associated with that document.

" - }; - - // Set and populate defaults - var _d = { - /** @scratch /panels/table/5 - * === Parameters - * - * size:: The number of hits to show per page - */ - size : 100, // Per page - /** @scratch /panels/table/5 - * pages:: The number of pages available - */ - pages : 5, // Pages available - /** @scratch /panels/table/5 - * offset:: The current page - */ - offset : 0, - /** @scratch /panels/table/5 - * sort:: An array describing the sort order of the table. For example [`@timestamp',`desc'] - */ - sort : ['_score','desc'], - /** @scratch /panels/table/5 - * overflow:: The css overflow property. `min-height' (expand) or `auto' (scroll) - */ - overflow: 'min-height', - /** @scratch /panels/table/5 - * fields:: the fields used a columns of the table, in an array. - */ - fields : [], - /** @scratch /panels/table/5 - * highlight:: The fields on which to highlight, in an array - */ - highlight : [], - /** @scratch /panels/table/5 - * sortable:: Set sortable to false to disable sorting - */ - sortable: true, - /** @scratch /panels/table/5 - * header:: Set to false to hide the table column names - */ - header : true, - /** @scratch /panels/table/5 - * paging:: Set to false to hide the paging controls of the table - */ - paging : true, - /** @scratch /panels/table/5 - * field_list:: Set to false to hide the list of fields. The user will be able to expand it, - * but it will be hidden by default - */ - field_list: true, - /** @scratch /panels/table/5 - * all_fields:: Set to true to show all fields in the mapping, not just the current fields in - * the table. - */ - all_fields: false, - /** @scratch /panels/table/5 - * trimFactor:: The trim factor is the length at which to truncate fields takinging into - * consideration the number of columns in the table. For example, a trimFactor of 100, with 5 - * columns in the table, would trim each column at 20 character. The entirety of the field is - * still available in the expanded view of the event. - */ - trimFactor: 300, - /** @scratch /panels/table/5 - * localTime:: Set to true to adjust the timeField to the browser's local time - */ - localTime: false, - /** @scratch /panels/table/5 - * timeField:: If localTime is set to true, this field will be adjusted to the browsers local time - */ - timeField: '@timestamp', - /** @scratch /panels/table/5 - * spyable:: Set to false to disable the inspect icon - */ - spyable : true, - /** @scratch /panels/table/5 - * ==== Queries - * queries object:: This object describes the queries to use on this panel. - * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ - * queries.ids::: In +selected+ mode, which query ids are selected. - */ - queries : { - mode : 'all', - ids : [] - }, - style : {'font-size': '9pt'}, - normTimes : true, - }; - _.defaults($scope.panel,_d); - - $scope.init = function () { - $scope.columns = {}; - _.each($scope.panel.fields,function(field) { - $scope.columns[field] = true; - }); - - $scope.Math = Math; - $scope.identity = angular.identity; - $scope.$on('refresh',function(){$scope.get_data();}); - - $scope.fields = fields; - $scope.get_data(); - }; - - // Create a percent function for the view - $scope.percent = kbn.to_percent; - - $scope.termsModal = function(field,chart) { - $scope.modalField = field; - showModal( - '{"height":"300px","chart":"'+chart+'","field":"'+field+'"}','terms'); - }; - - $scope.statsModal = function(field) { - $scope.modalField = field; - showModal( - '{"field":"'+field+'"}','statistics'); - }; - - var showModal = function(panel,type) { - $scope.facetPanel = panel; - $scope.facetType = type; - - // create a new modal. Can't reuse one modal unforunately as the directive will not - // re-render on show. - var panelModal = $modal({ - template: './app/panels/table/modal.html', - persist: true, - show: false, - scope: $scope, - keyboard: false - }); - - // and show it - $q.when(panelModal).then(function(modalEl) { - modalEl.modal('show'); - }); - }; - - $scope.toggle_micropanel = function(field,groups) { - var docs = _.map($scope.data,function(_d){return _d.kibana._source;}); - var topFieldValues = kbn.top_field_values(docs,field,10,groups); - $scope.micropanel = { - field: field, - grouped: groups, - values : topFieldValues.counts, - hasArrays : topFieldValues.hasArrays, - related : kbn.get_related_fields(docs,field), - limit: 10, - count: _.countBy(docs,function(doc){return _.contains(_.keys(doc),field);})['true'] - }; - }; - - $scope.micropanelColor = function(index) { - var _c = ['bar-success','bar-warning','bar-danger','bar-info','bar-primary']; - return index > _c.length ? '' : _c[index]; - }; - - $scope.set_sort = function(field) { - if($scope.panel.sort[0] === field) { - $scope.panel.sort[1] = $scope.panel.sort[1] === 'asc' ? 'desc' : 'asc'; - } else { - $scope.panel.sort[0] = field; - } - $scope.get_data(); - }; - - $scope.toggle_field = function(field) { - if (_.indexOf($scope.panel.fields,field) > -1) { - $scope.panel.fields = _.without($scope.panel.fields,field); - delete $scope.columns[field]; - } else { - $scope.panel.fields.push(field); - $scope.columns[field] = true; - } - }; - - $scope.toggle_highlight = function(field) { - if (_.indexOf($scope.panel.highlight,field) > -1) { - $scope.panel.highlight = _.without($scope.panel.highlight,field); - } else { - $scope.panel.highlight.push(field); - } - }; - - $scope.toggle_details = function(row) { - row.kibana.details = row.kibana.details ? false : true; - row.kibana.view = row.kibana.view || 'table'; - //row.kibana.details = !row.kibana.details ? $scope.without_kibana(row) : false; - }; - - $scope.page = function(page) { - $scope.panel.offset = page*$scope.panel.size; - $scope.get_data(); - }; - - $scope.build_search = function(field,value,negate) { - var query; - // This needs to be abstracted somewhere - if(_.isArray(value)) { - query = "(" + _.map(value,function(v){return angular.toJson(v);}).join(" AND ") + ")"; - } else if (_.isUndefined(value)) { - query = '*'; - negate = !negate; - } else { - query = angular.toJson(value); - } - $scope.panel.offset = 0; - filterSrv.set({type:'field',field:field,query:query,mandate:(negate ? 'mustNot':'must')}); - }; - - $scope.fieldExists = function(field,mandate) { - filterSrv.set({type:'exists',field:field,mandate:mandate}); - }; - - $scope.get_data = function(segment,query_id) { - var - _segment, - request, - boolQuery, - queries, - sort; - - $scope.panel.error = false; - - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - - sort = [$scope.ejs.Sort($scope.panel.sort[0]).order($scope.panel.sort[1])]; - if($scope.panel.localTime) { - sort.push($scope.ejs.Sort($scope.panel.timeField).order($scope.panel.sort[1])); - } - - - $scope.panelMeta.loading = true; - - _segment = _.isUndefined(segment) ? 0 : segment; - $scope.segment = _segment; - - request = $scope.ejs.Request().indices(dashboard.indices[_segment]); - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - - queries = querySrv.getQueryObjs($scope.panel.queries.ids); - - boolQuery = $scope.ejs.BoolQuery(); - _.each(queries,function(q) { - boolQuery = boolQuery.should(querySrv.toEjsObj(q)); - }); - - request = request.query( - $scope.ejs.FilteredQuery( - boolQuery, - filterSrv.getBoolFilter(filterSrv.ids) - )) - .highlight( - $scope.ejs.Highlight($scope.panel.highlight) - .fragmentSize(2147483647) // Max size of a 32bit unsigned int - .preTags('@start-highlight@') - .postTags('@end-highlight@') - ) - .size($scope.panel.size*$scope.panel.pages) - .sort(sort); - - $scope.populate_modal(request); - - // Populate scope when we have results - request.doSearch().then(function(results) { - $scope.panelMeta.loading = false; - - if(_segment === 0) { - $scope.hits = 0; - $scope.data = []; - $scope.current_fields = []; - query_id = $scope.query_id = new Date().getTime(); - } - - // Check for error and abort if found - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error); - return; - } - - // Check that we're still on the same query, if not stop - if($scope.query_id === query_id) { - - // This is exceptionally expensive, especially on events with a large number of fields - $scope.data = $scope.data.concat(_.map(results.hits.hits, function(hit) { - var - _h = _.clone(hit), - _p = _.omit(hit,'_source','sort','_score'); - - // _source is kind of a lie here, never display it, only select values from it - _h.kibana = { - _source : _.extend(kbn.flatten_json(hit._source),_p), - highlight : kbn.flatten_json(hit.highlight||{}) - }; - - // Kind of cheating with the _.map here, but this is faster than kbn.get_all_fields - $scope.current_fields = $scope.current_fields.concat(_.keys(_h.kibana._source)); - - return _h; - })); - - $scope.current_fields = _.uniq($scope.current_fields); - $scope.hits += results.hits.total; - - // Sort the data - $scope.data = _.sortBy($scope.data, function(v){ - if(!_.isUndefined(v.sort)) { - return v.sort[0]; - } else { - return 0; - } - }); - - // Reverse if needed - if($scope.panel.sort[1] === 'desc') { - $scope.data.reverse(); - } - - // Keep only what we need for the set - $scope.data = $scope.data.slice(0,$scope.panel.size * $scope.panel.pages); - - } else { - return; - } - - // If we're not sorting in reverse chrono order, query every index for - // size*pages results - // Otherwise, only get size*pages results then stop querying - if (($scope.data.length < $scope.panel.size*$scope.panel.pages || - !((_.contains(filterSrv.timeField(),$scope.panel.sort[0])) && $scope.panel.sort[1] === 'desc')) && - _segment+1 < dashboard.indices.length) { - $scope.get_data(_segment+1,$scope.query_id); - } - - }); - }; - - $scope.populate_modal = function(request) { - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - }; - - $scope.without_kibana = function (row) { - var _c = _.clone(row); - delete _c.kibana; - return _c; - }; - - $scope.set_refresh = function (state) { - $scope.refresh = state; - }; - - $scope.close_edit = function() { - if($scope.refresh) { - $scope.get_data(); - } - $scope.refresh = false; - }; - - $scope.locate = function(obj, path) { - path = path.split('.'); - var arrayPattern = /(.+)\[(\d+)\]/; - for (var i = 0; i < path.length; i++) { - var match = arrayPattern.exec(path[i]); - if (match) { - obj = obj[match[1]][parseInt(match[2],10)]; - } else { - obj = obj[path[i]]; - } - } - return obj; - }; - - - }); - - // This also escapes some xml sequences - module.filter('tableHighlight', function() { - return function(text) { - if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { - return text.toString(). - replace(/&/g, '&'). - replace(//g, '>'). - replace(/\r?\n/g, '
'). - replace(/@start-highlight@/g, ''). - replace(/@end-highlight@/g, ''); - } - return ''; - }; - }); - - module.filter('tableTruncate', function() { - return function(text,length,factor) { - if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { - return text.length > length/factor ? text.substr(0,length/factor)+'...' : text; - } - return ''; - }; - }); - - - - module.filter('tableJson', function() { - var json; - return function(text,prettyLevel) { - if (!_.isUndefined(text) && !_.isNull(text) && text.toString().length > 0) { - json = angular.toJson(text,prettyLevel > 0 ? true : false); - json = json.replace(/&/g, '&').replace(//g, '>'); - if(prettyLevel > 1) { - /* jshint maxlen: false */ - json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) { - var cls = 'number'; - if (/^"/.test(match)) { - if (/:$/.test(match)) { - cls = 'key strong'; - } else { - cls = ''; - } - } else if (/true|false/.test(match)) { - cls = 'boolean'; - } else if (/null/.test(match)) { - cls = 'null'; - } - return '' + match + ''; - }); - } - return json; - } - return ''; - }; - }); - - // WIP - module.filter('tableLocalTime', function(){ - return function(text,event) { - return moment(event.sort[1]).format("YYYY-MM-DDTHH:mm:ss.SSSZ"); - }; - }); - -}); \ No newline at end of file diff --git a/src/app/panels/table/pagination.html b/src/app/panels/table/pagination.html deleted file mode 100644 index 0a119710dd5..00000000000 --- a/src/app/panels/table/pagination.html +++ /dev/null @@ -1,27 +0,0 @@ -

-
-
Show Controls
-
-
-
Overflow
- -
-
-
-
-
Per Page
- -
-
-
 
-
-
-
-
Page limit
- -
-
-
Pageable
- = {{panel.size * panel.pages}} -
-
diff --git a/src/app/panels/terms/editor.html b/src/app/panels/terms/editor.html deleted file mode 100644 index e573d6c591e..00000000000 --- a/src/app/panels/terms/editor.html +++ /dev/null @@ -1,51 +0,0 @@ -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
- -
-
- -
-
- -
-
- -
-
diff --git a/src/app/panels/terms/module.html b/src/app/panels/terms/module.html deleted file mode 100644 index 4e65077b586..00000000000 --- a/src/app/panels/terms/module.html +++ /dev/null @@ -1,58 +0,0 @@ -
- - -
- - - - - -
{{term.label}}{{term.data[0][1]}}
- - -
- {{term.label}} ({{term.data[0][1]}}) -

- -
- - -
- -
- -
- - - - - -
{{term.label}}{{term.data[0][1]}}
- - -
- {{term.label}} ({{term.data[0][1]}}) -

- -
- - - - - - - - - - - -
Term Count Action
{{term.label}}{{term.data[0][1]}} - - - - -
- -
\ No newline at end of file diff --git a/src/app/panels/terms/module.js b/src/app/panels/terms/module.js deleted file mode 100644 index fe767360f22..00000000000 --- a/src/app/panels/terms/module.js +++ /dev/null @@ -1,358 +0,0 @@ -/** @scratch /panels/5 - * include::panels/terms.asciidoc[] - */ - -/** @scratch /panels/terms/0 - * == terms - * Status: *Stable* - * - * A table, bar chart or pie chart based on the results of an Elasticsearch terms facet. - * - */ -define([ - 'angular', - 'app', - 'underscore', - 'jquery', - 'kbn' -], -function (angular, app, _, $, kbn) { - 'use strict'; - - var module = angular.module('kibana.panels.terms', []); - app.useModule(module); - - module.controller('terms', function($scope, querySrv, dashboard, filterSrv) { - $scope.panelMeta = { - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], - editorTabs : [ - {title:'Queries', src:'app/partials/querySelect.html'} - ], - status : "Stable", - description : "Displays the results of an elasticsearch facet as a pie chart, bar chart, or a "+ - "table" - }; - - // Set and populate defaults - var _d = { - /** @scratch /panels/terms/5 - * === Parameters - * - * field:: The field on which to computer the facet - */ - field : '_type', - /** @scratch /panels/terms/5 - * exclude:: terms to exclude from the results - */ - exclude : [], - /** @scratch /panels/terms/5 - * missing:: Set to false to disable the display of a counter showing how much results are - * missing the field - */ - missing : true, - /** @scratch /panels/terms/5 - * other:: Set to false to disable the display of a counter representing the aggregate of all - * values outside of the scope of your +size+ property - */ - other : true, - /** @scratch /panels/terms/5 - * size:: Show this many terms - */ - size : 10, - /** @scratch /panels/terms/5 - * order:: count, term, reverse_count or reverse_term - */ - order : 'count', - style : { "font-size": '10pt'}, - /** @scratch /panels/terms/5 - * donut:: In pie chart mode, draw a hole in the middle of the pie to make a tasty donut. - */ - donut : false, - /** @scratch /panels/terms/5 - * tilt:: In pie chart mode, tilt the chart back to appear as more of an oval shape - */ - tilt : false, - /** @scratch /panels/terms/5 - * lables:: In pie chart mode, draw labels in the pie slices - */ - labels : true, - /** @scratch /panels/terms/5 - * arrangement:: In bar or pie mode, arrangement of the legend. horizontal or vertical - */ - arrangement : 'horizontal', - /** @scratch /panels/terms/5 - * chart:: table, bar or pie - */ - chart : 'bar', - /** @scratch /panels/terms/5 - * counter_pos:: The location of the legend in respect to the chart, above or below. - */ - counter_pos : 'above', - /** @scratch /panels/terms/5 - * spyable:: Set spyable to false to disable the inspect button - */ - spyable : true, - /** @scratch /panels/terms/5 - * ==== Queries - * queries object:: This object describes the queries to use on this panel. - * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ - * queries.ids::: In +selected+ mode, which query ids are selected. - */ - queries : { - mode : 'all', - ids : [] - }, - }; - _.defaults($scope.panel,_d); - - $scope.init = function () { - $scope.hits = 0; - - $scope.$on('refresh',function(){ - $scope.get_data(); - }); - $scope.get_data(); - - }; - - $scope.get_data = function() { - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } - - $scope.panelMeta.loading = true; - var request, - results, - boolQuery, - queries; - - request = $scope.ejs.Request().indices(dashboard.indices); - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - queries = querySrv.getQueryObjs($scope.panel.queries.ids); - - // This could probably be changed to a BoolFilter - boolQuery = $scope.ejs.BoolQuery(); - _.each(queries,function(q) { - boolQuery = boolQuery.should(querySrv.toEjsObj(q)); - }); - - - // Terms mode - request = request - .facet($scope.ejs.TermsFacet('terms') - .field($scope.panel.field) - .size($scope.panel.size) - .order($scope.panel.order) - .exclude($scope.panel.exclude) - .facetFilter($scope.ejs.QueryFilter( - $scope.ejs.FilteredQuery( - boolQuery, - filterSrv.getBoolFilter(filterSrv.ids) - )))).size(0); - - // Populate the inspector panel - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - - results = request.doSearch(); - - // Populate scope when we have results - results.then(function(results) { - var k = 0; - $scope.panelMeta.loading = false; - $scope.hits = results.hits.total; - $scope.data = []; - _.each(results.facets.terms.terms, function(v) { - var slice = { label : v.term, data : [[k,v.count]], actions: true}; - $scope.data.push(slice); - k = k + 1; - }); - - $scope.data.push({label:'Missing field', - data:[[k,results.facets.terms.missing]],meta:"missing",color:'#aaa',opacity:0}); - $scope.data.push({label:'Other values', - data:[[k+1,results.facets.terms.other]],meta:"other",color:'#444'}); - - $scope.$emit('render'); - }); - }; - - $scope.build_search = function(term,negate) { - if(_.isUndefined(term.meta)) { - filterSrv.set({type:'terms',field:$scope.panel.field,value:term.label, - mandate:(negate ? 'mustNot':'must')}); - } else if(term.meta === 'missing') { - filterSrv.set({type:'exists',field:$scope.panel.field, - mandate:(negate ? 'must':'mustNot')}); - } else { - return; - } - }; - - $scope.set_refresh = function (state) { - $scope.refresh = state; - }; - - $scope.close_edit = function() { - if($scope.refresh) { - $scope.get_data(); - } - $scope.refresh = false; - $scope.$emit('render'); - }; - - $scope.showMeta = function(term) { - if(_.isUndefined(term.meta)) { - return true; - } - if(term.meta === 'other' && !$scope.panel.other) { - return false; - } - if(term.meta === 'missing' && !$scope.panel.missing) { - return false; - } - return true; - }; - - }); - - module.directive('termsChart', function(querySrv) { - return { - restrict: 'A', - link: function(scope, elem) { - - // Receive render events - scope.$on('render',function(){ - render_panel(); - }); - - // Re-render if the window is resized - angular.element(window).bind('resize', function(){ - render_panel(); - }); - - // Function for rendering panel - function render_panel() { - var plot, chartData; - - // IE doesn't work without this - elem.css({height:scope.panel.height||scope.row.height}); - - // Make a clone we can operate on. - chartData = _.clone(scope.data); - chartData = scope.panel.missing ? chartData : - _.without(chartData,_.findWhere(chartData,{meta:'missing'})); - chartData = scope.panel.other ? chartData : - _.without(chartData,_.findWhere(chartData,{meta:'other'})); - - // Populate element. - require(['jquery.flot.pie'], function(){ - // Populate element - try { - // Add plot to scope so we can build out own legend - if(scope.panel.chart === 'bar') { - plot = $.plot(elem, chartData, { - legend: { show: false }, - series: { - lines: { show: false, }, - bars: { show: true, fill: 1, barWidth: 0.8, horizontal: false }, - shadowSize: 1 - }, - yaxis: { show: true, min: 0, color: "#c8c8c8" }, - xaxis: { show: false }, - grid: { - borderWidth: 0, - borderColor: '#eee', - color: "#eee", - hoverable: true, - clickable: true - }, - colors: querySrv.colors - }); - } - if(scope.panel.chart === 'pie') { - var labelFormat = function(label, series){ - return '
'+ - label+'
'+Math.round(series.percent)+'%
'; - }; - - plot = $.plot(elem, chartData, { - legend: { show: false }, - series: { - pie: { - innerRadius: scope.panel.donut ? 0.4 : 0, - tilt: scope.panel.tilt ? 0.45 : 1, - radius: 1, - show: true, - combine: { - color: '#999', - label: 'The Rest' - }, - stroke: { - width: 0 - }, - label: { - show: scope.panel.labels, - radius: 2/3, - formatter: labelFormat, - threshold: 0.1 - } - } - }, - //grid: { hoverable: true, clickable: true }, - grid: { hoverable: true, clickable: true }, - colors: querySrv.colors - }); - } - - // Populate legend - if(elem.is(":visible")){ - setTimeout(function(){ - scope.legend = plot.getData(); - if(!scope.$$phase) { - scope.$apply(); - } - }); - } - - } catch(e) { - elem.text(e); - } - }); - } - - elem.bind("plotclick", function (event, pos, object) { - if(object) { - scope.build_search(scope.data[object.seriesIndex]); - } - }); - - var $tooltip = $('
'); - elem.bind("plothover", function (event, pos, item) { - if (item) { - var value = scope.panel.chart === 'bar' ? item.datapoint[1] : item.datapoint[1][0][1]; - $tooltip - .html( - kbn.query_color_dot(item.series.color, 20) + ' ' + - item.series.label + " (" + value.toFixed(0)+")" - ) - .place_tt(pos.pageX, pos.pageY); - } else { - $tooltip.remove(); - } - }); - - } - }; - }); - -}); \ No newline at end of file diff --git a/src/app/panels/trends/editor.html b/src/app/panels/trends/editor.html deleted file mode 100644 index 85f6517f8fb..00000000000 --- a/src/app/panels/trends/editor.html +++ /dev/null @@ -1,20 +0,0 @@ -
-

Settings

-
-
- -
-
- - -
-
- - -
-
- - -
-
-
diff --git a/src/app/panels/trends/module.html b/src/app/panels/trends/module.html deleted file mode 100644 index 8b2fe384ca9..00000000000 --- a/src/app/panels/trends/module.html +++ /dev/null @@ -1,17 +0,0 @@ -
- - - -
- - - {{query.percent}}% - - ({{query.info.alias}}) -
-
\ No newline at end of file diff --git a/src/app/panels/trends/module.js b/src/app/panels/trends/module.js deleted file mode 100644 index 5efe02fb911..00000000000 --- a/src/app/panels/trends/module.js +++ /dev/null @@ -1,251 +0,0 @@ -/** @scratch /panels/5 - * include::panels/trends.asciidoc[] - */ - -/** @scratch /panels/trends/0 - * == trends - * Status: *Beta* - * - * A stock-ticker style representation of how queries are moving over time. For example, if the - * time is 1:10pm, your time picker was set to "Last 10m", and the "Time Ago" parameter was set to - * "1h", the panel would show how much the query results have changed since 12:00-12:10pm - * - */ -define([ - 'angular', - 'app', - 'underscore', - 'kbn' -], -function (angular, app, _, kbn) { - 'use strict'; - - var module = angular.module('kibana.panels.trends', []); - app.useModule(module); - - module.controller('trends', function($scope, kbnIndex, querySrv, dashboard, filterSrv) { - - $scope.panelMeta = { - modals : [ - { - description: "Inspect", - icon: "icon-info-sign", - partial: "app/partials/inspector.html", - show: $scope.panel.spyable - } - ], - editorTabs : [ - {title:'Queries', src:'app/partials/querySelect.html'} - ], - status : "Beta", - description : "A stock-ticker style representation of how queries are moving over time. "+ - "For example, if the time is 1:10pm, your time picker was set to \"Last 10m\", and the \"Time "+ - "Ago\" parameter was set to '1h', the panel would show how much the query results have changed"+ - " since 12:00-12:10pm" - }; - - // Set and populate defaults - var _d = { - /** @scratch /panels/trends/5 - * === Parameters - * - * ago:: A date math formatted string describing the relative time period to compare the - * queries to. - */ - ago : '1d', - /** @scratch /panels/trends/5 - * arrangement:: `horizontal' or `vertical' - */ - arrangement : 'vertical', - /** @scratch /panels/trends/5 - * spyable:: Set to false to disable the inspect icon - */ - spyable: true, - /** @scratch /panels/trends/5 - * ==== Queries - * queries object:: This object describes the queries to use on this panel. - * queries.mode::: Of the queries available, which to use. Options: +all, pinned, unpinned, selected+ - * queries.ids::: In +selected+ mode, which query ids are selected. - */ - queries : { - mode : 'all', - ids : [] - }, - style : { "font-size": '14pt'}, - }; - _.defaults($scope.panel,_d); - - $scope.init = function () { - $scope.hits = 0; - - $scope.$on('refresh', function(){$scope.get_data();}); - - $scope.get_data(); - }; - - $scope.get_data = function(segment,query_id) { - delete $scope.panel.error; - $scope.panelMeta.loading = true; - - // Make sure we have everything for the request to complete - if(dashboard.indices.length === 0) { - return; - } else { - $scope.index = segment > 0 ? $scope.index : dashboard.indices; - } - - // Determine a time field - var timeField = _.uniq(_.pluck(filterSrv.getByType('time'),'field')); - if(timeField.length > 1) { - $scope.panel.error = "Time field must be consistent amongst time filters"; - return; - } else if(timeField.length === 0) { - $scope.panel.error = "A time filter must exist for this panel to function"; - return; - } else { - timeField = timeField[0]; - } - - // This logic can be simplifie greatly with the new kbn.parseDate - $scope.time = filterSrv.timeRange('last'); - $scope.old_time = { - from : new Date($scope.time.from.getTime() - kbn.interval_to_ms($scope.panel.ago)), - to : new Date($scope.time.to.getTime() - kbn.interval_to_ms($scope.panel.ago)) - }; - - var _segment = _.isUndefined(segment) ? 0 : segment; - var request = $scope.ejs.Request(); - var _ids_without_time = _.difference(filterSrv.ids,filterSrv.idsByType('time')); - - $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries); - var queries = querySrv.getQueryObjs($scope.panel.queries.ids); - - // Build the question part of the query - _.each(queries, function(query) { - var q = $scope.ejs.FilteredQuery( - querySrv.toEjsObj(query), - filterSrv.getBoolFilter(_ids_without_time).must( - $scope.ejs.RangeFilter(timeField) - .from($scope.time.from) - .to($scope.time.to) - )); - - request = request - .facet($scope.ejs.QueryFacet(query.id) - .query(q) - ).size(0); - }); - - - // And again for the old time period - _.each(queries, function(query) { - var q = $scope.ejs.FilteredQuery( - querySrv.toEjsObj(query), - filterSrv.getBoolFilter(_ids_without_time).must( - $scope.ejs.RangeFilter(timeField) - .from($scope.old_time.from) - .to($scope.old_time.to) - )); - request = request - .facet($scope.ejs.QueryFacet("old_"+query.id) - .query(q) - ).size(0); - }); - - - // Populate the inspector panel - $scope.inspector = angular.toJson(JSON.parse(request.toString()),true); - - // If we're on the first segment we need to get our indices - if (_segment === 0) { - kbnIndex.indices( - $scope.old_time.from, - $scope.old_time.to, - dashboard.current.index.pattern, - dashboard.current.index.interval - ).then(function (p) { - $scope.index = _.union(p,$scope.index); - request = request.indices($scope.index[_segment]); - process_results(request.doSearch(),_segment,query_id); - }); - } else { - process_results(request.indices($scope.index[_segment]).doSearch(),_segment,query_id); - } - - }; - - // Populate scope when we have results - var process_results = function(results,_segment,query_id) { - results.then(function(results) { - $scope.panelMeta.loading = false; - if(_segment === 0) { - $scope.hits = {}; - $scope.data = []; - query_id = $scope.query_id = new Date().getTime(); - } - - // Check for error and abort if found - if(!(_.isUndefined(results.error))) { - $scope.panel.error = $scope.parse_error(results.error); - return; - } - - // Make sure we're still on the same query/queries - if($scope.query_id === query_id) { - var i = 0; - var queries = querySrv.getQueryObjs($scope.panel.queries.ids); - - _.each(queries, function(query) { - var n = results.facets[query.id].count; - var o = results.facets['old_'+query.id].count; - - var hits = { - new : _.isUndefined($scope.data[i]) || _segment === 0 ? n : $scope.data[i].hits.new+n, - old : _.isUndefined($scope.data[i]) || _segment === 0 ? o : $scope.data[i].hits.old+o - }; - - $scope.hits.new += n; - $scope.hits.old += o; - - var percent = percentage(hits.old,hits.new) == null ? - '?' : Math.round(percentage(hits.old,hits.new)*100)/100; - // Create series - $scope.data[i] = { - info: query, - hits: { - new : hits.new, - old : hits.old - }, - percent: percent - }; - - i++; - }); - $scope.$emit('render'); - if(_segment < $scope.index.length-1) { - $scope.get_data(_segment+1,query_id); - } else { - $scope.trends = $scope.data; - } - } - }); - }; - - function percentage(x,y) { - return x === 0 ? null : 100*(y-x)/x; - } - - $scope.set_refresh = function (state) { - $scope.refresh = state; - }; - - $scope.close_edit = function() { - if($scope.refresh) { - $scope.get_data(); - } - $scope.refresh = false; - $scope.$emit('render'); - }; - - }); -}); \ No newline at end of file diff --git a/tasks/default_task.js b/tasks/default_task.js index 86bef62326a..c81cf9ba610 100644 --- a/tasks/default_task.js +++ b/tasks/default_task.js @@ -1,4 +1,4 @@ // Lint and build CSS module.exports = function(grunt) { - grunt.registerTask('default', ['jshint:source', 'less:src', 'docs']); + grunt.registerTask('default', ['jshint:source', 'less:src']); }; \ No newline at end of file diff --git a/tasks/docs_task.js b/tasks/docs_task.js deleted file mode 100644 index 2ff68b885dc..00000000000 --- a/tasks/docs_task.js +++ /dev/null @@ -1,4 +0,0 @@ -// Lint and build CSS -module.exports = function(grunt) { - grunt.registerTask('docs', ['clean:docs', 'scratchy:docs']); -}; \ No newline at end of file diff --git a/tasks/options/s3.js b/tasks/options/s3.js deleted file mode 100644 index d41ed57a2e5..00000000000 --- a/tasks/options/s3.js +++ /dev/null @@ -1,34 +0,0 @@ -module.exports = function(config) { - return { - dist: { - bucket: 'download.elasticsearch.org', - access: 'private', - // debug: true, // uncommment to prevent actual upload - upload: [ - { - src: '<%= tempDir %>/<%= pkg.name %>-latest.zip', - dest: 'kibana/kibana/<%= pkg.name %>-latest.zip', - }, - { - src: '<%= tempDir %>/<%= pkg.name %>-latest.tar.gz', - dest: 'kibana/kibana/<%= pkg.name %>-latest.tar.gz', - } - ] - }, - release: { - bucket: 'download.elasticsearch.org', - access: 'private', - // debug: true, // uncommment to prevent actual upload - upload: [ - { - src: '<%= tempDir %>/<%= pkg.name %>-<%= pkg.version %>.zip', - dest: 'kibana/kibana/<%= pkg.name %>-<%= pkg.version %>.zip', - }, - { - src: '<%= tempDir %>/<%= pkg.name %>-<%= pkg.version %>.tar.gz', - dest: 'kibana/kibana/<%= pkg.name %>-<%= pkg.version %>.tar.gz', - } - ] - } - }; -}; \ No newline at end of file diff --git a/tasks/options/scratchy.js b/tasks/options/scratchy.js deleted file mode 100644 index a7f7ad2a486..00000000000 --- a/tasks/options/scratchy.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = function(config) { - return { - docs: { - src: ['src/app/**/*.js','src/config.js'], - dest: config.docsDir+"/kibana", - options: { - unslash: true, - extension: '.asciidoc', - annotate: '// ' - } - } - } -}; \ No newline at end of file