Completed
Push — master ( 63ca0f...fd375a )
by Edgar
03:21
created

Pattern::verticalHatch()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 4
1
<?php
2
namespace nstdio\svg\container;
3
4
use nstdio\svg\ElementInterface;
5
use nstdio\svg\shape\Line;
6
use nstdio\svg\shape\Shape;
7
8
/**
9
 * Class Pattern
10
 *
11
 * A pattern is used to fill or stroke an object using a pre-defined graphic object which can be replicated ("tiled")
12
 * at fixed intervals in x and y to cover the areas to be painted. Patterns are defined using a 'pattern' element and
13
 * then referenced by properties 'fill' and 'stroke' on a given graphics element to indicate that the given element
14
 * shall be filled or stroked with the referenced pattern.
15
 *
16
 * @link    https://www.w3.org/TR/SVG/pservers.html#Patterns
17
 * @property string patternUnits        "userSpaceOnUse | objectBoundingBox" Defines the coordinate system for
18
 *           attributes 'x',
19
 *           'y', 'width' and 'height'. If patternUnits="userSpaceOnUse", 'x', 'y', 'width' and 'height' represent
20
 *           values in the coordinate system that results from taking the current user coordinate system in place at
21
 *           the time when the 'pattern' element is referenced (i.e., the user coordinate system for the element
22
 *           referencing the 'pattern' element via a 'fill' or 'stroke' property) and then applying the transform
23
 *           specified by attribute 'patternTransform'. If patternUnits="objectBoundingBox", the user coordinate system
24
 *           for attributes 'x', 'y', 'width' and 'height' is established using the bounding box of the element to
25
 *           which the pattern is applied (see Object bounding box units) and then applying the transform specified by
26
 *           attribute 'patternTransform'. If attribute 'patternUnits' is not specified, then the effect is as if a
27
 *           value of 'objectBoundingBox' were specified.
28
 * @property string patternContentUnits = "userSpaceOnUse | objectBoundingBox" Defines the coordinate system for the
29
 *           contents of the ‘pattern’. Note that this attribute has no effect if attribute ‘viewBox’ is specified. If
30
 *           patternContentUnits="userSpaceOnUse", the user coordinate system for the contents of the ‘pattern’ element
31
 *           is the coordinate system that results from taking the current user coordinate system in place at the time
32
 *           when the ‘pattern’ element is referenced (i.e., the user coordinate system for the element referencing the
33
 *           ‘pattern’ element via a ‘fill’ or ‘stroke’ property) and then applying the transform specified by
34
 *           attribute ‘patternTransform’. If patternContentUnits="objectBoundingBox", the user coordinate system for
35
 *           the contents of the ‘pattern’ element is established using the bounding box of the element to which the
36
 *           pattern is applied (see Object bounding box units) and then applying the transform specified by attribute
37
 *           ‘patternTransform’. If attribute ‘patternContentUnits’ is not specified, then the effect is as if a value
38
 *           of 'userSpaceOnUse' were specified.
39
 * @property string patternTransform    = "<transform-list>" Contains the definition of an optional additional
40
 *           transformation from the pattern coordinate system onto the target coordinate system (i.e.,
41
 *           'userSpaceOnUse' or 'objectBoundingBox'). This allows for things such as skewing the pattern tiles. This
42
 *           additional transformation matrix is post-multiplied to (i.e., inserted to the right of) any previously
43
 *           defined transformations, including the implicit transformation necessary to convert from object bounding
44
 *           box units to user space. If attribute ‘patternTransform’ is not specified, then the effect is as if an
45
 *           identity transform were specified.
46
 * @property float  x                   = "<coordinate>" ‘x’, ‘y’, ‘width’ and ‘height’ indicate how the pattern tiles
47
 *           are placed and spaced. These attributes represent coordinates and values in the coordinate space specified
48
 *           by the combination of attributes ‘patternUnits’ and ‘patternTransform’. If the attribute is not specified,
49
 *           the effect is as if a value of zero were specified.
50
 * @property float  y                   = "<coordinate>" See ‘x’. If the attribute is not specified, the effect is as
51
 *           if a value of zero were specified.
52
 * @property float  width               = "<length>" See ‘x’. A negative value is an error (see Error processing). A
53
 *           value of zero disables rendering of the element (i.e., no paint is applied). If the attribute is not
54
 *           specified, the effect is as if a value of zero were specified.
55
 * @property float  height              = "<length>" See ‘x’. A negative value is an error (see Error processing). A
56
 *           value of zero disables rendering of the element (i.e., no paint is applied). If the attribute is not
57
 *           specified, the effect is as if a value of zero were specified.
58
 * @property float  xlink               :href = "<iri>" An IRI reference to a different ‘pattern’ element within the
59
 *           current SVG document fragment. Any attributes which are defined on the referenced element which are not
60
 *           defined on this element are inherited by this element. If this element has no children, and the referenced
61
 *           element does (possibly due to its own ‘xlink:href’ attribute), then this element inherits the children
62
 *           from the referenced element. Inheritance can be indirect to an arbitrary level; thus, if the referenced
63
 *           element inherits attributes or children due to its own ‘xlink:href’ attribute, then the current element
64
 *           can inherit those attributes or children.
65
 * @package nstdio\svg\container
66
 * @author  Edgar Asatryan <[email protected]>
67
 */
