mirror of
https://github.com/UnickSoft/graphonline.git
synced 2026-02-16 10:40:57 +00:00
Change script location.
Split js code. Added cache and changed loading mechanism for js sources.
This commit is contained in:
89
script/features/draw_graph/model/BaseBackgroundDrawer.js
Normal file
89
script/features/draw_graph/model/BaseBackgroundDrawer.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Graph drawer.
|
||||
*/
|
||||
|
||||
|
||||
function CommonBackgroundStyle()
|
||||
{
|
||||
this.commonColor = '#ffffff';
|
||||
this.commonOpacity = 1.0;
|
||||
this.image = null;
|
||||
}
|
||||
|
||||
CommonBackgroundStyle.prototype.Clear = function ()
|
||||
{
|
||||
delete this.commonColor;
|
||||
delete this.commonOpacity;
|
||||
delete this.image;
|
||||
}
|
||||
|
||||
CommonBackgroundStyle.prototype.ShouldLoad = function (field)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CommonBackgroundStyle.prototype.saveToJson = function (field)
|
||||
{
|
||||
return JSON.stringify({commonColor: this.commonColor, commonOpacity: this.commonOpacity, image: this.image != null ? this.image.src : null});
|
||||
}
|
||||
|
||||
CommonBackgroundStyle.prototype.loadFromJson = function (json, callbackOnLoaded)
|
||||
{
|
||||
this.commonColor = json["commonColor"];
|
||||
this.commonOpacity = json["commonOpacity"];
|
||||
this.image = null;
|
||||
if (typeof json["image"] === 'string') {
|
||||
this.image = new Image();
|
||||
this.image.onload = function() {
|
||||
callbackOnLoaded();
|
||||
}
|
||||
this.image.src = json["image"];
|
||||
}
|
||||
}
|
||||
|
||||
PrintBackgroundStyle.prototype = Object.create(CommonBackgroundStyle.prototype);
|
||||
|
||||
function PrintBackgroundStyle()
|
||||
{
|
||||
CommonBackgroundStyle.apply(this, arguments);
|
||||
|
||||
this.commonColor = '#ffffff';
|
||||
this.commonOpacity = 1.0;
|
||||
this.image = null;
|
||||
}
|
||||
|
||||
function BaseBackgroundDrawer(context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
BaseBackgroundDrawer.prototype.Draw = function(style, width, height, position, scale)
|
||||
{
|
||||
var context = this.context;
|
||||
|
||||
var rect = new Rect(position, position.add(new Point(width / scale, height / scale)));
|
||||
|
||||
context.clearRect(-rect.minPoint.x, -rect.minPoint.y, rect.size().x + 1, rect.size().y + 1);
|
||||
|
||||
var oldOpacity = context.globalAlpha;
|
||||
if (style.commonOpacity > 0.0)
|
||||
{
|
||||
context.globalAlpha = style.commonOpacity;
|
||||
context.fillStyle = style.commonColor;
|
||||
context.fillRect(-rect.minPoint.x, -rect.minPoint.y, rect.size().x + 1, rect.size().y + 1);
|
||||
this.DrawImage(style, width, height, position, scale);
|
||||
}
|
||||
context.globalAlpha = oldOpacity;
|
||||
}
|
||||
|
||||
BaseBackgroundDrawer.prototype.DrawImage = function(style, width, height, position, scale)
|
||||
{
|
||||
if (style.image == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var context = this.context;
|
||||
|
||||
context.clearRect(0, 0, style.image.width, style.image.height);
|
||||
context.drawImage(style.image, 0, 0)
|
||||
}
|
||||
564
script/features/draw_graph/model/BaseEdgeDrawer.js
Normal file
564
script/features/draw_graph/model/BaseEdgeDrawer.js
Normal file
@@ -0,0 +1,564 @@
|
||||
/**
|
||||
* Graph drawer.
|
||||
*/
|
||||
|
||||
|
||||
const lineDashTypes = [
|
||||
[],
|
||||
[4, 4],
|
||||
[12, 12],
|
||||
[16, 4, 4, 4],
|
||||
];
|
||||
|
||||
// Common text position
|
||||
const WeightTextCenter = 0,
|
||||
WeightTextUp = 1;
|
||||
|
||||
function BaseEdgeStyle()
|
||||
{
|
||||
this.baseStyles = [];
|
||||
}
|
||||
|
||||
BaseEdgeStyle.prototype.GetStyle = function (baseStyle, object)
|
||||
{
|
||||
this.baseStyles.forEach(function(element) {
|
||||
var styleObject = globalApplication.GetStyle("edge", element, object);
|
||||
baseStyle = styleObject.GetStyle(baseStyle, object);
|
||||
});
|
||||
|
||||
if (this.hasOwnProperty('weightText'))
|
||||
baseStyle.weightText = this.weightText;
|
||||
if (this.hasOwnProperty('strokeStyle'))
|
||||
baseStyle.strokeStyle = this.strokeStyle;
|
||||
if (this.hasOwnProperty('fillStyle'))
|
||||
baseStyle.fillStyle = this.fillStyle;
|
||||
if (this.hasOwnProperty('textPadding'))
|
||||
baseStyle.textPadding = this.textPadding;
|
||||
if (this.hasOwnProperty('textStrokeWidth'))
|
||||
baseStyle.textStrokeWidth = this.textStrokeWidth;
|
||||
if (this.hasOwnProperty('lineDash'))
|
||||
baseStyle.lineDash = this.lineDash;
|
||||
if (this.hasOwnProperty('additionalTextColor'))
|
||||
baseStyle.additionalTextColor = this.additionalTextColor;
|
||||
if (this.hasOwnProperty('weightPosition'))
|
||||
baseStyle.weightPosition = this.weightPosition;
|
||||
|
||||
return this.FixNewFields(baseStyle);
|
||||
}
|
||||
|
||||
BaseEdgeStyle.prototype.FixNewFields = function (style)
|
||||
{
|
||||
if (!style.hasOwnProperty('lineDash'))
|
||||
style.lineDash = 0;
|
||||
|
||||
if (!style.hasOwnProperty('weightPosition'))
|
||||
style.weightPosition = WeightTextCenter;
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
BaseEdgeStyle.prototype.Clear = function ()
|
||||
{
|
||||
delete this.weightText;
|
||||
delete this.strokeStyle;
|
||||
delete this.fillStyle;
|
||||
delete this.textPadding;
|
||||
delete this.textStrokeWidth;
|
||||
delete this.lineDash;
|
||||
delete this.additionalTextColor;
|
||||
delete this.weightPosition;
|
||||
}
|
||||
|
||||
BaseEdgeStyle.prototype.ShouldLoad = function (field)
|
||||
{
|
||||
return field != "baseStyles";
|
||||
}
|
||||
|
||||
function CommonEdgeStyle()
|
||||
{
|
||||
BaseEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#c7b7c7';
|
||||
this.weightText = '#f0d543';
|
||||
this.fillStyle = '#68aeba';
|
||||
this.textPadding = 4;
|
||||
this.textStrokeWidth = 2;
|
||||
this.lineDash = 0;
|
||||
this.additionalTextColor = '#c7b7c7';
|
||||
this.weightPosition = WeightTextCenter;
|
||||
}
|
||||
|
||||
CommonEdgeStyle.prototype = Object.create(BaseEdgeStyle.prototype);
|
||||
|
||||
function CommonPrintEdgeStyle()
|
||||
{
|
||||
BaseEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#000000';
|
||||
this.weightText = '#000000';
|
||||
this.fillStyle = '#FFFFFF';
|
||||
this.textPadding = 4;
|
||||
this.textStrokeWidth = 2;
|
||||
|
||||
this.baseStyles.push("common");
|
||||
}
|
||||
CommonPrintEdgeStyle.prototype = Object.create(BaseEdgeStyle.prototype);
|
||||
|
||||
function SelectedEdgeStyle0()
|
||||
{
|
||||
BaseEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#f0d543';
|
||||
this.weightText = '#f0d543';
|
||||
this.fillStyle = '#c7627a';
|
||||
|
||||
this.baseStyles.push("common");
|
||||
}
|
||||
SelectedEdgeStyle0.prototype = Object.create(BaseEdgeStyle.prototype);
|
||||
|
||||
function SelectedEdgeStyle1()
|
||||
{
|
||||
BaseEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#8FBF83';
|
||||
this.weightText = '#8FBF83';
|
||||
this.fillStyle = '#F9F9D5';
|
||||
|
||||
this.baseStyles.push("selected");
|
||||
}
|
||||
SelectedEdgeStyle1.prototype = Object.create(BaseEdgeStyle.prototype);
|
||||
|
||||
function SelectedEdgeStyle2()
|
||||
{
|
||||
BaseEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#8C4C86';
|
||||
this.weightText = '#8C4C86';
|
||||
this.fillStyle = '#253267';
|
||||
|
||||
this.baseStyles.push("selected");
|
||||
}
|
||||
SelectedEdgeStyle2.prototype = Object.create(BaseEdgeStyle.prototype);
|
||||
|
||||
|
||||
function SelectedEdgeStyle3()
|
||||
{
|
||||
BaseEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#6188FF';
|
||||
this.weightText = '#6188FF';
|
||||
this.fillStyle = '#E97CF9';
|
||||
|
||||
this.baseStyles.push("selected");
|
||||
}
|
||||
SelectedEdgeStyle3.prototype = Object.create(BaseEdgeStyle.prototype);
|
||||
|
||||
|
||||
function SelectedEdgeStyle4()
|
||||
{
|
||||
BaseEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#C6B484';
|
||||
this.weightText = '#C6B484';
|
||||
this.fillStyle = '#E0DEE1';
|
||||
|
||||
this.baseStyles.push("selected");
|
||||
}
|
||||
SelectedEdgeStyle4.prototype = Object.create(BaseEdgeStyle.prototype);
|
||||
|
||||
function SelectedEdgePrintStyle()
|
||||
{
|
||||
BaseEdgeStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#AAAAAA';
|
||||
this.weightText = '#000000';
|
||||
this.fillStyle = '#AAAAAA';
|
||||
|
||||
this.baseStyles.push("printed");
|
||||
}
|
||||
SelectedEdgePrintStyle.prototype = Object.create(BaseEdgeStyle.prototype);
|
||||
|
||||
var DefaultSelectedEdgeStyles = [new SelectedEdgeStyle0(), new SelectedEdgeStyle1(),
|
||||
new SelectedEdgeStyle2(), new SelectedEdgeStyle3(), new SelectedEdgeStyle4()];
|
||||
|
||||
var DefaultPrintSelectedEdgeStyles = [new SelectedEdgePrintStyle()];
|
||||
|
||||
function BaseEdgeDrawer(context, drawObjects)
|
||||
{
|
||||
if (drawObjects === undefined)
|
||||
{
|
||||
drawObjects = null;
|
||||
}
|
||||
|
||||
this.context = context;
|
||||
|
||||
this.drawObject = null;
|
||||
this.drawArc = null;
|
||||
this.startArrowDirection = null;
|
||||
this.finishArrowDirection = null;
|
||||
this.textCenterObject = null;
|
||||
this.getPointOnArc = null;
|
||||
|
||||
if (drawObjects)
|
||||
{
|
||||
if (drawObjects.hasOwnProperty("drawObject"))
|
||||
this.drawObject = drawObjects.drawObject;
|
||||
if (drawObjects.hasOwnProperty("drawArc"))
|
||||
this.drawArc = drawObjects.drawArc;
|
||||
if (drawObjects.hasOwnProperty("startArrowDirection"))
|
||||
this.startArrowDirection = drawObjects.startArrowDirection;
|
||||
if (drawObjects.hasOwnProperty("finishArrowDirection"))
|
||||
this.finishArrowDirection = drawObjects.finishArrowDirection;
|
||||
if (drawObjects.hasOwnProperty("textCenterObject"))
|
||||
this.textCenterObject = drawObjects.textCenterObject;
|
||||
if (drawObjects.hasOwnProperty("getPointOnArc"))
|
||||
this.getPointOnArc = drawObjects.getPointOnArc;
|
||||
}
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.Draw = function(baseEdge, arcStyle)
|
||||
{
|
||||
if (this.drawObject && this.drawObject != this)
|
||||
{
|
||||
this.drawObject.Draw(baseEdge, arcStyle);
|
||||
return;
|
||||
}
|
||||
|
||||
this.SetupStyle(baseEdge, arcStyle);
|
||||
|
||||
var lengthArrow = Math.max(baseEdge.model.width * 4, 8);
|
||||
var widthArrow = Math.max(baseEdge.model.width * 2, 4);
|
||||
var position1 = baseEdge.vertex1.position;
|
||||
var position2 = baseEdge.vertex2.position;
|
||||
var direction = position1.subtract(position2);
|
||||
direction.normalize(1.0);
|
||||
var positions = baseEdge.GetEdgePositionsShift();
|
||||
|
||||
var hasStartStyle = !position1.equals(position2) && baseEdge.GetStartEdgeStyle() != "";
|
||||
var hasFinishStyle = !position1.equals(position2) && baseEdge.GetFinishEdgeStyle() != "";
|
||||
|
||||
var arcPos1 = positions[0];
|
||||
var arcPos2 = positions[1];
|
||||
|
||||
if (hasStartStyle)
|
||||
{
|
||||
var dirArrow = this.GetStartArrowDirection(positions[0], positions[1], lengthArrow);
|
||||
arcPos1 = arcPos1.add(dirArrow.multiply(lengthArrow / 2));
|
||||
}
|
||||
|
||||
if (hasFinishStyle)
|
||||
{
|
||||
var dirArrow = this.GetFinishArrowDirection(positions[0], positions[1], lengthArrow);
|
||||
arcPos2 = arcPos2.add(dirArrow.multiply(-lengthArrow / 2));
|
||||
}
|
||||
|
||||
this.DrawArc (arcPos1, arcPos2, arcStyle);
|
||||
|
||||
this.context.fillStyle = this.context.strokeStyle;
|
||||
this.context.lineWidth = 0;
|
||||
|
||||
if (hasStartStyle)
|
||||
{
|
||||
this.DrawArrow(positions[0], this.GetStartArrowDirection(positions[0], positions[1], lengthArrow), lengthArrow, widthArrow);
|
||||
}
|
||||
if (hasFinishStyle)
|
||||
{
|
||||
this.DrawArrow(positions[1], this.GetFinishArrowDirection(positions[0], positions[1], lengthArrow), lengthArrow, widthArrow);
|
||||
}
|
||||
|
||||
this.SetupStyle(baseEdge, arcStyle);
|
||||
|
||||
if (arcStyle.weightPosition == WeightTextCenter)
|
||||
{
|
||||
if (baseEdge.GetText().length > 0)
|
||||
{
|
||||
this.DrawWeight(positions[0], positions[1], baseEdge.GetText(), arcStyle, false);
|
||||
}
|
||||
|
||||
if (baseEdge.GetUpText().length > 0)
|
||||
{
|
||||
this.DrawUpText(positions[0], positions[1], baseEdge.GetUpText(), arcStyle, false, arcStyle.additionalTextColor, baseEdge.model.width / 2 + 20, null);
|
||||
}
|
||||
}
|
||||
else if (arcStyle.weightPosition == WeightTextUp)
|
||||
{
|
||||
if (baseEdge.GetText().length > 0)
|
||||
{
|
||||
this.DrawUpText(positions[0], positions[1], baseEdge.GetText(), arcStyle, false, arcStyle.weightText, baseEdge.model.width / 2 + 10, "16px");
|
||||
}
|
||||
|
||||
if (baseEdge.GetUpText().length > 0)
|
||||
{
|
||||
this.DrawUpText(positions[0], positions[1], baseEdge.GetUpText(), arcStyle, false, arcStyle.additionalTextColor, - baseEdge.model.width / 2 - 15, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BaseEdgeDrawer.prototype.SetupStyle = function(baseEdge, arcStyle)
|
||||
{
|
||||
this.context.lineWidth = baseEdge.model.width;
|
||||
this.context.strokeStyle = arcStyle.strokeStyle;
|
||||
this.context.fillStyle = arcStyle.fillStyle;
|
||||
this.model = baseEdge.model;
|
||||
this.style = arcStyle;
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.DrawArc = function(position1, position2, arcStyle)
|
||||
{
|
||||
if (this.drawArc && this.drawArc != this)
|
||||
{
|
||||
this.drawArc.DrawArc(position1, position2, arcStyle);
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.setLineDash(lineDashTypes[arcStyle.lineDash]);
|
||||
if (position1.equals(position2))
|
||||
{
|
||||
this.context.beginPath();
|
||||
this.context.arc(position1.x - Math.cos(this.model.GetLoopShiftAngel()) * this.model.GetLoopSize(),
|
||||
position1.y - Math.sin(this.model.GetLoopShiftAngel()) * this.model.GetLoopSize(), this.model.GetLoopSize(), 0, 2 * Math.PI);
|
||||
this.context.stroke();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(position1.x, position1.y);
|
||||
this.context.lineTo(position2.x, position2.y);
|
||||
this.context.stroke();
|
||||
}
|
||||
this.context.setLineDash([]);
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.DrawWeight = function(position1, position2, text, arcStyle, hasPair)
|
||||
{
|
||||
var centerPoint = this.GetTextCenterPoint(position1, position2, hasPair, arcStyle);
|
||||
|
||||
this.context.font = "bold 16px sans-serif";
|
||||
this.context.textBaseline = "middle";
|
||||
this.context.lineWidth = arcStyle.textStrokeWidth;
|
||||
this.context.fillStyle = arcStyle.fillStyle;
|
||||
|
||||
var widthText = this.context.measureText(text).width;
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.rect(centerPoint.x - widthText / 2 - arcStyle.textPadding / 2,
|
||||
centerPoint.y - 8 - arcStyle.textPadding / 2,
|
||||
widthText + arcStyle.textPadding, 16 + arcStyle.textPadding);
|
||||
this.context.closePath();
|
||||
this.context.fill();
|
||||
this.context.stroke ();
|
||||
|
||||
this.context.fillStyle = arcStyle.weightText;
|
||||
this.context.fillText(text, centerPoint.x - widthText / 2, centerPoint.y);
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.DrawUpText = function(position1, position2, text, arcStyle, hasPair, color, offset, fontSize)
|
||||
{
|
||||
var centerPoint = this.GetTextCenterPoint(position1, position2, hasPair, arcStyle);
|
||||
|
||||
this.context.font = fontSize == null ? "bold 12px sans-serif" : "bold " + fontSize + " sans-serif";
|
||||
this.context.textBaseline = "middle";
|
||||
|
||||
var widthText = this.context.measureText(text).width;
|
||||
|
||||
this.context.fillStyle = color;
|
||||
|
||||
var vectorEdge = new Point(position2.x - position1.x, position2.y - position1.y);
|
||||
var angleRadians = Math.atan2(vectorEdge.y, vectorEdge.x);
|
||||
if (angleRadians > Math.PI / 2 || angleRadians < -Math.PI / 2)
|
||||
{
|
||||
vectorEdge = new Point(position1.x - position2.x, position1.y - position2.y);
|
||||
angleRadians = Math.atan2(vectorEdge.y, vectorEdge.x);
|
||||
}
|
||||
var normalize = vectorEdge.normal().normalizeCopy(offset);
|
||||
this.context.save();
|
||||
this.context.translate(centerPoint.x - normalize.x, centerPoint.y - normalize.y);
|
||||
this.context.rotate(angleRadians);
|
||||
this.context.textAlign = "center";
|
||||
|
||||
this.context.fillText(text, 0, 0);
|
||||
|
||||
this.context.restore();
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.DrawArrow = function(position, direction, length, width)
|
||||
{
|
||||
var normal = direction.normal();
|
||||
|
||||
var pointOnLine = position.subtract(direction.multiply(length));
|
||||
var point1 = pointOnLine.add(normal.multiply(width));
|
||||
var point2 = pointOnLine.add(normal.multiply(-width));
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(position.x, position.y);
|
||||
this.context.lineTo(point1.x, point1.y);
|
||||
this.context.lineTo(point2.x, point2.y);
|
||||
this.context.lineTo(position.x, position.y);
|
||||
this.context.closePath();
|
||||
this.context.fill();
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.GetStartArrowDirection = function(position1, position2, lengthArrow)
|
||||
{
|
||||
if (this.startArrowDirection && this.startArrowDirection != this)
|
||||
{
|
||||
return this.startArrowDirection.GetStartArrowDirection(position1, position2, lengthArrow);
|
||||
}
|
||||
|
||||
var direction = position1.subtract(position2);
|
||||
direction.normalize(1.0);
|
||||
return direction;
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.GetFinishArrowDirection = function(position1, position2, lengthArrow)
|
||||
{
|
||||
if (this.finishArrowDirection && this.finishArrowDirection != this)
|
||||
{
|
||||
return this.finishArrowDirection.GetFinishArrowDirection(position1, position2, lengthArrow);
|
||||
}
|
||||
|
||||
var direction = position2.subtract(position1);
|
||||
direction.normalize(1.0);
|
||||
return direction;
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.GetTextCenterPoint = function (position1, position2, hasPair, arcStyle)
|
||||
{
|
||||
if (this.textCenterObject && this.textCenterObject != this)
|
||||
{
|
||||
return this.textCenterObject.GetTextCenterPoint(position1, position2, hasPair, arcStyle);
|
||||
}
|
||||
|
||||
var textShift = Math.min(12 / position1.subtract(position2).length(), 0.4);
|
||||
var centerPoint = Point.interpolate(position1, position2, 0.5);
|
||||
if (position1.equals(position2))
|
||||
{
|
||||
let sinVal = Math.sin(this.model.GetLoopShiftAngel());
|
||||
let cosVal = Math.cos(this.model.GetLoopShiftAngel());
|
||||
centerPoint.x = centerPoint.x - cosVal * this.model.GetLoopSize();
|
||||
centerPoint.y = centerPoint.y - (sinVal + Math.sign(sinVal) * 1.0) * this.model.GetLoopSize();
|
||||
}
|
||||
|
||||
return centerPoint;
|
||||
}
|
||||
|
||||
BaseEdgeDrawer.prototype.GetPointOnArc = function (position1, position2, percent)
|
||||
{
|
||||
if (this.getPointOnArc && this.getPointOnArc != this)
|
||||
{
|
||||
return this.getPointOnArc.GetPointOnArc(position1, position2, percent);
|
||||
}
|
||||
|
||||
return Point.interpolate(position1, position2, percent);
|
||||
}
|
||||
|
||||
function ProgressArcDrawer(context, baseDrawer, progress)
|
||||
{
|
||||
this.context = context;
|
||||
this.baseDrawer = baseDrawer;
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
ProgressArcDrawer.prototype = Object.create(BaseEdgeDrawer.prototype);
|
||||
|
||||
|
||||
ProgressArcDrawer.prototype.Draw = function(baseEdge, arcStyle)
|
||||
{
|
||||
this.baseDrawer.Draw(baseEdge, arcStyle);
|
||||
|
||||
this.context.lineWidth = 10;
|
||||
|
||||
var positions = baseEdge.GetEdgePositionsShift();
|
||||
var progressSize = 10;
|
||||
|
||||
if (positions[0].equals(positions[1]))
|
||||
{
|
||||
var sizeInRadian = progressSize / (2 * Math.PI * this.baseDrawer.model.GetLoopSize()) * 6;
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.arc(positions[0].x - Math.cos(this.baseDrawer.model.GetLoopShiftAngel()) * this.baseDrawer.model.GetLoopSize(),
|
||||
positions[0].y - Math.sin(this.baseDrawer.model.GetLoopShiftAngel()) * this.baseDrawer.model.GetLoopSize(), this.baseDrawer.model.GetLoopSize(), this.progress * 2 * Math.PI, this.progress * 2 * Math.PI + sizeInRadian);
|
||||
this.context.stroke();
|
||||
}
|
||||
else
|
||||
{
|
||||
var startPosition = this.baseDrawer.GetPointOnArc(positions[0], positions[1], this.progress);
|
||||
var vectorOffset = positions[0].subtract(positions[1]).normalizeCopy(progressSize);
|
||||
var finishPosition = startPosition.add(vectorOffset);
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(startPosition.x, startPosition.y);
|
||||
this.context.lineTo(finishPosition.x, finishPosition.y);
|
||||
this.context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function CurvedArcDrawer(context, model)
|
||||
{
|
||||
this.context = context;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
CurvedArcDrawer.prototype = Object.create(BaseEdgeDrawer.prototype);
|
||||
|
||||
CurvedArcDrawer.prototype.DrawArc = function(position1, position2, arcStyle)
|
||||
{
|
||||
this.context.setLineDash(lineDashTypes[arcStyle.lineDash]);
|
||||
if (position1.equals(position2))
|
||||
{
|
||||
this.context.beginPath();
|
||||
this.context.arc(position1.x - Math.cos(this.model.GetLoopShiftAngel()) * this.model.GetLoopSize(),
|
||||
position1.y - Math.sin(this.model.GetLoopShiftAngel()) * this.model.GetLoopSize(), this.model.GetLoopSize(), 0, 2 * Math.PI);
|
||||
this.context.closePath();
|
||||
this.context.stroke();
|
||||
}
|
||||
else
|
||||
{
|
||||
var points = this.model.GetBezierPoints(position1, position2);
|
||||
var firstBezierPoint = points[0];
|
||||
var secondBezierPoint = points[1];
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(position1.x, position1.y);
|
||||
this.context.bezierCurveTo(firstBezierPoint.x, firstBezierPoint.y, secondBezierPoint.x, secondBezierPoint.y, position2.x, position2.y);
|
||||
this.context.stroke();
|
||||
}
|
||||
this.context.setLineDash([]);
|
||||
}
|
||||
|
||||
CurvedArcDrawer.prototype.GetStartArrowDirection = function(position1, position2, lengthArrow)
|
||||
{
|
||||
var dist = position1.distance(position2);
|
||||
var direction = position1.subtract(this.model.GetCurvePoint(position1, position2, lengthArrow / dist));
|
||||
direction.normalize(1.0);
|
||||
return direction;
|
||||
}
|
||||
|
||||
CurvedArcDrawer.prototype.GetFinishArrowDirection = function(position1, position2, lengthArrow)
|
||||
{
|
||||
var dist = position1.distance(position2);
|
||||
var direction = position2.subtract(this.model.GetCurvePoint(position1, position2, 1.0 - lengthArrow / dist));
|
||||
direction.normalize(1.0);
|
||||
return direction;
|
||||
}
|
||||
|
||||
CurvedArcDrawer.prototype.GetTextCenterPoint = function (position1, position2, hasPair, arcStyle)
|
||||
{
|
||||
var centerPoint = this.model.GetCurvePoint(position1, position2, 0.5)
|
||||
if (position1.equals(position2))
|
||||
{
|
||||
let sinVal = Math.sin(this.model.GetLoopShiftAngel());
|
||||
let cosVal = Math.cos(this.model.GetLoopShiftAngel());
|
||||
centerPoint.x = centerPoint.x - cosVal * this.model.GetLoopSize();
|
||||
centerPoint.y = centerPoint.y - (sinVal + Math.sign(sinVal) * 1.0) * this.model.GetLoopSize();
|
||||
}
|
||||
|
||||
return centerPoint;
|
||||
}
|
||||
|
||||
CurvedArcDrawer.prototype.GetPointOnArc = function (position1, position2, percent)
|
||||
{
|
||||
return this.model.GetCurvePoint(position1, position2, percent);
|
||||
}
|
||||
428
script/features/draw_graph/model/BaseVertexDrawer.js
Normal file
428
script/features/draw_graph/model/BaseVertexDrawer.js
Normal file
@@ -0,0 +1,428 @@
|
||||
/**
|
||||
* Graph drawer.
|
||||
*/
|
||||
|
||||
// Test graph: http://localhost:8080/?graph=oimDPgsdgiAjWGBHZZcst
|
||||
|
||||
|
||||
// Vertex shape
|
||||
const VertexCircleShape = 0,
|
||||
VertexSquareShape = 1,
|
||||
VertexTriangleShape = 2,
|
||||
VertexPentagonShape = 3,
|
||||
VertexHomeShape = 4,
|
||||
VertexTextboxShape = 5;
|
||||
VertexSnowflakeShape = 6;
|
||||
|
||||
// Common text position
|
||||
const CommonTextCenter = 0,
|
||||
CommonTextUp = 1;
|
||||
|
||||
// Fonts
|
||||
const DefaultFont = "px sans-serif",
|
||||
MainTextFontSize = 16,
|
||||
TopTextFontSize = 12.0;
|
||||
|
||||
function GetSquarePoints(diameter)
|
||||
{
|
||||
var res = [];
|
||||
|
||||
var a = diameter;
|
||||
res.push(new Point(-a / 2, - a / 2));
|
||||
res.push(new Point(a / 2, -a / 2));
|
||||
res.push(new Point(a / 2, a / 2));
|
||||
res.push(new Point(-a / 2, a / 2));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function GetTrianglePoints(diameter)
|
||||
{
|
||||
var res = [];
|
||||
|
||||
var effectiveDiameter = diameter * 1.5;
|
||||
var upOffset = effectiveDiameter / 2;
|
||||
var downOffset = effectiveDiameter / 4;
|
||||
var lrOffset = effectiveDiameter * 3 / (Math.sqrt(3) * 4);
|
||||
|
||||
res.push(new Point(0, - upOffset));
|
||||
res.push(new Point(lrOffset, downOffset));
|
||||
res.push(new Point(- lrOffset, downOffset));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function GetPentagonPoints(diameter)
|
||||
{
|
||||
var res = [];
|
||||
|
||||
var baseValue = diameter / 2 * 1.2;
|
||||
|
||||
res.push(new Point(0, - baseValue));
|
||||
res.push((new Point(0, - baseValue)).rotate(new Point(0, 0), 72));
|
||||
res.push((new Point(0, - baseValue)).rotate(new Point(0, 0), 72 * 2));
|
||||
res.push((new Point(0, - baseValue)).rotate(new Point(0, 0), 72 * 3));
|
||||
res.push((new Point(0, - baseValue)).rotate(new Point(0, 0), 72 * 4));
|
||||
res.push((new Point(0, - baseValue)).rotate(new Point(0, 0), 72 * 5));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function GetTextboxPoints(diameter, text)
|
||||
{
|
||||
var res = [];
|
||||
var width = diameter;
|
||||
var height = diameter;
|
||||
|
||||
if (text)
|
||||
{
|
||||
var tempContext = document.createElement('canvas').getContext('2d');
|
||||
tempContext.font = "bold " + MainTextFontSize + DefaultFont;
|
||||
width = tempContext.measureText(text).width + diameter / 2;
|
||||
}
|
||||
|
||||
res.push(new Point(-width / 2, -height / 2));
|
||||
res.push(new Point(width / 2, -height / 2));
|
||||
res.push(new Point(width / 2, height / 2));
|
||||
res.push(new Point(-width / 2, height / 2));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function GetShowflakePoints(diameter)
|
||||
{
|
||||
var res = [];
|
||||
|
||||
var superSmallRadius = diameter * 0.8 / 2;
|
||||
var smallRadius = diameter * 0.95 / 2;
|
||||
var bigRadius = diameter * 1.5 / 2;
|
||||
let angel = 8;
|
||||
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), - angel));
|
||||
res.push(new Point(smallRadius, 0));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), angel));
|
||||
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 - angel));
|
||||
res.push(new Point(smallRadius, 0).rotate(new Point(0, 0), 60));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + angel));
|
||||
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30 + 60));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 - angel));
|
||||
res.push(new Point(smallRadius, 0).rotate(new Point(0, 0), 60 + 60));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + angel));
|
||||
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30 + 60 + 60));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 - angel));
|
||||
res.push(new Point(smallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + angel));
|
||||
|
||||
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30 + 60 + 60 + 60));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60 - angel));
|
||||
res.push(new Point(smallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60 + angel));
|
||||
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30 + 60 + 60 + 60 + 60));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60 + 60 - angel));
|
||||
res.push(new Point(smallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60 + 60));
|
||||
res.push(new Point(superSmallRadius, 0).rotate(new Point(0, 0), 60 + 60 + 60 + 60 + 60 + angel));
|
||||
res.push(new Point(bigRadius, 0).rotate(new Point(0, 0), 30 + 60 + 60 + 60 + 60 + 60));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function GetPointsForShape(shape, diameter, text=null)
|
||||
{
|
||||
switch (parseInt(shape))
|
||||
{
|
||||
case VertexSquareShape: return GetSquarePoints(diameter); break;
|
||||
case VertexTriangleShape: return GetTrianglePoints(diameter); break;
|
||||
case VertexPentagonShape: return GetPentagonPoints(diameter); break;
|
||||
case VertexTextboxShape: return GetTextboxPoints(diameter, text); break;
|
||||
case VertexSnowflakeShape: return GetShowflakePoints(diameter); break;
|
||||
default: return null; break;
|
||||
}
|
||||
}
|
||||
|
||||
function GetSizeForShape(shape, diameter)
|
||||
{
|
||||
switch (parseInt(shape))
|
||||
{
|
||||
case VertexSquareShape: return diameter; break;
|
||||
case VertexTriangleShape: return diameter * 1.5; break;
|
||||
case VertexPentagonShape: return diameter * 1.2; break;
|
||||
case VertexTextboxShape: return diameter; break;
|
||||
case VertexSnowflakeShape: return diameter * 1.5; break;
|
||||
|
||||
default: return diameter; break;
|
||||
}
|
||||
}
|
||||
|
||||
function BaseVertexStyle()
|
||||
{
|
||||
this.baseStyles = [];
|
||||
}
|
||||
|
||||
BaseVertexStyle.prototype.GetStyle = function (baseStyle, object)
|
||||
{
|
||||
this.baseStyles.forEach(function(element) {
|
||||
var styleObject = globalApplication.GetStyle("vertex", element, object);
|
||||
baseStyle = styleObject.GetStyle(baseStyle, object);
|
||||
});
|
||||
|
||||
if (this.hasOwnProperty('lineWidth'))
|
||||
baseStyle.lineWidth = this.lineWidth;
|
||||
if (this.hasOwnProperty('strokeStyle'))
|
||||
baseStyle.strokeStyle = this.strokeStyle;
|
||||
if (this.hasOwnProperty('fillStyle'))
|
||||
baseStyle.fillStyle = this.fillStyle;
|
||||
if (this.hasOwnProperty('mainTextColor'))
|
||||
baseStyle.mainTextColor = this.mainTextColor;
|
||||
if (this.hasOwnProperty('shape'))
|
||||
baseStyle.shape = this.shape;
|
||||
if (this.hasOwnProperty('upTextColor'))
|
||||
baseStyle.upTextColor = this.upTextColor;
|
||||
if (this.hasOwnProperty('commonTextPosition'))
|
||||
baseStyle.commonTextPosition = this.commonTextPosition;
|
||||
|
||||
baseStyle.lineWidth = parseInt(baseStyle.lineWidth);
|
||||
|
||||
return this.FixNewFields(baseStyle);
|
||||
}
|
||||
|
||||
BaseVertexStyle.prototype.FixNewFields = function (style)
|
||||
{
|
||||
if (!style.hasOwnProperty('shape'))
|
||||
style.shape = VertexCircleShape;
|
||||
|
||||
if (!style.hasOwnProperty('commonTextPosition'))
|
||||
style.commonTextPosition = CommonTextCenter;
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
BaseVertexStyle.prototype.Clear = function ()
|
||||
{
|
||||
delete this.lineWidth;
|
||||
delete this.strokeStyle;
|
||||
delete this.fillStyle;
|
||||
delete this.mainTextColor;
|
||||
delete this.shape;
|
||||
delete this.upTextColor;
|
||||
delete this.commonTextPosition;
|
||||
delete this.lineWidth;
|
||||
}
|
||||
|
||||
BaseVertexStyle.prototype.ShouldLoad = function (field)
|
||||
{
|
||||
return field != "baseStyles";
|
||||
}
|
||||
|
||||
// Common style of Graphs.
|
||||
function CommonVertexStyle()
|
||||
{
|
||||
BaseVertexStyle.apply(this, arguments);
|
||||
|
||||
this.lineWidth = 2;
|
||||
this.strokeStyle = '#c7b7c7';
|
||||
this.fillStyle = '#68aeba';
|
||||
this.mainTextColor = '#f0d543';
|
||||
this.shape = VertexCircleShape;
|
||||
this.upTextColor = '#68aeba';
|
||||
this.commonTextPosition = CommonTextCenter;
|
||||
|
||||
this.baseStyles = [];
|
||||
}
|
||||
|
||||
CommonVertexStyle.prototype = Object.create(BaseVertexStyle.prototype);
|
||||
|
||||
function CommonPrintVertexStyle()
|
||||
{
|
||||
BaseVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#000000';
|
||||
this.fillStyle = '#FFFFFF';
|
||||
this.mainTextColor = '#000000';
|
||||
|
||||
this.baseStyles.push("common");
|
||||
}
|
||||
|
||||
CommonPrintVertexStyle.prototype = Object.create(BaseVertexStyle.prototype);
|
||||
|
||||
// Selected style of Graphs.
|
||||
function SelectedVertexStyle0()
|
||||
{
|
||||
BaseVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#f0d543';
|
||||
this.mainTextColor = '#f0d543';
|
||||
this.fillStyle = '#c7627a';
|
||||
|
||||
this.baseStyles.push("common");
|
||||
}
|
||||
|
||||
SelectedVertexStyle0.prototype = Object.create(BaseVertexStyle.prototype);
|
||||
|
||||
function SelectedVertexStyle1()
|
||||
{
|
||||
BaseVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#7a9ba0';
|
||||
this.mainTextColor = '#c3d2d5';
|
||||
this.fillStyle = '#534641';
|
||||
|
||||
this.baseStyles.push("selected");
|
||||
}
|
||||
|
||||
SelectedVertexStyle1.prototype = Object.create(BaseVertexStyle.prototype);
|
||||
|
||||
function SelectedVertexStyle2()
|
||||
{
|
||||
BaseVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#8C4C86';
|
||||
this.mainTextColor = '#dbbdd8';
|
||||
this.fillStyle = '#253267';
|
||||
|
||||
this.baseStyles.push("selected");
|
||||
}
|
||||
|
||||
SelectedVertexStyle2.prototype = Object.create(BaseVertexStyle.prototype);
|
||||
|
||||
function SelectedVertexStyle3()
|
||||
{
|
||||
BaseVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#6188FF';
|
||||
this.mainTextColor = '#6188FF';
|
||||
this.fillStyle = '#E97CF9';
|
||||
|
||||
this.baseStyles.push("selected");
|
||||
}
|
||||
|
||||
SelectedVertexStyle3.prototype = Object.create(BaseVertexStyle.prototype);
|
||||
|
||||
function SelectedVertexStyle4()
|
||||
{
|
||||
BaseVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#C6B484';
|
||||
this.mainTextColor = '#C6B484';
|
||||
this.fillStyle = '#E0DEE1';
|
||||
|
||||
this.baseStyles.push("selected");
|
||||
}
|
||||
|
||||
SelectedVertexStyle4.prototype = Object.create(BaseVertexStyle.prototype);
|
||||
|
||||
function SelectedPrintVertexStyle()
|
||||
{
|
||||
BaseVertexStyle.apply(this, arguments);
|
||||
|
||||
this.strokeStyle = '#000000';
|
||||
this.mainTextColor = '#000000';
|
||||
this.fillStyle = '#AAAAAA';
|
||||
|
||||
this.baseStyles.push("printed");
|
||||
}
|
||||
|
||||
SelectedPrintVertexStyle.prototype = Object.create(BaseVertexStyle.prototype);
|
||||
|
||||
var DefaultSelectedGraphStyles = [new SelectedVertexStyle0(), new SelectedVertexStyle1(),
|
||||
new SelectedVertexStyle2(), new SelectedVertexStyle3(), new SelectedVertexStyle4()];
|
||||
|
||||
var DefaultPrintSelectedGraphStyles = [new SelectedPrintVertexStyle()];
|
||||
|
||||
function BaseVertexDrawer(context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
BaseVertexDrawer.prototype.Draw = function(baseGraph, graphStyle)
|
||||
{
|
||||
this.SetupStyle(graphStyle);
|
||||
this.DrawShape(baseGraph);
|
||||
|
||||
if (this.currentStyle.lineWidth != 0)
|
||||
this.context.stroke();
|
||||
|
||||
this.context.fill();
|
||||
|
||||
var shapeSize = GetSizeForShape(graphStyle.shape, baseGraph.model.diameter + graphStyle.lineWidth);
|
||||
|
||||
if (graphStyle.commonTextPosition == CommonTextCenter)
|
||||
{
|
||||
this.DrawCenterText(baseGraph.position, baseGraph.mainText, graphStyle.mainTextColor,
|
||||
graphStyle.fillStyle, true, true, MainTextFontSize);
|
||||
// Top text
|
||||
this.DrawCenterText(baseGraph.position.add(new Point(0, - shapeSize / 2.0 - 9.0)), baseGraph.upText,
|
||||
graphStyle.upTextColor, graphStyle.strokeStyle, false, false, TopTextFontSize);
|
||||
}
|
||||
else if (graphStyle.commonTextPosition == CommonTextUp)
|
||||
{
|
||||
this.DrawCenterText(baseGraph.position.add(new Point(0, - shapeSize / 2.0 - 7.0)), baseGraph.mainText,
|
||||
graphStyle.mainTextColor, graphStyle.fillStyle, true, false, MainTextFontSize);
|
||||
// Top text
|
||||
this.DrawCenterText(baseGraph.position.add(new Point(0, shapeSize / 2.0 + 9.0)), baseGraph.upText,
|
||||
graphStyle.upTextColor, graphStyle.strokeStyle, false, false, TopTextFontSize);
|
||||
}
|
||||
/*
|
||||
// Bottom text
|
||||
this.DrawCenterText(baseGraph.position.add(new Point(0, + baseGraph.model.diameter / 2.0 + 7.0)),
|
||||
"Text 2", graphStyle.fillStyle, false, 12.0);
|
||||
*/
|
||||
}
|
||||
|
||||
BaseVertexDrawer.prototype.SetupStyle = function(style)
|
||||
{
|
||||
this.currentStyle = style;
|
||||
this.context.lineWidth = style.lineWidth;
|
||||
this.context.strokeStyle = style.strokeStyle;
|
||||
this.context.fillStyle = style.fillStyle;
|
||||
}
|
||||
|
||||
BaseVertexDrawer.prototype.DrawShape = function(baseGraph)
|
||||
{
|
||||
this.context.beginPath();
|
||||
if (this.currentStyle.shape == VertexCircleShape)
|
||||
{
|
||||
this.context.arc(baseGraph.position.x, baseGraph.position.y, baseGraph.model.diameter / 2.0, 0, 2 * Math.PI);
|
||||
}
|
||||
else
|
||||
{
|
||||
var points = GetPointsForShape(this.currentStyle.shape, baseGraph.model.diameter, baseGraph.mainText);
|
||||
|
||||
this.context.moveTo(baseGraph.position.x + points[points.length - 1].x, baseGraph.position.y + points[points.length - 1].y);
|
||||
|
||||
var context = this.context;
|
||||
|
||||
points.forEach(function(point) {
|
||||
context.lineTo(baseGraph.position.x + point.x, baseGraph.position.y + point.y);
|
||||
});
|
||||
}
|
||||
|
||||
this.context.closePath();
|
||||
}
|
||||
|
||||
BaseVertexDrawer.prototype.DrawText = function(position, text, color, outlineColor, outline, font)
|
||||
{
|
||||
this.context.fillStyle = color;
|
||||
this.context.font = font;
|
||||
this.context.lineWidth = 4;
|
||||
this.context.strokeStyle = outlineColor;
|
||||
|
||||
if (outline)
|
||||
{
|
||||
this.context.save();
|
||||
this.context.lineJoin = 'round';
|
||||
this.context.strokeText(text, position.x, position.y);
|
||||
this.context.restore();
|
||||
}
|
||||
|
||||
this.context.fillText(text, position.x, position.y);
|
||||
}
|
||||
|
||||
BaseVertexDrawer.prototype.DrawCenterText = function(position, text, color, outlineColor, bold, outline, size)
|
||||
{
|
||||
this.context.textBaseline="middle";
|
||||
this.context.font = (bold ? "bold " : "") + size + DefaultFont;
|
||||
var textWidth = this.context.measureText(text).width;
|
||||
this.DrawText(new Point(position.x - textWidth / 2, position.y), text, color, outlineColor, outline, this.context.font);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user