Giter Club home page Giter Club logo

react-heat-map's Introduction

HeatMap 日历热图

Buy me a coffee Build & Deploy Coverage Status npm version npm bundle size Open in Gitpod

A lightweight calendar heatmap react component built on SVG, customizable version of GitHub's contribution graph. Try it out on website example.

Install

# Not dependent on uiw.
npm install @uiw/react-heat-map --save

Basic Usage

Basic usage example, Please pay warning to the time setting.

⚠️ Example: 2016-01-11 -> 2016/01/11, Support Safari

import React from 'react';
import HeatMap from '@uiw/react-heat-map';

const value = [
  { date: '2016/01/11', count: 2 },
  { date: '2016/01/12', count: 20 },
  { date: '2016/01/13', count: 10 },
  ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx, content: '' })),
  { date: '2016/04/11', count: 2 },
  { date: '2016/05/01', count: 5 },
  { date: '2016/05/02', count: 5 },
  { date: '2016/05/04', count: 11 },
];

const Demo = () => {
  return (
    <div>
      <HeatMap
        value={value}
        weekLabels={['', 'Mon', '', 'Wed', '', 'Fri', '']}
        startDate={new Date('2016/01/01')}
      />
    </div>
  )
};

export default Demo

Set Color

Set the theme color style.

import React from 'react';
import HeatMap from '@uiw/react-heat-map';

const value = [
  { date: '2016/01/11', count:2 },
  { date: '2016/04/12', count:2 },
  { date: '2016/05/01', count:5 },
  { date: '2016/05/02', count:5 },
  { date: '2016/05/03', count:1 },
  { date: '2016/05/04', count:11 },
  { date: '2016/05/08', count:32 },
];

const Demo = () => {
  return (
    <HeatMap
      value={value}
      width={600}
      style={{ color: '#ad001d', '--rhm-rect-active': 'red' }}
      startDate={new Date('2016/01/01')}
      panelColors={{
        0: '#f4decd',
        2: '#e4b293',
        4: '#d48462',
        10: '#c2533a',
        20: '#ad001d',
        30: '#000',
      }}
    />
  )
};
export default Demo

Set Rect Style

Set the radius of the rect.

import React, { useState } from 'react';
import HeatMap from '@uiw/react-heat-map';

const value = [
  { date: '2016/01/11', count:2 },
  ...[...Array(17)].map((_, idx) => ({ date: `2016/01/${idx + 10}`, count: idx })),
  ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx })),
  { date: '2016/04/12', count:2 },
  { date: '2016/05/01', count:5 },
  { date: '2016/05/02', count:5 },
  { date: '2016/05/03', count:1 },
  { date: '2016/05/04', count:11 },
  { date: '2016/05/08', count:32 },
];

const Demo = () => {
  const [range, setRange] = useState(5)
  return (
    <div>
      <input type="range" min="0" max="5" step="0.1" value={range} onChange={(e) => setRange(e.target.value)} /> {range}
      <HeatMap
        value={value}
        width={600}
        style={{ '--rhm-rect': '#b9b9b9' }}
        startDate={new Date('2016/01/01')}
        legendRender={(props) => <rect {...props} y={props.y + 10} rx={range} />}
        rectProps={{
          rx: range
        }}
      />
    </div>
  )
};
export default Demo

Tooltip

A simple text popup tip.

import React from 'react';
import Tooltip from '@uiw/react-tooltip';
import HeatMap from '@uiw/react-heat-map';

const value = [
  { date: '2016/01/11', count:2 },
  ...[...Array(17)].map((_, idx) => ({ date: `2016/01/${idx + 10}`, count: idx, })),
  ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx, })),
  { date: '2016/04/12', count:2 },
  { date: '2016/05/01', count:5 },
  { date: '2016/05/02', count:5 },
  { date: '2016/05/03', count:1 },
  { date: '2016/05/04', count:11 },
  { date: '2016/05/08', count:32 },
];

const Demo = () => {
  return (
    <HeatMap
      value={value}
      width={600}
      startDate={new Date('2016/01/01')}
      rectRender={(props, data) => {
        // if (!data.count) return <rect {...props} />;
        return (
          <Tooltip placement="top" content={`count: ${data.count || 0}`}>
            <rect {...props} />
          </Tooltip>
        );
      }}
    />
  )
};
export default Demo

