軸線、刻度、工具提示框

responsive Axes
responsive d3.axisBottom( )

程式碼

          
            //html
            <div class="axisBottom"></div>
            //js
            const currentWidth	=	parseInt(d3.select(".axisBottom").style("width"));
            const height = 100;
            const margin = 20;
      
            const svg = d3.select('.axisBottom')
                          .append('svg')
                          .attr('width',currentWidth)
                          .attr('height',height)
                          .style('border', '1px solid rgb(96,96,96)')
      
            const xScale = d3.scaleLinear()
                              .domain([0,100])
                              .range([0,currentWidth-margin]);
      
            const xAxisGenerator = d3.axisBottom(xScale);

            const xAxis = svg.append('g')
                            .call(xAxisGenerator)
                            .attr('transform', `translate(${margin/2},${height-margin})`);
          
        
axis.ticks(Arguments...)

Number Ticks

程式碼

          
            // html
            <div class="numberTicks"></div>
            // js
            const currentWidth = parseInt(d3.select(".numberTicks").style("width"));
            const height = 100;
            const margin = 20;
      
            const svg = d3.select('.numberTicks')
                                    .append('svg')
                                    .attr('width',currentWidth)
                                    .attr('height',height)
                                    .style('border', '1px solid rgb(96,96,96)')
      
            const xScale = d3.scaleLinear()
                            .domain([0,100])
                            .range([0,currentWidth-margin*2])
                            .nice();
      
            const xAxisGenerator = d3.axisBottom(xScale).ticks(5, '.1f'); 
      
            const xAxis = svg.append('g')
                    .call(xAxisGenerator)
                    .attr('transform', `translate(${margin},${height-margin})`);
          
        

Time Ticks

程式碼

          
            // html
            <div class="timeTicks"></div>
            // js
            const currentWidth = parseInt(d3.select(".timeTicks").style("width"));
            const height = 100;
            const margin = 20;
            const January = new Date('2023/01')
            const December = new Date('2023/12');
      
            const svg = d3.select('.timeTicks')
                          .append('svg')
                          .attr('width',currentWidth)
                          .attr('height',height)
                          .style('border', '1px solid rgb(96,96,96)')
      
            const xScale = d3.scaleTime()
                            .domain([January,December])
                            .range([0,currentWidth-margin*2])
                            .nice();
      
            const xAxisGenerator = d3.axisBottom(xScale).ticks(12, '%B'); 
            const xAxis = svg.append('g')
                  .call(xAxisGenerator)
                  .attr('transform', `translate(${margin},${height-margin})`);
          
        
axis.tickValues( )

程式碼

          
            //html
            <div class="tickValues"></div>
            //js
            const currentWidth	=	parseInt(d3.select(".tickValues").style("width"));
            const height = 100;
            const margin = 20;
      
            const svg = d3.select('.tickValues')
                                    .append('svg')
                                    .attr('width',currentWidth)
                                    .attr('height',height)
            // Linear
            const xScaleLinear = d3.scaleLinear()
                            .domain([0,100])
                            .range([0,currentWidth-margin*2])
                            .nice();
      
            const xAxisLinearGenerator = d3.axisBottom(xScaleLinear)
                                           .tickValues([0,20,51,58,77,100]);
      
            const xAxisLinear = svg.append('g')
                        .call(xAxisLinearGenerator)
                        .attr('transform', `translate(${margin},0)`);
      
            // Band
            const data = ['鼠','牛','虎','兔','龍','蛇','馬','羊','猴','雞','狗','豬']
            const xScaleBand = d3.scaleBand()
                                  .domain(data)
                                  .range([0,currentWidth-margin*2]);
      
            const xAxisBandGenerator = d3.axisBottom(xScaleBand)
                                  .tickValues(
                                    xScaleBand.domain().filter((i,idx)=>idx%2===0)
                                   );
      
            const xAxisBand = svg.append('g')
                        .call(xAxisBandGenerator)
                        .attr('transform', `translate(${margin},${height*0.75})`);
          
        
axis.tickFormat( )

程式碼

          
            //html
            <div class="tickFormat"></div>
            //js
            const currentWidth	=	parseInt(d3.select(".tickFormat").style("width"));
            const height = 100;
            const margin = 20;
      
            const svg = d3.select('.tickFormat')
                                    .append('svg')
                                    .attr('width',currentWidth)
                                    .attr('height',height)
      
            const xScale = d3.scaleLinear()
                            .domain([0,100])
                            .range([0,currentWidth-margin*2])
                            .nice();
      
            const xAxisGenerator = d3.axisBottom(xScale)
                                     .tickFormat(d=>`${d}元`); 
      
            const xAxis = svg.append('g')
                            .call(xAxisGenerator)
                            .attr('transform', `translate(${margin},${margin})`);
      
            const xAxisFormatGenerator = d3.axisBottom(xScale)
                                     .tickFormat(d3.format('.1f')); 
                                     
            const xFormatAxis = svg.append('g')
                            .call(xAxisFormatGenerator)
                            .attr('transform', `translate(${margin},${height*0.75})`);
          
        
