2869 字
14 分鐘
[主題地圖]川普全球關稅戰統計地圖

關鍵字: 川普關稅、台灣關稅、關稅戰
[主題地圖]川普全球關稅統計地圖
文章目錄
1. 地圖展示
<script src="https://cdn.tailwindcss.com"></script><script src="https://d3js.org/d3.v7.min.js"></script><style> /* Tooltip 基本樣式 - 深色 */ #tooltip { position: absolute; opacity: 0; background-color: #1f2937; /* 深灰 */ color: #e5e7eb; /* 淺灰文字 */ border: 1px solid #4b5563; /* 中灰邊框 */ padding: 10px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); pointer-events: none; transition: opacity 0.2s ease-in-out, left 0.1s linear, top 0.1s linear; z-index: 10; max-width: 200px; } #tooltip.visible { opacity: 1; } /* Tooltip 內部文字顏色 */ #tooltip .font-bold.text-blue-600 { color: #fca5a5; /* 淺紅色 */ } #tooltip .text-gray-800 { color: #f9fafb; /* 更亮的灰色 */ } #tooltip .text-gray-700 { color: #d1d5db; /* 稍暗的淺灰 */ }
/* SVG 文本選取禁用 */ svg text::selection { background: none; } /* 強制 Tailwind 深色模式 (如果瀏覽器預設淺色) */ :root { color-scheme: dark; }</style><div class="flex flex-col items-center"> <h2 class="text-3xl font-bold mb-6 text-white-100">川普關稅戰統計地圖</h2>
<div id="chart-container" class="relative bg-gray-800 rounded-xl p-6 shadow-lg border border-gray-700 mb-8"> <svg id="bubble-chart" width="800" height="450" viewBox="0 0 800 450"> <title>關稅泡泡圖</title> <desc>顯示各國關稅稅率的泡泡圖,泡泡大小和顏色代表稅率高低。</desc> </svg> <div id="tooltip"></div> </div>
<div class="w-full max-w-3xl space-y-8"> <div class="flex flex-col md:flex-row justify-between bg-gray-800 p-6 rounded-xl shadow-md border border-gray-700 gap-6"> <div id="color-legend"> <h3 class="text-lg font-semibold mb-3 text-gray-100">關稅稅率 (顏色)</h3> <div class="flex items-center flex-wrap gap-x-4 gap-y-2"> </div> </div> <div id="size-legend"> <h3 class="text-lg font-semibold mb-3 text-gray-100">關稅稅率 (大小)</h3> <div class="flex items-end flex-wrap gap-x-4 gap-y-2">
</div> </div> </div>
<div id="top-countries" class="bg-gray-800 p-6 rounded-xl shadow-md border border-gray-700"> <h3 class="text-xl font-semibold mb-5 text-center text-gray-100">關稅最高的五個國家</h3> <div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-6 md:gap-8"> </div> </div> </div></div>
<script> document.addEventListener('DOMContentLoaded', function() {
const tariffData = [ {country: "中國", tariff: 34, region: "亞洲", x: 650, y: 180, originalName: "China"}, {country: "歐盟", tariff: 20, region: "歐洲", x: 450, y: 150, originalName: "European Union"}, {country: "越南", tariff: 46, region: "亞洲", x: 670, y: 210, originalName: "Vietnam"}, {country: "台灣", tariff: 32, region: "亞洲", x: 690, y: 190, originalName: "Taiwan"}, {country: "日本", tariff: 24, region: "亞洲", x: 720, y: 170, originalName: "Japan"}, {country: "印度", tariff: 26, region: "亞洲", x: 580, y: 210, originalName: "India"}, {country: "南韓", tariff: 25, region: "亞洲", x: 700, y: 175, originalName: "South Korea"}, {country: "泰國", tariff: 36, region: "亞洲", x: 650, y: 220, originalName: "Thailand"}, {country: "瑞士", tariff: 31, region: "歐洲", x: 430, y: 160, originalName: "Switzerland"}, {country: "印尼", tariff: 32, region: "亞洲", x: 650, y: 250, originalName: "Indonesia"}, {country: "馬來西亞", tariff: 24, region: "亞洲", x: 640, y: 230, originalName: "Malaysia"}, {country: "柬埔寨", tariff: 49, region: "亞洲", x: 655, y: 215, originalName: "Cambodia"}, {country: "英國", tariff: 10, region: "歐洲", x: 410, y: 145, originalName: "United Kingdom"}, {country: "南非", tariff: 30, region: "非洲", x: 480, y: 300, originalName: "South Africa"}, {country: "巴西", tariff: 10, region: "南美洲", x: 320, y: 280, originalName: "Brazil"}, {country: "孟加拉", tariff: 37, region: "亞洲", x: 600, y: 200, originalName: "Bangladesh"}, {country: "新加坡", tariff: 10, region: "亞洲", x: 645, y: 240, originalName: "Singapore"}, {country: "以色列", tariff: 17, region: "中東", x: 510, y: 200, originalName: "Israel"}, {country: "菲律賓", tariff: 17, region: "亞洲", x: 680, y: 220, originalName: "Philippines"}, {country: "智利", tariff: 10, region: "南美洲", x: 300, y: 320, originalName: "Chile"}, {country: "澳洲", tariff: 10, region: "大洋洲", x: 700, y: 310, originalName: "Australia"}, {country: "巴基斯坦", tariff: 29, region: "亞洲", x: 560, y: 200, originalName: "Pakistan"}, {country: "土耳其", tariff: 10, region: "中東", x: 490, y: 180, originalName: "Turkey"}, {country: "斯里蘭卡", tariff: 44, region: "亞洲", x: 590, y: 230, originalName: "Sri Lanka"}, {country: "哥倫比亞", tariff: 10, region: "南美洲", x: 290, y: 260, originalName: "Colombia"}, {country: "秘魯", tariff: 10, region: "南美洲", x: 280, y: 270, originalName: "Peru"}, {country: "尼加拉瓜", tariff: 18, region: "中美洲", x: 260, y: 230, originalName: "Nicaragua"}, {country: "挪威", tariff: 15, region: "歐洲", x: 430, y: 130, originalName: "Norway"}, {country: "哥斯大黎加", tariff: 10, region: "中美洲", x: 255, y: 240, originalName: "Costa Rica"}, {country: "約旦", tariff: 20, region: "中東", x: 520, y: 190, originalName: "Jordan"}, {country: "多明尼加", tariff: 10, region: "加勒比海", x: 280, y: 220, originalName: "Dominican Republic"}, {country: "阿聯酋", tariff: 10, region: "中東", x: 540, y: 210, originalName: "United Arab Emirates"}, {country: "紐西蘭", tariff: 10, region: "大洋洲", x: 760, y: 330, originalName: "New Zealand"}, {country: "阿根廷", tariff: 10, region: "南美洲", x: 310, y: 320, originalName: "Argentina"}, {country: "厄瓜多", tariff: 10, region: "南美洲", x: 270, y: 260, originalName: "Ecuador"}, {country: "瓜地馬拉", tariff: 10, region: "中美洲", x: 250, y: 220, originalName: "Guatemala"}, {country: "宏都拉斯", tariff: 10, region: "中美洲", x: 255, y: 225, originalName: "Honduras"}, {country: "馬達加斯加", tariff: 47, region: "非洲", x: 520, y: 290, originalName: "Madagascar"}, {country: "緬甸", tariff: 44, region: "亞洲", x: 630, y: 210, originalName: "Myanmar"}, {country: "突尼西亞", tariff: 28, region: "非洲", x: 440, y: 190, originalName: "Tunisia"}, {country: "哈薩克", tariff: 27, region: "亞洲", x: 560, y: 150, originalName: "Kazakhstan"}, {country: "塞爾維亞", tariff: 37, region: "歐洲", x: 460, y: 170, originalName: "Serbia"}, {country: "埃及", tariff: 10, region: "非洲", x: 490, y: 210, originalName: "Egypt"}, {country: "沙烏地阿拉伯", tariff: 10, region: "中東", x: 530, y: 220, originalName: "Saudi Arabia"}, {country: "薩爾瓦多", tariff: 10, region: "中美洲", x: 245, y: 230, originalName: "El Salvador"}, {country: "象牙海岸", tariff: 21, region: "非洲", x: 420, y: 250, originalName: "Côte d'Ivoire"}, {country: "寮國", tariff: 48, region: "亞洲", x: 640, y: 205, originalName: "Laos"}, {country: "波札那", tariff: 37, region: "非洲", x: 470, y: 290, originalName: "Botswana"}, {country: "千里達及托巴哥", tariff: 10, region: "加勒比海", x: 290, y: 235, originalName: "Trinidad and Tobago"}, {country: "摩洛哥", tariff: 10, region: "非洲", x: 410, y: 200, originalName: "Morocco"}, {country: "阿爾及利亞", tariff: 30, region: "非洲", x: 425, y: 210, originalName: "Algeria"}, {country: "阿曼", tariff: 10, region: "中東", x: 550, y: 220, originalName: "Oman"}, {country: "烏拉圭", tariff: 10, region: "南美洲", x: 320, y: 310, originalName: "Uruguay"}, {country: "美國", tariff: 0, region: "北美洲", x: 230, y: 170, originalName: "United States"}, {country: "墨西哥", tariff: 20, region: "北美洲", x: 220, y: 210, originalName: "Mexico"}, {country: "加拿大", tariff: 10, region: "北美洲", x: 230, y: 130, originalName: "Canada"}, {country: "俄羅斯", tariff: 20, region: "歐亞", x: 520, y: 130, originalName: "Russia"}, {country: "留尼旺", tariff: 73, region: "非洲", x: 530, y: 300, originalName: "Reunion"}, {country: "賴索托", tariff: 50, region: "非洲", x: 480, y: 310, originalName: "Lesotho"}, {country: "法國", tariff: 20, region: "歐洲", x: 425, y: 155, originalName: "France"}, {country: "德國", tariff: 20, region: "歐洲", x: 440, y: 145, originalName: "Germany"}, {country: "義大利", tariff: 20, region: "歐洲", x: 450, y: 165, originalName: "Italy"}, {country: "西班牙", tariff: 20, region: "歐洲", x: 410, y: 170, originalName: "Spain"}, {country: "奈及利亞", tariff: 14, region: "非洲", x: 440, y: 240, originalName: "Nigeria"}, {country: "肯亞", tariff: 10, region: "非洲", x: 510, y: 260, originalName: "Kenya"}, {country: "烏克蘭", tariff: 10, region: "歐洲", x: 480, y: 150, originalName: "Ukraine"}, {country: "伊朗", tariff: 10, region: "中東", x: 550, y: 190, originalName: "Iran"}, {country: "伊拉克", tariff: 39, region: "中東", x: 540, y: 200, originalName: "Iraq"} ];
const svg = d3.select("#bubble-chart"); const width = +svg.attr("width"); const height = +svg.attr("height"); const tooltip = d3.select("#tooltip");
// --- 紅色漸層顏色比例尺 --- const colorScale = d3.scaleLinear() .domain([0, 10, 25, 50, 75]) // 保持不變 .range(['#fee2e2', '#fca5a5', '#ef4444', '#b91c1c', '#7f1d1d']) // 紅色系 (從淺到深) .clamp(true);
const sizeScale = d3.scaleSqrt() .domain([0, 75]) .range([5, 28]);
// --- SVG 背景調整 --- svg.append("rect") .attr("x", 0) .attr("y", 0) .attr("width", width) .attr("height", height) .attr("fill", "#1f2937") // 深灰色背景 .attr("rx", 10) .attr("ry", 10);
const gridGroup = svg.append("g").attr("class", "grid-lines");
// --- 網格線顏色調整 --- const gridColor = "#4b5563"; // 中灰色 for (let x = 100; x <= 700; x += 100) { gridGroup.append("line") .attr("x1", x).attr("y1", 50) .attr("x2", x).attr("y2", 400) .attr("stroke", gridColor).attr("stroke-width", 0.5).attr("stroke-dasharray", "3,3"); // 變細一點 } for (let y = 100; y <= 350; y += 50) { gridGroup.append("line") .attr("x1", 100).attr("y1", y) .attr("x2", 700).attr("y2", y) .attr("stroke", gridColor).attr("stroke-width", 0.5).attr("stroke-dasharray", "3,3"); // 變細一點 }
const regionLabels = [ { x: 230, y: 90, text: "北美洲" }, { x: 445, y: 100, text: "歐洲" }, { x: 650, y: 120, text: "亞洲" }, { x: 520, y: 170, text: "中東" }, { x: 450, y: 350, text: "非洲" }, { x: 230, y: 200, text: "中美洲" }, { x: 280, y: 340, text: "南美洲" }, { x: 730, y: 340, text: "大洋洲" } ];
// --- 地區標籤顏色調整 --- svg.append("g") .attr("class", "region-labels") .selectAll("text") .data(regionLabels) .join("text") .attr("x", d => d.x) .attr("y", d => d.y) .attr("class", "font-semibold text-sm") .style("font-size", "14px") .style("fill", "#9ca3af") // 淺灰色標籤 .text(d => d.text);
const bubbles = svg.append("g") .attr("class", "bubbles") .selectAll("g") .data(tariffData) .join("g") .attr("transform", d => `translate(${d.x}, ${d.y})`) .style("cursor", "pointer") .on("mouseover", function(event, d) { tooltip.transition().duration(100).style("opacity", 1).attr("class", "visible"); tooltip.html(` <p class="font-bold text-lg text-gray-800">${d.country}</p> {/* Tooltip 樣式已在 <style> 中調整 */} <p class="text-base text-gray-700">關稅: <span class="font-bold text-blue-600">${d.tariff}%</span></p> <p class="text-base text-gray-700">地區: ${d.region}</p> `);
const chartRect = document.getElementById('chart-container').getBoundingClientRect(); const tooltipRect = tooltip.node().getBoundingClientRect(); let left = event.pageX + 15; let top = event.pageY - 15;
if (left + tooltipRect.width > chartRect.right) left = event.pageX - tooltipRect.width - 15; if (top + tooltipRect.height > chartRect.bottom) top = event.pageY - tooltipRect.height - 15; if (top < chartRect.top) top = event.pageY + 15;
tooltip.style("left", `${left}px`).style("top", `${top}px`);
d3.select(this).select("circle") .transition().duration(150) .attr("stroke-width", 1.5) .attr("stroke", "#f3f4f6") // 懸停時用亮邊框 .attr("opacity", 1); }) .on("mouseout", function(event, d) { tooltip.transition().duration(200).style("opacity", 0).attr("class", ""); d3.select(this).select("circle") .transition().duration(150) .attr("stroke-width", 0.5) .attr("stroke", "#6b7280") // 恢復深色邊框 .attr("opacity", 0.9); });
// --- 泡泡邊框顏色調整 --- bubbles.append("circle") .attr("r", d => sizeScale(d.tariff)) .attr("fill", d => colorScale(d.tariff)) // 使用新的紅色比例尺 .attr("stroke", "#6b7280") // 深灰色邊框 .attr("stroke-width", 0.5) .attr("opacity", 0.9);
const labelGroup = svg.append("g") .attr("class", "labels") .style("pointer-events", "none");
const getLabelPosition = (country) => { const manualPositions = { /* ...保持不變... */ "中國": "right", "越南": "right", "柬埔寨": "left", "寮國": "top", "緬甸": "left", "留尼旺": "right", "馬達加斯加": "left", "泰國": "bottom", "斯里蘭卡": "top", "印尼": "bottom", "賴索托": "top", "台灣": "right", "塞爾維亞": "right", "孟加拉": "left", "伊拉克": "bottom", "日本": "top", "印度": "left", "巴西": "right", "澳洲": "right", "美國": "top", "歐盟": "top", "俄羅斯": "top" }; if (manualPositions[country.country]) return manualPositions[country.country]; if (country.x < 400) return "left"; return "right"; };
const getLabelCoordinates = (country, direction) => { const radius = sizeScale(country.tariff); const offset = 5; switch(direction) { /* ...保持不變... */ case "top": return { x: 0, y: -radius - offset, anchor: "middle" }; case "right": return { x: radius + offset, y: 4, anchor: "start" }; case "bottom": return { x: 0, y: radius + offset + 7, anchor: "middle" }; case "left": return { x: -radius - offset, y: 4, anchor: "end" }; default: return { x: radius + offset, y: 4, anchor: "start" }; } };
const countriesToShowLabel = tariffData.filter(d => d.tariff > 30 || ["美國", "中國", "歐盟", "俄羅斯", "印度", "巴西", "日本", "澳洲"].includes(d.country) );
countriesToShowLabel.forEach(country => { const labelPos = getLabelPosition(country); const coords = getLabelCoordinates(country, labelPos); const group = labelGroup.append("g") .attr("transform", `translate(${country.x}, ${country.y})`);
// --- 連接線顏色調整 --- if (labelPos === "left" || labelPos === "right") { group.append("line") .attr("x1", labelPos === "left" ? -sizeScale(country.tariff) : sizeScale(country.tariff)) .attr("y1", 0) .attr("x2", coords.x * 0.8) .attr("y2", 0) .attr("stroke", "#9ca3af") // 淺灰色線 .attr("stroke-width", 0.5) .attr("stroke-dasharray", "2,1"); }
// --- 標籤文字顏色和描邊調整 --- const labelColor = country.tariff > 40 ? "#f9fafb" : "#e5e7eb"; // 高關稅用亮白色,其他用淺灰 const labelWeight = country.tariff > 40 ? "bold" : "normal";
// 背景描邊 (用深色背景的顏色) group.append("text") .attr("x", coords.x) .attr("y", coords.y) .attr("text-anchor", coords.anchor) .attr("font-size", "11px") .attr("font-weight", labelWeight) .attr("stroke", "#1f2937") // 深灰色描邊 .attr("stroke-width", 3) .attr("stroke-linejoin", "round") .text(`${country.country} (${country.tariff}%)`);
// 前景文字 group.append("text") .attr("x", coords.x) .attr("y", coords.y) .attr("text-anchor", coords.anchor) .attr("font-size", "11px") .attr("font-weight", labelWeight) .attr("fill", labelColor) // 使用計算出的標籤顏色 .text(`${country.country} (${country.tariff}%)`); });
// --- 圖例文字顏色調整 --- const legendTextColor = "text-gray-300"; // 圖例文字用稍暗的淺灰
const colorLegendContainer = d3.select("#color-legend .flex"); const colorRates = [0, 10, 25, 50, 75]; colorRates.forEach((rate, i) => { const item = colorLegendContainer.append("div") .attr("class", "flex flex-col items-center"); item.append("div") .attr("class", "w-8 h-8 md:w-10 md:h-10 mb-1 md:mb-2 rounded-md shadow-sm border border-gray-600") // 加個邊框 .style("background-color", colorScale(rate)); // 自動使用新比例尺 let label = ''; if (i === 0) label = '0%'; else if (i === colorRates.length - 1) label = `${colorRates[i-1]+1}%+`; else label = `${colorRates[i-1]+1}-${rate}%`; item.append("span") .attr("class", `text-xs md:text-sm ${legendTextColor} font-medium`) // 應用文字顏色 .text(label); });
const sizeLegendContainer = d3.select("#size-legend .flex"); const sizeRates = [10, 25, 50, 75]; sizeRates.forEach(rate => { const item = sizeLegendContainer.append("div") .attr("class", "flex flex-col items-center"); const radius = sizeScale(rate); const svgSize = radius * 2 + 4; item.append("svg") .attr("width", svgSize) .attr("height", svgSize) .append("circle") .attr("cx", radius + 2) .attr("cy", radius + 2) .attr("r", radius) .attr("fill", "none") .attr("stroke", "#9ca3af") // 淺灰色圓圈 .attr("stroke-width", 1); item.append("span") .attr("class", `text-xs md:text-sm ${legendTextColor} font-medium mt-1`) // 應用文字顏色 .text(`${rate}%`); });
// --- 前五名列表文字顏色調整 --- const top5Countries = [...tariffData].sort((a, b) => b.tariff - a.tariff).slice(0, 5); const topCountriesContainer = d3.select("#top-countries .grid");
top5Countries.forEach((country, i) => { const item = topCountriesContainer.append("div") .attr("class", "flex flex-col items-center"); item.append("div") .attr("class", "w-10 h-10 md:w-12 md:h-12 rounded-full mb-2 md:mb-3 flex items-center justify-center font-bold text-white shadow-md text-sm md:text-base border border-gray-600") // 加邊框 .style("background-color", colorScale(country.tariff)) // 自動使用新比例尺 .text(i + 1); const textDiv = item.append("div").attr("class", "text-center"); textDiv.append("p").attr("class", "text-sm md:text-base font-bold text-gray-100").text(country.country); // 亮白 textDiv.append("p").attr("class", "text-lg md:text-2xl font-bold text-red-400").text(`${country.tariff}%`); // 紅色關稅數字 textDiv.append("p").attr("class", "text-xs md:text-sm text-gray-400").text(country.region); // 灰色地區 });
});</script>
https://www.spatialgeolab.com/parking_online_pay/
https://www.spatialgeolab.com/spatial-speedcamera/
[主題地圖]川普全球關稅戰統計地圖
https://www.spatialgeolab.com/thrump-tariffs-map/分類導覽
© 2026 GeoLab. All Rights Reserved.
