donatso / family-chart

family tree visualization built on top of d3
MIT License
179 stars 63 forks source link

[NextJS] d3.select(...).transition is not a function #37

Open Fray117 opened 6 months ago

Fray117 commented 6 months ago

Hi, I find this module interesting and tried to implement to NextJS based on code generated on https://donatso.github.io/family-chart/examples/create-tree/

I wrap all componentDidMount to a useEffect hook, createRef with useRef hook.

I did a conditional if everything was mounted based on .current presence from the ref.

However it did not run as expected and returning the exact d3.select(...).transition is not a function error which I assume this was came from the family-chart that d3 module was not yet loaded, I've attached my code I working on this page.

'use client'

import { Suspense, useEffect, useRef } from 'react'
import f3 from 'family-chart'

import '@/styles/family-tree.css'

export default function RelationshipAnalisis() {

    const treeRef = useRef<HTMLDivElement>(null)

    const treeData = [
        {
            "id": "0",
            "rels": {
                "father": "83285456-43d8-44bd-bbf1-9204bd69111e",
                "mother": "fe5debe3-2ff0-4bf5-be51-317f595575d5",
                "spouses": [
                    "588da99f-31df-4887-b4c1-163e4d2a6cee"
                ]
            },
            "data": {
                "first name": "Name",
                "last name": "Surname",
                "birthday": 1970,
                "avatar": "https://static8.depositphotos.com/1009634/988/v/950/depositphotos_9883921-stock-illustration-no-user-profile-picture.jpg",
                "gender": "M"
            }
        },
        {
            "id": "83285456-43d8-44bd-bbf1-9204bd69111e",
            "data": {
                "gender": "M",
                "first name": "",
                "last name": "",
                "birthday": "",
                "avatar": ""
            },
            "rels": {
                "children": [
                    "0"
                ],
                "spouses": [
                    "fe5debe3-2ff0-4bf5-be51-317f595575d5"
                ]
            }
        },
        {
            "id": "fe5debe3-2ff0-4bf5-be51-317f595575d5",
            "data": {
                "gender": "F",
                "first name": "",
                "last name": "",
                "birthday": "",
                "avatar": ""
            },
            "rels": {
                "spouses": [
                    "83285456-43d8-44bd-bbf1-9204bd69111e"
                ],
                "children": [
                    "0"
                ]
            }
        },
        {
            "id": "588da99f-31df-4887-b4c1-163e4d2a6cee",
            "data": {
                "gender": "F",
                "first name": "",
                "last name": "",
                "birthday": "",
                "avatar": ""
            },
            "rels": {
                "spouses": [
                    "0"
                ]
            }
        }
    ]

    useEffect(() => {
        if (treeRef?.current) {
            const store = f3.createStore({
                data: treeData,
                node_separation: 250,
                level_separation: 150
            })

            const view = f3.d3AnimationView({
                store,
                cont: document.querySelector("#FamilyChart")
            })

            const Card = f3.elements.Card({
                store,
                svg: view.svg,
                card_dim: { w: 220, h: 70, text_x: 75, text_y: 15, img_w: 60, img_h: 60, img_x: 5, img_y: 5 },
                card_display: [(d: { data: { [x: string]: any } }) => `${d.data['first name'] || ''} ${d.data['last name'] || ''}`, (d: { data: { [x: string]: any } }) => `${d.data['birthday'] || ''}`],
                mini_tree: true,
                link_break: false
            })

            view.setCard(Card)
            store.setOnUpdate((props: any) => view.update(props || {}))
            store.update.tree({ initial: true })
        }
    }, [treeRef.current])

    return (
        <div className="px-12 sm:px-32">
            <h2 className="text-xl font-medium">Hubungan</h2>
            <Suspense>
                <div id="treeWrapper" className="w-full h-96">
                    <div className="f3" id="FamilyChart" ref={treeRef}></div>
                </div>
            </Suspense>
        </div>
    )
}
andrii-bodnar commented 4 months ago

@Fray117 it works well in my Next.js project. Try removing the useEffect dependency (treeRef.current)