Search code examples
javascripthighchartslabelheatmapyaxis

Highcharts Heatmap yAxis labels not rendering properly


HeatMap yAxis categories going inside the last cell instead of the left side outside. It is working fine on the code rendition but as you can see in the image, the yAxis is going inside the final cell.

My code for vue:

package.json

{
  "name": "my-dashboard",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "^6.5.2",
    "@fortawesome/free-brands-svg-icons": "^6.5.2",
    "@fortawesome/free-solid-svg-icons": "^6.5.2",
    "@fortawesome/vue-fontawesome": "^3.0.6",
    "@highcharts/map-collection": "^2.1.0",
    "@popperjs/core": "^2.11.8",
    "ag-grid-vue3": "^31.3.1",
    "axios": "^1.6.8",
    "bootstrap": "^5.3.3",
    "core-js": "^3.8.3",
    "country-list": "^2.3.0",
    "crypto-browserify": "^3.12.0",
    "dotenv": "^16.4.5",
    "highcharts": "^11.4.6",
    "highcharts-vue": "^2.0.1",
    "os-browserify": "^0.3.0",
    "path": "^0.12.7",
    "path-browserify": "^1.0.1",
    "require": "^2.4.20",
    "stream-browserify": "^3.0.0",
    "vm-browserify": "^1.1.2",
    "vue": "^3.4.33",
    "vue-axios": "^3.5.2",
    "vue-jalali-moment": "^1.0.0",
    "vue-multiselect": "^3.0.0-beta.3",
    "vue-router": "^4.3.2",
    "vue3-daterange-picker": "^1.0.1"
  },
  "devDependencies": {
    "@babel/core": "^7.12.16",
    "@babel/eslint-parser": "^7.12.16",
    "@types/bootstrap": "^5.2.10",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "sass": "^1.75.0",
    "sass-loader": "^14.2.1",
    "style-loader": "^4.0.0"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "browser": true,
      "es2021": true
    },
    "extends": [
      "plugin:vue/vue3-essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "@babel/eslint-parser",
      "ecmaVersion": 2021,
      "requireConfigFile": false
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead",
    "not ie 11"
  ]
}

main.js

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import Highcharts from "highcharts";
import Stock from "highcharts/modules/stock";
import Drilldown from "highcharts/modules/drilldown";
import HighchartsAccessibility from "highcharts/modules/accessibility";
import HighchartsExporting from "highcharts/modules/exporting";
import HighchartsExportData from "highcharts/modules/export-data";
import MapModule from "highcharts/modules/map";
import HighchartsHeatMap from "highcharts/modules/heatmap";
import HighchartsMore from "highcharts/highcharts-more";
import HighchartsVue from "highcharts-vue";
import mapDataWorld from "@highcharts/map-collection/custom/world.geo.json";
import "bootstrap/dist/css/bootstrap.min.css";

import axios from "axios";
import VueAxios from "vue-axios";
import moment from "moment";
import DateRangePicker from "vue3-daterange-picker";
import { getCode } from "country-list";

