در این مقاله، قصد داریم با استفاده از کتابخانه D3.js یک نقشه حبابی (Bubble Map) براساس جمعیت استانهای ایران ایجاد کنیم. این نقشه حبابی به ما امکان میدهد که توزیع جمعیت در استانهای مختلف ایران را به صورت بصری و جذاب مشاهده کنیم.
کد:
خروجی:
تنظیم ابعاد SVG
ابتدا ابعاد نقشه را تعیین میکنیم:
تنظیم پروجکشن و مسیر نقشه
برای نمایش نقشه ایران از پروجکشن `geoMercator` استفاده میکنیم و مرکز و مقیاس آن را تنظیم میکنیم:
بارگذاری و رسم نقشه ایران
با استفاده از دادههای GeoJSON نقشه ایران را رسم میکنیم:
- svg.append("g"): این خط یک عنصر گروهی (group)
g
به عنصرsvg
اضافه میکند. عنصرg
به عنوان یک کانتینر برای سایر عناصر SVG عمل میکند و به شما امکان میدهد تا چندین عنصر را به طور همزمان جابجا یا تغییر دهید. - selectAll("path"): این خط تمامی عناصر
path
موجود در گروهg
را انتخاب میکند. در این مرحله، هیچ عنصری وجود ندارد زیرا ما تازه عنصر گروهیg
را اضافه کردهایم. - data(iranMap.features): این خط دادههای
iranMap.features
را به عناصرpath
اتصال میدهد.iranMap.features
شامل دادههای GeoJSON برای نقشه ایران است که هرfeature
نشاندهنده یک استان است. - enter().append("path"): این خط برای هر دادهای که به هیچ عنصری اتصال نیافته، یک عنصر
path
جدید ایجاد میکند. در این مورد، برای هر استان یک عنصرpath
ایجاد میشود. - attr("d", path): این خط خصوصیت
d
را برای هر عنصرpath
تنظیم میکند. خصوصیتd
مسیر (path) را تعریف میکند و مقدار آن از تابعpath
که قبلاً تعریف شده بود، به دست میآید. تابعpath
هر ویژگی (feature) را به یک مسیر SVG تبدیل میکند که شکل استان را ترسیم میکند. - attr("fill", "#BFBFBF"): این خط خصوصیت
fill
را برای هر عنصرpath
تنظیم میکند و رنگ داخلی (پر) استانها را به خاکستری روشن#BFBFBF
تغییر میدهد. - attr("stroke", "white"): این خط خصوصیت
stroke
را برای هر عنصرpath
تنظیم میکند و رنگ حاشیه (stroke) استانها را سفید تعیین میکند. این خط باعث میشود که استانها به وضوح از هم جدا شوند.
محاسبه مراکز استانها
برای قرار دادن حبابها بر روی نقشه، ابتدا مراکز هندسی هر استان را محاسبه میکنیم:
- iranMap.features.forEach(function(feature): این خط یک
forEach
را بر روی آرایهfeatures
از شیءiranMap
اجرا میکند.iranMap.features
شامل تمام ویژگیهای (استانها) نقشه ایران است.function(feature)
یک تابع ناشناس است که برای هر عنصرfeature
در آرایهfeatures
فراخوانی میشود. - var centroid = path.centroid(feature): این خط مرکز جغرافیایی (centroid) هر ویژگی را محاسبه میکند. تابع
path.centroid(feature)
مرکز (مختصات x و y) هر ویژگی (استان) را به صورت یک آرایه[x, y]
برمیگرداند. این مختصات مرکز جغرافیایی استان را نشان میدهد. - feature.properties.centroid = centroid: این خط مختصات مرکز جغرافیایی محاسبه شده را به عنوان یک ویژگی جدید
centroid
به شیءproperties
هر ویژگی اضافه میکند. بنابراین، هرfeature
اکنون دارای مختصات مرکز جغرافیایی خود به عنوانfeature.properties.centroid
است.
تنظیم مقیاس اندازه دایرهها
یک مقیاس برای اندازه دایرهها بر اساس جمعیت استانها تعریف میکنیم:
- var radiusScale = d3.scaleSqrt(): این خط یک مقیاس جدید از نوع
d3.scaleSqrt
ایجاد میکند. مقیاسscaleSqrt
در D3.js برای نقشهبرداری مقادیر خطی به مقادیر ریشه دوم استفاده میشود. این نوع مقیاس برای نمودارهایی که مقادیر زیادی دارند و نیاز به یک توزیع یکنواختتر دارند، مناسب است. - domain([0, d3.max(iranPopulation, d => d.population)]): این خط دامنه (domain) مقیاس را تعیین میکند. دامنه مقادیر ورودی به مقیاس را مشخص میکند.
[0, d3.max(iranPopulation, d => d.population)]
: دامنه از 0 تا حداکثر جمعیت در دادههایiranPopulation
است.d3.max(iranPopulation, d => d.population)
: این تابع مقدار حداکثر جمعیت در آرایهiranPopulation
را پیدا میکند.iranPopulation
آرایهای از اشیاء است که هر شیء دارای یک ویژگیpopulation
است. تابعd3.max
این ویژگیpopulation
را برای پیدا کردن بزرگترین مقدار در آرایه جستجو میکند.- range([0, 50]): این خط محدوده (range) مقیاس را تعیین میکند. محدوده مقادیر خروجی از مقیاس را مشخص میکند.
[0, 50]
: مقادیر ورودی در دامنه[0, d3.max(...)]
به مقادیر خروجی در محدوده[0, 50]
نقشهبرداری میشوند. به عبارت دیگر، جمعیت 0 به شعاع دایره 0 و حداکثر جمعیت به شعاع دایره 50 تبدیل میشود. مقادیر میانی نیز به صورت نسبی به شعاعهای بین 0 و 50 نقشهبرداری میشوند.
افزودن دایرهها براساس جمعیت
دایرهها را براساس جمعیت استانها بر روی نقشه اضافه میکنیم و موقعیت آنها را بر اساس مراکز هندسی که قبلا محاسبه کردیم، تنظیم میکنیم:
در این مرحله، حبابها بر روی نقشه ایران قرار میگیرند و اندازه هر حباب براساس جمعیت استان مربوطه تنظیم میشود. همچنین با قرار گرفتن ماوس روی هر حباب، نام استان و جمعیت آن به صورت tooltip نمایش داده میشود.
- svg.append("g"): یک گروه (
<g>
) جدید به عنصرsvg
اضافه میکند که در آن تمامی دایرهها قرار میگیرند. گروهها به شما امکان میدهند تا چندین عنصر را با هم دستهبندی کنید. selectAll("circle")
: انتخاب تمام عناصرcircle
در گروه جدید. چون در ابتدا هیچ دایرهای وجود ندارد، این انتخاب یک انتخاب خالی است..data(iranPopulation)
: اتصال دادههایiranPopulation
به دایرهها. هر عنصر درiranPopulation
به یک دایره تبدیل میشود.enter()
: ایجاد یک عنصر جدید برای هر داده درiranPopulation
که به یک عنصرcircle
تبدیل نشده است.append("circle")
: افزودن یک عنصرcircle
جدید به گروه برای هر داده.attr("cx", d => {...})
: تنظیم موقعیتcx
(مختصات x) دایره بر اساس دادههای متصل.find(f => f.properties.name === d.province)
: جستجوی ویژگی (feature
) درiranMap.features
که نام استان (properties.name
) با نام استان در دادهها (d.province
) مطابقت دارد.feature ? feature.properties.centroid[0] : 0
: اگر ویژگی یافت شد، مقدارcx
برابر با اولین مقدار از مختصات مرکز (centroid
) آن ویژگی خواهد بود، در غیر این صورت 0 تنظیم میشود.attr("cy", d => {...})
: تنظیم موقعیتcy
(مختصات y) دایره بر اساس دادههای متصل.find(f => f.properties.name === d.province)
: جستجوی ویژگی درiranMap.features
که نام استان با نام استان در دادهها مطابقت دارد.feature ? feature.properties.centroid[1] : 0
: اگر ویژگی یافت شد، مقدارcy
برابر با دومین مقدار از مختصات مرکز آن ویژگی خواهد بود، در غیر این صورت 0 تنظیم میشود.attr("r", d => radiusScale(d.population))
: تنظیم شعاع (radius
) دایره بر اساس جمعیت استان. از مقیاسradiusScale
که قبلاً تعریف شده استفاده میکند تا جمعیت را به شعاع تبدیل کند.attr("fill", "steelblue")
: تنظیم رنگ دایرهها بهsteelblue
.attr("opacity", 0.7)
: تنظیم شفافیت دایرهها به 0.7 (70%).append("title")
: افزودن یک عنصرtitle
به دایره. این عنوان به عنوان یک tooltip نمایش داده میشود..text(d =>
${d.province}: ${d.population.toLocaleString()})
: تنظیم متن عنوان به نام استان و جمعیت آن به صورت فرمت شده با کاماها.
نمایش SVG
در نهایت، SVG ایجاد شده را به صفحه اضافه میکنیم:
نتیجه نهایی یک نقشه حبابی زیبا و کاربردی است که به ما امکان میدهد توزیع جمعیت استانهای ایران را به صورت بصری مشاهده کنیم. با استفاده از D3.js، این نوع نمودارها به سادگی قابل پیادهسازی و سفارشیسازی هستند.