这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ Feel free to [open a PR](https://github.com/DenverCoder1/readme-typing-svg/issue
| `multiline` | `true` to wrap lines or `false` to retype on one line (default: `false`) | boolean | `true` or `false` |
| `duration` | Duration of the printing of a single line in milliseconds (default: `5000`) | integer | Any positive number |
| `pause` | Duration of the pause between lines in milliseconds (default: `0`) | integer | Any non-negative number |
| `repeat` | `true` to loop around to the first line after the last (default: `true`) | boolean | `true` or `false` |

## 📤 Deploying it on your own

Expand Down
12 changes: 9 additions & 3 deletions src/demo/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,23 +83,29 @@ function gtag() {
<input class="param jscolor jscolor-active" id="background" name="background" alt="Background color" data-jscolor="{ format: 'hexa' }" value="#00000000">

<label for="center">Horizontally Centered</label>
<select class="param" id="center" name="center" alt="Horizontally Centered" value="false">
<select class="param" id="center" name="center" alt="Horizontally Centered">
<option>false</option>
<option>true</option>
</select>

<label for="vCenter">Vertically Centered</label>
<select class="param" id="vCenter" name="vCenter" alt="Vertically Centered" value="false">
<select class="param" id="vCenter" name="vCenter" alt="Vertically Centered">
<option>false</option>
<option>true</option>
</select>

<label for="multiline">Multiline</label>
<select class="param" id="multiline" name="multiline" alt="Multiline" value="false">
<select class="param" id="multiline" name="multiline" alt="Multiline">
<option value="false">Type sentences on one line</option>
<option value="true">Each sentence on a new line</option>
</select>

<label for="repeat">Repeat</label>
<select class="param" id="repeat" name="repeat" alt="Repeat">
<option>true</option>
<option>false</option>
</select>

<label for="dimensions" title="Width ✕ Height">Width ✕ Height</label>
<span id="dimensions">
<input class="param inline" type="number" id="width" name="width" alt="Width (px)" placeholder="435" value="435">
Expand Down
1 change: 1 addition & 0 deletions src/demo/js/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ let preview = {
height: "50",
duration: "5000",
pause: "0",
repeat: "true",
},
dummyText: [
"The five boxing wizards jump quickly",
Expand Down
5 changes: 5 additions & 0 deletions src/models/RendererModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class RendererModel
/** @var int $pause pause duration between lines in milliseconds */
public $pause;

/** @var bool $repeat Whether to loop around to the first line after the last */
public $repeat;

/** @var string $fontCSS CSS required for displaying the selected font */
public $fontCSS;

Expand All @@ -66,6 +69,7 @@ class RendererModel
"multiline" => "false",
"duration" => "5000",
"pause" => "0",
"repeat" => "true",
];

/**
Expand All @@ -90,6 +94,7 @@ public function __construct($template, $params)
$this->multiline = $this->checkBoolean($params["multiline"] ?? $this->DEFAULTS["multiline"]);
$this->duration = $this->checkNumberPositive($params["duration"] ?? $this->DEFAULTS["duration"], "duration");
$this->pause = $this->checkNumberNonNegative($params["pause"] ?? $this->DEFAULTS["pause"], "pause");
$this->repeat = $this->checkBoolean($params["repeat"] ?? $this->DEFAULTS["repeat"]);
$this->fontCSS = $this->fetchFontCSS($this->font, $this->weight, $params["lines"]);
}

Expand Down
83 changes: 51 additions & 32 deletions src/templates/main.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,62 @@
style='background-color: <?= $background ?>;'
width='<?= $width ?>px' height='<?= $height ?>px'>

<?= preg_replace("/\n/", "\n\t", $fontCSS) ?>
<?= $fontCSS ?>

<?php $previousId = "d" . (count($lines) - 1); ?>
<?php for ($i = 0; $i < count($lines); ++$i): ?>
<path id='path<?= $i ?>'>
<?php if (!$multiline): ?>
<animate id='d<?= $i ?>' attributeName='d' begin='<?= ($i == 0 ? "0s;" : "") .
$previousId ?>.end' dur='<?= $duration + $pause ?>ms'
values='m0,<?= $height / 2 ?> h0 ; m0,<?= $height / 2 ?> h<?= $width ?> ; m0,<?= $height /
2 ?> h<?= $width ?> ; m0,<?= $height / 2 ?> h0'
keyTimes='0;<?= (0.8 * $duration) / ($duration + $pause) ?>;<?= (0.8 * $duration + $pause) /
($duration + $pause) ?>;1' />
<?php else: ?>
<?php $lineHeight = $size + 5; ?>
<animate id='d<?= $i ?>' attributeName='d' dur='<?= ($duration + $pause) * ($i + 1) ?>ms' fill="freeze"
begin='0s;<?= "d" . (count($lines) - 1) ?>.end' keyTimes='0;<?= $i / ($i + 1) ?>;<?= $i / ($i + 1) +
$duration / (($duration + $pause) * ($i + 1)) ?>;1'
values='m0,<?= ($i + 1) * $lineHeight ?> h0 ; m0,<?= ($i + 1) * $lineHeight ?> h0 ; m0,<?= ($i + 1) *
$lineHeight ?> h<?= $width ?> ; m0,<?= ($i + 1) * $lineHeight ?> h<?= $width ?>' />
<?php endif; ?>
</path>
<?php $lastLineIndex = count($lines) - 1; ?>
<?php for ($i = 0; $i <= $lastLineIndex; ++$i): ?>
<path id='path<?= $i ?>'>
<?php if (!$multiline): ?>
<!-- Single line -->
<?php
// start after previous line
$begin = "d" . ($i - 1) . ".end";
if ($i == 0) {
// if this is the first line, start at 0 seconds
// and also after the last line if repeat is true
$begin = $repeat ? "0s;d$lastLineIndex.end" : "0s";
}
// don't delete text after typing the last line if repeat is false
$freeze = !$repeat && $i == $lastLineIndex;
// empty line values
$yOffset = $height / 2;
$emptyLine = "m0,$yOffset h0";
$fullLine = "m0,$yOffset h$width";
$values = [$emptyLine, $fullLine, $fullLine, $freeze ? $fullLine : $emptyLine];
// keyTimes for the animation
$keyTimes = [
"0",
(0.8 * $duration) / ($duration + $pause),
(0.8 * $duration + $pause) / ($duration + $pause),
"1",
];
?>
<animate id='d<?= $i ?>' attributeName='d' begin='<?= $begin ?>'
dur='<?= $duration + $pause ?>ms' fill='<?= $freeze ? "freeze" : "remove" ?>'
values='<?= implode(" ; ", $values) ?>' keyTimes='<?= implode(";", $keyTimes) ?>' />
<?php else: ?>
<!-- Multiline -->
<?php
$nextIndex = $i + 1;
$lineHeight = $size + 5;
$lineDuration = ($duration + $pause) * $nextIndex;
$yOffset = $nextIndex * $lineHeight;
$emptyLine = "m0,$yOffset h0";
$fullLine = "m0,$yOffset h$width";
$values = [$emptyLine, $emptyLine, $fullLine, $fullLine];
$keyTimes = ["0", $i / $nextIndex, $i / $nextIndex + $duration / $lineDuration, "1"];
?>
<animate id='d<?= $i ?>' attributeName='d' begin='0s<?= $repeat ? ";d$lastLineIndex.end" : "" ?>'
dur='<?= $lineDuration ?>ms' fill="freeze"
values='<?= implode(" ; ", $values) ?>' keyTimes='<?= implode(";", $keyTimes) ?>' />
<?php endif; ?>
</path>
<text font-family='"<?= $font ?>", monospace' fill='<?= $color ?>' font-size='<?= $size ?>'
<?php if ($vCenter): ?>
dominant-baseline='middle'
<?php else: ?>
dominant-baseline='auto'
<?php endif; ?>
<?php if ($center): ?>
x='50%' text-anchor='middle'>
<?php else: ?>
x='0%' text-anchor='start'>
<?php endif; ?>
dominant-baseline='<?= $vCenter ? "middle" : "auto" ?>'
x='<?= $center ? "50%" : "0%" ?>' text-anchor='<?= $center ? "middle" : "start" ?>'>
<textPath xlink:href='#path<?= $i ?>'>
<?= $lines[$i] . "\n" ?>
</textPath>
</text>

<?php $previousId = "d" . $i; ?>
<?php endfor; ?>
</svg>
1 change: 1 addition & 0 deletions src/views/RendererView.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function render()
"fontCSS" => $this->model->fontCSS,
"duration" => $this->model->duration,
"pause" => $this->model->pause,
"repeat" => $this->model->repeat,
]);
// render SVG with output buffering
ob_start();
Expand Down
29 changes: 29 additions & 0 deletions tests/OptionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,33 @@ public function testInvalidPause(): void
];
print_r(new RendererModel("src/templates/main.php", $params));
}

/**
* Test repeat set to true, false, other
*/
public function testRepeat(): void
{
// not set
$params = [
"lines" => "text",
];
$model = new RendererModel("src/templates/main.php", $params);
$this->assertEquals(true, $model->repeat);

// true
$params = [
"lines" => "text",
"repeat" => "true",
];
$model = new RendererModel("src/templates/main.php", $params);
$this->assertEquals(true, $model->repeat);

// other / false
$params = [
"lines" => "text",
"repeat" => "other",
];
$model = new RendererModel("src/templates/main.php", $params);
$this->assertEquals(false, $model->repeat);
}
}
79 changes: 77 additions & 2 deletions tests/RendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@

final class RendererTest extends TestCase
{
/**
* Static method to assert strings are equal while ignoring whitespace
*
* @param string $expected
* @param string $actual
*/
public static function compareNoCommentsOrWhitespace(string $expected, string $actual)
{
// remove comments and whitespace
$expected = preg_replace("/\s+/", " ", preg_replace("/<!--.*?-->/s", " ", $expected));
$actual = preg_replace("/\s+/", " ", preg_replace("/<!--.*?-->/s", " ", $actual));
// add newlines to make it easier to debug
$expected = str_replace(">", ">\n", $expected);
$actual = str_replace(">", ">\n", $actual);
// assert strings are equal
self::assertSame($expected, $actual);
}

/**
* Test normal card render
*/
Expand All @@ -26,7 +44,9 @@ public function testCardRender(): void
"height" => "50",
];
$controller = new RendererController($params);
$this->assertStringEqualsFile("tests/svg/test_normal.svg", $controller->render());
$expectedSVG = file_get_contents("tests/svg/test_normal.svg");
$actualSVG = $controller->render();
$this->compareNoCommentsOrWhitespace($expectedSVG, $actualSVG);
}

