Exemplo n.º 1
0
        internal override Point DefineInCanvas(double xOffsetToApplyBeforeMultiplication,
                                               double yOffsetToApplyBeforeMultiplication,
                                               double xOffsetToApplyAfterMultiplication,
                                               double yOffsetToApplyAfterMultiplication,
                                               double horizontalMultiplicator,
                                               double verticalMultiplicator,
                                               object canvasDomElement,
                                               Point previousLastPoint)
        {
            var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            // tell the context that there should be a quadratic bezier curve from the starting
            // point to this point, with the previous point as control point.
            //context.quadraticCurveTo(
            //    (Point1.X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
            //    (Point1.Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication,
            //    (Point2.X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
            //    (Point2.Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication);
            //Note: we replaced the code above with the one below because Bridge.NET has an issue when adding "0" to an Int64 (as of May 1st, 2020), so it is better to first multiply and then add, rather than the contrary:
            context.quadraticCurveTo(
                Point1.X * horizontalMultiplicator + xOffsetToApplyBeforeMultiplication * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
                Point1.Y * verticalMultiplicator + yOffsetToApplyBeforeMultiplication * verticalMultiplicator + yOffsetToApplyAfterMultiplication,
                Point2.X * horizontalMultiplicator + xOffsetToApplyBeforeMultiplication * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
                Point2.Y * verticalMultiplicator + yOffsetToApplyBeforeMultiplication * verticalMultiplicator + yOffsetToApplyAfterMultiplication);

            return(Point2);
        }
Exemplo n.º 2
0
        //protected internal override void INTERNAL_OnAttachedToVisualTree()
        //{
        //    ScheduleRedraw();
        //}

        override internal protected void Redraw()
        {
            if (INTERNAL_VisualTreeManager.IsElementInVisualTree(this))
            {
                double xOffsetToApplyBeforeMultiplication;
                double yOffsetToApplyBeforeMultiplication;
                double xOffsetToApplyAfterMultiplication;
                double yOffsetToApplyAfterMultiplication;
                double sizeX;
                double sizeY;
                double horizontalMultiplicator;
                double verticalMultiplicator;
                Size   shapeActualSize;
                Shape.GetShapeInfos(this, out xOffsetToApplyBeforeMultiplication, out yOffsetToApplyBeforeMultiplication, out xOffsetToApplyAfterMultiplication, out yOffsetToApplyAfterMultiplication, out sizeX, out sizeY, out horizontalMultiplicator, out verticalMultiplicator, out shapeActualSize);

                ApplyMarginToFixNegativeCoordinates(new Point());
                if (Stretch == Media.Stretch.None)
                {
                    ApplyMarginToFixNegativeCoordinates(_marginOffsets);
                }

                var    context = INTERNAL_HtmlDomManager.Get2dCanvasContext(_canvasDomElement);
                double x       = xOffsetToApplyBeforeMultiplication + xOffsetToApplyAfterMultiplication;
                double y       = yOffsetToApplyBeforeMultiplication + yOffsetToApplyAfterMultiplication;
                double width   = sizeX;
                double height  = sizeY;

                // Values greater than half the rectangle's width/height are treated as though equal to half the rectangle's width/height.
                // Negative values are treated as positive values.
                double radiusX = Math.Abs(RadiusX) > width / 2 ? width / 2 : Math.Abs(RadiusX);
                double radiusY = Math.Abs(RadiusY) > height / 2 ? height / 2 : Math.Abs(RadiusY);

                if (radiusX == 0 || radiusY == 0)
                {
                    // Just draw a rectangle if one of radiuses is 0
                    context.rect(x, y, width, height);
                }
                else
                {
                    context.moveTo(x + radiusX, y);
                    context.lineTo(x + width - radiusX, y);
                    context.ellipse(x + width - radiusX, y + radiusY, radiusX, radiusY, Math.PI, Math.PI / 2, Math.PI);
                    context.lineTo(x + width, y + height - radiusY);
                    context.ellipse(x + width - radiusX, y + height - radiusY, radiusX, radiusY, Math.PI, Math.PI, 3 * Math.PI / 2);
                    context.lineTo(x + radiusX, y + height);
                    context.ellipse(x + radiusX, y + height - radiusY, radiusX, radiusY, Math.PI, 3 * Math.PI / 2, 2 * Math.PI);
                    context.lineTo(x, y + radiusY);
                    context.ellipse(x + radiusX, y + radiusY, radiusX, radiusY, Math.PI, 2 * Math.PI, Math.PI / 2);
                }

                //todo: make sure the parameters below are correct.
                Shape.DrawFillAndStroke(this, "evenodd", xOffsetToApplyAfterMultiplication, yOffsetToApplyAfterMultiplication, xOffsetToApplyAfterMultiplication + sizeX, yOffsetToApplyAfterMultiplication + sizeY, horizontalMultiplicator, verticalMultiplicator, xOffsetToApplyBeforeMultiplication, yOffsetToApplyBeforeMultiplication, shapeActualSize);

                //context.fill("evenodd"); //note: remember: always fill before stroke, otherwise the filling will hide the stroke.
                //if (StrokeThickness > 0 && Stroke != null)
                //{
                //    context.stroke();
                //}
            }
        }
