@progress/kendo-charts
Version:
Kendo UI platform-independent Charts library
332 lines (264 loc) • 8.56 kB
JavaScript
import { drawing as draw } from '@progress/kendo-drawing';
import { WHITE } from '../common/constants';
import { deepExtend, valueOrDefault, autoTextColor } from '../common';
class ChartElement {
constructor(options) {
this.children = [];
this.initOptions(options);
}
initOptions(options) {
this.options = deepExtend({}, this.options, this.initUserOptions(options));
}
initUserOptions(options) {
return options;
}
reflow(targetBox) {
const children = this.children;
let box;
for (let i = 0; i < children.length; i++) {
let currentChild = children[i];
currentChild.reflow(targetBox);
box = box ? box.wrap(currentChild.box) : currentChild.box.clone();
}
this.box = box || targetBox;
}
destroy() {
const children = this.children;
if (this.animation) {
this.animation.destroy();
}
for (let i = 0; i < children.length; i++) {
children[i].destroy();
}
}
getRoot() {
const parent = this.parent;
return parent ? parent.getRoot() : null;
}
getSender() {
const service = this.getService();
if (service) {
return service.sender;
}
}
getService() {
let element = this;
while (element) {
if (element.chartService) {
return element.chartService;
}
element = element.parent;
}
}
translateChildren(dx, dy) {
const children = this.children;
const childrenCount = children.length;
for (let i = 0; i < childrenCount; i++) {
children[i].box.translate(dx, dy);
}
}
append() {
for (let i = 0; i < arguments.length; i++) {
let item = arguments[i];
this.children.push(item);
item.parent = this;
}
}
renderVisual() {
if (this.options.visible === false) {
return;
}
this.createVisual();
this.addVisual();
this.renderChildren();
this.createAnimation();
this.renderComplete();
}
addVisual() {
if (this.visual) {
this.visual.chartElement = this;
if (this.parent) {
this.parent.appendVisual(this.visual);
}
}
}
renderChildren() {
const children = this.children;
const length = children.length;
for (let i = 0; i < length; i++) {
children[i].renderVisual();
}
}
createVisual() {
this.visual = new draw.Group({
zIndex: this.options.zIndex,
visible: valueOrDefault(this.options.visible, true)
});
}
createAnimation() {
if (this.visual && this.options.animation) {
this.animation = draw.Animation.create(
this.visual, this.options.animation
);
}
}
appendVisual(childVisual) {
if (!childVisual.chartElement) {
childVisual.chartElement = this;
}
if (childVisual.options.noclip) {
this.clipRoot().visual.append(childVisual);
} else if (childVisual.options.zIndex !== undefined) {
this.stackRoot().stackVisual(childVisual);
} else if (this.isStackRoot) {
this.stackVisual(childVisual);
} else if (this.visual) {
this.visual.append(childVisual);
} else {
// Allow chart elements without visuals to
// pass through child visuals
this.parent.appendVisual(childVisual);
}
}
clipRoot() {
if (this.parent) {
return this.parent.clipRoot();
}
return this;
}
stackRoot() {
if (this.parent) {
return this.parent.stackRoot();
}
return this;
}
stackVisual(childVisual) {
const zIndex = childVisual.options.zIndex || 0;
const visuals = this.visual.children;
const length = visuals.length;
let pos;
for (pos = 0; pos < length; pos++) {
let sibling = visuals[pos];
let here = valueOrDefault(sibling.options.zIndex, 0);
if (here > zIndex) {
break;
}
}
this.visual.insert(pos, childVisual);
}
traverse(callback) {
const children = this.children;
const length = children.length;
for (let i = 0; i < length; i++) {
let child = children[i];
callback(child);
if (child.traverse) {
child.traverse(callback);
}
}
}
closest(match) {
let element = this;
let matched = false;
while (element && !matched) {
matched = match(element);
if (!matched) {
element = element.parent;
}
}
if (matched) {
return element;
}
}
renderComplete() {}
hasHighlight() {
const options = (this.options || {}).highlight;
return !(!this.createHighlight || (options && options.visible === false) || this.visible === false);
}
toggleHighlight(show, opacity) {
const options = (this.options || {}).highlight || {};
const customVisual = options.visual;
let highlight = this._highlight;
if (!highlight) {
const highlightOptions = {
fill: {
color: WHITE,
opacity: opacity || 0.2
},
stroke: {
color: WHITE,
width: 1,
opacity: opacity || 0.2
}
};
if (customVisual) {
highlight = this._highlight = customVisual(
Object.assign(this.highlightVisualArgs(), {
createVisual: () => this.createHighlight(highlightOptions),
sender: this.getSender(),
series: this.series,
dataItem: this.dataItem,
category: this.category,
value: this.value,
percentage: this.percentage,
runningTotal: this.runningTotal,
total: this.total
})
);
if (!highlight) {
return;
}
} else {
highlight = this._highlight = this.createHighlight(highlightOptions);
}
if (highlight.options.zIndex === undefined) {
highlight.options.zIndex = valueOrDefault(options.zIndex, this.options.zIndex);
}
this.appendVisual(highlight);
}
highlight.visible(show);
}
toggleFocusHighlight(show) {
const options = (this.options || {}).focusHighlight || {};
let focusHighlight = this._focusHighlight;
if (!show && !focusHighlight) {
return;
}
if (!focusHighlight) {
const rootBackground = this.getRoot().options.background;
const highlightColor = autoTextColor(rootBackground);
const focusHighlightOptions = {
fill: {
opacity: options.opacity,
color: options.color
},
stroke: Object.assign({}, {color: highlightColor}, options.border),
zIndex: options.zIndex
};
focusHighlight = this._focusHighlight = this.createFocusHighlight(focusHighlightOptions);
this.appendVisual(focusHighlight);
}
focusHighlight.visible(show);
}
createGradientOverlay(element, options, gradientOptions) {
const overlay = new draw.Path(Object.assign({
stroke: {
color: "none"
},
fill: this.createGradient(gradientOptions),
closed: element.options.closed
}, options));
overlay.segments.elements(element.segments.elements());
return overlay;
}
createGradient(options) {
if (this.parent) {
return this.parent.createGradient(options);
}
}
supportsPointInactiveOpacity() {
return true;
}
}
ChartElement.prototype.options = { };
export default ChartElement;