仿照git馬賽克牆實現的JS原生熱力圖數據可視化工具,支持自定義日期、支持自定義橫縱座標等javascript
先上效果圖css
說一說實現的心理歷程,原本想像碼雲那個同樣用div來實現的,可是腦子靈光一閃,我怎麼不用canvas試一試呢,以前沒什麼機會接觸過,恰好來練練手。 因而就實現了一波:java
this.init = (dom) => {
var section = this.option.size + this.option.gap
dom.width = section * this.option.xAxis.length
dom.height = section * this.option.yAxis.length
// 調用canvas對象的getContext()方法,c變量就包含了指向2d渲染環境的引用
var context = dom.getContext('2d')
var levelGap = (this.option.max - this.option.min) / 4
this.option.data.forEach((item) => {
// [x, y, value]
var differ = this.option.max - item[2]
switch(true) {
case (item[2] >= this.option.max) :
color = 'rgb(25, 97, 39)'
break
case (differ < levelGap) :
color = 'rgb(35, 154, 59)'
break
case (differ < levelGap * 2) :
color = 'rgb(123, 201, 111)'
break
case (differ < levelGap * 3) :
color = 'rgb(198, 228, 139)'
break
default:
color = 'rgb(235, 237, 240)'
}
context.fillStyle = color
context.fillRect(item[0] * section, item[1] * section, this.option.size, this.option.size)
})
}
複製代碼
寫到一半,發現不行啊,人家canvas是一整張畫布,可是我是須要一個個小方格能夠實現鼠標懸浮顯示詳細信息的呀,不妥不妥。因而我又想到了svg這個好傢伙,F12看了下git,正好人家也是使用svg實現的。git
實現過程不復雜,就是比較繞,感興趣怎麼實現的小夥伴,我把項目地址貼出來了噢。若是個人組件是你須要用到的,那歡迎使用哈哈哈哈~~,下面說一說怎麼使用,還有一些思考 github
仿照git馬賽克牆實現了個JS原生小工具,支持自定義日期、支持自定義橫縱座標npm
使用起來很簡單,只要引入css文件和js文件便可canvas
引入css:bash
<link rel="stylesheet" href="./heatMap.css" />
複製代碼
引入js:數據結構
<script src="./heatMap.js"></script>
複製代碼
<script>
var heatMap = new HeatMapDate()
var option = {
gap: 6,
type: 'custom',
xAxis: ['11', '22', '33', '44'],
yAxis: ['aa', 'bb'],
data: [
[0, 0, 0],
// ...
[3, 1, 1]
],
min: 0,
max: 6,
tip: {
show: true,
formatter: '第{y}月的第{x}天有{b}個提交'
}
}
heatMap.setOption(option)
heatMap.init(document.getElementById('mySvg'))
<\script>
複製代碼
heatMap.setOption(option)
複製代碼
heatMap.init(dom)
複製代碼
參數 | 說明 | 類型 | 可選值 | 默認值 |
---|---|---|---|---|
type | 熱力圖類型,分兩種,date-日曆型和custom-自定義型 | String | date/custom | date |
xAxis | 橫座標的label,當type爲custom類型時須要傳遞該參數 | Array | - | - |
yAxis | 縱座標的label,當type爲custom類型時須要傳遞該參數 | Array | - | - |
gap | 方格之間的間隔 | Number | - | 3 |
data | 數據,若是type是date,那data是Object類型,格式{yyyy-MM-dd: value ...};若是type是custom,那data是Array類型,格式[[x,y,value]...] | Object/Array | - | - |
dateStart | 當type爲date類型時起做用,表示起始日期,日期格式:yyyy-MM-dd | String | - | 去年的今天 |
rect | 方格的相關屬性 | Object | - | - |
dateEnd | 當type爲date類型時起做用,表示結束日期,日期格式:yyyy-MM-dd | String | - | 今天 |
min | 分級的最低值,默認總共五個等級 | Number | - | 0 |
max | 分級的最高值,默認總共五個等級 | Number | - | data裏頭的值的最大值 |
tip | 方格頂部鼠標懸浮小氣泡的相關屬性 | Object | - | - |
tip.show | 鼠標懸浮是否顯示小氣泡 | Boolean | true/false | true |
tip.formatter | 小氣泡的文本內容。type爲date的時候{a}表示日期,{b}表示數值;type爲custom的時候{x}表示x軸對應的值,{y}對應y軸的值,{b}表示數值;若是在替換字符串前加反斜槓(例如/{b}),則不會替換該字符串 | String | - | - |
rect | 方格的相關屬性 | Object | - | - |
rect.stroke | 方格邊框的相關屬性 | Object | - | - |
rect.stroke.show | 是否顯示方格邊框 | Boolean | true/false | false |
rect.stroke.background | 方格邊框顏色 | String | - | #333333 |
rect.stroke.opacity | 方格邊框透明度 | Float | 0~1 | 0.6 |
rect.colourMatching | 方格配色方案,能夠自定義(custom)也可使用現有的配色方案 | String | custom/green/pink/blue/orange/gray | green |
rect.stroke.backgroundArr | 當type爲custom類型時起做用,方格配色方案具體顏色,多少個顏色就表示多少個等級,等級由重到輕,第一個顏色表示等級最重 | Array | - | - |
說一說實現過程當中的痛點:app
日曆型我知道橫軸就是月份,縱軸就是星期,因此我new新的熱力圖的時候,傳的數據裏頭只要有日期和值就行。但自定義就不同了,自定義的橫縱座標都是後來定義的,因此爲了知道具體的哪一個小方格的值,傳的數據裏頭必須像[x, y, value]
這樣的結構。
日曆型熱力圖默認是當前時間往前推一年這樣一個時間跨度,因此我必須輪詢出這一年裏的全部日期,再拼裝組合起來。後期考慮到了靈活性,因此這個時間跨度也是能夠自定義的。
小方格的size關乎到左邊區域的大小。總的來講就是當前容器的寬度減去左邊區域大小,再除以列數,寫的時候的邏輯比較繞,跟寫高數題似的,想起了當年被支配的恐懼。。
頂部懸浮氣泡實際上我只定義了一個容器,每次調用的時候,改變定位和文字內容。
配色這一塊,有多少個配色就有多少個等級。我不但願把顏色定死,因此本身組合定義了五種配色方案:green、pink、blue、orange、gray。考慮到有改變等級和配色的須要,配置項能夠自定義。
總的來講,實現的思路並不難,就是實現的過程比較蛋疼。後期我打算增長一些自定義功能,而後作成根據屏幕大小來動態改變佈局。有想法將它封裝成npm工具,也算是個人第一個正兒八經開源小工具啦,源碼我已經貼出了來,有須要一塊兒學習的小夥伴自行clone~~筆芯
這就是我實現這個小工具的最核心代碼:
/** * 對Date的擴展,將 Date 轉化爲指定格式的String * 月(M)、日(d)、小時(h)、分(m)、秒(s)、季度(q) 能夠用 1-2 個佔位符, * 年(y)能夠用 1-4 個佔位符,毫秒(S)只能用 1 個佔位符(是 1-3 位的數字) * 例子: * (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 * (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18 * @param fmt 日期格式 */
Date.prototype.format = function (fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小時
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
/** * 字符串轉換爲日期對象 * @param dateStr Date 格式爲yyyy-MM-dd HH:mm:ss,必須按年月日時分秒的順序,中間分隔符不限制 */
Date.prototype.strToDate = function (dateStr) {
var data = dateStr
var reCat = /(\d{1,4})/gm
var t = data.match(reCat)
t[1] = t[1] - 1
eval('var d = new Date(' + t.join(',') + ')')
return d
}
/** * 獲取日期列表,不傳參默認當前時間爲截止日期,去年的今天爲起始日期 * @param dateStart 起始日期 格式爲yyyy-MM-dd,必須按年月日的順序,中間分隔符不限制 * @param dateEnd 截止日期 格式爲yyyy-MM-dd,必須按年月日的順序,中間分隔符不限制 */
Date.prototype.getDateList = function (dateStart, dateEnd) {
try {
var date, diff, list = {}
// 缺一不可,缺任何一個都採起默認時間
if (!dateStart || !dateEnd) {
// 當前時間
date = new Date()
// 當前時間往前推一年
date.setFullYear(date.getFullYear() - 1)
// 若是去年的今天不是星期天的話,補充天數直到起始日期是星期天爲止
while (date.getDay() > 0) {
date.setDate(date.getDate() - 1)
}
// 計算相差的天數
diff = parseInt((new Date().getTime() - date.getTime()) / (1000 * 60 * 60 * 24))
} else {
// 轉換爲日期對象
var start = this.strToDate(dateStart)
var end = this.strToDate(dateEnd)
// 補充天數直到起始日期是星期天爲止
while (start.getDay() > 0) {
start.setDate(start.getDate() - 1)
}
// 計算相差的天數
diff = parseInt((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24))
date = start
}
// 實際上連最後一天也要算上,因此diff加2
for (i = 1; i < diff + 2; i++) {
list[date.format("yyyy-MM-dd")] = date.getDay()
date.setDate(date.getDate() + 1)
}
return list
} catch(e) {
return {}
}
}
var weekMap = ['週日', '週一', '週二', '週三', '週四', '週五', '週六']
var monthMap = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']
var colorMap = {
'blue': ['#003C9D', '#409EFF', '#87CEFA', '#E0FFFF', '#EBEDF0'],
'pink': ['#990099', '#CC00CC', '#FF88C2', '#FFB7DD', '#EBEDF0'],
'green': ['#196127', '#239A3B', '#7BC96F', '#C6E48B', '#EBEDF0'],
'orange': ['#A42D00', '#CC6600', '#EE7700', '#FFAA33', '#EBEDF0'],
'gray': ['#303133', '#444444', '#808080', '#C0C0C0', '#EBEDF0']
}
// 合併兩個object,以mainObj爲基準
function matchObj(mainObj, obj) {
var resultObj = {}
for (var key in mainObj) {
if (!obj.hasOwnProperty(key)) {
resultObj[key] = mainObj[key]
} else if (Object.prototype.toString.call(mainObj[key]) === '[Object Object]' && key !== 'data') {
resultObj[key] = matchObj(mainObj[key], obj[key])
} else {
resultObj[key] = obj[key]
}
}
return resultObj
}
function HeatMapDate() {
this.option = {
type: 'date', // 類型:date-日曆型,custom-自定義型
xAxis: [], // 橫座標的label,type=custom起做用
yAxis: [], // 縱座標的label,type=custom起做用
gap: 3, // 方格之間的間隔
/* 數據 * 若是type是date。那data是Object類型,格式是{ 'yyyy-MM-dd' : value } * 若是type是custom。那data是Array類型,格式是[[x, y, value], ..., [x, y, value]] */
data: {},
rect: {
stroke: {
show: false,
background: '#333', // 正方形的邊框顏色
opacity: 0.6 // 正方形的邊框透明度
},
colourMatching: '', //配色方案,有custom-自定義和reen、pink、blue、orange、gray五種漸變色
backgroundArr: [] // 自定義配色方案,程度由重到輕
},
dateStart: '',
dateEnd: '',
min: 0, // 分級最低值,總共五個等級,不傳默認值是0
max: 0, // 分級最高值,總共五個等級,不傳默認值是
tip: { // 頂部鼠標懸浮小氣泡
show: true, // 是否展現
/** 文本內容 * type爲date的時候{a}表示日期,{b}表示數值 * type爲custom的時候表示{x}x軸對應的值,{y}y軸對應的值,{b}表示數值 * 若是在替換字符串前加反斜槓(例如/{b}),則不會替換該字符串 */
formatter: ''
}
}
// 初始化參數,沒傳的就使用默認值
this.setOption = (obj) => {
this.option = matchObj(this.option, obj)
if (!this.option.max) {
this.option.max = Object.values(obj.data).sort(function(a, b) {
return b - a
})[0] || 0
}
}
this.init = (dom) => {
// 初始化dom的樣式
dom.setAttribute('style', 'width:100%;height:100%;position:relative;')
// 獲取父級dom的寬度
var parentWidth = dom.offsetWidth
// 經過createElementNS建立svg元素並設置屬性
var svg = document.createElementNS('http://www.w3.org/2000/svg','svg')
svg.setAttribute('version', '1.1')
svg.setAttribute('class', 'svg-container')
dom.appendChild(svg) // 掛載元素。SVG元素添加到頁面內顯示
// 顯示頂部提示小氣泡
if (this.option.tip.show) {
// 建立tip容器並設置屬性
var tip = document.createElement('div')
tip.setAttribute('class', 'svg-tip svg-tip-one-line')
var title = document.createElement('strong')
tip.appendChild(title) // 掛載到父節點上
dom.appendChild(tip) // 掛載元素。掛載頂部提示氣泡
}
// 建立svg的group元素並設置屬性
var group = document.createElementNS('http://www.w3.org/2000/svg', 'g')
var translateX = 20 // 橫軸方向的偏移值
var translateY = 40 // 縱軸方向的偏移值
group.setAttribute('transform', 'translate(' + translateX + ',' + translateY + ')')
svg.appendChild(group) // 掛載到父節點上
var maxYLabelFontSize = 12
var labelPadding = 10
var maxStrLength = 0
if (this.option.type === 'date') {
// 獲取所有天數列表
var dateList = (new Date()).getDateList(this.option.dateStart, this.option.dateEnd)
var columnCount = Math.ceil(Object.keys(dateList).length / 7)
var size = Math.floor((parentWidth - translateX / 2 - maxYLabelFontSize * 2 - labelPadding - this.option.gap * columnCount) / columnCount)
var section = size + this.option.gap
// 縱軸的label值,這裏是星期值
for (var w = 0; w < 7; w++) {
//建立矩形元素並設置屬性
var yText = document.createElementNS('http://www.w3.org/2000/svg', 'text')
yText.style.fontSize = section * 0.7 > maxYLabelFontSize ? maxYLabelFontSize : section * 0.7 // 字體大小響應,最大是12px
yText.setAttribute('dx', -labelPadding)
yText.setAttribute('dy', w * section + size / 2 + 4)
yText.setAttribute('class', 'wday')
yText.innerHTML = weekMap[w]
group.appendChild(yText)
if (maxStrLength < yText.getBBox().width) {
maxStrLength = yText.getBBox().width
}
}
var index = 0 // 天數列表索引
var column = 0 // 分組索引,完整的一週爲一組
for (var dateKey in dateList) {
// 完整的一週爲一組
if (index === 0 || index % 7 === 0) {
// 建立svg的group元素並設置屬性,一週爲一組
var xGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g')
// 設置偏移值
xGroup.setAttribute('transform', 'translate(' + (column * section + maxStrLength) + ', 0)')
group.appendChild(xGroup) // 掛載到父節點
column++ // 遞增組數索引
// 判斷在哪一個分組的上方增長橫軸的label值,在這裏是月份
if (index > 0) {
var startMonth = dateKey.split('-')[1]
var preStartMonth = Object.keys(dateList)[index - 7].split('-')[1]
if (Math.abs(Number(startMonth) - Number(preStartMonth)) > 0) {
//建立text元素並設置屬性
var fontSize = section * 0.8 > maxYLabelFontSize ? maxYLabelFontSize : section * 0.8 // 字體大小響應,最大是14px
var xText = document.createElementNS('http://www.w3.org/2000/svg', 'text')
xText.style.fontSize = fontSize
xText.setAttribute('x', column * section)
xText.setAttribute('y', -labelPadding)
xText.setAttribute('class', 'month')
xText.innerHTML = monthMap[Number(startMonth) - 1]
group.appendChild(xText)
}
}
}
if(this.option.data.hasOwnProperty(dateKey)) {
// 開始畫正方形啦~建立矩形元素並設置屬性
var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('x', 0)
rect.setAttribute('y', dateList[dateKey] * section)
rect.setAttribute('id', dateKey) // 設置日期爲id值
rect.setAttribute('week', dateList[dateKey]) // 設置星期幾屬性
rect.setAttribute('column', column) // 設置分組的組索引屬性
rect.setAttribute('width', size)
rect.setAttribute('height', size)
color = '#fff' // 默認顏色是白色,就是啥也沒有時候的顏色,以你的背景色爲準
var colorSelect = ''
// 選擇的顏色系列
if (this.option.rect.colourMatching === 'custom') {
colorSelect = this.option.rect.backgroundArr
} else {
colorSelect = colorMap[this.option.rect.colourMatching]
}
// 默認綠色爲基本配色方案
colorSelect = colorSelect ? colorSelect : colorMap['green']
// 分爲五個等級,小於最小值最低等級,大於最大值最高等級。中間還應該有三個等級(可自定義)
var levelGap = (this.option.max - this.option.min) / (colorSelect.length - 2)
if (this.option.data.hasOwnProperty(dateKey)) {
var differ = this.option.max - this.option.data[dateKey]
// 小正方形的顏色決定於他的值處在哪一個level裏頭
switch(true) {
case (this.option.data[dateKey] >= this.option.max) :
color = colorSelect[0]
break
case (differ < levelGap) :
color = colorSelect[1]
break
case (differ < levelGap * 2) :
color = colorSelect[2]
break
case (differ < levelGap * 3) :
color = colorSelect[3]
break
default:
color = colorSelect[4]
}
// 設置小矩形的顏色
rect.setAttribute('style', 'fill:' + color)
// 顯示頂部提示小氣泡
if (this.option.tip.show) {
//矩形元素綁定鼠標事件實現動態效果
// 鼠標移入
rect.onmouseover = (e) => {
if (this.option.rect.stroke.show) {
e.srcElement.setAttribute('stroke-width', 1)
e.srcElement.setAttribute('stroke', this.option.rect.stroke.background)
e.srcElement.setAttribute('stroke-opacity', this.option.rect.stroke.opacity)
}
// 提示小氣泡的文本內容,默認==>日期:值
if (this.option.tip.formatter) {
var tipText = this.option.tip.formatter.replace(/(?<!\/){a}/g, e.target.id).replace(/(?<!\/){b}/g, this.option.data[e.target.id])
tip.innerHTML = tipText
} else {
tip.innerHTML = e.target.id + ':' + this.option.data[e.target.id]
}
tip.style.display = 'block'
tip.style.top = (e.target.attributes.week.value * section + dom.querySelector('.svg-tip').offsetHeight / 2 - translateY / 2 - labelPadding) + 'px'
tip.style.left = ((e.target.attributes.column.value - 1) * section + size / 2 + translateX / 2 + maxStrLength + labelPadding - dom.querySelector('.svg-tip').offsetWidth / 2) + 'px'
}
// 鼠標移出
rect.onmouseout = (e) => {
if (this.option.rect.stroke.show) {
e.srcElement.setAttribute('stroke-width', 0)
}
tip.style.display = 'none'
}
}
}
xGroup.appendChild(rect) //掛載矩形元素添加到小分組元素內
}
index++
}
// 設置svg元素的寬高
svg.style.width = Math.ceil(section * columnCount + translateX + maxStrLength + labelPadding)
svg.style.height = section * 7 + translateY
}
if (this.option.type === 'custom') {
var size = parseInt(parentWidth / this.option.xAxis.length) - this.option.gap * this.option.xAxis.length
var section = size + this.option.gap
var fontSize = section * 0.7 > maxYLabelFontSize ? maxYLabelFontSize : section * 0.7 // 字體大小響應,最大是12px
this.option.xAxis.forEach((xItem,xIndex) => {
var xGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g')
group.appendChild(xGroup)
this.option.yAxis.forEach((yItem,yIndex) => {
if (xIndex === 0) {
//建立矩形元素並設置屬性
var yText = document.createElementNS('http://www.w3.org/2000/svg', 'text')
yText.style.fontSize = fontSize
yText.setAttribute('dx', -labelPadding)
yText.setAttribute('dy', yIndex * section + size / 2 + 4)
yText.setAttribute('class', 'wday')
yText.innerHTML = yItem
group.appendChild(yText)
if (maxStrLength < yText.getBBox().width) {
maxStrLength = yText.getBBox().width
}
}
this.option.data.some((elem, i) => {
if (elem[0] === xIndex && elem[1] === yIndex) {
color = 'rgb(255, 255, 255)' // 默認顏色是白色,就是啥也沒有時候的顏色,以你的背景色爲準
var colorSelect = ''
// 選擇的顏色系列
if (this.option.rect.colourMatching === 'custom') {
colorSelect = this.option.rect.backgroundArr
} else {
colorSelect = colorMap[this.option.rect.colourMatching]
}
// 默認綠色爲基本配色方案
colorSelect = colorSelect ? colorSelect : colorMap['green']
// 分爲五個等級,小於最小值最低等級,大於最大值最高等級。中間還應該有三個等級(可自定義)
var levelGap = (this.option.max - this.option.min) / (colorSelect.length - 2)
var differ = this.option.max - elem[2]
// 小正方形的顏色決定於他的值處在哪一個level裏頭
switch(true) {
case (elem[2] >= this.option.max) :
color = colorSelect[0]
break
case (differ < levelGap) :
color = colorSelect[1]
break
case (differ < levelGap * 2) :
color = colorSelect[2]
break
case (differ < levelGap * 3) :
color = colorSelect[3]
break
default:
color = colorSelect[4]
}
//建立矩形元素並設置屬性
var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('x', 0)
rect.setAttribute('y', elem[1] * section)
rect.setAttribute('id', elem[0] + '_' + elem[1]) // 設置日期爲id值
rect.setAttribute('row', yIndex)
rect.setAttribute('column', xIndex)
rect.setAttribute('width', size)
rect.setAttribute('height', size)
rect.setAttribute('style', 'fill:' + color)
// 顯示頂部提示小氣泡
if (this.option.tip.show) {
//矩形元素綁定鼠標事件實現動態效果
// 鼠標移入
rect.onmouseover = (e) => {
if (this.option.rect.stroke.show) {
e.srcElement.setAttribute('stroke-width', 1)
e.srcElement.setAttribute('stroke', this.option.rect.stroke.background)
e.srcElement.setAttribute('stroke-opacity', this.option.rect.stroke.opacity)
}
var xyArr = e.target.id.split('_')
// 提示小氣泡的文本內容,默認==>x_y:值
if (this.option.tip.formatter) {
var tipText = this.option.tip.formatter.replace(/(?<!\/){x}/g, this.option.xAxis[xyArr[0]]).replace(/(?<!\/){y}/g, this.option.yAxis[xyArr[1]]).replace(/(?<!\/){b}/g, elem[2])
tip.innerHTML = tipText
} else {
tip.innerHTML = e.target.id + ':' + elem[2]
}
tip.style.display = 'block'
tip.style.top = (e.target.attributes.row.value * section + dom.querySelector('.svg-tip').offsetHeight / 2 - translateY / 2 - labelPadding) + 'px'
tip.style.left = (e.target.attributes.column.value * section + size / 2 + translateX / 2 + maxStrLength + labelPadding - dom.querySelector('.svg-tip').offsetWidth / 2) + 'px'
}
// 鼠標移出
rect.onmouseout = (e) => {
if (this.option.rect.stroke.show) {
e.srcElement.setAttribute('stroke-width', 0)
}
tip.style.display = 'none'
}
}
//將矩形元素添加到SVG元素內
xGroup.appendChild(rect)
return true
} else {
return false
}
})
})
xGroup.setAttribute('transform', 'translate(' + (xIndex * section + maxStrLength) + ', 0)')
//建立text元素並設置屬性
var xText = document.createElementNS('http://www.w3.org/2000/svg', 'text')
xText.style.fontSize = fontSize
xText.setAttribute('x', xIndex * section + maxStrLength)
xText.setAttribute('y', -labelPadding)
xText.setAttribute('class', 'month')
xText.innerHTML = xItem
group.appendChild(xText)
xText.setAttribute('textLength', size < xText.getBBox().width ? size : xText.getBBox().width)
})
// 設置svg元素的寬高
svg.style.width = section * this.option.xAxis.length + translateX / 2 + labelPadding + maxStrLength
svg.style.height = section * this.option.yAxis.length + translateY
}
}
}
複製代碼