src/axis/axis-layer.js
import ns from '../core/namespace';
import Layer from '../core/layer';
/**
* Simplified Layer for Axis. The main difference with a regular layer is that
* an axis layer use the `Timeline~timeContext` attributes to render it's layout
* and stay synchronized with the tracks visible area. All getters and setters
* to the `TimelineTimeContext` attributes are bypassed.
*
* It also handle it's own data and its updates. The `_generateData` method is
* responsible to create some usefull data to visualize
*
* [example usage of the layer-axis](./examples/layer-axis.html)
*/
export default class AxisLayer extends Layer {
/**
* @param {Function} generator - A function to create data according to
* the `Timeline~timeContext`.
* @param {Object} options - Layer options, cf. Layer for available options.
*/
constructor(generator, options) {
super('entity', [], options);
this._generator = generator;
/** @type {Element} */
this.$el = null;
/** @type {Element} */
this.$offset = null;
/** @type {Element} */
this.$background = null;
}
/** @private */
set stretchRatio(value) { return; }
/** @private */
set offset(value) { return; }
/** @private */
set start(value) { return; }
/** @private */
set duration(value) { return; }
/** @private */
get stretchRatio() { return; }
/** @private */
get offset() { return; }
/** @private */
get start() { return; }
/** @private */
get duration() { return; }
/**
* The generator that creates the data to be rendered to display the axis.
*
* @type {Function}
*/
set generator(func) {
this._generator = func;
}
/**
* The generator that creates the data to be rendered to display the axis.
*
* @type {Function}
*/
get generator() {
return this._generator;
}
/**
* This method is the main difference with a classical layer. An `AxisLayer`
* instance generates and maintains it's own data.
*/
_generateData() {
const data = this._generator(this.timeContext);
// prepend first arguments of splice for an apply
data.unshift(0, this.data[0].length);
// make sure to keep the same reference
Array.prototype.splice.apply(this.data[0], data);
}
/**
* Updates the rendering context for the shapes.
*/
_updateRenderingContext() {
this._renderingContext.timeToPixel = this.timeContext.timeToPixel;
this._renderingContext.valueToPixel = this._valueToPixel;
this._renderingContext.height = this.params.height;
this._renderingContext.width = this.timeContext.timeToPixel(this.timeContext.duration);
// for foreign object issue in chrome
this._renderingContext.offsetX = this.timeContext.timeToPixel(this.timeContext.offset);
// expose some timeline attributes - allow to improve perf in some cases - cf. Waveform
this._renderingContext.trackOffsetX = this.timeContext.timeToPixel(this.timeContext.offset);
this._renderingContext.visibleWidth = this.timeContext.visibleWidth;
}
/**
* Generates the data and update the layer.
*/
update() {
this._generateData();
super.update();
}
/**
* Render the DOM in memory on layer creation to be able to use it before
* the layer is actually inserted in the DOM
*/
_renderContainer() {
// wrapper group for `start, top and context flip matrix
this.$el = document.createElementNS(ns, 'g');
if (this.params.className !== null) {
this.$el.classList.add('layer', this.params.className);
}
// group to apply offset
this.$offset = document.createElementNS(ns, 'g');
this.$offset.classList.add('offset', 'items');
// layer background
this.$background = document.createElementNS(ns, 'rect');
this.$background.setAttributeNS(null, 'height', '100%');
this.$background.classList.add('background');
this.$background.style.fillOpacity = 0;
this.$background.style.pointerEvents = 'none';
// create the DOM tree
this.$el.appendChild(this.$offset);
this.$offset.appendChild(this.$background);
}
/**
* Updates the layout of the layer.
*/
updateContainer() {
this._updateRenderingContext();
const top = this.params.top;
const height = this.params.height;
// matrix to invert the coordinate system
const translateMatrix = `matrix(1, 0, 0, -1, 0, ${top + height})`;
this.$el.setAttributeNS(null, 'transform', translateMatrix);
this.$background.setAttributeNS(null, 'width', height);
}
}