import { library } from "@fortawesome/fontawesome-svg-core";
import {
  faGlobe,
  faFlag,
  faPodcast,
  faCalendar,
  faFileCsv,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import {
  faFacebook,
  faSquareXTwitter,
  faYoutube,
  faInstagram,
  faTelegram,
} from "@fortawesome/free-brands-svg-icons";

// Add icons to the library
library.add(
  faGlobe,
  faFlag,
  faFacebook,
  faSquareXTwitter,
  faYoutube,
  faInstagram,
  faTelegram,
  faPodcast,
  faCalendar,
  faFileCsv
);

// Create the Vue app instance
const app = createApp(App);

// Use Axios for HTTP requests
app.use(VueAxios, axios);
app.config.globalProperties.axios = axios;

// Use moment.js as a global property
app.config.globalProperties.$moment = moment;

// Make getCode from country-list available globally
app.config.globalProperties.$getCode = getCode;

// Enable Highcharts and its modules
Stock(Highcharts);
Drilldown(Highcharts);
HighchartsMore(Highcharts);
HighchartsHeatMap(Highcharts);
HighchartsExporting(Highcharts);
HighchartsExportData(Highcharts);
HighchartsAccessibility(Highcharts);
MapModule(Highcharts);
Highcharts.maps["myMapName"] = mapDataWorld;
app.use(HighchartsVue);

// Register the DateRangePicker component
app.component("DateRangePicker", DateRangePicker);

// Register the FontAwesomeIcon component
app.component("font-awesome-icon", FontAwesomeIcon);

// Use the router
app.use(router);

// Mount the app to the DOM
app.mount("#app");

componenets/MainHeatMap.vue

<template>
  <div>
    <highcharts
      :constructor-type="'stockChart'"
      class="hc"
      :options="chartOptions"
      ref="chart"
    ></highcharts>
  </div>
</template>

<script>
export default {
  data() {
    return {
      chartOptions: {
        chart: {
          backgroundColor: "#fbfcf8",
          type: "heatmap",
          plotBorderWidth: 1,
          height: "100%",
          margin: [0, 0, 0, 0],
        },
        title: { text: "Views", align: "center" },
        exporting: {
          enabled: true,
        },
        credits: { enabled: false },
        legend: { enabled: true, itemStyle: { color: "#000" } },
        rangeSelector: { enabled: false },
        navigator: { enabled: false },
        scrollbar: { enabled: false },
        xAxis: {
          categories: [
            "America",
            "South & Central Asia",
            "News Network",
            "Eurasia",
            "East Asia",
            "Africa",
            "English",
          ],
        },
        yAxis: {
          categories: [
            "Jun 16, 2024",
            "Jun 23, 2024",
            "Jun 30, 2024",
            "Jul 7, 2024",
            "Jul 14, 2024",
          ],
          reversed: false,
        },
        accessibility: {
          point: {
            descriptionFormat:
              "{(add index 1)}. {series.xAxis.categories.(x)} {series.yAxis.categories.(y)}, {value}.",
          },
        },
        colorAxis: { min: 0, minColor: "#FFFFFF", maxColor: "#DA70D6" },
        tooltip: { style: { color: "#000" } },
        series: [
          {
            name: "Video Views",
            borderWidth: 1,
            data: [
              [0, 0, 75059],
              [0, 1, 493747],
              [0, 2, 449083],
              [0, 3, 490321],
              [0, 4, 429733],
              [1, 0, 103570],
              [1, 1, 340369],
              [1, 2, 383821],
              [1, 3, 452833],
              [1, 4, 511894],
              [2, 0, 1361371],
              [2, 1, 4394413],
              [2, 2, 4518221],
              [2, 3, 4581342],
              [2, 4, 4623790],
              [3, 0, 231918],
              [3, 1, 976761],
              [3, 2, 791173],
              [3, 3, 1010918],
              [3, 4, 1065976],
              [4, 0, 2186104],
              [4, 1, 7183474],
              [4, 2, 7521511],
              [4, 3, 7750003],
              [4, 4, 7846560],
              [5, 0, 225868],
              [5, 1, 857518],
              [5, 2, 897654],
              [5, 3, 908779],
              [5, 4, 933288],
              [6, 0, 284781],
              [6, 1, 2015884],
              [6, 2, 1168136],
              [6, 3, 1088461],
              [6, 4, 1403736],
            ],
            dataLabels: { enabled: true, color: "#000000" },
          },
        ],
        responsive: {
          rules: [
            {
              condition: { maxWidth: 500 },
              chartOptions: {
                yAxis: { labels: { format: "{substr value 0 1}" } },
              },
            },
          ],
        },
      },
      fullData: [],
    };
  },
  watch: {
    chartData: {
      handler(newChartData, oldChartData) {
        if (newChartData !== oldChartData) {
          this.updateChartData(newChartData);
        }
      },
      deep: true,
    },
  },
};
</script>

componenets/Web/HeatMap.vue

<template>
  <SharedHeatMap :chartData="chartData" />
</template>

<script>
import SharedHeatMap from "@/components/MainHeatMap.vue";

export default {
  components: {
    SharedHeatMap,
  },
  props: {
    chartData: {
      type: Array,
      default: () => [],
    },
  },
};
</script>

<style scoped>
/* Add your component-specific styles here */
</style>

componenets/MainTab.vue

<template>
  <div id="webs" class="m-2 d-inline-flex">
    <div style="width: 100%" class="d-flex flex-column">
      <HeatMap id="heatMap" style="width: 100%" />
    </div>
  </div>
</template>

<script>
import "bootstrap/dist/css/bootstrap.min.css";
import HeatMap from "./WebTab/HeatMap.vue";

export default {
  components: { HeatMap },
};
</script>

<style>
/* Add your component-specific styles here */
</style>

But in my image:

my Heatmap

What is going on?


Solution

  • The problem was that in the chart config you use the stockChart constructor, which has different settings for the y-axis position. Additionally, you removed the margins, so elements such as the title, legend or axis labels will not be visible. The easiest way is to change the constructor to chart (line 4 in componenets/MainHeatMap.vue) and adjust the margin (line 22).

    Demo: https://codesandbox.io/p/sandbox/flamboyant-ganguly-dsdrjy
    API: https://github.com/highcharts/highcharts-vue?tab=readme-ov-file#implementing-stockchart-mapchart-and-ganttchart