reactive-zrender

A zrender-based declarative design drawing library.

MIT License

Stars
0

ReactiveZRender

English |

Note: This is an experimental project!

A zrender-based declarative design drawing library.

The build tool is based on rollup and typescript, among other tools.

About

The goal of this project is to wrap a declarative, component-based drawing library based on zrender, borrowing design patterns from React and Vue.

Supports 2 component declaration modes:

  • JSON
const Group = RZRender.defineComponent({
  type: 'Group',
  render: function ({ x = 0, y = 0 } = {}, children) {
    const offset = (index) => 50 * index;

    return {
      type: 'group',
      props: {
        opts: {
          x,
          y,
        },
      },
      children,
    };
  },
});
  • Class
class Rect extends RZRender.Component {
  static type = 'Rect';
  type = Rect.type;

  triggerTooltip = true;

  handleClick() {
    alert('click rect');
  }

  handleMouseEnter() {
    this.state.backgroundColor = 'red';
    this.update();
  }

  handleMouseLeave(backgroundColor) {
    this.state.backgroundColor = backgroundColor;
    this.update();
  }

  render(
    {
      width = 10,
      height = 10,
      backgroundColor = 'black',
      animation,
      ...rest
    } = {},
    children,
  ) {
    console.log('render', this.state.backgroundColor);

    return {
      type: 'rect',
      props: {
        ref: this.state.ref,
        opts: {
          ...rest,
          shape: {
            width,
            height,
          },
          style: {
            text: '11',
            fill: this.state.backgroundColor,
          },
          onclick: () => this.handleClick(),
          onmouseover: () => this.handleMouseEnter(),
          onmouseout: () => this.handleMouseLeave(backgroundColor),
        },
        animation,
      },
      children,
    };
  }

  onBeforeMount(props) {
    // console.log('onBeforeMount', props);
    this.state = {
      ref: RZRender.createRef(),
      backgroundColor: props.backgroundColor || 'black',
    };
  }

  onMounted(props) {
    // console.log('onMounted', props);
    // console.log('state', this, this.state);
    // console.log(
    // 'metadata',
    // dynamicRelationGraphs.relationGraphs.getElementMetadata(this.state.ref.value)
    // );
  }

  onBeforeUpdate(props, prevProps) {
    // console.log('onBeforeUpdate', props, prevProps);
  }

  onUpdated(props) {
    // console.log('onUpdated', props);
  }

  onBeforeUnMount() {
    // console.log('onBeforeUnMount', this.props);
  }
}

The declared component should be known to the rendering engine, so the registration API needs to be called.

const Group = RZRender.registerComponent(Group);
const Rect = RZRender.registerComponent(Rect);

Then, you can render declaratively by calling the render() api.

const canvas = new RZRender.ReactiveZRender($dom.id);

canvas.render(
  RZRender.Root(
    {
      opts: {
        x: 10,
        y: 100,
        scaleX: 2,
      },
    },
    [
      {
        type: 'text',
        props: {
          opts: {
            style: {
              text: 'Hello',
            },
          },
        },
      },
      Rect({
        backgroundColor: 'red',
        animation: {
          when: [
            {
              time: 300,
              value: {
                x: 25,
              },
            },
            {
              time: 1e3,
              value: {
                x: 75,
              },
            },
          ],
        },
      }),
      Group(
        {
          x: 40,
          y: 40,
        },
        [
          {
            type: 'rect',
            props: {
              opts: {
                shape: {
                  width: 10,
                  height: 10,
                },
                style: {
                  fill: 'pink',
                },
                x: 100,
              },
            },
          },
          Rect({
            width: 30,
            height: 10,
            backgroundColor: 'orange',
          }),
        ],
      ),
      Rect({
        width: 30,
        height: 10,
        x: 100,
        y: 0,
        scaleX: 3,
      }),
    ],
  )
);

Yes, the code is ugly, and that's because there's no JSX, because JSX requires compiler support.

render() can be called multiple times, implementing a React-like Diff mechanism.

Bundle

Run npm run build, the following bundles will eventually be generated.

types/
build/
 bundle.esm.js
 bundle.esm.min.js
 bundle.umd.js
 bundle.umd.min.js

Will also generate the corresponding sourcemap file.

Development Guidelines

Scripts

  • Development mode

    npm run dev # or $ npm run esbuild-dev
    
  • Development mode (web server)

    npm run dev-serve # or $ npm run esbuild-dev-serve
    
  • Run test

    npm run test
    
  • Build bundle

    npm run build
    
  • Build Html documents from Markdown documents

    npm run build:docs-html
    

See the scripts field in package.json for more commands.

Git Commit Message Format

Adopt community commit format best practices:

# Before
git commit

# Now
npm run commit

This constraint relies on tools commitizen and commitlint provided by the community.

npm publish

The version management of this module adopts the specifications recommended by the community Semantic Versioning. Follow version changes and maintain a CHANGELOG.md(Learn why).

# Update version and generate changelog before publishing to npm repository
npm run release
# Or, preview
npm run release -- --dry-run

# Then publish to npm, if yes is not selected when auto-publishing to npm
npm publish # npm publish --access public

These jobs are done with the help of release-it tool provided by the community.

License

MIT.

Badges
Extracted from project README
Codacy Badge Commitizen friendly
Related Projects