Show/Hide Legend

import React, { useState } from 'react';
import HeatMap from '@uiw/react-heat-map';

const value = [
  { date: '2016/01/11', count:2 },
  ...[...Array(17)].map((_, idx) => ({ date: `2016/01/${idx + 10}`, count: idx })),
  ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx })),
  { date: '2016/04/12', count:2 },
  { date: '2016/05/01', count:5 },
  { date: '2016/05/02', count:5 },
  { date: '2016/05/03', count:1 },
  { date: '2016/05/04', count:11 },
  { date: '2016/05/08', count:32 },
];

const Demo = () => {
  const [size, setSize] = useState(0)
  return (
    <div>
      <label style={{ userSelect: 'none' }}>
        <input
          type="checkbox"
          checked={size === 0}
          onChange={(e) => setSize(e.target.checked ? 0 : 12)}
        />
        {size === 0 ? ' Hide' : ' Show'} Legend
      </label>
      <HeatMap
        width={600}
        value={value}
        legendCellSize={size}
        startDate={new Date('2016/01/01')}
      />
    </div>
  )
};
export default Demo

Selected Rect

import React, { useState } from 'react';
import HeatMap from '@uiw/react-heat-map';

const value = [
  { date: '2016/01/11', count:2 },
  ...[...Array(17)].map((_, idx) => ({ date: `2016/01/${idx + 10}`, count: idx })),
  ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx })),
  { date: '2016/04/12', count:2 },
  { date: '2016/05/01', count:5 },
  { date: '2016/05/02', count:5 },
  { date: '2016/05/03', count:1 },
  { date: '2016/05/04', count:11 },
  { date: '2016/05/08', count:32 },
];

const Demo = () => {
  const [selected, setSelected] = useState('')
  return (
    <div>
      <HeatMap
        width={600}
        value={value}
        startDate={new Date('2016/01/01')}
        rectRender={(props, data) => {
          if (selected !== '') {
            props.opacity = data.date === selected ? 1 : 0.45
          }
          return (
            <rect {...props} onClick={() => {
              setSelected(data.date === selected ? '' : data.date);
            }} />
          );
        }}
      />
    </div>
  )
};
export default Demo

Props

Property Description Type Default
value Data to be displayed, required Array []
rectSize Grid size number 11
legendCellSize Size of the legend cells, in pixel. Value equal to 0 hide legend. number 11
startDate Start date Date new Date()
endDate End date Date -
space Interval between grid sizes number 2
monthPlacement position of month labels `'top' 'bottom'`
rectProps Grid node attribute settings React.SVGProps<SVGRectElement> 2
weekLabels Week display string[] ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
monthLabels Month display string[] ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
panelColors Backgroud color of active colors Record<number, string> { 0: '#EBEDF0', 8: '#7BC96F', 4: '#C6E48B', 12: '#239A3B', 32: '#196127' }
rectRender Single day block re-render <E = SVGRectElement>(data: E & { key: number }, valueItem: HeatMapValue & { date: string, column: number, row: number, index: number }) => React.ReactElement -
legendRender Single legend block re-render (props: React.SVGProps<SVGRectElement>) => React.ReactNode -

Development

development

Runs the project in development mode.

npm install
# Step 1, run first, listen to the component compile and output the .js file
# listen for compilation output type .d.ts file
npm run watch
# Step 2, development mode, listen to compile preview website instance
npm run start

production

Builds the app for production to the build folder.

npm run build
npm run doc

The build is minified and the filenames include the hashes. Your app is ready to be deployed!

Contributors

As always, thanks to our amazing contributors!

Made with github-action-contributors.

License

Licensed under the MIT License.

react-heat-map's People

Contributors

atompie avatar jaywcjlove avatar renovate-bot avatar renovate[bot] avatar sunlxy avatar zhangwei900808 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

react-heat-map's Issues

app-index.js:35 Warning: A props object containing a "key" prop is being spread into JSX: let props = {key: someKey, rx: ..., fill: ..., width: ..., height: ..., x: ..., y: ..., render: ..., value: ..., data-date: ..., data-index: ..., data-row: ..., data-column: ...}; <Rect {...props} /> React keys must be passed directly to JSX without using spread: let props = {rx: ..., fill: ..., width: ..., height: ..., x: ..., y: ..., render: ..., value: ..., data-date: ..., data-index: ..., data-row: ..., data-column: ...}; <Rect key={someKey} {...props} />

