From 2c90a7c99cc802cb3f765c7cf06cac13564b6b36 Mon Sep 17 00:00:00 2001 From: Alex Simonok Date: Mon, 17 Jun 2024 04:35:51 +0300 Subject: [PATCH] Update Dynamic Text External Resources examples (#684) * Update Dynamic Text External Resources examples * Advanced Leaflet.js added * Update external.mdx --------- Co-authored-by: vitPinchuk Co-authored-by: Mikhail Volkov --- .../volkovlabs-dynamictext-panel/external.mdx | 427 ++++++++++-------- 1 file changed, 251 insertions(+), 176 deletions(-) diff --git a/docs/volkovlabs-dynamictext-panel/external.mdx b/docs/volkovlabs-dynamictext-panel/external.mdx index 77f6cd64..db680b0f 100644 --- a/docs/volkovlabs-dynamictext-panel/external.mdx +++ b/docs/volkovlabs-dynamictext-panel/external.mdx @@ -28,12 +28,6 @@ To prevent the loading of third-party URLs, you can store CSS and JS files in th src="/img/plugins/volkovlabs-dynamictext-panel/external.png" /> -:::info Sanitization - -You need to disable the sanitization configuration to see external resources in the plugin options. - -::: - ## Manual scripts In the event when a library can not be referenced as an external script, you always can reference and initiate it directly in the **JavaScript->After Content Ready** @@ -86,7 +80,7 @@ Thanks to our community member [Josiah Solomon](https://github.com/yosiasz) for Use the following external Plotly's 3D Scatter chart library: ```md -https://cdn.plot.ly/plotly-2.24.1.min.js +https://esm.sh/plotly.js-dist-min ``` :::info @@ -119,11 +113,7 @@ You can run this example in two ways: Into the **Content** or **Default Content**: ```html - -
- -
- +
``` Into the **JavaScript->Before Content Rendering**: @@ -132,61 +122,6 @@ Into the **JavaScript->Before Content Rendering**: JavaScript code for Plotly example ```js -(async () => { - let url = - "https://raw.githubusercontent.com/plotly/datasets/master/3d-scatter.csv"; - - let fetchData = await fetch(url); - let csvData = await fetchData.text(); - let rows = csvToJson(csvData); - - var trace1 = { - x: unpack(rows, "x1"), - y: unpack(rows, "y1"), - z: unpack(rows, "z1"), - mode: "markers", - marker: { - size: 12, - line: { - color: "rgba(217, 217, 217, 0.14)", - width: 0.5, - }, - opacity: 0.8, - }, - type: "scatter3d", - }; - - var trace2 = { - x: unpack(rows, "x2"), - y: unpack(rows, "y2"), - z: unpack(rows, "z2"), - mode: "markers", - marker: { - color: "rgb(127, 127, 127)", - size: 12, - symbol: "circle", - line: { - color: "rgb(204, 204, 204)", - width: 1, - }, - opacity: 0.8, - }, - type: "scatter3d", - }; - - var data = [trace1, trace2]; - - var layout = { - margin: { - l: 0, - r: 0, - b: 0, - t: 0, - }, - }; - Plotly.newPlot("addisAbeba", data, layout); -})(); - const unpack = (rows, key) => { return rows.map(function (row) { return row[key]; @@ -206,6 +141,69 @@ const csvToJson = (data, delimiter = ",") => { ); }); }; + +/** + * Load plotly + */ +import("https://esm.sh/plotly.js-dist-min").then( + async ({ default: Plotly }) => { + let url = + "https://raw.githubusercontent.com/plotly/datasets/master/3d-scatter.csv"; + + let fetchData = await fetch(url); + let csvData = await fetchData.text(); + let rows = csvToJson(csvData); + + var trace1 = { + x: unpack(rows, "x1"), + y: unpack(rows, "y1"), + z: unpack(rows, "z1"), + mode: "markers", + marker: { + size: 12, + line: { + color: "rgba(217, 217, 217, 0.14)", + width: 0.5, + }, + opacity: 0.8, + }, + type: "scatter3d", + }; + + var trace2 = { + x: unpack(rows, "x2"), + y: unpack(rows, "y2"), + z: unpack(rows, "z2"), + mode: "markers", + marker: { + color: "rgb(127, 127, 127)", + size: 12, + symbol: "circle", + line: { + color: "rgb(204, 204, 204)", + width: 1, + }, + opacity: 0.8, + }, + type: "scatter3d", + }; + + var data = [trace1, trace2]; + + var layout = { + margin: { + l: 0, + r: 0, + b: 0, + t: 0, + }, + }; + + var config = { responsive: true }; + + Plotly.newPlot("plotly-chart", data, layout, config); + } +); ``` @@ -235,7 +233,7 @@ The main reason being the Mermaid Library size. After we added the External Reso Use the following external library ```md -https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js +https://esm.sh/mermaid ``` #### Code to copy @@ -243,7 +241,6 @@ https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js Use the following for the **Content** (when your data source is set to return something) or in the **Default Content** (when your data source returns nothing): ```diagram -flowchart LR
     graph LR
     A --- B
@@ -255,11 +252,13 @@ flowchart LR
 Use the following for the **JavaScript->After Content Ready**:
 
 ```js
-mermaid.initialize({ startOnLoad: true });
+import("https://esm.sh/mermaid").then(({ default: mermaid }) => {
+  mermaid.initialize({ startOnLoad: true });
 
-mermaid.run({
-  querySelector: ".mermaid",
-  suppressErrors: false,
+  mermaid.run({
+    querySelector: ".mermaid",
+    suppressErrors: false,
+  });
 });
 ```
 
@@ -282,7 +281,7 @@ Chart.js is one of the popular open source charting libraries. The Business Text
 Use the following external library
 
 ```md
-https://cdn.jsdelivr.net/npm/chart.js
+https://esm.sh/chart.js
 ```
 
 #### Code to copy
@@ -290,33 +289,44 @@ https://cdn.jsdelivr.net/npm/chart.js
 Use the following for the **Content**:
 
 ```js
-
+
 ```
 
 Use the following for the **JavaScript->After Content Ready**:
 
 ```js
-const ctx = document.getElementById("myChart");
+import("https://esm.sh/chart.js").then(({ Chart, registerables }) => {
+  Chart.register(...registerables);
+
+  /**
+   * Cleanup
+   */
+  if (this.chartInstance) {
+    this.chartInstance.destroy();
+  }
 
-new Chart(ctx, {
-  type: "bar",
-  data: {
-    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
-    datasets: [
-      {
-        label: "# of Votes",
-        data: [12, 19, 3, 5, 2, 3],
-        borderWidth: 1,
-      },
-    ],
-  },
-  options: {
-    scales: {
-      y: {
-        beginAtZero: true,
+  const ctx = document.getElementById("myChart");
+
+  this.chartInstance = new Chart(ctx, {
+    type: "bar",
+    data: {
+      labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
+      datasets: [
+        {
+          label: "# of Votes",
+          data: [12, 19, 3, 5, 2, 3],
+          borderWidth: 1,
+        },
+      ],
+    },
+    options: {
+      scales: {
+        y: {
+          beginAtZero: true,
+        },
       },
     },
-  },
+  });
 });
 ```
 
@@ -338,20 +348,23 @@ Simply, add two external libraries and then write your code addressing the Flowc
 #### External Resources
 
 ```
-https://flowchart.js.org/flowchart-latest.js
-https://cdnjs.cloudflare.com/ajax/libs/raphael/2.3.0/raphael.min.js
+https://esm.sh/flowchart.js
+https://esm.sh/raphael
 ```
 
 #### Content to copy
 
 ```html
-
+
``` #### JavaScript code to copy ``` -var flow = ` +import('https://esm.sh/flowchart.js').then(async (flowchart) => { + await import('https://esm.sh/raphael'); + + const flow = ` st=>start: Start:>http://www.google.com[blank] e=>end:>http://www.google.com op1=>operation: My Operation @@ -370,8 +383,9 @@ para(path1, bottom)->sub1(right)->op1 para(path2, top)->op1 para(path3, right)->in->out->e` -var diagram = flowchart.parse(flow); -diagram.drawSVG('addisAbeba'); + const diagram = flowchart.parse(flow); + diagram.drawSVG('flowchart'); +}) ``` :::info Render template parameter @@ -405,28 +419,14 @@ https://www.youtube.com/iframe_api #### JavaScript code to copy ```js -const videoList = ["AcQi-6GCrNU", "1ogv2jstrlI", "vky-7-DfvXE"]; - -const randomVideoId = videoList[Math.floor(Math.random() * videoList.length)]; +import("https://esm.sh/youtube-player").then(({ default: YouTubePlayer }) => { + const player = YouTubePlayer("player"); -const onPlayerReady = (event) => event.target.playVideo(); + const videoList = ["AcQi-6GCrNU", "1ogv2jstrlI", "vky-7-DfvXE"]; -const onPlayerStateChange = (event) => { - if (event.data === YT.PlayerState.ENDED) { - var newRandomVideoId = - videoList[Math.floor(Math.random() * videoList.length)]; - event.target.loadVideoById(newRandomVideoId); - } -}; + const randomVideoId = videoList[Math.floor(Math.random() * videoList.length)]; -const player = new YT.Player("player", { - height: "360", - width: "640", - videoId: randomVideoId, - events: { - onReady: onPlayerReady, - onStateChange: onPlayerStateChange, - }, + player.loadVideoById(randomVideoId); }); ``` @@ -463,13 +463,13 @@ The map on the dashboard from this example looks like in the illustration below. ``` https://unpkg.com/leaflet@1.9.4/dist/leaflet.css -https://unpkg.com/leaflet@1.9.4/dist/leaflet.js +https://esm.sh/leaflet ``` #### Content ```html -
+
``` #### JavaScript code @@ -478,73 +478,148 @@ https://unpkg.com/leaflet@1.9.4/dist/leaflet.js // This data is coming from the data source. // const geojson = JSON.parse(context.data[0][0].data); -//Addis Abeba centered -const map = L.map("map").setView([9.024857, 38.737607], 13); - -L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { - attribution: - 'Map data © OpenStreetMap contributors', - maxZoom: 18, -}).addTo(map); - -//if you want to use inline data -const geojson = { - type: "FeatureCollection", - crs: { type: "name", properties: { name: "urn:ogc:def:crs:OGC:1.3:CRS84" } }, - features: [ - { - type: "Feature", - properties: { AOIs: "bbb", daily: "33" }, - geometry: { - type: "Polygon", - coordinates: [ - [ - [33.5, 32.0], - [33.5, 29.0], - [36.0, 29.0], - [36.0, 27.5], - [33.5, 27.5], - [32.5, 27.5], - [29.0, 27.5], - [29.0, 32.0], - [33.5, 32.0], +import("https://esm.sh/leaflet").then(({ default: L }) => { + /** + * Cleanup + */ + if (this.map) { + this.map.remove(); + } + + const map = L.map("leaflet").setView([9.024857, 38.737607], 13); + this.map = map; + + L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + attribution: + 'Map data © OpenStreetMap contributors', + maxZoom: 18, + }).addTo(map); + + //if you want to use inline data + const geojson = { + type: "FeatureCollection", + crs: { + type: "name", + properties: { name: "urn:ogc:def:crs:OGC:1.3:CRS84" }, + }, + features: [ + { + type: "Feature", + properties: { AOIs: "bbb", daily: "33" }, + geometry: { + type: "Polygon", + coordinates: [ + [ + [33.5, 32.0], + [33.5, 29.0], + [36.0, 29.0], + [36.0, 27.5], + [33.5, 27.5], + [32.5, 27.5], + [29.0, 27.5], + [29.0, 32.0], + [33.5, 32.0], + ], ], - ], + }, }, - }, - { - type: "Feature", - properties: { AOIs: "aaa", daily: "23" }, - geometry: { - type: "Polygon", - coordinates: [ - [ - [34.5, 32.5], - [36.0, 32.5], - [36.0, 29.0], - [33.5, 29.0], - [33.5, 32.0], - [33.5, 32.5], - [34.5, 32.5], + { + type: "Feature", + properties: { AOIs: "aaa", daily: "23" }, + geometry: { + type: "Polygon", + coordinates: [ + [ + [34.5, 32.5], + [36.0, 32.5], + [36.0, 29.0], + [33.5, 29.0], + [33.5, 32.0], + [33.5, 32.5], + [34.5, 32.5], + ], ], - ], + }, }, - }, - ], -}; + ], + }; -var myStyle = { - color: "black", - weight: 10, -}; + var myStyle = { + color: "black", + weight: 10, + }; + + var geojsonLayer = L.geoJSON(geojson).addTo(map); +}); +``` + +#### CSS styles + +```css +#leaflet { + height: 480px; + display: flex; + flex-direction: row; +} +``` + +### Advanced using Leaflet.js interactive maps + +This is example based on example above and extend it with using dashboard variables and another approach to using `Leaflet.js` in the Business Text Plugin. +Follow the below outlined steps to display Leaflet.js maps on your Grafana dashboard. + +Dashboard variables + +```SQL +select 'China' as __text, '104.1954,35.8617' as __value union +select 'Ethiopia', '40.4897,9.1450' union +select 'Sardina', '9.283447, 40.078072' +``` + +#### External Resources + +``` +https://unpkg.com/leaflet@1.9.4/dist/leaflet.css +https://esm.sh/leaflet +``` + +#### Content + +```html +
+``` + +#### Code After Content section + +```js +// This data is coming from the data source. + +import('https://esm.sh/leaflet').then(({ default: L }) => { + /** + * Cleanup + */ + if (this.map) { + this.map.remove(); + } -var geojsonLayer = L.geoJSON(geojson).addTo(map); + var countries = context.grafana.replaceVariables("${countries:value}") + var lon = Number(countries.split(",")[0]) + var lat = Number(countries.split(",")[1]) + + var map = new L.Map('leaflet'); + map.setView(new L.LatLng(lat, lon), 4); + L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { + attribution: + 'Map data © OpenStreetMap contributors', + maxZoom: 10, + }).addTo(map); +}): ``` #### CSS styles ```css -#map { +#leaflet { height: 480px; display: flex; flex-direction: row;