Exemplo n.º 3
0
        internal static void ApplyTransformToCanvas(Transform transform, object canvasDomElement)
        {
            MatrixTransform matrixTransform = transform as MatrixTransform;

            if (matrixTransform != null)
            {
                Matrix m = matrixTransform.Matrix;

                // todo: this line gets called AFTER "translate(0.5, 0.5)" (in "INTERNAL_ShapesDrawHelpers.cs"),
                // but instead we should apply it BEFORE, otherwise the (0.5, 0.5) translation may get amplified/distorted
                // by the subsequent transform.

                var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);
                context.transform(m.M11, m.M12, m.M21, m.M22, m.OffsetX, m.OffsetY);

                //todo: also apply the transform to other geometry types.
            }
            else
            {
                if (transform != null)
                {
                    throw new NotSupportedException(string.Format("'{0}' is not currently supported in PathGeometry.", transform.GetType()));
                }
            }
        }
Exemplo n.º 4
0
        //protected internal override void INTERNAL_OnAttachedToVisualTree()
        //{
        //    ScheduleRedraw();
        //}

        override internal protected void Redraw()
        {
            if (INTERNAL_VisualTreeManager.IsElementInVisualTree(this))
            {
                double xOffsetToApplyBeforeMultiplication;
                double yOffsetToApplyBeforeMultiplication;
                double xOffsetToApplyAfterMultiplication;
                double yOffsetToApplyAfterMultiplication;
                double sizeX;
                double sizeY;
                double horizontalMultiplicator;
                double verticalMultiplicator;
                Size   shapeActualSize;
                Shape.GetShapeInfos(this, out xOffsetToApplyBeforeMultiplication, out yOffsetToApplyBeforeMultiplication, out xOffsetToApplyAfterMultiplication, out yOffsetToApplyAfterMultiplication, out sizeX, out sizeY, out horizontalMultiplicator, out verticalMultiplicator, out shapeActualSize);

                ApplyMarginToFixNegativeCoordinates(new Point());
                if (Stretch == Media.Stretch.None)
                {
                    ApplyMarginToFixNegativeCoordinates(_marginOffsets);
                }

                dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(_canvasDomElement);
                context.rect(xOffsetToApplyBeforeMultiplication + xOffsetToApplyAfterMultiplication, yOffsetToApplyBeforeMultiplication + yOffsetToApplyAfterMultiplication, sizeX, sizeY);

                //todo: make sure the parameters below are correct.
                Shape.DrawFillAndStroke(this, "evenodd", xOffsetToApplyAfterMultiplication, yOffsetToApplyAfterMultiplication, xOffsetToApplyAfterMultiplication + sizeX, yOffsetToApplyAfterMultiplication + sizeY, horizontalMultiplicator, verticalMultiplicator, xOffsetToApplyBeforeMultiplication, yOffsetToApplyBeforeMultiplication, shapeActualSize);

                //context.fill("evenodd"); //note: remember: always fill before stroke, otherwise the filling will hide the stroke.
                //if (StrokeThickness > 0 && Stroke != null)
                //{
                //    context.stroke();
                //}
            }
        }
