(function() {
/**
* @typedef {Help4.control2.hotspot.Hotspot.Params} Help4.control2.hotspot.Icon.Params
* @property {Help4.control2.AreaXYWH} [rect = {x: 0, y: 0, w: 0, h: 0}] - area of the assigned element
* @property {Help4.control2.PositionXY} [point = {x: 0, y: 0}] - center point of the assigned element
* @property {Help4.control2.PositionLeftTop} [delta = {left: 0, top: 0}] - in case hotspot is moved
* @property {string} icon - icon type
* @property {string} [size = ''] - icon size
* @property {string} pos - icon position relative to element
* @property {Help4.control2.hotspot.ANIMATION_TYPES} [animationType = 'none'] - type of animation
*/
/**
* Creates an icon hotspot.
* @augments Help4.control2.hotspot.Hotspot
* @property {Help4.control2.AreaXYWH} rect - area of the assigned element
* @property {Help4.control2.PositionXY} point - center point of the assigned element
* @property {Help4.control2.PositionLeftTop} delta - in case hotspot is moved
* @property {string} icon - icon type
* @property {string} size - icon size
* @property {string} pos - icon position relative to element
* @property {Help4.control2.hotspot.ANIMATION_TYPES} animationType - type of animation
*/
Help4.control2.hotspot.Icon = class extends Help4.control2.hotspot.Hotspot {
/**
* @override
* @param {Help4.control2.hotspot.Icon.Params} [params]
*/
constructor(params) {
const T = Help4.jscore.ControlBase.TYPES;
super(params, {
params: {
rect: {type: T.xywh},
point: {type: T.xy},
delta: {type: T.leftTop},
icon: {type: T.string, mandatory: true},
size: {type: T.string},
pos: {type: T.string, mandatory: true},
animationType: {type: T.string, init: Help4.control2.hotspot.ANIMATION_TYPES.none}
},
statics: {
_icon: {destroy: false}
},
config: {
css: 'icon'
}
});
}
/**
* @override
* @param {Help4.control2.PositionXY} point
*/
calcMeetingPoint({x, y}) {
const ra = _getSizeConfig(this.size).icon / 2;
const pt = {x: this._x + ra, y: this._y + ra};
const dx = pt.x - x;
const dy = pt.y - y;
const dist = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
// size of hotspot is: radius + border; line should start right at the border (so border-w + 1)
// see H4H.Connected._create for borderSize information
const norm = 1 - (ra + this.borderSize + 1) / dist;
return norm > 0
? {x: x + norm * dx, y: y + norm * dy}
: {x, y};
}
/**
* @override
* @param {Help4.control2.hotspot.Icon.Params} params - same params as provided to the constructor
*/
_onAfterInit(params) {
super._onAfterInit(params);
this._x = 0;
this._y = 0;
}
/** @override */
_onDomCreated(dom) {
super._onDomCreated(dom);
const c = this._content = this._createElement('div', {css: 'inner'});
this._icon = this._createElement('span', {dom: c, id: '-ico'});
}
/**
* @override
* @param {Help4.jscore.ControlBase.PropertyChangeEvent} event - the change event
*/
_applyPropertyToDom({name, value, oldValue}) {
switch (name) {
case 'rect':
case 'point':
case 'pos':
case 'delta':
_apply.call(this);
break;
case 'icon':
this.removeCss(oldValue);
this.addCss(value);
this._icon.innerHTML = Help4.control2.ICONS['icon_' + value];
break;
case 'size':
let config = _getSizeConfig(oldValue);
this.removeCss('size-' + config.localization);
config = _getSizeConfig(value);
this.addCss('size-' + config.localization);
_apply.call(this);
break;
case 'animationType':
this.removeCss(`ani-${oldValue}`);
this.addCss(`ani-${value}`);
break;
default:
super._applyPropertyToDom({name, value, oldValue});
break;
}
}
/**
* @override
*/
getDragStartPosition() {
const s = _getSizeConfig(this.size).icon;
const {x: rx, y: ry, w: rw, h: rh} = this.rect;
let x, y;
switch (_getPos(this.pos, this.rtl)) {
case 'A': // Top Left, Outside
x = rx - s;
y = ry - s;
break;
case 'B': // Top Left, Above
x = rx;
y = ry - s;
break;
case 'C': // Top Center
x = rx + (rw - s) / 2;
y = ry - s;
break;
case 'D': // Top Right, Above
x = rx + rw - s;
y = ry - s;
break;
case 'E': // Top Right, Outside
x = rx + rw;
y = ry - s;
break;
case 'F': // Top Left
x = rx - s;
y = ry;
break;
case 'G': // Top Right
x = rx + rw;
y = ry;
break;
case 'H': // Middle Left
x = rx - s;
y = ry + (rh - s) / 2;
break;
case 'I': // Middle Right
x = rx + rw;
y = ry + (rh - s) / 2;
break;
case 'J': // Bottom Left
x = rx - s;
y = ry + rh - s;
break;
case 'K': // Bottom Right
x = rx + rw;
y = ry + rh - s;
break;
case 'L': // Bottom Left, Outside
x = rx - s;
y = ry + rh;
break;
case 'M': // Bottom Left, Below
x = rx;
y = ry + rh;
break;
case 'N': // Bottom Center
x = rx + (rw - s) / 2;
y = ry + rh;
break;
case 'O': // Bottom Right, Below
x = rx + rw - s;
y = ry + rh;
break;
case 'P': // Bottom Right, Outside
x = rx + rw;
y = ry + rh;
break;
case 'Q': // Centered
x = rx + (rw - s) / 2;
y = ry + (rh - s) / 2;
break;
case 'R': // Manual
const {x: px, y: py} = this.point;
x = px - s / 2;
y = py - s / 2;
break;
}
return {x, y};
}
}
/**
* @memberof Help4.control2.hotspot.Icon#
* @private
*/
function _apply() {
const dom = this.getDom();
if (!dom) return;
const {x, y} = this.getDragStartPosition();
const {left: dx, top: dy} = this.delta;
dom.style.left = (this._x = x + dx) + 'px';
dom.style.top = (this._y = y + dy) + 'px';
}
/**
* @memberof Help4.control2.hotspot.Icon#
* @param {string} pos
* @param {boolean} rtl
* @returns {string}
* @private
*/
function _getPos(pos, rtl) {
const iconPosRtl = rtl ? Help4.getController().getConfiguration().iconPositionRtl : false;
if (!iconPosRtl) return pos;
// XRAY-4671: "Left" means "Start" and "Right" means "End" in case "iconPositionRtl" is set to true
// this effectively means that they move to the opposite side
return {
A: 'E', // Top Left, Outside
B: 'D', // Top Left, Above
// C: Top Center
D: 'B', // Top Right, Above
E: 'A', // Top Right, Outside
F: 'G', // Top Left
G: 'F', // Top Right
H: 'I', // Middle Left
I: 'H', // Middle Right
J: 'K', // Bottom Left
K: 'J', // Bottom Right
L: 'P', // Bottom Left, Outside
M: 'O', // Bottom Left, Below
// N: Bottom Center
O: 'M', // Bottom Right, Below
P: 'L' // Bottom Right, Outside
// Q: Centered
// R: Manual
}[pos] || pos;
}
/**
* @memberof Help4.control2.hotspot.Icon#
* @param {string} size
* @returns {Help4.typedef.HotspotSize}
* @private
*/
function _getSizeConfig(size) {
const {HOTSPOT_SIZES} = Help4;
return HOTSPOT_SIZES.find(hs => hs.size === size) || HOTSPOT_SIZES[0];
}
})();