This is an example of a technique that's shown in the Vue manual, basically you maintain two pieces of state, use one as the backing store and use a watcher to update the derived state using tweening mechanisms such as TweenLite in this case. Shown with a few hacks that are necessary to get it working with the d3-cluster node representation.

<template>
  <div>
    <svg viewBox="0 0 1024 768" width="1024" height="768" 
         xmlns="http://www.w3.org/2000/svg">
      <circle v-for="descendant in tweenedDescendants"
              :cx="descendant.x"
              :cy="descendant.y"
              r="10"
              stroke="red" fill="grey"/>
    </svg>

    <button v-on:click="relayout">Relayout</button>
  </div>
</template>

<script lang="ts">
import Vue from 'vue';
import {hierarchy, cluster, HierarchyNode} from 'd3';
import _ from 'lodash';
import {TweenLite} from 'gsap';

const familyData = {
    "name": "Eve",
    "children": [
        {
            "name": "Cain"
        },
        {
            "name": "Seth",
            "children": [
                {
                    "name": "Enos"
                },
                {
                    "name": "Noam"
                }
            ]
        },
        {
            "name": "Abel"
        },
        {
            "name": "Awan",
            "children": [
                {
                    "name": "Enoch"
                }
            ]
        },
        {
            "name": "Azura"
        }
    ]
};


interface FamilyDatum {
};

function initialCluster(val: any): HierarchyNode<FamilyDatum> {
    const theHierarchy = hierarchy(val);
    const clusterLayout = cluster();
    clusterLayout.size([1024, 768]);
    clusterLayout(theHierarchy);
    return theHierarchy;
}

export default Vue.extend({
    data() {

        return {
            hierarchyRoot: initialCluster(familyData) as HierarchyNode<FamilyDatum>,
            tweenedHierarchyRoot: initialCluster(familyData) as HierarchyNode<FamilyDatum>
        };
    },
    mounted() {
        window.setInterval(this.relayout, 1000);
    },
    methods: {
        relayout() {
            const clusterLayout = cluster();

            // these hacks necessary because cluster() itself does some array
            // mutations that fool the reactivity
            const clonedHierarchy = _.clone(this.hierarchyRoot);
            clusterLayout.size([Math.random() * 1024, Math.random() * 768]);
            clusterLayout(clonedHierarchy);

            this.hierarchyRoot = clonedHierarchy;
        },
    },
    computed: {
        descendants(): HierarchyNode<FamilyDatum>[] {
            return this.hierarchyRoot.descendants();
        },
        tweenedDescendants(): HierarchyNode<FamilyDatum>[] {
            return this.tweenedHierarchyRoot.descendants();
        },
    },
    watch: {
        // No deep watch needed because we always reassign the whole
        // array
        hierarchyRoot(val, oldVal) {
            console.log("inside handler function");
            // We know that descendants() function returns references to
            // the nodes that can be directly modified by mutation.
            // Because the x and y values have already been declared in the
            // data() method  -- that is, cluster() was already called once
            // to add the properties -- Vue knows that it should react to changes
            // on these properties.

            const targetDescendants = val.descendants();
            const tweenedDescendants = this.tweenedHierarchyRoot.descendants();

            for (var i = 0; i < tweenedDescendants.length; i++) {
                const node = tweenedDescendants[i];

                const targetX = targetDescendants[i].x;
                const targetY = targetDescendants[i].y;

                TweenLite.to(node, 0.5, {x: targetX, y: targetY});
            }
        }
    }
});
</script>

<elyts lang="less">
</style>

This is based on a technique from the Vue manual.