底辺SE奮闘記

年収300万SEブログ

【PHP・meyfa/php-svg】SVGLineのラスタライズメソッドrasterizeを点線 stroke-dasharray対応させる

github.com

オリジナルのmeyfa/php-svgのSVGLineクラスは点線を描画させるstroke-dasharrayに対応していない。

ので、自作。

<?php
namespace App\MyLibs;

use SVG\Rasterization\SVGRasterizer;

/**
 * SVGLineクラスの拡張
 */
class CustomSVGLine extends \SVG\Nodes\Shapes\SVGLine
{
    public function rasterize(SVGRasterizer $rasterizer)
    {
        //オリジナルソースからのコピー
        if ($this->getComputedStyle('display') === 'none') {
            return;
        }

        $visibility = $this->getComputedStyle('visibility');
        if ($visibility === 'hidden' || $visibility === 'collapse') {
            return;
        }
        //オリジナルソースからのコピー ここまで

        $x1 = $this->getX1();
        $y1 = $this->getY1();
        $x2 = $this->getX2();
        $y2 = $this->getY2();

    if ($x1 == $x2 && $y1 == $y2) {
        return;
    }

    $dashParam = $this->getStyle('stroke-dasharray');

        //点線
        if (!empty($dashParam) && $dashParam!=="none") {
            $dashes = explode(" ", $this->getStyle('stroke-dasharray'));
            $n = count($dashes);
            if ($n > 0) {
                $vx = $x2 <=> $x1;
                $vy = $y2 <=> $y1;
                if ($vx == 0) {
                    $diffX = 0; //x方向増分
                    $diffY = 1; //y方向増分
                } else {
                    $rad = atan(abs($y1-$y2)/abs($x1-$x2));
                    $diffX = cos($rad); //x方向増分
                    $diffY = sin($rad); //y方向増分
                }

                $counter = 0;
                $sumLength = 0;
                while (true) {
                    $px = $x1 + $vx * $sumLength * $diffX;
                    $py = $y1 + $vy * $sumLength * $diffY;
                    $qx = $px + $vx * ($dashes[$counter%$n]) * $diffX;
                    $qy = $py + $vy * ($dashes[$counter%$n]) * $diffY;

                    $rasterizer->render('line', array(
                        'x1'    => $px,
                        'y1'    => $py,
                        'x2'    => $qx,
                        'y2'    => $qy,
                    ), $this);

                    if (($vx < 0 && $qx < $x2)
                    || ($vx > 0 && $qx > $x2)
                    || ($vy < 0 && $qy < $y2)
                    || ($vy > 0 && $qy > $y2)) {
                        break;
                    }

                    $sumLength += $dashes[$counter%$n];
                    $counter++;
                    $sumLength += $dashes[$counter%$n];
                    $counter++;
                }
                return;
            }
        }
        //通常の直線
        $rasterizer->render('line', array(
            'x1'    => $x1,
            'y1'    => $y1,
            'x2'    => $x2,
            'y2'    => $y2,
        ), $this);
    }
}

使用例

<?php
// 中略
// 対応している入力
// 例1: "10"
// 例2: "10 5 7"
// 例3: "none"
// 例4: 設定しない
$image->getDocument()->addChild(
    (new \App\MyLibs\CustomSVGLine($x1, $y1, $x2, $y2))
        ->setStyle('stroke', "#00f")
        ->setStyle('stroke-width', 3)
        ->setStyle('stroke-dasharray', "10 5")
);

斜めの直線だとアンチエイリアスが効かず荒い。いまいち。