-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathGraphics_State.html
More file actions
127 lines (88 loc) · 8.78 KB
/
Copy pathGraphics_State.html
File metadata and controls
127 lines (88 loc) · 8.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html><head>
<title></title>
</head><body>
<div class="article">
<p>The PlotDevice canvas "remembers" the style and transformation settings used to draw primitives. These settings make up the "graphics state" and exist independently from the primitives you add to the canvas. This lets you keep drawing- and styling-related code separate and allows you to apply styles to groups of objects rather than needing to configure each one.</p>
<p>You can think of it like working on an oil-painting. While at the easel, you can hold one type of brush and put one color of paint on it. All the strokes you paint on the canvas will have the same color and texture according to the thickness of the brush and color of paint. Naturally, you could paint with both hands and feet holding multiple brushes with multiple colors … but we wouldn't recommend it.</p>
<p>In PlotDevice you ‘paint’ with one color at a time. All of the elements you draw have the same color
until you actively switch to a different one. Then all subsequent elements you draw will use that new color.</p>
<h1>Stateful Commands</h1>
<p>When you run a script, PlotDevice reads the code from <b>top to bottom</b>, like a recipe. When
it encounters certain state-changing commands, it responds not through any immediately visible change, but instead by silently updating the canvas's "current" setting for the given attribute. Afterwards, any primitives you draw will "inherit" the graphics state, including your modification.</p>
<p>Quite a few commands affect the graphics state, but they fall into four general categories:</p>
<ol>
<li>Color & line-style: <a href="../ref/Line+Color.html#color()">color()</a>, <a href="../ref/Line+Color.html#fill()">fill()</a>, <a href="../ref/Line+Color.html#stroke()">stroke()</a>, <a href="../ref/Line+Color.html#pen()">pen()</a></li>
<li>Compositing effects: <a href="../ref/Compositing.html#alpha()">alpha()</a>, <a href="../ref/Compositing.html#blend()">blend()</a>, <a href="../ref/Compositing.html#shadow()">shadow()</a></li>
<li>Transformations: <a href="../ref/Transform.html#transform()">transform()</a>, <a href="../ref/Transform.html#translate()">translate()</a>, <a href="../ref/Transform.html#rotate()">rotate()</a>, <a href="../ref/Transform.html#scale()">scale()</a>, <a href="../ref/Transform.html#skew()">skew()</a>, <a href="../ref/Transform.html#reset()">reset()</a></li>
<li>Typography: <a href="../ref/Typography.html#font()">font()</a>, <a href="../ref/Typography.html#layout()">layout()</a>, <a href="../ref/Typography.html#stylesheet()">stylesheet()</a></li>
</ol>
<p>At the beginning of your script, the state is initialized to a set of reasonable defaults:</p>
<ul>
<li>the <i>fill</i> color is <span class="message">black</span></li>
<li>the <i>stroke</i> color is <span class="message">transparent</span></li>
<li>the pen's <i>nib</i> size is <span class="message">1</span> (though lines will only be drawn if the <i>stroke</i> is visible)</li>
<li>the <i>transform</i> is <span class="message">reset</span> (to the "identity" matrix)</li>
<li>the <i>font</i> is <span class="message">Helvetica Neue</span> at 24pt (with a <i>leading</i> of <span class+'message'>1.2</span>)</li>
</ul>
<p>You can also restore the graphics state to these defaults at any time by calling the <a href="Canvas.html#clear()">clear()</a> command with the parameter <code class="kw">all</code>.</p>
<h1>Setting the State</h1>
<p>All the primitives we draw to the canvas will use the default style settings (until we overwrite them with new values). For example, observe the following script. We start by drawing a circular arc with the default color state. We then change the <em>fill</em> to <span class="message">red</span> and
draw a pair of circles below the first. Finally we change the <em>stroke</em> from transparent to <span class="message">black</span> and the <em>fill</em> color to <span class="message">transparent</span>. After making this change, we draw two more circles which inherit the new style:
</p>
<div class="media"><img alt="" height="469" src="../etc/tut/graphics_state1.png" width="657"/></div>
<a name="with"></a>
<h2>The magical "with" statement</h2>
<p>Many PlotDevice commands support an optional "clean up" behavior. In fact nearly everything that affects the graphics state can be made into a <em>temporary</em> modification by calling the command as part of a <code class="kw">with</code> statement.</p>
<p>When you call a command in a <code class="kw">with</code> statement, place a colon at the end of the line and add one or more indented lines of code below it. When called this way, the state-changing commands will "remember" the previous setting before modifying it. When the indented-block is done executing, the remembered state will be restored for the given command.</p>
<p>For example, both of the following are equivalent:</p>
<pre>
oldfill = fill() # remember the old color
fill('red') # set the new color
arc(40,40, 10) # draw
fill(oldfill) # restore the old color
</pre>
<pre>
with fill('red'): # remember the old color and set a new one
arc(40,40, 10) # draw
... # old color automatically restored
</pre>
<p>You can even combine multiple commands (separated by commas) and their effects will be limited to the drawing that happens <em>inside</em> the indented code-block that follows. Once you return to the outer indentation-level, it's as if you never changed the graphics state:
<div class="media"><img alt="" height="483" src="../etc/tut/graphics_state6.png" width="662"/></div>
</p>
<p>Commands that support the <code>with</code> statement are called "context managers" in Python lingo. Take a look at the Reference section's <a href="../manual.html#ref">table of contents</a> to see which commands can be used in this manner (they're all marked with dots). Then read their reference entries for details on how the <code class="kw">with</code> usage changes their behavior.</p>
<h1>Breaking the State</h1>
<p>If necessary, you can break away from the "current" state and colorize or transform elements individually. Each of the drawing primitives accepts optional parameters that correspond to the state-changing commands:</p>
<ul>
<li><i>fill</i> and <i>stroke</i> for colors</li>
<li><i>nib</i>, <i>join</i>, <i>cap</i>, and <i>dash</i> for line-drawing</li>
<li><i>alpha</i>, <i>blend</i>, and <i>shadow</i> for compositing effects</li>
</ul>
<p>In addition to these parameters, the <a href="../ref/Primitives.html#text()">text()</a> primitive also supports all of the settings available in the <i>font()</i> and <i>layout()</i> commands:</p>
<ul>
<li><i>family</i>, <i>size</i>, <i>italic</i>, <i>tracking</i>, etc. from <a href="../ref/Typography.html#font()">font()</a> for setting character styles</li>
<li><i>leading</i>, <i>indent</i>, <i>margin</i>, <i>align</i>, etc. from <a href="../ref/Typography.html#layout()">layout()</a> for setting paragraph styles</li>
</ul>
<p>So you could "override" the canvas's fill color with:</p>
<pre>rect(20, 20, 100, 100, fill="red")</pre>
<p>Or you could break away from the canvas's <a href="Typography.html">Typography</a> settings with:</p>
<pre>text("hello", 200, 200, family="Baskerville", size=24, italic=True, align=CENTER)</pre>
<h2>Restyling Primitives</h2>
<p>When you call a primitive command, it returns a reference to the <a href="../ref/Drawing.html#Bezier">Bezier</a>, <a href="../ref/Typography.html#Text">Text</a>, or <a href="../ref/Drawing.html#Image">Image</a> object that has been created. If you assign this value to a variable, you can inspect the style-settings it "inherited" from the global state and modify them for that object alone. This can come in handy in looping contexts where you may not know the settings you wish to modify until after calling the primitive command.</p>
<p>For instance, the previous example of drawing a red box (regardless of the current <i>fill()</i> color) could also be achieved by modifying a reference to the <i>Bezier</i> returned by the <i>rect()</i> command:
<pre>
r = rect(20, 20, 100, 100)
r.fill = color("red")
</pre>
<p>Similarly, you can modify the object's <a href="../ref/Transform.html#Transform">Transform</a> by calling its methods:</p>
<pre>r.translate(x, y=None)
r.rotate(angle)
r.scale(x, y=None)
r.skew(x, y=None)
r.reset()
</pre>
<p>The transformations are then applied only to rectangle r. Since each of the transform methods returns a reference to the primitive, you can even "chain" these calls:</p>
<pre>r.reset().translate(100, 50).rotate(45)
</pre>
</div>
</body></html>