WPF dynamically scale TextBlock Text without filling a container - wpf

I have a set of pages that look like this:
I have the content in grids with * Heights and Widths so the grid correctly scales when the entire window resizes. I would like the text to resize with the grid. Basically I would like the user to resize from this:
To this:
(preserving white space)
One way to do this would be to wrap the TextBlock in a ViewBox with margins on the right and bottom (for Grid.Row="3") to account for white space. But because I have several pages with different lengths and line counts I would have to set the margin specifically for each page otherwise the text sizes would differ on each page. Is there a better way to do this??

I don't think there is a better way to do this. There are different ways. But, I think it isn't just a matter of opinion that they would not be better.
Ways I can think of.
Render your text offscreen, rendertargetbitmap that so you've got a picture. Change your textblocks on screen to images and stretch them.
Or
Work out the size your text wants to be. Then do some calculation comes up with a different fontsize which is "better". This is a lot easier to write a description of than do.
In my opinion.
A viewbox is easier to implement. Way less error prone than calculations. Will give at least as good results as rendering to a picture.

I just want to add one more solution to the ones suggested by Andy, which is more of a scientific approach and takes a bit of practice to master.
Suppose you have to find a function F, which maps one or more variables to a desired single value. In your case that would be a function F, which takes aspect ratio of the window as input and outputs an appropriate font size.
How can you find such a function?
Well... you don't need to do any math yourself!
First, you need some data to begin with:
1. Resize the window randomly
2. Calculate aspect ration (X)
3. Pick an appropriate font size that looks good enough (Y)
4. Repeat the measurement 7 to 10 times (sorry data scientists)
5. Enter the data in Excel - one column for X and another one for Y
6. Insert a scatter chart
7. Choose the best trendline for your data, but avoid the polynomial one
8. Display the trendline equation and use the expression in your code
Now I should mention the pros and cons of this regression technique.
Pros:
1. It can solve a wide range of tricky problems:
"I use this 3rd party control, but when the text is too long it overlaps the title bar. How to trim it so it doesn't go beyond the top border?. Deadline is coming!"
2. Even if it doesn't solve the problem perfectly, the results are often acceptable
3. It takes minutes to try out unlike spending a day refreshing your math skills
Cons:
1. The biggest problem is that to keep it simple, you often lower the number of
variables by assuming some of them to be constant. In this post I've assumed that
the font family won't change for example, neither the font weight.
2. If any of the assumptions does not hold the final result could be even worse
This technique is fragile, but powerful. Use it as your last weapon and never leave magic expression like
fontSize = (int)(0.76 + 1.2 * aspectRation) without documenting how it came to be.

Related

Graphs the same size in gnuplot multiplot when each take up most of its canvas and one has labels

I've reedited this question a few times: I've made some good progress!
So, as I understand it, multiplot splits the whole canvas up into equal sized parts as needed. This is a little weird when your different plots have different dimensions, as in my case, but it works. The problem might come in when the graph are supposed to be very close together (e.g. each takes up most of its canvas), but one of them has labels. In that case, it seems the plot with labels must resize to be smaller so everything can fit. That's where I am now.
I see a few options.
make all the plots farther apart-- but I don't want to do that.
somehow make the label not part of the multiplot-- I would totally do this, but I don't know how. It's possible even just the axis tics themselves would be too big, but I can probably deal with that or compromise just that amount on the spacing.
So my question is, how can I put words in a gnuplot graph, completely separately from a plot?
(The picture is also giant, which is unfortunate, it was the only way I could make the formatting work)
Two things:
Multiplot has a convenience mode layout <rows>, <columns> that, as you say, splits the page into equal rectangles. But you do not have to use this convenience mode; you can assign each sub-plot to any arbitrary rectangle on the page, even one that overlaps or is interior to another rectangle. Here is an example from the online demo set that is close to what you show:
Demo of multiple plots with explicit alignment of borders
Placing text anywhere on the page: The set label command allows you to position the text using screen coordinates rather than plot coordinates. For example, to place a single large label centered at the top of a page that contains multiple plots:
set label 1 "This label is positioned independent of all plots"
set label 1 at screen 0.5, screen 0.95 center
set label 1 font "Times,20"

What is the most efficient method of displaying many components using the FlowLayout?

I'm working on a form that shows many our company's products in a FlowLayout, but on some categories that hold many products, performance in scrolling is noticeably affected. I switched to a List so I could leverage the performance benefits of using a renderer, but now I'm not happy with the layout since there's a lot of wasted space, especially if the device is in landscape mode.
My next thought was to use a Table, which I believe also uses renderers to optimize the display of its data; but to mimic a FlowLayout, I'd need to get the preferred width of some placeholder component, then divide the container's width by that to get the number of columns, and then fill the model with that number of columns in mind. I'd also need to change all that if the device changes orientation.
Before I go down that rabbit hole, I'm wondering if I'm making things unnecessarily complicated for myself and if there's already something that I can use to achieve that goal. So to summarize, what would be the most efficient way to display data (that would be shown as buttons) sequentially from left to right, and top to bottom?
I wouldn't use FlowLayout for anything serious although I doubt its the reason for your performance issues, those probably relate to something else. There is a performance how do I video which is a bit old but mostly still relevant: http://www.codenameone.com/how-do-i---improve-application-performance-or-track-down-performance-issues.html
In design terms flow layout is hugely problematic since the elements are not aligned properly thus producing a UI that doesn't look good when spanning multiple rows. I suggest using a grid layout which has a mode called auto fit. By using setAutoFit(true) on a grid of even 1x1 all the elements will take up all available space uniformly based on screen size and adapt with orientation changes.

