پرتوپرتو

نقشه گرمایی (Heat Map)

کامپوننت نقشه گرمایی برای نمایش الگوی شدت فعالیت

معرفی

نقشه گرمایی (HeatMap) برای نمایش الگوی شدت داده‌ها در دو بعد استفاده می‌شود. این کامپوننت معمولاً برای نمایش فعالیت در طول روزهای هفته و ساعات روز، یا هر نوع داده دوبعدی دیگر مناسب است.

پیش‌نمایش

استفاده

import { PartoHeatMap, toPersianDigits } from '@parto-system-design/ui';

// نام روزهای هفته به فارسی
const persianWeekdays = ['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنج‌شنبه', 'جمعه'];

// ساخت داده برای 24 ساعت
const data = persianWeekdays.map(day => ({
  id: day,  // مهم: id باید نام روز باشد (نه عدد)
  data: Array.from({ length: 24 }, (_, hour) => ({
    x: toPersianDigits(String(hour).padStart(2, '0')) + ':۰۰',
    y: Math.floor(Math.random() * 100),
  })),
}));

<div className="h-[400px]">
  <PartoHeatMap
    data={data}
    locale="fa"
    margin={{ top: 60, right: 50, bottom: 60, left: 150 }}
    axisTop={{
      tickSize: 0,
      tickPadding: 8,
    }}
    axisLeft={{
      tickSize: 0,
      tickPadding: 12,
      legend: 'روز هفته',
      legendPosition: 'middle',
      legendOffset: -120,
    }}
    axisBottom={{
      legend: 'ساعات',
      legendPosition: 'middle',
      legendOffset: 45,
    }}
  />
</div>

پشتیبانی از چند زبانه

کامپوننت از prop locale برای تغییر زبان و تبدیل اعداد پشتیبانی می‌کند. نمایش همیشه LTR است (چون Nivo از RTL پشتیبانی نمی‌کند):

فارسی

<PartoHeatMap
  data={dataFa}
  locale="fa"  // اعداد فارسی + نام روزهای فارسی
  valueFormat={(value) => toPersianDigits(value)}
  axisLeft={{
    legend: 'روز هفته',
  }}
  axisBottom={{
    legend: 'ساعات',
  }}
/>

انگلیسی

<PartoHeatMap
  data={dataEn}
  locale="en"  // اعداد انگلیسی + نام روزهای انگلیسی
  axisLeft={{
    legend: 'Day of Week',
  }}
  axisBottom={{
    legend: 'Hours',
  }}
/>

تبدیل اعداد

برای تبدیل اعداد به فارسی از توابع کمکی استفاده کنید:

import { toPersianDigits } from '@parto-system-design/ui';

<PartoHeatMap
  data={data}
  dir="rtl"
  valueFormat={(value) => toPersianDigits(value)}
  axisBottom={{
    format: (value) => {
      const hour = parseInt(value.split(':')[0]);
      if (hour % 3 === 0) {
        return toPersianDigits(hour.toString().padStart(2, '0')) + ':' + toPersianDigits('00');
      }
      return '';
    }
  }}
/>

سفارشی‌سازی رنگ‌ها

می‌توانید از طرح‌های رنگی مختلف استفاده کنید:

<PartoHeatMap
  data={data}
  colors={{
    type: 'sequential',
    scheme: 'blues', // یا 'greens', 'reds', 'purples', etc.
  }}
/>

Tooltip سفارشی

<PartoHeatMap
  data={data}
  tooltip={({ cell }) => (
    <div className="bg-popover text-popover-foreground rounded-md shadow-lg px-3 py-2 border border-border">
      <div className="font-semibold">
        {cell.serieId} - {cell.data.x}
      </div>
      <div>
        فعالیت: <span className="font-bold">{cell.value}</span>
      </div>
    </div>
  )}
/>

Props مهم

Prop

Type

ویژگی‌ها

  • پشتیبانی دوزبانه: تبدیل خودکار اعداد و تاریخ‌ها به فارسی یا انگلیسی
  • RTL/LTR: پشتیبانی کامل از راست به چپ و چپ به راست
  • تم خودکار: رنگ‌ها به صورت خودکار با تم سیستم هماهنگ می‌شوند
  • Responsive: در تمام اندازه‌های صفحه به خوبی نمایش داده می‌شود
  • Interactive: قابلیت hover و نمایش tooltip
  • انیمیشن: انیمیشن‌های نرم و دلپذیر

نکات

  • همیشه نمودار را در یک div با ارتفاع مشخص قرار دهید
  • از margin مناسب برای نمایش محورها و legend استفاده کنید
  • برای نمایش بهتر، تعداد تیک‌های محورها را محدود کنید
  • در حالت RTL، از toPersianDigits برای تبدیل اعداد استفاده کنید
  • داده‌های x و y باید به صورت مرتب و منظم باشند

نکته مهم درباره داده‌ها

⚠️ توجه: مقدار id در هر ردیف داده باید نام روز باشد (مثلاً 'شنبه'، 'یکشنبه') نه عدد (۱، ۲، ۳). اگر از اعداد استفاده کنید، نام روزها به درستی نمایش داده نمی‌شود.

// ✅ درست
const data = [
  { id: 'شنبه', data: [...] },
  { id: 'یکشنبه', data: [...] },
];

// ❌ اشتباه
const data = [
  { id: 1, data: [...] },  // نباید عدد باشد
  { id: 2, data: [...] },
];

مثال کامل

'use client';

import { PartoHeatMap, toPersianDigits } from '@parto-system-design/ui';

// نام روزهای هفته به فارسی
const persianWeekdays = ['شنبه', 'یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنج‌شنبه', 'جمعه'];

const data = persianWeekdays.map(day => ({
  id: day,  // استفاده از نام روز
  data: Array.from({ length: 24 }, (_, i) => ({
    x: toPersianDigits(String(i).padStart(2, '0')) + ':۰۰',
    y: Math.floor(Math.random() * 100),
  })),
}));

export function ActivityHeatMap() {
  return (
    <div className="h-[500px]">
      <PartoHeatMap
        data={data}
        locale="fa"
        margin={{ top: 60, right: 50, bottom: 60, left: 150 }}
        valueFormat={(value) => toPersianDigits(value)}
        axisTop={{
          tickSize: 0,
          tickPadding: 8,
          format: (value) => {
            const hour = parseInt(value.split(':')[0]);
            return hour % 3 === 0 ? value : '';
          }
        }}
        axisLeft={{
          tickSize: 0,
          tickPadding: 12,
          legend: 'روز هفته',
          legendPosition: 'middle',
          legendOffset: -120,
        }}
        axisBottom={{
          tickSize: 0,
          tickPadding: 8,
          legend: 'ساعات',
          legendPosition: 'middle',
          legendOffset: 45,
          format: (value) => {
            const hour = parseInt(value.split(':')[0]);
            return hour % 3 === 0 ? value : '';
          }
        }}
        colors={{
          type: 'sequential',
          scheme: 'blues',
        }}
        borderRadius={2}
        borderWidth={3}
        enableLabels={false}
        animate={true}
        legends={[
          {
            anchor: 'bottom',
            translateY: 30,
            length: 400,
            thickness: 8,
            direction: 'row',
            title: 'شدت فعالیت',
          }
        ]}
      />
    </div>
  );
}

کاربردها

  • نمایش الگوی فعالیت کاربران در طول روز و هفته
  • تحلیل داده‌های سری زمانی
  • نمایش ماتریس همبستگی
  • تحلیل داده‌های دما یا آب و هوا
  • نمایش دیتاهای دوبعدی با شدت متفاوت