ytkns/src/Effects/ForegroundImageEffect.php
2020-06-10 16:03:13 +00:00

154 lines
5.7 KiB
PHP

<?php
namespace YTKNS\Effects;
use Exception;
use YTKNS\HtmlTag;
use YTKNS\HtmlText;
use YTKNS\PageBuilder;
use YTKNS\PageEffectInterface;
use YTKNS\Upload;
use YTKNS\UploadNotFoundException;
class ForegroundImageEffect implements PageEffectInterface {
private const IMG_MIME = [
'image/png',
'image/jpeg',
'image/gif',
];
private const SPIN_DIRS = [
'cw' => 'Clockwise',
'ccw' => 'Counterclockwise',
];
private const SPIN_MIN = 0.01;
private const SPIN_MAX = 1000;
private $imageUpload = null;
private $spin = false;
private $spinSpeed = 1;
private $spinDirection = 'cw';
private $syncWithAudio = false;
public function getEffectName(): string {
return 'Foreground Image';
}
public function getEffectProperties(): array {
return [
[
'name' => 'img',
'title' => 'Image',
'type' => [
'name' => 'upload',
'allowed' => self::IMG_MIME,
],
],
[
'name' => 'spin',
'title' => 'Spin Animation',
'default' => false,
'type' => [
'name' => 'bool',
],
],
[
'name' => 'spnspd',
'title' => 'Spin Animation Period',
'default' => 1,
'type' => [
'name' => 'float',
'min' => self::SPIN_MIN,
'max' => self::SPIN_MAX,
],
],
[
'name' => 'spndir',
'title' => 'Spin Animation Direction',
'default' => 'br',
'type' => [
'name' => 'select',
'options' => self::SPIN_DIRS,
],
],
[
'name' => 'sync',
'title' => 'Synchronise with Background Audio',
'default' => false,
'type' => [
'name' => 'bool',
],
],
];
}
public function setEffectParams(array $vars, bool $quiet = false): void {
try {
if(isset($vars['img']) && is_string($vars['img'])) {
try {
$this->imageUpload = Upload::byId($vars['img']);
} catch(Exception $ex) {
if(!$quiet)
throw $ex;
}
if(!$quiet && !in_array($this->imageUpload->getType(), self::IMG_MIME))
throw new PageEffectException('Image upload was of invalid type.');
}
} catch(UploadNotFoundException $ex) {
$this->imageUpload = null;
}
if(isset($vars['spin']))
$this->spin = is_bool($vars['spin']) ? $vars['spin'] : (is_string($vars['spin']) ? boolval($vars['spin']) : false);
if(isset($vars['sync']))
$this->syncWithAudio = is_bool($vars['sync']) ? $vars['sync'] : (is_string($vars['sync']) ? boolval($vars['sync']) : false);
if(isset($vars['spnspd'])) {
$this->spinSpeed = is_int($vars['spnspd']) || is_float($vars['spnspd']) ? $vars['spnspd'] : (is_string($vars['spnspd']) ? floatval($vars['spnspd']) : 1);
if(!$quiet && ($this->spinSpeed < self::SPIN_MIN || $this->spinSpeed > self::SPIN_MAX))
throw new PageEffectException(sprintf('Spin speed may not be less than %d or more than %d', self::SPIN_MIN, self::SPIN_MAX));
}
if(isset($vars['spndir']) && is_string($vars['spndir']) && array_key_exists($vars['spndir'], self::SPIN_DIRS))
$this->spinDirection = $vars['spndir'];
}
public function getEffectParams(): array {
return [
'img' => empty($this->imageUpload) ? null : $this->imageUpload->getId(),
'spin' => $this->spin,
'spnspd' => $this->spinSpeed,
'spndir' => $this->spinDirection,
'sync' => $this->syncWithAudio,
];
}
public function applyEffect(PageBuilder $builder): void {
$element = $builder->getContainer()->appendChild(new HtmlTag('div', ['class' => 'ForegroundImage']));
$imageTarget = $element->appendChild(new HtmlTag('div', ['class' => 'ForegroundImage_Image', 'id' => 'ForegroundImage']));
if(!empty($this->imageUpload)) {
$imageSize = getimagesize($this->imageUpload->getPath());
if($imageSize !== false) {
$styleText = sprintf('width: %dpx; height: %dpx', $imageSize[0], $imageSize[1]);
if(!empty($_GET['preview']) || !$this->syncWithAudio)
$styleText .= sprintf(';background-image:url(\'%s\')', $this->imageUpload->getUrl());
if(empty($_GET['preview']) && $this->spin)
$styleText .= sprintf(';animation: SharedAnimation_Spin360 infinite linear %s %Fs', $this->spinDirection === 'cw' ? 'normal' : 'reverse', $this->spinSpeed);
$imageTarget->setAttribute('style', $styleText);
$scriptText = 'window.addEventListener(\'DOMContentLoaded\', function() {';
$scriptText .= 'synchroniseBackgroundWithAudio(\'' . $this->imageUpload->getUrl() . '\', \'ForegroundImage\');';
$scriptText .= '});';
$scriptTag = new HtmlTag('script', ['type' => 'text/javascript']);
$scriptTag->setTextContent($scriptText);
$builder->getHead()->appendChild($scriptTag);
}
}
}
}