goog.provide('M.style.Category');
goog.require('M.Style');
/**
* @namespace M.style.Category
*/
(function() {
/**
* @classdesc
* Main constructor of the class. Creates a categoryStyle
* with parameters specified by the user
* for the implementation
* provided by the user
* @constructor
* @extends {M.Style}
* @param {String} attributeName
* @param {Map<String,M.Style>} categoryStyles
* @api stable
*/
M.style.Category = (function(attributeName, categoryStyles, options = {}) {
if (M.utils.isNullOrEmpty(attributeName)) {
M.exception("No se ha especificado el nombre del atributo.");
}
/**
* TODO
* @public
* @type {String}
* @api stable
* @expose
*/
this.attributeName_ = attributeName;
/**
* TODO
* @public
* @type {Map<String,M.Style>}
* @api stable
* @expose
*/
this.categoryStyles_ = categoryStyles;
goog.base(this, options, {});
});
goog.inherits(M.style.Category, M.Style);
/**
* This function apply the styleCategory object to specified layer
*
* @function
* @public
* @param {M.layer.Vector} layer - layer is the layer where we want to apply the new Style
* @returns {M.style.Category}
* @api stable
*/
M.style.Category.prototype.apply = function(layer) {
this.layer_ = layer;
this.update_();
};
/**
* This function return the AttributeName
*
* @function
* @public
* @returns {String}
* @api stable
*/
M.style.Category.prototype.getAttributeName = function() {
return this.attributeName_;
};
/**
* This function set the AttributeName defined by user
*
* @function
* @public
* @param {String} attributeName - newAttributeName is the newAttributeName specified by the user
* @returns {M.style.Category}
* @api stable
*/
M.style.Category.prototype.setAttributeName = function(attributeName) {
this.attributeName_ = attributeName;
this.update_();
return this;
};
/**
* This function return an Array with the diferents Categories
*
* @function
* @public
* @returns {Array<String>}
* @api stable
*/
M.style.Category.prototype.getCategories = function() {
return this.categoryStyles_;
};
/**
* This function sets the object categories
*
* @function
* @public
* @param {Map<String,M.style>} categories
* @return {M.style.styleCategory}
* @api stable
*
*/
M.style.Category.prototype.setCategories = function(categories) {
this.categoryStyles_ = categories;
this.update_();
return this;
};
/**
* This function return the style of a specified Category defined by user
*
* @function
* @public
* @param {String} string - string is the name of a category value
* @returns {M.style}
* @api stable
*/
M.style.Category.prototype.getStyleForCategory = function(category) {
return this.categoryStyles_[category];
};
/**
* This function set the style of a specified Category defined by user
*
* @function
* @public
* @param {String} category - category is the name of a category value
* @param {M.style.Simple} style - style is the new style to switch
* @returns {M.style.Category}
* @api stable
*/
M.style.Category.prototype.setStyleForCategory = function(category, style) {
this.categoryStyles_[category] = style;
this.update_();
return this;
};
/**
* This function updates the canvas of style
*
* @function
* @public
* @api stable
*/
M.style.Category.prototype.updateCanvas = function() {
let canvasImages = [];
this.updateCanvasPromise_ = new Promise((success, fail) =>
this.loadCanvasImages_(0, canvasImages, success));
};
/**
* TODO
*
* @function
* @private
* @param {CanvasRenderingContext2D} vectorContext - context of style canvas
*/
M.style.Category.prototype.loadCanvasImages_ = function(currentIndex, canvasImages, callbackFn) {
let categories = this.getCategories();
let categoryNames = Object.keys(categories);
// base case
if (currentIndex === categoryNames.length) {
this.drawGeometryToCanvas(canvasImages, callbackFn);
}
// recursive case
else {
let category = categoryNames[currentIndex];
let style = this.getStyleForCategory(category);
let image = new Image();
image.crossOrigin = 'Anonymous';
let scope_ = this;
image.onload = function() {
canvasImages.push({
'image': this,
'categoryName': category
});
scope_.loadCanvasImages_((currentIndex + 1), canvasImages, callbackFn);
};
image.onerror = function() {
canvasImages.push({
'categoryName': category
});
scope_.loadCanvasImages_((currentIndex + 1), canvasImages, callbackFn);
};
style.updateCanvas();
if (style.get('icon.src')) {
M.utils.getImageSize(style.get('icon.src')).then((img) => {
image.width = style.get('icon.scale') ? img.width * style.get('icon.scale') : img.width;
image.height = style.get('icon.scale') ? img.height * style.get('icon.scale') : img.height;
image.src = style.toImage();
});
}
else {
image.src = style.toImage();
}
}
};
/**
* TODO
*
* @function
* @public
* @param {CanvasRenderingContext2D} vectorContext - context of style canvas
* @api stable
*/
M.style.Category.prototype.drawGeometryToCanvas = function(canvasImages, callbackFn) {
let heights = canvasImages.map(canvasImage => canvasImage['image'].height);
let widths = canvasImages.map(canvasImage => canvasImage['image'].width);
let vectorContext = this.canvas_.getContext('2d');
vectorContext.canvas.height = heights.reduce((acc, h) => acc + h + 5);
vectorContext.textBaseline = "middle";
let maxWidth = Math.max.apply(widths, widths);
canvasImages.forEach((canvasImage, index) => {
let image = canvasImage['image'];
let categoryName = canvasImage['categoryName'];
let coordinateY = 0;
let prevHeights = heights.slice(0, index);
if (!M.utils.isNullOrEmpty(prevHeights)) {
coordinateY = prevHeights.reduce((acc, h) => acc + h + 5);
coordinateY += 5;
}
let imageHeight = 0;
if (!M.utils.isNullOrEmpty(image)) {
imageHeight = image.height;
vectorContext.drawImage(image, (maxWidth - image.width) / 2, coordinateY, image.width, image.height);
}
vectorContext.fillText(categoryName, maxWidth + 5, coordinateY + (imageHeight / 2));
}, this);
callbackFn();
};
/**
* This function updates the style
*
* @function
* @private
* @return {M.style.styleCategory}
* @api stable
*/
M.style.Category.prototype.update_ = function() {
if (!M.utils.isNullOrEmpty(this.layer_)) {
let styleOther = this.categoryStyles_['other'];
this.layer_.getFeatures().forEach(function(feature) {
let value = feature.getAttribute(this.attributeName_);
let style = this.categoryStyles_[value];
if (!M.utils.isNullOrEmpty(style)) {
feature.setStyle(style);
}
else if (!M.utils.isNullOrEmpty(styleOther)) {
feature.setStyle(styleOther);
}
}.bind(this));
this.updateCanvas();
}
};
})();