Skip to content

Commit daff299

Browse files
authored
feat: Add pause duration parameter (#119)
1 parent 3ae7732 commit daff299

File tree

14 files changed

+312
-35
lines changed

14 files changed

+312
-35
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ Feel free to [open a PR](https://github.com/DenverCoder1/readme-typing-svg/issue
8484
| `vCenter` | `true` to center vertically or `false`(default) to align above the center | boolean | `true` or `false` |
8585
| `multiline` | `true` to wrap lines or `false` to retype on one line (default: `false`) | boolean | `true` or `false` |
8686
| `duration` | Duration of the printing of a single line in milliseconds (default: `5000`) | integer | Any positive number |
87+
| `pause` | Duration of the pause between lines in milliseconds (default: `0`) | integer | Any non-negative number |
8788

8889
## 📤 Deploying it on your own
8990

src/demo/index.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ function gtag() {
7070
<label for="duration">Duration (ms per line)</label>
7171
<input class="param" type="number" id="duration" name="duration" alt="Print duration (ms)" placeholder="5000" value="5000">
7272

73+
<label for="pause">Pause (ms after line)</label>
74+
<input class="param" type="number" id="pause" name="pause" alt="Pause duration (ms)" placeholder="500" value="500">
75+
7376
<label for="color">Font color</label>
7477
<input class="param jscolor jscolor-active" id="color" name="color" alt="Font color" data-jscolor="{ format: 'hexa' }" value="#36BCF7">
7578

src/demo/js/script.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ let preview = {
1010
multiline: "false",
1111
width: "400",
1212
height: "50",
13-
duration: "5000"
13+
duration: "5000",
14+
pause: "0",
1415
},
1516
dummyText: [
1617
"The five boxing wizards jump quickly",

src/models/RendererModel.php

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class RendererModel
4040
/** @var int $duration print duration in milliseconds */
4141
public $duration;
4242

43+
/** @var int $pause pause duration between lines in milliseconds */
44+
public $pause;
45+
4346
/** @var string $fontCSS CSS required for displaying the selected font */
4447
public $fontCSS;
4548

@@ -60,7 +63,8 @@ class RendererModel
6063
"width" => "400",
6164
"height" => "50",
6265
"multiline" => "false",
63-
"duration" => "5000"
66+
"duration" => "5000",
67+
"pause" => "0",
6468
);
6569

6670
/**
@@ -78,13 +82,14 @@ public function __construct($template, $params, $database)
7882
$this->font = $this->checkFont($params["font"] ?? $this->DEFAULTS["font"]);
7983
$this->color = $this->checkColor($params["color"] ?? $this->DEFAULTS["color"], "color");
8084
$this->background = $this->checkColor($params["background"] ?? $this->DEFAULTS["background"], "background");
81-
$this->size = $this->checkNumber($params["size"] ?? $this->DEFAULTS["size"], "Font size");
85+
$this->size = $this->checkNumberPositive($params["size"] ?? $this->DEFAULTS["size"], "Font size");
8286
$this->center = $this->checkBoolean($params["center"] ?? $this->DEFAULTS["center"]);
8387
$this->vCenter = $this->checkBoolean($params["vCenter"] ?? $this->DEFAULTS["vCenter"]);
84-
$this->width = $this->checkNumber($params["width"] ?? $this->DEFAULTS["width"], "Width");
85-
$this->height = $this->checkNumber($params["height"] ?? $this->DEFAULTS["height"], "Height");
88+
$this->width = $this->checkNumberPositive($params["width"] ?? $this->DEFAULTS["width"], "Width");
89+
$this->height = $this->checkNumberPositive($params["height"] ?? $this->DEFAULTS["height"], "Height");
8690
$this->multiline = $this->checkBoolean($params["multiline"] ?? $this->DEFAULTS["multiline"]);
87-
$this->duration = $this->checkNumber($params["duration"] ?? $this->DEFAULTS["duration"], "duration");
91+
$this->duration = $this->checkNumberPositive($params["duration"] ?? $this->DEFAULTS["duration"], "duration");
92+
$this->pause = $this->checkNumberNonNegative($params["pause"] ?? $this->DEFAULTS["pause"], "pause");
8893
$this->fontCSS = $this->fetchFontCSS($this->font);
8994
}
9095

@@ -136,13 +141,13 @@ private function checkColor($color, $field)
136141
}
137142

138143
/**
139-
* Validate numeric parameter and return valid integer
144+
* Validate positive numeric parameter and return valid integer
140145
*
141146
* @param string $num Parameter to validate
142147
* @param string $field Field name for displaying in case of error
143148
* @return int Sanitized digits and int
144149
*/
145-
private function checkNumber($num, $field)
150+
private function checkNumberPositive($num, $field)
146151
{
147152
$digits = intval(preg_replace("/[^0-9\-]/", "", $num));
148153
if ($digits <= 0) {
@@ -151,6 +156,22 @@ private function checkNumber($num, $field)
151156
return $digits;
152157
}
153158

159+
/**
160+
* Validate non-negative numeric parameter and return valid integer
161+
*
162+
* @param string $num Parameter to validate
163+
* @param string $field Field name for displaying in case of error
164+
* @return int Sanitized digits and int
165+
*/
166+
private function checkNumberNonNegative($num, $field)
167+
{
168+
$digits = intval(preg_replace("/[^0-9\-]/", "", $num));
169+
if ($digits < 0) {
170+
throw new InvalidArgumentException("$field must be a non-negative number.");
171+
}
172+
return $digits;
173+
}
174+
154175
/**
155176
* Validate "true" or "false" value as string and return boolean
156177
*

src/templates/main.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111
<?php for ($i = 0; $i < count($lines); ++$i): ?>
1212
<path id='path<?php echo $i ?>'>
1313
<?php if (!$multiline): ?>
14-
<animate id='d<?php echo $i ?>' attributeName='d' begin='<?php echo ($i == 0 ? "0s;" : "") . $previousId ?>.end' dur='<?php echo $duration ?>ms'
15-
values='m0,<?php echo $height / 2 ?> h0 ; m0,<?php echo $height / 2 ?> h<?php echo $width ?> ; m0,<?php echo $height / 2 ?> h0' keyTimes='0;0.8;1' />
14+
<animate id='d<?php echo $i ?>' attributeName='d' begin='<?php echo ($i == 0 ? "0s;" : "") . $previousId ?>.end' dur='<?php echo $duration + $pause ?>ms'
15+
values='m0,<?php echo $height / 2 ?> h0 ; m0,<?php echo $height / 2 ?> h<?php echo $width ?> ; m0,<?php echo $height / 2 ?> h<?php echo $width ?> ; m0,<?php echo $height / 2 ?> h0'
16+
keyTimes='0;<?php echo 0.8 * $duration / ($duration + $pause) ?>;<?php echo (0.8 * $duration + $pause) / ($duration + $pause) ?>;1' />
1617
<?php else: ?>
1718
<?php $lineHeight = $size + 5;?>
18-
<animate id='d<?php echo $i ?>' attributeName='d' dur='<?php echo $duration * ($i + 1) ?>ms' fill="freeze"
19-
begin='0s;<?php echo "d" . (count($lines) - 1) ?>.end' keyTimes="0;<?php echo $i / ($i + 1); ?>;1"
20-
values='m0,<?php echo ($i + 1) * $lineHeight ?> h0 ; m0,<?php echo ($i + 1) * $lineHeight ?> h0 ; m0,<?php echo ($i + 1) * $lineHeight ?> h<?php echo $width ?>' />
19+
<animate id='d<?php echo $i ?>' attributeName='d' dur='<?php echo ($duration + $pause) * ($i + 1) ?>ms' fill="freeze"
20+
begin='0s;<?php echo "d" . (count($lines) - 1) ?>.end' keyTimes="0;<?php echo $i / ($i + 1); ?>;<?php echo $i / ($i + 1) + $duration / (($duration + $pause) * ($i + 1)); ?>;1"
21+
values='m0,<?php echo ($i + 1) * $lineHeight ?> h0 ; m0,<?php echo ($i + 1) * $lineHeight ?> h0 ; m0,<?php echo ($i + 1) * $lineHeight ?> h<?php echo $width ?> ; m0,<?php echo ($i + 1) * $lineHeight ?> h<?php echo $width ?>' />
2122
<?php endif;?>
2223
</path>
2324
<text font-family='"<?php echo $font ?>", monospace' fill='<?php echo $color ?>' font-size='<?php echo $size ?>'

src/views/RendererView.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public function render()
3939
"multiline" => $this->model->multiline,
4040
"fontCSS" => $this->model->fontCSS,
4141
"duration" => $this->model->duration,
42+
"pause" => $this->model->pause,
4243
));
4344
// render SVG with output buffering
4445
ob_start();

tests/OptionsTest.php

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
<?php declare (strict_types = 1);
1+
<?php
2+
3+
declare(strict_types=1);
4+
25
use PHPUnit\Framework\TestCase;
36

47
require 'vendor/autoload.php';
@@ -198,7 +201,7 @@ public function testCenterIsNotTrue(): void
198201
$model = new RendererModel("src/templates/main.php", $params, self::$database);
199202
$this->assertEquals(false, $model->center);
200203
}
201-
204+
202205
/**
203206
* Test vCenter set to true
204207
*/
@@ -224,4 +227,71 @@ public function testVCenterIsNotTrue(): void
224227
$model = new RendererModel("src/templates/main.php", $params, self::$database);
225228
$this->assertEquals(false, $model->vCenter);
226229
}
230+
231+
/**
232+
* Test valid duration
233+
*/
234+
public function testValidDuration(): void
235+
{
236+
$params = array(
237+
"lines" => "text",
238+
"duration" => "500",
239+
);
240+
$model = new RendererModel("src/templates/main.php", $params, self::$database);
241+
$this->assertEquals(500, $model->duration);
242+
}
243+
244+
/**
245+
* Test exception thrown when duration is invalid
246+
*/
247+
public function testInvalidDuration(): void
248+
{
249+
$this->expectException("InvalidArgumentException");
250+
$this->expectExceptionMessage("duration must be a positive number.");
251+
$params = array(
252+
"lines" => "text",
253+
"duration" => "-1",
254+
);
255+
print_r(new RendererModel("src/templates/main.php", $params, self::$database));
256+
}
257+
258+
/**
259+
* Test valid pause
260+
*/
261+
public function testValidPause(): void
262+
{
263+
$params = array(
264+
"lines" => "text",
265+
"pause" => "500",
266+
);
267+
$model = new RendererModel("src/templates/main.php", $params, self::$database);
268+
$this->assertEquals(500, $model->pause);
269+
}
270+
271+
/**
272+
* Test valid pause at 0
273+
*/
274+
public function testValidPauseZero(): void
275+
{
276+
$params = array(
277+
"lines" => "text",
278+
"pause" => "0",
279+
);
280+
$model = new RendererModel("src/templates/main.php", $params, self::$database);
281+
$this->assertEquals(0, $model->pause);
282+
}
283+
284+
/**
285+
* Test exception thrown when pause is invalid
286+
*/
287+
public function testInvalidPause(): void
288+
{
289+
$this->expectException("InvalidArgumentException");
290+
$this->expectExceptionMessage("pause must be a non-negative number.");
291+
$params = array(
292+
"lines" => "text",
293+
"pause" => "-1",
294+
);
295+
print_r(new RendererModel("src/templates/main.php", $params, self::$database));
296+
}
227297
}

tests/RendererTest.php

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
<?php declare (strict_types = 1);
1+
<?php
2+
3+
declare(strict_types=1);
4+
25
use PHPUnit\Framework\TestCase;
36

47
require 'vendor/autoload.php';
@@ -105,7 +108,7 @@ public function testInvalidGoogleFont(): void
105108
$expected = str_replace('"monospace"', '"Not-A-Font"', file_get_contents("tests/svg/test_normal.svg"));
106109
$this->assertEquals($expected, $controller->render());
107110
}
108-
111+
109112
/**
110113
* Test if a trailing ";" in lines is trimmed; see issue #25
111114
*/
@@ -127,7 +130,7 @@ public function testLineTrimming(): void
127130
$controller = new RendererController($params, self::$database);
128131
$this->assertEquals(file_get_contents("tests/svg/test_normal.svg"), $controller->render());
129132
}
130-
133+
131134
/**
132135
* Test normal vertical alignment
133136
*/
@@ -147,4 +150,49 @@ public function testNormalVerticalAlignment(): void
147150
$controller = new RendererController($params, self::$database);
148151
$this->assertEquals(file_get_contents("tests/svg/test_normal_vertical_alignment.svg"), $controller->render());
149152
}
153+
154+
/**
155+
* Test pause parameter
156+
*/
157+
public function testPauseParameter(): void
158+
{
159+
$params = array(
160+
"lines" => implode(";", array(
161+
"Full-stack web and app developer",
162+
"Self-taught UI/UX Designer",
163+
"10+ years of coding experience",
164+
"Always learning new things",
165+
)),
166+
"center" => "true",
167+
"vCenter" => "true",
168+
"width" => "380",
169+
"height" => "50",
170+
"pause" => "1000",
171+
);
172+
$controller = new RendererController($params, self::$database);
173+
$this->assertEquals(file_get_contents("tests/svg/test_pause.svg"), $controller->render());
174+
}
175+
176+
/**
177+
* Test pause on multiline card
178+
*/
179+
public function testPauseMultiline(): void
180+
{
181+
$params = array(
182+
"lines" => implode(";", array(
183+
"Full-stack web and app developer",
184+
"Self-taught UI/UX Designer",
185+
"10+ years of coding experience",
186+
"Always learning new things",
187+
)),
188+
"center" => "true",
189+
"vCenter" => "true",
190+
"width" => "380",
191+
"height" => "200",
192+
"multiline" => "true",
193+
"pause" => "1000",
194+
);
195+
$controller = new RendererController($params, self::$database);
196+
$this->assertEquals(file_get_contents("tests/svg/test_pause_multiline.svg"), $controller->render());
197+
}
150198
}

tests/svg/test_fonts.svg

Lines changed: 2 additions & 1 deletion
Loading

tests/svg/test_multiline.svg

Lines changed: 8 additions & 8 deletions
Loading

0 commit comments

Comments
 (0)