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); }); }