JavaScript/jQuery Sankey - Custom Sources

To bind DevExtreme Sankey to a custom data source, implement a CustomStore. You can use the following extensions to configure CustomStore and implement server-side data processing to bind DevExtreme components to Web API and MongoDB services:

To access a server that uses another technology, configure the CustomStore manually. In this case, data can be processed on the client or server. In the former case, switch the CustomStore to the raw mode and load all data from the server in the load function as shown in the following example:

jQuery
index.js
$("#sankeyContainer").dxSankey({
    dataSource: new DevExpress.data.DataSource({
        store: new DevExpress.data.CustomStore({
            loadMode: "raw",
            load: function () {
                return $.getJSON('https://mydomain.com/MyDataService');
            }
        }),
        paginate: false,
    })
});
Angular
app.component.ts
app.component.html
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { DataSource, CustomStore } from "devextreme-angular/common/data";
import { lastValueFrom } from "rxjs";
import { DxSankeyComponent } from "devextreme-angular/ui/sankey";

@Component({
    imports: [DxSankeyComponent],
    // ...
})
export class AppComponent {
    sankeyDataSource: DataSource;
    constructor(httpClient: HttpClient) {
        this.sankeyDataSource = new DataSource({
            store: new CustomStore({
                loadMode: "raw",
                load: () => {
                    return lastValueFrom(httpClient.get('https://mydomain.com/MyDataService'));
                }
            }),
            paginate: false,
        });
    }
}
<dx-sankey
    [dataSource]="sankeyDataSource"
></dx-sankey>
Vue
App.vue
<template>
    <DxSankey :data-source="sankeyDataSource" />
</template>

<script setup lang="ts">
import { DxSankey } from "devextreme-vue/sankey";
import { DataSource, CustomStore } from "devextreme-vue/common/data";
import "whatwg-fetch";

function handleErrors(response) {
    if (!response.ok)
        throw Error(response.statusText);
    return response;
}

const sankeyDataSource = new DataSource({
    store: new CustomStore({
        loadMode: "raw",
        load: () => {
            return fetch("https://mydomain.com/MyDataService")
                .then(handleErrors);
        }
    }),
    paginate: false,
});
</script>
React
App.tsx
import React from "react";
import { Sankey } from "devextreme-react/sankey";
import { DataSource, CustomStore } from "devextreme-react/common/data";
import "whatwg-fetch";

function handleErrors(response) {
    if (!response.ok)
        throw Error(response.statusText);
    return response;
}

const sankeyDataSource = new DataSource({
    store: new CustomStore({
        loadMode: "raw",
        load: () => {
            return fetch("https://mydomain.com/MyDataService")
                .then(handleErrors);
        }
    }),
    paginate: false,
});

function App() {
    return (
        <Sankey dataSource={sankeyDataSource} />
    );
}

In the latter case, use the CustomStore's load function to send data processing settings to the server. These settings are passed as a parameter to the load function and depend on the operations (filtering, sorting, and others) you enabled in the DataSource. The following settings apply to the Sankey:

After receiving these settings, the server should apply them to data and send back an object with the following structure:

Code
{
    data: [ ... ] // result data objects
}

The following example shows how to make a query for data:

