Skip to content

Frontend Konva Components

caasi Huang edited this page Dec 12, 2018 · 11 revisions

We uses react-konva to draw our map. It's a good library. However there are some limitations you should know before you use it.

  • React Konva will not reflow things for you.
  • React Konva Text will not give you the right text width when the font size is small.

So we created some components to help us handle those issues. We put them in src/components/Layout.

Layout Components

The Layout component is in src/component/Layout. It draws child components with a onResize event and emits its own dimension after everything has been rendered.

You can specify the flow direction with row or column and set the children gap with a margin attribute. Until someone implements a CSS-like box model.

It draws children recursively to simplify its state, but it's also ok to use a loop to do the same thing if anyone want to refactor it.

Text

By using refs, Text exposes Konva Text node width and height with an onResize event. So the parent component can understand children's dimension automatically.

Nothing

Layout children should handle the onResize event. So if you want to render nothing, you can't just pass a null to it. A Nothing component renders nothing and emits the zero width and zero height.

TextList (deprecated)

The TextList component has the same behavior like the Layout component. It has been implemented before the Layout component and it should be reimplement with the Layout component.

Selectable

The Selectable component intercepts mouse events(onMouseDown, onMouseUp, onMouseMove, onTap) and emits two new events: onSelect and onDeselect. And it's necessary to pass the current select state to it. So other Konva components can be free from having their own selection states.

Caret

The Caret component is just a reusable triangle component for many other components.

Map Components

The whole picture mode(like a mini-map) used to be a separated map in src/components/WholeMap. But now it has merged into the map components. So only Box, Card and CardList components are in the whole map directory. Other map components are in src/components/Map.

Box

The Box component draws a sense box on the map.

two map boxes

The simplified component looks like this:

<Selectable>
  <Group>
    <Header />
    { isDirty && <Circle /> }
    <Layout>
      {
        this.state.listDisplay === ListDisplay.COLLAPSED
          ? <Nothing />
          : <Layout>{ cards.map(card => <Card />) }</Layout>
      }
      <Toggle />
    </Layout>
  </Group>
</Selectable>

You can see how Selectable component wraps everything. The Layout component can be nested, because it also emits an onResize event.

It has three child compnonets:

  • Header shows box title, summary and tags.
  • Card shows a card inside a box.
  • Toggle draws a handler to expand box cards.

Card

A Card component draws a sense card on the map.

a map card

The simplified structure looks like this:

<Selectable>
  <Group>
    <Rect />
    { isDirty && <Circle /> }
    <Layout>
      <Creator />
      <Text text={summary} />
      <Text text={description} />
      <TagList />
    </Layout>
  </Group>
</Selectable>

It's also wrapped in a Selectable component and managed by a Layout component.

WholeMap Box

A whole-map box is a lightweight box showed in the whole picture mode.

a wholemap box

WholeMap Card

A whole-map card is a lightweight card showed in the whole picture mode.

a wholemap card

WholeMap CardList (the card hovering popup)

A whole-map card list popped up when you hover to a whole-map object.

a wholemap cardlist

Edge

An edge component draws a sense edge with its direction and content on the map.

an edge

EdgeDescription (the edge hovering popup)

An edge description popped up when you hover to an edge with content.

an edge description

Other Components

There are some other components shared by boxes and cards.

  • The Creator component shows the object creator and creating time.
  • The Tag component draws a tag and the TagList component manages their position like the Layout component, but with a different behavior - it receives a width as a bound and hides any overflowed tags.
You can’t perform that action at this time.