public function testMultilineCardRender(): void
Expand Down Expand Up @@ -134,7 +154,9 @@ public function testLineTrimming(): void
"height" => "50",
];
$controller = new RendererController($params);
$this->assertStringEqualsFile("tests/svg/test_normal.svg", $controller->render());
$expectedSVG = file_get_contents("tests/svg/test_normal.svg");
$actualSVG = $controller->render();
$this->compareNoCommentsOrWhitespace($expectedSVG, $actualSVG);
}

/**
Expand Down Expand Up @@ -205,4 +227,57 @@ public function testPauseMultiline(): void
$this->assertStringContainsString("dur='12000ms'", $controller->render());
$this->assertStringContainsString("keyTimes='0;0.5;0.91666666666667;1'", $controller->render());
}

/**
* Test repeat set to false
*/
public function testRepeatFalse(): void
{
$params = [
"lines" => implode(";", [
"Full-stack web and app developer",
"Self-taught UI/UX Designer",
"10+ years of coding experience",
"Always learning new things",
]),
"center" => "true",
"vCenter" => "true",
"width" => "380",
"height" => "50",
"repeat" => "false",
];
$controller = new RendererController($params);
$actualSVG = preg_replace("/\s+/", " ", $controller->render());
$this->assertStringContainsString("begin='0s'", $actualSVG);
$this->assertStringContainsString(
"begin='d2.end' dur='5000ms' fill='freeze' values='m0,25 h0 ; m0,25 h380 ; m0,25 h380 ; m0,25 h380'",
$actualSVG
);
$this->assertStringNotContainsString(";d3.end", $actualSVG);
}

/**
* Test repeat set to false on multiline card
*/
public function testRepeatFalseMultiline(): void
{
$params = [
"lines" => implode(";", [
"Full-stack web and app developer",
"Self-taught UI/UX Designer",
"10+ years of coding experience",
"Always learning new things",
]),
"center" => "true",
"vCenter" => "true",
"width" => "380",
"height" => "200",
"multiline" => "true",
"repeat" => "false",
];
$controller = new RendererController($params);
$actualSVG = preg_replace("/\s+/", " ", $controller->render());
$this->assertStringContainsString("begin='0s'", $actualSVG);
$this->assertStringNotContainsString(";d3.end", $actualSVG);
}
}
13 changes: 8 additions & 5 deletions tests/svg/test_normal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.