من با نوع جدیدی از نمودار برای تجسم داده ها به نام a نمودار رادار زمانی که یک پروژه آن را درخواست کرد. برای من جدید بود، اما ایده این است که یک دایره دایره‌ای دوبعدی با نمودارهایی وجود دارد که در اطراف نمودار می‌چرخند. به جای محورهای ساده X و Y، هر نمودار در نمودار رادار، محور خاص خود است و نقطه ای را بین لبه بیرونی دایره و مرکز آن مشخص می کند. نمودارها نوعی دسته را نشان می دهند، و هنگام اتصال آنها به یکدیگر، مانند رئوس هستند که شکل هایی را برای کمک به دیدن رابطه مقادیر دسته تشکیل می دهند، نه کاملاً بر خلاف بردارهای یک SVG.

نمودار مقایسه ابرخازن.
نمودار مقایسه ابرخازن. (منبع تصویر: ناسا) (پیش نمایش بزرگ)

گاهی اوقات نمودار رادار a نامیده می شود نمودار عنکبوتی، و فهمیدن دلیل آن آسان است. محورهایی که به سمت بیرون جریان دارند با کرت های متصل شده تلاقی می کنند و ظاهری شبیه به شبکه را تشکیل می دهند. بنابراین، اگر شما حواس اسپایدی در نگاه اول گزگز می کردند، می دانید چرا.

شما از قبل می دانید که با این به کجا می رویم: ما با هم یک نمودار رادار می سازیم! ما از ابتدا با چیزی جز HTML، CSS و جاوا اسکریپت کار نمی کنیم. اما قبل از اینکه به آنجا برویم، لازم است به چند نکته در مورد نمودارهای رادار اشاره کنیم.

اولا، شما این کار را نمی کنید دارند برای ساختن آنها از ابتدا Chart.js و D3.js با رویکردهای راحت که فرآیند را بسیار ساده می کند، به راحتی در دسترس هستند. از آنجایی که من فقط به یک نمودار برای پروژه نیاز داشتم، تصمیم گرفتم از کتابخانه استفاده نکنم و چالش ساخت آن را خودم به عهده گرفتم. من چیز جدیدی یاد گرفتم و امیدوارم شما هم همینطور!

دوم، وجود دارد در مورد استفاده از نمودارهای رادار هشدار می دهد برای تجسم داده ها اگرچه آنها واقعاً مؤثر هستند، اما خواندن آنها در هنگام جمع شدن چندین سری دشوار است. روابط بین نمودارها تقریباً به اندازه نمودارهای میله ای قابل رمزگشایی نیستند. ترتیب دسته‌ها در اطراف دایره بر شکل کلی تأثیر می‌گذارد و مقیاس بین سری‌ها باید برای نتیجه‌گیری سازگار باشد.

همه اینها گفته شد، بیایید به داخل شیرجه بزنیم و دستمان را با نمودارهای داده ای بچسبانیم.

اجزاء

چیزی که من بلافاصله در مورد نمودارهای رادار دوست دارم این است که آنها ذاتاً هندسی هستند. اتصال نمودارها مجموعه ای از زاویه ها را ایجاد می کند که اشکال چند ضلعی را تشکیل می دهد. طرفین خطوط مستقیم هستند. و CSS برای کار با چند ضلعی‌ها کاملاً فوق‌العاده است، با توجه به اینکه ما آن را داریم CSS polygon() تابع برای ترسیم آنها با اعلام هر تعداد نقطه که در آرگومان های تابع نیاز داریم.

ما با یک نمودار پنج ضلعی شکل با پنج دسته داده شروع خواهیم کرد.