axis.tickSize( )

程式碼

          
            //html
            <div class="tickSize"></div>
            
            //js
            const currentWidth	=	500;
            const height = 150;
            const margin = 20;
      
            const svg = d3.select('.tickSize')
                                    .append('svg')
                                    .attr('width',currentWidth)
                                    .attr('height',height)
      
            const xScale = d3.scaleLinear()
                            .domain([0,100])
                            .range([0,currentWidth-margin*2]);
           // 正數
            const xAxisGeneratorPositive = d3.axisBottom(xScale)
                                             .tickSize(30); 

            const xAxisPositive = svg.append('g')
                            .call(xAxisGeneratorPositive)
                            .attr('transform', `translate(${margin},0)`);
            // 負數
            const xAxisGeneratorNegative = d3.axisBottom(xScale)
                                             .tickSize(-30); 

            const xAxisNegative = svg.append('g')
                            .call(xAxisGeneratorNegative)
                            .attr('transform', `translate(${margin},${height-margin})`);
          
        
axis.tickSizeInner( )

程式碼

          
            //html
            <div class="tickSizeInner"></div>
            
            //js
            const currentWidth	=	parseInt(d3.select(".tickSizeInner").style("width"));
            const height = 100;
            const margin = 20;
      
            const svg = d3.select('.tickSizeInner')
                                    .append('svg')
                                    .attr('width',currentWidth)
                                    .attr('height',height)
      
            const data = ['鼠','牛','虎','兔','龍','蛇','馬','羊','猴','雞','狗','豬']
            const xScale = d3.scaleBand()
                            .domain(data)
                            .range([0,currentWidth-margin*2]);
      
            const xAxisGenerator = d3.axisBottom(xScale)
                                     .tickSizeInner(30);
                                     
            const xAxis = svg.append('g')
                            .call(xAxisGenerator)
                            .attr('transform', `translate(${margin},${margin})`);
          
        
axis.tickSizeOuter( )

程式碼

          
            //html
            <div class="tickSizeOuter"></div>
            //js
            const currentWidth	=	parseInt(d3.select(".tickSizeOuter").style("width"));
            const height = 100;
            const margin = 20;
      
            const svg = d3.select('.tickSizeOuter')
                                    .append('svg')
                                    .attr('width',currentWidth)
                                    .attr('height',height)
      
            const xScale = d3.scaleLinear()
                            .domain([0,100])
                            .range([0,currentWidth-margin*2]);
      
            const xAxisGenerator = d3.axisBottom(xScale)
                                    .tickSizeOuter(30); 
                                    
            const xAxis = svg.append('g')
                            .call(xAxisGenerator)
                            .attr('transform', `translate(${margin},${margin})`);
          }
          
        
axis.tickPadding( )

程式碼

          
            //html 
            <div class="tickPadding"></div>
            //js 
            const currentWidth	=	parseInt(d3.select(".tickPadding").style("width"));
            const height = 100;
            const margin = 20;
      
            const svg = d3.select('.tickPadding')
                                    .append('svg')
                                    .attr('width',currentWidth)
                                    .attr('height',height)
      
            const xScale = d3.scaleLinear()
                            .domain([0,100])
                            .range([0,currentWidth-margin*2]);
      
            const xAxisGenerator = d3.axisBottom(xScale)
                                     .tickPadding(60);

            const xAxis = svg.append('g')
                            .call(xAxisGenerator)
                            .attr('transform', `translate(${margin},${margin})`);

          
        
XY軸線

