1402 lines
39 KiB
JavaScript
1402 lines
39 KiB
JavaScript
/*
|
||
* (c) Copyright Ascensio System SIA 2010-2024
|
||
*
|
||
* This program is a free software product. You can redistribute it and/or
|
||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||
* version 3 as published by the Free Software Foundation. In accordance with
|
||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||
* of any third-party rights.
|
||
*
|
||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||
*
|
||
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
||
* street, Riga, Latvia, EU, LV-1050.
|
||
*
|
||
* The interactive user interfaces in modified source and object code versions
|
||
* of the Program must display Appropriate Legal Notices, as required under
|
||
* Section 5 of the GNU AGPL version 3.
|
||
*
|
||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||
* grant you any rights under trademark law for use of our trademarks.
|
||
*
|
||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||
* well as technical writing content are licensed under the terms of the
|
||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||
*
|
||
*/
|
||
|
||
"use strict";
|
||
|
||
(function (/** Window */window, undefined) {
|
||
|
||
/*
|
||
* Import
|
||
* -----------------------------------------------------------------------------
|
||
*/
|
||
var FontStyle = AscFonts.FontStyle;
|
||
|
||
var asc = window["Asc"];
|
||
var asc_round = asc.round;
|
||
var asc_floor = asc.floor;
|
||
|
||
function colorObjToAscColor(color) {
|
||
if (!color) {
|
||
return AscCommon.CreateAscColorCustom(0, 0, 0, true);
|
||
}
|
||
|
||
var oRes = null;
|
||
var r = color.getR();
|
||
var g = color.getG();
|
||
var b = color.getB();
|
||
var bTheme = false;
|
||
if (color instanceof AscCommonExcel.ThemeColor && null != color.theme) {
|
||
var array_colors_types = [6, 15, 7, 16, 0, 1, 2, 3, 4, 5];
|
||
var themePresentation = array_colors_types[color.theme];
|
||
var tintExcel = 0;
|
||
if (null != color.tint) {
|
||
tintExcel = color.tint;
|
||
}
|
||
var tintPresentation = 0;
|
||
var basecolor = AscCommonExcel.g_oColorManager.getThemeColor(color.theme);
|
||
var oThemeColorTint = AscCommonExcel.g_oThemeColorsDefaultModsSpreadsheet[AscCommon.GetDefaultColorModsIndex(
|
||
basecolor.getR(), basecolor.getG(), basecolor.getB())];
|
||
if (null != oThemeColorTint) {
|
||
for (var i = 0, length = oThemeColorTint.length; i < length; ++i) {
|
||
var cur = oThemeColorTint[i];
|
||
//0.005 установлено экспериментально
|
||
if (Math.abs(cur - tintExcel) < 0.005) {
|
||
bTheme = true;
|
||
tintPresentation = i;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (bTheme) {
|
||
oRes = new Asc.asc_CColor();
|
||
oRes.r = r;
|
||
oRes.g = g;
|
||
oRes.b = b;
|
||
oRes.a = 255;
|
||
oRes.type = Asc.c_oAscColor.COLOR_TYPE_SCHEME;
|
||
oRes.value = themePresentation;
|
||
}
|
||
}
|
||
if (!bTheme) {
|
||
oRes = AscCommon.CreateAscColorCustom(r, g, b);
|
||
}
|
||
return oRes;
|
||
}
|
||
|
||
var oldPpi = undefined, cvt = undefined;
|
||
|
||
/**
|
||
* Gets ratio to convert units
|
||
* @param {Number} fromUnits Units (0=px, 1=pt, 2=in, 3=mm)
|
||
* @param {Number} toUnits Units (0=px, 1=pt, 2=in, 3=mm)
|
||
* @param {Number} ppi Points per inch
|
||
* @return {Number} Ratio
|
||
*/
|
||
function getCvtRatio(fromUnits, toUnits, ppi) {
|
||
if (ppi !== oldPpi || oldPpi === undefined) {
|
||
var _ppi = 1 / ppi, _72 = 1 / 72, _25_4 = 1 / 25.4;
|
||
cvt = [/* px pt in mm */
|
||
/*px*/[1, 72 * _ppi, _ppi, 25.4 * _ppi], /*pt*/[ppi * _72, 1, _72, 25.4 * _72], /*in*/
|
||
[ppi, 72, 1, 25.4], /*mm*/[ppi * _25_4, 72 * _25_4, _25_4, 1]];
|
||
oldPpi = ppi;
|
||
}
|
||
return cvt[fromUnits][toUnits];
|
||
}
|
||
|
||
/** @const */
|
||
var MATRIX_ORDER_PREPEND = AscCommon.MATRIX_ORDER_PREPEND;
|
||
var MATRIX_ORDER_APPEND = AscCommon.MATRIX_ORDER_APPEND;
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function Matrix() {
|
||
if (!(this instanceof Matrix)) {
|
||
return new Matrix();
|
||
}
|
||
|
||
this.sx = 1.0;
|
||
this.shx = 0.0;
|
||
this.shy = 0.0;
|
||
this.sy = 1.0;
|
||
this.tx = 0.0;
|
||
this.ty = 0.0;
|
||
|
||
return this;
|
||
}
|
||
|
||
Matrix.prototype.reset = function () {
|
||
this.sx = 1.0;
|
||
this.shx = 0.0;
|
||
this.shy = 0.0;
|
||
this.sy = 1.0;
|
||
this.tx = 0.0;
|
||
this.ty = 0.0;
|
||
};
|
||
|
||
Matrix.prototype.assign = function (sx, shx, shy, sy, tx, ty) {
|
||
this.sx = sx;
|
||
this.shx = shx;
|
||
this.shy = shy;
|
||
this.sy = sy;
|
||
this.tx = tx;
|
||
this.ty = ty;
|
||
};
|
||
|
||
Matrix.prototype.copyFrom = function (matrix) {
|
||
this.sx = matrix.sx;
|
||
this.shx = matrix.shx;
|
||
this.shy = matrix.shy;
|
||
this.sy = matrix.sy;
|
||
this.tx = matrix.tx;
|
||
this.ty = matrix.ty;
|
||
};
|
||
|
||
Matrix.prototype.clone = function () {
|
||
var m = new Matrix();
|
||
m.copyFrom(this);
|
||
return m;
|
||
};
|
||
|
||
Matrix.prototype.multiply = function (matrix, order) {
|
||
if (MATRIX_ORDER_PREPEND === order) {
|
||
var m = matrix.clone();
|
||
m.multiply(this, MATRIX_ORDER_APPEND);
|
||
this.copyFrom(m);
|
||
} else {
|
||
var t0 = this.sx * matrix.sx + this.shy * matrix.shx;
|
||
var t2 = this.shx * matrix.sx + this.sy * matrix.shx;
|
||
var t4 = this.tx * matrix.sx + this.ty * matrix.shx + matrix.tx;
|
||
this.shy = this.sx * matrix.shy + this.shy * matrix.sy;
|
||
this.sy = this.shx * matrix.shy + this.sy * matrix.sy;
|
||
this.ty = this.tx * matrix.shy + this.ty * matrix.sy + matrix.ty;
|
||
this.sx = t0;
|
||
this.shx = t2;
|
||
this.tx = t4;
|
||
}
|
||
};
|
||
|
||
Matrix.prototype.translate = function (x, y, order) {
|
||
var m = new Matrix();
|
||
m.tx = x;
|
||
m.ty = y;
|
||
this.multiply(m, order);
|
||
};
|
||
|
||
Matrix.prototype.scale = function (x, y, order) {
|
||
var m = new Matrix();
|
||
m.sx = x;
|
||
m.sy = y;
|
||
this.multiply(m, order);
|
||
};
|
||
|
||
Matrix.prototype.rotate = function (a, order) {
|
||
var m = new Matrix();
|
||
var rad = AscCommon.deg2rad(a);
|
||
m.sx = Math.cos(rad);
|
||
m.shx = Math.sin(rad);
|
||
m.shy = -Math.sin(rad);
|
||
m.sy = Math.cos(rad);
|
||
this.multiply(m, order);
|
||
};
|
||
|
||
Matrix.prototype.rotateAt = function (a, x, y, order) {
|
||
this.translate(-x, -y, order);
|
||
this.rotate(a, order);
|
||
this.translate(x, y, order);
|
||
};
|
||
|
||
Matrix.prototype.determinant = function () {
|
||
return this.sx * this.sy - this.shy * this.shx;
|
||
};
|
||
|
||
Matrix.prototype.invert = function () {
|
||
var det = this.determinant();
|
||
if (0.0001 > det) {
|
||
return;
|
||
}
|
||
var d = 1 / det;
|
||
|
||
var t0 = this.sy * d;
|
||
this.sy = this.sx * d;
|
||
this.shy = -this.shy * d;
|
||
this.shx = -this.shx * d;
|
||
|
||
var t4 = -this.tx * t0 - this.ty * this.shx;
|
||
this.ty = -this.tx * this.shy - this.ty * this.sy;
|
||
|
||
this.sx = t0;
|
||
this.tx = t4;
|
||
};
|
||
|
||
Matrix.prototype.transformPointX = function (x, y) {
|
||
return x * this.sx + y * this.shx + this.tx;
|
||
};
|
||
|
||
Matrix.prototype.transformPointY = function (x, y) {
|
||
return x * this.shy + y * this.sy + this.ty;
|
||
};
|
||
|
||
/** Calculates rotation angle */
|
||
Matrix.prototype.getRotation = function () {
|
||
var x1 = 0.0;
|
||
var y1 = 0.0;
|
||
var x2 = 1.0;
|
||
var y2 = 0.0;
|
||
this.transformPoint(x1, y1);
|
||
this.transformPoint(x2, y2);
|
||
var a = Math.atan2(y2 - y1, x2 - x1);
|
||
return AscCommon.rad2deg(a);
|
||
};
|
||
|
||
/**
|
||
* Creates text metrics
|
||
* -----------------------------------------------------------------------------
|
||
* @constructor
|
||
* @param {Number} width
|
||
* @param {Number} height
|
||
* @param {Number} lineHeight
|
||
* @param {Number} baseline
|
||
* @param {Number} descender
|
||
* @param {Number} fontSize
|
||
* @param {Number} widthBB
|
||
*
|
||
* @memberOf Asc
|
||
*/
|
||
function TextMetrics(width, height, lineHeight, baseline, descender, fontSize, widthBB) {
|
||
this.width = width || 0;
|
||
this.height = height || 0;
|
||
this.lineHeight = lineHeight || 0;
|
||
this.baseline = baseline || 0;
|
||
this.descender = descender || 0;
|
||
this.fontSize = fontSize || 0;
|
||
this.widthBB = widthBB || 0;
|
||
|
||
return this;
|
||
}
|
||
|
||
|
||
/**
|
||
* Creates font metrics
|
||
* -----------------------------------------------------------------------------
|
||
* @constructor
|
||
*
|
||
* @memberOf Asc
|
||
*/
|
||
function FontMetrics() {
|
||
this.ascender = 0;
|
||
this.descender = 0;
|
||
this.lineGap = 0;
|
||
|
||
this.nat_scale = 0;
|
||
this.nat_y1 = 0;
|
||
this.nat_y2 = 0;
|
||
}
|
||
|
||
FontMetrics.prototype.clone = function () {
|
||
var res = new FontMetrics();
|
||
res.ascender = this.ascender;
|
||
res.descender = this.descender;
|
||
res.lineGap = this.lineGap;
|
||
|
||
res.nat_scale = this.nat_scale;
|
||
res.nat_y1 = this.nat_y1;
|
||
res.nat_y2 = this.nat_y2;
|
||
return res;
|
||
};
|
||
|
||
function NativeContext() {
|
||
this.ctx = window["native"];
|
||
}
|
||
|
||
NativeContext.prototype.save = function () {
|
||
this.ctx["PD_Save"]();
|
||
};
|
||
NativeContext.prototype.restore = function () {
|
||
this.ctx["PD_Restore"]();
|
||
};
|
||
NativeContext.prototype.rect = function (x, y, w, h) {
|
||
this.ctx["PD_rect"](x, y, w, h);
|
||
};
|
||
NativeContext.prototype.clip = function () {
|
||
this.ctx["PD_clip"]();
|
||
};
|
||
NativeContext.prototype.fill = function () {
|
||
this.ctx["PD_Fill"]();
|
||
};
|
||
NativeContext.prototype.stroke = function () {
|
||
this.ctx["PD_Stroke"]();
|
||
};
|
||
NativeContext.prototype.fillRect = function (x, y, w, h) {
|
||
this.rect(x, y, w, h);
|
||
this.fill();
|
||
};
|
||
NativeContext.prototype.strokeRect = function (x, y, w, h) {
|
||
this.rect(x, y, w, h);
|
||
this.stroke();
|
||
};
|
||
NativeContext.prototype.beginPath = function () {
|
||
this.ctx["PD_PathStart"]();
|
||
};
|
||
NativeContext.prototype.closePath = function () {
|
||
this.ctx["PD_PathClose"]();
|
||
};
|
||
NativeContext.prototype.moveTo = function (x, y) {
|
||
this.ctx["PD_PathMoveTo"](x, y);
|
||
};
|
||
NativeContext.prototype.lineTo = function (x, y) {
|
||
this.ctx["PD_PathLineTo"](x, y);
|
||
};
|
||
NativeContext.prototype.lineHor = function (x1, y, x2) {
|
||
this.ctx["PD_PathMoveTo"](x1, y);
|
||
this.ctx["PD_PathLineTo"](x2, y);
|
||
};
|
||
NativeContext.prototype.lineVer = function (x, y1, y2) {
|
||
this.ctx["PD_PathMoveTo"](x, y1);
|
||
this.ctx["PD_PathLineTo"](x, y2);
|
||
};
|
||
NativeContext.prototype.bezierCurveTo = function (x1, y1, x2, y2, x3, y3) {
|
||
this.ctx["PD_PathCurveTo"](x1, y1, x2, y2, x3, y3);
|
||
};
|
||
NativeContext.prototype.setStrokeStyle = function (r, g, b, a) {
|
||
this.ctx["PD_p_color"](r, g, b, a * 255);
|
||
};
|
||
NativeContext.prototype.setFillStyle = function (r, g, b, a) {
|
||
this.ctx["PD_b_color1"](r, g, b, a * 255);
|
||
};
|
||
|
||
Object.defineProperty(NativeContext.prototype, "lineWidth", {
|
||
set: function (value) {
|
||
this.ctx["PD_p_width"](value);
|
||
}
|
||
});
|
||
|
||
NativeContext.prototype.clearRect = function (x, y, w, h) {};
|
||
NativeContext.prototype.getImageData = function (sx,sy,sw,sh) {};
|
||
NativeContext.prototype.putImageData = function (image_data,dx,dy,dirtyX,dirtyY,dirtyWidth,dirtyHeight) {};
|
||
|
||
// В текущей реализации используется несколько разных DrawingContext, но ссылающихся на одни и те же
|
||
// FontManager, чтобы разрулить правильное выставление шрифта используем здесь локальные переменные
|
||
let setupFontSize = -1;
|
||
let setupFontName = "";
|
||
let setupFontStyle = -1;
|
||
let setupRotated = false;
|
||
let setupPpiX = -1;
|
||
let setupPpiY = -1;
|
||
|
||
function resetDrawingContextFonts() {
|
||
setupFontSize = -1;
|
||
setupFontName = "";
|
||
setupFontStyle = -1;
|
||
setupRotated = false;
|
||
setupPpiX = -1;
|
||
setupPpiY = -1;
|
||
}
|
||
|
||
/**
|
||
* Emulates scalable canvas context
|
||
* -----------------------------------------------------------------------------
|
||
* @constructor
|
||
* @param {Object} settings Settings : {
|
||
* canvas : HTMLElement
|
||
* units : units (0=px, 1=pt, 2=in, 3=mm)
|
||
* font : AscCommonExcel.Font
|
||
* }
|
||
*
|
||
* @memberOf Asc
|
||
*/
|
||
function DrawingContext(settings) {
|
||
this.canvas = null;
|
||
this.ctx = null;
|
||
|
||
this.setCanvas(settings.canvas);
|
||
|
||
this.textRotated = false;
|
||
this.ppiX = 96;
|
||
this.ppiY = 96;
|
||
this.scaleFactor = 1;
|
||
this._ppiInit();
|
||
|
||
this.LastFontOriginInfo = undefined;
|
||
|
||
this._mct = new Matrix(); // units transform
|
||
this._mt = new Matrix(); // user transform
|
||
this._mbt = new Matrix(); // bound transform
|
||
this._mft = new Matrix(); // full transform
|
||
this._mift = new Matrix(); // inverted full transform
|
||
this._im = new Matrix();
|
||
|
||
this.units = 3/*mm*/;
|
||
this.changeUnits(undefined !== settings.units ? settings.units : this.units);
|
||
|
||
this.fmgrGraphics = undefined !== settings.fmgrGraphics ? settings.fmgrGraphics : null;
|
||
|
||
if (null === this.fmgrGraphics) {
|
||
throw "Can not set graphics in DrawingContext";
|
||
}
|
||
|
||
/** @type AscCommonExcel.Font */
|
||
this.font = undefined !== settings.font ? settings.font : null;
|
||
// Font должен быть передан (он общий для всех DrawingContext, т.к. может возникнуть ситуация как в баге http://bugzilla.onlyoffice.com/show_bug.cgi?id=19784)
|
||
if (null === this.font) {
|
||
throw "Can not set font in DrawingContext";
|
||
}
|
||
|
||
// AscCommon.CColor
|
||
this.fillColor = new AscCommon.CColor(255, 255, 255);
|
||
return this;
|
||
}
|
||
|
||
DrawingContext.prototype._ppiInit = function () {
|
||
this.scaleFactor = 1;
|
||
|
||
if (window["IS_NATIVE_EDITOR"]) {
|
||
this.ppiX = this.ppiY = window["native"]["GetDeviceDPI"]();
|
||
} else {
|
||
this.ppiX = AscCommon.AscBrowser.convertToRetinaValue(96, true);
|
||
this.ppiY = AscCommon.AscBrowser.convertToRetinaValue(96, true);
|
||
}
|
||
};
|
||
|
||
DrawingContext.prototype.toDataURL = function (type) {
|
||
type = type || 'image/png';
|
||
var canvas = this.getCanvas();
|
||
return canvas.toDataURL(type);
|
||
};
|
||
|
||
/**
|
||
* Returns width of drawing context in current units
|
||
* @param {Number} [units] Единицы измерения (0=px, 1=pt, 2=in, 3=mm) в которых будет возвращена ширина
|
||
* @return {Number}
|
||
*/
|
||
DrawingContext.prototype.getWidth = function (units) {
|
||
var i = units >= 0 && units <= 3 ? units : this.units;
|
||
return this.canvas.width * getCvtRatio(0/*px*/, i, this.ppiX);
|
||
};
|
||
|
||
/**
|
||
* Returns height of drawing context in current units
|
||
* @param {Number} [units] Единицы измерения (0=px, 1=pt, 2=in, 3=mm) в которых будет возвращена высота
|
||
* @return {Number}
|
||
*/
|
||
DrawingContext.prototype.getHeight = function (units) {
|
||
var i = units >= 0 && units <= 3 ? units : this.units;
|
||
return this.canvas.height * getCvtRatio(0/*px*/, i, this.ppiY);
|
||
};
|
||
|
||
/**
|
||
* Returns canvas element
|
||
* @type {Element}
|
||
*/
|
||
DrawingContext.prototype.getCanvas = function () {
|
||
return this.canvas;
|
||
};
|
||
|
||
/**
|
||
*
|
||
* @param canvas
|
||
*/
|
||
DrawingContext.prototype.setCanvas = function (canvas) {
|
||
this.canvas = canvas || null;
|
||
this.ctx = window["IS_NATIVE_EDITOR"] ? new NativeContext() : (this.canvas && AscCommon.AscBrowser.getContext2D(this.canvas));
|
||
};
|
||
|
||
/**
|
||
* Returns pixels per inch ratio
|
||
* @type {Number}
|
||
*/
|
||
DrawingContext.prototype.getPPIX = function () {
|
||
return this.ppiX;
|
||
};
|
||
|
||
/**
|
||
* Returns pixels per inch ratio
|
||
* @type {Number}
|
||
*/
|
||
DrawingContext.prototype.getPPIY = function () {
|
||
return this.ppiY;
|
||
};
|
||
|
||
/**
|
||
* Returns currrent units (0=px, 1=pt, 2=in, 3=mm)
|
||
* @type {Number}
|
||
*/
|
||
DrawingContext.prototype.getUnits = function () {
|
||
return this.units;
|
||
};
|
||
|
||
DrawingContext.prototype.moveImageDataSafari = function (sx, sy, w, h, x, y) {
|
||
var sr = this._calcRect(sx, sy, w, h);
|
||
var r = this._calcRect(x, y);
|
||
var imgData = this.ctx.getImageData(sr.x, sr.y, sr.w, sr.h);
|
||
|
||
var minX, maxX, minY, maxY;
|
||
if (sx < x) {
|
||
minX = sr.x;
|
||
maxX = r.x;
|
||
} else {
|
||
minX = r.x;
|
||
maxX = sr.x;
|
||
}
|
||
if (sy < y) {
|
||
minY = sr.y;
|
||
maxY = r.y;
|
||
} else {
|
||
minY = r.y;
|
||
maxY = sr.y;
|
||
}
|
||
this.ctx.clearRect(minX, minY, maxX + sr.w, maxY + sr.h);
|
||
this.ctx.putImageData(imgData, r.x, r.y);
|
||
return this;
|
||
};
|
||
DrawingContext.prototype.moveImageData = function (sx, sy, w, h, x, y) {
|
||
var sr = this._calcRect(sx, sy, w, h);
|
||
var r = this._calcRect(x, y);
|
||
|
||
this.ctx.save();
|
||
this.ctx.globalCompositeOperation = 'copy';
|
||
this.ctx.beginPath();
|
||
this.ctx.rect(r.x, r.y, sr.w, sr.h);
|
||
this.ctx.clip();
|
||
|
||
this.ctx.drawImage(this.getCanvas(), sr.x, sr.y, sr.w, sr.h, r.x, r.y, sr.w, sr.h);
|
||
|
||
this.ctx.restore();
|
||
this.ctx.beginPath();
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Changes units of drawing context
|
||
* @param {Number} units New units of drawing context (0=px, 1=pt, 2=in, 3=mm)
|
||
*/
|
||
DrawingContext.prototype.changeUnits = function (units) {
|
||
var i = units >= 0 && units <= 3 ? units : 0;
|
||
this._mct.sx = getCvtRatio(i, 0/*px*/, this.ppiX);
|
||
this._mct.sy = getCvtRatio(i, 0/*px*/, this.ppiY);
|
||
this._calcMFT();
|
||
this.units = units;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns currrent zoom ratio
|
||
* @type {Number}
|
||
*/
|
||
DrawingContext.prototype.getZoom = function () {
|
||
return this.scaleFactor;
|
||
};
|
||
|
||
/**
|
||
* Changes scale factor of drawing context by changing its PPI
|
||
* @param {Number} factor
|
||
*/
|
||
DrawingContext.prototype.changeZoom = function (factor) {
|
||
if (!factor) {
|
||
factor = this.scaleFactor;
|
||
this._ppiInit();
|
||
}
|
||
|
||
factor = asc_round(factor * 1000) / 1000;
|
||
|
||
this.ppiX = asc_round(this.ppiX / this.scaleFactor * factor * 1000) / 1000;
|
||
this.ppiY = asc_round(this.ppiY / this.scaleFactor * factor * 1000) / 1000;
|
||
this.scaleFactor = factor;
|
||
|
||
// reinitialize
|
||
this.changeUnits(this.units);
|
||
this.setFont(this.font);
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Resets dimensions of drawing context (canvas 'width' and 'height' attributes)
|
||
* @param {Number} width New width in current units
|
||
* @param {Number} height New height in current units
|
||
*/
|
||
DrawingContext.prototype.resetSize = function (width, height) {
|
||
var w = asc_round(width * getCvtRatio(this.units, 0/*px*/, this.ppiX)), h = asc_round(
|
||
height * getCvtRatio(this.units, 0/*px*/, this.ppiY));
|
||
if (w !== this.canvas.width) {
|
||
this.canvas.width = w;
|
||
}
|
||
if (h !== this.canvas.height) {
|
||
this.canvas.height = h;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Expands dimensions of drawing context (canvas 'width' and 'height' attributes)
|
||
* @param {Number} width New width in current units
|
||
* @param {Number} height New height in current units
|
||
*/
|
||
DrawingContext.prototype.expand = function (width, height) {
|
||
var w = asc_round(width * getCvtRatio(this.units, 0/*px*/, this.ppiX)), h = asc_round(
|
||
height * getCvtRatio(this.units, 0/*px*/, this.ppiY));
|
||
if (w > this.canvas.width) {
|
||
this.canvas.width = w;
|
||
}
|
||
if (h > this.canvas.height) {
|
||
this.canvas.height = h;
|
||
}
|
||
return this;
|
||
};
|
||
|
||
// Canvas methods
|
||
|
||
DrawingContext.prototype.clear = function () {
|
||
this.clearRect(0, 0, this.getWidth(), this.getHeight());
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.AddClipRect = function (x, y, w, h) {
|
||
return this.save().beginPath().rect(x, y, w, h).clip();
|
||
};
|
||
|
||
DrawingContext.prototype.RemoveClipRect = function () {
|
||
return this.restore();
|
||
};
|
||
|
||
DrawingContext.prototype.save = function () {
|
||
this.ctx.save();
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.restore = function () {
|
||
this.ctx.restore();
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.scale = function (kx, ky) {
|
||
//TODO: implement scale()
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.rotate = function (a) {
|
||
//TODO: implement rotate()
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.translate = function (dx, dy) {
|
||
//TODO: implement translate()
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.transform = function (sx, shy, shx, sy, tx, ty) {
|
||
//TODO: implement transform()
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.setTransform = function (sx, shy, shx, sy, tx, ty) {
|
||
this._mbt.assign(sx, shx, shy, sy, tx, ty);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.setTextTransform = function (sx, shy, shx, sy, tx, ty) {
|
||
this._mt.assign(sx, shx, shy, sy, tx, ty);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.updateTransforms = function () {
|
||
this._calcMFT();
|
||
this.fmgrGraphics[1].SetTextMatrix(this._mt.sx, this._mt.shy, this._mt.shx, this._mt.sy, this._mt.tx,
|
||
this._mt.ty);
|
||
};
|
||
|
||
DrawingContext.prototype.resetTransforms = function () {
|
||
this.setTransform(this._im.sx, this._im.shy, this._im.shx, this._im.sy, this._im.tx, this._im.ty);
|
||
this.setTextTransform(this._im.sx, this._im.shy, this._im.shx, this._im.sy, this._im.tx, this._im.ty);
|
||
this._calcMFT();
|
||
|
||
if (window["IS_NATIVE_EDITOR"]) {
|
||
window["native"]["PD_transform"](this._im.sx, this._im.shy, this._im.shx, this._im.sy, this._im.tx, this._im.ty);
|
||
}
|
||
};
|
||
|
||
// Style methods
|
||
|
||
DrawingContext.prototype.getFillStyle = function () {
|
||
return this.ctx.fillStyle;
|
||
};
|
||
|
||
DrawingContext.prototype.getStrokeStyle = function () {
|
||
return this.ctx.strokeStyle;
|
||
};
|
||
|
||
DrawingContext.prototype.getLineWidth = function () {
|
||
return this.ctx.lineWidth;
|
||
};
|
||
|
||
DrawingContext.prototype.getLineCap = function () {
|
||
return this.ctx.lineCap;
|
||
};
|
||
|
||
DrawingContext.prototype.getLineJoin = function () {
|
||
return this.ctx.lineJoin;
|
||
};
|
||
|
||
/**
|
||
* @param {AscCommonExcel.RgbColor || AscCommonExcel.ThemeColor || AscCommon.CColor} val
|
||
* @returns {DrawingContext}
|
||
*/
|
||
DrawingContext.prototype.setFillStyle = function (val) {
|
||
var _r = val.getR();
|
||
var _g = val.getG();
|
||
var _b = val.getB();
|
||
var _a = val.getA();
|
||
this.fillColor = new AscCommon.CColor(_r, _g, _b, _a);
|
||
if (this.ctx.fillStyle) {
|
||
this.ctx.fillStyle = "rgba(" + _r + "," + _g + "," + _b + "," + _a + ")";
|
||
} else {
|
||
this.ctx.setFillStyle(_r, _g, _b, _a);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.setFillPattern = function (val) {
|
||
this.ctx.fillStyle = val;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* @param {AscCommonExcel.RgbColor || AscCommonExcel.ThemeColor || AscCommon.CColor} val
|
||
* @returns {DrawingContext}
|
||
*/
|
||
DrawingContext.prototype.setStrokeStyle = function (val) {
|
||
var _r = val.getR();
|
||
var _g = val.getG();
|
||
var _b = val.getB();
|
||
var _a = val.getA();
|
||
if (this.ctx.strokeStyle) {
|
||
this.ctx.strokeStyle = "rgba(" + _r + "," + _g + "," + _b + "," + _a + ")";
|
||
} else {
|
||
this.ctx.setStrokeStyle(_r, _g, _b, _a);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.setLineWidth = function (width) {
|
||
this.ctx.lineWidth = width;
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.setLineCap = function (cap) {
|
||
this.ctx.lineCap = cap;
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.setLineJoin = function (join) {
|
||
this.ctx.lineJoin = join;
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.setLineDash = function (segments) {
|
||
if (this.ctx.setLineDash) {
|
||
this.ctx.setLineDash(segments);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.fillRect = function (x, y, w, h) {
|
||
var r = this._calcRect(x, y, w, h);
|
||
this.ctx.fillRect(r.x, r.y, r.w, r.h);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.strokeRect = function (x, y, w, h) {
|
||
var isEven = 0 !== this.ctx.lineWidth % 2 ? 0.5 : 0;
|
||
var r = this._calcRect(x, y, w, h);
|
||
this.ctx.strokeRect(r.x + isEven, r.y + isEven, r.w, r.h);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.clearRect = function (x, y, w, h) {
|
||
var r = this._calcRect(x, y, w, h);
|
||
this.ctx.clearRect(r.x, r.y, r.w, r.h);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.clearRectByX = function (x, y, w, h) {
|
||
var r = this._calcRect(x, y, w, h);
|
||
this.ctx.clearRect(r.x - 1, r.y, r.w + 1, r.h);
|
||
};
|
||
DrawingContext.prototype.clearRectByY = function (x, y, w, h) {
|
||
var r = this._calcRect(x, y, w, h);
|
||
this.ctx.clearRect(r.x, r.y - 1, r.w, r.h + 1);
|
||
};
|
||
|
||
// Font and text methods
|
||
|
||
DrawingContext.prototype.getFont = function () {
|
||
return this.font.clone();
|
||
};
|
||
|
||
DrawingContext.prototype.getFontSize = function () {
|
||
return this.font.getSize();
|
||
};
|
||
|
||
/**
|
||
* @param {Number} [units] Units of result (0=px, 1=pt, 2=in, 3=mm)
|
||
* @return {FontMetrics}
|
||
*/
|
||
DrawingContext.prototype.getFontMetrics = function (units) {
|
||
var fm = this.fmgrGraphics[3];
|
||
var d = Math.abs(fm.m_lDescender);
|
||
var ppiX = AscCommon.AscBrowser.convertToRetinaValue(96, true);
|
||
|
||
var r = getCvtRatio(0/*px*/, units >= 0 && units <= 3 ? units : this.units, ppiX);
|
||
var r2 = getCvtRatio(1/*pt*/, units >= 0 && units <= 3 ? units : this.units, ppiX);
|
||
var factor = this.getFontSize() * r / fm.m_lUnits_Per_Em;
|
||
|
||
var res = new FontMetrics();
|
||
res.ascender = factor * fm.m_lAscender;
|
||
res.descender = factor * d;
|
||
res.lineGap = factor * (fm.m_lLineHeight - fm.m_lAscender - d);
|
||
|
||
var faceMetrics = fm.m_pFont.cellGetMetrics();
|
||
res.nat_scale = faceMetrics[0];
|
||
res.nat_y1 = faceMetrics[1];
|
||
res.nat_y2 = faceMetrics[2];
|
||
|
||
res.nat_y1 *= r2;
|
||
res.nat_y2 *= r2;
|
||
return res;
|
||
};
|
||
|
||
DrawingContext.prototype.nativeTextDecorationTransform = function(isStart)
|
||
{
|
||
// текст рисуется с трансформом, а strikeout/underline - без (матрица применяется ДО отрисовщика)
|
||
if (isStart)
|
||
window["native"]["PD_transform"](this._im.sx, this._im.shy, this._im.shx, this._im.sy, this._im.tx, this._im.ty);
|
||
else
|
||
window["native"]["PD_transform"](this._mt.sx, this._mt.shy, this._mt.shx, this._mt.sy, this._mt.tx, this._mt.ty);
|
||
};
|
||
|
||
/**
|
||
*
|
||
* @param font
|
||
* @param [angle]
|
||
* @returns {DrawingContext}
|
||
*/
|
||
DrawingContext.prototype.setFont = function (font, angle) {
|
||
|
||
this.font.assign(font);
|
||
|
||
var italic = this.font.getItalic();
|
||
var bold = this.font.getBold();
|
||
var fontStyle;
|
||
if (italic && bold) {
|
||
fontStyle = FontStyle.FontStyleBoldItalic;
|
||
} else if (italic) {
|
||
fontStyle = FontStyle.FontStyleItalic;
|
||
} else if (bold) {
|
||
fontStyle = FontStyle.FontStyleBold;
|
||
} else {
|
||
fontStyle = FontStyle.FontStyleRegular;
|
||
}
|
||
|
||
this.setTextRotated(!!angle);
|
||
this._setFont(this.font.getName(), this.font.getSize(), fontStyle);
|
||
return this;
|
||
};
|
||
|
||
|
||
DrawingContext.prototype._setFont = function(fontName, fontSize, fontStyle) {
|
||
let isRotated = this.textRotated;
|
||
|
||
if (setupFontName === fontName
|
||
&& setupFontSize === fontSize
|
||
&& setupFontStyle === fontStyle
|
||
&& setupPpiX === this.ppiX
|
||
&& setupPpiY === this.ppiY
|
||
&& setupRotated === isRotated) {
|
||
if (!window["IS_NATIVE_EDITOR"]) {
|
||
// disable this optimization (see m_isPassCommands (core-ext))
|
||
return;
|
||
}
|
||
}
|
||
|
||
setupFontSize = fontSize;
|
||
setupFontName = fontName;
|
||
setupFontStyle = fontStyle;
|
||
setupRotated = isRotated;
|
||
setupPpiX = this.ppiX;
|
||
setupPpiY = this.ppiY;
|
||
|
||
this.font.setName(fontName);
|
||
this.font.setSize(fontSize);
|
||
this.font.setBold(fontStyle & FontStyle.FontStyleBold);
|
||
this.font.setItalic(fontStyle & FontStyle.FontStyleItalic);
|
||
|
||
if (window["IS_NATIVE_EDITOR"]) {
|
||
var fontInfo = AscFonts.g_fontApplication.GetFontInfo(fontName, fontStyle, this.LastFontOriginInfo);
|
||
fontInfo = AscCommon.GetLoadInfoForMeasurer(fontInfo, fontStyle);
|
||
|
||
var flag = 0;
|
||
if (fontInfo.NeedBold) {
|
||
flag |= 0x01;
|
||
}
|
||
if (fontInfo.NeedItalic) {
|
||
flag |= 0x02;
|
||
}
|
||
if (fontInfo.SrcBold) {
|
||
flag |= 0x04;
|
||
}
|
||
if (fontInfo.SrcItalic) {
|
||
flag |= 0x08;
|
||
}
|
||
|
||
// выставляем шрифт и отрисовщику...
|
||
var drawFontSize = fontSize * this.scaleFactor * 96.0 / 25.4;
|
||
window["native"]["PD_LoadFont"](fontInfo.Path, fontInfo.FaceIndex, drawFontSize, flag);
|
||
|
||
// на отрисовке ячейки трансформ выставляется/сбрасывается. так что тут - только если есть angle
|
||
if (isRotated)
|
||
window["native"]["PD_transform"](this._mt.sx, this._mt.shy, this._mt.shx, this._mt.sy, this._mt.tx, this._mt.ty);
|
||
|
||
// ...и измерятелю
|
||
AscFonts.g_fontApplication.LoadFont(fontName, AscCommon.g_font_loader, this.fmgrGraphics[3], fontSize, fontStyle, this.ppiX, this.ppiY);
|
||
} else {
|
||
let r;
|
||
if (isRotated) {
|
||
r = AscFonts.g_fontApplication.LoadFont(fontName, AscCommon.g_font_loader, this.fmgrGraphics[1], fontSize, fontStyle, this.ppiX, this.ppiY);
|
||
} else {
|
||
r = AscFonts.g_fontApplication.LoadFont(fontName, AscCommon.g_font_loader, this.fmgrGraphics[0], fontSize, fontStyle, this.ppiX, this.ppiY);
|
||
AscFonts.g_fontApplication.LoadFont(fontName, AscCommon.g_font_loader, this.fmgrGraphics[3], fontSize, fontStyle, this.ppiX, this.ppiY);
|
||
}
|
||
|
||
if (isRotated) {
|
||
this.fmgrGraphics[1].SetTextMatrix(this._mt.sx, this._mt.shy, this._mt.shx, this._mt.sy, this._mt.tx, this._mt.ty);
|
||
}
|
||
|
||
if (r === false) {
|
||
throw "Can not use " + fontName + " font. (Check whether font file is loaded)";
|
||
}
|
||
}
|
||
|
||
};
|
||
|
||
DrawingContext.prototype.SetFontInternal = function(name, size, style) {
|
||
this._setFont(name, size, style);
|
||
};
|
||
|
||
DrawingContext.prototype.setTextRotated = function(isRotated) {
|
||
this.textRotated = isRotated;
|
||
};
|
||
|
||
/**
|
||
* Returns dimensions of first char of string
|
||
* @param {String} text Character to measure
|
||
* @param {Number} units Units (0 = px, 1 = pt, 2 = in, 3 = mm)
|
||
* @return {TextMetrics} Returns the char dimension
|
||
*/
|
||
DrawingContext.prototype.measureChar = function (text, units, code) {
|
||
return this.measureText(text ? text.charAt(0) : null, units, [code]);
|
||
};
|
||
|
||
/**
|
||
* Returns dimensions of string
|
||
* @param {String} text String to measure
|
||
* @param {Number} units Units (0 = px, 1 = pt, 2 = in, 3 = mm)
|
||
* @return {TextMetrics} Returns the dimension of string {width: w, height: h}
|
||
*/
|
||
DrawingContext.prototype.measureText = function (text, units, aCodes) {
|
||
var code;
|
||
var fm = this.fmgrGraphics[3];
|
||
var r = getCvtRatio(0/*px*/, units >= 0 && units <= 3 ? units : this.units, this.ppiX);
|
||
var textLength = aCodes ? aCodes.length : text.length;
|
||
for (var tmp, w = 0, w2 = 0, i = 0; i < textLength; ++i) {
|
||
code = aCodes ? aCodes[i] : text.charCodeAt(i);
|
||
// Replace Non-breaking space(0xA0) with White-space(0x20)
|
||
tmp = fm.MeasureChar(0xA0 === code ? 0x20 : code);
|
||
w += asc_round(tmp.fAdvanceX); // ToDo скачет при wrap в ячейке и zoom
|
||
}
|
||
w2 = w - tmp.fAdvanceX + tmp.oBBox.fMaxX - tmp.oBBox.fMinX + 1;
|
||
return this._calcTextMetrics(w * r, w2 * r, fm, r);
|
||
};
|
||
|
||
DrawingContext.prototype.fillGlyph = function (pGlyph, fmgr) {
|
||
var nW = pGlyph.oBitmap.nWidth;
|
||
var nH = pGlyph.oBitmap.nHeight;
|
||
|
||
if (!(nW > 0 && nH > 0)) {
|
||
return;
|
||
}
|
||
|
||
var nX = asc_floor(fmgr.m_oGlyphString.m_fX + pGlyph.fX + pGlyph.oBitmap.nX);
|
||
var nY = asc_floor(fmgr.m_oGlyphString.m_fY + pGlyph.fY - pGlyph.oBitmap.nY);
|
||
|
||
var _r = this.fillColor.r;
|
||
var _g = this.fillColor.g;
|
||
var _b = this.fillColor.b;
|
||
|
||
pGlyph.oBitmap.oGlyphData.checkColor(_r, _g, _b, nW, nH);
|
||
pGlyph.oBitmap.draw(this.ctx, nX, nY);
|
||
};
|
||
|
||
DrawingContext.prototype.fillText = function (text, x, y, maxWidth, charWidths, angle) {
|
||
var code, pGlyph;
|
||
var manager = angle ? this.fmgrGraphics[1] : this.fmgrGraphics[0];
|
||
|
||
var _x = this._mift.transformPointX(x, y);
|
||
var _y = this._mift.transformPointY(x, y);
|
||
|
||
var length = text.length;
|
||
for (var i = 0; i < length; ++i) {
|
||
code = text.charCodeAt ? text.charCodeAt(i) : text[i];
|
||
// Replace Non-breaking space(0xA0) with White-space(0x20)
|
||
code = 0xA0 === code ? 0x20 : code;
|
||
if (window["IS_NATIVE_EDITOR"]) {
|
||
window["native"]["PD_FillText"](_x, _y, code);
|
||
// убрать это!!! все сдвиги ДОЛЖНЫ быть вщять из измерятеля/шейпера
|
||
_x += asc_round((this.measureChar(undefined, 3, code).width) * this.scaleFactor * 96.0 / 25.4);
|
||
} else {
|
||
_x = asc_round(manager.LoadString4C(code, _x, _y));
|
||
pGlyph = manager.m_oGlyphString.m_pGlyphsBuffer[0];
|
||
if (null === pGlyph || null === pGlyph.oBitmap) {
|
||
continue;
|
||
}
|
||
|
||
this.fillGlyph(pGlyph, manager);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.fillTextCode = function (text, x, y, maxWidth, charWidths, angle) {
|
||
return this.fillText(text, x, y, maxWidth, charWidths, angle);
|
||
};
|
||
|
||
DrawingContext.prototype.tg = function(gid, x, y, codePoints) {
|
||
|
||
var _x = this._mift.transformPointX(x, y);
|
||
var _y = this._mift.transformPointY(x, y);
|
||
|
||
if (window["IS_NATIVE_EDITOR"]) {
|
||
window["native"]["PD_FillTextG"](_x, _y, gid);
|
||
} else {
|
||
let fontManager = this.textRotated ? this.fmgrGraphics[1] : this.fmgrGraphics[0];
|
||
try {
|
||
fontManager.LoadString3C(gid, _x, _y, codePoints);
|
||
}
|
||
catch(err){}
|
||
|
||
let glyph = fontManager.m_oGlyphString.m_pGlyphsBuffer[0];
|
||
if (!glyph || !glyph.oBitmap)
|
||
return this;
|
||
|
||
this.fillGlyph(glyph, fontManager);
|
||
}
|
||
return this;
|
||
};
|
||
|
||
// Path methods
|
||
|
||
DrawingContext.prototype.beginPath = function () {
|
||
this.ctx.beginPath();
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.closePath = function () {
|
||
this.ctx.closePath();
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.moveTo = function (x, y) {
|
||
var r = this._calcRect(x, y);
|
||
this.ctx.moveTo(r.x, r.y);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.lineTo = function (x, y) {
|
||
var r = this._calcRect(x, y);
|
||
this.ctx.lineTo(r.x, r.y);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.lineDiag = function (x1, y1, x2, y2) {
|
||
var isEven = 0 !== this.ctx.lineWidth % 2 ? 0.5 : 0;
|
||
var r1 = this._calcRect(x1, y1);
|
||
var r2 = this._calcRect(x2, y2);
|
||
this.ctx.moveTo(r1.x + isEven, r1.y + isEven);
|
||
this.ctx.lineTo(r2.x + isEven, r2.y + isEven);
|
||
return this;
|
||
};
|
||
DrawingContext.prototype.lineHor = function (x1, y, x2) {
|
||
var isEven = 0 !== this.ctx.lineWidth % 2 ? 0.5 : 0;
|
||
var r1 = this._calcRect(x1, y);
|
||
var r2 = this._calcRect(x2, y);
|
||
this.ctx.moveTo(r1.x, r1.y + isEven);
|
||
this.ctx.lineTo(r2.x, r2.y + isEven);
|
||
return this;
|
||
};
|
||
DrawingContext.prototype.lineVer = function (x, y1, y2) {
|
||
var isEven = 0 !== this.ctx.lineWidth % 2 ? 0.5 : 0;
|
||
var r1 = this._calcRect(x, y1);
|
||
var r2 = this._calcRect(x, y2);
|
||
this.ctx.moveTo(r1.x + isEven, r1.y);
|
||
this.ctx.lineTo(r2.x + isEven, r2.y);
|
||
return this;
|
||
};
|
||
|
||
// Отрисовка на 1px меньше
|
||
DrawingContext.prototype.lineHorPrevPx = function (x1, y, x2) {
|
||
var isEven = (0 !== this.ctx.lineWidth % 2 ? 0.5 : 0) - 1;
|
||
var r1 = this._calcRect(x1, y);
|
||
var r2 = this._calcRect(x2, y);
|
||
this.ctx.moveTo(r1.x, r1.y + isEven);
|
||
this.ctx.lineTo(r2.x, r2.y + isEven);
|
||
return this;
|
||
};
|
||
DrawingContext.prototype.lineVerPrevPx = function (x, y1, y2) {
|
||
var isEven = (0 !== this.ctx.lineWidth % 2 ? 0.5 : 0) - 1;
|
||
var r1 = this._calcRect(x, y1);
|
||
var r2 = this._calcRect(x, y2);
|
||
this.ctx.moveTo(r1.x + isEven, r1.y);
|
||
this.ctx.lineTo(r2.x + isEven, r2.y);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.dashLineCleverHor = function (x1, y, x2) {
|
||
var isEven = 0 !== this.ctx.lineWidth % 2 ? 0.5 : 0;
|
||
var w_dot = AscCommonExcel.c_oAscCoAuthoringDottedWidth, w_dist = AscCommonExcel.c_oAscCoAuthoringDottedDistance;
|
||
var _x1 = this._mct.transformPointX(x1, y);
|
||
var _y = this._mct.transformPointY(x1, y) - 1;
|
||
var _x2 = this._mct.transformPointX(x2, y);
|
||
var ctx = this.ctx;
|
||
|
||
_x1 = (_x1 >> 0);
|
||
_y = (_y >> 0) + isEven;
|
||
_x2 = (_x2 >> 0);
|
||
|
||
for (; _x1 < _x2; _x1 += w_dist) {
|
||
ctx.moveTo(_x1, _y);
|
||
_x1 += w_dot;
|
||
|
||
if (_x1 > _x2) {
|
||
_x1 = _x2;
|
||
}
|
||
|
||
ctx.lineTo(_x1, _y);
|
||
}
|
||
};
|
||
DrawingContext.prototype.dashLineCleverVer = function (x, y1, y2) {
|
||
var isEven = 0 !== this.ctx.lineWidth % 2 ? 0.5 : 0;
|
||
var w_dot = AscCommonExcel.c_oAscCoAuthoringDottedWidth, w_dist = AscCommonExcel.c_oAscCoAuthoringDottedDistance;
|
||
var _y1 = this._mct.transformPointY(x, y1);
|
||
var _x = this._mct.transformPointX(x, y1) - 1;
|
||
var _y2 = this._mct.transformPointY(x, y2);
|
||
var ctx = this.ctx;
|
||
|
||
_y1 = (_y1 >> 0);
|
||
_x = (_x >> 0) + isEven;
|
||
_y2 = (_y2 >> 0);
|
||
|
||
for (; _y1 < _y2; _y1 += w_dist) {
|
||
ctx.moveTo(_x, _y1);
|
||
_y1 += w_dot;
|
||
|
||
if (_y1 > _y2) {
|
||
_y1 = _y2;
|
||
}
|
||
|
||
ctx.lineTo(_x, _y1);
|
||
}
|
||
};
|
||
|
||
DrawingContext.prototype.dashLine = function (x1, y1, x2, y2, w_dot, w_dist) {
|
||
var len = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
|
||
if (len < 1) {
|
||
len = 1;
|
||
}
|
||
|
||
var len_x1 = Math.abs(w_dot * (x2 - x1) / len);
|
||
var len_y1 = Math.abs(w_dot * (y2 - y1) / len);
|
||
var len_x2 = Math.abs(w_dist * (x2 - x1) / len);
|
||
var len_y2 = Math.abs(w_dist * (y2 - y1) / len);
|
||
var i, j;
|
||
|
||
if (x1 <= x2 && y1 <= y2) {
|
||
for (i = x1, j = y1; i < x2 || j < y2; i += len_x2, j += len_y2) {
|
||
this.moveTo(i, j);
|
||
|
||
i += len_x1;
|
||
j += len_y1;
|
||
|
||
if (i > x2) {
|
||
i = x2;
|
||
}
|
||
if (j > y2) {
|
||
j = y2;
|
||
}
|
||
|
||
this.lineTo(i, j);
|
||
}
|
||
} else if (x1 <= x2 && y1 > y2) {
|
||
for (i = x1, j = y1; i < x2 || j > y2; i += len_x2, j -= len_y2) {
|
||
this.moveTo(i, j);
|
||
|
||
i += len_x1;
|
||
j -= len_y1;
|
||
|
||
if (i > x2) {
|
||
i = x2;
|
||
}
|
||
if (j < y2) {
|
||
j = y2;
|
||
}
|
||
|
||
this.lineTo(i, j);
|
||
}
|
||
} else if (x1 > x2 && y1 <= y2) {
|
||
for (i = x1, j = y1; i > x2 || j < y2; i -= len_x2, j += len_y2) {
|
||
this.moveTo(i, j);
|
||
|
||
i -= len_x1;
|
||
j += len_y1;
|
||
|
||
if (i < x2) {
|
||
i = x2;
|
||
}
|
||
if (j > y2) {
|
||
j = y2;
|
||
}
|
||
|
||
this.lineTo(i, j);
|
||
}
|
||
} else {
|
||
for (i = x1, j = y1; i > x2 || j > y2; i -= len_x2, j -= len_y2) {
|
||
this.moveTo(i, j);
|
||
|
||
i -= len_x1;
|
||
j -= len_y1;
|
||
|
||
if (i < x2) {
|
||
i = x2;
|
||
}
|
||
if (j < y2) {
|
||
j = y2;
|
||
}
|
||
|
||
this.lineTo(i, j);
|
||
}
|
||
}
|
||
};
|
||
|
||
DrawingContext.prototype.dashRect = function (x1, y1, x2, y2, x3, y3, x4, y4, w_dot, w_dist) {
|
||
this.dashLine(x1, y1, x2, y2, w_dot, w_dist);
|
||
this.dashLine(x2, y2, x4, y4, w_dot, w_dist);
|
||
this.dashLine(x4, y4, x3, y3, w_dot, w_dist);
|
||
this.dashLine(x3, y3, x1, y1, w_dot, w_dist);
|
||
};
|
||
|
||
DrawingContext.prototype.rect = function (x, y, w, h) {
|
||
var r = this._calcRect(x, y, w, h);
|
||
this.ctx.rect(r.x, r.y, r.w, r.h);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.arc = function (x, y, radius, startAngle, endAngle, antiClockwise, dx, dy) {
|
||
var r = this._calcRect(x, y);
|
||
dx = typeof dx !== "undefined" ? dx : 0;
|
||
dy = typeof dy !== "undefined" ? dy : 0;
|
||
this.ctx.arc(r.x + dx, r.y + dy, radius, startAngle, endAngle, antiClockwise);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.bezierCurveTo = function (x1, y1, x2, y2, x3, y3) {
|
||
var p1 = this._calcRect(x1, y1), p2 = this._calcRect(x2, y2), p3 = this._calcRect(x3, y3);
|
||
this.ctx.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.fill = function () {
|
||
this.ctx.fill();
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.stroke = function () {
|
||
this.ctx.stroke();
|
||
return this;
|
||
};
|
||
|
||
DrawingContext.prototype.clip = function () {
|
||
this.ctx.clip();
|
||
return this;
|
||
};
|
||
|
||
// Image methods
|
||
DrawingContext.prototype.drawImage = function (img, sx, sy, sw, sh, dx, dy, dw, dh) {
|
||
var sr = this._calcRect(sx, sy, sw, sh), dr = this._calcRect(dx, dy, dw, dh);
|
||
this.ctx.drawImage(img, sr.x, sr.y, sr.w, sr.h, dr.x, dr.y, dr.w, dr.h);
|
||
return this;
|
||
};
|
||
|
||
// Private methods
|
||
DrawingContext.prototype._calcRect = function (x, y, w, h) {
|
||
var wh = w !== undefined && h !== undefined, x2 = x + w, y2 = y + h, _x = this._mft.transformPointX(x,
|
||
y), _y = this._mft.transformPointY(x, y);
|
||
return {
|
||
x: asc_round(_x),
|
||
y: asc_round(_y),
|
||
w: wh ? asc_round(this._mft.transformPointX(x2, y2) - _x) : undefined,
|
||
h: wh ? asc_round(this._mft.transformPointY(x2, y2) - _y) : undefined
|
||
};
|
||
};
|
||
|
||
DrawingContext.prototype._calcMFT = function () {
|
||
this._mft = this._mct.clone();
|
||
this._mft.multiply(this._mbt, MATRIX_ORDER_PREPEND);
|
||
this._mft.multiply(this._mt, MATRIX_ORDER_PREPEND);
|
||
|
||
this._mift = this._mt.clone();
|
||
this._mift.invert();
|
||
this._mift.multiply(this._mft, MATRIX_ORDER_PREPEND);
|
||
};
|
||
|
||
/**
|
||
* @param {Number} w Ширина текста
|
||
* @param {Number} wBB Ширина Bound Box текста
|
||
* @param {AscFonts.CFontManager} fm Объект AscFonts.CFontManager для получения метрик шрифта
|
||
* @param {Number} r Коэффициент перевода pt -> в текущие единицы измерения (this.units)
|
||
* @return {TextMetrics}
|
||
*/
|
||
DrawingContext.prototype._calcTextMetrics = function (w, wBB, fm, r) {
|
||
var factor = this.getFontSize() * r / fm.m_lUnits_Per_Em, l = fm.m_lLineHeight * factor, b = fm.m_lAscender *
|
||
factor, d = Math.abs(fm.m_lDescender * factor);
|
||
return new TextMetrics(w, b + d, l, b, d, this.font.getSize(), wBB);
|
||
};
|
||
|
||
|
||
/*
|
||
* Export
|
||
* -----------------------------------------------------------------------------
|
||
*/
|
||
|
||
window['Asc'] = window['Asc'] || {};
|
||
window["Asc"].getCvtRatio = getCvtRatio;
|
||
window["Asc"].colorObjToAscColor = colorObjToAscColor;
|
||
|
||
window["Asc"].TextMetrics = TextMetrics;
|
||
window["Asc"].FontMetrics = FontMetrics;
|
||
window["Asc"].DrawingContext = DrawingContext;
|
||
window["Asc"].Matrix = Matrix;
|
||
|
||
window['AscCommonExcel'] = window['AscCommonExcel'] || {};
|
||
window["AscCommonExcel"].resetDrawingContextFonts = resetDrawingContextFonts;
|
||
|
||
})(window);
|