File: /var/www/html/shootinschool/wp-content/plugins/wp-google-maps/js/v8/modern-store-locator-circle.js
/**
* @namespace WPGMZA
* @module ModernStoreLocatorCircle
* @requires WPGMZA
*/
jQuery(function($) {
/**
* This is the base class the modern store locator circle. <strong>Please <em>do not</em> call this constructor directly. Always use createInstance rather than instantiating this class directly.</strong> Using createInstance allows this class to be externally extensible.
* @class WPGMZA.ModernStoreLocatorCircle
* @constructor WPGMZA.ModernStoreLocatorCircle
* @param {int} map_id The ID of the map this circle belongs to
* @param {object} [settings] Settings to pass into this circle, such as strokeColor
*/
WPGMZA.ModernStoreLocatorCircle = function(map_id, settings) {
var self = this;
var map;
if(WPGMZA.isProVersion())
map = this.map = WPGMZA.getMapByID(map_id);
else
map = this.map = WPGMZA.maps[0];
this.map_id = map_id;
this.mapElement = map.element;
this.mapSize = {
width: $(this.mapElement).width(),
height: $(this.mapElement).height()
};
this.initCanvasLayer();
this.settings = {
center: new WPGMZA.LatLng(0, 0),
radius: 1,
color: "#ff0000",
shadowColor: "white",
shadowBlur: 4,
centerRingRadius: 10,
centerRingLineWidth: 3,
numInnerRings: 9,
innerRingLineWidth: 1,
innerRingFade: true,
numOuterRings: 7,
ringLineWidth: 1,
mainRingLineWidth: 2,
numSpokes: 6,
spokesStartAngle: Math.PI / 2,
numRadiusLabels: 6,
radiusLabelsStartAngle: Math.PI / 2,
radiusLabelFont: "13px sans-serif",
visible: false
};
if(settings)
this.setOptions(settings);
};
/**
* Returns the contructor to be used by createInstance, depending on the selected maps engine.
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @return {function} The appropriate contructor
*/
WPGMZA.ModernStoreLocatorCircle.createInstance = function(map, settings) {
if(WPGMZA.settings.engine == "google-maps")
return new WPGMZA.GoogleModernStoreLocatorCircle(map, settings);
else
return new WPGMZA.OLModernStoreLocatorCircle(map, settings);
};
/**
* Abstract function to initialize the canvas layer
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
*/
WPGMZA.ModernStoreLocatorCircle.prototype.initCanvasLayer = function() {
}
/**
* Handles the map viewport being resized
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
*/
WPGMZA.ModernStoreLocatorCircle.prototype.onResize = function(event) {
this.draw();
};
/**
* Updates and redraws the circle
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
*/
WPGMZA.ModernStoreLocatorCircle.prototype.onUpdate = function(event) {
this.draw();
};
/**
* Sets options on the circle (for example, strokeColor)
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @param {object} options An object of options to iterate over and set on this circle.
*/
WPGMZA.ModernStoreLocatorCircle.prototype.setOptions = function(options) {
for(var name in options)
{
var functionName = "set" + name.substr(0, 1).toUpperCase() + name.substr(1);
if(typeof this[functionName] == "function")
this[functionName](options[name]);
else
this.settings[name] = options[name];
}
};
/**
* Gets the resolution scale for drawing on the circles canvas.
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @return {number} The device pixel ratio, or 1 where that is not present.
*/
WPGMZA.ModernStoreLocatorCircle.prototype.getResolutionScale = function() {
return window.devicePixelRatio || 1;
};
/**
* Returns the center of the circle
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @return {object} A latLng literal
*/
WPGMZA.ModernStoreLocatorCircle.prototype.getCenter = function() {
return this.getPosition();
};
/**
* Sets the center of the circle
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @param {WPGMZA.LatLng|object} A LatLng literal or instance of WPGMZA.LatLng
*/
WPGMZA.ModernStoreLocatorCircle.prototype.setCenter = function(value) {
this.setPosition(value);
};
/**
* Gets the center of the circle
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @return {object} The center as a LatLng literal
*/
WPGMZA.ModernStoreLocatorCircle.prototype.getPosition = function() {
return this.settings.center;
};
/**
* Alias for setCenter
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
*/
WPGMZA.ModernStoreLocatorCircle.prototype.setPosition = function(position) {
this.settings.center = position;
};
/**
* Gets the circle radius, in kilometers
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @return {number} The circles radius, in kilometers
*/
WPGMZA.ModernStoreLocatorCircle.prototype.getRadius = function() {
return this.settings.radius;
};
/**
* Sets the circles radius, in kilometers
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @param {number} radius The radius, in kilometers
* @throws Invalid radius
*/
WPGMZA.ModernStoreLocatorCircle.prototype.setRadius = function(radius) {
if(isNaN(radius))
throw new Error("Invalid radius");
this.settings.radius = radius;
};
/**
* Gets the visibility of the circle
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @return {bool} Whether or not the circle is visible
*/
WPGMZA.ModernStoreLocatorCircle.prototype.getVisible = function() {
return this.settings.visible;
};
/**
* Sets the visibility of the circle
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @param {bool} visible Whether the circle should be visible
*/
WPGMZA.ModernStoreLocatorCircle.prototype.setVisible = function(visible) {
this.settings.visible = visible;
};
/**
* Abstract function to get the transformed circle radius (see subclasses)
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @param {number} km The input radius, in kilometers
* @throws Abstract function called
*/
WPGMZA.ModernStoreLocatorCircle.prototype.getTransformedRadius = function(km)
{
throw new Error("Abstract function called");
}
/**
* Abstract function to set the canvas context
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @param {string} type The context type
* @throws Abstract function called
*/
WPGMZA.ModernStoreLocatorCircle.prototype.getContext = function(type)
{
throw new Error("Abstract function called");
}
/**
* Abstract function to get the canvas dimensions
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
* @throws Abstract function called
*/
WPGMZA.ModernStoreLocatorCircle.prototype.getCanvasDimensions = function()
{
throw new Error("Abstract function called");
}
/**
* Validates the circle settings and corrects them where they are invalid
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
*/
WPGMZA.ModernStoreLocatorCircle.prototype.validateSettings = function()
{
if(!WPGMZA.isHexColorString(this.settings.color))
this.settings.color = "#ff0000";
}
/**
* Draws the circle to the canvas
* @method
* @memberof WPGMZA.ModernStoreLocatorCircle
*/
WPGMZA.ModernStoreLocatorCircle.prototype.draw = function() {
this.validateSettings();
var settings = this.settings;
var canvasDimensions = this.getCanvasDimensions();
var canvasWidth = canvasDimensions.width;
var canvasHeight = canvasDimensions.height;
var map = this.map;
var resolutionScale = this.getResolutionScale();
context = this.getContext("2d");
context.clearRect(0, 0, canvasWidth, canvasHeight);
if(!settings.visible)
return;
context.shadowColor = settings.shadowColor;
context.shadowBlur = settings.shadowBlur;
// NB: 2018/02/13 - Left this here in case it needs to be calibrated more accurately
/*if(!this.testCircle)
{
this.testCircle = new google.maps.Circle({
strokeColor: "#ff0000",
strokeOpacity: 0.5,
strokeWeight: 3,
map: this.map,
center: this.settings.center
});
}
this.testCircle.setCenter(settings.center);
this.testCircle.setRadius(settings.radius * 1000);*/
// Reset transform
context.setTransform(1, 0, 0, 1, 0, 0);
var scale = this.getScale();
context.scale(scale, scale);
// Translate by world origin
var offset = this.getWorldOriginOffset();
context.translate(offset.x, offset.y);
// Get center and project to pixel space
var center = new WPGMZA.LatLng(this.settings.center);
var worldPoint = this.getCenterPixels();
var rgba = WPGMZA.hexToRgba(settings.color);
var ringSpacing = this.getTransformedRadius(settings.radius) / (settings.numInnerRings + 1);
// TODO: Implement gradients for color and opacity
// Inside circle (fixed?)
context.strokeStyle = settings.color;
context.lineWidth = (1 / scale) * settings.centerRingLineWidth;
context.beginPath();
context.arc(
worldPoint.x,
worldPoint.y,
this.getTransformedRadius(settings.centerRingRadius) / scale, 0, 2 * Math.PI
);
context.stroke();
context.closePath();
// Spokes
var radius = this.getTransformedRadius(settings.radius) + (ringSpacing * settings.numOuterRings) + 1;
var grad = context.createRadialGradient(0, 0, 0, 0, 0, radius);
var rgba = WPGMZA.hexToRgba(settings.color);
var start = WPGMZA.rgbaToString(rgba), end;
var spokeAngle;
rgba.a = 0;
end = WPGMZA.rgbaToString(rgba);
grad.addColorStop(0, start);
grad.addColorStop(1, end);
context.save();
context.translate(worldPoint.x, worldPoint.y);
context.strokeStyle = grad;
context.lineWidth = 2 / scale;
for(var i = 0; i < settings.numSpokes; i++)
{
spokeAngle = settings.spokesStartAngle + (Math.PI * 2) * (i / settings.numSpokes);
x = Math.cos(spokeAngle) * radius;
y = Math.sin(spokeAngle) * radius;
context.setLineDash([2 / scale, 15 / scale]);
context.beginPath();
context.moveTo(0, 0);
context.lineTo(x, y);
context.stroke();
}
context.setLineDash([]);
context.restore();
// Inner ringlets
context.lineWidth = (1 / scale) * settings.innerRingLineWidth;
for(var i = 1; i <= settings.numInnerRings; i++)
{
var radius = i * ringSpacing;
if(settings.innerRingFade)
rgba.a = 1 - (i - 1) / settings.numInnerRings;
context.strokeStyle = WPGMZA.rgbaToString(rgba);
context.beginPath();
context.arc(worldPoint.x, worldPoint.y, radius, 0, 2 * Math.PI);
context.stroke();
context.closePath();
}
// Main circle
context.strokeStyle = settings.color;
context.lineWidth = (1 / scale) * settings.centerRingLineWidth;
context.beginPath();
context.arc(worldPoint.x, worldPoint.y, this.getTransformedRadius(settings.radius), 0, 2 * Math.PI);
context.stroke();
context.closePath();
// Outer ringlets
var radius = radius + ringSpacing;
for(var i = 0; i < settings.numOuterRings; i++)
{
if(settings.innerRingFade)
rgba.a = 1 - i / settings.numOuterRings;
context.strokeStyle = WPGMZA.rgbaToString(rgba);
context.beginPath();
context.arc(worldPoint.x, worldPoint.y, radius, 0, 2 * Math.PI);
context.stroke();
context.closePath();
radius += ringSpacing;
}
// Text
if(settings.numRadiusLabels > 0)
{
var m;
var radius = this.getTransformedRadius(settings.radius);
var clipRadius = (12 * 1.1) / scale;
var x, y;
if(m = settings.radiusLabelFont.match(/(\d+)px/))
clipRadius = (parseInt(m[1]) / 2 * 1.1) / scale;
context.font = settings.radiusLabelFont;
context.textAlign = "center";
context.textBaseline = "middle";
context.fillStyle = settings.color;
context.save();
context.translate(worldPoint.x, worldPoint.y)
for(var i = 0; i < settings.numRadiusLabels; i++)
{
var spokeAngle = settings.radiusLabelsStartAngle + (Math.PI * 2) * (i / settings.numRadiusLabels);
var textAngle = spokeAngle + Math.PI / 2;
var text = settings.radiusString;
var width;
if(Math.sin(spokeAngle) > 0)
textAngle -= Math.PI;
x = Math.cos(spokeAngle) * radius;
y = Math.sin(spokeAngle) * radius;
context.save();
context.translate(x, y);
context.rotate(textAngle);
context.scale(1 / scale, 1 / scale);
width = context.measureText(text).width;
height = width / 2;
context.clearRect(-width, -height, 2 * width, 2 * height);
context.fillText(settings.radiusString, 0, 0);
context.restore();
}
context.restore();
}
}
});