@syncfusion/ej2-diagrams
Version:
Feature-rich diagram control to create diagrams like flow charts, organizational charts, mind maps, and BPMN diagrams. Its rich feature set includes built-in shapes, editing, serializing, exporting, printing, overview, data binding, and automatic layouts.
907 lines (906 loc) • 42 kB
JavaScript
/* eslint-disable no-case-declarations */
/* eslint-disable @typescript-eslint/indent */
import { Size } from './../primitives/size';
import { Point } from './../primitives/point';
import { processPathData, pathSegmentCollection, getRectanglePath } from './../utility/path-util';
import { overFlow } from './../utility/base-util';
import { createHtmlElement, setChildPosition } from './../utility/dom-util';
import { PathElement } from '../core/elements/path-element';
import { TextElement } from '../core/elements/text-element';
import { ImageElement } from '../core/elements/image-element';
import { ElementAction, FlipDirection } from '../enum/enum';
import { DiagramElement } from '../core/elements/diagram-element';
import { Diagram } from '../diagram';
/**
* Canvas Renderer
*/
/** @private */
var CanvasRenderer = /** @class */ (function () {
function CanvasRenderer() {
}
/**
* Provide the context value for the canvas \
*
* @returns {CanvasRenderingContext2D} Provide the context value for the canvas .\
* @param { HTMLCanvasElement} canvas - Return the dashed array values .
* @private
*/
CanvasRenderer.getContext = function (canvas) {
return canvas.getContext('2d');
};
CanvasRenderer.setCanvasSize = function (canvas, width, height) {
if (canvas) {
canvas.setAttribute('width', width.toString());
canvas.setAttribute('height', height.toString());
}
};
/**
* Draw the gradient for the diagram shapes .\
*
* @returns {SVGElement} Draw the gradient for the diagram shapes.
* @param {StyleAttributes} options - Provide the options for the gradient element .
* @param {SVGElement} ctx - Provide canvas values .
* @param {string} x - Provide the x value for the gradient .
* @param {string} y - Provide the x value for the gradient .
* @private
*/
CanvasRenderer.prototype.renderGradient = function (options, ctx, x, y) {
var max;
var min;
var grd;
if (options.gradient.type !== 'None') {
for (var i = 0; i < options.gradient.stops.length; i++) {
max = max !== undefined ? options.gradient.stops[parseInt(i.toString(), 10)].offset
: Math.max(max, options.gradient.stops[parseInt(i.toString(), 10)].offset);
min = min !== undefined ? options.gradient.stops[parseInt(i.toString(), 10)].offset
: Math.min(min, options.gradient.stops[parseInt(i.toString(), 10)].offset);
}
if (options.gradient.type === 'Linear') {
var linear = options.gradient;
//952013 - Gradient is not rendered correctly upon export
var x1 = linear.x1;
var x2 = linear.x2;
var y1 = linear.y1;
var y2 = linear.y2;
if (linear.controlParent instanceof Diagram && linear.controlParent.mode === 'SVG') {
x1 = options.width ? x1 * options.width / 100 : x1;
x2 = options.width ? x2 * options.width / 100 : x2;
y1 = options.height ? y1 * options.height / 100 : y1;
y2 = options.height ? y2 * options.height / 100 : y2;
if (x1 !== x2 && y1 !== y2) {
var xdistance = x2 - x1;
var ydistance = y2 - y1;
var angleRad = Math.atan2(ydistance, xdistance);
var angleDeg = (angleRad * (180 / Math.PI)) % 360;
angleDeg = angleDeg < 0 ? angleDeg + 360 : angleDeg;
var inverseAngleDeg = 90 - angleDeg;
var inverseAngleRad = inverseAngleDeg * (Math.PI / 180);
var effectiveDistance = (xdistance * Math.sin(angleRad)) + (ydistance * Math.cos(angleRad));
x2 = x1 + effectiveDistance * Math.cos(inverseAngleRad);
y2 = y1 + effectiveDistance * Math.sin(inverseAngleRad);
}
}
grd = ctx.createLinearGradient(x + x1, y + y1, x + x2, y + y2);
}
else {
var radial = options.gradient;
grd = ctx.createRadialGradient(x + radial.fx, y + radial.fy, 0, x + radial.cx, y + radial.cy, radial.r);
}
for (var i = 0; i < options.gradient.stops.length; i++) {
var stop_1 = options.gradient.stops[parseInt(i.toString(), 10)];
var offset = min < 0 ? (max + stop_1.offset) / (2 * max) : stop_1.offset / max;
grd.addColorStop(offset, stop_1.color);
}
ctx.fillStyle = grd;
}
return ctx;
};
/**
* Draw the shawdow for the rectangle shape in diagram \
*
* @returns {void} Draw the shawdow for the rectangle shape in diagram .\
*
* @param { SVGElement} options - Provide the base attributes .
* @param { RectAttributes} canvas - Provide the canvas values .
* @param { string} collection - Provide the collection value.
* @private
*/
CanvasRenderer.prototype.renderShadow = function (options, canvas, collection) {
if (collection === void 0) { collection = null; }
var ctx = CanvasRenderer.getContext(canvas);
ctx.save();
ctx.beginPath();
ctx.strokeStyle = ctx.fillStyle = options.shadow.color;
ctx.globalAlpha = options.shadow.opacity;
var ptModel = { x: 0, y: 0 };
var point = Point.transform(ptModel, options.shadow.angle, options.shadow.distance);
var transX = options.x + point.x;
var transY = options.y + point.y;
var pivotX = transX + options.width * options.pivotX;
var pivotY = transY + options.height * options.pivotY;
this.rotateContext(canvas, options.angle, pivotX, pivotY);
if (collection) {
ctx.translate(transX, transY);
this.renderPath(canvas, options, collection);
ctx.translate(-transX, -transY);
}
else {
ctx.rect(transX, transY, options.width, options.height);
ctx.fillRect(transX, transY, options.width, options.height);
}
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
};
/**
* Create canvas element for the diagram \
*
* @returns {HTMLCanvasElement} Create canvas element for the diagram .\
*
* @param { SVGElement} id - Provide the id for the canvas.
* @param { Object} width - Provide the width for the canvas.
* @param { Object} height - Provide the height for the canvas.
* @private
*/
CanvasRenderer.createCanvas = function (id, width, height) {
var canvasObj = createHtmlElement('canvas', { 'id': id });
this.setCanvasSize(canvasObj, width, height);
return canvasObj;
};
CanvasRenderer.prototype.setStyle = function (canvas, style) {
var ctx = CanvasRenderer.getContext(canvas);
if (style.fill === 'none') {
style.fill = 'transparent';
}
if (style.stroke === 'none') {
style.stroke = 'transparent';
}
ctx.strokeStyle = style.stroke;
ctx.lineWidth = style.strokeWidth;
if (style.strokeWidth === 0) {
ctx.strokeStyle = 'transparent';
}
ctx.globalAlpha = style.opacity;
var dashArray = [];
if (style.dashArray) {
dashArray = this.parseDashArray(style.dashArray);
}
ctx.setLineDash(dashArray);
if (style.gradient && style.gradient.type !== 'None') {
if (style.shapeType === 'Rectangle') {
this.renderGradient(style, ctx, style.x, style.y);
}
else {
this.renderGradient(style, ctx, 0, 0);
}
}
else {
ctx.fillStyle = style.fill;
}
};
CanvasRenderer.prototype.rotateContext = function (canvas, angle, x, y) {
var ctx = CanvasRenderer.getContext(canvas);
ctx.translate(x, y);
ctx.rotate(angle * Math.PI / 180);
ctx.translate(-x, -y);
};
CanvasRenderer.prototype.setFontStyle = function (canvas, text) {
var ctx = CanvasRenderer.getContext(canvas);
var font = '';
if (text.italic) {
font += 'italic ';
}
if (text.bold) {
font += 'bold ';
}
font += (text.fontSize) + 'px ';
font += text.fontFamily;
ctx.font = font;
};
/**
* Return the dashed array values \
*
* @returns {number[]} Return the dashed array values .\
* @param { SVGElement} dashArray - Return the dashed array values .
* @private
*/
CanvasRenderer.prototype.parseDashArray = function (dashArray) {
var dashes = [];
var separator = dashArray.indexOf(' ') !== -1 ? ' ' : ',';
var splittedDashes = dashArray.split(separator);
for (var _i = 0, splittedDashes_1 = splittedDashes; _i < splittedDashes_1.length; _i++) {
var i = splittedDashes_1[_i];
dashes.push(Number(i));
}
return dashes;
};
CanvasRenderer.prototype.drawRoundedRect = function (canvas, options) {
var context = CanvasRenderer.getContext(canvas);
context.beginPath();
var x = options.x;
var y = options.y;
var w = options.width;
var h = options.height;
var mx = x + w / 2;
var my = y + h / 2;
context.beginPath();
this.setStyle(canvas, options);
context.moveTo(x, my);
context.quadraticCurveTo(x, y, mx, y);
context.quadraticCurveTo(x + w, y, x + w, my);
context.quadraticCurveTo(x + w, y + h, mx, y + h);
context.quadraticCurveTo(x, y + h, x, my);
//892454-Fill color not applied for BPMN activity shapes inside the symbol palette.
context.fill();
context.stroke();
};
//Rendering Part
/**
* Draw the Rectangle for the diagram \
*
* @returns {void} Draw the Rectangle for the diagram .\
*
* @param { SVGElement} canvas - Provide the SVG .
* @param { RectAttributes} options - Provide the Rect attributes .
* @param { string} diagramId - Provide the diagram id .
* @param { boolean} isExport - Provide the isExport .
* @param { boolean} isSelector - Provide the selector possobilities .
* @param { SVGSVGElement} parentSvg - Provide the parent svg element .
* @param { Object} ariaLabel - Provide the Arial label attributes .
* @param { boolean} isCircularHandle - Provide the boolean attribute for the circular handle .
* @param { number} enableSelector - Provide the selector possobilities .
* @param { any } renderer - Provide the renderer value .
* @param { any } element - Provide the element value .
* @private
*/
CanvasRenderer.prototype.drawRectangle = function (canvas, options, diagramId, isExport, isSelector, parentSvg, ariaLabel, isCircularHandle, enableSelector, renderer, element) {
if (options.visible === true) {
if (options.cornerRadius) {
if (!isExport && (options.width < 30 || options.height < 30)) {
this.drawRoundedRect(canvas, options);
}
else {
options.data = getRectanglePath(options.cornerRadius, options.height, options.width);
this.drawPath(canvas, options, diagramId, isSelector, parentSvg, ariaLabel, undefined, renderer, element);
}
}
else {
var ctx = CanvasRenderer.getContext(canvas);
if (options.shadow) {
this.renderShadow(options, canvas);
}
ctx.save();
ctx.beginPath();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
var cornerRadius = options.cornerRadius;
var pivotX = options.x + options.width * options.pivotX;
var pivotY = options.y + options.height * options.pivotY;
//To flip the annotation background rect.
if (options.textWrapping && options.wrapBounds) {
this.applyFlipAndRotate(ctx, options, canvas, pivotX, pivotY, renderer, element);
}
else {
var angle = options.isImage ? -options.angle : options.angle;
this.rotateContext(canvas, angle, pivotX, pivotY);
}
this.setStyle(canvas, options);
ctx.rect(options.x, options.y, options.width, options.height);
ctx.fillRect(options.x, options.y, options.width, options.height);
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
}
}
};
// public updateSelectionRegion(canvas: HTMLCanvasElement, options: RectAttributes): void {
// this.drawRectangle(canvas, options);
// }
// public drawLine(canvas: HTMLCanvasElement, options: LineAttributes): void {
// let ctx: CanvasRenderingContext2D = CanvasRenderer.getContext(canvas);
// ctx.save();
// ctx.beginPath();
// let pivotX: number = options.x + options.width * options.pivotX;
// let pivotY: number = options.y + options.height * options.pivotY;
// this.rotateContext(canvas, options.angle, pivotX, pivotY);
// this.setStyle(canvas, options as StyleAttributes);
// ctx.translate(options.x, options.y);
// ctx.moveTo(options.startPoint.x, options.startPoint.y);
// ctx.lineTo(options.endPoint.x, options.endPoint.y);
// ctx.translate(-options.x, -options.y);
// ctx.stroke();
// ctx.closePath();
// ctx.restore();
// }
// public drawCircle(canvas: HTMLCanvasElement, options: CircleAttributes): void {
// let ctx: CanvasRenderingContext2D = CanvasRenderer.getContext(canvas);
// ctx.save();
// ctx.beginPath();
// let pivotY: number = options.y + options.height * options.pivotY;
// let pivotX: number = options.x + options.width * options.pivotX;
// this.setStyle(canvas, options as StyleAttributes);
// this.rotateContext(canvas, options.angle, pivotX, pivotY);
// ctx.arc(options.centerX, options.centerY, options.radius, 0, 2 * Math.PI);
// ctx.fill();
// ctx.stroke();
// ctx.closePath();
// ctx.restore();
// }
/**
* Draw the path element for the diagram\
*
* @returns {void} Draw the path element for the diagram .\
*
* @param { SVGElement} canvas - Provide the SVG element .
* @param { PathAttributes} options - Provide the path element attributes .
* @param {string} diagramId - Provide the diagram id .
* @param {boolean} isSelector - Provide selector boolean value .
* @param {SVGSVGElement} parentSvg - Provide the parent SVG element .
* @param {Object} ariaLabel - Provide arial label value .
* @param {number} scale - Provide the scale value .
* @param {any} renderer - Provide the renderer value .
* @param {PathElement} element - Provide the path element value .
* @private
*/
CanvasRenderer.prototype.drawPath = function (canvas, options, diagramId, isSelector, parentSvg, ariaLabel, scale, renderer, element) {
var collection = [];
collection = processPathData(options.data);
collection = pathSegmentCollection(collection);
if (options.shadow) {
this.renderShadow(options, canvas, collection);
}
var ctx = CanvasRenderer.getContext(canvas);
ctx.save();
ctx.beginPath();
var pivotY = options.y + options.height * options.pivotY;
var pivotX = options.x + options.width * options.pivotX;
this.applyFlipAndRotate(ctx, options, canvas, pivotX, pivotY, renderer, element);
this.setStyle(canvas, options);
ctx.translate(options.x, options.y);
this.renderPath(canvas, options, collection);
ctx.fill();
ctx.translate(-options.x, -options.y);
ctx.stroke();
ctx.restore();
};
/**
* Draw the path element for the diagram\
*
* @returns {void} Draw the path element for the diagram .\
*
* @param { SVGElement} canvas - Provide the SVG element .
* @param {PathAttributes} options - Provide the path element attributes .
* @param {Object[]} collection - Provide the parent SVG element .
* @private
*/
CanvasRenderer.prototype.renderPath = function (canvas, options, collection) {
if (options.visible === true) {
var arcCount = 0;
var ctx = CanvasRenderer.getContext(canvas);
var x0 = void 0;
var y0 = void 0;
var x1 = void 0;
var y1 = void 0;
var x2 = void 0;
var y2 = void 0;
var x = void 0;
var y = void 0;
var length_1;
var i = void 0;
var segs = collection;
for (x = 0, y = 0, i = 0, length_1 = segs.length; i < length_1; ++i) {
var obj = segs[parseInt(i.toString(), 10)];
var seg = obj;
var char = seg.command;
if ('x1' in seg) {
x1 = seg.x1;
}
if ('x2' in seg) {
x2 = seg.x2;
}
if ('y1' in seg) {
y1 = seg.y1;
}
if ('y2' in seg) {
y2 = seg.y2;
}
if ('x' in seg) {
x = seg.x;
}
if ('y' in seg) {
y = seg.y;
}
switch (char) {
case 'M':
ctx.moveTo(x, y);
seg.x = x;
seg.y = y;
break;
case 'L':
ctx.lineTo(x, y);
seg.x = x;
seg.y = y;
break;
case 'C':
ctx.bezierCurveTo(x1, y1, x2, y2, x, y);
seg.x = x;
seg.y = y;
seg.x1 = x1;
seg.y1 = y1;
seg.x2 = x2;
seg.y2 = y2;
break;
case 'Q':
ctx.quadraticCurveTo(x1, y1, x, y);
seg.x = x;
seg.y = y;
seg.x1 = x1;
seg.y1 = y1;
break;
case 'A':
// eslint-disable-next-line
var curr = { x: x0, y: y0 };
var rx = void 0;
var ry = void 0;
if (options.arc && options.arc.length > 0) {
if (seg.r1 === 0) {
rx = options.arc[parseInt(arcCount.toString(), 10)].r1;
}
else {
rx = seg.r1;
}
if (seg.r2 === 0) {
ry = options.arc[parseInt(arcCount.toString(), 10)].r2;
}
else {
ry = seg.r2;
}
arcCount++;
}
else {
rx = seg.r1;
ry = seg.r2;
}
var xAxisRotation = seg.angle * (Math.PI / 180.0);
var largeArc = seg.largeArc;
var sweep = seg.sweep;
var cp = { x: x, y: y };
var currp = {
x: Math.cos(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.sin(xAxisRotation) * (curr.y - cp.y) / 2.0,
y: -Math.sin(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.cos(xAxisRotation) * (curr.y - cp.y) / 2.0
};
var l = Math.pow(currp.x, 2) / Math.pow(rx, 2) + Math.pow(currp.y, 2) / Math.pow(ry, 2);
if (l > 1) {
rx *= Math.sqrt(l);
ry *= Math.sqrt(l);
}
var k = (Math.pow(ry, 2) * Math.pow(currp.x, 2));
var s = (largeArc === sweep ? -1 : 1) * Math.sqrt(((Math.pow(rx, 2) * Math.pow(ry, 2)) - (Math.pow(rx, 2) * Math.pow(currp.y, 2)) - k) /
(Math.pow(rx, 2) * Math.pow(currp.y, 2) + Math.pow(ry, 2) * Math.pow(currp.x, 2)));
if (isNaN(s)) {
s = 0;
}
var cpp = { x: s * rx * currp.y / ry, y: s * -ry * currp.x / rx };
var centp = {
x: (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y,
y: (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y
};
var a1 = this.a([1, 0], [(currp.x - cpp.x) / rx, (currp.y - cpp.y) / ry]);
var u = [(currp.x - cpp.x) / rx, (currp.y - cpp.y) / ry];
var v = [(-currp.x - cpp.x) / rx, (-currp.y - cpp.y) / ry];
var ad = this.a(u, v);
if (this.r(u, v) <= -1) {
ad = Math.PI;
}
if (this.r(u, v) >= 1) {
ad = 0;
}
var dir = !sweep ? -1.0 : 1.0;
var ah = a1 + dir * (ad / 2.0);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
var halfWay = {
x: centp.x + rx * Math.cos(ah),
y: centp.y + ry * Math.sin(ah)
};
seg.centp = centp;
seg.xAxisRotation = xAxisRotation;
seg.rx = rx;
seg.ry = ry;
seg.a1 = a1;
seg.ad = ad;
seg.sweep = sweep;
if (ctx != null) {
var ra = rx > ry ? rx : ry;
var sx = rx > ry ? 1 : rx / ry;
var sy = rx > ry ? ry / rx : 1;
ctx.save();
ctx.translate(centp.x, centp.y);
ctx.rotate(xAxisRotation);
ctx.scale(sx, sy);
ctx.arc(0, 0, ra, a1, a1 + ad, !sweep);
ctx.scale(1 / sx, 1 / sy);
ctx.rotate(-xAxisRotation);
ctx.translate(-centp.x, -centp.y);
ctx.restore();
}
break;
case 'Z':
case 'z':
ctx.closePath();
x = x0;
y = y0;
break;
}
x0 = x;
y0 = y;
}
}
};
/**
* Draw the text element for the diagram\
*
* @returns {void} Draw the text element for the diagram .\
*
* @param { SVGElement} canvas - Provide the SVG element .
* @param {TextAttributes} options - Provide the text element attributes .
* @param {SVGSVGElement} parentSvg - Provide the parent SVG element .
* @param {Object} ariaLabel - Provide the label properties .
* @param {string} diagramId - Provide the diagram id .
* @param {number} scaleValue - Provide the scale value .
* @param {any} renderer - Provide the renderer value .
* @param {element} element - Provide the text element value.
* @private
*/
CanvasRenderer.prototype.drawText = function (canvas, options, parentSvg, ariaLabel, diagramId, scaleValue, renderer, element) {
if (options.content && options.visible === true) {
var parentNode = renderer.groupElement;
var ctx = CanvasRenderer.getContext(canvas);
ctx.save();
this.setStyle(canvas, options);
if (scaleValue) {
options.fontSize *= scaleValue;
}
var pivotX = options.x + options.width * options.pivotX;
var pivotY = options.y + options.height * options.pivotY;
// 919944: Text Flip and Rotation Not Applied in Exported Image
this.applyFlipAndRotate(ctx, options, canvas, pivotX, pivotY, renderer, element);
this.setFontStyle(canvas, options);
var i = 0;
var childNodes = [];
childNodes = options.childNodes;
var wrapBounds = options.wrapBounds;
ctx.fillStyle = options.color;
if (wrapBounds) {
var position = this.labelAlign(options, wrapBounds, childNodes);
for (i = 0; i < childNodes.length; i++) {
var child = childNodes[parseInt(i.toString(), 10)];
child.x = setChildPosition(child, childNodes, i, options);
var offsetX = position.x + (scaleValue ? child.x * scaleValue : child.x) - wrapBounds.x;
var offsetY = position.y + (scaleValue ? child.dy * scaleValue : child.dy) * i + ((options.fontSize) * 0.8);
if (wrapBounds.width > options.width && options.textOverflow !== 'Wrap' && options.textWrapping === 'NoWrap') {
child.text = overFlow(child.text, options);
}
if ((options.textOverflow === 'Clip' || options.textOverflow === 'Ellipsis') && options.textWrapping === 'Wrap') {
if (offsetY < parentNode.actualSize.height + parentNode.bounds.y) {
if (options.textOverflow === 'Ellipsis' && childNodes[i + 1]) {
var temp = childNodes[i + 1];
var y = position.y + temp.dy * (i + 1) + ((options.fontSize) * 0.8);
if (y > parentNode.actualSize.height + parentNode.bounds.y) {
child.text = child.text.slice(0, child.text.length - 3);
child.text = child.text.concat('...');
}
}
ctx.fillText(child.text, offsetX, offsetY);
}
}
else {
ctx.fillText(child.text, offsetX, offsetY);
}
if (options.textDecoration === 'Underline'
|| options.textDecoration === 'Overline'
|| options.textDecoration === 'LineThrough') {
var startPointX = offsetX;
var startPointY = void 0;
var textlength = ctx.measureText(child.text).width;
var endPointX = offsetX + textlength;
var endPointY = void 0;
switch (options.textDecoration) {
case 'Underline':
startPointY = offsetY + 2;
endPointY = offsetY + 2;
break;
case 'Overline':
startPointY = (position.y + child.dy * i);
endPointY = (position.y + child.dy * i);
break;
case 'LineThrough':
startPointY = ((offsetY + position.y + child.dy * i) / 2) + 2;
endPointY = ((offsetY + position.y + child.dy * i) / 2) + 2;
}
ctx.beginPath();
ctx.moveTo(startPointX, startPointY);
ctx.lineTo(endPointX, endPointY);
ctx.strokeStyle = options.color;
ctx.lineWidth = options.fontSize * .08;
ctx.globalAlpha = options.opacity;
ctx.stroke();
}
}
}
ctx.restore();
}
};
// 919944: Flip position and rotate angle calculation for elements
CanvasRenderer.prototype.applyFlipAndRotate = function (ctx, options, canvas, pivotX, pivotY, renderer, element) {
if (options.flip !== FlipDirection.None && renderer && element && !(element.elementActions & ElementAction.ElementIsPort)) {
var parent_1 = renderer.groupElement;
var textWrapper = element;
var transform = void 0;
if ((element instanceof TextElement && element.position)) {
transform = renderer.renderFlipTextElement(parent_1, canvas, textWrapper, options.flip, options.flipMode, true);
}
else if (element instanceof PathElement || element instanceof ImageElement || (element instanceof TextElement
&& !element.position) || element instanceof DiagramElement) {
transform = renderer.renderFlipElement(parent_1, canvas, options.flip, true);
}
transform = this.setElementTransform(element, renderer) || transform;
//To set the translate and scale for the diagram elements while print and export.
if (transform && transform.transform) {
// Parse and apply the transform directly
var transformRegex = /(translate|scale|rotate)\(([^)]+)\)/g;
var match = void 0;
// eslint-disable-next-line no-cond-assign
while ((match = transformRegex.exec(transform.transform)) !== null) {
var type = match[1]; // translate, scale, rotate
var values = match[2].split(',').map(function (v) { return parseFloat(v.trim()); });
switch (type) {
case 'translate': {
var tx = values[0] || 0;
var ty = values[1] || 0;
ctx.translate(tx, ty);
break;
}
case 'scale': {
var sx = values[0] || 1;
var sy = values[1] || sx; // Use uniform scaling if sy is not specified
ctx.scale(sx, sy);
break;
}
}
}
}
}
this.rotateContext(canvas, options.angle, pivotX, pivotY);
};
CanvasRenderer.prototype.setElementTransform = function (element, renderer) {
var eventSuffixes = [
'_cancel_1_event', '_cancel_0_event', '_cancel_2_trigger',
'_success_0_event', '_success_1_event', '_success_2_trigger',
'_failure_0_event', '_failure_1_event', '_failure_2_trigger'
];
// Check if the id ends with the transaction sub type ids.
for (var _i = 0, eventSuffixes_1 = eventSuffixes; _i < eventSuffixes_1.length; _i++) {
var suffix = eventSuffixes_1[_i];
if (element.id.endsWith(suffix)) {
var bounds = renderer.transactionBounds;
var posX = 0;
var posY = 0;
var scaleX = 1;
var scaleY = 1;
var offsetX = 0;
var offsetY = 0;
if (element.flip === 1 || element.flip === 3) {
posX = bounds.center.x;
scaleX = -1;
offsetX = -posX;
}
if (element.flip === 2 || element.flip === 3) {
posY = bounds.center.y;
scaleY = -1;
offsetY = -posY;
}
return {
transform: 'translate(' + posX + ',' + posY + ') scale(' + scaleX + ','
+ scaleY + ') translate(' + offsetX + ',' + offsetY + ')'
};
}
}
return null;
};
CanvasRenderer.prototype.loadImage = function (ctx, obj, canvas, pivotX, pivotY) {
// 919944: Image Node Flip and Rotation Not Applied in Exported Image
var image = new Image();
image.src = obj.source;
this.image(ctx, image, obj.x, obj.y, obj.width, obj.height, obj);
};
/**
* Draw the image element for the diagram\
*
* @returns {void} Draw the image element for the diagram .
* @param { SVGElement | HTMLCanvasElement} canvas - Provide the SVG element .
* @param {ImageAttributes} obj - Provide the image attributes .
* @param {SVGSVGElement} parentSvg - Provide the parent SVG element .
* @param {boolean} fromPalette - Provide the pointer event value .
* @param {any} renderer - provide renderer value
* @param {ImageElement} element - provide image element
* @private
*/
CanvasRenderer.prototype.drawImage = function (canvas, obj, parentSvg, fromPalette, renderer, element) {
var _this = this;
if (obj.visible) {
var ctx_1 = CanvasRenderer.getContext(canvas);
ctx_1.save();
var pivotX_1 = obj.x + obj.width * obj.pivotX;
var pivotY_1 = obj.y + obj.height * obj.pivotY;
var imageObj = new Image();
imageObj.src = obj.source;
// 919867: Opacity for the image node is not applied to the exported image
this.setStyle(canvas, obj);
var id = ctx_1.canvas.id.split('_');
// eslint-disable-next-line
var value = id[id.length - 1] === ('diagram' || 'diagramLayer') ? true : false;
// eslint-disable-next-line
/**
* Since Clipping portion for node with slice option is not calculated properly
* if (obj.sourceX !== undefined && obj.sourceY !== undefined && obj.sourceWidth !== undefined
* && obj.sourceHeight !== undefined) {
* ctx.drawImage(imageObj, obj.sourceX, obj.sourceY, obj.sourceWidth, obj.sourceHeight, obj.x, obj.y, obj.width, obj.height);
* } else {
* ctx.drawImage(imageObj, obj.x, obj.y, obj.width, obj.height);
* }
*/
// 919944: Image Node Flip and Rotation Not Applied in Exported Image
this.applyFlipAndRotate(ctx_1, obj, canvas, pivotX_1, pivotY_1, renderer, element);
if (!fromPalette) {
this.loadImage(ctx_1, obj, canvas, pivotX_1, pivotY_1);
}
else {
imageObj.onload = function () {
_this.loadImage(ctx_1, obj, canvas, pivotX_1, pivotY_1);
};
}
ctx_1.restore();
}
};
CanvasRenderer.prototype.image = function (ctx, image, x, y, width, height, alignOptions) {
ctx.beginPath();
var srcWidth = image.width;
var srcHeight = image.height;
var destinationW = width;
var destinationH = height;
var resultWidth = 0;
var resultHeight = 0;
if (alignOptions && alignOptions.alignment !== 'None') {
var xalign = alignOptions.alignment.toLowerCase().substr(1, 3);
var yalign = alignOptions.alignment.toLowerCase().substr(5, 3);
if (alignOptions.scale === 'Slice') {
// eslint-disable-next-line
var a = function () {
resultWidth = destinationW;
resultHeight = srcHeight * destinationW / srcWidth;
};
// eslint-disable-next-line
var b = function () {
resultWidth = srcWidth * destinationH / srcHeight;
resultHeight = destinationH;
};
if (destinationW > destinationH) {
a();
if (destinationH > resultHeight) {
b();
}
}
else if (destinationW === destinationH) {
if (srcWidth > srcHeight) {
b();
}
else {
a();
}
}
else {
b();
if (destinationW > resultWidth) {
a();
}
}
var x1 = this.getSliceOffset(xalign, resultWidth, destinationW, srcWidth);
var y1 = this.getSliceOffset(yalign, resultHeight, destinationH, srcHeight);
var sWidth = srcWidth - x1;
var sHeight = srcHeight - y1;
var dWidth = resultWidth - (x1 * (resultWidth / srcWidth));
var dHeight = resultHeight - (y1 * (resultHeight / srcHeight));
var canvas1 = createHtmlElement('canvas', { 'width': width.toString(), 'height': height.toString() });
var ctx1 = canvas1.getContext('2d');
ctx1.drawImage(image, x1, y1, sWidth, sHeight, 0, 0, dWidth, dHeight);
ctx.drawImage(canvas1, x, y, width, height);
}
else if (alignOptions.scale === 'Meet') {
var srcRatio = (srcHeight / srcWidth);
var destRatio = (destinationH / destinationW);
resultWidth = destRatio > srcRatio ? destinationW : destinationH / srcRatio;
resultHeight = destRatio > srcRatio ? destinationW * srcRatio : destinationH;
x += this.getMeetOffset(xalign, resultWidth, destinationW);
y += this.getMeetOffset(yalign, resultHeight, destinationH);
ctx.drawImage(image, 0, 0, srcWidth, srcHeight, x, y, resultWidth, resultHeight);
}
else {
ctx.drawImage(image, x, y, width, height);
}
}
else {
ctx.drawImage(image, x, y, width, height);
}
ctx.closePath();
};
CanvasRenderer.prototype.getSliceOffset = function (arg, res, dest, src) {
switch (arg) {
case 'min': return 0;
case 'mid': return (res - dest) / 2 * src / res;
case 'max': return (res - dest) * src / res;
default: return 0;
}
};
CanvasRenderer.prototype.getMeetOffset = function (arg, res, dest) {
var max = Math.max(res, dest);
var min = Math.min(res, dest);
switch (arg) {
case 'min': return 0;
case 'mid': return (max - min) / 2;
case 'max': return max - min;
default: return 0;
}
};
//end region
// vector magnitude
CanvasRenderer.prototype.m = function (v) { return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2)); };
// ratio between two vectors
CanvasRenderer.prototype.r = function (u, v) { return (u[0] * v[0] + u[1] * v[1]) / (this.m(u) * this.m(v)); };
// angle between two vectors
CanvasRenderer.prototype.a = function (u, v) { return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(this.r(u, v)); };
// text utility
/**
* Draw the SVG label.\
*
* @returns {PointModel} Draw the SVG label .
* @param {TextAttributes} text - Provide the canvas element .
* @param {Object} wrapBounds - Provide the canvas element .
* @param {SubTextElement []} childNodes - Provide the canvas element .
* @private
*/
CanvasRenderer.prototype.labelAlign = function (text, wrapBounds, childNodes) {
var bounds = new Size(wrapBounds.width, childNodes.length * (text.fontSize * 1.2));
var position = { x: 0, y: 0 };
var labelX = text.x;
var labelY = text.y;
var offsetx = text.width * 0.5;
var offsety = text.height * 0.5;
var pointx = offsetx;
var pointy = offsety;
if (text.textAlign === 'left') {
pointx = 0;
}
else if (text.textAlign === 'center') {
if (wrapBounds.width > text.width && (text.textOverflow === 'Ellipsis' || text.textOverflow === 'Clip')) {
if (text.textWrapping === 'NoWrap') {
pointx = 0;
}
else {
pointx = text.width * 0.5;
}
}
else {
pointx = text.width * 0.5;
}
}
else if (text.textAlign === 'right') {
pointx = (text.width * 1);
}
position.x = labelX + pointx + (wrapBounds ? wrapBounds.x : 0);
position.y = labelY + pointy - bounds.height / 2;
return position;
};
return CanvasRenderer;
}());
export { CanvasRenderer };