First version
20
.gitignore
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
test/javasource/
|
||||
test/deployment/
|
||||
test/.classpath
|
||||
test/.project
|
||||
test/theme/
|
||||
test/userlib/
|
||||
test/.classpath
|
||||
test/.project
|
||||
*.launch
|
||||
*.tmp
|
||||
*.lock
|
||||
.idea/
|
||||
|
||||
dist/
|
||||
|
||||
node_modules/
|
||||
.editorconfig
|
||||
*DS_Store*
|
||||
.vscode/
|
||||
*.bak
|
||||
23
.jshintrc
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
// Enforcing
|
||||
"curly" : false,
|
||||
"forin" : false,
|
||||
"latedef" : "nofunc",
|
||||
"newcap" : true,
|
||||
"quotmark" : "double",
|
||||
"eqeqeq" : true,
|
||||
"undef" : true,
|
||||
"globals" : {
|
||||
"mendix" : false,
|
||||
"mx" : false,
|
||||
"logger" : false
|
||||
},
|
||||
|
||||
// Relaxing
|
||||
"laxbreak" : true,
|
||||
|
||||
// Environments
|
||||
"browser" : true,
|
||||
"devel" : true,
|
||||
"dojo" : true
|
||||
}
|
||||
223
Gruntfile.js
Normal file
@@ -0,0 +1,223 @@
|
||||
// Generated on 2016-02-12 using generator-mendix 1.3.3 :: git+https://github.com/mendix/generator-mendix.git
|
||||
/*jshint -W069*/
|
||||
/*global module*/
|
||||
"use strict";
|
||||
|
||||
// In case you seem to have trouble starting Mendix through `grunt start-mendix`, you might have to set the path to the Mendix application.
|
||||
// If it works, leave MODELER_PATH at null
|
||||
var MODELER_PATH = null;
|
||||
var MODELER_ARGS = "/file:{path}";
|
||||
|
||||
/********************************************************************************
|
||||
* Do not edit anything below, unless you know what you are doing
|
||||
********************************************************************************/
|
||||
|
||||
var path = require("path"),
|
||||
mendixApp = require("node-mendix-modeler-path"),
|
||||
base64 = require("node-base64-image"),
|
||||
semver = require("semver"),
|
||||
xml2js = require("xml2js"),
|
||||
parser = new xml2js.Parser(),
|
||||
builder = new xml2js.Builder({
|
||||
renderOpts: { pretty: true, indent: " ", newline: "\n" },
|
||||
xmldec: { standalone: null, encoding: "utf-8" }
|
||||
}),
|
||||
shelljs = require("shelljs"),
|
||||
pkg = require("./package.json");
|
||||
|
||||
var TEST_PATH = path.join(shelljs.pwd(), "/test/Test.mpr");
|
||||
var WIDGET_XML = path.join(shelljs.pwd(), "/src/", pkg.name, "/", pkg.name + ".xml");
|
||||
var PACKAGE_XML = path.join(shelljs.pwd(), "/src/package.xml");
|
||||
var TEST_WIDGETS_FOLDER = path.join(shelljs.pwd(), "./test/widgets");
|
||||
var TEST_WIDGETS_DEPLOYMENT_FOLDER = path.join(shelljs.pwd(), "./test/deployment/web/widgets");
|
||||
|
||||
/**
|
||||
* If you want to use a custom folder for the test project, make sure these are added to package.json:
|
||||
* "paths": {
|
||||
* "testProjectFolder": "./test/",
|
||||
* "testProjectFileName": "Test.mpr"
|
||||
* },
|
||||
* You can test it by running: `grunt folders`
|
||||
**/
|
||||
|
||||
if (pkg.paths && pkg.paths.testProjectFolder && pkg.paths.testProjectFileName) {
|
||||
var folder = pkg.paths.testProjectFolder;
|
||||
if (folder.indexOf(".") === 0) {
|
||||
folder = path.join(shelljs.pwd(), folder);
|
||||
}
|
||||
TEST_PATH = path.join(folder, pkg.paths.testProjectFileName);
|
||||
TEST_WIDGETS_FOLDER = path.join(folder, "/widgets");
|
||||
TEST_WIDGETS_DEPLOYMENT_FOLDER = path.join(folder, "/deployment/web/widgets");
|
||||
}
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.initConfig({
|
||||
watch: {
|
||||
autoDeployUpdate: {
|
||||
"files": [ "./src/**/*" ],
|
||||
"tasks": [ "compress", "newer:copy" ],
|
||||
options: {
|
||||
debounceDelay: 250,
|
||||
livereload: true
|
||||
}
|
||||
}
|
||||
},
|
||||
compress: {
|
||||
makezip: {
|
||||
options: {
|
||||
archive: "./dist/" + pkg.name + ".mpk",
|
||||
mode: "zip"
|
||||
},
|
||||
files: [{
|
||||
expand: true,
|
||||
date: new Date(),
|
||||
store: false,
|
||||
cwd: "./src",
|
||||
src: ["**/*"]
|
||||
}]
|
||||
}
|
||||
},
|
||||
copy: {
|
||||
deployment: {
|
||||
files: [
|
||||
{ dest: TEST_WIDGETS_DEPLOYMENT_FOLDER, cwd: "./src/", src: ["**/*"], expand: true }
|
||||
]
|
||||
},
|
||||
mpks: {
|
||||
files: [
|
||||
{ dest: TEST_WIDGETS_FOLDER, cwd: "./dist/", src: [ pkg.name + ".mpk"], expand: true }
|
||||
]
|
||||
}
|
||||
},
|
||||
clean: {
|
||||
build: [
|
||||
path.join(shelljs.pwd(), "dist", pkg.name, "/*")
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks("grunt-contrib-compress");
|
||||
grunt.loadNpmTasks("grunt-contrib-clean");
|
||||
grunt.loadNpmTasks("grunt-contrib-watch");
|
||||
grunt.loadNpmTasks("grunt-contrib-copy");
|
||||
grunt.loadNpmTasks("grunt-newer");
|
||||
|
||||
grunt.registerTask("start-modeler", function () {
|
||||
var done = this.async();
|
||||
if (MODELER_PATH !== null || (mendixApp.err === null && mendixApp.output !== null && mendixApp.output.cmd && mendixApp.output.arg)) {
|
||||
grunt.util.spawn({
|
||||
cmd: MODELER_PATH || mendixApp.output.cmd,
|
||||
args: [
|
||||
(MODELER_PATH !== null ? MODELER_ARGS : mendixApp.output.arg).replace("{path}", TEST_PATH)
|
||||
]
|
||||
}, function () {
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
console.error("Cannot start Modeler, see error:");
|
||||
console.log(mendixApp.err);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask("version", function (version) {
|
||||
var done = this.async();
|
||||
if (!grunt.file.exists(PACKAGE_XML)) {
|
||||
grunt.log.error("Cannot find " + PACKAGE_XML);
|
||||
return done();
|
||||
}
|
||||
|
||||
var xml = grunt.file.read(PACKAGE_XML);
|
||||
parser.parseString(xml, function (err, res) {
|
||||
if (err) {
|
||||
grunt.log.error(err);
|
||||
return done();
|
||||
}
|
||||
if (res.package.clientModule[0]["$"]["version"]) {
|
||||
var currentVersion = res.package.clientModule[0]["$"]["version"];
|
||||
if (!version) {
|
||||
grunt.log.writeln("\nCurrent version is " + currentVersion);
|
||||
grunt.log.writeln("Set new version by running 'grunt version:x.y.z'");
|
||||
done();
|
||||
} else {
|
||||
if (!semver.valid(version) || !semver.satisfies(version, ">= 1.0.0")) {
|
||||
grunt.log.error("\nPlease provide a valid version that is higher than 1.0.0. Current version: " + currentVersion);
|
||||
done();
|
||||
} else {
|
||||
res.package.clientModule[0]["$"]["version"] = version;
|
||||
pkg.version = version;
|
||||
var xmlString = builder.buildObject(res);
|
||||
grunt.file.write(PACKAGE_XML, xmlString);
|
||||
grunt.file.write("package.json", JSON.stringify(pkg, null, 2));
|
||||
done();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
grunt.log.error("Cannot find current version number");
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
grunt.registerTask("generate-icon", function () {
|
||||
var iconPath = path.join(shelljs.pwd(), "/icon.png"),
|
||||
options = {localFile: true, string: true},
|
||||
done = this.async();
|
||||
|
||||
grunt.log.writeln("Processing icon");
|
||||
|
||||
if (!grunt.file.exists(iconPath) || !grunt.file.exists(WIDGET_XML)) {
|
||||
grunt.log.error("can\'t generate icon");
|
||||
return done();
|
||||
}
|
||||
|
||||
base64.base64encoder(iconPath, options, function (err, image) {
|
||||
if (!err) {
|
||||
var xmlOld = grunt.file.read(WIDGET_XML);
|
||||
parser.parseString(xmlOld, function (err, result) {
|
||||
if (!err) {
|
||||
if (result && result.widget && result.widget.icon) {
|
||||
result.widget.icon[0] = image;
|
||||
}
|
||||
var xmlString = builder.buildObject(result);
|
||||
grunt.file.write(WIDGET_XML, xmlString);
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
grunt.log.error("can\'t generate icon");
|
||||
return done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
grunt.registerTask("folders", function () {
|
||||
var done = this.async();
|
||||
grunt.log.writeln("\nShowing file paths that Grunt will use. You can edit the package.json accordingly\n");
|
||||
grunt.log.writeln("TEST_PATH: ", TEST_PATH);
|
||||
grunt.log.writeln("WIDGET_XML: ", WIDGET_XML);
|
||||
grunt.log.writeln("PACKAGE_XML: ", PACKAGE_XML);
|
||||
grunt.log.writeln("TEST_WIDGETS_FOLDER: ", TEST_WIDGETS_FOLDER);
|
||||
grunt.log.writeln("TEST_WIDGETS_DEPLOYMENT_FOLDER: ", TEST_WIDGETS_DEPLOYMENT_FOLDER);
|
||||
return done();
|
||||
});
|
||||
|
||||
grunt.registerTask("start-mendix", [ "start-modeler" ]);
|
||||
|
||||
grunt.registerTask(
|
||||
"default",
|
||||
"Watches for changes and automatically creates an MPK file, as well as copying the changes to your deployment folder",
|
||||
[ "watch" ]
|
||||
);
|
||||
|
||||
grunt.registerTask(
|
||||
"clean build",
|
||||
"Compiles all the assets and copies the files to the build directory.",
|
||||
[ "clean", "compress", "copy" ]
|
||||
);
|
||||
|
||||
grunt.registerTask(
|
||||
"build",
|
||||
[ "clean build" ]
|
||||
);
|
||||
};
|
||||
202
LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
134
README.md
Normal file
@@ -0,0 +1,134 @@
|
||||
#OpenLayers Maps Widget
|
||||
|
||||
Add different type of maps to your application, using [Leaflet.js](http://leafletjs.com/)! This widget is almost the same as the GoogleMaps widget, without the typical interaction you have in Google Maps, but with a wide variety of maps available.
|
||||
|
||||
##Typical usage scenario
|
||||
|
||||
Showing an overview where all your branches/members/clients/orders/etc. are.
|
||||
|
||||
##Features and limitations
|
||||
|
||||
Easy to implement. Can use both a context object as well as without.
|
||||
|
||||
The maptypes come from a separate Leaflet plugin: [Leaflet-providers](https://github.com/leaflet-extras/leaflet-providers).
|
||||
|
||||
A preview of the various map types can be seen [here](http://leaflet-extras.github.io/leaflet-providers/preview/).
|
||||
|
||||
Note that some of the map types have been disabled in this widget (you will see more examples in the previous link). This is because:
|
||||
* They are too localized (limited to a certain region)
|
||||
* Need extra configuration (HERE and MapBox need API keys, not implemented yet)
|
||||
* Are not very functional yet (is an overlay instead of a full map. Overlays might be enabled in the future)
|
||||
|
||||
We will be adding more maps in the future. This is the current list of map providers:
|
||||
|
||||
```
|
||||
Providers:
|
||||
OpenStreetMap
|
||||
.Mapnik (this is the default map)
|
||||
.BlackAndWhite
|
||||
.DE
|
||||
.France
|
||||
.HOT
|
||||
OpenTopoMap
|
||||
Thunderforest
|
||||
.OpenCycleMap
|
||||
.Transport
|
||||
.TransportDark
|
||||
.SpinalMap
|
||||
.Landscape
|
||||
.Outdoors
|
||||
.Pioneer
|
||||
MapQuestOpen
|
||||
.OSM
|
||||
.Aerial
|
||||
.HybridOverlay
|
||||
Stamen
|
||||
.Toner
|
||||
.TonerBackground
|
||||
.TonerHybrid
|
||||
.TonerLines
|
||||
.TonerLabels
|
||||
.TonerLite
|
||||
.Watercolor
|
||||
Esri
|
||||
.WorldStreetMap
|
||||
.DeLorme
|
||||
.WorldTopoMap
|
||||
.WorldImagery
|
||||
.WorldTerrain
|
||||
.WorldShadedRelief
|
||||
.WorldPhysical
|
||||
.OceanBasemap
|
||||
.NatGeoWorldMap
|
||||
.WorldGrayCanvas
|
||||
```
|
||||
|
||||
##Dependencies
|
||||
Mendix 5.18 or higher.
|
||||
|
||||
##Configuration
|
||||
|
||||
There are 3 use-cases for which this widget can be used.
|
||||
|
||||
Outside a dataview: Will just retrieve the objects specified and show them on the map.
|
||||
Inside a dataview not matching the Objects property: Will show the objects specified, can use '[%CurrentObject%]' in XPath Constraint.
|
||||
Inside a dataview matching the Objects property: Will show the objects specified, can NOT use '[%CurrentObject%]'. Can set up the dataview to listen to a matching datagrid. If 'Pan to context' is set to true, it will focus on the marker of the object that is selected in the datagrid.
|
||||
|
||||
To finish up, just enter the correct values into the widget. For more information on the different input properties, read below.
|
||||
|
||||
##Properties
|
||||
|
||||
####Behaviour
|
||||
* Pan to context: Set this only to true if your object containing the address matches your dataview. With this you can have your dataview listen to a datagrid of your Users objects containing the addresses and it will jump to the matching marker on the map.
|
||||
* Default latitude: The default latitude the map should use when no objects are found or there is no object found (when using an XPath with CurrentObject)
|
||||
* Default longitude: The default longitude the map should use when no objects are found or there is no object found (when using an XPath with CurrentObject)
|
||||
* Single item zoom level: The zoom level to be used when showing a single item or the default location. Level 1 shows the entire globe, 15 is city level and 20 is house level.
|
||||
* Refresh on entity changes: When set to true, the map refreshes on any changes to the mapped entity (and/or 1-deep entity). This includes on create/delete/change. Do note that it simply reloads the entire map, so this is not recommended when mapping a lot of objects.
|
||||
|
||||
####Data Source
|
||||
* Objects: The widget retrieves its own objects based on the entity specified here.
|
||||
* XPath constraint: The XPath constraint to be used for retrieving the objects. Important: Even though the Modeler lets you, you can't use '[%CurrentObject%]' if your dataview entity matches the entity of the objects you are retrieving. Doing so will result in an error.
|
||||
* Marker attribute: The attribute that contains the text to display in the info window at the location. No info window will be shown if this is left empty. Tip: The window displays HTML, you can use the Rich Text Editor widget to create your styled text and have it saved as HTML. This can then be directly used for the info window! This can be 1-deep association.
|
||||
* Latitude attribute: The attribute containing the latitudes of the objects. This can be 1-deep association.
|
||||
* Longitude attribute: The attribute containing the longitudes of the objects. This can be 1-deep association.
|
||||
* On click microflow: Microflow to be executed when clicking on a marker. The Microflow will have the corresponding object as an input parameter
|
||||
|
||||
####Appearance
|
||||
* Height: The height the widget will have (in pixels) . This attribute is required.
|
||||
* Width: The width of the widget, can be in pixels or percentage.
|
||||
* Marker template: If you set the Marker attribute in Data Source, you can control the html that is used inside the popup that is shown when clicking a marker
|
||||
|
||||
####Map Type
|
||||
* Maptype: Map type, see features
|
||||
* Use custom map type: If you want to use your own map type, set this to 'Yes'
|
||||
* Custom Map Url: Set the URL for the custom map type*
|
||||
* Custom Map Options: Set extra options for the custom map type. Make sure this is a valid JSON object. Open with ``{`` and close with ``}``. The keys and values need to be strings, so surrounded by double quotes ``"key":"value"``*
|
||||
|
||||
> **More information about the Custom Map Url and the Custom Map Options can be found on the [Leaflet Reference](http://leafletjs.com/reference.html#tilelayer).**
|
||||
|
||||
####Controls
|
||||
* Mouse dragging: Enable/disable dragging the map using the mouse
|
||||
* Touch zoom: Enable/disable zooming by touch-dragging two fingers (mobile)
|
||||
* Mouse scrolling: Enable/disable scrolling by using the mouse wheel
|
||||
* Zoom control: Enable/disable zoom control (+/- buttons on the map)
|
||||
* Zoom control position: Position of the zoomcontrol on the map
|
||||
* Attribution control: Enable/disable attribution control (credits that are shown on the bottom right of the map)
|
||||
* Attribution control position: Position of the attribution on the map
|
||||
* Fullscreen control: Enable/disable fullscreen button
|
||||
|
||||
####Location
|
||||
* Add geolocation button: This will add a button that you can use to find your location
|
||||
* Geolocation control position: Position of the geolocation button on the map
|
||||
* Draw an uncertainty circle: Draw a circle around the location, indicating how big the uncertainty is
|
||||
* Keep zoom level: When locating, keep the current zoom level. If this is set to false, it will use the maximimum zoom level
|
||||
|
||||
####Scale
|
||||
* Add scale: Add a scale indicator on the map
|
||||
* Scale position
|
||||
* Show metric scale line (m/km)
|
||||
* Show imperial scale line (mi/ft)
|
||||
* Max width (in pixels, dynamically rounded)
|
||||
|
||||
##Troubleshooting
|
||||
|
||||
* If your map does not load on Cloud deployment, it usually means it tries to download map files from a HTTP source, instead of HTTPS. This is usually blocked. If that happens, please report this as an issue, so we can disable the map type. If you use a custom Map Type, make sure the URL starts with ``https://`` or ``//``.
|
||||
BIN
assets/app_store_banner.png
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
assets/app_store_icon.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/icon.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
33
package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "Leaflet",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"license": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"grunt": "0.4.5",
|
||||
"grunt-contrib-clean": "^0.6.0",
|
||||
"grunt-contrib-compress": "^0.14.0",
|
||||
"grunt-contrib-copy": "^0.8.2",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-newer": "^1.1.1",
|
||||
"node-base64-image": "^0.1.0",
|
||||
"shelljs": "^0.5.3",
|
||||
"xml2js": "^0.4.15",
|
||||
"semver": "^5.1.0",
|
||||
"node-mendix-modeler-path": "https://github.com/JelteMX/node-mendix-modeler-path/archive/v1.0.0.tar.gz"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
},
|
||||
"generatorVersion": "1.3.3",
|
||||
"paths": {
|
||||
"testProjectFolder": "./test/",
|
||||
"testProjectFileName": "Test.mpr"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
}
|
||||
}
|
||||
301
src/Leaflet/Leaflet.xml
Normal file
197
src/Leaflet/lib/leaflet-fullscreen.js
Normal file
@@ -0,0 +1,197 @@
|
||||
// Source: https://github.com/brunob/leaflet.fullscreen/blob/master/Control.FullScreen.js
|
||||
|
||||
/*
|
||||
Edited by J.W. Lagendijk <jelte.lagendijk@mendix.com> to make sure it works within the Mendix environment
|
||||
*/
|
||||
|
||||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['Leaflet/lib/leaflet-src'], factory);
|
||||
} else if (typeof modules === 'object' && module.exports) {
|
||||
// define a Common JS module that relies on 'leaflet'
|
||||
module.exports = factory(require('leaflet'));
|
||||
} else {
|
||||
// Assume Leaflet is loaded into global object L already
|
||||
factory(L);
|
||||
}
|
||||
}(this, function (L) {
|
||||
'use strict';
|
||||
|
||||
L.Control.FullScreen = L.Control.extend({
|
||||
options: {
|
||||
position: 'topleft',
|
||||
title: 'Full Screen',
|
||||
titleCancel: 'Exit Full Screen',
|
||||
forceSeparateButton: false,
|
||||
forcePseudoFullscreen: false
|
||||
},
|
||||
|
||||
onAdd: function(map) {
|
||||
var className = 'leaflet-control-zoom-fullscreen',
|
||||
container, content = '';
|
||||
|
||||
if (map.zoomControl && !this.options.forceSeparateButton) {
|
||||
container = map.zoomControl._container;
|
||||
} else {
|
||||
container = L.DomUtil.create('div', 'leaflet-bar');
|
||||
}
|
||||
|
||||
if (this.options.content) {
|
||||
content = this.options.content;
|
||||
} else {
|
||||
className += ' fullscreen-icon';
|
||||
}
|
||||
|
||||
this._createButton(this.options.title, className, content, container, this.toggleFullScreen, this);
|
||||
|
||||
this._map.on('enterFullscreen exitFullscreen', this._toggleTitle, this);
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
_createButton: function(title, className, content, container, fn, context) {
|
||||
this.link = L.DomUtil.create('a', className, container);
|
||||
this.link.href = '#';
|
||||
this.link.title = title;
|
||||
this.link.innerHTML = content;
|
||||
|
||||
L.DomEvent.addListener(this.link, 'click', L.DomEvent.stopPropagation)
|
||||
.addListener(this.link, 'click', L.DomEvent.preventDefault)
|
||||
.addListener(this.link, 'click', fn, context);
|
||||
|
||||
L.DomEvent.addListener(container, fullScreenApi.fullScreenEventName, L.DomEvent.stopPropagation)
|
||||
.addListener(container, fullScreenApi.fullScreenEventName, L.DomEvent.preventDefault)
|
||||
.addListener(container, fullScreenApi.fullScreenEventName, this._handleEscKey, context);
|
||||
|
||||
L.DomEvent.addListener(document, fullScreenApi.fullScreenEventName, L.DomEvent.stopPropagation)
|
||||
.addListener(document, fullScreenApi.fullScreenEventName, L.DomEvent.preventDefault)
|
||||
.addListener(document, fullScreenApi.fullScreenEventName, this._handleEscKey, context);
|
||||
|
||||
return this.link;
|
||||
},
|
||||
|
||||
toggleFullScreen: function() {
|
||||
var map = this._map;
|
||||
map._exitFired = false;
|
||||
if (map._isFullscreen) {
|
||||
if (fullScreenApi.supportsFullScreen && !this.options.forcePseudoFullscreen) {
|
||||
fullScreenApi.cancelFullScreen(map._container);
|
||||
} else {
|
||||
L.DomUtil.removeClass(map._container, 'leaflet-pseudo-fullscreen');
|
||||
}
|
||||
map.invalidateSize();
|
||||
map.fire('exitFullscreen');
|
||||
map._exitFired = true;
|
||||
map._isFullscreen = false;
|
||||
} else {
|
||||
if (fullScreenApi.supportsFullScreen && !this.options.forcePseudoFullscreen) {
|
||||
fullScreenApi.requestFullScreen(map._container);
|
||||
} else {
|
||||
L.DomUtil.addClass(map._container, 'leaflet-pseudo-fullscreen');
|
||||
}
|
||||
map.invalidateSize();
|
||||
map.fire('enterFullscreen');
|
||||
map._isFullscreen = true;
|
||||
}
|
||||
},
|
||||
|
||||
_toggleTitle: function() {
|
||||
this.link.title = this._map._isFullscreen ? this.options.title : this.options.titleCancel;
|
||||
},
|
||||
|
||||
_handleEscKey: function() {
|
||||
var map = this._map;
|
||||
if (!fullScreenApi.isFullScreen(map) && !map._exitFired) {
|
||||
map.fire('exitFullscreen');
|
||||
map._exitFired = true;
|
||||
map._isFullscreen = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.addInitHook(function() {
|
||||
if (this.options.fullscreenControl) {
|
||||
this.fullscreenControl = L.control.fullscreen(this.options.fullscreenControlOptions);
|
||||
this.addControl(this.fullscreenControl);
|
||||
}
|
||||
});
|
||||
|
||||
L.control.fullscreen = function(options) {
|
||||
return new L.Control.FullScreen(options);
|
||||
};
|
||||
|
||||
/*
|
||||
Native FullScreen JavaScript API
|
||||
-------------
|
||||
Assumes Mozilla naming conventions instead of W3C for now
|
||||
|
||||
source : http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/
|
||||
|
||||
*/
|
||||
|
||||
var
|
||||
fullScreenApi = {
|
||||
supportsFullScreen: false,
|
||||
isFullScreen: function() {
|
||||
return false;
|
||||
},
|
||||
requestFullScreen: function() {},
|
||||
cancelFullScreen: function() {},
|
||||
fullScreenEventName: '',
|
||||
prefix: ''
|
||||
},
|
||||
browserPrefixes = 'webkit moz o ms khtml'.split(' ');
|
||||
|
||||
// check for native support
|
||||
if (typeof document.exitFullscreen !== 'undefined') {
|
||||
fullScreenApi.supportsFullScreen = true;
|
||||
} else {
|
||||
// check for fullscreen support by vendor prefix
|
||||
for (var i = 0, il = browserPrefixes.length; i < il; i++) {
|
||||
fullScreenApi.prefix = browserPrefixes[i];
|
||||
if (typeof document[fullScreenApi.prefix + 'CancelFullScreen'] !== 'undefined') {
|
||||
fullScreenApi.supportsFullScreen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update methods to do something useful
|
||||
if (fullScreenApi.supportsFullScreen) {
|
||||
fullScreenApi.fullScreenEventName = fullScreenApi.prefix + 'fullscreenchange';
|
||||
fullScreenApi.isFullScreen = function() {
|
||||
switch (this.prefix) {
|
||||
case '':
|
||||
return document.fullScreen;
|
||||
case 'webkit':
|
||||
return document.webkitIsFullScreen;
|
||||
default:
|
||||
return document[this.prefix + 'FullScreen'];
|
||||
}
|
||||
};
|
||||
fullScreenApi.requestFullScreen = function(el) {
|
||||
return (this.prefix === '') ? el.requestFullscreen() : el[this.prefix + 'RequestFullScreen']();
|
||||
};
|
||||
fullScreenApi.cancelFullScreen = function() {
|
||||
return (this.prefix === '') ? document.exitFullscreen() : document[this.prefix + 'CancelFullScreen']();
|
||||
};
|
||||
}
|
||||
|
||||
// jQuery plugin
|
||||
if (typeof jQuery !== 'undefined') {
|
||||
jQuery.fn.requestFullScreen = function() {
|
||||
return this.each(function() {
|
||||
var el = jQuery(this);
|
||||
if (fullScreenApi.supportsFullScreen) {
|
||||
fullScreenApi.requestFullScreen(el);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// export api
|
||||
window.fullScreenApi = fullScreenApi;
|
||||
|
||||
return L;
|
||||
}));
|
||||
504
src/Leaflet/lib/leaflet-locatecontrol.js
Normal file
@@ -0,0 +1,504 @@
|
||||
/*!
|
||||
Copyright (c) 2016 Dominik Moritz
|
||||
|
||||
This file is part of the leaflet locate control. It is licensed under the MIT license.
|
||||
You can find the project at: https://github.com/domoritz/leaflet-locatecontrol
|
||||
*/
|
||||
(function (factory, window) {
|
||||
// see https://github.com/Leaflet/Leaflet/blob/master/PLUGIN-GUIDE.md#module-loaders
|
||||
// for details on how to structure a leaflet plugin.
|
||||
|
||||
// define an AMD module that relies on 'leaflet'
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(['Leaflet/lib/leaflet-src'], factory);
|
||||
|
||||
// define a Common JS module that relies on 'leaflet'
|
||||
} else if (typeof exports === 'object') {
|
||||
if (typeof window !== 'undefined' && window.L) {
|
||||
module.exports = factory(L);
|
||||
} else {
|
||||
module.exports = factory(require('leaflet'));
|
||||
}
|
||||
}
|
||||
|
||||
// attach your plugin to the global 'L' variable
|
||||
if(typeof window !== 'undefined' && window.L){
|
||||
window.L.Locate = factory(L);
|
||||
}
|
||||
|
||||
} (function (L) {
|
||||
L.Control.Locate = L.Control.extend({
|
||||
options: {
|
||||
position: 'topleft',
|
||||
layer: undefined, // use your own layer for the location marker
|
||||
drawCircle: true,
|
||||
follow: false, // follow with zoom and pan the user's location
|
||||
stopFollowingOnDrag: false, // if follow is true, stop following when map is dragged (deprecated)
|
||||
// if true locate control remains active on click even if the user's location is in view.
|
||||
// clicking control will just pan to location
|
||||
remainActive: false,
|
||||
markerClass: L.circleMarker, // L.circleMarker or L.marker
|
||||
// range circle
|
||||
circleStyle: {
|
||||
color: '#136AEC',
|
||||
fillColor: '#136AEC',
|
||||
fillOpacity: 0.15,
|
||||
weight: 2,
|
||||
opacity: 0.5
|
||||
},
|
||||
// inner marker
|
||||
markerStyle: {
|
||||
color: '#136AEC',
|
||||
fillColor: '#2A93EE',
|
||||
fillOpacity: 0.7,
|
||||
weight: 2,
|
||||
opacity: 0.9,
|
||||
radius: 5
|
||||
},
|
||||
// changes to range circle and inner marker while following
|
||||
// it is only necessary to provide the things that should change
|
||||
followCircleStyle: {},
|
||||
followMarkerStyle: {
|
||||
//color: '#FFA500',
|
||||
//fillColor: '#FFB000'
|
||||
},
|
||||
icon: 'fa fa-map-marker', // fa-location-arrow or fa-map-marker
|
||||
iconLoading: 'fa fa-spinner fa-spin',
|
||||
iconElementTag: 'span', // span or i
|
||||
circlePadding: [0, 0],
|
||||
metric: true,
|
||||
onLocationError: function(err) {
|
||||
// this event is called in case of any location error
|
||||
// that is not a time out error.
|
||||
alert(err.message);
|
||||
},
|
||||
onLocationOutsideMapBounds: function(control) {
|
||||
// this event is repeatedly called when the location changes
|
||||
control.stop();
|
||||
alert(control.options.strings.outsideMapBoundsMsg);
|
||||
},
|
||||
setView: true, // automatically sets the map view to the user's location
|
||||
// keep the current map zoom level when displaying the user's location. (if 'false', use maxZoom)
|
||||
keepCurrentZoomLevel: false,
|
||||
showPopup: true, // display a popup when the user click on the inner marker
|
||||
strings: {
|
||||
title: "Show me where I am",
|
||||
metersUnit: "meters",
|
||||
feetUnit: "feet",
|
||||
popup: "You are within {distance} {unit} from this point",
|
||||
outsideMapBoundsMsg: "You seem located outside the boundaries of the map"
|
||||
},
|
||||
locateOptions: {
|
||||
maxZoom: Infinity,
|
||||
watch: true // if you overwrite this, visualization cannot be updated
|
||||
}
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
L.Map.addInitHook(function () {
|
||||
if (this.options.locateControl) {
|
||||
this.addControl(this);
|
||||
}
|
||||
});
|
||||
|
||||
for (var i in options) {
|
||||
if (typeof this.options[i] === 'object') {
|
||||
L.extend(this.options[i], options[i]);
|
||||
} else {
|
||||
this.options[i] = options[i];
|
||||
}
|
||||
}
|
||||
|
||||
L.extend(this.options.locateOptions, {
|
||||
setView: false // have to set this to false because we have to
|
||||
// do setView manually
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* This method launches the location engine.
|
||||
* It is called before the marker is updated,
|
||||
* event if it does not mean that the event will be ready.
|
||||
*
|
||||
* Override it if you want to add more functionalities.
|
||||
* It should set the this._active to true and do nothing if
|
||||
* this._active is not true.
|
||||
*/
|
||||
_activate: function() {
|
||||
if (this.options.setView) {
|
||||
this._locateOnNextLocationFound = true;
|
||||
}
|
||||
|
||||
if(!this._active) {
|
||||
this._map.locate(this.options.locateOptions);
|
||||
}
|
||||
this._active = true;
|
||||
|
||||
if (this.options.follow) {
|
||||
this._startFollowing(this._map);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called to stop the location engine.
|
||||
*
|
||||
* Override it to shutdown any functionalities you added on start.
|
||||
*/
|
||||
_deactivate: function() {
|
||||
this._map.stopLocate();
|
||||
|
||||
this._map.off('dragstart', this._stopFollowing, this);
|
||||
if (this.options.follow && this._following) {
|
||||
this._stopFollowing(this._map);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Draw the resulting marker on the map.
|
||||
*
|
||||
* Uses the event retrieved from onLocationFound from the map.
|
||||
*/
|
||||
drawMarker: function(map) {
|
||||
if (this._event.accuracy === undefined) {
|
||||
this._event.accuracy = 0;
|
||||
}
|
||||
|
||||
var radius = this._event.accuracy;
|
||||
if (this._locateOnNextLocationFound) {
|
||||
if (this._isOutsideMapBounds()) {
|
||||
this.options.onLocationOutsideMapBounds(this);
|
||||
} else {
|
||||
// If accuracy info isn't desired, keep the current zoom level
|
||||
if(this.options.keepCurrentZoomLevel) {
|
||||
map.panTo([this._event.latitude, this._event.longitude]);
|
||||
} else {
|
||||
map.fitBounds(this._event.bounds, {
|
||||
padding: this.options.circlePadding,
|
||||
maxZoom: this.options.keepCurrentZoomLevel ?
|
||||
map.getZoom() : this.options.locateOptions.maxZoom
|
||||
});
|
||||
}
|
||||
}
|
||||
this._locateOnNextLocationFound = false;
|
||||
}
|
||||
|
||||
// circle with the radius of the location's accuracy
|
||||
var style, o;
|
||||
if (this.options.drawCircle) {
|
||||
if (this._following) {
|
||||
style = this.options.followCircleStyle;
|
||||
} else {
|
||||
style = this.options.circleStyle;
|
||||
}
|
||||
|
||||
if (!this._circle) {
|
||||
this._circle = L.circle(this._event.latlng, radius, style)
|
||||
.addTo(this._layer);
|
||||
} else {
|
||||
this._circle.setLatLng(this._event.latlng).setRadius(radius);
|
||||
for (o in style) {
|
||||
this._circle.options[o] = style[o];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var distance, unit;
|
||||
if (this.options.metric) {
|
||||
distance = radius.toFixed(0);
|
||||
unit = this.options.strings.metersUnit;
|
||||
} else {
|
||||
distance = (radius * 3.2808399).toFixed(0);
|
||||
unit = this.options.strings.feetUnit;
|
||||
}
|
||||
|
||||
// small inner marker
|
||||
var mStyle;
|
||||
if (this._following) {
|
||||
mStyle = this.options.followMarkerStyle;
|
||||
} else {
|
||||
mStyle = this.options.markerStyle;
|
||||
}
|
||||
|
||||
if (!this._marker) {
|
||||
this._marker = this.createMarker(this._event.latlng, mStyle)
|
||||
.addTo(this._layer);
|
||||
} else {
|
||||
this.updateMarker(this._event.latlng, mStyle);
|
||||
}
|
||||
|
||||
var t = this.options.strings.popup;
|
||||
if (this.options.showPopup && t) {
|
||||
this._marker.bindPopup(L.Util.template(t, {distance: distance, unit: unit}))
|
||||
._popup.setLatLng(this._event.latlng);
|
||||
}
|
||||
|
||||
this._toggleContainerStyle();
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the marker.
|
||||
*
|
||||
* Should return the base marker so it is possible to bind a pop-up if the
|
||||
* option is activated.
|
||||
*
|
||||
* Used by drawMarker, you can ignore it if you have overridden it.
|
||||
*/
|
||||
createMarker: function(latlng, mStyle) {
|
||||
return this.options.markerClass(latlng, mStyle);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the marker with current coordinates.
|
||||
*
|
||||
* Used by drawMarker, you can ignore it if you have overridden it.
|
||||
*/
|
||||
updateMarker: function(latlng, mStyle) {
|
||||
this._marker.setLatLng(latlng);
|
||||
for (var o in mStyle) {
|
||||
this._marker.options[o] = mStyle[o];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the marker from map.
|
||||
*/
|
||||
removeMarker: function() {
|
||||
this._layer.clearLayers();
|
||||
this._marker = undefined;
|
||||
this._circle = undefined;
|
||||
},
|
||||
|
||||
onAdd: function (map) {
|
||||
var container = L.DomUtil.create('div',
|
||||
'leaflet-control-locate leaflet-bar leaflet-control');
|
||||
|
||||
this._layer = this.options.layer || new L.LayerGroup();
|
||||
this._layer.addTo(map);
|
||||
this._event = undefined;
|
||||
|
||||
// extend the follow marker style and circle from the normal style
|
||||
var tmp = {};
|
||||
L.extend(tmp, this.options.markerStyle, this.options.followMarkerStyle);
|
||||
this.options.followMarkerStyle = tmp;
|
||||
tmp = {};
|
||||
L.extend(tmp, this.options.circleStyle, this.options.followCircleStyle);
|
||||
this.options.followCircleStyle = tmp;
|
||||
|
||||
this._link = L.DomUtil.create('a', 'leaflet-bar-part leaflet-bar-part-single', container);
|
||||
this._link.href = '#';
|
||||
this._link.title = this.options.strings.title;
|
||||
this._icon = L.DomUtil.create(this.options.iconElementTag, this.options.icon, this._link);
|
||||
|
||||
L.DomEvent
|
||||
.on(this._link, 'click', L.DomEvent.stopPropagation)
|
||||
.on(this._link, 'click', L.DomEvent.preventDefault)
|
||||
.on(this._link, 'click', function() {
|
||||
var shouldStop = (this._event === undefined ||
|
||||
this._map.getBounds().contains(this._event.latlng) ||
|
||||
!this.options.setView || this._isOutsideMapBounds());
|
||||
if (!this.options.remainActive && (this._active && shouldStop)) {
|
||||
this.stop();
|
||||
} else {
|
||||
this.start();
|
||||
}
|
||||
}, this)
|
||||
.on(this._link, 'dblclick', L.DomEvent.stopPropagation);
|
||||
|
||||
this._resetVariables();
|
||||
this.bindEvents(map);
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Binds the actions to the map events.
|
||||
*/
|
||||
bindEvents: function(map) {
|
||||
map.on('locationfound', this._onLocationFound, this);
|
||||
map.on('locationerror', this._onLocationError, this);
|
||||
map.on('unload', this.stop, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts the plugin:
|
||||
* - activates the engine
|
||||
* - draws the marker (if coordinates available)
|
||||
*/
|
||||
start: function() {
|
||||
this._activate();
|
||||
|
||||
if (!this._event) {
|
||||
this._setClasses('requesting');
|
||||
} else {
|
||||
this.drawMarker(this._map);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Stops the plugin:
|
||||
* - deactivates the engine
|
||||
* - reinitializes the button
|
||||
* - removes the marker
|
||||
*/
|
||||
stop: function() {
|
||||
this._deactivate();
|
||||
|
||||
this._cleanClasses();
|
||||
this._resetVariables();
|
||||
|
||||
this.removeMarker();
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls deactivate and dispatches an error.
|
||||
*/
|
||||
_onLocationError: function(err) {
|
||||
// ignore time out error if the location is watched
|
||||
if (err.code == 3 && this.options.locateOptions.watch) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.stop();
|
||||
this.options.onLocationError(err);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stores the received event and updates the marker.
|
||||
*/
|
||||
_onLocationFound: function(e) {
|
||||
// no need to do anything if the location has not changed
|
||||
if (this._event &&
|
||||
(this._event.latlng.lat === e.latlng.lat &&
|
||||
this._event.latlng.lng === e.latlng.lng &&
|
||||
this._event.accuracy === e.accuracy)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._active) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._event = e;
|
||||
|
||||
if (this.options.follow && this._following) {
|
||||
this._locateOnNextLocationFound = true;
|
||||
}
|
||||
|
||||
this.drawMarker(this._map);
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatches the 'startfollowing' event on map.
|
||||
*/
|
||||
_startFollowing: function() {
|
||||
this._map.fire('startfollowing', this);
|
||||
this._following = true;
|
||||
if (this.options.stopFollowingOnDrag) {
|
||||
this._map.on('dragstart', this._stopFollowing, this);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatches the 'stopfollowing' event on map.
|
||||
*/
|
||||
_stopFollowing: function() {
|
||||
this._map.fire('stopfollowing', this);
|
||||
this._following = false;
|
||||
if (this.options.stopFollowingOnDrag) {
|
||||
this._map.off('dragstart', this._stopFollowing, this);
|
||||
}
|
||||
this._toggleContainerStyle();
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if location is in map bounds
|
||||
*/
|
||||
_isOutsideMapBounds: function() {
|
||||
if (this._event === undefined)
|
||||
return false;
|
||||
return this._map.options.maxBounds &&
|
||||
!this._map.options.maxBounds.contains(this._event.latlng);
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles button class between following and active.
|
||||
*/
|
||||
_toggleContainerStyle: function() {
|
||||
if (!this._container) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._following) {
|
||||
this._setClasses('following');
|
||||
} else {
|
||||
this._setClasses('active');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the CSS classes for the state.
|
||||
*/
|
||||
_setClasses: function(state) {
|
||||
if (state == 'requesting') {
|
||||
L.DomUtil.removeClasses(this._container, "active following");
|
||||
L.DomUtil.addClasses(this._container, "requesting");
|
||||
|
||||
L.DomUtil.removeClasses(this._icon, this.options.icon);
|
||||
L.DomUtil.addClasses(this._icon, this.options.iconLoading);
|
||||
} else if (state == 'active') {
|
||||
L.DomUtil.removeClasses(this._container, "requesting following");
|
||||
L.DomUtil.addClasses(this._container, "active");
|
||||
|
||||
L.DomUtil.removeClasses(this._icon, this.options.iconLoading);
|
||||
L.DomUtil.addClasses(this._icon, this.options.icon);
|
||||
} else if (state == 'following') {
|
||||
L.DomUtil.removeClasses(this._container, "requesting");
|
||||
L.DomUtil.addClasses(this._container, "active following");
|
||||
|
||||
L.DomUtil.removeClasses(this._icon, this.options.iconLoading);
|
||||
L.DomUtil.addClasses(this._icon, this.options.icon);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all classes from button.
|
||||
*/
|
||||
_cleanClasses: function() {
|
||||
L.DomUtil.removeClass(this._container, "requesting");
|
||||
L.DomUtil.removeClass(this._container, "active");
|
||||
L.DomUtil.removeClass(this._container, "following");
|
||||
|
||||
L.DomUtil.removeClasses(this._icon, this.options.iconLoading);
|
||||
L.DomUtil.addClasses(this._icon, this.options.icon);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reinitializes attributes.
|
||||
*/
|
||||
_resetVariables: function() {
|
||||
this._active = false;
|
||||
this._locateOnNextLocationFound = this.options.setView;
|
||||
this._following = false;
|
||||
}
|
||||
});
|
||||
|
||||
L.control.locate = function (options) {
|
||||
return new L.Control.Locate(options);
|
||||
};
|
||||
|
||||
(function(){
|
||||
// leaflet.js raises bug when trying to addClass / removeClass multiple classes at once
|
||||
// Let's create a wrapper on it which fixes it.
|
||||
var LDomUtilApplyClassesMethod = function(method, element, classNames) {
|
||||
classNames = classNames.split(' ');
|
||||
classNames.forEach(function(className) {
|
||||
L.DomUtil[method].call(this, element, className);
|
||||
});
|
||||
};
|
||||
|
||||
L.DomUtil.addClasses = function(el, names) { LDomUtilApplyClassesMethod('addClass', el, names); };
|
||||
L.DomUtil.removeClasses = function(el, names) { LDomUtilApplyClassesMethod('removeClass', el, names); };
|
||||
})();
|
||||
|
||||
return L.Control.Locate;
|
||||
}, window));
|
||||
673
src/Leaflet/lib/leaflet-providers.js
Normal file
@@ -0,0 +1,673 @@
|
||||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['Leaflet/lib/leaflet-src'], factory);
|
||||
} else if (typeof modules === 'object' && module.exports) {
|
||||
// define a Common JS module that relies on 'leaflet'
|
||||
module.exports = factory(require('leaflet'));
|
||||
} else {
|
||||
// Assume Leaflet is loaded into global object L already
|
||||
factory(L);
|
||||
}
|
||||
}(this, function (L) {
|
||||
'use strict';
|
||||
|
||||
L.TileLayer.Provider = L.TileLayer.extend({
|
||||
initialize: function (arg, options) {
|
||||
var providers = L.TileLayer.Provider.providers;
|
||||
|
||||
var parts = arg.split('.');
|
||||
|
||||
var providerName = parts[0];
|
||||
var variantName = parts[1];
|
||||
|
||||
if (!providers[providerName]) {
|
||||
throw 'No such provider (' + providerName + ')';
|
||||
}
|
||||
|
||||
var provider = {
|
||||
url: providers[providerName].url,
|
||||
options: providers[providerName].options
|
||||
};
|
||||
|
||||
// overwrite values in provider from variant.
|
||||
if (variantName && 'variants' in providers[providerName]) {
|
||||
if (!(variantName in providers[providerName].variants)) {
|
||||
throw 'No such variant of ' + providerName + ' (' + variantName + ')';
|
||||
}
|
||||
var variant = providers[providerName].variants[variantName];
|
||||
var variantOptions;
|
||||
if (typeof variant === 'string') {
|
||||
variantOptions = {
|
||||
variant: variant
|
||||
};
|
||||
} else {
|
||||
variantOptions = variant.options;
|
||||
}
|
||||
provider = {
|
||||
url: variant.url || provider.url,
|
||||
options: L.Util.extend({}, provider.options, variantOptions)
|
||||
};
|
||||
}
|
||||
|
||||
var forceHTTP = window.location.protocol === 'file:' || provider.options.forceHTTP;
|
||||
if (provider.url.indexOf('//') === 0 && forceHTTP) {
|
||||
provider.url = 'http:' + provider.url;
|
||||
}
|
||||
|
||||
// If retina option is set
|
||||
if (provider.options.retina) {
|
||||
// Check retina screen
|
||||
if (options.detectRetina && L.Browser.retina) {
|
||||
// The retina option will be active now
|
||||
// But we need to prevent Leaflet retina mode
|
||||
options.detectRetina = false;
|
||||
} else {
|
||||
// No retina, remove option
|
||||
provider.options.retina = '';
|
||||
}
|
||||
}
|
||||
|
||||
// replace attribution placeholders with their values from toplevel provider attribution,
|
||||
// recursively
|
||||
var attributionReplacer = function (attr) {
|
||||
if (attr.indexOf('{attribution.') === -1) {
|
||||
return attr;
|
||||
}
|
||||
return attr.replace(/\{attribution.(\w*)\}/,
|
||||
function (match, attributionName) {
|
||||
return attributionReplacer(providers[attributionName].options.attribution);
|
||||
}
|
||||
);
|
||||
};
|
||||
provider.options.attribution = attributionReplacer(provider.options.attribution);
|
||||
|
||||
// Compute final options combining provider options with any user overrides
|
||||
var layerOpts = L.Util.extend({}, provider.options, options);
|
||||
L.TileLayer.prototype.initialize.call(this, provider.url, layerOpts);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Definition of providers.
|
||||
* see http://leafletjs.com/reference.html#tilelayer for options in the options map.
|
||||
*/
|
||||
|
||||
L.TileLayer.Provider.providers = {
|
||||
OpenStreetMap: {
|
||||
url: '//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
maxZoom: 19,
|
||||
attribution:
|
||||
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
},
|
||||
variants: {
|
||||
Mapnik: {},
|
||||
BlackAndWhite: {
|
||||
url: 'http://{s}.tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
maxZoom: 18
|
||||
}
|
||||
},
|
||||
DE: {
|
||||
url: 'http://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
maxZoom: 18
|
||||
}
|
||||
},
|
||||
France: {
|
||||
url: 'http://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
attribution: '© Openstreetmap France | {attribution.OpenStreetMap}'
|
||||
}
|
||||
},
|
||||
HOT: {
|
||||
url: 'http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
attribution: '{attribution.OpenStreetMap}, Tiles courtesy of <a href="http://hot.openstreetmap.org/" target="_blank">Humanitarian OpenStreetMap Team</a>'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
OpenSeaMap: {
|
||||
url: 'http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
attribution: 'Map data: © <a href="http://www.openseamap.org">OpenSeaMap</a> contributors'
|
||||
}
|
||||
},
|
||||
OpenTopoMap: {
|
||||
url: '//{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
maxZoom: 16,
|
||||
attribution: 'Map data: {attribution.OpenStreetMap}, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: © <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
|
||||
}
|
||||
},
|
||||
Thunderforest: {
|
||||
url: '//{s}.tile.thunderforest.com/{variant}/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
attribution:
|
||||
'© <a href="http://www.thunderforest.com/">Thunderforest</a>, {attribution.OpenStreetMap}',
|
||||
variant: 'cycle'
|
||||
},
|
||||
variants: {
|
||||
OpenCycleMap: 'cycle',
|
||||
Transport: {
|
||||
options: {
|
||||
variant: 'transport',
|
||||
maxZoom: 19
|
||||
}
|
||||
},
|
||||
TransportDark: {
|
||||
options: {
|
||||
variant: 'transport-dark',
|
||||
maxZoom: 19
|
||||
}
|
||||
},
|
||||
SpinalMap: {
|
||||
options: {
|
||||
variant: 'spinal-map',
|
||||
maxZoom: 11
|
||||
}
|
||||
},
|
||||
Landscape: 'landscape',
|
||||
Outdoors: 'outdoors',
|
||||
Pioneer: 'pioneer'
|
||||
}
|
||||
},
|
||||
OpenMapSurfer: {
|
||||
url: 'http://korona.geog.uni-heidelberg.de/tiles/{variant}/x={x}&y={y}&z={z}',
|
||||
options: {
|
||||
maxZoom: 20,
|
||||
variant: 'roads',
|
||||
attribution: 'Imagery from <a href="http://giscience.uni-hd.de/">GIScience Research Group @ University of Heidelberg</a> — Map data {attribution.OpenStreetMap}'
|
||||
},
|
||||
variants: {
|
||||
Roads: 'roads',
|
||||
AdminBounds: {
|
||||
options: {
|
||||
variant: 'adminb',
|
||||
maxZoom: 19
|
||||
}
|
||||
},
|
||||
Grayscale: {
|
||||
options: {
|
||||
variant: 'roadsg',
|
||||
maxZoom: 19
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Hydda: {
|
||||
url: 'http://{s}.tile.openstreetmap.se/hydda/{variant}/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
variant: 'full',
|
||||
attribution: 'Tiles courtesy of <a href="http://openstreetmap.se/" target="_blank">OpenStreetMap Sweden</a> — Map data {attribution.OpenStreetMap}'
|
||||
},
|
||||
variants: {
|
||||
Full: 'full',
|
||||
Base: 'base',
|
||||
RoadsAndLabels: 'roads_and_labels'
|
||||
}
|
||||
},
|
||||
MapQuestOpen: {
|
||||
/* Mapquest does support https, but with a different subdomain:
|
||||
* https://otile{s}-s.mqcdn.com/tiles/1.0.0/{type}/{z}/{x}/{y}.{ext}
|
||||
* which makes implementing protocol relativity impossible.
|
||||
*/
|
||||
url: 'https://otile{s}-s.mqcdn.com/tiles/1.0.0/{type}/{z}/{x}/{y}.{ext}', // Changed default to HTTPS
|
||||
options: {
|
||||
type: 'map',
|
||||
ext: 'jpg',
|
||||
attribution:
|
||||
'Tiles Courtesy of <a href="http://www.mapquest.com/">MapQuest</a> — ' +
|
||||
'Map data {attribution.OpenStreetMap}',
|
||||
subdomains: '1234'
|
||||
},
|
||||
variants: {
|
||||
OSM: {},
|
||||
Aerial: {
|
||||
options: {
|
||||
type: 'sat',
|
||||
attribution:
|
||||
'Tiles Courtesy of <a href="http://www.mapquest.com/">MapQuest</a> — ' +
|
||||
'Portions Courtesy NASA/JPL-Caltech and U.S. Depart. of Agriculture, Farm Service Agency'
|
||||
}
|
||||
},
|
||||
HybridOverlay: {
|
||||
options: {
|
||||
type: 'hyb',
|
||||
ext: 'png',
|
||||
opacity: 0.9
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
MapBox: {
|
||||
url: '//api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}',
|
||||
options: {
|
||||
attribution:
|
||||
'Imagery from <a href="http://mapbox.com/about/maps/">MapBox</a> — ' +
|
||||
'Map data {attribution.OpenStreetMap}',
|
||||
subdomains: 'abcd'
|
||||
}
|
||||
},
|
||||
Stamen: {
|
||||
url: '//stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}.{ext}',
|
||||
options: {
|
||||
attribution:
|
||||
'Map tiles by <a href="http://stamen.com">Stamen Design</a>, ' +
|
||||
'<a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — ' +
|
||||
'Map data {attribution.OpenStreetMap}',
|
||||
subdomains: 'abcd',
|
||||
minZoom: 0,
|
||||
maxZoom: 20,
|
||||
variant: 'toner',
|
||||
ext: 'png'
|
||||
},
|
||||
variants: {
|
||||
Toner: 'toner',
|
||||
TonerBackground: 'toner-background',
|
||||
TonerHybrid: 'toner-hybrid',
|
||||
TonerLines: 'toner-lines',
|
||||
TonerLabels: 'toner-labels',
|
||||
TonerLite: 'toner-lite',
|
||||
Watercolor: {
|
||||
options: {
|
||||
variant: 'watercolor',
|
||||
minZoom: 1,
|
||||
maxZoom: 16
|
||||
}
|
||||
},
|
||||
Terrain: {
|
||||
options: {
|
||||
variant: 'terrain',
|
||||
minZoom: 4,
|
||||
maxZoom: 18,
|
||||
bounds: [[22, -132], [70, -56]]
|
||||
}
|
||||
},
|
||||
TerrainBackground: {
|
||||
options: {
|
||||
variant: 'terrain-background',
|
||||
minZoom: 4,
|
||||
maxZoom: 18,
|
||||
bounds: [[22, -132], [70, -56]]
|
||||
}
|
||||
},
|
||||
TopOSMRelief: {
|
||||
options: {
|
||||
variant: 'toposm-color-relief',
|
||||
ext: 'jpg',
|
||||
bounds: [[22, -132], [51, -56]]
|
||||
}
|
||||
},
|
||||
TopOSMFeatures: {
|
||||
options: {
|
||||
variant: 'toposm-features',
|
||||
bounds: [[22, -132], [51, -56]],
|
||||
opacity: 0.9
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Esri: {
|
||||
url: '//server.arcgisonline.com/ArcGIS/rest/services/{variant}/MapServer/tile/{z}/{y}/{x}',
|
||||
options: {
|
||||
variant: 'World_Street_Map',
|
||||
attribution: 'Tiles © Esri'
|
||||
},
|
||||
variants: {
|
||||
WorldStreetMap: {
|
||||
options: {
|
||||
attribution:
|
||||
'{attribution.Esri} — ' +
|
||||
'Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong), Esri (Thailand), TomTom, 2012'
|
||||
}
|
||||
},
|
||||
DeLorme: {
|
||||
options: {
|
||||
variant: 'Specialty/DeLorme_World_Base_Map',
|
||||
minZoom: 1,
|
||||
maxZoom: 11,
|
||||
attribution: '{attribution.Esri} — Copyright: ©2012 DeLorme'
|
||||
}
|
||||
},
|
||||
WorldTopoMap: {
|
||||
options: {
|
||||
variant: 'World_Topo_Map',
|
||||
attribution:
|
||||
'{attribution.Esri} — ' +
|
||||
'Esri, DeLorme, NAVTEQ, TomTom, Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL, Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong), and the GIS User Community'
|
||||
}
|
||||
},
|
||||
WorldImagery: {
|
||||
options: {
|
||||
variant: 'World_Imagery',
|
||||
attribution:
|
||||
'{attribution.Esri} — ' +
|
||||
'Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
|
||||
}
|
||||
},
|
||||
WorldTerrain: {
|
||||
options: {
|
||||
variant: 'World_Terrain_Base',
|
||||
maxZoom: 13,
|
||||
attribution:
|
||||
'{attribution.Esri} — ' +
|
||||
'Source: USGS, Esri, TANA, DeLorme, and NPS'
|
||||
}
|
||||
},
|
||||
WorldShadedRelief: {
|
||||
options: {
|
||||
variant: 'World_Shaded_Relief',
|
||||
maxZoom: 13,
|
||||
attribution: '{attribution.Esri} — Source: Esri'
|
||||
}
|
||||
},
|
||||
WorldPhysical: {
|
||||
options: {
|
||||
variant: 'World_Physical_Map',
|
||||
maxZoom: 8,
|
||||
attribution: '{attribution.Esri} — Source: US National Park Service'
|
||||
}
|
||||
},
|
||||
OceanBasemap: {
|
||||
options: {
|
||||
variant: 'Ocean_Basemap',
|
||||
maxZoom: 13,
|
||||
attribution: '{attribution.Esri} — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri'
|
||||
}
|
||||
},
|
||||
NatGeoWorldMap: {
|
||||
options: {
|
||||
variant: 'NatGeo_World_Map',
|
||||
maxZoom: 16,
|
||||
attribution: '{attribution.Esri} — National Geographic, Esri, DeLorme, NAVTEQ, UNEP-WCMC, USGS, NASA, ESA, METI, NRCAN, GEBCO, NOAA, iPC'
|
||||
}
|
||||
},
|
||||
WorldGrayCanvas: {
|
||||
options: {
|
||||
variant: 'Canvas/World_Light_Gray_Base',
|
||||
maxZoom: 16,
|
||||
attribution: '{attribution.Esri} — Esri, DeLorme, NAVTEQ'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
OpenWeatherMap: {
|
||||
url: 'http://{s}.tile.openweathermap.org/map/{variant}/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
maxZoom: 19,
|
||||
attribution: 'Map data © <a href="http://openweathermap.org">OpenWeatherMap</a>',
|
||||
opacity: 0.5
|
||||
},
|
||||
variants: {
|
||||
Clouds: 'clouds',
|
||||
CloudsClassic: 'clouds_cls',
|
||||
Precipitation: 'precipitation',
|
||||
PrecipitationClassic: 'precipitation_cls',
|
||||
Rain: 'rain',
|
||||
RainClassic: 'rain_cls',
|
||||
Pressure: 'pressure',
|
||||
PressureContour: 'pressure_cntr',
|
||||
Wind: 'wind',
|
||||
Temperature: 'temp',
|
||||
Snow: 'snow'
|
||||
}
|
||||
},
|
||||
HERE: {
|
||||
/*
|
||||
* HERE maps, formerly Nokia maps.
|
||||
* These basemaps are free, but you need an API key. Please sign up at
|
||||
* http://developer.here.com/getting-started
|
||||
*
|
||||
* Note that the base urls contain '.cit' whichs is HERE's
|
||||
* 'Customer Integration Testing' environment. Please remove for production
|
||||
* envirionments.
|
||||
*/
|
||||
url:
|
||||
'//{s}.{base}.maps.cit.api.here.com/maptile/2.1/' +
|
||||
'{type}/{mapID}/{variant}/{z}/{x}/{y}/{size}/{format}?' +
|
||||
'app_id={app_id}&app_code={app_code}&lg={language}',
|
||||
options: {
|
||||
attribution:
|
||||
'Map © 1987-2014 <a href="http://developer.here.com">HERE</a>',
|
||||
subdomains: '1234',
|
||||
mapID: 'newest',
|
||||
'app_id': '<insert your app_id here>',
|
||||
'app_code': '<insert your app_code here>',
|
||||
base: 'base',
|
||||
variant: 'normal.day',
|
||||
maxZoom: 20,
|
||||
type: 'maptile',
|
||||
language: 'eng',
|
||||
format: 'png8',
|
||||
size: '256'
|
||||
},
|
||||
variants: {
|
||||
normalDay: 'normal.day',
|
||||
normalDayCustom: 'normal.day.custom',
|
||||
normalDayGrey: 'normal.day.grey',
|
||||
normalDayMobile: 'normal.day.mobile',
|
||||
normalDayGreyMobile: 'normal.day.grey.mobile',
|
||||
normalDayTransit: 'normal.day.transit',
|
||||
normalDayTransitMobile: 'normal.day.transit.mobile',
|
||||
normalNight: 'normal.night',
|
||||
normalNightMobile: 'normal.night.mobile',
|
||||
normalNightGrey: 'normal.night.grey',
|
||||
normalNightGreyMobile: 'normal.night.grey.mobile',
|
||||
|
||||
basicMap: {
|
||||
options: {
|
||||
type: 'basetile'
|
||||
}
|
||||
},
|
||||
mapLabels: {
|
||||
options: {
|
||||
type: 'labeltile',
|
||||
format: 'png'
|
||||
}
|
||||
},
|
||||
trafficFlow: {
|
||||
options: {
|
||||
base: 'traffic',
|
||||
type: 'flowtile'
|
||||
}
|
||||
},
|
||||
carnavDayGrey: 'carnav.day.grey',
|
||||
hybridDay: {
|
||||
options: {
|
||||
base: 'aerial',
|
||||
variant: 'hybrid.day'
|
||||
}
|
||||
},
|
||||
hybridDayMobile: {
|
||||
options: {
|
||||
base: 'aerial',
|
||||
variant: 'hybrid.day.mobile'
|
||||
}
|
||||
},
|
||||
pedestrianDay: 'pedestrian.day',
|
||||
pedestrianNight: 'pedestrian.night',
|
||||
satelliteDay: {
|
||||
options: {
|
||||
base: 'aerial',
|
||||
variant: 'satellite.day'
|
||||
}
|
||||
},
|
||||
terrainDay: {
|
||||
options: {
|
||||
base: 'aerial',
|
||||
variant: 'terrain.day'
|
||||
}
|
||||
},
|
||||
terrainDayMobile: {
|
||||
options: {
|
||||
base: 'aerial',
|
||||
variant: 'terrain.day.mobile'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
FreeMapSK: {
|
||||
url: 'http://t{s}.freemap.sk/T/{z}/{x}/{y}.jpeg',
|
||||
options: {
|
||||
minZoom: 8,
|
||||
maxZoom: 16,
|
||||
subdomains: '1234',
|
||||
bounds: [[47.204642, 15.996093], [49.830896, 22.576904]],
|
||||
attribution:
|
||||
'{attribution.OpenStreetMap}, vizualization CC-By-SA 2.0 <a href="http://freemap.sk">Freemap.sk</a>'
|
||||
}
|
||||
},
|
||||
MtbMap: {
|
||||
url: 'http://tile.mtbmap.cz/mtbmap_tiles/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
attribution:
|
||||
'{attribution.OpenStreetMap} & USGS'
|
||||
}
|
||||
},
|
||||
CartoDB: {
|
||||
url: 'http://{s}.basemaps.cartocdn.com/{variant}/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
attribution: '{attribution.OpenStreetMap} © <a href="http://cartodb.com/attributions">CartoDB</a>',
|
||||
subdomains: 'abcd',
|
||||
maxZoom: 19,
|
||||
variant: 'light_all'
|
||||
},
|
||||
variants: {
|
||||
Positron: 'light_all',
|
||||
PositronNoLabels: 'light_nolabels',
|
||||
PositronOnlyLabels: 'light_only_labels',
|
||||
DarkMatter: 'dark_all',
|
||||
DarkMatterNoLabels: 'dark_nolabels',
|
||||
DarkMatterOnlyLabels: 'dark_only_labels'
|
||||
}
|
||||
},
|
||||
HikeBike: {
|
||||
url: 'http://{s}.tiles.wmflabs.org/{variant}/{z}/{x}/{y}.png',
|
||||
options: {
|
||||
maxZoom: 19,
|
||||
attribution: '{attribution.OpenStreetMap}',
|
||||
variant: 'hikebike'
|
||||
},
|
||||
variants: {
|
||||
HikeBike: {},
|
||||
HillShading: {
|
||||
options: {
|
||||
maxZoom: 15,
|
||||
variant: 'hillshading'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
BasemapAT: {
|
||||
url: '//maps{s}.wien.gv.at/basemap/{variant}/normal/google3857/{z}/{y}/{x}.{format}',
|
||||
options: {
|
||||
maxZoom: 19,
|
||||
attribution: 'Datenquelle: <a href="www.basemap.at">basemap.at</a>',
|
||||
subdomains: ['', '1', '2', '3', '4'],
|
||||
format: 'png',
|
||||
bounds: [[46.358770, 8.782379], [49.037872, 17.189532]],
|
||||
variant: 'geolandbasemap'
|
||||
},
|
||||
variants: {
|
||||
basemap: 'geolandbasemap',
|
||||
grau: 'bmapgrau',
|
||||
overlay: 'bmapoverlay',
|
||||
highdpi: {
|
||||
options: {
|
||||
variant: 'bmaphidpi',
|
||||
format: 'jpeg'
|
||||
}
|
||||
},
|
||||
orthofoto: {
|
||||
options: {
|
||||
variant: 'bmaporthofoto30cm',
|
||||
format: 'jpeg'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
NASAGIBS: {
|
||||
url: '//map1.vis.earthdata.nasa.gov/wmts-webmerc/{variant}/default/{time}/{tilematrixset}{maxZoom}/{z}/{y}/{x}.{format}',
|
||||
options: {
|
||||
attribution:
|
||||
'Imagery provided by services from the Global Imagery Browse Services (GIBS), operated by the NASA/GSFC/Earth Science Data and Information System ' +
|
||||
'(<a href="https://earthdata.nasa.gov">ESDIS</a>) with funding provided by NASA/HQ.',
|
||||
bounds: [[-85.0511287776, -179.999999975], [85.0511287776, 179.999999975]],
|
||||
minZoom: 1,
|
||||
maxZoom: 9,
|
||||
format: 'jpg',
|
||||
time: '',
|
||||
tilematrixset: 'GoogleMapsCompatible_Level'
|
||||
},
|
||||
variants: {
|
||||
ModisTerraTrueColorCR: 'MODIS_Terra_CorrectedReflectance_TrueColor',
|
||||
ModisTerraBands367CR: 'MODIS_Terra_CorrectedReflectance_Bands367',
|
||||
ViirsEarthAtNight2012: {
|
||||
options: {
|
||||
variant: 'VIIRS_CityLights_2012',
|
||||
maxZoom: 8
|
||||
}
|
||||
},
|
||||
ModisTerraLSTDay: {
|
||||
options: {
|
||||
variant: 'MODIS_Terra_Land_Surface_Temp_Day',
|
||||
format: 'png',
|
||||
maxZoom: 7,
|
||||
opacity: 0.75
|
||||
}
|
||||
},
|
||||
ModisTerraSnowCover: {
|
||||
options: {
|
||||
variant: 'MODIS_Terra_Snow_Cover',
|
||||
format: 'png',
|
||||
maxZoom: 8,
|
||||
opacity: 0.75
|
||||
}
|
||||
},
|
||||
ModisTerraAOD: {
|
||||
options: {
|
||||
variant: 'MODIS_Terra_Aerosol',
|
||||
format: 'png',
|
||||
maxZoom: 6,
|
||||
opacity: 0.75
|
||||
}
|
||||
},
|
||||
ModisTerraChlorophyll: {
|
||||
options: {
|
||||
variant: 'MODIS_Terra_Chlorophyll_A',
|
||||
format: 'png',
|
||||
maxZoom: 7,
|
||||
opacity: 0.75
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
NLS: {
|
||||
// NLS maps are copyright National library of Scotland.
|
||||
// http://maps.nls.uk/projects/api/index.html
|
||||
// Please contact NLS for anything other than non-commercial low volume usage
|
||||
//
|
||||
// Map sources: Ordnance Survey 1:1m to 1:63K, 1920s-1940s
|
||||
// z0-9 - 1:1m
|
||||
// z10-11 - quarter inch (1:253440)
|
||||
// z12-18 - one inch (1:63360)
|
||||
url: '//nls-{s}.tileserver.com/nls/{z}/{x}/{y}.jpg',
|
||||
options: {
|
||||
attribution: '<a href="http://geo.nls.uk/maps/">National Library of Scotland Historic Maps</a>',
|
||||
bounds: [[49.6, -12], [61.7, 3]],
|
||||
minZoom: 1,
|
||||
maxZoom: 18,
|
||||
subdomains: '0123',
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
L.tileLayer.provider = function (provider, options) {
|
||||
return new L.TileLayer.Provider(provider, options);
|
||||
};
|
||||
|
||||
return L;
|
||||
}));
|
||||
9168
src/Leaflet/lib/leaflet-src.js
Normal file
471
src/Leaflet/widget/Leaflet.js
Normal file
@@ -0,0 +1,471 @@
|
||||
define([
|
||||
"dojo/_base/declare",
|
||||
"mxui/widget/_WidgetBase",
|
||||
"dijit/_TemplatedMixin",
|
||||
"dojo/dom-style",
|
||||
"dojo/dom-construct",
|
||||
"dojo/_base/array",
|
||||
"dojo/_base/lang",
|
||||
"dojo/text!Leaflet/widget/template/Leaflet.html",
|
||||
// Leaflet
|
||||
"Leaflet/lib/leaflet-src",
|
||||
|
||||
// Plugins
|
||||
"Leaflet/lib/leaflet-providers",
|
||||
"Leaflet/lib/leaflet-locatecontrol",
|
||||
"Leaflet/lib/leaflet-fullscreen"
|
||||
|
||||
], function (declare, _WidgetBase, _TemplatedMixin, domStyle, domConstruct, dojoArray, lang, widgetTemplate, Leaflet) {
|
||||
"use strict";
|
||||
|
||||
var LL = Leaflet.noConflict();
|
||||
LL.Icon.Default.imagePath = require.toUrl("Leaflet/widget/ui/").split("?")[0];
|
||||
|
||||
return declare("Leaflet.widget.Leaflet", [_WidgetBase, _TemplatedMixin], {
|
||||
|
||||
// Template
|
||||
templateString: widgetTemplate,
|
||||
|
||||
// DOM node
|
||||
mapContainer: null,
|
||||
|
||||
// Set by modeler
|
||||
gotocontext: false,
|
||||
defaultLat: 0,
|
||||
defaultLng: 0,
|
||||
minZoom: 0,
|
||||
maxZoom: 20,
|
||||
lowestZoom: 10,
|
||||
updateRefresh: false,
|
||||
|
||||
mapEntity: "",
|
||||
xpathConstraint: "",
|
||||
markerDisplayAttr: "",
|
||||
latAttr: "",
|
||||
lngAttr: "",
|
||||
onClickMarkerMf: "",
|
||||
|
||||
mapHeight: "",
|
||||
mapWidth: "",
|
||||
markerTemplate: "<p>{Marker}</p>",
|
||||
|
||||
mapType: "OpenStreetMap_Mapnik",
|
||||
customMapType: false,
|
||||
customMapTypeUrl: "//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||
customMapTypOptions: "{subdomains:'abc'}",
|
||||
|
||||
controlDragging: true,
|
||||
controlTouchZoom: true,
|
||||
controlScrollWheelZoom: true,
|
||||
controlZoomControl: true,
|
||||
controlZoomControlPosition: "topleft",
|
||||
controlAttribution: true,
|
||||
controlAttributionPosition: "bottomright",
|
||||
controlFullscreen: false,
|
||||
controlFullscreenPosition: "topright",
|
||||
|
||||
locateControl: false,
|
||||
locateControlPosition: "topleft",
|
||||
locateControlDrawCircle: true,
|
||||
locateControlKeepZoomLevel: false,
|
||||
|
||||
scaleControl: false,
|
||||
scaleControlPosition: "bottomleft",
|
||||
scaleControlMetric: true,
|
||||
scaleControlImperial: true,
|
||||
scaleControlMaxWidth: 100,
|
||||
|
||||
// Internal variables
|
||||
_markerCache: [],
|
||||
_layerGroup: null,
|
||||
_minZoom: 0,
|
||||
_maxZoom: 20,
|
||||
|
||||
_defaultPosition: [],
|
||||
_handle: null,
|
||||
_contextObj: null,
|
||||
_map: null,
|
||||
|
||||
postCreate: function () {
|
||||
logger.debug(this.id + ".postCreate");
|
||||
|
||||
this._defaultPosition = [
|
||||
parseFloat(this.defaultLat),
|
||||
parseFloat(this.defaultLng)
|
||||
];
|
||||
|
||||
this._minZoom = this.minZoom >= 0 ? this.minZoom : 0;
|
||||
this._maxZoom = this.maxZoom > this.minZoom ? this.maxZoom : this.minZoom;
|
||||
|
||||
this._layerGroup = new LL.layerGroup();
|
||||
},
|
||||
|
||||
update: function (obj, callback) {
|
||||
logger.debug(this.id + ".update");
|
||||
this._contextObj = obj;
|
||||
this._resetSubscriptions();
|
||||
|
||||
if (!this._map) {
|
||||
this._loadMap(callback);
|
||||
} else {
|
||||
this._fetchMarkers(callback);
|
||||
}
|
||||
},
|
||||
|
||||
resize: function (box) {
|
||||
logger.debug(this.id + ".resize");
|
||||
if (this._map) {
|
||||
this._map.invalidateSize();
|
||||
}
|
||||
},
|
||||
|
||||
_resetSubscriptions: function () {
|
||||
logger.debug(this.id + "._resetSubscriptions");
|
||||
|
||||
if (this._handle) {
|
||||
logger.debug(this.id + "._resetSubscriptions unsubscribe", this._handle);
|
||||
this.unsubscribe(this._handle);
|
||||
this._handle = null;
|
||||
}
|
||||
|
||||
if (this._contextObj) {
|
||||
logger.debug(this.id + "._resetSubscriptions subscribe", this._contextObj.getGuid());
|
||||
this._handle = this.subscribe({
|
||||
guid: this._contextObj.getGuid(),
|
||||
callback: lang.hitch(this, function (guid) {
|
||||
this._fetchMarkers();
|
||||
})
|
||||
});
|
||||
} else {
|
||||
this._handle = this.subscribe({
|
||||
entity: this.mapEntity,
|
||||
callback: lang.hitch(this, function (entity) {
|
||||
this._fetchMarkers();
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_getMapLayer: function () {
|
||||
var tileLayer = null;
|
||||
|
||||
if (this.customMapType && this.customMapTypeUrl) {
|
||||
var options = null;
|
||||
|
||||
try {
|
||||
options = JSON.parse(this.customMapTypeOptions);
|
||||
} catch (e) {
|
||||
console.error(this.id + "._getMapLayer error parsing Custom Map Options: " + e.toString());
|
||||
options = {};
|
||||
}
|
||||
|
||||
tileLayer = LL.tileLayer(this.customMapTypeUrl, options);
|
||||
|
||||
} else {
|
||||
var providerName = this.mapType.replace(/_/g, ".");
|
||||
tileLayer = LL.tileLayer.provider(providerName);
|
||||
}
|
||||
|
||||
if (tileLayer.options.minZoom < this._minZoom) {
|
||||
tileLayer.options.minZoom = this._minZoom;
|
||||
}
|
||||
|
||||
if (tileLayer.options.maxZoom > this._maxZoom) {
|
||||
tileLayer.options.maxZoom = this._maxZoom;
|
||||
}
|
||||
|
||||
return tileLayer;
|
||||
},
|
||||
|
||||
_loadMap: function (callback) {
|
||||
logger.debug(this.id + "._loadMap");
|
||||
|
||||
domStyle.set(this.domNode, { height: this.mapHeight });
|
||||
domStyle.set(this.mapContainer, {
|
||||
height: this.mapHeight,
|
||||
width: this.mapWidth
|
||||
});
|
||||
|
||||
this._map = LL.map(this.mapContainer, {
|
||||
dragging: this.controlDragging,
|
||||
touchZoom: this.controlTouchZoom,
|
||||
scrollWheelZoom: this.controlScrollWheelZoom,
|
||||
zoomControl: this.controlZoomControl,
|
||||
attributionControl: this.controlAttribution
|
||||
}).setView(this._defaultPosition, this.lowestZoom);
|
||||
|
||||
if (this.controlZoomControl) {
|
||||
this._map.zoomControl.setPosition(this.controlZoomControlPosition);
|
||||
}
|
||||
|
||||
if (this.controlAttribution) {
|
||||
this._map.attributionControl.setPosition(this.controlAttributionPosition);
|
||||
}
|
||||
|
||||
if (this.controlFullscreen) {
|
||||
LL.control.fullscreen({
|
||||
position: "topright",
|
||||
forceSeparateButton: true
|
||||
}).addTo(this._map);
|
||||
}
|
||||
|
||||
if (this.scaleControl) {
|
||||
LL.control.scale({
|
||||
position: this.scaleControlPosition,
|
||||
maxWidth: this.scaleControlMaxWidth > 0 ? this.scaleControlMaxWidth : 100,
|
||||
metric: this.scaleControlMetric,
|
||||
imperial: this.scaleControlImperial
|
||||
}).addTo(this._map);
|
||||
}
|
||||
|
||||
if (this.locateControl) {
|
||||
LL.control.locate({
|
||||
position: this.locateControlPosition,
|
||||
drawCircle: this.locateControlDrawCircle,
|
||||
keepCurrentZoomLevel: this.locateControlKeepZoomLevel,
|
||||
icon: "glyphicon glyphicon-screenshot", // Using glyphicons that are part of Mendix
|
||||
iconLoading: "glyphicon glyphicon-refresh"
|
||||
}).addTo(this._map);
|
||||
}
|
||||
|
||||
this._map.addLayer(this._getMapLayer());
|
||||
this._map.setZoom(this.lowestZoom); // trigger setzoom to make sure it is rendered
|
||||
this._layerGroup.addTo(this._map);
|
||||
|
||||
this._fetchMarkers(callback);
|
||||
},
|
||||
|
||||
_fetchMarkers: function (callback) {
|
||||
logger.debug(this.id + "._fetchMarkers");
|
||||
if (this.gotocontext) {
|
||||
this._goToContext(callback);
|
||||
} else {
|
||||
if (this.updateRefresh) {
|
||||
this._fetchFromDB(callback);
|
||||
} else {
|
||||
if (this._markerCache) {
|
||||
this._fetchFromCache(callback);
|
||||
} else {
|
||||
this._fetchFromDB(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_refreshMap: function (objs, callback) {
|
||||
logger.debug(this.id + "._refreshMap");
|
||||
var panPosition = this._defaultPosition,
|
||||
positions = [];
|
||||
|
||||
dojoArray.forEach(objs, lang.hitch(this, function (obj) {
|
||||
this._addMarker(obj);
|
||||
var position = this._getLatLng(obj);
|
||||
if (position) {
|
||||
positions.push(position); // reversing lat lng for boundingExtent
|
||||
panPosition = position;
|
||||
} else {
|
||||
logger.error(this.id + ": " + "Incorrect coordinates (" + this.checkAttrForDecimal(obj, this.latAttr) + "," + this.checkAttrForDecimal(obj, this.lngAttr) + ")");
|
||||
}
|
||||
}));
|
||||
|
||||
if (positions.length < 2) {
|
||||
this._map.setZoom(this.lowestZoom);
|
||||
this._map.panTo(panPosition);
|
||||
} else {
|
||||
this._map.fitBounds(positions);
|
||||
}
|
||||
|
||||
mendix.lang.nullExec(callback);
|
||||
},
|
||||
|
||||
_fetchFromDB: function (callback) {
|
||||
logger.debug(this.id + "._fetchFromDB");
|
||||
var xpath = "//" + this.mapEntity + this.xpathConstraint;
|
||||
|
||||
this._removeAllMarkers();
|
||||
|
||||
if (this._contextObj) {
|
||||
xpath = xpath.replace("[%CurrentObject%]", this._contextObj.getGuid());
|
||||
mx.data.get({
|
||||
xpath: xpath,
|
||||
callback: lang.hitch(this, function (objs) {
|
||||
this._refreshMap(objs, callback);
|
||||
})
|
||||
});
|
||||
} else if (!this._contextObj && (xpath.indexOf("[%CurrentObject%]") > -1)) {
|
||||
console.warn("No context for xpath, not fetching.");
|
||||
if (typeof callback === "function") {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
mx.data.get({
|
||||
xpath: xpath,
|
||||
callback: lang.hitch(this, function (objs) {
|
||||
this._refreshMap(objs, callback);
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_fetchFromCache: function (callback) {
|
||||
logger.debug(this.id + "._fetchFromCache");
|
||||
var cached = false,
|
||||
bounds = [];
|
||||
|
||||
this._removeAllMarkers();
|
||||
|
||||
dojoArray.forEach(this._markerCache, lang.hitch(this, function (markerObj, index) {
|
||||
if (this._contextObj) {
|
||||
if (markerObj.id === this._contextObj.getGuid()) {
|
||||
markerObj.marker.addTo(this._map);
|
||||
bounds.push(markerObj.loc);
|
||||
cached = true;
|
||||
}
|
||||
} else {
|
||||
markerObj.marker.addTo(this._map);
|
||||
}
|
||||
if (index === this._markerCache.length - 1) {
|
||||
this._map.fitBounds(bounds);
|
||||
}
|
||||
}));
|
||||
|
||||
if (!cached) {
|
||||
this._fetchFromDB(callback);
|
||||
} else if (typeof callback === "function") {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
|
||||
_removeAllMarkers: function () {
|
||||
logger.debug(this.id + "._removeAllMarkers");
|
||||
if (this._map) {
|
||||
this._layerGroup.clearLayers();
|
||||
}
|
||||
},
|
||||
|
||||
_addMarker: function (obj) {
|
||||
logger.debug(this.id + "._addMarker");
|
||||
|
||||
var id = this._contextObj ? this._contextObj.getGuid() : null,
|
||||
lat = parseFloat(this.checkAttrForDecimal(obj, this.latAttr)),
|
||||
lng = parseFloat(this.checkAttrForDecimal(obj, this.lngAttr)),
|
||||
loc = [lat, lng],
|
||||
markerObj = {
|
||||
context: id,
|
||||
obj: obj,
|
||||
marker: null,
|
||||
loc: loc
|
||||
};
|
||||
|
||||
var marker = LL.marker(loc);
|
||||
|
||||
if (this.onClickMarkerMf !== "") {
|
||||
marker.on("click", lang.hitch(this, function (e) {
|
||||
this._executeMf(this.onClickMarkerMf, obj);
|
||||
}));
|
||||
}
|
||||
|
||||
if (this.markerDisplayAttr) {
|
||||
var template = this.markerTemplate !== "" ?
|
||||
this.markerTemplate.replace("{Marker}", obj.get(this.markerDisplayAttr)) :
|
||||
"<p>" + obj.get(this.markerDisplayAttr) + "<p/>";
|
||||
|
||||
marker.bindPopup(template, {
|
||||
closeButton: false
|
||||
});
|
||||
}
|
||||
|
||||
this._layerGroup.addLayer(marker);
|
||||
markerObj.marker = marker;
|
||||
|
||||
if (!this._markerCache) {
|
||||
this._markerCache = [];
|
||||
}
|
||||
|
||||
var found = false;
|
||||
dojoArray.forEach(this._markerCache, lang.hitch(this, function (markerObj) {
|
||||
if (markerObj.obj.getGuid() === obj.getGuid()) {
|
||||
found = true;
|
||||
}
|
||||
}));
|
||||
|
||||
if (!found) {
|
||||
this._markerCache.push(markerObj);
|
||||
}
|
||||
},
|
||||
|
||||
checkAttrForDecimal: function (obj, attr) {
|
||||
logger.debug(this.id + ".checkAttrForDecimal");
|
||||
if (obj.get(attr) === "Decimal") {
|
||||
return obj.get(attr).toFixed(5);
|
||||
} else {
|
||||
return obj.get(attr);
|
||||
}
|
||||
},
|
||||
|
||||
_getLatLng: function (obj) {
|
||||
logger.debug(this.id + "._getLatLng");
|
||||
var lat = this.checkAttrForDecimal(obj, this.latAttr),
|
||||
lng = this.checkAttrForDecimal(obj, this.lngAttr);
|
||||
|
||||
if (lat === "" && lng === "") {
|
||||
return this._defaultPosition;
|
||||
} else if (!isNaN(lat) && !isNaN(lng) && lat !== "" && lng !== "") {
|
||||
return [
|
||||
parseFloat(lat),
|
||||
parseFloat(lng)
|
||||
];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
_goToContext: function (callback) {
|
||||
logger.debug(this.id + "._goToContext");
|
||||
this._removeAllMarkers();
|
||||
if (this._map && this._contextObj) {
|
||||
var objs = [];
|
||||
if (this._contextObj) {
|
||||
objs = [ this._contextObj ];
|
||||
} else {
|
||||
logger.error(this.id + "._goToContext: no Context object while you have set \"Pan to context\" in the Modeler! Showing default position");
|
||||
}
|
||||
this._refreshMap(objs, callback);
|
||||
} else {
|
||||
mendix.lang.nullExec(callback);
|
||||
}
|
||||
},
|
||||
|
||||
_executeMf: function(mf, obj) {
|
||||
logger.debug(this.id + "._executeMf");
|
||||
if (mf && obj && obj.getGuid()) {
|
||||
mx.data.action({
|
||||
store: {
|
||||
caller: this.mxform
|
||||
},
|
||||
params: {
|
||||
guids: [ obj.getGuid() ],
|
||||
applyto: "selection",
|
||||
actionname: mf
|
||||
},
|
||||
callback: lang.hitch(this, function() {
|
||||
logger.debug(this.id + "._executeMf success");
|
||||
}),
|
||||
error: lang.hitch(this, function(e) {
|
||||
console.error(this.id + "._executeMf failed, error: ", e.toString());
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
uninitialize: function () {
|
||||
logger.debug(this.id + ".uninitialize");
|
||||
if (this._map) {
|
||||
this._map.remove();
|
||||
this._markerCache = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
require(["Leaflet/widget/Leaflet"], function() {});
|
||||
3
src/Leaflet/widget/template/Leaflet.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<div class="openLayers">
|
||||
<div data-dojo-attach-point="mapContainer"></div>
|
||||
</div>
|
||||
520
src/Leaflet/widget/ui/Leaflet.css
Normal file
@@ -0,0 +1,520 @@
|
||||
/* 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;
|
||||
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;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.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; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* 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-container,
|
||||
.leaflet-dragging .leaflet-clickable {
|
||||
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 #38f;
|
||||
background: rgba(255,255,255,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 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-bar a:hover {
|
||||
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 {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-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 a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
.leaflet-control-zoom-out {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in {
|
||||
font-size: 22px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
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: #fff;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.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;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.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-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
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;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip-container {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
/* Leaflet Locate Control */
|
||||
.leaflet-control-locate .glyphicon {
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
.leaflet-control-locate a {
|
||||
font-size: 1.4em;
|
||||
color: #444;
|
||||
}
|
||||
.leaflet-control-locate.active a {
|
||||
color: #2074B6;
|
||||
}
|
||||
.leaflet-control-locate.active.following a {
|
||||
color: #FC8428;
|
||||
}
|
||||
|
||||
/* Leaflet Fullscreen */
|
||||
.fullscreen-icon {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAYElEQVR42u2UwQkAIAwDHckROpobdgRHURQRQcgngn3kIL9o+kibhAhFO+TA56eXDTLgs5dBFfgqG+Rj2vVRBr68PDbfkJQ98a3ytBhICvoQRJQhQr35hQ19gvijKkQYOnXBYeFRr/ZKAAAAAElFTkSuQmCC');
|
||||
}
|
||||
|
||||
.leaflet-retina .fullscreen-icon {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAA0CAYAAADFeBvrAAAAq0lEQVR42u2Y0QmAMAwFHcHR3DAjOUJH6AhV/CgE0UJK6wPv4H0aOFtjmwUAAAAAfkV5yR6otzdqjqUhswbqrVVKSCg7mZhUVlshW+KYzgr1S5nKN5QHCuV5Qr4B2IAtZ65RDOfezaxH5qlOlfqY7Uyqb7uddD0jhZcpkahKpQ6hpChUeoIQQggh5ELb5scqcvThcMr1YdIFjys4Q5IJYywGjYyCAQAAAECZA/11ewjNJ8u0AAAAAElFTkSuQmCC');
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
|
||||
.leaflet-container:-webkit-full-screen {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
.leaflet-pseudo-fullscreen {
|
||||
position: fixed !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
top: 0px !important;
|
||||
left: 0px !important;
|
||||
z-index: 99999;
|
||||
}
|
||||
BIN
src/Leaflet/widget/ui/layers-2x.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
src/Leaflet/widget/ui/layers.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/Leaflet/widget/ui/marker-icon-2x.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
src/Leaflet/widget/ui/marker-icon.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/Leaflet/widget/ui/marker-shadow.png
Normal file
|
After Width: | Height: | Size: 797 B |
11
src/package.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://www.mendix.com/package/1.0/">
|
||||
<clientModule name="OpenLayers" version="1.0.0" xmlns="http://www.mendix.com/clientModule/1.0/">
|
||||
<widgetFiles>
|
||||
<widgetFile path="Leaflet/Leaflet.xml"/>
|
||||
</widgetFiles>
|
||||
<files>
|
||||
<file path="Leaflet/widget/"/>
|
||||
</files>
|
||||
</clientModule>
|
||||
</package>
|
||||
BIN
test/Test.mpr
Normal file
BIN
test/widgets/Leaflet.mpk
Normal file
156
xsd/widget.xsd
Normal file
@@ -0,0 +1,156 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.mendix.com/widget/1.0/"
|
||||
xmlns="http://www.mendix.com/widget/1.0/"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<xs:element name="widget" type="widgetType"/>
|
||||
|
||||
<xs:complexType name="widgetType">
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:string"/>
|
||||
<xs:element name="description" type="xs:string"/>
|
||||
<xs:element name="icon" type="xs:base64Binary" minOccurs="0"/>
|
||||
<xs:element name="properties" type="propertiesType"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" type="xs:string" use="required"/>
|
||||
<xs:attribute name="needsEntityContext" type="xs:boolean" use="required"/>
|
||||
<xs:attribute name="mobile" type="xs:boolean" default="false"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="propertiesType">
|
||||
<xs:sequence>
|
||||
<xs:element name="property" type="propertyType" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="propertyType">
|
||||
<xs:sequence>
|
||||
<xs:element name="caption" type="xs:string"/>
|
||||
<xs:element name="category" type="xs:string"/>
|
||||
<xs:element name="description" type="xs:string"/>
|
||||
<xs:element name="attributeTypes" type="attributeTypesType" minOccurs="0"/>
|
||||
<xs:element name="enumerationValues" type="enumerationValuesType" minOccurs="0"/>
|
||||
<xs:element name="properties" type="propertiesType" minOccurs="0"/>
|
||||
<xs:element name="returnType" type="returnTypeType" minOccurs="0"/>
|
||||
<xs:element name="translations" type="translationsType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="key" type="xs:string" use="required"/>
|
||||
<xs:attribute name="type" type="propertyTypeType" use="required"/>
|
||||
<xs:attribute name="isList" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="entityProperty" type="xs:string"/>
|
||||
<xs:attribute name="allowNonPersistableEntities" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="isPath" type="isPathType" default="no"/>
|
||||
<xs:attribute name="pathType" type="pathTypeType"/>
|
||||
<xs:attribute name="parameterIsList" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="multiline" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="defaultValue" type="xs:string" default=""/>
|
||||
<xs:attribute name="required" type="xs:boolean" default="true"/>
|
||||
<xs:attribute name="isDefault" type="xs:boolean" default="false"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:simpleType name="propertyTypeType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="attribute"/>
|
||||
<xs:enumeration value="boolean"/>
|
||||
<xs:enumeration value="entity"/>
|
||||
<xs:enumeration value="entityConstraint"/>
|
||||
<xs:enumeration value="enumeration"/>
|
||||
<xs:enumeration value="form"/>
|
||||
<xs:enumeration value="image"/>
|
||||
<xs:enumeration value="integer"/>
|
||||
<xs:enumeration value="microflow"/>
|
||||
<xs:enumeration value="object"/>
|
||||
<xs:enumeration value="string"/>
|
||||
<xs:enumeration value="translatableString"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="attributeTypesType">
|
||||
<xs:sequence>
|
||||
<xs:element name="attributeType" type="attributeTypeType" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="attributeTypeType">
|
||||
<xs:attribute name="name" type="attributeTypeNameType" use="required"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:simpleType name="attributeTypeNameType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="AutoNumber"/>
|
||||
<xs:enumeration value="Binary"/>
|
||||
<xs:enumeration value="Boolean"/>
|
||||
<xs:enumeration value="Currency"/>
|
||||
<xs:enumeration value="DateTime"/>
|
||||
<xs:enumeration value="Enum"/>
|
||||
<xs:enumeration value="Float"/>
|
||||
<xs:enumeration value="HashString"/>
|
||||
<xs:enumeration value="Integer"/>
|
||||
<xs:enumeration value="Long"/>
|
||||
<xs:enumeration value="String"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="isPathType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="no"/>
|
||||
<xs:enumeration value="optional"/>
|
||||
<xs:enumeration value="yes"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="pathTypeType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="reference"/>
|
||||
<xs:enumeration value="referenceSet"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="enumerationValuesType">
|
||||
<xs:sequence>
|
||||
<xs:element name="enumerationValue" type="enumerationValueType" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="enumerationValueType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="key" type="xs:string" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="returnTypeType">
|
||||
<xs:attribute name="type" type="returnTypeTypeType" use="required"/>
|
||||
<xs:attribute name="isList" type="xs:boolean" default="false"/>
|
||||
<xs:attribute name="entityProperty" type="xs:string"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:simpleType name="returnTypeTypeType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="Void"/>
|
||||
<xs:enumeration value="Boolean"/>
|
||||
<xs:enumeration value="Integer"/>
|
||||
<xs:enumeration value="Float"/>
|
||||
<xs:enumeration value="DateTime"/>
|
||||
<xs:enumeration value="String"/>
|
||||
<xs:enumeration value="Object"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:complexType name="translationsType">
|
||||
<xs:sequence>
|
||||
<xs:element name="translation" type="translationType" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="translationType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="lang" type="xs:string" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
</xs:schema>
|
||||