chrt-annotation
Version:
Annotation component for Chrt
141 lines (119 loc) • 3.59 kB
JavaScript
import chrtObject, { utils, cssDisplay } from 'chrt-object';
const { isNull, create } = utils;
import {
color,
position,
top,
left,
align,
valign,
offset,
} from './lib';
function chrtAnnotation(text, options = {x: 'x', y: 'y'}) {
chrtObject.call(this);
this.type = 'annnotation';
this.div = null;
this.attr('text', text ?? '')
this.attr('color', null);
this.attr('position', {});
this.attr('alignment', {
horizontal: 'middle',
vertical: 'middle',
});
this.attr('offset', [0, 0]);
this._classNames = ['chrt-annotation'];
// console.log('chrtAnnotation', options)
this.text = (text) => {
return this.attr('text', text)
}
this.draw = () => {
// annotations can only added to the main chrtCore component
if (this.parentNode.type !== 'chrt') {
return this;
}
// TODO: probably should be the last one
const scales = {
x: this.parentNode.scales.x[options.x] || Object.values(this.parentNode.scales.x)[0],
y: this.parentNode.scales.y[options.y] || Object.values(this.parentNode.scales.y)[0],
}
// console.log('options', options)
// console.log('scales', scales)
if (!this.div) {
this.div = create('div');
this.parentNode.root.appendChild(this.div);
if(this.parentNode.root?.style?.position === '') {
this.parentNode.root.style.position = 'relative';
}
this.div.style.position = 'absolute';
this.g = this.div;
}
console.log('display', this.attr('display')())
cssDisplay.call(this, this.attr('display')());
this.div.setAttribute('id', this.id())
this.div.classList.remove(...this.div.classList)
this.div.classList.add(...this._classNames);
if(scales && scales['x']) {
const _position = this.attr('position')();
const x = isNull(_position.x) ? 0 : scales.x(_position.x);
// if y is not defined by the user, it should be calculated based on the closest Y value based on X
const y = isNull(_position.y) ? 0 : scales.y(_position.y);
const _offsets = this.attr('offset')(); // offset.call(this)();
this.div.style.left = `${x + _offsets[0]}px`;
this.div.style.top = `${y + _offsets[1]}px`;
}
const transform = {
x: 0,
y: 0,
}
const _alignment = this.attr('alignment')();
switch(_alignment.horizontal) {
case 'left':
transform.x = '0';
break;
case 'right':
transform.x = '-100%';
break;
case 'center':
case 'middle':
default:
transform.x = '-50%';
}
switch(_alignment.vertical) {
case 'bottom':
transform.y = '0';
break;
case 'top':
transform.y = '-100%';
break;
case 'center':
case 'middle':
default:
transform.y = '-50%';
}
this.div.style.transform = `translate(${transform.x},${transform.y})`;
let label = this.div.querySelector('span');
if (!label) {
label = create('span');
label.style.color = this.color()() ?? 'inherit';
this.div.appendChild(label);
}
label.innerHTML = this.attr('text')();
return this;
}
}
chrtAnnotation.prototype = Object.create(chrtObject.prototype);
chrtAnnotation.prototype.constructor = chrtAnnotation;
chrtAnnotation.parent = chrtObject.prototype;
chrtAnnotation.prototype = Object.assign(chrtAnnotation.prototype, {
color,
position,
top,
left,
align,
valign,
offset,
});
// export default chrtAnnotation;
export default function(text, options) {
return new chrtAnnotation(text, options);
}