Éditer un clip animé
Cet article explique comment à partir d'une animation programmée en CSS obtenir l'effet équivalent dans un clip et coder l'édition des paramètres du clip.
Voir le Manuel du programmeur.
- <?php $text='Paris • London • '; ?>
- <?php $color='#ccbb66'?>
- <?php $font='Slackey'; ?>
- <?php $fontsize=36; ?>
- <?php $size=240; ?>
Définit le contenu du texte affiché, la couleur, la police et la taille de la police du texte, la taille de l'emblème.
- <?php head('font', $font); ?>
Ajoute la balise <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Slackey" />
à la section <head>
du document HTML.
RAPPEL : head
est une fonction d'iZend.
Adaptez le code à votre environnement de développement.
- #emblemtest {
- position: relative;
- overflow: hidden;
- margin: 0;
- width: <?php echo $size; ?>px;
- height: <?php echo $size; ?>px;
- font-family: "<?php echo $font; ?>", sans-serif;
- font-size: <?php echo $fontsize; ?>px;
- font-weight: bold;
- text-align: center;
- text-transform: uppercase;
- color: <?php echo $color; ?>
- }
- #emblemtest span {position:absolute;left:0;right:0;top:0;bottom:0;}
Configure le style du texte. Positionne chaque caractère individuel du texte.
- #emblemtest {
- animation: spin 5s ease-in-out 1s 2 alternate;
- }
- @keyframes spin {
- from { transform: rotate(0deg); }
- to { transform: rotate(360deg); }
- }
Programme l'animation du texte.
- <div id="emblemtest"> </div>
Le texte sera affiché dans cette <div>
. NOTE : Le
dans la <div>
fait en sorte que la police soit chargée par le navigateur.
- function draw(widget, text) {
- let angle = 360/text.length;
- for (let i = 0; i < text.length; i++) {
- let span = document.createElement('span');
- let letter = document.createTextNode(text[i]);
- span.appendChild(letter);
- let r = i * angle;
- span.style.transform = `rotate(${r}deg)`;
- widget.appendChild(span);
- }
- }
draw
affiche text
en rond dans widget
.
draw
ajoute dans widget
une balise <span>
pour chaque caractère de text
avec une rotation pour un total de 360°.
- const emblemtest = document.getElementById('emblemtest');
Assigne à emblemtest
la <div>
d'affichage du texte.
- draw(emblemtest, '<?php echo $text; ?>');
Dessine l'emblème.
Clip
Cliquez dans le texte pour démarrer l'animation.
- Model
- ClipModel
- EmblemModel
- ClipModel
- function EmblemModel(clipname) {
- ClipModel.call(this, clipname);
- this._value = {
- size: EmblemModel.defaultSize,
- text: EmblemModel.defaultText,
- textFont: EmblemModel.defaultTextFont,
- textSize: EmblemModel.defaultTextSize,
- textBold: EmblemModel.defaultTextBold,
- textColor: EmblemModel.defaultTextColor,
- duration: EmblemModel.defaultDuration,
- easing: EmblemModel.defaultEasing,
- delay: EmblemModel.defaultDelay
- };
- }
- EmblemModel.prototype = Object.create(ClipModel.prototype);
- Object.defineProperty(EmblemModel.prototype, 'constructor', { value: EmblemModel, enumerable: false, writable: true });
- EmblemModel.defaultSize = 160;
- EmblemModel.defaultText = ''; // 'London • Paris • ';
- EmblemModel.defaultTextFont = 'Open Sans';
- EmblemModel.defaultTextSize = 22;
- EmblemModel.defaultTextBold = true;
- EmblemModel.defaultTextColor = '#cccccc';
- EmblemModel.defaultEasing = 'ease-in-out';
- EmblemModel.defaultDuration = 5;
- EmblemModel.defaultDelay = 1;
- EmblemModel.minSize = 120;
- EmblemModel.maxSize = 960;
- EmblemModel.minTextLength = 0;
- EmblemModel.maxTextLength = 40;
- EmblemModel.minTextSize = 10;
- EmblemModel.maxTextSize = 60;
- EmblemModel.minDuration = 1;
- EmblemModel.maxDuration = 9;
- EmblemModel.minDelay = 0;
- EmblemModel.maxDelay = 5;
- EmblemModel.easingOptions = Validator.easingOptions;
- EmblemModel.prototype.validateValue = function(prop, val) {
- if (prop == 'size')
- return Number.isInteger(val);
- if (prop == 'text')
- return typeof val === 'string' && val.length >= EmblemModel.minTextLength;
- if (prop == 'textFont')
- return typeof val === 'string';
- if (prop == 'textSize')
- return Number.isInteger(val);
- if (prop == 'textColor')
- return Validator.validateColor(val);
- if (prop == 'duration')
- return Number.isInteger(val);
- if (prop == 'delay')
- return Number.isInteger(val);
- if (prop == 'easing')
- return Validator.validateEasing(val);
- return true;
- };
- EmblemModel.prototype.normalizeValue = function(prop, val) {
- if (prop == 'size') {
- if (val < EmblemModel.minSize)
- val = EmblemModel.minSize;
- else if (val > EmblemModel.maxSize)
- val = EmblemModel.maxSize;
- }
- else if (prop == 'text') {
- if (val.length > EmblemModel.maxTextLength)
- val = val.substring(0, EmblemModel.maxTextLength);
- }
- else if (prop == 'textSize') {
- if (val < EmblemModel.minTextSize)
- val = EmblemModel.minTextSize;
- else if (val > EmblemModel.maxTextSize)
- val = EmblemModel.maxTextSize;
- }
- else if (prop == 'textBold')
- val = val ? true : false;
- else if (prop == 'textColor')
- val = Validator.normalizeColor(val);
- else if (prop == 'duration') {
- if (val < EmblemModel.minDuration)
- val = EmblemModel.minDuration;
- else if (val > EmblemModel.maxDuration)
- val = EmblemModel.maxDuration;
- }
- else if (prop == 'delay') {
- if (val < EmblemModel.minDelay)
- val = EmblemModel.minDelay;
- else if (val > EmblemModel.maxDelay)
- val = EmblemModel.maxDelay;
- }
- return val;
- };
- Responder
- View
- Clip
- AnimateClip
- EmblemClip
- AnimateClip
- Clip
- View
- function EmblemClip() {
- AnimateClip.call(this);
- this._options = {duration: 0, delay: 0, easing: 'linear'};
- }
- EmblemClip.prototype = Object.create(AnimateClip.prototype);
- Object.defineProperty(EmblemClip.prototype, 'constructor', { value: EmblemClip, enumerable: false, writable: true });
- EmblemClip.prototype._draw = function(text) {
- while (this._widget.firstChild)
- this._widget.removeChild(this._widget.firstChild);
- let angle = 360/text.length;
- for (let i = 0; i < text.length; i++) {
- let span = document.createElement('span');
- let letter = document.createTextNode(text[i]);
- span.appendChild(letter);
- let r = i * angle;
- span.style.transform = `rotate(${r}deg)`;
- this._widget.appendChild(span);
- }
- return this;
- };
- EmblemClip.prototype.set = function(options) {
- const {size, text, textFont, textSize, textBold, textColor, duration, delay, easing} = options;
- this.setSize(size);
- this.setText(text);
- this.setTextFont(textFont);
- this.setTextSize(textSize);
- this.setTextBold(textBold);
- this.setTextColor(textColor);
- this.setAnimation(duration, delay, easing);
- return this;
- };
- EmblemClip.prototype.setValue = function(prop, val) {
- if (prop == 'size')
- this.setSize(val);
- else if (prop == 'text')
- this.setText(val);
- else if (prop == 'textFont')
- this.setTextFont(val);
- else if (prop == 'textSize')
- this.setTextSize(val);
- else if (prop == 'textBold')
- this.setTextBold(val);
- else if (prop == 'textColor')
- this.setTextColor(val);
- else if (prop == 'duration')
- this.setDuration(val);
- else if (prop == 'delay')
- this.setDelay(val);
- else if (prop == 'easing')
- this.setEasing(val);
- return this;
- };
- EmblemClip.prototype.setSize = function(px) {
- this.setStyle('width', `${px}px`);
- this.setStyle('height', `${px}px`);
- this._width = this._height = px;
- return this;
- };
- EmblemClip.prototype.setText = function(text) {
- if (text)
- this._draw(text);
- return this;
- };
- EmblemClip.prototype.setTextFont = function(font) {
- this.addFont(font).setStyle('fontFamily', `"${font}", sans-serif`);
- return this;
- };
- EmblemClip.prototype.setTextSize = function(px) {
- this.setStyle('fontSize', `${px}px`);
- return this;
- };
- EmblemClip.prototype.setTextBold = function(bold) {
- this.setStyle('fontWeight', bold ? 'bold' : 'normal');
- return this;
- };
- EmblemClip.prototype.setTextColor = function(color) {
- this.setStyle('color', color);
- return this;
- };
- EmblemClip.prototype.setDuration = function(ms) {
- this.setAnimation(ms, this._options.delay, this._options.easing);
- return this;
- };
- EmblemClip.prototype.setDelay = function(s) {
- this.setAnimation(this._options.duration, s, this._options.easing);
- return this;
- };
- EmblemClip.prototype.setEasing = function(easing) {
- this.setAnimation(this._options.duration, this._options.delay, easing);
- return this;
- };
- EmblemClip.prototype.setAnimation = function(duration, delay, easing) {
- const keyframes = [
- { transform: 'rotate(0deg)' },
- { transform: 'rotate(360deg)' }
- ];
- const options = {
- duration: duration*1000,
- direction: 'alternate',
- iterations: 2,
- easing: easing,
- delay: delay*1000,
- endDelay: 0
- };
- const animations = [
- [this._widget, keyframes, options]
- ];
- this.animate(animations, false);
- this._options.duration = duration;
- this._options.delay = delay;
- this._options.easing = easing;
- return this;
- };
- <?php $debug=false; ?>
Mettre $debug
à true
permet d'accéder dans la console du navigateur à tous les composants de l'interface.
Si $debug
vaut false
, tout le code en JavaScript est protégé par une fonction de fermeture.
- <?php $text='Paris • London • '; ?>
- <?php $color='#ccbb66'?>
- <?php $size=240; ?>
- <?php $font='Slackey'; ?>
- <?php $fontsize=36; ?>
Définit le texte affiché par l'emblème, sa couleur et sa taille, la police de caractères du texte et sa taille.
- <?php head('font', $font); ?>
Ajoute la balise <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Slackey" />
à la section <head>
du document HTML.
RAPPEL : head
est une fonction d'iZend.
Adaptez le code à votre environnement de développement.
- <?php $id=uniqid('id'); ?>
Définit l'identifiant de la <div>
qui encadre le HTML de l'interface.
- .emblem {
- position: relative;
- overflow: hidden;
- margin: 0;
- text-align: center;
- text-transform: uppercase;
- user-select: none;
- }
- .emblem span {position:absolute;left:0;right:0;top:0;bottom:0;}
Configure le CSS de l'emblème. Positionne chaque caractère.
- <div id="<?php echo $id; ?>" class="clip">
- <div class="emblem"></div>
- </div>
Crée la <div>
qui affiche l'emblème.
- <?php head('javascript', '/objectivejs/Objective.js'); ?>
- <?php head('javascript', '/objectivejs/Responder.js'); ?>
- <?php head('javascript', '/objectivejs/View.js'); ?>
- <?php head('javascript', '/objectivejs/Clip.js'); ?>
- <?php head('javascript', '/objectivejs/Model.js'); ?>
- <?php head('javascript', '/objectivejs/Validator.js'); ?>
- <?php head('javascript', '/objectivejs/ClipModel.js'); ?>
- <?php head('javascript', '/objectivejs/ClipController.js'); ?>
- <?php head('javascript', '/objectivejs/AnimateClip.js'); ?>
- <?php head('javascript', '/objectivejs/tests/EmblemModel.js'); ?>
- <?php head('javascript', '/objectivejs/tests/EmblemClip.js'); ?>
Inclut le code de toutes les classes nécessaires.
- <?php if (!$debug): ?>
- (function() {
- <?php endif; ?>
Isole tout le code en JavaScript dans une fonction de fermeture si $debug
vaut false
.
- const clip = new EmblemClip();
- const model = new EmblemModel();
- const container = document.querySelector('#<?php echo $id; ?>');
- clip.setManagedWidget(container.querySelector('.emblem'));
- clip.enablePlayer();
- const controller = new ClipController(clip, model);
- const options = {
- size: <?php echo $size; ?>,
- text: '<?php echo $text; ?>',
- textColor: '<?php echo $color; ?>',
- textFont: '<?php echo $font; ?>',
- textSize: <?php echo $fontsize; ?>
- };
- model.set(options);
Crée le clip, le modèle du clip et son interface. Active les contrôles au clavier et à la souris du clip. Crée un simple contrôleur qui configure le clip quand le modèle a été changé. Configure le modèle du clip.
- <?php if (!$debug): ?>
- })();
- <?php endif; ?>
Ferme la fonction qui isole le code en JavaScript si $debug
vaut false
.
Éditeur
Tapez quelques mots, e.g. Paris • London •
.
Appuyez sur Entrée pour valider le texte.
NOTE : Le texte est toujours affiché en lettres capitales.
Modifiez la taille de la police.
Cochez la case pour mettre le texte en gras.
Changez la police du texte en entrant le nom d'une police de Google Fonts, e.g. Slackey
ou Righteous
.
Choisissez la couleur du texte, e.g. #CB6
.
Ajustez les dimensions du clip.
Changez la durée en nombre de secondes de l'animation et du délai au démarrage.
Essayez différents effets d'animation, e.g. linear
ou ease-in-out
.
NOTE : L'animation s'exécute deux fois en alternant le sens de rotation.
La durée totale du clip est égale à 2 fois la durée de l'animation + le délai au démarrage.
Cliquez sur l'emblème pour démarrer l'animation. Cliquez de nouveau pour la mettre en pause, la relancer.
Rechargez la page. Les modifications sont enregistrées.
Voir Architecture d'un éditeur.
- <?php $debug=false; ?>
Mettre $debug
à true
permet d'accéder dans la console du navigateur à tous les composants de l'interface.
Si $debug
vaut false
, tout le code en JavaScript est protégé par une fonction de fermeture.
- <?php $editor=true; ?>
- <?php $player=true; ?>
Mettre $editor
à true
affiche l'éditeur du clip.
Mettre $player
à true
active les contrôles du clip.
Essayez de mettre chaque option à false
.
- <?php $clipname='emblem'; ?>
Définit le nom du modèle qui définit le nom du cookie qui enregistre les données du modèle.
- <?php head('javascript', 'js.cookie.js'); ?>
Ajoute la balise <script src="/js/js.cookie.js"/>
à la section <head>
du document HTML.
RAPPEL : head
est une fonction d'iZend.
Adaptez le code à votre environnement de développement.
- <?php if ($editor): ?>
- <?php head('javascript', 'jquery.minicolors'); ?>
- <?php head('stylesheet', 'jquery.minicolors', 'screen'); ?>
- <?php endif; ?>
Si l'éditeur est affiché, ajoute les balises <script src="/js/jquery.minicolors.js"/>
et <link rel="stylesheet" href="/css/jquery.minicolors.css" media="screen"/>
à la section <head>
du document HTML pour charger le code et la feuille de style de MiniColors en jQuery.
- <?php $id=uniqid('id'); ?>
Définit l'identifiant de la <div>
qui encadre le HTML de l'interface.
- .emblem {
- position: relative;
- overflow: hidden;
- margin: 0;
- text-align: center;
- text-transform: uppercase;
- user-select: none;
- }
- .emblem span {position:absolute;left:0;right:0;top:0;bottom:0;}
Configure le CSS de l'emblème. Positionne chaque caractère.
- #<?php echo $id; ?>_emblem_text {
- width: 20em;
- }
- #<?php echo $id; ?>_emblem_textsize {
- width: 3em;
- }
Configure la largeur des champs de saisie du texte de l'emblème et de sa largeur.
- <div id="<?php echo $id; ?>" class="clip">
- <?php if ($editor): ?>
- <div class="ojs">
- <div>
- <div class="ojs_undo">
- <button type="submit" class="ojs_button narrow control_undo" disabled><i class="fas fa-undo"></i></button>
- <button type="submit" class="ojs_button narrow control_redo" disabled><i class="fas fa-redo"></i></button>
- </div>
- <span><input class="ojs_size" type="number" step="10"/> <i class="fas fa-expand small"></i></span>
- </div>
- <span><input id="<?php echo $id; ?>_emblem_text" type="text" size="20" spellcheck="false"/></span>
- <div>
- <span><input id="<?php echo $id; ?>_emblem_textsize" type="number" step="1"/> <i class="fas fa-text-height small"></i></span>
- <span><input id="<?php echo $id; ?>_emblem_textbold" type="checkbox"/><label for="<?php echo $id; ?>_emblem_textbold"><i class="fas fa-bold small"></i></label></span>
- <span id="<?php echo $id; ?>_emblem_textcolor"></span>
- </div>
- <div>
- <span><input id="<?php echo $id; ?>_emblem_textfont" type="text" size="20" spellcheck="false"/> <i class="fas fa-font small"></i></span>
- </div>
- <fieldset class="ojs_animation">
- <legend><i class="fas fa-history"></i> <span class="ojs_timing">0</span></legend>
- <span><input class="ojs_duration" type="number" min="1" step="1"/> <i class="fas fa-clock small"></i></span>
- <span><input class="ojs_delay" type="number" min="0" max="5" step="1"/> <i class="fas fa-play-circle small"></i></span>
- <select class="ojs_easing" size="1">
- <option value="linear">linear</option>
- <option value="ease">ease</option>
- <option value="ease-in">ease-in</option>
- <option value="ease-out">ease-out</option>
- <option value="ease-in-out">ease-in-out</option>
- </select>
- </fieldset>
- </div>
- <?php endif; ?>
- <div class="emblem"></div>
- </div>
Crée les widgets de l'interface.
- <?php head('javascript', '/objectivejs/Objective.js'); ?>
- <?php head('javascript', '/objectivejs/Responder.js'); ?>
- <?php head('javascript', '/objectivejs/View.js'); ?>
- <?php head('javascript', '/objectivejs/Clip.js'); ?>
- <?php head('javascript', '/objectivejs/Model.js'); ?>
- <?php head('javascript', '/objectivejs/Validator.js'); ?>
- <?php if ($editor): ?>
- <?php head('javascript', '/objectivejs/Editor.js'); ?>
- <?php head('javascript', '/objectivejs/ClipEditor.js'); ?>
- <?php head('javascript', '/objectivejs/Inspector.js'); ?>
- <?php head('javascript', '/objectivejs/BooleanInspector.js'); ?>
- <?php head('javascript', '/objectivejs/NumberInspector.js'); ?>
- <?php head('javascript', '/objectivejs/StringInspector.js'); ?>
- <?php head('javascript', '/objectivejs/SelectInspector.js'); ?>
- <?php head('javascript', '/objectivejs/ColorInspector.js'); ?>
- <?php head('javascript', '/objectivejs/Undo.js'); ?>
- <?php head('javascript', '/objectivejs/Panel.js'); ?>
- <?php head('javascript', '/objectivejs/UndoPanel.js'); ?>
- <?php else: ?>
- <?php head('javascript', '/objectivejs/ClipController.js'); ?>
- <?php endif; ?>
- <?php head('javascript', '/objectivejs/ClipModel.js'); ?>
- <?php head('javascript', '/objectivejs/AnimateClip.js'); ?>
- <?php head('javascript', '/objectivejs/ModelCookieDelegate.js'); ?>
- <?php head('javascript', '/objectivejs/tests/EmblemModel.js'); ?>
- <?php head('javascript', '/objectivejs/tests/EmblemClip.js'); ?>
Inclut le code de toutes les classes nécessaires.
Si l'éditeur n'est pas affiché, un simple contrôleur configure le clip quand le modèle a été changé.
RAPPEL : La fonction head de la librairie iZend ajoute une balise telle que <script src="/objectivejs/Objective.js"></script>
à la section <head>
du document HTML. Adaptez le code à votre environnement de développement.
- <?php if (!$debug): ?>
- (function() {
- <?php endif; ?>
Isole tout le code en JavaScript dans une fonction de fermeture si $debug
vaut false
.
- const clip = new EmblemClip();
- const model = new EmblemModel('<?php echo $clipname; ?>');
- const container = document.querySelector('#<?php echo $id; ?>');
- clip.setManagedWidget(container.querySelector('.emblem'));
- clip.set(model.get());
Crée le clip et le modèle de données à éditer.
Récupère la <div>
qui encadre le HTML du programme.
Configure l'interface du clip.
Initialise le clip avec les données du modèle.
- clip.enablePlayer();
Active les contrôles au clavier et à la souris du clip si $player
vaut true
.
- const panel = new UndoPanel();
- panel.setManagedWidget(container.querySelector('.ojs_undo')).resetWidget();
- const sizeInspector = new NumberInspector(model.getValue('size'), {min: EmblemModel.minSize, max: EmblemModel.maxSize});
- sizeInspector.setManagedWidget(container.querySelector('.ojs_size')).resetWidget();
- const textInspector = new StringInspector(model.getValue('text'), {min: EmblemModel.minTextLength, max: EmblemModel.maxTextLength, trim: false, required: false});
- textInspector.setManagedWidget(container.querySelector('#<?php echo $id; ?>_emblem_text')).resetWidget();
- const textSizeInspector = new NumberInspector(model.getValue('textSize'), {min: EmblemModel.minTextSize, max: EmblemModel.maxTextSize});
- textSizeInspector.setManagedWidget(container.querySelector('#<?php echo $id; ?>_emblem_textsize')).resetWidget();
- const textBoldInspector = new BooleanInspector(model.getValue('textBold'));
- textBoldInspector.setManagedWidget(container.querySelector('#<?php echo $id; ?>_emblem_textbold')).resetWidget();
- const textColorInspector = new ColorInspector(model.getValue('textColor'));
- textColorInspector.createManagedWidget(container.querySelector('#<?php echo $id; ?>_emblem_textcolor'));
- const textFontInspector = new StringInspector(model.getValue('textFont'));
- textFontInspector.setManagedWidget(container.querySelector('#<?php echo $id; ?>_emblem_textfont')).resetWidget();
- const durationInspector = new NumberInspector(model.getValue('duration'), {min: EmblemModel.minDuration, max: EmblemModel.maxDuration});
- durationInspector.setManagedWidget(container.querySelector('.ojs_duration')).resetWidget();
- const delayInspector = new NumberInspector(model.getValue('delay'), {min: EmblemModel.minDelay, max: EmblemModel.maxDelay});
- delayInspector.setManagedWidget(container.querySelector('.ojs_delay')).resetWidget();
- const easingInspector = new SelectInspector(model.getValue('easing'), {tags: EmblemModel.easingOptions});
- easingInspector.setManagedWidget(container.querySelector('.ojs_easing')).resetWidget();
- const timing = new View();
- timing.setManagedWidget(container.querySelector('.ojs_timing'));
- const inspectors = {
- size: sizeInspector,
- text: textInspector,
- textFont: textFontInspector,
- textSize: textSizeInspector,
- textBold: textBoldInspector,
- textColor: textColorInspector,
- duration: durationInspector,
- delay: delayInspector,
- easing: easingInspector
- };
- const editor = new ClipEditor(model, clip, inspectors, panel, timing);
Si $editor
vaut true
, crée le panneau avec les boutons pour défaire et refaire une modification, crée les inspecteurs de tous les paramètres du clip, crée la vue qui affiche la durée du clip, crée l'éditeur.
- const controller = new ClipController(clip, model);
Si l'éditeur n'est pas affiché, crée un contrôleur.
- model.setDelegate(new ModelCookieDelegate());
- if (model.isSaved())
- model.readIn();
- else {
- model.setValue('text', 'Paris • London • ');
- model.setValue('textFont', 'Slackey');
- model.setValue('textColor', '#CB6');
- model.setValue('textSize', 36);
- model.setValue('size', 240);
- }
- model.enableSync();
Associe le modèle à un délégué en charge de la sauvegarde de ses données dans un cookie. Configure le modèle avec les données déjà enregistrées ou l'initialise avec des valeurs par défaut. Active la sauvegarde des données du modèle dès modification.
- <?php if (!$debug): ?>
- })();
- <?php endif; ?>
Ferme la fonction qui isole le code en JavaScript si $debug
vaut false
.
Un clip peut toujours être converti en une vidéo.
Cliquez dans la vidéo pour la démarrer. Cliquez de nouveau pour la mettre en pause.
VOIR AUSSI
Objective, Model, Clip, AnimateClip, Inspector, ModelCookieDelegate, Editor, Architecture d'un éditeur, Éditer un clip programmé, Éditer un clip vidéo, Écrire des données sur un serveur
Commentaires