1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using System.Globalization;
|
---|
4 | using System.Windows;
|
---|
5 | using System.Windows.Media;
|
---|
6 |
|
---|
7 | using SharpVectors.Dom.Svg;
|
---|
8 |
|
---|
9 | namespace SharpVectors.Renderers.Texts
|
---|
10 | {
|
---|
11 | public sealed class WpfTextOnPathDrawing : WpfTextOnPathBase
|
---|
12 | {
|
---|
13 | #region Private Fields
|
---|
14 |
|
---|
15 | private double _fontSize;
|
---|
16 |
|
---|
17 | private double _pathLength;
|
---|
18 | private double _textLength;
|
---|
19 |
|
---|
20 | private List<Point> _formattedOrigins;
|
---|
21 | private List<FormattedText> _formattedChars;
|
---|
22 |
|
---|
23 | #endregion
|
---|
24 |
|
---|
25 | #region Constructors and Destructor
|
---|
26 |
|
---|
27 | public WpfTextOnPathDrawing()
|
---|
28 | {
|
---|
29 | _fontSize = 100;
|
---|
30 | _formattedChars = new List<FormattedText>();
|
---|
31 | _formattedOrigins = new List<Point>();
|
---|
32 | }
|
---|
33 |
|
---|
34 | #endregion
|
---|
35 |
|
---|
36 | #region Public Properties
|
---|
37 |
|
---|
38 | public double FontSize
|
---|
39 | {
|
---|
40 | get
|
---|
41 | {
|
---|
42 | return _fontSize;
|
---|
43 | }
|
---|
44 | set
|
---|
45 | {
|
---|
46 | if (value >= 6)
|
---|
47 | {
|
---|
48 | _fontSize = value;
|
---|
49 | }
|
---|
50 | }
|
---|
51 | }
|
---|
52 |
|
---|
53 | #endregion
|
---|
54 |
|
---|
55 | #region Public Methods
|
---|
56 |
|
---|
57 | public void BeginTextPath()
|
---|
58 | {
|
---|
59 | if (_formattedChars == null || _formattedChars.Count != 0)
|
---|
60 | {
|
---|
61 | _formattedChars = new List<FormattedText>();
|
---|
62 | _formattedOrigins = new List<Point>();
|
---|
63 | }
|
---|
64 | _formattedChars.Clear();
|
---|
65 | _formattedOrigins.Clear();
|
---|
66 |
|
---|
67 | _textLength = 0;
|
---|
68 | _pathLength = 0;
|
---|
69 |
|
---|
70 | _fontSize = 100;
|
---|
71 |
|
---|
72 | //typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
|
---|
73 | }
|
---|
74 |
|
---|
75 | public void AddTextPath(string text, Point origin)
|
---|
76 | {
|
---|
77 | if (String.IsNullOrEmpty(text))
|
---|
78 | {
|
---|
79 | return;
|
---|
80 | }
|
---|
81 | Typeface typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
|
---|
82 |
|
---|
83 | foreach (char ch in text)
|
---|
84 | {
|
---|
85 | FormattedText formattedText =
|
---|
86 | new FormattedText(ch.ToString(), CultureInfo.CurrentCulture,
|
---|
87 | FlowDirection.LeftToRight, typeface, _fontSize, Foreground);
|
---|
88 |
|
---|
89 | _formattedChars.Add(formattedText);
|
---|
90 | _formattedOrigins.Add(origin);
|
---|
91 |
|
---|
92 | _textLength += formattedText.WidthIncludingTrailingWhitespace;
|
---|
93 | }
|
---|
94 | }
|
---|
95 |
|
---|
96 | public void EndTextPath()
|
---|
97 | {
|
---|
98 | if (_formattedChars != null)
|
---|
99 | {
|
---|
100 | _formattedChars.Clear();
|
---|
101 | }
|
---|
102 |
|
---|
103 | if (_formattedOrigins != null)
|
---|
104 | {
|
---|
105 | _formattedOrigins.Clear();
|
---|
106 | }
|
---|
107 | }
|
---|
108 |
|
---|
109 | public void DrawTextPath(DrawingContext dc, PathGeometry pathGeometry,
|
---|
110 | ISvgAnimatedLength startOffset, TextAlignment alignment, SvgTextPathMethod method,
|
---|
111 | SvgTextPathSpacing spacing)
|
---|
112 | {
|
---|
113 | if (alignment == TextAlignment.Right)
|
---|
114 | {
|
---|
115 | this.DrawEndAlignedTextPath(dc, pathGeometry, startOffset);
|
---|
116 | }
|
---|
117 | else
|
---|
118 | {
|
---|
119 | this.DrawStartAlignedTextPath(dc, pathGeometry, startOffset, alignment);
|
---|
120 | }
|
---|
121 | }
|
---|
122 |
|
---|
123 | #endregion
|
---|
124 |
|
---|
125 | #region Private Methods
|
---|
126 |
|
---|
127 | private void DrawStartAlignedTextPath(DrawingContext dc, PathGeometry pathGeometry,
|
---|
128 | ISvgAnimatedLength startOffset, TextAlignment alignment)
|
---|
129 | {
|
---|
130 | if (pathGeometry == null || pathGeometry.Figures == null ||
|
---|
131 | pathGeometry.Figures.Count != 1)
|
---|
132 | {
|
---|
133 | return;
|
---|
134 | }
|
---|
135 |
|
---|
136 | _pathLength = GetPathFigureLength(pathGeometry.Figures[0]);
|
---|
137 | if (_pathLength == 0 || _textLength == 0)
|
---|
138 | return;
|
---|
139 |
|
---|
140 | //double scalingFactor = pathLength / textLength;
|
---|
141 | double scalingFactor = 1.0; // Not scaling the text to fit...
|
---|
142 | double progress = 0;
|
---|
143 | if (startOffset != null)
|
---|
144 | {
|
---|
145 | ISvgLength offsetLength = startOffset.AnimVal;
|
---|
146 | if (offsetLength != null)
|
---|
147 | {
|
---|
148 | switch (offsetLength.UnitType)
|
---|
149 | {
|
---|
150 | case SvgLengthType.Percentage:
|
---|
151 | if ((float)offsetLength.ValueInSpecifiedUnits != 0)
|
---|
152 | {
|
---|
153 | progress += offsetLength.ValueInSpecifiedUnits / 100d;
|
---|
154 | }
|
---|
155 | break;
|
---|
156 | }
|
---|
157 | }
|
---|
158 | }
|
---|
159 | //PathGeometry pathGeometry =
|
---|
160 | // new PathGeometry(new PathFigure[] { PathFigure });
|
---|
161 |
|
---|
162 | Point ptOld = new Point(0, 0);
|
---|
163 |
|
---|
164 | for (int i = 0; i < _formattedChars.Count; i++)
|
---|
165 | {
|
---|
166 | FormattedText formText = _formattedChars[i];
|
---|
167 |
|
---|
168 | double width = scalingFactor *
|
---|
169 | formText.WidthIncludingTrailingWhitespace;
|
---|
170 | double baseline = scalingFactor * formText.Baseline;
|
---|
171 | progress += width / 2 / _pathLength;
|
---|
172 | Point point, tangent;
|
---|
173 |
|
---|
174 | pathGeometry.GetPointAtFractionLength(progress,
|
---|
175 | out point, out tangent);
|
---|
176 |
|
---|
177 | if (i != 0)
|
---|
178 | {
|
---|
179 | if (point == ptOld)
|
---|
180 | {
|
---|
181 | break;
|
---|
182 | }
|
---|
183 | }
|
---|
184 |
|
---|
185 | dc.PushTransform(
|
---|
186 | new TranslateTransform(point.X - width / 2,
|
---|
187 | point.Y - baseline));
|
---|
188 | dc.PushTransform(
|
---|
189 | new RotateTransform(Math.Atan2(tangent.Y, tangent.X)
|
---|
190 | * 180 / Math.PI, width / 2, baseline));
|
---|
191 | //dc.PushTransform(
|
---|
192 | // new ScaleTransform(scalingFactor, scalingFactor));
|
---|
193 |
|
---|
194 | dc.DrawText(formText, _formattedOrigins[i]);
|
---|
195 | dc.Pop();
|
---|
196 | dc.Pop();
|
---|
197 | //dc.Pop();
|
---|
198 |
|
---|
199 | progress += width / 2 / _pathLength;
|
---|
200 |
|
---|
201 | ptOld = point;
|
---|
202 | }
|
---|
203 | }
|
---|
204 |
|
---|
205 | private void DrawEndAlignedTextPath(DrawingContext dc, PathGeometry pathGeometry,
|
---|
206 | ISvgAnimatedLength startOffset)
|
---|
207 | {
|
---|
208 | if (pathGeometry == null || pathGeometry.Figures == null ||
|
---|
209 | pathGeometry.Figures.Count != 1)
|
---|
210 | {
|
---|
211 | return;
|
---|
212 | }
|
---|
213 |
|
---|
214 | _pathLength = GetPathFigureLength(pathGeometry.Figures[0]);
|
---|
215 | if (_pathLength == 0 || _textLength == 0)
|
---|
216 | return;
|
---|
217 |
|
---|
218 | //double scalingFactor = pathLength / textLength;
|
---|
219 | double scalingFactor = 1.0; // Not scaling the text to fit...
|
---|
220 | double progress = 1.0;
|
---|
221 | //PathGeometry pathGeometry =
|
---|
222 | // new PathGeometry(new PathFigure[] { PathFigure });
|
---|
223 |
|
---|
224 | Point ptOld = new Point(0, 0);
|
---|
225 |
|
---|
226 | int itemCount = _formattedChars.Count - 1;
|
---|
227 |
|
---|
228 | for (int i = itemCount; i >= 0; i--)
|
---|
229 | {
|
---|
230 | FormattedText formText = _formattedChars[i];
|
---|
231 |
|
---|
232 | double width = scalingFactor *
|
---|
233 | formText.WidthIncludingTrailingWhitespace;
|
---|
234 | double baseline = scalingFactor * formText.Baseline;
|
---|
235 | progress -= width / 2 / _pathLength;
|
---|
236 | Point point, tangent;
|
---|
237 |
|
---|
238 | pathGeometry.GetPointAtFractionLength(progress,
|
---|
239 | out point, out tangent);
|
---|
240 |
|
---|
241 | if (i != itemCount)
|
---|
242 | {
|
---|
243 | if (point == ptOld)
|
---|
244 | {
|
---|
245 | break;
|
---|
246 | }
|
---|
247 | }
|
---|
248 |
|
---|
249 | dc.PushTransform(
|
---|
250 | new TranslateTransform(point.X - width / 2,
|
---|
251 | point.Y - baseline));
|
---|
252 | dc.PushTransform(
|
---|
253 | new RotateTransform(Math.Atan2(tangent.Y, tangent.X)
|
---|
254 | * 180 / Math.PI, width / 2, baseline));
|
---|
255 | //dc.PushTransform(
|
---|
256 | // new ScaleTransform(scalingFactor, scalingFactor));
|
---|
257 |
|
---|
258 | dc.DrawText(formText, _formattedOrigins[i]);
|
---|
259 | dc.Pop();
|
---|
260 | dc.Pop();
|
---|
261 | //dc.Pop();
|
---|
262 |
|
---|
263 | progress -= width / 2 / _pathLength;
|
---|
264 |
|
---|
265 | ptOld = point;
|
---|
266 | }
|
---|
267 | }
|
---|
268 |
|
---|
269 | //protected override void OnPathPropertyChanged(DependencyPropertyChangedEventArgs args)
|
---|
270 | //{
|
---|
271 | // pathLength = GetPathFigureLength(PathFigure);
|
---|
272 | // //TransformVisualChildren();
|
---|
273 | //}
|
---|
274 |
|
---|
275 | protected override void OnFontPropertyChanged(DependencyPropertyChangedEventArgs args)
|
---|
276 | {
|
---|
277 | //OnTextPropertyChanged(args);
|
---|
278 | }
|
---|
279 |
|
---|
280 | protected override void OnForegroundPropertyChanged(DependencyPropertyChangedEventArgs args)
|
---|
281 | {
|
---|
282 | //OnTextPropertyChanged(args);
|
---|
283 | }
|
---|
284 |
|
---|
285 | //protected override void OnTextPropertyChanged(DependencyPropertyChangedEventArgs args)
|
---|
286 | //{
|
---|
287 | // //GenerateVisualChildren();
|
---|
288 | //}
|
---|
289 |
|
---|
290 | //protected virtual void GenerateVisualChildren()
|
---|
291 | //{
|
---|
292 | // visualChildren.Clear();
|
---|
293 |
|
---|
294 | // foreach (FormattedText formText in formattedChars)
|
---|
295 | // {
|
---|
296 | // DrawingVisual drawingVisual = new DrawingVisual();
|
---|
297 |
|
---|
298 | // TransformGroup transformGroup = new TransformGroup();
|
---|
299 | // transformGroup.Children.Add(new ScaleTransform());
|
---|
300 | // transformGroup.Children.Add(new RotateTransform());
|
---|
301 | // transformGroup.Children.Add(new TranslateTransform());
|
---|
302 | // drawingVisual.Transform = transformGroup;
|
---|
303 |
|
---|
304 | // DrawingContext dc = drawingVisual.RenderOpen();
|
---|
305 | // dc.DrawText(formText, new Point(0, 0));
|
---|
306 | // dc.Close();
|
---|
307 |
|
---|
308 | // visualChildren.Add(drawingVisual);
|
---|
309 | // }
|
---|
310 |
|
---|
311 | // TransformVisualChildren();
|
---|
312 | //}
|
---|
313 |
|
---|
314 | //protected virtual void TransformVisualChildren()
|
---|
315 | //{
|
---|
316 | // boundingRect = new Rect();
|
---|
317 |
|
---|
318 | // if (pathLength == 0 || textLength == 0)
|
---|
319 | // return;
|
---|
320 |
|
---|
321 | // if (formattedChars.Count != visualChildren.Count)
|
---|
322 | // return;
|
---|
323 |
|
---|
324 | // double scalingFactor = pathLength / textLength;
|
---|
325 | // PathGeometry pathGeometry =
|
---|
326 | // new PathGeometry(new PathFigure[] { PathFigure });
|
---|
327 | // double progress = 0;
|
---|
328 | // boundingRect = new Rect();
|
---|
329 |
|
---|
330 | // for (int index = 0; index < visualChildren.Count; index++)
|
---|
331 | // {
|
---|
332 | // FormattedText formText = formattedChars[index];
|
---|
333 | // double width = scalingFactor *
|
---|
334 | // formText.WidthIncludingTrailingWhitespace;
|
---|
335 | // double baseline = scalingFactor * formText.Baseline;
|
---|
336 | // progress += width / 2 / pathLength;
|
---|
337 | // Point point, tangent;
|
---|
338 | // pathGeometry.GetPointAtFractionLength(progress,
|
---|
339 | // out point, out tangent);
|
---|
340 |
|
---|
341 | // DrawingVisual drawingVisual =
|
---|
342 | // visualChildren[index] as DrawingVisual;
|
---|
343 | // TransformGroup transformGroup =
|
---|
344 | // drawingVisual.Transform as TransformGroup;
|
---|
345 | // ScaleTransform scaleTransform =
|
---|
346 | // transformGroup.Children[0] as ScaleTransform;
|
---|
347 | // RotateTransform rotateTransform =
|
---|
348 | // transformGroup.Children[1] as RotateTransform;
|
---|
349 | // TranslateTransform translateTransform =
|
---|
350 | // transformGroup.Children[2] as TranslateTransform;
|
---|
351 |
|
---|
352 | // scaleTransform.ScaleX = scalingFactor;
|
---|
353 | // scaleTransform.ScaleY = scalingFactor;
|
---|
354 | // rotateTransform.Angle =
|
---|
355 | // Math.Atan2(tangent.Y, tangent.X) * 180 / Math.PI;
|
---|
356 | // rotateTransform.CenterX = width / 2;
|
---|
357 | // rotateTransform.CenterY = baseline;
|
---|
358 | // translateTransform.X = point.X - width / 2;
|
---|
359 | // translateTransform.Y = point.Y - baseline;
|
---|
360 |
|
---|
361 | // Rect rect = drawingVisual.ContentBounds;
|
---|
362 | // rect.Transform(transformGroup.Value);
|
---|
363 | // boundingRect.Union(rect);
|
---|
364 |
|
---|
365 | // progress += width / 2 / pathLength;
|
---|
366 | // }
|
---|
367 | // InvalidateMeasure();
|
---|
368 | //}
|
---|
369 |
|
---|
370 | //protected override int VisualChildrenCount
|
---|
371 | //{
|
---|
372 | // get
|
---|
373 | // {
|
---|
374 | // return visualChildren.Count;
|
---|
375 | // }
|
---|
376 | //}
|
---|
377 |
|
---|
378 | //protected override Visual GetVisualChild(int index)
|
---|
379 | //{
|
---|
380 | // if (index < 0 || index >= visualChildren.Count)
|
---|
381 | // throw new ArgumentOutOfRangeException("index");
|
---|
382 |
|
---|
383 | // return visualChildren[index];
|
---|
384 | //}
|
---|
385 |
|
---|
386 | //protected override Size MeasureOverride(Size availableSize)
|
---|
387 | //{
|
---|
388 | // return (Size)boundingRect.BottomRight;
|
---|
389 | //}
|
---|
390 |
|
---|
391 | #endregion
|
---|
392 | }
|
---|
393 | }
|
---|