jQuery
index.js
$(function() {
    $("#sankeyContainer").dxSankey({
        dataSource: new DevExpress.data.DataSource({
            store: new DevExpress.data.CustomStore({
                load: function(loadOptions) {
                    const d = $.Deferred(),
                        params = {};
                    [
                        "sort",
                        "filter",
                        "searchExpr",
                        "searchOperation",
                        "searchValue"
                    ].forEach(function(i) {
                        if(i in loadOptions && isNotEmpty(loadOptions[i]))
                            params[i] = JSON.stringify(loadOptions[i]);
                    });
                    $.getJSON("https://mydomain.com/MyDataService", params)
                        .done(function(result) {
                            // Here, you can perform operations unsupported by the server
                            // or any other operations on the retrieved data
                            d.resolve(result.data);
                        });
                    return d.promise();
                }
            }),
            paginate: false
        })
    });
});
function isNotEmpty(value) {
    return value !== undefined && value !== null && value !== "";
}
Angular
app.component.ts
app.component.html
app.module.ts
import { Component, Inject } from "@angular/core";
import { HttpClient, HttpParams } from "@angular/common/http";
import DataSource from "devextreme/data/data_source";
import CustomStore from "devextreme/data/custom_store";
import { lastValueFrom } from "rxjs";
// ...
export class AppComponent {
    sankeyDataSource: any = {};
    constructor(@Inject(HttpClient) httpClient: HttpClient) {
        function isNotEmpty(value: any): boolean {
            return value !== undefined && value !== null && value !== "";
        }
        this.sankeyDataSource = new DataSource({
            store: new CustomStore({
                load: (loadOptions) => {
                    let params: HttpParams = new HttpParams();
                    [
                        "sort",
                        "filter",
                        "searchExpr",
                        "searchOperation",
                        "searchValue"
                    ].forEach(function(i) {
                        if(i in loadOptions && isNotEmpty(loadOptions[i]))
                            params = params.set(i, JSON.stringify(loadOptions[i]));
                    });
                    return lastValueFrom(httpClient.get("https://mydomain.com/MyDataService", { params: params }))
                        .then(result => {
                            // Here, you can perform operations unsupported by the server
                            // or any other operations on the retrieved data
                            return result.data;
                        });
                }
            }),
            paginate: false
        });
    }
}
<dx-sankey ...
    [dataSource]="sankeyDataSource">
</dx-sankey>
import { NgModule } from "@angular/core";
import { HttpClientModule } from "@angular/common/http";
import { DxSankeyModule } from "devextreme-angular";

@NgModule({
    imports: [
        // ...
        DxSankeyModule,
        HttpClientModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxSankey ...
        :data-source="sankeyDataSource" />
</template>

<script setup lang="ts">
import DxSankey from "devextreme-vue/sankey";
import CustomStore from "devextreme/data/custom_store";
import DataSource from "devextreme/data/data_source";
import 'whatwg-fetch';

function isNotEmpty(value) {
    return value !== undefined && value !== null && value !== "";
}
function handleErrors(response) {
    if (!response.ok)
        throw Error(response.statusText);
    return response;
}
const sankeyDataSource = new DataSource({
    store: new CustomStore({
        load: (loadOptions) => {
            let params = "?";
            [
                "sort",
                "filter",
                "searchExpr",
                "searchOperation",
                "searchValue"
            ].forEach(function(i) {
                if(i in loadOptions && isNotEmpty(loadOptions[i]))
                    params += `${i}=${JSON.stringify(loadOptions[i])}&`;
            });
            params = params.slice(0, -1);
            return fetch(`https://mydomain.com/MyDataService${params}`)
                .then(handleErrors)
                .then(response => response.json())
                .then((result) => {
                    // Here, you can perform operations unsupported by the server
                    // or any other operations on the retrieved data
                    return result.data;
                });
        }
    }),
    paginate: false
});
</script>
React
App.tsx
import React from "react";
import { Sankey } from "devextreme-react/sankey";
import CustomStore from "devextreme/data/custom_store";
import DataSource from "devextreme/data/data_source";
import 'whatwg-fetch';

function isNotEmpty(value) {
    return value !== undefined && value !== null && value !== "";
}
function handleErrors(response) {
    if (!response.ok)
        throw Error(response.statusText);
    return response;
}
const sankeyDataSource = new DataSource({
    store: new CustomStore({
        load: (loadOptions) => {
            let params = "?";
            [
                "sort",
                "filter",
                "searchExpr",
                "searchOperation",
                "searchValue"
            ].forEach(function(i) {
                if(i in loadOptions && isNotEmpty(loadOptions[i]))
                    params += `${i}=${JSON.stringify(loadOptions[i])}&`;
            });
            params = params.slice(0, -1);
            return fetch(`https://mydomain.com/MyDataService${params}`)
                .then(handleErrors)
                .then(response => response.json())
                .then((result) => {
                    // Here, you can perform operations unsupported by the server
                    // or any other operations on the retrieved data
                    return result.data;
                });
        }
    }),
    paginate: false
});

function App() {
    return (
        <Sankey ...
            dataSource={sankeyDataSource}>
        </Sankey>
    );
}

export default App;
See Also