Exemplo n.º 5
0
        internal override Point DefineInCanvas(double xOffsetToApplyBeforeMultiplication, double yOffsetToApplyBeforeMultiplication, double xOffsetToApplyAfterMultiplication, double yOffsetToApplyAfterMultiplication, double horizontalMultiplicator, double verticalMultiplicator, object canvasDomElement, Point previousLastPoint)
        {
            dynamic context   = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);
            int     i         = 0;
            Point   lastPoint = previousLastPoint;

            while (i < Points.Count - 2)
            {
                double controlPoint1X = Points[i].X;
                double controlPoint1Y = Points[i].Y;
                ++i;
                double controlPoint2X = Points[i].X;
                double controlPoint2Y = Points[i].Y;
                ++i;
                lastPoint = Points[i];
                double endPointX = lastPoint.X;
                double endPointY = lastPoint.Y;
                ++i;
                context.bezierCurveTo(
                    (controlPoint1X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication, (controlPoint1Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication,
                    (controlPoint2X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication, (controlPoint2Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication,
                    (endPointX + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication, (endPointY + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication); // tell the context that there should be a cubic bezier curve from the starting point to this point, with the two previous points as control points.
            }
            return(lastPoint);
        }
Exemplo n.º 6
0
        internal override Point DefineInCanvas(double xOffsetToApplyBeforeMultiplication, double yOffsetToApplyBeforeMultiplication, double xOffsetToApplyAfterMultiplication, double yOffsetToApplyAfterMultiplication, double horizontalMultiplicator, double verticalMultiplicator, object canvasDomElement, Point previousLastPoint)
        {
            dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.lineTo((Point.X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication, (Point.Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication); // tell the context that there should be a line from the starting point to this point
            return(Point);
        }
Exemplo n.º 7
0
 internal protected virtual void ManageStrokeThicknessChanged()
 {
     if (INTERNAL_VisualTreeManager.IsElementInVisualTree(this))
     {
         dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(_canvasDomElement);
         context.lineWidth = StrokeThickness + "";
         ScheduleRedraw();
     }
 }
Exemplo n.º 8
0
        internal override Point DefineInCanvas(double xOffsetToApplyBeforeMultiplication, double yOffsetToApplyBeforeMultiplication, double xOffsetToApplyAfterMultiplication, double yOffsetToApplyAfterMultiplication, double horizontalMultiplicator, double verticalMultiplicator, object canvasDomElement, Point previousLastPoint)
        {
            dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.bezierCurveTo(
                (Point1.X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication, (Point1.Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication,
                (Point2.X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication, (Point2.Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication,
                (Point3.X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication, (Point3.Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication); // tell the context that there should be a cubic bezier curve from the starting point to this point, with the two previous points as control points.
            return(Point3);
        }
Exemplo n.º 9
0
        internal override Point DefineInCanvas(double xOffsetToApplyBeforeMultiplication, double yOffsetToApplyBeforeMultiplication, double xOffsetToApplyAfterMultiplication, double yOffsetToApplyAfterMultiplication, double horizontalMultiplicator, double verticalMultiplicator, object canvasDomElement, Point previousLastPoint)
        {
            //HOW IT WORKS IN WINRT:
            //  - Starting point and ending point are two fixed points that will belong to the curve
            //  - we find the two possible ellipses that pass on these two points, with the given width, height and angle
            //  - We chose one ellipse depending on the IsLargeArc combined with SweepDirection property
            //  - we draw the arc connecting the two points on the ellipse starting on the startpoint and ending on the endpoint, folowing the sweepdirection.


            //we use canvas' arc method since it is the easiest way to do this. Another solution would have been bezier segments but defining the angle would be harder.
            //JAVASCRIPT
            //  // cx,cy - center, r - horizontal radius X
            //function drawEllipseWithArcAndScale(ctx, cx, cy, rx, ry, style) {
            //  ctx.save(); // save state
            //  ctx.translate(cx-rx, cy-ry);
            //  ctx.scale(rx, ry);
            //  ctx.arc(1, 1, 1, 0, 2 * Math.PI, false);
            //  //ctx.arc(centerX, centerY, Radius, StartingAngle, EndAngle, isCounterClockwise)
            //  ctx.restore(); // restore to original state
            //  ctx.save();
            //  if(style)
            //    ctx.strokeStyle=style;
            //  ctx.stroke();
            //  ctx.restore();
            //}
            //END OF JAVASCRIPT

            UpdateArcData();


            dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.save(); // save state
            context.translate(xOffsetToApplyBeforeMultiplication * horizontalMultiplicator + xOffsetToApplyAfterMultiplication, yOffsetToApplyBeforeMultiplication * verticalMultiplicator + yOffsetToApplyAfterMultiplication);
            context.scale(horizontalMultiplicator, verticalMultiplicator);
            context.rotate(RotationAngle * Math.PI / 180);
            double horizontalScaling = (Size.Width) / (Size.Height);

            context.scale(horizontalScaling, 1);
            //double centerX = ((center.X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication);
            //double centerY = (center.Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication;
            //double centerX = center.X;
            //double centerY = center.Y;
            double centerX = _ellipseCenterInCircleCoordinates.X;
            double centerY = _ellipseCenterInCircleCoordinates.Y;

            context.arc(centerX, centerY, Size.Height * _additionalScalingForShapetoSmallToReachEndPoint, _angle1, _angle2, SweepDirection == SweepDirection.Counterclockwise);
            //ctx.arc(centerX, centerY, Radius, StartingAngle, EndAngle, isCounterClockwise)
            context.restore(); // restore to original state
            context.stroke();

            return(Point);
        }
Exemplo n.º 10
0
        private static void StrokeDashOffset_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Shape shape = (Shape)d;

            if (INTERNAL_VisualTreeManager.IsElementInVisualTree(shape))
            {
                if (shape._canvasDomElement != null)
                {
                    dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(shape._canvasDomElement);
                    context.lineDashOffset = shape.StrokeDashOffset.ToString();
                }
            }
        }
Exemplo n.º 11
0
        internal static void PrepareLine(object canvasDomElement, Point StartPoint, Point EndPoint)
        {
            var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.beginPath();                        //this allows to state that we are drawing a new shape (not sure what it serves to but it is apparently good practice to always use it)
            context.moveTo(StartPoint.X, StartPoint.Y); //starting point of the line
            context.lineTo(EndPoint.X, EndPoint.Y);     // tell the context that there should be a line from the starting point to this point



            //not set in this method:
            //context.strokeStyle = strokeAsString; //set the shape's lines color
            //context.lineWidth = path.StrokeThickness;
        }
Exemplo n.º 12
0
        // note: we only define the line. Erasing the previous one (if any) and actually drawing the
        // new one should be made directly by the container.
        internal protected override void DefineInCanvas(Path path,
                                                        object canvasDomElement,
                                                        double horizontalMultiplicator,
                                                        double verticalMultiplicator,
                                                        double xOffsetToApplyBeforeMultiplication,
                                                        double yOffsetToApplyBeforeMultiplication,
                                                        double xOffsetToApplyAfterMultiplication,
                                                        double yOffsetToApplyAfterMultiplication,
                                                        Size shapeActualSize)
        {
            dynamic ctx = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            ctx.moveTo(StartPoint.X, StartPoint.Y);
            ctx.lineTo(EndPoint.X, EndPoint.Y);
        }
Exemplo n.º 13
0
        internal static void PreparePolygon(object canvasDomElement, PointCollection points)
        {
            var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.beginPath();
            context.moveTo(points[0].X, points[0].Y);

            for (int i = 1; i < points.Count; i++)
            {
                context.lineTo(points[i].X, points[i].Y);
            }

            context.closePath();
            context.fill();
        }
Exemplo n.º 14
0
        // note: we only define the line. Erasing the previous one (if any) and actually drawing the
        // new one should be made directly by the container.
        internal protected override void DefineInCanvas(Path path,
                                                        object canvasDomElement,
                                                        double horizontalMultiplicator,
                                                        double verticalMultiplicator,
                                                        double xOffsetToApplyBeforeMultiplication,
                                                        double yOffsetToApplyBeforeMultiplication,
                                                        double xOffsetToApplyAfterMultiplication,
                                                        double yOffsetToApplyAfterMultiplication,
                                                        Size shapeActualSize)
        {
            string strokeAsString = string.Empty;

            INTERNAL_ShapesDrawHelpers.PrepareLine(path._canvasDomElement, StartPoint, EndPoint);

            dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.strokeStyle = strokeAsString; //set the shape's lines color
            context.lineWidth   = path.StrokeThickness + "px";
        }
Exemplo n.º 15
0
        internal void DefineInCanvas(double xOffsetToApplyBeforeMultiplication,
                                     double yOffsetToApplyBeforeMultiplication,
                                     double xOffsetToApplyAfterMultiplication,
                                     double yOffsetToApplyAfterMultiplication,
                                     double horizontalMultiplicator,
                                     double verticalMultiplicator,
                                     object canvasDomElement,
                                     double strokeThickness,
                                     Size shapeActualSize)
        {
            var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            // todo: In order to support IsFilled, add a call to context.beginPath() here
            // (instead the call to beginPath() that is located in "Path.cs") and handle
            // the filling here (in the PathFigure) instead of in the Redraw of the Path.

            Point segmentStartingPosition = new Point(StartPoint.X, StartPoint.Y);

            // tell the context that there should be a line from the starting point to this point
            //context.moveTo((StartPoint.X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
            //               (StartPoint.Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication);
            //Note: we replaced the code above with the one below because Bridge.NET has an issue when adding "0" to an Int64 (as of May 1st, 2020), so it is better to first multiply and then add, rather than the contrary:
            context.moveTo(StartPoint.X * horizontalMultiplicator + xOffsetToApplyBeforeMultiplication * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
                           StartPoint.Y * verticalMultiplicator + yOffsetToApplyBeforeMultiplication * verticalMultiplicator + yOffsetToApplyAfterMultiplication);

            foreach (PathSegment segment in Segments)
            {
                segmentStartingPosition = segment.DefineInCanvas(xOffsetToApplyBeforeMultiplication,
                                                                 yOffsetToApplyBeforeMultiplication,
                                                                 xOffsetToApplyAfterMultiplication,
                                                                 yOffsetToApplyAfterMultiplication,
                                                                 horizontalMultiplicator,
                                                                 verticalMultiplicator,
                                                                 canvasDomElement,
                                                                 segmentStartingPosition);
            }
            if (IsClosed) // we close the figure:
            {
                // tell the context that there should be a line from the starting point to this point
                context.closePath();
            }
        }
Exemplo n.º 16
0
        internal protected override void DefineInCanvas(Path path,
                                                        object canvasDomElement,
                                                        double horizontalMultiplicator,
                                                        double verticalMultiplicator,
                                                        double xOffsetToApplyBeforeMultiplication,
                                                        double yOffsetToApplyBeforeMultiplication,
                                                        double xOffsetToApplyAfterMultiplication,
                                                        double yOffsetToApplyAfterMultiplication,
                                                        Size shapeActualSize)
        {
            dynamic ctx = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            Rect rect = Rect;

            ctx.rect(
                rect.X + xOffsetToApplyBeforeMultiplication + xOffsetToApplyAfterMultiplication,
                rect.Y + yOffsetToApplyBeforeMultiplication + yOffsetToApplyAfterMultiplication,
                rect.Width,
                rect.Height);
        }
Exemplo n.º 17
0
        internal protected override void DefineInCanvas(Shapes.Path path,
                                                        object canvasDomElement,
                                                        double horizontalMultiplicator,
                                                        double verticalMultiplicator,
                                                        double xOffsetToApplyBeforeMultiplication,
                                                        double yOffsetToApplyBeforeMultiplication,
                                                        double xOffsetToApplyAfterMultiplication,
                                                        double yOffsetToApplyAfterMultiplication,
                                                        Size shapeActualSize)
        {
            dynamic ctx = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            ctx.ellipse(
                Center.X + xOffsetToApplyBeforeMultiplication + xOffsetToApplyAfterMultiplication,
                Center.Y + yOffsetToApplyBeforeMultiplication + yOffsetToApplyAfterMultiplication,
                RadiusX,
                RadiusY,
                0,
                0,
                2 * Math.PI);
        }
Exemplo n.º 18
0
        internal override Point DefineInCanvas(double xOffsetToApplyBeforeMultiplication,
                                               double yOffsetToApplyBeforeMultiplication,
                                               double xOffsetToApplyAfterMultiplication,
                                               double yOffsetToApplyAfterMultiplication,
                                               double horizontalMultiplicator,
                                               double verticalMultiplicator,
                                               object canvasDomElement,
                                               Point previousLastPoint)
        {
            //todo: the size of the canvas
            var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            foreach (Point point in Points)
            {
                // tell the context that there should be a line from the starting point to this point
                context.lineTo(
                    (point.X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
                    (point.Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication);
            }
            return(Points.Count == 0 ? previousLastPoint : Points[Points.Count - 1]);
        }
        internal override Point DefineInCanvas(double xOffsetToApplyBeforeMultiplication,
                                               double yOffsetToApplyBeforeMultiplication,
                                               double xOffsetToApplyAfterMultiplication,
                                               double yOffsetToApplyAfterMultiplication,
                                               double horizontalMultiplicator,
                                               double verticalMultiplicator,
                                               object canvasDomElement,
                                               Point previousLastPoint)
        {
            var   context   = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);
            int   i         = 0;
            Point lastPoint = previousLastPoint;

            while (i < Points.Count - 1)
            {
                double controlPoint1X = Points[i].X;
                double controlPoint1Y = Points[i].Y;
                ++i;
                lastPoint = Points[i];
                double endPointX = lastPoint.X;
                double endPointY = lastPoint.Y;
                ++i;

                // tell the context that there should be a cubic bezier curve from the starting
                // point to this point, with the two previous points as control points.
                //context.quadraticCurveTo(
                //    (controlPoint1X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
                //    (controlPoint1Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication,
                //    (endPointX + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
                //    (endPointY + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication);
                //Note: we replaced the code above with the one below because Bridge.NET has an issue when adding "0" to an Int64 (as of May 1st, 2020), so it is better to first multiply and then add, rather than the contrary:
                context.quadraticCurveTo(
                    controlPoint1X * horizontalMultiplicator + xOffsetToApplyBeforeMultiplication * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
                    controlPoint1Y * verticalMultiplicator + yOffsetToApplyBeforeMultiplication * verticalMultiplicator + yOffsetToApplyAfterMultiplication,
                    endPointX * horizontalMultiplicator + xOffsetToApplyBeforeMultiplication * horizontalMultiplicator + xOffsetToApplyAfterMultiplication,
                    endPointY * verticalMultiplicator + yOffsetToApplyBeforeMultiplication * verticalMultiplicator + yOffsetToApplyAfterMultiplication);
            }
            return(lastPoint);
        }
Exemplo n.º 20
0
        internal void DefineInCanvas(double xOffsetToApplyBeforeMultiplication, double yOffsetToApplyBeforeMultiplication, double xOffsetToApplyAfterMultiplication, double yOffsetToApplyAfterMultiplication, double horizontalMultiplicator, double verticalMultiplicator, object canvasDomElement, double strokeThickness, Size shapeActualSize)
        {
            dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            //todo: In order to support IsFilled, add a call to context.beginPath() here (instead the call to beginPath() that is located in "Path.cs") and handle the filling here (in the PathFigure) instead of in the Redraw of the Path.
            Point segmentStartingPosition = new Point(StartPoint.X, StartPoint.Y);

            context.moveTo((StartPoint.X + xOffsetToApplyBeforeMultiplication) * horizontalMultiplicator + xOffsetToApplyAfterMultiplication, (StartPoint.Y + yOffsetToApplyBeforeMultiplication) * verticalMultiplicator + yOffsetToApplyAfterMultiplication); // tell the context that there should be a line from the starting point to this point
            foreach (PathSegment segment in Segments)
            {
                if (segment is ArcSegment)
                {
                    ((ArcSegment)segment).UpdateStartPosition(segmentStartingPosition);
                    ((ArcSegment)segment).UpdateStrokeThickness(strokeThickness);
                }
                segmentStartingPosition = segment.DefineInCanvas(xOffsetToApplyBeforeMultiplication, yOffsetToApplyBeforeMultiplication, xOffsetToApplyAfterMultiplication, yOffsetToApplyAfterMultiplication, horizontalMultiplicator, verticalMultiplicator, canvasDomElement, segmentStartingPosition);
            }
            if (IsClosed)            //we close the figure:
            {
                context.closePath(); // tell the context that there should be a line from the starting point to this point
            }
        }
Exemplo n.º 21
0
        internal override void DefineInCanvas(Shapes.Path path, object canvasDomElement, double horizontalMultiplicator, double verticalMultiplicator, double xOffsetToApplyBeforeMultiplication, double yOffsetToApplyBeforeMultiplication, double xOffsetToApplyAfterMultiplication, double yOffsetToApplyAfterMultiplication, Size shapeActualSize)
        {
            string strokeAsString = string.Empty;

            if (path.Stroke == null || path.Stroke is SolidColorBrush) //todo: make sure we want the same behaviour when it is null and when it is a SolidColorBrush (basically, check if null means default value)
            {
                if (path.Stroke != null)                               //if stroke is null, we want to set it as an empty string, otherwise, it is a SolidColorBrush and we want to get its color.
                {
                    strokeAsString = ((SolidColorBrush)path.Stroke).INTERNAL_ToHtmlString();
                }
            }
            else
            {
                throw new NotSupportedException("The specified brush is not supported.");
            }
            dynamic context      = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);
            double  actualWidth  = RadiusX * 2; //it's a radius and we want the whole width (basically a "diameter")
            double  actualHeight = RadiusY * 2; //it's a radius and we want the whole height

            INTERNAL_ShapesDrawHelpers.PrepareEllipse(canvasDomElement, actualWidth, actualHeight, Center.X + xOffsetToApplyBeforeMultiplication + xOffsetToApplyAfterMultiplication, Center.Y + yOffsetToApplyBeforeMultiplication + yOffsetToApplyAfterMultiplication);
            context.strokeStyle = strokeAsString;
        }
Exemplo n.º 22
0
        internal static void PrepareLines(object canvasDomElement, PointCollection points, double strokeThikness, bool isClosed)
        {
            if (points?.Count < 2)
            {
                return;
            }

            var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.beginPath();
            context.moveTo(points[0].X, points[0].Y);

            for (int i = 1; i < points.Count; i++)
            {
                context.lineTo(points[i].X, points[i].Y);
            }

            if (isClosed)
            {
                context.closePath();
                context.fill();
            }
        }
Exemplo n.º 23
0
        internal override void DefineInCanvas(Path path, object canvasDomElement, double horizontalMultiplicator, double verticalMultiplicator, double xOffsetToApplyBeforeMultiplication, double yOffsetToApplyBeforeMultiplication, double xOffsetToApplyAfterMultiplication, double yOffsetToApplyAfterMultiplication, Size shapeActualSize) //note: we only define the line. Erasing the previous one (if any) and actually drawing the new one should be made directly by the container.
        {
            string strokeAsString = string.Empty;

            //if (path.Stroke == null || path.Stroke is SolidColorBrush) //todo: make sure we want the same behaviour when it is null and when it is a SolidColorBrush (basically, check if null means default value)
            //{
            //    if (path.Stroke != null) //if stroke is null, we want to set it as an empty string, otherwise, it is a SolidColorBrush and we want to get its color.
            //    {
            //        strokeAsString = ((SolidColorBrush)path.Stroke).Color.INTERNAL_ToHtmlString();
            //    }
            //}
            //else
            //{
            //    throw new NotSupportedException("The specified brush is not supported.");
            //}


            INTERNAL_ShapesDrawHelpers.PrepareLine(path._canvasDomElement, StartPoint, EndPoint);

            dynamic context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.strokeStyle = strokeAsString; //set the shape's lines color
            context.lineWidth   = path.StrokeThickness + "px";
        }
Exemplo n.º 24
0
        //INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);

        /// <summary>
        /// Prepares the Shape so that its canvas has the size it should have, depending on its container, content and Stretch mode.
        /// </summary>
        /// <param name="frameworkElement">The Shape containing the canvas.</param>
        /// <param name="canvasDomElement">The canvas in the Shape.</param>
        /// <param name="minX">The minimum X-coordinate of the points in the Shape.</param>
        /// <param name="maxX">The maximum X-coordinate of the points in the Shape.</param>
        /// <param name="minY">The minimum Y-coordinate of the points in the Shape.</param>
        /// <param name="maxY">The maximum Y-coordinate of the points in the Shape.</param>
        /// <param name="stretch">The Stretch mode to apply on the Shape</param>
        /// <param name="shapeActualSize"></param>
        internal static void PrepareStretch(FrameworkElement frameworkElement, object canvasDomElement, double minX, double maxX, double minY, double maxY, Stretch stretch, out Size shapeActualSize)
        {
            var canvasStyle = INTERNAL_HtmlDomManager.GetDomElementStyleForModification(canvasDomElement);

            //Two steps:
            // 1) We get the size the Shape would take if Stretch = None so that we know its prefered size
            // 2) We make the element take the allowed size closest to that prefered size.

            //We get the size the Shape would take if its Stretch mode was Stretch.None:
            //in Stretch.None mode, the size is from 0 to the rightmost poit and bottommost point:
            double sizeX = maxX;
            double sizeY = maxY;

            //in other Stretched modes, the size is from the leftmost point to the rightmost point and from the topmost to the bottommost point:
            if (stretch != Stretch.None)
            {
                sizeX = maxX - minX;
                sizeY = maxY - minY;
            }
            else //we want to add the size of the shape that goes into negative values:
            {
                if (minX < 0)
                {
                    sizeX = maxX - minX;
                }
                if (minY < 0)
                {
                    sizeY = maxY - minY;
                }
            }

            //todo: (?) for the line below, replace the "+ 1" with the StrokeThickness/LineWidth
            Size sizeToApply = new Size(Math.Max(sizeX + 1, 0), Math.Max(sizeY + 1, 0)); //example: a vertical line still needs 1 pixel width

            //we apply the possible defined size of the outerDomElement of the shape:
            var    style = INTERNAL_HtmlDomManager.GetFrameworkElementOuterStyleForModification(frameworkElement);
            bool   frameworkElementWidthWasSpecified = false;
            double frameworkElementWidth             = frameworkElement.Width;
            double frameworkElementHeight            = frameworkElement.Height;

            if (!double.IsNaN(frameworkElementWidth))
            {
                frameworkElementWidthWasSpecified = true;
                sizeToApply.Width = frameworkElementWidth + 1;
                style.width       = sizeToApply.Width.ToInvariantString() + "px";
            }
            bool frameworkElementHeightWasSpecified = false;

            if (!double.IsNaN(frameworkElementHeight))
            {
                frameworkElementHeightWasSpecified = true;
                sizeToApply.Height = frameworkElementHeight + 1;
                style.height       = sizeToApply.Height.ToInvariantString() + "px";
            }

            if (frameworkElementWidthWasSpecified && frameworkElementHeightWasSpecified)
            {
                shapeActualSize = new Size(frameworkElementWidth, frameworkElementHeight);

                //We apply the size defined earlier (size either by the Width and/or Height of the Shape (when they are set) or by the width and/or height of its content):
                INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", sizeToApply.Width);
                INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);

                canvasStyle.width  = sizeToApply.Width.ToInvariantString() + "px"; // The "sizeToApply" is the size that the shape would take if it was not constrained by the parent framework element.
                canvasStyle.height = sizeToApply.Height.ToInvariantString() + "px";
            }
            else
            {
                if (frameworkElement.IsUnderCustomLayout == false)
                {
                    //We apply the size defined earlier (size either by the Width and/or Height of the Shape (when they are set) or by the width and/or height of its content):
                    INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", sizeToApply.Width);
                    INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);

                    canvasStyle.width  = sizeToApply.Width.ToInvariantString() + "px"; // The "sizeToApply" is the size that the shape would take if it was not constrained by the parent framework element.
                    canvasStyle.height = sizeToApply.Height.ToInvariantString() + "px";

                    shapeActualSize = frameworkElement.INTERNAL_GetActualWidthAndHeight(); //Note: in case that the framework element is constrained, it won't take the size of its canvas2d content, so we then resize the canvas2d content so that the shape stretches.

                    if (!frameworkElementWidthWasSpecified)
                    {
                        canvasStyle.width = shapeActualSize.Width.ToInvariantString() + "px";
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", shapeActualSize.Width + 1); //todo: add StrokeThickness instead of +1?
                    }
                    if (!frameworkElementHeightWasSpecified)
                    {
                        canvasStyle.height = shapeActualSize.Height.ToInvariantString() + "px";
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", shapeActualSize.Height + 1); //todo: add StrokeThickness instead of +1?
                    }
                }
                else
                {
                    shapeActualSize = frameworkElement.VisualBounds.Size;

                    if (!frameworkElementWidthWasSpecified)
                    {
                        canvasStyle.width = shapeActualSize.Width.ToInvariantString() + "px";
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", shapeActualSize.Width + 1); //todo: add StrokeThickness instead of +1?
                    }
                    else
                    {
                        shapeActualSize.Width = frameworkElementWidth;
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "width", sizeToApply.Width);
                        canvasStyle.width = sizeToApply.Width.ToInvariantString() + "px";
                    }

                    if (!frameworkElementHeightWasSpecified)
                    {
                        canvasStyle.height = shapeActualSize.Height.ToInvariantString() + "px";
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", shapeActualSize.Height + 1); //todo: add StrokeThickness instead of +1?
                    }
                    else
                    {
                        shapeActualSize.Height = frameworkElementHeight;
                        INTERNAL_HtmlDomManager.SetDomElementAttribute(canvasDomElement, "height", sizeToApply.Height);
                        canvasStyle.height = sizeToApply.Height.ToInvariantString() + "px";
                    }
                }
            }

            var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            context.translate(0.5, 0.5); //makes is less blurry for some reason.
        }
Exemplo n.º 25
0
        internal static void PrepareEllipse(object canvasDomElement, double ellipseWidth, double ellipseHeight, double centerX, double centerY)
        {
            var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(canvasDomElement);

            //todo: StrokeThickness --> ?


            //solutions below have been found at http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
            //todo: check which version is the most effective (note, there are other implementation possibilities in the link above so we might check with those too)
            //todo: once todo above done, apply result on EllipseGeometry class too

            #region using bezier's curves

            //JAVASCRIPT
            //function drawEllipseWithBezier(ctx, x, y, w, h, style) {
            //    var kappa = .5522848,
            //        ox = (w / 2) * kappa, // control point offset horizontal
            //        oy = (h / 2) * kappa, // control point offset vertical
            //        xe = x + w,           // x-end
            //        ye = y + h,           // y-end
            //        xm = x + w / 2,       // x-middle
            //        ym = y + h / 2;       // y-middle

            //    ctx.save();
            //    ctx.beginPath();
            //    ctx.moveTo(x, ym);
            //    ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
            //    ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
            //    ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
            //    ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
            //    if(style)
            //      ctx.strokeStyle=style;
            //    ctx.stroke();
            //    ctx.restore();
            //  }
            //END OF JAVASCRIPT


            //    ctx.bezierCurveTo(x, y + h / 2 - oy, x + w / 2 - ox, y, x + w / 2, y);
            //    ctx.bezierCurveTo(x + w / 2 + ox, y, xe, y + h / 2 - oy, xe, y + h / 2);
            //    ctx.bezierCurveTo(xe, y + h / 2 + oy, x + w / 2 + ox, ye, x + w / 2, ye);
            //    ctx.bezierCurveTo(x + w / 2 - ox, ye, x, y + h / 2 + oy, x, y + h / 2);

            double kappa = .5522848;
            double ox    = (ellipseWidth / 2) * kappa;  // control point offset horizontal
            double oy    = (ellipseHeight / 2) * kappa; // control point offset vertical

            Point topPoint    = new Point(centerX, centerY - ellipseHeight / 2);
            Point leftPoint   = new Point(centerX - ellipseWidth / 2, centerY);
            Point rightPoint  = new Point(centerX + ellipseWidth / 2, centerY);
            Point bottomPoint = new Point(centerX, centerY + ellipseHeight / 2); //the "+ 1" are so that the ellipse is not cut on the edges.

            context.beginPath();
            context.moveTo(leftPoint.X, leftPoint.Y); //start on the leftmost point of the ellipse
            context.bezierCurveTo(centerX - ellipseWidth / 2, centerY - oy,
                                  centerX - ox, centerY - ellipseHeight / 2,
                                  topPoint.X, topPoint.Y); //bezier to the topmost point of the ellipse
            context.bezierCurveTo(centerX + ox, centerY - ellipseHeight / 2,
                                  centerX + ellipseWidth / 2, centerY - oy,
                                  rightPoint.X, rightPoint.Y); //bezier to the rightmost point of the ellipse
            context.bezierCurveTo(centerX + ellipseWidth / 2, centerY + oy,
                                  centerX + ox, centerY + ellipseHeight / 2,
                                  bottomPoint.X, bottomPoint.Y); //bezier to the bottommost point of the ellipse
            context.bezierCurveTo(centerX - ox, centerY + ellipseHeight / 2,
                                  centerX - ellipseWidth / 2, centerY + oy,
                                  leftPoint.X, leftPoint.Y); //bezier to the first point (leftmost point of the ellipse)
            #endregion

            #region using arc and scale

            //JAVASCRIPT
            //  // cx,cy - center, r - horizontal radius X
            //function drawEllipseWithArcAndScale(ctx, cx, cy, rx, ry, style) {
            //  ctx.save(); // save state
            //  ctx.beginPath();
            //  ctx.translate(cx-rx, cy-ry);
            //  ctx.scale(rx, ry);
            //  ctx.arc(1, 1, 1, 0, 2 * Math.PI, false);
            //  ctx.restore(); // restore to original state
            //  ctx.save();
            //  if(style)
            //    ctx.strokeStyle=style;
            //  ctx.stroke();
            //  ctx.restore();
            //}
            //END OF JAVASCRIPT


            //context.save(); // save state
            //context.beginPath();
            //context.scale(actualWidth / 2, actualHeight / 2); ///2 because in context.arc, we put 1 as the radius, so 2 as the perimeter --> 2 as the initial width
            //context.arc(1, 1, 1, 0, 2 * Math.PI, false);
            //context.restore(); // restore to original state
            //context.save();
            //context.strokeStyle = strokeAsString;
            //context.lineWidth = StrokeThickness;
            //context.restore();
            //context.stroke();
            #endregion
        }
Exemplo n.º 26
0
        protected internal override void Redraw()
        {
            if (INTERNAL_VisualTreeManager.IsElementInVisualTree(this))
            {
                if (Data != null)
                {
                    double minX = double.MaxValue;
                    double minY = double.MaxValue;
                    double maxX = double.MinValue;
                    double maxY = double.MinValue;
                    if (Data is PathGeometry pathGeometry)
                    {
                        if (pathGeometry.Figures == null || pathGeometry.Figures.Count == 0)
                        {
                            return;
                        }
                    }
                    Data.GetMinMaxXY(ref minX, ref maxX, ref minY, ref maxY);


                    // If the rare case that the shape is so big (in terms of coordinates of the points, prior to any transform) that it exceeds the size of Int32 (for an example, refer to the charts in "Client_LD"), we need to make it smaller so that the HTML <canvas> control is able to draw it. We compensate by applying a ScaleTransform to the Data.Tranform:
                    Transform originalTransform = Data.Transform;
                    Transform actualTransform   = originalTransform;
                    double    int32FactorX      = 1d;
                    double    int32FactorY      = 1d;
                    INTERNAL_ShapesDrawHelpers.FixCoordinatesGreaterThanInt32MaxValue(minX,
                                                                                      minY,
                                                                                      maxX,
                                                                                      maxY,
                                                                                      ref actualTransform,
                                                                                      ref int32FactorX,
                                                                                      ref int32FactorY);

                    // Apply the transform to the min/max:
                    if (originalTransform != null)
                    {
                        // todo: appying the transform to the min/max is accurate only for Scale and
                        // translate transforms. For other transforms such as rotate, the min/max is incorrect.
                        // For a correct result, we should apply the transform to each point of the figure.

                        Point tmp1 = originalTransform.Transform(new Point(minX, minY));
                        Point tmp2 = originalTransform.Transform(new Point(maxX, maxY));
                        minX = tmp1._x;
                        minY = tmp1._y;
                        maxX = tmp2._x;
                        maxY = tmp2._y;
                    }

                    Size shapeActualSize;
                    INTERNAL_ShapesDrawHelpers.PrepareStretch(this, _canvasDomElement, minX, maxX, minY, maxY, Stretch, out shapeActualSize);

                    double horizontalMultiplicator;
                    double verticalMultiplicator;
                    double xOffsetToApplyBeforeMultiplication;
                    double yOffsetToApplyBeforeMultiplication;
                    double xOffsetToApplyAfterMultiplication;
                    double yOffsetToApplyAfterMultiplication;
                    double strokeThickness = Stroke == null ? 0d : StrokeThickness;
                    INTERNAL_ShapesDrawHelpers.GetMultiplicatorsAndOffsetForStretch(this,
                                                                                    strokeThickness,
                                                                                    minX,
                                                                                    maxX,
                                                                                    minY,
                                                                                    maxY,
                                                                                    Stretch,
                                                                                    shapeActualSize,
                                                                                    out horizontalMultiplicator,
                                                                                    out verticalMultiplicator,
                                                                                    out xOffsetToApplyBeforeMultiplication,
                                                                                    out yOffsetToApplyBeforeMultiplication,
                                                                                    out xOffsetToApplyAfterMultiplication,
                                                                                    out yOffsetToApplyAfterMultiplication,
                                                                                    out _marginOffsets);

                    ApplyMarginToFixNegativeCoordinates(new Point());
                    if (Stretch == Stretch.None)
                    {
                        ApplyMarginToFixNegativeCoordinates(_marginOffsets);
                    }

                    // A call to "context.beginPath" is required on IE and Edge for the figures to be drawn properly (cf. ZenDesk #971):
                    CSHTML5.Interop.ExecuteJavaScriptAsync(@"$0.getContext('2d').beginPath()", _canvasDomElement);

                    var context = INTERNAL_HtmlDomManager.Get2dCanvasContext(_canvasDomElement);

                    // We want the Transform to be applied only while drawing with the "DefineInCanvas" method, not when applying the stroke and fill, so that the Stroke Thickness does not get affected by the transform (like in Silverlight). To do so, we save the current canvas context, then apply the transform, then draw, and then restore to the original state before applying the stroke:
                    context.save();

                    // Apply the transform if any:
                    INTERNAL_ShapesDrawHelpers.ApplyTransformToCanvas(actualTransform, _canvasDomElement);

                    //problem here: the shape seems to be overall smaller than intended due to the edges of the path not being sharp?
                    Data.DefineInCanvas(this,
                                        _canvasDomElement,
                                        horizontalMultiplicator * int32FactorX,
                                        verticalMultiplicator * int32FactorY,
                                        xOffsetToApplyBeforeMultiplication,
                                        yOffsetToApplyBeforeMultiplication,
                                        xOffsetToApplyAfterMultiplication,
                                        yOffsetToApplyAfterMultiplication,
                                        shapeActualSize);

                    // Read the comment near the "save()" above to know what this "restore" is here for.
                    context.restore();

                    Shape.DrawFillAndStroke(this,
                                            Data.GetFillRuleAsString(),
                                            minX,
                                            minY,
                                            maxX,
                                            maxY,
                                            horizontalMultiplicator, // Note: here we do not multiply by "int32Factor" because we do not want to affect the tickness
                                            verticalMultiplicator,   // Note: here we do not multiply by "int32Factor" because we do not want to affect the tickness
                                            xOffsetToApplyBeforeMultiplication,
                                            yOffsetToApplyBeforeMultiplication,
                                            shapeActualSize);
                }
            }
        }