app-index.js:35 Warning: A props object containing a "key" prop is being spread into JSX:
let props = {key: someKey, rx: ..., fill: ..., width: ..., height: ..., x: ..., y: ..., render: ..., value: ..., data-date: ..., data-index: ..., data-row: ..., data-column: ...};
<Rect {...props} />
React keys must be passed directly to JSX without using spread:
let props = {rx: ..., fill: ..., width: ..., height: ..., x: ..., y: ..., render: ..., value: ..., data-date: ..., data-index: ..., data-row: ..., data-column: ...};
<Rect key={someKey} {...props} />

image

<HeatMap
              value={value}
              width={700}
              style={{
                color: "#fafafa",
              }}
              legendCellSize={0}
              rectSize={10}
              startDate={
                new Date(new Date().setDate(new Date().getDate() - 365))
              }
              endDate={new Date()}
              monthLabels={[
                "Jan",
                "Feb",
                "Mar",
                "Apr",
                "May",
                "Jun",
                "Jul",
                "Aug",
                "Sep",
                "Oct",
                "Nov",
                "Dec",
              ]}
              weekLabels={["", "Mon", "", "Wed", "", "Fri", ""]}
              panelColors={{
                0: "#202020",
                2: "#525252",
                4: "#71717a",
                10: "#a3a3a3",
                20: "#d4d4d4",
                30: "#e5e5e5",
              }}
              rectProps={{
                rx: 2.5,
              }}
            />

image

image

image

"@uiw/react-heat-map": "^2.2.1",

nextjs 14.

need help

Can we add an option to customise rect width and height?

Currently, I see the rect size is hardcoded to 11. Can we make changes to accept width and height in rectProps and use the same ?

Hardcoded values:
const { transform, gridNum = 0, startY = 0, panelColors = {}, initStartDate, space = 2, value = [], rectSize = 15, endDate, rectProps, rectRender } = props;

rectProps example:

rectProps={{
rx: 5,
width:'15',
height:'15',
}}

How to make a custom Tooltip

I am trying to make a custom Tooltip component instead of using the one you provided.

This is my code, but the squares are not rendering:

<HeatMap
        value={data}
        startDate={new Date(startDate)}
        endDate={new Date(endDate)}
        legendRender={(props) => <rect {...props} y={props.y + 5} rx="2" />}
        rectProps={{
          rx: 2,
        }}
        rectRender={(props, data) => {
          return (
         
            <rect
              {...props}
              onClick={() => {
                setSelected(
                  data.date === selected ? '' : `${data.date} ${data.count}`
                )
              }}
            />
          )
        }}
      />

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Other Branches

These updates are pending. To force PRs open, click the checkbox below.

  • chore(deps): update actions/checkout action to v4
  • chore(deps): update actions/setup-node action to v4
  • chore(deps): update peaceiris/actions-gh-pages action to v4

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/ci.yml
  • actions/checkout v3
  • actions/setup-node v3
  • peaceiris/actions-gh-pages v3
  • ncipollo/release-action v1
npm
core/package.json
  • @babel/runtime >=7.10.0
  • react >=16.9.0
  • react-dom >=16.9.0
package.json
  • @kkt/less-modules ^7.4.9
  • @kkt/ncc ^1.0.14
  • compile-less-cli ^1.8.13
  • husky ^8.0.3
  • kkt ^7.4.9
  • lerna ^8.0.0
  • lint-staged ^15.0.0
  • prettier ^3.0.0
  • react-test-renderer ^18.2.0
  • tsbb ^4.1.4
  • node >=16.0.0
www/package.json
  • @uiw/react-markdown-preview-example ^2.0.0
  • @uiw/react-tooltip ^4.21.11
  • @uiw/reset.css ^1.0.6
  • react ^18.2.0
  • react-dom ^18.2.0
  • @kkt/less-modules ^7.4.9
  • @kkt/raw-modules ^7.4.9
  • @kkt/scope-plugin-options ^7.4.9
  • @types/katex ^0.16.0
  • @types/react ^18.0.33
  • @types/react-dom ^18.0.11
  • kkt ^7.4.9
  • markdown-react-code-preview-loader ^2.1.2
  • source-map-explorer ^2.5.3

  • Check this box to trigger a request for Renovate to run again on this repository