程式碼

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

            //JS
            const currentWidth = parseInt(d3.select(".xyAxes").style("width"));;
            const height = 400;
            const margin = 40;
    
            const svg = d3.select(".xyAxes")
                          .append("svg")
                          .attr("width", currentWidth)
                          .attr("height", height)
                          .style("border", "1px solid rgb(96,96,96)");

            const data = [{x:100, y:20}, {x:18, y:30}, {x:90, Y:250}]

            // 抓出xy軸需要用的資料
            const xData = data.map((i) => i.x); // 得到 [100, 18, 90] 陣列
            const yData = data.map((i) => i.y); // 得到 [20, 30, 150] 陣列
    
            // X比例尺與軸線
            const xScale = d3.scaleLinear()
                            .domain([0, d3.max(xData)])
                            .range([margin, currentWidth - margin]);
    
            const xAxisGenerator = d3.axisBottom(xScale);
            const xAxis = svg.append("g")
                      .call(xAxisGenerator)
                      .attr("transform", `translate(0,${height - margin})`);
    
            // Y比例尺與軸線
            const yScale = d3.scaleLinear()
                            .domain([0, d3.max(yData)])
                            .range([height - margin * 2, 0])
                            .nice();
    
            const yAxisGenerator = d3.axisLeft(yScale);

            const yAxis = svg.append("g")
                    .call(yAxisGenerator)
                    .attr("transform", `translate(${margin},${margin})`);
          
        
軸線樣式調整

程式碼

          
            const width = 500;
            const height = 300;
            const margin = 20;
    
            const svg = d3.select(".tickStyle")
                          .append("svg")
                          .attr("width", width)
                          .attr("height", height);
    
            const xScale = d3.scaleLinear()
                             .domain([0, 100])
                             .range([0, width - margin * 2]);
    
            const xAxisGenerator = d3.axisBottom(xScale)
                            .tickSize(`${-height + margin * 2}`)
                            .tickSizeOuter(0)
                            .tickPadding(10);
    
            const xAxis = svg.append("g")
                  .call(xAxisGenerator)
                  .attr("class", "xStyleAxis")
                  .attr("transform", `translate(${margin},${height - margin})`);

            // 設定軸線樣式
            d3.selectAll(".xStyleAxis line")
              .style("stroke-dasharray", "2 10 5")
              .style("stroke", "#f68b47")
              .style("stroke-width", "2");
          
        
棋盤軸線樣式

程式碼

          
            // html 
            <div class="checkerboardTicks"></div>
            // js
            const currentWidth = 500
            const height = 400;
            const margin = 40;
    
            const svg = d3.select(".checkerboardTicks")
                          .append("svg")
                          .attr("width", currentWidth)
                          .attr("height", height);
    
            // x軸線
            const xScale = d3.scaleLinear()
                          .domain([0, 100])
                          .range([margin, currentWidth - margin]);
    
            const xAxisGenerator = d3.axisBottom(xScale)
                              .tickSize(`${-height + margin * 2}`)
                              .tickSizeOuter(0)
                              .tickPadding(10);
    
            const xAxis = svg.append("g")
                  .call(xAxisGenerator)
                  .attr("transform", `translate(0,${height - margin})`);
    
            // y軸線
            const yScale = d3.scaleLinear()
                        .domain([0, 100])
                        .range([height - margin, margin]);
    
            const yAxisGenerator = d3.axisLeft(yScale)
                      .tickSize(`${-currentWidth + margin * 2}`)
                      .tickSizeOuter(0)
                      .tickPadding(10);
    
            const yAxis = svg.append("g")
                      .call(yAxisGenerator)
                      .attr("transform", `translate(${margin},0)`);
          
        
井字軸線樣式

程式碼

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

            // js
            const currentWidth = 500;
            const height = 400;
            const margin = 60;
    
            const svg = d3.select(".wellTicks")
                  .append("svg")
                  .attr("width", currentWidth)
                  .attr("height", height);
    
            // X軸線
            const xScale = d3.scaleLinear()
                  .domain([0, 100])
                  .range([margin, currentWidth - margin]);
    
            const xAxisGenerator = d3.axisBottom(xScale)
                  .tickSize(`${-height + margin}`)
                  .tickSizeOuter(0)
                  .tickPadding(40);
    
            const xAxis = svg.append("g")
                  .attr("class", "xCheckerboardAxis")
                  .call(xAxisGenerator)
                  .attr("transform", `translate(0,${height - margin})`);
    
            // Y軸線
            const yScale = d3.scaleLinear()
                    .domain([0, 100])
                    .range([height - margin, margin]);
    
            const yAxisGenerator = d3.axisLeft(yScale)
                    .tickSize(`${-currentWidth + margin}`)
                    .tickSizeOuter(0)
                    .tickPadding(40);
    
            const yAxis = svg.append("g")
                    .attr("class", "yCheckerboardAxis")
                    .call(yAxisGenerator)
                    .attr("transform", `translate(${margin},0)`);
    
            // 調整tick特殊樣式
            d3.selectAll(".xCheckerboardAxis line").attr(
              "transform",
              `translate(0,${margin / 2})`
            );
    
            d3.selectAll(".yCheckerboardAxis line").attr(
              "transform",
              `translate(${-margin / 2},0)`
            );
          
        
Grid軸線樣式

