@xiaomengqiang/charts
Version:
hcharts library for web visualization
332 lines (321 loc) • 12.3 kB
JavaScript
import Layout from './Layout.js';
import { insertIcon } from './insertIcon.js';
import defendXSS from '../../util/defendXSS.js';
import tips from '../../util/tips.js';
import { insertSvg } from './insertSvg.js';
/**
* Copyright (c) 2024 - present OpenTiny HUICharts Authors.
* Copyright (c) 2024 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
var NodeManager = /*#__PURE__*/function () {
function NodeManager(data, option, container) {
// 节点数据
this.data = void 0;
this.layoutNodes = void 0;
this.dom = void 0;
// 节点容器
this.scaleCon = null;
this.NODE_ID_PREFIX = 'mc-node-';
this.defaultColor = '#F3F3F3';
this.option = option;
this.dom = container;
this.render = option.render;
}
var _proto = NodeManager.prototype;
_proto.create = function create(data, option, Theme) {
this.option.Theme = Theme;
this.scaleCon = this.dom.getElementsByClassName('mc-scales')[0];
this.layoutNodes = new Layout(data, option, this.dom);
this.createNodes(this.option, this.scaleCon);
if (this.option.assign == 'date') {
this.option = this.layoutNodes.computePositions(this.option);
} else {
this.option = this.layoutNodes.computeAveragePositions(this.option);
}
this.layoutNodes.setTipsPosition(this.option);
if (this.option.current) this.createCurrentNode(this.option.current, this.dom.getElementsByClassName('mc-current')[0]);
}
/**
* 创建tooltip节点
*/;
_proto.createTooltipDom = function createTooltipDom(nodeDom, data) {
var tooltipDom = document.createElement('div');
tooltipDom.classList.add('mc-scales-item-tooltip');
if (this.option.tooltip) {
this.option.tooltip(tooltipDom, data);
} else {
var date = new Date(data.date * 1000); // 将时间戳转换成毫秒
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
tooltipDom.textContent = year + '/' + month + '/' + day;
}
nodeDom.appendChild(tooltipDom);
}
/**
* 创建节点
*/;
_proto.createNode = function createNode(ndata, nextData, size) {
var _nodeDom$classList;
var id = ndata.id,
render = ndata.render,
date = ndata.date,
icon = ndata.icon,
tilte = ndata.tilte,
tooltip = ndata.tooltip,
prompt = ndata.prompt,
promptIcon = ndata.promptIcon;
if (!date) tips.error('The second parameter date is required');
this.getDefBg(ndata, this.option.Theme);
var nodeDom = document.createElement('div');
var lineBg = defendXSS(nextData && nextData.line && (nextData.line.color || nextData.line.defColor) || ndata.line.defColor);
var lineHeight = defendXSS(nextData && nextData.line && nextData.line.height || ndata.line && ndata.line.height || 8);
var classList = [];
var tooltipClass = tooltip && tooltip.show ? 'tooltip' : '';
var firstLine = '';
size = size > 48 ? 48 : size;
if (this.option.data && this.option.data.length === 1) {
ndata.width = this.dom.offsetWidth - 40;
lineBg = defendXSS(ndata.line.color || ndata.line.defColor);
firstLine = 'block';
}
nodeDom.innerHTML = "<div class=\"mc-scales-item-line\" style=\"background:" + lineBg + ";height:" + lineHeight + "px;width: " + defendXSS(ndata.width || ndata.tipsWidth) + "px;display:" + firstLine + "\"></div>\n <div class='mc-scales-item-icon " + tooltipClass + "' style=\"width:" + defendXSS(size) + "px;height:" + defendXSS(size) + "px;\">\n </div>";
nodeDom.style.left = ndata.x + 'px';
classList.push('mc-scales-item');
if (icon && icon.name) classList.push(icon.name);
if (ndata.position) classList.push(ndata.position);
if (this.option.line) classList.push('line');
(_nodeDom$classList = nodeDom.classList).add.apply(_nodeDom$classList, classList);
nodeDom.id = this.NODE_ID_PREFIX + id;
var iconDom = nodeDom.getElementsByClassName('mc-scales-item-icon')[0];
insertSvg(iconDom, {
theme: this.option.theme,
icon: icon
}, this.option.Theme);
// 高亮标注
if (prompt) {
var promptDom = document.createElement('img');
promptDom.classList.add('prompt');
promptDom.src = promptIcon ? promptIcon : insertIcon('prompt');
iconDom.appendChild(promptDom);
}
// 悬浮显示
if (tooltip && tooltip.show) {
this.createTooltipDom(nodeDom, ndata);
}
// 节点信息
var renderFun = render || this.render;
var tipsDom = this.createTips(renderFun, ndata);
tipsDom && nodeDom.appendChild(tipsDom);
return nodeDom;
};
_proto.getDefBg = function getDefBg(data, Theme) {
var color = '';
var name = data.icon.name || '';
switch (name) {
case 'success':
color = Theme.config.colorState.colorSuccess;
break;
case 'done':
color = Theme.config.colorState.colorSuccess;
break;
case 'doing':
color = Theme.config.colorState.colorInfo;
break;
case 'todo':
color = Theme.config.colorState.colorNone;
break;
default:
color = Theme.config.colorState.colorNone;
break;
}
if (!data.line) data.line = {};
data.line.defColor = color;
data.icon.defColor = color;
}
/**
* 创建节点, 用户数据是否包含render
*/;
_proto.createTips = function createTips(renderFun, ndata) {
var tipsDom = document.createElement('div');
tipsDom.style['border-color'] = ndata.line && (ndata.icon.color || ndata.icon.defColor) || this.defaultColor;
tipsDom.classList.add('mc-scales-item-tips');
tipsDom.style['max-width'] = (ndata.width || ndata.tipsWidth) + 'px';
if (renderFun) {
renderFun(tipsDom, ndata);
this.createTipsDom(tipsDom, ndata);
} else {
var date = new Date(ndata.date * 1000); // 将时间戳转换成毫秒
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
tipsDom.textContent = year + '/' + month + '/' + day;
this.createTipsDom(tipsDom, ndata);
}
return tipsDom;
}
/**
* 创建节点dom
*/;
_proto.createTipsDom = function createTipsDom(tipsDom, data) {
// 克隆一个元素用于计算宽高
var cloneNode = tipsDom.cloneNode(true);
cloneNode.style.opacity = 0;
document.body.appendChild(cloneNode);
// 获取div的宽度和高度
var prevWidth = cloneNode.offsetWidth;
// 移除div元素
document.body.removeChild(cloneNode);
data.tipsWidth = prevWidth;
return tipsDom;
}
/**
* 根据用户传入数据生成节点Dom,并插入进container中
*/;
_proto.createNodes = function createNodes(option, scaleCon) {
var _this = this;
var self = this;
option.data.forEach(function (node, index) {
var nodeDom = _this.createNode(node, option.data[index + 1], node.icon && node.icon.size || option.itemStyle && option.itemStyle.iconSize || 12);
node.dom = nodeDom;
scaleCon.appendChild(nodeDom);
});
this.initHoverEvent();
this.initItemClickEvent();
setTimeout(function () {
self.setActions();
}, 100);
};
_proto.setActions = function setActions() {
var domWidth = this.dom.offsetWidth;
var contentWidth = this.dom.scrollWidth;
if (domWidth < contentWidth) {
var prevDom = this.dom.getElementsByClassName('mc-btn-prev')[0];
var nextDom = this.dom.getElementsByClassName('mc-btn-next')[0];
prevDom.style.display = 'block';
nextDom.style.display = 'block';
this.initHandoffEvent();
}
}
// 创建今天节点
;
_proto.createCurrentNode = function createCurrentNode(current, dom) {
var className = 'top';
var data = this.option.data;
data.forEach(function (item, index) {
var prev = data[index - 1];
var tipsWidth = item.dom && item.dom.getElementsByClassName('mc-scales-item-tips')[0].scrollWidth || 0;
var prevTipsWidth = prev && prev.dom.getElementsByClassName('mc-scales-item-tips')[0].scrollWidth || 0;
var itemPos = item.position.split('-');
var prevPos = prev && prev.position.split('-') || '';
if (current.x === item.x) {
if (itemPos[0] === 'up') {
className = 'bottom';
}
} else if (prev && prev.x < current.x && current.x < item.x) {
if (prevPos[0] === 'up' && current.x < prev.x + prevTipsWidth) {
className = 'bottom';
}
if (itemPos[0] === 'up' && current.x > item.x - tipsWidth) {
className = 'bottom';
}
}
});
dom.classList.add(className);
dom.getElementsByClassName('mc-current-text')[0].textContent = current.tip;
dom.style.left = current.x + 'px';
if (current.x == undefined) {
dom.style.display = 'none';
}
insertSvg(dom, {
theme: this.option.theme,
icon: {
src: current.icon || '',
name: 'current'
}
}, this.option.Theme);
}
// 绑定hover事件
;
_proto.initHoverEvent = function initHoverEvent() {
var elements = this.scaleCon.getElementsByClassName('tooltip');
Array.prototype.forEach.call(elements, function (element) {
// 鼠标滑入
element.addEventListener('mouseover', function () {
var parentNode = element.parentNode;
var tooltipDom = parentNode.getElementsByClassName('mc-scales-item-tooltip')[0];
tooltipDom.style.display = 'block';
element.style.zIndex = 2;
var x = parentNode.offsetLeft;
tooltipDom.style.left = '-' + (x - tooltipDom.offsetWidth / 2 >= 0 ? tooltipDom.offsetWidth / 2 : 0) + 'px';
tooltipDom.style.top = 'calc(50% - ' + (tooltipDom.offsetHeight / 2 + 24) + 'px)';
});
// 鼠标移出
element.addEventListener('mouseout', function () {
var parentNode = element.parentNode;
var tooltipDom = parentNode.getElementsByClassName('mc-scales-item-tooltip')[0];
tooltipDom.style.display = 'none';
});
});
}
// 绑定click事件
;
_proto.initItemClickEvent = function initItemClickEvent() {
var elements = this.scaleCon.getElementsByClassName('mc-scales-item');
var onClick = this.option.onClick && this.option.onClick;
this.option.data.forEach(function (item, index) {
elements[index].addEventListener("click", function () {
onClick(elements[index], item);
});
});
}
// 绑定前后切换click事件
;
_proto.initHandoffEvent = function initHandoffEvent() {
var position = 0;
var prev = false;
var next = true;
var num = this.option.newPitch;
var alignment = this.option.alignment;
num = alignment === 'left' ? 30 : alignment === 'right' ? num[0] + 10 : num;
var domWidth = this.dom.offsetWidth;
var contentWidth = this.dom.getElementsByClassName('mc-content')[0].scrollWidth;
var contentDom = this.dom.getElementsByClassName('mc-content')[0];
var prevDom = this.dom.getElementsByClassName('mc-btn-prev')[0];
var nextDom = this.dom.getElementsByClassName('mc-btn-next')[0];
prevDom.onmousedown = function () {
if (!prev) return;
next = true;
position -= 0.5;
var left = position * domWidth;
var newnum = alignment == 'center' ? num[0] : num;
if (left <= newnum) {
left = 0;
position = 0;
prev = false;
}
contentDom.style.left = -left + 'px';
};
nextDom.onmousedown = function () {
if (!next) return;
prev = true;
position += 0.5;
var left = position * domWidth;
var newnum = alignment == 'center' ? num[1] : num;
if (domWidth + left > contentWidth) {
left = contentWidth - domWidth + newnum;
next = false;
}
contentDom.style.left = -left + 'px';
};
};
return NodeManager;
}();
export { NodeManager as default };