From 8ab8ff0a450d53442017cee93f368b8a4cc87f5b Mon Sep 17 00:00:00 2001 From: Stefan Kuethe Date: Wed, 24 Jan 2024 15:15:26 +0100 Subject: [PATCH] Update jupyter --- docs/examples/jupyter/getting_started.ipynb | 200 +++----------------- maplibre/srcjs/index.js | 8 +- maplibre/srcjs/ipywidget.js | 132 ++----------- package.json | 3 +- srcjs/mapmethods.js | 14 +- srcjs/pymaplibregl.js | 4 + srcjs/utils.js | 18 ++ 7 files changed, 71 insertions(+), 308 deletions(-) create mode 100644 srcjs/utils.js diff --git a/docs/examples/jupyter/getting_started.ipynb b/docs/examples/jupyter/getting_started.ipynb index 388953c0..1d293c23 100644 --- a/docs/examples/jupyter/getting_started.ipynb +++ b/docs/examples/jupyter/getting_started.ipynb @@ -70,14 +70,14 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 27, "id": "e6e2284c-1862-4697-ad94-f535b3682197", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "ece4babe53924aa7886553d1b5d53bec", + "model_id": "8424f04853ea4a41ac6a3697349bbd3e", "version_major": 2, "version_minor": 0 }, @@ -85,7 +85,7 @@ "MapWidget(calls=[['addControl', ('ScaleControl', {'unit': 'metric'}, 'bottom-left')], ['addLayer', ({'id': 'ea…" ] }, - "execution_count": 4, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -94,7 +94,7 @@ "m = Map()\n", "m.add_control(ScaleControl(), position=\"bottom-left\")\n", "m.add_layer(earthquake_circles)\n", - "m.add_tooltip(layer_id, \"mag\")\n", + "m.add_tooltip(layer_id)\n", "m.add_marker(Marker(lng_lat=(100.507, 13.745)))\n", "m" ] @@ -109,39 +109,29 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 28, "id": "356960fa-b866-42c8-a58e-0c9a417c28eb", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "60ef57a918734016b9766e41615c1935", + "model_id": "7998e7feb14045d6a8dfc637d6775c98", "version_major": 2, "version_minor": 0 }, "text/plain": [ - "interactive(children=(IntSlider(value=5, description='radius', max=15, min=-5), Output()), _dom_classes=('widg…" + "interactive(children=(IntSlider(value=4, description='radius', max=8, min=1), Output()), _dom_classes=('widget…" ] }, "metadata": {}, "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "(radius)>" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "widgets.interact(\n", + "change_radius = widgets.interact(\n", " lambda radius: m.set_paint_property(layer_id, \"circle-radius\", radius),\n", - " radius=5\n", + " radius=(1, 8, 1)\n", ")" ] }, @@ -155,14 +145,14 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 21, "id": "8ecd93a6-f471-4350-a052-7a9171fa1606", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "9b52cdb12c3b4af4ac8bbbfc885aea30", + "model_id": "ca7ad45e679d479795b3c05014c8e6b4", "version_major": 2, "version_minor": 0 }, @@ -172,20 +162,10 @@ }, "metadata": {}, "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "(color)>" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "widgets.interact(\n", + "change_color = widgets.interact(\n", " lambda color: m.set_paint_property(layer_id, \"circle-color\", color),\n", " color=[\"green\", \"yellow\", \"orange\", \"red\"]\n", ")" @@ -201,39 +181,29 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 31, "id": "0b73f056-f35a-46bb-a092-d899c64cd67e", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "5a4891d6fb0e418bbfe22c4661363022", + "model_id": "405b4aba579b42248573eaf356f629d4", "version_major": 2, "version_minor": 0 }, "text/plain": [ - "interactive(children=(IntSlider(value=3, description='mag_min', max=9, min=-3), Output()), _dom_classes=('widg…" + "interactive(children=(IntSlider(value=4, description='mag_min', max=7, min=1), Output()), _dom_classes=('widge…" ] }, "metadata": {}, "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "(mag_min)>" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "widgets.interact(\n", + "filter_mag = widgets.interact(\n", " lambda mag_min: m.set_filter(layer_id, [\">=\", [\"get\", \"mag\"], mag_min]),\n", - " mag_min=3\n", + " mag_min=(1,7,1)\n", ")" ] }, @@ -247,14 +217,14 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 32, "id": "a9c5ddf7-074e-45b0-8cfe-15750fd0b4d5", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "119b58c9640f4b058fc218ce17203edf", + "model_id": "3957fc738b2643cfa207f9b62edbfdda", "version_major": 2, "version_minor": 0 }, @@ -262,7 +232,7 @@ "Output()" ] }, - "execution_count": 8, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } @@ -284,136 +254,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "7ad74d91-1137-45b4-8791-83dc3546535e", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on _InteractFactory in module ipywidgets.widgets.interaction object:\n", - "\n", - "class _InteractFactory(builtins.object)\n", - " | _InteractFactory(cls, options, kwargs={})\n", - " | \n", - " | Factory for instances of :class:`interactive`.\n", - " | \n", - " | This class is needed to support options like::\n", - " | \n", - " | >>> @interact.options(manual=True)\n", - " | ... def greeting(text=\"World\"):\n", - " | ... print(\"Hello {}\".format(text))\n", - " | \n", - " | Parameters\n", - " | ----------\n", - " | cls : class\n", - " | The subclass of :class:`interactive` to construct.\n", - " | options : dict\n", - " | A dict of options used to construct the interactive\n", - " | function. By default, this is returned by\n", - " | ``cls.default_options()``.\n", - " | kwargs : dict\n", - " | A dict of **kwargs to use for widgets.\n", - " | \n", - " | Methods defined here:\n", - " | \n", - " | __call__(self, _InteractFactory__interact_f=None, **kwargs)\n", - " | Make the given function interactive by adding and displaying\n", - " | the corresponding :class:`interactive` widget.\n", - " | \n", - " | Expects the first argument to be a function. Parameters to this\n", - " | function are widget abbreviations passed in as keyword arguments\n", - " | (``**kwargs``). Can be used as a decorator (see examples).\n", - " | \n", - " | Returns\n", - " | -------\n", - " | f : __interact_f with interactive widget attached to it.\n", - " | \n", - " | Parameters\n", - " | ----------\n", - " | __interact_f : function\n", - " | The function to which the interactive widgets are tied. The `**kwargs`\n", - " | should match the function signature. Passed to :func:`interactive()`\n", - " | **kwargs : various, optional\n", - " | An interactive widget is created for each keyword argument that is a\n", - " | valid widget abbreviation. Passed to :func:`interactive()`\n", - " | \n", - " | Examples\n", - " | --------\n", - " | Render an interactive text field that shows the greeting with the passed in\n", - " | text::\n", - " | \n", - " | # 1. Using interact as a function\n", - " | def greeting(text=\"World\"):\n", - " | print(\"Hello {}\".format(text))\n", - " | interact(greeting, text=\"Jupyter Widgets\")\n", - " | \n", - " | # 2. Using interact as a decorator\n", - " | @interact\n", - " | def greeting(text=\"World\"):\n", - " | print(\"Hello {}\".format(text))\n", - " | \n", - " | # 3. Using interact as a decorator with named parameters\n", - " | @interact(text=\"Jupyter Widgets\")\n", - " | def greeting(text=\"World\"):\n", - " | print(\"Hello {}\".format(text))\n", - " | \n", - " | Render an interactive slider widget and prints square of number::\n", - " | \n", - " | # 1. Using interact as a function\n", - " | def square(num=1):\n", - " | print(\"{} squared is {}\".format(num, num*num))\n", - " | interact(square, num=5)\n", - " | \n", - " | # 2. Using interact as a decorator\n", - " | @interact\n", - " | def square(num=2):\n", - " | print(\"{} squared is {}\".format(num, num*num))\n", - " | \n", - " | # 3. Using interact as a decorator with named parameters\n", - " | @interact(num=5)\n", - " | def square(num=2):\n", - " | print(\"{} squared is {}\".format(num, num*num))\n", - " | \n", - " | __init__(self, cls, options, kwargs={})\n", - " | Initialize self. See help(type(self)) for accurate signature.\n", - " | \n", - " | options(self, **kwds)\n", - " | Change options for interactive functions.\n", - " | \n", - " | Returns\n", - " | -------\n", - " | A new :class:`_InteractFactory` which will apply the\n", - " | options when called.\n", - " | \n", - " | widget(self, f)\n", - " | Return an interactive function widget for the given function.\n", - " | \n", - " | The widget is only constructed, not displayed nor attached to\n", - " | the function.\n", - " | \n", - " | Returns\n", - " | -------\n", - " | An instance of ``self.cls`` (typically :class:`interactive`).\n", - " | \n", - " | Parameters\n", - " | ----------\n", - " | f : function\n", - " | The function to which the interactive widgets are tied.\n", - " | \n", - " | ----------------------------------------------------------------------\n", - " | Data descriptors defined here:\n", - " | \n", - " | __dict__\n", - " | dictionary for instance variables (if defined)\n", - " | \n", - " | __weakref__\n", - " | list of weak references to the object (if defined)\n", - "\n" - ] - } - ], + "outputs": [], "source": [] }, { diff --git a/maplibre/srcjs/index.js b/maplibre/srcjs/index.js index 04cabad5..dc3f5b15 100644 --- a/maplibre/srcjs/index.js +++ b/maplibre/srcjs/index.js @@ -1,7 +1,7 @@ -(()=>{var B=Object.prototype.toString,_=Array.isArray||function(e){return B.call(e)==="[object Array]"};function R(r){return typeof r=="function"}function D(r){return _(r)?"array":typeof r}function P(r){return r.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function x(r,e){return r!=null&&typeof r=="object"&&e in r}function H(r,e){return r!=null&&typeof r!="object"&&r.hasOwnProperty&&r.hasOwnProperty(e)}var N=RegExp.prototype.test;function W(r,e){return N.call(r,e)}var q=/\S/;function F(r){return!W(q,r)}var G={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function K(r){return String(r).replace(/[&<>"'`=\/]/g,function(t){return G[t]})}var V=/\s*/,z=/\s+/,j=/\s*=/,J=/\s*\}/,Q=/#|\^|\/|>|\{|&|=|!/;function X(r,e){if(!r)return[];var t=!1,n=[],a=[],s=[],o=!1,i=!1,p="",u=0;function h(){if(o&&!i)for(;s.length;)delete a[s.pop()];else s=[];o=!1,i=!1}var v,m,O;function U(y){if(typeof y=="string"&&(y=y.split(z,2)),!_(y)||y.length!==2)throw new Error("Invalid tags: "+y);v=new RegExp(P(y[0])+"\\s*"),m=new RegExp("\\s*"+P(y[1])),O=new RegExp("\\s*"+P("}"+y[1]))}U(e||g.tags);for(var l=new E(r),w,f,d,k,L,b;!l.eos();){if(w=l.pos,d=l.scanUntil(v),d)for(var M=0,A=d.length;M"?L=[f,d,w,l.pos,p,u,t]:L=[f,d,w,l.pos],u++,a.push(L),f==="#"||f==="^")n.push(L);else if(f==="/"){if(b=n.pop(),!b)throw new Error('Unopened section "'+d+'" at '+w);if(b[1]!==d)throw new Error('Unclosed section "'+b[1]+'" at '+w)}else f==="name"||f==="{"||f==="&"?i=!0:f==="="&&U(d)}if(h(),b=n.pop(),b)throw new Error('Unclosed section "'+b[1]+'" at '+l.pos);return Z(Y(a))}function Y(r){for(var e=[],t,n,a=0,s=r.length;a0?n[n.length-1][4]:e;break;default:t.push(a)}return e}function E(r){this.string=r,this.tail=r,this.pos=0}E.prototype.eos=function(){return this.tail===""};E.prototype.scan=function(e){var t=this.tail.match(e);if(!t||t.index!==0)return"";var n=t[0];return this.tail=this.tail.substring(n.length),this.pos+=n.length,n};E.prototype.scanUntil=function(e){var t=this.tail.search(e),n;switch(t){case-1:n=this.tail,this.tail="";break;case 0:n="";break;default:n=this.tail.substring(0,t),this.tail=this.tail.substring(t)}return this.pos+=n.length,n};function C(r,e){this.view=r,this.cache={".":this.view},this.parent=e}C.prototype.push=function(e){return new C(e,this)};C.prototype.lookup=function(e){var t=this.cache,n;if(t.hasOwnProperty(e))n=t[e];else{for(var a=this,s,o,i,p=!1;a;){if(e.indexOf(".")>0)for(s=a.view,o=e.split("."),i=0;s!=null&&i"?u=this.renderPartial(i,t,n,s):p==="&"?u=this.unescapedValue(i,t):p==="name"?u=this.escapedValue(i,t,s):p==="text"&&(u=this.rawValue(i)),u!==void 0&&(o+=u);return o};c.prototype.renderSection=function(e,t,n,a,s){var o=this,i="",p=t.lookup(e[1]);function u(m){return o.render(m,t,n,s)}if(p){if(_(p))for(var h=0,v=p.length;h0||!n)&&(s[o]=a+s[o]);return s.join(` -`)};c.prototype.renderPartial=function(e,t,n,a){if(n){var s=this.getConfigTags(a),o=R(n)?n(e[1]):n[e[1]];if(o!=null){var i=e[6],p=e[5],u=e[4],h=o;p==0&&u&&(h=this.indentPartial(o,u,i));var v=this.parse(h,s);return this.renderTokens(v,t,n,h,a)}}};c.prototype.unescapedValue=function(e,t){var n=t.lookup(e[1]);if(n!=null)return n};c.prototype.escapedValue=function(e,t,n){var a=this.getConfigEscape(n)||g.escape,s=t.lookup(e[1]);if(s!=null)return typeof s=="number"&&a===g.escape?String(s):a(s)};c.prototype.rawValue=function(e){return e[1]};c.prototype.getConfigTags=function(e){return _(e)?e:e&&typeof e=="object"?e.tags:void 0};c.prototype.getConfigEscape=function(e){if(e&&typeof e=="object"&&!_(e))return e.escape};var g={name:"mustache.js",version:"4.2.0",tags:["{{","}}"],clearCache:void 0,escape:void 0,parse:void 0,render:void 0,Scanner:void 0,Context:void 0,Writer:void 0,set templateCache(r){T.templateCache=r},get templateCache(){return T.templateCache}},T=new c;g.clearCache=function(){return T.clearCache()};g.parse=function(e,t){return T.parse(e,t)};g.render=function(e,t,n,a){if(typeof e!="string")throw new TypeError('Invalid template! Template should be a "string" but "'+D(e)+'" was given as the first argument for mustache#render(template, view, partials)');return T.render(e,t,n,a)};g.escape=K;g.Scanner=E;g.Context=C;g.Writer=c;var I=g;function $(r,e,t){return t!==null?I.render(t,r.properties):e===null?Object.keys(r.properties).map(a=>`${a}: ${r.properties[a]}`).join("
"):r.properties[e]}var S=class{constructor(e){this._id=e.container,this._map=new maplibregl.Map(e),this._map.on("mouseover",()=>{this._map.getCanvas().style.cursor="pointer"}),this._map.on("mouseout",()=>{this._map.getCanvas().style.cursor=""}),this._map.addControl(new maplibregl.NavigationControl)}getMap(){return this._map}applyMapMethod(e,t){this._map[e](...t)}addControl(e,t,n){this._map.addControl(new maplibregl[e](t),n)}addMarker({lngLat:e,popup:t,options:n}){let a=new maplibregl.Marker(n).setLngLat(e);if(t){let s=new maplibregl.Popup(t.options).setHTML(t.text);a.setPopup(s)}a.addTo(this._map)}addLayer(e){this._map.addLayer(e),typeof Shiny<"u"&&this._map.on("click",e.id,t=>{console.log(t,t.features[0]);let n=e.id.replaceAll("-","_"),a=`${this._id}_layer_${n}`,s={props:t.features[0].properties,layer_id:e.id};console.log(a,s),Shiny.onInputChange(a,s)})}addPopup(e,t,n=null){let a={closeButton:!1},s=new maplibregl.Popup(a);this._map.on("click",e,o=>{let i=o.features[0],p=$(i,t,n);s.setLngLat(o.lngLat).setHTML(p).addTo(this._map)})}addTooltip(e,t,n=null){let a={closeButton:!1,closeOnClick:!1},s=new maplibregl.Popup(a);this._map.on("mousemove",e,o=>{let i=o.features[0],p=$(i,t,n);s.setLngLat(o.lngLat).setHTML(p).addTo(this._map)}),this._map.on("mouseleave",e,()=>{s.remove()})}setSourceData(e,t){this._map.getSource(e).setData(t)}render(e){e.forEach(([t,n])=>{if(["addLayer","addPopup","addTooltip","addMarker","addPopup","addControl","setSourceData"].includes(t)){console.log("Custom method",t,n),this[t](...n);return}console.log("Map method",t),this.applyMapMethod(t,n)})}};var ee="0.1.0";console.log("pymaplibregl",ee);typeof Shiny>"u"&&(window.pymaplibregl=function({mapOptions:r,calls:e}){let t="pymaplibregl",n=document.getElementById(t),a=new S(Object.assign({container:n.id},r));a.getMap().on("load",()=>{a.render(e)})});if(typeof Shiny<"u"){class r extends Shiny.OutputBinding{find(t){return t.find(".shiny-maplibregl-output")}renderValue(t,n){console.log("id:",t.id,"payload:",n);let a=new S(Object.assign({container:t.id},n.mapData.mapOptions)),s=a.getMap();s.on("load",()=>{a.render(n.mapData.calls)}),s.on("click",i=>{console.log(i);let p=`${t.id}`,u={coords:i.lngLat,point:i.point};console.log(p,u),Shiny.onInputChange(p,u)});let o=`pymaplibregl-${t.id}`;console.log(o),Shiny.addCustomMessageHandler(o,({id:i,calls:p})=>{console.log(i,p),a.render(p)})}}Shiny.outputBindings.register(new r,"shiny-maplibregl-output")}})(); +(()=>{var B=Object.prototype.toString,_=Array.isArray||function(e){return B.call(e)==="[object Array]"};function R(n){return typeof n=="function"}function D(n){return _(n)?"array":typeof n}function P(n){return n.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function j(n,e){return n!=null&&typeof n=="object"&&e in n}function F(n,e){return n!=null&&typeof n!="object"&&n.hasOwnProperty&&n.hasOwnProperty(e)}var H=RegExp.prototype.test;function N(n,e){return H.call(n,e)}var W=/\S/;function q(n){return!N(W,n)}var G={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function K(n){return String(n).replace(/[&<>"'`=\/]/g,function(t){return G[t]})}var V=/\s*/,z=/\s+/,I=/\s*=/,J=/\s*\}/,Q=/#|\^|\/|>|\{|&|=|!/;function X(n,e){if(!n)return[];var t=!1,r=[],a=[],s=[],o=!1,i=!1,p="",u=0;function h(){if(o&&!i)for(;s.length;)delete a[s.pop()];else s=[];o=!1,i=!1}var v,m,x;function U(y){if(typeof y=="string"&&(y=y.split(z,2)),!_(y)||y.length!==2)throw new Error("Invalid tags: "+y);v=new RegExp(P(y[0])+"\\s*"),m=new RegExp("\\s*"+P(y[1])),x=new RegExp("\\s*"+P("}"+y[1]))}U(e||g.tags);for(var l=new E(n),w,f,d,k,L,b;!l.eos();){if(w=l.pos,d=l.scanUntil(v),d)for(var M=0,A=d.length;M"?L=[f,d,w,l.pos,p,u,t]:L=[f,d,w,l.pos],u++,a.push(L),f==="#"||f==="^")r.push(L);else if(f==="/"){if(b=r.pop(),!b)throw new Error('Unopened section "'+d+'" at '+w);if(b[1]!==d)throw new Error('Unclosed section "'+b[1]+'" at '+w)}else f==="name"||f==="{"||f==="&"?i=!0:f==="="&&U(d)}if(h(),b=r.pop(),b)throw new Error('Unclosed section "'+b[1]+'" at '+l.pos);return Z(Y(a))}function Y(n){for(var e=[],t,r,a=0,s=n.length;a0?r[r.length-1][4]:e;break;default:t.push(a)}return e}function E(n){this.string=n,this.tail=n,this.pos=0}E.prototype.eos=function(){return this.tail===""};E.prototype.scan=function(e){var t=this.tail.match(e);if(!t||t.index!==0)return"";var r=t[0];return this.tail=this.tail.substring(r.length),this.pos+=r.length,r};E.prototype.scanUntil=function(e){var t=this.tail.search(e),r;switch(t){case-1:r=this.tail,this.tail="";break;case 0:r="";break;default:r=this.tail.substring(0,t),this.tail=this.tail.substring(t)}return this.pos+=r.length,r};function C(n,e){this.view=n,this.cache={".":this.view},this.parent=e}C.prototype.push=function(e){return new C(e,this)};C.prototype.lookup=function(e){var t=this.cache,r;if(t.hasOwnProperty(e))r=t[e];else{for(var a=this,s,o,i,p=!1;a;){if(e.indexOf(".")>0)for(s=a.view,o=e.split("."),i=0;s!=null&&i"?u=this.renderPartial(i,t,r,s):p==="&"?u=this.unescapedValue(i,t):p==="name"?u=this.escapedValue(i,t,s):p==="text"&&(u=this.rawValue(i)),u!==void 0&&(o+=u);return o};c.prototype.renderSection=function(e,t,r,a,s){var o=this,i="",p=t.lookup(e[1]);function u(m){return o.render(m,t,r,s)}if(p){if(_(p))for(var h=0,v=p.length;h0||!r)&&(s[o]=a+s[o]);return s.join(` +`)};c.prototype.renderPartial=function(e,t,r,a){if(r){var s=this.getConfigTags(a),o=R(r)?r(e[1]):r[e[1]];if(o!=null){var i=e[6],p=e[5],u=e[4],h=o;p==0&&u&&(h=this.indentPartial(o,u,i));var v=this.parse(h,s);return this.renderTokens(v,t,r,h,a)}}};c.prototype.unescapedValue=function(e,t){var r=t.lookup(e[1]);if(r!=null)return r};c.prototype.escapedValue=function(e,t,r){var a=this.getConfigEscape(r)||g.escape,s=t.lookup(e[1]);if(s!=null)return typeof s=="number"&&a===g.escape?String(s):a(s)};c.prototype.rawValue=function(e){return e[1]};c.prototype.getConfigTags=function(e){return _(e)?e:e&&typeof e=="object"?e.tags:void 0};c.prototype.getConfigEscape=function(e){if(e&&typeof e=="object"&&!_(e))return e.escape};var g={name:"mustache.js",version:"4.2.0",tags:["{{","}}"],clearCache:void 0,escape:void 0,parse:void 0,render:void 0,Scanner:void 0,Context:void 0,Writer:void 0,set templateCache(n){T.templateCache=n},get templateCache(){return T.templateCache}},T=new c;g.clearCache=function(){return T.clearCache()};g.parse=function(e,t){return T.parse(e,t)};g.render=function(e,t,r,a){if(typeof e!="string")throw new TypeError('Invalid template! Template should be a "string" but "'+D(e)+'" was given as the first argument for mustache#render(template, view, partials)');return T.render(e,t,r,a)};g.escape=K;g.Scanner=E;g.Context=C;g.Writer=c;var $=g;function O(n,e,t){return t!==null?$.render(t,n.properties):e===null?Object.keys(n.properties).map(a=>`${a}: ${n.properties[a]}`).join("
"):n.properties[e]}var S=class{constructor(e){this._id=e.container,this._map=new maplibregl.Map(e),this._map.on("mouseover",()=>{this._map.getCanvas().style.cursor="pointer"}),this._map.on("mouseout",()=>{this._map.getCanvas().style.cursor=""}),this._map.addControl(new maplibregl.NavigationControl)}getMap(){return this._map}applyMapMethod(e,t){this._map[e](...t)}addControl(e,t,r){this._map.addControl(new maplibregl[e](t),r)}addMarker({lngLat:e,popup:t,options:r}){let a=new maplibregl.Marker(r).setLngLat(e);if(t){let s=new maplibregl.Popup(t.options).setHTML(t.text);a.setPopup(s)}a.addTo(this._map)}addLayer(e){this._map.addLayer(e),typeof Shiny<"u"&&this._map.on("click",e.id,t=>{console.log(t,t.features[0]);let r=e.id.replaceAll("-","_"),a=`${this._id}_layer_${r}`,s={props:t.features[0].properties,layer_id:e.id};console.log(a,s),Shiny.onInputChange(a,s)})}addPopup(e,t,r=null){let a={closeButton:!1},s=new maplibregl.Popup(a);this._map.on("click",e,o=>{let i=o.features[0],p=O(i,t,r);s.setLngLat(o.lngLat).setHTML(p).addTo(this._map)})}addTooltip(e,t,r=null){let a={closeButton:!1,closeOnClick:!1},s=new maplibregl.Popup(a);this._map.on("mousemove",e,o=>{let i=o.features[0],p=O(i,t,r);s.setLngLat(o.lngLat).setHTML(p).addTo(this._map)}),this._map.on("mouseleave",e,()=>{s.remove()})}setSourceData(e,t){this._map.getSource(e).setData(t)}render(e){e.forEach(([t,r])=>{if(["addLayer","addPopup","addTooltip","addMarker","addPopup","addControl","setSourceData"].includes(t)){console.log("Custom method",t,r),this[t](...r);return}console.log("Map method",t),this.applyMapMethod(t,r)})}};var ee="0.1.0";console.log("pymaplibregl",ee);typeof Shiny>"u"&&(window.pymaplibregl=function({mapOptions:n,calls:e}){let t="pymaplibregl",r=document.getElementById(t),a=new S(Object.assign({container:r.id},n));a.getMap().on("load",()=>{a.render(e)})});if(typeof Shiny<"u"){class n extends Shiny.OutputBinding{find(t){return t.find(".shiny-maplibregl-output")}renderValue(t,r){console.log("id:",t.id,"payload:",r);let a=new S(Object.assign({container:t.id},r.mapData.mapOptions)),s=a.getMap();s.on("load",()=>{a.render(r.mapData.calls)}),s.on("click",i=>{console.log(i);let p=`${t.id}`,u={coords:i.lngLat,point:i.point};console.log(p,u),Shiny.onInputChange(p,u)});let o=`pymaplibregl-${t.id}`;console.log(o),Shiny.addCustomMessageHandler(o,({id:i,calls:p})=>{console.log(i,p),a.render(p)})}}Shiny.outputBindings.register(new n,"shiny-maplibregl-output")}})(); /*! Bundled license information: mustache/mustache.mjs: diff --git a/maplibre/srcjs/ipywidget.js b/maplibre/srcjs/ipywidget.js index 3a488ce7..46b5d102 100644 --- a/maplibre/srcjs/ipywidget.js +++ b/maplibre/srcjs/ipywidget.js @@ -1,122 +1,12 @@ -// srcjs/ipywidget.js -import maplibregl from "https://esm.sh/maplibre-gl@3.6.2"; +import R from"https://esm.sh/maplibre-gl@3.6.2";var H=Object.prototype.toString,T=Array.isArray||function(e){return H.call(e)==="[object Array]"};function U(n){return typeof n=="function"}function N(n){return T(n)?"array":typeof n}function L(n){return n.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function _(n,e){return n!=null&&typeof n=="object"&&e in n}function $(n,e){return n!=null&&typeof n!="object"&&n.hasOwnProperty&&n.hasOwnProperty(e)}var B=RegExp.prototype.test;function D(n,e){return B.call(n,e)}var z=/\S/;function K(n){return!D(z,n)}var G={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function J(n){return String(n).replace(/[&<>"'`=\/]/g,function(t){return G[t]})}var Q=/\s*/,V=/\s+/,A=/\s*=/,X=/\s*\}/,Y=/#|\^|\/|>|\{|&|=|!/;function Z(n,e){if(!n)return[];var t=!1,r=[],s=[],a=[],o=!1,i=!1,c="",u=0;function p(){if(o&&!i)for(;a.length;)delete s[a.pop()];else a=[];o=!1,i=!1}var g,C,m;function O(y){if(typeof y=="string"&&(y=y.split(V,2)),!T(y)||y.length!==2)throw new Error("Invalid tags: "+y);g=new RegExp(L(y[0])+"\\s*"),C=new RegExp("\\s*"+L(y[1])),m=new RegExp("\\s*"+L("}"+y[1]))}O(e||v.tags);for(var l=new S(n),w,h,d,E,P,b;!l.eos();){if(w=l.pos,d=l.scanUntil(g),d)for(var x=0,q=d.length;x"?P=[h,d,w,l.pos,c,u,t]:P=[h,d,w,l.pos],u++,s.push(P),h==="#"||h==="^")r.push(P);else if(h==="/"){if(b=r.pop(),!b)throw new Error('Unopened section "'+d+'" at '+w);if(b[1]!==d)throw new Error('Unclosed section "'+b[1]+'" at '+w)}else h==="name"||h==="{"||h==="&"?i=!0:h==="="&&O(d)}if(p(),b=r.pop(),b)throw new Error('Unclosed section "'+b[1]+'" at '+l.pos);return te(ee(s))}function ee(n){for(var e=[],t,r,s=0,a=n.length;s0?r[r.length-1][4]:e;break;default:t.push(s)}return e}function S(n){this.string=n,this.tail=n,this.pos=0}S.prototype.eos=function(){return this.tail===""};S.prototype.scan=function(e){var t=this.tail.match(e);if(!t||t.index!==0)return"";var r=t[0];return this.tail=this.tail.substring(r.length),this.pos+=r.length,r};S.prototype.scanUntil=function(e){var t=this.tail.search(e),r;switch(t){case-1:r=this.tail,this.tail="";break;case 0:r="";break;default:r=this.tail.substring(0,t),this.tail=this.tail.substring(t)}return this.pos+=r.length,r};function k(n,e){this.view=n,this.cache={".":this.view},this.parent=e}k.prototype.push=function(e){return new k(e,this)};k.prototype.lookup=function(e){var t=this.cache,r;if(t.hasOwnProperty(e))r=t[e];else{for(var s=this,a,o,i,c=!1;s;){if(e.indexOf(".")>0)for(a=s.view,o=e.split("."),i=0;a!=null&&i"?u=this.renderPartial(i,t,r,a):c==="&"?u=this.unescapedValue(i,t):c==="name"?u=this.escapedValue(i,t,a):c==="text"&&(u=this.rawValue(i)),u!==void 0&&(o+=u);return o};f.prototype.renderSection=function(e,t,r,s,a){var o=this,i="",c=t.lookup(e[1]);function u(C){return o.render(C,t,r,a)}if(c){if(T(c))for(var p=0,g=c.length;p0||!r)&&(a[o]=s+a[o]);return a.join(` +`)};f.prototype.renderPartial=function(e,t,r,s){if(r){var a=this.getConfigTags(s),o=U(r)?r(e[1]):r[e[1]];if(o!=null){var i=e[6],c=e[5],u=e[4],p=o;c==0&&u&&(p=this.indentPartial(o,u,i));var g=this.parse(p,a);return this.renderTokens(g,t,r,p,s)}}};f.prototype.unescapedValue=function(e,t){var r=t.lookup(e[1]);if(r!=null)return r};f.prototype.escapedValue=function(e,t,r){var s=this.getConfigEscape(r)||v.escape,a=t.lookup(e[1]);if(a!=null)return typeof a=="number"&&s===v.escape?String(a):s(a)};f.prototype.rawValue=function(e){return e[1]};f.prototype.getConfigTags=function(e){return T(e)?e:e&&typeof e=="object"?e.tags:void 0};f.prototype.getConfigEscape=function(e){if(e&&typeof e=="object"&&!T(e))return e.escape};var v={name:"mustache.js",version:"4.2.0",tags:["{{","}}"],clearCache:void 0,escape:void 0,parse:void 0,render:void 0,Scanner:void 0,Context:void 0,Writer:void 0,set templateCache(n){M.templateCache=n},get templateCache(){return M.templateCache}},M=new f;v.clearCache=function(){return M.clearCache()};v.parse=function(e,t){return M.parse(e,t)};v.render=function(e,t,r,s){if(typeof e!="string")throw new TypeError('Invalid template! Template should be a "string" but "'+N(e)+'" was given as the first argument for mustache#render(template, view, partials)');return M.render(e,t,r,s)};v.escape=J;v.Scanner=S;v.Context=k;v.Writer=f;var F=v;function j(n,e,t){return t!==null?F.render(t,n.properties):e===null?Object.keys(n.properties).map(s=>`${s}: ${n.properties[s]}`).join("
"):n.properties[e]}function I(n,e){let[t,r]=e;console.log(t,r),n[t](...r)}function W(n,e){return{addTooltip:function(t,r,s=null){let a={closeButton:!1,closeOnClick:!1},o=new n.Popup(a);e.on("mousemove",t,i=>{let c=i.features[0],u=j(c,r,s);o.setLngLat(i.lngLat).setHTML(u).addTo(e)}),e.on("mouseleave",t,()=>{o.remove()})},addControl:function(t,r,s){e.addControl(new n[t](r),s)},addPopup:function(t,r,s=null){let a={closeButton:!1},o=new n.Popup(a);e.on("click",t,i=>{let c=i.features[0],u=j(c,r,s);o.setLngLat(i.lngLat).setHTML(u).addTo(e)})},addMarker:function({lngLat:t,popup:r,options:s}){let a=new n.Marker(s).setLngLat(t);if(r){let o=new n.Popup(r.options).setHTML(r.text);a.setPopup(o)}a.addTo(e)},setSourceData:function(t,r){e.getSource(t).setData(r)}}}function ne(n){let e="pymaplibregl",t=document.createElement("div");return t.id=e,t.style.height=n.get("height"),t}function re(n,e){let t=new R.Map(n);return n.navigationControl===void 0&&(n.navigationControl=!0),n.navigationControl&&t.addControl(new R.NavigationControl),t.on("mouseover",()=>{t.getCanvas().style.cursor="pointer"}),t.on("mouseout",()=>{t.getCanvas().style.cursor=""}),t.on("click",r=>{e.set("lng_lat",r.lngLat),e.save_changes()}),t.once("load",()=>{t.resize()}),t}function pe({model:n,el:e}){console.log("maplibregl",R.version);let t=ne(n),r=Object.assign({container:t},n.get("map_options"));console.log(r);let s=re(r,n),a=W(R,s),o=c=>{c.forEach(u=>{if(Object.keys(a).includes(u[0])){console.log("internal call",u);let[p,g]=u;a[p](...g);return}I(s,u)})},i=n.get("calls");s.on("load",()=>{console.log("init calls",i),o(i),n.set("_rendered",!0),n.save_changes()}),n.on("msg:custom",c=>{console.log("custom msg",c),o(c.calls)}),e.appendChild(t)}export{pe as render}; +/*! Bundled license information: -// srcjs/mapmethods.js -function applyMapMethod(map, call) { - const [methodName, params] = call; - console.log(methodName, params); - map[methodName](...params); -} -function getCustomMapMethods(maplibregl2, map) { - return { - addTooltip: function(layerId, property) { - const popupOptions = { - closeButton: false, - closeOnClick: false - }; - const popup = new maplibregl2.Popup(popupOptions); - map.on("mousemove", layerId, (e) => { - const feature = e.features[0]; - const text = feature.properties[property]; - popup.setLngLat(e.lngLat).setHTML(text).addTo(map); - }); - map.on("mouseleave", layerId, () => { - popup.remove(); - }); - }, - addControl: function(type, options, position) { - map.addControl(new maplibregl2[type](options), position); - }, - addPopup: function(layerId, property) { - const popupOptions = { - closeButton: false - }; - const popup = new maplibregl2.Popup(popupOptions); - map.on("click", layerId, (e) => { - const feature = e.features[0]; - const text = feature.properties[property]; - popup.setLngLat(e.lngLat).setHTML(text).addTo(map); - }); - }, - addMarker: function({ lngLat, popup, options }) { - const marker = new maplibregl2.Marker(options).setLngLat(lngLat); - if (popup) { - const popup_ = new maplibregl2.Popup(popup.options).setHTML(popup.text); - marker.setPopup(popup_); - } - marker.addTo(map); - }, - setSourceData: function(sourceId, data) { - map.getSource(sourceId).setData(data); - } - }; -} - -// srcjs/ipywidget.js -function createContainer(model) { - const id = "pymaplibregl"; - const container = document.createElement("div"); - container.id = id; - container.style.height = model.get("height"); - return container; -} -function createMap(mapOptions, model) { - const map = new maplibregl.Map(mapOptions); - if (mapOptions.navigationControl === void 0) { - mapOptions.navigationControl = true; - } - if (mapOptions.navigationControl) { - map.addControl(new maplibregl.NavigationControl()); - } - map.on("mouseover", () => { - map.getCanvas().style.cursor = "pointer"; - }); - map.on("mouseout", () => { - map.getCanvas().style.cursor = ""; - }); - map.on("click", (e) => { - model.set("lng_lat", e.lngLat); - model.save_changes(); - }); - map.once("load", () => { - map.resize(); - }); - return map; -} -function render({ model, el }) { - console.log("maplibregl", maplibregl.version); - const container = createContainer(model); - const mapOptions = Object.assign( - { container }, - model.get("map_options") - ); - console.log(mapOptions); - const map = createMap(mapOptions, model); - const customMapMethods = getCustomMapMethods(maplibregl, map); - const apply = (calls2) => { - calls2.forEach((call) => { - if (Object.keys(customMapMethods).includes(call[0])) { - console.log("internal call", call); - const [name, params] = call; - customMapMethods[name](...params); - return; - } - applyMapMethod(map, call); - }); - }; - const calls = model.get("calls"); - map.on("load", () => { - console.log("init calls", calls); - apply(calls); - model.set("_rendered", true); - model.save_changes(); - }); - model.on("msg:custom", (msg) => { - console.log("custom msg", msg); - apply(msg.calls); - }); - el.appendChild(container); -} -export { - render -}; +mustache/mustache.mjs: + (*! + * mustache.js - Logic-less {{mustache}} templates with JavaScript + * http://github.com/janl/mustache.js + *) +*/ diff --git a/package.json b/package.json index beb7d000..afbf809e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "scripts": { "build": "esbuild srcjs/index.js --bundle --minify --outfile=maplibre/srcjs/index.js", "build-dev": "esbuild srcjs/index.js --bundle --outfile=maplibre/srcjs/index.js", - "build-ipywidget": "esbuild srcjs/ipywidget.js --bundle --format=esm --outfile=maplibre/srcjs/ipywidget.js", + "build-ipywidget": "esbuild srcjs/ipywidget.js --bundle --minify --format=esm --outfile=maplibre/srcjs/ipywidget.js", + "build-ipywidget-dev": "esbuild srcjs/ipywidget.js --bundle --format=esm --outfile=maplibre/srcjs/ipywidget.js", "build-rwidget": "esbuild srcjs/rwidget.js --bundle --minify --outfile=../r-maplibregl/inst/htmlwidgets/maplibre.js", "prettier": "prettier srcjs --write", "test": "echo \"Error: no test specified\" && exit 1" diff --git a/srcjs/mapmethods.js b/srcjs/mapmethods.js index 17d094fd..4572f495 100644 --- a/srcjs/mapmethods.js +++ b/srcjs/mapmethods.js @@ -1,3 +1,5 @@ +import { getTextFromFeature } from "./utils"; + function applyMapMethod(map, call) { const [methodName, params] = call; console.log(methodName, params); @@ -8,7 +10,7 @@ function applyMapMethod(map, call) { // Custom map methods function getCustomMapMethods(maplibregl, map) { return { - addTooltip: function (layerId, property) { + addTooltip: function (layerId, property, template = null) { const popupOptions = { closeButton: false, closeOnClick: false, @@ -17,7 +19,9 @@ function getCustomMapMethods(maplibregl, map) { map.on("mousemove", layerId, (e) => { const feature = e.features[0]; - const text = feature.properties[property]; + + // const text = feature.properties[property]; + const text = getTextFromFeature(feature, property, template); popup.setLngLat(e.lngLat).setHTML(text).addTo(map); }); @@ -30,14 +34,16 @@ function getCustomMapMethods(maplibregl, map) { map.addControl(new maplibregl[type](options), position); }, - addPopup: function (layerId, property) { + addPopup: function (layerId, property, template = null) { const popupOptions = { closeButton: false, }; const popup = new maplibregl.Popup(popupOptions); map.on("click", layerId, (e) => { const feature = e.features[0]; - const text = feature.properties[property]; + + // const text = feature.properties[property]; + const text = getTextFromFeature(feature, property, template); popup.setLngLat(e.lngLat).setHTML(text).addTo(map); }); }, diff --git a/srcjs/pymaplibregl.js b/srcjs/pymaplibregl.js index 0774443a..f62427b4 100644 --- a/srcjs/pymaplibregl.js +++ b/srcjs/pymaplibregl.js @@ -1,6 +1,9 @@ import mustache from "mustache"; + // import { getCustomMapMethods } from "./mapmethods"; +import { getTextFromFeature } from "./utils"; +/* function getTextFromFeature(feature, property, template) { if (template !== null) { return mustache.render(template, feature.properties); @@ -15,6 +18,7 @@ function getTextFromFeature(feature, property, template) { return feature.properties[property]; } + */ export default class PyMapLibreGL { constructor(mapOptions) { diff --git a/srcjs/utils.js b/srcjs/utils.js new file mode 100644 index 00000000..cedd917b --- /dev/null +++ b/srcjs/utils.js @@ -0,0 +1,18 @@ +import mustache from "mustache"; + +function getTextFromFeature(feature, property, template) { + if (template !== null) { + return mustache.render(template, feature.properties); + } + + if (property === null) { + const text = Object.keys(feature.properties) + .map((key) => `${key}: ${feature.properties[key]}`) + .join("
"); + return text; + } + + return feature.properties[property]; +} + +export { getTextFromFeature };