Closed37

@yamada-ui/chartsの記録

Hidden comment
Hidden comment
Hidden comment
Hidden comment
Hidden comment
Hidden comment
108えん108えん

cursorの色指定がどうしてもclassnameではできない

use-chart-tooltip.tsx
  const cursorClassName = getClassName({
    fill: ["primary.400", "secondary.400"],
  })(theme)

...

      cursor: <Rectangle className={cursorClassName} />,
108えん108えん

fillとstrokeだけ取り出してこんな感じにするしかない

use-chart-tooltip.ts
  const tooltipVars: CSSUIProps["var"] = useMemo(
    () => [
      {
        __prefix: "ui",
        name: "cursor-fill",
        token: "colors",
        value: cursor.fill ?? "transparent",
      },
    ],
    [cursor.fill],
  )

...

      cursor: {
        fill: "var(--ui-cursor-fill)",
      },
108えん108えん

どのclassnameが当たるか調べる

108えん108えん

v3.x

当たる

BarChart.stories.tsx
<Bar dataKey="pv" fill="#8884d8" background={{ className: 'background-test', fill: '#eee' }} />

当たらない

BarChart.stories.tsx
  <Bar
    dataKey="pv"
    fill="#8884d8"
    activeBar={<Rectangle fill="pink" stroke="blue" className="activebar-test" />}
  />
BarChart.stories.tsx
<Tooltip cursor={{ className: 'cursor-test' }} />
108えん108えん

cursorはこれでもいいのでは?

BarChart.tsx
const CustomCursor: React.FunctionComponent<any> = (props: any) => {
  const { x, y, width, height, fill, payloadIndex } = props;
  return (
    <Rectangle x={x} y={y} fill={fill} width={width} height={height} onMouseEnter={() => console.log(payloadIndex)} />
  );
};
108えん108えん

ここまでやってもcursorにclassNameは当たらなかった

export const Simple = {
  render: () => {
    const CustomCursor: React.FunctionComponent<any> = (props: any) => {
      const { x, y, width, height, fill, payloadIndex } = props;
      return (
        <div className="cursor-classname-test">
          <Rectangle
            x={x}
            y={y}
            fill="red"
            width={width}
            height={height}
            onMouseEnter={() => console.log(payloadIndex)}
          />
        </div>
      );
    };
    return (
      <ResponsiveContainer width="100%" height="100%">
        <BarChart
          width={500}
          height={300}
          data={pageData}
          margin={{
            top: 5,
            right: 30,
            left: 20,
            bottom: 5,
          }}
        >
          <CartesianGrid strokeDasharray="3 3" />
          <XAxis dataKey="name" />
          <YAxis />
          <Tooltip cursor={<CustomCursor />} />
          <Legend />
          <Bar dataKey="pv" fill="#8884d8" activeBar={<Rectangle fill="pink" stroke="blue" />} />
          <Bar dataKey="uv" fill="#82ca9d" activeBar={<Rectangle fill="gold" stroke="purple" />} />
        </BarChart>
      </ResponsiveContainer>
    );
  },
};
108えん108えん

cursorはこれで当たるようにはなる

Cursor.tsx
  const cursorProps = {
    stroke: '#ccc',
    pointerEvents: 'none',
    ...offset,
    ...restProps,
    ...filterProps(element.props.cursor, false),
    payload: activePayload,
    payloadIndex: activeTooltipIndex,
-    className: 'recharts-tooltip-cursor',
+    className: clsx('recharts-tooltip-cursor', element.props.cursor.className),
  };
108えん108えん

pathに一緒にclassNameが当たっている

BarChart.stories.tsx
            activeBar={{ fill: 'pink', stroke: 'blue', className: 'activeBar-className-test' }}
108えん108えん

円みたいな方は、className上書きしているせいで当たっていないから色が変わらない

