feat:map chart

This commit is contained in:
Rama Priyanto 2025-06-23 22:51:20 +07:00
parent 1fc236bff3
commit 17e9faec56
6 changed files with 10089 additions and 134 deletions

View File

@ -68,6 +68,7 @@ import {
} from "@/components/icons";
import { format } from "date-fns";
import ApexChartColumnVisitors from "./chart/visitor-chart";
import { IndonesiaMap } from "@/components/ui/maps-charts";
type ArticleData = Article & {
no: number;
@ -81,6 +82,16 @@ interface TopPages {
viewCount: number;
}
const colors = [
"#38bdf8",
"#155e75",
"#0e7490",
"#0284c7",
"#0ea5e9",
"#38bdf8",
"#7dd3fc",
];
interface PostCount {
userLevelId: number;
no: number;
@ -103,6 +114,19 @@ const months = [
"Dec",
];
const dummyData = [
{ name: "DI. ACEH", value: 10, id: 1 },
{ name: "SUMATERA UTARA", value: 20, id: 2 },
{ name: "DKI JAKARTA", value: 100, id: 3 },
{ name: "JAWA BARAT", value: 30, id: 4 },
{ name: "IRIAN JAYA TIMUR", value: 20, id: 5 },
];
const getTotalData: number[] = [];
dummyData.map((list) => {
getTotalData.push(list.value);
});
export default function DashboardContainer() {
const { isOpen, onOpen, onOpenChange } = useDisclosure();
@ -940,6 +964,34 @@ export default function DashboardContainer() {
</div>
</div>
</div>
<div className="flex flex-row gap-6 w-full">
<div className="w-screen md:w-[80%] h-[360px] lg:h-[600px]">
<IndonesiaMap />
</div>
<div className="w-screen md:w-[300px] h-[360px] lg:h-[600px] overflow-auto gap-2 flex flex-col">
{dummyData.map((list) => (
// <p
// key={list.id}
// className={`text-white py-1 pl-3 rounded-sm`}
// style={{
// backgroundColor: colors[list.id % 5],
// width: `calc(50px + ${Math.min(
// (list.value / Math.max(...getTotalData)) * 100,
// 100
// )}%)`,
// }}
// >
// {list.value}
// </p>
<div key={list.id} className="w-full flex flex-row gap-2">
<p className="w-1/2">{list.name}</p>{" "}
<p className="w-1/2 bg-[#0e7490] text-white border-white ">
{list.value}
</p>
</div>
))}
</div>
</div>
</div>
<Modal isOpen={isOpen} onOpenChange={onOpenChange} size="3xl">
<ModalContent>

View File

@ -0,0 +1,86 @@
import React, { useEffect, useRef } from "react";
import * as echarts from "echarts";
import indonesiaGeo from "../../public/assets/geo/indonesia.json";
export const IndonesiaMap: React.FC = () => {
const chartRef = useRef<HTMLDivElement>(null);
const myChart = useRef<echarts.EChartsType | null>(null);
useEffect(() => {
if (!chartRef.current) return;
(window as any).echarts = echarts;
const fixedGeo = {
...indonesiaGeo,
features: indonesiaGeo.features.map((f) => ({
...f,
properties: {
...f.properties,
name: f.properties.Propinsi, // 🔥 inilah kuncinya
},
})),
};
echarts.registerMap("indonesia", fixedGeo as any);
const chart = echarts.init(chartRef.current);
myChart.current = chart;
const rawData = [
{ name: "DI. ACEH", value: 10 },
{ name: "SUMATERA UTARA", value: 20 },
{ name: "DKI JAKARTA", value: 100 },
{ name: "JAWA BARAT", value: 30 },
{ name: "IRIAN JAYA TIMUR", value: 20 },
];
console.log("raw", rawData);
chart.setOption({
backgroundColor: "#d3d3d3",
title: {
text: "Sebaran Data",
left: "center",
textStyle: { color: "#000" },
},
visualMap: {
min: 0,
max: 100,
show: true,
seriesIndex: 0,
inRange: {
color: ["#ffffff", "#ff0000"],
},
},
series: [
{
type: "map",
map: "indonesia",
// nameProperty: "properties.Propinsi", // harus cocok
roam: true,
zoom: 1.2,
center: [120, -2],
label: {
show: false,
color: "#000",
},
itemStyle: {
borderColor: "#999",
},
emphasis: {
itemStyle: {
areaColor: "#ffcccc",
},
},
data: rawData,
},
],
});
return () => {
chart.dispose();
};
}, []);
return <div ref={chartRef} style={{ height: "100%", width: "100%" }} />;
};

191
package-lock.json generated
View File

@ -25,8 +25,9 @@
"@hookform/resolvers": "^3.3.4",
"@react-aria/ssr": "^3.8.0",
"@react-aria/visually-hidden": "^3.8.6",
"@types/echarts": "^5.0.0",
"@types/js-cookie": "^3.0.6",
"@types/node": "20.5.7",
"@types/node": "^20.5.7",
"@types/react": "19.1.2",
"@types/react-datepicker": "^6.0.1",
"@types/react-dom": "19.1.2",
@ -38,6 +39,8 @@
"dayjs": "^1.11.13",
"docx": "^9.3.0",
"dompurify": "^3.2.0",
"echarts": "^5.6.0",
"echarts-gl": "^2.0.9",
"eslint": "8.48.0",
"eslint-config-next": "15.3.0",
"framer-motion": "^10.18.0",
@ -1981,39 +1984,6 @@
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
}
},
"node_modules/@heroui/form/node_modules/framer-motion": {
"version": "12.7.4",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.7.4.tgz",
"integrity": "sha512-jX0bPsTmU0oPZTYz/dVyD0dmOyEOEJvdn0TaZBE5I8g2GvVnnQnW9f65cJnoVfUkY3WZWNXGXnPbVA9YnaIfVA==",
"peer": true,
"dependencies": {
"motion-dom": "^12.7.4",
"motion-utils": "^12.7.2",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/@heroui/form/node_modules/tailwindcss": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.4.tgz",
"integrity": "sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==",
"peer": true
},
"node_modules/@heroui/input": {
"version": "2.4.10",
"resolved": "https://registry.npmjs.org/@heroui/input/-/input-2.4.10.tgz",
@ -4108,12 +4078,6 @@
"tailwindcss": "*"
}
},
"node_modules/@heroui/react/node_modules/tailwindcss": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.4.tgz",
"integrity": "sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==",
"peer": true
},
"node_modules/@heroui/shared-icons": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/@heroui/shared-icons/-/shared-icons-2.1.6.tgz",
@ -4189,33 +4153,6 @@
"react-dom": ">=18 || >=19.0.0-rc.0"
}
},
"node_modules/@heroui/snippet/node_modules/@heroui/aria-utils/node_modules/framer-motion": {
"version": "12.7.4",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.7.4.tgz",
"integrity": "sha512-jX0bPsTmU0oPZTYz/dVyD0dmOyEOEJvdn0TaZBE5I8g2GvVnnQnW9f65cJnoVfUkY3WZWNXGXnPbVA9YnaIfVA==",
"peer": true,
"dependencies": {
"motion-dom": "^12.7.4",
"motion-utils": "^12.7.2",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/@heroui/snippet/node_modules/@heroui/button": {
"version": "2.2.9",
"resolved": "https://registry.npmjs.org/@heroui/button/-/button-2.2.9.tgz",
@ -4881,25 +4818,6 @@
"react": ">=18 || >=19.0.0-rc.0"
}
},
"node_modules/@heroui/system/node_modules/@heroui/theme": {
"version": "2.4.13",
"resolved": "https://registry.npmjs.org/@heroui/theme/-/theme-2.4.13.tgz",
"integrity": "sha512-W1wm/x3dx9rZXNdyvjQRueK+9ieTpT2icyttGuVEn7NWgzMhpIbEKsAwtTLZGc5zMHJE2cxJQ/jpdCR8HBe0Dw==",
"peer": true,
"dependencies": {
"@heroui/shared-utils": "2.1.7",
"clsx": "^1.2.1",
"color": "^4.2.3",
"color2k": "^2.0.3",
"deepmerge": "4.3.1",
"flat": "^5.0.2",
"tailwind-merge": "2.5.4",
"tailwind-variants": "0.3.0"
},
"peerDependencies": {
"tailwindcss": ">=3.4.0"
}
},
"node_modules/@heroui/system/node_modules/@react-aria/overlays": {
"version": "3.26.1",
"resolved": "https://registry.npmjs.org/@react-aria/overlays/-/overlays-3.26.1.tgz",
@ -4930,38 +4848,6 @@
"node": ">=6"
}
},
"node_modules/@heroui/system/node_modules/tailwind-merge": {
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.4.tgz",
"integrity": "sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
}
},
"node_modules/@heroui/system/node_modules/tailwind-variants": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-0.3.0.tgz",
"integrity": "sha512-ho2k5kn+LB1fT5XdNS3Clb96zieWxbStE9wNLK7D0AV64kdZMaYzAKo0fWl6fXLPY99ffF9oBJnIj5escEl/8A==",
"peer": true,
"dependencies": {
"tailwind-merge": "^2.5.4"
},
"engines": {
"node": ">=16.x",
"pnpm": ">=7.x"
},
"peerDependencies": {
"tailwindcss": "*"
}
},
"node_modules/@heroui/system/node_modules/tailwindcss": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.4.tgz",
"integrity": "sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==",
"peer": true
},
"node_modules/@heroui/theme": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/@heroui/theme/-/theme-2.4.5.tgz",
@ -9504,6 +9390,15 @@
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.5.tgz",
"integrity": "sha512-j2K5UJqGTxeesj6oQuGpMgifpT5k9HprgQd8D1Y0lOFqKHl3PJu5GMeS4Y5EgjS55AE6OQxf8mPED9uaGbf4Cg=="
},
"node_modules/@types/echarts": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/echarts/-/echarts-5.0.0.tgz",
"integrity": "sha512-5uc/16BlYpzH8kU/u8aeRRgY2FV6yRY7RjPnYfUFPowl0F3kvNgfaz09PmeVdLkqdAtMft3XkCfqiJPJjG2DNQ==",
"deprecated": "This is a stub types definition. echarts provides its own type definitions, so you do not need this installed.",
"dependencies": {
"echarts": "*"
}
},
"node_modules/@types/eslint": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
@ -11010,6 +10905,11 @@
"resolved": "vendor/ckeditor5",
"link": true
},
"node_modules/claygl": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz",
"integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ=="
},
"node_modules/clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@ -11802,6 +11702,32 @@
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
},
"node_modules/echarts": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz",
"integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==",
"dependencies": {
"tslib": "2.3.0",
"zrender": "5.6.1"
}
},
"node_modules/echarts-gl": {
"version": "2.0.9",
"resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-2.0.9.tgz",
"integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==",
"dependencies": {
"claygl": "^1.2.1",
"zrender": "^5.1.1"
},
"peerDependencies": {
"echarts": "^5.1.2"
}
},
"node_modules/echarts/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"node_modules/electron-to-chromium": {
"version": "1.5.140",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.140.tgz",
@ -14400,21 +14326,6 @@
"node": ">=10"
}
},
"node_modules/motion-dom": {
"version": "12.7.4",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.7.4.tgz",
"integrity": "sha512-1ZUHAoSUMMxP6jPqyxlk9XUfb6NxMsnWPnH2YGhrOhTURLcXWbETi6eemoKb60Pe32NVJYduL4B62VQSO5Jq8Q==",
"peer": true,
"dependencies": {
"motion-utils": "^12.7.2"
}
},
"node_modules/motion-utils": {
"version": "12.7.2",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.7.2.tgz",
"integrity": "sha512-XhZwqctxyJs89oX00zn3OGCuIIpVevbTa+u82usWBC6pSHUd2AoNWiYa7Du8tJxJy9TFbZ82pcn5t7NOm1PHAw==",
"peer": true
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@ -18721,6 +18632,19 @@
"url": "https://github.com/sponsors/colinhacks"
}
},
"node_modules/zrender": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz",
"integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==",
"dependencies": {
"tslib": "2.3.0"
}
},
"node_modules/zrender/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"node_modules/zustand": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz",
@ -18750,6 +18674,7 @@
}
},
"vendor/ckeditor5": {
"name": "ckeditor5-custom-build",
"version": "0.0.1",
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {

View File

@ -26,8 +26,9 @@
"@hookform/resolvers": "^3.3.4",
"@react-aria/ssr": "^3.8.0",
"@react-aria/visually-hidden": "^3.8.6",
"@types/echarts": "^5.0.0",
"@types/js-cookie": "^3.0.6",
"@types/node": "20.5.7",
"@types/node": "^20.5.7",
"@types/react": "19.1.2",
"@types/react-datepicker": "^6.0.1",
"@types/react-dom": "19.1.2",
@ -39,6 +40,8 @@
"dayjs": "^1.11.13",
"docx": "^9.3.0",
"dompurify": "^3.2.0",
"echarts": "^5.6.0",
"echarts-gl": "^2.0.9",
"eslint": "8.48.0",
"eslint-config-next": "15.3.0",
"framer-motion": "^10.18.0",

Binary file not shown.

File diff suppressed because it is too large Load Diff