UNPKG

chrt-annotation

Version:

Annotation component for Chrt

141 lines (119 loc) 3.59 kB
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); }