@aurigma/design-atoms
Version:
Design Atoms is a part of Customer's Canvas SDK which allows for manipulating individual design elements through your code.
1,046 lines • 63.4 kB
JavaScript
import { EventWithSenderArg } from "@aurigma/design-atoms-model/EventObject";
import { ScrollBarsStyle } from "./ScrollBarsStyle";
import { ViewportAlignment } from "./ViewportAlignment";
import { ZoomMode } from "./ZoomMode";
import { ZoomQuality } from "./ZoomQuality";
import { UpdateStatus } from "../UpdateStatus";
import { ViewerClientSideOptions } from "./ViewerClientSideOptions";
import { Cursor } from "../Utils/Common";
import { PointF, normalizeAngle } from "@aurigma/design-atoms-model/Math";
import { StandardIntervalCheckLoop } from "./StandardIntervalCheckLoop";
import Environment from "@aurigma/design-atoms-model/Utils/Environment";
import { RulersConfigUnit, getUnitScale } from "./Interfaces";
import { CoordinatesConvertUtils } from "../Utils/CoordinatesConvertUtils";
import { DefaultCursorHelper } from "../Input/InputHandler/Default/DefaultCursorHandler";
export class ZoomParams {
}
export class BaseViewer {
constructor(_zone = null) {
this._zone = _zone;
this._contentElements = [];
this._rulerBorderWidth = 1;
this._rulerDivision = 5;
this._ignoreDocumentClickOnce = false;
this._documentClickEvent = new EventWithSenderArg();
this._workspaceDoubleClickEvent = new EventWithSenderArg();
this._workspaceMouseDownEvent = new EventWithSenderArg();
this._workspaceMouseUpEvent = new EventWithSenderArg();
this._workspaceMouseMoveEvent = new EventWithSenderArg();
this._statusChangedEvent = new EventWithSenderArg();
this._scrolledEvent = new EventWithSenderArg();
this._onresizeEvent = new EventWithSenderArg();
this._zoomedEvent = new EventWithSenderArg();
this._intervalCheckLoop = StandardIntervalCheckLoop;
this._contentAngle = 0;
this._rulersOnHover = (e) => {
// used to draw slide bars just when somebody move mouse over content but don't hold some object
// and don't use setCapture
if (!this.rulerEnabled)
return;
var topSlideBar = this._rulers.topSlideBar;
var leftSlideBar = this._rulers.leftSlideBar;
var viewerLocation = CoordinatesConvertUtils.getElementPageCoord(this._viewerElement);
var x = e.page.x - viewerLocation.left;
var y = e.page.y - viewerLocation.top;
topSlideBar.style.left = x + "px";
leftSlideBar.style.top = y + "px";
};
this._onDocumentClick = (e) => { };
this._onScroll = (e) => {
if (this._scrollInitialized) {
this._scrollInitialized = false;
return;
}
this._scrollingPosition = this.getActualScrollPosition();
this._canvas.onScroll();
//Raise a client event.
this._scrolledEvent.notify(this);
};
this._maxZoom = 16;
this._minZoom = 0.05;
this._screenXDpi = 72;
this._screenYDpi = 72;
this._scrollBarsStyle = ScrollBarsStyle.auto;
this._scrollingPosition = new PointF(0, 0);
this._viewportAlignment = ViewportAlignment.leftTop;
this._zoom = 1;
this._zoomMode = ZoomMode.none,
this._zoomQuality = ZoomQuality.shrinkHighStretchLow,
this._bestFitWhiteSpacePc = 0,
this._status = UpdateStatus.ready;
this._exceptionDescription = "";
this._returnValue = "";
this._clientSideOptions = new ViewerClientSideOptions(this);
this._delayedRefreshTimeout = 1000;
this._refreshTimer = null;
this._contentElements = [];
//Specify whether we need to refresh the image.
this._needToRefresh = false;
this._rulerEnabled = false;
this._rulerWidth = 13;
this._rulerScale = 1; // to translate points to inches for example.
this._rulerOffsetX = 0;
this._rulerOffsetY = 0;
this._rulersOnScrollDelegate = null;
this._rulersOnZoomDelegate = null;
this._pinchZoomEnabled = true;
this._holderBounds = null;
this._contentCtxDimension = {};
this._holderElement = null;
this._rulers = {};
this._bodyCursor = null;
}
get element() {
return this._viewerElement;
}
get id() {
return this._viewerElement.id;
}
get contentAngle() {
return this._contentAngle;
}
set contentAngle(value) {
if (value == null || value === this._contentAngle)
return;
this._contentAngle = normalizeAngle(value);
var translate = "(0, 0)";
if (this._contentAngle === 90) {
translate = "(0px, -100%)";
}
else if (this._contentAngle === 180) {
translate = "(-100%, -100%)";
}
else if (this._contentAngle === 270) {
translate = "(-100%, 0px)";
}
this._contentCtx.style.transform = "rotate(" + this._contentAngle + "deg) translate" + translate;
this._contentCtx.style.transformOrigin = "left top";
this._updateViewport();
this._canvas.setZoom(this.zoom, undefined, { force: true });
this._canvas.updateSelection();
this._canvas.redraw();
}
get holderBounds() {
return this._getElementBounds(this.element);
}
get contentWidth() {
/// <summary>Gets a value that represents the width of the control's content taking into account its horizontal resolution and zoom value.</summary>
/// <value type="Number">The width of the control's content.</value>
/// <remarks><para>This property corresponds to <see cref="P:Aurigma.AjaxControls.BaseViewer.ContentWidth">BaseViewer.ContentWidth</see> server-side member.</para></remarks>
return this._holderBounds.width;
}
get width() {
/// <summary>Gets the width (in pixels) of the control area.</summary>
/// <value type="Number">The width of the control area.</value>
/// <remarks><para>This property corresponds to <see cref="P:Aurigma.AjaxControls.BaseViewer.Width">BaseViewer.Width</see> server-side member.</para></remarks>
return this._holderBounds.offsetWidth;
}
get contentHeight() {
/// <summary>Gets a value that represents the height of the control's content taking into account its vertical resolution and zoom value.</summary>
/// <value type="Number">The height of the control's content.</value>
/// <remarks><para>This property corresponds to <see cref="P:Aurigma.AjaxControls.BaseViewer.ContentHeight">BaseViewer.ContentHeight</see> server-side member.</para></remarks>
return this._holderBounds.height;
}
get height() {
/// <summary>Gets the height (in pixels) of the control area.</summary>
/// <value type="Number">The height of the control area.</value>
/// <remarks><para>This property corresponds to <see cref="P:Aurigma.AjaxControls.BaseViewer.Height">BaseViewer.Height</see> server-side member.</para></remarks>
return this._holderBounds.offsetHeight;
}
_notifySizeChanged() {
this._onResize(null, false);
}
_renderContent(sb) {
return sb;
}
get hasContent() {
return true;
}
_render() {
var wsize = "width:" + this.contentWidth + "px;height:" + this.contentHeight + "px;";
let sb = "";
sb += "\u003cdiv id=\"cvContent\" style=\"position:absolute; overflow: hidden; box-sizing: content-box; -webkit-box-sizing: content-box; -moz-box-sizing: content-box;";
// todo: remove
// only for debug
sb += "display: none;";
if (this.hasContent)
sb += wsize;
else
sb += "display:none;";
var vl = this.getViewportLocation();
sb += "left:" + vl.x + "px;top:" + vl.y + "px";
sb += "\"\u003e";
sb = this._renderContent(sb);
// close content.
sb += "\u003c/div\u003e";
sb += "\u003c/div\u003e";
return sb;
}
_clearElement(el) {
while (el.firstChild)
el.removeChild(el.firstChild);
}
_rulersOnScroll() {
this._updateRulersStyle();
}
_rulersOnZoom() {
this._drawRulers();
this._updateRulersStyle();
this._canvas.updateViewport();
}
_initializeRulers() {
// create Rulers.
var el = this.element.parentNode;
var doc = el.ownerDocument;
var rulersStyle = "z-index: 2; -webkit-transform: translate3d(0px, 0px, 0px); -moz-transform: translate3d(0px, 0px, 0px)";
var topRuller = doc.createElement("div");
topRuller.setAttribute("style", rulersStyle);
var fullTopRuller = doc.createElement("div");
var leftRuller = doc.createElement("div");
leftRuller.setAttribute("style", rulersStyle);
var fullLeftRuller = doc.createElement("div");
var whiteRect = doc.createElement("div");
whiteRect.style.zIndex = "2";
var topSlideBar = doc.createElement("div");
var leftSlideBar = doc.createElement("div");
this._rulers.topRuller = topRuller;
this._rulers.leftRuller = leftRuller;
this._rulers.fullTopRuller = fullTopRuller;
this._rulers.fullLeftRuller = fullLeftRuller;
this._rulers.whiteRect = whiteRect;
this._rulers.topSlideBar = topSlideBar;
this._rulers.leftSlideBar = leftSlideBar;
var id = this.element.id;
topRuller.id = id + "_TopRuler";
fullTopRuller.id = id + "_FullTopRuler";
leftRuller.id = id + "_LeftRuler";
fullLeftRuller.id = id + "_FullLeftRuler";
whiteRect.id = id + "_WhiteRect";
topSlideBar.id = id + "_TopSlideBar";
leftSlideBar.id = id + "_LeftSlideBar";
fullTopRuller = topRuller.appendChild(fullTopRuller);
fullLeftRuller = leftRuller.appendChild(fullLeftRuller);
topSlideBar = topRuller.appendChild(topSlideBar);
leftSlideBar = leftRuller.appendChild(leftSlideBar);
topRuller = el.appendChild(topRuller);
leftRuller = el.appendChild(leftRuller);
whiteRect = el.appendChild(whiteRect);
topRuller.style.position =
fullTopRuller.style.position =
leftRuller.style.position =
fullLeftRuller.style.position =
whiteRect.style.position =
topSlideBar.style.position =
leftSlideBar.style.position = "absolute";
leftSlideBar.style.width = topSlideBar.style.height = this.rulerWidth + "px";
leftSlideBar.style.height = topSlideBar.style.width = "1px";
leftSlideBar.style.backgroundColor = topSlideBar.style.backgroundColor = "#ff0000";
leftSlideBar.style.overflow = topSlideBar.style.overflow = "hidden";
leftSlideBar.style.webkitTransform = topSlideBar.style.webkitTransform = "translate3d(0, 0, 0)";
topRuller.style.overflow =
leftRuller.style.overflow =
whiteRect.style.overflow = "hidden";
topRuller.style.visibility =
leftRuller.style.visibility =
whiteRect.style.visibility = "hidden";
whiteRect.style.backgroundColor = "#909090";
el.style.position = "relative";
this._drawRulers();
this._updateRulersStyle();
if (!this._rulersOnScrollDelegate) {
this._rulersOnScrollDelegate = this._rulersOnScroll.bind(this);
this.add_scrolled(this._rulersOnScrollDelegate);
}
if (!this._rulersOnZoomDelegate) {
this._rulersOnZoomDelegate = this._rulersOnZoom.bind(this);
this.add_zoomed(this._rulersOnZoomDelegate);
}
}
_disposeRulers() {
if (this._rulersOnScrollDelegate) {
this.remove_scrolled(this._rulersOnScrollDelegate);
this._rulersOnScrollDelegate = null;
}
if (this._rulersOnZoomDelegate) {
this.remove_zoomed(this._rulersOnZoomDelegate);
this._rulersOnZoomDelegate = null;
}
}
_updateRulersStyle() {
// Set ruler style.
let leftRuller = this._rulers.leftRuller;
let topRuller = this._rulers.topRuller;
let fullLeftRuller = this._rulers.fullLeftRuller;
let fullTopRuller = this._rulers.fullTopRuller;
let whiteRect = this._rulers.whiteRect;
let width = this.width;
let hight = this.height;
let contentWidth = this.contentWidth;
let contentHeight = this.contentHeight;
let scrollBarWidth = this.scrollBarWidth;
let leftRullerStyle = leftRuller.style;
let topRullerStyle = topRuller.style;
let fullTopRullerStyle = fullTopRuller.style;
let fullLeftRullerStyle = fullLeftRuller.style;
let whiteRectStyle = whiteRect.style;
if (!this._rulerEnabled) {
topRullerStyle.width = topRullerStyle.height = leftRullerStyle.width = leftRullerStyle.height =
topRullerStyle.borderWidth = leftRullerStyle.borderWidth = whiteRectStyle.width =
whiteRectStyle.height = "0px";
leftRullerStyle.visibility = topRullerStyle.visibility = whiteRectStyle.visibility = "hidden";
}
else {
leftRullerStyle.visibility = topRullerStyle.visibility = whiteRectStyle.visibility = "inherit";
leftRullerStyle.backgroundColor = topRullerStyle.backgroundColor = "#ffffff";
leftRullerStyle.borderRight = topRullerStyle.borderBottom = `${this._rulerBorderWidth}px solid black`;
let sbAlways = this.scrollBarsStyle == ScrollBarsStyle.always;
let sbAuto = this.scrollBarsStyle == ScrollBarsStyle.auto;
let isThisScrollBar = sbAlways || (sbAuto && (contentHeight > hight - this.rulerWidth));
let isThatScrollBar = sbAlways || (sbAuto && (contentWidth > width - this.rulerWidth));
isThisScrollBar =
isThisScrollBar ||
(isThatScrollBar && sbAuto && (contentHeight > hight - this.rulerWidth - scrollBarWidth));
isThatScrollBar =
isThatScrollBar ||
(isThisScrollBar && sbAuto && (contentWidth > width - this.rulerWidth - scrollBarWidth));
let rw = isThisScrollBar ? width - scrollBarWidth : width;
let rh = isThatScrollBar ? hight - scrollBarWidth : hight;
topRullerStyle.width = rw + "px";
leftRullerStyle.height = rh + "px";
fullTopRullerStyle.height = topRullerStyle.height = whiteRect.style.height = this._rulerWidth + "px";
fullLeftRullerStyle.width = leftRullerStyle.width = whiteRect.style.width = this._rulerWidth + "px";
// to get clear scroll we need rulers positioned in top-left corner.
topRullerStyle.top = leftRullerStyle.top = topRullerStyle.left = leftRullerStyle.left =
whiteRect.style.top = whiteRect.style.left = "0px";
const sp = this.scrollingPosition;
fullTopRullerStyle.left = -sp.x + "px";
fullLeftRullerStyle.top = -sp.y + "px";
}
}
_setRulersConfig(config) {
if (config === null || config === void 0 ? void 0 : config.enabled) {
var scale = getUnitScale(config);
this._rulerEnabled = true;
this._rulerOffsetX = -1 * config.origin.X / scale;
this._rulerOffsetY = -1 * config.origin.Y / scale;
this._rulerScale = scale;
this._rulerDivision = config.unit === RulersConfigUnit.Inch ? 4 : 5;
}
else {
this._rulerEnabled = false;
}
this._notifySizeChanged();
}
_drawRulers() {
if (!this._rulerEnabled || this._baseRulersOffset == null)
return;
var doc = this.element.parentNode.ownerDocument;
var fullLeftRuler = this._rulers.fullLeftRuller;
var fullTopRuler = this._rulers.fullTopRuller;
var axes = [
{
controlLength: this.width,
contentLength: this.contentWidth,
viewportLocation: this.getViewportLocation().x,
factor: this.zoom * this.actualSizeHorizontalScale,
ruler: fullTopRuler,
startWorkspaceLocation: null,
endWorkspaceLocation: null,
rulerPixelLength: null,
origin: null
},
{
controlLength: this.height,
contentLength: this.contentHeight,
viewportLocation: this.getViewportLocation().y,
factor: this.zoom * this.actualSizeHorizontalScale,
ruler: fullLeftRuler,
startWorkspaceLocation: null,
endWorkspaceLocation: null,
rulerPixelLength: null,
origin: null
}
];
var rulerOffsets = [this.rulerOffsetX + this._baseRulersOffset.x, this.rulerOffsetY + this._baseRulersOffset.y];
var sw = this.scrollBarWidth;
var sbAlways = this.scrollBarsStyle == ScrollBarsStyle.always;
var sbAuto = this.scrollBarsStyle == ScrollBarsStyle.auto;
var rulerScale = this.rulerScale;
for (var i = 0; i < axes.length; i++) {
axes[i].origin = axes[i].viewportLocation + rulerOffsets[i] * axes[i].factor;
var isThisScrollBar = sbAlways ||
(sbAuto && (axes[1 - i].contentLength > axes[1 - i].controlLength - this.rulerWidth));
var isThatScrollBar = sbAlways ||
(sbAuto && (axes[i].contentLength > axes[i].controlLength - this.rulerWidth));
isThisScrollBar =
isThisScrollBar ||
(isThatScrollBar &&
sbAuto &&
(axes[1 - i].contentLength > axes[1 - i].controlLength - this.rulerWidth - sw));
isThatScrollBar =
isThatScrollBar ||
(isThisScrollBar &&
sbAuto &&
(axes[i].contentLength > axes[i].controlLength - this.rulerWidth - sw));
if (isThatScrollBar)
axes[i].rulerPixelLength = Math.max(axes[i].contentLength + this.rulerWidth, axes[i].controlLength - (isThisScrollBar ? sw : 0));
else
axes[i].rulerPixelLength =
(isThisScrollBar) ? axes[i].controlLength - sw : axes[i].controlLength;
axes[i].startWorkspaceLocation = -axes[i].origin;
axes[i].endWorkspaceLocation = axes[i].startWorkspaceLocation + axes[i].rulerPixelLength;
axes[i].startWorkspaceLocation /= axes[i].factor;
axes[i].endWorkspaceLocation /= axes[i].factor;
axes[i].startWorkspaceLocation *= rulerScale;
axes[i].endWorkspaceLocation *= rulerScale;
// generate division.
var maxCutLength = 80; // pixels;
var minCutLength = 4; // pixels;
var currentDivision = 1;
var tmp = (maxCutLength / axes[i].factor) * rulerScale;
var size = 1;
while (tmp > 10) {
tmp /= 10;
size *= 10;
}
if (tmp > 5) {
size = 5 * size;
currentDivision = this._rulerDivision;
}
else if (tmp > 2) {
size = 2 * size;
currentDivision = 2;
}
// generate first fragmentation (with numbers);
var cuts = [{ location: 0, index: 0 }];
var cur = 0;
while (cur < axes[i].endWorkspaceLocation) {
cur += size;
cuts.push({ location: cur, index: 0 });
}
cur = 0;
while (cur > axes[i].startWorkspaceLocation) {
cur -= size;
cuts.push({ location: cur, index: 0 });
}
// clear elements.
this._clearElement(axes[i].ruler);
// draw text.
var j;
for (j = 0; j < cuts.length; j++) {
var txt = doc.createElement("span");
var labelText = Math.abs(Math.round(cuts[j].location)).toString();
txt.innerHTML = (i == 1) ? labelText.split('').join('<br/>') : labelText;
txt.style.position = "absolute";
txt.style.fontSize = "9px";
txt.style.margin = "0px";
txt.style.padding = "0px";
txt.style.fontFamily = "Tahoma, Verdana, Arial;";
txt.style.backgroundColor = "#ffffff";
var offset = Math.round(cuts[j].location * axes[i].factor / rulerScale + axes[i].origin);
txt.style.top = (i == 0) ? "-1px" : offset + 2 + "px";
txt.style.left = (i == 1) ? "2px" : offset + 2 + "px";
axes[i].ruler.appendChild(txt);
}
// create other cuts.
var currentIndex = 1;
var divs = {
1: { newDiv: this._rulerDivision, fractions: 2 },
2: { newDiv: 1, fractions: 2 }
};
divs[this._rulerDivision] = { newDiv: 1, fractions: this._rulerDivision };
var c = divs[currentDivision];
var newSize = size / c.fractions;
while (newSize * axes[i].factor / rulerScale > minCutLength) {
var l = cuts.length - 1;
while (l >= 0) {
for (var k = 0; k < c.fractions - 1; k++)
cuts.push({ index: currentIndex, location: cuts[l].location + newSize * (k + 1) });
l--;
}
currentIndex++;
c = divs[c.newDiv];
newSize = newSize / c.fractions;
}
for (let j = 0; j < cuts.length; j++) {
var cut = doc.createElement("div");
cut.style.position = "absolute";
cut.style.overflow = "hidden";
cut.style.backgroundColor = "#000000";
cut.style.padding = "0px";
cut.style.margin = "0px";
var offset = Math.round(cuts[j].location * axes[i].factor / rulerScale +
axes[i].origin /* + this.rulerWidth*/);
var rw = this.rulerWidth;
var cutWidth = Math.max(Math.ceil(rw / Math.pow(2, cuts[j].index)), 2);
cut.style.width = (i == 0) ? "1px" : cutWidth + "px";
cut.style.height = (i == 1) ? "1px" : cutWidth + "px";
cut.style.top = (i == 0) ? (rw - cutWidth) + "px" : offset + "px";
cut.style.left = (i == 1) ? (rw - cutWidth) + "px" : offset + "px";
cut.style.webkitTransform = "translate3d(0, 0, 0)";
axes[i].ruler.appendChild(cut);
}
}
}
getActualScrollPosition() {
var holder = this.element;
var scrollLeft = holder.scrollLeft, scrollTop = holder.scrollTop;
return new PointF(scrollLeft, scrollTop);
}
getViewportLocation() {
var rulerWidth = this.actualRulerWidth;
var elementBounds = this._holderBounds;
var viewAreaWidth = elementBounds.width - rulerWidth;
var viewAreaHeight = elementBounds.height - rulerWidth;
var swapSides = this._contentAngle === 90 || this._contentAngle === 270;
var contentWidth = swapSides ? this.contentHeight : this.contentWidth;
var contentHeight = swapSides ? this.contentWidth : this.contentHeight;
let x, y;
switch (this._viewportAlignment) {
case ViewportAlignment.centerBottom:
case ViewportAlignment.centerCenter:
case ViewportAlignment.centerTop:
x = Math.floor((viewAreaWidth - contentWidth) / 2);
break;
case ViewportAlignment.leftBottom:
case ViewportAlignment.leftCenter:
case ViewportAlignment.leftTop:
x = 0;
break;
case ViewportAlignment.rightBottom:
case ViewportAlignment.rightCenter:
case ViewportAlignment.rightTop:
x = viewAreaWidth - contentWidth;
break;
}
;
switch (this._viewportAlignment) {
case ViewportAlignment.centerCenter:
case ViewportAlignment.leftCenter:
case ViewportAlignment.rightCenter:
y = Math.floor((viewAreaHeight - contentHeight) / 2);
break;
case ViewportAlignment.centerTop:
case ViewportAlignment.leftTop:
case ViewportAlignment.rightTop:
y = 0;
break;
case ViewportAlignment.centerBottom:
case ViewportAlignment.leftBottom:
case ViewportAlignment.rightBottom:
y = viewAreaHeight - contentHeight;
break;
}
;
return new PointF(Math.max(rulerWidth, x + rulerWidth), Math.max(rulerWidth, y + rulerWidth));
}
ignoreDocumentClickOnce() {
this._ignoreDocumentClickOnce = true;
}
_makeInactive(domElement) {
domElement.ondrag = () => false;
domElement.unselectable = "on";
}
_resizeContentElements() {
const contentWidth = this.contentWidth;
const contentHeight = this.contentHeight;
const el = this._contentElements;
for (let i = 0; i < el.length; i++) {
el[i].style.width = contentWidth + "px";
el[i].style.height = contentHeight + "px";
if (el[i].tagName == "IMG") {
el[i].width = contentWidth;
el[i].height = contentHeight;
}
}
this._contentCtxDimension.width = contentWidth;
this._contentCtxDimension.height = contentHeight;
this._holderBounds = this._getElementBounds(this.element);
}
_getElementBounds(element) {
//when the element is placed in the hidden element ("display: none" style)
//then clientWidth, clientHeight, offsetWidth, offsetHeight, offsetTop, offsetLeft are 0
const hiddenElements = [];
//remove display:none style from parent elements
while (element.length > 0 && element != document) {
if (element.style.display == "none") {
hiddenElements.push({
element: element,
display: element.style.display,
visibility: element.style.visibility
});
element.style.visibility = "hidden";
element.style.display = "block";
}
element = element.parent();
}
//get element properties
const width = element.clientWidth;
const height = element.clientHeight;
const offsetHeight = element.offsetHeight;
const offsetWidth = element.offsetWidth;
const offsetTop = element.offsetTop;
const offsetLeft = element.offsetLeft;
//restore display:none style
for (let i = 0; i < hiddenElements.length; i++) {
const hiddenElementBound = hiddenElements[i];
hiddenElementBound.element[0].style.visibility = hiddenElementBound.visibility;
hiddenElementBound.element[0].style.display = hiddenElementBound.display;
}
return {
"width": width,
"height": height,
"offsetWidth": offsetWidth,
"offsetHeight": offsetHeight,
"offsetTop": offsetTop,
"offsetLeft": offsetLeft
};
}
initialize(intervalCheckLoop = null) {
if (intervalCheckLoop != null)
this._intervalCheckLoop = intervalCheckLoop;
var style = document.createElement("style");
style.id = "aurigmaStyles";
style.type = "text/css";
style.innerHTML = ".aurigmaNoSelect {" +
"-webkit-user-select: none;" +
"-moz-user-select: none;" +
"-ms-user-select: none;" +
"user-select: none;" +
"}";
document.getElementsByTagName("head")[0].appendChild(style);
//super.initialize();
var holderElement = this.element;
this._holderBounds = this._getElementBounds(holderElement);
this._holderElement = holderElement;
var html = this._render();
//console.log(`initialize html`, html);
//console.log(`initialize html element`, this.element);
//console.log(`initialize html element style bg`, this.element.style.background);
holderElement.innerHTML = html;
this._makeInactive(holderElement);
var contentElement = holderElement.querySelectorAll("#cvContent");
this._contentElements.push(this._contentCtx = contentElement[0]);
this._addSetCapture(holderElement);
//Init scrolling position
var sp = this._scrollingPosition;
this._scrollInitialized = true;
holderElement.scrollLeft = sp.x;
holderElement.scrollTop = sp.y;
this._initializeRulers();
//mouse/touch events handling
document.addEventListener("click", this._onDocumentClick);
this._holderElement.addEventListener("scroll", this._onScroll);
this._holderElement.addEventListener("contextmenu", (e) => e.preventDefault());
this._contentCtxDimension = {
width: this.contentWidth,
height: this.contentHeight
};
this._updateViewport();
this._updateViewportAlignment();
this._updateRulersStyle();
this._startIntervalCheckLoop();
}
_startIntervalCheckLoop() {
this._intervalCheckLoop.start({ checkFunction: () => {
var bounds = this._getElementBounds(this.element);
if (bounds.width > 0 && bounds.width !== this._holderBounds.width || bounds.height > 0 && bounds.height !== this._holderBounds.height)
return true;
return false;
},
onChange: () => {
var bounds = this._getElementBounds(this.element);
this._holderBounds = bounds;
this._onResize(this, false);
} });
}
setIntervalCheckLoop(intervalCheckLoop) {
if (intervalCheckLoop == null)
return;
this._intervalCheckLoop = intervalCheckLoop;
this._startIntervalCheckLoop();
}
get _pointerEvents() {
let pointerStartEvents = "mousedown";
let pointerMoveEvents = "mousemove";
let pointerUpEvents = "mouseup";
let pointerCancel = "";
if (Environment.IsTouchDevice()) {
// @ts-ignore
if (window.navigator.pointerEnabled) {
pointerStartEvents = "pointerdown";
pointerMoveEvents = "pointermove";
pointerUpEvents = "pointerup";
pointerCancel = "pointerCancel";
}
else {
pointerStartEvents = "mousedown touchstart";
pointerMoveEvents = "mousemove touchmove";
pointerUpEvents = "mouseup touchend";
pointerCancel = "touchcancel";
}
}
return {
start: pointerStartEvents,
move: pointerMoveEvents,
up: pointerUpEvents,
cancel: pointerCancel
};
}
_onResize(sender, updateButtonGroup) {
this._updateViewport(true);
this._updateViewportAlignment();
this._updateRulersStyle();
this._scrollingPosition = this.getActualScrollPosition();
this._onresizeEvent.notify(this);
}
_updateViewport(ignoreZoomConfigRestrictions = false) {
if (!this.hasContent)
return;
var mode = this.zoomMode;
const calculatedZoom = this.calculateZoomByZoomMode(mode);
if (calculatedZoom == null || calculatedZoom < 0)
return;
if (ignoreZoomConfigRestrictions)
this._zoom = calculatedZoom;
else
this._zoom = Math.min(Math.max(calculatedZoom, this.minZoom), this.getMaxZoom());
this._resizeContentElements();
var vl = this.getViewportLocation();
this._contentCtx.style.left = vl.x + "px";
this._contentCtx.style.top = vl.y + "px";
//Raise the client event
this._zoomedEvent.notify(this);
}
_addSetCapture(holderElement) {
//polyfill for setCapture/releaseCapture
const viewerElement = this._viewerElement;
if (HTMLElement) {
const element = HTMLElement.prototype;
const mouseEventNames = ["click", "mousedown", "mouseup", "mousemove", "mouseover", "mouseout"];
let captureElement = null;
element.setCapture = function () {
//It is incorrect implementation in the general case due to the fact that holderElement inherits preventing of selection,
//but there is not use cases that sensetive to it now.
document.querySelector("body").classList.add("aurigmaNoSelect");
captureElement = this;
for (const eventName of mouseEventNames)
window.addEventListener(eventName, handleCapturedEvent, true);
};
const originalReleaseCapture = element.releaseCapture;
element.releaseCapture = function () {
document.querySelector("body").classList.remove("aurigmaNoSelect");
if (originalReleaseCapture != null)
originalReleaseCapture.call(this);
for (const eventName of mouseEventNames)
window.removeEventListener(eventName, handleCapturedEvent, true);
captureElement = null;
};
const handleCapturedEvent = (event) => {
window.removeEventListener(event.type, handleCapturedEvent, true);
const eventPath = event.path || event.composedPath();
if (captureElement != null && (viewerElement == null || !eventPath.some((element) => element.id === viewerElement.id)))
captureElement.dispatchEvent(cloneMouseEvent(event));
window.addEventListener(event.type, handleCapturedEvent, true);
};
// Not intended to be used with subclasses of MouseEvent
const cloneMouseEvent = (event) => {
let eventToDispatch;
if (document.createEvent) { // IE prevents the use of new MouseEvent(ev.type, ev)
eventToDispatch = document.createEvent('MouseEvent');
eventToDispatch.initMouseEvent(event.type, event.bubbles, event.cancelable, event.view, event.detail, event.screenX, event.screenY, event.clientX, event.clientY, event.ctrlKey, event.altKey, event.shiftKey, event.metaKey, event.button, event.relatedTarget);
}
else {
eventToDispatch = new MouseEvent(event.type, event);
}
const buttonsValue = event.buttons;
if (eventToDispatch.buttons !== buttonsValue)
Object.defineProperty(eventToDispatch, "buttons", { get() { return buttonsValue; } });
return eventToDispatch;
};
}
}
_zoomToPagePoint(zoom, pageX, pageY, ignoreZoomConfigRestrictions = false) {
var workspacePt = CoordinatesConvertUtils.pageToWorkspacePoint(new PointF(pageX, pageY), this, true);
this._zoomToWorkspacePoint(zoom, workspacePt, ignoreZoomConfigRestrictions);
}
_zoomToWorkspacePoint(zoom, workspacePt, ignoreZoomConfigRestrictions = false) {
this._setZoom(zoom, ignoreZoomConfigRestrictions);
var contentPt = CoordinatesConvertUtils.workspaceToContentPoint(workspacePt, this);
var rulerWidth = this.rulerEnabled ? this._rulerWidth : 0;
var scroll = new PointF(Math.round(contentPt.x - ((this._holderBounds.width - rulerWidth) / 2)), Math.round(contentPt.y - ((this._holderBounds.height - rulerWidth) / 2)));
this.scrollingPosition = scroll;
}
_updateViewportAlignment() {
var vl = this.getViewportLocation();
this._contentCtx.style.left = vl.x + "px";
this._contentCtx.style.top = vl.y + "px";
}
/** Gets a scroll bar length (in other words, the right-bottom point of the image fragment which is out of the visible area). */
get scrollingSize() {
var holder = this.element;
var w = holder.scrollWidth - holder.clientWidth;
var h = holder.scrollHeight - holder.clientHeight;
if (w < 0)
w = 0;
if (h < 0)
h = 0;
return new PointF(Math.round(w), Math.round(h));
}
get contentCtx() {
return this._contentCtx;
}
get clientSideOptions() {
/// <value type="ViewerClientSideOptions"><see cref="T:J:ViewerClientSideOptions" /> class instance which provides an access to properties which configure automatic postback for individual events.</value>
/// <summary>Gets values which configure automatic postback for individual events.</summary>
/// <remarks><para>Automatic postback can be enabled for all events with the <see cref="P:J:BaseViewer.autoPostBack" /> property. However if you want to disable automatic postback for certain events (e.g. <see cref="E:J:BaseViewer.zoomed" />) and enable it for the other ones (e.g. <see cref="E:J:BaseViewer.workspaceClick" />), you can use this property. It exposes a boolean property for each event. </para><para>This property makes sense only if <see cref="P:J:BaseViewer.autoPostBack" /> is <b>false</b>. If it is <b>true</b>, postback occurs regardless of values of properties of the <see cref="T:J:ViewerClientSideOptions" /> object.</para><para>This property corresponds to <see cref="P:Aurigma.AjaxControls.BaseViewer.ClientSideOptions">BaseViewer.ClientSideOptions</see> server-side member.</para></remarks>
return this._clientSideOptions;
}
get zoomConfig() {
//console.log("not implemented");
return null;
}
setCursor(cursor, onBody = false) {
this._getElementForCursor().style.cursor = DefaultCursorHelper.toCss(cursor);
if (window != null) {
cursor = onBody === true ? cursor : Cursor.defaultCursor;
if (cursor === this._bodyCursor)
return;
window.document.querySelector("body").style.cursor = DefaultCursorHelper.toCss(cursor);
this._bodyCursor = cursor;
}
}
_getElementForCursor() {
return this._contentCtx;
}
get delayedRefreshTimeout() {
/// <value type="Number" integer="true">The value which represents amount of milliseconds to wait before delayed refresh will be invoked.</value>
/// <summary>Amount of milliseconds to wait before delayed refresh will be invoked.</summary>
return this._delayedRefreshTimeout;
}
set delayedRefreshTimeout(v) {
this._delayedRefreshTimeout = v;
}
/**
* Gets the maximum allowed zoom value.
* @remarks Zoom values are measured in percents/100.
* It means that value = 1 specify 100% zoom (i.e. actual size), value = 10 means 1000% zoom (10x), value = 0,5 means 50% zoom (half), etc.
**/
getMaxZoom() {
return this._maxZoom > 0 ? this._maxZoom : 2.5;
}
setMaxZoom(value) {
this._maxZoom = value;
if (this.zoom > this.getMaxZoom())
this.setZoom(this.getMaxZoom(), null);
}
/**
* Gets the minimum allowed zoom value
* @remarks Zoom values are measured in percents/100.
* It means that value = 1 specify 100% zoom (i.e. actual size), value = 10 means 1000% zoom (10x), value = 0,5 means 50% zoom (half), etc.
*/
get minZoom() {
let minZoom = 0;
if (this.zoomConfig) {
minZoom = this.zoomConfig.min;
}
else {
minZoom = this._minZoom > 0 ? this._minZoom : 0.001;
}
return minZoom;
}
set minZoom(value) {
this._minZoom = value;
if (this.zoom < this.minZoom)
this.setZoom(this.minZoom, null);
}
set screenXDpi(v) {
this._screenXDpi = v;
}
get screenXDpi() {
/// <value type="Number">The value representing horizontal resolution in DPI used to show content in the browser.</value>
/// <summary>Gets a value representing horizontal resolution in DPI used to show content in the browser.</summary>
/// <remarks><para>If the <see cref="P:J:BitmapViewer.scaleToActualSize" /> property is set to <b>true</b> the value of the <see cref="P:J:BaseViewer.screenXDpi" /> property is used to scale content width to its actual size. </para><para>This property corresponds to <see cref="P:Aurigma.AjaxControls.BaseViewer.ScreenXDpi">BaseViewer.ScreenXDpi</see> server-side member.</para></remarks>
return this._screenXDpi;
}
set screenYDpi(v) {
this._screenYDpi = v;
}
get screenYDpi() {
/// <value type="Number">The value representing vertical resolution in DPI used to show content in the browser.</value>
/// <summary>Gets a value representing vertical resolution in DPI used to show content in the browser.</summary>
/// <remarks><para>If the <see cref="P:J:BitmapViewer.scaleToActualSize" /> property is set to <b>true</b> the value of the <see cref="P:J:BaseViewer.screenYDpi" /> property is used to scale content height to its actual size. </para><para>This property corresponds to <see cref="P:Aurigma.AjaxControls.BaseViewer.ScreenYDpi">BaseViewer.ScreenYDpi</see> server-side member.</para></remarks>
return this._screenYDpi;
}
get scrollBarsStyle() {
/// <value type="ScrollBarsStyle">The <see cref="T:J:ScrollBarsStyle" /> enumeration member that specifies when to display scroll bars.</value>
/// <summary>Gets a value that specifies whether to display scroll bars and whether to hide them automatically when the displayed content is less than the control size.</summary>
/// <remarks><para>This property corresponds to <see cref="P:Aurigma.AjaxControls.BaseViewer.ScrollBarsStyle">BaseViewer.ScrollBarsStyle</see> server-side member.</para></remarks>
return this._scrollBarsStyle;
}
set scrollBarsStyle(value) {
this._scrollBarsStyle = value;
}
get scrollBarWidth() {
/// <value type="Number" integer="true">The value that represents a scroll bar width (in pixels) in calculations.</value>
/// <summary>Gets a value that represents a scroll bar width (in pixels) in calculations.</summary>
/// <remarks><para>Since there is no simple way to determine the scroll bar width from the JavaScript (taking into account different platform, accessibility modes, etc) the estimated value is specified by this property.</para>
/// <para>This property corresponds to <see cref="P:Aurigma.AjaxControls.BaseViewer.ScrollBarWidth">BaseViewer.ScrollBarWidth</see> server-side member.</para></remarks>
if (this._actualScrollbarWidth == null) {
var outerWidth = 100;
var outer = document.createElement("div");
outer.style.visibility = "hidden";
outer.style.width = `${outerWidth}px`;
outer.style.overflow = "scroll";
document.body.appendChild(outer);
var inner = document.createElement("div");
inner.style.width = "100%";
outer.appendChild(inner);
this._actualScrollbarWidth = outerWidth - inner.offsetWidth;
outer.remove();
}
return this._actualScrollbarWidth;
}
/** Gets/sets the position of the scroll bars */
get scrollingPosition() {
this._scrollingPosition = this.getActualScrollPosition();
return this._scrollingPosition.round();
}
set scrollingPosition(value) {
var holder = this.element;
holder.scrollLeft = value.x;
holder.scrollTop = value.y;
var pt = this.scrollingPosition;
this._scrollingPosition = new PointF(pt.x, pt.y);
this._scrolledEvent.notify(this);
}
/** Gets/sets a value that specifies content alignment in the control. */
get viewportAlignment() {
return this._viewportAlignment;
}
set viewportAlignment(v) {
this._viewportAlignment = v;
this._updateViewportAlignment();
this._drawRulers();
this._updateRulersStyle();
this._canvas.updateViewport();
}
get zoom() {
return this._zoom;
}
setZoom(zoom, params, ignoreZoomConfigRestrictions = false, withoutUpdate = false) {
var _a, _b;
var zoomCenterX, zoomCenterY;
if (!params) {
var pageCoords = CoordinatesConvertUtils.getElementPageCoord(this.element);
var rulerWidth = this.actualRulerWidth;
var viewportWidth = this._holderBounds.width - rulerWidth, viewportHeight = this._holderBounds.height - rulerWidth;
zoomCenterX = Math.round(pageCoords.left + rulerWidth + viewportWidth / 2);
zoomCenterY = Math.round(pageCoords.top + rulerWidth + viewportHeight / 2);
}
else if (params.skipZoomToCenter) {
this._setZoom(zoom, ignoreZoomConfigRestrictions);
return this._zoom;
}
else {
zoomCenterX = (_a = params.centerPageX) !== null && _a !== void 0 ? _a : params.workspaceX;
zoomCenterY = (_b = params.centerPageY) !== null && _b !== void 0 ? _b : params.workspaceY;
}
if ((params === null || params === void 0 ? void 0 : params.workspaceX) != null) {
this._zoomToWorkspacePoint(zoom, new PointF(zoomCenterX, zoomCenterY), ignoreZoomConfigRestrictions);
}
else {
this._zoomToPagePoint(zoom, zoomCenterX, zoomCenterY, ignoreZoomConfigRestrictions);
}
return this._zoom;
}
_setZoom(value, ignoreZoomConfigRestrictions = false) {
if (this._zoom == value && this._zoomMode == ZoomMode.none)
return;
if (ignoreZoomConfigRestrictions) {
this._zoom = value;
}
else {
this._zoom = Math.min(Math.max(value, this.minZoom), this.getMaxZoom());
}
this._zoomMode = ZoomMode.none;
this._updateViewport(ignoreZoomConfigRestrictions);
}
get pinchZoomEnabled() {
return this._pinchZoomEnabled;
}
set pinchZoomEnabled(v) {
this._pinchZoomEnabled = v;
}
get rulerEnabled() {
return this._rulerEnabled;
}
set rulerEnabled(v) {
var displayStatus = v ? "block" : "none";
this._rulers.fullLeftRuller.style.display = displayStatus;
this._rulers.fullTopRuller.style.display = displayStatus;
this._rulers.leftRuller.style.display = displayStatus;
this._rulers.topRuller.style.display = displayStatus;
this._rulers.whiteRect.style.display = displayStatus;
this._rulerEnabled = v;
this.zoomMode = this.zoomMode;
}
get rulerScale() {
return this._rulerScale;
}
set rulerScale(v) {
if (v <= 0)
throw new Error('Ruler scale should be greater 0.');
this._rulerScale = v;
this._updateViewport();
}
get rulerDivision() {
return this._rulerDivision;
}
set rulerDivision(v) {
if (v <= 0)
throw new Error('Ruler division should be greater 0.');
this._rulerDivision = v;
this._updateViewport();
}
get rulerOffsetX() {
return this._rulerOffsetX;
}
set rulerOffsetX(v) {
this._rulerOffsetX = v;
this._updateViewport();
}
get rulerOffsetY() {
return this._rulerOffsetY;
}
set rulerOffsetY(v) {
this._rulerOffsetY = v;
this._updateViewport();
}
get actualRulerWidth() {
return this.rulerEnabled ? this.rulerWidth : 0;
}
get rulerWidth() {
return this._rulerWidth;
}
set rulerWidth(v) {
this._rulerWidth = v;
this._updateViewport();
}
get zoomMode() {
return this._zoomMode;
}
set zoomMode(v) {
this._setZoomMode(v);
}
_setZoomMode(v) {
this._zoomMode = v;
this._updateViewport();
}
get bestFitWhiteSpacePc() {
/// <summary>Gets or sets white space between content maximal demention and canvas</summary>
/// <value type="Number">white space in percent (from 1 to 99)</value>
return this._bestFitWhiteSpacePc * 100;
}
set bestFitWhiteSpacePc(v) {
if