68
class Pattern extends Container
69
{
70
    public function __construct(ElementInterface $parent, $id = null)
71
    {
72
        if ($parent instanceof SVG) {
73
            $defs = $parent->getFirstChild();
74
            $parent = $defs;
75
        }
76
        parent::__construct($parent);
77
78
        $this->id = $id;
79
    }
80
81
    public function getName()
82
    {
83
        return 'pattern';
84
    }
85
86
    public static function withShape(ContainerInterface $container, Shape $shape, array $patternConfig = [], $id = null)
87
    {
88
        $patternConfig = array_merge(self::getDefaultConfig(), $patternConfig);
89
90
        $shapeBox = $shape->getBoundingBox();
91
        $patternConfig['width'] = $shapeBox['width'];
92
        $patternConfig['height'] = $shapeBox['height'];
93
94
        $pattern = (new self($container, $id))->apply($patternConfig);
95
        $shape->selfRemove();
0 ignored issues
show
Bug introduced by
The method selfRemove() cannot be called from this context as it is declared protected in class nstdio\svg\SVGElement.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
96
        $pattern->append($shape);
97
98
        return $pattern;
99
    }
100
101
    public static function verticalHatch(ContainerInterface $container, array $patternConfig = [], array $lineConfig = [], $id = null)
102
    {
103
        return self::hatch($container, $patternConfig, $lineConfig, $id);
104
    }
105
106
    public static function horizontalHatch(ContainerInterface $container, array $patternConfig = [], array $lineConfig = [], $id = null)
107
    {
108
        $patternConfig['patternTransform'] = "rotate(90)";
109
110
        return self::hatch($container, $patternConfig, $lineConfig, $id);
111
    }
112
113
    public static function diagonalHatch(ContainerInterface $container, array $patternConfig = [], array $lineConfig = [], $id = null)
114
    {
115
        $patternConfig['patternTransform'] = "rotate(45)";
116
117
        return self::hatch($container, $patternConfig, $lineConfig, $id);
118
    }
119
120
    public static function crossHatch(ContainerInterface $container, array $patternConfig = [], array $lineConfig = [], $id = null)
121
    {
122
        if (isset($patternConfig['width'])) {
123
            $patternConfig['height'] = $patternConfig['width'];
124
        }
125
        if (isset($patternConfig['height'])) {
126
            $patternConfig['width'] = $patternConfig['height'];
127
        }
128
129
        $patternConfig['patternTransform'] = "rotate(45)";
130
        $pattern = self::hatch($container, $patternConfig, $lineConfig, $id);
131
132
        /** @var Line $firstLine */
133
        $firstLine = $pattern->getFirstChild()->apply([
134
            'x1' => 0,
135
            'y1' => $pattern->height / 2,
0 ignored issues
show
Bug introduced by
Accessing height on the interface nstdio\svg\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
136
            'x2' => $pattern->width,
0 ignored issues
show
Bug introduced by
Accessing width on the interface nstdio\svg\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
137
            'y2' => $pattern->height / 2,
0 ignored issues
show
Bug introduced by
Accessing height on the interface nstdio\svg\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
138
        ]);
139
140
        $attrs = $firstLine->allAttributes(['x1', 'y1', 'x2', 'y2', 'id']);
141
        $line = new Line($pattern, $pattern->width / 2, 0, $pattern->width / 2, $pattern->height);
0 ignored issues
show
Bug introduced by
Accessing width on the interface nstdio\svg\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing height on the interface nstdio\svg\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
142
        $line->id = null;
143
        $line->apply($attrs);
144
145
        return $pattern;
146
    }
147
148
    public static function straightCrossHatch(ContainerInterface $container, array $patternConfig = [], array $lineConfig = [], $id = null)
149
    {
150
        $patternConfig['patternTransform'] = 'rotate(45)';
151
152
        return self::crossHatch($container, $patternConfig, $lineConfig, $id);
153
    }
154
155
    protected static function hatch(ContainerInterface $container, array $patternConfig = [], array $lineConfig = [], $id = null)
156
    {
157
        $patternConfig = array_merge(self::getDefaultConfig(), $patternConfig);
158
        $lineDefaultConfig = ['stroke' => 'black', 'stroke-width' => 1, 'fill' => 'none'];
159
        $lineConfig = array_merge($lineDefaultConfig, $lineConfig);
160
161
        $pattern = (new self($container, $id))->apply($patternConfig);
162
163
        (new Line($pattern, 0, 0, 0, $pattern->height))->apply($lineConfig);
0 ignored issues
show
Bug introduced by
Accessing height on the interface nstdio\svg\ElementInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
164
165
        return $pattern;
166
    }
167
168
    protected static function getDefaultConfig()
169
    {
170
        return ['x' => 0, 'y' => 0, 'height' => 4, 'width' => 4, 'patternUnits' => 'userSpaceOnUse'];
171
    }
172
}