程式碼

          
            const currentWidth = parseInt(d3.select(".gridTicks").style("width"));
            const height = 400;
            const margin = 35;
    
            const svg = d3
              .select(".gridTicks")
              .append("svg")
              .attr("width", currentWidth)
              .attr("height", height);
    
            // X軸線
            const xScale = d3
              .scaleLinear()
              .domain([0, 100])
              .range([margin, currentWidth - margin]);
    
            const xAxisGenerator = d3
              .axisBottom(xScale)
              .tickSize(15)
              .tickPadding(5);
    
            const xAxis = svg
              .append("g")
              .attr("class", "xGridAxis")
              .call(xAxisGenerator)
              .attr("transform", `translate(0,${height - margin})`);
    
            // Y軸線
            const yScale = d3
              .scaleLinear()
              .domain([0, 100])
              .range([height - margin, margin]);
    
            const yAxisGenerator = d3.axisLeft(yScale)
                                     .tickSize(15)
                                     .tickPadding(5);
    
            const yAxis = svg
              .append("g")
              .attr("class", "yGridAxis")
              .call(yAxisGenerator)
              .attr("transform", `translate(${margin},0)`);
    
            //繪製 X 軸向上的不同色軸線
            d3.selectAll(".xGridAxis .tick")
              .append("line")
              .attr("x1", 0)
              .attr("y1", 0)
              .attr("x2", 0)
              .attr("y2", -height + margin * 2)
              .attr("stroke", "#e4e4e4");
    
            //繪製 Y 軸向右的不同色軸線
            d3.selectAll(".yGridAxis .tick")
               // 不繪製第一條與 x 軸重疊的 y 軸線
              .filter((d, i) => i !== 0)
              .append("line")
              .attr("x1", 0)
              .attr("y1", 0)
              .attr("x2", currentWidth - margin * 2)
              .attr("y2", 0)
              .attr("stroke", "#e4e4e4");
          
        
文字標籤旋轉

程式碼

          
            const currentWidth = 500;
            const height = 400;
            const margin = 35;
            const marginBottom = 60;
    
            const svg = d3
              .select(".textLabelRotate")
              .append("svg")
              .attr("width", currentWidth)
              .attr("height", height);
    
            // date
            const currentYear = new Date("2023-01-01");
            const nextYear = new Date("2024-01-01");
    
            // X軸線
            const xScale = d3
              .scaleTime()
              .domain([currentYear, nextYear])
              .nice()
              .range([margin, currentWidth - margin]);
    
            const xAxisGenerator = d3
              .axisBottom(xScale)
              .tickSize(15)
              .tickPadding(35)
              .tickFormat(d3.timeFormat("%Y-%m-%d"));
    
            const xAxis = svg
              .append("g")
              .attr("class", "x-axis")
              .call(xAxisGenerator)
              .attr("transform", `translate(0,${height - marginBottom})`);
    
            // 旋轉文字標籤
            d3.selectAll(".x-axis text").attr(
              "transform",
              "translate(-50, 0) rotate(-45)"
            );
    
            // Y軸線
            const yScale = d3
              .scaleLinear()
              .domain([0, 100])
              .range([height - marginBottom, margin]);
    
            const yAxisGenerator = d3.axisLeft(yScale).tickSize(15).tickPadding(5);
    
            const yAxis = svg
              .append("g")
              .call(yAxisGenerator)
              .attr("transform", `translate(${margin},0)`);
          
        
文字標籤置中

程式碼

          
            //html
            <div class="textLabelCenter"></div>
            //js
            const currentWidth = 500;
            const height = 400;
            const margin = 35;
            const marginBottom = 60;
    
            const svg = d3
              .select(".textLabelCenter")
              .append("svg")
              .attr("width", currentWidth)
              .attr("height", height);
    
            // date
            const currentYear = new Date("2023-01-01");
            const nextYear = new Date("2024-01-01");
    
            // X軸比例尺
            const xScale = d3
              .scaleTime()
              .domain([currentYear, nextYear])
              .nice()
              .range([margin, currentWidth - margin]);
    
            // x 軸-刻度線
            const xAxisTicksGenerator = d3
              .axisBottom(xScale)
              .tickSize(15)
              .tickFormat("");
    
            const xTicksAxis = svg
              .append("g")
              .call(xAxisTicksGenerator)
              .attr("transform", `translate(0,${height - marginBottom})`);

            // 取得刻度間距
              const getTicksDistance = (scale) => {
                const ticks = scale.ticks();
                const distance = parseInt(scale(ticks[1]) - scale(ticks[0]));
                return distance;
              };
    
            // x 軸-文字標籤
            const xAxisLabelsGenerator = d3
              .axisBottom(xScale)
              .tickSize(0)
              .tickPadding(25)
              .tickFormat(d3.timeFormat("%B"));
    
            // 調整 x 文字標籤軸位置
            const xLabelsAxis = svg
              .append("g")
              .attr("class", "xLabelsAxis")
              .call(xAxisLabelsGenerator)
              .attr(
                "transform",
                `translate(${getTicksDistance(xScale) / 2},${
                  height - marginBottom
                })`
              );
    
            // Y軸線
            const yScale = d3
              .scaleLinear()
              .domain([0, 100])
              .range([height - marginBottom, margin]);
    
            const yAxisGenerator = d3.axisLeft(yScale).tickSize(15).tickPadding(5);
    
            const yAxis = svg
              .append("g")
              .call(yAxisGenerator)
              .attr("transform", `translate(${margin},0)`);
          
        
