npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

wafer-map

v7.0.27

Published

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

Readme

English | 简体中文

wafer-map

SVG Map for React. It supports element (station / meeting room, etc.) state coloring, single / multiple selection, rubber-band selection, search marking, cross-floor path guidance, area jumping and legend exporting.

Table of Contents

Using

  • install

npm i wafer-map yarn add wafer-map

  • using in react
import React, { Component } from 'react';
import WaferMap from 'wafer-map';

class App extends Component {
     render() {
         const mapProps = {
             mapId: '1',
             componentWidth: 1920,
             componentHeight: 1080
         };

         return (
             <div className="App">
                 <WaferMap {...mapProps}/>
             </div>
         );
     }
}

notice: mapId is the only mark on the map.

Calling component methods with ref:

import React, { useRef } from 'react';
import WaferMap from 'wafer-map';

function App() {
    const mapRef = useRef(null);

    const handleClear = () => {
        // clear selected elements
        mapRef.current.clearSelectElement();
        // read the internal state
        console.log(mapRef.current.state.selectedEle);
    };

    return (
        <div style={{ width: 1920, height: 1080 }}>
            <WaferMap
                ref={mapRef}
                mapId="1"
                componentWidth={1920}
                componentHeight={1080}
                onClick={(element, selected) => console.log('single select', element, selected)}
                onClickError={(code, element) => console.warn('not clickable', code, element)}
            />
            <button onClick={handleClear}>Clear</button>
        </div>
    );
}

Features

| Feature | Description | Props | |---------|-------------|-------| | Base map | Renders an SVG base map or an image URL base map returned by the API, or a fully external base map | mapId, customBaseMap, mapKey | | Element rendering | Renders map elements (station / meeting room, etc.) with material SVG, supports rotation, state coloring and area binding | mapElementsList, elementsColor, showStateIds | | Element text | Multi-line text, ellipsis when overflowing, i18n, gender avatars, tooltip instead of text | noName, textColor, textShadow, isGenders, hideNameType, isTextToolTip | | Visibility / clickability | Controls visibility and clickability separately by element id, element type and element state | visibleElement, visibleType, visibleState, clickableElement, clickableType, clickableState | | Single / multiple selection | Single select replaces the current one; multiple select accumulates and renders a numbered icon | multiple, onClick, onSelect | | Rubber-band selection | Drag a rectangle to select elements in batch, with element type filtering | selectMode, selectableType, setSelectMode | | Selection echo | Echoes the selection from outside through selectedEle or selectedIds | selectedEle, selectedIds, setSelectedEleFinish | | Search mark | Highlights the target element by markId, accepts a single id or an id array | markId, markSvg, markStateId, markStateSvg | | Path guide | Same-floor / cross-floor path drawing, flowing dash animation, start & end icons, path layer on top | showPath, pathStyle, pathAnimType, pathEdges, guideFirstSvg, etc. | | Area jumping | Emits the target area mapId when clicking an area-bound element to switch maps | mapSpaceJump, reSetMapId | | Zoom / pan | Wheel, gesture and touch zoom & pan, with scale factor and pan boundary limits | mapZoom, mapMove, scaleFactorMax, panBoundary | | Center & zoom element | Centers and zooms an element after clicking | clickToCenter, centerElement, centerEleRate | | Tooltip | Displays a custom SVG tooltip when hovering an element | tooltipContent, defaultTooltipKey | | Custom render | Custom rendering before / after element text, extra svg, legend | elementRenderHandle, elementRenderTextAfterHandle, AppendSvg, legendRender | | Multiple maps | Supports rendering two maps at the same time | isDoubleMap |

Props

Basic

| Prop | default value | is required | description | |------|---------------|-------------|-------------| | mapId | | true | map id, the only mark on the map | | componentWidth | 1920 | false | Map container width | | componentHeight | 1080 | false | Map container height | | background | #ddd | false | Map container background color | | SVGBackground | #fff | false | SVG background color | | SVGStyle | {} | false | SVG element style | | style | {} | false | Outer container style | | mapExtraProps | | false | Extra props, currently used to add extra width / height to leave blank margins, e.g. { width: 100, height: 100 } | | defaultPath | vsk/ | false | API path prefix | | requestPrefix | '' | false | Request URL prefix | | signatureKey | null | false | Signature key | | restfulSignature | false | false | Controls whether to sign or not, when set to true the signature key must be valid | | lang | cn | false | Language, cn Chinese, en English, tw Traditional Chinese | | customBaseMap | null | false | External base map data, the base map API will not be requested when provided | | reloadMap | false | false | Reload the map | | reloadFinish | () => {} | false | Callback when reloading the map is finished |

