1

I have highcharts3d and I wanted to implement Anaglyph effect with highcharts3d

the below code is working component, You can copy paste this code into any of the reactJS application Only thing is not working in below example is anaglyph effect.

Expecting some suggestions or changes based on my current code Thanks in advance.

import React, { useState, useEffect, useRef } from 'react';
import * as THREE from 'three';
import { AnaglyphEffect } from 'three/examples/jsm/effects/AnaglyphEffect.js'
import HighchartsReact from 'highcharts-react-official'
import Highcharts from 'highcharts'
import highcharts3d from 'highcharts/highcharts-3d'
import highchartsMore from 'highcharts/highcharts-more'
highcharts3d(Highcharts)
highchartsMore(Highcharts)

const HChart = () => {
  const chartRef = useRef(null)
  const [chartOptions] = useState({
    chart: {
      type: "column",
      options3d: {
        enabled: true,
      },
      events: {
        render: (event) => {
          event.target.reflow()
        },
      },
    },
    title: {
      text: '3D Chart',
    },
    accessibility: {
      enabled: false,
    },
    series: [
      {
        data: [],
        color: 'rgba(0,255,255,0.5)'
      },
    ]
  })

  useEffect(() => {
    // const container = document.createElement('div');
    const container = document.querySelector('.highcharts-container')
    let camera, scene, renderer, effect;

    init()
    animate()

    function init() {

      camera = new THREE.PerspectiveCamera(
        60,
        window.innerWidth / window.innerHeight,
        0.01,
        100,
      )
      camera.position.z = 3
      camera.focalLength = 3

      scene = new THREE.Scene()


      renderer = new THREE.WebGLRenderer()
      renderer.setPixelRatio(window.devicePixelRatio)
      container.appendChild(renderer.domElement)
      // chartRef.current.appendChild(renderer.domElement) // This line is giving error

      const width = window.innerWidth || 2
      const height = window.innerHeight || 2

      effect = new AnaglyphEffect(renderer)
      effect.setSize(width, height)

      window.addEventListener('resize', onWindowResize)
    }


    function animate() {
      requestAnimationFrame(animate)
      render()
    }

    function onWindowResize() {
      camera.aspect = window.innerWidth / window.innerHeight
      camera.updateProjectionMatrix()

      effect.setSize(window.innerWidth, window.innerHeight)
    }
    function render() {
      effect.render(scene, camera)
    }
  }, [])

    useEffect(() => {
    const baseData = [49.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4];
    const distance = 0.05;
    const anaglyphicData = [];
    baseData.forEach((dataEl, index) => {
      anaglyphicData.push(
        [index, dataEl], {
        x: index - distance,
        y: dataEl + distance,
        color: 'rgba(255,0,0,0.5)'
      }
      );
    });

      chartRef.current.chart.series[0].setData(anaglyphicData)
    },[])
  
  function addEvents(H, chart) {
    function dragStart(eStart) {
      eStart = chart.pointer.normalize(eStart)

      let posX = eStart.chartX,
        posY = eStart.chartY,
        alpha = chart.options.chart.options3d.alpha,
        beta = chart.options.chart.options3d.beta,
        sensitivity = 5, // lower is more sensitive
        handlers = []

      function drag(event) {
        // Get e.chartX and e.chartY

        event = chart.pointer.normalize(event)

        chart.update(
          {
            chart: {
              options3d: {
                alpha: alpha + (event.chartY - posY) / sensitivity,
                beta: beta + (posX - event.chartX) / sensitivity,
              },
            },
          },
          undefined,
          undefined,
          false,
        )
      }

      function unbindAll() {
        handlers.forEach(function(unbind) {
          if (unbind) {
            unbind()
          }
        })
        handlers.length = 0
      }

      handlers.push(H.addEvent(document, 'mousemove', drag))
      handlers.push(H.addEvent(document, 'touchmove', drag))

      handlers.push(H.addEvent(document, 'mouseup', unbindAll))
      handlers.push(H.addEvent(document, 'touchend', unbindAll))
    }
    H.addEvent(chart.container, 'mousedown', dragStart)
    H.addEvent(chart.container, 'touchstart', dragStart)
    // chartContainer = chart.container
  }
  return (
    <div className="chartContainer" >
      <HighchartsReact
        highcharts={Highcharts}
        ref={chartRef}
        options={chartOptions}
        allowChartUpdate={true}
        containerProps={{ style: { width: '100%', height: '100%' } }}
        callback={function(chart) {
          addEvents(Highcharts, chart)
        }}
      />
    </div>
  )
}

export default HChart;

Above Component Result

1 Answers1

0

There is not any integration between Highcharts and threejs. However, implementing an anaglyph effect seems to be really simple, for example by duplicating data.

For example:

const baseData = [1, 2, 3, 4, 5];
const distance = 0.05;
const anaglyphicData = [];
baseData.forEach((dataEl, index) => {
  anaglyphicData.push(
    [index, dataEl], {
      x: index - distance,
      y: dataEl + distance,
      color: 'rgba(255,0,0,0.5)'
    }
  );
});

Highcharts.chart('container', {
  ...,
  series: [{
    data: anaglyphicData,
    color: 'rgba(0,255,255,0.5)'
  }]
});

Live demo: https://jsfiddle.net/BlackLabel/csrzj4d3/

Docs: https://www.highcharts.com/docs/chart-concepts/3d-charts

ppotaczek
  • 36,341
  • 2
  • 14
  • 24
  • Hi @ppotaczek, Thanks for your effort, It looks good in 2D chart but in 3D chart which we can rotate in that It was not working as expected. half of the bars are red and half of the bars are the other color It was not applying properly, I've updated your code in my question. – Hasansab Takked Feb 06 '23 at 05:14
  • Hi @Hasansab Takked, It is really hard to do that with the rotation feature. The trick is to place a mocked column almost in the same place as the original one, but there is a limitation in Highcharts related to z-index calculation in such a case. You would have to duplicate svg shapes in some other way or add some modification(https://www.highcharts.com/docs/extending-highcharts/extending-highcharts) to Highcharts code: https://github.com/highcharts/highcharts/blob/master/ts/Series/Column3D/Column3DComposition.ts – ppotaczek Feb 06 '23 at 15:00