English | [简体中文](./README-zh_CN.md)

# @ray-js/common-charts

Chart component for **Tuya Ray** mini programs. It wraps ECharts via the mini program RJS plugin layer—if you know ECharts options, you can use this package with little extra learning.

## Table of contents

- [Requirements](#requirements)
- [Installation](#installation)
- [Usage](#usage)
- [Advanced usage](#advanced-usage)
- [FAQ](#faq)

## Requirements

| Item                       | Notes                                                                                                                                          |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| **Peer dependency**        | [`@ray-js/ray`](https://www.npmjs.com/package/@ray-js/ray) `^1.4.9` (align with your app’s Ray version).                                       |
| **Underlying UI**          | This package depends on [`@tuya-miniapp/common-charts`](https://github.com/Tuya-Community/tuya-miniapp-materials?path=materials/CommonCharts). |
| **Optional: full ECharts** | When using `usingPlugin`, add `echarts` to your app and configure RJS plugins (see [Advanced usage](#advanced-usage)).                         |

## Installation

```bash
npm install @ray-js/common-charts
# or
yarn add @ray-js/common-charts
```

## Usage

The default export is **`CommonCharts`**. For HTML tooltips (`renderMode: 'html'`), build markup inside the string formatter with normal string concatenation—the package also exports an optional **`html()`** helper if you want it (see [Tooltip (HTML)](#tooltip-html)). For prop types, see [`src/props.ts`](./src/props.ts).

### Basic example

```jsx
import CommonCharts from '@ray-js/common-charts';

<CommonCharts
  unit="℃"
  option={{
    backgroundColor: '#fff',
    xAxis: {
      type: 'category',
      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
    },
    yAxis: { type: 'value' },
    tooltip: {},
    series: [
      {
        name: 'Demo',
        data: [150, 230, 224, 218, 135, 147, 260],
        type: 'line',
      },
    ],
  }}
/>;
```

### Custom class name

```jsx
<CommonCharts
  option={{ backgroundColor: 'transparent', ...lineOption } as EChartsOption}
  customClass={styles['my-chart']}
/>
```

### `notMerge` — skip default option merging (v0.0.4+)

Use this when you want **full control** over the ECharts `option`. The component will stop merging or adjusting your config.

> **Note:** React props cannot pass real `function` values into RJS. Heavy customization without merge is still limited—enable `notMerge` only when you need it.

```jsx
<CommonCharts option={fullEchartsOption} notMerge />
```

You can also pass ECharts init options via `opts` (e.g. `notMerge` there) — see [ECharts `opts`](#echarts-opts).

### Themes

Built-in: `dark` | `light`.

```jsx
<CommonCharts theme="dark" />
```

### ECharts `opts`

<a id="echarts-opts"></a>

Forwards to the underlying chart (e.g. merge strategy).

```jsx
<CommonCharts
  opts={{ notMerge: true }}
  option={updatedOption as EChartsOption}
  customStyle={{
    width: '100%',
    height: '300px',
  }}
/>
```

### Full screen

`supportFullScreen` toggles full-screen display. **Default scroll blocking is not implemented**—handle orientation or layout yourself (e.g. `ty.onWindowResize`).

```jsx
<CommonCharts supportFullScreen />
```

### Error message

```jsx
<CommonCharts option={{} as EChartsOption} errMsg={Strings.getLang('errorMsg')} />
```

### Loading text

```jsx
<CommonCharts loadingText="Loading..." />
```

### `unit`

When using the default tooltip behavior, `unit` is applied for you.

```jsx
<CommonCharts unit="m" />
```

### Tooltip (HTML) (v0.1.3)

<a id="tooltip-html"></a>

Set `renderMode: 'html'` and return HTML from the string `formatter` as you would in plain ECharts. The example below uses the optional **`html()`** helper from this package; you can use raw strings instead (see [Advanced usage](#advanced-usage)).

```jsx
import CommonCharts, { html } from '@ray-js/common-charts';

<CommonCharts
  option={{
    ...lineChartOption,
    tooltip: {
      formatter: `function (params) {
        var text = _.reduce(params, function (acc, cur, idx) {
          return acc + ${html(
            'div',
            { style: { fontSize: '10px' } },
            "cur.marker + cur.seriesName + ':' + cur.value"
          )}
        }, '');
        return ${html(
          'div',
          {
            style: {
              color: 'red',
              fontSize: '10px',
              textAlign: 'center',
            },
          },
          'dayjs(Date.now()).format("YYYY-MM-DD HH:mm:ss")'
        )} + text;
      }`,
      renderMode: 'html',
      confine: true,
    },
  }}
/>;
```

### ECharts events (v0.0.3+)

```jsx
<CommonCharts
  on={{
    click(e) {
      console.log(e);
    },
  }}
/>
```

### `getEchartsProxy` (v0.0.3+)

The value you receive is a **proxy** for the RJS instance (see [FAQ](#faq)).

```jsx
<CommonCharts
  getEchartsProxy={instance => {
    instance.showLoading();
  }}
/>
```

### `onLoad` / `onRender` (v0.1.2+)

String bodies run in the chart context (ES5 only, same rules as [Advanced usage](#advanced-usage)).

- **`onLoad`** — runs after the first `setOption`.
- **`onRender`** — runs after every `setOption`.

```jsx
<CommonCharts
  onLoad={`
    function () {
      console.log('after first setOption');
      myChart.group = 'chart';
      Echarts.connect('chart');
    }
  `}
  onRender={`
    function () {
      console.log('after each setOption');
    }
  `}
/>
```

### Focus / blur (v0.1.5)

```jsx
<CommonCharts
  option={lineOption as EChartsOption}
  blurAutoHideTooltip
  customStyle={{
    width: '100%',
    height: '300px',
    outline: isFocus ? '1px solid black' : 'none',
  }}
  onBlur={() => {
    console.log('onblur');
    setIsFocus(false);
  }}
  onFocus={() => {
    console.log('onfocus');
    setIsFocus(true);
  }}
/>
```

### On-demand ECharts plugins (v0.1.8)

```jsx
<CommonCharts
  option={{
    xAxis: {
      type: 'category',
      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
    },
    yAxis: { type: 'value' },
    series: [
      {
        data: [20, 80, 110, 150, 200, 320, 400],
        type: 'line',
        smooth: true,
      },
    ],
    visualMap: {
      show: false,
      type: 'piecewise',
      dimension: 1,
      pieces: [
        { gt: 0, lte: 100, color: '#1F65AE' },
        { gt: 100, lte: 300, color: '#40B243' },
        { gt: 300, color: '#FFD27F' },
      ],
    },
  }}
  usingPlugin
  usingPluginList={['rjs://echarts/lib/component/visualMap/installVisualMapPiecewise.js']}
/>
```

## Advanced usage

_Available since v0.1.0._

### String functions in `option`

You cannot pass real functions across the JS ↔ RJS bridge. Instead, pass a **string** whose content is an ES5 function body.

- No arrow functions.
- ES5 syntax only.
- For HTML tooltips, plain string concatenation is fine; the optional **`html()`** helper (exported from this package) is only a convenience.

**Globals available inside the evaluated string:**

| Name       | Description                         |
| :--------- | :---------------------------------- |
| `_`        | [lodash](https://www.lodashjs.com/) |
| `myChart`  | ECharts instance                    |
| `option`   | Current `option`                    |
| `Echarts`  | ECharts class                       |
| `dayjs`    | dayjs                               |
| `unit`     | `unit` prop                         |
| `theme`    | `theme` prop                        |
| _(custom)_ | Values from `injectVars`            |

```ts
// Manual HTML strings
{
  tooltip: {
    formatter: `function (params) {
      var text = _.reduce(params, function (acc, cur, idx) {
        var lineText = cur.marker + cur.seriesName + ": " + cur.value;
        return acc + "<div style='font-size: 10px'>" + lineText + "</div>";
      }, "");
      return "<div style='color: red;font-size: 10px;text-align: center'>" +
        dayjs(Date.now()).format("YYYY-MM-DD HH:mm:ss") + "</div>" + text;
    }`,
  },
}
```

```ts
// Optional: same tooltip using the html() helper (import html from this package)
{
  tooltip: {
    formatter: `function (params) {
        var text = _.reduce(params, function (acc, cur, idx) {
          return acc + ${html(
            'div',
            { style: { fontSize: '10px' } },
            "cur.marker + cur.seriesName + ':' + cur.value"
          )}
        }, '');
        return ${html(
          'div',
          {
            style: {
              color: 'red',
              fontSize: '10px',
              textAlign: 'center',
            },
          },
          'dayjs(Date.now()).format("YYYY-MM-DD HH:mm:ss")'
        )} + text;
      }`,
  },
}
```

### `usingPlugin` — beyond the default ECharts bundle

1. **Install ECharts** in the app that enables plugins:

   ```bash
   npm install echarts
   ```

2. **Enable on the component:**

   ```jsx
   <CommonCharts usingPlugin />
   ```

3. **Register RJS plugins** in `global.config.ts` via `usingPlugins`. Official plugin IDs are documented in the [plugin guide](https://developer.tuya.com/en/miniapp/develop/miniapp/framework/plugin/intro).

   `package.json` (example — match the version your toolchain expects, often **5.4.2** for the default plugin set):

   ```json
   {
     "echarts": "5.4.2"
   }
   ```

   ```ts
   {
     "usingPlugins": ["rjs://echarts"]
   }
   ```

4. **`usingPluginList` (v0.1.8+)** — If omitted or empty, **all** ECharts plugins load and the bundle grows. List only the RJS entry files you need.

   The built-in plugin set targets **ECharts 5.4.2**. For on-demand loading, keep your `echarts` version aligned. To override the bundled plugin version completely, add **`echarts/core`** to `usingPluginList`.

   Example — **visualMap (piecewise)** only:

   ```ts
   {
     "usingPlugins": ["rjs://echarts/lib/component/visualMap/installVisualMapPiecewise.js"]
   }
   ```

   ```tsx
   <CommonCharts
     option={/* ... */}
     usingPlugin
     usingPluginList={['rjs://echarts/lib/component/visualMap/installVisualMapPiecewise.js']}
   />
   ```

## FAQ

1. **Functions inside `option` do nothing**  
   JS → RJS carries data only. Use **string** function bodies (v0.1.0+). See [Advanced usage](#advanced-usage).

2. **Some event callback fields are `null`**  
   ECharts sometimes uses circular references or getters; the bridge serializes a safe subset.

3. **`getEchartsProxy` calls don’t return real results**  
   The instance lives in RJS; the JS side is a proxy for fire-and-forget calls and events.

4. **Can I use only merge helpers and render ECharts myself?**  
   Yes — `import { autoInject } from '@tuya-miniapp/common-charts/lib/core/inject.js'`. Rendering still goes through the mini program [plugin system](https://developer.tuya.com/en/miniapp/develop/miniapp/framework/plugin/intro).

5. **Disable merging completely**  
   Use `notMerge` (v0.0.4+). Same limitation: no real `function` values in props.

6. **Works on echarts.apache.org but not in the mini program**  
   Check `renderMode: 'html'` and any raw `function` in options; use string functions as in FAQ 1.