Zoom & Pan

| Prop | default value | is required | description | |------|---------------|-------------|-------------| | mapZoom | true | false | Whether the map can be zoomed | | mapMove | true | false | Whether the map can be moved | | touchable | true | false | Touch control | | isTouchDevice | false | false | Whether it is an all-in-one device | | windowsTouchSupport | false | false | Whether Windows touch screen is supported | | scaleFactorMax | undefined | false | Maximum amount of scale a user can zoom in to, e.g. 5 | | scaleFactorMin | undefined | false | Minimum amount of scale a user can zoom out of, e.g. 0.5 | | zoomRate | 1 | false | Map fit magnification | | panBoundary | false | false | Pan boundary limit.false no limit; undefined keeps the original limit (bufferX = centerX / 2); 'auto' calculates automatically, keeping 1/10 outside the viewport; a number uses centerX / panBoundary as the boundary buffer | | fitWidthOrHeight | '' | false | Fit by height or width (not effective in the current version) |

Element Visibility & Clickability

| Prop | default value | is required | description | |------|---------------|-------------|-------------| | visibleElement | undefined | false | Displayable collection of element ids, no restriction when empty or not passed | | visibleType | undefined | false | Displayable collection of element types, no restriction when empty or not passed | | visibleState | undefined | false | Displayable collection of element states, no restriction when empty or not passed | | clickableElement | undefined | false | Clickable collection of element ids, no restriction when empty or not passed | | clickableType | undefined | false | Clickable collection of element types, no restriction when empty or not passed | | clickableState | undefined | false | Clickable collection of element states, no restriction when empty or not passed | | isNotAllowedEle | false | false | Shows a not-allowed cursor for elements that cannot be clicked | | noName | false | false | Element names are not displayed on the map | | hideNameType | [] | false | Material types whose content is hidden | | elementsColor | [] | false | Set color according to element id, data structure: [{ id: 1, color: '#fff' }, {}] | | showStateIds | [] | false | Display different states of different elements, data structure: [{ id: 1, state: 'XX', color: '#fff', text: '' }, {}] | | isShowSvgDefaultColor | false | false | Whether to display the default color of elements without material | | textColor | '' | false | Element text color | | textShadow | false | false | Whether the element text has a shadow, slight performance cost when there are many elements | | isGenders | false | false | Display male and female outsourcing type avatars before the name of the material | | isShowArea | false | false | Whether to display the map area (depends on areaAge returned by the API) |

Selection

| Prop | default value | is required | description | |------|---------------|-------------|-------------| | multiple | false | false | Multiple switch | | selectMode | false | false | Whether rubber-band selection is enabled | | setSelectMode | () => {} | false | Reset the rubber-band selection state | | selectableType | '' | false | Batch operation type, used to restrict multi-select to the same element type | | selectedEle | [] | false | Selected element collection, used to echo the selection from outside | | setSelectedEleFinish | () => {} | false | Callback after echoing the selected elements, the parent should clear the echoed collection afterwards | | selectedIds | [] | false | Selected element id collection, used to echo the selection from outside | | deleteId | '' | false | Delete the selected element id | | deleteFinish | () => {} | false | Callback after deleting the selected element | | onClick | () => {} | false | Single select callback, arguments (element, selected) | | onSelect | () => {} | false | Multi-select callback, returns all selected objects every time | | onClickError | () => {} | false | Callback for a failed selection, arguments (code, element) | | fixedSelectedIcon | false | false | Whether the selected icon keeps a fixed size and does not scale with the base map, false follows the base map |

Marks & Icons