Tooltip is not rendering correctly

I am trying to make use of this tool in following contrived example and the tool tip doesn't seem to be rendering correctly. Not sure what is wrong. Please suggest!

Screen.Recording.2024-04-01.at.4.11.53.pm.mov

package.json

{
  "name": "react-heatmap-demo",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@uiw/react-heat-map": "^2.2.2",
    "@uiw/react-tooltip": "^4.22.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

Demo.js

import React from 'react';
import Tooltip from '@uiw/react-tooltip';
import HeatMap from '@uiw/react-heat-map';

const value = [
  { date: '2016/01/11', count:2 },
  ...[...Array(17)].map((_, idx) => ({ date: `2016/01/${idx + 10}`, count: idx, })),
  ...[...Array(17)].map((_, idx) => ({ date: `2016/02/${idx + 10}`, count: idx, })),
  { date: '2016/04/12', count:2 },
  { date: '2016/05/01', count:5 },
  { date: '2016/05/02', count:5 },
  { date: '2016/05/03', count:1 },
  { date: '2016/05/04', count:11 },
  { date: '2016/05/08', count:32 },
];

const Demo = () => {
  return (
        <HeatMap
          value={value}
          startDate={new Date('2016/01/01')}
          rectRender={(props, data) => {
            if (!data.count) return <rect {...props} />;
            return (
              <Tooltip placement="top" content={`count: ${data.count || 0}`}>
                <rect {...props} />
              </Tooltip>
            );
          }}
        />
  )
};

export default Demo;

App.js

import Demo from './Demo';

function App() {
  return (
    <div
      style={{
        width: 900,
        height: 200,
        display: 'flex',
        margin: 'auto',
        marginTop: '100px',
      }}
    >
      <Demo />
    </div>
  );
}

export default App;

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Responsive Heatmap

Hey there :) I was wondering if there was any intention to make the heatmap responsive on all screen sizes?

On small screens, I wish the heatmap could crop itself to include the current day and then a number of columns on either side depending on how much room there is.

Thanks!

设置时间段出错

我设置下面时间段,可是显示的时候却显示了2019年的数据,以及开始时间和结束时间完全不正确。

startDate={new Date('2020/01/01')}
endDate={new Date('2020/12/31')}
rectRender={(props, data) => {
          // console.log('data=', data)
  return (
    <Tooltip mouseEnterDelay={0} mouseLeaveDelay={0} arrowPointAtCenter placement="top"
             title={`提交 ${data.count || 0} 次,${data.date}`}>
      <rect {...props} />
    </Tooltip>
  );
}}

image
image

in next.js error - ./node_modules/@uiw/react-heat-map/esm/style/index.css

error - ./node_modules/@uiw/react-heat-map/esm/style/index.css
Global CSS cannot be imported from within node_modules.
Read more: https://nextjs.org/docs/messages/css-npm
Location: node_modules/@uiw/react-heat-map/esm/index.js
TypeError: _interopRequireDefault is not a function
    at Object.<anonymous> (/Users/zhangwei/Workspace/com.awbeci/Seaurl/web/seaurl-webapp/node_modules/@uiw/react-heat-map/cjs/index.js:13:22)
    at Module._compile (internal/modules/cjs/loader.js:1072:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)
    at Module.load (internal/modules/cjs/loader.js:937:32)
    at Function.Module._load (internal/modules/cjs/loader.js:778:12)
    at Module.require (internal/modules/cjs/loader.js:961:19)
    at require (internal/modules/cjs/helpers.js:92:18)
    at Object.@uiw/react-heat-map (/Users/zhangwei/Workspace/com.awbeci/Seaurl/web/seaurl-webapp/.next/server/pages/[username].js:1296:18)
    at __webpack_require__ (/Users/zhangwei/Workspace/com.awbeci/Seaurl/web/seaurl-webapp/.next/server/webpack-runtime.js:33:42)
    at eval (webpack-internal:///./src/components/user/userHeatmap/index.js:14:77)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.