Editing an animated clip
This article explains how to obtain from an animation programmed in CSS the equivalent effect in a clip and how editing the clip parameters is coded.
See the Programmer's manual.
- <?php $text='Paris • London • '; ?>
- <?php $color='#ccbb66'?>
- <?php $font='Slackey'; ?>
- <?php $fontsize=36; ?>
- <?php $size=240; ?>
Defines the content of the text which is displayed, the color, the font and the size of the font of the text, the size of the emblem.
- <?php head('font', $font); ?>
Adds the tag <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Slackey" />
to the <head>
section of the HTML document.
REMINDER: head
is a function of iZend.
Adapt the code to your development environment.
- #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;}
Configures the style of the text. Positions each individual character of the text.
- #emblemtest {
- animation: spin 5s ease-in-out 1s 2 alternate;
- }
- @keyframes spin {
- from { transform: rotate(0deg); }
- to { transform: rotate(360deg); }
- }
Programs the animation of the text.
- <div id="emblemtest"> </div>
The text will be displayed in this <div>
. NOTE: The
in the <div>
makes sure the font is loaded by the navigator.
- 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
displays text
in a circle in widget
.
draw
adds in widget
a tag <span>
for every character of text
with a rotation for a total of 360°.
- const emblemtest = document.getElementById('emblemtest');
Assigns to emblemtest
the display <div>
of the text.
- draw(emblemtest, '<?php echo $text; ?>');
Draws the emblem.
Clip
Click in the text to start the 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; ?>
Setting $debug
to true
gives access in the console of the navigator to all the components of the interface.
If $debug
is false
, all the code in JavaScript is protected by a closure function.
- <?php $text='Paris • London • '; ?>
- <?php $color='#ccbb66'?>
- <?php $size=240; ?>
- <?php $font='Slackey'; ?>
- <?php $fontsize=36; ?>
Defines the text displayed by the emblem, its color and its size, the character font of the text and its size.
- <?php head('font', $font); ?>
Adds the tag <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Slackey" />
to the <head>
section of the HTML document.
REMINDER: head
is a function of iZend.
Adapt the code to your development environment.
- <?php $id=uniqid('id'); ?>
Defines the identifier of the <div>
which surrounds the HTML of the 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;}
Configures the CSS of the emblem. Positions each character.
- <div id="<?php echo $id; ?>" class="clip">
- <div class="emblem"></div>
- </div>
Creates the <div>
which displays the emblem.
- <?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'); ?>
Includes the code of all the necessary classes.
- <?php if (!$debug): ?>
- (function() {
- <?php endif; ?>
Isolates all the code in JavaScript in a closure function if $debug
is 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);
Creates the clip, the model of the clip and its interface. Enables the keyboard and the mouse controls of the clip. Creates a simple controller which configures the clip when the model has been set. Configures the model of the clip.
- <?php if (!$debug): ?>
- })();
- <?php endif; ?>
Closes the function which isolates the code in JavaScript if $debug
is false
.
Editor
Type in a couple of words, e.g. Paris • London •
.
Press Enter to validate the text. NOTE: The text is always displayed in capital letters.
Modify the size of the font.
Check the box to show the text in bold.
Change the font of the text by entering the name of a font from Google Fonts, e.g. Slackey
or Righteous
.
Choose the color of the text, e.g. #CB6
.
Adjust the dimensions of the clip.
Change the numbers of seconds of the duration of the animation and the start delay.
Try different animation effects, e.g. linear
ou ease-in-out
.
NOTE: The animation runs two times alternating the direction of the rotation.
The total duration of the clip is equal to 2 times the duration of the animation + the start delay.
Click on the emblem to start the animation. Click again to pause it, to continue to play it.
Reload the page. The modifications are saved.
See Architecture of an editor.
- <?php $debug=false; ?>
Setting $debug
to true
gives access in the console of the navigator to all the components of the interface.
If $debug
is false
, all the code in JavaScript is protected by a closure function.
- <?php $editor=true; ?>
- <?php $player=true; ?>
Setting $editor
to true
displays the editor of the clip.
Setting $player
to true
activates the controls of the clip.
Try setting each option to false
.
- <?php $clipname='emblem'; ?>
Defines the name of the model which defines the name of the cookie which records the data of the model.
- <?php head('javascript', 'js.cookie.js'); ?>
Adds the tag <script src="/js/js.cookie.js"></script>
to the <head>
section of the document in HTML.
- <?php if ($editor): ?>
- <?php head('javascript', 'jquery.minicolors'); ?>
- <?php head('stylesheet', 'jquery.minicolors', 'screen'); ?>
- <?php endif; ?>
If the editor is displayed, adds the tags <script src="/js/jquery.minicolors.js"/>
and <link rel="stylesheet" href="/css/jquery.minicolors.css" media="screen"/>
to the <head>
section of the HTML document to load the code and the style sheet of MiniColors in jQuery.
- <?php $id=uniqid('id'); ?>
Defines the identifier of the <div>
which surrounds the HTML of the 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;}
Configures the CSS of the emblem. Positions each character.
- #<?php echo $id; ?>_emblem_text {
- width: 20em;
- }
- #<?php echo $id; ?>_emblem_textsize {
- width: 3em;
- }
Configures the width of the input fields for the text of the emblem and its width.
- <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>
Creates the widgets of the 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'); ?>
Includes the code of all the necessary classes.
If the editor isn't displayed, a simple controller configures the clip when the model has been set.
REMINDER: The function head of the iZend library adds a tag such as <script src="/objectivejs/Objective.js"></script>
to the <head>
section of the document in HTML.
Adapt the code to your development environment.
- <?php if (!$debug): ?>
- (function() {
- <?php endif; ?>
Isolates all the code in JavaScript in a closure function if $debug
is 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());
Creates the clip and the data model to be edited.
Retrieves the <div>
which surrounds the HTML of the program.
Configures the interface of the clip.
Initializes the clip with the data of the model.
- clip.enablePlayer();
Enables the keyboard and the mouse controls of the clip if $player
is 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);
If $editor
is true
, creates the panel with the buttons to undo and redo a modification, creates the inspectors for all the parameters of the clip, creates the view which displays the duration of the clip, creates the editor.
- const controller = new ClipController(clip, model);
If the editor isn't displayed, creates a simple controller.
- 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();
Associates the model to a delegate in charge of saving its data in a cookie. Configures the model with the data already saved or initializes it with default values. Enables saving the data of the model whenever it is changed.
- <?php if (!$debug): ?>
- })();
- <?php endif; ?>
Closes the function which isolates the code in JavaScript if $debug
is false
.
A clip can always be converted into a video.
Click in the video to start it. Click again to pause it.
SEE ALSO
Objective, Model, Clip, AnimateClip, Inspector, ModelCookieDelegate, Editor, Architecture of an editor, Editing a programmed clip, Editing a video clip, Write data on a server
Comments