Distribute text top-to-bottom instead of left-to-right

I'm working on a view that's implementing a multi-column text layout using CoreText (using CTFramesetter).
CoreText usually fills each frame completely, so when I call CTFramesetterCreateFrame with three rects that make up my columns, I get a layout that's similar to the following image:
So the left column is filled completely, the middle column partially and the right column is empty. But instead, I'd like the text to distribute over the three columns so that they take up the least vertical space possible, like in this image:
How to achieve this with CoreText?
I don't mind going low-level here, even drawing each CTRun by hand is an option if necessary.
One idea I came up with would be to create a large frame with the width of a column and then figure out which CTLine to draw in which column. But this has a few limitations:
It would only work if all columns had the same width.
It does not work with clipping paths.
Unfortunately, I'll need to use clipping paths (as in kCTFrameClippingPathsAttributeName) so this idea is out. I could live the fixed column width limitation, though.
Another idea would be to reduce the height until the last frame overflows but that's a pretty brute-force way that surely wastes resources.
(BTW, due to compability requirements the use of TextKit classes like NSTextStorage isn't possible; the resulting view is intended to be used on Mac and iOS, but it needs to work on iOS < 7)
Since there doesn't seem to be a non-expensive way to solve this, here's how I've done it:
I did go with the "reduce the height until the last frame overflows" approach. To reduce the height, I simply have another clipping path (kCTFrameClippingPathsAttributeName) which is a rectangle that fills the bottom of the view to the required height.
The probably most expensive but simple way would have been to increase the rectangle height until finally the text doesn't fit inside the last frame any more.
Instead I've implemented a binary search for that. For my demo app, I usually find the correct height after 8-10 recursions which still is expensive but at least it's pixel-perfect and doesn't rely on any other information other than "did the last frame overflow".

Display percentage value as a fill in a custom shape

I'm looking at some new options for displaying a percentage value as a fill in a custom shape. Consider the effect to be similar to a "progress thermometer" in a traditional dashboard UI sense.
Considerations
Goal - a graphic element showing a percentage value for a custom report.
Format - Either a full graphic (or infographic) itself, or part of a PDF via Photoshop/InDesign or even iBooks (as an excuse to use it).
Usage - I'd like the process to be programmatic, for re-use. It needs to be accurate, and I'd like the solution to be somewhat object oriented to apply to other datasets and graphical containers. This rules out hand-drawn charting.
Source data - currently a pivot table in Excel, but I can work with any other host as required.
Shape - is a custom vector shape that will originate from Illustrator/Inkscape. final format as best fits resolution and rendering of the report. I would also be interested in any other generative shape ideas (such as java/javascript).
Fill - I'd like to be able to represent the fill as both an actual percentage of total area (true up), and as a percentage of the vertical scale. I'd imagine this flexibility would also help reuse of the method as a fill value against selected object variables (height, area, whatever).
I know I'm being slightly vague in the programming languages or hosts side of things, but this gives me an opportunity to break out of the usual analytic toolchain and scope out some innovative or new solutions. I'm specifically interested in open source solutions, but I'm very keen to review other current methods you might suggest.
This might be a little open ended for you, but d3.js is very powerful. There might be some useful templates on the site, or you can build your own from the library.
If you limit yourself to shapes where the percentage can be easily converted into a new shape by varying one of the dimensions, then the display part can be covered by creating a second shape based on the first one, and filling in 100% of the second shape.
This obviously works best with simple shapes like squares, rectangles, circles, etc, where it is simple to convert "50% of the area" or "75% of the height" into manipulation of vector nodes.
However, things gets significantly more difficult if you want to support genuinely arbitrary custom shapes. One way to handle that would be to break up a complex "progress bar" into "progress pieces" (e.g. a thermometer bulb that represents 10% of total progress, then a simple bar for the remaining 90%).
As has been mentioned, D3 seems like it would meet your needs - here are some simple examples of what I think you are asking:
Changing the fill color of a distinct shape: http://jsfiddle.net/jsl6906/YCMb8/
Changing the 'fill amount' of a simple shape: http://jsfiddle.net/jsl6906/YCMb8/1/

WPF tabswitch/ render takes too much time

I have a WPF application with many tabs..
in one tab.. i make a verycomplex vector drawing consisting of thousands of drawing visuals.. (this represents a machine and all elements need to be interactable..)
It takes 3/4 seconds for drawing this for the first time..After the first draw it should be done..
The problem is if i switch to another tab and comeback, it takes atlease 2,3 seconds to show the tabpage with drawing again.. Since there is no redraw, why should it take so much time..?
If the component is not going to change, you could call Freeze() on it to mark it as done. Without trying it out I don't know if that would help, but you could give it a shot.
Not all objects are Freezable. Check out the MSDN documentation for more info:
http://msdn.microsoft.com/en-us/library/ms750509.aspx
Another thing you could try would be rendering the vector art to a bitmap, and displaying that. Maybe it makes you feel icky to lose the vector precision, but if you know it's not going to change and it will look the same, what's the harm? (If you support printing or something that will require a hi-res version, you could always switch back for that operation.) For info on how to convert a UIElement to a bitmap, check out:
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.rendertargetbitmap.aspx
Another possible solution: You don't really explain what kind of interaction you are doing with the elements, but if all you want to do is zoom and pan, a RenderTransform may be good enough (which is more efficient than a LayoutTransform and/or moving all the elements individually). I haven't played around with combining Freeze() and a RenderTransform, but you may be able to get the desired zooming while reducing the amount of layout WPF has to do.

Resources