138 lines
3.3 KiB
TypeScript
138 lines
3.3 KiB
TypeScript
import React, { useEffect, useRef, useState } from "react";
|
|
import * as echarts from "echarts";
|
|
import indonesiaGeo from "../../public/assets/geo/indonesia.json";
|
|
|
|
const IndonesiaMap = (props: { data: any }) => {
|
|
const chartRef = useRef<HTMLDivElement>(null);
|
|
const myChart = useRef<echarts.EChartsType | null>(null);
|
|
const [selectedProvince, setSelectedProvince] = useState("");
|
|
|
|
const selectedProvinceRef = useRef<string | null>(null);
|
|
const chartOptionRef = useRef<any>(null);
|
|
|
|
const option = {
|
|
backgroundColor: "#d3d3d3",
|
|
title: {
|
|
text: "Sebaran Data",
|
|
left: "center",
|
|
textStyle: { color: "#000" },
|
|
},
|
|
visualMap: {
|
|
min: 0,
|
|
max: 100,
|
|
show: true,
|
|
seriesIndex: 0,
|
|
inRange: {
|
|
color: ["#ff0000", "#ffffff"],
|
|
},
|
|
},
|
|
series: [
|
|
{
|
|
type: "map",
|
|
map: "indonesia",
|
|
|
|
roam: true,
|
|
zoom: 1.2,
|
|
center: [118, -2],
|
|
label: {
|
|
show: false,
|
|
color: "#000",
|
|
},
|
|
itemStyle: {
|
|
borderColor: "#999",
|
|
},
|
|
emphasis: {
|
|
label: {
|
|
show: true,
|
|
color: "#000",
|
|
},
|
|
itemStyle: {
|
|
areaColor: "#ffcccc",
|
|
},
|
|
},
|
|
data: props.data,
|
|
},
|
|
],
|
|
};
|
|
|
|
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.PROVINSI,
|
|
},
|
|
})),
|
|
};
|
|
|
|
echarts.registerMap("indonesia", fixedGeo as any);
|
|
|
|
const chart = echarts.init(chartRef.current);
|
|
myChart.current = chart;
|
|
|
|
chart.on("click", (params: any) => {
|
|
highlightProvince(params.name);
|
|
});
|
|
chartOptionRef.current = option;
|
|
chart.setOption(option);
|
|
|
|
return () => {
|
|
chart.dispose();
|
|
};
|
|
}, []);
|
|
|
|
const highlightProvince = (name: string) => {
|
|
if (!myChart.current || !chartOptionRef.current) return;
|
|
|
|
myChart.current.clear();
|
|
myChart.current.setOption(chartOptionRef.current);
|
|
|
|
myChart.current.dispatchAction({
|
|
type: "highlight",
|
|
name,
|
|
});
|
|
|
|
myChart.current.dispatchAction({
|
|
type: "showTip",
|
|
name,
|
|
});
|
|
|
|
selectedProvinceRef.current = name;
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-col lg:flex-row gap-6 w-full pr-2 md:pr-0">
|
|
<div className="w-screen md:w-[70%] h-[360px] lg:h-[600px]">
|
|
<div ref={chartRef} style={{ height: "100%", width: "100%" }} />
|
|
</div>
|
|
<div className="w-screen md:w-[30%] h-[360px] lg:h-[600px] overflow-auto flex flex-col">
|
|
{props.data.map((list: any) => (
|
|
<a
|
|
key={list.name}
|
|
onClick={() => highlightProvince(list.name)}
|
|
className={`w-full flex flex-row cursor-pointer gap-2 ${
|
|
selectedProvince === list.name ? "bg-slate-300" : ""
|
|
}`}
|
|
>
|
|
<p className="w-4/5">{list.name}</p>{" "}
|
|
<p
|
|
className={`w-1/5 ${
|
|
selectedProvince === list.name ? "bg-slate-300" : "bg-[#a9d7e4]"
|
|
} text-black border-white text-center`}
|
|
>
|
|
{list.value}
|
|
</p>
|
|
</a>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default IndonesiaMap;
|