This demo uses imperative chart updates. The generated code is a faithful Angular translation: open it in CodeSandbox to run and tweak.

import { Component, AfterViewInit, OnDestroy, ViewChild } from '@angular/core';
import {
  ChartComponent,
  ApexAxisChartSeries,
  ApexNonAxisChartSeries,
  ApexChart,
  ApexXAxis,
  ApexYAxis,
  ApexTitleSubtitle,
  ApexDataLabels,
  ApexStroke,
  ApexFill,
  ApexLegend,
  ApexTooltip,
  ApexMarkers,
  ApexPlotOptions,
  ApexResponsive,
  ApexGrid,
  ApexAnnotations,
  ApexStates,
  ApexTheme,
  NgApexchartsModule,
} from 'ng-apexcharts';

export type ChartOptions = {
  series?: ApexAxisChartSeries | ApexNonAxisChartSeries;
  chart?: ApexChart;
  xaxis?: ApexXAxis;
  yaxis?: ApexYAxis | ApexYAxis[];
  title?: ApexTitleSubtitle;
  subtitle?: ApexTitleSubtitle;
  dataLabels?: ApexDataLabels;
  stroke?: ApexStroke;
  fill?: ApexFill;
  legend?: ApexLegend;
  tooltip?: ApexTooltip;
  markers?: ApexMarkers;
  plotOptions?: ApexPlotOptions;
  responsive?: ApexResponsive[];
  grid?: ApexGrid;
  annotations?: ApexAnnotations;
  states?: ApexStates;
  theme?: ApexTheme;
  colors?: string[];
  labels?: any;
};

@Component({
  selector: 'app-chart',
  standalone: true,
  imports: [NgApexchartsModule],
  templateUrl: './chart.component.html',
})
export class AppChart implements AfterViewInit, OnDestroy {
  @ViewChild('chart') chart!: ChartComponent;
  private pointCount: any = 50000;

  private gauss = (mean: any, sd: any): any => {
          var u = 1 - Math.random()
          var v = Math.random()
          return mean + sd * Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v)
        };

  private generateClusters = (count: any): any => {
          var half = Math.floor(count / 2)
          var a = new Array(half)
          var b = new Array(count - half)
          for (var i = 0; i < a.length; i++) {
            a[i] = [+this.gauss(32, 9).toFixed(2), +this.gauss(62, 15).toFixed(2)]
          }
          for (var j = 0; j < b.length; j++) {
            b[j] = [+this.gauss(70, 10).toFixed(2), +this.gauss(34, 13).toFixed(2)]
          }
          return [a, b]
        };

  private clusters: any = this.generateClusters(this.pointCount);

  private lastRenderMs: any = 0;

  private domNodeCount = (): any => {
          var el = document.querySelector('#chart')
          return el ? el.getElementsByTagName('*').length : 0
        };

  private updateStats = (chart: any): any => {
          var el = document.getElementById('stats')
          if (!el || !chart) return
          var active = chart.getActiveRenderer ? chart.getActiveRenderer() : 'svg'
          el.innerHTML =
            'Points: <b>' +
            this.pointCount.toLocaleString() +
            '</b> &nbsp;·&nbsp; Active renderer: <b>' +
            active.toUpperCase() +
            '</b> &nbsp;·&nbsp; DOM nodes in chart: <b>' +
            this.domNodeCount().toLocaleString() +
            '</b> &nbsp;·&nbsp; Render: <b>' +
            (this.lastRenderMs > 0 ? this.lastRenderMs + ' ms' : 'change a control to time it') +
            '</b>'
        };

  private rebuild = (): any => {
          this.pointCount = parseInt(document.getElementById('pointCount').value, 10)
          var mode = document.getElementById('rendererMode').value
  
          this.clusters = this.generateClusters(this.pointCount)
          this.chartOptions.chart.renderer = mode
          this.chartOptions.series = [
            { name: 'Cluster A', data: this.clusters[0] },
            { name: 'Cluster B', data: this.clusters[1] },
          ]
          this.chartOptions.title.text =
            'Scatter: ' +
            this.pointCount.toLocaleString() +
            ' points on the ' +
            (mode === 'auto' ? 'auto-selected' : mode) +
            ' renderer'
  
          var t = performance.now()
          this.chart.destroy()
          this.chart = new ApexCharts(document.querySelector('#chart'), this.chartOptions)
          this.chart.render().then(function () {
            this.lastRenderMs = Math.round(performance.now() - t)
            this.updateStats(this.chart)
          })
        };

  public chartOptions: Partial<ChartOptions> = {
          series: [
            { name: 'Cluster A', data: this.clusters[0] },
            { name: 'Cluster B', data: this.clusters[1] },
          ],
          chart: {
            height: 480,
            type: 'scatter',
            renderer: 'auto',
            rendererThreshold: 8000,
            animations: { enabled: false },
            zoom: { enabled: true, type: 'xy' },
            toolbar: { autoSelected: 'zoom' },
          },
          markers: { size: 3, strokeWidth: 0 },
          colors: ['#008FFB', '#FF4560'],
          title: {
            text: 'Scatter: 50,000 points on the auto-selected renderer',
            align: 'left',
          },
          subtitle: {
            text: 'Dense series marks paint to a canvas layer; axes, grid, zoom and tooltip stay SVG',
            align: 'left',
          },
          xaxis: {
            type: 'numeric',
            tickAmount: 10,
            labels: {
              formatter: (val) => {
                return parseFloat(val).toFixed(0)
              },
            },
          },
          yaxis: {
            tickAmount: 8,
            labels: {
              formatter: (val) => {
                return val.toFixed(0)
              },
            },
          },
          legend: { position: 'top' },
          tooltip: { shared: true, intersect: false },
        };
  ngAfterViewInit() {
    (window as any).ApexCharts.setLicense('APEX-eyJpc3N1ZURhdGUiOiIyMDI2LTA0LTE2IiwiZXhwaXJ5RGF0ZSI6IjIwNTItMDQtMTciLCJwbGFuIjoiZW50ZXJwcmlzZSIsImRvbWFpbnMiOlsiYXBleGNoYXJ0cy5jb20iLCIxMjcuMC4wLjEiXX0=');

    requestAnimationFrame(() => {
            if (this.chart && this.chart.chart?.w && this.chart.chart?.w.globals && this.chart.chart?.w.globals.series) {
              this.updateStats(this.chart)
            } else {
              requestAnimationFrame(poll)
            }
          })
    document.getElementById('rerender').addEventListener('click', this.rebuild)
    document.getElementById('rendererMode').addEventListener('change', this.rebuild)
    document.getElementById('pointCount').addEventListener('change', this.rebuild)
    document.getElementById('resetZoom').addEventListener('click', () => {
            if (this.chart) this.chart.resetSeries(true, true)
          })
  }

  ngOnDestroy() {
    // no cleanup needed
  }
}
Canvas Renderer (High-Density) - Angular Scatter Charts | ApexCharts.js | ApexCharts.js