氣泡圖 bubble chart

          
            // html 
            <div class="bubbleChart"></div>

            // js
            const drawBubbleChart = async () => {
              // 建立SVG
              const margin = { top: 10, right: 20, bottom: 30, left: 50 },
                svgWidth = parseInt(d3.select(".bubbleChart").style("width")),
                svgHeight = 500,
                width = svgWidth - margin.left - margin.right,
                height = svgHeight - margin.top - margin.bottom;
      
              const svg = d3
                .select(".bubbleChart")
                .append("svg")
                .attr("width", svgWidth)
                .attr("height", svgHeight);
      
              const url ="https://raw.githubusercontent.com/holtzy/
                          data_to_viz/master/Example_dataset/4_ThreeNum.csv";
              const data = await d3.csv(`${url}`);
              
              // 整理xy軸資料、Z的人口數量資料
              const xData = data.map((i) => parseInt(i.gdpPercap));
              const yData = data.map((i) => i.lifeExp);
              const zData = data.map((i) => i.pop);
      
              // 建立X比例尺與軸線
              const xScale = d3
                .scaleLinear()
                .domain([0, d3.max(xData)])
                .range([margin.left, width])
                .nice();
      
              const xAxisGenerator = d3
                  .axisBottom(xScale)
                  .tickFormat((d) => "$" + d);
      
              svg
                .append("g")
                .attr("transform", `translate(0, ${height})`)
                .call(xAxisGenerator);
      
              // 建立Y比例尺與軸線
              const yScale = d3
                .scaleLinear()
                .domain(d3.extent(yData))
                .range([height, margin.top])
                .nice();
      
              const yAxisGenerator = d3
                  .axisLeft(yScale)
                  .tickFormat((d) => d + "歲");
      
              svg
                .append("g")
                .attr("transform", `translate(${margin.left}, 0)`)
                .call(yAxisGenerator);
      
              // 按照人口去設定氣泡大小的比例尺
              const radiusScale = d3
                .scaleLinear()
                .domain([d3.min(zData), 1310000000])
                .range([4, 40]);
      
              // 設定氣泡顏色,根據不同洲來設定
              const bubbleColor = d3
                .scaleOrdinal()
                .domain(["Asia", "Europe", "Americas", "Africa", "Oceania"])
                .range(d3.schemeSet2);
      
              // 建立標籤tooltips
              const tooltip = d3
                .select(".bubbleChart")
                .append("div")
                .style("display", "none")
                .attr("class", "dotsTooltip")
                .style("position", "absolute")
                .style("background-color", "black")
                .style("border-radius", "5px")
                .style("padding", "10px")
                .style("color", "white");
      
              // 設定顯示、移動、隱藏tooltips
              const showTooltip = (event, d) => {
                // 設定樣式與呈現文字
                tooltip.style("display", "block")
                       .html(`

國家:${d.country}

人口數:${d.pop}

GDP:${d.gdpPercap}

平均壽命:${d.lifeExp}

`) .style("left", `${event.x}px`) .style("top", `${event.y}px`); // 圓點強調 d3.select(event.target) .attr("r", radiusScale(d.pop) + 5) .style("opacity", 0.7); }; const moveTooltip = () => tooltip.style("display", "block"); const hideTooltip = (event, d) => { tooltip.style("display", "none"); // 圓點復原 d3.select(event.target) .attr("r", radiusScale(d.pop)) .style("opacity", 1); }; // 綁定氣泡 const bubble = svg .append("g") .selectAll("dot") .data(data) .join("circle") .attr("class", "bubbles") .attr("cx", (d) => xScale(d.gdpPercap)) .attr("cy", (d) => yScale(d.lifeExp)) .attr("r", (d) => radiusScale(d.pop)) .style("fill", (d) => bubbleColor(d.continent)) .style("cursor", "pointer") .on("mouseover", showTooltip) .on("mousemove", moveTooltip) .on("mouseleave", hideTooltip); }; drawBubbleChart();