UNPKG

suoqiu-f2

Version:

Charts for mobile visualization.

417 lines (371 loc) 9.98 kB
import { deepMix, isNumber, mix, isNil, each, parsePadding } from '../util/common'; const MARKER_RADIUS = 3; class List { getDefaultCfg() { return { showTitle: false, /** * title string * @type {?String} */ title: null, /** * items array * @type {?Array} */ items: null, /** * offset between title and items * @type {Number} */ titleGap: 12, /** * offset between each item * @type {Number} */ itemGap: 10, /** * the offset between each item in vertical direaction * @type {Number} */ itemMarginBottom: 12, /** * the formatter for item text * @type {[type]} */ itemFormatter: null, itemWidth: null, /** * offset between marker and text * @type {Number} */ wordSpace: 6, x: 0, y: 0, layout: 'horizontal', /** * the join string of `name` and `value` * @type {String} */ joinString: ': ' }; } constructor(cfg) { deepMix(this, this.getDefaultCfg(), cfg); this._init(); this._renderTitle(); this._renderItems(); } _init() { const parent = this.parent; if (!parent) return; const container = parent.addGroup({ zIndex: this.zIndex || 0 }); this.container = container; const wrapper = container.addGroup(); this.wrapper = wrapper; const itemsGroup = wrapper.addGroup({ className: 'itemsGroup' }); this.itemsGroup = itemsGroup; } _renderTitle(title) { title = title || this.title; let titleShape = this.titleShape; let titleHeight = 0; if (this.showTitle && title) { if (titleShape && !titleShape.get('destroyed')) { titleShape.attr('text', title); } else { const { wrapper, titleStyle } = this; titleShape = wrapper.addShape('text', { className: 'title', attrs: mix({ x: 0, y: 0, text: title }, titleStyle) }); this.titleShape = titleShape; } titleHeight = titleShape.getBBox().height + this.titleGap; } this._titleHeight = titleHeight; } _renderItems(items) { const self = this; items = items || self.items; if (!items) { return; } if (self.reversed) { items.reverse(); } each(items, (item, index) => { self._addItem(item, index); }); if (items.length > 1) { this._adjustItems(); } this._renderBackground(); } _renderBackground() { const background = this.background; if (background) { const container = this.container; const wrapper = this.wrapper; const { minX, minY, width, height } = wrapper.getBBox(); let padding = background.padding || [ 0, 0, 0, 0 ]; padding = parsePadding(padding); const attrs = mix({ x: minX - padding[3], y: minY - padding[0], width: width + padding[1] + padding[3], height: height + padding[0] + padding[2] }, background); let backShape = this.backShape; if (backShape) { backShape.attr(attrs); } else { backShape = container.addShape('Rect', { zIndex: -1, attrs }); } this.backShape = backShape; container.sort(); } } _addItem(item) { const itemsGroup = this.itemsGroup; const itemGroup = itemsGroup.addGroup({ name: item.name, value: item.value, dataValue: item.dataValue, checked: item.checked }); const { unCheckStyle, unCheckColor, nameStyle, valueStyle, wordSpace } = this; const { marker, value } = item; let startX = 0; if (unCheckColor) { unCheckStyle.fill = unCheckColor; } if (marker) { const radius = marker.radius || MARKER_RADIUS; const markerAttrs = mix({ x: radius, y: this._titleHeight }, marker); if (item.checked === false) { mix(markerAttrs, unCheckStyle); } const markerShape = itemGroup.addShape('marker', { className: 'item-marker', attrs: markerAttrs }); startX += markerShape.getBBox().width + wordSpace; } let nameText; let name = item.name; if (name) { const joinString = this.joinString || ''; name = value ? name + joinString : name; nameText = itemGroup.addShape('text', { className: 'name', attrs: mix({ x: startX, y: this._titleHeight, text: this._formatItemValue(name) }, nameStyle, item.checked === false ? unCheckStyle : null) }); } if (value) { let valueX = startX; if (nameText) { valueX += nameText.getBBox().width; } itemGroup.addShape('text', { className: 'value', attrs: mix({ x: valueX, y: this._titleHeight, text: value }, valueStyle, item.checked === false ? unCheckStyle : null) }); } return itemGroup; } _formatItemValue(value) { const formatter = this.itemFormatter; if (formatter) { value = formatter.call(this, value); } return value; } _getMaxItemWidth() { let width; const itemWidth = this.itemWidth; if (isNumber(itemWidth) || isNil(itemWidth)) { return itemWidth; } if (itemWidth === 'auto') { const itemsGroup = this.itemsGroup; const children = itemsGroup.get('children'); const count = children.length; let maxItemWidth = 0; for (let i = 0; i < count; i++) { const { width } = children[i].getBBox(); maxItemWidth = Math.max(maxItemWidth, width); } const maxLength = this.maxLength; const itemGap = this.itemGap; const twoAvgWidth = (maxLength - itemGap) / 2; const threeAvgWidth = (maxLength - itemGap * 2) / 3; if (count === 2) { width = Math.max(maxItemWidth, twoAvgWidth); } else { // 1. max <= 3Avg, 3Avg // 2. 3Avg < max && max < 2avg, 2avg // 3. max > 2avg, max, one column if (maxItemWidth <= threeAvgWidth) { width = threeAvgWidth; } else if (maxItemWidth <= twoAvgWidth) { width = twoAvgWidth; } else { width = maxItemWidth; } } return width; } } _adjustHorizontal() { const { maxLength, itemsGroup } = this; const children = itemsGroup.get('children'); const { itemGap, itemMarginBottom } = this; const titleHeight = this._titleHeight; let row = 0; let rowWidth = 0; let width; let height; const itemWidth = this._getMaxItemWidth(); const legendHitBoxes = []; for (let i = 0, len = children.length; i < len; i++) { const child = children[i]; const box = child.getBBox(); const childHeight = box.height; const childWidth = box.width; width = itemWidth || childWidth; height = childHeight + itemMarginBottom; if (width - (maxLength - rowWidth) > 0.0001) { row++; rowWidth = 0; } child.moveTo(rowWidth, row * height); legendHitBoxes.push({ x: rowWidth, y: row * height + titleHeight - childHeight / 2, width: childWidth * 1.375, height: childHeight * 1.375 }); rowWidth += width + itemGap; } this.legendHitBoxes = legendHitBoxes; return; } _adjustVertical() { const { maxLength, itemsGroup } = this; const { itemGap, itemMarginBottom, itemWidth } = this; const titleHeight = this._titleHeight; const children = itemsGroup.get('children'); let colHeight = 0; let width; let height; let maxItemWidth = 0; let totalWidth = 0; const legendHitBoxes = []; for (let i = 0, length = children.length; i < length; i++) { const child = children[i]; const bbox = child.getBBox(); width = bbox.width; height = bbox.height; if (isNumber(itemWidth)) { maxItemWidth = itemWidth + itemGap; } else if (width > maxItemWidth) { maxItemWidth = width + itemGap; } if (maxLength - colHeight < height) { colHeight = 0; totalWidth += maxItemWidth; child.moveTo(totalWidth, 0); legendHitBoxes.push({ x: totalWidth, y: titleHeight - height / 2, width: width * 1.375, height: height * 1.375 }); } else { child.moveTo(totalWidth, colHeight); legendHitBoxes.push({ x: totalWidth, y: colHeight - height / 2 + titleHeight, width: width * 1.375, height: height * 1.375 }); } colHeight += height + itemMarginBottom; } this.legendHitBoxes = legendHitBoxes; return; } _adjustItems() { const layout = this.layout; if (layout === 'horizontal') { this._adjustHorizontal(); } else { this._adjustVertical(); } } moveTo(x, y) { this.x = x; this.y = y; const container = this.container; container && container.moveTo(x, y); return this; } setItems(items) { this.clearItems(); this._renderItems(items); } setTitle(title) { this._renderTitle(title); } clearItems() { const itemsGroup = this.itemsGroup; itemsGroup.clear(); } getWidth() { const container = this.container; const bbox = container.getBBox(); return bbox.width; } getHeight() { const container = this.container; const bbox = container.getBBox(); return bbox.height; } show() { const container = this.container; container.show(); } hide() { const container = this.container; container.hide(); } clear() { const container = this.container; container.clear(); container.remove(true); } } export default List;