UNPKG

@progress/kendo-charts

Version:

Kendo UI platform-independent Charts library

326 lines (268 loc) 9.96 kB
import { drawing as draw } from '@progress/kendo-drawing'; import { BoxElement, FloatElement, TextBox } from '../../core'; import { AREA, LEGEND_ITEM_ARIA_ROLE_DESCRIPTION, LEGEND_ITEM_CLASSNAME, LEGEND_ITEM_CLICK, LEGEND_ITEM_HOVER, LEGEND_ITEM_LEAVE, LEGEND_ITEM_ROLE, LINE } from '../constants'; import { BOTTOM, CENTER, WHITE } from '../../common/constants'; import { deepExtend, eventElement, setDefaultOptions } from '../../common'; import addAccessibilityAttributesToVisual from '../../core/utils/add-accessibility-attributes-to-visual'; import guid from '../../core/utils/guid'; import LegendItemMarker from './legend-item-marker'; import MarkerLineArea from './legend-item-line-area'; import LegendItemLine from './legend-item-line'; import LegendItemSquare from './legend-item-square'; class LegendItem extends BoxElement { constructor(options) { super(options); this.createContainer(); if (!options.rtl) { this.createMarker(); this.createLabel(); } else { this.createLabel(); this.createMarker(); } this._id = guid(); this.options.accessibility.ariaChecked = options.active; } createContainer() { this.container = new FloatElement({ vertical: false, wrap: false, align: CENTER, spacing: this.options.spacing }); this.append(this.container); } createMarker() { this.markerWrap = new BoxElement({ vertical: false, shrinkToFit: true, wrap: false, margin: 1, width: 22, height: 22 }); this.container.append(this.markerWrap); this.createMarkerArea(); if (this.options.markers.visible) { this._marker = this._createMarker(); this.markerWrap.append(this._marker); } } createMarkerArea() { const options = this.options; const { markerColor, line = {} } = options; const lineOptions = { border: { color: line.color || markerColor, opacity: line.opacity, dashType: line.dashType } }; return this._createLine(lineOptions) || this._createMarkerLine(lineOptions, line) || this._createSquare(); } markerOptions() { const options = this.options; const { markers = {}, markerColor } = options; const { border = {} } = markers; markers.zIndex = undefined; return deepExtend({}, markers, { border: { color: border.color || markerColor }, highlight: options.highlight.markers }); } _highlightOptions() { const options = this.options; return deepExtend( { markers: { type: options.markers.type } }, options.highlight ); } _createLine(lineOptions) { const options = this.options; if (options.type === LINE && !options.markers.visible) { this._line = new LegendItemLine(deepExtend({}, { background: options.markerColor, highlight: this._highlightOptions(), }, lineOptions, options.line)); this.markerWrap.append(this._line); } return this._line; } _createMarkerLine(lineOptions, line) { const options = this.options; if (options.type === LINE) { this._markerLineArea = new MarkerLineArea(deepExtend({}, { border: { width: line.height } }, lineOptions)); this.markerWrap.append(this._markerLineArea); } return this._markerLineArea; } _reduceSize(object, prop, factor = 0.6) { if (typeof object[prop] === 'number') { object[prop] = object[prop] * factor; } } _createSquare() { const options = this.options; if (options.type === AREA) { let pattern = options.pattern || (options.series || {}).pattern; if (pattern) { if (typeof pattern === 'function') { pattern = pattern(options.series); } pattern = Object.assign({}, pattern); this._reduceSize(pattern, 'gap'); this._reduceSize(pattern, 'width'); this._reduceSize(pattern, 'radius'); } this._square = new LegendItemSquare(Object.assign({}, {border: options.border, vAlign: options.markers.visible ? BOTTOM : CENTER, highlight: this._highlightOptions()}, options.area, {pattern: pattern, background: options.area.background || options.markerColor})); this.markerWrap.append(this._square); } return this._square; } _createMarker() { return new LegendItemMarker(this.markerOptions()); } _highlightMarkers() { if (this.options.active) { this._toggleHighlight(true); } } _restoreMarkers() { this._toggleHighlight(false); } _toggleHighlight(show) { if (!this.options.highlight.visible) { return; } const element = this._marker || this._square || this._line; if (element && element === this._line) { this._line.visual.visible(!show); } if (element) { let highlight = element.highlight; if (!highlight) { highlight = element.createHighlight(); highlight.forEach(h => h && this.markerWrap.appendVisual(h)); } highlight.forEach(h => h && h.visible(show)); } } createLabel() { const options = this.options; const labelOptions = deepExtend({}, options.labels); this.container.append(new TextBox(options.text, labelOptions)); } getAriaLabelText() { return this.options.text; } focusVisual() { this.visual.options.set("id", this._id); this.toggleFocusHighlight(true); this._highlightMarkers(); } clearFocusFromVisual() { this.visual.options.set("id", ""); this.toggleFocusHighlight(false); this._restoreMarkers(); } renderComplete() { super.renderComplete(); const cursor = this.options.cursor || {}; const eventSink = this._itemOverlay = draw.Path.fromRect(this.container.box.toRect(), { fill: { color: WHITE, opacity: 0 }, stroke: null, cursor: cursor.style || cursor }); this.appendVisual(eventSink); } click(widget, e) { const args = this.eventArgs(e); if (!widget.trigger(LEGEND_ITEM_CLICK, args) && e && e.type === 'contextmenu') { e.preventDefault(); } } over(widget, e) { const args = this.eventArgs(e); if (!widget.trigger(LEGEND_ITEM_HOVER, args)) { widget._legendItemHover(args.seriesIndex, args.pointIndex); this._highlightMarkers(); } // Don't trigger point hover for legend items return true; } out(widget, e) { widget._unsetActivePoint(); this._restoreMarkers(); widget.trigger(LEGEND_ITEM_LEAVE, this.eventArgs(e)); } eventArgs(e) { const options = this.options; return { element: eventElement(e), text: options.text, series: options.series, seriesIndex: options.series.index, pointIndex: options.pointIndex }; } createVisual() { super.createVisual(); const options = this.options; if (this.options.visible) { const accessibilityOptions = deepExtend({ ariaLabel: options.accessibility.ariaLabel !== undefined ? options.accessibility.ariaLabel : options.text }, options.accessibility); addAccessibilityAttributesToVisual(this.visual, accessibilityOptions); } } renderVisual() { const options = this.options; const customVisual = options.visual; if (customVisual) { this.visual = customVisual({ active: options.active, series: options.series, sender: this.getSender(), pointIndex: options.pointIndex, options: { type: options.type, // Passing the markerColor as a background option for backwards compatibility. // Example in jq docs - https://docs.telerik.com/kendo-ui/api/javascript/dataviz/ui/chart/configuration/legend.item#legenditemvisual markers: deepExtend({ background: this.options.markerColor }, this.markerOptions()), labels: options.labels }, createVisual: () => { this.createVisual(); this.renderChildren(); this.renderComplete(); const defaultVisual = this.visual; delete this.visual; return defaultVisual; } }); this._marker = this._markerLineArea = this._square = this._line = null; this.addVisual(); } else { super.renderVisual(); } } createFocusHighlight(style) { const borderWidth = style.stroke.width; return draw.Path.fromRect(this.container.box.pad(borderWidth / 2).toRect(), style); } } setDefaultOptions(LegendItem, { accessibility: { role: LEGEND_ITEM_ROLE, className: LEGEND_ITEM_CLASSNAME, ariaRoleDescription: LEGEND_ITEM_ARIA_ROLE_DESCRIPTION }, markers: {}, highlight: { visible: true, markers: {} } }); export default LegendItem;