قلم را ببینید [Radar chart (Pentagon) [forked]](https://codepen.io/smashingmag/pen/abMaEyo) توسط پریتی سام.

قلم را ببینید نمودار رادار (پنتاگون) [forked] توسط پریتی سام.

وجود دارد سه جزء قبل از اینکه روی استایلینگ کار کنیم باید در HTML ایجاد کنیم. اینها خواهند بود:

  1. شبکه ها: اینها محورهایی را که نمودارها بر روی آنها ترسیم می شوند ارائه می کنند. این تار عنکبوت این دسته است.
  2. نمودارها: اینها چند ضلعی هایی هستند که با مختصات هر نمودار داده قبل از رنگ آمیزی آنها ترسیم می کنیم.
  3. برچسب ها: متنی که دسته بندی ها را در امتداد محورهای نمودارها مشخص می کند.

در اینجا تصمیم گرفتم آن را در HTML بیاورم:

<!-- GRIDS -->
<div class="wrapper">
  <div class="grids polygons">
    <div></div>
  </div>
  <div class="grids polygons">
    <div></div>
  </div>
  <div class="grids polygons">
    <div></div>
  </div>
</div>

<!-- GRAPHS -->
<div class="wrapper">
  <div class="graphs polygons">
    <div><!-- Set 1 --></div>
  </div>
  <div class="graphs polygons">
    <div><!-- Set 2 --></div>
  </div>
  <div class="graphs polygons">
    <div><!-- Set 3 --></div>
  </div>
  <!-- etc. -->
</div>

<!-- LABELS -->
<div class="wrapper">
  <div class="labels">Data A</div>
  <div class="labels">Data B</div>
  <div class="labels">Data C</div>
  <div class="labels">Data D</div>
  <div class="labels">Data E</div>
  <!-- etc. -->
</div>

من مطمئن هستم که می توانید نشانه گذاری را بخوانید و ببینید چه اتفاقی می افتد، اما ما سه عنصر اصلی داریم (.wrapper) که هر کدام دارای یکی از اجزای اصلی هستند. والد اول شامل .grids، والد دوم شامل .graphs، و والد سوم شامل .labels.

سبک های پایه

ما با تنظیم چند متغیر رنگی شروع می کنیم که می توانیم از آنها برای پر کردن موارد در حین حرکت استفاده کنیم:

:root {
  --color1: rgba(78, 36, 221, 0.6); /* graph set 1 */
  --color2: rgba(236, 19, 154, 0.6); /* graph set 2 */
  --color3: rgba(156, 4, 223, 0.6); /* graph set 3 */
  --colorS: rgba(255, 0, 95, 0.1); /* graph shadow */
}

سفارش بعدی ما ایجاد طرح است. CSS Grid یک رویکرد محکم برای این است زیرا می‌توانیم هر سه آیتم گرید را تنها در چند خط با هم روی شبکه قرار دهیم:

/* Parent container */
.wrapper { display: grid; }

/* Placing elements on the grid */
.wrapper > div {
  grid-area: 1 / 1; /* There's only one grid area to cover */
}

بیایید جلو برویم و اندازه ای را روی آیتم های شبکه تنظیم کنیم. من از یک مقدار طول ثابت استفاده می کنم 300px، اما می توانید از هر مقداری که نیاز دارید استفاده کنید و اگر قصد استفاده از آن را در مکان های دیگر دارید، آن را تغییر دهید. و به جای اعلام یک ارتفاع صریح، بیایید بار محاسبه ارتفاع را بر روی CSS با استفاده از aspect-ratio برای تشکیل مربع های کامل

/* Placing elements on the grid */
.wrapper div {
  aspect-ratio: 1 / 1;
  grid-area: 1 / 1;
  width: 300px;
}

ما هنوز چیزی نمی بینیم. ما باید چیزها را در موارد زیر رنگ کنیم:

/* ----------
Graphs
---------- */
.graphs:nth-of-type(1) > div { background: var(--color1); }
.graphs:nth-of-type(2) > div { background: var(--color2); }
.graphs:nth-of-type(3) > div { background: var(--color3); }

.graphs {
  filter: 
    drop-shadow(1px 1px 10px var(--colorS))
    drop-shadow(-1px -1px 10px var(--colorS))
    drop-shadow(-1px 1px 10px var(--colorS))
    drop-shadow(1px -1px 10px var(--colorS));
}

/* --------------
Grids 
-------------- */
.grids {
  filter: 
    drop-shadow(1px 1px 1px #ddd)
    drop-shadow(-1px -1px 1px #ddd)
    drop-shadow(-1px 1px 1px #ddd)
    drop-shadow(1px -1px 1px #ddd);
    mix-blend-mode: multiply;
}

.grids > div { background: white; }

صبر کن! باید عرض ها را روی شبکه ها و چند ضلعی ها تنظیم کنیم تا شکل بگیرند:

.grids:nth-of-type(2) { width: 66%; }
.grids:nth-of-type(3) { width: 33%; }

/* --------------
Polygons 
-------------- */
.polygons { place-self: center; }
.polygons > div { width: 100%; }

از آنجایی که ما قبلاً اینجا هستیم، می‌خواهم برچسب‌ها را به صورت ضخیم قرار دهم و به آنها عرض بدهم:

/* --------------
Labels
-------------- */
.labels:first-of-type { inset-block-sptart: -10%; }

.labels {
  height: 1lh;
  position: relative;
  width: max-content;
}

ما هنوز نمی‌توانیم ببینیم چه اتفاقی می‌افتد، اما اگر به طور موقت مرزهایی را در اطراف عناصر ترسیم کنیم، می‌توانیم ببینیم.

قلم را ببینید [Radar chart layout [forked]](https://codepen.io/smashingmag/pen/QWoVamB) توسط پریتی سام.

قلم را ببینید طرح نمودار رادار [forked] توسط پریتی سام.

همه با هم، تا اینجا خیلی عالی به نظر نمی رسد. اساساً، ما یک سری شبکه‌های همپوشانی داریم که به دنبال آن نمودارهای کاملاً مربعی درست روی هم چیده شده‌اند. برچسب ها نیز در گوشه ای خاموش هستند. ما هنوز چیزی ترسیم نکرده‌ایم، بنابراین فعلاً من را آزار نمی‌دهد، زیرا ما عناصر HTML مورد نیاز خود را داریم، و CSS از نظر فنی در حال ایجاد طرح‌بندی است که باید با شروع رسم نقاط و ترسیم چند ضلعی‌ها، گرد هم بیاید.

به طور خاص:

  • این .wrapper عناصر به عنوان کانتینرهای CSS Grid نمایش داده می شوند.
  • فرزندان مستقیم از .wrapper عناصر هستند divs دقیقا در همان قرار داده شده است grid-area. این باعث می شود که آنها یکی را درست روی دیگری قرار دهند.
  • این .polygons متمرکز هستند (place-self: center).
  • کودک divدر .polygons تمام عرض را بگیرد (width:100%).
  • تک تک div است 300px پهن و مربع با یک به یک aspect-ratio.
  • ما به صراحت موضع نسبی را در مورد آن اعلام می کنیم .labels. به این ترتیب، هنگامی که ما شروع به کار در جاوا اسکریپت می کنیم، می توانند به طور خودکار در موقعیت قرار گیرند.

بقیه؟ به سادگی برخی از رنگ ها را به عنوان پس زمینه اعمال کنید و سایه ها را رها کنید.

محاسبه مختصات پلات

نگران نباشید. ما در مورد هندسه چند ضلعی وارد یک بررسی عمیق نمی شویم. در عوض، اجازه دهید نگاهی گذرا به معادلاتی بیندازیم که برای محاسبه مختصات رئوس هر چند ضلعی استفاده می کنیم. برای استفاده از کدی که می‌خواهیم بنویسیم، لازم نیست این معادلات را بدانید، اما نگاه کردن به زیر کاپوت برای دیدن اینکه چگونه با هم ترکیب می‌شود، ضرری ندارد.

x1 = x + cosθ1 = cosθ1 if x=0
y1 = y + sinθ1 = sinθ1 if y=0
x2 = x + cosθ2 = cosθ2 if x=0
y2 = y + sinθ2 = sinθ2 if y=0
etc.

x, y = center of the polygon (assigned (0, 0) in our examples)

x1, x2… = x coordinates of each vertex (vertex 1, 2, and so on)
y1, y2… = y coordinates of each vertex
θ1, θ2… = angle each vertex makes to the x-axis

می توانیم فرض کنیم که 𝜃 است 90deg (یعنی 𝜋/2) از آنجایی که یک راس همیشه می تواند درست در بالا یا پایین مرکز قرار گیرد (یعنی، داده A در این مثال). بقیه زاویه ها را می توان به صورت زیر محاسبه کرد:

n = number of sides of the polygon

𝜃1 = 𝜃0 + 2𝜋/𝑛 = 𝜋/2 + 2𝜋/𝑛
𝜃2 = 𝜃0 + 4𝜋/𝑛 = 𝜋/2 + 4𝜋/𝑛
𝜃3 = 𝜃0 + 6𝜋/𝑛 = 𝜋/2 + 6𝜋/𝑛
𝜃3 = 𝜃0 + 8𝜋/𝑛 = 𝜋/2 + 8𝜋/𝑛
𝜃3 = 𝜃0 + 10𝜋/𝑛 = 𝜋/2 + 10𝜋/𝑛

مسلح با این زمینه، ما می توانیم برای خود حل کنیم x و y ارزش های:

x1 = cos(𝜋/2 + 2𝜋/# sides)
y1 = sin(𝜋/2 + 2𝜋/# sides)
x2 = cos(𝜋/2 + 4𝜋/# sides)
y2 = sin(𝜋/2 + 4𝜋/# sides)
etc.

تعداد اضلاع بستگی به تعداد کرت های مورد نیاز ما دارد. ما از قبل گفتیم که این یک شکل پنج ضلعی است، بنابراین در این مثال خاص با پنج ضلع کار می کنیم.

x1 = cos(𝜋/2 + 2𝜋/5)
y1 = sin(𝜋/2 + 2𝜋/5)
x2 = cos(𝜋/2 + 4𝜋/5)
y2 = sin(𝜋/2 + 4𝜋/5)
etc.

ترسیم چند ضلعی با جاوا اسکریپت

اکنون که ریاضی به حساب می‌آید، آنچه را که برای شروع کار در جاوا اسکریپت به منظور ترسیم مختصات، اتصال آنها به یکدیگر و نقاشی در چند ضلعی‌های حاصل نیاز داریم، داریم.

برای سادگی، ما آن را ترک می کنیم Canvas API از این کار خارج شده و در عوض از عناصر معمولی HTML برای رسم نمودار استفاده کنید. با این حال، می توانید از ریاضیات ذکر شده در بالا و منطق زیر به عنوان پایه ای برای ترسیم چند ضلعی ها در هر زبان، چارچوب یا API که ترجیح می دهید استفاده کنید.

خوب، بنابراین ما سه نوع مؤلفه برای کار داریم: شبکه‌ها، نمودارها و برچسب‌ها. ما با شبکه شروع می کنیم و از آنجا به بالا کار می کنیم. در هر مورد، من به سادگی کد را وارد می کنم و توضیح می دهم که چه اتفاقی می افتد.

ترسیم شبکه

// Variables
let sides = 5; // # of data points
let units = 1; // # of graphs + 1
let vertices = (new Array(units)).fill(""); 
let percents = new Array(units);
percents[0] = (new Array(sides)).fill(100); // for the polygon's grid component
let gradient = "conic-gradient(";
let angle = 360/sides;

// Calculate vertices
with(Math) { 
  for(i=0, n = 2 * PI; i < sides; i++, n += 2 * PI) {
    for(j=0; j < units; j++) {
      let x = ( round(cos(-1 * PI/2 + n/sides) * percents[j][i]) + 100 ) / 2; 
      let y = ( round(sin(-1 * PI/2 + n/sides) * percents[j][i]) + 100 ) / 2; 
      vertices[j] += `${x}% ${y} ${i == sides - 1 ? '%':'%, '}`;
  }
  gradient += `white ${
    (angle * (i+1)) - 1}deg,
    #ddd ${ (angle * (i+1)) - 1 }deg,
    #ddd ${ (angle * (i+1)) + 1 }deg,
    white ${ (angle * (i+1)) + 1 }deg,
  `;}
}

// Draw the grids
document.querySelectorAll('.grids>div').forEach((grid,i) => {
  grid.style.clipPath =`polygon(${ vertices[0] })`;
});
document.querySelector('.grids:nth-of-type(1) > div').style.background =`${gradient.slice(0, -1)} )`;

آن را بررسی کنید! ما در حال حاضر یک تار عنکبوت داریم.

قلم را ببینید [Radar chart (Grid) [forked]](https://codepen.io/smashingmag/pen/poYOpOG) توسط پریتی سام.

قلم را ببینید نمودار رادار (شبکه) [forked] توسط پریتی سام.

این چیزی است که در کد اتفاق می افتد:

  1. sides تعداد اضلاع نمودار است. باز هم، ما با پنج طرف کار می کنیم.
  2. vertices آرایه ای است که مختصات هر رأس را ذخیره می کند.
  3. از آنجایی که ما هنوز هیچ نموداری را نمی سازیم – فقط شبکه – تعداد units تنظیم شده است 1، و فقط یک مورد به آن اضافه می شود percents آرایه در percents[0]. برای چند ضلعی های شبکه، مقادیر داده ها هستند 100.
  4. gradient یک رشته برای ساخت است conic-gradient() که خطوط شبکه را ایجاد می کند.
  5. angle یک محاسبه است 360deg تقسیم بر تعداد کل sides.

از آنجا، رئوس را محاسبه می کنیم:

  1. i یک تکرار کننده است که در تعداد کل چرخه می شود sides (یعنی 5).
  2. j یک تکرار کننده است که در تعداد کل چرخه می شود units (یعنی 1).
  3. n شمارنده ای است که به صورت افزایشی به حساب می آید 2*PI (یعنی 2𝜋، 4𝜋، 6𝜋، و غیره).

این x و y مقادیر هر رأس بر اساس معادلات هندسی که قبلاً بحث کردیم به شرح زیر محاسبه می شود. توجه داشته باشید که ضرب می کنیم 𝜋 توسط -1 برای هدایت چرخش

cos(-1 * PI/2 + n/sides) // cos(𝜋/2 + 2𝜋/sides), cos(𝜋/2 + 4𝜋/sides)...
sin(-1 * PI/2 + n/sides) // sin(𝜋/2 + 2𝜋/sides), sin(𝜋/2 + 4𝜋/sides)...

را تبدیل می کنیم x و y مقادیر را به درصد (از آنجایی که نقاط داده به این ترتیب قالب بندی می شوند) و سپس آنها را در نمودار قرار دهید.

let x = (round(cos(-1 * PI/2 + n/sides) * percents[j][i]) + 100) / 2;
let y = (round(sin(-1 * PI/2 + n/sides) * percents[j][i]) + 100) / 2;

ما همچنین می سازیم conic-gradient(), که بخشی از شبکه است. هر توقف رنگ مربوط به زاویه هر رأس است – در هر یک از افزایش زاویه، یک خاکستری (#ddd) خط کشیده شده است.

gradient += 
  `white ${ (angle * (i+1)) - 1 }deg,
   #ddd ${ (angle * (i+1)) - 1 }deg,
   #ddd ${ (angle * (i+1)) + 1 }deg,
   white ${ (angle * (i+1)) + 1 }deg,`

اگر متغیرهای محاسبه شده را بعد از for حلقه، این نتایج برای شبکه خواهد بود vertices و gradient:

console.log(`polygon( ${vertices[0]} )`); /* grid’s polygon */
// polygon(97.5% 34.5%, 79.5% 90.5%, 20.5% 90.5%, 2.5% 34.5%, 50% 0%)

console.log(gradient.slice(0, -1)); /* grid’s gradient */
// conic-gradient(white 71deg, #ddd 71deg,# ddd 73deg, white 73deg, white 143deg, #ddd 143deg, #ddd 145deg, white 145deg, white 215deg, #ddd 215deg, #ddd 217deg, white 217deg, white 287deg, #ddd 287deg, #ddd 289deg, white 289deg, white 359deg, #ddd 359deg, #ddd 361deg, white 361deg

این مقادیر به شبکه اختصاص داده می شود clipPath و backgroundبه ترتیب، و بنابراین شبکه در صفحه ظاهر می شود.

نمودار

// Following the other variable declarations 
// Each graph's data points in the order [B, C, D... A] 
percents[1] = [100, 50, 60, 50, 90]; 
percents[2] = [100, 80, 30, 90, 40];
percents[3] = [100, 10, 60, 60, 80];

// Next to drawing grids
document.querySelectorAll('.graphs > div').forEach((graph,i) => {
  graph.style.clipPath =`polygon( ${vertices[i+1]} )`;
});

قلم را ببینید [Radar chart (Graph) [forked]](https://codepen.io/smashingmag/pen/KKExZYE) توسط پریتی سام.

قلم را ببینید نمودار رادار (گراف) [forked] توسط پریتی سام.

حالا انگار داریم به جایی می رسیم! برای هر نمودار، مجموعه ای از نقاط داده آن را به آن اضافه می کنیم percents آرایه پس از افزایش مقدار units برای مطابقت با تعداد نمودارها و این تمام چیزی است که برای ترسیم نمودارها روی نمودار نیاز داریم. بیایید فعلاً توجه خود را به برچسب ها معطوف کنیم.

برچسب ها

// Positioning labels

// First label is always set in the top middle
let firstLabel = document.querySelector('.labels:first-of-type');
firstLabel.style.insetInlineStart =`calc(50% - ${firstLabel.offsetWidth / 2}px)`;

// Setting labels for the rest of the vertices (data points). 
let v = Array.from(vertices[0].split(' ').splice(0, (2 * sides) - 2), (n)=> parseInt(n)); 

document.querySelectorAll('.labels:not(:first-of-type)').forEach((label, i) => {
  let width = label.offsetWidth / 2; 
  let height = label.offsetHeight;
  label.style.insetInlineStart = `calc( ${ v[i*2] }% + ${ v[i*2] < 50 ? - 3*width : v[i*2] == 50 ? - width: width}px )`;
  label.style.insetBlockStart = `calc( ${ v[(i*2) + 1] }% - ${ v[(i * 2) + 1] == 100 ? - height: height / 2 }px )`;
});

موقعیت برچسب ها با سه چیز تعیین می شود:

  1. مختصات رئوس (یعنی نقاط داده) باید در کنار آنها باشد،
  2. عرض و ارتفاع متن آنها و
  3. هر فضای خالی که در اطراف برچسب‌ها مورد نیاز است تا بر روی نمودار همپوشانی نداشته باشند.

همه برچسب ها در موقعیت قرار دارند relative در CSS با اضافه کردن inset-inline-start و inset-block-start مقادیر موجود در اسکریپت، ما می توانیم برچسب ها را با استفاده از مقادیر به عنوان مختصات تغییر مکان دهیم. اولین برچسب همیشه در موقعیت بالا و وسط تنظیم می شود. مختصات بقیه برچسب ها مانند رئوس مربوطه به اضافه یک افست است. افست به این صورت تعیین می شود:

  1. محور x/ افقی
    اگر برچسب در سمت چپ باشد (یعنی x کمتر است از 50%، سپس بر اساس آن به سمت چپ حرکت می کند width. در غیر این صورت به سمت راست حرکت می کند. به این ترتیب، لبه های سمت راست یا چپ برچسب ها، بسته به اینکه در کدام سمت نمودار قرار دارند، به طور یکنواخت با رئوس آنها تراز می شوند.
  2. محور y/عمودی
    ارتفاع هر برچسب ثابت است. جابجایی زیادی برای اضافه کردن وجود ندارد به جز اینکه ممکن است آنها را به نصف قد خود پایین بیاورید. هر برچسبی در پایین (به عنوان مثال، چه زمانی y 100٪ است، با این حال، می تواند از فضای اضافی بالای آن برای اتاق تنفس استفاده کند.

و حدس بزنید چه…

انجام شد!

قلم را ببینید [Radar chart (Pentagon) [forked]](https://codepen.io/smashingmag/pen/XWGPVLJ) توسط پریتی سام.

قلم را ببینید نمودار رادار (پنتاگون) [forked] توسط پریتی سام.

خیلی هم کهنه نیست، درسته؟ من فکر می کنم پیچیده ترین بخش ریاضی است. اما از آنجایی که ما متوجه شده ایم، عملاً می توانیم آن را به هر موقعیت دیگری که به نمودار راداری نیاز است متصل کنیم. در عوض به نمودار چهار نقطه ای نیاز دارید؟ تعداد رئوس را در اسکریپت به‌روزرسانی کنید و عناصر کمتری در نشانه‌گذاری و سبک‌ها در نظر بگیرید.

در واقع، در اینجا دو مثال دیگر وجود دارد که پیکربندی های مختلف را نشان می دهد. در هر مورد، من فقط تعداد رئوس را کم یا زیاد می کنم، که اسکریپت از آنها برای تولید مجموعه های متفاوتی از مختصات استفاده می کند که به قرار دادن نقاط در امتداد شبکه کمک می کند.

فقط به سه طرف نیاز دارید؟ تمام این بدان معناست که دو مجموعه مختصات کمتر است:

قلم را ببینید [Radar chart (Triangle) [forked]](https://codepen.io/smashingmag/pen/vYPzpqJ) توسط پریتی سام.

قلم را ببینید نمودار رادار (مثلث) [forked] توسط پریتی سام.

به هفت ضلع نیاز دارید؟ در عوض مجموعه‌های مختصات بیشتری تولید می‌کنیم:

قلم را ببینید [Radar chart (Heptagon) [forked]](https://codepen.io/smashingmag/pen/WNmgdqY) توسط پریتی سام.

قلم را ببینید نمودار رادار (هفت ضلعی) [forked] توسط پریتی سام.
سرمقاله Smashing
(gg, yk)