const root = document.createElement('canvas')
const context = root.getContext('2d')
const width = 800
const height = 100
root.width = width
root.height = height
const tick_length = 20
const axis_rectangle = [5, 50 - tick_length, width - 100, 50]
const axis_container = {
width: axis_rectangle[2] - axis_rectangle[0],
height: axis_rectangle[3] - axis_rectangle[1]
}
const transitionTime = 500
const dataArray = [12, 15, 25, 38, 45, 51, 64, 87, 92, 112, 234, 345, 456, 567, 678, 789, 899, 999, 1023, 1123, 1234, 1345, 1456, 678, 567, 456, 345, 234, 999]
const dataContainer = d3.select(
document.createElement("custom")
)
function drawCustom(data, index) {
const allowedUnits = allowedAxisUnits(data)
const allowedUnitsDict = []
allowedUnits.forEach(d => {
allowedUnitsDict.push({ name: d.toString(), value: d, highest_value: data })
})
const dataBinding = dataContainer
.selectAll("custom.ticks")
.data(allowedUnitsDict, d => d.name)
dataBinding
.enter()
.append('custom')
.classed('ticks', true)
.attr('tickColor', 'rgba(252, 110, 34,0)')
.attr('tickLabel', d => d.value)
.attr('x', d => d.value)
.attr('tickSize', 7)
.attr('highest_val', d => d.highest_value)
dataBinding
.transition()
.ease(d3.easeLinear)
.duration(transitionTime)
.delay(index * transitionTime)
.attr('tickColor', 'rgba(252, 110, 34,0.9)')
.attr('x', d => d.value)
.attr('highest_val', d => d.highest_value)
.attr('tickSize', 7)
dataBinding
.exit()
.transition()
.duration(transitionTime)
.delay(index * transitionTime)
.attr('tickColor', 'rgba(252, 110, 34,0)')
.remove()
}
function drawCanvas() {
context.clearRect(0, 0, width + 100, height)
// draw main line
context.beginPath()
context.strokeStyle = 'black'
context.moveTo(axis_rectangle[0], axis_rectangle[1]);
context.lineTo(axis_rectangle[2], axis_rectangle[3] - tick_length)
context.stroke()
// draw ticks and tick labels
const elements = dataContainer.selectAll('custom.ticks')
elements.each(function (d) {
const node = d3.select(this)
const tick_len = parseFloat(node.attr('tickSize'))
const xVal = parseFloat(node.attr('x'))
// ticks
const point = scaleLin(
xVal,
[0, parseFloat(node.attr('highest_val'))],
[axis_rectangle[0], axis_rectangle[2]]
)
context.beginPath()
context.strokeStyle = node.attr('tickColor')
context.moveTo(point + axis_rectangle[0], axis_rectangle[1])
context.lineTo(point + axis_rectangle[0], axis_rectangle[1] + tick_len)
context.stroke()
// tick label
context.fillStyle = node.attr('tickColor')
context.font = '14px Arial'
context.textAlign = 'center'
context.fillText(
node.attr("tickLabel"),
point + axis_rectangle[0],
axis_rectangle[1] + tick_len + 15
)
context.closePath()
})
}
for (let index = 0; index < dataArray.length; index++) {
drawCustom(dataArray[index], index)
}
d3.timer(drawCanvas)
setTimeout(() => {
document.body.append(root)
})
function scaleLin(value, domain, range) {
const dominDiff = domain[1] - domain[0]
const rangeDiff = range[1] - range[0]
const ratio = rangeDiff / dominDiff
return range[0] + value * ratio
}
function allowedAxisUnits(n) {
const u = axisNiceUnit(n)
const returnArray = []
let count = 0
while (u * count <= n) {
returnArray.push(u * count)
count++
}
returnArray.push(u * count)
count++
returnArray.push(u * count)
return returnArray
}
function axisNiceUnit(n) {
const f = firstDigitPower(n)
if (n < 0.5 * 10 ** (f + 1)) {
return 1 * 10 ** f
} else {
return 2 * 10 ** f
}
}
// 得出数字的位数,如 1=>0 0.1=>-1 0.01=>-2
function firstDigitPower(n) {
if (n < 0) {
n *= -1
}
let count = 0
if (n >= 1) {
const n1 = parseInt(n)
return n1.toString().length - 1
} else {
while (n < 1) {
// console.log(n)
count = count - 1
n = n * 10
}
return count
}
}
console