| Prop | default value | is required | description | |------|---------------|-------------|-------------| | markId | '' | false | The element id that needs to be tagged, such as '1'; if multiple, use string array format, such as ['1', '2'] | | markSvg | undefined | false | Search anchor or mark icon, this icon contains only elements inside svg, without svg tags | | selectedSvg | undefined | false | Selected icon, this icon contains only elements inside svg, without svg tags | | markStateId | [] | false | Tagged element state id collection | | markStateSvg | undefined | false | Tagged element state svg icon function | | pathStartSvg | undefined | false | Guide start icon, this icon contains only elements inside svg, without svg tags | | pathEndSvg | undefined | false | Guide end icon, this icon contains only elements inside svg, without svg tags |

Note: when markId and the selected state hit the same element, markSvg is used in single select mode and selectedSvg is used in multiple select mode.

Note: the location icon scale (iconScale) and the multiple-select index color (iconOrderColor) are read from the base map API response, at the same level as icon / iconUrl, and are not passed as props.

Path Guide & Navigation

| Prop | default value | is required | description | |------|---------------|-------------|-------------| | showPath | false | false | Display the guide path | | pathStyle | {} | false | Guide path style, style setting reference svg element attributes | | pathExStyle | {} | false | Style of the second guide path on the same floor | | pathAnimType | undefined | false | Guide path animation type: 1 straight line, 2 flowing dash, 3 dash + flowing arrow, 4 straight line + flowing arrow. Takes precedence over colors.guidesStyle returned by the API | | pathEdges | null | false | Path point collection, each item is { x1, y1, x2, y2 }. When provided, the path is drawn from these points and overrides the path returned by the API | | pathLineKey | { start: 'lineStart', end: 'lineEnd', mid: 'lineMid' } | false | Field mapping of the guide path | | pathLevelUp | false | false | Whether the navigation layer is on top | | isStartGuide | false | false | Whether to start navigation | | refreshGuide | -1 | false | Whether to refresh the navigation | | guideFirstSvg | undefined | false | First navigation segment svg icon function, current floor | | guideSecondSvg | undefined | false | Second navigation segment svg icon function, displayed on the lower map by design. Should check going up or down and modify the path start / end points | | guideThirdSvg | undefined | false | Third navigation segment svg icon function, target floor | | guideFirstSvgEx | undefined | false | The second navigation of the current floor | | handleGetPathInfo | () => {} | false | Path callback method | | appGetPathByUrl | false | false | Whether the mobile side gets the path info from the API | | mapSpaceJump | false | false | Whether the area jumping switch is enabled | | reSetMapId | () => {} | false | Callback of the target area mapId of an area-bound element | | isDoubleMap | false | false | Whether it is a double map |

Data Source

| Prop | default value | is required | description | |------|---------------|-------------|-------------| | mapDataSource | false | false | Element source, false means fetched inside the component, true means passed from outside | | mapElementsList | [] | false | Map element collection. It cannot be empty when mapDataSource is true | | mapKey | { url: 'baseMapUrl' } | false | Field mapping of the map | | onElementsLoad | () => {} | false | Callback when the material loading is finished |

Custom Render & Legend

| Prop | default value | is required | description | |------|---------------|-------------|-------------| | tooltipContent | () => {} | false | Content and style of the tooltip when hovering an element | | defaultTooltipKey | '' | false | You can customize the default key in the bubble, such as orgName | | isTextToolTip | false | false | Whether the element text is displayed with a tooltip | | textToolTipList | [] | false | List of the element text tooltip | | textToolTipRender | undefined | false | Render method of the whole element text tooltip | | elementRenderHandle | undefined | false | Custom handling when rendering an element (before the text) | | elementRenderTextAfterHandle | undefined | false | Custom handling when rendering an element (after the text) | | AppendSvg | undefined | false | Extra svg to append, mainly used to display map areas | | centerElement | {} | false | Set the central material | | centerEleRate | 1 | false | Set the center material magnification | | clickToCenter | false | false | If set true, clicking an element will center it and zoom in | | legendList | [] | false | Legend added when exporting PDF, data structure [{ color, text }] | | legendRender | undefined | false | Legend render function | | getSvgDom | () => {} | false | Callback to get the viewerDOM of the SVG |

Methods (via ref)

Get the component instance through ref and then call the following methods or read the internal state:

| Method / Property | props | return | description | |------|-------|--------|-------------| | fitToViewerReSet | | | Fit the map zoom and position to the current container again | | clearSelectElement | | | Clears the selected set of elements | | state | | object | Internal state object of the component, see the table below |

Fields of the state object:

