Amir Doosti
Amir Doosti

Reputation: 56

ApexCharts type line - background color

i have a simple js, html file, im using ApexCharts and want to handle the positive and negative parts of chart.

3 things about it:

  1. markers style (handled already)
  2. line color (handled already)
  3. the background gradient below the line (problem)

is there any way to add a background to the line type chart below the line?

desired chart : desired chart

  <div id="chart"></div>
  <script src="exp.js"></script>
const dataPoints = [-10, 3, -5, -18, -10, 12, 8]

const discreteMarkers = dataPoints.map((value, index) => {
  return {
    shape: "circle",
    size: 4,
    seriesIndex: 0,
    dataPointIndex: index,
    fillColor: "#ffffff",
    strokeColor: value >= 0 ? "#157446" : "#C13446",
    strokeWidth: 1,
  };
});

var options = {
  chart: {
    height: 380,
    type: "line",
    foreColor: '#aaa',
    zoom: {
      type: 'x',
      enabled: true,
      autoScaleYaxis: true
    },
  },
  series: [
    {
      name: "Series 1",
      data: dataPoints
    }
  ],
  stroke: {
    width: 5,
    curve: "monotoneCubic"
  },
  plotOptions: {
    line: {
      colors: {
        threshold: 0,
        colorAboveThreshold: '#157446',
        colorBelowThreshold: '#C13446',
      },
    },
  },
  markers: {
    discrete: discreteMarkers
  },
  grid: {
     borderColor: '#6D6D6D',
     strokeDashArray: 3,
  },
  xaxis: {
    categories: [
      "01 Jan",
      "02 Jan",
      "03 Jan",
      "04 Jan",
      "05 Jan",
      "06 Jan",
      "07 Jan"
    ]
  },
  stroke: {
      curve: 'smooth',
      width: 2
  },
};

var chart = new ApexCharts(document.querySelector("#chart"), options);

chart.render();

here is a link to check output. https://codepen.io/amirdoosti/pen/RNbQWPK

Upvotes: 0

Views: 60

Answers (3)

Amir Doosti
Amir Doosti

Reputation: 56

i figured it out. the plotOption has a property for area charts named fillTo :

fillTo = When negative values are present in the area chart, this option fill the area either from 0 (origin) or from the end of the chart as illustrated below.

area: {
  fillTo: "end",
},

also i handled the colors using fill property to show positive and negative values.

andd... for better controlling data i made a function to set 0 label always in center of the chart. ( minY , minX ).


i didnt check all versions of apexcharts but i was supposed to use my script in a nuxt2 app. so the compatible version with my nuxt app was 3.40. so i can tell this script can work from 3.40 version and higher

const dataPoints = [-80, 3, -5, 100, -40, 120, 8];
let lowest_point = Math.min(...dataPoints);
let highest_point = Math.max(...dataPoints);

let zero_stop_percent = 100 - (Math.abs(lowest_point) / (Math.abs(lowest_point) + highest_point)) * 100;
const isNegativeHigher = Math.abs(lowest_point) > Math.abs(highest_point);

const minY =
  Math.min(...dataPoints) === 0 && Math.max(...dataPoints) === 0
    ? -500
    : Math.min(...dataPoints) === 0 && Math.max(...dataPoints) > 0
    ? Math.max(...dataPoints) * -1
    : Math.abs(Math.min(...dataPoints)) < Math.max(...dataPoints)
    ? Math.max(...dataPoints) * -1
    : Math.min(...dataPoints);

const maxY =
  Math.max(...dataPoints) === 0 && Math.min(...dataPoints) === 0
    ? 500
    : Math.max(...dataPoints) === 0 && Math.min(...dataPoints) < 0
    ? Math.abs(Math.min(...dataPoints))
    : Math.abs(Math.min(...dataPoints)) > Math.max(...dataPoints)
    ? Math.abs(Math.min(...dataPoints))
    : Math.max(...dataPoints);

