var startYear, endYear, startYM, endYM, lastMonthYM, lastYearYM;
var language=(((window.location.href.indexOf("GA28E"))>=0 || (window.location.href.indexOf("GA35E"))>=0)?"english":"chinese");
var isHomePage=((window.location.href.indexOf("GA35"))>=0?true:false);
$(document).ready(function($) {
// 圖表列印、下載選單
$(".chart-menu").hover(function() {
$(this).find(".chart-menu-option").show();
$(this).css("height", "90px");
}, function() {
$(this).find(".chart-menu-option").hide();
$(this).css("height", "30px");
});
// 取得圖表基本資料
$.ajax({
url: 'GA28_getChartData',
type: "POST",
dataType: "json",
data: {
"searchInfo.Type": "info",
"searchInfo.Notes": language
},
success: function(data) {
// 年月起訖
startYear=data[0]["startYear"];
endYear=data[0]["endYear"];
startYM=data[0]["startYM"];
endYM=data[0]["endYM"];
lastMonthYM=data[0]["lastMonthYM"];
lastYearYM=data[0]["lastYearYM"];
// 當月進出口總值增減率
let thisMonthIm=Number(data[0]["thisMonthIm"]);
let thisMonthEx=Number(data[0]["thisMonthEx"]);
let lastMonthComparisonRateIm=Number(data[0]["lastMonthComparisonRateIm"]);
let lastYearComparisonRateIm=Number(data[0]["lastYearComparisonRateIm"]);
let lastMonthComparisonRateEx=Number(data[0]["lastMonthComparisonRateEx"]);
let lastYearComparisonRateEx=Number(data[0]["lastYearComparisonRateEx"]);
let ifnoText=data[0]["infoText"];
// 更新上方標題
$("#info-title").append(language=="chinese"?endYM.substr(0,3)+"年"+Number(endYM.substr(3))+"月 ":(Number(endYM.substr(0,3))+1911)+"/"+endYM.substr(3));
// 更新左邊圖表
let monthText=["", "Jan.", "Feb.", "Mar.", "Apr.", "May.", "Jun.", "Jul.", "Aug.", "Sep.", "Oct.", "Nov.", "Dec."];
$("#info-title-en").append(monthText[Number(lastYearYM.substr(3))]);
$("#this-month-im").append(language=="chinese"?thisMonthIm:thisMonthIm.toFixed(1));
$("#this-month-ex").append(language=="chinese"?thisMonthEx:thisMonthEx.toFixed(1));
$("#last-month-im").append(Math.abs(lastMonthComparisonRateIm).toFixed(1)+"%");
$("#last-year-im").append(Math.abs(lastYearComparisonRateIm).toFixed(1)+"%");
$("#last-month-ex").append(Math.abs(lastMonthComparisonRateEx).toFixed(1)+"%");
$("#last-year-ex").append(Math.abs(lastYearComparisonRateEx).toFixed(1)+"%");
$("#last-month-im span").addClass(Math.sign(lastMonthComparisonRateIm)==1?"caret-up":"caret-down");
$("#last-year-im span").addClass(Math.sign(lastYearComparisonRateIm)==1?"caret-up":"caret-down");
$("#last-month-ex span").addClass(Math.sign(lastMonthComparisonRateEx)==1?"caret-up":"caret-down");
$("#last-year-ex span").addClass(Math.sign(lastYearComparisonRateEx)==1?"caret-up":"caret-down");
// 更新右邊文字說明
$("#info-text").text(ifnoText);
if(isHomePage){
chart1();
}
else{
chart1();
chart2();
chart3();
}
}
});
// 設定header、footer寬度符合內容
$("#Header, #Nav, #Footer").width($("body>table").width());
// 配合視窗大小調整內容
$( window ).resize(function() {
$("#Header, #Nav, #Footer").width($("body>table").width());
// 貨品圖例置中
$("#c2_2_legned").css("left", $("#c2_1").width()+(($("#c2_2").width()-c22LegendWidth)/2)+"px");
// 貿易夥伴圖例置中
$("#c3_2_legned").css("left", ($("#c3_1").width()+$("#c3_2").width()-c32LegendWidth-c32Margin.right)+"px");
});
});
//字型大小
var axisFontSize="14px";
//顏色
var backgroundColor="#FFFCF9";
var barColor={"import": "#F4849F", "export": "#118AB2", "highlight": "#FFD166", "surplus": "#06D6A0"};
var lineColor="#C9CBA3";
var partnerColor={"A01": "#F5CAC3", "A02": "#C9CBA3", "A03": "#F7E3AF", "A04": "#B0D0D3", "A05": "#F7AF9D", "A06": "#B8BEDD", "A07": "#F6BD60", "A08": "#50808E", "A09": "#9A8C98"};
var goodsTypeColor={"1": "#F5CAC3", "2": "#C9CBA3", "3": "#F7E3AF", "4": "#B0D0D3", "5": "#F7AF9D", "6": "#B8BEDD", "7": "#F6BD60", "8": "#50808E", "9": "#9A8C98", "10": "#97A7B3", "11": "#A8577E"};
//延遲時間
var duration = 2000;
// ========== 進出口總值 ==========
// 座標軸名稱
var c1YLeftLabelWithUnit=language=="chinese"?"金額(百萬美元)":"Value(Million US$)";
var c1YRightLabelWithUnit=language=="chinese"?"年增率(%)":"YOY(%)";
var c1YLeftLabel=c1YLeftLabelWithUnit.split("(")[0];
var c1YRightLabel=c1YRightLabelWithUnit.split("(")[0];
// 設定圖表長寬與邊框寬度
var c1Margin = isHomePage?{top: 20, right: 70, bottom: 90, left: 85}:{top: 50, right: 70, bottom: 90, left: 85};
var c1LegendY1 = 0;
var c1Width = $("#CONTENT form").width() - c1Margin.left - c1Margin.right,
c1Height = 500 - c1Margin.top - c1Margin.bottom;
// Tooltip物件
var c1Tooltip = addTooltip(d3.select("#c1"));
// svg物件
var c1Svg = addSvg(d3.select("#c1"), c1Width, c1Height, c1Margin, "");
c1Svg.selectAll(".axis-title, .legend").remove();
// Legend 圖例
let c1LegendY=c1Height+60+c1LegendY1;
var c1YLeftLegend=addLegend(c1Svg, 0, c1LegendY, barColor["export"], c1YLeftLabelWithUnit);
addLegend(c1Svg, 180, c1LegendY, lineColor, c1YRightLabelWithUnit);
// Y軸(左邊)名稱
addAxisTitle(c1Svg, -c1Margin.top-(c1Height/2)+20, -c1Margin.left+22, "rotate(-90)", c1YLeftLabel);
// Y軸(右邊)名稱
addAxisTitle(c1Svg, c1Margin.top+(c1Height/2)+21, -c1Width-c1Margin.right+25, "rotate(90)", c1YRightLabel);
// X軸(年/月)
var c1X = d3.scaleBand()
.range([ 0, c1Width ])
.padding(0.2);
var c1XAxisGenerator = d3.axisBottom(c1X);
var c1XAxis=c1Svg.append("g")
.style("font", axisFontSize)
.attr("transform", "translate(0," + c1Height + ")");
// Y軸(左邊): 金額
var c1YLeft = d3.scaleLinear()
.range([c1Height, 0])
.nice();
var c1YLeftAxis = c1Svg.append("g")
.style("font", axisFontSize);
// Y軸(右邊): 年增率
var c1YRight = d3.scaleLinear()
.range([c1Height, 0])
.nice();
var c1YRightAxisGenerator = d3.axisRight(c1YRight);
var c1YRightAxis = c1Svg.append("g")
.style("font", axisFontSize)
.attr("transform", "translate("+c1Width+",0)");
var lastC1TypeTime="";
function chart1(){
// 進出口總值標題
$("#c1Title").html($("label[for='"+$("input[name='c1TypePort']:checked")[0].id+"']").text());
// 取得查詢條件
let typePort=$("input[name='c1TypePort']:checked").val();
let typeTime=$("input[name='c1TypeTime']:checked").val();
if(typeTime=="year" && lastC1TypeTime!="year"){
c1Margin.bottom-=25;
c1LegendY1=-25;
}
else if(typeTime=="month" && lastC1TypeTime=="year"){
c1Margin.bottom+=25;
c1LegendY1=0;
}
c1Width = $("#c1").width() - c1Margin.left - c1Margin.right;
c1Height = 500 - c1Margin.top - c1Margin.bottom;
// 調整svg排版
d3.select("#c1>svg")
.attr("width", c1Width + c1Margin.left + c1Margin.right)
.attr("height", c1Height + c1Margin.top + c1Margin.bottom);
c1Svg.attr("transform", "translate(" + c1Margin.left + "," + c1Margin.top + ")");
d3.select("#c1 svg text.axis-title:nth-child(6)")
.attr("y", -c1Width-c1Margin.right+25);
// 調整圖例顏色
c1YLeftLegend.style("fill", barColor[typePort]);
// 讀取資料
d3.json('GA28_getChartData', {
method:"POST",
body: new URLSearchParams({
"searchInfo.Type": "c1",
"searchInfo.TypePort": typePort,
"searchInfo.TypeTime": typeTime,
"searchInfo.StartYear": startYear,
"searchInfo.StartMonth": startYM,
"searchInfo.EndYear": endYear,
"searchInfo.EndMonth": endYM
}),
headers: {
"Content-type": "application/x-www-form-urlencoded"
}
}).then( function(data) {
data.forEach(function(d) {
if(language=="chinese"){
d.year = d.year+"年";
if(typeTime=="month"){
d.month = d.month+"月";
}
}
else{
d.year = d.year+1911;
}
});
// X軸(年/月)
c1X.range([ 0, c1Width ])
.domain(data.map(d => typeTime=="month"?d.year+"|"+d.month:d.year));
c1XAxisGenerator = d3.axisBottom(c1X)
.tickFormat(d => typeTime=="month"?d.split("|")[1]:d);
c1XAxis.attr("transform", "translate(0," + c1Height + ")")
.transition().duration(duration).call(c1XAxisGenerator);
if(typeTime=="year" && lastC1TypeTime=="month"){
c1XAxis.selectAll("g.tick line").remove();
c1Svg.selectAll(".c1XAxis").remove();
}
else if(typeTime=="month" && lastC1TypeTime!="month"){
c1XAxis.selectAll("path").remove();
c1XAxis.selectAll("line").remove();
// X軸(年): 框線
const xYear = d3.scaleBand()
.range([ 0, c1Width ])
.domain(data.map(d => typeTime=="month"?d.year+"|"+d.month:d.year))
.padding(0.2);
const xYearAxisGenerator = fc.axisOrdinalBottom(xYear);
xYearAxisGenerator
.tickValues(xYear.domain().filter(function(d,i){
let mm=d.split("|")[1];
if(mm=="12月" || mm=="12" || i==xYear.domain().length-1){
return true;
}
return false;
}))
.tickFormat(d => "")
.tickSize(40);
const xYearAxis=c1Svg.append("g")
.attr("class", "c1XAxis")
.attr("transform", "translate(0," + c1Height + ")")
.transition().duration(duration).call(xYearAxisGenerator);
xYearAxis.selectAll("text").remove();
// X軸(年): 文字
const xYearAxisGenerator1 = fc.axisOrdinalBottom(xYear);
let nowYear="";
xYearAxisGenerator1.tickFormat(function(d){
let yyy=d.split("|")[0];
if(yyy!=nowYear){
nowYear=yyy;
return yyy;
}
return "";
});
const xYearAxis1=c1Svg.append("g")
.attr("class", "c1XAxis")
.style("font", axisFontSize)
.attr("transform", "translate(0," + (c1Height+24) + ")")
.call(xYearAxisGenerator1);
xYearAxis1.selectAll("path").remove();
xYearAxis1.selectAll("line").remove();
}
// 更新Y軸(左邊)
c1YLeft.range([c1Height, 0])
.domain([0, d3.max(data, d => d.godValue)])
.nice();
c1YLeftAxis.transition().duration(duration).call(d3.axisLeft(c1YLeft));
// 更新Y軸(右邊)
c1YRight.range([c1Height, 0])
.domain([d3.min(data, d => d.YOY), d3.max(data, d => d.YOY)])
.nice();
c1YRightAxisGenerator.tickFormat(function(d){return d+"%";});
c1YRightAxis.transition().duration(duration).attr("transform", "translate("+c1Width+",0)").call(c1YRightAxisGenerator);
// 長條圖: 金額
c1Svg.selectAll(".bar")
.data(data)
.join("rect")
.attr("id", function(d, i){return "c1Bar_"+i;})
.attr("class", "bar")
.attr("x", d => c1X(typeTime=="month"?d.year+"|"+d.month:d.year))
.attr("y", d => c1YLeft(0))
.attr("width", c1X.bandwidth())
.attr("height", d => c1Height - c1YLeft(0))
.attr("fill", barColor[typePort]);
// 折線圖: 年增率
c1Svg.select("#c1LinePath").remove();
const linePath=c1Svg.append("path")
.interrupt()
.datum(data)
.attr("id", "c1LinePath")
.attr("fill", "none")
.attr("stroke", lineColor)
.attr("stroke-width", 2.5)
.attr("d", d3.line()
.x(d => c1X(typeTime=="month"?d.year+"|"+d.month:d.year) + c1X.bandwidth() / 2)
.y(d => c1YRight(d.YOY))
.curve(d3.curveMonotoneX)
);
// 折線圖上的點
c1Svg.selectAll("circle").remove();
const lineCircle=c1Svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("id", function(d, i){return "c1Circle_"+i;})
.attr("fill", lineColor)
.attr("r", 0)
.attr("cx", d => c1X(typeTime=="month"?d.year+"|"+d.month:d.year) + c1X.bandwidth() / 2)
.attr("cy", d => c1YRight(d.YOY));
// 透明長條圖 tooltip用
c1Svg.selectAll(".bar-for-tooltip")
.data(data)
.join("rect")
.attr("id", function(d, i){return "idx_"+i;})
.attr("class", "bar-for-tooltip")
.style("opacity", 0)
.attr("x", d => c1X(typeTime=="month"?d.year+"|"+d.month:d.year))
.attr("y", d => c1YLeft(0))
.attr("width", c1X.bandwidth())
.attr("height", d => c1Height - c1YLeft(0))
// 滑鼠移入: 改變顏色並顯示tooltip
.on("mouseover", function(event, d) {
controlC1Tooltip(this.id.split("_")[1], barColor["highlight"], 5, "show");
// 顯示tooltip
c1Tooltip.html(d.year+(typeTime=="month"?(language=="english"?"/":"")+d.month:"")+"
"+c1YLeftLabel+": "+d.godValue.toLocaleString('en-US')+"
"+c1YRightLabel+": "+d.YOY.toFixed(2)+"%");
moveTooltip("#c1", c1Tooltip, event);
})
// 滑鼠移動: 改變tooltip位置
.on("mousemove", function(event, d) {
moveTooltip("#c1", c1Tooltip, event);
})
// 滑鼠移出: 恢復顏色並隱藏tooltip
.on("mouseout", function(d) {
controlC1Tooltip(this.id.split("_")[1], barColor[typePort], 3, "hide");
});
let each_delay = duration/data.length; //計算讀取物件長度,計算每個項目所分到的延遲時間
// 動畫: 長條圖
animationBar(c1Svg, ".bar",
d => c1YLeft(d.godValue),
d => c1Height - c1YLeft(d.godValue),
each_delay);
animationBar(c1Svg, ".bar-for-tooltip",
d => c1YLeft(d.godValue) c1Height-(c1YLeft(d.godValue) typeTime=="month"?d.year+"|"+d.month:d.year));
c23XAxisGenerator = d3.axisBottom(c23X)
.tickFormat(d => typeTime=="month"?d.split("|")[1]:d);
c23XAxis.attr("transform", "translate(0," + c23Height + ")")
.transition().duration(duration).call(c23XAxisGenerator);
if(typeTime=="year" && lastC23TypeTime=="month"){
c23XAxis.selectAll("g.tick line").remove();
c23Svg.selectAll(".c23XAxis").remove();
}
else if(typeTime=="month" && lastC23TypeTime!="month"){
c23XAxis.selectAll("path").remove();
c23XAxis.selectAll("line").remove();
// X軸(年): 框線
const xYear = d3.scaleBand()
.range([ 0, c23Width ])
.domain(data.map(d => typeTime=="month"?d.year+"|"+d.month:d.year))
.padding(0.2);
const xYearAxisGenerator = fc.axisOrdinalBottom(xYear);
xYearAxisGenerator
.tickValues(xYear.domain().filter(function(d,i){
let mm=d.split("|")[1];
if(mm=="12月" || mm=="12" || i==xYear.domain().length-1){
return true;
}
return false;
}))
.tickFormat(d => "")
.tickSize(40);
const xYearAxis=c23Svg.append("g")
.attr("class", "c23XAxis")
.attr("transform", "translate(0," + c23Height + ")")
.transition().duration(duration).call(xYearAxisGenerator);
xYearAxis.selectAll("text").remove();
// X軸(年): 文字
const xYearAxisGenerator1 = fc.axisOrdinalBottom(xYear);
let nowYear="";
xYearAxisGenerator1.tickFormat(function(d){
let yyy=d.split("|")[0];
if(yyy!=nowYear){
nowYear=yyy;
return yyy;
}
return "";
});
const xYearAxis1=c23Svg.append("g")
.attr("class", "c23XAxis")
.style("font", axisFontSize)
.attr("transform", "translate(0," + (c23Height+24) + ")")
.call(xYearAxisGenerator1);
xYearAxis1.selectAll("path").remove();
xYearAxis1.selectAll("line").remove();
}
// 更新Y軸(左邊)
const c23YLeftScale=c23YLeft.range([c23Height, 0])
.domain([0, d3.max(data, d => d.godValue)])
.nice();
const c23YLeftMinValue = c23YLeftScale.domain()[0];
const c23YLeftMaxValue = c23YLeftScale.domain()[1];
const c23YLeftTicksAmount = 5;
const c23YLeftTickStep = (c23YLeftMaxValue - c23YLeftMinValue) / (c23YLeftTicksAmount);
const c23YLeftStep = Math.ceil(c23YLeftTickStep / 5) * 5;
c23YLeftAxisGenerator
.ticks(c23YLeftTicksAmount)
.tickValues(d3.range(c23YLeftMinValue, c23YLeftMaxValue + c23YLeftStep, c23YLeftStep));
c23YLeftAxis.transition().duration(duration).call(c23YLeftAxisGenerator);
// 更新Y軸(右邊)
const c23YRightScale=c23YRight.range([c23Height, 0])
.domain([d3.min(data, d => d.YOY), d3.max(data, d => d.YOY)])
.nice();
const c23YRightMinValue = c23YRightScale.domain()[0];
const c23YRightMaxValue = c23YRightScale.domain()[1];
const c23YRightTicksAmount = 6;
const c23YRightTickStep = (c23YRightMaxValue - c23YRightMinValue) / (c23YRightTicksAmount);
const c23YRightStep = Math.ceil(c23YRightTickStep / 5) * 5;
c23YRightAxisGenerator
.ticks(c23YRightTicksAmount)
.tickValues(d3.range(c23YRightMinValue, c23YRightMaxValue + c23YRightStep, c23YRightStep))
.tickFormat(function(d){return d+"%";});
// c23YRightAxisGenerator.tickFormat(function(d){return d+"%";});
c23YRightAxis.transition().duration(duration).attr("transform", "translate("+c23Width+",0)").call(c23YRightAxisGenerator);
// 長條圖: 金額
c23Svg.selectAll(".bar")
.data(data)
.join("rect")
.attr("id", function(d, i){return "c23Bar_"+i;})
.attr("class", "bar")
.attr("x", d => c23X(typeTime=="month"?d.year+"|"+d.month:d.year))
.attr("y", d => c23YLeft(0))
.attr("width", c23X.bandwidth())
.attr("height", d => c23Height - c23YLeft(0))
.attr("fill", (d, i) => (i==data.length-1)?barColor["highlight"]:barColor[typePort]);
// 折線圖: 年增率
if($("#c23LinePath").length==0){
c23Svg.append("path").attr("id", "c23LinePath");
}
const linePath=c23Svg.select("#c23LinePath")
.datum(data)
.attr("fill", "none")
.attr("stroke", lineColor)
.attr("stroke-width", 2.5)
.attr("d", d3.line()
.x(d => c23X(typeTime=="month"?d.year+"|"+d.month:d.year) + c23X.bandwidth() / 2)
.y(d => c23YRight(d.YOY))
.curve(d3.curveMonotoneX)
);
c23Svg.select("#c23LinePath").raise();
// 折線圖上的點
c23Svg.selectAll("circle")
.data(data)
.join("circle")
.attr("id", function(d, i){return "c23Circle_"+i;})
.attr("fill", lineColor)
.attr("r", 0)
.attr("cx", d => c23X(typeTime=="month"?d.year+"|"+d.month:d.year) + c23X.bandwidth() / 2)
.attr("cy", d => c23YRight(d.YOY));
let lastIdx=data.length-1;
// 透明長條圖 tooltip用
c23Svg.selectAll(".bar-for-tooltip")
.data(data)
.join("rect")
.attr("id", function(d, i){return "idx_"+i;})
.attr("class", "bar-for-tooltip")
.style("opacity", 0)
.attr("x", d => c23X(typeTime=="month"?d.year+"|"+d.month:d.year))
.attr("y", d => c23YLeft(0))
.attr("width", c23X.bandwidth())
.attr("height", d => c23Height - c23YLeft(0))
// 滑鼠移入: 改變顏色並顯示tooltip
.on("mouseover", function(event, d) {
let idx=this.id.split("_")[1];
if(idx!=lastIdx){
// 更新上方圖表
year=d.year.toString().replace("年", "");
month=(typeTime=="month")?d.month.toString().replace("月", "").padStart(2, "0"):"";
chart2_1(typePort, typeTime, year, month, goodsType);
chart2_2(typePort, typeTime, year, month, goodsType);
// 恢復前一個的顏色
d3.select("#c23Bar_"+lastIdx).attr("fill", barColor[typePort]);
// 恢復前一個的圓點大小
d3.select("#c23Circle_"+lastIdx).attr("r", 3);
// 改變長條圖顏色
d3.select("#c23Bar_"+idx).attr("fill", barColor["highlight"]);
// 改變折線圖圓點大小
d3.select("#c23Circle_"+idx).attr("r", 5);
lastIdx=idx;
}
// 顯示tooltip
c23Tooltip.html(d.year+(typeTime=="month"?(language=="english"?"/":"")+d.month:"")+"
"+c23YLeftLabel+": "+d.godValue.toLocaleString('en-US')+"
"+c23YRightLabel+": "+d.YOY.toFixed(2)+"%");
controlTooltip(c23Tooltip, "show");
moveC23Tooltip(this.id.split("_")[1], data.length, event);
})
// 滑鼠移動: 改變tooltip位置
.on("mousemove", function(event, d) {
moveC23Tooltip(this.id.split("_")[1], data.length, event);
})
// 滑鼠移出: 恢復顏色並隱藏tooltip
.on("mouseout", function(d) {
// 隱藏tooltip
controlTooltip(c23Tooltip, "hide");
});
let each_delay = duration/data.length; //計算讀取物件長度,計算每個項目所分到的延遲時間
// 動畫: 長條圖
animationBar(c23Svg, ".bar",
d => c23YLeft(d.godValue),
d => c23Height - c23YLeft(d.godValue),
each_delay);
animationBar(c23Svg, ".bar-for-tooltip",
d => c23YLeft(d.godValue) c23Height-(c23YLeft(d.godValue) d.godValue)]);
// 更新Y軸
c21Y.range([0, c21Height])
.domain(data.map(d => d.goodsType));
c21YAxis.transition().duration(duration).call(d3.axisLeft(c21Y));
//隱藏框線
c21YAxis.selectAll("path").remove();
c21YAxis.selectAll("line").remove();
// 長條圖: 金額
c21Svg.selectAll(".bar")
.data(data)
.join("rect")
.attr("class", "bar")
.attr("x", d => c21X(0))
.attr("y", d => c21Y(d.goodsType))
.attr("width", d => c21X(0))
.attr("height", c21Y.bandwidth())
.attr("fill", d => goodsType==d.goodsTypeKey?barColor["highlight"]:barColor[typePort]);
// 長條圖數值
c21Svg.selectAll(".bar-text")
.data(data)
.join("text")
.attr("class", "bar-text")
.attr("fill", "currentColor")
.attr("text-anchor", "middle")
.attr("y", d => c21Y(d.goodsType)+c21Y.bandwidth()-7)
.text(d => d.godValue.toLocaleString('en-US'));
let each_delay = duration/data.length; //計算讀取物件長度,計算每個項目所分到的延遲時間
// 動畫: 長條圖
animationBarWithText(c21Svg,
".bar", d => c21X(d.godValue),
".bar-text", d => c21X(d.godValue)+25,
each_delay);
});
}
//---------- 右上 夥伴國別結構圖。 ----------
//設定圖表長寬與邊框寬度
var c22Margin = {top: 0, right: 0, bottom: 10, left: 0};
var c22Width = $("#c2_2").width(),
c22Height = 300;
var c22Radius = Math.min(c22Width, c22Height) / 2 ;
var c22Arc=d3.arc()
.innerRadius(100)
.outerRadius(c22Radius);
// Tooltip物件
var c22Tooltip = addTooltip(d3.select("#c2_2"));
// svg物件
var c22Svg = addSvg(d3.select("#c2_2"), c22Width, c22Height-c22Margin.bottom, c22Margin, "translate(" + (c22Width/2) + "," + (c22Height-c22Margin.bottom) + ")");
var c22LegendWidth = $("#c2_2_legned").width();
function chart2_2(typePort, typeTime, year, month, goodsType){
// 貨品標題
let c2Title="";
if(language=="chinese"){
c2Title=year+"年"+(typeTime=="month"?month+"月":"")+
$("label[for='"+$("input[name='c2GoodsType']:checked")[0].id+"']").text().replaceAll(" ", "")+
$("label[for='"+$("input[name='c2TypePort']:checked")[0].id+"']").text().replace("總值", "")+
"概況";
}
else{
c2Title=year+(typeTime=="month"?"/"+month:"")+" "+
$("label[for='"+$("input[name='c2TypePort']:checked")[0].id+"']").text().replace("Total ", "")+" of “"+
$("label[for='"+$("input[name='c2GoodsType']:checked")[0].id+"']").text()+"”";
}
$("#c2Title .chart-title").html(c2Title);
if(language=="english"){
year=year-1911;
}
// 讀取資料
d3.json('GA28_getChartData', {
method:"POST",
body: new URLSearchParams({
"searchInfo.Type": "c22",
"searchInfo.TypePort": typePort,
"searchInfo.TypeTime": typeTime,
"searchInfo.startYear": year,
"searchInfo.startMonth": month,
"searchInfo.GoodsType": goodsType,
"searchInfo.Notes": language
}),
headers: {
"Content-type": "application/x-www-form-urlencoded"
}
}).then( function(data) {
let keyList=getKeyList("partner", data);
let colorList=getColorList("partner", keyList);
// 圖例
let godValueSum=0;
data.forEach(function(d) {
$("#legend_"+d.partnerKey).css("background-color", partnerColor[d.partnerKey]);
godValueSum+=d.godValue;
});
data.forEach(function(d) {
$("#legend_percent_"+d.partnerKey).text((Math.round(d.godValue*100*100/godValueSum)/100).toFixed(2)+"%");
});
// 圖例置中
$("#c2_2_legned").css("top", $("#c2Title").height()+10+"px");
$("#c2_2_legned").css("left", $("#c2_1").width()+(($("#c2_2").width()-$("#c2_2_legned").width())/2)+"px");
const color = d3.scaleOrdinal()
.domain(keyList)
.range(colorList);
addPie(c22Svg, c22Tooltip, "2", data, color, c22Arc, "partner");
});
}
// ========== 貿易夥伴 ==========
// 根據視窗大小調整統計圖比例
if(window.innerWidth<1500){
$("#c3_1").css("width", "40%");
$("#c3_2").css("width", "60%");
}
else{
$("#c3_1, #c3_2").css("width", "50%");
}
//---------- 下 國家/區域進出口值趨勢圖 ----------
//座標軸名稱
var c3LabelExport=language=="chinese"?"出口總值":"Total Exports";
var c3LabelImport=language=="chinese"?"進口總值":"Total Imports";
var c3LabelSurplus=language=="chinese"?"出超":"Surplus";
//設定圖表長寬與邊框寬度
// 暫時隱藏Y軸
// var c33Margin = {top: 15, right: 10, bottom: 90, left: 70};
var c33Margin = {top: 15, right: 10, bottom: 90, left: 10};
var c33LegendY1 = 0;
var c33Width = $("#c3_3").width() - c33Margin.left - c33Margin.right,
c33Height = 300 - c33Margin.top - c33Margin.bottom;
// Tooltip物件
var c33Tooltip = addTooltip(d3.select("#c3_3"));
// svg物件
var c33Svg = addSvg(d3.select("#c3_3"), c33Width, c33Height, c33Margin, "");
// Clip物件
var c33Clip = c33Svg.append("clipPath")
.attr("id", "c33Clip");
var c33ClipRect = c33Clip.append("rect")
.attr("width", 0)
.attr("height", c33Height)
c33Svg.selectAll(".axis-title, .legend").remove();
// Legend 圖例
let c33LegendY=c33Height+60+c33LegendY1;
addLegend(c33Svg, 0, c33LegendY, barColor["export"], c3LabelExport);
addLegend(c33Svg, 140, c33LegendY, barColor["import"], c3LabelImport);
addLegend(c33Svg, 280, c33LegendY, barColor["surplus"], c3LabelSurplus);
// X軸(年/月)
var c33X = d3.scaleBand()
.range([ 0, c33Width ]);
var c33XAxisGenerator = d3.axisBottom(c33X);
var c33XAxis=c33Svg.append("g")
.style("font", axisFontSize)
.attr("transform", "translate(0," + c33Height + ")");
// Y軸: 金額 暫時隱藏Y軸
var c33Y = d3.scaleLinear()
.range([c33Height, 0])
.nice();
// var c33YAxis = c33Svg.append("g")
// .style("font", axisFontSize);
//出超區塊樣式
const surplusPattern = c33Svg
.append("pattern")
.attr("id", "surplus-pattern")
.attr("height", 1)
.attr("width", 0.005);
surplusPattern.append("rect").attr("height", "100%").attr("width", "100%").attr("fill", barColor["surplus"]);
surplusPattern
.append("rect")
.attr("x", 3)
.attr("y", 0)
.attr("height", "100%")
.attr("width", "3px")
.attr("fill", backgroundColor);
var lastC33TypeTime="", lastC33Partner="";
function chart3(){
// 取得查詢條件
let typeTime=$("input[name='c3TypeTime']:checked").val();
let partner=$("input[name='c3Partner']:checked").val();
let year="", month="";
//---------- 下 國家/區域進出口值趨勢圖 ----------
if(typeTime=="year" && lastC33TypeTime!="year"){
c33Margin.bottom-=25;
c33LegendY1=-25;
}
else if(typeTime=="month" && lastC33TypeTime=="year"){
c33Margin.bottom+=25;
c33LegendY1=0;
}
c33Width = $("#c3_3").width() - c33Margin.left - c33Margin.right;
c33Height = 300 - c33Margin.top - c33Margin.bottom;
// 調整svg排版
d3.select("#c3_3 svg")
.attr("width", c33Width + c33Margin.left + c33Margin.right)
.attr("height", c33Height + c33Margin.top + c33Margin.bottom);
c33Svg.attr("transform", "translate(" + c33Margin.left + "," + c33Margin.top + ")");
// 讀取資料
d3.json('GA28_getChartData', {
method:"POST",
body: new URLSearchParams({
"searchInfo.Type": "c33",
"searchInfo.TypeTime": typeTime,
"searchInfo.CountryName": partner,
"searchInfo.StartYear": startYear,
"searchInfo.StartMonth": startYM,
"searchInfo.EndYear": endYear,
"searchInfo.EndMonth": endYM
}),
headers: {
"Content-type": "application/x-www-form-urlencoded"
}
}).then( function(data) {
data.forEach(function(d) {
if(language=="chinese"){
d.year = d.year+"年";
if(typeTime=="month"){
d.month = d.month+"月";
}
}
else{
d.year = d.year+1911;
}
});
// X軸(年/月)
c33X.range([ 0, c33Width ])
.domain(data.map(d => typeTime=="month"?d.year+"|"+d.month:d.year));
c33XAxisGenerator = d3.axisBottom(c33X)
.tickFormat(d => typeTime=="month"?d.split("|")[1]:d);
c33XAxis.attr("transform", "translate(0," + c33Height + ")")
.transition().duration(duration).call(c33XAxisGenerator);
if(typeTime=="year" && lastC33TypeTime=="month"){
c33XAxis.selectAll("g.tick line").remove();
c33Svg.selectAll(".c33XAxis").remove();
}
else if(typeTime=="month" && lastC33TypeTime!="month"){
c33XAxis.selectAll("path").remove();
c33XAxis.selectAll("line").remove();
// X軸(年): 框線
const xYear = d3.scaleBand()
.range([ 0, c33Width ])
.domain(data.map(d => typeTime=="month"?d.year+"|"+d.month:d.year));
const xYearAxisGenerator = fc.axisOrdinalBottom(xYear);
xYearAxisGenerator
.tickValues(xYear.domain().filter(function(d,i){
let mm=d.split("|")[1];
if(mm=="12月" || mm=="12" || i==xYear.domain().length-1){
return true;
}
return false;
}))
.tickFormat(d => "")
.tickSize(40);
const xYearAxis=c33Svg.append("g")
.attr("class", "c33XAxis")
.attr("transform", "translate(0," + c33Height + ")")
.transition().duration(duration).call(xYearAxisGenerator);
xYearAxis.selectAll("text").remove();
// X軸(年): 文字
const xYearAxisGenerator1 = fc.axisOrdinalBottom(xYear);
let nowYear="";
xYearAxisGenerator1.tickFormat(function(d){
let yyy=d.split("|")[0];
if(yyy!=nowYear){
nowYear=yyy;
return yyy;
}
return "";
});
const xYearAxis1=c33Svg.append("g")
.attr("class", "c33XAxis")
.style("font", axisFontSize)
.attr("transform", "translate(0," + (c33Height+24) + ")")
.call(xYearAxisGenerator1);
xYearAxis1.selectAll("path").remove();
xYearAxis1.selectAll("line").remove();
}
// 更新Y軸
c33Y.range([c33Height, 0])
.domain([0, d3.max(data, d => d.importGodValue>d.exportGodValue?d.importGodValue:d.exportGodValue)])
.nice();
// c33YAxis.transition().duration(duration).call(d3.axisLeft(c33Y));
// 出超區塊
c33ClipRect.attr("width", 0);
c33Svg.select("#c33AreaSurplus").remove();
c33Svg.append("path")
.datum(data)
.attr("id", "c33AreaSurplus")
.attr("fill", "url(#surplus-pattern)")
.attr("d", d3.area()
.x(d => c33X(typeTime=="month"?d.year+"|"+d.month:d.year) + c33X.bandwidth() / 2)
.y0(d => d.exportGodValue>d.importGodValue?c33Y(d.importGodValue):c33Y(d.exportGodValue))
.y1(d => c33Y(d.exportGodValue))
.curve(d3.curveMonotoneX)
)
.attr("clip-path", "url(#c33Clip)");
// 遮住多餘的區塊
c33Svg.select("#c33AreaImport").remove();
c33Svg.append("path")
.datum(data)
.attr("id", "c33AreaImport")
.attr("fill", backgroundColor)
.attr("d", d3.area()
.x(d => c33X(typeTime=="month"?d.year+"|"+d.month:d.year) + c33X.bandwidth() / 2)
.y0(d => c33Y(0))
.y1(d => c33Y(d.importGodValue))
.curve(d3.curveMonotoneX)
);
c33Svg.select("#c33AreaImport").lower();
c33Svg.select("#c33AreaSurplus").lower();
// 折線圖: 進口總值
c33Svg.select("#c33LinePathImport").remove();
const linePathImport=c33Svg.append("path")
.datum(data)
.attr("id", "c33LinePathImport")
.attr("fill", "none")
.attr("stroke", barColor["import"])
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(d => c33X(typeTime=="month"?d.year+"|"+d.month:d.year) + c33X.bandwidth() / 2)
.y(d => c33Y(d.importGodValue))
.curve(d3.curveMonotoneX)
);
// 折線圖上的點
c33Svg.selectAll(".c33CircleImport")
.data(data)
.join("circle")
.attr("id", function(d, i){return "c33CircleImport_"+i;})
.attr("class", "c33CircleImport")
.attr("fill", barColor["import"])
.attr("r", 0)
.attr("cx", d => c33X(typeTime=="month"?d.year+"|"+d.month:d.year) + c33X.bandwidth() / 2)
.attr("cy", d => c33Y(d.importGodValue));
// 折線圖: 出口總值
c33Svg.select("#c33LinePathExport").remove();
const linePathExport=c33Svg.append("path")
.datum(data)
.attr("id", "c33LinePathExport")
.attr("fill", "none")
.attr("stroke", barColor["export"])
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(d => c33X(typeTime=="month"?d.year+"|"+d.month:d.year) + c33X.bandwidth() / 2)
.y(d => c33Y(d.exportGodValue))
.curve(d3.curveMonotoneX)
);
// 折線圖上的點
c33Svg.selectAll(".c33CircleExport")
.data(data)
.join("circle")
.attr("id", function(d, i){return "c33CircleExport_"+i;})
.attr("fill", barColor["export"])
.attr("class", "c33CircleExport")
.attr("r", 0)
.attr("cx", d => c33X(typeTime=="month"?d.year+"|"+d.month:d.year) + c33X.bandwidth() / 2)
.attr("cy", d => c33Y(d.exportGodValue));
let lastIdx=data.length-1;
// 透明長條圖 tooltip用
c33Svg.selectAll(".bar-for-tooltip")
.data(data)
.join("rect")
.attr("id", function(d, i){return "idx_"+i;})
.attr("class", "bar-for-tooltip")
.style("fill", backgroundColor)
.style("opacity", (d, i) => (i==data.length-1)?0.5:0)
.attr("x", d => c33X(typeTime=="month"?d.year+"|"+d.month:d.year))
.attr("y", d => c33Y(0))
.attr("width", c33X.bandwidth())
.attr("height", d => c33Height - c33Y(0))
// 滑鼠移入: 改變顏色並顯示tooltip
.on("mouseover", function(event, d) {
let idx=this.id.split("_")[1];
if(idx!=lastIdx){
// 更新上方圖表
year=d.year.toString().replace("年", "");
month=(typeTime=="month")?d.month.toString().replace("月", "").padStart(2, "0"):"";
chart3_1(typeTime, year, month, partner);
chart3_2(typeTime, year, month, partner);
// 恢復前一個的顏色
c33Svg.select("#idx_"+lastIdx).style("opacity", 0);
// 恢復前一個的圓點大小
d3.select("#c33CircleExport_"+lastIdx).attr("r", 2);
d3.select("#c33CircleImport_"+lastIdx).attr("r", 2);
// 改變長條圖顏色
d3.select(this).style("opacity", 0.5);
// 改變折線圖圓點大小
d3.select("#c33CircleExport_"+idx).attr("r", 5);
d3.select("#c33CircleImport_"+idx).attr("r", 5);
lastIdx=idx;
}
// 顯示tooltip
c33Tooltip.html(d.year+(typeTime=="month"?(language=="english"?"/":"")+d.month:"")+"
"+
// 千元轉換成百萬元
c3LabelExport+": "+Math.round(d.exportGodValue/1000).toLocaleString('en-US')+"
"+
c3LabelImport+": "+Math.round(d.importGodValue/1000).toLocaleString('en-US'));
controlTooltip(c33Tooltip, "show");
moveC33Tooltip(this.id.split("_")[1], data.length, event);
})
// 滑鼠移動: 改變tooltip位置
.on("mousemove", function(event, d) {
moveC33Tooltip(this.id.split("_")[1], data.length, event);
})
// 滑鼠移出: 恢復顏色並隱藏tooltip
.on("mouseout", function(d) {
// 隱藏tooltip
controlTooltip(c33Tooltip, "hide");
});
c33Svg.selectAll(".bar-for-tooltip").raise();
let each_delay = duration/data.length; //計算讀取物件長度,計算每個項目所分到的延遲時間
// 動畫: 出超區塊
c33ClipRect.transition()
.duration(3000)
.ease(d3.easeSin)
.attr("width", c33Width);
// 動畫: 長條圖
animationBar(c33Svg, ".bar-for-tooltip",
// 包含空白的地方
d => 0,
d => c33Height,
// 僅包含進/出口之間
// d => (d.importGodValue>d.exportGodValue?c33Y(d.importGodValue):c33Y(d.exportGodValue))-30,
// d => (d.importGodValue +(b.importGodValue+b.exportGodValue) - +(a.importGodValue+a.exportGodValue));
// 更新X軸
c31X.range([ 0, c31Width ])
.domain([0, d3.max(data, d => d.importGodValue+d.exportGodValue)]);
// 更新Y軸
c31Y.range([0, c31Height])
.domain(data.map(d => d.partner));
c31YAxis.transition().duration(duration).call(d3.axisLeft(c31Y));
//隱藏框線
c31YAxis.selectAll("path").remove();
c31YAxis.selectAll("line").remove();
var c31SackedData = d3.stack().keys(["exportGodValue", "importGodValue"])(data);
// 長條圖: 金額
c31Svg.selectAll(".bar")
.data(c31SackedData)
// 按進/出口分組
.join("g")
.attr("class", "bar")
.attr("fill", d => c31Color(d.key))
.style("stroke", d => c31Color(d.key))
.style("stroke-width", 2)
.selectAll("rect")
// 進/出口的各個貿易夥伴
.data(d => d)
.join("rect")
.attr("x", d => c31X(d[0]))
.attr("y", d => c31Y(d.data.partner))
.attr("width", d => c31X(0))
.attr("height", c31Y.bandwidth())
.attr("fill", d => partner==d.data.partnerKey?barColor["highlight"]:"");
// 長條圖數值
c31Svg.selectAll(".bar-text")
.data(data)
.join("text")
.attr("class", "bar-text")
.attr("fill", "currentColor")
.attr("text-anchor", "middle")
.attr("y", d => c31Y(d.partner)+c31Y.bandwidth()-7)
//總值 千元轉換成百萬元
.text(d => Math.round((d.exportGodValue+d.importGodValue)/1000).toLocaleString('en-US'));
// 透明長條圖 tooltip用
c31Svg.selectAll(".bar-for-tooltip")
.data(data)
.join("rect")
.attr("class", "bar-for-tooltip")
.style("fill", backgroundColor)
.style("opacity", 0)
.attr("x", d => c31X(0))
.attr("y", d => c31Y(d.partner))
.attr("width", d => c31X(d.exportGodValue+d.importGodValue))
.attr("height", c31Y.bandwidth())
// 滑鼠移入: 改變顏色並顯示tooltip
.on("mouseover", function(event, d) {
// 改變長條圖顏色
d3.select(this).style("opacity", 0.5);
// 顯示tooltip
c31Tooltip.html(d.partner+"
"+
c3LabelExport+": "+Math.round(d.exportGodValue/1000).toLocaleString('en-US')+"
"+
c3LabelImport+": "+Math.round(d.importGodValue/1000).toLocaleString('en-US'));
controlTooltip(c31Tooltip, "show");
moveC31Tooltip(event);
})
// 滑鼠移動: 改變tooltip位置
.on("mousemove", function(event, d) {
moveC31Tooltip(event);
})
// 滑鼠移出: 恢復顏色並隱藏tooltip
.on("mouseout", function(d) {
// 恢復顏色
d3.select(this).style("opacity", 0);
// 隱藏tooltip
controlTooltip(c31Tooltip, "hide");
});
c31Svg.selectAll(".bar-for-tooltip").raise();
let each_delay = duration/data.length; //計算讀取物件長度,計算每個項目所分到的延遲時間
// 動畫: 長條圖
animationBarWithText(c31Svg,
".bar rect", d => c31X(d[1]) - c31X(d[0])-3,
".bar-text", d => c31X(d.importGodValue+d.exportGodValue)+30,
each_delay/2);
});
}
function moveC31Tooltip(event){
// let w=$("#c3_1>div.tooltip").width(), h=$("#c3_1>div.tooltip").height();
// c31Tooltip.style("left", (event.offsetX-(w/2)) + "px")
// .style("top", (event.offsetY+70) + "px");
const x=event.offsetX-($("#c3_1 .tooltip").width()/2),
y=event.offsetY+($("#c3_1 .tooltip").height()*0.5);
c31Tooltip.style("transform", "translate("+x+"px,"+y+"px)");
}
//---------- 右上 進出口貨品結構圓餅圖 ----------
//設定圖表長寬與邊框寬度
var c32Margin = {top: 10, right: 0, bottom: 10, left: 0};
var c32Width = $("#c3_2").width() - c32Margin.left - c32Margin.right,
c32Height = c31SvgHeight - c32Margin.top - c32Margin.bottom,
c32HeightForPie = (window.innerWidth<1920?200:c31SvgHeight) - c32Margin.top - c32Margin.bottom;
var c32Radius = Math.min(c32Width, c32HeightForPie) / 2 ;
var c32Arc=d3.arc()
.innerRadius(window.innerWidth<1920?50:100)
.outerRadius(c32Radius);
// Tooltip物件
var c32Tooltip = addTooltip(d3.select("#c3_2"));
// svg物件
var c32Svg = addSvg(d3.select("#c3_2"), c32Width, c32Height, c32Margin,
"translate(" + ((c32Width-$("#c3_2_legned").width())/2+c32Margin.left) + "," + ((c32Height/2)+c32Margin.top) + ")");
var c32LegendWidth = $("#c3_2_legned").width();
// 進出口分隔線
var c32LineX=-c32HeightForPie/2-40;
c32Svg.append("line")
.style("stroke", "#555")
.style("stroke-width", 2)
.transition()
.duration(duration)
.attr("x1", c32LineX)
.attr("y1", 0)
.attr("x2", c32HeightForPie/2+10)
.attr("y2", 0);
var c32LineExport=language=="chinese"?"出口":"Ex";
var c32LineImport=language=="chinese"?"進口":"Im";
c32LineX+=language=="chinese"?5:20;
addLegend(c32Svg, c32LineX, -10-8, "", c32LineExport);
addLegend(c32Svg, c32LineX, 15-8, "", c32LineImport);
function chart3_2(typeTime, year, month, partner){
// 貿易夥伴標題
let c3Title="";
if(language=="chinese"){
c3Title=year+"年"+(typeTime=="month"?month+"月":"")+"對"+
$("label[for='"+$("input[name='c3Partner']:checked")[0].id+"']").text()+
"進出口概況";
}
else{
c3Title="Overview of trade with "+
$("label[for='"+$("input[name='c3Partner']:checked")[0].id+"']").text()+", "+
year+(typeTime=="month"?"/"+month:"");
}
$("#c3Title .chart-title").html(c3Title);
if(language=="english"){
year=year-1911;
}
// 讀取資料
d3.json('GA28_getChartData', {
method:"POST",
body: new URLSearchParams({
"searchInfo.Type": "c32",
"searchInfo.TypeTime": typeTime,
"searchInfo.startYear": year,
"searchInfo.startMonth": month,
"searchInfo.CountryName": partner,
"searchInfo.Notes": language
}),
headers: {
"Content-type": "application/x-www-form-urlencoded"
}
}).then( function(data) {
let keyList=getKeyList("goods", data);
let colorList=getColorList("goods", keyList);
// 圖例
let exportGodValueSum=0, importGodValueSum=0;
data.forEach(function(d) {
$("#legend_"+d.goodsTypeKey).css("background-color", goodsTypeColor[d.goodsTypeKey]);
exportGodValueSum+=d.exportGodValue;
importGodValueSum+=d.importGodValue;
});
data.forEach(function(d) {
$("#legend_percent_"+d.goodsTypeKey+"_ex").text((Math.round(d.exportGodValue*100*100/exportGodValueSum)/100).toFixed(2)+"%");
$("#legend_percent_"+d.goodsTypeKey+"_im").text((Math.round(d.importGodValue*100*100/importGodValueSum)/100).toFixed(2)+"%");
});
// 圖例靠左,上下置中
$("#c3_2_legned").css("left", ($("#c3_1").width()+$("#c3_2").width()-$("#c3_2_legned").width()-c32Margin.right)+"px");
$("#c3_2_legned").css("top", ($("#c3Title").height()+($("#c3_2").height()-$("#c3_2_legned").height())/2)+"px");
const color = d3.scaleOrdinal()
.domain(keyList)
.range(colorList);
addPie(c32Svg, c32Tooltip, "3", data, color, c32Arc, "export");
addPie(c32Svg, c32Tooltip, "3", data, color, c32Arc, "import");
// 分隔線移到最上層
c32Svg.select("line").raise();
});
}
//========== 共用function ==========
function addSvg(div, width, height, margin, transform){
return div
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("background", backgroundColor)
.append("g")
.attr("transform", transform==""?"translate(" + margin.left + "," + margin.top + ")":transform);
}
function addTitle(svg, text){
svg.append("text")
.attr("x", 5)
.attr("y", 5)
.attr("class", "chart-title")
.attr("fill", "currentColor")
.text(text)
.style("font-size", "18px")
.attr("alignment-baseline","middle");
}
function addTooltip(div){
return div.append("div")
.attr("class", "tooltip")
.style("background", "#fff")
.style("padding", "5px")
.style("opacity", 0);
}
function moveTooltip(selector, tooltip, event){
const x=event.offsetX-($(selector+" .tooltip").width()/2),
y=event.offsetY-($(selector+" .tooltip").height()*1.5);
tooltip.style("transform", "translate("+x+"px,"+y+"px)");
}
function controlTooltip(tooltip, type){
let opacity=(type=="show")?0.9:0;
// 顯示/隱藏 tooltip
tooltip.transition()
.duration(500)
.style("opacity", opacity);
}
function addLegend(svg, x, y, color, text){
let height="15", yForLine=0, xForText=0;
if(color==lineColor){
height="3";
yForLine=6;
}
let colorElement=null;
if(color!=""){
colorElement=svg.append("rect")
.attr("x", x)
.attr("y", y+yForLine)
.attr("width", "30px")
.attr("height", height+"px")
.attr("class", "legend")
.style("fill", color);
xForText=40;
}
svg.append("text")
.attr("x", x+xForText)
.attr("y", y+8)
.attr("class", "axis-title")
.attr("fill", "currentColor")
.text(text)
.style("font-size", "13px")
.attr("alignment-baseline","middle");
return colorElement;
}
function addAxisTitle(svg, x, y, transform, text){
svg.append("text")
.attr("class", "axis-title")
.attr("fill", "currentColor")
.attr("text-anchor", "end")
.attr("transform", transform)
.attr("x", x)
.attr("y", y)
.text(text);
}
function addPie(svg, tooltip, chartNo, data, color, arc, type){
let pieExist=($("#c"+chartNo+"_2 > svg > g > path."+type+"-path").length>0)?true:false;
let pie = d3.pie()
.startAngle((type=="import"?90:-90) * (Math.PI / 180))
.endAngle((type=="import"?270:90) * (Math.PI / 180))
.value(d => type=="partner"?d.godValue:(type=="export"?d.exportGodValue:d.importGodValue));
let data_ready = pie(data);
let piePath=svg.selectAll("."+type+"-path")
.data(data_ready);
let p=piePath.enter()
.append('path')
.attr('class', type+"-path")
// 滑鼠移入: 改變顏色並顯示tooltip
.on("mouseover", function(event, d) {
// 顯示tooltip
tooltip.html((type=="partner"?d.data.partner:d.data.goodsType)+"
"+
(language=="chinese"?"金額":"Value")+": "+
// 金額 千元轉換成百萬元
Math.round((type=="partner"?d.data.godValue:(type=="export"?d.data.exportGodValue:d.data.importGodValue))/1000).toLocaleString('en-US'));
controlPieTooltip(this, tooltip, d, "show", (type=="partner"?d.data.partnerKey:d.data.goodsTypeKey));
moveTooltip("#c"+chartNo+"_2", tooltip, event);
})
// 滑鼠移動: 改變tooltip位置
.on("mousemove", function(event, d) {
moveTooltip("#c"+chartNo+"_2", tooltip, event);
})
// 滑鼠移出: 恢復顏色並隱藏tooltip
.on("mouseout", function(event, d) {
controlPieTooltip(this, tooltip, d, "hide", (type=="partner"?d.data.partnerKey:d.data.goodsTypeKey));
})
.merge(piePath)
.transition()
.duration(duration)
.attr("fill", d => color(type=="partner"?d.data.partnerKey:d.data.goodsTypeKey))
.attr("stroke", backgroundColor)
.style("stroke-width", "2px");
// 動畫: 圓餅圖
if(pieExist){
p.attr("d", arc);
}
else{
if(chartNo=="2"){
p.attrTween("d", c22TweenPie);
}
else if(chartNo=="3"){
p.attrTween("d", c32TweenPie);
}
}
piePath.exit().remove();
}
function controlPieTooltip(pieThis, tooltip, d, type, key){
// 改變/恢復 顏色
let c=$("#legend_"+key).css("background-color");
c=(type=="show")?(c.replace("rgb", "rgba").replace(")", ", 0.7)")):(c.replace("rgba", "rgb").replace(", 0.7)", ")"));
let o=(type=="show")?0.7:1;
let fw=(type=="show")?"bold":"";
d3.select(pieThis).style("opacity", o);
$("#legend_"+key).css("background-color", c);
if(key.length==1){
$("tr:has(> #legend_text_"+key+")").css("font-weight", fw);
}
else{
$("#legend_text_"+key+", #legend_percent_"+key).css("font-weight", fw);
}
// 顯示/隱藏 tooltip
controlTooltip(tooltip, type);
}
function c22TweenPie(b) {
var i = d3.interpolate({startAngle: -90 * (Math.PI / 180), endAngle: 90 * (Math.PI / 180)}, b);
return function(t) { return c22Arc(i(t)); };
}
function c32TweenPie(b) {
var i = d3.interpolate({startAngle: -90 * (Math.PI / 180), endAngle: 90 * (Math.PI / 180)}, b);
return function(t) { return c32Arc(i(t)); };
}
function getKeyList(type, data){
let keyList=[];
for(d of data){
let k=(type=="goods")?d.goodsTypeKey:d.partnerKey;
keyList.push(k);
}
return keyList;
}
function getColorList(type, keyList){
let colorList=[];
let colorMap=(type=="goods")?goodsTypeColor:partnerColor;
for(k of keyList){
colorList.push(colorMap[k]);
}
return colorList;
}
function animationBar(svg, selector, y, height, each_delay){
svg.selectAll(selector)
.transition()
.duration(duration)
.attr("y", y)
.attr("height", height)
.delay(function(d,i){return(i*each_delay);});
}
function animationBarWithText(svg, barSelector, width, textSelector, x, each_delay){
// 動畫: 長條圖
svg.selectAll(barSelector)
.transition()
.duration(duration)
.attr("width", width)
.delay(function(d,i){return(i*each_delay);});
// 動畫: 長條圖數值
if(textSelector!=""){
svg.selectAll(textSelector)
.transition()
.duration(duration)
.attr("x", x)
.delay(function(d,i){return(i*each_delay);});
}
}
function animationLine(data, svg, linePath, circleSelector, circleSize, selectLastCircle, each_delay){
// 動畫: 折線圖
const pathLength = linePath.node().getTotalLength();
const transitionPath = d3.transition()
.ease(d3.easeSin)
.duration(3000);
linePath.attr("stroke-dashoffset", pathLength)
.attr("stroke-dasharray", pathLength)
.transition(transitionPath)
.attr("stroke-dashoffset", 0);
// 動畫: 折線圖上的點
svg.selectAll(circleSelector)
.data(data)
.transition().duration(duration)
.attr("r", selectLastCircle?((d, i) => (i==data.length-1)?5:circleSize):circleSize)
.delay(function(d, i) {return i * each_delay;});
}
function printChart(chartSelector) {
$(chartSelector+" .chart-menu").hide();
html2canvas(document.querySelector(chartSelector), {
scrollX: 0,
scrollY: 0
}).then(canvas => {
$(chartSelector+" .chart-menu").show();
// 取得標題
let windowTitle="";
if ($(chartSelector+" .chart-title").length ) {
windowTitle=$(chartSelector+" .chart-title").text();
}
// 於新視窗開啟列印畫面
let chartUrl = canvas.toDataURL();
let windowUrl = 'about:blank';
let printWindow = window.open(windowUrl);
printWindow.document.write('');
printWindow.document.close();
printWindow.focus();
printWindow.document.title=windowTitle;
if(Boolean(window.chrome)) {
setTimeout(function(){
printWindow.print();
printWindow.close();
}, 500);
}
else {
printWindow.print();
printWindow.close();
}
});
}
function downloadChart(chartSelector) {
$(chartSelector+" .chart-menu").hide();
html2canvas(document.querySelector(chartSelector)).then(canvas => {
$(chartSelector+" .chart-menu").show();
// 取得檔名
let imageName="";
if ($(chartSelector+" .chart-title").length ) {
imageName=$(chartSelector+" .chart-title").text();
}
// 下載圖片
var a = document.createElement('a');
a.href = canvas.toDataURL();
a.download = imageName+".png";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
}