| Field | description | |-------|-------------| | mapElementState | Element collection on the map | | baseMap | Base map info (width, height, base map content, area, etc.) | | selectedEle | Currently selected elements | | showTip / tipObj | Tooltip visibility and tooltip data | | path / start / end | Path, start point and end point of the first guide line | | path2 / start2 / end2 | Path, start point and end point of the second guide line | | mapId | Current map id | | rateZoom | Current zoom rate | | locationSvgMark | Mark icon data | | mapColorSet | Map color config | | allElements | All element materials | | selectedCenter | Start point of the rubber-band selection | | selectedArea | Range of the rubber-band selection | | tool | Current tool type | | svgValue | Map view state | | zoom | Current zoom value |

onClickError Error Code

| code | description | |------|-------------| | 100 | Selected elements that cannot be displayed | | 101 | Selected elements that the ID cannot be selected | | 102 | Selected elements that the types cannot be selected | | 103 | Selected elements that the states cannot be selected | | 104 | Multi-select mode cannot select different types at the same time | | 105 | Multi-select mode without a valid batch operation type (selectableType) |

Examples

1. Multiple selection + rubber-band selection

<WaferMap
    mapId="1"
    componentWidth={1920}
    componentHeight={1080}
    multiple
    selectMode={selectMode}
    selectableType="station"
    setSelectMode={setSelectMode}
    onSelect={(list) => console.log('selected', list)}
/>

2. Search mark

<WaferMap
    mapId="1"
    markId={['1', '2']}
    markSvg={() => (
        <circle cx="0" cy="0" r="8" fill="#FFC13D" />
    )}
/>

3. Guide path

<WaferMap
    mapId="1"
    showPath
    pathAnimType={3}
    pathStyle={{ stroke: '#00ba00', strokeWidth: 3 }}
    pathStartSvg={() => <circle r="6" fill="#00ba00" />}
    pathEndSvg={() => <circle r="6" fill="#ff0000" />}
/>

4. External element data

<WaferMap
    mapId="1"
    mapDataSource
    mapElementsList={elements}
    visibleElement={visibleList}
    onElementsLoad={(list) => console.log('elements loaded', list)}
/>

tooltipContent example of use

tipObj is the object returned by this method. When tooltipContent is null, the tooltip shows the defaultTooltipKey value; if defaultTooltipKey is empty or missing, the tooltip is not displayed.

 tooltipContent = (tooltipObj)=>{
    const radius = 5;
    const width = 150;
    const height = 45;
    return (
        <g>
          <path
              fill="black"
              fillOpacity="0.7"
              d={`M0 0 l10 10 h ${width / 2 - 10 - radius}
          a ${radius} ${radius} 90 0 1 ${radius} ${radius} v ${height}
          a ${radius} ${radius} 90 0 1 ${-radius} ${radius} h ${2 * radius - width}
          a ${radius} ${radius} 90 0 1 ${-radius} ${-radius} v ${-height}
          a ${radius} ${radius} 90 0 1 ${radius} ${-radius} h ${width / 2 - 10 - radius} Z`}
          />
          <text
              dy="23"
              dominantBaseline="text-before-edge"
              fill="white"
              textAnchor="middle"
          >
            {tooltipObj.orgName}
          </text>
        </g>
    )
  }

The tipObj object needs to get data from the getMapStationList method and store it into the contentObj object to get the complete object:

 *getMapStationList({ payload }, { call, put, select }) {
      const { locationId } = yield select(state => state.swsCommon);
      const param = payload || { locationId };
      const { info } = yield select(state => state.login);
      if (info && info.tenant_id) {
        param.domainId = info.tenant_id;
      }
      const result = yield call(service.getMapStationList, { payload: param });
      if (result && result.code === 0) {
        const onMapList = [];
        const visibleList = [];
        result.data.forEach(item => {
          if (item && item.elementId) {
            visibleList.push(item.elementId);
            onMapList.push({
              id: item.elementId,
              state: item.statusCode,
              color: item.statusColor,
              text: item.userNames || item.stationNum,
              contentObj: item
            });
          }
        });

        yield put({
          type: 'saveOrUpdateData',
          payload: {
            mapStationList: result.data,
            stationsOnMap: onMapList,
            visibleList,
          },
        });
      }
    }   

Publish

yarn build
yarn publish