File: ia\charts\layers\ComparisonTimeBarLayer.js
/**
* The base class for comparison time bar series layers.
*
* @author J Clare
* @class ia.ComparisonTimeBarLayer
* @extends ia.TimeLayer
* @constructor
*/
ia.ComparisonTimeBarLayer = function()
{
ia.ComparisonTimeBarLayer.baseConstructor.call(this);
this.isComparison = true;
this.displayAll = false;
this.selectedDate = "";
};
ia.extend(ia.TimeBarLayer, ia.ComparisonTimeBarLayer);
/**
* The selected date.
*
* @property selectedDate
* @type String
* @default ia.Shape.SQUARE
*/
ia.ComparisonTimeBarLayer.prototype.selectedDate;
/**
* Specifies a thematic for the layer.
*
* @property thematic
* @type ia.Thematic
*/
ia.ComparisonTimeBarLayer.prototype.thematic;
/**
* Should all data be displayed.
*
* @property displayAll
* @type Boolean
* @default false
*/
ia.ComparisonTimeBarLayer.prototype.displayAll;
/**
* Shortcut to avoid verbose code - referenced in ia.TimeLayer.
*
* @property isComparison
* @type Boolean
* @default true
*/
ia.ComparisonTimeBarLayer.prototype.isComparison;
/**
* Renders the data.
*
* @method render
*/
ia.ComparisonTimeBarLayer.prototype.render = function()
{
// Clear the canvas.
this.clear();
// Reset the context styles in case the layer styles has changed.
for (var p in this.style)
{
this.context[p] = this.style[p];
this.highlightContext[p] = this.style[p];
this.selectionContext[p] = this.style[p];
}
this.highlightContext.strokeStyle = ia.Color.toRGBA(this.highlightColor, 0.8);
this.highlightContext.fillStyle = ia.Color.toRGBA(this.highlightColor, 0.1);
this.highlightContext.lineWidth = parseFloat(this.style.lineWidth) + 1.5;
this.selectionContext.lineWidth = parseFloat(this.style.lineWidth) + 1.5;
this.context.lineWidth = parseFloat(this.style.lineWidth) + 1.5;
// Render the items.
var nItems = this.itemArray.length;
for (var i = 0; i < nItems; i++)
{
var chartItem = this.itemArray[i];
var nChildItems = chartItem.childItems.length;
for (var j = 0; j < nChildItems; j++)
{
var childItem = chartItem.childItems[j];
if (childItem.value !== undefined) this._setItemShape(childItem, j, nChildItems);
}
if (this.displayAll) this._renderItem(chartItem);
}
this.renderSelection();
};
/**
* Sets an items dimensions.
*
* @method _setItemShape
* @param {Object} item The item.
* @param {Number} index The index of the item in the item array.
* @param {Number} nItems The number of items.
* @private
*/
ia.ComparisonTimeBarLayer.prototype._setItemShape = function(item, index, nItems)
{
var h = 4;
// Reset the pixel drawing area for the point.
if (ia.IS_TOUCH_DEVICE) // Larger hit area for touch devices.
{
h = 8;
}
if (this.map.orientation === "vertical")
{
// Calculate the bounding box of the chart item.
var barY, barHeight;
if (this.map.getBBox().getYMin() < 0) // Chart with negative values.
{
if (item.value < 0) barY = this.map.getPixelY(0);
else barY = this.map.getPixelY(item.value);
barHeight = this.map.getPixelHeight(Math.abs(item.value));
}
else // Chart min is 0 or greater.
{
var barY = this.map.getPixelY(item.value);
barHeight = this.map.getPixelHeight(Math.abs(item.value) - this.map.getBBox().getYMin());
}
// Adjust for when bar value is outside fixed min/max values.
if (item.value < this.map.getBBox().getYMin())
{
barY = this.map.canvasY + this.map.canvasHeight;
barHeight = barHeight - this.map.getPixelHeight(Math.abs(item.value) - this.map.getBBox().getYMin());
}
if (item.value > this.map.getBBox().getYMax())
{
barY = this.map.canvasY;
barHeight = barHeight - this.map.getPixelHeight(Math.abs(item.value) - this.map.getBBox().getYMax());
}
var barWidth = this.map.canvasWidth / nItems;
var x = this.map.canvasX + (barWidth * index);
// The pixel drawing rectangle for the bar.
item.rect.y = barY
item.rect.height = barHeight;
item.rect.width = barWidth;
item.rect.x = x;
// The pixel hit area for the bar.
item.hitArea.x = item.rect.x;
if (item.value > 0)
item.hitArea.y = barY - h;
else
item.hitArea.y = (barY + barHeight) - h;
item.hitArea.width = item.rect.width;
item.hitArea.height = h * 2;
}
else
{
// Calculate the bounding box of the chart item.
var barX, barWidth;
if (this.map.getBBox().getXMin() < 0) // Chart with negative values.
{
if (item.value < 0) barX = this.map.getPixelX(item.value);
else barX = this.map.getPixelX(0);
barWidth = this.map.getPixelWidth(Math.abs(item.value));
}
else // Chart min is 0 or greater.
{
var barX = this.map.getPixelX(this.map.getBBox().getXMin());
barWidth = this.map.getPixelWidth(Math.abs(item.value) - this.map.getBBox().getXMin());
}
// Adjust for when bar value is outside fixed min/max values.
if (item.value < this.map.getBBox().getXMin())
{
barX = this.map.canvasX;
barWidth = barWidth - this.map.getPixelWidth(Math.abs(item.value) - Math.abs(this.map.getBBox().getXMin()));
}
if (item.value > this.map.getBBox().getXMax())
{
barWidth = barWidth - this.map.getPixelWidth(Math.abs(item.value) - Math.abs(this.map.getBBox().getXMax()));
}
var barHeight = this.map.canvasHeight / nItems;
var y = this.map.canvasY + (barHeight * index);
// The pixel drawing rectangle for the bar.
item.rect.x = barX;
item.rect.width = barWidth;
item.rect.height = barHeight;
item.rect.y = y;
// The pixel hit area for the bar.
if (item.value < 0)
item.hitArea.x = barX - h;
else
item.hitArea.x = (barX + barWidth) - h;
item.hitArea.y = item.rect.y;
item.hitArea.width = h * 2;
item.hitArea.height = item.rect.height;
}
};
/**
* Clears all selections.
*
* @method clearSelection
*/
ia.ComparisonTimeBarLayer.prototype.clearSelection = function() {};
/**
* Renders the item to the given context.
*
* @method _renderItem
* @param {Object} item The item.
* @private
*/
ia.ComparisonTimeBarLayer.prototype._renderItem = function(item)
{
this.context.strokeStyle = item.color;
this._drawItem(item, this.context);
};
/**
* Selects the item.
*
* @method selectItem
* @param {Object} item The item.
*/
ia.ComparisonTimeBarLayer.prototype.selectItem = function(item)
{
this.selectionContext.strokeStyle = item.color;
this._drawItem(item, this.selectionContext);
};
/**
* Highlights the item.
*
* @method highlightItem
* @param {Object} item The item.
*/
ia.ComparisonTimeBarLayer.prototype.highlightItem = function(item)
{
this.highlightContext.strokeStyle = ia.Color.toRGBA(item.color, 0.8);
this.highlightContext.fillStyle = ia.Color.toRGBA(item.color, 0.1);
var n = item.childItems.length;
for (var i = 0; i < n; i++)
{
var childItem = item.childItems[i];
if (childItem.value !== undefined)
{
var drawStroke = false
if (this.map.orientation === "vertical")
{
var x1 = this.map.canvasX + ((this.map.canvasWidth / n) * i);
var x2 = this.map.canvasX + ((this.map.canvasWidth / n) * (i+1));
var y1 = childItem.rect.y;
if (childItem.value < 0) y1 = y1 + childItem.rect.height;
var y2 = y1;
if (childItem.value >= this.map.getBBox().getYMin()
&& childItem.value <= this.map.getBBox().getYMax())
{
drawStroke = true;
}
}
else
{
var x1 = childItem.rect.x + childItem.rect.width;
if (childItem.value < 0) x1 = x1 - childItem.rect.width;
var x2 = x1;
var y1 = this.map.canvasY + ((this.map.canvasHeight / n) * i);
var y2 = this.map.canvasY + ((this.map.canvasHeight / n) * (i+1));
if (childItem.value >= this.map.getBBox().getXMin()
&& childItem.value <= this.map.getBBox().getXMax())
{
drawStroke = true;
}
}
if (drawStroke)
{
this.highlightContext.beginPath();
this.highlightContext.moveTo(x1, y1);
this.highlightContext.lineTo(x2, y2);
this.highlightContext.stroke();
}
this.highlightContext.beginPath();
if (this.map.orientation === "vertical") this.highlightContext.rect(x1, childItem.rect.y, x2-x1, childItem.rect.height);
else this.highlightContext.rect(childItem.rect.x, y1, childItem.rect.width, y2-y1);
this.highlightContext.fill();
}
}
};
/**
* Does the actual drawing.
*
* @method _drawItem
* @param {Object} item The item.
* @param {HTML Canvas Context} ctx The context to render to.
* @private
*/
ia.ComparisonTimeBarLayer.prototype._drawItem = function(item, ctx)
{
var n = item.childItems.length;
ctx.beginPath();
for (var i = 0; i < n; i++)
{
var childItem = item.childItems[i];
if (childItem.value !== undefined)
{
if (this.map.orientation === "vertical")
{
var x1 = childItem.rect.x;
var x2 = childItem.rect.x + childItem.rect.width;
var y1 = childItem.rect.y;
if (childItem.value < 0) y1 = y1 + childItem.rect.height;
var y2 = y1;
}
else
{
var x1 = childItem.rect.x + childItem.rect.width;
if (childItem.value < 0) x1 = x1 - childItem.rect.width;
var x2 = x1;
var y1 = childItem.rect.y;
var y2 = childItem.rect.y + childItem.rect.height;
}
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
if (this.map.animationMode && childItem.name === this.selectedDate) break;
}
}
ctx.stroke();
};
/**
* Runs a hit test on an item.
*
* @method hitItem
* @param {Object} item The item to hit test.
* @param {ia.MapMouseEvent} event An <code>ia.MapMouseEvent</code>.
*/
ia.ComparisonTimeBarLayer.prototype.hitItem = function(item, event)
{
if (this.isSelected(item.id) || this.displayAll)
{
var n = item.childItems.length;
for (var i = 0; i < n; i++)
{
var childItem = item.childItems[i];
if (childItem.value !== undefined)
{
if (childItem.hitArea.intersects(event.x,event.y)) return true;
}
}
}
return false;
};