Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Compete to become Power BI Data Viz World Champion! First round ends August 18th. Get started.

Reply
BmBIDev
Regular Visitor

Need help in displaying a Custom Argis map in power bi

Hi,

 

I am working on a Power BI Proof of Concept project that involves ArcGIS Map visuals. My organization has custom ArcGIS maps that need to be integrated with the Power BI report. The challenge here is that the project needs to be deployed in an environment where ArcGIS online access (login & connect to the Argis portal through the Argis map visualization) is not working. 

The idea is to get the HTML code of the map and use it directly in the report to avoid access issues. I tried the method below.

 

I hosted the HTML code of the map on GitHub and established a GitHub page. Following this, I created a Power BI table, with the URL as one of the column values. Subsequently, I crafted a measure based on the table and integrated the measure's value into an HTML iframe in another measure, as demonstrated below

 

IFrame = 
"<!DOCTYPE html>
<html>
<body>
<iframe src='"& [murl] &"' style='position: fixed; width:100%; height:100%'></iframe>

</body>
</html>"

 

This Iframe measure then used as "Value" in the "Html Content" visual. 

Based on the above steps I am able to display the interactive Custom Argis Map. 

 

The current requirement is to incorporate the HTML code of a visual directly within Power BI, facilitating data integration with other datasets using DAX. I attempted to embed the HTML code into a measure and used it within the HTML Content visual, but this resulted in a blank page.

 

Below is the URL of the Argis sample map : https://developers.arcgis.com/javascript/latest/sample-code/layers-scenelayerview-query-stats/live/ 

 

