public converter()

in src/sankeyDiagram.ts [425:627]


    public converter(dataView: DataView): SankeyDiagramDataView {
        const settings: SankeyDiagramSettings = this.parseSettings(dataView);

        if (!dataView
            || !dataView.matrix
            || !dataView.matrix.rows
            || !dataView.matrix.rows.levels
            || !dataView.matrix.rows.levels[0]
            || !dataView.matrix.rows.levels[0].sources
            || !dataView.matrix.rows.levels[0].sources[0]
            || !dataView.matrix.rows.levels[0].sources[0].displayName
            || !dataView.matrix.rows.levels[1]
            || !dataView.matrix.rows.levels[1].sources
            || !dataView.matrix.rows.levels[1].sources[0]
            || !dataView.matrix.rows.levels[1].sources[0].displayName
            || !dataView.matrix.rows.root
            || !dataView.matrix.rows.root.children
            || !dataView.matrix.valueSources) {
            return {
                settings,
                nodes: [],
                links: [],
                columns: []
            }
        }

        let nodes: SankeyDiagramNode[] = [],
            links: SankeyDiagramLink[] = [],
            categories: any[] = [],
            sourceCategories: any[] = [],
            destinationCategories: any[] = [],
            sourceCategoriesLabels: any[] = [],
            destinationCategoriesLabels: any[] = [],
            objects: any[] = [],
            weights: any[] = [],
            selectionIdBuilder: SelectionIdBuilder = new SelectionIdBuilder(
                this.visualHost,
                dataView.matrix),
            valueSources = dataView.matrix.valueSources;



        const sourceLabelIndex: number = valueSources.indexOf(valueSources.filter((column: powerbi.DataViewMetadataColumn) => {
            return column.roles.SourceLabels;
        }).pop());


        const weightIndex: number = valueSources.indexOf(valueSources.filter((source: powerbi.DataViewMetadataColumn) => {
            return source.roles.Weight;
        }).pop());

        const sourceFieldName = dataView.matrix.rows.levels[0].sources[0].displayName;
        const destinationFieldName = dataView.matrix.rows.levels[1].sources[0].displayName;
        const valueFieldName = dataView.matrix.valueSources[weightIndex] ? dataView.matrix.valueSources[weightIndex].displayName : null;

        const formatOfWeigth = valueFormatter.getFormatStringByColumn(valueSources[weightIndex]);


        let weightValues: number[] = [1];

        dataView.matrix.rows.root.children.forEach(parent => {
            let newSourceNode = this.createNewNode(parent, settings)
            newSourceNode.identity = this.visualHost.createSelectionIdBuilder()
                .withMatrixNode(parent, dataView.matrix.rows.levels)
                .createSelectionId();
            nodes.push(newSourceNode);

        });

        const valuesFormatterForWeigth = valueFormatter.create({
            format: formatOfWeigth,
            value: Math.max(
                settings.labels.unit !== 0 ? settings.labels.unit : d3.max(weightValues) || SankeyDiagram.MinWeightValue,
                SankeyDiagram.MinWeightValue),
        });


        dataView.matrix.rows.root.children.forEach(parent => {
            let foundSource: SankeyDiagramNode = nodes.find(found => found.label.name === parent.value)

            parent.children.forEach(child => {
                let linkLabel = undefined;
                let weigth: any = SankeyDiagram.DefaultWeightValue;

                let foundDestination: SankeyDiagramNode = nodes.find(found => found.label.name === child.value)
                if (!foundDestination) {
                    foundDestination = this.createNewNode(child, settings);
                    foundDestination.identity = this.visualHost.createSelectionIdBuilder()
                        .withMatrixNode(parent, dataView.matrix.rows.levels)
                        .withMatrixNode(child, dataView.matrix.rows.levels)
                        .createSelectionId();
                    nodes.push(foundDestination);
                }

                if (sourceLabelIndex != -1) {
                    linkLabel = (child.values[sourceLabelIndex] && child.values[sourceLabelIndex].value) ?
                        child.values[sourceLabelIndex].value || SankeyDiagram.DefaultWeightValue : SankeyDiagram.MinWeightValue;
                }


                // If weights are present, populate the weights array
                if (weightIndex != -1) {
                    weigth = (child.values[weightIndex] && child.values[weightIndex].value) ?
                        child.values[weightIndex].value || SankeyDiagram.DefaultWeightValue : SankeyDiagram.MinWeightValue;

                    weightValues.push(weigth);

                }

                let linkFillColor = this.getColor(
                    SankeyDiagram.LinksPropertyIdentifier,
                    SankeyDiagram.DefaultColourOfLink,
                    child.objects);
                let linkStrokeColor = this.colorHelper.isHighContrast ? this.colorHelper.getHighContrastColor("foreground", linkFillColor) : linkFillColor;


                let tooltipInfo = SankeyDiagram.getTooltipDataForLink(
                    valuesFormatterForWeigth,
                    foundSource.label.formattedName,
                    foundDestination.label.formattedName,
                    weigth,
                    sourceFieldName,
                    destinationFieldName,
                    valueFieldName
                );

                let link: SankeyDiagramLink = {
                    label: linkLabel && linkLabel.toString(),
                    source: foundSource,
                    destination: foundDestination,
                    weigth: weigth,
                    height: 10,
                    fillColor: linkFillColor,
                    strokeColor: linkStrokeColor,
                    dySource: 0,
                    dyDestination: 0,
                    tooltipInfo: tooltipInfo,
                    identity: this.visualHost.createSelectionIdBuilder()
                        .withMatrixNode(parent, dataView.matrix.rows.levels)
                        .withMatrixNode(child, dataView.matrix.rows.levels)
                        .createSelectionId(),
                    selected: false,
                    direction: SankeyLinkDirrections.Forward
                }

                let selectableDataPoint: SelectableDataPoint = SankeyDiagram.createSelectableDataPoint(<ISelectionId>link.identity);
                foundSource.selectableDataPoints.push(selectableDataPoint);
                foundDestination.selectableDataPoints.push(selectableDataPoint);

                links.push(link);

                foundSource.links.push(link);
                foundDestination.links.push(link);

                SankeyDiagram.updateValueOfNode(foundSource);
                SankeyDiagram.updateValueOfNode(foundDestination);
            });
        });

        

        let cycles: SankeyDiagramCycleDictionary = this.checkCycles(nodes);

        if (settings.cyclesLinks.drawCycles === CyclesDrawType.Duplicate) {
            links = this.processCyclesForwardLinks(cycles, nodes, links, settings);
        }

        nodes.forEach((node: SankeyDiagramNode) => {
            node.tooltipInfo = SankeyDiagram.getTooltipForNode(
                valuesFormatterForWeigth,
                node.label.formattedName,
                node.inputWeight
                    ? node.inputWeight
                    : node.outputWeight,
                this.localizationManager,
                node.inputWeight > 0 && node.outputWeight > 0 ? `${sourceFieldName}-${destinationFieldName}` : node.outputWeight > 0
                    ? sourceFieldName
                    : destinationFieldName,
                valueFieldName
            );
        });


        let sankeyDiagramDataView = {
            nodes,
            links,
            settings,
            columns: []
        };

        if (settings.cyclesLinks.drawCycles === CyclesDrawType.Backward) {
            SankeyDiagram.computeXPositions(sankeyDiagramDataView);
            sankeyDiagramDataView.links = this.processCyclesForBackwardLinks(cycles, sankeyDiagramDataView.nodes, links, settings);
            sankeyDiagramDataView.links.forEach((link: SankeyDiagramLink) => {
                if (link.destination === link.source) {
                    link.direction = SankeyLinkDirrections.SelfLink;
                }
            });
        }
        this.checkNodePositionSettings(nodes, settings);
        this.restoreNodePositions(nodes, settings);
        return sankeyDiagramDataView;
    }