export default function transformProps()

in superset-frontend/plugins/plugin-chart-echarts/src/Graph/transformProps.ts [156:372]


export default function transformProps(
  chartProps: EchartsGraphChartProps,
): GraphChartTransformedProps {
  const {
    width,
    height,
    formData,
    queriesData,
    hooks,
    inContextMenu,
    filterState,
    emitCrossFilters,
    theme,
  } = chartProps;
  const data: DataRecord[] = queriesData[0].data || [];
  const coltypeMapping = getColtypesMapping(queriesData[0]);
  const {
    source,
    target,
    sourceCategory,
    targetCategory,
    colorScheme,
    metric = '',
    layout,
    roam,
    draggable,
    selectedMode,
    showSymbolThreshold,
    edgeLength,
    gravity,
    repulsion,
    friction,
    legendMargin,
    legendOrientation,
    legendType,
    showLegend,
    baseEdgeWidth,
    baseNodeSize,
    edgeSymbol,
    sliceId,
  }: EchartsGraphFormData = { ...DEFAULT_GRAPH_FORM_DATA, ...formData };

  const refs: Refs = {};
  const metricLabel = getMetricLabel(metric);
  const colorFn = CategoricalColorNamespace.getScale(colorScheme as string);
  const firstColor = colorFn.range()[0];
  const nodes: { [name: string]: number } = {};
  const categories: Set<string> = new Set();
  const echartNodes: EChartGraphNode[] = [];
  const echartLinks: EdgeWithStyles[] = [];

  /**
   * Get the node id of an existing node,
   * or create a new node if it doesn't exist.
   */
  function getOrCreateNode(
    name: string,
    col: string,
    category?: string,
    color?: string,
  ) {
    if (!(name in nodes)) {
      nodes[name] = echartNodes.length;
      echartNodes.push({
        id: String(nodes[name]),
        name,
        col,
        value: 0,
        category,
        select: DEFAULT_GRAPH_SERIES_OPTION.select,
        tooltip: {
          ...getDefaultTooltip(refs),
          ...DEFAULT_GRAPH_SERIES_OPTION.tooltip,
        },
        itemStyle: { color },
      });
    }
    const node = echartNodes[nodes[name]];
    if (category) {
      categories.add(category);
      // category may be empty when one of `sourceCategory`
      // or `targetCategory` is not set.
      if (!node.category) {
        node.category = category;
      }
    }
    return node;
  }

  data.forEach(link => {
    const value = link[metricLabel] as number;
    if (!value) {
      return;
    }
    const sourceName = link[source] as string;
    const targetName = link[target] as string;
    const sourceCategoryName = sourceCategory
      ? getCategoryName(sourceCategory, link[sourceCategory])
      : undefined;
    const targetCategoryName = targetCategory
      ? getCategoryName(targetCategory, link[targetCategory])
      : undefined;
    const sourceNodeColor = sourceCategoryName
      ? colorFn(sourceCategoryName)
      : firstColor;
    const targetNodeColor = targetCategoryName
      ? colorFn(targetCategoryName)
      : firstColor;

    const sourceNode = getOrCreateNode(
      sourceName,
      source,
      sourceCategoryName,
      sourceNodeColor,
    );
    const targetNode = getOrCreateNode(
      targetName,
      target,
      targetCategoryName,
      targetNodeColor,
    );

    sourceNode.value += value;
    targetNode.value += value;

    echartLinks.push({
      source: sourceNode.id,
      target: targetNode.id,
      value,
      lineStyle: {
        color: sourceNodeColor,
      },
      emphasis: {},
      select: {},
    });
  });

  normalizeStyles(echartNodes, echartLinks, {
    showSymbolThreshold,
    baseEdgeWidth,
    baseNodeSize,
  });

  const categoryList = [...categories];
  const series: GraphSeriesOption[] = [
    {
      zoom: DEFAULT_GRAPH_SERIES_OPTION.zoom,
      type: 'graph',
      categories: categoryList.map(c => ({
        name: c,
        itemStyle: {
          color: colorFn(c, sliceId),
        },
      })),
      layout,
      force: {
        ...DEFAULT_GRAPH_SERIES_OPTION.force,
        edgeLength,
        gravity,
        repulsion,
        friction,
      },
      circular: DEFAULT_GRAPH_SERIES_OPTION.circular,
      data: echartNodes,
      links: echartLinks,
      roam,
      draggable,
      edgeSymbol: parseEdgeSymbol(edgeSymbol),
      edgeSymbolSize: baseEdgeWidth * 2,
      selectedMode,
      ...getChartPadding(showLegend, legendOrientation, legendMargin),
      animation: DEFAULT_GRAPH_SERIES_OPTION.animation,
      label: DEFAULT_GRAPH_SERIES_OPTION.label,
      lineStyle: DEFAULT_GRAPH_SERIES_OPTION.lineStyle,
      emphasis: DEFAULT_GRAPH_SERIES_OPTION.emphasis,
    },
  ];

  const echartOptions: EChartsCoreOption = {
    animationDuration: DEFAULT_GRAPH_SERIES_OPTION.animationDuration,
    animationEasing: DEFAULT_GRAPH_SERIES_OPTION.animationEasing,
    tooltip: {
      ...getDefaultTooltip(refs),
      show: !inContextMenu,
      formatter: (params: any): string => {
        const source = sanitizeHtml(
          getKeyByValue(nodes, Number(params.data.source)),
        );
        const target = sanitizeHtml(
          getKeyByValue(nodes, Number(params.data.target)),
        );
        const title = `${source} > ${target}`;
        return tooltipHtml([[metricLabel, `${params.value}`]], title);
      },
    },
    legend: {
      ...getLegendProps(legendType, legendOrientation, showLegend, theme),
      data: categoryList,
    },
    series,
  };

  const { onContextMenu, setDataMask } = hooks;

  return {
    width,
    height,
    formData,
    echartOptions,
    onContextMenu,
    setDataMask,
    filterState,
    refs,
    emitCrossFilters,
    coltypeMapping,
  };
}