"use strict";
var _ = require("underscore");
var Type = require("../core/Type");
var CrosshairZone = require("../crosshair/CrosshairZone");
const _default_config = {
lineColor: "#000000",
labelHeight: 16,
showTimeLabel: false,
labelFont: "7pt normal normal arial;",
labelBgColor: "#000000",
labelColor: "#FFFFFF",
timeLabelWidth: 70,
};
/**
* Represents a crosshair (pair of crosshairs) overlaid on chart.
*
* @extends core.Type
* @memberof crosshair
*/
class Crosshair extends Type {
/**
* Instantiate Crosshair
* @constructor
* @param {core:Chart} parent_chart
* @param {Object} config
*/
constructor(parent_chart, config) {
config = _.extend({}, _default_config, config);
super(config);
this._crosshair_zones = {};
this._parent_chart = parent_chart;
this.width = this.getParentChart().getWidth();
this.lineWidth = this.getParentChart().getDrawingWidth();
this.valueLabelWidth = this.width - this.lineWidth;
this._render();
this._listenForDOMEvents();
}
/**
* Destroy underlying HTMLElements
*/
destroy() {
for(var i in this._crosshair_zones)
{
if(this._crosshair_zones.hasOwnProperty(i))
{
var canvas = this._crosshair_zones[i].getEl();
if(canvas && canvas.parentNode)
{
canvas.parentNode.removeChild(canvas);
}
}
}
}
/**
* Get parent chart
* @returns {core.Chart} chart
*/
getParentChart() {
return this._parent_chart;
}
/**
* Destroy and re-render.
* @private
*/
_render() {
this.destroy();
var comps = this.getParentChart().getComponents();
for(var i = 0; i < comps.length; i++)
{
var ch_zone = new CrosshairZone(this, comps[i]);
this._crosshair_zones[""+i+""] = ch_zone;
ch_zone.render(i);
}
}
/**
* Listen for mousemove and mouseout events.
* @private
*/
_listenForDOMEvents() {
this.getParentChart().getEl().addEventListener("mousemove", this._handleMousemove.bind(this));
this.getParentChart().getEl().addEventListener("mouseout", this._handleMouseout.bind(this));
}
/**
* Handle mousemove event
* @param {external:Event} ev
* @private
*/
_handleMousemove(ev) {
var zone_index = ev.target.getAttribute("ch-zone-index");
var ch_zone = this._crosshair_zones[zone_index];
this._draw(ev.offsetX, ev.offsetY, ch_zone, this._crosshair_zones);
}
/**
* Handle mouseout event
* @param {external:Event} ev
* @private
*/
_handleMouseout(ev) {
this.clear();
}
/**
* Refresh dimensions, for example after browser window is resized.
*/
refresh() {
this.width = this.getParentChart().getWidth();
this.lineWidth = this.getParentChart().getDrawingWidth();
this.valueLabelWidth = this.width - this.lineWidth;
this._render();
}
/**
* Handle mouseout event
* @param {number} x
* @param {number} y
* @param {crosshair.CrosshairZone} ch_zone
* @param {Object} ch_zones {crosshair.CrosshairZone} map
* @private
*/
_draw(x, y, ch_zone, ch_zones) {
if(ch_zone)
{
for(var i in ch_zones)
{
if(ch_zones.hasOwnProperty(i))
{
var comp = ch_zones[i].getComponent();
var canvas = ch_zones[i].getEl();
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
// Vertical crosshair
context.beginPath();
context.rect(x, 0, 1, canvas.height);
context.fillStyle = this.lineColor;
context.fill();
if(comp.crosshair && comp.crosshair.time && comp.crosshair.time.label)
{
// label
context.beginPath();
context.rect(x, 0, this.timeLabelWidth, this.labelHeight);
context.fillStyle = this.labelBgColor;
context.fill();
var time_grid = this.getParentChart().getTimeGrid();
var time_text = time_grid.pixelToTimeString(x);
context.font = this.labelFont;
context.textAlign = "left";
context.textBaseline = "middle";
context.fillStyle = this.labelColor;
context.fillText(time_text, x + 4, this.labelHeight * 0.5);
}
// Horizontal crosshair
if(ch_zones[i] === ch_zone && (comp.crosshair === undefined || comp.crosshair.value))
{
// line
context.beginPath();
context.rect(0, y, this.lineWidth, 1);
context.fillStyle = this.lineColor;
context.fill();
// label
context.beginPath();
context.rect(this.lineWidth, y - (this.labelHeight * 0.5), this.valueLabelWidth, this.labelHeight);
context.fillStyle = this.labelBgColor;
context.fill();
var value_text = "" + comp.pixelToValue(y).toFixed(4);
context.font = this.labelFont;
context.textAlign = "left";
context.textBaseline = "middle";
context.fillStyle = this.labelColor;
context.fillText(value_text, this.lineWidth + 4, y);
}
}
}
}
}
/**
* Clear all crosshair canvases.
*/
clear() {
for(var i in this._crosshair_zones)
{
if(this._crosshair_zones.hasOwnProperty(i))
{
var canvas = this._crosshair_zones[i].getEl();
if(canvas)
{
canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
}
}
}
}
}
module.exports = Crosshair;