0
# Styling and Gradients
1
2
ZRender provides a comprehensive styling system for controlling the visual appearance of graphics elements. This includes solid colors, gradients, patterns, shadows, and advanced rendering effects.
3
4
## Basic Styling Properties
5
6
All visual elements support these fundamental styling properties:
7
8
```typescript { .api }
9
interface PathStyleProps {
10
// Fill properties
11
fill?: string | LinearGradient | RadialGradient | Pattern;
12
fillOpacity?: number;
13
14
// Stroke properties
15
stroke?: string;
16
strokeOpacity?: number;
17
lineWidth?: number;
18
lineDash?: number[];
19
lineDashOffset?: number;
20
lineCap?: 'butt' | 'round' | 'square';
21
lineJoin?: 'bevel' | 'round' | 'miter';
22
miterLimit?: number;
23
24
// Overall opacity
25
opacity?: number;
26
27
// Shadow effects
28
shadowBlur?: number;
29
shadowColor?: string;
30
shadowOffsetX?: number;
31
shadowOffsetY?: number;
32
33
// Advanced rendering
34
blend?: string;
35
globalCompositeOperation?: string;
36
}
37
```
38
39
## Gradient Classes
40
41
### LinearGradient
42
43
Creates linear gradients with customizable direction and color stops:
44
45
```typescript { .api }
46
class LinearGradient {
47
constructor(x1: number, y1: number, x2: number, y2: number, colorStops: ColorStop[], globalCoord?: boolean);
48
49
x1: number; // Start point X (0-1 in local coordinates)
50
y1: number; // Start point Y (0-1 in local coordinates)
51
x2: number; // End point X (0-1 in local coordinates)
52
y2: number; // End point Y (0-1 in local coordinates)
53
colorStops: ColorStop[];
54
global: boolean; // Use global coordinates instead of local
55
}
56
57
interface LinearGradientObject {
58
type: 'linear';
59
x1: number;
60
y1: number;
61
x2: number;
62
y2: number;
63
colorStops: ColorStop[];
64
global?: boolean;
65
}
66
67
interface ColorStop {
68
offset: number; // Position along gradient (0-1)
69
color: string; // Color at this stop
70
}
71
```
72
73
### RadialGradient
74
75
Creates radial gradients emanating from a center point:
76
77
```typescript { .api }
78
class RadialGradient {
79
constructor(x: number, y: number, r: number, colorStops: ColorStop[], globalCoord?: boolean);
80
81
x: number; // Center X (0-1 in local coordinates)
82
y: number; // Center Y (0-1 in local coordinates)
83
r: number; // Radius (0-1 in local coordinates)
84
colorStops: ColorStop[];
85
global: boolean; // Use global coordinates instead of local
86
}
87
88
interface RadialGradientObject {
89
type: 'radial';
90
x: number;
91
y: number;
92
r: number;
93
colorStops: ColorStop[];
94
global?: boolean;
95
}
96
```
97
98
## Pattern Class
99
100
Creates pattern fills using images or other elements:
101
102
```typescript { .api }
103
class Pattern {
104
constructor(image: PatternImageSource, repeat: PatternRepeat);
105
106
image: PatternImageSource;
107
repeat: PatternRepeat;
108
}
109
110
type PatternImageSource =
111
| HTMLImageElement
112
| HTMLCanvasElement
113
| HTMLVideoElement
114
| string; // URL or data URI
115
116
type PatternRepeat = 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat';
117
118
interface PatternObjectBase {
119
type: 'pattern';
120
repeat: PatternRepeat;
121
}
122
123
interface ImagePatternObject extends PatternObjectBase {
124
image: HTMLImageElement | HTMLCanvasElement | string;
125
x?: number;
126
y?: number;
127
rotation?: number;
128
scaleX?: number;
129
scaleY?: number;
130
}
131
132
interface SVGPatternObject extends PatternObjectBase {
133
svgElement: SVGElement;
134
svgWidth: number;
135
svgHeight: number;
136
x?: number;
137
y?: number;
138
rotation?: number;
139
scaleX?: number;
140
scaleY?: number;
141
}
142
143
type PatternObject = ImagePatternObject | SVGPatternObject;
144
```
145
146
## Text Styling
147
148
Text elements have additional styling properties:
149
150
```typescript { .api }
151
interface TextStyleProps {
152
// Text content and basic properties
153
text?: string;
154
fontSize?: number;
155
fontFamily?: string;
156
fontStyle?: 'normal' | 'italic' | 'oblique';
157
fontWeight?: string | number;
158
159
// Text positioning and alignment
160
textAlign?: 'left' | 'center' | 'right';
161
textVerticalAlign?: 'top' | 'middle' | 'bottom';
162
textBaseline?: 'top' | 'middle' | 'bottom' | 'alphabetic' | 'ideographic' | 'hanging';
163
164
// Text appearance
165
fill?: string | LinearGradient | RadialGradient | Pattern;
166
stroke?: string;
167
lineWidth?: number;
168
opacity?: number;
169
170
// Text shadows
171
textShadowBlur?: number;
172
textShadowColor?: string;
173
textShadowOffsetX?: number;
174
textShadowOffsetY?: number;
175
176
// Text layout
177
width?: number;
178
height?: number;
179
textPadding?: number | number[];
180
textLineHeight?: number;
181
182
// Rich text formatting
183
rich?: Record<string, TextStyleProps>;
184
185
// Text truncation
186
truncate?: {
187
outerWidth?: number;
188
outerHeight?: number;
189
ellipsis?: string;
190
placeholder?: string;
191
};
192
193
// Rendering effects
194
blend?: string;
195
}
196
```
197
198
## Usage Examples
199
200
### Solid Colors and Basic Styling
201
202
```typescript
203
import { Circle, Rect } from "zrender";
204
205
// Simple solid color fill
206
const circle = new Circle({
207
shape: { cx: 100, cy: 100, r: 50 },
208
style: {
209
fill: '#ff6b6b', // Solid red fill
210
stroke: '#d63031', // Dark red border
211
lineWidth: 3,
212
opacity: 0.8
213
}
214
});
215
216
// Advanced stroke styling
217
const rect = new Rect({
218
shape: { x: 200, y: 50, width: 120, height: 80 },
219
style: {
220
fill: 'none',
221
stroke: '#74b9ff',
222
lineWidth: 4,
223
lineDash: [10, 5], // Dashed line
224
lineCap: 'round', // Rounded line ends
225
lineJoin: 'round' // Rounded corners
226
}
227
});
228
229
zr.add(circle);
230
zr.add(rect);
231
```
232
233
### Linear Gradients
234
235
```typescript
236
import { Rect, LinearGradient } from "zrender";
237
238
// Horizontal gradient
239
const horizontalGradient = new LinearGradient(0, 0, 1, 0, [
240
{ offset: 0, color: '#ff7675' },
241
{ offset: 0.5, color: '#fd79a8' },
242
{ offset: 1, color: '#fdcb6e' }
243
]);
244
245
// Vertical gradient
246
const verticalGradient = new LinearGradient(0, 0, 0, 1, [
247
{ offset: 0, color: '#74b9ff' },
248
{ offset: 1, color: '#0984e3' }
249
]);
250
251
// Diagonal gradient
252
const diagonalGradient = new LinearGradient(0, 0, 1, 1, [
253
{ offset: 0, color: '#00b894' },
254
{ offset: 1, color: '#00cec9' }
255
]);
256
257
const rect1 = new Rect({
258
shape: { x: 50, y: 50, width: 150, height: 80 },
259
style: { fill: horizontalGradient }
260
});
261
262
const rect2 = new Rect({
263
shape: { x: 250, y: 50, width: 80, height: 150 },
264
style: { fill: verticalGradient }
265
});
266
267
const rect3 = new Rect({
268
shape: { x: 50, y: 180, width: 120, height: 120 },
269
style: { fill: diagonalGradient }
270
});
271
272
zr.add(rect1);
273
zr.add(rect2);
274
zr.add(rect3);
275
```
276
277
### Radial Gradients
278
279
```typescript
280
import { Circle, RadialGradient } from "zrender";
281
282
// Center-focused radial gradient
283
const radialGradient = new RadialGradient(0.5, 0.5, 0.5, [
284
{ offset: 0, color: '#ffffff' },
285
{ offset: 0.7, color: '#74b9ff' },
286
{ offset: 1, color: '#0984e3' }
287
]);
288
289
// Off-center radial gradient for lighting effect
290
const lightingGradient = new RadialGradient(0.3, 0.3, 0.8, [
291
{ offset: 0, color: '#fff5b4' },
292
{ offset: 0.4, color: '#ffda79' },
293
{ offset: 1, color: '#e17055' }
294
]);
295
296
const circle1 = new Circle({
297
shape: { cx: 150, cy: 150, r: 80 },
298
style: { fill: radialGradient }
299
});
300
301
const circle2 = new Circle({
302
shape: { cx: 350, cy: 150, r: 80 },
303
style: {
304
fill: lightingGradient,
305
stroke: '#d63031',
306
lineWidth: 2
307
}
308
});
309
310
zr.add(circle1);
311
zr.add(circle2);
312
```
313
314
### Pattern Fills
315
316
```typescript
317
import { Rect, Pattern } from "zrender";
318
319
// Create pattern from image
320
const createImagePattern = (imageUrl: string) => {
321
const img = new Image();
322
img.src = imageUrl;
323
return new Pattern(img, 'repeat');
324
};
325
326
// Create pattern from canvas
327
const createCanvasPattern = () => {
328
const canvas = document.createElement('canvas');
329
canvas.width = 20;
330
canvas.height = 20;
331
const ctx = canvas.getContext('2d')!;
332
333
// Draw a simple pattern
334
ctx.fillStyle = '#e17055';
335
ctx.fillRect(0, 0, 10, 10);
336
ctx.fillStyle = '#fdcb6e';
337
ctx.fillRect(10, 10, 10, 10);
338
339
return new Pattern(canvas, 'repeat');
340
};
341
342
const patternRect = new Rect({
343
shape: { x: 100, y: 100, width: 200, height: 150 },
344
style: {
345
fill: createCanvasPattern(),
346
stroke: '#2d3436',
347
lineWidth: 2
348
}
349
});
350
351
zr.add(patternRect);
352
```
353
354
### Shadow Effects
355
356
```typescript
357
import { Circle, Text } from "zrender";
358
359
// Drop shadow effect
360
const shadowCircle = new Circle({
361
shape: { cx: 150, cy: 150, r: 60 },
362
style: {
363
fill: '#74b9ff',
364
shadowBlur: 20,
365
shadowColor: 'rgba(116, 185, 255, 0.6)',
366
shadowOffsetX: 10,
367
shadowOffsetY: 10
368
}
369
});
370
371
// Glow effect
372
const glowCircle = new Circle({
373
shape: { cx: 350, cy: 150, r: 50 },
374
style: {
375
fill: '#00b894',
376
shadowBlur: 30,
377
shadowColor: '#00b894'
378
// No offset for glow effect
379
}
380
});
381
382
// Text with shadow
383
const shadowText = new Text({
384
style: {
385
text: 'Shadow Text',
386
fontSize: 24,
387
fill: '#2d3436',
388
textShadowBlur: 5,
389
textShadowColor: 'rgba(0, 0, 0, 0.5)',
390
textShadowOffsetX: 2,
391
textShadowOffsetY: 2
392
},
393
position: [200, 300]
394
});
395
396
zr.add(shadowCircle);
397
zr.add(glowCircle);
398
zr.add(shadowText);
399
```
400
401
### Advanced Text Styling
402
403
```typescript
404
import { Text } from "zrender";
405
406
// Rich text with multiple styles
407
const richText = new Text({
408
style: {
409
text: '{title|ZRender} {subtitle|Graphics Library}\n{body|Create beautiful 2D graphics}',
410
rich: {
411
title: {
412
fontSize: 28,
413
fontWeight: 'bold',
414
fill: '#2d3436'
415
},
416
subtitle: {
417
fontSize: 16,
418
fill: '#636e72',
419
fontStyle: 'italic'
420
},
421
body: {
422
fontSize: 14,
423
fill: '#74b9ff',
424
textPadding: [10, 0, 0, 0]
425
}
426
},
427
width: 300,
428
textAlign: 'center'
429
},
430
position: [150, 100]
431
});
432
433
// Gradient text fill
434
const gradientText = new Text({
435
style: {
436
text: 'Gradient Text',
437
fontSize: 32,
438
fontWeight: 'bold',
439
fill: new LinearGradient(0, 0, 1, 0, [
440
{ offset: 0, color: '#ff7675' },
441
{ offset: 0.5, color: '#fd79a8' },
442
{ offset: 1, color: '#e84393' }
443
]),
444
stroke: '#2d3436',
445
lineWidth: 1
446
},
447
position: [150, 250]
448
});
449
450
zr.add(richText);
451
zr.add(gradientText);
452
```
453
454
### Animated Styling
455
456
```typescript
457
import { Circle, LinearGradient } from "zrender";
458
459
// Create animated gradient
460
const animatedCircle = new Circle({
461
shape: { cx: 200, cy: 200, r: 60 },
462
style: {
463
fill: new LinearGradient(0, 0, 1, 0, [
464
{ offset: 0, color: '#74b9ff' },
465
{ offset: 1, color: '#0984e3' }
466
]),
467
shadowBlur: 0
468
}
469
});
470
471
// Animate color transitions
472
animatedCircle.animate('style')
473
.when(1000, {
474
shadowBlur: 20,
475
shadowColor: '#74b9ff'
476
})
477
.when(2000, {
478
shadowBlur: 0
479
})
480
.start('easeInOut');
481
482
// Animate gradient color stops
483
const animateGradient = () => {
484
const newGradient = new LinearGradient(0, 0, 1, 0, [
485
{ offset: 0, color: '#e17055' },
486
{ offset: 1, color: '#fdcb6e' }
487
]);
488
489
animatedCircle.animate('style')
490
.when(1500, { fill: newGradient })
491
.start();
492
};
493
494
// Trigger gradient animation on click
495
animatedCircle.on('click', animateGradient);
496
497
zr.add(animatedCircle);
498
```
499
500
### Style State Management
501
502
```typescript
503
import { Rect } from "zrender";
504
505
// Interactive styling with state management
506
const interactiveRect = new Rect({
507
shape: { x: 100, y: 100, width: 120, height: 80, r: 8 },
508
style: {
509
fill: '#74b9ff',
510
stroke: '#0984e3',
511
lineWidth: 2,
512
opacity: 1
513
}
514
});
515
516
// Store original style
517
const originalStyle = { ...interactiveRect.style };
518
519
// Hover states
520
interactiveRect.on('mouseover', () => {
521
interactiveRect.animate('style')
522
.when(200, {
523
fill: '#a29bfe',
524
shadowBlur: 10,
525
shadowColor: '#74b9ff',
526
opacity: 0.9
527
})
528
.start('easeOut');
529
});
530
531
interactiveRect.on('mouseout', () => {
532
interactiveRect.animate('style')
533
.when(200, originalStyle)
534
.start('easeOut');
535
});
536
537
// Active/pressed state
538
interactiveRect.on('mousedown', () => {
539
interactiveRect.animate('style')
540
.when(100, {
541
fill: '#6c5ce7',
542
shadowBlur: 5
543
})
544
.start();
545
});
546
547
interactiveRect.on('mouseup', () => {
548
interactiveRect.animate('style')
549
.when(100, {
550
fill: '#a29bfe',
551
shadowBlur: 10
552
})
553
.start();
554
});
555
556
zr.add(interactiveRect);
557
```