時鐘軸線

程式碼

          
          //html
          <div class="clockAxis"></div>
          
          //js
          const currentWidth = parseInt(d3.select(".clockAxis").style("width")),
          height = 500,
          clockRadius = height / 3,
          minuteTickLength = clockRadius - 10,
          hourTickLength = clockRadius - 18,
          radians = Math.PI / 180, //弧度
          minuteLabelRadius = clockRadius + 15, // 分鐘半徑
          minuteLabelYOffset = 5,
          hourLabelRadius = clockRadius - 35, // 小時半徑
          hourLabelYOffset = 10;
  
          const svg = d3
            .select(".clockAxis")
            .append("svg")
            .attr("width", currentWidth)
            .attr("height", height);
  
          // 小時比例尺(12小時映射到360度)
          const hourScale = d3.scaleLinear().domain([0, 12]).range([0, 360]);
  
          // 分鐘比例尺(60分鐘映射到360度)
          const minuteScale = d3.scaleLinear().domain([0, 60]).range([0, 360]);
  
          const clock = svg
            .append("g")
            .attr("id", "clock")
            // 繪製起始點移動到svg中央
            .attr(
              "transform",
              `translate(${[parseInt(currentWidth / 2), height / 2]})`
            );
  
          // 分鐘刻度
          clock
            .selectAll(".minuteTicks")
            .data(d3.range(0, 60))
            .enter()
            .append("line")
            .attr("class", "minuteTicks")
            .attr("x1", "0")
            .attr("x2", "0")
            .attr("y1", clockRadius)
            .attr("y2", minuteTickLength)
            .attr("stroke-width", "3")
            .attr("stroke", "black")
            .attr("transform", (d) => `rotate(${minuteScale(d)})`);
  
          // 分鐘數字標籤
          clock
            .selectAll("minuteLabels")
            .data(d3.range(5, 61, 5)) //5到61,間格5
            .enter()
            .append("text")
            .attr("class", "minuteLabels")
            .attr("text-anchor", "middle")
            // 標籤的半徑乘以角度(比例尺承弧度)的正弦值(Math.sin)
            .attr("x", (d) => 
                minuteLabelRadius * Math.sin(minuteScale(d) * radians))
            //標籤的半徑乘以角度(比例尺承弧度)的餘弦函數
            .attr("y", (d) => 
               -minuteLabelRadius * Math.cos(minuteScale(d) * radians) +
               minuteLabelYOffset)
            .text((d) => d)
            .style("stroke", "#A0A0A0");
  
          // 小時刻度
          clock
            .selectAll(".hourTick")
            .data(d3.range(0, 12))
            .enter()
            .append("line")
            .attr("class", "hourTicks")
            .attr("x1", "0")
            .attr("x2", "0")
            .attr("y1", clockRadius)
            .attr("y2", hourTickLength)
            .attr("stroke-width", "6")
            .attr("stroke", "black")
            .attr("transform", (d) => `rotate(${hourScale(d)})`);
  
          // 小時數字標籤
          clock
            .selectAll(".hourLabels")
            .data(d3.range(3, 13, 3))
            .enter()
            .append("text")
            .attr("class", "hourLabels")
            .attr("text-anchor", "middle")
            // 標籤的半徑乘以角度(比例尺承弧度)的正弦值(Math.sin)
            .attr("x", (d) => 
                hourLabelRadius * Math.sin(hourScale(d) * radians)
            //標籤的半徑乘以角度(比例尺承弧度)的餘弦函數
            .attr("y", (d) => 
                -hourLabelRadius * Math.cos(hourScale(d) * radians) +
                hourLabelYOffset)
            .text((d) => d)
            .style("font-size", "24px")
            .style("font-weight", "bolder");