UNPKG

@progress/kendo-charts

Version:

Kendo UI platform-independent Charts library

314 lines (259 loc) 9.03 kB
import { ChartElement, BoxElement, Box, TextBox, FloatElement } from '../../core'; import LegendLayout from './legend-layout'; import LegendItem from './legend-item'; import { TOP, RIGHT, BOTTOM, LEFT, CENTER, X, Y, BLACK, CIRCLE, POINTER, START, END, HORIZONTAL, SQUARE } from '../../common/constants'; import { deepExtend, defined, getTemplate, getSpacing, inArray, setDefaultOptions } from '../../common'; const CUSTOM = "custom"; class Legend extends ChartElement { constructor(options, chartService = {}) { super(options); this.chartService = chartService; if (!inArray(this.options.position, [ TOP, RIGHT, BOTTOM, LEFT, CUSTOM ])) { this.options.position = RIGHT; } this.createContainers(); this.createLegendTitle(options.title); this.createItems(); } createContainers() { const options = this.options; const { position, align: userAlign } = options; let align = position; let vAlign = CENTER; if (position === CUSTOM) { align = LEFT; } else if (inArray(position, [ TOP, BOTTOM ])) { if (userAlign === START) { align = LEFT; } else if (userAlign === END) { align = RIGHT; } else { align = CENTER; } vAlign = position; } else if (userAlign) { if (userAlign === START) { vAlign = TOP; } else if (userAlign === END) { vAlign = BOTTOM; } } this.container = new BoxElement({ margin: options.margin, padding: options.padding, background: options.background, border: options.border, vAlign: vAlign, align: align, zIndex: options.zIndex, shrinkToFit: true }); if (this.hasTitle()) { this.itemsContainer = new BoxElement({ vAlign: vAlign, align: align, zIndex: options.zIndex, shrinkToFit: true }); } else { this.itemsContainer = this.container; } this.append(this.container); } createItems() { const chartService = this.getService(); const options = this.options; const vertical = this.isVertical(); const innerElement = new LegendLayout({ vertical: vertical, spacing: options.spacing, rtl: chartService.rtl }, chartService); let data = options.data; if (options.reverse) { data = data.slice(0).reverse(); } const count = data.length; for (let i = 0; i < count; i++) { let dataItem = data[i]; const { markers = {}, dashType, legendItem, opacity } = dataItem.series || {}; const markersOptions = deepExtend({ visible: markers.visible !== false, type: CIRCLE }, markers); delete markersOptions.size; const itemOptions = deepExtend({}, { markers: markersOptions, labels: options.labels, rtl: chartService.rtl, line: Object.assign({}, {dashType: dashType}, options.line), area: Object.assign({}, {opacity: opacity}, options.area), opacity: opacity, accessibility: options.accessibility, focusHighlight: options.focusHighlight }, options.item, legendItem, dataItem, { markers: options.markers } ); innerElement.append(new LegendItem(itemOptions)); } innerElement.render(); this.itemsContainer.append(innerElement); } isVertical() { const { orientation, position } = this.options; const vertical = (position === CUSTOM && orientation !== HORIZONTAL) || (defined(orientation) ? orientation !== HORIZONTAL : inArray(position, [ LEFT, RIGHT ])); return vertical; } hasItems() { return this.container.children[0].children.length > 0; } getItems() { return this.itemsContainer.children[0].children; } reflow(targetBox) { const options = this.options; const legendBox = targetBox.clone(); if (!this.hasItems()) { this.box = legendBox; return; } if (options.position === CUSTOM) { this.containerCustomReflow(legendBox); this.box = legendBox; } else { this.containerReflow(legendBox); } if (this.hasTitle()) { this.title.reflow(new Box(this.container.box.x1, this.title.box.y1, this.container.box.x2, this.title.box.y2)); } } containerReflow(targetBox) { const { options, container } = this; const { position, width, height } = options; const pos = position === TOP || position === BOTTOM ? X : Y; const vertical = this.isVertical(); const alignTarget = targetBox.clone(); let containerBox = targetBox.clone(); if (position === LEFT || position === RIGHT) { containerBox.y1 = alignTarget.y1 = 0; } if (vertical && height) { containerBox.y2 = containerBox.y1 + height; containerBox.align(alignTarget, Y, container.options.vAlign); } else if (!vertical && width) { containerBox.x2 = containerBox.x1 + width; containerBox.align(alignTarget, X, container.options.align); } container.reflow(containerBox); containerBox = container.box; const box = containerBox.clone(); if (options.offsetX || options.offsetY) { containerBox.translate(options.offsetX, options.offsetY); container.reflow(containerBox); } box[pos + 1] = targetBox[pos + 1]; box[pos + 2] = targetBox[pos + 2]; this.box = box; } containerCustomReflow(targetBox) { const { options, container } = this; const { offsetX, offsetY, width, height } = options; const vertical = this.isVertical(); let containerBox = targetBox.clone(); if (vertical && height) { containerBox.y2 = containerBox.y1 + height; } else if (!vertical && width) { containerBox.x2 = containerBox.x1 + width; } container.reflow(containerBox); containerBox = container.box; container.reflow(new Box( offsetX, offsetY, offsetX + containerBox.width(), offsetY + containerBox.height() )); } renderVisual() { if (this.hasItems()) { super.renderVisual(); } } createLegendTitle(title) { let titleOptions = deepExtend({}, { color: BLACK, position: TOP, align: CENTER }, title); let text = titleOptions.text; if (!title || title.visible === false || !title.text) { return; } if (defined(titleOptions) && titleOptions.visible) { const labelTemplate = getTemplate(titleOptions); if (labelTemplate) { text = labelTemplate({ text: text }); } else if (titleOptions.format) { text = this.chartService.format.auto(titleOptions.format, text); } } this.title = new TextBox(text, titleOptions); this.createTitleLayout(); this.appendTitleLayoutContent(); } createTitleLayout() { this.layout = new FloatElement({ vertical: true, wrap: false }); this.container.append(this.layout); } hasTitle() { return Boolean(this.options.title && this.options.title.visible !== false && this.options.title.text); } appendTitleLayoutContent() { const options = this.options; if (options.title.position === BOTTOM) { this.layout.append(this.itemsContainer); this.layout.append(this.title); } else { this.layout.append(this.title); this.layout.append(this.itemsContainer); } } } setDefaultOptions(Legend, { position: RIGHT, data: [], offsetX: 0, offsetY: 0, margin: getSpacing(2), padding: getSpacing(5), border: { color: BLACK, width: 0 }, item: { cursor: POINTER, spacing: 6 }, spacing: 6, background: "", zIndex: 1, markers: {}, line: { width: 20, height: 2, cursor: POINTER, opacity: 1 }, area: { type: SQUARE, align: RIGHT, width: 15, height: 15, } }); export default Legend;