Below is the HTML code behind this map.

 

 

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <title>SceneLayerView - query statistics by geometry | Sample | ArcGIS Maps SDK for JavaScript 4.28</title>
    <style>
      html,
      body,
      #viewDiv {
        padding: 0;
        margin: 0;
        height: 100%;
        width: 100%;
      }

      .esri-ui-top-right {
        max-height: 100%;
      }

      #queryDiv,
      #resultDiv {
        min-width: 250px;
        font-size: 14px;
        padding: 10px;
        display: none;
        overflow-y: auto;
        overflow-x: hidden;
      }

      .geometry-options {
        display: flex;
        flex-direction: row;
      }
      .geometry-button {
        flex: 1;
        border-style: solid;
        border-width: 1px;
        border-image: none;
      }
      .geometry-button-selected {
        background: #4c4c4c;
        color: #fff;
      }

      #bufferNum {
        width: 90%;
        margin: 2.5em auto 0;
      }

      .count {
        white-space: nowrap;
        font-size: 14px;
        font-weight: bold;
        display: inline-block;
      }
    </style>
    <!-- Load the Chart.js library -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>

    <link rel="stylesheet" href="https://js.arcgis.com/4.28/esri/themes/light/main.css" />
    <script src="https://js.arcgis.com/4.28/"></script>

    <script>
      require([
        "esri/WebScene",
        "esri/views/SceneView",
        "esri/layers/GraphicsLayer",
        "esri/widgets/Sketch/SketchViewModel",
        "esri/widgets/Slider",
        "esri/geometry/geometryEngine",
        "esri/Graphic",
        "esri/core/promiseUtils"
      ], (WebScene, SceneView, GraphicsLayer, SketchViewModel, Slider, geometryEngine, Graphic, promiseUtils) => {
        // Load webscene and display it in a SceneView
        const webscene = new WebScene({
          portalItem: {
            id: "fb5948b2bb76439792786000b942e5b7"
          }
        });
        // create the SceneView
        const view = new SceneView({
          container: "viewDiv",
          map: webscene
        });
        window.view = view;
        // add a GraphicsLayer for the sketches and the buffer
        const sketchLayer = new GraphicsLayer();
        const bufferLayer = new GraphicsLayer();
        view.map.addMany([bufferLayer, sketchLayer]);

        let sceneLayer = null;
        let sceneLayerView = null;
        let bufferSize = 0;

        // Assign scene layer once webscene is loaded and initialize UI
        webscene.load().then(() => {
          sceneLayer = webscene.layers.find((layer) => {
            return layer.title === "Helsinki textured buildings";
          });
          sceneLayer.outFields = ["buildingMaterial", "yearCompleted"];

          view.whenLayerView(sceneLayer).then((layerView) => {
            sceneLayerView = layerView;
            queryDiv.style.display = "block";
          });
        });

        view.ui.add([queryDiv], "bottom-left");
        view.ui.add([resultDiv], "top-right");

        // use SketchViewModel to draw polygons that are used as a query
        let sketchGeometry = null;
        const sketchViewModel = new SketchViewModel({
          layer: sketchLayer,
          defaultUpdateOptions: {
            tool: "reshape",
            toggleToolOnClick: false
          },
          view: view,
          defaultCreateOptions: { hasZ: false }
        });

        sketchViewModel.on("create", (event) => {
          if (event.state === "complete") {
            sketchGeometry = event.graphic.geometry;
            runQuery();
          }
        });

        sketchViewModel.on("update", (event) => {
          if (event.state === "complete") {
            sketchGeometry = event.graphics[0].geometry;
            runQuery();
          }
        });
        // draw geometry buttons - use the selected geometry to sktech
        const pointBtn = document.getElementById("point-geometry-button");
        const lineBtn = document.getElementById("line-geometry-button");
        const polygonBtn = document.getElementById("polygon-geometry-button");
        pointBtn.addEventListener("click", geometryButtonsClickHandler);
        lineBtn.addEventListener("click", geometryButtonsClickHandler);
        polygonBtn.addEventListener("click", geometryButtonsClickHandler);
        function geometryButtonsClickHandler(event) {
          const geometryType = event.target.value;
          clearGeometry();
          sketchViewModel.create(geometryType);
        }

        const bufferNumSlider = new Slider({
          container: "bufferNum",
          min: 0,
          max: 500,
          steps: 1,
          visibleElements: {
            labels: true
          },
          precision: 0,
          labelFormatFunction: (value, type) => {
            return `${value.toString()}m`;
          },
          values: [0]
        });
        // get user entered values for buffer
        bufferNumSlider.on(["thumb-change", "thumb-drag"], bufferVariablesChanged);
        function bufferVariablesChanged(event) {
          bufferSize = event.value;
          runQuery();
        }
        // Clear the geometry and set the default renderer
        const clearGeometryBtn = document.getElementById("clearGeometry");
        clearGeometryBtn.addEventListener("click", clearGeometry);

        // Clear the geometry and set the default renderer
        function clearGeometry() {
          sketchGeometry = null;
          sketchViewModel.cancel();
          sketchLayer.removeAll();
          bufferLayer.removeAll();
          clearHighlighting();
          clearCharts();
          resultDiv.style.display = "none";
        }

        // set the geometry query on the visible SceneLayerView
        const debouncedRunQuery = promiseUtils.debounce(() => {
          if (!sketchGeometry) {
            return;
          }

          resultDiv.style.display = "block";
          updateBufferGraphic(bufferSize);
          return promiseUtils.eachAlways([queryStatistics(), updateSceneLayer()]);
        });

        function runQuery() {
          debouncedRunQuery().catch((error) => {
            if (error.name === "AbortError") {
              return;
            }

            console.error(error);
          });
        }

        // Set the renderer with objectIds
        let highlightHandle = null;
        function clearHighlighting() {
          if (highlightHandle) {
            highlightHandle.remove();
            highlightHandle = null;
          }
        }

        function highlightBuildings(objectIds) {
          // Remove any previous highlighting
          clearHighlighting();
          const objectIdField = sceneLayer.objectIdField;
          document.getElementById("count").innerHTML = objectIds.length;

          highlightHandle = sceneLayerView.highlight(objectIds);
        }

        // update the graphic with buffer
        function updateBufferGraphic(buffer) {
          // add a polygon graphic for the buffer
          if (buffer > 0) {
            const bufferGeometry = geometryEngine.geodesicBuffer(sketchGeometry, buffer, "meters");
            if (bufferLayer.graphics.length === 0) {
              bufferLayer.add(
                new Graphic({
                  geometry: bufferGeometry,
                  symbol: sketchViewModel.polygonSymbol
                })
              );
            } else {
              bufferLayer.graphics.getItemAt(0).geometry = bufferGeometry;
            }
          } else {
            bufferLayer.removeAll();
          }
        }

        function updateSceneLayer() {
          const query = sceneLayerView.createQuery();
          query.geometry = sketchGeometry;
          query.distance = bufferSize;
          return sceneLayerView.queryObjectIds(query).then(highlightBuildings);
        }

        let yearChart = null;
        let materialChart = null;

        function queryStatistics() {
          const statDefinitions = [
            {
              onStatisticField: "CASE WHEN buildingMaterial = 'concrete or lightweight concrete' THEN 1 ELSE 0 END",
              outStatisticFieldName: "material_concrete",
              statisticType: "sum"
            },
            {
              onStatisticField: "CASE WHEN buildingMaterial = 'brick' THEN 1 ELSE 0 END",
              outStatisticFieldName: "material_brick",
              statisticType: "sum"
            },
            {
              onStatisticField: "CASE WHEN buildingMaterial = 'wood' THEN 1 ELSE 0 END",
              outStatisticFieldName: "material_wood",
              statisticType: "sum"
            },
            {
              onStatisticField: "CASE WHEN buildingMaterial = 'steel' THEN 1 ELSE 0 END",
              outStatisticFieldName: "material_steel",
              statisticType: "sum"
            },
            {
              onStatisticField:
                "CASE WHEN buildingMaterial IN ('concrete or lightweight concrete', 'brick', 'wood', 'steel') THEN 0 ELSE 1 END",
              outStatisticFieldName: "material_other",
              statisticType: "sum"
            },
            {
              onStatisticField: "CASE WHEN (yearCompleted >= '1850' AND yearCompleted <= '1899') THEN 1 ELSE 0 END",
              outStatisticFieldName: "year_1850",
              statisticType: "sum"
            },
            {
              onStatisticField: "CASE WHEN (yearCompleted >= '1900' AND yearCompleted <= '1924') THEN 1 ELSE 0 END",
              outStatisticFieldName: "year_1900",
              statisticType: "sum"
            },
            {
              onStatisticField: "CASE WHEN (yearCompleted >= '1925' AND yearCompleted <= '1949') THEN 1 ELSE 0 END",
              outStatisticFieldName: "year_1925",
              statisticType: "sum"
            },
            {
              onStatisticField: "CASE WHEN (yearCompleted >= '1950' AND yearCompleted <= '1974') THEN 1 ELSE 0 END",
              outStatisticFieldName: "year_1950",
              statisticType: "sum"
            },
            {
              onStatisticField: "CASE WHEN (yearCompleted >= '1975' AND yearCompleted <= '1999') THEN 1 ELSE 0 END",
              outStatisticFieldName: "year_1975",
              statisticType: "sum"
            },
            {
              onStatisticField: "CASE WHEN (yearCompleted >= '2000' AND yearCompleted <= '2015') THEN 1 ELSE 0 END",
              outStatisticFieldName: "year_2000",
              statisticType: "sum"
            }
          ];
          const query = sceneLayerView.createQuery();
          query.geometry = sketchGeometry;
          query.distance = bufferSize;
          query.outStatistics = statDefinitions;

          return sceneLayerView.queryFeatures(query).then((result) => {
            const allStats = result.features[0].attributes;
            updateChart(materialChart, [
              allStats.material_concrete,
              allStats.material_brick,
              allStats.material_wood,
              allStats.material_steel,
              allStats.material_other
            ]);
            updateChart(yearChart, [
              allStats.year_1850,
              allStats.year_1900,
              allStats.year_1925,
              allStats.year_1950,
              allStats.year_1975,
              allStats.year_2000
            ]);
          }, console.error);
        }

        // Updates the given chart with new data
        function updateChart(chart, dataValues) {
          chart.data.datasets[0].data = dataValues;
          chart.update();
        }

        function createYearChart() {
          const yearCanvas = document.getElementById("year-chart");
          yearChart = new Chart(yearCanvas.getContext("2d"), {
            type: "horizontalBar",
            data: {
              labels: ["1850-1899", "1900-1924", "1925-1949", "1950-1974", "1975-1999", "2000-2015"],
              datasets: [
                {
                  label: "Build year",
                  backgroundColor: "#149dcf",
                  stack: "Stack 0",
                  data: [0, 0, 0, 0, 0, 0]
                }
              ]
            },
            options: {
              responsive: false,
              legend: {
                display: false
              },
              title: {
                display: true,
                text: "Build year"
              },
              scales: {
                xAxes: [
                  {
                    stacked: true,
                    ticks: {
                      beginAtZero: true,
                      precision: 0
                    }
                  }
                ],
                yAxes: [
                  {
                    stacked: true
                  }
                ]
              }
            }
          });
        }
        function createMaterialChart() {
          const materialCanvas = document.getElementById("material-chart");
          materialChart = new Chart(materialCanvas.getContext("2d"), {
            type: "doughnut",
            data: {
              labels: ["Concrete", "Brick", "Wood", "Steel", "Other"],
              datasets: [
                {
                  backgroundColor: ["#FD7F6F", "#7EB0D5", "#B2E061", "#BD7EBE", "#FFB55A"],
                  borderWidth: 0,
                  data: [0, 0, 0, 0, 0]
                }
              ]
            },
            options: {
              responsive: false,
              cutoutPercentage: 35,
              legend: {
                position: "bottom"
              },
              title: {
                display: true,
                text: "Building Material"
              }
            }
          });
        }

        function clearCharts() {
          updateChart(materialChart, [0, 0, 0, 0, 0]);
          updateChart(yearChart, [0, 0, 0, 0, 0, 0]);
          document.getElementById("count").innerHTML = 0;
        }

        createYearChart();
        createMaterialChart();
      });
    </script>
  </head>

  <body>
    <div id="viewDiv"></div>
    <div id="queryDiv" class="esri-widget">
      <b>Query by geometry</b><br />
      <br />Draw a geometry to query by:
      <div class="geometry-options">
        <button
          class="esri-widget--button esri-icon-map-pin geometry-button"
          id="point-geometry-button"
          value="point"
          title="Query by point"
        ></button>
        <button
          class="esri-widget--button esri-icon-polyline geometry-button"
          id="line-geometry-button"
          value="polyline"
          title="Query by line"
        ></button>
        <button
          class="esri-widget--button esri-icon-polygon geometry-button"
          id="polygon-geometry-button"
          value="polygon"
          title="Query by polygon"
        ></button>
      </div>
      <br />
      <div class="tooltip">
        <label for="bufferNum">Set a geometry buffer size:</label>
        <div id="bufferNum"></div>
      </div>
      <br />
      <button class="esri-button" id="clearGeometry" type="button">Clear</button>
    </div>

    <div id="resultDiv" class="esri-widget">
      <div class="count">
        Selected Buildings:
        <div class="count" id="count">0</div>
      </div>
      <div class="charts">
        <div>
          <canvas id="year-chart" height="250" width="260" />
        </div>
        <div>
          <canvas id="material-chart" width="250" height="300" />
        </div>
      </div>
    </div>
  </body>
</html>

 

 

Is there anyway i can use this HTML code directly and display an interactive MAP in power bi instead of hosting it in github & use Iframe. Is there any visual other than "HTML content" can be used to display rich HTML (with Java script, CSS) ?

 

Any help much appreciated. 

 

 

2 REPLIES 2
BmBIDev
Regular Visitor

I tried Most of HTML visual apps in the Appstore. None of them seems to be supporting this.  

Anonymous
Not applicable

Hi @BmBIDev ,

 

Usually it's all about customizing visual objects in powerbi. If you use HTML you may not be able to fully apply your needs. You can try Business Apps – Microsoft AppSource

 

Hope it helps!

 

Best regards,
Community Support Team_ Scott Chang

 

If this post helps then please consider Accept it as the solution to help the other members find it more quickly.

Helpful resources

Announcements
August Power BI Update Carousel

Power BI Monthly Update - August 2025

Check out the August 2025 Power BI update to learn about new features.

August 2025 community update carousel

Fabric Community Update - August 2025

Find out what's new and trending in the Fabric community.

Top Solution Authors