Commit addf2669 authored by GoshaZotov's avatar GoshaZotov Committed by GitHub

Merge pull request #90 from ONLYOFFICE/Feature/3d_perspective_pie

Feature/3d perspective pie
parents 3328c59d d621e895
...@@ -90,11 +90,10 @@ function Processor3D(width, height, left, right, bottom, top, chartSpace, charts ...@@ -90,11 +90,10 @@ function Processor3D(width, height, left, right, bottom, top, chartSpace, charts
this.angleOy = this.view3D && this.view3D.rotY ? (- this.view3D.rotY / 360) * (Math.PI * 2) : 0; this.angleOy = this.view3D && this.view3D.rotY ? (- this.view3D.rotY / 360) * (Math.PI * 2) : 0;
this.angleOz = this.view3D && this.view3D.rotZ ? (- this.view3D.rotZ / 360) * (Math.PI * 2) : 0; this.angleOz = this.view3D && this.view3D.rotZ ? (- this.view3D.rotZ / 360) * (Math.PI * 2) : 0;
/*if(this.view3D.rAngAx && this.view3D.rotX < 0) if(!this.view3D.rAngAx && AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type)
{ {
this.angleOx = - this.angleOx; this.angleOy = 0;
this.angleOy = - this.angleOy; }
}*/
this.orientationCatAx = null; this.orientationCatAx = null;
this.orientationValAx = null; this.orientationValAx = null;
...@@ -139,6 +138,55 @@ Processor3D.prototype.calaculate3DProperties = function(baseDepth, gapDepth, bIs ...@@ -139,6 +138,55 @@ Processor3D.prototype.calaculate3DProperties = function(baseDepth, gapDepth, bIs
this._recalculateScaleWithMaxWidth(); this._recalculateScaleWithMaxWidth();
} }
} }
if(AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type && !this.view3D.rAngAx)
{
//TODO пересмотреть функцию
this.tempChangeAspectRatioForPie();
}
};
Processor3D.prototype.tempChangeAspectRatioForPie = function()
{
var perspectiveDepth = this.depthPerspective;
var widthCanvas = this.widthCanvas;
var originalWidthChart = widthCanvas - this.left - this.right;
var heightCanvas = this.heightCanvas;
var heightChart = heightCanvas - this.top - this.bottom;
var points = [], faces = [];
points.push(new Point3D(this.left + originalWidthChart / 2, this.top, perspectiveDepth, this));
points.push(new Point3D(this.left, this.top, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart, this.top, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top, 0, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, perspectiveDepth, this));
points.push(new Point3D(this.left, this.top + heightChart, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart, this.top + heightChart, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, 0, this));
faces.push([0,1,2,3]);
faces.push([2,5,4,3]);
faces.push([1,6,7,0]);
faces.push([6,5,4,7]);
faces.push([7,4,3,0]);
faces.push([1,6,2,5]);
var minMaxOx = this._getMinMaxOx(points, faces);
var minMaxOy = this._getMinMaxOy(points, faces);
var kF = ((minMaxOx.right - minMaxOx.left) / originalWidthChart);
if((minMaxOy.bottom - minMaxOy.top) / kF > heightChart)
{
kF = ((minMaxOy.bottom - minMaxOy.top) / heightChart);
}
this.aspectRatioX = this.aspectRatioX * kF;
this.aspectRatioY = this.aspectRatioY * kF;
this.aspectRatioZ = this.aspectRatioZ * kF;
}; };
Processor3D.prototype.calculateCommonOptions = function() Processor3D.prototype.calculateCommonOptions = function()
...@@ -157,6 +205,13 @@ Processor3D.prototype._calculateAutoHPercent = function() ...@@ -157,6 +205,13 @@ Processor3D.prototype._calculateAutoHPercent = function()
this.hPercent = this.view3D.hPercent === null ? (heightLine / widthLine) : this.view3D.hPercent / 100; this.hPercent = this.view3D.hPercent === null ? (heightLine / widthLine) : this.view3D.hPercent / 100;
if(this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && ((this.view3D.hPercent === null && this.view3D.rAngAx) || (this.view3D.hPercent !== null && !this.view3D.rAngAx))) if(this.chartsDrawer.calcProp.type === AscFormat.c_oChartTypes.HBar && ((this.view3D.hPercent === null && this.view3D.rAngAx) || (this.view3D.hPercent !== null && !this.view3D.rAngAx)))
this.hPercent = 1 / this.hPercent; this.hPercent = 1 / this.hPercent;
if(AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type)
{
this.hPercent = 0.12;
//this.view3D.depthPercent = 180;
}
} }
}; };
...@@ -1107,6 +1162,12 @@ Processor3D.prototype._calculateDepthPerspective = function() ...@@ -1107,6 +1162,12 @@ Processor3D.prototype._calculateDepthPerspective = function()
var gapWidth = this.chartSpace.chart.plotArea.chart.gapWidth != null ? (this.chartSpace.chart.plotArea.chart.gapWidth / 100) : (150 / 100); var gapWidth = this.chartSpace.chart.plotArea.chart.gapWidth != null ? (this.chartSpace.chart.plotArea.chart.gapWidth / 100) : (150 / 100);
var gapDepth = this.chartSpace.chart.plotArea.chart.gapDepth != null ? (this.chartSpace.chart.plotArea.chart.gapDepth / 100) : (150 / 100); var gapDepth = this.chartSpace.chart.plotArea.chart.gapDepth != null ? (this.chartSpace.chart.plotArea.chart.gapDepth / 100) : (150 / 100);
if(AscFormat.c_oChartTypes.Area === this.chartsDrawer.calcProp.type)
{
gapWidth = 0;
gapDepth = 0;
}
var baseDepth = width / (seriesCount - (seriesCount - 1) * overlap + gapWidth); var baseDepth = width / (seriesCount - (seriesCount - 1) * overlap + gapWidth);
if(this.chartsDrawer.calcProp.subType == "standard" || this.chartsDrawer.calcProp.type == AscFormat.c_oChartTypes.Line || isNormalArea) if(this.chartsDrawer.calcProp.subType == "standard" || this.chartsDrawer.calcProp.type == AscFormat.c_oChartTypes.Line || isNormalArea)
baseDepth = (width / (seriesCount - (seriesCount - 1) * overlap + gapWidth)) * seriesCount; baseDepth = (width / (seriesCount - (seriesCount - 1) * overlap + gapWidth)) * seriesCount;
...@@ -1187,6 +1248,21 @@ Processor3D.prototype._calculateCameraDiff = function (/*isSkip*/) ...@@ -1187,6 +1248,21 @@ Processor3D.prototype._calculateCameraDiff = function (/*isSkip*/)
//add test points for parallelepiped rect //add test points for parallelepiped rect
var points = []; var points = [];
var faces = []; var faces = [];
/*if(AscFormat.c_oChartTypes.Pie === this.chartsDrawer.calcProp.type)
{
points.push(new Point3D(this.left + originalWidthChart / 2, this.top, perspectiveDepth, this));
points.push(new Point3D(this.left, this.top, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart, this.top, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top, 0, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, perspectiveDepth, this));
points.push(new Point3D(this.left, this.top + heightChart, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart, this.top + heightChart, perspectiveDepth / 2, this));
points.push(new Point3D(this.left + originalWidthChart / 2, this.top + heightChart, 0, this));
}
else
{*/
points.push(new Point3D(this.left, this.top, perspectiveDepth, this)); points.push(new Point3D(this.left, this.top, perspectiveDepth, this));
points.push(new Point3D(this.left, heightChart + this.top, perspectiveDepth, this)); points.push(new Point3D(this.left, heightChart + this.top, perspectiveDepth, this));
points.push(new Point3D(originalWidthChart + this.left, heightChart + this.top, perspectiveDepth, this)); points.push(new Point3D(originalWidthChart + this.left, heightChart + this.top, perspectiveDepth, this));
...@@ -1195,6 +1271,7 @@ Processor3D.prototype._calculateCameraDiff = function (/*isSkip*/) ...@@ -1195,6 +1271,7 @@ Processor3D.prototype._calculateCameraDiff = function (/*isSkip*/)
points.push(new Point3D(originalWidthChart + this.left, heightChart + this.top, 0, this)); points.push(new Point3D(originalWidthChart + this.left, heightChart + this.top, 0, this));
points.push(new Point3D(this.left, heightChart + this.top, 0, this)); points.push(new Point3D(this.left, heightChart + this.top, 0, this));
points.push(new Point3D(this.left, this.top, 0, this)); points.push(new Point3D(this.left, this.top, 0, this));
//}
faces.push([0,1,2,3]); faces.push([0,1,2,3]);
faces.push([2,5,4,3]); faces.push([2,5,4,3]);
...@@ -1449,6 +1526,7 @@ Processor3D.prototype.checkOutSideArea = function(newPoints) ...@@ -1449,6 +1526,7 @@ Processor3D.prototype.checkOutSideArea = function(newPoints)
} }
}; };
calculateZ(100);
calculateZ(10); calculateZ(10);
calculateZ(1); calculateZ(1);
......
...@@ -2532,7 +2532,16 @@ CChartsDrawer.prototype = ...@@ -2532,7 +2532,16 @@ CChartsDrawer.prototype =
if(numCache != null && numCache.pts && numCache.pts.length) if(numCache != null && numCache.pts && numCache.pts.length)
{ {
if(!this.calcProp.ptCount) if(!this.calcProp.ptCount)
{
if(AscFormat.c_oChartTypes.Pie === this.calcProp.type)
{
this.calcProp.ptCount = 1;
}
else
{
this.calcProp.ptCount = numCache.ptCount; this.calcProp.ptCount = numCache.ptCount;
}
}
//TODO возможно нужно будет проверку добавить на isHidden //TODO возможно нужно будет проверку добавить на isHidden
counter++; counter++;
...@@ -2543,6 +2552,11 @@ CChartsDrawer.prototype = ...@@ -2543,6 +2552,11 @@ CChartsDrawer.prototype =
} }
} }
if(AscFormat.c_oChartTypes.Pie === this.calcProp.type)
{
counter = 1;
}
return counter; return counter;
}, },
...@@ -3111,7 +3125,7 @@ CChartsDrawer.prototype = ...@@ -3111,7 +3125,7 @@ CChartsDrawer.prototype =
{ {
res = true; res = true;
} }
else if(isPerspective && (isBar || isLine|| isHBar || isArea)) else if(isPerspective && (isBar || isLine|| isHBar || isArea || isPie))
{ {
res = true; res = true;
} }
...@@ -5923,7 +5937,6 @@ drawAreaChart.prototype = ...@@ -5923,7 +5937,6 @@ drawAreaChart.prototype =
{ {
//ширина линии //ширина линии
var brush; var brush;
var FillUniColor;
var pen; var pen;
var seria, dataSeries; var seria, dataSeries;
...@@ -7067,7 +7080,6 @@ drawHBarChart.prototype = ...@@ -7067,7 +7080,6 @@ drawHBarChart.prototype =
_DrawBars3D: function() _DrawBars3D: function()
{ {
var t = this; var t = this;
var processor3D = this.cChartDrawer.processor3D;
var drawVerges = function(i, j, paths, onlyLessNull, k, isNotPen, isNotBrush) var drawVerges = function(i, j, paths, onlyLessNull, k, isNotPen, isNotBrush)
{ {
...@@ -7431,6 +7443,8 @@ function drawPieChart() ...@@ -7431,6 +7443,8 @@ function drawPieChart()
this.angleFor3D = null; this.angleFor3D = null;
this.properties3d = null; this.properties3d = null;
this.usually3dPropsCalc = []; this.usually3dPropsCalc = [];
this.tempDrawOrder = null;
} }
drawPieChart.prototype = drawPieChart.prototype =
...@@ -7463,13 +7477,20 @@ drawPieChart.prototype = ...@@ -7463,13 +7477,20 @@ drawPieChart.prototype =
this.paths = {}; this.paths = {};
if(this.cChartDrawer.nDimensionCount === 3) if(this.cChartDrawer.nDimensionCount === 3)
{
if(this.cChartDrawer.processor3D.view3D.rAngAx)
{ {
this.properties3d = this.cChartDrawer.processor3D.calculatePropertiesForPieCharts(); this.properties3d = this.cChartDrawer.processor3D.calculatePropertiesForPieCharts();
this._reсalculatePie3D(); this._recalculatePie3D();
}
else
{
this._recalculatePie3DPerspective();
}
} }
else else
{ {
this._reсalculatePie(); this._recalculatePie();
} }
}, },
...@@ -7489,92 +7510,7 @@ drawPieChart.prototype = ...@@ -7489,92 +7510,7 @@ drawPieChart.prototype =
} }
}, },
_drawPie3D_Slow: function () _recalculatePie: function ()
{
var numCache = this._getFirstRealNumCache();
var props = this.cChartSpace.getParentObjects();
var brush, pen, val;
var path;
for(var n = 0; n < this.paths.series.length; n++)
{
for (var i = 0, len = numCache.length; i < len; i++) {
val = numCache[i];
brush = val.brush;
if(n === 0 || n === this.paths.series.length - 1)
{
pen = val.pen;
}
else
{
pen = null;
}
path = this.paths.series[n][i];
var duplicateBrush = brush;
if(n !== this.paths.series.length - 1)
{
var duplicateBrush = brush.createDuplicate();
var cColorMod = new AscFormat.CColorMod;
cColorMod.val = 35000;
cColorMod.name = "shade";
duplicateBrush.addColorMod(cColorMod);
duplicateBrush.calculate(props.theme, props.slide, props.layout, props.master, new AscFormat.CUniColor().RGBA);
}
this.cChartDrawer.drawPath(path, pen, duplicateBrush);
}
}
},
_reсalculatePie3D_Slow: function ()
{
var trueWidth = this.chartProp.trueWidth;
var trueHeight = this.chartProp.trueHeight;
var numCache = this._getFirstRealNumCache();
var sumData = this.cChartDrawer._getSumArray(numCache, true);
var radius = Math.min(trueHeight, trueWidth) / 2;
if(radius < 0)
radius = 0;
var xCenter = this.chartProp.chartGutter._left + trueWidth/2;
var yCenter = this.chartProp.chartGutter._top + trueHeight/2;
var startAngle = this.cChartDrawer.processor3D.angleOy ? this.cChartDrawer.processor3D.angleOy : 0;
var startAngle3D = startAngle !== 0 && startAngle !== undefined ? this._changeAngle(radius, Math.PI/2, startAngle, xCenter, yCenter, this.properties3d) : 0;
this.tempAngle = Math.PI/2 + startAngle;
this.angleFor3D = Math.PI/2 - startAngle3D;
//рисуем против часовой стрелки, поэтому цикл с конца
var depth = this.properties3d.depth;
for(var n = 0; n < depth; n++)
{
if(!this.paths.series)
this.paths.series = [];
for (var i = numCache.length - 1; i >= 0; i--)
{
var angle = Math.abs((parseFloat(numCache[i].val / sumData)) * (Math.PI * 2));
if(!this.paths.series[n])
this.paths.series[n] = [];
if(sumData === 0)//TODO стоит пересмотреть
this.paths.series[n][i] = this._calculateEmptySegment(radius, xCenter, yCenter);
else
this.paths.series[n][i] = this._calculateSegment3D(angle, radius, xCenter, yCenter, n, i);
}
}
},
_reсalculatePie: function ()
{ {
var trueWidth = this.chartProp.trueWidth; var trueWidth = this.chartProp.trueWidth;
var trueHeight = this.chartProp.trueHeight; var trueHeight = this.chartProp.trueHeight;
...@@ -7599,7 +7535,7 @@ drawPieChart.prototype = ...@@ -7599,7 +7535,7 @@ drawPieChart.prototype =
this.paths.series[i] = this._calculateEmptySegment(radius, xCenter, yCenter); this.paths.series[i] = this._calculateEmptySegment(radius, xCenter, yCenter);
else else
this.paths.series[i] = this._calculateSegment(angle, radius, xCenter, yCenter); this.paths.series[i] = this._calculateSegment(angle, radius, xCenter, yCenter);
}; }
}, },
_getFirstRealNumCache: function() _getFirstRealNumCache: function()
...@@ -7633,22 +7569,6 @@ drawPieChart.prototype = ...@@ -7633,22 +7569,6 @@ drawPieChart.prototype =
return path; return path;
}, },
_calculateSegment3D_Slow: function (angle, radius, xCenter, yCenter, depth, i)
{
if(isNaN(angle))
return null;
var startAngle = (this.tempAngle);
var swapAngle = angle;
var endAngle = startAngle + angle;
var path = this._calculateArc3D(radius, startAngle, swapAngle, xCenter, yCenter, depth, i);
this.tempAngle += angle;
return path;
},
_calculateEmptySegment: function(radius, xCenter, yCenter) _calculateEmptySegment: function(radius, xCenter, yCenter)
{ {
var path = new Path(); var path = new Path();
...@@ -7703,74 +7623,8 @@ drawPieChart.prototype = ...@@ -7703,74 +7623,8 @@ drawPieChart.prototype =
return path; return path;
}, },
_calculateArc3D_Slow : function(radius, stAng, swAng, xCenter, yCenter, depth, seriaNum) _changeAngle: function(radius, stAng, swAng, xCenter, yCenter, depth, radius1, radius2)
{
var radius1 = this.properties3d.radius1;
var radius2 = this.properties3d.radius2;
var pxToMm = this.chartProp.pxToMM;
var t = this;
var x0, y0, radiusSpec;
var calculateProps = function()
{
if(t.usually3dPropsCalc && t.usually3dPropsCalc[seriaNum])
{
swAng = t.usually3dPropsCalc[seriaNum].swAng;
stAng = t.usually3dPropsCalc[seriaNum].stAng;
radiusSpec = t.usually3dPropsCalc[seriaNum].radiusSpec;
x0 = t.usually3dPropsCalc[seriaNum].x0;
yCenter = yCenter + t.properties3d.depth / 2 - depth;
y0 = (yCenter - radiusSpec*Math.sin(stAng));
}
else
{
swAng = t._changeAngle(radius, stAng, swAng, xCenter, yCenter, t.properties3d);
stAng = t.angleFor3D;
//корректируем центр
yCenter = yCenter + t.properties3d.depth / 2 - depth;
radiusSpec = (radius1 * radius2) / Math.sqrt(Math.pow(radius2, 2) * Math.pow((Math.cos(stAng)), 2) + Math.pow(radius1, 2) * Math.pow(Math.sin(stAng),2));
x0 = (xCenter + radiusSpec*Math.cos(stAng));
y0 = (yCenter - radiusSpec*Math.sin(stAng));
}
};
var path = new Path();
var pathH = this.chartProp.pathH;
var pathW = this.chartProp.pathW;
var gdLst = [];
path.pathH = pathH;
path.pathW = pathW;
gdLst["w"] = 1;
gdLst["h"] = 1;
calculateProps();
path.moveTo(xCenter /pxToMm * pathW, yCenter / pxToMm * pathH);
path.lnTo(x0 /pxToMm * pathW, y0 / pxToMm * pathH);
path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * stAng*cToDeg, -1 * swAng*cToDeg);
path.lnTo(xCenter /pxToMm * pathW, yCenter / pxToMm * pathH);
path.recalculate(gdLst);
this.angleFor3D += swAng;
if(!this.usually3dPropsCalc[seriaNum])
this.usually3dPropsCalc[seriaNum] = {swAng: swAng, stAng: stAng, xCenter: xCenter, x0: x0, radiusSpec: radiusSpec};
return path;
},
_changeAngle: function(radius, stAng, swAng, xCenter, yCenter, properties)
{ {
var depth = properties.depth;
var radius1 = properties.radius1;
var radius2 = properties.radius2;
//корректируем центр //корректируем центр
yCenter = yCenter - depth / 2; yCenter = yCenter - depth / 2;
...@@ -7780,9 +7634,9 @@ drawPieChart.prototype = ...@@ -7780,9 +7634,9 @@ drawPieChart.prototype =
var kFY = radius / radius2; var kFY = radius / radius2;
var cX; var cX;
if(this.cX !== null) //if(this.cX !== null)
cX = this.cX; //cX = this.cX;
else if(x0 < xCenter) if(x0 < xCenter)
cX = xCenter - (xCenter - x0) / kFX; cX = xCenter - (xCenter - x0) / kFX;
else if(x0 > xCenter) else if(x0 > xCenter)
cX = xCenter + (x0 - xCenter) / kFX; cX = xCenter + (x0 - xCenter) / kFX;
...@@ -7790,9 +7644,9 @@ drawPieChart.prototype = ...@@ -7790,9 +7644,9 @@ drawPieChart.prototype =
cX = xCenter; cX = xCenter;
var cY; var cY;
if(this.cY !== null) //if(this.cY !== null)
cY = this.cY; //cY = this.cY;
else if(y0 < yCenter) if(y0 < yCenter)
cY = yCenter - (yCenter - y0) / kFY; cY = yCenter - (yCenter - y0) / kFY;
else if(y0 > yCenter) else if(y0 > yCenter)
cY = yCenter + (y0 - yCenter) / kFY; cY = yCenter + (y0 - yCenter) / kFY;
...@@ -7843,572 +7697,472 @@ drawPieChart.prototype = ...@@ -7843,572 +7697,472 @@ drawPieChart.prototype =
return res; return res;
}, },
_calculateBestFitPosition: function(fStartAngle, fSweepAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY, bLayout){ _calculateDLbl: function(chartSpace, ser, val, bLayout)
var fStartAngle_ = fStartAngle; {
var fEndAngle = fStartAngle + fSweepAngle; var pxToMm = this.chartProp.pxToMM;
if(bLayout){
return this._calculateBestFitPositionOuter(fStartAngle_, fEndAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY); //TODO сделать через idx как у drawDoughnutChart!!!
if(!this.paths.series[val])
return;
var path;
if(this.cChartDrawer.nDimensionCount === 3)
{
if(this.paths.series[val][ser] && this.paths.series[val][ser].upPath)
{
path = this.paths.series[val][ser].upPath.ArrPathCommand;
} }
var oRet = this._calculateBestFitPositionInner(fStartAngle_, fEndAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY);
if(!oRet.bError){
if(AscFormat.fCheckBoxIntersectionSegment(oRet.fX, oRet.fY, fWidth, fHeight, fCenterX, fCenterY, fCenterX + fRadius*Math.cos(fStartAngle_), fCenterY + fRadius*Math.sin(fStartAngle_))
|| AscFormat.fCheckBoxIntersectionSegment(oRet.fX, oRet.fY, fWidth, fHeight, fCenterX, fCenterY, fCenterX + fRadius*Math.cos(fEndAngle), fCenterY + fRadius*Math.sin(fEndAngle))){
oRet.bError = true;
} }
else
{
path = this.paths.series[val].ArrPathCommand;
} }
if(oRet.bError){
return this._calculateBestFitPositionOuter(fStartAngle_, fEndAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY); if(!path)
{
return;
} }
return oRet;
},
_calculateBestFitPositionInner: function(fStartAngle, fEndAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY){ var getEllipseRadius = function(radius1, radius2, alpha)
var oResult = {bError: true}; {
var fBisectAngle = AscFormat.normalizeRotate((fStartAngle + fEndAngle)/2.0); var a = radius1 * radius2;
var b = Math.sqrt(Math.pow(radius2, 2) * Math.pow(Math.cos(alpha), 2) + Math.pow(radius1, 2) * Math.pow(Math.sin(alpha), 2));
var res = a / b;
if(AscFormat.fApproxEqual(fBisectAngle, 0) || AscFormat.fApproxEqual(fBisectAngle, Math.PI/2) || AscFormat.fApproxEqual(fBisectAngle, Math.PI) || AscFormat.fApproxEqual(fBisectAngle, 3*Math.PI/2)){ return res;
return this._calculateInEndDLblPosition(fStartAngle, fStartAngle + fEndAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY); };
var centerX = path[0].X;
var centerY = path[0].Y;
var radius = path[2].hR;
var stAng = path[2].stAng;
var swAng = path[2].swAng;
if(this.cChartDrawer.nDimensionCount === 3 && path[2].wR)
{
radius = getEllipseRadius(path[2].hR, path[2].wR, -1 * stAng - swAng / 2 - Math.PI / 2);
} }
var fBisectAngle2 = AscFormat.normalizeRotate(fBisectAngle + Math.PI/4) - Math.PI/4;
var nIndexArea = ((fBisectAngle2 + Math.PI/4)/(Math.PI/2)) >> 0;
var point = this.chartProp.series[0].val.numRef ? this.chartProp.series[0].val.numRef.numCache.pts[val] : this.chartProp.series[0].val.numLit.pts[val];
var fLengthCoeff = ((fBisectAngle2 + Math.PI/4) - (Math.PI/2)*nIndexArea)/(Math.PI/2); if(!point)
return;
var fXs = fCenterX + fPieRadius*Math.cos(fBisectAngle); var width = point.compiledDlb.extX;
var fYs = fCenterY + fPieRadius*Math.sin(fBisectAngle); var height = point.compiledDlb.extY;
var fDeltaX, fDeltaY, oSolvation;
switch(nIndexArea){ var tempCenterX, tempCenterY;
case 0:{
if(fBisectAngle2 < 0){ //TODO высчитать позиции, как в екселе + ограничения
fDeltaX = fLabelWidth; switch ( point.compiledDlb.dLblPos )
fDeltaY = -(1 - fLengthCoeff)*fLabelHeight; {
case c_oAscChartDataLabelsPos.bestFit:
{
var oPos = this._calculateBestFitPosition(stAng, swAng, radius, width, height, centerX, centerY, bLayout);
if(!oPos.bError){
centerX = oPos.fX;
centerY = oPos.fY;
} }
else{ else{
fDeltaX = fLabelWidth; centerX = centerX + (radius / 2) * Math.cos(-1 * stAng - swAng / 2) - width / 2;
fDeltaY = fLabelHeight*fLengthCoeff; centerY = centerY - (radius / 2) * Math.sin(-1 * stAng - swAng / 2) - height / 2;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
} }
else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){ break;
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
} }
case c_oAscChartDataLabelsPos.ctr:
{
centerX = centerX + (radius / 2) * Math.cos(-1 * stAng - swAng / 2) - width / 2;
centerY = centerY - (radius / 2) * Math.sin(-1 * stAng - swAng / 2) - height / 2;
break;
} }
case c_oAscChartDataLabelsPos.inBase:
{
centerX = centerX + (radius / 2) * Math.cos(-1 * stAng - swAng / 2) - width / 2;
centerY = centerY - (radius / 2) * Math.sin(-1 * stAng - swAng / 2) - height / 2;
break; break;
} }
case 1:{ case c_oAscChartDataLabelsPos.inEnd:
if(fBisectAngle < Math.PI/2){ {
fDeltaX = (1 - fLengthCoeff)*fLabelWidth; var oPos = this._calculateInEndDLblPosition(stAng, swAng, radius, width, height, centerX, centerY);
fDeltaY = fLabelHeight; if(!oPos.bError){
centerX = oPos.fX;
centerY = oPos.fY;
break;
} }
else{ tempCenterX = centerX + (radius) * Math.cos(-1 * stAng - swAng / 2);
fDeltaX = - fLengthCoeff*fLabelWidth; tempCenterY = centerY - (radius) * Math.sin(-1 * stAng - swAng / 2);
fDeltaY = fLabelHeight;
if(tempCenterX < centerX && tempCenterY < centerY)
{
centerX = tempCenterX;
centerY = tempCenterY;
} }
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius); else if(tempCenterX > centerX && tempCenterY < centerY)
if(!oSolvation.bError){ {
if(oSolvation.x1 > 0 && oSolvation.x1 < 1){ centerX = tempCenterX - width;
oResult.bError = false; centerY = tempCenterY;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY);
} }
else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){ else if(tempCenterX < centerX && tempCenterY > centerY)
oResult.bError = false; {
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff; centerX = tempCenterX;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY); centerY = tempCenterY - height;
} }
else
{
centerX = tempCenterX - width;
centerY = tempCenterY - height;
} }
break; break;
} }
case 2:{ case c_oAscChartDataLabelsPos.outEnd:
if(fBisectAngle < Math.PI){ {
fDeltaX = -fLabelWidth; tempCenterX = centerX + (radius) * Math.cos(-1 * stAng - swAng / 2);
fDeltaY = (1 - fLengthCoeff)*fLabelHeight; tempCenterY = centerY - (radius) * Math.sin(-1 * stAng - swAng / 2);
}
else{
fDeltaX = -fLabelWidth;
fDeltaY = - fLengthCoeff*fLabelHeight;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
if(tempCenterX < centerX && tempCenterY < centerY)
{
centerX = tempCenterX - width;
centerY = tempCenterY - height;
} }
else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){ else if(tempCenterX > centerX && tempCenterY < centerY)
oResult.bError = false; {
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth; centerX = tempCenterX;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight*fLengthCoeff; centerY = tempCenterY - height;
}
}
break;
} }
case 3:{ else if(tempCenterX < centerX && tempCenterY > centerY)
fLengthCoeff = 1 - fLengthCoeff; {
if(fBisectAngle < 3*Math.PI/2){ centerX = tempCenterX - width;
fDeltaX = -fLabelWidth*fLengthCoeff; centerY = tempCenterY;
fDeltaY = -fLabelHeight;
} }
else{ else
fDeltaX = (1 - fLengthCoeff)*fLabelWidth; {
fDeltaY = -fLabelHeight; centerX = tempCenterX;
centerY = tempCenterY;
} }
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius); break;
if(!oSolvation.bError){
if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight;
} }
else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight;
} }
if(centerX < 0)
centerX = 0;
if(centerX + width > this.chartProp.widthCanvas / pxToMm)
centerX = this.chartProp.widthCanvas / pxToMm - width;
if(centerY < 0)
centerY = 0;
if(centerY + height > this.chartProp.heightCanvas / pxToMm)
centerY = this.chartProp.heightCanvas / pxToMm - height;
return {x: centerX, y: centerY};
},
//****fast calulate and drawing(for switch on slow drawing: change name function _Slow)
_recalculatePie3D: function ()
{
var trueWidth = this.chartProp.trueWidth;
var trueHeight = this.chartProp.trueHeight;
var numCache = this._getFirstRealNumCache();
var sumData = this.cChartDrawer._getSumArray(numCache, true);
var radius = Math.min(trueHeight, trueWidth) / 2;
if(radius < 0)
{
radius = 0;
} }
break;
var xCenter = this.chartProp.chartGutter._left + trueWidth/2;
var yCenter = this.chartProp.chartGutter._top + trueHeight/2;
var startAngle = this.cChartDrawer.processor3D.angleOy ? this.cChartDrawer.processor3D.angleOy : 0;
var startAngle3D = startAngle !== 0 && startAngle !== undefined ? this._changeAngle(radius, Math.PI/2, startAngle, xCenter, yCenter, this.properties3d.depth, this.properties3d.radius1, this.properties3d.radius2) : 0;
this.angleFor3D = Math.PI/2 - startAngle3D;
startAngle = startAngle + Math.PI / 2;
for (var i = numCache.length - 1; i >= 0; i--)
{
var partOfSum = numCache[i].val / sumData;
var swapAngle = Math.abs((parseFloat(partOfSum)) * (Math.PI * 2));
if(!this.paths.series)
{
this.paths.series = [];
} }
this.paths.series[i] = this._calculateSegment3D(startAngle, swapAngle, radius, xCenter, yCenter);
startAngle += swapAngle;
} }
return oResult;
}, },
_calculateBestFitPositionOuter: function(fStartAngle, fEndAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY){ _recalculatePie3DPerspective: function ()
var oResult = {bError: true}; {
var fBisectAngle = AscFormat.normalizeRotate((fStartAngle + fEndAngle)/2.0); var left = this.chartProp.chartGutter._left;
var fBisectAngle2 = AscFormat.normalizeRotate(fBisectAngle + Math.PI/4) - Math.PI/4; var right = this.chartProp.chartGutter._right;
var nIndexArea = ((fBisectAngle2 + Math.PI/4)/(Math.PI/2)) >> 0; var top = this.chartProp.chartGutter._top;
var bottom = this.chartProp.chartGutter._bottom;
var trueWidth = this.chartProp.trueWidth;
var fLengthCoeff = ((fBisectAngle2 + Math.PI/4) - (Math.PI/2)*nIndexArea)/(Math.PI/2); var widthCanvas = this.chartProp.widthCanvas;
var heightCanvas = this.chartProp.heightCanvas;
var fXs = fCenterX + fPieRadius*Math.cos(fBisectAngle); var height = heightCanvas - (top + bottom);
var fYs = fCenterY + fPieRadius*Math.sin(fBisectAngle); var width = widthCanvas - (left + right);
var fDeltaX, fDeltaY, oSolvation;
var fAngleApproxDelta = 1e-4; var tempDepth = this.cChartDrawer.processor3D.depthPerspective;
switch(nIndexArea){
case 0:{ var x1 = left, y1 = top + height, z1 = 0;
if(AscFormat.fApproxEqual(fBisectAngle2, 0, fAngleApproxDelta)){ var x2 = left, y2 = top, z2 = 0;
fDeltaX = 0; var x3 = left + width, y3 = top, z3 = 0;
fDeltaY = 0; var x4 = left + width, y4 = top + height, z4 = 0;
var x5 = left, y5 = top + height, z5 = tempDepth;
var x6 = left, y6 = top, z6 = tempDepth;
var x7 = left + width, y7 = top, z7 = tempDepth;
var x8 = left + width, y8 = top + height, z8 = tempDepth;
var point1 = this.cChartDrawer._convertAndTurnPoint(x1, y1, z1);
var point2 = this.cChartDrawer._convertAndTurnPoint(x2, y2, z2);
//var point3 = this.cChartDrawer._convertAndTurnPoint(x3, y3, z3);
//var point4 = this.cChartDrawer._convertAndTurnPoint(x4, y4, z4);
var point5 = this.cChartDrawer._convertAndTurnPoint(x5, y5, z5);
var point6 = this.cChartDrawer._convertAndTurnPoint(x6, y6, z6);
//var point7 = this.cChartDrawer._convertAndTurnPoint(x7, y7, z7);
//var point8 = this.cChartDrawer._convertAndTurnPoint(x8, y8, z8);
var radius3D1 = (z6 - z2) / 2;
var radius3D2 = (z5 - z1) / 2;
var center3D1 = new Point3D(x2 + ((x3 - x2) / 2), y2, z2 + (radius3D1));
var center3D2 = new Point3D(x1 + ((x4 - x1) / 2), y1, z1 + (radius3D2));
var pointCenter1 = this.cChartDrawer._convertAndTurnPoint(center3D1.x, center3D1.y, center3D1.z);
var pointCenter2 = this.cChartDrawer._convertAndTurnPoint(center3D2.x, center3D2.y, center3D2.z);
//TEST DRAW FRAME
//this._calculateTestFrame(point1, point2, point3, point4, point5, point6, point7, point8);
var test1 = this.cChartDrawer._convertAndTurnPoint(x2, y2, center3D1.z);
var test2 = this.cChartDrawer._convertAndTurnPoint(x3, y3, center3D1.z);
var test11 = this.cChartDrawer._convertAndTurnPoint(x4, y4, center3D2.z);
var test22 = this.cChartDrawer._convertAndTurnPoint(x1, y1, center3D2.z);
var radius11 = Math.abs((test2.x - test1.x) / 2);
var radius12 = Math.abs((point6.y - point2.y) / 2);
var radius21 = Math.abs((test22.x - test11.x) / 2);
var radius22 = Math.abs((point5.y - point1.y) / 2);
var center1 = {x: this.chartProp.chartGutter._left + trueWidth/2, y: (point2.y - point6.y) / 2 + point6.y};
var center2 = {x: this.chartProp.chartGutter._left + trueWidth/2, y: (point1.y - point5.y) / 2 + point5.y};
var angles1 = this._calculateAngles3DPerspective(center1.x, center1.y, radius11, radius12, radius3D1, center3D1);
var angles2 = this._calculateAngles3DPerspective(center2.x, center2.y, radius21, radius22, radius3D2, center3D2);
if(!this.paths.series)
{
this.paths.series = [];
} }
else if(fBisectAngle2 < 0){
fDeltaX = 0; for(var i = 0; i < angles1.length; i++)
fDeltaY = fLengthCoeff*fLabelHeight; {
var start = angles1[i].start;
var start1 = angles2[i].start;
if(i === angles1.length - 1)
{
var end = angles1[0].start + 2 * Math.PI;
angles1[i].swap = end - start;
var end1 = angles2[0].start + 2 * Math.PI;
angles2[i].swap = end1 - start1;
} }
else{
fDeltaX = 0; var paths = this._calculateSegment3DPerspective(radius11, radius12, radius21, radius22, angles1[i], angles2[i], center1, center2, pointCenter1, pointCenter2, Math.sign(point2.y - point6.y));
fDeltaY = -(1 - fLengthCoeff)*fLabelHeight;
if(null === this.tempDrawOrder)
{
this.tempDrawOrder = Math.sign(point2.y - point6.y) < 0 ? true : null;
} }
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){ if(!this.paths.series[angles1.length - i - 1])
if(oSolvation.x1 >= 1){ {
oResult.bError = false; this.paths.series[angles1.length - i - 1] = [];
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
} }
else if(oSolvation.x2 >= 1){
oResult.bError = false; this.paths.series[angles1.length - i - 1].push(paths);
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
}
else if(oSolvation.x1 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
}
else if(oSolvation.x2 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
}
}
break;
}
case 1:{
if(AscFormat.fApproxEqual(fBisectAngle, Math.PI/2, fAngleApproxDelta)){
fDeltaX = 0;
fDeltaY = 0;
}
else if(fBisectAngle < Math.PI/2){
fDeltaX = -fLengthCoeff*fLabelWidth;
fDeltaY = 0;
} }
else{ },
fDeltaX = (1 - fLengthCoeff)*fLabelWidth;
fDeltaY = 0; _calculateAngles3DPerspective: function(xCenter, yCenter, radius1, radius2, radius3D1, center3D1)
{
var t = this;
var widthCanvas = this.chartProp.widthCanvas;
var numCache = this._getFirstRealNumCache();
var sumData = this.cChartDrawer._getSumArray(numCache, true);
var startAngle = Math.PI / 2;
var newStartAngle = startAngle;
var firstAngle = this.cChartSpace.chart.view3D && this.cChartSpace.chart.view3D.rotY ? (- this.cChartSpace.chart.view3D.rotY / 360) * (Math.PI * 2) : 0;
var getAngleByCoordsSidesTriangle = function(aC, bC, cC)
{
var res;
var a = Math.sqrt(Math.pow(aC.x, 2) + Math.pow(aC.y, 2));
var b = Math.sqrt(Math.pow(bC.x, 2) + Math.pow(bC.y, 2));
var c = Math.sqrt(Math.pow(cC.x, 2) + Math.pow(cC.y, 2));
res = Math.acos((Math.pow(b, 2) + Math.pow(c, 2) - Math.pow(a, 2)) / (2 * b * c));
return res;
};
var getPointsByAngle = function(angle)
{
var point1 = t.cChartDrawer._convertAndTurnPoint(center3D1.x + radius3D1 * Math.cos(angle), center3D1.y, center3D1.z + radius3D1 * Math.sin(angle));
var y11 = point1.y;
var x11 = Math.sqrt(Math.abs(Math.pow(radius1, 2)*(1 - (Math.pow(y11 - (yCenter), 2) / Math.pow(radius2, 2)))));
var x111;
if((angle <= 3*Math.PI/2 && angle >= Math.PI/2) || (angle >= -3*Math.PI/2 && angle <= -Math.PI/2))
{
x111 = xCenter - x11;
} }
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius); else
if(!oSolvation.bError){ {
if(oSolvation.x1 >= 1){ x111 = widthCanvas - (xCenter - x11)
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY);
} }
else if(oSolvation.x2 >= 1){
oResult.bError = false; return {x: x111, y: y11};
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff; };
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY);
var angles = [];
for (var i = numCache.length; i >= 0; i--)
{
//рассчитываем угол
if(i === numCache.length)
{
var swapAngle = firstAngle
} }
else if(oSolvation.x1 >= 0){ else
oResult.bError = false; {
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff; var partOfSum = numCache[i].val / sumData;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY); var swapAngle = Math.abs((parseFloat(partOfSum)) * (Math.PI * 2));
} }
else if(oSolvation.x2 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff; var tempSwapAngle = 0, newSwapAngle = 0, tempStartAngle = startAngle;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY); while(true)
{
if(i === numCache.length && swapAngle < 0)
{
if(tempStartAngle - Math.PI / 2 > startAngle + swapAngle)
{
tempSwapAngle = -Math.PI / 2;
} }
else
{
tempSwapAngle = (startAngle + swapAngle) - tempStartAngle;
} }
break;
} }
case 2:{ else
if(AscFormat.fApproxEqual(fBisectAngle, Math.PI, fAngleApproxDelta)){ {
fDeltaX = 0; if(tempStartAngle + Math.PI / 2 < startAngle + swapAngle)
fDeltaY = 0; {
tempSwapAngle = Math.PI / 2;
} }
else if(fBisectAngle < Math.PI){ else
fDeltaX = 0; {
fDeltaY = -fLengthCoeff*fLabelHeight; tempSwapAngle = (startAngle + swapAngle) - tempStartAngle;
} }
else{
fDeltaX = 0;
fDeltaY = (1 - fLengthCoeff)*fLabelHeight;
} }
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
}
else if(oSolvation.x2 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
}
else if(oSolvation.x1 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
var p1 = getPointsByAngle(tempStartAngle);
var p2 = getPointsByAngle(tempStartAngle + tempSwapAngle);
newSwapAngle += getAngleByCoordsSidesTriangle({x: p2.x - p1.x, y: p2.y - p1.y}, {x: xCenter - p1.x, y: yCenter - p1.y}, {x: xCenter - p2.x, y: yCenter - p2.y});
if(i === numCache.length && swapAngle < 0)
{
if(tempStartAngle - Math.PI / 2 > startAngle + swapAngle)
{
tempStartAngle -= Math.PI / 2;
} }
else if(oSolvation.x2 >= 0){ else
oResult.bError = false; {
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth; if(i !== numCache.length)
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight*fLengthCoeff; angles.push({start: newStartAngle, swap: newSwapAngle, end: newStartAngle + newSwapAngle});
}
}
break; break;
} }
case 3:{
if(fBisectAngle < 3*Math.PI/2){
fDeltaX = fLabelWidth*fLengthCoeff;
fDeltaY = 0;
}
else{
fDeltaX = -(1 - fLengthCoeff)*fLabelWidth;
fDeltaY = 0;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight;
}
else if(oSolvation.x2 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight;
}
else if(oSolvation.x1 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight;
}
else if(oSolvation.x2 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight;
}
}
break;
} }
else
{
if(tempStartAngle + Math.PI / 2 < startAngle + swapAngle)
{
tempStartAngle += Math.PI / 2;
} }
return oResult; else
}, {
if(i !== numCache.length)
angles.push({start: newStartAngle, swap: newSwapAngle, end: newStartAngle + newSwapAngle});
_calculateInEndDLblPosition: function(fStartAngle, fSweepAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY){ break;
var fEndAngle = fStartAngle + fSweepAngle;
var oResult = {bError: true, fX: 0.0, fY: 0.0};
var fBisectAngle = AscFormat.normalizeRotate((fStartAngle + fEndAngle)/2);
var nQuadrantIndex = (2.0*fBisectAngle/Math.PI) >> 0;
var fHalfRectWidthVector = fLabelWidth/ 2, fHalfRectHeightVector = fLabelHeight/2;
if(nQuadrantIndex === 1 || nQuadrantIndex == 2){
fHalfRectWidthVector = -fHalfRectWidthVector;
} }
if(nQuadrantIndex === 2 || nQuadrantIndex == 3){
fHalfRectHeightVector = -fHalfRectHeightVector;
} }
var fXs = fCenterX + fPieRadius*Math.cos(fBisectAngle), fYs = fCenterY + fPieRadius*Math.sin(fBisectAngle);
var a = fPieRadius*fPieRadius, b = 2*( (fXs - fCenterX)*fHalfRectWidthVector + (fYs - fCenterY)*fHalfRectHeightVector), c = fHalfRectWidthVector*fHalfRectWidthVector + fHalfRectHeightVector*fHalfRectHeightVector - fPieRadius*fPieRadius;
var oSolution = AscFormat.fSolveQuadraticEquation(a, b, c);
if(oSolution.bError){
return oResult;
}
var D = b*b - 4*a*c;
if(D < 0){
return oResult;
}
var t1 = oSolution.x1, t2 = oSolution.x2;
if(t1 > 0 && t1 < 1){
oResult.bError = false;
oResult.fX = fCenterX + t1*(fXs - fCenterX) - fLabelWidth/2;
oResult.fY = fCenterY + t1*(fYs - fCenterY) - fLabelHeight/2;
return oResult
}
if(t2 > 0 && t2 < 1){
oResult.bError = false;
oResult.fX = fCenterX + t2*(fXs - fCenterX) - fLabelWidth/2;
oResult.fY = fCenterY + t2*(fYs - fCenterY) - fLabelHeight/2;
return oResult
} }
return oResult;
},
_calculateDLbl: function(chartSpace, ser, val, bLayout)
{
var pxToMm = this.chartProp.pxToMM;
//TODO сделать через idx как у drawDoughnutChart!!!
if(!this.paths.series[val])
return;
var path; startAngle += swapAngle;
if(this.cChartDrawer.nDimensionCount === 3) if(i === numCache.length)
{ {
if(this.paths.series[val][ser] && this.paths.series[val][ser].upPath) if(swapAngle < 0)
{ {
path = this.paths.series[val][ser].upPath.ArrPathCommand; newStartAngle -= newSwapAngle;
}
} }
else else
{ {
path = this.paths.series[val].ArrPathCommand; newStartAngle += newSwapAngle;
} }
if(!path) }
else
{ {
return; newStartAngle += newSwapAngle;
}
} }
var getEllipseRadius = function(radius1, radius2, alpha) return angles;
},
_calculateArc3D : function(radius, stAng, swAng, xCenter, yCenter, bIsNotDrawFrontFace, depth, radius1, radius2)
{ {
var a = radius1 * radius2; var properties = this.cChartDrawer.processor3D.calculatePropertiesForPieCharts();
var b = Math.sqrt(Math.pow(radius2, 2) * Math.pow(Math.cos(alpha), 2) + Math.pow(radius1, 2) * Math.pow(Math.sin(alpha), 2));
var res = a / b;
return res; depth = !depth ? properties.depth : depth;
}; radius1 = !radius1 ? properties.radius1 : radius1;
radius2 = !radius2 ? properties.radius2 : radius2;
var centerX = path[0].X;
var centerY = path[0].Y;
var radius = path[2].hR;
var stAng = path[2].stAng;
var swAng = path[2].swAng;
if(this.cChartDrawer.nDimensionCount === 3 && path[2].wR) var pxToMm = this.chartProp.pxToMM;
{ var pathH = this.chartProp.pathH;
radius = getEllipseRadius(path[2].hR, path[2].wR, -1 * stAng - swAng / 2 - Math.PI / 2); var pathW = this.chartProp.pathW;
}
var point = this.chartProp.series[0].val.numRef ? this.chartProp.series[0].val.numRef.numCache.pts[val] : this.chartProp.series[0].val.numLit.pts[val]; var gdLst = [];
gdLst["w"] = 1;
gdLst["h"] = 1;
if(!point) swAng = this._changeAngle(radius, stAng, swAng, xCenter, yCenter, depth, radius1, radius2);
return;
var constMargin = 5 / pxToMm;
var width = point.compiledDlb.extX;
var height = point.compiledDlb.extY;
var tempCenterX, tempCenterY;
//TODO высчитать позиции, как в екселе + ограничения
switch ( point.compiledDlb.dLblPos )
{
case c_oAscChartDataLabelsPos.bestFit:
{
var oPos = this._calculateBestFitPosition(stAng, swAng, radius, width, height, centerX, centerY, bLayout);
if(!oPos.bError){
centerX = oPos.fX;
centerY = oPos.fY;
}
else{
centerX = centerX + (radius / 2) * Math.cos(-1 * stAng - swAng / 2) - width / 2;
centerY = centerY - (radius / 2) * Math.sin(-1 * stAng - swAng / 2) - height / 2;
}
break;
}
case c_oAscChartDataLabelsPos.ctr:
{
centerX = centerX + (radius / 2) * Math.cos(-1 * stAng - swAng / 2) - width / 2;
centerY = centerY - (radius / 2) * Math.sin(-1 * stAng - swAng / 2) - height / 2;
break;
}
case c_oAscChartDataLabelsPos.inBase:
{
centerX = centerX + (radius / 2) * Math.cos(-1 * stAng - swAng / 2) - width / 2;
centerY = centerY - (radius / 2) * Math.sin(-1 * stAng - swAng / 2) - height / 2;
break;
}
case c_oAscChartDataLabelsPos.inEnd:
{
var oPos = this._calculateInEndDLblPosition(stAng, swAng, radius, width, height, centerX, centerY);
if(!oPos.bError){
centerX = oPos.fX;
centerY = oPos.fY;
break;
}
tempCenterX = centerX + (radius) * Math.cos(-1 * stAng - swAng / 2);
tempCenterY = centerY - (radius) * Math.sin(-1 * stAng - swAng / 2);
if(tempCenterX < centerX && tempCenterY < centerY)
{
centerX = tempCenterX;
centerY = tempCenterY;
}
else if(tempCenterX > centerX && tempCenterY < centerY)
{
centerX = tempCenterX - width;
centerY = tempCenterY;
}
else if(tempCenterX < centerX && tempCenterY > centerY)
{
centerX = tempCenterX;
centerY = tempCenterY - height;
}
else
{
centerX = tempCenterX - width;
centerY = tempCenterY - height;
}
break;
}
case c_oAscChartDataLabelsPos.outEnd:
{
tempCenterX = centerX + (radius) * Math.cos(-1 * stAng - swAng / 2);
tempCenterY = centerY - (radius) * Math.sin(-1 * stAng - swAng / 2);
if(tempCenterX < centerX && tempCenterY < centerY)
{
centerX = tempCenterX - width;
centerY = tempCenterY - height;
}
else if(tempCenterX > centerX && tempCenterY < centerY)
{
centerX = tempCenterX;
centerY = tempCenterY - height;
}
else if(tempCenterX < centerX && tempCenterY > centerY)
{
centerX = tempCenterX - width;
centerY = tempCenterY;
}
else
{
centerX = tempCenterX;
centerY = tempCenterY;
}
break;
}
}
if(centerX < 0)
centerX = 0;
if(centerX + width > this.chartProp.widthCanvas / pxToMm)
centerX = this.chartProp.widthCanvas / pxToMm - width;
if(centerY < 0)
centerY = 0;
if(centerY + height > this.chartProp.heightCanvas / pxToMm)
centerY = this.chartProp.heightCanvas / pxToMm - height;
return {x: centerX, y: centerY};
},
//****fast calulate and drawing(for switch on slow drawing: change name function _Slow)
_reсalculatePie3D: function ()
{
var trueWidth = this.chartProp.trueWidth;
var trueHeight = this.chartProp.trueHeight;
var numCache = this._getFirstRealNumCache();
var sumData = this.cChartDrawer._getSumArray(numCache, true);
var radius = Math.min(trueHeight, trueWidth)/2;
var radius = Math.min(trueHeight, trueWidth) / 2;
if(radius < 0)
{
radius = 0;
}
var xCenter = this.chartProp.chartGutter._left + trueWidth/2;
var yCenter = this.chartProp.chartGutter._top + trueHeight/2;
var startAngle = this.cChartDrawer.processor3D.angleOy ? this.cChartDrawer.processor3D.angleOy : 0;
var startAngle3D = startAngle !== 0 && startAngle !== undefined ? this._changeAngle(radius, Math.PI/2, startAngle, xCenter, yCenter, this.properties3d) : 0;
this.angleFor3D = Math.PI/2 - startAngle3D;
startAngle = startAngle + Math.PI / 2;
for (var i = numCache.length - 1; i >= 0; i--)
{
var val = numCache[i].val;
var partOfSum = numCache[i].val / sumData;
var swapAngle = Math.abs((parseFloat(partOfSum)) * (Math.PI * 2));
if(!this.paths.series)
{
this.paths.series = [];
}
this.paths.series[i] = this._calculateSegment3D(startAngle, swapAngle, radius, xCenter, yCenter);
startAngle += swapAngle;
}
},
_calculateArc3D : function(radius, stAng, swAng, xCenter, yCenter, bIsNotDrawFrontFace)
{
var properties = this.cChartDrawer.processor3D.calculatePropertiesForPieCharts();
var depth = properties.depth;
var radius1 = properties.radius1;
var radius2 = properties.radius2;
var pxToMm = this.chartProp.pxToMM;
var pathH = this.chartProp.pathH;
var pathW = this.chartProp.pathW;
var t = this;
var gdLst = [];
gdLst["w"] = 1;
gdLst["h"] = 1;
swAng = this._changeAngle(radius, stAng, swAng, xCenter, yCenter, properties);
stAng = this.angleFor3D; stAng = this.angleFor3D;
//корректируем центр //корректируем центр
yCenter = yCenter - depth / 2; yCenter = yCenter - depth / 2;
...@@ -8518,209 +8272,952 @@ drawPieChart.prototype = ...@@ -8518,209 +8272,952 @@ drawPieChart.prototype =
var endAng = startAng + swapAng; var endAng = startAng + swapAng;
var p = getSegmentPoints(startAng, endAng); var p = getSegmentPoints(startAng, endAng);
path.moveTo(p.x0 /pxToMm * pathW, p.y0 / pxToMm * pathH); path.moveTo(p.x0 /pxToMm * pathW, p.y0 / pxToMm * pathH);
path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * startAng*cToDeg, -1 * swapAng*cToDeg); path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * startAng*cToDeg, -1 * swapAng*cToDeg);
path.lnTo(p.x3 /pxToMm * pathW, p.y3 / pxToMm * pathH); path.lnTo(p.x3 /pxToMm * pathW, p.y3 / pxToMm * pathH);
path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * startAng*cToDeg - 1 * swapAng*cToDeg, 1 * swapAng*cToDeg); path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * startAng*cToDeg - 1 * swapAng*cToDeg, 1 * swapAng*cToDeg);
path.lnTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH); path.lnTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH);
path.recalculate(gdLst); path.recalculate(gdLst);
return path;
};
var calculateUpFace = function(startAng, swapAng)
{
var path = getNewPath();
var endAng = startAng + swapAng;
var p = getSegmentPoints(startAng, endAng);
path.moveTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH);
path.lnTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH);
path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * stAng*cToDeg, -1 * swapAng*cToDeg);
path.lnTo(xCenter /pxToMm * pathW, yCenter / pxToMm * pathH);
path.recalculate(gdLst);
return path;
};
var calculateDownFace = function(startAng, swapAng)
{
var path = getNewPath();
var endAng = startAng + swapAng;
var p = getSegmentPoints(startAng, endAng);
path.moveTo(xCenter / pxToMm * pathW, (yCenter + depth) / pxToMm * pathH);
path.lnTo(p.x0 / pxToMm * pathW, (p.y0 + depth) / pxToMm * pathH);
path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * stAng*cToDeg, -1 * swapAng*cToDeg);
path.lnTo(xCenter /pxToMm * pathW, (yCenter + depth) / pxToMm * pathH);
path.recalculate(gdLst);
return path;
};
//FRONT FACES
//break front faces
var arrAngles = breakAng(stAng, swAng);
var frontPath = [];
for(var i = 1; i < arrAngles.length; i++)
{
var start = arrAngles[i - 1].angle;
var end = arrAngles[i].angle;
var swap = end - start;
if((start >= 0 && start >= Math.PI && start <= 2 * Math.PI) || (start < 0 && start >= -Math.PI && start <= 0))
{
frontPath.push(calculateFrontFace(start, swap));
}
}
//INSIDE FACES
var insidePath = calculateInsideFaces(stAng, swAng);
//UP FACE
var upPath = calculateUpFace(stAng, swAng);
//DOWN FACE
var downPath = calculateDownFace(stAng, swAng);
this.angleFor3D += swAng;
return {frontPath: frontPath, upPath: upPath, insidePath: insidePath, downPath: downPath};
},
_calculateSegment3D: function (startAngle, swapAngle, radius, xCenter, yCenter)
{
if(isNaN(swapAngle))
{
return null;
}
if(radius < 0)
{
radius = 0;
}
var path = [];
path.push(this._calculateArc3D(radius, startAngle, swapAngle, xCenter, yCenter));
return path;
},
_calculateSegment3DPerspective: function(radiusUp1, radiusUp2, radiusDown1, radiusDown2, angles1, angles2, center1, center2, pointCenter1, pointCenter2, upFaceSign)
{
var xCenter = center1.x, yCenter = center1.y, xCenter1 = center2.x, yCenter1 = center2.y;
var startAngle1 = angles1.start, swapAngle1 = angles1.swap, startAngle2 = angles2.start, swapAngle2 = angles2.swap;
var pxToMm = this.chartProp.pxToMM;
var pathH = this.chartProp.pathH;
var pathW = this.chartProp.pathW;
var gdLst = [];
gdLst["w"] = 1;
gdLst["h"] = 1;
var getNewPath = function()
{
var path = new Path();
path.pathH = pathH;
path.pathW = pathW;
return path;
};
var getSegmentPoints = function(startAng, endAng, startAng2, endAng2)
{
var radiusSpec = (radiusUp1 * radiusUp2) / Math.sqrt(Math.pow(radiusUp2, 2) * Math.pow((Math.cos(startAng)), 2) + Math.pow(radiusUp1, 2) * Math.pow(Math.sin(startAng),2));
var radiusSpec2 = (radiusUp1 * radiusUp2) / Math.sqrt(Math.pow(radiusUp2, 2) * Math.pow((Math.cos(endAng)), 2) + Math.pow(radiusUp1, 2) * Math.pow(Math.sin(endAng),2));
var radiusSpec11 = (radiusDown1 * radiusDown2) / Math.sqrt(Math.pow(radiusDown2, 2) * Math.pow((Math.cos(startAng2)), 2) + Math.pow(radiusDown1, 2) * Math.pow(Math.sin(startAng2),2));
var radiusSpec12 = (radiusDown1 * radiusDown2) / Math.sqrt(Math.pow(radiusDown2, 2) * Math.pow((Math.cos(endAng2)), 2) + Math.pow(radiusDown1, 2) * Math.pow(Math.sin(endAng2),2));
var x0 = (xCenter + radiusSpec*Math.cos(startAng));
var y0 = (yCenter - radiusSpec*Math.sin(startAng));
var x1 = (xCenter1 + radiusSpec11*Math.cos(startAng2));
var y1 = ((yCenter1) - radiusSpec11*Math.sin(startAng2));
var x2 = (xCenter + radiusSpec2*Math.cos(endAng));
var y2 = (yCenter - radiusSpec2*Math.sin(endAng));
var x3 = (xCenter1 + radiusSpec12 * Math.cos(endAng2));
var y3 = ((yCenter1) - radiusSpec12 * Math.sin(endAng2));
return {x0: x0, y0: y0, x1: x1, y1: y1, x2: x2, y2: y2, x3: x3, y3: y3};
};
var breakAng = function(startAng, swapAng)
{
var res = [];
var endAng = startAng + swapAng;
res.push({angle: startAng});
var tempStartAng = startAng;
var tempEndAng = endAng;
var tempPI = Math.PI;
if(tempStartAng <= -2*tempPI && tempEndAng > -2*tempPI)
{
res.push({angle: -2*Math.PI});
}
if(tempStartAng <= -tempPI && tempEndAng > -tempPI)
{
res.push({angle: -Math.PI});
}
if(tempStartAng <= 0 && tempEndAng > 0)
{
res.push({angle: 0});
}
if(tempStartAng <= tempPI && tempEndAng > tempPI)
{
res.push({angle: Math.PI});
}
if(tempStartAng <= 2*tempPI && tempEndAng > 2*tempPI)
{
res.push({angle: 2*Math.PI});
}
res.push({angle: endAng});
return res;
};
var calculateInsideFaces = function(startAng1, swapAng1, startAng2, swapAng2)
{
var path = getNewPath();
var endAng1 = startAng1 + swapAng1;
var endAng2 = startAng2 + swapAng2;
var p = getSegmentPoints(startAng1, endAng1, startAng2, endAng2);
path.moveTo(pointCenter1.x /pxToMm * pathW, pointCenter1.y / pxToMm * pathH);
path.lnTo(p.x0 /pxToMm * pathW, p.y0 / pxToMm * pathH);
path.lnTo(p.x1 /pxToMm * pathW, p.y1 / pxToMm * pathH);
path.lnTo(pointCenter2.x / pxToMm * pathW, (pointCenter2.y) / pxToMm * pathH);
path.moveTo(pointCenter1.x /pxToMm * pathW, pointCenter1.y / pxToMm * pathH);
path.lnTo(p.x2 / pxToMm * pathW, p.y2 / pxToMm * pathH);
path.lnTo(p.x3 / pxToMm * pathW, p.y3 / pxToMm * pathH);
path.lnTo(pointCenter2.x / pxToMm * pathW, (pointCenter2.y) / pxToMm * pathH);
path.recalculate(gdLst);
return path;
};
var calculateFrontFace = function(startAng, swapAng, startAng2, swapAng2)
{
var path = getNewPath();
var endAng = startAng + swapAng;
var endAng2 = startAng2 + swapAng2;
var p = getSegmentPoints(startAng, endAng, startAng2, endAng2);
//var p2 = getSegmentPoints(startAng2, endAng2);
path.moveTo(p.x0 /pxToMm * pathW, p.y0 / pxToMm * pathH);
path.arcTo(radiusUp1 / pxToMm * pathW, radiusUp2 / pxToMm * pathH, -1 * startAng*cToDeg, -1 * swapAng*cToDeg);
path.lnTo(p.x3 /pxToMm * pathW, p.y3 / pxToMm * pathH);
path.arcTo(radiusDown1 / pxToMm * pathW, radiusDown2 / pxToMm * pathH, -1 * startAng2*cToDeg - 1 * swapAng2*cToDeg, 1 * swapAng2*cToDeg);
path.lnTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH);
path.recalculate(gdLst);
return path;
};
var calculateUpFace = function(startAng, swapAng)
{
var path = getNewPath();
var radiusSpec = (radiusUp1 * radiusUp2) / Math.sqrt(Math.pow(radiusUp2, 2) * Math.pow((Math.cos(startAng)), 2) + Math.pow(radiusUp1, 2) * Math.pow(Math.sin(startAng),2));
var x0 = (xCenter + radiusSpec*Math.cos(startAng));
var y0 = (yCenter - radiusSpec*Math.sin(startAng));
path.moveTo(pointCenter1.x / pxToMm * pathW, pointCenter1.y / pxToMm * pathH);
path.lnTo(x0 / pxToMm * pathW, y0 / pxToMm * pathH);
path.arcTo(radiusUp1 / pxToMm * pathW, radiusUp2 / pxToMm * pathH, -1 * startAng*cToDeg, -1 * swapAng*cToDeg);
path.lnTo(pointCenter1.x /pxToMm * pathW, pointCenter1.y / pxToMm * pathH);
path.recalculate(gdLst);
return path;
};
var calculateDownFace = function(startAng, swapAng)
{
var path = getNewPath();
var radiusSpec = (radiusDown1 * radiusDown2) / Math.sqrt(Math.pow(radiusDown2, 2) * Math.pow((Math.cos(startAng)), 2) + Math.pow(radiusDown1, 2) * Math.pow(Math.sin(startAng),2));
//var radiusSpec2 = (radius11 * radius2) / Math.sqrt(Math.pow(radius2, 2) * Math.pow((Math.cos(endAng)), 2) + Math.pow(radius11, 2) * Math.pow(Math.sin(endAng),2))
var x = (xCenter1 + radiusSpec*Math.cos(startAng));
var y = (yCenter1 - radiusSpec*Math.sin(startAng));
path.moveTo(pointCenter2.x / pxToMm * pathW, (pointCenter2.y) / pxToMm * pathH);
path.lnTo(x / pxToMm * pathW, y / pxToMm * pathH);
path.arcTo(radiusDown1 / pxToMm * pathW, radiusDown2 / pxToMm * pathH, -1 * startAng*cToDeg, -1 * swapAng*cToDeg);
path.lnTo(pointCenter2.x /pxToMm * pathW, (pointCenter2.y) / pxToMm * pathH);
path.recalculate(gdLst);
return path;
};
//FRONT FACES
//break front faces
var arrAngles = breakAng(startAngle1, swapAngle1);
var arrAngles2 = breakAng(startAngle2, swapAngle2);
var frontPath = [];
for(var i = 1; i < arrAngles.length; i++)
{
var start = arrAngles[i - 1].angle;
var end = arrAngles[i].angle;
var swap = end - start;
var start2 = arrAngles2[i - 1].angle;
var end2;
if(!arrAngles2[i])
{
end2 = arrAngles2[i - 1].angle;
}
else
{
end2 = arrAngles2[i].angle;
}
var swap2 = end2 - start2;
if((start >= 0 && start >= Math.PI && start <= 2 * Math.PI) || (start < 0 && start >= -Math.PI && start <= 0))
{
frontPath.push(calculateFrontFace(upFaceSign*start, upFaceSign*swap, start2, swap2));
}
}
//INSIDE FACES
var insidePath = calculateInsideFaces(upFaceSign*startAngle1, upFaceSign*swapAngle1, startAngle2, swapAngle2);
//UP FACE
var upPath = calculateUpFace(upFaceSign*startAngle1, upFaceSign*swapAngle1);
//DOWN FACE
var downPath = calculateDownFace(startAngle2, swapAngle2);
return {frontPath: frontPath, upPath: upPath, insidePath: insidePath, downPath: downPath};
},
_drawPie3D: function ()
{
var numCache = this._getFirstRealNumCache();
var t = this;
var shade = "shade";
var shadeValue = 35000;
var drawPath = function(path, pen, brush, isShadePen, isShadeBrush)
{
if(path)
{
if(brush)
{
var props = t.cChartSpace.getParentObjects();
var duplicateBrush = brush.createDuplicate();
var cColorMod = new AscFormat.CColorMod;
cColorMod.val = shadeValue;
cColorMod.name = shade;
if(duplicateBrush)
{
duplicateBrush.addColorMod(cColorMod);
duplicateBrush.calculate(props.theme, props.slide, props.layout, props.master, new AscFormat.CUniColor().RGBA);
}
if(isShadePen)
{
pen = AscFormat.CreatePenFromParams(duplicateBrush, undefined, undefined, undefined, undefined, 0);
}
if(isShadeBrush)
{
brush = duplicateBrush;
}
}
t.cChartDrawer.drawPath(path, pen, brush);
}
};
var pen = numCache[0].pen;
drawPath(this.paths.test, pen, null);
var sides = {down: 0, inside: 1, up: 2, front: 3};
var drawPaths = function(side)
{
for (var i = 0,len = numCache.length; i < len; i++)
{
var val = numCache[i];
var brush = val.brush;
var pen = val.pen;
var path = t.paths.series[i];
if(path)
{
for(var j = path.length - 1; j >= 0; j--)
{
if(side === sides.down)
{
drawPath(path[j].downPath, pen, null);
}
else if(side === sides.inside)
{
drawPath(path[j].insidePath, pen, brush, null, true);
}
else if(side === sides.up)
{
drawPath(path[j].upPath, pen, brush);
}
else if(side === sides.frontPath)
{
for(var k = 0; k < path[j].frontPath.length;k++)
{
drawPath(path[j].frontPath[k], pen, brush, true, true);
}
}
}
}
}
};
drawPaths(sides.down);
drawPaths(sides.inside);
if(this.tempDrawOrder !== null)
{
drawPaths(sides.up);
drawPaths(sides.frontPath);
}
else
{
drawPaths(sides.frontPath);
drawPaths(sides.up);
}
},
//best fit DLbl
_calculateBestFitPosition: function(fStartAngle, fSweepAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY, bLayout){
var fStartAngle_ = fStartAngle;
var fEndAngle = fStartAngle + fSweepAngle;
if(bLayout){
return this._calculateBestFitPositionOuter(fStartAngle_, fEndAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY);
}
var oRet = this._calculateBestFitPositionInner(fStartAngle_, fEndAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY);
if(!oRet.bError){
if(AscFormat.fCheckBoxIntersectionSegment(oRet.fX, oRet.fY, fWidth, fHeight, fCenterX, fCenterY, fCenterX + fRadius*Math.cos(fStartAngle_), fCenterY + fRadius*Math.sin(fStartAngle_))
|| AscFormat.fCheckBoxIntersectionSegment(oRet.fX, oRet.fY, fWidth, fHeight, fCenterX, fCenterY, fCenterX + fRadius*Math.cos(fEndAngle), fCenterY + fRadius*Math.sin(fEndAngle))){
oRet.bError = true;
}
}
if(oRet.bError){
return this._calculateBestFitPositionOuter(fStartAngle_, fEndAngle, fRadius, fWidth, fHeight, fCenterX, fCenterY);
}
return oRet;
},
_calculateBestFitPositionInner: function(fStartAngle, fEndAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY){
var oResult = {bError: true};
var fBisectAngle = AscFormat.normalizeRotate((fStartAngle + fEndAngle)/2.0);
if(AscFormat.fApproxEqual(fBisectAngle, 0) || AscFormat.fApproxEqual(fBisectAngle, Math.PI/2) || AscFormat.fApproxEqual(fBisectAngle, Math.PI) || AscFormat.fApproxEqual(fBisectAngle, 3*Math.PI/2)){
return this._calculateInEndDLblPosition(fStartAngle, fStartAngle + fEndAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY);
}
var fBisectAngle2 = AscFormat.normalizeRotate(fBisectAngle + Math.PI/4) - Math.PI/4;
var nIndexArea = ((fBisectAngle2 + Math.PI/4)/(Math.PI/2)) >> 0;
var fLengthCoeff = ((fBisectAngle2 + Math.PI/4) - (Math.PI/2)*nIndexArea)/(Math.PI/2);
var fXs = fCenterX + fPieRadius*Math.cos(fBisectAngle);
var fYs = fCenterY + fPieRadius*Math.sin(fBisectAngle);
var fDeltaX, fDeltaY, oSolvation;
switch(nIndexArea){
case 0:{
if(fBisectAngle2 < 0){
fDeltaX = fLabelWidth;
fDeltaY = -(1 - fLengthCoeff)*fLabelHeight;
}
else{
fDeltaX = fLabelWidth;
fDeltaY = fLabelHeight*fLengthCoeff;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
}
else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
}
}
break;
}
case 1:{
if(fBisectAngle < Math.PI/2){
fDeltaX = (1 - fLengthCoeff)*fLabelWidth;
fDeltaY = fLabelHeight;
}
else{
fDeltaX = - fLengthCoeff*fLabelWidth;
fDeltaY = fLabelHeight;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY);
}
else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY);
}
}
break;
}
case 2:{
if(fBisectAngle < Math.PI){
fDeltaX = -fLabelWidth;
fDeltaY = (1 - fLengthCoeff)*fLabelHeight;
}
else{
fDeltaX = -fLabelWidth;
fDeltaY = - fLengthCoeff*fLabelHeight;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
}
else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
}
}
break;
}
case 3:{
fLengthCoeff = 1 - fLengthCoeff;
if(fBisectAngle < 3*Math.PI/2){
fDeltaX = -fLabelWidth*fLengthCoeff;
fDeltaY = -fLabelHeight;
}
else{
fDeltaX = (1 - fLengthCoeff)*fLabelWidth;
fDeltaY = -fLabelHeight;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 > 0 && oSolvation.x1 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight;
}
else if(oSolvation.x2 > 0 && oSolvation.x2 < 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight;
}
}
break;
}
}
return oResult;
},
_calculateBestFitPositionOuter: function(fStartAngle, fEndAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY){
var oResult = {bError: true};
var fBisectAngle = AscFormat.normalizeRotate((fStartAngle + fEndAngle)/2.0);
var fBisectAngle2 = AscFormat.normalizeRotate(fBisectAngle + Math.PI/4) - Math.PI/4;
var nIndexArea = ((fBisectAngle2 + Math.PI/4)/(Math.PI/2)) >> 0;
var fLengthCoeff = ((fBisectAngle2 + Math.PI/4) - (Math.PI/2)*nIndexArea)/(Math.PI/2);
var fXs = fCenterX + fPieRadius*Math.cos(fBisectAngle);
var fYs = fCenterY + fPieRadius*Math.sin(fBisectAngle);
var fDeltaX, fDeltaY, oSolvation;
var fAngleApproxDelta = 1e-4;
switch(nIndexArea){
case 0:{
if(AscFormat.fApproxEqual(fBisectAngle2, 0, fAngleApproxDelta)){
fDeltaX = 0;
fDeltaY = 0;
}
else if(fBisectAngle2 < 0){
fDeltaX = 0;
fDeltaY = fLengthCoeff*fLabelHeight;
}
else{
fDeltaX = 0;
fDeltaY = -(1 - fLengthCoeff)*fLabelHeight;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
}
else if(oSolvation.x2 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
}
else if(oSolvation.x1 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
}
else if(oSolvation.x2 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX);
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - (1 - fLengthCoeff)*fLabelHeight;
}
}
break;
}
case 1:{
if(AscFormat.fApproxEqual(fBisectAngle, Math.PI/2, fAngleApproxDelta)){
fDeltaX = 0;
fDeltaY = 0;
}
else if(fBisectAngle < Math.PI/2){
fDeltaX = -fLengthCoeff*fLabelWidth;
fDeltaY = 0;
}
else{
fDeltaX = (1 - fLengthCoeff)*fLabelWidth;
fDeltaY = 0;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY);
}
else if(oSolvation.x2 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY);
}
else if(oSolvation.x1 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY);
}
else if(oSolvation.x2 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth*fLengthCoeff;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY);
}
}
break;
}
case 2:{
if(AscFormat.fApproxEqual(fBisectAngle, Math.PI, fAngleApproxDelta)){
fDeltaX = 0;
fDeltaY = 0;
}
else if(fBisectAngle < Math.PI){
fDeltaX = 0;
fDeltaY = -fLengthCoeff*fLabelHeight;
}
else{
fDeltaX = 0;
fDeltaY = (1 - fLengthCoeff)*fLabelHeight;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
}
else if(oSolvation.x2 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
}
else if(oSolvation.x1 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - fLabelWidth;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
}
else if(oSolvation.x2 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - fLabelWidth;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight*fLengthCoeff;
}
}
break;
}
case 3:{
if(fBisectAngle < 3*Math.PI/2){
fDeltaX = fLabelWidth*fLengthCoeff;
fDeltaY = 0;
}
else{
fDeltaX = -(1 - fLengthCoeff)*fLabelWidth;
fDeltaY = 0;
}
oSolvation = AscFormat.fSolveQuadraticEquation(fPieRadius*fPieRadius, 2*(fDeltaX*(fXs - fCenterX) + fDeltaY*(fYs - fCenterY)), fDeltaX*fDeltaX + fDeltaY*fDeltaY - fPieRadius*fPieRadius);
if(!oSolvation.bError){
if(oSolvation.x1 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight;
}
else if(oSolvation.x2 >= 1){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight;
}
else if(oSolvation.x1 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x1*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
oResult.fY = fCenterY + oSolvation.x1*(fYs - fCenterY) - fLabelHeight;
}
else if(oSolvation.x2 >= 0){
oResult.bError = false;
oResult.fX = fCenterX + oSolvation.x2*(fXs - fCenterX) - (1 - fLengthCoeff)*fLabelWidth;
oResult.fY = fCenterY + oSolvation.x2*(fYs - fCenterY) - fLabelHeight;
}
}
break;
}
}
return oResult;
},
_calculateInEndDLblPosition: function(fStartAngle, fSweepAngle, fPieRadius, fLabelWidth, fLabelHeight, fCenterX, fCenterY){
var fEndAngle = fStartAngle + fSweepAngle;
var oResult = {bError: true, fX: 0.0, fY: 0.0};
var fBisectAngle = AscFormat.normalizeRotate((fStartAngle + fEndAngle)/2);
var nQuadrantIndex = (2.0*fBisectAngle/Math.PI) >> 0;
var fHalfRectWidthVector = fLabelWidth/ 2, fHalfRectHeightVector = fLabelHeight/2;
if(nQuadrantIndex === 1 || nQuadrantIndex == 2){
fHalfRectWidthVector = -fHalfRectWidthVector;
}
if(nQuadrantIndex === 2 || nQuadrantIndex == 3){
fHalfRectHeightVector = -fHalfRectHeightVector;
}
var fXs = fCenterX + fPieRadius*Math.cos(fBisectAngle), fYs = fCenterY + fPieRadius*Math.sin(fBisectAngle);
var a = fPieRadius*fPieRadius, b = 2*( (fXs - fCenterX)*fHalfRectWidthVector + (fYs - fCenterY)*fHalfRectHeightVector), c = fHalfRectWidthVector*fHalfRectWidthVector + fHalfRectHeightVector*fHalfRectHeightVector - fPieRadius*fPieRadius;
var oSolution = AscFormat.fSolveQuadraticEquation(a, b, c);
if(oSolution.bError){
return oResult;
}
var D = b*b - 4*a*c;
if(D < 0){
return oResult;
}
var t1 = oSolution.x1, t2 = oSolution.x2;
if(t1 > 0 && t1 < 1){
oResult.bError = false;
oResult.fX = fCenterX + t1*(fXs - fCenterX) - fLabelWidth/2;
oResult.fY = fCenterY + t1*(fYs - fCenterY) - fLabelHeight/2;
return oResult
}
if(t2 > 0 && t2 < 1){
oResult.bError = false;
oResult.fX = fCenterX + t2*(fXs - fCenterX) - fLabelWidth/2;
oResult.fY = fCenterY + t2*(fYs - fCenterY) - fLabelHeight/2;
return oResult
}
return oResult;
},
//For test
_calculateTestFrame: function(point1, point2, point3, point4, point5, point6, point7, point8)
{
var pxToMm = this.chartProp.pxToMM;
var pathH = this.chartProp.pathH;
var pathW = this.chartProp.pathW;
var path = new Path();
path.pathH = pathH;
path.pathW = pathW;
var gdLst = [];
gdLst["w"] = 1;
gdLst["h"] = 1;
path.moveTo(point1.x / pxToMm * pathW, point1.y / pxToMm * pathH);
path.lnTo(point2.x / pxToMm * pathW, point2.y / pxToMm * pathH);
path.lnTo(point3.x / pxToMm * pathW, point3.y / pxToMm * pathH);
path.lnTo(point4.x / pxToMm * pathW, point4.y / pxToMm * pathH);
path.lnTo(point1.x / pxToMm * pathW, point1.y / pxToMm * pathH);
path.moveTo(point5.x / pxToMm * pathW, point5.y / pxToMm * pathH);
path.lnTo(point6.x / pxToMm * pathW, point6.y / pxToMm * pathH);
path.lnTo(point7.x / pxToMm * pathW, point7.y / pxToMm * pathH);
path.lnTo(point8.x / pxToMm * pathW, point8.y / pxToMm * pathH);
path.lnTo(point5.x / pxToMm * pathW, point5.y / pxToMm * pathH);
return path; path.moveTo(point1.x / pxToMm * pathW, point1.y / pxToMm * pathH);
}; path.lnTo(point5.x / pxToMm * pathW, point5.y / pxToMm * pathH);
var calculateUpFace = function(startAng, swapAng) path.moveTo(point2.x / pxToMm * pathW, point2.y / pxToMm * pathH);
{ path.lnTo(point6.x / pxToMm * pathW, point6.y / pxToMm * pathH);
var path = getNewPath();
var endAng = startAng + swapAng; path.moveTo(point3.x / pxToMm * pathW, point3.y / pxToMm * pathH);
var p = getSegmentPoints(startAng, endAng); path.lnTo(point7.x / pxToMm * pathW, point7.y / pxToMm * pathH);
path.moveTo(xCenter / pxToMm * pathW, yCenter / pxToMm * pathH); path.moveTo(point4.x / pxToMm * pathW, point4.y / pxToMm * pathH);
path.lnTo(p.x0 / pxToMm * pathW, p.y0 / pxToMm * pathH); path.lnTo(point8.x / pxToMm * pathW, point8.y / pxToMm * pathH);
path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * stAng*cToDeg, -1 * swapAng*cToDeg);
path.lnTo(xCenter /pxToMm * pathW, yCenter / pxToMm * pathH);
path.recalculate(gdLst); path.recalculate(gdLst);
return path; this.paths.test = path;
}; },
var calculateDownFace = function(startAng, swapAng) //TODO delete after test
_recalculatePie3D_Slow: function ()
{ {
var path = getNewPath(); var trueWidth = this.chartProp.trueWidth;
var trueHeight = this.chartProp.trueHeight;
var endAng = startAng + swapAng; var numCache = this._getFirstRealNumCache();
var p = getSegmentPoints(startAng, endAng); var sumData = this.cChartDrawer._getSumArray(numCache, true);
path.moveTo(xCenter / pxToMm * pathW, (yCenter + depth) / pxToMm * pathH); var radius = Math.min(trueHeight, trueWidth) / 2;
path.lnTo(p.x0 / pxToMm * pathW, (p.y0 + depth) / pxToMm * pathH); if(radius < 0)
path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * stAng*cToDeg, -1 * swapAng*cToDeg); radius = 0;
path.lnTo(xCenter /pxToMm * pathW, (yCenter + depth) / pxToMm * pathH);
path.recalculate(gdLst); var xCenter = this.chartProp.chartGutter._left + trueWidth/2;
var yCenter = this.chartProp.chartGutter._top + trueHeight/2;
return path; var startAngle = this.cChartDrawer.processor3D.angleOy ? this.cChartDrawer.processor3D.angleOy : 0;
} var startAngle3D = startAngle !== 0 && startAngle !== undefined ? this._changeAngle(radius, Math.PI/2, startAngle, xCenter, yCenter, this.properties3d) : 0;
//FRONT FACES this.tempAngle = Math.PI/2 + startAngle;
//break front faces this.angleFor3D = Math.PI/2 - startAngle3D;
var arrAngles = breakAng(stAng, swAng);
var frontPath = []; //рисуем против часовой стрелки, поэтому цикл с конца
for(var i = 1; i < arrAngles.length; i++) var depth = this.properties3d.depth;
for(var n = 0; n < depth; n++)
{ {
var start = arrAngles[i - 1].angle; if(!this.paths.series)
var end = arrAngles[i].angle; this.paths.series = [];
var swap = end - start;
if((start >= 0 && start >= Math.PI && start <= 2 * Math.PI) || (start < 0 && start >= -Math.PI && start <= 0)) for (var i = numCache.length - 1; i >= 0; i--)
{ {
frontPath.push(calculateFrontFace(start, swap)); var angle = Math.abs((parseFloat(numCache[i].val / sumData)) * (Math.PI * 2));
if(!this.paths.series[n])
this.paths.series[n] = [];
if(sumData === 0)//TODO стоит пересмотреть
this.paths.series[n][i] = this._calculateEmptySegment(radius, xCenter, yCenter);
else
this.paths.series[n][i] = this._calculateSegment3D(angle, radius, xCenter, yCenter, n, i);
} }
} }
//INSIDE FACES
var insidePath = calculateInsideFaces(stAng, swAng);
//UP FACE
var upPath = calculateUpFace(stAng, swAng);
//DOWN FACE
var downPath = calculateDownFace(stAng, swAng);
this.angleFor3D += swAng;
return {frontPath: frontPath, upPath: upPath, insidePath: insidePath, downPath: downPath};
}, },
_calculateSegment3D: function (startAngle, swapAngle, radius, xCenter, yCenter) _calculateSegment3D_Slow: function (angle, radius, xCenter, yCenter, depth, i)
{
if(isNaN(swapAngle))
{ {
if(isNaN(angle))
return null; return null;
}
if(radius < 0) var startAngle = (this.tempAngle);
{ var swapAngle = angle;
radius = 0;
}
var path = []; var path = this._calculateArc3D(radius, startAngle, swapAngle, xCenter, yCenter, depth, i);
path.push(this._calculateArc3D(radius, startAngle, swapAngle, xCenter, yCenter));
this.tempAngle += angle;
return path; return path;
}, },
_calculateArc3D_Slow : function(radius, stAng, swAng, xCenter, yCenter, depth, seriaNum)
_drawPie3D: function ()
{ {
var numCache = this._getFirstRealNumCache(); var radius1 = this.properties3d.radius1;
var radius2 = this.properties3d.radius2;
var pxToMm = this.chartProp.pxToMM;
var t = this; var t = this;
var shade = "shade";
var shadeValue = 35000;
var drawPath = function(path, pen, brush, isShadePen, isShadeBrush) var x0, y0, radiusSpec;
{ var calculateProps = function()
if(path)
{ {
if(brush) if(t.usually3dPropsCalc && t.usually3dPropsCalc[seriaNum])
{ {
var props = t.cChartSpace.getParentObjects(); swAng = t.usually3dPropsCalc[seriaNum].swAng;
var duplicateBrush = brush.createDuplicate(); stAng = t.usually3dPropsCalc[seriaNum].stAng;
var cColorMod = new AscFormat.CColorMod; radiusSpec = t.usually3dPropsCalc[seriaNum].radiusSpec;
x0 = t.usually3dPropsCalc[seriaNum].x0;
cColorMod.val = shadeValue;
cColorMod.name = shade;
if(duplicateBrush) yCenter = yCenter + t.properties3d.depth / 2 - depth;
{ y0 = (yCenter - radiusSpec*Math.sin(stAng));
duplicateBrush.addColorMod(cColorMod);
duplicateBrush.calculate(props.theme, props.slide, props.layout, props.master, new AscFormat.CUniColor().RGBA);
}
if(isShadePen)
{
pen = AscFormat.CreatePenFromParams(duplicateBrush, undefined, undefined, undefined, undefined, 0);
} }
if(isShadeBrush) else
{ {
brush = duplicateBrush; swAng = t._changeAngle(radius, stAng, swAng, xCenter, yCenter, t.properties3d);
} stAng = t.angleFor3D;
}
t.cChartDrawer.drawPath(path, pen, brush); //корректируем центр
} yCenter = yCenter + t.properties3d.depth / 2 - depth;
radiusSpec = (radius1 * radius2) / Math.sqrt(Math.pow(radius2, 2) * Math.pow((Math.cos(stAng)), 2) + Math.pow(radius1, 2) * Math.pow(Math.sin(stAng),2));
x0 = (xCenter + radiusSpec*Math.cos(stAng));
y0 = (yCenter - radiusSpec*Math.sin(stAng));
}
}; };
//DOWN var path = new Path();
for (var i = 0,len = numCache.length; i < len; i++)
{
var val = numCache[i];
var brush = val.brush;
var pen = val.pen;
var path = this.paths.series[i];
if(path) var pathH = this.chartProp.pathH;
{ var pathW = this.chartProp.pathW;
for(var j = path.length - 1; j >= 0; j--) var gdLst = [];
{
drawPath(path[j].downPath, pen, null);
}
}
}
//INSIDE path.pathH = pathH;
for (var i = 0,len = numCache.length; i < len; i++) path.pathW = pathW;
{ gdLst["w"] = 1;
var val = numCache[i]; gdLst["h"] = 1;
var brush = val.brush;
var pen = val.pen;
var path = this.paths.series[i];
if(path) calculateProps();
{
for(var j = path.length - 1; j >= 0; j--)
{
drawPath(path[j].insidePath, pen, brush, null, true);
}
}
}
//FRONT path.moveTo(xCenter /pxToMm * pathW, yCenter / pxToMm * pathH);
for (var i = 0,len = numCache.length; i < len; i++) path.lnTo(x0 /pxToMm * pathW, y0 / pxToMm * pathH);
{ path.arcTo(radius1 / pxToMm * pathW, radius2 / pxToMm * pathH, -1 * stAng*cToDeg, -1 * swAng*cToDeg);
var val = numCache[i]; path.lnTo(xCenter /pxToMm * pathW, yCenter / pxToMm * pathH);
var brush = val.brush;
var pen = val.pen;
var path = this.paths.series[i];
if(path) path.recalculate(gdLst);
this.angleFor3D += swAng;
if(!this.usually3dPropsCalc[seriaNum])
this.usually3dPropsCalc[seriaNum] = {swAng: swAng, stAng: stAng, xCenter: xCenter, x0: x0, radiusSpec: radiusSpec};
return path;
},
_drawPie3D_Slow: function ()
{ {
for(var j = path.length - 1; j >= 0; j--) var numCache = this._getFirstRealNumCache();
var props = this.cChartSpace.getParentObjects();
var brush, pen, val;
var path;
for(var n = 0; n < this.paths.series.length; n++)
{ {
for(var k = 0; k < path[j].frontPath.length;k++) for (var i = 0, len = numCache.length; i < len; i++) {
val = numCache[i];
brush = val.brush;
if(n === 0 || n === this.paths.series.length - 1)
{ {
drawPath(path[j].frontPath[k], pen, brush, true, true); pen = val.pen;
}
}
} }
else
{
pen = null;
} }
//UP path = this.paths.series[n][i];
for (var i = 0,len = numCache.length; i < len; i++)
{
var val = numCache[i];
var brush = val.brush;
var pen = val.pen;
var path = this.paths.series[i];
if(path) var duplicateBrush = brush;
{ if(n !== this.paths.series.length - 1)
for(var j = path.length - 1; j >= 0; j--)
{ {
drawPath(path[j].upPath, pen, brush); duplicateBrush = brush.createDuplicate();
var cColorMod = new AscFormat.CColorMod;
cColorMod.val = 35000;
cColorMod.name = "shade";
duplicateBrush.addColorMod(cColorMod);
duplicateBrush.calculate(props.theme, props.slide, props.layout, props.master, new AscFormat.CUniColor().RGBA);
} }
this.cChartDrawer.drawPath(path, pen, duplicateBrush);
} }
} }
} }
}; };
...@@ -8758,7 +9255,7 @@ drawDoughnutChart.prototype = ...@@ -8758,7 +9255,7 @@ drawDoughnutChart.prototype =
_drawPie: function () _drawPie: function ()
{ {
var brush, pen, val; var brush, pen;
var path; var path;
var idxPoint, numCache; var idxPoint, numCache;
...@@ -8874,8 +9371,8 @@ drawDoughnutChart.prototype = ...@@ -8874,8 +9371,8 @@ drawDoughnutChart.prototype =
var x1 = xCenter + radius2*Math.cos(stAng); var x1 = xCenter + radius2*Math.cos(stAng);
var y1 = yCenter - radius2*Math.sin(stAng); var y1 = yCenter - radius2*Math.sin(stAng);
var x3 = xCenter + radius1*Math.cos(stAng + swAng); //var x3 = xCenter + radius1*Math.cos(stAng + swAng);
var y3 = yCenter - radius1*Math.sin(stAng + swAng); //var y3 = yCenter - radius1*Math.sin(stAng + swAng);
var x4 = xCenter + radius2*Math.cos(stAng + swAng); var x4 = xCenter + radius2*Math.cos(stAng + swAng);
var y4 = yCenter - radius2*Math.sin(stAng + swAng); var y4 = yCenter - radius2*Math.sin(stAng + swAng);
...@@ -8893,17 +9390,10 @@ drawDoughnutChart.prototype = ...@@ -8893,17 +9390,10 @@ drawDoughnutChart.prototype =
_calculateDLbl: function(chartSpace, ser, val) _calculateDLbl: function(chartSpace, ser, val)
{ {
var pxToMm = this.chartProp.pxToMM;
if(!this.paths.series[ser][val]) if(!this.paths.series[ser][val])
return; return;
var path = this.paths.series[ser][val].ArrPathCommand; var path = this.paths.series[ser][val].ArrPathCommand;
var x1 = path[0].X;
var y1 = path[0].Y;
var x2 = path[1].X;
var y2 = path[1].Y;
var radius1 = path[2].hR; var radius1 = path[2].hR;
var stAng = path[2].stAng; var stAng = path[2].stAng;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment