several fixes

This commit is contained in:
2022-11-04 22:26:10 +01:00
parent 00bb15a3c1
commit 313f83f715
43 changed files with 10192 additions and 5 deletions

View File

@ -0,0 +1,75 @@
// Karma configuration
// Generated on Fri Jul 18 2014 10:58:08 GMT+0100 (BST)
module.exports = function(config) {
var options = {
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '..',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'test/unit.setup.js',
'src/pathformer.js',
'src/vivus.js',
'test/unit/**.js'
],
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'../src/pathformer.js': ['coverage'],
'../src/vivus.js': ['coverage']
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress', 'coverage'],
// optionally, configure the reporter
coverageReporter: {
type: 'html',
dir: '../coverage/'
},
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true
};
if (process.env.TRAVIS) {
options.customLaunchers = {
Chrome_travis_ci: {
base: 'Chrome',
flags: ['--no-sandbox']
}
};
options.browsers = ['Chrome_travis_ci'];
}
config.set(options);
};

View File

@ -0,0 +1,30 @@
<svg height="300" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
viewBox="0 0 404.7 354" enable-background="new 0 0 404.7 354">
<g stroke="#f9f9f9" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10">
<!-- HI -->
<path data-duration="10" d="M324.6,61.2c16.6,0,29.5-12.9,29.5-29.5c0-16.6-12.9-29.5-29.5-29.5c-16.6,0-29.5,12.9-29.5,29.5C295.1,48.4,308,61.2,324.6,61.2z"/>
<path data-duration="130" d="M366.2,204.2c-9.8,0-15-5.6-15-15.1V77.2h-85v28h19.5c9.8,0,8.5,2.1,8.5,11.6v72.4c0,9.5,0.5,15.1-9.3,15.1H277h-20.7c-8.5,0-14.2-4.1-14.2-12.9V52.4c0-8.5,5.7-12.3,14.2-12.3h18.8v-28h-127v28h18.1c8.5,0,9.9,2.1,9.9,8.9v56.1h-75V53.4c0-11.5,8.6-13.3,17-13.3h11v-28H2.2v28h26c8.5,0,12,2.1,12,7.9v142.2c0,8.5-3.6,13.9-12,13.9h-21v33h122v-33h-11c-8.5,0-17-4.1-17-12.2v-57.8h75v58.4c0,9.1-1.4,11.6-9.9,11.6h-18.1v33h122.9h5.9h102.2v-33H366.2z"/>
<path data-async="" data-delay="20" d="M358.8,82.8c11.1-4.2,18.8-14.7,18.8-27.5c0-8.5-3.4-16-8.9-21.3"/>
<path data-async="" d="M124.2,105.7V77c0-11.5,9.1-13.8,17.5-13.8h10.5V44.7"/>
<polyline data-async="" points="147.9,40.2 171.2,63.2 175.7,63.2"/>
<line data-async="" x1="295.1" y1="32.1" x2="275.2" y2="12.2"/>
<path data-async="" d="M266.2,204.7V75.9c0-8.5,5.2-12.8,13.7-12.8h18.3V44.7"/>
<polyline data-async="" points="265.9,105.2 289.2,129.2 293.7,129.2"/>
<polyline data-async="" points="374.2,204.7 374.2,94.2 358.8,82.8 351.2,77.2"/>
<polyline data-async="" points="148.2,237.2 171.2,261.2 294.6,261.2 300.5,261.2 402.2,261.2 402.2,228.2 379.2,204.2"/>
<polyline data-async="" points="124.2,204.7 124.2,157.2 175.7,157.2"/>
<line data-async="" x1="147.7" y1="228.2" x2="129.2" y2="204.2"/>
<polyline data-async="" points="7.2,237.3 30.2,261.2 152.2,261.2 152.2,241.7"/>
<polyline data-async="" points="1.9,40.2 26,63.2 39.7,63.2"/>
<line data-async="" x1="129.2" y1="12.2" x2="148.2" y2="33.2"/>
<line data-async="" x1="303.9" y1="53" x2="328.1" y2="77.2"/>
<line x1="345.1" y1="10.5" x2="368.7" y2="34"/>
<!-- there -->
<path data-delay="30" data-duration="60" stroke-linecap="round" stroke-linejoin="round" d="M76.8,337.3c0,0,1.9,12.2,13.1,12.2c22.1,0,23.8-1.8,59-66.4c-19.7,35.7-36.4,66.2-19.3,66.2c15.2,0,22.9-14.2,28.3-23.7c3.3-0.5,24-3.2,35-25.5c4-8.1,4.1-17.8-8.1-15.2c-5.6,1.2-13.1,14.8-15.7,19.2c-7.6,12.7-22.4,45.2-22.4,45.2s10.3-22.4,21.5-22.4c15.5,0-9.4,22.4,4.7,22.4c4.9,0,11.7-11.4,16.6-20.9c7.5,4.7,19.7,1.7,24.5-8.1c10.1-20.4-14.4-12.8-24.5,8.1c-5.5,11.3-2.2,21.1,11.2,21.1c16.4,0,26.1-28.3,30.5-37.5c9.9,2.5,14,2.5,22.7-1.1c-3.5,5.1-24,38.1-8.3,38.1c6.7,0,11.7-11.4,16.6-20.9c7.5,4.7,19.7,1.7,24.5-8.1c10.1-20.4-14.4-12.8-24.5,8.1c-5.5,11.3-2.2,21.1,11.2,21.1c16.4,0,20.6-4,24.7-10.5"/>
<path stroke-linecap="round" stroke-linejoin="round" d="M157.3,300.8c3.8-2.3-29,0.8-35.6,3.2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,425 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>vivus.js - manual tests page</title>
<meta name="description" content="SVG Drawing Animation" />
<style type="text/css">
/* Base style */
html {
font-size: 24px;
height: 100%;
}
body {
height: 100%;
margin: 0 0 40px;
font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
font-weight: 200;
color: #666666;
background-color: #ffffff;
word-break: break-word;
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
font-weight: 100;
}
a,
a:visited,
a:hover,
a:link {
color: inherit;
outline: 0;
}
small {
font-weight: 100;
}
p {
font-size: 1rem;
line-height: 1.4rem;
}
button,
.button {
margin: 0;
padding: 3px 6px;
border-radius: 6px;
border: 1px solid currentColor;
color: inherit;
background-color: rgba(0, 0, 0, 0);
font-size: 0.6rem;
font-weight: 300;
text-decoration: none;
cursor: pointer;
outline: 0;
}
button.active,
.button.active {
background-color: currentColor;
}
button.active span,
.button.active span {
color: #ffffff;
}
i {
background-color: rgba(0, 0, 0, 0.25);
border-radius: 4px;
}
svg * {
fill: none;
stroke: currentColor;
}
table {
border-collapse: collapse;
}
table,
th,
td {
border: 1px solid currentColor;
line-height: 0;
}
/* Layout */
.content {
margin: auto;
max-width: 960px;
width: 100%;
}
.box {
width: 100%;
display: inline-block;
vertical-align: top;
}
.section {
min-height: 90%;
padding: 20px;
box-sizing: border-box;
}
.warning {
padding: 0.5rem 0.75rem;
border: 1px solid currentColor;
color: #fff;
background-color: #c00;
border-radius: 0.25rem;
}
.hidden {
display: none;
}
@media (min-width: 768px) {
.box-50 {
width: 50%;
}
.section {
display: flex;
flex-direction: row;
}
}
/* Themes */
.intro {
display: block;
}
.sunrise {
color: #f037a5;
background-color: #f8c72c;
}
.matrix {
color: #86e0c4;
background-color: #181f21;
}
.electric {
color: #78c9db;
background-color: #e4175b;
}
.night {
color: #d3d679;
background-color: #316bd2;
}
</style>
</head>
<body>
<div class="section intro">
<h2>Vivus manual (cheap) tests.</h2>
<p>
Just scroll along the page and if a glitch appear or the visual
appearance is not like the description, it's not good.
</p>
<p id="config-instructions" class="warning hidden">
To use this page you must use an HTTP server to serve files. Run
<i>npm run serve</i> in the repository then go to the
<a href="http://127.0.0.1:8844/test/manual">test page</a>
</p>
</div>
<div class="section matrix">
<div class="content">
<div class="box box-50">
<p>
This should display the obturateur SVG like on the demo page. The
strokes must be orange. The element must remain an
<i>object</i> tag.
</p>
<button
onclick="this.textContent=(document.querySelector('object#obt')?'Pass!':'Failed.')"
>
Test
</button>
</div>
<div class="box box-50">
<object
id="obt"
data="obturateur.svg"
type="image/svg+xml"
style="width: 100%; max-height: 250px"
></object>
</div>
</div>
</div>
<div class="section sunrise">
<div class="content">
<div class="box box-50">
<div id="polaroid-dynamic"></div>
</div>
<div class="box box-50">
<p>
This should display the polaroid SVG like on the demo page. The
strokes must have the same color as this text.
</p>
</div>
</div>
</div>
<div class="section electric">
<div class="content">
<div class="box box-50">
<p>
This should display the 'Hi there' SVG like ready to start. Be sure
no glitch appear (no small path or dots). Click on the following
button to start.
</p>
<button onclick="hiD.play();">Start</button>
</div>
<div class="box box-50">
<div id="hi-dynamic" style="max-width: 300px; margin: auto"></div>
</div>
</div>
</div>
<div class="section night">
<div class="content">
<div class="box box-50">
<div id="synth-dynamic" style="max-width: 400px; margin: auto"></div>
</div>
<div class="box box-50">
<p>
This should display a synth ready to start. Be sure no glitch appear
(no small path or dots). The animation should use a custom path
timing function (ease_in: slow at start then finish fast.). Click on
the following button to start.
</p>
<button onclick="synthD.play();">Start</button>
</div>
</div>
</div>
<div class="section electric">
<div class="content">
<table id="nonScaling">
<tr style="height: 16.66%">
<td style="width: 16.66%">
<svg viewBox="0 0 100 100" width="100%" height="100%">
<line
vector-effect="non-scaling-stroke"
x1="0"
y1="0"
x2="200"
y2="200"
transform="scale(.5,.5)"
/>
</svg>
</td>
<td style="width: 33.33%">
<svg viewBox="0 0 200 100" width="100%" height="100%">
<line
vector-effect="non-scaling-stroke"
x1="0"
y1="0"
x2="200"
y2="200"
transform="scale(1,.5)"
/>
</svg>
</td>
<td style="width: 50%">
<svg viewBox="0 0 300 100" width="100%" height="100%">
<line
vector-effect="non-scaling-stroke"
x1="0"
y1="0"
x2="200"
y2="200"
transform="scale(1.5,.5)"
/>
</svg>
</td>
</tr>
<tr style="height: 33.33%">
<td>
<svg viewBox="0 0 100 200" width="100%" height="100%">
<line
vector-effect="non-scaling-stroke"
x1="0"
y1="0"
x2="200"
y2="200"
transform="scale(.5,1)"
/>
</svg>
</td>
<td>
<svg viewBox="0 0 200 200" width="100%" height="100%">
<line
vector-effect="non-scaling-stroke"
x1="0"
y1="0"
x2="200"
y2="200"
transform="scale(1,1)"
/>
</svg>
</td>
<td>
<svg viewBox="0 0 300 200" width="100%" height="100%">
<line
vector-effect="non-scaling-stroke"
x1="0"
y1="0"
x2="200"
y2="200"
transform="scale(1.5,1)"
/>
</svg>
</td>
</tr>
<tr style="height: 50%">
<td>
<svg viewBox="0 0 100 300" width="100%" height="100%">
<line
vector-effect="non-scaling-stroke"
x1="0"
y1="0"
x2="200"
y2="200"
transform="scale(.5,1.5)"
/>
</svg>
</td>
<td>
<svg viewBox="0 0 200 300" width="100%" height="100%">
<line
vector-effect="non-scaling-stroke"
x1="0"
y1="0"
x2="200"
y2="200"
transform="scale(1,1.5)"
/>
</svg>
</td>
<td>
<svg viewBox="0 0 300 300" width="100%" height="100%">
<line
vector-effect="non-scaling-stroke"
x1="0"
y1="0"
x2="200"
y2="200"
transform="scale(1.5,1.5)"
/>
</svg>
</td>
</tr>
</table>
<p>
Non scaling path<br />In any case of a resize, the animation of each
line must be complete.
</p>
<button onclick="nonScalingResize();">Resize</button>
<button onclick="nonScalingReplay();">Replay</button>
</div>
</div>
<!-- Le scripts -->
<script src="/dist/vivus.js"></script>
<script>
// Display warning message if not on http server
if (window.location.protocol === 'file:') {
var configIntro = document.getElementById('config-instructions');
configIntro.style.display = 'block';
}
// Obturateur
var obt1 = new Vivus('obt', {
type: 'delayed',
duration: 150,
});
// polaroid-dynamic
var polaroidD = new Vivus('polaroid-dynamic', {
file: 'polaroid.svg',
type: 'scenario-sync',
duration: 20,
});
var hiD = new Vivus('hi-dynamic', {
file: 'hi-there.svg',
type: 'scenario-sync',
duration: 20,
start: 'manual',
});
var synthD = new Vivus('synth-dynamic', {
file: 'synth.svg',
type: 'oneByOne',
duration: 200,
start: 'manual',
animTimingFunction: Vivus.EASE_IN,
});
// Non scaling
const resizeObserver = new ResizeObserver((entries) => {
nonScalingVivuses.forEach((v) => v.recalc());
});
resizeObserver.observe(window.nonScaling);
var nonScalingVivuses = Array.from(
document.querySelectorAll('#nonScaling svg')
).map((svg) => new Vivus(svg, { start: 'autostart' }));
function nonScalingResize() {
const newWidth = Math.floor(Math.random() * 100);
const newHeight = Math.floor(Math.random() * 100);
window.nonScaling.style.width = `${newWidth}%`;
window.nonScaling.style.height = `${newHeight}%`;
nonScalingVivuses.forEach((v) => v.recalc());
}
function nonScalingReplay() {
nonScalingVivuses.forEach((v) => v.reset().play());
}
</script>
</body>
</html>

View File

@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
width="100%" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200">
<g stroke="#f60" fill="none" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" >
<circle cx="100" cy="100" r="90"/>
<circle cx="100" cy="100" r="85.74"/>
<circle cx="100" cy="100" r="72.947"/>
<circle cx="100" cy="100" r="39.74"/>
<line x1="34.042" y1="131.189" x2="67.047" y2="77.781"/>
<line x1="31.306" y1="75.416" x2="92.41" y2="60.987"/>
<line x1="68.81" y1="34.042" x2="122.219" y2="67.046"/>
<line x1="124.584" y1="31.305" x2="139.013" y2="92.409"/>
<line x1="165.957" y1="68.809" x2="132.953" y2="122.219"/>
<line x1="168.693" y1="124.584" x2="107.59" y2="139.012"/>
<line x1="131.19" y1="165.957" x2="77.781" y2="132.953"/>
<line x1="75.417" y1="168.693" x2="60.987" y2="107.59"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 910 B

View File

@ -0,0 +1,62 @@
<svg id="polaroid" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
viewBox="0 0 200 160" enable-background="new 0 0 200 160">
<g stroke="#f9f9f9" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10">
<!-- Case -->
<!-- The case items will be drawn at the same time (attribute `data-async` on each tag) with a custom duration of 40 frames (attribute `data-duration`). WARNING: When you want to draw a bloc asynchronously (like here), the last item need to be `data-async` free. Otherwise the following tags will also start at the same time. I know it's a bit confusing, play a bit with it and you'll see. -->
<path data-async="" data-duration="40" d="
M106.725,104.742c-0.773,2.498-3.586,4.229-6.285,3.867L12.473,96.802c-2.699-0.363-4.262-2.682-3.49-5.18l25.164-81.436
c0.771-2.496,3.584-4.229,6.283-3.866l87.966,11.808c2.699,0.362,4.264,2.68,3.49,5.179L106.725,104.742z"/>
<path data-async="" data-duration="40" d="
M101.02,123.207c-0.773,2.5-3.587,4.23-6.286,3.867L6.766,115.27c-2.699-0.363-4.26-2.682-3.488-5.182l2.91-9.417
c0.771-2.499,3.585-4.23,6.285-3.87l87.967,11.809c2.699,0.361,4.261,2.682,3.49,5.18L101.02,123.207z"/>
<line data-async="" data-duration="40" x1="103.377" y1="128.225" x2="154.768" y2="155.32"/>
<line data-async="" data-duration="40" x1="109.852" y1="112.684" x2="155.035" y2="136.906"/>
<path data-async="" data-duration="40" d="
M9.096,120.207l47.932,21.994c0,0,98.06,12.414,97.74,13.119c-0.318,0.709,5.426-16.205,5.426-16.205l-2.646-96.842
c-1.098-7.587-2.467-11.8-8.559-15.024l-12.635-6.604"/>
<path data-async="" data-duration="40" d="
M161.586,38.135l30.717,16.085c0,0,5.295,2.323,4.543,6.504l-3.215,10.527c-0.648,2.621-2.939,4.988-8.229,2.798l-9.154-4.701
l-11.834,56.441"/>
<path data-duration="40" d="
M183.148,49.518c0,0,5.295,2.324,4.543,6.506l-3.215,10.526c-0.648,2.622-2.938,4.988-8.229,2.798"/>
<!-- Lens -->
<!-- All item will be drawn line by line, with an exception for the first one, a little delay (attribute `data-delay) to make a break between the drawing of the case and the start of the lens part -->
<path data-delay="20" d="
M87.176,56.143C83.274,68.78,69.043,77.538,55.395,75.706S33.846,62.146,37.75,49.511c3.903-12.637,18.135-21.392,31.783-19.562
C83.181,31.782,91.081,43.51,87.176,56.143z"/>
<path d="
M92.745,56.891c-4.785,15.48-22.219,26.213-38.942,23.969C37.079,78.615,27.4,64.245,32.184,48.763
c4.783-15.48,22.218-26.211,38.94-23.968C87.848,27.041,97.528,41.411,92.745,56.891z"/>
<path d="
M78.99,26.933c16.169,7.426,19.398,10.989,22.026,20.105c1.283,4.449,1.271,9.411-0.3,14.489
c-4.783,15.479-22.217,26.213-38.941,23.969c-8.68-1.165-21.171-7.963-25.613-14.055"/>
<path d="
M42.602,50.162c3.137-10.157,14.573-17.193,25.543-15.722"/>
<!-- Flash -->
<!-- This tag does not have any extra attribute. So it will start when the previous tag is finished. His duration and delay will be the one given in the options. -->
<path d="
M103.789,29.275c-0.568,1.841,0.582,3.549,2.57,3.818l12.807,1.72c1.988,0.266,4.062-1.012,4.633-2.851l1.66-5.38
c0.568-1.843-0.582-3.551-2.57-3.816l-12.807-1.72c-1.988-0.268-4.062,1.01-4.633,2.85L103.789,29.275z"/>
<!-- Output -->
<!-- Same case as Flash -->
<path d="
M11.129,105.791c-0.297,0.965,0.305,1.855,1.346,1.994l81.446,10.932c1.038,0.141,2.123-0.527,2.42-1.49l0,0
c0.298-0.961-0.304-1.855-1.343-1.996l-81.447-10.93C12.51,104.16,11.426,104.828,11.129,105.791L11.129,105.791z"/>
<!-- Design (color lines on the front) -->
<!-- All the lines will start at the same time, because they all have the attribute `data-async` -->
<line data-async="" x1="47.583" y1="101.505" x2="51.561" y2="88.267"/>
<line data-async="" x1="53.391" y1="102.326" x2="57.047" y2="90.125"/>
<line data-async="" x1="59.224" y1="103.068" x2="62.749" y2="91.295"/>
<line data-async="" x1="65.057" y1="103.814" x2="69.015" y2="90.637"/>
<line data-async="" x1="72.87" y1="19.969" x2="75.497" y2="11.082"/>
<line data-async="" x1="78.512" y1="21.325" x2="81.317" y2="11.868"/>
<line data-async="" x1="83.833" y1="23.718" x2="87.16" y2="12.582"/>
<line data-async="" x1="89.145" y1="26.141" x2="92.939" y2="13.498"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="378.995px" height="259.5px" viewBox="0 0 378.995 259.5" enable-background="new 0 0 378.995 259.5" xml:space="preserve">
<g id="Synth">
<path fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M375.5,108.934c1.549,2.693,0.627,5.739-2.059,6.804L72.043,235.257c-2.685,1.064-6.116-0.254-7.665-2.946L5.362,129.69
c-1.548-2.692-0.625-5.737,2.059-6.802L308.818,3.369c2.686-1.065,6.117,0.254,7.666,2.946L375.5,108.934z"/>
<path fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M376.246,111.47l-2.068,18.344c0,0-0.621,5.361-4.932,7.726L69.601,256.365c-2.685,1.064-6.116-0.254-7.665-2.946L3.693,152.145
c-1.548-2.692-0.878-9.891-0.878-9.891l0.82-7.014"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="373.785" y1="112.765" x2="371.715" y2="130.65"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="70.318" y1="250.17" x2="371.715" y2="130.65"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="319.578" y1="22.078" x2="19.852" y2="140.935"/>
<polyline fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
19.852,140.935 72.387,232.284 70.318,250.17 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="371.715" y1="130.65" x2="365.053" y2="119.063"/>
<g id="octaves_1_">
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="93.572" y1="226.72" x2="73.09" y2="191.106"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="114.616" y1="218.126" x2="94.134" y2="182.512"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="136.629" y1="209.646" x2="82.765" y2="115.986"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="158.158" y1="201.108" x2="137.674" y2="165.493"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="179.688" y1="192.572" x2="159.203" y2="156.957"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="201.213" y1="184.034" x2="180.732" y2="148.419"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="222.742" y1="175.497" x2="168.879" y2="81.838"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="244.27" y1="166.959" x2="223.789" y2="131.346"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="265.799" y1="158.423" x2="245.318" y2="122.809"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="287.328" y1="149.886" x2="233.463" y2="56.226"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="308.855" y1="141.349" x2="288.375" y2="105.734"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="330.385" y1="132.812" x2="309.902" y2="97.197"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="351.912" y1="124.274" x2="331.432" y2="88.66"/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="373.441" y1="115.737" x2="319.578" y2="22.078"/>
</g>
<g id="bemols_1_">
<g>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
67.427,190.815 35.241,134.85 39.708,133.061 44.176,131.271 76.24,177.929 76.362,187.236 "/>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
69.3,180.708 36.616,135.539 44.606,132.34 76.24,177.929 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="69.077" y1="183.09" x2="68.222" y2="187.702"/>
</g>
<g>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
89.117,182.213 56.931,126.247 61.398,124.458 65.866,122.669 97.93,169.326 98.052,178.634 "/>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
90.99,172.105 58.306,126.937 66.295,123.736 97.93,169.326 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="90.767" y1="174.487" x2="89.912" y2="179.1"/>
</g>
<g>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
132.012,165.204 99.826,109.238 104.293,107.449 108.762,105.661 140.825,152.317 140.948,161.625 "/>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
133.885,155.098 101.202,109.928 109.191,106.728 140.825,152.317 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="133.661" y1="157.479" x2="132.807" y2="162.091"/>
</g>
<g>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
153.541,156.666 121.354,100.7 125.821,98.911 130.289,97.122 162.354,143.779 162.475,153.088 "/>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
155.416,146.559 122.729,101.39 130.719,98.19 162.354,143.779 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="155.191" y1="148.94" x2="154.335" y2="153.554"/>
</g>
<g>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
175.068,148.129 142.881,92.164 147.348,90.374 151.817,88.585 183.881,135.242 184.004,144.551 "/>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
176.941,138.021 144.256,92.853 152.247,89.653 183.881,135.242 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="176.719" y1="140.403" x2="175.863" y2="145.017"/>
</g>
<g>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
218.127,131.056 185.939,75.089 190.406,73.3 194.875,71.512 226.938,118.169 227.061,127.476 "/>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
220,120.948 187.314,75.778 195.305,72.579 226.938,118.169 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="219.775" y1="123.329" x2="218.922" y2="127.942"/>
</g>
<g>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
239.656,122.518 207.469,66.553 211.936,64.763 216.402,62.975 248.467,109.631 248.59,118.939 "/>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
241.529,112.411 208.844,67.241 216.834,64.042 248.467,109.631 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="241.305" y1="114.792" x2="240.449" y2="119.405"/>
</g>
<g>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
282.713,105.443 250.525,49.478 254.992,47.688 259.459,45.9 291.523,92.558 291.646,101.864 "/>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
284.584,95.337 251.902,50.168 259.891,46.968 291.523,92.558 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="284.361" y1="97.718" x2="283.508" y2="102.33"/>
</g>
<g>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
304.24,96.906 272.055,40.941 276.52,39.151 280.988,37.363 313.053,84.02 313.174,93.328 "/>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
306.113,86.8 273.43,41.631 281.42,38.431 313.053,84.02 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="305.891" y1="89.181" x2="305.035" y2="93.794"/>
</g>
<g>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
325.768,88.369 293.582,32.404 298.049,30.614 302.518,28.825 334.58,75.482 334.703,84.791 "/>
<polygon fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="
327.641,78.262 294.957,33.093 302.947,29.894 334.58,75.482 "/>
<line fill="none" stroke="#241F20" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="327.418" y1="80.644" x2="326.562" y2="85.257"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,14 @@
/* Here is a cheap and bad implementation
* of requestAnimationFrame and
* cancelAnimationFrame mock.
* But it's more than enough
* for our tests.
*/
window.requestAnimFrameStack = [];
window.requestAnimationFrame = function (callback) {
window.requestAnimFrameStack.push(callback);
return true;
};
window.cancelAnimationFrame = function () {
window.requestAnimFrameStack = [];
};

View File

@ -0,0 +1,322 @@
'use strict';
/**
* Unit tests for Pathformer
*
*/
describe('Pathformer', function () {
var svgTag,
svgTagId = 'my-svg',
svgGroupTag,
svgGroupTagId = 'my-svg-group';
beforeEach(function () {
// Remove tag if existing
svgTag = document.getElementById(svgTagId);
if (svgTag) {
svgTag.remove();
}
// Create the SVG
svgTag = document.createElementNS('http://www.w3.org/2000/svg','svg');
svgTag.id = svgTagId;
svgTag.innerHTML = '<circle fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" cx="100" cy="100" r="72.947"/>' +
'<circle fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" cx="100" cy="100" r="39.74"/>' +
'<g id="' + svgGroupTagId + '">' +
'<line fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" x1="34.042" y1="131.189" x2="67.047" y2="77.781"/>' +
'<line fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" x1="165.957" y1="68.809" x2="132.953" y2="122.219"/>' +
'<line fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" x1="131.19" y1="165.957" x2="77.781" y2="132.953"/>' +
'<line fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" x1="68.81" y1="34.042" x2="122.219" y2="67.046"/>' +
'</g>';
svgGroupTag = svgTag.querySelector('#'+svgGroupTagId);
// Insert it to the body
document.body.appendChild(svgTag);
});
describe('[param tests]', function () {
// Tests about the SVG element
it('should throw an error if the SVG is given in parameter', function () {
expect(function () {
new Pathformer();
}).toThrow(new Error('Pathformer [constructor]: "element" parameter is required'));
});
it('should work with only the SVG id', function () {
expect(function () {
new Pathformer(svgTagId);
}).not.toThrow();
});
it('should work with only the SVG object', function () {
expect(function () {
new Pathformer(svgTag);
}).not.toThrow();
});
it('should work with only the SVG group object', function () {
expect(function () {
new Pathformer(svgGroupTag);
}).not.toThrow();
});
it('should throw an error if the SVG ID given is invalid', function () {
expect(function () {
new Pathformer('my-unexisting-svg');
}).toThrow(new Error('Pathformer [constructor]: "element" parameter is not related to an existing ID'));
});
it('should throw an error if the ID given is not related to a SVG element', function () {
var divTag = document.createElement('div');
divTag.id = 'my-div';
document.body.appendChild(divTag);
expect(function () {
new Pathformer('my-div');
}).toThrow(new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement'));
});
it('should throw an error if the element is not a correct type (DOM object or string)', function () {
expect(function () { new Pathformer({}); }).toThrow(new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement'));
expect(function () { new Pathformer(42); }).toThrow(new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement'));
expect(function () { new Pathformer(false); }).toThrow(new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement'));
expect(function () { new Pathformer(new Date()); }).toThrow(new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement'));
expect(function () { new Pathformer(function () {}); }).toThrow(new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement'));
expect(function () { new Pathformer(document.createElement('div')); }).toThrow(new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement'));
});
});
describe('[translation]', function () {
// Line object
describe('line', function () {
it('should return an object with a `d` attribute', function () {
var output = Pathformer.prototype.lineToPath({});
expect(output.d).toBeDefined();
});
it('should return an object with an unclosed shape', function () {
var output = Pathformer.prototype.lineToPath({});
expect(output.d.substr(-1)).not.toEqual('Z');
});
it('should set default positino attributes to zero', function () {
var output = Pathformer.prototype.lineToPath({
x1: '21', x2: '32', y1: '11'
});
expect(output.d.indexOf('0')).not.toEqual(-1);
expect(output.d.indexOf('undefined')).toEqual(-1);
});
});
// Rect object
describe('rect', function () {
it('should return an object with a `d` attribute', function () {
var output = Pathformer.prototype.rectToPath({});
expect(output.d).toBeDefined();
});
it('should return an object with a closed shape', function () {
var output = Pathformer.prototype.rectToPath({});
expect(output.d.substr(-1)).toEqual('Z');
});
it('should set default positino attributes to zero', function () {
var output = Pathformer.prototype.rectToPath({
x: '21', height: '32', width: '11'
});
expect(output.d.indexOf('0')).not.toEqual(-1);
expect(output.d.indexOf('undefined')).toEqual(-1);
});
it('should apply rounded corners', function () {
var result = 'M 50,10 ' +
'L 50,10 A 40,20,0,0,1,90,30 ' +
'L 90,50 A 40,20,0,0,1,50,70 ' +
'L 50,70 A 40,20,0,0,1,10,50 ' +
'L 10,30 A 40,20,0,0,1,50,10';
var output = Pathformer.prototype.rectToPath({
x:10, y:10, width:80, height:60, rx:100, ry:20
});
expect(output.d).toEqual(result);
});
it('should apply rounded corners even when a value is missing', function () {
var result = 'M 30,10 ' +
'L 70,10 A 20,20,0,0,1,90,30 ' +
'L 90,50 A 20,20,0,0,1,70,70 ' +
'L 30,70 A 20,20,0,0,1,10,50 ' +
'L 10,30 A 20,20,0,0,1,30,10';
var output = Pathformer.prototype.rectToPath({
x:10, y:10, width:80, height:60, ry:20
});
expect(output.d).toEqual(result);
});
});
// Polyline object
describe('polyline', function () {
var polyline;
beforeEach(function () {
polyline = {
points: '2,3 4,5 6,7'
};
});
it('should return an object with a `d` attribute', function () {
var output = Pathformer.prototype.polylineToPath(polyline);
expect(output.d).toBeDefined();
});
it('should return an object with an unclosed shape', function () {
var output = Pathformer.prototype.polylineToPath(polyline);
expect(output.d.substr(-1)).not.toEqual('Z');
});
it('should ignore incorrect points', function () {
var output;
polyline.points += ' 43';
output = Pathformer.prototype.polylineToPath(polyline);
expect(output.d.indexOf('43')).toEqual(-1);
});
it('should accept points defined with and without commas', function () {
var outputWithPoint = Pathformer.prototype.polylineToPath(polyline);
var outputWithoutPoint = Pathformer.prototype.polylineToPath({points: '2 3 4 5 6 7'});
expect(outputWithPoint).toEqual(outputWithoutPoint);
});
});
// Polygon object
describe('polygon', function () {
var polygon;
beforeEach(function () {
polygon = {
points: '2,3 4,5 6,7'
};
});
it('should return an object with a `d` attribute', function () {
var output = Pathformer.prototype.polygonToPath(polygon);
expect(output.d).toBeDefined();
});
it('should return an object with a closed shape', function () {
var output = Pathformer.prototype.polygonToPath(polygon);
expect(output.d.substr(-1)).toEqual('Z');
});
});
// Ellipse object
describe('ellipse', function () {
var ellipse;
beforeEach(function () {
ellipse = {
cx: 2,
cy: 3,
rx: 3
};
});
it('should return an object with a `d` attribute', function () {
var output = Pathformer.prototype.ellipseToPath(ellipse);
expect(output.d).toBeDefined();
});
it('should return an object with an unclosed shape', function () {
var output = Pathformer.prototype.ellipseToPath(ellipse);
expect(output.d.substr(-1)).not.toEqual('Z');
});
it('should set default positino attributes to zero', function () {
delete ellipse.cy;
var output = Pathformer.prototype.ellipseToPath(ellipse);
expect(output.d.indexOf('0')).not.toEqual(-1);
expect(output.d.indexOf('undefined')).toEqual(-1);
});
});
// Circle object
describe('circle', function () {
var circle;
beforeEach(function () {
circle = {
cx: 2,
cy: 3,
rx: 3,
r: 1
};
});
it('should return an object with a `d` attribute', function () {
var output = Pathformer.prototype.circleToPath(circle);
expect(output.d).toBeDefined();
});
it('should return an object with an unclosed shape', function () {
var output = Pathformer.prototype.circleToPath(circle);
expect(output.d.substr(-1)).not.toEqual('Z');
});
it('should set default positino attributes to zero', function () {
delete circle.cy;
var output = Pathformer.prototype.circleToPath(circle);
expect(output.d.indexOf('0')).not.toEqual(-1);
expect(output.d.indexOf('undefined')).toEqual(-1);
});
});
});
describe('[utils]', function () {
describe('attribute parser', function () {
it('should return an empty object if attributes length are undefined', function () {
var output = Pathformer.prototype.parseAttr({});
expect(output).toEqual({});
});
});
describe('engine', function () {
it('shouldn\'t throw an error if the SVG got a tag not taken in charge', function () {
svgTag.innerHTML = '<polypentagoneofhell fill="none" stroke="#666666" stroke-width="6" stroke-miterlimit="666" cx="666" cy="666"/>';
expect(function () {
new Pathformer(svgTagId);
}).not.toThrow();
});
it('should remove useless attributes during transformation', function () {
new Pathformer(svgTagId);
expect(svgTag.childNodes[0].getAttribute('cx')).toBe(null);
});
});
describe('validity', function () {
it('should throw error if the SVG contain shape with percentage value', function () {
// Create the SVG
var svgTagPrc = document.createElementNS('http://www.w3.org/2000/svg','svg');
svgTagPrc.innerHTML = '<circle cx="100%" cy="100" r="10"/>';
expect(function () {
new Pathformer(svgTagPrc);
}).toThrow(new Error('Pathformer [parseAttr]: a SVG shape got values in percentage. This cannot be transformed into \'path\' tags. Please use \'viewBox\'.'));
});
it('shouldn\'t throw error if the SVG contain shape with percentage value on a non-data attribute', function () {
// Create the SVG
var svgTagPrc = document.createElementNS('http://www.w3.org/2000/svg','svg');
svgTagPrc.innerHTML = '<circle width="100%" cx="100" cy="100" r="10"/>';
expect(function () {
new Pathformer(svgTagPrc);
}).not.toThrow();
});
});
});
});

View File

@ -0,0 +1,669 @@
'use strict';
/**
* Unit tests for Vivus
*
*/
describe('Vivus', function () {
var ObjectElementMock,
triggerFrames,
myVivus,
objTag,
wrapTag,
svgTag,
svgTagId = 'my-svg',
svgGroupTagId = 'my-svg-group';
// Mock ObjectElement and it's constructor via createElement
ObjectElementMock = function () {
this.loadCb = [];
this.attr = {};
this.addEventListener = function (evtName, cb) {
if (evtName === 'load') {
this.loadCb.push(cb);
}
};
this.loaded = function () {
for (var i = 0; i < this.loadCb.length; i++) {
this.loadCb[i]({target: this});
}
};
this.getBoundingClientRect = function () {
return {
height: 11,
top: 364
};
};
this.insertBefore = function () {};
this.removeChild = function () {};
this.setAttribute = function (key, val) {
this.attr[key] = val;
};
this.getAttribute = function (key) {
return this.attr[key];
};
};
window.HTMLObjectElement = ObjectElementMock;
triggerFrames = function (counter) {
counter = counter || -1;
while (window.requestAnimFrameStack.length && counter !== 0) {
window.requestAnimFrameStack.shift()();
counter--;
}
};
beforeEach(function () {
// Create the SVG
svgTag = document.createElementNS('http://www.w3.org/2000/svg','svg');
svgTag.id = svgTagId;
svgTag.innerHTML = '<circle fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" cx="100" cy="100" r="72.947"/>' +
'<circle fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" cx="100" cy="100" r="39.74"/>' +
'<g id="' + svgGroupTagId + '">' +
'<line fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" x1="34.042" y1="131.189" x2="67.047" y2="77.781"/>' +
'<line fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" x1="165.957" y1="68.809" x2="132.953" y2="122.219"/>' +
'<line fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" x1="131.19" y1="165.957" x2="77.781" y2="132.953"/>' +
'<line fill="none" stroke="#f9f9f9" stroke-width="3" stroke-miterlimit="10" x1="68.81" y1="34.042" x2="122.219" y2="67.046"/>' +
'</g>';
wrapTag = document.createElement('div');
wrapTag.appendChild(svgTag);
document.body.appendChild(wrapTag);
// Reset the request anim frame stack
window.requestAnimFrameStack = [];
});
afterEach(function () {
// Remove tag
svgTag.remove();
wrapTag.remove();
});
describe('[basic tests]', function () {
it('should the class be defined under Vivus name', function () {
expect(Vivus).toBeDefined();
});
it('should have timing functions set', function () {
expect(Vivus.LINEAR).toBeDefined();
expect(Vivus.EASE).toBeDefined();
expect(Vivus.EASE_IN).toBeDefined();
expect(Vivus.EASE_OUT).toBeDefined();
expect(Vivus.EASE_OUT_BOUNCE).toBeDefined();
});
it('should have timing functions returning correct value on limits', function () {
expect(Vivus.LINEAR(0)).toEqual(0);
expect(Vivus.LINEAR(1)).toEqual(1);
expect(Vivus.EASE(0)).toEqual(0);
expect(Vivus.EASE(1)).toEqual(1);
expect(Vivus.EASE_IN(0)).toEqual(0);
expect(Vivus.EASE_IN(1)).toEqual(1);
expect(Vivus.EASE_OUT(0)).toEqual(0);
expect(Vivus.EASE_OUT(1)).toEqual(1);
expect(Vivus.EASE_OUT_BOUNCE(0)).toEqual(0);
expect(Vivus.EASE_OUT_BOUNCE(1)).toEqual(1);
});
});
describe('[param tests]', function () {
// Tests about the SVG element
it('should throw an error if the SVG is given in parameter', function () {
expect(function () {
new Vivus();
}).toThrow(new Error('Vivus [constructor]: "element" parameter is required'));
});
it('should work with only the SVG id', function () {
expect(function () {
new Vivus(svgTagId);
}).not.toThrow();
});
it('should work with only the SVG object', function () {
expect(function () {
new Vivus(svgTag);
}).not.toThrow();
});
it('should work with the SVG group object', function () {
expect(function () {
new Vivus(svgGroupTagId);
}).not.toThrow();
});
it('should throw an error if the SVG ID given is invalid', function () {
expect(function () {
new Vivus('my-unexisting-svg');
}).toThrow(new Error('Vivus [constructor]: "element" parameter is not related to an existing ID'));
});
it('should throw an error if the ID given is not related to a SVG element', function () {
var divTag = document.createElement('div');
divTag.id = 'my-div';
document.body.appendChild(divTag);
expect(function () {
new Vivus('my-div');
}).toThrow(new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)'));
});
it('should accept any DOM element if `file` option is set', function () {
var divTag = document.createElement('div');
spyOn(window, 'XMLHttpRequest');
try {
new Vivus(divTag, {file: 'opensource.svg'});
}
catch(err) {}
expect(window.XMLHttpRequest).toHaveBeenCalled();
});
it('should throw an error if the element is not a correct type (DOM object or string)', function () {
expect(function () { new Vivus({}); }).toThrow(new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)'));
expect(function () { new Vivus(42); }).toThrow(new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)'));
expect(function () { new Vivus(false); }).toThrow(new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)'));
expect(function () { new Vivus(new Date()); }).toThrow(new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)'));
expect(function () { new Vivus(function () {}); }).toThrow(new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)'));
expect(function () { new Vivus(document.createElement('div')); }).toThrow(new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)'));
});
it('should accept object element', function () {
// Create a mock Object getElementById
objTag = new ObjectElementMock();
objTag.contentDocument = wrapTag;
expect(function () {
new Vivus(objTag);
}).not.toThrow();
});
it('the vivus state should be ready if the SVG is already loaded', function () {
objTag = new ObjectElementMock();
objTag.contentDocument = wrapTag;
objTag.loaded();
var myVivus = new Vivus(objTag);
expect(myVivus.isReady).toEqual(true);
});
it('the vivus instance should have `el` and `parentEl` different if the element is an object', function () {
objTag = new ObjectElementMock();
objTag.contentDocument = wrapTag;
objTag.loaded();
var myVivus = new Vivus(objTag);
expect(myVivus.parentEl).not.toEqual(myVivus.el);
});
it('should call `onReady` callback once the SVG is loaded', function () {
objTag = new ObjectElementMock();
objTag.contentDocument = document.createElement('div');
var myVivus = new Vivus(objTag);
objTag.contentDocument = wrapTag;
objTag.loaded();
expect(myVivus.isReady).toEqual(true);
});
it('should throw an error if the SVG file does not exists', function () {
objTag = new ObjectElementMock();
objTag.contentDocument = document.createElement('div');
new Vivus(objTag);
expect(function () {
objTag.loaded();
}).toThrow();
});
// Options
it('should work without options', function () {
expect(function () {
new Vivus(svgTag);
}).not.toThrow();
});
it('should throw an error if options is not an object', function () {
expect(function () { new Vivus(svgTag, []); }).toThrow(new Error('Vivus [constructor]: "options" parameter must be an object'));
expect(function () { new Vivus(svgTag, 42); }).toThrow(new Error('Vivus [constructor]: "options" parameter must be an object'));
expect(function () { new Vivus(svgTag, false); }).toThrow(new Error('Vivus [constructor]: "options" parameter must be an object'));
expect(function () { new Vivus(svgTag, new Date()); }).toThrow(new Error('Vivus [constructor]: "options" parameter must be an object'));
expect(function () { new Vivus(svgTag, 'manual'); }).toThrow(new Error('Vivus [constructor]: "options" parameter must be an object'));
expect(function () { new Vivus(svgTag, function () {}); }).toThrow(new Error('Vivus [constructor]: "options" parameter must be an object'));
});
// Options
it('should work with empty option object', function () {
expect(function () {
new Vivus(svgTag, {});
}).not.toThrow();
});
it('should throw an error if the `type` value given in options does not exists', function () {
expect(function () {
new Vivus(svgTag, {type: 'by-unicorn'});
}).toThrow(new Error('Vivus [constructor]: by-unicorn is not an existing animation `type`'));
});
it('should throw an error if the `start` value given in options is not a string', function () {
expect(function () {
new Vivus(svgTag, {start: 'when-unicorn-ready'});
}).toThrow(new Error('Vivus [constructor]: when-unicorn-ready is not an existing `start` option'));
});
it('should throw an error if the `delay` value is bigger (or equal) than `duration`', function () {
expect(function () {
new Vivus(svgTag, {duration: 200, delay: 199});
}).not.toThrow();
expect(function () {
new Vivus(svgTag, {duration: 200, delay: 200});
}).toThrow(new Error('Vivus [constructor]: delay must be shorter than duration'));
expect(function () {
new Vivus(svgTag, {duration: 200, delay: 201});
}).toThrow(new Error('Vivus [constructor]: delay must be shorter than duration'));
});
it('should override `duration` if invalid', function () {
myVivus = new Vivus(svgTag, {duration: -12});
expect(myVivus.duration > 0).toBe(true);
});
it('should override `delay` if invalid, with a null value', function () {
myVivus = new Vivus(svgTag, {delay: -12});
expect(!myVivus.delay).toBe(false);
});
it('should set up default values', function () {
myVivus = new Vivus(svgTag, {});
expect(myVivus.type).toBeDefined();
expect(myVivus.start).toBeDefined();
expect(myVivus.duration).toBeDefined();
});
it('the vivus instance should have `el` and `parentEl` equal if the element is a SVG object', function () {
myVivus = new Vivus(svgTag, {});
expect(myVivus.el).toEqual(myVivus.parentEl);
});
// Callback
it('should throw an error if callback is non a function', function () {
expect(function () {
new Vivus(svgTag, {}, 42);
}).toThrow(new Error('Vivus [constructor]: "callback" parameter must be a function'));
});
it('should use scale to determine path length when vector effect is non-scaling-stroke', function () {
var scalingSvgTag = document.createElementNS('http://www.w3.org/2000/svg','svg');
var scalingWrapTag = document.createElement('div');
scalingSvgTag.setAttribute('viewBox', '0 0 500 200');
scalingWrapTag.style.width = '1000px';
scalingSvgTag.id = 'scaling-stroke-test';
scalingSvgTag.innerHTML = '<path vector-effect="non-scaling-stroke" fill="none" stroke="#f9f9f9" stroke-width="3" d="M0,68.57346635098205L20.833333333333332,3.8875909891199285L41.666666666666664,47.366000806779425L62.5,57.171841641625065L83.33333333333333"/>' +
'<path fill="none" stroke="#f9f9f9" stroke-width="3" d="M0,68.57346635098205L20.833333333333332,3.8875909891199285L41.666666666666664,47.366000806779425L62.5,57.171841641625065L83.33333333333333"/>';
scalingWrapTag.appendChild(scalingSvgTag);
document.body.appendChild(scalingWrapTag);
myVivus = new Vivus(scalingSvgTag);
expect(myVivus.map.length).toEqual(2);
expect(myVivus.map[0].length).toEqual(280);
expect(myVivus.map[1].length).toEqual(141);
});
});
describe('[engine]', function () {
// Mapping
describe('Mapping:', function () {
it('should not trigger any error if the SVG is empty', function () {
expect(function () {
var svgTag = document.createElementNS('http://www.w3.org/2000/svg','svg');
myVivus = new Vivus(svgTag, {});
}).not.toThrow();
});
it('should create a mapping of the SVG', function () {
myVivus = new Vivus(svgTag, {});
expect(myVivus.map && myVivus.map.length).toEqual(6);
});
it('should map with correct values for start and duration', function () {
var i, typeIndex, types = ['delayed', 'sync', 'oneByOne', 'scenario', 'scenario-sync'];
for (typeIndex in types) {
myVivus = new Vivus(svgTag, {type: types[typeIndex], duration: 200});
for (i in myVivus.map) {
expect(myVivus.map[i].startAt >= 0).toBe(true);
expect(myVivus.map[i].duration >= 0).toBe(true);
}
}
});
// Tests for 'getTotalLength' method in case of awkward results
describe('SVG parsing issue', function () {
var getTotalLengthBkp = SVGPathElement.prototype.getTotalLength,
warnBkp = console.warn;
beforeEach(function () {
SVGPathElement.prototype.getTotalLength = function () {
return NaN;
};
});
afterEach(function () {
SVGPathElement.prototype.getTotalLength = getTotalLengthBkp;
console.warn = warnBkp;
});
it('should call console.warn if a path length is NaN', function () {
var warnSpy = jasmine.createSpy('spy');
console.warn = warnSpy;
myVivus = new Vivus(svgTag);
expect(warnSpy.calls.count()).toEqual(6);
expect(myVivus.map.length).toEqual(0);
});
it('shouldn\'t call console.warn if not defined a path length is NaN', function () {
console.warn = null;
myVivus = new Vivus(svgTag);
expect(myVivus.map.length).toEqual(0);
});
});
});
describe('Visibility checking:', function () {
it('should not accept a path which is not displayed', function () {
// Hide a path
svgTag.childNodes[1].style.display = 'none';
myVivus = new Vivus(svgTag, {ignoreInvisible: true});
expect(myVivus.map.length).toEqual(5);
});
it('should not accept a path which with an ignore tag', function () {
svgTag.childNodes[1].setAttribute('data-ignore', 'true');
myVivus = new Vivus(svgTag);
expect(myVivus.map.length).toEqual(5);
});
it('should not accept a path which is not displayed', function () {
svgTag.childNodes[1].setAttribute('data-ignore', 'false');
myVivus = new Vivus(svgTag);
expect(myVivus.map.length).toEqual(6);
});
});
// Drawing
describe('Drawing:', function () {
it('should call the callback once the animation is finished', function () {
var done = false;
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'autostart'
}, function () {
done = true;
});
triggerFrames();
expect(done).toBe(true);
});
it('should call the callback once the reverse animation is finished', function () {
var done = false;
myVivus = new Vivus(svgTag, {
type: 'oneByOne',
duration: 6
}, function () {
done = true;
});
myVivus.finish().play(-1);
triggerFrames();
expect(done).toBe(true);
});
it('should call the method callback as the second param once the animation is finished', function () {
var done = false;
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'manual',
});
myVivus.play(1, function() {
done = true;
});
triggerFrames();
expect(done).toBe(true);
});
it('should call the method callback as the first param once the animation is finished', function () {
var done = false;
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'manual',
});
myVivus.play(function() {
done = true;
});
triggerFrames();
expect(done).toBe(true);
});
it('should call the method callback once the reverse animation is finished', function () {
var done = false;
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'manual',
});
myVivus.finish().play(-1, function() {
done = true;
});
triggerFrames();
expect(done).toBe(true);
});
it('should call the method callback provided in the last play call', function () {
var done = false;
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'manual',
});
myVivus.finish().play(-1, function () {});
myVivus.play(function() {
done = true;
});
triggerFrames();
expect(done).toBe(true);
});
it('should call destroy method once the animation is finished', function () {
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'manual',
selfDestroy: true
});
myVivus.destroy = jasmine.createSpy('spy');
myVivus.play();
triggerFrames();
expect(myVivus.destroy.calls.count()).toEqual(1);
});
it('should\' call destroy method if selfDestroy option is not present', function () {
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'manual'
});
myVivus.destroy = jasmine.createSpy('spy');
myVivus.play();
triggerFrames();
expect(myVivus.destroy.calls.count()).toEqual(0);
});
it('should stop animation if destroy has been called', function () {
var callbackSpy = jasmine.createSpy('spy');
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'autostart'
}, callbackSpy);
triggerFrames(1);
myVivus.destroy();
triggerFrames();
expect(callbackSpy.calls.count()).toEqual(0);
});
it('should stop the animation once it reaches currentFrame == 0', function () {
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'manual'
});
myVivus.stop = jasmine.createSpy('spy');
myVivus.play(-1);
triggerFrames();
expect(myVivus.stop.calls.count()).toEqual(1);
});
it('should trace reasonably', function () {
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'manual'
});
spyOn(myVivus, 'trace').and.callThrough();
myVivus.play(0.5);
triggerFrames();
expect(myVivus.trace.calls.count()).toEqual(12);
});
it('should start by the last path if reverseStack is enabled', function () {
myVivus = new Vivus(svgTag, {
type: 'oneByOne',
duration: 5,
reverseStack: true
});
myVivus.setFrameProgress(0.5);
var paths = svgTag.querySelectorAll('path');
expect(+paths[0].style.strokeDashoffset).not.toEqual(0);
expect(+paths[paths.length -1].style.strokeDashoffset).toEqual(0);
});
});
describe('Force Render:', function () {
it('should use renderPath if forceRender option is set to true', function () {
myVivus = new Vivus(svgTag, { duration: 2, start: 'manual', forceRender: true });
var originalFirstPath = myVivus.map[0].el;
myVivus.renderPath(0);
expect(myVivus.map[0].el).not.toBe(originalFirstPath);
});
it('should not use renderPath if forceRender option is set to false', function () {
myVivus = new Vivus(svgTag, { duration: 2, start: 'manual', forceRender: false });
var originalFirstPath = myVivus.map[0].el;
myVivus.renderPath(0);
expect(myVivus.map[0].el).toBe(originalFirstPath);
});
it('renderPath should not throw an error if the index doesn\'t exists', function () {
myVivus = new Vivus(svgTag, { duration: 2, start: 'manual', forceRender: true });
expect(function () {
myVivus.renderPath(42);
}).not.toThrow();
});
});
});
describe('[controls]', function () {
beforeEach(function () {
myVivus = new Vivus(svgTag, {
type: 'oneByOne',
duration: 2,
start: 'manual'
});
});
it('shouldn\'t play if the parameter in incorrect', function () {
expect(function () {myVivus.play('a');}).toThrow(new Error('Vivus [play]: invalid speed'));
expect(function () {myVivus.play({});}).toThrow(new Error('Vivus [play]: invalid speed'));
expect(function () {myVivus.play([]);}).toThrow(new Error('Vivus [play]: invalid speed'));
expect(function () {myVivus.play('1');}).toThrow(new Error('Vivus [play]: invalid speed'));
});
it('should return the correct status', function () {
expect(myVivus.getStatus()).toEqual('start');
myVivus.setFrameProgress(0.5);
expect(myVivus.getStatus()).toEqual('progress');
myVivus.finish();
expect(myVivus.getStatus()).toEqual('end');
myVivus.reset();
expect(myVivus.getStatus()).toEqual('start');
});
it('should play with the normal speed by default', function () {
myVivus.play();
expect(myVivus.speed).toEqual(1);
});
it('shouldn\'t run another process of drawing if the animation is in progress', function () {
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'manual'
});
spyOn(myVivus, 'trace').and.callThrough();
myVivus.play(0.5);
myVivus.play(0.5);
triggerFrames();
expect(myVivus.trace.calls.count()).toEqual(12);
});
it('should stop the animation only when the animation is running', function () {
myVivus = new Vivus(svgTag, {
duration: 6,
start: 'manual'
});
myVivus.play();
expect(myVivus.handle).toBeTruthy();
myVivus.stop();
expect(myVivus.handle).toBeFalsy();
myVivus.stop();
expect(myVivus.handle).toBeFalsy();
});
it('should remove all unecessary styling on every path element', function () {
var i, paths;
myVivus.destroy();
paths = svgTag.querySelectorAll('path');
for (i = 0; i < paths.length; i++) {
expect(!!paths[i].style.strokeDashoffset).toEqual(false);
expect(!!paths[i].style.strokeDasharray).toEqual(false);
}
});
/**
* Where are the tests about `util` methods?
* Well....
* to be honest, I've been struggling a bit for these kind of tests
* which seems difficult to test from Karma.
*/
});
});