modify:新增小程序
This commit is contained in:
242
Sale/components/ec-canvas/echarts.js
Normal file
242
Sale/components/ec-canvas/echarts.js
Normal file
@@ -0,0 +1,242 @@
|
||||
/**
|
||||
* 简化版 ECharts - 仅支持折线图
|
||||
* 用于微信小程序 Canvas 2D
|
||||
*/
|
||||
|
||||
class ECharts {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas
|
||||
this.ctx = canvas.getContext('2d')
|
||||
this.option = null
|
||||
// canvas.width 已经是缩放后的尺寸,直接使用
|
||||
this.width = canvas.width || 750
|
||||
this.height = canvas.height || 500
|
||||
this.padding = { top: 40, right: 40, bottom: 60, left: 80 }
|
||||
|
||||
console.log('ECharts 构造函数:', {
|
||||
canvasWidth: canvas.width,
|
||||
canvasHeight: canvas.height,
|
||||
chartWidth: this.width,
|
||||
chartHeight: this.height
|
||||
})
|
||||
}
|
||||
|
||||
setOption(option) {
|
||||
this.option = option
|
||||
this.render()
|
||||
}
|
||||
|
||||
clear() {
|
||||
if (!this.ctx) return
|
||||
this.ctx.clearRect(0, 0, this.width, this.height)
|
||||
}
|
||||
|
||||
resize() {
|
||||
// 自动调整大小
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.option || !this.ctx) {
|
||||
console.log('ECharts render: 缺少 option 或 ctx')
|
||||
return
|
||||
}
|
||||
|
||||
const { xAxis, yAxis, series } = this.option
|
||||
if (!series || !series[0]) {
|
||||
console.log('ECharts render: 缺少 series 数据')
|
||||
return
|
||||
}
|
||||
|
||||
const data = series[0].data || []
|
||||
const categories = xAxis?.data || []
|
||||
|
||||
console.log('ECharts render:', {
|
||||
dataCount: data.length,
|
||||
categoryCount: categories.length,
|
||||
width: this.width,
|
||||
height: this.height
|
||||
})
|
||||
|
||||
this.clear()
|
||||
|
||||
// 计算绘图区域
|
||||
const chartWidth = this.width - this.padding.left - this.padding.right
|
||||
const chartHeight = this.height - this.padding.top - this.padding.bottom
|
||||
|
||||
// 计算数据范围
|
||||
const maxValue = Math.max(...data) * 1.1
|
||||
const minValue = Math.min(...data) * 0.9
|
||||
const valueRange = maxValue - minValue || 1
|
||||
|
||||
// 绘制坐标轴
|
||||
this.drawAxes(chartWidth, chartHeight, minValue, maxValue, categories)
|
||||
|
||||
// 绘制区域填充
|
||||
if (series[0].areaStyle) {
|
||||
this.drawArea(data, chartWidth, chartHeight, minValue, valueRange)
|
||||
}
|
||||
|
||||
// 绘制折线
|
||||
this.drawLine(data, chartWidth, chartHeight, minValue, valueRange)
|
||||
|
||||
// 绘制数据点
|
||||
this.drawPoints(data, chartWidth, chartHeight, minValue, valueRange)
|
||||
}
|
||||
|
||||
drawAxes(chartWidth, chartHeight, minValue, maxValue, categories) {
|
||||
const ctx = this.ctx
|
||||
const { top, right, bottom, left } = this.padding
|
||||
|
||||
ctx.strokeStyle = '#e0e0e0'
|
||||
ctx.lineWidth = 1
|
||||
|
||||
// X 轴
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(left, top + chartHeight)
|
||||
ctx.lineTo(left + chartWidth, top + chartHeight)
|
||||
ctx.stroke()
|
||||
|
||||
// Y 轴
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(left, top)
|
||||
ctx.lineTo(left, top + chartHeight)
|
||||
ctx.stroke()
|
||||
|
||||
// 绘制 Y 轴刻度
|
||||
ctx.fillStyle = '#666'
|
||||
ctx.font = '20px sans-serif'
|
||||
ctx.textAlign = 'right'
|
||||
ctx.textBaseline = 'middle'
|
||||
|
||||
const ySteps = 5
|
||||
for (let i = 0; i <= ySteps; i++) {
|
||||
const value = minValue + (maxValue - minValue) * (i / ySteps)
|
||||
const y = top + chartHeight - (chartHeight * (i / ySteps))
|
||||
|
||||
ctx.fillText(
|
||||
'¥' + Math.round(value),
|
||||
left - 10,
|
||||
y
|
||||
)
|
||||
|
||||
// 绘制网格线
|
||||
ctx.strokeStyle = '#f0f0f0'
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(left, y)
|
||||
ctx.lineTo(left + chartWidth, y)
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
// 绘制 X 轴标签
|
||||
ctx.textAlign = 'center'
|
||||
ctx.textBaseline = 'top'
|
||||
|
||||
const xStep = chartWidth / (categories.length || 1)
|
||||
const skipStep = Math.ceil(categories.length / 6) // 最多显示6个标签
|
||||
|
||||
categories.forEach((category, index) => {
|
||||
if (index % skipStep !== 0) return // 跳过部分标签
|
||||
|
||||
const x = left + xStep * (index + 0.5)
|
||||
const y = top + chartHeight + 10
|
||||
|
||||
ctx.save()
|
||||
ctx.translate(x, y)
|
||||
ctx.rotate(45 * Math.PI / 180)
|
||||
ctx.fillText(category, 0, 0)
|
||||
ctx.restore()
|
||||
})
|
||||
}
|
||||
|
||||
drawLine(data, chartWidth, chartHeight, minValue, valueRange) {
|
||||
const ctx = this.ctx
|
||||
const { top, left } = this.padding
|
||||
|
||||
const xStep = chartWidth / (data.length || 1)
|
||||
|
||||
ctx.strokeStyle = '#1890ff'
|
||||
ctx.lineWidth = 3
|
||||
ctx.lineCap = 'round'
|
||||
ctx.lineJoin = 'round'
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
data.forEach((value, index) => {
|
||||
const x = left + xStep * (index + 0.5)
|
||||
const y = top + chartHeight - ((value - minValue) / valueRange) * chartHeight
|
||||
|
||||
if (index === 0) {
|
||||
ctx.moveTo(x, y)
|
||||
} else {
|
||||
ctx.lineTo(x, y)
|
||||
}
|
||||
})
|
||||
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
drawArea(data, chartWidth, chartHeight, minValue, valueRange) {
|
||||
const ctx = this.ctx
|
||||
const { top, left } = this.padding
|
||||
|
||||
const xStep = chartWidth / (data.length || 1)
|
||||
|
||||
// 创建渐变
|
||||
const gradient = ctx.createLinearGradient(0, top, 0, top + chartHeight)
|
||||
gradient.addColorStop(0, 'rgba(24, 144, 255, 0.3)')
|
||||
gradient.addColorStop(1, 'rgba(24, 144, 255, 0.05)')
|
||||
|
||||
ctx.fillStyle = gradient
|
||||
ctx.beginPath()
|
||||
|
||||
data.forEach((value, index) => {
|
||||
const x = left + xStep * (index + 0.5)
|
||||
const y = top + chartHeight - ((value - minValue) / valueRange) * chartHeight
|
||||
|
||||
if (index === 0) {
|
||||
ctx.moveTo(x, y)
|
||||
} else {
|
||||
ctx.lineTo(x, y)
|
||||
}
|
||||
})
|
||||
|
||||
// 闭合路径
|
||||
const lastX = left + xStep * (data.length - 0.5)
|
||||
ctx.lineTo(lastX, top + chartHeight)
|
||||
ctx.lineTo(left + xStep * 0.5, top + chartHeight)
|
||||
ctx.closePath()
|
||||
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
drawPoints(data, chartWidth, chartHeight, minValue, valueRange) {
|
||||
const ctx = this.ctx
|
||||
const { top, left } = this.padding
|
||||
|
||||
const xStep = chartWidth / (data.length || 1)
|
||||
|
||||
data.forEach((value, index) => {
|
||||
const x = left + xStep * (index + 0.5)
|
||||
const y = top + chartHeight - ((value - minValue) / valueRange) * chartHeight
|
||||
|
||||
// 绘制点
|
||||
ctx.fillStyle = '#fff'
|
||||
ctx.strokeStyle = '#1890ff'
|
||||
ctx.lineWidth = 2
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.arc(x, y, 4, 0, 2 * Math.PI)
|
||||
ctx.fill()
|
||||
ctx.stroke()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function init(canvas, width, height) {
|
||||
const chart = new ECharts(canvas)
|
||||
return chart
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init
|
||||
}
|
||||
Reference in New Issue
Block a user