UNPKG

@xiaomengqiang/charts

Version:

hcharts library for web visualization

332 lines (321 loc) 12.3 kB
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 };