Search code examples
javascriptcssamchartsamcharts4

Add HTML Element On Top Of Amchart Instance


I can't find this in the documentation, but is it possible to add a custom div element on top of an Amchart Instance?

Such that:

    <div class="container-fluid px-0 mx-0">
        <div id="chartdiv"></div>
        <ul>
            <li>Thailand</li>
            <li>Myanmar</li>
            <li>Etc...</li>
        </ul>
    </div>

With the UL displaying at the bottom of the instance?

JS:

    <script src="https://www.amcharts.com/lib/4/core.js"></script>
    <script src="https://www.amcharts.com/lib/4/maps.js"></script>
    <script src="https://www.amcharts.com/lib/4/geodata/worldUltra.js"></script>
    <script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
    <script>

       am4core.useTheme(am4themes_animated);

       var container = am4core.create("chartdiv", am4core.Container);
       container.width = am4core.percent(100);
       container.height = am4core.percent(100);
       container.layout = "vertical";

       // Create map instance
       var chart = container.createChild(am4maps.MapChart);

       // Set map definition
       chart.geodata = am4geodata_worldUltra;

       // Set projection
       chart.projection = new am4maps.projections.Miller();

       // Create map polygon series
       var polygonSeries = chart.series.push(new am4maps.MapPolygonSeries());

       // Exclude Antartica
       polygonSeries.exclude = ["AQ"];

       // Make map load polygon (like country names) data from GeoJSON
       polygonSeries.useGeodata = true;

       // Configure series
       var polygonTemplate = polygonSeries.mapPolygons.template;
       polygonTemplate.tooltipText = "{name}";
       polygonTemplate.fill = am4core.color("#dcdcdc");

       // Create hover state and set alternative fill color
       var hs = polygonTemplate.states.create("hover");
       hs.properties.fill = am4core.color("#a98239");

       chart.events.on("ready", function(ev) {
         chart.zoomToMapObject(polygonSeries.getPolygonById("TH"));
       });

       chart.zoomControl = new am4maps.ZoomControl();
       chart.chartContainer.wheelable = false;



    </script>

If I missed something in the docs, I apologize - hoping someone can point me in the right direction!


Solution

  • AmCharts is SVG based so everything in the chartdiv is controlled by the library and mostly contains SVG with a little bit of HTML, without any native options to include custom div objects. One potential workaround is to use a Label object and set its html property to include your HTML code. Note that this uses <foreignObject> to accomplish this, so you may need to be mindful of browser support (IE11, if that still matters).

    Here's an example that creates a list on top of the chart

    var label = chart.chartContainer.createChild(am4core.Label);
    //label.isMeasured = false; //uncomment to make the label not adjust the rest of the chart elements to accommodate its placement
    label.fontSize = 16;
    label.x = am4core.percent(5);
    label.horizontalCenter = "middle";
    label.verticalCenter = "bottom";
    label.html = "<ul><li>List item 1</li><li>List item 2</li></ul>";
    label.toBack(); //move list to top of the chart area. See: https://www.amcharts.com/docs/v4/concepts/svg-engine/containers/#Ordering_elements
    

    Demo:

    // Create chart instance
    var chart = am4core.create("chartdiv", am4charts.XYChart);
    
    // Add data
    chart.data = [{
      "category": "Research",
      "value": 450
    }, {
      "category": "Marketing",
      "value": 1200
    }, {
      "category": "Distribution",
      "value": 1850
    }];
    
    // Create axes
    var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
    categoryAxis.dataFields.category = "category";
    categoryAxis.renderer.grid.template.location = 0;
    //categoryAxis.renderer.minGridDistance = 30;
    
    var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
    
    // Create series
    var series = chart.series.push(new am4charts.ColumnSeries());
    series.dataFields.valueY = "value";
    series.dataFields.categoryX = "category";
    
    var label = chart.chartContainer.createChild(am4core.Label);
    //label.isMeasured = false; //uncomment to make the label not adjust the rest of the chart elements to accommodate its placement
    label.fontSize = 16;
    label.x = am4core.percent(5);
    label.horizontalCenter = "middle";
    label.verticalCenter = "bottom";
    label.html = "<ul><li>List item 1</li><li>List item 2</li></ul>";
    label.toBack(); //move list to top of the chart area. See: https://www.amcharts.com/docs/v4/concepts/svg-engine/containers/#Ordering_elements
    html, body { width: 100%; height: 100%; margin: 0;}
    #chartdiv { width: 100%; height: 100%;}
    <script src="//www.amcharts.com/lib/4/core.js"></script>
    <script src="//www.amcharts.com/lib/4/charts.js"></script>
    <div id="chartdiv"></div>