Показаны сообщения с ярлыком SVG. Показать все сообщения
Показаны сообщения с ярлыком SVG. Показать все сообщения

Кривые Безье в Cocoa на примере создания простой прямоугольной выноски

Рассмотрим как с помощью класса NSBezierPath можно нарисовать простую прямоугольную выноску.


Для этого в методе drawRect: класса NSView напишем следующий код:

    NSBezierPath *thePath = [NSBezierPath bezierPath];
    [thePath moveToPoint:NSMakePoint(NSMidX(aDirtyRect), NSMaxY(aDirtyRect))];
    
    NSUInteger theArrWidth = 32, theArrHeight = 24;
    [thePath lineToPoint:NSMakePoint(NSMidX(aDirtyRect) + theArrWidth / 2, NSMaxY(aDirtyRect) - theArrHeight)];
    [thePath lineToPoint:NSMakePoint(NSMaxX(aDirtyRect), NSMaxY(aDirtyRect) - theArrHeight)];
    [thePath lineToPoint:NSMakePoint(NSMaxX(aDirtyRect), NSMinY(aDirtyRect))];
    [thePath lineToPoint:NSMakePoint(NSMinX(aDirtyRect), NSMinY(aDirtyRect))];
    [thePath lineToPoint:NSMakePoint(NSMinX(aDirtyRect), NSMaxY(aDirtyRect) - theArrHeight)];
    [thePath lineToPoint:NSMakePoint(NSMidX(aDirtyRect) - theArrWidth / 2, NSMaxY(aDirtyRect) - theArrHeight)];
    
    [thePath closePath];
    
    [[NSColor colorWithDeviceWhite:1.0 alpha:1.0] setFill];
    [thePath fill];
    
    [[NSColor blueColor] setStroke];
    [thePath stroke];

Крыша у выноски получилась более четкая, чем остальные краевые линии собственно потому что мы краевые линии рисовали на границе вьюхи. Тут не помешало бы сделать отступ с помощью NSInsetRect.

Если дальше развивать код, то с помощью функции curveToPoint:controlPoint1:controlPoint2: можно сделать закругленные углы, сделав тем самым скругленную прямоугольную выноску.

исходники

P.S. Кстати еще можно автоматически парсить SVG path и рисовать его на вью.

Линейный градиент в SVG

В SVG есть два типа градиентов: линейный и радиальный. Пример реализации линейного градиента:

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN"
 "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">

<svg width="100%" height="100%">
    <defs>
        <linearGradient id="gradientDefinition" gradientUnits="userSpaceOnUse">
            <stop stop-color="yellow" stop-opacity=".2" offset="0%"/>
            <stop stop-color="black" offset="100%"/>
        </linearGradient>
    </defs>
    
    <rect x="60" y="60" width="400" height="200" stroke-width="4" stroke="red" stroke-dasharray="2 2 2 2" fill="black"/>
    <rect x="50" y="50" width="400" height="200" stroke-width="4" stroke="red" stroke-dasharray="2 2 2 2" fill="url(#gradientDefinition)"/>
</svg>

Линейный градиент определяется в контейнере defs с помощью элемента linearGradient. Чтобы потом можно было назначить градиент конкретной фигуре для определения градиента задается атрибут id. Назначить градиент фигуре можно указав id градиента как значение атрибута fill фигуры.


fill="url(#gradientDefinition)"

Сам градиент определяется неким набором контрольных точек - стопов. Похоже на Photoshop (ну в принципе во всех графических редакторах это делается одинаково). Только в Photoshop'e это делается визуально через GUI, а здесь задается текстово. Для каждого стопа можно указать цвет, прозрачность, смещение...

Радиальный градиент в SVG

Радиальный градиент определяется аналогично линейному. Также задаются стопы. Только если в линейном градиенте стопы расположены по прямой то в радиальном градиенте стопы расположены по кольцам. Эти кольца напоминают кольца, которые образуются если бросить камешек в воду.

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN"
 "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">

<svg width="100%" height="100%">
    <defs>
        <radialGradient id="gradientDefinition" gradientUnits="userSpaceOnUse">
            <stop stop-color="yellow" offset="0%"/>
            <stop stop-color="black" offset="100%"/>
        </radialGradient>
    </defs>
    
    <rect x="65" y="65" width="400" height="250" stroke-width="4" stroke="yellow" stroke-dasharray="2 2 2 2" fill="black"/>
    <rect x="50" y="50" width="400" height="250" stroke-width="4" stroke="yellow" stroke-dasharray="2 2 2 2" fill="url(#gradientDefinition)"/>
</svg>

Код практически ничем не отличается от кода для линейного градиента. В принципе единственное отличие это вместо linearGradient стоит radialGradient.


Почему-то на результате получилось что градиент куда-то уехал и видно только его край. Надо будет разобраться с этим...