PolarGrid.tsx
const ConcentricCircle: React.FC<ConcentricProps> = props => {
  const { cx, cy, radius, index } = props;
  const concentricCircleProps = {
    stroke: '#ccc',
    ...filterProps(props, false),
    fill: 'none',
  };

  return (
    <circle
      {...concentricCircleProps}
      className="recharts-polar-grid-concentric-circle"
      key={`circle-${index}`}
      cx={cx}
      cy={cy}
      r={radius}
    />
  );
};

// Draw concentric polygons
const ConcentricPolygon: React.FC<ConcentricProps> = props => {
  const { radius, index } = props;
  const concentricPolygonProps = {
    stroke: '#ccc',
    ...filterProps(props, false),
    fill: 'none',
  };

  return (
    <path
      {...concentricPolygonProps}
      className="recharts-polar-grid-concentric-polygon"
      key={`path-${index}`}
      d={getPolygonPath(radius, props.cx, props.cy, props.polarAngles)}
    />
  );
};
108えん108えん

dotにclassNameが当たらない。
Areaと同じバグ。

Radar.tsx
  static renderDotItem(option: RadarDot, props: any) {
    let dotItem;

    if (React.isValidElement(option)) {
      dotItem = React.cloneElement(option, props);
    } else if (isFunction(option)) {
      dotItem = option(props);
    } else {
      dotItem = <Dot {...props} className="recharts-radar-dot" />;
    }

    return dotItem;
  }
108えん108えん

PolarRadiusAxis.tsxPolarAngleAxis.tsxもlabelにclassName当たってないけど当てる?そこまでしなくても感はある

PolarRadiusAxis.tsx
  static renderTickItem(option: Props['tick'], props: any, value: string | number) {
    let tickItem;

    if (React.isValidElement(option)) {
      tickItem = React.cloneElement(option, props);
    } else if (isFunction(option)) {
      tickItem = option(props);
    } else {
      tickItem = (
        <Text {...props} className="recharts-polar-radius-axis-tick-value">
          {value}
        </Text>
      );
    }

    return tickItem;
  }
108えん108えん

当たってないとこまとめ

  • PolarGridの円みたいな方
  • dot
  • PolarAngleAxis全体
  • PolarRadiusAxis全体
  • PolarRadiusAxisPolarAngleAxis.tsxのラベル(tick)
108えん108えん

プルリクの下書き
Put the className as in the following example.

      <RadarChart width={600} height={300} data={data} margin={{ top: 5, right: 30, left: 20, bottom: 5 }}>
        <PolarGrid className="polar-grid-custom-className" />
        <PolarRadiusAxis
          angle={90}
          type="number"
          className="polar-radius-axis-custom-className"
          tick={{ className: 'polar-radius-axis-tick-custom-className' }}
        />
        <PolarAngleAxis
          dataKey="angle"
          type="number"
          domain={[0, 360]}
          tickCount={9}
          className="polar-angle-axis-custom-className"
          tick={{ className: 'polar-angle-axis-tick-custom-className' }}
        />
        <Radar dataKey="value" fillOpacity={0} stroke="#000" dot={{ className: 'radar-custom-className' }} />
      </RadarChart>

If it is acceptable to modify it, I will fix it.
PolarGrid.tsx

const ConcentricCircle: React.FC<ConcentricProps> = props => {
...
  return (
    <circle
      {...concentricCircleProps}
-      className="recharts-polar-grid-concentric-circle"
+      className={clsx('recharts-polar-grid-concentric-circle', props.className)}
      key={`circle-${index}`}
      cx={cx}
      cy={cy}
      r={radius}
    />
  );
};

// Draw concentric polygons
const ConcentricPolygon: React.FC<ConcentricProps> = props => {
...
  return (
    <path
      {...concentricPolygonProps}
-      className="recharts-polar-grid-concentric-polygon"
+      className={clsx('recharts-polar-grid-concentric-polygon', props.className)}
      key={`path-${index}`}
      d={getPolygonPath(radius, props.cx, props.cy, props.polarAngles)}
    />
  );
};