const discreteMarkers = dataPoints.map((value, index) => {
  return {
    shape: "circle",
    size: 4,
    seriesIndex: 1,
    dataPointIndex: index,
    fillColor: "#ffffff",
    strokeColor: value >= 0 ? "#157446" : "#C13446",
    strokeWidth: 1,
  };
});
var options = {
  // okayyy
  chart: {
    height: 250,
    width: 380,
    toolbar: {
      show: false,
    },
  },
  // okayyy
  series: [
    {
      name: "TEAMA",
      type: "area",
      data: dataPoints, // Your area chart data
      zIndex: 2,
    },
    {
      name: "TEAMB",
      type: "line",
      data: dataPoints, // Your area chart data
      zIndex: 1,
    },
  ],
  markers: {
    discrete: discreteMarkers,
  },
  fill: {
    type: "gradient",
    gradient: {
      shade: "light",
      type: "vertical",
      shadeIntensity: 0.5,
      opacityFrom: 0.2,
      opacityTo: 0.2,
      colorStops: [
        // area
        [
          {
            offset: 0,
            color: "#589F7E", // Green for positive values
            opacity: 0.15,
          },
          {
            offset: isNegativeHigher ? zero_stop_percent : 50,
            color: "#589F7E", // Transition at zero
            opacity: 0.15,
          },
          {
            offset: isNegativeHigher ? zero_stop_percent : 50,
            color: "#D98B95", // Red for negative values
            opacity: 0.15,
          },
          {
            offset: 100,
            color: "#FBF5F5",
            opacity: 0.1,
          },
        ],
        // line
        [
          {
            offset: 0,
            color: "#157446", // Green for positive values
            opacity: 1,
          },
          {
            offset: zero_stop_percent,
            color: "#157446", // Transition at zero
            opacity: 1,
          },
          {
            offset: zero_stop_percent,
            color: "#C13446", // Red for negative values
            opacity: 1,
          },
          {
            offset: 100,
            color: "#C13446",
            opacity: 1,
          },
        ],
      ],
    },
  },
  xaxis: {
    categories: ["12/20", "12/21", "12/22", "12/23", "12/24", "12/25", "12/26"],
    tooltip: {
      enabled: false,
    },
  },
  legend: {
    show: false,
  },
  tooltip: {
    enabled: true, // Disable tooltip entirely if unwanted
    shared: false, // Ensure no shared tooltip for markers
    x: {
      show: false,
    },
    y: {
      formatter(val) {
        return val;
      },
      title: {
        formatter(seriesName) {
          return "";
        },
      },
    },
    style: {
      fontSize: "12px",
      fontFamily: "iransansx",
      width: "fit-content",
    },
  },
  yaxis: {
    forceNiceScale: true,
    min: minY,
    max: maxY,
    tickAmount: 4,
    labels: {
      offsetX: -25,
      style: {
        colors: "#5B5C5F",
      },
      minWidth: 36,
      show: true,
    },
  },
  // okayyy
  stroke: {
    width: 2,
    curve: "smooth",
    colors: ["transparent"],
  },

  // okayyy
  plotOptions: {
    area: {
      fillTo: "end",
    },
  },
  grid: {
    borderColor: "#EAEAEB",
    strokeDashArray: 4,
    position: "back",
  },
};

var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
.apexcharts-datalabel,
      .apexcharts-datalabel-label,
      .apexcharts-datalabel-value,
      .apexcharts-datalabels,
      .apexcharts-pie-label {
        display: none !important;
      }
      .apexcharts-tooltip-series-group.apexcharts-active,
      .apexcharts-tooltip-series-group:last-child {
        padding-bottom: 0 !important;
      }
      .apexcharts-tooltip-series-group {
        padding: 0 8px !important;
      }
      .apexcharts-tooltip-series-group.apexcharts-active .apexcharts-tooltip-marker {
        display: none !important;
      }
      .apexcharts-tooltip-text-goals-value,
      .apexcharts-tooltip-text-y-value,
      .apexcharts-tooltip-text-z-value {
        margin-left: unset !important;
      }
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>bb</title>
  </head>
  <body>
    <div id="chart"></div>

    <script src="
    https://cdn.jsdelivr.net/npm/[email protected]/dist/apexcharts.min.js
    "></script>
    <link
      href="
    https://cdn.jsdelivr.net/npm/[email protected]/dist/apexcharts.min.css
    "
      rel="stylesheet"
    />
  </body>
</html>

Upvotes: 2

josip
josip

Reputation: 308

What you are trying to achieve is an "area" chart type, not "line" chart.

Try changing your script to this:

const dataPoints = [-10, 3, -5, -18, -10, 12, 8]

const discreteMarkers = dataPoints.map((value, index) => {
  return {
    shape: "circle",
    size: 4,
    seriesIndex: 0,
    dataPointIndex: index,
    fillColor: "#ffffff",
    strokeWidth: 1,
  };
});

var options = {
  chart: {
    height: 380,
    type: "area",
    foreColor: '#aaa',
    zoom: {
      type: 'x',
      enabled: true,
      autoScaleYaxis: true
    },
  },
  series: [
    {
      name: "Series 1",
      data: dataPoints
    }
  ],
  stroke: {
    width: 5,
    curve: "monotoneCubic"
  },
  plotOptions: {
    line: {
      colors: {
        threshold: 0,
        colorAboveThreshold: '#157446',
        colorBelowThreshold: '#C13446',
      },
    },
  },
  markers: {
    discrete: discreteMarkers
  },
  grid: {
     borderColor: '#6D6D6D',
     strokeDashArray: 3,
  },
  xaxis: {
    categories: [
      "01 Jan",
      "02 Jan",
      "03 Jan",
      "04 Jan",
      "05 Jan",
      "06 Jan",
      "07 Jan"
    ]
  },
  dataLabels: {
    enabled: false
  },
  
  stroke: {
      curve: 'smooth',
      width: 2
  },
  fill: {
    type: "solid",
    colors: ["#E6F4EA" ]
  },
};

var chart = new ApexCharts(document.querySelector("#chart"), options);

chart.render();

That would render this:

Apex Area Chart with fill

Upvotes: 1

Dallas
Dallas

Reputation: 91

You can use the fill property to handle that! I try that solution in your codepen and this is the result (to achieve it I remove plotOptions)

enter image description here

fill: {
    type: "gradient",
    gradient: {
      shade: "light",
      type: "vertical",
      gradientToColors: ["#157446", "#C13446"], // Green for positive, red for negative
      shadeIntensity: 0.5,
      opacityFrom: 0.5,
      opacityTo: 0.1,
      stops: [0, 50, 100],
      colorStops: [
        {
          offset: 0,
          color: "#C13446", // Start with red
          opacity: 0.5,
        },
        {
          offset: 50,
          color: "#ffffff", // Middle white transition
          opacity: 0.2,
        },
        {
          offset: 100,
          color: "#157446", // End with green
          opacity: 0.5,
        },
      ],
    },
  },

Upvotes: 0

Related Questions