1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.vectomatic.svg.edit.client.engine;
19
20 import org.vectomatic.dom.svg.OMSVGDefsElement;
21 import org.vectomatic.dom.svg.OMSVGDocument;
22 import org.vectomatic.dom.svg.OMSVGGElement;
23 import org.vectomatic.dom.svg.OMSVGLength;
24 import org.vectomatic.dom.svg.OMSVGPathElement;
25 import org.vectomatic.dom.svg.OMSVGPathSegList;
26 import org.vectomatic.dom.svg.OMSVGPatternElement;
27 import org.vectomatic.dom.svg.OMSVGPoint;
28 import org.vectomatic.dom.svg.OMSVGRectElement;
29 import org.vectomatic.dom.svg.OMSVGSVGElement;
30 import org.vectomatic.dom.svg.impl.SVGSVGElement;
31 import org.vectomatic.dom.svg.utils.DOMHelper;
32 import org.vectomatic.dom.svg.utils.SVGConstants;
33 import org.vectomatic.svg.edit.client.AppBundle;
34 import org.vectomatic.svg.edit.client.AppCss;
35 import org.vectomatic.svg.edit.client.model.svg.SVGViewBoxElementModel;
36
37 import com.google.gwt.core.client.GWT;
38 import com.google.gwt.dom.client.Style.Unit;
39 import com.google.gwt.dom.client.Style.Visibility;
40 import com.google.gwt.event.dom.client.MouseMoveEvent;
41 import com.google.gwt.event.dom.client.MouseMoveHandler;
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 public class Grid {
88
89
90
91 private boolean showsGrid;
92
93
94
95 private boolean showsGuides;
96
97
98
99 private boolean snapsToGrid;
100
101
102
103 private OMSVGDefsElement defs;
104
105
106
107 private OMSVGGElement root;
108
109
110
111 private OMSVGRectElement grid;
112
113
114
115 private OMSVGGElement hruler;
116
117
118
119 private OMSVGGElement vruler;
120
121
122
123 private OMSVGPathElement hmarker;
124
125
126
127 private OMSVGPathElement vmarker;
128
129
130
131 private MouseMoveHandler moveHandler;
132
133
134
135 private SVGModel svgModel;
136
137
138
139 private float dx;
140
141
142
143 private float dy;
144
145 public Grid() {
146 moveHandler = new MouseMoveHandler() {
147 @Override
148 public void onMouseMove(MouseMoveEvent event) {
149 if (showsGuides && isAttached()) {
150 OMSVGPoint p = svgModel.getCoordinates(event, true);
151 setHMarkerPosition(p.getX());
152 setVMarkerPosition(p.getY());
153 }
154 }
155 };
156 }
157
158 public boolean showsGrid() {
159 return showsGrid;
160 }
161
162 public void setShowsGrid(boolean showsGrid) {
163 GWT.log("Grid.setShowsGrid(" + showsGrid + ")");
164 this.showsGrid = showsGrid;
165 grid.getStyle().setVisibility(showsGrid ? Visibility.VISIBLE : Visibility.HIDDEN);
166 }
167
168 public boolean showsGuides() {
169 return showsGuides;
170 }
171
172 public void setShowsGuides(boolean showsGuides) {
173 GWT.log("Grid.setShowsGuides(" + showsGuides + ")");
174 this.showsGuides = showsGuides;
175 hruler.getStyle().setVisibility(showsGuides ? Visibility.VISIBLE : Visibility.HIDDEN);
176 vruler.getStyle().setVisibility(showsGuides ? Visibility.VISIBLE : Visibility.HIDDEN);
177 }
178
179 public boolean snapsToGrid() {
180 return snapsToGrid;
181 }
182
183 public void setSnapsToGrid(boolean snapsToGrid) {
184 GWT.log("Grid.setSnapsToGrid(" + snapsToGrid + ")");
185 this.snapsToGrid = snapsToGrid;
186 }
187
188 public OMSVGDefsElement getDefs() {
189 return defs;
190 }
191
192 public OMSVGGElement getRoot() {
193 return root;
194 }
195
196 public MouseMoveHandler getMouseMoveHandler() {
197 return moveHandler;
198 }
199
200
201
202
203
204
205 public OMSVGPoint snap(OMSVGPoint p) {
206 SVGViewBoxElementModel viewBox = svgModel.getViewBox();
207 OMSVGSVGElement svg = svgModel.getSvgElement();
208 OMSVGPoint p0 = svg.createSVGPoint(viewBox.<Float>get(SVGConstants.SVG_X_ATTRIBUTE), viewBox.<Float>get(SVGConstants.SVG_Y_ATTRIBUTE));
209 OMSVGPoint p1 = p.substract(p0, svg.createSVGPoint());
210 p1.setX(dx * (Math.round(p1.getX() / dx)));
211 p1.setY(dy * (Math.round(p1.getY() / dy)));
212 return p1.add(p0);
213 }
214
215 public void setHMarkerPosition(float xPos) {
216 if (isAttached()) {
217
218 SVGViewBoxElementModel viewBox = svgModel.getViewBox();
219 float x = viewBox.<Float>get(SVGConstants.SVG_X_ATTRIBUTE);
220 float width = viewBox.<Float>get(SVGConstants.SVG_WIDTH_ATTRIBUTE);
221 xPos = Math.min(Math.max(xPos, x), x + width);
222
223 hmarker.getTransform().getBaseVal().getItem(0).setTranslate(xPos, 0);
224 }
225 }
226
227 public void setVMarkerPosition(float yPos) {
228 if (isAttached()) {
229
230 SVGViewBoxElementModel viewBox = svgModel.getViewBox();
231 float y = viewBox.<Float>get(SVGConstants.SVG_Y_ATTRIBUTE);
232 float height = viewBox.<Float>get(SVGConstants.SVG_HEIGHT_ATTRIBUTE);
233 yPos = Math.min(Math.max(yPos, y), y + height);
234 vmarker.getTransform().getBaseVal().getItem(0).setTranslate(0, yPos);
235 }
236 }
237
238 public boolean isAttached() {
239 return svgModel != null;
240 }
241
242 public void attach(SVGModel svgModel) {
243 this.svgModel = svgModel;
244 AppCss css = AppBundle.INSTANCE.css();
245 OMSVGSVGElement svg = svgModel.getSvgElement();
246 OMSVGDocument doc = (OMSVGDocument) svg.getOwnerDocument();
247 String modelId = svg.getId();
248
249
250 dx = dy = 5;
251 OMSVGPathElement gridPath1 = new OMSVGPathElement();
252 OMSVGPathSegList gridSegs1 = gridPath1.getPathSegList();
253 for (int i = 1; i < 5; i++) {
254 gridSegs1.appendItem(gridPath1.createSVGPathSegMovetoAbs(0, i * 5));
255 gridSegs1.appendItem(gridPath1.createSVGPathSegLinetoHorizontalAbs(25));
256 }
257 for (int i = 1; i < 5; i++) {
258 gridSegs1.appendItem(gridPath1.createSVGPathSegMovetoAbs(i * 5, 0));
259 gridSegs1.appendItem(gridPath1.createSVGPathSegLinetoVerticalAbs(25));
260 }
261 gridPath1.setClassNameBaseVal(css.grid1());
262
263 OMSVGPathElement gridPath2 = new OMSVGPathElement();
264 OMSVGPathSegList gridSegs2 = gridPath2.getPathSegList();
265 gridSegs2.appendItem(gridPath2.createSVGPathSegMovetoAbs(0, 0));
266 gridSegs2.appendItem(gridPath1.createSVGPathSegLinetoHorizontalAbs(25));
267 gridSegs2.appendItem(gridPath2.createSVGPathSegMovetoAbs(0, 0));
268 gridSegs2.appendItem(gridPath1.createSVGPathSegLinetoVerticalAbs(25));
269 OMSVGPatternElement gridPattern = createPattern(0, 0, 25, 25);
270 gridPath2.setClassNameBaseVal(css.grid2());
271 String gridPatternId = modelId + "-grid";
272 gridPattern.setId(gridPatternId);
273 gridPattern.appendChild(gridPath1);
274 gridPattern.appendChild(gridPath2);
275
276
277 OMSVGRectElement hrulerPatternRect = doc.createSVGRectElement(0, 0, 100, 20, 0, 0);
278 OMSVGPathElement hrulerPatternPath = new OMSVGPathElement();
279 OMSVGPathSegList hrulerPatternSegs = hrulerPatternPath.getPathSegList();
280 for (int i = 0; i < 10; i++) {
281 hrulerPatternSegs.appendItem(hrulerPatternPath.createSVGPathSegMovetoAbs(i * 10, 20));
282 hrulerPatternSegs.appendItem(hrulerPatternPath.createSVGPathSegLinetoVerticalRel(i == 0 ? -18 : (i % 2 == 1 ? -5 : -10)));
283 }
284 OMSVGPatternElement hrulerPattern = createPattern(0, 0, 100, 20);
285 hrulerPattern.setClassNameBaseVal(css.hrulerPattern());
286 String hrulerPatternId = modelId + "-hruler";
287 hrulerPattern.setId(hrulerPatternId);
288 hrulerPattern.appendChild(hrulerPatternRect);
289 hrulerPattern.appendChild(hrulerPatternPath);
290
291
292 OMSVGRectElement vrulerPatternRect = doc.createSVGRectElement(0, 0, 20, 100, 0, 0);
293 OMSVGPathElement vrulerPatternPath = new OMSVGPathElement();
294 OMSVGPathSegList vrulerSegs = vrulerPatternPath.getPathSegList();
295 for (int i = 0; i < 10; i++) {
296 vrulerSegs.appendItem(vrulerPatternPath.createSVGPathSegMovetoAbs(20, i * 10));
297 vrulerSegs.appendItem(vrulerPatternPath.createSVGPathSegLinetoHorizontalRel(i == 0 ? -18 : (i % 2 == 1 ? -5 : -10)));
298 }
299 OMSVGPatternElement vrulerPattern = createPattern(0, 0, 20, 100);
300 vrulerPattern.setClassNameBaseVal(css.vrulerPattern());
301 String vrulerPatternId = modelId + "-vruler";
302 vrulerPattern.setId(vrulerPatternId);
303 vrulerPattern.appendChild(vrulerPatternRect);
304 vrulerPattern.appendChild(vrulerPatternPath);
305
306
307 defs = new OMSVGDefsElement();
308 defs.appendChild(gridPattern);
309 defs.appendChild(hrulerPattern);
310 defs.appendChild(vrulerPattern);
311
312
313 SVGViewBoxElementModel viewBox = svgModel.getViewBox();
314 float x = viewBox.<Float>get(SVGConstants.SVG_X_ATTRIBUTE);
315 float y = viewBox.<Float>get(SVGConstants.SVG_Y_ATTRIBUTE);
316 float width = viewBox.<Float>get(SVGConstants.SVG_WIDTH_ATTRIBUTE);
317 float height = viewBox.<Float>get(SVGConstants.SVG_HEIGHT_ATTRIBUTE);
318 grid = doc.createSVGRectElement(x, y, width, height, 0, 0);
319 grid.getStyle().setProperty(SVGConstants.CSS_FILL_PROPERTY, DOMHelper.toUrl(gridPatternId));
320 grid.getStyle().setProperty(SVGConstants.CSS_STROKE_PROPERTY, SVGConstants.CSS_BLACK_VALUE);
321
322
323 OMSVGRectElement hrulerRect = doc.createSVGRectElement(x, y - 20, width, 20, 0, 0);
324 hrulerRect.getStyle().setProperty(SVGConstants.CSS_FILL_PROPERTY, DOMHelper.toUrl(hrulerPatternId));
325 OMSVGGElement hGradations = new OMSVGGElement();
326 for (int i = (((int)x)/100)*100; i < width; i+=100) {
327 hGradations.appendChild(doc.createSVGTextElement(i, -10, OMSVGLength.SVG_LENGTHTYPE_PX, Integer.toString(i)));
328 }
329
330
331 hmarker = doc.createSVGPathElement();
332 OMSVGPathSegList hmarkerSegs = hmarker.getPathSegList();
333 hmarkerSegs.appendItem(hmarker.createSVGPathSegMovetoAbs(0, 0));
334 hmarkerSegs.appendItem(hmarker.createSVGPathSegLinetoRel(-4, -7));
335 hmarkerSegs.appendItem(hmarker.createSVGPathSegLinetoHorizontalRel(8));
336 hmarkerSegs.appendItem(hmarker.createSVGPathSegClosePath());
337 hmarker.getTransform().getBaseVal().appendItem(svg.createSVGTransform());
338 hmarker.setClassNameBaseVal(css.gridMarker());
339
340 hruler = new OMSVGGElement();
341 hruler.setClassNameBaseVal(css.hruler());
342 hruler.appendChild(hrulerRect);
343 hruler.appendChild(hGradations);
344 hruler.appendChild(hmarker);
345
346
347 OMSVGRectElement vrulerRect = doc.createSVGRectElement(x - 20, y, 20, height, 0, 0);
348 vrulerRect.getStyle().setProperty(SVGConstants.CSS_FILL_PROPERTY, DOMHelper.toUrl(vrulerPatternId));
349 OMSVGGElement vGradations = new OMSVGGElement();
350 for (int i = (((int)y)/100)*100; i < height; i+=100) {
351 vGradations.appendChild(doc.createSVGTextElement(-15, i, OMSVGLength.SVG_LENGTHTYPE_PX, Integer.toString(i)));
352 }
353
354
355 vmarker = doc.createSVGPathElement();
356 OMSVGPathSegList vmarkerSegs = vmarker.getPathSegList();
357 vmarkerSegs.appendItem(vmarker.createSVGPathSegMovetoAbs(0, 0));
358 vmarkerSegs.appendItem(vmarker.createSVGPathSegLinetoRel(-7, -4));
359 vmarkerSegs.appendItem(vmarker.createSVGPathSegLinetoVerticalRel(8));
360 vmarkerSegs.appendItem(vmarker.createSVGPathSegClosePath());
361 vmarker.getTransform().getBaseVal().appendItem(svg.createSVGTransform());
362 vmarker.setClassNameBaseVal(css.gridMarker());
363
364 vruler = new OMSVGGElement();
365 vruler.setClassNameBaseVal(css.vruler());
366 vruler.appendChild(vrulerRect);
367 vruler.appendChild(vGradations);
368 vruler.appendChild(vmarker);
369
370 root = new OMSVGGElement();
371 root.appendChild(grid);
372 root.appendChild(hruler);
373 root.appendChild(vruler);
374 setShowsGrid(false);
375 setShowsGuides(false);
376 }
377
378 private static OMSVGPatternElement createPattern(float x, float y, float width, float height) {
379 OMSVGPatternElement pattern = new OMSVGPatternElement();
380 pattern.getX().getBaseVal().newValueSpecifiedUnits(Unit.PX, x);
381 pattern.getY().getBaseVal().newValueSpecifiedUnits(Unit.PX, y);
382 pattern.getWidth().getBaseVal().newValueSpecifiedUnits(Unit.PX, width);
383 pattern.getHeight().getBaseVal().newValueSpecifiedUnits(Unit.PX, height);
384 if (!pattern.hasAttribute(SVGConstants.SVG_VIEW_BOX_ATTRIBUTE)) {
385 StringBuilder builder = new StringBuilder();
386 builder.append(x);
387 builder.append(" ");
388 builder.append(y);
389 builder.append(" ");
390 builder.append(width);
391 builder.append(" ");
392 builder.append(height);
393 pattern.setAttribute(SVGConstants.SVG_VIEW_BOX_ATTRIBUTE, builder.toString());
394 } else {
395 pattern.getViewBox().getBaseVal().setX(x);
396 pattern.getViewBox().getBaseVal().setY(y);
397 pattern.getViewBox().getBaseVal().setWidth(width);
398 pattern.getViewBox().getBaseVal().setHeight(height);
399 }
400 pattern.setAttribute(SVGConstants.SVG_PATTERN_UNITS_ATTRIBUTE, SVGConstants.SVG_USER_SPACE_ON_USE_VALUE);
401 return pattern;
402 }
403 }