程式碼
//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})`);
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})`);
程式碼
//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})`);
程式碼
//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})`);
程式碼
//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})`);
程式碼
//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})`);
程式碼
//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})`);
}
程式碼
//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})`);
程式碼
//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)`
);
程式碼
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");