").addClass(errClass).css("position", "absolute")
356 | .css("top", el.offsetTop)
357 | .css("left", el.offsetLeft)
358 | // setting width can push out the page size, forcing otherwise
359 | // unnecessary scrollbars to appear and making it impossible for
360 | // the element to shrink; so use max-width instead
361 | .css("maxWidth", el.offsetWidth)
362 | .css("height", el.offsetHeight);
363 | errorDiv.text(err.message);
364 | $el.after(errorDiv);
365 |
366 | // Really dumb way to keep the size/position of the error in sync with
367 | // the parent element as the window is resized or whatever.
368 | var intId = setInterval(function() {
369 | if (!errorDiv[0].parentElement) {
370 | clearInterval(intId);
371 | return;
372 | }
373 | errorDiv
374 | .css("top", el.offsetTop)
375 | .css("left", el.offsetLeft)
376 | .css("maxWidth", el.offsetWidth)
377 | .css("height", el.offsetHeight);
378 | }, 500);
379 | }
380 | }
381 | },
382 | clearError: function(el) {
383 | var $el = $(el);
384 | var display = $el.data("restore-display-mode");
385 | $el.data("restore-display-mode", null);
386 |
387 | if (display === "inline" || display === "inline-block") {
388 | if (display)
389 | $el.css("display", display);
390 | $(el.nextSibling).filter(".htmlwidgets-error").remove();
391 | } else if (display === "block"){
392 | $el.css("visibility", "inherit");
393 | $(el.nextSibling).filter(".htmlwidgets-error").remove();
394 | }
395 | },
396 | sizing: {}
397 | };
398 |
399 | // Called by widget bindings to register a new type of widget. The definition
400 | // object can contain the following properties:
401 | // - name (required) - A string indicating the binding name, which will be
402 | // used by default as the CSS classname to look for.
403 | // - initialize (optional) - A function(el) that will be called once per
404 | // widget element; if a value is returned, it will be passed as the third
405 | // value to renderValue.
406 | // - renderValue (required) - A function(el, data, initValue) that will be
407 | // called with data. Static contexts will cause this to be called once per
408 | // element; Shiny apps will cause this to be called multiple times per
409 | // element, as the data changes.
410 | window.HTMLWidgets.widget = function(definition) {
411 | if (!definition.name) {
412 | throw new Error("Widget must have a name");
413 | }
414 | if (!definition.type) {
415 | throw new Error("Widget must have a type");
416 | }
417 | // Currently we only support output widgets
418 | if (definition.type !== "output") {
419 | throw new Error("Unrecognized widget type '" + definition.type + "'");
420 | }
421 | // TODO: Verify that .name is a valid CSS classname
422 |
423 | // Support new-style instance-bound definitions. Old-style class-bound
424 | // definitions have one widget "object" per widget per type/class of
425 | // widget; the renderValue and resize methods on such widget objects
426 | // take el and instance arguments, because the widget object can't
427 | // store them. New-style instance-bound definitions have one widget
428 | // object per widget instance; the definition that's passed in doesn't
429 | // provide renderValue or resize methods at all, just the single method
430 | // factory(el, width, height)
431 | // which returns an object that has renderValue(x) and resize(w, h).
432 | // This enables a far more natural programming style for the widget
433 | // author, who can store per-instance state using either OO-style
434 | // instance fields or functional-style closure variables (I guess this
435 | // is in contrast to what can only be called C-style pseudo-OO which is
436 | // what we required before).
437 | if (definition.factory) {
438 | definition = createLegacyDefinitionAdapter(definition);
439 | }
440 |
441 | if (!definition.renderValue) {
442 | throw new Error("Widget must have a renderValue function");
443 | }
444 |
445 | // For static rendering (non-Shiny), use a simple widget registration
446 | // scheme. We also use this scheme for Shiny apps/documents that also
447 | // contain static widgets.
448 | window.HTMLWidgets.widgets = window.HTMLWidgets.widgets || [];
449 | // Merge defaults into the definition; don't mutate the original definition.
450 | var staticBinding = extend({}, defaults, definition);
451 | overrideMethod(staticBinding, "find", function(superfunc) {
452 | return function(scope) {
453 | var results = superfunc(scope);
454 | // Filter out Shiny outputs, we only want the static kind
455 | return filterByClass(results, "html-widget-output", false);
456 | };
457 | });
458 | window.HTMLWidgets.widgets.push(staticBinding);
459 |
460 | if (shinyMode) {
461 | // Shiny is running. Register the definition with an output binding.
462 | // The definition itself will not be the output binding, instead
463 | // we will make an output binding object that delegates to the
464 | // definition. This is because we foolishly used the same method
465 | // name (renderValue) for htmlwidgets definition and Shiny bindings
466 | // but they actually have quite different semantics (the Shiny
467 | // bindings receive data that includes lots of metadata that it
468 | // strips off before calling htmlwidgets renderValue). We can't
469 | // just ignore the difference because in some widgets it's helpful
470 | // to call this.renderValue() from inside of resize(), and if
471 | // we're not delegating, then that call will go to the Shiny
472 | // version instead of the htmlwidgets version.
473 |
474 | // Merge defaults with definition, without mutating either.
475 | var bindingDef = extend({}, defaults, definition);
476 |
477 | // This object will be our actual Shiny binding.
478 | var shinyBinding = new Shiny.OutputBinding();
479 |
480 | // With a few exceptions, we'll want to simply use the bindingDef's
481 | // version of methods if they are available, otherwise fall back to
482 | // Shiny's defaults. NOTE: If Shiny's output bindings gain additional
483 | // methods in the future, and we want them to be overrideable by
484 | // HTMLWidget binding definitions, then we'll need to add them to this
485 | // list.
486 | delegateMethod(shinyBinding, bindingDef, "getId");
487 | delegateMethod(shinyBinding, bindingDef, "onValueChange");
488 | delegateMethod(shinyBinding, bindingDef, "onValueError");
489 | delegateMethod(shinyBinding, bindingDef, "renderError");
490 | delegateMethod(shinyBinding, bindingDef, "clearError");
491 | delegateMethod(shinyBinding, bindingDef, "showProgress");
492 |
493 | // The find, renderValue, and resize are handled differently, because we
494 | // want to actually decorate the behavior of the bindingDef methods.
495 |
496 | shinyBinding.find = function(scope) {
497 | var results = bindingDef.find(scope);
498 |
499 | // Only return elements that are Shiny outputs, not static ones
500 | var dynamicResults = results.filter(".html-widget-output");
501 |
502 | // It's possible that whatever caused Shiny to think there might be
503 | // new dynamic outputs, also caused there to be new static outputs.
504 | // Since there might be lots of different htmlwidgets bindings, we
505 | // schedule execution for later--no need to staticRender multiple
506 | // times.
507 | if (results.length !== dynamicResults.length)
508 | scheduleStaticRender();
509 |
510 | return dynamicResults;
511 | };
512 |
513 | // Wrap renderValue to handle initialization, which unfortunately isn't
514 | // supported natively by Shiny at the time of this writing.
515 |
516 | shinyBinding.renderValue = function(el, data) {
517 | Shiny.renderDependencies(data.deps);
518 | // Resolve strings marked as javascript literals to objects
519 | if (!(data.evals instanceof Array)) data.evals = [data.evals];
520 | for (var i = 0; data.evals && i < data.evals.length; i++) {
521 | window.HTMLWidgets.evaluateStringMember(data.x, data.evals[i]);
522 | }
523 | if (!bindingDef.renderOnNullValue) {
524 | if (data.x === null) {
525 | el.style.visibility = "hidden";
526 | return;
527 | } else {
528 | el.style.visibility = "inherit";
529 | }
530 | }
531 | if (!elementData(el, "initialized")) {
532 | initSizing(el);
533 |
534 | elementData(el, "initialized", true);
535 | if (bindingDef.initialize) {
536 | var result = bindingDef.initialize(el, el.offsetWidth,
537 | el.offsetHeight);
538 | elementData(el, "init_result", result);
539 | }
540 | }
541 | bindingDef.renderValue(el, data.x, elementData(el, "init_result"));
542 | evalAndRun(data.jsHooks.render, elementData(el, "init_result"), [el, data.x]);
543 | };
544 |
545 | // Only override resize if bindingDef implements it
546 | if (bindingDef.resize) {
547 | shinyBinding.resize = function(el, width, height) {
548 | // Shiny can call resize before initialize/renderValue have been
549 | // called, which doesn't make sense for widgets.
550 | if (elementData(el, "initialized")) {
551 | bindingDef.resize(el, width, height, elementData(el, "init_result"));
552 | }
553 | };
554 | }
555 |
556 | Shiny.outputBindings.register(shinyBinding, bindingDef.name);
557 | }
558 | };
559 |
560 | var scheduleStaticRenderTimerId = null;
561 | function scheduleStaticRender() {
562 | if (!scheduleStaticRenderTimerId) {
563 | scheduleStaticRenderTimerId = setTimeout(function() {
564 | scheduleStaticRenderTimerId = null;
565 | window.HTMLWidgets.staticRender();
566 | }, 1);
567 | }
568 | }
569 |
570 | // Render static widgets after the document finishes loading
571 | // Statically render all elements that are of this widget's class
572 | window.HTMLWidgets.staticRender = function() {
573 | var bindings = window.HTMLWidgets.widgets || [];
574 | forEach(bindings, function(binding) {
575 | var matches = binding.find(document.documentElement);
576 | forEach(matches, function(el) {
577 | var sizeObj = initSizing(el, binding);
578 |
579 | if (hasClass(el, "html-widget-static-bound"))
580 | return;
581 | el.className = el.className + " html-widget-static-bound";
582 |
583 | var initResult;
584 | if (binding.initialize) {
585 | initResult = binding.initialize(el,
586 | sizeObj ? sizeObj.getWidth() : el.offsetWidth,
587 | sizeObj ? sizeObj.getHeight() : el.offsetHeight
588 | );
589 | elementData(el, "init_result", initResult);
590 | }
591 |
592 | if (binding.resize) {
593 | var lastSize = {
594 | w: sizeObj ? sizeObj.getWidth() : el.offsetWidth,
595 | h: sizeObj ? sizeObj.getHeight() : el.offsetHeight
596 | };
597 | var resizeHandler = function(e) {
598 | var size = {
599 | w: sizeObj ? sizeObj.getWidth() : el.offsetWidth,
600 | h: sizeObj ? sizeObj.getHeight() : el.offsetHeight
601 | };
602 | if (size.w === 0 && size.h === 0)
603 | return;
604 | if (size.w === lastSize.w && size.h === lastSize.h)
605 | return;
606 | lastSize = size;
607 | binding.resize(el, size.w, size.h, initResult);
608 | };
609 |
610 | on(window, "resize", resizeHandler);
611 |
612 | // This is needed for cases where we're running in a Shiny
613 | // app, but the widget itself is not a Shiny output, but
614 | // rather a simple static widget. One example of this is
615 | // an rmarkdown document that has runtime:shiny and widget
616 | // that isn't in a render function. Shiny only knows to
617 | // call resize handlers for Shiny outputs, not for static
618 | // widgets, so we do it ourselves.
619 | if (window.jQuery) {
620 | window.jQuery(document).on(
621 | "shown.htmlwidgets shown.bs.tab.htmlwidgets shown.bs.collapse.htmlwidgets",
622 | resizeHandler
623 | );
624 | window.jQuery(document).on(
625 | "hidden.htmlwidgets hidden.bs.tab.htmlwidgets hidden.bs.collapse.htmlwidgets",
626 | resizeHandler
627 | );
628 | }
629 |
630 | // This is needed for the specific case of ioslides, which
631 | // flips slides between display:none and display:block.
632 | // Ideally we would not have to have ioslide-specific code
633 | // here, but rather have ioslides raise a generic event,
634 | // but the rmarkdown package just went to CRAN so the
635 | // window to getting that fixed may be long.
636 | if (window.addEventListener) {
637 | // It's OK to limit this to window.addEventListener
638 | // browsers because ioslides itself only supports
639 | // such browsers.
640 | on(document, "slideenter", resizeHandler);
641 | on(document, "slideleave", resizeHandler);
642 | }
643 | }
644 |
645 | var scriptData = document.querySelector("script[data-for='" + el.id + "'][type='application/json']");
646 | if (scriptData) {
647 | var data = JSON.parse(scriptData.textContent || scriptData.text);
648 | // Resolve strings marked as javascript literals to objects
649 | if (!(data.evals instanceof Array)) data.evals = [data.evals];
650 | for (var k = 0; data.evals && k < data.evals.length; k++) {
651 | window.HTMLWidgets.evaluateStringMember(data.x, data.evals[k]);
652 | }
653 | binding.renderValue(el, data.x, initResult);
654 | evalAndRun(data.jsHooks.render, initResult, [el, data.x]);
655 | }
656 | });
657 | });
658 |
659 | invokePostRenderHandlers();
660 | }
661 |
662 |
663 | function has_jQuery3() {
664 | if (!window.jQuery) {
665 | return false;
666 | }
667 | var $version = window.jQuery.fn.jquery;
668 | var $major_version = parseInt($version.split(".")[0]);
669 | return $major_version >= 3;
670 | }
671 |
672 | /*
673 | / Shiny 1.4 bumped jQuery from 1.x to 3.x which means jQuery's
674 | / on-ready handler (i.e., $(fn)) is now asyncronous (i.e., it now
675 | / really means $(setTimeout(fn)).
676 | / https://jquery.com/upgrade-guide/3.0/#breaking-change-document-ready-handlers-are-now-asynchronous
677 | /
678 | / Since Shiny uses $() to schedule initShiny, shiny>=1.4 calls initShiny
679 | / one tick later than it did before, which means staticRender() is
680 | / called renderValue() earlier than (advanced) widget authors might be expecting.
681 | / https://github.com/rstudio/shiny/issues/2630
682 | /
683 | / For a concrete example, leaflet has some methods (e.g., updateBounds)
684 | / which reference Shiny methods registered in initShiny (e.g., setInputValue).
685 | / Since leaflet is privy to this life-cycle, it knows to use setTimeout() to
686 | / delay execution of those methods (until Shiny methods are ready)
687 | / https://github.com/rstudio/leaflet/blob/18ec981/javascript/src/index.js#L266-L268
688 | /
689 | / Ideally widget authors wouldn't need to use this setTimeout() hack that
690 | / leaflet uses to call Shiny methods on a staticRender(). In the long run,
691 | / the logic initShiny should be broken up so that method registration happens
692 | / right away, but binding happens later.
693 | */
694 | function maybeStaticRenderLater() {
695 | if (shinyMode && has_jQuery3()) {
696 | window.jQuery(window.HTMLWidgets.staticRender);
697 | } else {
698 | window.HTMLWidgets.staticRender();
699 | }
700 | }
701 |
702 | if (document.addEventListener) {
703 | document.addEventListener("DOMContentLoaded", function() {
704 | document.removeEventListener("DOMContentLoaded", arguments.callee, false);
705 | maybeStaticRenderLater();
706 | }, false);
707 | } else if (document.attachEvent) {
708 | document.attachEvent("onreadystatechange", function() {
709 | if (document.readyState === "complete") {
710 | document.detachEvent("onreadystatechange", arguments.callee);
711 | maybeStaticRenderLater();
712 | }
713 | });
714 | }
715 |
716 |
717 | window.HTMLWidgets.getAttachmentUrl = function(depname, key) {
718 | // If no key, default to the first item
719 | if (typeof(key) === "undefined")
720 | key = 1;
721 |
722 | var link = document.getElementById(depname + "-" + key + "-attachment");
723 | if (!link) {
724 | throw new Error("Attachment " + depname + "/" + key + " not found in document");
725 | }
726 | return link.getAttribute("href");
727 | };
728 |
729 | window.HTMLWidgets.dataframeToD3 = function(df) {
730 | var names = [];
731 | var length;
732 | for (var name in df) {
733 | if (df.hasOwnProperty(name))
734 | names.push(name);
735 | if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") {
736 | throw new Error("All fields must be arrays");
737 | } else if (typeof(length) !== "undefined" && length !== df[name].length) {
738 | throw new Error("All fields must be arrays of the same length");
739 | }
740 | length = df[name].length;
741 | }
742 | var results = [];
743 | var item;
744 | for (var row = 0; row < length; row++) {
745 | item = {};
746 | for (var col = 0; col < names.length; col++) {
747 | item[names[col]] = df[names[col]][row];
748 | }
749 | results.push(item);
750 | }
751 | return results;
752 | };
753 |
754 | window.HTMLWidgets.transposeArray2D = function(array) {
755 | if (array.length === 0) return array;
756 | var newArray = array[0].map(function(col, i) {
757 | return array.map(function(row) {
758 | return row[i]
759 | })
760 | });
761 | return newArray;
762 | };
763 | // Split value at splitChar, but allow splitChar to be escaped
764 | // using escapeChar. Any other characters escaped by escapeChar
765 | // will be included as usual (including escapeChar itself).
766 | function splitWithEscape(value, splitChar, escapeChar) {
767 | var results = [];
768 | var escapeMode = false;
769 | var currentResult = "";
770 | for (var pos = 0; pos < value.length; pos++) {
771 | if (!escapeMode) {
772 | if (value[pos] === splitChar) {
773 | results.push(currentResult);
774 | currentResult = "";
775 | } else if (value[pos] === escapeChar) {
776 | escapeMode = true;
777 | } else {
778 | currentResult += value[pos];
779 | }
780 | } else {
781 | currentResult += value[pos];
782 | escapeMode = false;
783 | }
784 | }
785 | if (currentResult !== "") {
786 | results.push(currentResult);
787 | }
788 | return results;
789 | }
790 | // Function authored by Yihui/JJ Allaire
791 | window.HTMLWidgets.evaluateStringMember = function(o, member) {
792 | var parts = splitWithEscape(member, '.', '\\');
793 | for (var i = 0, l = parts.length; i < l; i++) {
794 | var part = parts[i];
795 | // part may be a character or 'numeric' member name
796 | if (o !== null && typeof o === "object" && part in o) {
797 | if (i == (l - 1)) { // if we are at the end of the line then evalulate
798 | if (typeof o[part] === "string")
799 | o[part] = tryEval(o[part]);
800 | } else { // otherwise continue to next embedded object
801 | o = o[part];
802 | }
803 | }
804 | }
805 | };
806 |
807 | // Retrieve the HTMLWidget instance (i.e. the return value of an
808 | // HTMLWidget binding's initialize() or factory() function)
809 | // associated with an element, or null if none.
810 | window.HTMLWidgets.getInstance = function(el) {
811 | return elementData(el, "init_result");
812 | };
813 |
814 | // Finds the first element in the scope that matches the selector,
815 | // and returns the HTMLWidget instance (i.e. the return value of
816 | // an HTMLWidget binding's initialize() or factory() function)
817 | // associated with that element, if any. If no element matches the
818 | // selector, or the first matching element has no HTMLWidget
819 | // instance associated with it, then null is returned.
820 | //
821 | // The scope argument is optional, and defaults to window.document.
822 | window.HTMLWidgets.find = function(scope, selector) {
823 | if (arguments.length == 1) {
824 | selector = scope;
825 | scope = document;
826 | }
827 |
828 | var el = scope.querySelector(selector);
829 | if (el === null) {
830 | return null;
831 | } else {
832 | return window.HTMLWidgets.getInstance(el);
833 | }
834 | };
835 |
836 | // Finds all elements in the scope that match the selector, and
837 | // returns the HTMLWidget instances (i.e. the return values of
838 | // an HTMLWidget binding's initialize() or factory() function)
839 | // associated with the elements, in an array. If elements that
840 | // match the selector don't have an associated HTMLWidget
841 | // instance, the returned array will contain nulls.
842 | //
843 | // The scope argument is optional, and defaults to window.document.
844 | window.HTMLWidgets.findAll = function(scope, selector) {
845 | if (arguments.length == 1) {
846 | selector = scope;
847 | scope = document;
848 | }
849 |
850 | var nodes = scope.querySelectorAll(selector);
851 | var results = [];
852 | for (var i = 0; i < nodes.length; i++) {
853 | results.push(window.HTMLWidgets.getInstance(nodes[i]));
854 | }
855 | return results;
856 | };
857 |
858 | var postRenderHandlers = [];
859 | function invokePostRenderHandlers() {
860 | while (postRenderHandlers.length) {
861 | var handler = postRenderHandlers.shift();
862 | if (handler) {
863 | handler();
864 | }
865 | }
866 | }
867 |
868 | // Register the given callback function to be invoked after the
869 | // next time static widgets are rendered.
870 | window.HTMLWidgets.addPostRenderHandler = function(callback) {
871 | postRenderHandlers.push(callback);
872 | };
873 |
874 | // Takes a new-style instance-bound definition, and returns an
875 | // old-style class-bound definition. This saves us from having
876 | // to rewrite all the logic in this file to accomodate both
877 | // types of definitions.
878 | function createLegacyDefinitionAdapter(defn) {
879 | var result = {
880 | name: defn.name,
881 | type: defn.type,
882 | initialize: function(el, width, height) {
883 | return defn.factory(el, width, height);
884 | },
885 | renderValue: function(el, x, instance) {
886 | return instance.renderValue(x);
887 | },
888 | resize: function(el, width, height, instance) {
889 | return instance.resize(width, height);
890 | }
891 | };
892 |
893 | if (defn.find)
894 | result.find = defn.find;
895 | if (defn.renderError)
896 | result.renderError = defn.renderError;
897 | if (defn.clearError)
898 | result.clearError = defn.clearError;
899 |
900 | return result;
901 | }
902 | })();
903 |
904 |
--------------------------------------------------------------------------------
/libs/leaflet-providers-plugin/leaflet-providers-plugin.js:
--------------------------------------------------------------------------------
1 | LeafletWidget.methods.addProviderTiles = function(provider, layerId, group, options) {
2 | this.layerManager.addLayer(L.tileLayer.provider(provider, options), "tile", layerId, group);
3 | };
4 |
--------------------------------------------------------------------------------
/libs/leaflet-providers/leaflet-providers_1.9.0.js:
--------------------------------------------------------------------------------
1 | (function (root, factory) {
2 | if (typeof define === 'function' && define.amd) {
3 | // AMD. Register as an anonymous module.
4 | define(['leaflet'], factory);
5 | } else if (typeof modules === 'object' && module.exports) {
6 | // define a Common JS module that relies on 'leaflet'
7 | module.exports = factory(require('leaflet'));
8 | } else {
9 | // Assume Leaflet is loaded into global object L already
10 | factory(L);
11 | }
12 | }(this, function (L) {
13 | 'use strict';
14 |
15 | L.TileLayer.Provider = L.TileLayer.extend({
16 | initialize: function (arg, options) {
17 | var providers = L.TileLayer.Provider.providers;
18 |
19 | var parts = arg.split('.');
20 |
21 | var providerName = parts[0];
22 | var variantName = parts[1];
23 |
24 | if (!providers[providerName]) {
25 | throw 'No such provider (' + providerName + ')';
26 | }
27 |
28 | var provider = {
29 | url: providers[providerName].url,
30 | options: providers[providerName].options
31 | };
32 |
33 | // overwrite values in provider from variant.
34 | if (variantName && 'variants' in providers[providerName]) {
35 | if (!(variantName in providers[providerName].variants)) {
36 | throw 'No such variant of ' + providerName + ' (' + variantName + ')';
37 | }
38 | var variant = providers[providerName].variants[variantName];
39 | var variantOptions;
40 | if (typeof variant === 'string') {
41 | variantOptions = {
42 | variant: variant
43 | };
44 | } else {
45 | variantOptions = variant.options;
46 | }
47 | provider = {
48 | url: variant.url || provider.url,
49 | options: L.Util.extend({}, provider.options, variantOptions)
50 | };
51 | }
52 |
53 | // replace attribution placeholders with their values from toplevel provider attribution,
54 | // recursively
55 | var attributionReplacer = function (attr) {
56 | if (attr.indexOf('{attribution.') === -1) {
57 | return attr;
58 | }
59 | return attr.replace(/\{attribution.(\w*)\}/g,
60 | function (match, attributionName) {
61 | return attributionReplacer(providers[attributionName].options.attribution);
62 | }
63 | );
64 | };
65 | provider.options.attribution = attributionReplacer(provider.options.attribution);
66 |
67 | // Compute final options combining provider options with any user overrides
68 | var layerOpts = L.Util.extend({}, provider.options, options);
69 | L.TileLayer.prototype.initialize.call(this, provider.url, layerOpts);
70 | }
71 | });
72 |
73 | /**
74 | * Definition of providers.
75 | * see http://leafletjs.com/reference.html#tilelayer for options in the options map.
76 | */
77 |
78 | L.TileLayer.Provider.providers = {
79 | OpenStreetMap: {
80 | url: '//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
81 | options: {
82 | maxZoom: 19,
83 | attribution:
84 | '©
OpenStreetMap contributors'
85 | },
86 | variants: {
87 | Mapnik: {},
88 | DE: {
89 | url: '//{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png',
90 | options: {
91 | maxZoom: 18
92 | }
93 | },
94 | CH: {
95 | url: '//tile.osm.ch/switzerland/{z}/{x}/{y}.png',
96 | options: {
97 | maxZoom: 18,
98 | bounds: [[45, 5], [48, 11]]
99 | }
100 | },
101 | France: {
102 | url: '//{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png',
103 | options: {
104 | maxZoom: 20,
105 | attribution: '© Openstreetmap France | {attribution.OpenStreetMap}'
106 | }
107 | },
108 | HOT: {
109 | url: '//{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png',
110 | options: {
111 | attribution:
112 | '{attribution.OpenStreetMap}, ' +
113 | 'Tiles style by
Humanitarian OpenStreetMap Team ' +
114 | 'hosted by
OpenStreetMap France'
115 | }
116 | },
117 | BZH: {
118 | url: '//tile.openstreetmap.bzh/br/{z}/{x}/{y}.png',
119 | options: {
120 | attribution: '{attribution.OpenStreetMap}, Tiles courtesy of
Breton OpenStreetMap Team',
121 | bounds: [[46.2, -5.5], [50, 0.7]]
122 | }
123 | }
124 | }
125 | },
126 | OpenSeaMap: {
127 | url: '//tiles.openseamap.org/seamark/{z}/{x}/{y}.png',
128 | options: {
129 | attribution: 'Map data: ©
OpenSeaMap contributors'
130 | }
131 | },
132 | OpenPtMap: {
133 | url: 'http://openptmap.org/tiles/{z}/{x}/{y}.png',
134 | options: {
135 | maxZoom: 17,
136 | attribution: 'Map data: ©
OpenPtMap contributors'
137 | }
138 | },
139 | OpenTopoMap: {
140 | url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
141 | options: {
142 | maxZoom: 17,
143 | attribution: 'Map data: {attribution.OpenStreetMap},
SRTM | Map style: ©
OpenTopoMap (
CC-BY-SA)'
144 | }
145 | },
146 | OpenRailwayMap: {
147 | url: 'https://{s}.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png',
148 | options: {
149 | maxZoom: 19,
150 | attribution: 'Map data: {attribution.OpenStreetMap} | Map style: ©
OpenRailwayMap (
CC-BY-SA)'
151 | }
152 | },
153 | OpenFireMap: {
154 | url: 'http://openfiremap.org/hytiles/{z}/{x}/{y}.png',
155 | options: {
156 | maxZoom: 19,
157 | attribution: 'Map data: {attribution.OpenStreetMap} | Map style: ©
OpenFireMap (
CC-BY-SA)'
158 | }
159 | },
160 | SafeCast: {
161 | url: '//s3.amazonaws.com/te512.safecast.org/{z}/{x}/{y}.png',
162 | options: {
163 | maxZoom: 16,
164 | attribution: 'Map data: {attribution.OpenStreetMap} | Map style: ©
SafeCast (
CC-BY-SA)'
165 | }
166 | },
167 | Thunderforest: {
168 | url: 'https://{s}.tile.thunderforest.com/{variant}/{z}/{x}/{y}.png?apikey={apikey}',
169 | options: {
170 | attribution:
171 | '©
Thunderforest, {attribution.OpenStreetMap}',
172 | variant: 'cycle',
173 | apikey: '
',
174 | maxZoom: 22
175 | },
176 | variants: {
177 | OpenCycleMap: 'cycle',
178 | Transport: {
179 | options: {
180 | variant: 'transport'
181 | }
182 | },
183 | TransportDark: {
184 | options: {
185 | variant: 'transport-dark'
186 | }
187 | },
188 | SpinalMap: {
189 | options: {
190 | variant: 'spinal-map'
191 | }
192 | },
193 | Landscape: 'landscape',
194 | Outdoors: 'outdoors',
195 | Pioneer: 'pioneer',
196 | MobileAtlas: 'mobile-atlas',
197 | Neighbourhood: 'neighbourhood'
198 | }
199 | },
200 | OpenMapSurfer: {
201 | url: 'https://maps.heigit.org/openmapsurfer/tiles/{variant}/webmercator/{z}/{x}/{y}.png',
202 | options: {
203 | maxZoom: 19,
204 | variant: 'roads',
205 | attribution: 'Imagery from GIScience Research Group @ University of Heidelberg | Map data '
206 | },
207 | variants: {
208 | Roads: {
209 | options: {
210 | variant: 'roads',
211 | attribution: '{attribution.OpenMapSurfer}{attribution.OpenStreetMap}'
212 | }
213 | },
214 | Hybrid: {
215 | options: {
216 | variant: 'hybrid',
217 | attribution: '{attribution.OpenMapSurfer}{attribution.OpenStreetMap}'
218 | }
219 | },
220 | AdminBounds: {
221 | options: {
222 | variant: 'adminb',
223 | maxZoom: 18,
224 | attribution: '{attribution.OpenMapSurfer}{attribution.OpenStreetMap}'
225 | }
226 | },
227 | ContourLines: {
228 | options: {
229 | variant: 'asterc',
230 | maxZoom: 18,
231 | minZoom: 13,
232 | attribution: '{attribution.OpenMapSurfer} ASTER GDEM'
233 | }
234 | },
235 | Hillshade: {
236 | options: {
237 | variant: 'asterh',
238 | maxZoom: 18,
239 | attribution: '{attribution.OpenMapSurfer} ASTER GDEM, SRTM'
240 | }
241 | },
242 | ElementsAtRisk: {
243 | options: {
244 | variant: 'elements_at_risk',
245 | attribution: '{attribution.OpenMapSurfer}{attribution.OpenStreetMap}'
246 | }
247 | }
248 | }
249 | },
250 | Hydda: {
251 | url: '//{s}.tile.openstreetmap.se/hydda/{variant}/{z}/{x}/{y}.png',
252 | options: {
253 | maxZoom: 18,
254 | variant: 'full',
255 | attribution: 'Tiles courtesy of OpenStreetMap Sweden — Map data {attribution.OpenStreetMap}'
256 | },
257 | variants: {
258 | Full: 'full',
259 | Base: 'base',
260 | RoadsAndLabels: 'roads_and_labels'
261 | }
262 | },
263 | MapBox: {
264 | url: 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}{r}.png?access_token={accessToken}',
265 | options: {
266 | attribution:
267 | '© Mapbox ' +
268 | '{attribution.OpenStreetMap} ' +
269 | 'Improve this map',
270 | subdomains: 'abcd',
271 | id: 'mapbox.streets',
272 | accessToken: '',
273 | }
274 | },
275 | Stamen: {
276 | url: '//stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}{r}.{ext}',
277 | options: {
278 | attribution:
279 | 'Map tiles by Stamen Design, ' +
280 | 'CC BY 3.0 — ' +
281 | 'Map data {attribution.OpenStreetMap}',
282 | subdomains: 'abcd',
283 | minZoom: 0,
284 | maxZoom: 20,
285 | variant: 'toner',
286 | ext: 'png'
287 | },
288 | variants: {
289 | Toner: 'toner',
290 | TonerBackground: 'toner-background',
291 | TonerHybrid: 'toner-hybrid',
292 | TonerLines: 'toner-lines',
293 | TonerLabels: 'toner-labels',
294 | TonerLite: 'toner-lite',
295 | Watercolor: {
296 | url: '//stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}.{ext}',
297 | options: {
298 | variant: 'watercolor',
299 | ext: 'jpg',
300 | minZoom: 1,
301 | maxZoom: 16
302 | }
303 | },
304 | Terrain: {
305 | options: {
306 | variant: 'terrain',
307 | minZoom: 0,
308 | maxZoom: 18
309 | }
310 | },
311 | TerrainBackground: {
312 | options: {
313 | variant: 'terrain-background',
314 | minZoom: 0,
315 | maxZoom: 18
316 | }
317 | },
318 | TerrainLabels: {
319 | options: {
320 | variant: 'terrain-labels',
321 | minZoom: 0,
322 | maxZoom: 18
323 | }
324 | },
325 | TopOSMRelief: {
326 | url: '//stamen-tiles-{s}.a.ssl.fastly.net/{variant}/{z}/{x}/{y}.{ext}',
327 | options: {
328 | variant: 'toposm-color-relief',
329 | ext: 'jpg',
330 | bounds: [[22, -132], [51, -56]]
331 | }
332 | },
333 | TopOSMFeatures: {
334 | options: {
335 | variant: 'toposm-features',
336 | bounds: [[22, -132], [51, -56]],
337 | opacity: 0.9
338 | }
339 | }
340 | }
341 | },
342 | TomTom: {
343 | url: 'https://{s}.api.tomtom.com/map/1/tile/{variant}/{style}/{z}/{x}/{y}.{ext}?key={apikey}',
344 | options: {
345 | variant: 'basic',
346 | maxZoom: 22,
347 | attribution:
348 | '© 1992 - ' + new Date().getFullYear() + ' TomTom. ',
349 | subdomains: 'abcd',
350 | style: 'main',
351 | ext: 'png',
352 | apikey: '',
353 | },
354 | variants: {
355 | Basic: 'basic',
356 | Hybrid: 'hybrid',
357 | Labels: 'labels'
358 | }
359 | },
360 | Esri: {
361 | url: '//server.arcgisonline.com/ArcGIS/rest/services/{variant}/MapServer/tile/{z}/{y}/{x}',
362 | options: {
363 | variant: 'World_Street_Map',
364 | attribution: 'Tiles © Esri'
365 | },
366 | variants: {
367 | WorldStreetMap: {
368 | options: {
369 | attribution:
370 | '{attribution.Esri} — ' +
371 | 'Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong), Esri (Thailand), TomTom, 2012'
372 | }
373 | },
374 | DeLorme: {
375 | options: {
376 | variant: 'Specialty/DeLorme_World_Base_Map',
377 | minZoom: 1,
378 | maxZoom: 11,
379 | attribution: '{attribution.Esri} — Copyright: ©2012 DeLorme'
380 | }
381 | },
382 | WorldTopoMap: {
383 | options: {
384 | variant: 'World_Topo_Map',
385 | attribution:
386 | '{attribution.Esri} — ' +
387 | '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'
388 | }
389 | },
390 | WorldImagery: {
391 | options: {
392 | variant: 'World_Imagery',
393 | attribution:
394 | '{attribution.Esri} — ' +
395 | 'Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
396 | }
397 | },
398 | WorldTerrain: {
399 | options: {
400 | variant: 'World_Terrain_Base',
401 | maxZoom: 13,
402 | attribution:
403 | '{attribution.Esri} — ' +
404 | 'Source: USGS, Esri, TANA, DeLorme, and NPS'
405 | }
406 | },
407 | WorldShadedRelief: {
408 | options: {
409 | variant: 'World_Shaded_Relief',
410 | maxZoom: 13,
411 | attribution: '{attribution.Esri} — Source: Esri'
412 | }
413 | },
414 | WorldPhysical: {
415 | options: {
416 | variant: 'World_Physical_Map',
417 | maxZoom: 8,
418 | attribution: '{attribution.Esri} — Source: US National Park Service'
419 | }
420 | },
421 | OceanBasemap: {
422 | options: {
423 | variant: 'Ocean_Basemap',
424 | maxZoom: 13,
425 | attribution: '{attribution.Esri} — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri'
426 | }
427 | },
428 | NatGeoWorldMap: {
429 | options: {
430 | variant: 'NatGeo_World_Map',
431 | maxZoom: 16,
432 | attribution: '{attribution.Esri} — National Geographic, Esri, DeLorme, NAVTEQ, UNEP-WCMC, USGS, NASA, ESA, METI, NRCAN, GEBCO, NOAA, iPC'
433 | }
434 | },
435 | WorldGrayCanvas: {
436 | options: {
437 | variant: 'Canvas/World_Light_Gray_Base',
438 | maxZoom: 16,
439 | attribution: '{attribution.Esri} — Esri, DeLorme, NAVTEQ'
440 | }
441 | }
442 | }
443 | },
444 | OpenWeatherMap: {
445 | url: 'http://{s}.tile.openweathermap.org/map/{variant}/{z}/{x}/{y}.png?appid={apiKey}',
446 | options: {
447 | maxZoom: 19,
448 | attribution: 'Map data © OpenWeatherMap',
449 | apiKey:'',
450 | opacity: 0.5
451 | },
452 | variants: {
453 | Clouds: 'clouds',
454 | CloudsClassic: 'clouds_cls',
455 | Precipitation: 'precipitation',
456 | PrecipitationClassic: 'precipitation_cls',
457 | Rain: 'rain',
458 | RainClassic: 'rain_cls',
459 | Pressure: 'pressure',
460 | PressureContour: 'pressure_cntr',
461 | Wind: 'wind',
462 | Temperature: 'temp',
463 | Snow: 'snow'
464 | }
465 | },
466 | HERE: {
467 | /*
468 | * HERE maps, formerly Nokia maps.
469 | * These basemaps are free, but you need an API key. Please sign up at
470 | * https://developer.here.com/plans
471 | */
472 | url:
473 | 'https://{s}.{base}.maps.api.here.com/maptile/2.1/' +
474 | '{type}/{mapID}/{variant}/{z}/{x}/{y}/{size}/{format}?' +
475 | 'app_id={app_id}&app_code={app_code}&lg={language}',
476 | options: {
477 | attribution:
478 | 'Map © 1987-' + new Date().getFullYear() + ' HERE',
479 | subdomains: '1234',
480 | mapID: 'newest',
481 | 'app_id': '',
482 | 'app_code': '',
483 | base: 'base',
484 | variant: 'normal.day',
485 | maxZoom: 20,
486 | type: 'maptile',
487 | language: 'eng',
488 | format: 'png8',
489 | size: '256'
490 | },
491 | variants: {
492 | normalDay: 'normal.day',
493 | normalDayCustom: 'normal.day.custom',
494 | normalDayGrey: 'normal.day.grey',
495 | normalDayMobile: 'normal.day.mobile',
496 | normalDayGreyMobile: 'normal.day.grey.mobile',
497 | normalDayTransit: 'normal.day.transit',
498 | normalDayTransitMobile: 'normal.day.transit.mobile',
499 | normalDayTraffic: {
500 | options: {
501 | variant: 'normal.traffic.day',
502 | base: 'traffic',
503 | type: 'traffictile'
504 | }
505 | },
506 | normalNight: 'normal.night',
507 | normalNightMobile: 'normal.night.mobile',
508 | normalNightGrey: 'normal.night.grey',
509 | normalNightGreyMobile: 'normal.night.grey.mobile',
510 | normalNightTransit: 'normal.night.transit',
511 | normalNightTransitMobile: 'normal.night.transit.mobile',
512 | reducedDay: 'reduced.day',
513 | reducedNight: 'reduced.night',
514 | basicMap: {
515 | options: {
516 | type: 'basetile'
517 | }
518 | },
519 | mapLabels: {
520 | options: {
521 | type: 'labeltile',
522 | format: 'png'
523 | }
524 | },
525 | trafficFlow: {
526 | options: {
527 | base: 'traffic',
528 | type: 'flowtile'
529 | }
530 | },
531 | carnavDayGrey: 'carnav.day.grey',
532 | hybridDay: {
533 | options: {
534 | base: 'aerial',
535 | variant: 'hybrid.day'
536 | }
537 | },
538 | hybridDayMobile: {
539 | options: {
540 | base: 'aerial',
541 | variant: 'hybrid.day.mobile'
542 | }
543 | },
544 | hybridDayTransit: {
545 | options: {
546 | base: 'aerial',
547 | variant: 'hybrid.day.transit'
548 | }
549 | },
550 | hybridDayGrey: {
551 | options: {
552 | base: 'aerial',
553 | variant: 'hybrid.grey.day'
554 | }
555 | },
556 | hybridDayTraffic: {
557 | options: {
558 | variant: 'hybrid.traffic.day',
559 | base: 'traffic',
560 | type: 'traffictile'
561 | }
562 | },
563 | pedestrianDay: 'pedestrian.day',
564 | pedestrianNight: 'pedestrian.night',
565 | satelliteDay: {
566 | options: {
567 | base: 'aerial',
568 | variant: 'satellite.day'
569 | }
570 | },
571 | terrainDay: {
572 | options: {
573 | base: 'aerial',
574 | variant: 'terrain.day'
575 | }
576 | },
577 | terrainDayMobile: {
578 | options: {
579 | base: 'aerial',
580 | variant: 'terrain.day.mobile'
581 | }
582 | }
583 | }
584 | },
585 | FreeMapSK: {
586 | url: 'http://t{s}.freemap.sk/T/{z}/{x}/{y}.jpeg',
587 | options: {
588 | minZoom: 8,
589 | maxZoom: 16,
590 | subdomains: '1234',
591 | bounds: [[47.204642, 15.996093], [49.830896, 22.576904]],
592 | attribution:
593 | '{attribution.OpenStreetMap}, vizualization CC-By-SA 2.0 Freemap.sk'
594 | }
595 | },
596 | MtbMap: {
597 | url: 'http://tile.mtbmap.cz/mtbmap_tiles/{z}/{x}/{y}.png',
598 | options: {
599 | attribution:
600 | '{attribution.OpenStreetMap} & USGS'
601 | }
602 | },
603 | CartoDB: {
604 | url: 'https://{s}.basemaps.cartocdn.com/{variant}/{z}/{x}/{y}{r}.png',
605 | options: {
606 | attribution: '{attribution.OpenStreetMap} © CARTO',
607 | subdomains: 'abcd',
608 | maxZoom: 19,
609 | variant: 'light_all'
610 | },
611 | variants: {
612 | Positron: 'light_all',
613 | PositronNoLabels: 'light_nolabels',
614 | PositronOnlyLabels: 'light_only_labels',
615 | DarkMatter: 'dark_all',
616 | DarkMatterNoLabels: 'dark_nolabels',
617 | DarkMatterOnlyLabels: 'dark_only_labels',
618 | Voyager: 'rastertiles/voyager',
619 | VoyagerNoLabels: 'rastertiles/voyager_nolabels',
620 | VoyagerOnlyLabels: 'rastertiles/voyager_only_labels',
621 | VoyagerLabelsUnder: 'rastertiles/voyager_labels_under'
622 | }
623 | },
624 | HikeBike: {
625 | url: 'https://tiles.wmflabs.org/{variant}/{z}/{x}/{y}.png',
626 | options: {
627 | maxZoom: 19,
628 | attribution: '{attribution.OpenStreetMap}',
629 | variant: 'hikebike'
630 | },
631 | variants: {
632 | HikeBike: {},
633 | HillShading: {
634 | options: {
635 | maxZoom: 15,
636 | variant: 'hillshading'
637 | }
638 | }
639 | }
640 | },
641 | BasemapAT: {
642 | url: '//maps{s}.wien.gv.at/basemap/{variant}/normal/google3857/{z}/{y}/{x}.{format}',
643 | options: {
644 | maxZoom: 19,
645 | attribution: 'Datenquelle: basemap.at',
646 | subdomains: ['', '1', '2', '3', '4'],
647 | format: 'png',
648 | bounds: [[46.358770, 8.782379], [49.037872, 17.189532]],
649 | variant: 'geolandbasemap'
650 | },
651 | variants: {
652 | basemap: {
653 | options: {
654 | maxZoom: 20, // currently only in Vienna
655 | variant: 'geolandbasemap'
656 | }
657 | },
658 | grau: 'bmapgrau',
659 | overlay: 'bmapoverlay',
660 | highdpi: {
661 | options: {
662 | variant: 'bmaphidpi',
663 | format: 'jpeg'
664 | }
665 | },
666 | orthofoto: {
667 | options: {
668 | maxZoom: 20, // currently only in Vienna
669 | variant: 'bmaporthofoto30cm',
670 | format: 'jpeg'
671 | }
672 | }
673 | }
674 | },
675 | nlmaps: {
676 | url: '//geodata.nationaalgeoregister.nl/tiles/service/wmts/{variant}/EPSG:3857/{z}/{x}/{y}.png',
677 | options: {
678 | minZoom: 6,
679 | maxZoom: 19,
680 | bounds: [[50.5, 3.25], [54, 7.6]],
681 | attribution: 'Kaartgegevens © Kadaster'
682 | },
683 | variants: {
684 | 'standaard': 'brtachtergrondkaart',
685 | 'pastel': 'brtachtergrondkaartpastel',
686 | 'grijs': 'brtachtergrondkaartgrijs',
687 | 'luchtfoto': {
688 | 'url': '//geodata.nationaalgeoregister.nl/luchtfoto/rgb/wmts/1.0.0/2016_ortho25/EPSG:3857/{z}/{x}/{y}.png',
689 | }
690 | }
691 | },
692 | NASAGIBS: {
693 | url: 'https://map1.vis.earthdata.nasa.gov/wmts-webmerc/{variant}/default/{time}/{tilematrixset}{maxZoom}/{z}/{y}/{x}.{format}',
694 | options: {
695 | attribution:
696 | 'Imagery provided by services from the Global Imagery Browse Services (GIBS), operated by the NASA/GSFC/Earth Science Data and Information System ' +
697 | '(ESDIS) with funding provided by NASA/HQ.',
698 | bounds: [[-85.0511287776, -179.999999975], [85.0511287776, 179.999999975]],
699 | minZoom: 1,
700 | maxZoom: 9,
701 | format: 'jpg',
702 | time: '',
703 | tilematrixset: 'GoogleMapsCompatible_Level'
704 | },
705 | variants: {
706 | ModisTerraTrueColorCR: 'MODIS_Terra_CorrectedReflectance_TrueColor',
707 | ModisTerraBands367CR: 'MODIS_Terra_CorrectedReflectance_Bands367',
708 | ViirsEarthAtNight2012: {
709 | options: {
710 | variant: 'VIIRS_CityLights_2012',
711 | maxZoom: 8
712 | }
713 | },
714 | ModisTerraLSTDay: {
715 | options: {
716 | variant: 'MODIS_Terra_Land_Surface_Temp_Day',
717 | format: 'png',
718 | maxZoom: 7,
719 | opacity: 0.75
720 | }
721 | },
722 | ModisTerraSnowCover: {
723 | options: {
724 | variant: 'MODIS_Terra_Snow_Cover',
725 | format: 'png',
726 | maxZoom: 8,
727 | opacity: 0.75
728 | }
729 | },
730 | ModisTerraAOD: {
731 | options: {
732 | variant: 'MODIS_Terra_Aerosol',
733 | format: 'png',
734 | maxZoom: 6,
735 | opacity: 0.75
736 | }
737 | },
738 | ModisTerraChlorophyll: {
739 | options: {
740 | variant: 'MODIS_Terra_Chlorophyll_A',
741 | format: 'png',
742 | maxZoom: 7,
743 | opacity: 0.75
744 | }
745 | }
746 | }
747 | },
748 | NLS: {
749 | // NLS maps are copyright National library of Scotland.
750 | // http://maps.nls.uk/projects/api/index.html
751 | // Please contact NLS for anything other than non-commercial low volume usage
752 | //
753 | // Map sources: Ordnance Survey 1:1m to 1:63K, 1920s-1940s
754 | // z0-9 - 1:1m
755 | // z10-11 - quarter inch (1:253440)
756 | // z12-18 - one inch (1:63360)
757 | url: '//nls-{s}.tileserver.com/nls/{z}/{x}/{y}.jpg',
758 | options: {
759 | attribution: 'National Library of Scotland Historic Maps',
760 | bounds: [[49.6, -12], [61.7, 3]],
761 | minZoom: 1,
762 | maxZoom: 18,
763 | subdomains: '0123',
764 | }
765 | },
766 | JusticeMap: {
767 | // Justice Map (http://www.justicemap.org/)
768 | // Visualize race and income data for your community, county and country.
769 | // Includes tools for data journalists, bloggers and community activists.
770 | url: 'http://www.justicemap.org/tile/{size}/{variant}/{z}/{x}/{y}.png',
771 | options: {
772 | attribution: 'Justice Map',
773 | // one of 'county', 'tract', 'block'
774 | size: 'county',
775 | // Bounds for USA, including Alaska and Hawaii
776 | bounds: [[14, -180], [72, -56]]
777 | },
778 | variants: {
779 | income: 'income',
780 | americanIndian: 'indian',
781 | asian: 'asian',
782 | black: 'black',
783 | hispanic: 'hispanic',
784 | multi: 'multi',
785 | nonWhite: 'nonwhite',
786 | white: 'white',
787 | plurality: 'plural'
788 | }
789 | },
790 | Wikimedia: {
791 | url: 'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}{r}.png',
792 | options: {
793 | attribution: 'Wikimedia',
794 | minZoom: 1,
795 | maxZoom: 19
796 | }
797 | },
798 | GeoportailFrance: {
799 | url: 'https://wxs.ign.fr/{apikey}/geoportail/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE={style}&TILEMATRIXSET=PM&FORMAT={format}&LAYER={variant}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}',
800 | options: {
801 | attribution: 'Geoportail France',
802 | bounds: [[-75, -180], [81, 180]],
803 | minZoom: 2,
804 | maxZoom: 18,
805 | // Get your own geoportail apikey here : http://professionnels.ign.fr/ign/contrats/
806 | // NB : 'choisirgeoportail' is a demonstration key that comes with no guarantee
807 | apikey: 'choisirgeoportail',
808 | format: 'image/jpeg',
809 | style : 'normal',
810 | variant: 'GEOGRAPHICALGRIDSYSTEMS.MAPS.SCAN-EXPRESS.STANDARD'
811 | },
812 | variants: {
813 | parcels: {
814 | options : {
815 | variant: 'CADASTRALPARCELS.PARCELS',
816 | maxZoom: 20,
817 | style : 'bdparcellaire',
818 | format: 'image/png'
819 | }
820 | },
821 | ignMaps: 'GEOGRAPHICALGRIDSYSTEMS.MAPS',
822 | maps: 'GEOGRAPHICALGRIDSYSTEMS.MAPS.SCAN-EXPRESS.STANDARD',
823 | orthos: {
824 | options: {
825 | maxZoom: 19,
826 | variant: 'ORTHOIMAGERY.ORTHOPHOTOS'
827 | }
828 | }
829 | }
830 | },
831 | OneMapSG: {
832 | url: '//maps-{s}.onemap.sg/v3/{variant}/{z}/{x}/{y}.png',
833 | options: {
834 | variant: 'Default',
835 | minZoom: 11,
836 | maxZoom: 18,
837 | bounds: [[1.56073, 104.11475], [1.16, 103.502]],
838 | attribution: '
New OneMap | Map data © contributors, Singapore Land Authority'
839 | },
840 | variants: {
841 | Default: 'Default',
842 | Night: 'Night',
843 | Original: 'Original',
844 | Grey: 'Grey',
845 | LandLot: 'LandLot'
846 | }
847 | }
848 | };
849 |
850 | L.tileLayer.provider = function (provider, options) {
851 | return new L.TileLayer.Provider(provider, options);
852 | };
853 |
854 | return L;
855 | }));
856 |
--------------------------------------------------------------------------------
/libs/leaflet/images/layers-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RamiKrispin/gis-dataviz-workshop/cbdee699fcaf68becc652d4efc1599b23761eaad/libs/leaflet/images/layers-2x.png
--------------------------------------------------------------------------------
/libs/leaflet/images/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RamiKrispin/gis-dataviz-workshop/cbdee699fcaf68becc652d4efc1599b23761eaad/libs/leaflet/images/layers.png
--------------------------------------------------------------------------------
/libs/leaflet/images/marker-icon-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RamiKrispin/gis-dataviz-workshop/cbdee699fcaf68becc652d4efc1599b23761eaad/libs/leaflet/images/marker-icon-2x.png
--------------------------------------------------------------------------------
/libs/leaflet/images/marker-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RamiKrispin/gis-dataviz-workshop/cbdee699fcaf68becc652d4efc1599b23761eaad/libs/leaflet/images/marker-icon.png
--------------------------------------------------------------------------------
/libs/leaflet/images/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RamiKrispin/gis-dataviz-workshop/cbdee699fcaf68becc652d4efc1599b23761eaad/libs/leaflet/images/marker-shadow.png
--------------------------------------------------------------------------------
/libs/leaflet/leaflet.css:
--------------------------------------------------------------------------------
1 | /* required styles */
2 |
3 | .leaflet-pane,
4 | .leaflet-tile,
5 | .leaflet-marker-icon,
6 | .leaflet-marker-shadow,
7 | .leaflet-tile-container,
8 | .leaflet-pane > svg,
9 | .leaflet-pane > canvas,
10 | .leaflet-zoom-box,
11 | .leaflet-image-layer,
12 | .leaflet-layer {
13 | position: absolute;
14 | left: 0;
15 | top: 0;
16 | }
17 | .leaflet-container {
18 | overflow: hidden;
19 | }
20 | .leaflet-tile,
21 | .leaflet-marker-icon,
22 | .leaflet-marker-shadow {
23 | -webkit-user-select: none;
24 | -moz-user-select: none;
25 | user-select: none;
26 | -webkit-user-drag: none;
27 | }
28 | /* Safari renders non-retina tile on retina better with this, but Chrome is worse */
29 | .leaflet-safari .leaflet-tile {
30 | image-rendering: -webkit-optimize-contrast;
31 | }
32 | /* hack that prevents hw layers "stretching" when loading new tiles */
33 | .leaflet-safari .leaflet-tile-container {
34 | width: 1600px;
35 | height: 1600px;
36 | -webkit-transform-origin: 0 0;
37 | }
38 | .leaflet-marker-icon,
39 | .leaflet-marker-shadow {
40 | display: block;
41 | }
42 | /* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
43 | /* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
44 | .leaflet-container .leaflet-overlay-pane svg,
45 | .leaflet-container .leaflet-marker-pane img,
46 | .leaflet-container .leaflet-shadow-pane img,
47 | .leaflet-container .leaflet-tile-pane img,
48 | .leaflet-container img.leaflet-image-layer {
49 | max-width: none !important;
50 | max-height: none !important;
51 | }
52 |
53 | .leaflet-container.leaflet-touch-zoom {
54 | -ms-touch-action: pan-x pan-y;
55 | touch-action: pan-x pan-y;
56 | }
57 | .leaflet-container.leaflet-touch-drag {
58 | -ms-touch-action: pinch-zoom;
59 | /* Fallback for FF which doesn't support pinch-zoom */
60 | touch-action: none;
61 | touch-action: pinch-zoom;
62 | }
63 | .leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
64 | -ms-touch-action: none;
65 | touch-action: none;
66 | }
67 | .leaflet-container {
68 | -webkit-tap-highlight-color: transparent;
69 | }
70 | .leaflet-container a {
71 | -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
72 | }
73 | .leaflet-tile {
74 | filter: inherit;
75 | visibility: hidden;
76 | }
77 | .leaflet-tile-loaded {
78 | visibility: inherit;
79 | }
80 | .leaflet-zoom-box {
81 | width: 0;
82 | height: 0;
83 | -moz-box-sizing: border-box;
84 | box-sizing: border-box;
85 | z-index: 800;
86 | }
87 | /* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
88 | .leaflet-overlay-pane svg {
89 | -moz-user-select: none;
90 | }
91 |
92 | .leaflet-pane { z-index: 400; }
93 |
94 | .leaflet-tile-pane { z-index: 200; }
95 | .leaflet-overlay-pane { z-index: 400; }
96 | .leaflet-shadow-pane { z-index: 500; }
97 | .leaflet-marker-pane { z-index: 600; }
98 | .leaflet-tooltip-pane { z-index: 650; }
99 | .leaflet-popup-pane { z-index: 700; }
100 |
101 | .leaflet-map-pane canvas { z-index: 100; }
102 | .leaflet-map-pane svg { z-index: 200; }
103 |
104 | .leaflet-vml-shape {
105 | width: 1px;
106 | height: 1px;
107 | }
108 | .lvml {
109 | behavior: url(#default#VML);
110 | display: inline-block;
111 | position: absolute;
112 | }
113 |
114 |
115 | /* control positioning */
116 |
117 | .leaflet-control {
118 | position: relative;
119 | z-index: 800;
120 | pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
121 | pointer-events: auto;
122 | }
123 | .leaflet-top,
124 | .leaflet-bottom {
125 | position: absolute;
126 | z-index: 1000;
127 | pointer-events: none;
128 | }
129 | .leaflet-top {
130 | top: 0;
131 | }
132 | .leaflet-right {
133 | right: 0;
134 | }
135 | .leaflet-bottom {
136 | bottom: 0;
137 | }
138 | .leaflet-left {
139 | left: 0;
140 | }
141 | .leaflet-control {
142 | float: left;
143 | clear: both;
144 | }
145 | .leaflet-right .leaflet-control {
146 | float: right;
147 | }
148 | .leaflet-top .leaflet-control {
149 | margin-top: 10px;
150 | }
151 | .leaflet-bottom .leaflet-control {
152 | margin-bottom: 10px;
153 | }
154 | .leaflet-left .leaflet-control {
155 | margin-left: 10px;
156 | }
157 | .leaflet-right .leaflet-control {
158 | margin-right: 10px;
159 | }
160 |
161 |
162 | /* zoom and fade animations */
163 |
164 | .leaflet-fade-anim .leaflet-tile {
165 | will-change: opacity;
166 | }
167 | .leaflet-fade-anim .leaflet-popup {
168 | opacity: 0;
169 | -webkit-transition: opacity 0.2s linear;
170 | -moz-transition: opacity 0.2s linear;
171 | -o-transition: opacity 0.2s linear;
172 | transition: opacity 0.2s linear;
173 | }
174 | .leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
175 | opacity: 1;
176 | }
177 | .leaflet-zoom-animated {
178 | -webkit-transform-origin: 0 0;
179 | -ms-transform-origin: 0 0;
180 | transform-origin: 0 0;
181 | }
182 | .leaflet-zoom-anim .leaflet-zoom-animated {
183 | will-change: transform;
184 | }
185 | .leaflet-zoom-anim .leaflet-zoom-animated {
186 | -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
187 | -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
188 | -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
189 | transition: transform 0.25s cubic-bezier(0,0,0.25,1);
190 | }
191 | .leaflet-zoom-anim .leaflet-tile,
192 | .leaflet-pan-anim .leaflet-tile {
193 | -webkit-transition: none;
194 | -moz-transition: none;
195 | -o-transition: none;
196 | transition: none;
197 | }
198 |
199 | .leaflet-zoom-anim .leaflet-zoom-hide {
200 | visibility: hidden;
201 | }
202 |
203 |
204 | /* cursors */
205 |
206 | .leaflet-interactive {
207 | cursor: pointer;
208 | }
209 | .leaflet-grab {
210 | cursor: -webkit-grab;
211 | cursor: -moz-grab;
212 | }
213 | .leaflet-crosshair,
214 | .leaflet-crosshair .leaflet-interactive {
215 | cursor: crosshair;
216 | }
217 | .leaflet-popup-pane,
218 | .leaflet-control {
219 | cursor: auto;
220 | }
221 | .leaflet-dragging .leaflet-grab,
222 | .leaflet-dragging .leaflet-grab .leaflet-interactive,
223 | .leaflet-dragging .leaflet-marker-draggable {
224 | cursor: move;
225 | cursor: -webkit-grabbing;
226 | cursor: -moz-grabbing;
227 | }
228 |
229 | /* marker & overlays interactivity */
230 | .leaflet-marker-icon,
231 | .leaflet-marker-shadow,
232 | .leaflet-image-layer,
233 | .leaflet-pane > svg path,
234 | .leaflet-tile-container {
235 | pointer-events: none;
236 | }
237 |
238 | .leaflet-marker-icon.leaflet-interactive,
239 | .leaflet-image-layer.leaflet-interactive,
240 | .leaflet-pane > svg path.leaflet-interactive {
241 | pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
242 | pointer-events: auto;
243 | }
244 |
245 | /* visual tweaks */
246 |
247 | .leaflet-container {
248 | background: #ddd;
249 | outline: 0;
250 | }
251 | .leaflet-container a {
252 | color: #0078A8;
253 | }
254 | .leaflet-container a.leaflet-active {
255 | outline: 2px solid orange;
256 | }
257 | .leaflet-zoom-box {
258 | border: 2px dotted #38f;
259 | background: rgba(255,255,255,0.5);
260 | }
261 |
262 |
263 | /* general typography */
264 | .leaflet-container {
265 | font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
266 | }
267 |
268 |
269 | /* general toolbar styles */
270 |
271 | .leaflet-bar {
272 | box-shadow: 0 1px 5px rgba(0,0,0,0.65);
273 | border-radius: 4px;
274 | }
275 | .leaflet-bar a,
276 | .leaflet-bar a:hover {
277 | background-color: #fff;
278 | border-bottom: 1px solid #ccc;
279 | width: 26px;
280 | height: 26px;
281 | line-height: 26px;
282 | display: block;
283 | text-align: center;
284 | text-decoration: none;
285 | color: black;
286 | }
287 | .leaflet-bar a,
288 | .leaflet-control-layers-toggle {
289 | background-position: 50% 50%;
290 | background-repeat: no-repeat;
291 | display: block;
292 | }
293 | .leaflet-bar a:hover {
294 | background-color: #f4f4f4;
295 | }
296 | .leaflet-bar a:first-child {
297 | border-top-left-radius: 4px;
298 | border-top-right-radius: 4px;
299 | }
300 | .leaflet-bar a:last-child {
301 | border-bottom-left-radius: 4px;
302 | border-bottom-right-radius: 4px;
303 | border-bottom: none;
304 | }
305 | .leaflet-bar a.leaflet-disabled {
306 | cursor: default;
307 | background-color: #f4f4f4;
308 | color: #bbb;
309 | }
310 |
311 | .leaflet-touch .leaflet-bar a {
312 | width: 30px;
313 | height: 30px;
314 | line-height: 30px;
315 | }
316 | .leaflet-touch .leaflet-bar a:first-child {
317 | border-top-left-radius: 2px;
318 | border-top-right-radius: 2px;
319 | }
320 | .leaflet-touch .leaflet-bar a:last-child {
321 | border-bottom-left-radius: 2px;
322 | border-bottom-right-radius: 2px;
323 | }
324 |
325 | /* zoom control */
326 |
327 | .leaflet-control-zoom-in,
328 | .leaflet-control-zoom-out {
329 | font: bold 18px 'Lucida Console', Monaco, monospace;
330 | text-indent: 1px;
331 | }
332 |
333 | .leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
334 | font-size: 22px;
335 | }
336 |
337 |
338 | /* layers control */
339 |
340 | .leaflet-control-layers {
341 | box-shadow: 0 1px 5px rgba(0,0,0,0.4);
342 | background: #fff;
343 | border-radius: 5px;
344 | }
345 | .leaflet-control-layers-toggle {
346 | background-image: url(images/layers.png);
347 | width: 36px;
348 | height: 36px;
349 | }
350 | .leaflet-retina .leaflet-control-layers-toggle {
351 | background-image: url(images/layers-2x.png);
352 | background-size: 26px 26px;
353 | }
354 | .leaflet-touch .leaflet-control-layers-toggle {
355 | width: 44px;
356 | height: 44px;
357 | }
358 | .leaflet-control-layers .leaflet-control-layers-list,
359 | .leaflet-control-layers-expanded .leaflet-control-layers-toggle {
360 | display: none;
361 | }
362 | .leaflet-control-layers-expanded .leaflet-control-layers-list {
363 | display: block;
364 | position: relative;
365 | }
366 | .leaflet-control-layers-expanded {
367 | padding: 6px 10px 6px 6px;
368 | color: #333;
369 | background: #fff;
370 | }
371 | .leaflet-control-layers-scrollbar {
372 | overflow-y: scroll;
373 | overflow-x: hidden;
374 | padding-right: 5px;
375 | }
376 | .leaflet-control-layers-selector {
377 | margin-top: 2px;
378 | position: relative;
379 | top: 1px;
380 | }
381 | .leaflet-control-layers label {
382 | display: block;
383 | }
384 | .leaflet-control-layers-separator {
385 | height: 0;
386 | border-top: 1px solid #ddd;
387 | margin: 5px -10px 5px -6px;
388 | }
389 |
390 | /* Default icon URLs */
391 | .leaflet-default-icon-path {
392 | background-image: url(images/marker-icon.png);
393 | }
394 |
395 |
396 | /* attribution and scale controls */
397 |
398 | .leaflet-container .leaflet-control-attribution {
399 | background: #fff;
400 | background: rgba(255, 255, 255, 0.7);
401 | margin: 0;
402 | }
403 | .leaflet-control-attribution,
404 | .leaflet-control-scale-line {
405 | padding: 0 5px;
406 | color: #333;
407 | }
408 | .leaflet-control-attribution a {
409 | text-decoration: none;
410 | }
411 | .leaflet-control-attribution a:hover {
412 | text-decoration: underline;
413 | }
414 | .leaflet-container .leaflet-control-attribution,
415 | .leaflet-container .leaflet-control-scale {
416 | font-size: 11px;
417 | }
418 | .leaflet-left .leaflet-control-scale {
419 | margin-left: 5px;
420 | }
421 | .leaflet-bottom .leaflet-control-scale {
422 | margin-bottom: 5px;
423 | }
424 | .leaflet-control-scale-line {
425 | border: 2px solid #777;
426 | border-top: none;
427 | line-height: 1.1;
428 | padding: 2px 5px 1px;
429 | font-size: 11px;
430 | white-space: nowrap;
431 | overflow: hidden;
432 | -moz-box-sizing: border-box;
433 | box-sizing: border-box;
434 |
435 | background: #fff;
436 | background: rgba(255, 255, 255, 0.5);
437 | }
438 | .leaflet-control-scale-line:not(:first-child) {
439 | border-top: 2px solid #777;
440 | border-bottom: none;
441 | margin-top: -2px;
442 | }
443 | .leaflet-control-scale-line:not(:first-child):not(:last-child) {
444 | border-bottom: 2px solid #777;
445 | }
446 |
447 | .leaflet-touch .leaflet-control-attribution,
448 | .leaflet-touch .leaflet-control-layers,
449 | .leaflet-touch .leaflet-bar {
450 | box-shadow: none;
451 | }
452 | .leaflet-touch .leaflet-control-layers,
453 | .leaflet-touch .leaflet-bar {
454 | border: 2px solid rgba(0,0,0,0.2);
455 | background-clip: padding-box;
456 | }
457 |
458 |
459 | /* popup */
460 |
461 | .leaflet-popup {
462 | position: absolute;
463 | text-align: center;
464 | margin-bottom: 20px;
465 | }
466 | .leaflet-popup-content-wrapper {
467 | padding: 1px;
468 | text-align: left;
469 | border-radius: 12px;
470 | }
471 | .leaflet-popup-content {
472 | margin: 13px 19px;
473 | line-height: 1.4;
474 | }
475 | .leaflet-popup-content p {
476 | margin: 18px 0;
477 | }
478 | .leaflet-popup-tip-container {
479 | width: 40px;
480 | height: 20px;
481 | position: absolute;
482 | left: 50%;
483 | margin-left: -20px;
484 | overflow: hidden;
485 | pointer-events: none;
486 | }
487 | .leaflet-popup-tip {
488 | width: 17px;
489 | height: 17px;
490 | padding: 1px;
491 |
492 | margin: -10px auto 0;
493 |
494 | -webkit-transform: rotate(45deg);
495 | -moz-transform: rotate(45deg);
496 | -ms-transform: rotate(45deg);
497 | -o-transform: rotate(45deg);
498 | transform: rotate(45deg);
499 | }
500 | .leaflet-popup-content-wrapper,
501 | .leaflet-popup-tip {
502 | background: white;
503 | color: #333;
504 | box-shadow: 0 3px 14px rgba(0,0,0,0.4);
505 | }
506 | .leaflet-container a.leaflet-popup-close-button {
507 | position: absolute;
508 | top: 0;
509 | right: 0;
510 | padding: 4px 4px 0 0;
511 | border: none;
512 | text-align: center;
513 | width: 18px;
514 | height: 14px;
515 | font: 16px/14px Tahoma, Verdana, sans-serif;
516 | color: #c3c3c3;
517 | text-decoration: none;
518 | font-weight: bold;
519 | background: transparent;
520 | }
521 | .leaflet-container a.leaflet-popup-close-button:hover {
522 | color: #999;
523 | }
524 | .leaflet-popup-scrolled {
525 | overflow: auto;
526 | border-bottom: 1px solid #ddd;
527 | border-top: 1px solid #ddd;
528 | }
529 |
530 | .leaflet-oldie .leaflet-popup-content-wrapper {
531 | zoom: 1;
532 | }
533 | .leaflet-oldie .leaflet-popup-tip {
534 | width: 24px;
535 | margin: 0 auto;
536 |
537 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
538 | filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
539 | }
540 | .leaflet-oldie .leaflet-popup-tip-container {
541 | margin-top: -1px;
542 | }
543 |
544 | .leaflet-oldie .leaflet-control-zoom,
545 | .leaflet-oldie .leaflet-control-layers,
546 | .leaflet-oldie .leaflet-popup-content-wrapper,
547 | .leaflet-oldie .leaflet-popup-tip {
548 | border: 1px solid #999;
549 | }
550 |
551 |
552 | /* div icon */
553 |
554 | .leaflet-div-icon {
555 | background: #fff;
556 | border: 1px solid #666;
557 | }
558 |
559 |
560 | /* Tooltip */
561 | /* Base styles for the element that has a tooltip */
562 | .leaflet-tooltip {
563 | position: absolute;
564 | padding: 6px;
565 | background-color: #fff;
566 | border: 1px solid #fff;
567 | border-radius: 3px;
568 | color: #222;
569 | white-space: nowrap;
570 | -webkit-user-select: none;
571 | -moz-user-select: none;
572 | -ms-user-select: none;
573 | user-select: none;
574 | pointer-events: none;
575 | box-shadow: 0 1px 3px rgba(0,0,0,0.4);
576 | }
577 | .leaflet-tooltip.leaflet-clickable {
578 | cursor: pointer;
579 | pointer-events: auto;
580 | }
581 | .leaflet-tooltip-top:before,
582 | .leaflet-tooltip-bottom:before,
583 | .leaflet-tooltip-left:before,
584 | .leaflet-tooltip-right:before {
585 | position: absolute;
586 | pointer-events: none;
587 | border: 6px solid transparent;
588 | background: transparent;
589 | content: "";
590 | }
591 |
592 | /* Directions */
593 |
594 | .leaflet-tooltip-bottom {
595 | margin-top: 6px;
596 | }
597 | .leaflet-tooltip-top {
598 | margin-top: -6px;
599 | }
600 | .leaflet-tooltip-bottom:before,
601 | .leaflet-tooltip-top:before {
602 | left: 50%;
603 | margin-left: -6px;
604 | }
605 | .leaflet-tooltip-top:before {
606 | bottom: 0;
607 | margin-bottom: -12px;
608 | border-top-color: #fff;
609 | }
610 | .leaflet-tooltip-bottom:before {
611 | top: 0;
612 | margin-top: -12px;
613 | margin-left: -6px;
614 | border-bottom-color: #fff;
615 | }
616 | .leaflet-tooltip-left {
617 | margin-left: -6px;
618 | }
619 | .leaflet-tooltip-right {
620 | margin-left: 6px;
621 | }
622 | .leaflet-tooltip-left:before,
623 | .leaflet-tooltip-right:before {
624 | top: 50%;
625 | margin-top: -6px;
626 | }
627 | .leaflet-tooltip-left:before {
628 | right: 0;
629 | margin-right: -12px;
630 | border-left-color: #fff;
631 | }
632 | .leaflet-tooltip-right:before {
633 | left: 0;
634 | margin-left: -12px;
635 | border-right-color: #fff;
636 | }
637 |
--------------------------------------------------------------------------------
/libs/leafletfix/leafletfix.css:
--------------------------------------------------------------------------------
1 | /* Work around CSS properties introduced on img by bootstrap */
2 | img.leaflet-tile {
3 | padding: 0;
4 | margin: 0;
5 | border-radius: 0;
6 | border: none;
7 | }
8 | .info {
9 | padding: 6px 8px;
10 | font: 14px/16px Arial, Helvetica, sans-serif;
11 | background: white;
12 | background: rgba(255,255,255,0.8);
13 | box-shadow: 0 0 15px rgba(0,0,0,0.2);
14 | border-radius: 5px;
15 | }
16 | .legend {
17 | line-height: 18px;
18 | color: #555;
19 | }
20 | .legend svg text {
21 | fill: #555;
22 | }
23 | .legend svg line {
24 | stroke: #555;
25 | }
26 | .legend i {
27 | width: 18px;
28 | height: 18px;
29 | margin-right: 4px;
30 | opacity: 0.7;
31 | display: inline-block;
32 | vertical-align: top;
33 | /*For IE 7*/
34 | zoom: 1;
35 | *display: inline;
36 | }
37 |
--------------------------------------------------------------------------------
/libs/mapviewCSS/mapview-popup.css:
--------------------------------------------------------------------------------
1 | /* table class css */
2 | table.mapview-popup {
3 | overflow: scroll;
4 | width: auto;
5 | height: auto;
6 | border-collapse: collapse;
7 | }
8 |
9 | /*
10 | table.mapview-popup tr:first-child td {
11 | background: #A8E6A8;
12 | }
13 | */
14 |
15 | table.mapview-popup tr:nth-child(even) {
16 | background: #D1E0FF;
17 | }
18 |
19 | table.mapview-popup tr:nth-child(odd) {
20 | background: #ebf1ff;
21 | }
22 |
23 | table.mapview-popup, th, td {
24 | border-bottom: 1px solid #ffffff;
25 | }
26 |
27 | /*
28 | table.tab tr:hover {
29 | background: #00ffff;
30 | }
31 | */
32 |
33 |
34 | /* general leaflet popup css '*/
35 | .leaflet-popup-content {
36 | margin: 1px 1px 1px 1px;
37 | line-height: 1.5;
38 | overflow-y: auto;
39 | overflow-x: scoll;
40 | }
41 |
42 | .leaflet-container a.leaflet-popup-close-button {
43 | position: absolute;
44 | top: 0;
45 | right: -20px;
46 | padding: 3px 0 0 0;
47 | text-align: center;
48 | width: 18px;
49 | height: 14px;
50 | font: 16px/14px Tahoma, Verdana, sans-serif;
51 | font-weight: bold;
52 | color: #c3c3c3;
53 | text-decoration: none;
54 | background: transparent;
55 | }
56 |
57 | .leaflet-container a.leaflet-popup-close-button:hover {
58 | color: #999;
59 | }
60 |
61 | .leaflet-popup-content-wrapper, .leaflet-popup-tip {
62 | padding: 1px;
63 | -webkit-border-radius: 0;
64 | border-radius: 0;
65 | background: #ffffff; /*#4c4c4c;*/
66 | box-shadow: 0 3px 14px rgba(0,0,0,0.4);
67 | }
68 |
69 |
70 | div::-webkit-scrollbar {
71 | width: 5px;
72 | height: 5px;
73 | }
74 | div::-webkit-scrollbar-button {
75 | width: 0;
76 | height: 0;
77 | }
78 | div::-webkit-scrollbar-thumb {
79 | background: #666666;
80 | border: 0 none #ffffff;
81 | border-radius: 0;
82 | }
83 | div::-webkit-scrollbar-thumb:hover {
84 | background: #333333;
85 | }
86 | div::-webkit-scrollbar-thumb:active {
87 | background: #333333;
88 | }
89 | div::-webkit-scrollbar-track {
90 | background: #e1e1e1;
91 | border: 0 none #ffffff;
92 | border-radius: 50px;
93 | }
94 | div::-webkit-scrollbar-track:hover {
95 | background: #e1e1e1;
96 | }
97 | div::-webkit-scrollbar-track:active {
98 | background: #e1e1e1;
99 | }
100 | div::-webkit-scrollbar-corner {
101 | background: transparent;
102 | }
103 |
--------------------------------------------------------------------------------
/libs/mapviewCSS/mapview.css:
--------------------------------------------------------------------------------
1 | .leaflet-control br {clear: both;}
2 |
--------------------------------------------------------------------------------
/libs/remark-css-0.0.1/default-fonts.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
2 | @import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
3 | @import url(https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700);
4 |
5 | body { font-family: 'Droid Serif', 'Palatino Linotype', 'Book Antiqua', Palatino, 'Microsoft YaHei', 'Songti SC', serif; }
6 | h1, h2, h3 {
7 | font-family: 'Yanone Kaffeesatz';
8 | font-weight: normal;
9 | }
10 | .remark-code, .remark-inline-code { font-family: 'Source Code Pro', 'Lucida Console', Monaco, monospace; }
11 |
--------------------------------------------------------------------------------
/libs/remark-css-0.0.1/default.css:
--------------------------------------------------------------------------------
1 | a, a > code {
2 | color: rgb(249, 38, 114);
3 | text-decoration: none;
4 | }
5 | .footnote {
6 | position: absolute;
7 | bottom: 3em;
8 | padding-right: 4em;
9 | font-size: 90%;
10 | }
11 | .remark-code-line-highlighted { background-color: #ffff88; }
12 |
13 | .inverse {
14 | background-color: #272822;
15 | color: #d6d6d6;
16 | text-shadow: 0 0 20px #333;
17 | }
18 | .inverse h1, .inverse h2, .inverse h3 {
19 | color: #f3f3f3;
20 | }
21 | /* Two-column layout */
22 | .left-column {
23 | color: #777;
24 | width: 20%;
25 | height: 92%;
26 | float: left;
27 | }
28 | .left-column h2:last-of-type, .left-column h3:last-child {
29 | color: #000;
30 | }
31 | .right-column {
32 | width: 75%;
33 | float: right;
34 | padding-top: 1em;
35 | }
36 | .pull-left {
37 | float: left;
38 | width: 47%;
39 | }
40 | .pull-right {
41 | float: right;
42 | width: 47%;
43 | }
44 | .pull-right + * {
45 | clear: both;
46 | }
47 | img, video, iframe {
48 | max-width: 100%;
49 | }
50 | blockquote {
51 | border-left: solid 5px lightgray;
52 | padding-left: 1em;
53 | }
54 | .remark-slide table {
55 | margin: auto;
56 | border-top: 1px solid #666;
57 | border-bottom: 1px solid #666;
58 | }
59 | .remark-slide table thead th { border-bottom: 1px solid #ddd; }
60 | th, td { padding: 5px; }
61 | .remark-slide thead, .remark-slide tfoot, .remark-slide tr:nth-child(even) { background: #eee }
62 |
63 | @page { margin: 0; }
64 | @media print {
65 | .remark-slide-scaler {
66 | width: 100% !important;
67 | height: 100% !important;
68 | transform: scale(1) !important;
69 | top: 0 !important;
70 | left: 0 !important;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/libs/remark-css/default.css:
--------------------------------------------------------------------------------
1 | a, a > code {
2 | color: rgb(249, 38, 114);
3 | text-decoration: none;
4 | }
5 | .footnote {
6 | position: absolute;
7 | bottom: 3em;
8 | padding-right: 4em;
9 | font-size: 90%;
10 | }
11 | .remark-code-line-highlighted { background-color: #ffff88; }
12 |
13 | .inverse {
14 | background-color: #272822;
15 | color: #d6d6d6;
16 | text-shadow: 0 0 20px #333;
17 | }
18 | .inverse h1, .inverse h2, .inverse h3 {
19 | color: #f3f3f3;
20 | }
21 | /* Two-column layout */
22 | .left-column {
23 | color: #777;
24 | width: 20%;
25 | height: 92%;
26 | float: left;
27 | }
28 | .left-column h2:last-of-type, .left-column h3:last-child {
29 | color: #000;
30 | }
31 | .right-column {
32 | width: 75%;
33 | float: right;
34 | padding-top: 1em;
35 | }
36 | .pull-left {
37 | float: left;
38 | width: 47%;
39 | }
40 | .pull-right {
41 | float: right;
42 | width: 47%;
43 | }
44 | .pull-right + * {
45 | clear: both;
46 | }
47 | img, video, iframe {
48 | max-width: 100%;
49 | }
50 | blockquote {
51 | border-left: solid 5px lightgray;
52 | padding-left: 1em;
53 | }
54 | .remark-slide table {
55 | margin: auto;
56 | border-top: 1px solid #666;
57 | border-bottom: 1px solid #666;
58 | }
59 | .remark-slide table thead th { border-bottom: 1px solid #ddd; }
60 | th, td { padding: 5px; }
61 | .remark-slide thead, .remark-slide tfoot, .remark-slide tr:nth-child(even) { background: #eee }
62 |
63 | @page { margin: 0; }
64 | @media print {
65 | .remark-slide-scaler {
66 | width: 100% !important;
67 | height: 100% !important;
68 | transform: scale(1) !important;
69 | top: 0 !important;
70 | left: 0 !important;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/libs/rstudio_leaflet/images/1px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RamiKrispin/gis-dataviz-workshop/cbdee699fcaf68becc652d4efc1599b23761eaad/libs/rstudio_leaflet/images/1px.png
--------------------------------------------------------------------------------
/libs/rstudio_leaflet/rstudio_leaflet.css:
--------------------------------------------------------------------------------
1 | .leaflet-tooltip.leaflet-tooltip-text-only,
2 | .leaflet-tooltip.leaflet-tooltip-text-only:before,
3 | .leaflet-tooltip.leaflet-tooltip-text-only:after {
4 | background: none;
5 | border: none;
6 | box-shadow: none;
7 | }
8 |
9 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-left {
10 | margin-left: 5px;
11 | }
12 |
13 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-right {
14 | margin-left: -5px;
15 | }
16 |
17 | .leaflet-tooltip:after {
18 | border-right: 6px solid transparent;
19 | /* right: -16px; */
20 | }
21 |
22 | .leaflet-popup-pane .leaflet-popup-tip-container {
23 | /* when the tooltip container is clicked, it is closed */
24 | pointer-events: all;
25 | /* tooltips should display the "hand" icon, just like .leaflet-interactive*/
26 | cursor: pointer;
27 | }
28 |
29 | /* have the widget be displayed in the right 'layer' */
30 | .leaflet-map-pane {
31 | z-index: auto;
32 | }
33 |
--------------------------------------------------------------------------------
/mycss.css:
--------------------------------------------------------------------------------
1 | @import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic);
2 | @import url(https://fonts.googleapis.com/css?family=Roboto+Condensed);
3 | @import url(https://fonts.googleapis.com/css?family=Roboto+Mono);
4 |
5 | body {
6 | font-family: 'Lato', Arial, sans-serif;
7 | font-size: 26px;
8 | }
9 | h1, h2, h3, h4 {
10 | font-family: 'Roboto Condensed', 'Arial Narrow OS', Arial, sans-serif;
11 | font-weight: normal;
12 | }
13 | .remark-slide-content { font-size: 1em; }
14 | .remark-code, .remark-inline-code {
15 | font-family: 'Roboto Mono', 'Lucida Console', Monaco, Consolas, monospace;
16 | font-size: 1em;
17 | color: #650C92;
18 | }
19 |
20 | /* Make inline code slightly smaller; prevents vertical jumps
21 | from slides with to slides without inline code. */
22 | .remark-inline-code { font-size: 0.94em; line-height: 1.0; }
23 |
24 | .title-font {
25 | font-family: 'Roboto Condensed', 'Arial Narrow OS', Arial, sans-serif;
26 | font-weight: normal;
27 | font-size: 1.5em;
28 | }
29 | .small-font { font-size: 0.86em; }
30 | .tiny-font { font-size: 0.66em; }
31 | .xtiny-font { font-size: 0.60em; }
32 |
33 | .white { color: white; }
34 |
35 | .highlight { font-weight: bold; color: #91322F; }
36 |
37 | .nogap p {margin-top: 0; margin-bottom: 0}
38 |
39 | a, a > code {
40 | color: #650C92;
41 | }
42 |
43 | td {
44 | padding: 5px 10px;
45 | }
46 |
47 | table {
48 | display: inline-block;
49 | }
50 |
51 | .width-10 {
52 | width: 10%
53 | }
54 | .width-15 {
55 | width: 15%
56 | }
57 | .width-20 {
58 | width: 20%
59 | }
60 | .width-25 {
61 | width: 25%
62 | }
63 | .width-30 {
64 | width: 30%
65 | }
66 | .width-35 {
67 | width: 35%
68 | }
69 | .width-40 {
70 | width: 40%
71 | }
72 | .width-45 {
73 | width: 45%
74 | }
75 | .width-50 {
76 | width: 50%
77 | }
78 | .width-55 {
79 | width: 55%
80 | }
81 | .width-60 {
82 | width: 60%
83 | }
84 | .width-65 {
85 | width: 65%
86 | }
87 | .width-70 {
88 | width: 70%
89 | }
90 | .width-75 {
91 | width: 75%
92 | }
93 | .width-80 {
94 | width: 80%
95 | }
96 | .width-85 {
97 | width: 85%
98 | }
99 | .width-90 {
100 | width: 90%
101 | }
102 |
103 | .move-up-1em {
104 | margin-top: -1em;
105 | }
106 |
107 | .move-up-2em {
108 | margin-top: -2em;
109 | }
110 |
111 | .move-up-3em {
112 | margin-top: -3em;
113 | }
114 |
115 | .move-down-1em {
116 | margin-top: 1em;
117 | }
118 |
119 | .move-down-2em {
120 | margin-top: 2em;
121 | }
122 |
123 | .move-down-3em {
124 | margin-top: 2em;
125 | }
126 |
127 | .absolute-bottom-left {
128 | position: absolute;
129 | bottom: 0;
130 | left: 4em;
131 | }
132 |
133 | .absolute-bottom-right {
134 | position: absolute;
135 | bottom: 0;
136 | right: 4em;
137 | }
--------------------------------------------------------------------------------
/renv.lock:
--------------------------------------------------------------------------------
1 | {
2 | "R": {
3 | "Version": "4.1.2",
4 | "Repositories": [
5 | {
6 | "Name": "CRAN",
7 | "URL": "https://cran.rstudio.com"
8 | }
9 | ]
10 | },
11 | "Packages": {
12 | "renv": {
13 | "Package": "renv",
14 | "Version": "0.14.0",
15 | "Source": "Repository",
16 | "Repository": "CRAN",
17 | "Hash": "30e5eba91b67f7f4d75d31de14bbfbdc"
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/renv/.gitignore:
--------------------------------------------------------------------------------
1 | library/
2 | local/
3 | lock/
4 | python/
5 | staging/
6 |
--------------------------------------------------------------------------------
/renv/activate.R:
--------------------------------------------------------------------------------
1 |
2 | local({
3 |
4 | # the requested version of renv
5 | version <- "0.14.0"
6 |
7 | # the project directory
8 | project <- getwd()
9 |
10 | # allow environment variable to control activation
11 | activate <- Sys.getenv("RENV_ACTIVATE_PROJECT")
12 | if (!nzchar(activate)) {
13 |
14 | # don't auto-activate when R CMD INSTALL is running
15 | if (nzchar(Sys.getenv("R_INSTALL_PKG")))
16 | return(FALSE)
17 |
18 | }
19 |
20 | # bail if activation was explicitly disabled
21 | if (tolower(activate) %in% c("false", "f", "0"))
22 | return(FALSE)
23 |
24 | # avoid recursion
25 | if (nzchar(Sys.getenv("RENV_R_INITIALIZING")))
26 | return(invisible(TRUE))
27 |
28 | # signal that we're loading renv during R startup
29 | Sys.setenv("RENV_R_INITIALIZING" = "true")
30 | on.exit(Sys.unsetenv("RENV_R_INITIALIZING"), add = TRUE)
31 |
32 | # signal that we've consented to use renv
33 | options(renv.consent = TRUE)
34 |
35 | # load the 'utils' package eagerly -- this ensures that renv shims, which
36 | # mask 'utils' packages, will come first on the search path
37 | library(utils, lib.loc = .Library)
38 |
39 | # check to see if renv has already been loaded
40 | if ("renv" %in% loadedNamespaces()) {
41 |
42 | # if renv has already been loaded, and it's the requested version of renv,
43 | # nothing to do
44 | spec <- .getNamespaceInfo(.getNamespace("renv"), "spec")
45 | if (identical(spec[["version"]], version))
46 | return(invisible(TRUE))
47 |
48 | # otherwise, unload and attempt to load the correct version of renv
49 | unloadNamespace("renv")
50 |
51 | }
52 |
53 | # load bootstrap tools
54 | bootstrap <- function(version, library) {
55 |
56 | # attempt to download renv
57 | tarball <- tryCatch(renv_bootstrap_download(version), error = identity)
58 | if (inherits(tarball, "error"))
59 | stop("failed to download renv ", version)
60 |
61 | # now attempt to install
62 | status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity)
63 | if (inherits(status, "error"))
64 | stop("failed to install renv ", version)
65 |
66 | }
67 |
68 | renv_bootstrap_tests_running <- function() {
69 | getOption("renv.tests.running", default = FALSE)
70 | }
71 |
72 | renv_bootstrap_repos <- function() {
73 |
74 | # check for repos override
75 | repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA)
76 | if (!is.na(repos))
77 | return(repos)
78 |
79 | # if we're testing, re-use the test repositories
80 | if (renv_bootstrap_tests_running())
81 | return(getOption("renv.tests.repos"))
82 |
83 | # retrieve current repos
84 | repos <- getOption("repos")
85 |
86 | # ensure @CRAN@ entries are resolved
87 | repos[repos == "@CRAN@"] <- getOption(
88 | "renv.repos.cran",
89 | "https://cloud.r-project.org"
90 | )
91 |
92 | # add in renv.bootstrap.repos if set
93 | default <- c(FALLBACK = "https://cloud.r-project.org")
94 | extra <- getOption("renv.bootstrap.repos", default = default)
95 | repos <- c(repos, extra)
96 |
97 | # remove duplicates that might've snuck in
98 | dupes <- duplicated(repos) | duplicated(names(repos))
99 | repos[!dupes]
100 |
101 | }
102 |
103 | renv_bootstrap_download <- function(version) {
104 |
105 | # if the renv version number has 4 components, assume it must
106 | # be retrieved via github
107 | nv <- numeric_version(version)
108 | components <- unclass(nv)[[1]]
109 |
110 | methods <- if (length(components) == 4L) {
111 | list(
112 | renv_bootstrap_download_github
113 | )
114 | } else {
115 | list(
116 | renv_bootstrap_download_cran_latest,
117 | renv_bootstrap_download_cran_archive
118 | )
119 | }
120 |
121 | for (method in methods) {
122 | path <- tryCatch(method(version), error = identity)
123 | if (is.character(path) && file.exists(path))
124 | return(path)
125 | }
126 |
127 | stop("failed to download renv ", version)
128 |
129 | }
130 |
131 | renv_bootstrap_download_impl <- function(url, destfile) {
132 |
133 | mode <- "wb"
134 |
135 | # https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17715
136 | fixup <-
137 | Sys.info()[["sysname"]] == "Windows" &&
138 | substring(url, 1L, 5L) == "file:"
139 |
140 | if (fixup)
141 | mode <- "w+b"
142 |
143 | utils::download.file(
144 | url = url,
145 | destfile = destfile,
146 | mode = mode,
147 | quiet = TRUE
148 | )
149 |
150 | }
151 |
152 | renv_bootstrap_download_cran_latest <- function(version) {
153 |
154 | spec <- renv_bootstrap_download_cran_latest_find(version)
155 |
156 | message("* Downloading renv ", version, " ... ", appendLF = FALSE)
157 |
158 | type <- spec$type
159 | repos <- spec$repos
160 |
161 | info <- tryCatch(
162 | utils::download.packages(
163 | pkgs = "renv",
164 | destdir = tempdir(),
165 | repos = repos,
166 | type = type,
167 | quiet = TRUE
168 | ),
169 | condition = identity
170 | )
171 |
172 | if (inherits(info, "condition")) {
173 | message("FAILED")
174 | return(FALSE)
175 | }
176 |
177 | # report success and return
178 | message("OK (downloaded ", type, ")")
179 | info[1, 2]
180 |
181 | }
182 |
183 | renv_bootstrap_download_cran_latest_find <- function(version) {
184 |
185 | # check whether binaries are supported on this system
186 | binary <-
187 | getOption("renv.bootstrap.binary", default = TRUE) &&
188 | !identical(.Platform$pkgType, "source") &&
189 | !identical(getOption("pkgType"), "source") &&
190 | Sys.info()[["sysname"]] %in% c("Darwin", "Windows")
191 |
192 | types <- c(if (binary) "binary", "source")
193 |
194 | # iterate over types + repositories
195 | for (type in types) {
196 | for (repos in renv_bootstrap_repos()) {
197 |
198 | # retrieve package database
199 | db <- tryCatch(
200 | as.data.frame(
201 | utils::available.packages(type = type, repos = repos),
202 | stringsAsFactors = FALSE
203 | ),
204 | error = identity
205 | )
206 |
207 | if (inherits(db, "error"))
208 | next
209 |
210 | # check for compatible entry
211 | entry <- db[db$Package %in% "renv" & db$Version %in% version, ]
212 | if (nrow(entry) == 0)
213 | next
214 |
215 | # found it; return spec to caller
216 | spec <- list(entry = entry, type = type, repos = repos)
217 | return(spec)
218 |
219 | }
220 | }
221 |
222 | # if we got here, we failed to find renv
223 | fmt <- "renv %s is not available from your declared package repositories"
224 | stop(sprintf(fmt, version))
225 |
226 | }
227 |
228 | renv_bootstrap_download_cran_archive <- function(version) {
229 |
230 | name <- sprintf("renv_%s.tar.gz", version)
231 | repos <- renv_bootstrap_repos()
232 | urls <- file.path(repos, "src/contrib/Archive/renv", name)
233 | destfile <- file.path(tempdir(), name)
234 |
235 | message("* Downloading renv ", version, " ... ", appendLF = FALSE)
236 |
237 | for (url in urls) {
238 |
239 | status <- tryCatch(
240 | renv_bootstrap_download_impl(url, destfile),
241 | condition = identity
242 | )
243 |
244 | if (identical(status, 0L)) {
245 | message("OK")
246 | return(destfile)
247 | }
248 |
249 | }
250 |
251 | message("FAILED")
252 | return(FALSE)
253 |
254 | }
255 |
256 | renv_bootstrap_download_github <- function(version) {
257 |
258 | enabled <- Sys.getenv("RENV_BOOTSTRAP_FROM_GITHUB", unset = "TRUE")
259 | if (!identical(enabled, "TRUE"))
260 | return(FALSE)
261 |
262 | # prepare download options
263 | pat <- Sys.getenv("GITHUB_PAT")
264 | if (nzchar(Sys.which("curl")) && nzchar(pat)) {
265 | fmt <- "--location --fail --header \"Authorization: token %s\""
266 | extra <- sprintf(fmt, pat)
267 | saved <- options("download.file.method", "download.file.extra")
268 | options(download.file.method = "curl", download.file.extra = extra)
269 | on.exit(do.call(base::options, saved), add = TRUE)
270 | } else if (nzchar(Sys.which("wget")) && nzchar(pat)) {
271 | fmt <- "--header=\"Authorization: token %s\""
272 | extra <- sprintf(fmt, pat)
273 | saved <- options("download.file.method", "download.file.extra")
274 | options(download.file.method = "wget", download.file.extra = extra)
275 | on.exit(do.call(base::options, saved), add = TRUE)
276 | }
277 |
278 | message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE)
279 |
280 | url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version)
281 | name <- sprintf("renv_%s.tar.gz", version)
282 | destfile <- file.path(tempdir(), name)
283 |
284 | status <- tryCatch(
285 | renv_bootstrap_download_impl(url, destfile),
286 | condition = identity
287 | )
288 |
289 | if (!identical(status, 0L)) {
290 | message("FAILED")
291 | return(FALSE)
292 | }
293 |
294 | message("OK")
295 | return(destfile)
296 |
297 | }
298 |
299 | renv_bootstrap_install <- function(version, tarball, library) {
300 |
301 | # attempt to install it into project library
302 | message("* Installing renv ", version, " ... ", appendLF = FALSE)
303 | dir.create(library, showWarnings = FALSE, recursive = TRUE)
304 |
305 | # invoke using system2 so we can capture and report output
306 | bin <- R.home("bin")
307 | exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R"
308 | r <- file.path(bin, exe)
309 | args <- c("--vanilla", "CMD", "INSTALL", "-l", shQuote(library), shQuote(tarball))
310 | output <- system2(r, args, stdout = TRUE, stderr = TRUE)
311 | message("Done!")
312 |
313 | # check for successful install
314 | status <- attr(output, "status")
315 | if (is.numeric(status) && !identical(status, 0L)) {
316 | header <- "Error installing renv:"
317 | lines <- paste(rep.int("=", nchar(header)), collapse = "")
318 | text <- c(header, lines, output)
319 | writeLines(text, con = stderr())
320 | }
321 |
322 | status
323 |
324 | }
325 |
326 | renv_bootstrap_platform_prefix <- function() {
327 |
328 | # construct version prefix
329 | version <- paste(R.version$major, R.version$minor, sep = ".")
330 | prefix <- paste("R", numeric_version(version)[1, 1:2], sep = "-")
331 |
332 | # include SVN revision for development versions of R
333 | # (to avoid sharing platform-specific artefacts with released versions of R)
334 | devel <-
335 | identical(R.version[["status"]], "Under development (unstable)") ||
336 | identical(R.version[["nickname"]], "Unsuffered Consequences")
337 |
338 | if (devel)
339 | prefix <- paste(prefix, R.version[["svn rev"]], sep = "-r")
340 |
341 | # build list of path components
342 | components <- c(prefix, R.version$platform)
343 |
344 | # include prefix if provided by user
345 | prefix <- renv_bootstrap_platform_prefix_impl()
346 | if (!is.na(prefix) && nzchar(prefix))
347 | components <- c(prefix, components)
348 |
349 | # build prefix
350 | paste(components, collapse = "/")
351 |
352 | }
353 |
354 | renv_bootstrap_platform_prefix_impl <- function() {
355 |
356 | # if an explicit prefix has been supplied, use it
357 | prefix <- Sys.getenv("RENV_PATHS_PREFIX", unset = NA)
358 | if (!is.na(prefix))
359 | return(prefix)
360 |
361 | # if the user has requested an automatic prefix, generate it
362 | auto <- Sys.getenv("RENV_PATHS_PREFIX_AUTO", unset = NA)
363 | if (auto %in% c("TRUE", "True", "true", "1"))
364 | return(renv_bootstrap_platform_prefix_auto())
365 |
366 | # empty string on failure
367 | ""
368 |
369 | }
370 |
371 | renv_bootstrap_platform_prefix_auto <- function() {
372 |
373 | prefix <- tryCatch(renv_bootstrap_platform_os(), error = identity)
374 | if (inherits(prefix, "error") || prefix %in% "unknown") {
375 |
376 | msg <- paste(
377 | "failed to infer current operating system",
378 | "please file a bug report at https://github.com/rstudio/renv/issues",
379 | sep = "; "
380 | )
381 |
382 | warning(msg)
383 |
384 | }
385 |
386 | prefix
387 |
388 | }
389 |
390 | renv_bootstrap_platform_os <- function() {
391 |
392 | sysinfo <- Sys.info()
393 | sysname <- sysinfo[["sysname"]]
394 |
395 | # handle Windows + macOS up front
396 | if (sysname == "Windows")
397 | return("windows")
398 | else if (sysname == "Darwin")
399 | return("macos")
400 |
401 | # check for os-release files
402 | for (file in c("/etc/os-release", "/usr/lib/os-release"))
403 | if (file.exists(file))
404 | return(renv_bootstrap_platform_os_via_os_release(file, sysinfo))
405 |
406 | # check for redhat-release files
407 | if (file.exists("/etc/redhat-release"))
408 | return(renv_bootstrap_platform_os_via_redhat_release())
409 |
410 | "unknown"
411 |
412 | }
413 |
414 | renv_bootstrap_platform_os_via_os_release <- function(file, sysinfo) {
415 |
416 | # read /etc/os-release
417 | release <- utils::read.table(
418 | file = file,
419 | sep = "=",
420 | quote = c("\"", "'"),
421 | col.names = c("Key", "Value"),
422 | comment.char = "#",
423 | stringsAsFactors = FALSE
424 | )
425 |
426 | vars <- as.list(release$Value)
427 | names(vars) <- release$Key
428 |
429 | # get os name
430 | os <- tolower(sysinfo[["sysname"]])
431 |
432 | # read id
433 | id <- "unknown"
434 | for (field in c("ID", "ID_LIKE")) {
435 | if (field %in% names(vars) && nzchar(vars[[field]])) {
436 | id <- vars[[field]]
437 | break
438 | }
439 | }
440 |
441 | # read version
442 | version <- "unknown"
443 | for (field in c("UBUNTU_CODENAME", "VERSION_CODENAME", "VERSION_ID", "BUILD_ID")) {
444 | if (field %in% names(vars) && nzchar(vars[[field]])) {
445 | version <- vars[[field]]
446 | break
447 | }
448 | }
449 |
450 | # join together
451 | paste(c(os, id, version), collapse = "-")
452 |
453 | }
454 |
455 | renv_bootstrap_platform_os_via_redhat_release <- function() {
456 |
457 | # read /etc/redhat-release
458 | contents <- readLines("/etc/redhat-release", warn = FALSE)
459 |
460 | # infer id
461 | id <- if (grepl("centos", contents, ignore.case = TRUE))
462 | "centos"
463 | else if (grepl("redhat", contents, ignore.case = TRUE))
464 | "redhat"
465 | else
466 | "unknown"
467 |
468 | # try to find a version component (very hacky)
469 | version <- "unknown"
470 |
471 | parts <- strsplit(contents, "[[:space:]]")[[1L]]
472 | for (part in parts) {
473 |
474 | nv <- tryCatch(numeric_version(part), error = identity)
475 | if (inherits(nv, "error"))
476 | next
477 |
478 | version <- nv[1, 1]
479 | break
480 |
481 | }
482 |
483 | paste(c("linux", id, version), collapse = "-")
484 |
485 | }
486 |
487 | renv_bootstrap_library_root_name <- function(project) {
488 |
489 | # use project name as-is if requested
490 | asis <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT_ASIS", unset = "FALSE")
491 | if (asis)
492 | return(basename(project))
493 |
494 | # otherwise, disambiguate based on project's path
495 | id <- substring(renv_bootstrap_hash_text(project), 1L, 8L)
496 | paste(basename(project), id, sep = "-")
497 |
498 | }
499 |
500 | renv_bootstrap_library_root <- function(project) {
501 |
502 | path <- Sys.getenv("RENV_PATHS_LIBRARY", unset = NA)
503 | if (!is.na(path))
504 | return(path)
505 |
506 | path <- Sys.getenv("RENV_PATHS_LIBRARY_ROOT", unset = NA)
507 | if (!is.na(path)) {
508 | name <- renv_bootstrap_library_root_name(project)
509 | return(file.path(path, name))
510 | }
511 |
512 | prefix <- renv_bootstrap_profile_prefix()
513 | paste(c(project, prefix, "renv/library"), collapse = "/")
514 |
515 | }
516 |
517 | renv_bootstrap_validate_version <- function(version) {
518 |
519 | loadedversion <- utils::packageDescription("renv", fields = "Version")
520 | if (version == loadedversion)
521 | return(TRUE)
522 |
523 | # assume four-component versions are from GitHub; three-component
524 | # versions are from CRAN
525 | components <- strsplit(loadedversion, "[.-]")[[1]]
526 | remote <- if (length(components) == 4L)
527 | paste("rstudio/renv", loadedversion, sep = "@")
528 | else
529 | paste("renv", loadedversion, sep = "@")
530 |
531 | fmt <- paste(
532 | "renv %1$s was loaded from project library, but this project is configured to use renv %2$s.",
533 | "Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.",
534 | "Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.",
535 | sep = "\n"
536 | )
537 |
538 | msg <- sprintf(fmt, loadedversion, version, remote)
539 | warning(msg, call. = FALSE)
540 |
541 | FALSE
542 |
543 | }
544 |
545 | renv_bootstrap_hash_text <- function(text) {
546 |
547 | hashfile <- tempfile("renv-hash-")
548 | on.exit(unlink(hashfile), add = TRUE)
549 |
550 | writeLines(text, con = hashfile)
551 | tools::md5sum(hashfile)
552 |
553 | }
554 |
555 | renv_bootstrap_load <- function(project, libpath, version) {
556 |
557 | # try to load renv from the project library
558 | if (!requireNamespace("renv", lib.loc = libpath, quietly = TRUE))
559 | return(FALSE)
560 |
561 | # warn if the version of renv loaded does not match
562 | renv_bootstrap_validate_version(version)
563 |
564 | # load the project
565 | renv::load(project)
566 |
567 | TRUE
568 |
569 | }
570 |
571 | renv_bootstrap_profile_load <- function(project) {
572 |
573 | # if RENV_PROFILE is already set, just use that
574 | profile <- Sys.getenv("RENV_PROFILE", unset = NA)
575 | if (!is.na(profile) && nzchar(profile))
576 | return(profile)
577 |
578 | # check for a profile file (nothing to do if it doesn't exist)
579 | path <- file.path(project, "renv/local/profile")
580 | if (!file.exists(path))
581 | return(NULL)
582 |
583 | # read the profile, and set it if it exists
584 | contents <- readLines(path, warn = FALSE)
585 | if (length(contents) == 0L)
586 | return(NULL)
587 |
588 | # set RENV_PROFILE
589 | profile <- contents[[1L]]
590 | if (nzchar(profile))
591 | Sys.setenv(RENV_PROFILE = profile)
592 |
593 | profile
594 |
595 | }
596 |
597 | renv_bootstrap_profile_prefix <- function() {
598 | profile <- renv_bootstrap_profile_get()
599 | if (!is.null(profile))
600 | return(file.path("renv/profiles", profile))
601 | }
602 |
603 | renv_bootstrap_profile_get <- function() {
604 | profile <- Sys.getenv("RENV_PROFILE", unset = "")
605 | renv_bootstrap_profile_normalize(profile)
606 | }
607 |
608 | renv_bootstrap_profile_set <- function(profile) {
609 | profile <- renv_bootstrap_profile_normalize(profile)
610 | if (is.null(profile))
611 | Sys.unsetenv("RENV_PROFILE")
612 | else
613 | Sys.setenv(RENV_PROFILE = profile)
614 | }
615 |
616 | renv_bootstrap_profile_normalize <- function(profile) {
617 |
618 | if (is.null(profile) || profile %in% c("", "default"))
619 | return(NULL)
620 |
621 | profile
622 |
623 | }
624 |
625 | # load the renv profile, if any
626 | renv_bootstrap_profile_load(project)
627 |
628 | # construct path to library root
629 | root <- renv_bootstrap_library_root(project)
630 |
631 | # construct library prefix for platform
632 | prefix <- renv_bootstrap_platform_prefix()
633 |
634 | # construct full libpath
635 | libpath <- file.path(root, prefix)
636 |
637 | # attempt to load
638 | if (renv_bootstrap_load(project, libpath, version))
639 | return(TRUE)
640 |
641 | # load failed; inform user we're about to bootstrap
642 | prefix <- paste("# Bootstrapping renv", version)
643 | postfix <- paste(rep.int("-", 77L - nchar(prefix)), collapse = "")
644 | header <- paste(prefix, postfix)
645 | message(header)
646 |
647 | # perform bootstrap
648 | bootstrap(version, libpath)
649 |
650 | # exit early if we're just testing bootstrap
651 | if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA)))
652 | return(TRUE)
653 |
654 | # try again to load
655 | if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) {
656 | message("* Successfully installed and loaded renv ", version, ".")
657 | return(renv::load())
658 | }
659 |
660 | # failed to download or load renv; warn the user
661 | msg <- c(
662 | "Failed to find an renv installation: the project will not be loaded.",
663 | "Use `renv::activate()` to re-initialize the project."
664 | )
665 |
666 | warning(paste(msg, collapse = "\n"), call. = FALSE)
667 |
668 | })
669 |
--------------------------------------------------------------------------------
/renv/settings.dcf:
--------------------------------------------------------------------------------
1 | external.libraries:
2 | ignored.packages:
3 | package.dependency.fields: Imports, Depends, LinkingTo
4 | r.version:
5 | snapshot.type: implicit
6 | use.cache: TRUE
7 | vcs.ignore.library: TRUE
8 | vcs.ignore.local: TRUE
9 |
--------------------------------------------------------------------------------