PolarRadiusAxis.tsx

  renderTicks() {
...
      return (
        <Layer
-          className="recharts-polar-radius-axis-tick"
+          className={clsx('recharts-polar-radius-axis-tick', get(tick, 'className'))}
          key={`tick-${entry.coordinate}`}
          {...adaptEventsOfChild(this.props, entry, i)}
        >
          {PolarRadiusAxis.renderTickItem(tick, tickProps, tickFormatter ? tickFormatter(entry.value, i) : entry.value)}
        </Layer>
      );
    });

    return <Layer className="recharts-polar-radius-axis-ticks">{items}</Layer>;
  }
...
  render() {
    const { ticks, axisLine, tick } = this.props;

    if (!ticks || !ticks.length) {
      return null;
    }

    return (
-      <Layer className="recharts-polar-radius-axis">
+      <Layer className={clsx('recharts-polar-radius-axis', this.props.className)}>
        {axisLine && this.renderAxisLine()}
        {tick && this.renderTicks()}
        {Label.renderCallByParent(this.props, this.getViewBox())}
      </Layer>
    );
  }

PolarAngleAxis.tsx

  renderTicks() {
...
      return (
        <Layer
-          className="recharts-polar-angle-axis-tick"
+          className={clsx('recharts-polar-angle-axis-tick', get(tick, 'className'))}
          key={`tick-${entry.coordinate}`}
          {...adaptEventsOfChild(this.props, entry, i)}
        >
          {tickLine && <line className="recharts-polar-angle-axis-tick-line" {...tickLineProps} {...lineCoord} />}
          {tick &&
            PolarAngleAxis.renderTickItem(tick, tickProps, tickFormatter ? tickFormatter(entry.value, i) : entry.value)}
        </Layer>
      );
    });

    return <Layer className="recharts-polar-angle-axis-ticks">{items}</Layer>;
  }
...
  render() {
    const { ticks, radius, axisLine } = this.props;

    if (radius <= 0 || !ticks || !ticks.length) {
      return null;
    }

    return (
-      <Layer className="recharts-polar-angle-axis"
+      <Layer className={clsx('recharts-polar-angle-axis', this.props.className)}>
        {axisLine && this.renderAxisLine()}
        {this.renderTicks()}
      </Layer>
    );
  }

generateCategoricalChart.tsx

    renderPolarAxis = (element: any, displayName: string, index: number) => {
      const axisType = get(element, 'type.axisType');
      const axisMap = get(this.state, `${axisType}Map`);
      const axisOption: BaseAxisProps | undefined = axisMap && axisMap[element.props[`${axisType}Id`]];

      return cloneElement(element, {
        ...axisOption,
-        className: axisType,
+        className: clsx(axisType, axisOption.className),
        key: element.key || `${displayName}-${index}`,
        ticks: getTicksOfAxis(axisOption, true),
      });
    };

Radar.tsx

  static renderDotItem(option: RadarDot, props: any) {
    let dotItem;

    if (React.isValidElement(option)) {
      dotItem = React.cloneElement(option, props);
    } else if (isFunction(option)) {
      dotItem = option(props);
    } else {
-      dotItem = <Dot {...props} className="recharts-radar-dot" />;
+      dotItem = (
+        <Dot {...props} className={clsx('recharts-radar-dot', typeof option !== 'boolean' ? option.className : '')} />
+      );
    }

    return dotItem;
  }
108えん108えん

メモ

  • piechartをデフォルトにして、donutchartは上書きするようにする

  • 90,-270にするのは0時始まりにしたいから

  • startangleとendangleは共通でよい

  • DonutChartProps=PieChartProps& DonutChartOptionsにして、DonutChartOptionsの中身は消す

  • innerだけ中身戻して指定する

  • 60%の初期になってJSDOもできる

  • endAngleも初期値いらない

  • numberだったらpxであることをコメントに記載する

    • labellineとかinnerRadiusとか
  • labelをもう少し離して、labelLineを伸ばすのはべつチケットにする

108えん108えん
  • tabIndexを-1にする必要がある
  • outlineもnoneにするべき
_focus:{outline:none}
  • pieにフォーカスが当たっている
    withLegend?"100%":"80%"をdonutchart側でもやる
このスクラップは1ヶ月前にクローズされました