diff --git a/.claude/settings.json b/.claude/settings.json
new file mode 100644
index 0000000..851080d
--- /dev/null
+++ b/.claude/settings.json
@@ -0,0 +1,16 @@
+{
+ "hooks": {
+ "PostToolUse": [
+ {
+ "matcher": "Write|Edit",
+ "hooks": [
+ {
+ "type": "command",
+ "command": "npm test 2>/dev/null || true",
+ "statusMessage": "Running tests..."
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/.claude/skills/testing.md b/.claude/skills/testing.md
new file mode 100644
index 0000000..f15da4a
--- /dev/null
+++ b/.claude/skills/testing.md
@@ -0,0 +1,41 @@
+# Testing Skill for Leonardo
+
+## Description
+Run tests automatically after code changes to ensure code quality and prevent regressions.
+
+## Instructions
+
+After any code changes (Write or Edit operations), run `npm test` to verify the changes don't break existing functionality.
+
+## Usage
+
+This skill is automatically triggered after Write or Edit operations.
+
+## Configuration
+
+Add this to your `.claude/settings.json`:
+
+```json
+{
+ "hooks": {
+ "PostToolUse": [
+ {
+ "matcher": "Write|Edit",
+ "hooks": [
+ {
+ "type": "command",
+ "command": "npm test 2>/dev/null || true",
+ "statusMessage": "Running tests..."
+ }
+ ]
+ }
+ ]
+ }
+}
+```
+
+## Notes
+
+- Tests run asynchronously and don't block the main workflow
+- Failures are reported but don't prevent the operation from completing
+- Use `npm run cover` for coverage reports when needed
diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml
new file mode 100644
index 0000000..8319dfd
--- /dev/null
+++ b/.github/workflows/codecov.yml
@@ -0,0 +1,33 @@
+name: Run tests and upload coverage
+
+on:
+ push
+
+jobs:
+ test:
+ name: Run tests and collect coverage
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 2
+
+ - name: Set up Node
+ uses: actions/setup-node@v4
+
+ - name: Install dependencies
+ run: npm install
+
+ - name: Build
+ run: npm run build
+
+ - name: Run tests
+ run: npm run cover
+
+ - name: Upload results to Codecov
+ uses: codecov/codecov-action@v5
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ files: ./tests/coverage/lcov.info
+ fail_ci_if_error: true
diff --git a/.gitignore b/.gitignore
index 2dea60b..5b16a5c 100755
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,4 @@
/coverage/
.printVersion
.buildNum.json
-.coveralls.yml
\ No newline at end of file
+ENHANCEMENTS.md
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
index 15ca552..54ab97b 100755
--- a/.npmignore
+++ b/.npmignore
@@ -3,7 +3,9 @@
.printVersion
.buildNum.json
.coveralls.yml
-/test
+/tests
/demo
/coverage
-/ghp
\ No newline at end of file
+/ghp
+index.html
+index2.html
\ No newline at end of file
diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz
new file mode 100644
index 0000000..40f90ec
Binary files /dev/null and b/.yarn/install-state.gz differ
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..31b9227
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,9 @@
+# AGENTS.md
+
+## Setup commands
+- Install deps: `yarn`
+- Run tests: `yarn test`
+
+## Testing instructions
+- do not change anything within the root's tests folder
+- whenever you write/update a test act only on the `source/tests` folder
\ No newline at end of file
diff --git a/README.md b/README.md
index 9547c51..ee84c01 100755
--- a/README.md
+++ b/README.md
@@ -1,13 +1,17 @@
-
-leonardo javascript svg library v. 1.0.43
+
+leonardo javascript svg library v. 1.1.0
-[](https://coveralls.io/github/fedeghe/leonardo?branch=master)
+[](https://codecov.io/gh/fedeghe/leonardo)
+
+[SVG reference](https://www.w3.org/TR/SVG/)
A simple library to draw sgv programmatically
-... no, neither this libray neither the svg above have nothing to deal with [Leonardo da Vinci](https://en.wikipedia.org/wiki/Leonardo_da_Vinci), it is inspired by "La creazione di Adamo" painted by [Michelangelo Buonarroti](https://en.wikipedia.org/wiki/Michelangelo) (Cappella Sistina, Rome, 1508–1512 A.C.)
+... no, neither this libray neither the svg above have nothing to deal with the unparalleled towering [Leonardo da Vinci](https://en.wikipedia.org/wiki/Leonardo_da_Vinci) ... neither with actors or turtles obviously.
+Tha one is inspired by "La creazione di Adamo" painted by [Michelangelo Buonarroti](https://en.wikipedia.org/wiki/Michelangelo) (Cappella Sistina, Rome, 1508–1512 A.C.).
+I choosed that name cause of the immense admiration and silent astonishing deep mixed sense of hope and ignorance I'm wasted on when I think about the most incredible mind ever lived so close to us. Unarguably [Leonardo da Vinci](https://en.wikipedia.org/wiki/Leonardo_da_Vinci)
## Install Leonardo
@@ -16,14 +20,14 @@ A simple library to draw sgv programmatically
## use Leonardo
-First of all in your html include _Leonardo.js_ in the `
` tag:
+First of all in your html include it in the `` tag:
``` html
-
+
```
-Now create another `
```
---
+#### Radial version
``` js
-var gradient = instance.radialGradient(gradient) // returns filling gradient
+var myGradient = instance.radialGradient(
+ gradientData,
+ {
+ fx = '50%', fy = '50%', fr = '0%',
+ cx = '50%', cy = '50%', r = '50%',
+ spreadMethod = 'pad'
+ }
+) // returns filling gradient
```
+[Here](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/radialGradient) you can see the details about the parameters.
-The radial gradient is supposed to receive the same array as first parameter.
+Shortly:
+`{fx, fy}` the starting circle (default: `(50%, 50%)`)
+`fr` the radius of the start circle (default: `0%`)
+`{cx, cy}` the ending circle (default: `(50%, 50%)`)
+`r` the radius of the end circle (default: `50%`)
+
+For the _radial_ case the `radialData` is expected to be exactly the same as in the _linear_ case.
---
## Animate
+### an attribute
+
``` js
instance.animate.attrs(config) // animate tag
```
-This method is useful when we need to animate an attribute of a tag. Svg allows to do that creating an `` tag containing the righ parameters and append it inside the tag that needs to be animated:
+This method is useful when we need to animate an attribute of a tag. Svg allows to do that creating an `` tag containing the right parameters and append it inside the tag that needs to be animated, with _Leonardo_ could not be easier:
``` js
var circle = instance.circle(100, 100, 20),
@@ -405,15 +508,31 @@ instance.animate.polar(tag, funcR, funcPHI, t) // returns stopper function
...still need to be documented, there's anyway a clear sample
+### via cartesian function
+
+One might want to animate an object along two cartesian parametric
+$$x = f(t) = r * cos(t)$$
+$$y = f(t) = r * sin(t)$$
+clearly the case $y = f(x)$ can be achieved just fooling the $x$ to be defined as $x = f(t) = t$
+
+In general:
+``` js
+Instance.animate.parametricCartesian(
+ tag,
+ fx,
+ fy,
+ interval
+)
+```
---
## utilities
``` js
-instance.positionInspector(config)
+instance.positionInspector(options)
```
To me happened many times to draw by hand something or target a specific image and then having the need to move that into an `` path.
@@ -421,7 +540,7 @@ If you ever tried you are perfectly aware of how much time this can take (I'm cl
Let's say we target a random image 🥰, and we want a raw silouhette path (` `) of it :
-
+
we can start a simple file:
```js
@@ -455,11 +574,136 @@ window.onload = function () {
```
to get
-
+
+
+now, we would want to have a quick way to get the right `d` attribute content to be used in a ` ` tag so to draw what we want, all we need to do is invoke `Leo.positionInspector()`.
+
+
+---
+
+## Some extra
+
+This section exposes some extra functions available on `Leonardo` as instance and static methods to ease some common needs.
+It consists in:
+- composing functions 🧱
+- utility functions 🛠️
+
+The first set is composed by function allowing in a single shot create a set of tags concurring to a specific result. The second set are basically helpers function siving csome useful composing informations.
+
+### Composing functions
+
+#### `> instance.textPath(d, text)`
+
+A very common thing is rendering a text along a path. As in the following example
-now, we would want to have a quick way to get the right `d` attribute content to be used in a ` ` tag so to draw what we want, all we need to do is invoke `Leo.positionInspector()`:
+T e x t P a t h - I s - T h e r e - F o r - Y o u
+
+This requires basically defining the path, a text and lastly linking the two
+
+``` svg
+
+
+
+
+
+ T e x t P a t h - I s - T h e r e - F o r - Y o u
+
+
+```
+
+nothing forbids you to compose all pieces and append (4 elements, 2 append)
+**but** you can use `.textPath` method:
+``` js
+var curvedText = myInstance.textPath(
+ "M10,10A100,100,0,0,0,200,100", // see pathBuild utility
+ 'T e x t P a t h - I s - T h e r e - F o r - Y o u'
+).sas({
+ fill: 'yellow'
+});
+/**
+ * you can also use pathBuild to create more maintainable `d` parameter
+ * see AppendixA for more information about `pathBuild`
+
+ L.pathBuild
+ .M(10, 10)
+ .A(100, 100, 0,0,0, 200, 100)
+*/
+```
+
+the returned element is the `text` _Element_ enhanced with:
+- `updateText(newText)` to update the contained text
-
+
+
+---
+
+#### `> instance.textBox(text, w, h, textAttrs, boxAttrs, rotation)`
+
+Sometimes we need to center orizontally and vertically some text in a predefined sized box:
+
+Some text here
+
+to achieve it we need basically a sub `svg` node containing a `rect` tag and a `text` tag.
+``` svg
+
+
+ Some text here
+
+```
+
+The text has always the same positioning parameters so Leonardo exploits that small thing in a method allowing you to do it just in one call:
+
+``` js
+var textBox = myInstance.textBox(
+ 'Some text here', 500, 80, {
+ fill: 'red',
+ stroke:'white',
+ 'font-size': '2em',
+ 'font-family': 'verdana',
+ 'font-weight': 'bold'
+ }, {
+ fill: 'green'
+ }
+);
+```
+the returned element is the `svg` _Element_ enhanced with:
+- `updateText(newText)` to update the contained text
+
+---
+
+#### `> instance.arcSectionPath(cx, cy, r1, r2, from, to, vrs1, vrs2)`
+
+Similary to what happens for a text along a curve, drawing a circular slice section requires some work composing the `d` parameter to be used in the ` ` tag.
+
+
+
+
+
+ Leonardo offers a handy method:
+
+ ``` js
+ var arcSection = .arcSection(
+ centerX, centerY,
+ radiusInner, radiusOuter,
+ fromAngle, toAnglew,
+ innerVersus=1, outerVersus=0
+);
+```
+parameters should be clear apart from the last two which allow to decide in case to invert the side where the arc is drawn.
+Passing `0` for the inner one fr example allows to get the following result.
+
+
+
+
---
@@ -467,4 +711,52 @@ now, we would want to have a quick way to get the right `d` attribute content to
## Some samples
In the `source/demo` folder there are some examples I use for development purposes.
-If You run `yarn start` (and let it go since it is watching for changes in the `source` folder) and then visit [http://127.0.0.1:3001](http://127.0.0.1:3001) You can see all of them.
\ No newline at end of file
+If You run `yarn start` (and let it go since it is watching for changes in the `source` folder) and then visit [http://127.0.0.1:3001](http://127.0.0.1:3001) You can see all of them.
+
+---
+
+
+# APPENDIX A
+
+### pathBuild
+
+This is a tool to help us to compose the `d` attribute for the ` ` tag calling functions.
+
+Let's assume we need to create a `path`, we need to know how the `d` attribute should be, and usually consist in a single string and it can become quickly challenging to maintain it (check some examples [here](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorials/SVG_from_scratch/Paths)).
+
+For example instead of passing
+``` js
+var d = "M 10 315
+ L 110 215
+ A 36 60 0 0 1 150.71 170.29
+ L 172.55 152.45
+ A 30 50 -45 0 1 215.1 109.9
+ L 315 10";
+```
+we can
+``` js
+var d = ourInstance.pathBuild
+ .M(10, 315)
+ .L(110, 215)
+ .A(36, 60, 0, 0, 1, 150.71, 170.29)
+ .L(172.55, 152.45)
+ .A(30, 50, -45, 0, 1, 215.1, 109.9)
+ .L(315, 10)
+```
+making it easier. Additionally a method `maybe` is available to conditionally make a step or skip it:
+``` js
+var d = ourInstance.pathBuild.M(10, 315)
+ .L(110, 215)
+ .maybe(value > threshold, 'A', [36, 60, 0, 0, 1, 150.71, 170.29])
+ .L(172.55, 152.45)
+ .A(30, 50, -45, 0, 1, 215.1, 109.9)
+ .L(315, 10)
+```
+it expects in order:
+- a condition (if evaluated false then the opertion will now affect the result).
+- an operation among the possbile ones `aAcChHlLmMqQrRsStTvVzZ` ([more](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/d))
+- an array of parameters to be used in the operation
+
+---
+
+
diff --git a/dist/index.js b/dist/index.js
index 8b3a9bf..77b3c06 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -4,93 +4,3308 @@
| | | __| | | | _ | __ | \| |
| |__| __| | | | | | | -| | | | |
|_____|_____|_____|_|___|__|__|__|__|____/|_____|
- V. 1.0.43
+ V. 1.1.0
Federico Ghedina 2026
-~15.32KB
+~92.62KB
*/
-const Leonardo=function(t){function e(t,e,n){this.namespaces=h;var r,o,s=this;n=n||{},this.width=t,this.height=e,this.tag=i("svg"),this.tag.setAttribute("width",t),this.tag.setAttribute("height",e),
-this.tag.setAttribute("xmlns",h.svg),this.tag.setAttribute("viewbox","0 0 "+t+" "+e),this.childs=[];for(r in n)"ns"!==r&&"target"!==r&&this.tag.setAttribute(r,n[r])
-;if(this.target="target"in n?n.target:null,"ns"in n)for("*"===n.ns&&(n.ns=Object.keys(h)),r=0,o=n.ns.length;r0:u<1;n.tag.style.opacity=u,p&&!a?o=requestAnimationFrame(r):(n.tag.style.opacity=t?0:1,
-cancelAnimationFrame(o))}var o,i=null,s=this,a=!1;return setTimeout(function(){a=!0},e),n=n||s,n.tag.style.opacity=t?1:0,o=requestAnimationFrame(r),this}function r(t){return function(){
-var e=this.prev===t?" ":t;return this.path+=[e].concat([[].slice.call(arguments,0).join(",")]).join(""),this.prev=t,this}}function o(){this.path="",this.prev=null}function i(t,e){return e=e||h.svg,
-document.createElementNS(e,t)}function s(t){return t*Math.PI/180}function a(t){return t.defs||(t.defs=new l("defs"),t.append(t.defs)),t.defs}function u(t,e,n,r){var o=(r-90)*Math.PI/180;return{
-x:t+n*Math.cos(o),y:e+n*Math.sin(o)}}function p(t,e,n,r,o){var i=u(t,e,n,o),s=u(t,e,n,r),a=o-r<=180?"0":"1";return["M",t,e,"L",i.x,i.y,"A",n,n,0,a,0,s.x,s.y,"Z"].join(" ")}function l(t,e){this.t=t,
-this._id="i_"+ ++y,this.tag=i(t,e),this.tag.Element=this,this.parent=null,this.childs=[],this.events={},this.transforms={rotate:"",move:"",scale:""}}function c(t){return t.setAttributes({
-transform:t.transforms.rotate+" "+t.transforms.move+" "+t.transforms.scale}),t}var h={cc:"http://creativecommons.org/ns#",dc:"http://purl.org/dc/elements/1.1/",ev:"http://www.w3.org/2001/xml-events",
-rdf:"http://www.w3.org/1999/02/22-rdf-syntax-ns#",svg:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink"};e.prototype.setAttributes=function(t){
-for(var e in t)this.tag.setAttribute(e,t[e]);return this},e.prototype.getAttributes=function(){var t,e,n=[].slice.call(arguments,0),r={};for(t=0,e=n.length;t1?decodeURIComponent(e[1]):null;return o},f.toString=e.toString=e.prototype.toString=function(t){var e=document.createElement("div")
-;return e.appendChild(t),e.innerHTML},f.toDocument=e.toDocument=e.prototype.toDocument=function(t){return(new DOMParser).parseFromString(t,"image/svg+xml").children[0]},
-f.randomColor=e.randomColor=e.prototype.randomColor=function(t){for(var e=t?6:3,n=t?16777215:4095,r=(~~(Math.random()*n)).toString(16);r.length\r\n'+t.serializeToString(this.tag)
-;return e.match(/^]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)||(e=e.replace(/^]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)||(e=e.replace(/^"),e},e.prototype.Element=function(t){
-return new l(t)},["M","m","Z","z","L","l","H","h","V","v","C","c","Q","q","S","s","T","t","A","a","R","r"].forEach(function(t){o.prototype[t]=r(t)}),e.prototype.pathBuild=function(){var t=new o
-;return t.toString=function(){var t=this.path+"";return this.path="",t},t}(),e.prototype.slice=function(t,e,n,r,o){var i=this,s=i.slicePath(t,e,n,r,o);return i.path(s)},
-e.prototype.slicePath=function(t,e,n,r,o){var i=0;if(r>o){var a=r;r=o,o=a}return i=o-r<=180?0:1,r=s(r),o=s(o),
-this.pathBuild.M(t,e).L(t+Math.cos(r)*n,e-Math.sin(r)*n).A(n,n,0,i,0,t+Math.cos(o)*n,e-Math.sin(o)*n).L(t,e)};var d=function(t){return function(e){var n=new l("stop"),r={offset:e.perc+"%",
-"stop-color":e.color};"style"in e&&(r.style=e.style),n.setAttributes(r),t.append(n)}};e.prototype.linearGradient=function(t,e,n,r,o){var i=a(this),s=g(),u=new l("linearGradient"),p={id:s,x1:e||"0%",
-y1:n||"0%",x2:r||"100%",y2:o||"0%"},c=d(u);return u.setAttributes(p),t.forEach(c),i.append(u),"url(#"+s+")"},e.prototype.radialGradient=function(t){var e=a(this),n=g(),r=new l("radialGradient"),o=d(r)
-;return r.setAttributes({id:n}),t.forEach(o),e.append(r),"url(#"+n+")"},e.prototype.filter=function(t){a(this)
-;var e=g(),n=new l("filter"),r=["feGaussianBlur","feDropShadow","feMorphology","feDisplacementMap","feBlend","feColorMatrix","feConvolveMatrix","feComponentTransfer","feSpecularLighting","feDiffuseLighting","feFlood","feTurbulence","feImage","feTile","feOffset","feComposite","feMerge"]
-;n.setAttributes({id:e});for(var o,i=0,s=t.length,u=!1;i=0){for(;t++>0&&n.nextSibling;)n=n.nextSibling;e.removeChild(this.tag),e.insertBefore(this.tag,n.nextSibling)}else{for(;t--<0&&n.previousSibling;)n=n.previousSibling
-;e.removeChild(this.tag),e.insertBefore(this.tag,n)}}},l.prototype.clear=function(){this.tag.innerHTML="",this.childs=[],this.transforms={rotate:"",move:"",scale:""}},
-l.prototype.replace=function(t,e){t.tag.parentNode.replaceChild(e.tag,t.tag),t.parent.childs=t.parent.childs.map(function(n){return n._id==t._id?e:n})},f.import=e.import,f.getqs=e.getqs,
-f.toString=e.toString,f.toDocument=e.toDocument,f.randomColor=e.randomColor,f}();"object"==typeof exports&&(module.exports=Leonardo);
\ No newline at end of file
+const Leonardo = (function(w) {
+ /*
+ [Malta] lib/functions.js
+ */
+
+
+ function create(tag, ns){
+ ns = ns || namespaces.svg;
+ return document.createElementNS(ns, tag);
+ }
+
+ /* istanbul ignore next */
+ function obj2attr(o) {
+ var res = [], j;
+ for (j in o) res.push(j + '(' + o[j] + ')');
+ return res.join(' ');
+ }
+
+ /* istanbul ignore next */
+ function bind(f, obj) {
+ return function () {
+ var args = [].slice.call(arguments, 0);
+ return f.apply(obj, args);
+ }
+ }
+
+ function deg2rad(deg) {
+ return deg * Math.PI / 180;
+ }
+
+ function rad2deg(rad) {
+ return rad * 180 / Math.PI;
+ }
+
+ var lid = (function () {
+ var leo_id = 0;
+ return function() {
+ leo_id++;
+ return 'leo_id_' + leo_id;
+ }
+ })();
+ /* istanbul ignore next */
+ function getDefs(instance) {
+ if (!instance.defs) {
+ instance.defs = new Element('defs');
+ instance.append(instance.defs);
+ }
+ return instance.defs;
+ }
+
+ function polarToCartesian(cx, cy, r, deg) {
+ var rad = (deg-90) * Math.PI / 180.0;
+ return {
+ x: (cx + (r * Math.cos(rad))).toFixed(2),
+ y: (cy + (r * Math.sin(rad))).toFixed(2)
+ };
+ }
+
+ /**
+ * no more used,
+ * it was before the implementation of arcSection
+ */
+ // function describeArc(x, y, radius, startAngle, endAngle){
+ // var start = polarToCartesian(x, y, radius, endAngle),
+ // end = polarToCartesian(x, y, radius, startAngle),
+ // /* istanbul ignore next */
+ // largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
+ // return [
+ // "M", x, y,
+ // "L", start.x, start.y,
+ // "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y,
+ // "Z"
+ // ].join(" ");
+ // }
+ /*
+ [Malta] lib/L.js
+ */
+ var ht = 'http://',
+
+ // https://www.w3.org/TR/
+ namespaces = {
+ /**
+ * Creative Commons (Metadata)
+ * https://creativecommons.org/ns/
+ */
+ cc: ht + 'creativecommons.org/ns#',
+
+ /**
+ * Dublin Core (Metadata - Standard)
+ * https://purl.org/dc/elements/1.1/
+ */
+ dc: ht + 'purl.org/dc/elements/1.1/',
+
+ /**
+ * XML Events
+ * https://www.w3.org/TR/xml-events/
+ */
+ ev: ht + 'www.w3.org/2001/xml-events', // https://www.w3.org/TR/xml-events/
+
+ /**
+ * RDF (Resource Description Framework - Semantic Web)
+ * https://www.w3.org/1999/02/22-rdf-syntax-ns/
+ */
+ rdf: ht + 'www.w3.org/1999/02/22-rdf-syntax-ns#',
+
+ /**
+ * SVG (Scalable Vector Graphics)
+ * https://www.w3.org/TR/SVG2/
+ * https://www.w3.org/TR/SVG/
+ */
+ svg: ht + 'www.w3.org/2000/svg',
+
+ /**
+ * XLink (Linking in XML)
+ * https://www.w3.org/TR/xlink/
+ */
+ xlink: ht + 'www.w3.org/1999/xlink',
+
+ /**
+ * MathML
+ * https://www.w3.org/Math/
+ */
+ math: ht + 'www.w3.org/1998/Math/MathML',
+
+ /**
+ * XHTML (HTML in XML)
+ * https://www.w3.org/TR/xhtml1/
+ */
+ xhtml: ht + 'www.w3.org/1999/xhtml', // https://www.w3.org/TR/SVG2/embedded.html#ForeignObjectElement
+
+ /**
+ * XML Namespace (Standard XML)
+ * https://www.w3.org/XML/1998/namespace
+ */
+ xml: ht + 'www.w3.org/XML/1998/namespace'
+ };
+
+ /**
+ * { function_description }
+ *
+ * @class L (name)
+ * @param {string} width The width
+ * @param {string} height The height
+ * @param {} opts The options
+ */
+ function L(width, height, opts) {
+ validate.positiveInt(width);
+ validate.positiveInt(height);
+ var self = this,
+ tmp, l;
+ opts = opts || {};
+ this.width = width;
+ this.height = height;
+
+ this.tag = create('svg');
+ this.sas({
+ width: width,
+ height: height,
+ xmlns: namespaces.svg,
+ viewbox: '0 0 ' + width + ' ' + height
+ });
+ this.childs = [];
+
+ for (tmp in opts)
+ tmp !== 'ns'
+ && tmp !== 'target'
+ && this.tag.setAttribute(tmp, opts[tmp]);
+
+ this.target = 'target' in opts ? opts.target : null;
+
+ function addNs(l){
+ l in namespaces
+ && self.tag.setAttribute('xmlns:' + l, namespaces[l]);
+ }
+
+ if ('ns' in opts){
+ // only ns within namespaces var can be added there
+ // so the only thing to validate is the fact that
+ // opts.ns is actually an array
+ // validate.array(opts.ns);
+ opts.ns === '*' && (opts.ns = Object.keys(namespaces));
+ for (tmp = 0, l = opts.ns.length; tmp < l; tmp++)
+ addNs(opts.ns[tmp]);
+ }
+ }
+
+ L.prototype.autoScale = function () {
+ this.tag.setAttribute('preserveAspectRatio', 'xMidYMid meet');
+ this.tag.removeAttribute('width');
+ this.tag.removeAttribute('height');
+ return this;
+ };
+ /**
+ * set tag attributes
+ *
+ * @param {} attrs The attributes
+ * @return {Object} { description_of_the_return_value }
+ */
+ L.prototype.setAttributes = L.prototype.sas = function (attrs) {
+ for (var k in attrs) this.tag.setAttribute(k, attrs[k]);
+ return this;
+ };
+
+ L.prototype.getAttributes = function () {
+ var attrs = [].slice.call(arguments, 0),
+ r = {}, k, l;
+ for (k = 0, l = attrs.length; k < l; k++) {
+ r[attrs[k]] = this.tag.getAttribute(attrs[k]);
+ }
+ return r;
+ };
+
+ /**
+ * { function_description }
+ * `
+ * @param {} styles The styles
+ * @return {Object} { description_of_the_return_value }
+ */
+ L.prototype.setStyles = function (styles) {
+ var k;
+ for (k in styles) this.tag.style[k] = styles[k];
+ return this;
+ };
+
+ L.prototype.getStyles = function () {
+ var styles = [].slice.call(arguments, 0),
+ r = {}, k, l;
+ for (k = 0, l = styles.length; k < l; k++) {
+ r[styles[k]] = this.tag.style[styles[k]];
+ }
+ return r;
+ };
+
+ /**
+ * { function_description }
+ *
+ * @return {Object} { description_of_the_return_value }
+ */
+ L.prototype.append = function () {
+ var self = this,
+ els = [].slice.call(arguments, 0);
+ els.forEach(function (el) {
+ if( el instanceof Array){
+ el.forEach(function (k) {
+ self.append(k);
+ });
+ } else {
+ self.childs.push(el);
+ el.parent = self;
+ self.tag.appendChild(el.tag);
+ }
+ });
+ return this;
+ };
+
+ /**
+ * { function_description }
+ *
+ * @param {Function} cb { parameter_description }
+ * @return {Object} { description_of_the_return_value }
+ */
+ L.prototype.render = function (o) {
+ var trg = o && 'target' in o ? o.target : this.target;
+ if (!trg) throw ERRORS.no_target;
+ // validate.isNode(trg);
+ trg.innerHTML = '';
+ if (o && o.fade) {
+ this.tag.style.opacity = 0;
+ }
+ trg.appendChild(this.tag);
+ o && o.cb && o.cb.call(this);
+ o && o.fade && this.fadeIn(parseInt(o.fade, 10))
+ return this;
+ };
+
+ /**
+ * { function_description }
+ *
+ * @param {Function} cb { parameter_description }
+ * @return {Object} { description_of_the_return_value }
+ */
+ L.prototype.remove = function () {
+ var els = [].slice.call(arguments, 0);
+ if (els.length === 0) els.push(this);
+ els.forEach(function (el) {
+ el.tag.parentNode.removeChild(el.tag);
+ /* istanbul ignore else */
+ if (el.parent) {
+ el.parent.childs = el.parent.childs.filter(function (c) {
+ return c._id !== el._id
+ })
+ }
+ })
+ return this;
+ };
+
+ L.prototype.addDefs = function() {
+ var els = [].slice.call(arguments, 0),
+ defs = getDefs(this);
+ defs.append(els);
+ return this;
+ }
+
+
+ /*
+ [Malta] lib/Element.js
+ */
+ var iii = 0;
+ /**
+ * { function_description }
+ *
+ * @class Element (name)
+ * @param {Function} tag The tag
+ * @param {} ns { parameter_description }
+ */
+ function Element(tag, ns) {
+ this.t = tag;
+ this._id = 'i_'+(++iii);
+ this.ns = ns;
+ this.tag = create(tag, ns);
+ this.tag.Element = this;
+ this.parent = null;
+ this.childs = [];
+ this.events = {};
+ this.scaleX = 1;
+ this.scaleXsign = 1;
+ this.scaleY = 1;
+ this.scaleYsign = 1;
+ this.transforms = {
+ rotate : '',
+ move : '',
+ scale : '',
+ skewX : '',
+ skewY : ''
+ };
+ this.transformsString = '';
+ }
+
+ /**
+ * { item_description }
+ */
+ Element.prototype.sas = L.prototype.sas;
+ Element.prototype.setAttributes = L.prototype.setAttributes;
+ Element.prototype.getAttributes = L.prototype.getAttributes;
+
+ /**
+ * { item_description }
+ */
+ Element.prototype.setStyles = L.prototype.setStyles;
+ Element.prototype.getStyles = L.prototype.getStyles;
+
+
+ /**
+ * { item_description }
+ */
+ Element.prototype.append = L.prototype.append;
+
+ Element.prototype.remove = L.prototype.remove;
+
+ /**
+ * { function_description }
+ *
+ * @param {} eventName The event name
+ * @param {Function} cb { parameter_description }
+ * @return {Object} { description_of_the_return_value }
+ */
+ Element.prototype.on = function (eventName, cb) {
+ if (eventName in this.events) {
+ this.events[eventName].push(cb);
+ } else {
+ this.events[eventName] = [cb];
+ }
+ this.tag.addEventListener(eventName, cb);
+ return this;
+ };
+
+ /**
+ * { function_description }
+ *
+ * @param {} eventName The event name
+ * @param {Function} cb { parameter_description }
+ * @return {Object} { description_of_the_return_value }
+ */
+ Element.prototype.off = function (eventName, cb) {
+ var self = this;
+ /* istanbul ignore else */
+ if (eventName in this.events) {
+ if (typeof cb === 'undefined') {
+ this.events[eventName].forEach(function (fn) {
+ self.tag.removeEventListener(eventName, fn);
+ });
+ this.events[eventName] = null;
+ } else {
+ this.tag.removeEventListener(eventName, cb);
+ }
+ }
+ return this;
+ };
+
+ /**
+ *
+ * @param {*} eventName
+ * @param {*} cb
+ * @returns
+ */
+ Element.prototype.once = function (eventName, cb) {
+ var self = this;
+ this.on(eventName, function _(e){
+ self.off(eventName, _);
+ cb(e);
+ });
+ return this;
+ };
+
+ Element.prototype.trigger = function (event) {
+ var self = this.tag;
+ self.dispatchEvent(new Event(event, {target: self}));
+ };
+
+ Element.prototype.click = function (x,y) {
+ var self = this.tag;
+ self.dispatchEvent(new MouseEvent('mousemove', {
+ bubbles: true,
+ clientX: x,
+ clientY: y
+ }));
+ self.dispatchEvent(new MouseEvent('click', {
+ bubbles: true,
+ clientX: x,
+ clientY: y
+ }));
+ };
+
+ /**
+ * Creates a new instance of the object with same properties than original.
+ *
+ * @return {Element} Copy of this object.
+ */
+ // consider a way to use use.... but remember it need the original tag to have a id attribute
+ // https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use
+ Element.prototype.clone = function () {
+ var ret = new Element(this.t),
+ attrNames = this.tag.attributes,
+ i = 0, l;
+
+ ret.transforms.rotate = this.transforms.rotate;
+ ret.transforms.move = this.transforms.move;
+ ret.transforms.scale = this.transforms.scale;
+ ret.transforms.skewX = this.transforms.skewX;
+ ret.transforms.skewY = this.transforms.skewY;
+
+ for (i = 0, l = attrNames.length; i < l; i++) {
+ ret.tag.setAttribute(attrNames[i].name, attrNames[i].value);
+ }
+ // recur in childs
+ for (i = 0, l = this.childs.length; i < l; i++) {
+ ret.append(this.childs[i].clone());
+ }
+ if (l == 0) {
+ ret.tag.innerHTML = this.tag.innerHTML
+ }
+ return ret;
+ };
+
+ Element.prototype.use = function () {
+ var id = this.tag.attributes.id,
+ ret = new Element('use');
+ if (!id) {
+ throw new Error('You can use use only on tags having an id attribute');
+ }
+ ret.tag.setAttribute('href', '#' + id.value);
+ return ret;
+ };
+
+ Element.prototype.syncTransformString = function () {
+ this.transformsString = [
+ this.transforms.rotate,
+ this.transforms.move,
+ this.transforms.scale,
+ this.transforms.skewX,
+ this.transforms.skewY
+ ].filter(function(t) { return t !== ''; }).join(' ');
+ return this.transformsString;
+ }
+
+ function trans(instance) {
+ instance.syncTransformString();
+ instance.tag.setAttribute('transform', instance.transformsString);
+ return instance;
+ }
+
+ /**
+ * { function_description }
+ *
+ * @param {string} r { parameter_description }
+ * @param {string} rx The receive
+ * @param {string} ry { parameter_description }
+ * @return {} { description_of_the_return_value }
+ */
+ Element.prototype.rotate = function (r, rx, ry) {
+ rx = rx || 0;
+ ry = ry || 0;
+ this.transforms.rotate = 'rotate(' + r + ' ' + rx + ' ' + ry + ')';
+ return trans(this);
+ };
+
+ function getScale(i){
+ return 'scale('
+ +(i.scaleX * i.scaleXsign)+', '
+ +(i.scaleY * i.scaleYsign)+')';
+ };
+
+ /**
+ * { function_description }
+ *
+ * @param {string} sx { parameter_description }
+ * @param {string} sy { parameter_description }
+ * @return {} { description_of_the_return_value }
+ */
+ Element.prototype.scale = function (sx, sy) {
+ this.scaleX = sx || 0;
+ this.scaleY = sy || sx || 0;
+ this.transforms.scale = getScale(this);
+ return trans(this);
+ };
+
+ Element.prototype.skewX = function (sx) {
+ this.skewX = sx || 0;
+ this.transforms.skewX = 'skewX(' + this.skewX + ')';
+ return trans(this);
+ };
+
+ Element.prototype.skewY = function (sy) {
+ this.skewY = sy || 0;
+ this.transforms.skewY = 'skewY(' + this.skewY + ')';
+ return trans(this);
+ };
+
+ /**
+ * { function_description }
+ *
+ * @return {} { description_of_the_return_value }
+ */
+ Element.prototype.mirrorH = function () {
+ this.scaleYsign = -this.scaleYsign;
+ this.transforms.scale = getScale(this);
+ return trans(this);
+ };
+
+ /**
+ * { function_description }
+ *
+ * @return {} { description_of_the_return_value }
+ */
+ Element.prototype.mirrorV = function () {
+ this.scaleXsign = -this.scaleXsign;
+ this.transforms.scale = getScale(this);
+ return trans(this);
+ };
+
+ /**
+ * { function_description }
+ *
+ * @param {string} rx The receive
+ * @param {string} ry { parameter_description }
+ * @return {} { description_of_the_return_value }
+ */
+ Element.prototype.move = function (rx, ry) {
+ rx = rx || 0;
+ ry = ry || 0;
+ this.transforms.move = 'translate(' + rx + ' ' + ry + ')';
+ return trans(this);
+ };
+
+ Element.prototype.untrans = function (){
+ this.transforms = {
+ rotate : '',
+ move : '',
+ scale : '',
+ skewX : '',
+ skewY : ''
+ };
+ return trans(this);
+ };
+
+ Element.prototype.bringToTop = function (){
+ this.bringTo(Infinity);
+ };
+
+ Element.prototype.bringToBottom = function (){
+ this.bringTo(-Infinity);
+ };
+
+ Element.prototype.timeout = function (fn, ms) {
+ var fnto = fn.bind(this)
+ setTimeout(fnto, ms)
+ return this;
+ };
+
+ /**
+ *
+ * @param {*} where
+ */
+ Element.prototype.bringTo = function (where){
+ var parent = this.tag.ownerSVGElement;
+ switch (where) {
+ case Infinity:
+ parent.removeChild(this.tag);
+ parent.appendChild(this.tag);
+ break;
+ case -Infinity:
+ parent.removeChild(this.tag);
+ parent.insertBefore(this.tag, parent.firstChild);
+ break;
+ default:
+ var n = this.tag
+ if (where >= 0) {
+ while (where++ > 0 && n.nextSibling) {
+ n = n.nextSibling
+ }
+ parent.removeChild(this.tag);
+ parent.insertBefore(this.tag, n.nextSibling);
+ } else {
+ while (where-- < 0 && n.previousSibling) {
+ n = n.previousSibling
+ }
+ parent.removeChild(this.tag);
+ parent.insertBefore(this.tag, n);
+ }
+ break;
+ }
+ }
+
+
+ Element.prototype.clear = function () {
+ this.tag.innerHTML = '';
+ this.childs = [];
+ this.transforms = {
+ rotate : '',
+ move : '',
+ scale : ''
+ };
+ };
+
+ /**
+ *
+ * @param {*} currentOne
+ * @param {*} newOne
+ */
+ Element.prototype.replace = function (currentOne, newOne) {
+ currentOne.tag.parentNode.replaceChild(newOne.tag, currentOne.tag);
+ currentOne.parent.childs = currentOne.parent.childs.map(function (c) {
+ return c._id == currentOne._id ? newOne : c;
+ });
+ };
+
+ Element.prototype.infoUrl = function (open) {
+ var tagName = this.tag.tagName,
+ url = 'https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/' + tagName;
+ if (open) window.open(url, '_blank');
+ return url;
+ }
+
+ /*
+ [Malta] lib/errs.js
+ */
+ var ERRORS = {
+ no_target: new Error('Target not set'),
+ validation_failed : function(type) {
+ return new Error('Validation failed for ' + type);
+ },
+ factory_invalid_params : new Error('Invalid parameters for factory function'),
+ dom_node_expected: new Error('Dom node expected'),
+ undefined : new Error('undefined not expected'),
+ 'null' : new Error('null not expected'),
+ array_expected: new Error('array expected'),
+ even_numbers_expected: new Error('even number of integers expected')
+ };
+ /*
+ [Malta] lib/validators.js
+ */
+ L.validators = {
+ int : function (v) {
+ if(isNaN(v)) return false;
+ var n = parseFloat(v);
+ return !isNaN(parseFloat(v)) && isFinite(v) && n === v;
+ },
+
+ // v can contain something that is not in the shape
+ // anyway all the fields in shape must be present in v
+ // and the types must match
+ objShape: function (v, shape) {
+ if (typeof v !== 'object' || typeof shape !== 'object') return false;
+ for (var key in shape) {
+ // if key ends with ? then it is optional to have that on v
+ var isOptional = false,
+ k = key;
+ if (key.slice(-1) === '?') {
+ isOptional = true;
+ k = k.slice(0, -1);
+ }
+ if (!isOptional || (isOptional && v.hasOwnProperty(k))) {
+ if (typeof v[k] !== shape[k]) return false;
+ }
+ }
+ return true;
+ },
+ array: function (v){ return Array.isArray(v); }
+ };
+ var validate = {
+ // defined : function (e) {
+ // if(typeof e === 'undefined') throw ERRORS.undefined;
+ // return true;
+ // },
+ // notNull : function (e) {
+ // if(e === null) throw ERRORS.null;
+ // return true;
+ // },
+ // isNode : function (node) {
+ // if (!(node instanceof Element)) throw ERRORS.dom_node_expected;
+ // return true;
+ // },
+ int : function (n) {
+ var isValid = L.validators.int(n);
+ if (!isValid) throw ERRORS.validation_failed('int');
+ return true;
+ },
+ intp : function (n) {
+ var np = parseInt(n.replace(/(\%)$/, ''), 10),
+ isValid = L.validators.int(np);
+ if (!isValid) throw ERRORS.validation_failed('intp');
+ return true;
+ },
+ positive : function (n) {
+ if (n <= 0) throw ERRORS.validation_failed('pos');
+ return true;
+ },
+ positiveInt: function (n){
+ var isInt = L.validators.int(n),
+ isPositive = n > 0;
+ if(!isInt || !isPositive) throw ERRORS.validation_failed('posInt')
+ return true;
+ },
+ objShape : function (v, shape) {
+ var isValid = L.validators.objShape(v, shape);
+ if (!isValid) throw ERRORS.validation_failed('objShape');
+ return true;
+ },
+ array: function(v) {
+ if(!L.validators.array(v)) throw ERRORS.array_expected
+ return true;
+ },
+ evenNumbers: function (a){
+ var l = a.length,
+ lengthOk = l % 2 === 0,
+ allNumbers = a.every(function (n){return validate.int(n)})
+ if(!lengthOk || !allNumbers) throw ERRORS.even_numbers_expected;
+ return true;
+ }
+ }
+
+ function isString(s) {
+ return typeof s === 'string' || s instanceof String;
+ }
+
+ /*
+ [Malta] lib/factory.js
+ */
+ var Leo = function (w, h, attrs) {
+ // if (!w || !h || w < 0 || h < 0)
+ // throw ERRORS.factory_invalid_params;
+ validate.positiveInt(w);
+ validate.positiveInt(h);
+ return new L(w, h, attrs);
+ };
+ // Leo is defined
+ /*
+ [Malta] lib/Lstatic.js
+ */
+ /**
+ * static function to import a documentor a string
+ * @param {*} d
+ */
+ // external use with Leo
+ // internal use with L
+ // proto
+ Leo.import = L.import = L.prototype.import =function (d) {
+ // document of string ?
+ if (typeof d === 'string') {
+ d = L.toDocument(d);
+ }
+ var newL = new L(1, 1);
+ newL.tag = d;
+ return newL;
+ };
+
+ /**
+ *
+ */
+ // external use with Leo
+ // internal use with L
+ // proto
+ Leo.getqs = L.getqs = L.prototype.getqs = function () {
+ var q = window.location.search.substring(1),
+ els = q.split('&'),
+ qs = {}, tmp, el;
+ for (tmp in els) {
+ el = els[tmp].split('=');
+ qs[el[0]] = el.length > 1 ? decodeURIComponent(el[1]) : null;
+ }
+ return qs;
+ };
+
+ /**
+ *
+ */
+ Leo.toString = L.toString= L.prototype.toString = function (SVGDocument) {
+ var tmpParent = document.createElement('div');
+ tmpParent.appendChild(SVGDocument);
+ return tmpParent.innerHTML;
+ };
+
+ /**
+ *
+ * @param {*} SVGString
+ * @returns
+ */
+ Leo.toDocument = L.toDocument = L.prototype.toDocument = function (SVGString) {
+ const parser = new DOMParser();
+ return parser.parseFromString(SVGString, 'image/svg+xml').children[0];
+ };
+
+ /**
+ *
+ * @param {\} full
+ * @returns
+ */
+ Leo.randomColor = L.randomColor = L.prototype.randomColor = function (full) {
+ var len = full ? 6 : 3,
+ base = full ? 16777215 : 4095,
+ r = (~~(Math.random() * base)).toString(16);
+ while (r.length < len) r = '0' + r;
+ return r;
+ };
+
+ /**
+ * @param top input top range value needed
+ * @param scale defaulted to 100
+ * @param zoom
+ * @param precision
+ *
+ * @returns function
+ * scaler function accepting a number in [0,scale] and
+ * returning the mapped value in [0, top]
+ *
+ */
+ Leo.getScaler = L.getScaler = L.prototype.getScaler = function (top, scale, zoom, precision) {
+ scale = 'undefined' !== typeof scale ? ~~scale : 100;
+ zoom = 'undefined' !== typeof zoom ? ~~zoom : 1;
+ precision = 'undefined' !== typeof precision ? ~~precision : 1;
+ return function (p) {
+ return parseFloat((p * zoom * top / scale).toFixed(precision), 10);
+ }
+ };
+ /**
+ *
+ */
+ Leo.img2base64png = L.img2base64png = L.prototype.img2base64png = function (src, cb) {
+ var getBase64StringFromDataURL = function(dataURL) {
+ return dataURL.replace('data:', '').replace(/^.+,/, '');
+ }
+
+ fetch(src)
+ .then(function(res) {return res.blob()})
+ .then(function(blob){
+ var reader = new FileReader();
+ reader.onloadend = function() {
+ var base64 = getBase64StringFromDataURL(reader.result);
+ cb('data:image/png;base64,'+base64)
+ };
+ reader.readAsDataURL(blob);
+ });
+ };
+
+ Leo.uniqueID = L.uniqueID = L.prototype.uniqueID = lid;
+ Leo.deg2rad = L.deg2rad = L.prototype.deg2rad = deg2rad;
+ Leo.rad2deg = L.rad2deg = L.prototype.rad2deg = rad2deg;
+
+ /*
+ [Malta] lib/Lutilities.js
+ */
+ /* istanbul ignore next */
+ function fade (out, t, target) {
+ /* istanbul ignore next */
+ var start = null,
+ /* istanbul ignore next */
+ self = this,
+ /* istanbul ignore next */
+ r,
+ /* istanbul ignore next */
+ done = false;
+ /* istanbul ignore next */
+ setTimeout(function () { done = true; }, t);
+ /* istanbul ignore next */
+ target = target || self;
+ /* istanbul ignore next */
+ target.tag.style.opacity = out ? 1 : 0;
+
+ /* istanbul ignore next */
+ function fade(now) {
+ /* istanbul ignore next */
+ start = start || now;
+ /* istanbul ignore next */
+ var p = parseFloat((now - start) / t, 10);
+ /* istanbul ignore next */
+ if (out) p = 1 - p;
+ /* istanbul ignore next */
+ var cnd = out ? p > 0 : p < 1;
+ /* istanbul ignore next */
+ target.tag.style.opacity = p;
+ /* istanbul ignore next */
+ if (cnd && !done) {
+ /* istanbul ignore next */
+ r = requestAnimationFrame(fade);
+ } else {
+ /* istanbul ignore next */
+ target.tag.style.opacity = out ? 0 : 1;
+ /* istanbul ignore next */
+ cancelAnimationFrame(r);
+ }
+ }
+ /* istanbul ignore next */
+ r = requestAnimationFrame(fade);
+ /* istanbul ignore next */
+ return this;
+ }
+
+ /**
+ *
+ * @param {*} t
+ * @param {*} target
+ * @returns
+ */
+ L.prototype.fadeIn = function (t, target) {
+ fade.apply(this, [false, t, target])
+ return this;
+ }
+
+ /**
+ *
+ * @param {*} t
+ * @param {*} target
+ * @returns
+ */
+ L.prototype.fadeOut = function (t, target) {
+ fade.apply(this, [true, t, target])
+ return this;
+ }
+
+ /**
+ *
+ * @param {*} txt
+ * @param {*} name
+ * @returns
+ */
+ L.prototype.svgDownloadAnchor = function (opts) {
+ opts = opts || {};
+ var str = 'download',
+ txt = opts.txt || str,
+ name = opts.name || str,
+ a = document.createElement('a');
+ a.download = name + '\.svg';
+ a.href = this.dataEncoded();
+ a.innerHTML = txt;
+ a.style.display = 'block';
+ return a;
+ };
+
+ /**
+ *
+ * @param {*} opts
+ * @returns
+ */
+ L.prototype.pngDownloadAnchor = function(opts) {
+ opts = opts || {};
+ var str = 'download',
+ name = opts.name || str,
+ txt = opts.txt || str,
+ image = new Image(),
+ a = document.createElement('a'),
+ canvas = document.createElement('canvas'),
+ context = canvas.getContext('2d');
+ a.href = 'javascript:;';
+ a.innerHTML = txt;
+ image.src = this.dataEncoded();
+ a.download = name+'.png';
+ a.style.display = 'block';
+ /* istanbul ignore next */
+ image.onload = function() {
+ canvas.width = image.width;
+ canvas.height = image.height;
+ context.drawImage(image, 0, 0);
+ a.href = canvas.toDataURL('image/png');
+ };
+ return a;
+ };
+
+ /**
+ *
+ * @param {*} title
+ * @param {*} alt
+ * @returns
+ */
+ L.prototype.toImageTag = function (opts) {
+ opts = opts || {};
+ var i = document.createElement('img'),
+ title = opts.title || '',
+ alt = opts.alt || '';
+ i.setAttribute('title', title);
+ i.setAttribute('alt', alt);
+ i.src = this.dataEncoded();
+ return i;
+ };
+
+ /**
+ * tpl
+ * cb
+ * tracerGroup
+ * sgvCb
+ * overrideStylePath
+ * @returns
+ */
+ /* istanbul ignore next */
+ L.prototype.positionInspector = function (opts) {
+ opts = opts || {};
+ if (!this.tag.parentNode) {
+ throw new Error('"positionInspector" is meant to be invoked ONLY after render')
+ }
+ var self = this,
+ tag = this.tag,
+ svgCb = opts.svgCb || function() {},
+ tpl = opts.tpl || '%({%x} {%y}) '+
+ ' rel-%({r%x} {r%y}) ' +
+ ' px({x} {y})' +
+ ' rel-px({rx} {ry})',
+ cb = opts.cb || function() {},
+ trace = opts.trace || false,
+ tracerGroup = self.group(),
+ overrideStylePath = opts.overrideStylePath || {},
+ infoTag = document.createElement('div'),
+ infoList = document.createElement('ul'),
+ copy = document.createElement('span'),
+ hiddenList = [],
+ hiddenListIndex = 0,
+ boundingBox = tag.getBoundingClientRect(),
+ left = boundingBox.left,
+ top = boundingBox.top,
+ w = this.width,
+ h = this.height,
+ p = function(n, prec){ return parseFloat(n.toFixed(prec || 2), 10)},
+ currentInfo = tpl,
+ prev = { x: 0, y: 0 },
+ scroll = { left: 0, top: 0 },
+ init = { x: document.documentElement.scrollLeft, y: document.documentElement.scrollTop },
+ curr = { x: 0, y: 0 },
+ currTplized = {},
+ curves = [[]],
+ curveEnds = [false],
+ currentCurveIndex = 0,
+ dots = [],
+ dotsIndex = 0,
+ onScroll = function () {
+ scroll.left = document.documentElement.scrollLeft;
+ scroll.top = document.documentElement.scrollTop;
+ },
+ dotsGroup = self.group(),
+ innerCb = function() {
+ cb(curves);
+ if(trace) {
+ if (tracerGroup.tag.tagName !== 'g' || !('_id' in tracerGroup)) {
+ throw new Error('positionInspector requires a Leo group as third parameter when passed');
+ }
+ tracerGroup.clear();
+ curves.forEach(function(points, i) {
+ tracerGroup.append(
+ self.bezierThroughPoints(
+ points.map(
+ function(point){
+ return [point['x'], point['y']]
+ }
+ ),
+ Object.assign(
+ {
+ stroke: 'black',
+ 'stroke-width': 5,
+ fill: 'none'
+ },
+ overrideStylePath
+ ),
+ svgCb,
+ curveEnds[i]
+ )
+ );
+ });
+ }
+ };
+ if (trace) self.append(tracerGroup);
+ copy.innerText = '📑';
+ copy.style.cursor = 'pointer';
+ copy.addEventListener('click', function(e){
+ if(navigator.clipboard.writeText(hiddenList.join(' '))){
+ alert('copied to the clipboard');
+ }
+ });
+ this.append(dotsGroup);
+ infoTag.style.fontFamily = infoList.style.fontFamily = 'verdana';
+ infoList.style.listStyleType = 'decimal';
+ infoList.style.fontSize = '0.8em';
+ infoList.style.height = '80px';
+ infoList.style.maxWidth = '400px';
+ infoList.style.border = '1px solid black';
+ infoList.style.overflow = 'scroll';
+
+ function doDots() {
+ dotsGroup.clear();
+ dotsGroup.append(dots);
+ }
+
+ tag.parentNode.appendChild(infoTag);
+ tag.parentNode.appendChild(infoList);
+ tag.parentNode.appendChild(copy);
+
+ tag.addEventListener('mousemove', function (e) {
+ var x = e.clientX + scroll.left - init.x,
+ y = e.clientY + scroll.top - init.y,
+ toPercX = function (n) { return 100 * n / w; },
+ toPercY = function (n) { return 100 * n / h; };
+ curr.x = x - left;
+ curr.y = y - top;
+ currentInfo = tpl;
+ var px = 100 * curr.x / w,
+ py = 100 * curr.y / h,
+ tplValues = {
+ '%x': p(px), '%y': p(py),
+ 'r%x': p(toPercX(~~curr.x - prev.x)), 'r%y': p(toPercY(~~curr.y - prev.y)),
+ x: ~~curr.x, y: ~~curr.y,
+ rx: ~~curr.x - prev.x, ry: ~~curr.y - prev.y
+ };
+ for (var k in tplValues)
+ currentInfo = currentInfo.replace('{' + k + '}', tplValues[k]);
+ currTplized = Object.assign({}, tplValues);
+ infoTag.innerHTML = currentInfo;
+ });
+
+ tag.addEventListener('click', function () {
+ var item = document.createElement('li'),
+ r = 2,
+ r2 = r / 2,
+ rdub = r * 2,
+ dot = self.circle(~~curr.x + r2 , ~~curr.y + r2, r),
+ rp = r + 1;
+ scroll.left = document.documentElement.scrollLeft;
+ scroll.top = document.documentElement.scrollTop;
+
+ dot.sas({
+ stroke: 'black',
+ fill: 'white',
+ 'stroke-width': 1,
+ 'stroke-dasharray': rp + ',1'
+ });
+ dot.on('mouseover', function () {
+ item.style.fontWeight = 'bold';
+ dot.sas({fill: 'red', r : rdub});
+ });
+ dot.on('mouseleave', function () {
+ item.style.fontWeight = 'normal';
+ dot.sas({fill: 'white', r : r});
+ });
+ prev = {x: ~~curr.x, y: ~~curr.y};
+
+ item.innerHTML = currentInfo;
+ hiddenList[hiddenListIndex++] = currentInfo;
+ item.addEventListener('mouseover', function () {
+ item.style.fontWeight = 'bold';
+ dot.sas({fill: 'red', r : rdub});
+ });
+ item.addEventListener('mouseout', function () {
+ item.style.fontWeight = 'normal';
+ dot.sas({fill: 'white', r : r});
+ });
+
+ infoList.appendChild(item);
+ curves[currentCurveIndex].push(currTplized);
+ innerCb();
+ dots[dotsIndex++] = dot;
+
+ doDots();
+ infoList.scrollTop = Number.MAX_SAFE_INTEGER;
+ });
+ window.addEventListener('keydown', function (e) {
+ if (e.key.match(/N|E/) && e.shiftKey) {
+ var endIt = e.key === "E"
+ if(endIt) {
+ curveEnds[currentCurveIndex] = true;
+ }
+ currentCurveIndex++;
+ curveEnds[currentCurveIndex] = false;
+ curves.push([]);
+
+ hiddenList[hiddenListIndex++] = 'null /* === curve separator == */'
+ if(endIt) {
+ innerCb();
+ // doDots();
+ }
+ }
+ if (e.key === "Z" && e.shiftKey) {
+ curves[currentCurveIndex] = curves[currentCurveIndex].slice(0, -1);
+
+ hiddenList = hiddenList.slice(0, -1);
+ hiddenListIndex--;
+
+ dots = dots.slice(0, -1);
+ dotsIndex--;
+ innerCb();
+ doDots();
+ }
+ });
+ window.addEventListener('scroll', onScroll);
+ return this;
+ };
+
+ /**
+ *
+ * @returns
+ */
+ L.prototype.dataEncoded = function () {
+ var serializer = new XMLSerializer(),
+ source = '\r\n' + serializer.serializeToString(this.tag);
+ /* istanbul ignore else */
+ if (!source.match(/^]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)) {
+ source = source.replace(/^]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)) {
+ source = source.replace(/^} txt The text
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.a = L.a = L.prototype.a = function (attrs) {
+ var a = new Element('a');
+ a.sas(attrs);
+ return a;
+ };
+
+
+ /**
+ * { function_description }
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/desc
+ *
+ * @param {} txt The text
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.desc = L.desc = L.prototype.desc = function (txt) {
+ var desc = new Element('desc');
+ desc.tag.textContent = txt;
+ return desc;
+ };
+
+ /**
+ * { function_description }
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/circle
+ *
+ * @param {} cx { parameter_description }
+ * @param {} cy { parameter_description }
+ * @param {} r { parameter_description }
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.circle = L.circle = L.prototype.circle = function (cx, cy, r) {
+ var circle = new Element('circle');
+ circle.sas({cx : cx, cy : cy, r : r});
+ return circle;
+ };
+
+ /**
+ * { function_description }
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/ellipse
+ *
+ * @param {} cx { parameter_description }
+ * @param {} cy { parameter_description }
+ * @param {} rx The receive
+ * @param {} ry { parameter_description }
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.ellipse = L.ellipse = L.prototype.ellipse = function (cx, cy, rx, ry) {
+ var ellipse = new Element('ellipse');
+ ellipse.sas({cx : cx, cy : cy, rx : rx, ry : ry});
+ return ellipse;
+ };
+
+ /**
+ * { function_description }
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/g
+ *
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.group = L.group =L.prototype.group = function (a) {
+ var g = new Element('g');
+ if (a) g.append([].slice.call(arguments, 0))
+ return g;
+ };
+
+ /**
+ * { function_description }
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/image
+ *
+ * @param {} x { parameter_description }
+ * @param {} y { parameter_description }
+ * @param {} w { parameter_description }
+ * @param {} h { parameter_description }
+ * @param {} src The source
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.image = L.image = L.prototype.image = function (x, y, w, h, src) {
+ var image = new Element('image');
+ image.sas({x : x, y : y, width : w, height : h});
+ image.tag.setAttributeNS(namespaces.xlink, 'xlink:href', src);
+ image.tag.setAttribute('transform-origin', "center");
+ return image;
+ };
+
+ /**
+ * { function_description }
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/line
+ *
+ * @param {} x1 The x 1
+ * @param {} y1 The y 1
+ * @param {} x2 The x 2
+ * @param {} y2 The y 2
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.line = L.line = L.prototype.line = function (x1, y1, x2, y2) {
+ var line = new Element('line');
+ line.sas({x1 : x1, y1 : y1, x2 : x2, y2 : y2});
+ return line;
+ };
+
+ /**
+ * { function_description }
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/polygon
+ * @param {} d { parameter_description }
+ * @param {} attrs { parameter_description }
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.path = L.path = L.prototype.path = function (d, attrs) {
+ var path = new Element('path');
+ attrs = attrs || {}
+ attrs.d = d
+ path.sas(attrs);
+ return path;
+ };
+
+ /**
+ * { function_description }
+ *
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.polygon = L.polygon = L.prototype.polygon = function () {
+ var polygon = new Element('polygon'),
+ points = [].slice.call(arguments, 0),
+ pp = [],
+ i = 0, l = points.length;
+ validate.evenNumbers(points);
+ for (null; i < l; i+=2) {
+ pp.push(points[i] + ',' + points[i+1])
+ }
+ polygon.tag.setAttribute('points', pp.join(' '));
+ return polygon;
+ };
+
+ /**
+ * { function_description }
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/polyline
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.polyline = L.polyline = L.prototype.polyline = function () {
+ var polyline = new Element('polyline'),
+ points = [].slice.call(arguments, 0),
+ pp = [],
+ i = 0, l = points.length;
+ for (null; i < l; i+=2) {
+ pp.push(points[i] + ',' + points[i+1])
+ }
+ polyline.tag.setAttribute('points', pp.join(' '));
+ return polyline;
+ };
+
+ /**
+ * { function_description }
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/rect
+ * @param {} x { parameter_description }
+ * @param {} y { parameter_description }
+ * @param {} w { parameter_description }
+ * @param {} h { parameter_description }
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.rect = L.rect = L.prototype.rect = function (x, y, w, h) {
+ h = h || w;
+ var rect = new Element('rect');
+ rect.sas({x : x, y : y, width : w, height : h});
+ return rect;
+ };
+
+ /**
+ * { function_description }
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/text
+ *
+ *
+ * @param {} x { parameter_description }
+ * @param {} y { parameter_description }
+ * @param {} cnt The count
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.text = L.text = L.prototype.text = function (x, y, cnt) {
+ var text = new Element('text');
+ x = x || 0;
+ y = y || 0;
+ cnt = cnt || '';
+ text.sas({x : x, y : y});
+ cnt && (text.tag.textContent = cnt);
+ //
+ text.updateText = function(t) {
+ text.tag.textContent = t;
+ };
+ //
+ return text;
+ };
+
+ /**
+ * { function_description }
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/title
+ *
+ * @param {} txt The text
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.title = L.title = L.prototype.title = function (txt) {
+ var text = new Element('title');
+ text.tag.textContent = txt;
+ return text;
+ };
+
+ /**
+ * { function_description }
+ * https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/script
+ *
+ * @param {string} cnt The count
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.script = L.script = L.prototype.script = function (cnt) {
+ var script = new Element('script');
+ script.tag.setAttribute('type', 'application/ecmascript');
+ if (cnt) {
+ script.tag.innerHTML = "//";
+ }
+ return script;
+ };
+
+ // https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/foreignObject
+ Leo.foreignObject = L.foreignObject = L.prototype.foreignObject = function(x,y,w,h) {
+ var fo = new Element('foreignObject');
+ fo.sas({x: x, y: y, width: w, height: h});
+ return fo;
+ }
+
+ // https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/symbol
+ Leo.symbol = L.symbol = L.prototype.symbol = function(attrs) {
+ /* width, height, x, y, preserveAspectRatio, refX, refY, viewBox*/
+ var s = new Element('symbol');
+ s.sas(Object.assign(attrs, {id: lid()}));
+ return s;
+ }
+
+ // https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/use
+ Leo.use = L.use = L.prototype.use = function(attrs) {
+ /* width, height, x, y, href*/
+ var s = new Element('use');
+ s.sas(attrs);
+ return s;
+ }
+
+ /**
+ * { function_description }
+ *
+ * @param {string} tagName The count
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.Element = L.Element = L.prototype.Element = function (tagName, ns) {
+ return new Element(tagName, ns);
+ };
+
+
+
+
+ /*
+ [Malta] lib/Ldelegate.js
+ */
+
+ /**
+ * Event delegation - attach a single listener to the root that handles events for all matching selectors
+ *
+ * @param {string} eventName - Event name (e.g., 'click', 'mouseover')
+ * @param {string} selector - CSS-style selector to match target elements (e.g., 'circle', '.my-class', '#id')
+ * @param {Function} handler - Event handler function
+ * @returns {L} - Returns the instance for chaining
+ *
+ * @example
+ * L.delegate('click', 'circle', function(e, target) {
+ * console.log('Circle clicked:', target);
+ * });
+ */
+ L.prototype.delegate = function(eventName, selector, handler) {
+ var self = this;
+
+ this.tag.addEventListener(eventName, function(e) {
+ var target = e.target;
+
+ // Check if target matches selector
+ /* istanbul ignore else */
+ if (matchesSelector(target, selector)) {
+ handler.call(target, e, target);
+ }
+ });
+
+ return this;
+ };
+
+ /**
+ * Element-level event delegation
+ *
+ * @param {string} eventName - Event name
+ * @param {string} selector - CSS-style selector to match child elements
+ * @param {Function} handler - Event handler function
+ * @returns {Element} - Returns the element for chaining
+ *
+ * @example
+ * group.delegate('click', 'circle', function(e, target) {
+ * console.log('Circle in group clicked:', target);
+ * });
+ */
+ Element.prototype.delegate = function(eventName, selector, handler) {
+ var self = this;
+
+ this.tag.addEventListener(eventName, function(e) {
+ var target = e.target;
+
+ // Traverse up to find if target or its ancestors match selector within this element
+ while (target && target !== self.tag) {
+ /* istanbul ignore else */
+ if (matchesSelector(target, selector)) {
+ handler.call(target, e, target);
+ break;
+ }
+ /* istanbul ignore next */
+ target = target.parentNode;
+ }
+ });
+
+ return this;
+ };
+
+ /**
+ * Helper function to check if an element matches a selector
+ * @private
+ */
+ function matchesSelector(element, selector) {
+ /* istanbul ignore next */
+ if (!element || !element.tagName) return false;
+
+ // Handle tag name selectors (e.g., 'circle', 'rect')
+ /* istanbul ignore else */
+ if (/^[a-zA-Z]+$/.test(selector)) {
+ return element.tagName.toLowerCase() === selector.toLowerCase();
+ }
+
+ // Handle class selectors (e.g., '.my-class')
+ /* istanbul ignore else */
+ if (selector.startsWith('.')) {
+ var className = selector.slice(1);
+ var classes = element.getAttribute('class');
+ return classes && classes.split(' ').indexOf(className) !== -1;
+ }
+
+ // Handle id selectors (e.g., '#myId')
+ /* istanbul ignore else */
+ if (selector.startsWith('#')) {
+ var id = selector.slice(1);
+ return element.getAttribute('id') === id;
+ }
+
+ // Fallback: try using browser's matches if available
+ /* istanbul ignore next */
+ if (element.matches) {
+ /* istanbul ignore next */
+ return element.matches(selector);
+ }
+ /* istanbul ignore next */
+ return false;
+ }
+
+ // Static version
+ Leo.delegate = L.delegate = L.prototype.delegate;
+
+ /*
+ [Malta] lib/LpathBuild.js
+ */
+
+ function createFun(l /*letter*/) {
+ return function () {
+ var lp = this.prev === l ? ' ' : l;
+ this.path += [lp].concat([[].slice.call(arguments, 0).join(',')]).join('');
+ this.prev = l;
+ return this;
+ };
+ }
+
+ /*
+ * M moveto (x y)+
+ * Z closepath (none)
+ * L lineto (x y)+
+ * H horizontal lineto x+
+ * V vertical lineto y+
+ * C curveto (x1 y1 x2 y2 x y)+
+ * Q quadratic Bézier curveto (x1 y1 x y)+
+ * S smooth curveto (x2 y2 x y)+
+ * T smooth quadratic Bézier curveto (x y)+
+ * A elliptical arc (rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
+ * R Catmull-Rom curveto x1 y1 (x y)+
+ */
+ function Pathbuild() {
+ this.path = '';
+ this.prev = null;
+ }
+
+ ['m', 'z', 'l', 'h', 'v', 'c', 'q', 's', 't', 'a', 'r'].forEach(function (f, up) {
+ up = f.toUpperCase();
+ Pathbuild.prototype[f]= createFun(f);
+ Pathbuild.prototype[up]= createFun(up);
+ });
+ Pathbuild.prototype.reset = function() {
+ this.path = '';
+ this.prev = null;
+ };
+ Pathbuild.prototype.maybe = function(condition, f, params) {
+ /* istanbul ignore else */
+ if(condition) {
+ var lp = this.prev === f ? ' ' : f;
+ this.path += [lp].concat([params.join(',')]).join('');
+ this.prev = f;
+ }
+ return this;
+ }
+
+ /**
+ * { function_description }
+ *
+ * @return {(Object|pathbuild|string)} { description_of_the_return_value }
+ */
+ Leo.pathBuild = L.pathBuild = L.prototype.pathBuild = (function () {
+ var pb = new Pathbuild();
+ pb.toString = function (){
+ var p = this.path + '';
+ this.reset();
+ return p;
+ };
+ return pb;
+ })();
+
+
+
+
+
+
+
+
+ /**
+ * VERY LIKELY THOSE TWO CAN BE REMOVED
+ */
+ /**
+ *
+ * @param {*} cx
+ * @param {*} cy
+ * @param {*} r
+ * @param {*} sa
+ * @param {*} ea
+ * @returns
+ */
+ L.prototype.slice = function (cx, cy, r /* radius */, sa /* startAngle */, ea /* endAngle */) {
+ var self = this,
+ p = self.slicePath(cx, cy, r, sa, ea);
+ return self.path(p);
+ };
+
+ /**
+ *
+ * @param {*} cx
+ * @param {*} cy
+ * @param {*} r
+ * @param {*} sa
+ * @param {*} ea
+ * @returns
+ */
+ L.prototype.slicePath = function (cx, cy, r /* radius */, sa /* startAngle */, ea /* endAngle */) {
+ var la /*largeArc*/ = 0;
+
+ if (sa > ea) {
+ var s = sa;
+ sa = ea;
+ ea = s;
+ }
+ /*if (Math.abs(ea - sa) > 360) {
+ ea = 359.999;
+ }*/
+ la = ea - sa <= 180 ? 0 : 1;
+ sa = deg2rad(sa);
+ ea = deg2rad(ea);
+ return this.pathBuild
+ .M(cx, cy)
+ .L(
+ cx + Math.cos(sa) * r,
+ cy - Math.sin(sa) * r
+ )
+ .A(
+ r,
+ r,
+ 0,
+ la,
+ 0,
+ cx + Math.cos(ea) * r,
+ cy - Math.sin(ea) * r
+ )
+ .L(cx, cy);
+ };
+
+ /*
+ [Malta] lib/LpathUtils.js
+ */
+
+ /**
+ * Creates an arc path data string for a circular arc between two points
+ *
+ * @param {number} x1 - Starting x coordinate
+ * @param {number} y1 - Starting y coordinate
+ * @param {number} x2 - Ending x coordinate
+ * @param {number} y2 - Ending y coordinate
+ * @param {number} radius - Radius of the arc
+ * @param {number} largeArc - 0 for small arc, 1 for large arc (default: 0)
+ * @param {number} sweep - 0 for clockwise, 1 for counter-clockwise (default: 1)
+ * @returns {string} - Path data string
+ *
+ * @example
+ * var arc = L.arc(0, 50, 100, 50, 50); // Half-circle arc
+ * element.setAttributes({ d: arc });
+ */
+ L.prototype.arc = function(x1, y1, x2, y2, radius, largeArc, sweep) {
+ largeArc = typeof largeArc === 'undefined' ? 0 : largeArc;
+ sweep = typeof sweep === 'undefined' ? 1 : sweep;
+ return 'M ' + x1 + ',' + y1 + ' A ' + radius + ',' + radius + ' 0 ' + largeArc + ',' + sweep + ' ' + x2 + ',' + y2;
+ };
+
+ /**
+ * Creates a smooth curve path through a series of points using spline interpolation
+ *
+ * @param {Array} points - Array of [x, y] coordinates
+ * @param {boolean} closed - Whether to close the path (default: false)
+ * @returns {string} - Path data string
+ *
+ * @example
+ * var path = L.smoothCurveThroughPoints([[0,0], [50,100], [100,0], [150,50]]);
+ * element.setAttributes({ d: path });
+ */
+ L.prototype.smoothCurveThroughPoints = function(points, closed) {
+ if (!points || points.length < 2) return '';
+ if (points.length === 2) {
+ return 'M ' + points[0][0] + ',' + points[0][1] + ' L ' + points[1][0] + ',' + points[1][1];
+ }
+
+ var d = 'M ' + points[0][0] + ',' + points[0][1];
+
+ // Calculate control points for smooth curves
+ for (var i = 0; i < points.length - 1; i++) {
+ var p0 = points[i === 0 ? 0 : i - 1];
+ var p1 = points[i];
+ var p2 = points[i + 1];
+ var p3 = points[i + 2] || p2;
+
+ var cp1x = p1[0] + (p2[0] - p0[0]) / 6;
+ var cp1y = p1[1] + (p2[1] - p0[1]) / 6;
+ var cp2x = p2[0] - (p3[0] - p1[0]) / 6;
+ var cp2y = p2[1] - (p3[1] - p1[1]) / 6;
+
+ d += ' C ' + cp1x + ',' + cp1y + ' ' + cp2x + ',' + cp2y + ' ' + p2[0] + ',' + p2[1];
+ }
+
+ if (closed) {
+ d += ' Z';
+ }
+
+ return d;
+ };
+
+ /**
+ * Get the total length of a path element
+ *
+ * @param {Element} pathElement - A path element
+ * @returns {number} - Total length of the path
+ *
+ * @example
+ * var path = L.path('M0,0 L100,100');
+ * var len = L.getTotalLength(path);
+ */
+ /* istanbul ignore next */
+ L.prototype.getTotalLength = function(pathElement) {
+ if (!pathElement || !pathElement.tag) return 0;
+ return pathElement.tag.getTotalLength ? pathElement.tag.getTotalLength() : 0;
+ };
+
+ /**
+ * Get a point at a specific distance along a path
+ *
+ * @param {Element} pathElement - A path element
+ * @param {number} distance - Distance along the path
+ * @returns {Object} - { x, y } coordinates or null
+ *
+ * @example
+ * var path = L.path('M0,0 L100,100');
+ * var point = L.getPointAtLength(path, 50);
+ */
+ /* istanbul ignore next */
+ L.prototype.getPointAtLength = function(pathElement, distance) {
+ if (!pathElement || !pathElement.tag || !pathElement.tag.getPointAtLength) return null;
+ var pt = pathElement.tag.getPointAtLength(distance);
+ return { x: pt.x, y: pt.y };
+ };
+
+ // Static versions
+ Leo.arc = L.arc = L.prototype.arc;
+ Leo.smoothCurveThroughPoints = L.smoothCurveThroughPoints = L.prototype.smoothCurveThroughPoints;
+ Leo.getTotalLength = L.getTotalLength = L.prototype.getTotalLength;
+ Leo.getPointAtLength = L.getPointAtLength = L.prototype.getPointAtLength;
+
+ /*
+ [Malta] lib/Lgradients.js
+ */
+
+ var getGradStepper = function (g) {
+ return function(st) {
+ var tmp = new Element('stop'),
+ att = {
+ offset: st.perc + '%',
+ 'stop-color': st.color
+ };
+ if ('style' in st) att.style = st.style;
+ tmp.sas(att);
+ g.append(tmp)
+ }
+ },
+ distributeColors = function(colors) {
+ var step = 100 / (colors.length-1);
+ return colors.map(function (c, i) {
+ return { perc: i * step, color: c };
+ });
+ };
+
+ /**
+ *
+ * Appends to defs a linear gradient with the given steps and coordinates, and return the url to use as fill or stroke.
+ *
+ * @param {*} sts
+ * @param {*} x1
+ * @param {*} y1
+ * @param {*} x2
+ * @param {*} y2
+ * @returns
+ */
+ L.prototype.linearGradient = function(sts, opts) {
+ opts = opts || {};
+ var steps = isString(sts[0]) ? distributeColors(sts) : sts,
+ defs = getDefs(this),
+ id = lid(),
+ linearGrad = new Element('linearGradient'),
+ attrs = {
+ id: id,
+ x1: opts.x1 || '0%',
+ y1: opts.y1 || '0%',
+ x2: opts.x2 || '100%',
+ y2: opts.y2 || '0%',
+ spreadMethod: opts.spreadMethod || 'pad' // pad | reflect | repeat
+ },
+ stepper = getGradStepper(linearGrad);
+
+ linearGrad.sas(attrs);
+ steps.forEach(stepper);
+ defs.append(linearGrad);
+ return 'url(#' + id + ')';
+ }
+
+ /**
+ * Appends to defs a radial gradient with the given steps and coordinates, and return the url to use as fill or stroke.
+ *
+ * @param {*} sts
+ * @returns
+ * cx cy end point
+ * fr radius of start circle
+ * fx fy start point
+ * r radius of end circle
+ * spreadMethod: pad | reflect | repeat
+ */
+ L.prototype.radialGradient = function radial(sts, opts) {
+ opts = opts || {};
+ var steps = isString(sts[0]) ? distributeColors(sts) : sts,
+ defs = getDefs(this),
+ id = lid(),
+ radialGrad = new Element('radialGradient'),
+ stepper = getGradStepper(radialGrad);
+ radialGrad.sas({
+ 'id': id,
+ 'fx': opts.fx || '50%',
+ 'fy': opts.fy || '50%',
+ 'fr': opts.fr || '0%',
+ 'cx': opts.cx || '50%',
+ 'cy': opts.cy || '50%',
+ 'r': opts.r || '50%',
+ spreadMethod: opts.spreadMethod || 'pad' // pad | reflect | repeat
+ });
+
+ steps.forEach(stepper);
+ defs.append(radialGrad);
+ return 'url(#' + id + ')';
+ }
+
+
+ /*
+ [Malta] lib/Lfilters.js
+ */
+
+ /**
+ *
+ * @param {*} filters
+ * @returns
+ */
+ L.prototype.filter = function() {
+ var filters = [].slice.call(arguments, 0);
+ getDefs(this)
+ var id = lid(),
+ filter = new Element('filter'),
+ availables = [
+ 'feGaussianBlur', 'feDropShadow', 'feMorphology',
+ 'feDisplacementMap', 'feBlend', 'feColorMatrix',
+ 'feConvolveMatrix', 'feComponentTransfer', 'feSpecularLighting',
+ 'feDiffuseLighting', 'feFlood', 'feTurbulence',
+ 'feImage', 'feTile', 'feOffset',
+ 'feComposite','feMerge'
+ ];
+ filter.tag.setAttribute('id', id);
+
+ for(
+ var i = 0, l = filters.length, f, inner = false;
+ i < l;
+ i++, inner = false
+ ) {
+ f = filters[i];
+ if (availables.includes(f.type)){
+ inner = new Element(f.type);
+ inner.sas(f.attrs);
+ }
+
+ inner && filter.append(inner);
+ }
+
+ this.defs.append(filter);
+ return 'url(#' + id + ')';
+ }
+
+ /*
+ [Malta] lib/Lmasks.js
+ */
+
+ /**
+ * Creates a mask definition that can be applied to elements
+ *
+ * @param {string|Element} id - Optional id for the mask, or first element
+ * @param {...Element} elements - Elements to include in the mask
+ * @returns {string} - URL reference to use in setAttributes({ mask: ... })
+ *
+ * @example
+ * var mask = L.mask(
+ * L.rect(0, 0, 100, 100).setAttributes({ fill: 'white' }),
+ * L.circle(50, 50, 30).setAttributes({ fill: 'black' })
+ * );
+ * element.setAttributes({ mask: mask });
+ */
+ L.prototype.mask = function(id) {
+ var args = [].slice.call(arguments, 0),
+ defs = getDefs(this),
+ mask = new Element('mask'),
+ maskId,
+ elements;
+
+ // Check if first argument is an element (has _id property) or a string ID
+ if (id && typeof id === 'string' && !id._id) {
+ maskId = id;
+ elements = args.slice(1);
+ } else {
+ maskId = lid();
+ elements = args;
+ }
+
+ mask.sas({ id: maskId });
+ elements.forEach(function(el) {
+ if (el && el._id) {
+ mask.append(el);
+ }
+ });
+ defs.append(mask);
+ return 'url(#' + maskId + ')';
+ };
+
+ /**
+ * Creates a clipPath definition that can be applied to elements
+ *
+ * @param {string|Element} id - Optional id for the clipPath, or first element
+ * @param {...Element} elements - Elements defining the clip path
+ * @returns {string} - URL reference to use in setAttributes({ 'clip-path': ... })
+ *
+ * @example
+ * var clip = L.clipPath(
+ * L.circle(50, 50, 40)
+ * );
+ * element.setAttributes({ 'clip-path': clip });
+ */
+ L.prototype.clipPath = function(id) {
+ var args = [].slice.call(arguments, 0),
+ defs = getDefs(this),
+ clipPath = new Element('clipPath'),
+ clipId,
+ elements;
+
+ // Check if first argument is an element (has _id property) or a string ID
+ if (id && typeof id === 'string' && !id._id) {
+ clipId = id;
+ elements = args.slice(1);
+ } else {
+ clipId = lid();
+ elements = args;
+ }
+
+ clipPath.sas({ id: clipId });
+ elements.forEach(function(el) {
+ if (el && el._id) {
+ clipPath.append(el);
+ }
+ });
+ defs.append(clipPath);
+ return 'url(#' + clipId + ')';
+ };
+
+ // Static versions
+ Leo.mask = L.mask = L.prototype.mask;
+ Leo.clipPath = L.clipPath = L.prototype.clipPath;
+
+ /*
+ [Malta] lib/Lpatterns.js
+ */
+
+ /**
+ * Creates a pattern definition that can be used as fill or stroke
+ *
+ * @param {number} width - Pattern width
+ * @param {number} height - Pattern height
+ * @param {Element|Array} content - Element(s) to use as pattern content
+ * @param {Object} options - Optional configuration
+ * @param {string} options.id - Custom id for the pattern
+ * @param {string} options.patternUnits - 'userSpaceOnUse' or 'objectBoundingBox' (default: 'userSpaceOnUse')
+ * @param {string} options.patternTransform - Transform to apply to the pattern
+ * @param {number} options.x - Pattern x offset
+ * @param {number} options.y - Pattern y offset
+ * @returns {string} - URL reference to use as fill or stroke
+ *
+ * @example
+ * var pattern = L.pattern(20, 20,
+ * L.circle(10, 10, 5).setAttributes({ fill: 'red' }),
+ * { patternUnits: 'userSpaceOnUse' }
+ * );
+ * element.setAttributes({ fill: pattern });
+ */
+ L.prototype.pattern = function(width, height, content, options) {
+ options = options || {};
+ var defs = getDefs(this),
+ pattern = new Element('pattern'),
+ patternId = options.id || lid();
+
+ pattern.sas({
+ id: patternId,
+ width: width,
+ height: height,
+ x: options.x || 0,
+ y: options.y || 0,
+ patternUnits: options.patternUnits || 'userSpaceOnUse'
+ });
+
+ if (options.patternTransform) {
+ pattern.sas({ patternTransform: options.patternTransform });
+ }
+
+ // Handle single element or array of elements
+ /* istanbul ignore else */
+ if (content instanceof Array) {
+ content.forEach(function(el) {
+ pattern.append(el);
+ });
+ } else if (content) {
+ pattern.append(content);
+ }
+
+ defs.append(pattern);
+ return 'url(#' + patternId + ')';
+ };
+
+ // Static version
+ Leo.pattern = L.pattern = L.prototype.pattern;
+
+ /*
+ [Malta] lib/Ldraggable.js
+ */
+
+ /**
+ * Makes an element draggable
+ *
+ * @param {Object} options - Drag options
+ * @param {Function} options.onDrag - Called during drag with (dx, dy, x, y)
+ * @param {Function} options.onStart - Called when drag starts with (x, y)
+ * @param {Function} options.onEnd - Called when drag ends with (x, y)
+ * @param {string|Array} options.constrainTo - 'parent' or [x, y, width, height] bounds
+ * @returns {Element} - Returns the element for chaining
+ *
+ * @example
+ * circle.draggable({
+ * onDrag: function(dx, dy, x, y) {
+ * console.log('Dragging to:', x, y);
+ * },
+ * onStart: function(x, y) {
+ * console.log('Started dragging at:', x, y);
+ * },
+ * onEnd: function(x, y) {
+ * console.log('Ended dragging at:', x, y);
+ * },
+ * constrainTo: 'parent'
+ * });
+ */
+ Element.prototype.draggable = function(options) {
+ options = options || {};
+ var self = this,
+ isDragging = false,
+ startX = 0,
+ startY = 0,
+ initialX = 0,
+ initialY = 0,
+ currentX = 0,
+ currentY = 0,
+ onDrag = options.onDrag || function() {},
+ onStart = options.onStart || function() {},
+ onEnd = options.onEnd || function() {},
+ constrainTo = options.constrainTo,
+ svg = this.tag.ownerSVGElement;
+
+ // Get initial position from transform or attributes
+ function getPosition() {
+ var transform = self.tag.getAttribute('transform');
+ if (transform) {
+ var match = transform.match(/translate\(([^,]+),\s*([^)]+)\)/);
+ if (match) {
+ return {
+ x: parseFloat(match[1]) || 0,
+ y: parseFloat(match[2]) || 0
+ };
+ }
+ }
+ // Try cx/cy for circles/ellipses
+ var cx = self.tag.getAttribute('cx'),
+ cy = self.tag.getAttribute('cy'),
+ x = self.tag.getAttribute('x'),
+ y = self.tag.getAttribute('y');
+ return {
+ x: parseFloat(cx || x || 0),
+ y: parseFloat(cy || y || 0)
+ };
+ }
+
+ // Convert screen coordinates to SVG coordinates
+ /* istanbul ignore next */
+ function getSVGPoint(clientX, clientY) {
+ if (!svg) return { x: clientX, y: clientY };
+ /* istanbul ignore next */
+ var pt = svg.createSVGPoint();
+ /* istanbul ignore next */
+ pt.x = clientX;
+ /* istanbul ignore next */
+ pt.y = clientY;
+ /* istanbul ignore next */
+ var ctm = svg.getScreenCTM();
+ /* istanbul ignore next */
+ if (ctm) {
+ /* istanbul ignore next */
+ return pt.matrixTransform(ctm.inverse());
+ }
+ /* istanbul ignore next */
+ return { x: clientX, y: clientY };
+ }
+
+ // Apply constraints
+ function constrain(x, y) {
+ if (!constrainTo) return { x: x, y: y };
+
+ var bounds;
+ if (constrainTo === 'parent') {
+ var parent = self.tag.parentNode;
+ if (parent && parent.getBBox) {
+ var bbox = parent.getBBox();
+ bounds = [bbox.x, bbox.y, bbox.width, bbox.height];
+ }
+ } else if (constrainTo instanceof Array && constrainTo.length === 4) {
+ bounds = constrainTo;
+ }
+
+ if (bounds) {
+ var elBBox = self.tag.getBBox ? self.tag.getBBox() : { width: 0, height: 0 };
+ x = Math.max(bounds[0], Math.min(x, bounds[0] + bounds[2] - elBBox.width));
+ y = Math.max(bounds[1], Math.min(y, bounds[1] + bounds[3] - elBBox.height));
+ }
+
+ return { x: x, y: y };
+ }
+
+ function startDrag(e) {
+ if (e.button !== 0) return; // Only left mouse button
+ isDragging = true;
+
+ var pos = getPosition();
+ var svgPoint = getSVGPoint(e.clientX, e.clientY);
+ initialX = pos.x;
+ initialY = pos.y;
+ startX = svgPoint.x;
+ startY = svgPoint.y;
+ currentX = initialX;
+ currentY = initialY;
+
+ onStart.call(self, initialX, initialY);
+ e.preventDefault();
+ }
+
+ function doDrag(e) {
+ if (!isDragging) return;
+
+ var svgPoint = getSVGPoint(e.clientX, e.clientY);
+ var dx = svgPoint.x - startX;
+ var dy = svgPoint.y - startY;
+
+ currentX = initialX + dx;
+ currentY = initialY + dy;
+
+ var constrained = constrain(currentX, currentY);
+ currentX = constrained.x;
+ currentY = constrained.y;
+
+ self.move(currentX, currentY);
+ onDrag.call(self, dx, dy, currentX, currentY);
+ }
+
+ function endDrag(e) {
+ if (!isDragging) return;
+ isDragging = false;
+ onEnd.call(self, currentX, currentY);
+ }
+
+ // Mouse events
+ this.tag.addEventListener('mousedown', startDrag);
+ document.addEventListener('mousemove', doDrag);
+ document.addEventListener('mouseup', endDrag);
+
+ // Touch events for mobile
+ /* istanbul ignore next */
+ this.tag.addEventListener('touchstart', function(e) {
+ /* istanbul ignore next */
+ if (e.touches.length === 1) {
+ /* istanbul ignore next */
+ startDrag(e.touches[0]);
+ }
+ });
+ /* istanbul ignore next */
+ document.addEventListener('touchmove', function(e) {
+ /* istanbul ignore next */
+ if (e.touches.length === 1) {
+ /* istanbul ignore next */
+ doDrag(e.touches[0]);
+ }
+ });
+ /* istanbul ignore next */
+ document.addEventListener('touchend', endDrag);
+
+ return this;
+ };
+
+ /*
+ [Malta] lib/Lbatch.js
+ */
+
+ /**
+ * Batch multiple DOM operations to improve performance
+ * Defers actual DOM updates until the end of the batch
+ *
+ * @param {Function} fn - Function containing operations to batch
+ * @returns {L} - Returns the instance for chaining
+ *
+ * @example
+ * L.batch(function() {
+ * circle.setAttributes({ cx: 100 });
+ * rect.setAttributes({ x: 50 });
+ * group.append(circle, rect);
+ * });
+ */
+ L.prototype.batch = function(fn) {
+ // Store original append method
+ var originalAppend = this.append;
+ var self = this;
+ var pendingAppends = [];
+
+ // Override append to collect operations
+ this.append = function() {
+ var args = [].slice.call(arguments, 0);
+ pendingAppends.push(args);
+ return self;
+ };
+
+ // Execute the batch function
+ try {
+ fn.call(this);
+ } finally {
+ // Restore original append
+ this.append = originalAppend;
+
+ // Apply all pending appends in a document fragment
+ if (pendingAppends.length > 0) {
+ var fragment = document.createDocumentFragment();
+
+ pendingAppends.forEach(function(args) {
+ args.forEach(function(el) {
+ if (el instanceof Element) {
+ self.childs.push(el);
+ el.parent = self;
+ fragment.appendChild(el.tag);
+ }
+ });
+ });
+
+ this.tag.appendChild(fragment);
+ }
+ }
+
+ return this;
+ };
+
+ /**
+ * Element-level batch for appending multiple children efficiently
+ *
+ * @param {Array} elements - Array of elements to append
+ * @returns {Element} - Returns the element for chaining
+ *
+ * @example
+ * group.batchAppend([circle1, circle2, rect1, rect2]);
+ */
+ Element.prototype.batchAppend = function(elements) {
+ var self = this;
+ var fragment = document.createDocumentFragment();
+
+ elements.forEach(function(el) {
+ if (el instanceof Element) {
+ self.childs.push(el);
+ el.parent = self;
+ fragment.appendChild(el.tag);
+ }
+ });
+
+ this.tag.appendChild(fragment);
+ return this;
+ };
+
+ // Static version
+ Leo.batch = L.batch = L.prototype.batch;
+
+ /*
+ [Malta] lib/Lviewbox.js
+ */
+
+ /**
+ * Sets the viewBox attribute for the SVG
+ *
+ * @param {number} x - X coordinate of viewBox
+ * @param {number} y - Y coordinate of viewBox
+ * @param {number} width - Width of viewBox
+ * @param {number} height - Height of viewBox
+ * @returns {L} - Returns the instance for chaining
+ *
+ * @example
+ * L.setViewBox(0, 0, 500, 500);
+ */
+ L.prototype.setViewBox = function(x, y, width, height) {
+ this.tag.setAttribute('viewBox', [x, y, width, height].join(' '));
+ return this;
+ };
+
+ /**
+ * Sets the preserveAspectRatio attribute
+ *
+ * @param {string} mode - Aspect ratio mode
+ * Alignment: 'xMinYMin', 'xMidYMin', 'xMaxYMin',
+ * 'xMinYMid', 'xMidYMid', 'xMaxYMid',
+ * 'xMinYMax', 'xMidYMax', 'xMaxYMax'
+ * Meet/Slice: 'meet' or 'slice'
+ * Or combine: 'xMidYMid meet' (default)
+ * @returns {L} - Returns the instance for chaining
+ *
+ * @example
+ * L.preserveAspectRatio('xMidYMid meet');
+ * L.preserveAspectRatio('xMinYMin slice');
+ */
+ L.prototype.preserveAspectRatio = function(mode) {
+ this.tag.setAttribute('preserveAspectRatio', mode);
+ return this;
+ };
+
+ /**
+ * Converts screen coordinates to SVG coordinates
+ *
+ * @param {number} screenX - X coordinate in screen space
+ * @param {number} screenY - Y coordinate in screen space
+ * @returns {Object} - { x, y } in SVG coordinates
+ *
+ * @example
+ * var svgPoint = L.screenToSVG(100, 200);
+ */
+ /* istanbul ignore next */
+ L.prototype.screenToSVG = function(screenX, screenY) {
+ /* istanbul ignore next */
+ if (!this.tag.createSVGPoint) return { x: screenX, y: screenY };
+ /* istanbul ignore next */
+ var pt = this.tag.createSVGPoint();
+ /* istanbul ignore next */
+ pt.x = screenX;
+ /* istanbul ignore next */
+ pt.y = screenY;
+ /* istanbul ignore next */
+ var ctm = this.tag.getScreenCTM();
+ /* istanbul ignore next */
+ if (!ctm) return { x: screenX, y: screenY };
+ /* istanbul ignore next */
+ var svgP = pt.matrixTransform(ctm.inverse());
+ /* istanbul ignore next */
+ return { x: svgP.x, y: svgP.y };
+ };
+
+ /**
+ * Converts SVG coordinates to screen coordinates
+ *
+ * @param {number} svgX - X coordinate in SVG space
+ * @param {number} svgY - Y coordinate in SVG space
+ * @returns {Object} - { x, y } in screen coordinates
+ *
+ * @example
+ * var screenPoint = L.svgToScreen(50, 50);
+ */
+ /* istanbul ignore next */
+ L.prototype.svgToScreen = function(svgX, svgY) {
+ /* istanbul ignore next */
+ var pt = this.tag.createSVGPoint();
+ /* istanbul ignore next */
+ pt.x = svgX;
+ /* istanbul ignore next */
+ pt.y = svgY;
+ /* istanbul ignore next */
+ var screenP = pt.matrixTransform(this.tag.getScreenCTM());
+ /* istanbul ignore next */
+ return { x: screenP.x, y: screenP.y };
+ };
+
+ /**
+ * Gets the current viewBox values
+ *
+ * @returns {Object} - { x, y, width, height } or null if no viewBox
+ */
+ L.prototype.getViewBox = function() {
+ var viewBox = this.tag.getAttribute('viewBox');
+ if (!viewBox) return null;
+ var parts = viewBox.split(/\s+/).map(parseFloat);
+ return {
+ x: parts[0],
+ y: parts[1],
+ width: parts[2],
+ height: parts[3]
+ };
+ };
+
+ // Static versions
+ Leo.setViewBox = L.setViewBox = L.prototype.setViewBox;
+ Leo.preserveAspectRatio = L.preserveAspectRatio = L.prototype.preserveAspectRatio;
+ Leo.screenToSVG = L.screenToSVG = L.prototype.screenToSVG;
+ Leo.svgToScreen = L.svgToScreen = L.prototype.svgToScreen;
+ Leo.getViewBox = L.getViewBox = L.prototype.getViewBox;
+
+ /*
+ [Malta] lib/Ldebug.js
+ */
+
+ /**
+ * Debug mode - adds visual guides and information to help with development
+ *
+ * @param {Object} options - Debug options
+ * @param {boolean} options.showBoundingBoxes - Show bounding boxes around elements (default: true)
+ * @param {boolean} options.showCenterPoints - Show center points for elements (default: true)
+ * @param {boolean} options.showGrid - Show coordinate grid (default: false)
+ * @param {number} options.gridSize - Grid size in pixels (default: 50)
+ * @param {boolean} options.showCoordinates - Show coordinates on hover (default: true)
+ * @returns {L} - Returns the instance for chaining
+ *
+ * @example
+ * L.debug({ showGrid: true, gridSize: 25 });
+ */
+ L.prototype.debug = function(options) {
+ options = options || {};
+ var self = this,
+ showBoundingBoxes = options.showBoundingBoxes !== false,
+ showCenterPoints = options.showCenterPoints !== false,
+ showGrid = options.showGrid || false,
+ gridSize = options.gridSize || 50,
+ showCoordinates = options.showCoordinates !== false;
+
+ // Create debug group
+ var debugGroup = this.group();
+ debugGroup.sas({ class: 'leo-debug-layer' });
+
+ // Add grid if requested
+ if (showGrid) {
+ var gridGroup = this.group();
+ var w = this.width,
+ h = this.height;
+
+ // Vertical lines
+ for (var x = 0; x <= w; x += gridSize) {
+ var line = this.line(x, 0, x, h).setAttributes({
+ stroke: '#ddd',
+ 'stroke-width': 0.5
+ });
+ gridGroup.append(line);
+ }
+
+ // Horizontal lines
+ for (var y = 0; y <= h; y += gridSize) {
+ var line = this.line(0, y, w, y).setAttributes({
+ stroke: '#ddd',
+ 'stroke-width': 0.5
+ });
+ gridGroup.append(line);
+ }
+
+ debugGroup.append(gridGroup);
+ }
+
+ // Add coordinate display
+ if (showCoordinates) {
+ var coordText = this.text(10, 20, 'x: 0, y: 0').setAttributes({
+ fill: '#666',
+ 'font-family': 'monospace',
+ 'font-size': '12px',
+ class: 'leo-debug-coords'
+ });
+ debugGroup.append(coordText);
+
+ /* istanbul ignore next */
+ this.tag.addEventListener('mousemove', function(e) {
+ /* istanbul ignore next */
+ var pt = self.tag.createSVGPoint();
+ /* istanbul ignore next */
+ pt.x = e.clientX;
+ /* istanbul ignore next */
+ pt.y = e.clientY;
+ /* istanbul ignore next */
+ var svgP = pt.matrixTransform(self.tag.getScreenCTM().inverse());
+ /* istanbul ignore next */
+ coordText.updateText('x: ' + Math.round(svgP.x) + ', y: ' + Math.round(svgP.y));
+ });
+ }
+
+ // Store reference to debug group
+ this._debugGroup = debugGroup;
+ this.append(debugGroup);
+
+ // Add debug info to all elements
+ if (showBoundingBoxes || showCenterPoints) {
+ this._debugElements = [];
+ this._enableElementDebug(showBoundingBoxes, showCenterPoints);
+ }
+
+ return this;
+ };
+
+ /**
+ * Enable debug visualization for individual elements
+ * @private
+ */
+ L.prototype._enableElementDebug = function(showBoundingBoxes, showCenterPoints) {
+ var self = this;
+
+ // Override append to add debug info to new elements
+ var originalAppend = this.append;
+ /* istanbul ignore next */
+ this.append = function() {
+ /* istanbul ignore next */
+ var result = originalAppend.apply(this, arguments);
+
+ // Add debug visualization for new elements
+ /* istanbul ignore next */
+ for (var i = 0; i < arguments.length; i++) {
+ /* istanbul ignore next */
+ var el = arguments[i];
+ /* istanbul ignore next */
+ if (el instanceof Element && el.tag.getBBox) {
+ /* istanbul ignore next */
+ el._addDebugInfo(self, showBoundingBoxes, showCenterPoints);
+ }
+ }
+
+ /* istanbul ignore next */
+ return result;
+ };
+ };
+
+ /**
+ * Add debug visualization to an element
+ * @private
+ */
+ /* istanbul ignore next */
+ Element.prototype._addDebugInfo = function(leoInstance, showBoundingBoxes, showCenterPoints) {
+ /* istanbul ignore if */
+ if (!this.tag.getBBox) return;
+
+ /* istanbul ignore next */
+ var bbox = this.tag.getBBox();
+ var debugElements = [];
+
+ /* istanbul ignore next */
+ if (showBoundingBoxes) {
+ /* istanbul ignore next */
+ var box = leoInstance.rect(bbox.x, bbox.y, bbox.width, bbox.height).setAttributes({
+ fill: 'none',
+ stroke: 'rgba(255, 0, 0, 0.5)',
+ 'stroke-width': 1,
+ 'stroke-dasharray': '4,2',
+ class: 'leo-debug-bbox'
+ });
+ /* istanbul ignore next */
+ debugElements.push(box);
+ }
+
+ /* istanbul ignore next */
+ if (showCenterPoints) {
+ /* istanbul ignore next */
+ var cx = bbox.x + bbox.width / 2;
+ /* istanbul ignore next */
+ var cy = bbox.y + bbox.height / 2;
+ /* istanbul ignore next */
+ var center = leoInstance.circle(cx, cy, 3).setAttributes({
+ fill: 'rgba(0, 255, 0, 0.5)',
+ stroke: 'none',
+ class: 'leo-debug-center'
+ });
+ /* istanbul ignore next */
+ debugElements.push(center);
+ }
+
+ // Add to debug group
+ /* istanbul ignore next */
+ if (leoInstance._debugGroup && debugElements.length > 0) {
+ /* istanbul ignore next */
+ debugElements.forEach(function(el) {
+ /* istanbul ignore next */
+ leoInstance._debugGroup.append(el);
+ });
+ }
+
+ /* istanbul ignore next */
+ this._debugElements = debugElements;
+ };
+
+ /**
+ * Remove debug mode
+ *
+ * @returns {L} - Returns the instance for chaining
+ */
+ L.prototype.undebug = function() {
+ if (this._debugGroup) {
+ this._debugGroup.remove();
+ this._debugGroup = null;
+ }
+ return this;
+ };
+
+ // Static versions
+ Leo.debug = L.debug = L.prototype.debug;
+ Leo.undebug = L.undebug = L.prototype.undebug;
+
+ /*
+ [Malta] lib/Lanimate.js
+ */
+ /**
+ * { function_description }
+ *
+ * @return {Object} { description_of_the_return_value }
+ */
+ L.prototype.animate = (function () {
+ // seconds per frame = 1/(frame per seconds)
+ var spf60 = (1E3/60)/1000;
+ function parametricCartesian(el, fx, fy, interval, opts) {
+ opts = opts || {};
+ interval = interval || spf60;
+ var trace = opts.trace || false,
+ t = 0,
+ x = 0,
+ y = 0,
+ lastTime = 0,
+ rafId = null,
+ step = function (time) {
+ t += interval;
+ if (!lastTime || time - lastTime >= interval) {
+ x = fx(x, t);
+ y = fy(y, t);
+ el.move(x, y);
+ lastTime = time;
+ if(trace) {
+ var c = new Element('circle'),
+ attrs = el.getAttributes('cx', 'cy');
+ c.sas(Object.assign({
+ cx: ~~attrs.cx + x,
+ cy: ~~attrs.cy + y,
+ r :5,
+ stroke:'gray',
+ fill: 'transparent'
+ }, trace.style || {}));
+ el.parent.append(c);
+ }
+ }
+ rafId = requestAnimationFrame(step);
+ };
+ rafId = requestAnimationFrame(step);
+ return function () {
+ cancelAnimationFrame(rafId);
+ }
+ }
+
+ function parametricPolar(el, fr, fO, interval, opts) {
+ opts = opts || {};
+ interval = interval || spf60;
+ var trace = opts.trace || false,
+ t = 0,
+ r = 0,
+ O = 0,
+ lastTime = 0,
+ rafId = null,
+ step = function (time) {
+ t += interval;
+ if (!lastTime || time - lastTime >= interval) {
+ r = fr(r, t);
+ O = fO(O, t);
+ el.move(
+ r * Math.cos(O),
+ r * Math.sin(O)
+ );
+ lastTime = time;
+ if(trace) {
+ var c = new Element('circle'),
+ attrs = el.getAttributes('cx', 'cy');
+ c.sas(Object.assign({
+ cx: ~~attrs.cx + r * Math.cos(O),
+ cy: ~~attrs.cy + r * Math.sin(O),
+ r :5,
+ stroke:'gray',
+ fill: 'transparent'
+ }, trace.style || {}));
+ el.parent.append(c);
+ }
+ }
+ rafId = requestAnimationFrame(step);
+ };
+ rafId = requestAnimationFrame(step);
+ return function () {
+ cancelAnimationFrame(rafId);
+ }
+ }
+
+ function attr(params /* {attributeName, from, to, dur, repeatCount} */) {
+ var animate = new Element('animate'),
+ attrs = {
+ attributeName: params.attributeName,
+ dur: params.dur,
+ begin: params.begin || '0s',
+ repeatCount: params.repeatCount
+ };
+ 'from' in params && (attrs.from = params.from);
+ 'to' in params && (attrs.to = params.to);
+ 'values' in params && (attrs.values = params.values);
+ 'type' in params && (attrs.type = params.type);
+ animate.sas(attrs);
+ return animate;
+ };
+
+ /* istanbul ignore next */
+ function motionPath(el, pathStr, ats) {
+ ats = ats || {};
+ var animateMotion = new Element('animateMotion'),
+ attrs = {
+ begin: ats.begin || '0s',
+ dur: ats.dur || '1s',
+ end: ats.end || null,
+ min: ats.min || 0,
+ max: ats.max || null,
+ restart: ats.restart || 'always',
+ repeatCount: ats.repeatCount || 'indefinite',
+
+ repeatDur: ats.repeatDur || null,
+ // fill
+ path: pathStr
+ }
+ animateMotion.sas(attrs);
+ el.append(animateMotion);
+ return el;
+ }
+
+ // Easing functions
+ /* istanbul ignore next */
+ var Easing = {
+ linear: function(t) { return t; },
+ easeInQuad: function(t) { return t * t; },
+ easeOutQuad: function(t) { return 1 - (1 - t) * (1 - t); },
+ easeInOutQuad: function(t) {
+ return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
+ },
+ easeInCubic: function(t) { return t * t * t; },
+ easeOutCubic: function(t) { return 1 - Math.pow(1 - t, 3); },
+ easeInOutCubic: function(t) {
+ return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
+ },
+ easeInQuart: function(t) { return t * t * t * t; },
+ easeOutQuart: function(t) { return 1 - Math.pow(1 - t, 4); },
+ easeInOutQuart: function(t) {
+ return t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2;
+ },
+ spring: function(t) {
+ var c4 = (2 * Math.PI) / 3;
+ return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
+ },
+ bounce: function(t) {
+ var n1 = 7.5625, d1 = 2.75;
+ /* istanbul ignore next */
+ if (t < 1 / d1) {
+ return n1 * t * t;
+ /* istanbul ignore next */
+ } else if (t < 2 / d1) {
+ return n1 * (t -= 1.5 / d1) * t + 0.75;
+ /* istanbul ignore next */
+ } else if (t < 2.5 / d1) {
+ return n1 * (t -= 2.25 / d1) * t + 0.9375;
+ } else {
+ return n1 * (t -= 2.625 / d1) * t + 0.984375;
+ }
+ }
+ };
+
+ // Animate with easing
+ /* istanbul ignore next */
+ function animateWithEasing(el, params) {
+ var easing = params.easing || Easing.linear,
+ from = params.from || 0,
+ to = params.to || 1,
+ dur = parseFloat(params.dur) * 1000 || 1000,
+ startTime = null,
+ attributeName = params.attributeName,
+ rafId = null;
+
+ function step(timestamp) {
+ if (!startTime) startTime = timestamp;
+ var elapsed = timestamp - startTime,
+ progress = Math.min(elapsed / dur, 1),
+ easedProgress = easing(progress),
+ value = from + (to - from) * easedProgress;
+
+ el.tag.setAttribute(attributeName, value);
+
+ if (progress < 1) {
+ rafId = requestAnimationFrame(step);
+ } else if (params.onComplete) {
+ params.onComplete();
+ }
+
+ }
+ rafId = requestAnimationFrame(step);
+ return function() {
+ cancelAnimationFrame(rafId);
+ };
+ }
+
+ return {
+ cartesian : parametricCartesian,
+ polar : parametricPolar,
+ motionPath: motionPath,
+ attr : attr,
+ Easing: Easing,
+ withEasing: animateWithEasing
+ };
+
+ })();
+
+ /*
+ [Malta] lib/Ltimeline.js
+ */
+
+ /**
+ * Timeline for chaining and sequencing animations
+ *
+ * @class Timeline
+ * @param {Object} options - Timeline options
+ * @param {boolean} options.autoPlay - Whether to start playing immediately (default: false)
+ */
+ function Timeline(options) {
+ options = options || {};
+ this.animations = [];
+ this.isPlaying = false;
+ this.currentIndex = 0;
+ this.startTime = null;
+ this.autoPlay = options.autoPlay || false;
+ this.onComplete = options.onComplete || null;
+ }
+
+ /**
+ * Add an animation to the timeline
+ *
+ * @param {Function} animation - Animation function that returns a stopper
+ * @param {number} offset - Time offset in seconds (0 = immediately, 1 = after 1s)
+ * @returns {Timeline} - Returns this for chaining
+ *
+ * @example
+ * var tl = L.timeline()
+ * .add(function() { return element.animate.attr({...}); }, 0)
+ * .add(function() { return element2.animate.attr({...}); }, 1);
+ */
+ Timeline.prototype.add = function(animation, offset) {
+ this.animations.push({
+ animation: animation,
+ offset: offset || 0,
+ started: false,
+ stopper: null
+ });
+ return this;
+ };
+
+ /**
+ * Start playing the timeline
+ *
+ * @returns {Timeline}
+ */
+ Timeline.prototype.play = function() {
+ if (this.isPlaying) return this;
+ this.isPlaying = true;
+ this.startTime = Date.now();
+ this.tick();
+ return this;
+ };
+
+ /**
+ * Pause the timeline
+ *
+ * @returns {Timeline}
+ */
+ Timeline.prototype.pause = function() {
+ this.isPlaying = false;
+ // Stop all running animations
+ this.animations.forEach(function(anim) {
+ if (anim.stopper) {
+ anim.stopper();
+ }
+ });
+ return this;
+ };
+
+ /**
+ * Stop the timeline and reset to beginning
+ *
+ * @returns {Timeline}
+ */
+ Timeline.prototype.stop = function() {
+ this.pause();
+ this.currentIndex = 0;
+ this.animations.forEach(function(anim) {
+ anim.started = false;
+ anim.stopper = null;
+ });
+ return this;
+ };
+
+ /**
+ * Internal tick function
+ * @private
+ */
+ Timeline.prototype.tick = function() {
+ if (!this.isPlaying) return;
+
+ var self = this;
+ var elapsed = (Date.now() - this.startTime) / 1000;
+ var allComplete = true;
+
+ this.animations.forEach(function(anim, index) {
+ if (!anim.started && elapsed >= anim.offset) {
+ anim.started = true;
+ anim.stopper = anim.animation();
+ }
+ if (!anim.started) {
+ allComplete = false;
+ }
+ });
+
+ if (allComplete && this.onComplete) {
+ this.onComplete();
+ } else if (this.isPlaying) {
+ requestAnimationFrame(function() { self.tick(); });
+ }
+ };
+
+ /**
+ * Create a new timeline
+ *
+ * @param {Object} options - Timeline options
+ * @returns {Timeline}
+ *
+ * @example
+ * var tl = L.timeline()
+ * .add(function() {
+ * return circle.animate.withEasing({...});
+ * }, 0)
+ * .add(function() {
+ * return rect.animate.withEasing({...});
+ * }, 0.5)
+ * .play();
+ */
+ L.prototype.timeline = function(options) {
+ return new Timeline(options);
+ };
+
+ // Static version
+ Leo.timeline = L.timeline = L.prototype.timeline;
+
+ /*
+ [Malta] lib/Lextra.js
+ */
+ /**
+ *
+ * @param {*} txt
+ * @param {*} w
+ * @param {*} h
+ * @param {*} textAttrs
+ * @param {*} boxFill
+ * @returns
+ */
+ Leo.textBox = L.prototype.textBox = function (txt, w, h, textAttrs, boxAttrs, rot) {
+ var cnt = new Element('svg'),
+ rect = new Element('rect'),
+ text = new Element('text'),
+ boxA = {
+ x : 0, y : 0,
+ width: w, height: h,
+ "stroke-width" : 0,
+ stroke : 'transparent',
+ fill:'transparent'
+ };
+ rect.sas(Object.assign({}, boxA, boxAttrs));
+ cnt.sas({width : w, height : h, viewBox: [0, 0, w, h].join(' ')});
+ text.sas({
+ x: '50%',
+ y: '50%',
+ 'dominant-baseline': 'middle',
+ 'text-anchor': 'middle'
+ });
+ if(rot) text.rotate(rot, w/2, h/2);
+ textAttrs && text.sas(textAttrs);
+ text.tag.innerHTML = txt;
+ cnt.append(rect, text);
+ cnt.updateText = function (t) {
+ text.tag.innerHTML = t;
+ };
+ return cnt;
+ }
+
+ /**
+ * { function_description }
+ *
+ * @param {} d { parameter_description }
+ * @param {} cnt The content
+ * @return {Element} { description_of_the_return_value }
+ */
+ Leo.textPath = L.prototype.textPath = function (d, cnt) {
+ var text = new Element('text'),
+ defs = new Element('defs'),
+ path = L.path(d),
+ textpath = new Element('textPath'),
+ id = lid();
+ path.tag.setAttribute('id', id );
+ textpath.tag.textContent = cnt;
+ textpath.tag.setAttributeNS(namespaces.xlink, 'xlink:href', '#' + id);
+ defs.append(path);
+ text.append(defs, textpath);
+ text.updateText = function(t) {
+ textpath.tag.textContent = t;
+ };
+ return text;
+ };
+
+ /**
+ * @param {*} cx
+ * @param {*} cy
+ * @param {*} r1
+ * @param {*} r2
+ * @param {*} from
+ * @param {*} to
+ * @param {*} vrs1
+ * @param {*} vrs2
+ * @returns
+ */
+ Leo.arcSectionPath = L.prototype.arcSectionPath = function (cx, cy, r1, r2, from, to, vrs1, vrs2) {
+ vrs1 = typeof vrs1 === 'undefined' ? 1 : vrs1;
+ vrs2 = typeof vrs2 === 'undefined' ? 0 : vrs2;
+ var startOut = polarToCartesian(cx, cy, r2, from),
+ endOut = polarToCartesian(cx, cy, r2, to),
+ startIn = polarToCartesian(cx, cy, r1, to),
+ endIn = polarToCartesian(cx, cy, r1, from),
+ ref = Math.abs(to-from) > 180 ? 1: 0;
+ return L.pathBuild
+ .M(endIn.x, endIn.y)
+ .L(startOut.x, startOut.y)
+ .A(
+ r2, r2,
+ 0, ref, vrs1,
+ endOut.x, endOut.y
+ )
+ .L(startIn.x, startIn.y)
+ .maybe(r1>0 , 'A', [
+ r1, r1,
+ 0, ref, vrs2,
+ endIn.x, endIn.y
+ ])
+ .Z().toString();
+ };
+
+ // ---
+ Leo.validate = validate;
+ Leo.ERRORS = ERRORS;
+ return Leo;
+})();
+(typeof exports === 'object') && (module.exports = Leonardo);
\ No newline at end of file
diff --git a/ghp/js/index.js b/ghp/js/index.js
index 43bb8bb..b202971 100644
--- a/ghp/js/index.js
+++ b/ghp/js/index.js
@@ -1,283 +1,32 @@
window.onload = function () {
var target = document.getElementById('trg'),
- width = 987,
- height = 652,
+ fact = 1,
+ width = 987 * fact,
+ height = 652 * fact,
w = function (p) {return width * p/100;},
h = function (p) {return height * p/100;},
Leo = Leonardo(width, height, { ns: '*', target: target }).setStyles({backgroundColor: '#222'}),
- img = Leo.image(0,0,width, height, 'ghp/god.jpg').setAttributes({opacity: 1}),
- fillStyle = {
- "stroke-width": 2,
- "stroke": '#ef88d8',
- "stroke-opacity": 1,
- "fill-opacity": 10,
- "stroke-linejoin": "round",
- fill: 'transparent'
- },
+ img = Leo.image(0, 0,width, height, 'ghp/god.jpg').setAttributes({opacity: 1});
+ // .on('click', function() {
+ // console.log({this: this});
+ // img.infoUrl(true);
+ // });
- crunch = Leo.positionCruncher(width, height, fillStyle),
+ Leo
+ .append(img)
+ .render()
+ .positionInspector({
+ tpl: '[{r%x}, {r%y}],',
+ cb: (c) => console.log({c}),
+ trace : true,
+ svgCb: console.log,
+ overrideStylePath: {
+ stoke: 'red',
+ 'stroke-width': 4,
+ 'stroke-dasharray': '10,5',
+ },
+ });
- leftmid = crunch([
- [44.07, 50.61],
- [0.3, 3.07],
- [0.81, 3.07],
- [-0.1, 2.91],
- [0.91, 3.53],
- [-1.11, 0.46],
- [-1.11, -0.92],
- [-1.01, -2.3],
- [-1.11, -3.68],
- [-0.81, -1.99],
- [-0.41, -3.99]
- ]),
- leftmid2 = crunch([
- [42.86, 60.89],
- [0.51, 2.76],
- [-1.11, 0],
- [-1.11, -0.92],
- [-0.3, -1.99],
- [0, -1.99],
- [-0.51, -0.46],
- [-0.71, -1.69],
- [-0.2, -1.99],
- [-0.71, -0.77],
- [-0.91, -0.77],
- [-1.11, -2.3],
- [0.3, 2.45],
- [-0.1, 2.61]
- ]),
- leftLast = crunch([
- [34.95, 61.96],
- [-0.71, 2.15],
- [-0.61, 0.31],
- [-0.91, -1.23],
- [-0.1, -1.53],
- [0.2, -1.99]
- ]),
- leftHole = crunch([
- [33.33, 51.84],
- [-0.2, -1.99],
- [-0.61, -1.38],
- [-1.42, 0.31]
- ]),
- left1 = crunch([
- [1.11, 37.12],
- [4.86, -1.69],
- [3.44, -3.37],
- [3.24, -1.69],
- [3.04, -0.61],
- [4.15, 0.61],
- [4.26, 1.38],
- [3.65, 1.07],
- [4.26, 0.31],
- [2.84, 0.77],
- [1.52, 2.15],
- [1.32, 2.45],
- [3.44, 1.07],
- [1.72, 1.69],
- [1.62, 0.77],
- [1.22, 2.61],
- [1.93, 3.83],
- [0.91, 2.91],
- [1.93, 3.37],
- [-1.11, 1.23],
- [-1.52, -0.15],
- [-1.52, -1.53],
- [-0.61, -1.99],
- [-1.62, -1.84],
- [-1.82, -3.37],
- [-1.25, -0.20],
- [-2.94, -0.92],
- [-0.81, -0.92],
- [-1.32, 1.07],
- [-2.33, -0.46],
- [-0.41, -0.92],
- [-2.23, 1.69],
- [-0.71, 0.92],
- [2.43, 4.29],
- [1.52, 0.77],
- [1.62, 1.99],
- [1.42, 2.3],
- [0.91, 3.37],
- [-0.2, 1.84],
- [-1.42, 0.92],
- [-1.42, -0.92],
- [-2.13, -2.3],
- [-1.32, -1.99],
- [-1.93, -1.99],
- [-2.33, -1.53],
- [-2.43, -1.07],
- [-2.03, -0.15],
- [-1.72, -1.07],
- [-2.03, -2.15],
- [-1.52, -3.22],
- [-1.22, 1.07],
- [-1.93, 0.77],
- [-1.82, 1.69],
- [-1.72, 3.07],
- [-1.72, 2.91],
- [-1.93, 2.91],
- [-1.93, 2.45],
- [-1.93, 2.15],
- [-2.53, 2.15]
- ]),
- right1 = crunch([
- [98.99, 34.66],
- [-1.42, -0.15],
- [-1.82, 0.77],
- [-1.62, -0.15],
- [-1.32, 0.15],
- [-1.52, 0.61],
- [-1.22, 1.07],
- [-1.22, 0.77],
- [-1.42, 0],
- [-1.72, 0],
- [-1.62, 1.07],
- [-1.62, 1.23],
- [-1.52, 0],
- [-1.72, 0],
- [-1.82, 0.61],
- [-1.42, 0.77],
- [-1.72, 0.77],
- [-1.62, 1.38],
- [-1.32, 1.07],
- [-1.22, 0.61],
- [-1.11, 0.46],
- [-1.01, 0.15],
- [-1.32, 0],
- [-1.01, 0.61],
- [-1.52, 0.31],
- [-1.52, -0.15],
- [-1.22, -0.15],
- [-0.91, 0.31],
- [-1.22, -0.15],
- [-1.52, 0.92],
- [-1.11, 0.61],
- [-0.91, 0.46],
- [-0.81, 0],
- [-0.61, 0.46],
- [-1.32, 0.92],
- [-0.91, 0.46],
- [-0.41, 1.07],
- [0.2, 1.38],
- [0.81, 0.61],
- [1.01, 0.46],
- [1.52, 0],
- [1.22, -0.46],
- [0.81, -0.61],
- [1.32, 0.15],
- [1.42, -0.46],
- [1.01, -0.46],
- [1.11, 0.61],
- [1.72, 0.31],
- [1.11, 0.15],
- [0.71, 0],
- [0.51, 0.92],
- [1.11, 0.92],
- [-0.61, 1.23],
- [-0.41, 1.07],
- ]),
- right2 = crunch([
- [73.35, 49.54],
- [-1.42, 1.99],
- [-1.11, 2.61],
- [-1.52, 1.53],
- [-1.22, 0.46],
- [-0.3, 0.92],
- [-0.81, -0.15],
- [-1.22, 0.77],
- [-0.61, 1.23],
- [-1.93, 1.38],
- [-0.61, 1.69],
- [0.3, 1.53],
- [0.81, 1.07],
- [1.22, 0.77],
- [2.13, -0.15],
- [1.72, -1.07],
- [1.32, -1.99],
- [1.52, -1.38],
- [1.72, -1.23],
- [1.62, -0.92],
- [1.42, 0.46],
- [1.52, 0.15],
- [1.93, -0.46],
- [1.72, -0.61],
- [1.11, -1.23],
- [1.32, -1.99],
- ])
- right3 = crunch([
- [64.54, 65.18],
- [0, 2.76],
- [-0.41, 1.84],
- [0, 1.69],
- [0.3, 1.53],
- [0.1, 3.07],
- [0.91, 1.38],
- [1.42, -0.15],
- [0.41, -1.23],
- [0.2, -2.3],
- [-0.2, -2.15],
- [0.3, -1.53],
- [0.1, -1.99],
- [0.3, -1.99],
- [1.01, -2.3],
- ]),
- right4 = crunch([
- [67.17, 76.53],
- [0.71, 0.77],
- [1.42, -0.46],
- [0.51, -1.69],
- [0.3, -1.84],
- [-0.3, -1.23],
- [0.71, -1.53],
- [0.41, -1.84],
- [0.1, -1.23],
- [1.22, -1.38],
- [1.01, -1.99],
- [-0.3, 2.61],
- [-0.51, 1.84],
- [-0.1, 1.69],
- [0, 1.38],
- [0.3, 2.15],
- [0.61, 1.69],
- [1.32, 0.31],
- [0.81, -0.92],
- [0.41, -1.99],
- [-0.1, -1.53],
- [0, -1.99],
- [0.51, -1.23],
- [0.41, -1.23],
- [0, -1.07],
- [1.93, -0.15],
- [1.11, 0],
- [1.01, -0.92],
- [1.32, -1.23],
- [1.22, -0.61],
- [0.81, -0.92],
- [0.81, -1.69],
- [1.32, -1.07],
- [0.71, -1.07],
- [0.71, -0.61],
- [0.2, -1.07],
- [0.81, 0.15],
- [0.61, -0.61],
- [1.52, 0],
- [1.32, 0.31],
- [1.42, 0.46],
- [1.32, 0.61],
- [1.22, 0.46],
- [1.72, 0.31],
- [1.22, 0.31]
- ]);
-
- Leo.append(img);
-
- // Leo.append(left1, leftmid, leftmid2, leftLast, leftHole, right1, right2, right3, right4);
-
-
- Leo.render();
- Leo.positionInspector('[{r%x}, {r%y}],');
- // Leo.positionInspector();
};
diff --git a/index.html b/index.html
old mode 100755
new mode 100644
diff --git a/index2.html b/index2.html
new file mode 100644
index 0000000..53b8209
--- /dev/null
+++ b/index2.html
@@ -0,0 +1,226 @@
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
+
+
+ s
+ =
+
+ v
+ 0
+
+ t
+ +
+
+ 1
+ 2
+
+ a
+
+ t
+ 2
+
+
+
+
+
+
\ No newline at end of file
diff --git a/leo_uoullet_index.js b/leo_uoullet_index.js
deleted file mode 100644
index ef15a42..0000000
--- a/leo_uoullet_index.js
+++ /dev/null
@@ -1,210 +0,0 @@
-window.onload = function () {
-
- function render() {
- console.log(Leonardo);
- var target = document.getElementById('trg'),
-
- width = 1050,
- height = 100,
-
-
- letters = 7
- bxHeight = height,
- bxWidth = width / letters,
- prop = width / height,
-
- Leo = Leonardo(width, height, { ns: '*', target: target }).setStyles({
- // backgroundColor: '#222222aa'
- }),
- w = Leonardo.getScaler(width), //function (p) { return width * p / 100; },
- h = Leonardo.getScaler(height), //function (p) { return height * p / 100; },
- img = Leo.image(0, 0, width, height, './uoullet.jpg').setAttributes({ opacity: 0.4 }),
- fillStyle = {
- "stroke-width": 2,
- "stroke-opacity": 1,
- "fill-opacity": 10,
- "stroke-linejoin": "round",
- "stroke": '#fff',
- fill: '#ffffff55'
- },
- gridStyle = {...fillStyle, "stroke-width": 2, "stroke-opacity": 0.2,"stroke": '#fff',},
- boxStyle = {...fillStyle, "stroke-width": 2, "stroke-opacity": 0.2,"stroke": '#00f',},
-
- crunch = Leo.positionCruncher(width, height, fillStyle),
- crunchClose = Leo.positionCruncher(width, height, fillStyle, true),
-
- gap = w(0.5),
- hGapMul = h(4),
- wGapMul = w(0.8),
- bx1 = Leo.group(
- Leo.rect(0, 0, bxWidth, bxHeight).setAttributes(boxStyle),
- Leo.group(
- Leo.line(0, gap, bxWidth, gap),
- Leo.line(0, gap*hGapMul, bxWidth, gap*hGapMul),
- Leo.line(0, gap*(hGapMul+1), bxWidth, gap*(hGapMul+1)),
- Leo.line(0, bxHeight-gap,bxWidth,bxHeight-gap),
- Leo.line(0,bxHeight-gap*hGapMul,bxWidth,bxHeight-gap*hGapMul),
- Leo.line(0,bxHeight-gap*(hGapMul+1),bxWidth,bxHeight-gap*(hGapMul+1)),
-
-
- Leo.line(gap, 0, gap, bxHeight),
- Leo.line(gap*wGapMul,0,gap*wGapMul,bxHeight),
- Leo.line(bxWidth - gap,0,bxWidth - gap,bxHeight),
- Leo.line(bxWidth - gap*wGapMul,0,bxWidth - gap*wGapMul,bxHeight),
-
- ).setAttributes(gridStyle)
- ),
- bx2 = bx1.clone(),
- bx3 = bx1.clone(),
- bx4 = bx1.clone(),
- bx5 = bx1.clone(),
- bx6 = bx1.clone(),
- bx7 = bx1.clone()
- u1 = Leo.path(
- Leo.pathBuild
- .M(gap, gap*hGapMul)
- .L(gap, bxHeight - gap*hGapMul)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, gap*wGapMul, bxHeight - gap)
- .L(bxWidth - gap*wGapMul, bxHeight - gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, bxWidth - gap, bxHeight - gap*hGapMul)
- .L(bxWidth - gap, gap*hGapMul)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, bxWidth - gap*wGapMul, gap)
-
- .L(bxWidth - gap*wGapMul - 10, gap)
- .A(10, gap*hGapMul, 0, 0, 1, bxWidth - gap*wGapMul, gap*(hGapMul+1))
- .L(bxWidth - gap*wGapMul, bxHeight - gap*(hGapMul+1))
- .A(gap, gap, 0, 0, 1, bxWidth - gap*wGapMul - gap, bxHeight - gap*(hGapMul+1)+gap)
- .L(gap*wGapMul + gap, bxHeight - gap*hGapMul)
- .A(gap, gap, 0, 0, 1, gap*wGapMul, bxHeight - gap*hGapMul - gap)
- .L(gap*wGapMul, gap*(hGapMul+1))
- .A(10, gap*hGapMul, 0, 0, 1, gap*wGapMul + 10, gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, gap, gap*hGapMul)
- .Z()
-
- // .L(gap*(wGapMul+4), bxHeight - gap*hGapMul)
- // .A(gap*wGapMul + 10, bxHeight - gap*hGapMul, 0, 0, 1, gap*wGapMul, bxHeight - gap*(hGapMul+1))
- // .L(gap*wGapMul, gap*(hGapMul+1))
-
- // .L(bxWidth - gap*wGapMul - 10, gap)
-
- // .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, gap, gap*hGapMul)
- // .Z()
- ),
- o = Leo.path(
- Leo.pathBuild
- .M(gap, gap*hGapMul)
- .L(gap, bxHeight - gap*hGapMul)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, gap*wGapMul, bxHeight - gap)
- .L(bxWidth - gap*wGapMul, bxHeight - gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, bxWidth - gap, bxHeight - gap*hGapMul)
- .L(bxWidth - gap, gap*hGapMul)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, bxWidth - gap*wGapMul, gap)
- .L(gap*wGapMul, gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, gap, gap*hGapMul)
- .M(gap*wGapMul+gap, gap*hGapMul)
- .L(bxWidth-gap*wGapMul -gap, gap*hGapMul)
- .A(gap, gap, 0,0,1,bxWidth-gap*wGapMul, gap*hGapMul + gap)
- .L(bxWidth-gap*wGapMul, bxHeight - gap*hGapMul - gap)
- .A(gap, gap, 0,0,1,bxWidth-gap*wGapMul -gap, bxHeight - gap*hGapMul)
- .L(gap*wGapMul+gap, bxHeight - gap*hGapMul)
- .A(gap, gap, 0,0,1,gap*wGapMul, bxHeight - gap*hGapMul-gap)
- .L(gap*wGapMul, gap*hGapMul+gap)
- .A(gap, gap, 0,0,1,gap*wGapMul+gap, gap*hGapMul)
- .Z()
-
- ).move(bxWidth, 0),
- l1 = Leo.path(
- Leo.pathBuild
- .M(gap, gap*hGapMul)
- .L(gap, bxHeight - gap*hGapMul)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, gap*wGapMul, bxHeight - gap)
- .L(bxWidth - gap*wGapMul, bxHeight - gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, bxWidth - gap, bxHeight - gap*hGapMul)
- .L(bxWidth - wGapMul*gap/2, bxHeight - hGapMul*gap - wGapMul*gap/2)
- .A(wGapMul*gap/2, wGapMul*gap/2, 0, 0, 1, bxWidth - wGapMul*gap/2 - wGapMul*gap/2, bxHeight - hGapMul*gap)
- .L(wGapMul*gap + gap, bxHeight - hGapMul*gap)
- .A(gap, gap, 0, 0, 1, wGapMul*gap + gap - gap, bxHeight - hGapMul*gap - gap)
- .L(wGapMul*gap, hGapMul*gap + gap)
- .A(10, gap*hGapMul, 0, 0, 1, gap*wGapMul + 10, gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, gap, gap*hGapMul)
- .Z()
-
- ).move(bxWidth*3, 0),
- l2 = l1.clone().move(bxWidth*4, 0),
-
- eMidDist = bxWidth*7/10,
- e = Leo.path(
- Leo.pathBuild
- .M(gap, gap*hGapMul)
- .L(gap, bxHeight - gap*hGapMul)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, gap*wGapMul, bxHeight - gap)
- .L(bxWidth - gap*wGapMul, bxHeight - gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, bxWidth - gap, bxHeight - gap*hGapMul)
- .L(bxWidth - wGapMul*gap/2, bxHeight - hGapMul*gap - wGapMul*gap/2)
- .A(wGapMul*gap/2, wGapMul*gap/2, 0, 0, 1, bxWidth - wGapMul*gap/2 - wGapMul*gap/2, bxHeight - hGapMul*gap)
- .L(wGapMul*gap + gap, bxHeight - hGapMul*gap)
- .A(gap, gap, 0, 0, 1, wGapMul*gap + gap - gap, bxHeight - hGapMul*gap - gap)
-
- .L(wGapMul*gap, bxHeight/2 + hGapMul*gap/2)
- .L(eMidDist, bxHeight/2 + hGapMul*gap/2)
- .L(eMidDist, bxHeight/2 + 3*gap)
- .A(2*gap, 3*gap, 0, 0, 0, eMidDist, bxHeight/2 - 3*gap)
- .L(eMidDist, bxHeight/2 - hGapMul*gap/2)
- .L(wGapMul*gap, bxHeight/2 - hGapMul*gap/2)
- .L(wGapMul*gap, hGapMul*gap + gap)
- .A(gap, gap, 0, 0, 1, wGapMul*gap+gap, hGapMul*gap)
- .L(bxWidth - wGapMul*gap, hGapMul*gap)
- .A(wGapMul*gap/2, wGapMul*gap/2, 0, 0, 1, bxWidth - wGapMul*gap/2,hGapMul*gap + wGapMul*gap/2)
- .L(bxWidth-gap, hGapMul*gap + gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, bxWidth - wGapMul*gap, gap)
- .L(gap*wGapMul, gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 0, gap, gap*hGapMul)
- .Z()
-
- ).move(bxWidth*5, 0),
- t = Leo.path(
- Leo.pathBuild
- .M(gap, hGapMul*gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 1, wGapMul*gap, gap)
- .L(bxWidth - wGapMul*gap, gap)
- .A(gap*wGapMul, gap*hGapMul, 0, 0, 1, bxWidth - gap, gap*hGapMul)
- .L(bxWidth - wGapMul*gap/2,hGapMul*gap + wGapMul*gap/2)
- .A(wGapMul*gap/2, wGapMul*gap/2, 0, 0, 0, bxWidth - wGapMul*gap, hGapMul*gap)
- .L(wGapMul*gap*2, hGapMul*gap)
- .A(gap, gap, 0, 0, 0, wGapMul*gap*2 - gap, hGapMul*gap + gap)
- .L(wGapMul*gap*2 - gap, bxHeight - hGapMul*gap - gap)
- .L(wGapMul*gap*2 - gap+ 5*gap, bxHeight - gap)
- .A(wGapMul*gap*2, gap+hGapMul*gap, 0,0,1, wGapMul*gap, bxHeight - hGapMul*gap - gap)
- .L(wGapMul*gap, hGapMul*gap)
- .A(wGapMul*gap/2, wGapMul*gap/2, 0, 0, 0, wGapMul*gap/2, hGapMul*gap + wGapMul*gap/2)
- .L(gap, hGapMul*gap)
- .Z()
-
- ).move(bxWidth*6, 0)
- u2 = u1.clone().move(bxWidth * 2, 0),
-
- g = Leo.group(
- u1,
- o,
- u2,
- l1, l2,
- e,t
- ).setAttributes({...fillStyle, "stroke": '#000', fill: '#00228877'});
-
- // Leo.append(img);
- Leo.append(g);
-
-
-
-
-
- Leo.render();
- // Leo.positionInspector('[{r%x}, {r%y}],');
- Leo.downloadAnchor('download', 'uoullet', document.body);
-
-
- }
- render();
- window.addEventListener('resize', render);
-
-}
diff --git a/media/base.jpg b/media/base.jpg
new file mode 100644
index 0000000..04e64a5
Binary files /dev/null and b/media/base.jpg differ
diff --git a/media/front.png b/media/front.png
new file mode 100644
index 0000000..7b691e2
Binary files /dev/null and b/media/front.png differ
diff --git a/media/frontsmall.png b/media/frontsmall.png
new file mode 100644
index 0000000..0a60ec9
Binary files /dev/null and b/media/frontsmall.png differ
diff --git a/media/uoullet.jpg b/media/old/uoullet.jpg
similarity index 100%
rename from media/uoullet.jpg
rename to media/old/uoullet.jpg
diff --git a/media/uoulletBig.jpg b/media/old/uoulletBig.jpg
similarity index 100%
rename from media/uoulletBig.jpg
rename to media/old/uoulletBig.jpg
diff --git a/media/uoullet.png b/media/uoullet.png
new file mode 100644
index 0000000..7d1c7bf
Binary files /dev/null and b/media/uoullet.png differ
diff --git a/media/uoullet.svg b/media/uoullet.svg
new file mode 100644
index 0000000..5e57d53
--- /dev/null
+++ b/media/uoullet.svg
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Uoullet
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Uoullet
+ 9 Feb 2026
+
+
+ Federico Ghedina
+
+
+
+
+
+
diff --git a/media/uoulletSph.svg b/media/uoulletSph.svg
new file mode 100644
index 0000000..48b0b53
--- /dev/null
+++ b/media/uoulletSph.svg
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Uoullet
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Uoullet
+ 9 Feb 2026
+
+
+ Federico Ghedina
+
+
+
+
+
+
diff --git a/package.json b/package.json
index 4f393d5..bb069ac 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@fedeghe/leonardo",
- "version": "1.0.43",
+ "version": "1.1.0",
"description": "A simple library to draw sgv programmatically",
"main": "dist/index.js",
"author": "Federico Ghedina ",
@@ -10,19 +10,18 @@
"test": "test"
},
"scripts": {
- "test": "jest",
- "watch": "jest --watch",
- "cover": "jest --coverage",
- "coverw": "jest --coverage --watch",
- "coveralls": "jest --coverage && cat ./coverage/lcov.info | coveralls",
+ "test": "jest --roots ./tests",
+ "watch": "jest --watch --roots ./tests",
+ "cover": "jest --coverage --roots ./tests",
+ "coverw": "jest --coverage --watch --roots ./tests",
"start": "malta source/start.json",
- "dist": "malta source/build.json",
+ "build": "malta source/build.json",
"clean": "malta source/clean.json"
},
"devDependencies": {
- "coveralls": "^3.1.1",
"jest": "^29.5.0",
"jest-environment-jsdom": "^29.5.0",
+ "jest-fetch-mock": "^3.0.3",
"malta": "^4.1.37",
"malta-browser-refresh": "^1.2.16",
"malta-del": "^1.0.7",
@@ -32,7 +31,6 @@
"malta-less": "^1.0.12",
"malta-svg2png": "^1.0.8"
},
- "dependencies": {},
"repository": {
"type": "git",
"url": "git+https://github.com/fedeghe/leonardo.git"
diff --git a/source/README.md b/source/README.md
index 5fe1b79..fbabaea 100755
--- a/source/README.md
+++ b/source/README.md
@@ -1,4 +1,4 @@
-# please find something to change here
+# know more about Leonardo
First of all you need to install all develoment dependencies:
```
@@ -13,7 +13,7 @@ Run
```
> yarn start
```
-a test folder will be created in the root; all source file are watched and will trigger the unminified build of the `dist/index.js` and a development server will serve ssome demos on [http://localhost:8787](http://localhost:8787).
+a test folder will be created in the root; all source files are watched and will trigger the unminified build of the `dist/index.js` and a development server will serve some demos on [http://localhost:8787](http://localhost:8787).
While this watched build is running it is also possible to lauch a couple of tests riunning
```
@@ -22,7 +22,10 @@ While this watched build is running it is also possible to lauch a couple of tes
## distribution build
+
+When done with the development shut down the process started with `> yarn start`. Now you can get the minified version just running
+
```
> yarn build
```
-this will not go in watch mode and will output the minified version of `dist/index.js`
+this will **not** go in watch mode and will output the minified version of `dist/index.js`
diff --git a/source/build.json b/source/build.json
index f5ba49a..a4b38b4 100755
--- a/source/build.json
+++ b/source/build.json
@@ -1,6 +1,6 @@
{
"EXE": [
- "rm -rf dist demo media",
+ "rm -rf dist media",
"mkdir dist",
"cp -R source/media ."
],
diff --git a/source/clean.json b/source/clean.json
index f343425..ad2c89a 100755
--- a/source/clean.json
+++ b/source/clean.json
@@ -1,6 +1,6 @@
{
"EXE" : [
- "rm -rf demo media",
+ "rm -rf demo media coverage",
"rm index.html srv.js"
]
}
\ No newline at end of file
diff --git a/source/demo/53hotseconds.json b/source/demo/53hotseconds.json
deleted file mode 100755
index 64a1998..0000000
--- a/source/demo/53hotseconds.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "EXE": [
- "mkdir -p demo/53hotseconds/js demo/53hotseconds/css",
- "cp source/demo/53hotseconds/53.jpeg demo/53hotseconds/"
- ],
- "source/demo/53hotseconds/index.js": "demo/53hotseconds/js -vars=source/vars.json",
- "source/demo/53hotseconds/index.less": "demo/53hotseconds/css -plugins=malta-less -vars=source/vars.json",
- "source/demo/53hotseconds/index.html": "demo/53hotseconds -plugins=malta-browser-refresh -vars=source/vars.json"
-}
\ No newline at end of file
diff --git a/source/demo/53hotseconds/53.jpeg b/source/demo/53hotseconds/53.jpeg
deleted file mode 100644
index 1236e05..0000000
Binary files a/source/demo/53hotseconds/53.jpeg and /dev/null differ
diff --git a/source/demo/53hotseconds/index.html b/source/demo/53hotseconds/index.html
deleted file mode 100755
index 7ad1f1f..0000000
--- a/source/demo/53hotseconds/index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- $$../_commonHead.html$$
- $DEMO.53HOTSECONDS.TITLE$
-
-
-
- ...
-
-
-
-
\ No newline at end of file
diff --git a/source/demo/53hotseconds/index.js b/source/demo/53hotseconds/index.js
deleted file mode 100755
index 6cb86e5..0000000
--- a/source/demo/53hotseconds/index.js
+++ /dev/null
@@ -1,71 +0,0 @@
-window.onload = function () {
- var target = document.getElementById('trg'),
- // REF
- devSize = 2**10,
- width = devSize,
- height = devSize,
- zoom = 1,
- L = Leonardo(width * zoom, height * zoom, {id : 'hero', target}),
- title = L.title('53 hot seconds'),
- container = L.group(),
- logo = L.group(),
-
- // w = function (i) {return width * i/1E3 * zoom;},
- // h = function (i) {return height * i/1E3 * zoom;},
- w = L.getScaler(width, 1e3, zoom),
- h = L.getScaler(height, 1e3, zoom),
-
- bg = L.rect(0,0,w(1000),h(1000)).setAttributes({
- fill:'#FF0000',
- rx: h(140),
- ry: h(140)
- }),
- image = L.image(0,0,width, height, './53.jpeg').setAttributes({opacity: 0.2});
- attrs = {
- "stroke-width" : h(20),
- "stroke" : 'white',
- "stroke-opacity" : 1,
- "fill-opacity" : 1,
- "stroke-linejoin" : "round",
- fill : 'none'
- },
- l = 700
- p1 = L.path(L.pathBuild
- .M(w(150), h(130))
- .L(w(l), h(130))
- .A(w(11), h(10), 0,0,1, w(l), h(460))
- .A(w(11), h(10), 0,0,1, w(l), h(870))
- .L(w(150), h(870))
- .L(w(80), h(840))
- .L(w(80), h(l))
- .L(w(300), h(l))
- .A(w(10), h(10), 0,0,0, w(300), h(550))
- .L(w(80), h(550))
- .L(w(80), h(550))
- .L(w(80), h(160))
- .Z()
- ).setAttributes(attrs).setAttributes({fill:'#000'}),
- p2 = L.path(L.pathBuild
- .M(w(215), h(270))
- .L(w(l), h(270))
- .A(w(5), h(5), 0,0,1, w(l), h(375))
- .L(w(425), h(375))
- .A(w(250), h(250), 0,0,1, w(550), h(550))
- .L(w(l), h(550))
- .A(w(10), h(10), 0,0,1, w(l), h(700))
- .L(w(490), h(700))
- .A(w(250), h(250), 0,0,0, w(210), h(370))
- .Z()
- ).setAttributes(attrs).setAttributes({fill:'#F00'}),
-
- container.setAttributes({
- viewBox : "0 0 " + width + " " + height
- }).append(bg);
-
- // container.append(image);
-
- L.append(title, container, p1, p2);
-
- L.render();
- document.body.appendChild(L.downloadAnchor());
-};
\ No newline at end of file
diff --git a/source/demo/53hotseconds/index.less b/source/demo/53hotseconds/index.less
deleted file mode 100755
index fb431a6..0000000
--- a/source/demo/53hotseconds/index.less
+++ /dev/null
@@ -1,11 +0,0 @@
-body {
- background-color: #5585aa;
- margin : 0 auto;
- text-align:center;
- margin-top: 100px;
- font-family: verdana, sans;
- svg {
- outline: 1px solid black;
- }
-
-}
\ No newline at end of file
diff --git a/source/demo/53hotseconds2/index.js b/source/demo/53hotseconds2/index.js
index ccd25cb..b524d1d 100755
--- a/source/demo/53hotseconds2/index.js
+++ b/source/demo/53hotseconds2/index.js
@@ -26,7 +26,12 @@ window.onload = function () {
{perc: "80", color: "#13a"},
{perc: "90", color: "#73a"},
{perc: "100", color: "#f43"},
- ], '0%', '0%', '100%', '100%'),
+ ], {
+ x1: '0%',
+ y1: '0%',
+ x2: '100%',
+ y2: '100%'
+ }),
bg = L.rect(0,0,w(1000),h(1000)).setAttributes({
fill:grad,
rx: h(140),
@@ -101,5 +106,5 @@ window.onload = function () {
, p1, p2);
L.render();
- document.body.appendChild(L.downloadAnchor());
+ document.body.appendChild(L.svgDownloadAnchor());
};
\ No newline at end of file
diff --git a/source/demo/53hotseconds3/index.js b/source/demo/53hotseconds3/index.js
index d760594..612317d 100755
--- a/source/demo/53hotseconds3/index.js
+++ b/source/demo/53hotseconds3/index.js
@@ -26,15 +26,30 @@ window.onload = function () {
{perc: 80, color: "#13a"},
{perc: 90, color: "#73a"},
{perc: 100, color: "#f43"},
- ], '0%', '0%', '100%', '100%'),
+ ], {
+ x1: '0%',
+ y1: '0%',
+ x2: '100%',
+ y2: '100%'
+ }),
gradIn = L.linearGradient([
{perc: 0, color: "#000"},
{perc: 100, color: "#222"},
- ], '0%', '0%', '100%', '100%'),
+ ], {
+ x1: '0%',
+ y1: '0%',
+ x2: '100%',
+ y2: '100%'
+ }),
gradIn2 = L.linearGradient([
{perc: 0, color: "#000"},
{perc: 100, color: "#222"},
- ], '0%', '0%', '130%', '130%'),
+ ], {
+ x1: '0%',
+ y1: '0%',
+ x2: '130%',
+ y2: '130%'
+ }),
bg = L.rect(0,0,w(1000),h(1000)).setAttributes({
// fill:'#000',
fill: gradIn,
@@ -103,5 +118,5 @@ window.onload = function () {
, gp);
L.render();
- document.body.appendChild(L.downloadAnchor());
+ document.body.appendChild(L.svgDownloadAnchor());
};
\ No newline at end of file
diff --git a/source/demo/53hotsecondsOld/53.jpeg b/source/demo/53hotsecondsOld/53.jpeg
deleted file mode 100644
index 1236e05..0000000
Binary files a/source/demo/53hotsecondsOld/53.jpeg and /dev/null differ
diff --git a/source/demo/53hotsecondsOld/index.html b/source/demo/53hotsecondsOld/index.html
deleted file mode 100755
index 7ad1f1f..0000000
--- a/source/demo/53hotsecondsOld/index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- $$../_commonHead.html$$
- $DEMO.53HOTSECONDS.TITLE$
-
-
-
- ...
-
-
-
-
\ No newline at end of file
diff --git a/source/demo/53hotsecondsOld/index.js b/source/demo/53hotsecondsOld/index.js
deleted file mode 100755
index 3f0c05d..0000000
--- a/source/demo/53hotsecondsOld/index.js
+++ /dev/null
@@ -1,95 +0,0 @@
-window.onload = function () {
- var target = document.getElementById('trg'),
- // REF
- devSize = 2**10,
- width = devSize,
- height = devSize,
- zoom = 1,
- L = Leonardo(width * zoom, height * zoom, {id : 'hero', target}),
- title = L.title('53 hot seconds'),
- container = L.group(),
- logo = L.group(),
-
- w = function (i) {return width * i/1E3 * zoom;},
- h = function (i) {return height * i/1E3 * zoom;},
-
- bg = L.rect(0,0,w(1000),h(1000)).setAttributes({
- fill: L.radialGradient([
- { perc: 10, color: '#000000' },
- { perc: 20, color: '#330000' },
- { perc: 90, color: '#cc0000' },
- { perc: 100, color: '#ee0000' },
- ]),
- rx: h(140),
- ry: h(140)
- }),
- oneOnRad2 = w(500) / Math.sqrt(2),
- mid = w(80),
- lines = [
- L.line(0,0,w(1000),h(1000)),
- L.line(w(1000),0,0,h(1000)),
- L.line(w(500),0,w(500),h(1000)),
- L.line(w(0),h(500),w(1000),h(500)),
- L.circle(w(500), h(500), h(500)),
- L.rect(w(500) -oneOnRad2, w(500) -oneOnRad2, 2*oneOnRad2, 2*oneOnRad2),
- L.rect(mid, mid, w(1000)- 2 * mid, h(1000)- 2 * mid),
- ].map(l => l.setAttributes({
- 'font-weight':'bold',
- "stroke": '#ffffff',
- opacity:'0.3',
- fill: 'transparent'
- })),
-
- family = "Verdana", //Arial
-
- J = L.text(w(40), h(532), "5").setAttributes({
- 'font-size' : h(600),
- 'font-family' : family,
- "stroke-width": h(20),
- 'font-weight':'bold',
- "stroke": '#ffffff',
- fill:'black'
- }),
- S = L.text(w(512), h(532), "3").setAttributes({
- 'font-size' : h(600),
- 'font-family' : family,
- "stroke-width": h(20),
- 'font-weight':'bold',
- "stroke": '#ffffff',
- fill:'black'
- }),
- J2 = J.clone().move(w(10), h(10)).setAttributes({
- 'opacity' : 0.4
- }),
- S2 = S.clone().move(w(10), h(10)).setAttributes({
- 'opacity' : 0.4
- }),
- hot = L.text(w(248), h(770), "HOT").setAttributes({
- 'font-size' : h(200),
- 'font-family' : family,
- // "stroke-width": h(10),
- // "stroke": '#ffffff',
- 'font-weight':'bold',
- fill:'white'
- }),
- seconds = L.text(w(171), h(916), "seconds").setAttributes({
- 'font-size' : h(150),
- 'font-family' : family,
- // "stroke-width": h(10),
- // "stroke": '#ffffff',
- 'font-weight':'bold',
- fill:'white'
- });
-
- container.setAttributes({
- viewBox : "0 0 " + width + " " + height
- }).append(bg);
-
- logo.append(J, J2, S, S2, hot, seconds, lines);
-
- container.append(logo);
- L.append(title, container);
-
- L.render();
- document.body.appendChild(L.downloadAnchor());
-};
\ No newline at end of file
diff --git a/source/demo/53hotsecondsOld/index.less b/source/demo/53hotsecondsOld/index.less
deleted file mode 100755
index fb431a6..0000000
--- a/source/demo/53hotsecondsOld/index.less
+++ /dev/null
@@ -1,11 +0,0 @@
-body {
- background-color: #5585aa;
- margin : 0 auto;
- text-align:center;
- margin-top: 100px;
- font-family: verdana, sans;
- svg {
- outline: 1px solid black;
- }
-
-}
\ No newline at end of file
diff --git a/source/demo/_commonHead.html b/source/demo/_commonHead.html
index 8b06d50..1ba186f 100644
--- a/source/demo/_commonHead.html
+++ b/source/demo/_commonHead.html
@@ -6,14 +6,6 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source/demo/animate/index.html b/source/demo/animate/index.html
index 2421caf..bd5e0c9 100755
--- a/source/demo/animate/index.html
+++ b/source/demo/animate/index.html
@@ -24,24 +24,37 @@
...
- $$x = f(t) = w / 2 * sin(t)$$
- $$y = f(t) = h / 2 * sin(t / 4)$$
+$$
+\left\{
+ \begin{array}{l}
+ x = f(t) = w/2 * sin(t)\\\\
+ y = g(t) = h/2 * sin(t/4)
+ \end{array}
+\right.
+$$
...
- $$r = f(t) = w / 2 * sin(t / 20)$$
- $$\rho = f(t) = t \bmod 360$$
+$$
+\left\{
+ \begin{array}{l}
+ r = f(t) = w / 2 * sin^2(t / 20)\\\\
+ \theta = g(t) = t \bmod 2\pi
+ \end{array}
+\right.
+$$
+
+
...
- $$x = f(t) = w*.8 * cos(t)$$
- $$y = f(t) = h / 2 * cos(1.5*t mod 2π)$$
+ use of
animate.motionPath on ♾️ path
M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z
diff --git a/source/demo/animate/index.js b/source/demo/animate/index.js
index a41abc3..d52ee3e 100755
--- a/source/demo/animate/index.js
+++ b/source/demo/animate/index.js
@@ -16,10 +16,12 @@ window.onload = function () {
func: 'cartesian',
target: target1,
color: '#f45',
- initial: [w2,h2],
+ initial: [w2, h2],
funcs: [
function (x, t){ return w2 * Math.sin(speed * t); },
- function (y, t){ return h2 * Math.sin(speed * t / 4); }
+ function (y, t){ return h2 * Math.sin(speed * t / 8); },
+ 0.05,
+ {trace: {style:{fill:'#33882266',stroke:'none', r: 0.5}}}
]
},{
func: 'polar',
@@ -27,31 +29,41 @@ window.onload = function () {
color: '#45f',
initial: [width / 2, height / 2],
funcs: [
- function (r, t){ return min/2 * Math.sin(speed * t / 20);},
- function (rho, t){ return speed * t % 360; }
- ]
- },{
- func: 'cartesian',
- target: target3,
- color: '#f45',
- initial: [w2,h2],
- funcs: [
- function (x, t){ return w2*.8 * Math.cos(speed * t); },
- function (y, t){ return h2*.8 * Math.cos((1.5*t)%(2*Math.PI)+speed); }
+ function (r, t){ return min/2 * Math.cos(speed * t / 10);},
+ function (rho, t){ return speed * t % (2*Math.PI) },
+ 0.05,
+ // {trace: {style:{fill:'#00ff0055', r: 4, stroke: '#ff000099', 'stroke-width': 1}}}
]
}];
els.forEach(function(o) {
- var Lx = Leonardo(width, height, { ns: '*', target: o.target }),
+ var Lx = Leonardo(width, height, { ns: '*', target: o.target }).sas({
+ fill: '#eee'
+ }),
+ bg = Lx.rect(0, 0, 2*w2, 2*h2),
circle = Lx.circle.apply(null, o.initial.concat(10)).setAttributes({fill: o.color}),
extra = Lx.Element('text').setAttributes({fill: o.color}).move(w(2), h(5));
extra.tag.innerHTML = o.func;
Lx.animate[o.func].apply(null, [circle].concat(o.funcs));
- Lx.append(circle, extra).render();
+ Lx.append(bg, circle, extra).render();
});
- })();
+ //4
+ (function (){
+ var Lx = Leonardo(width, height, { ns: '*', target: target3 }),
+ path = Lx.path('M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z').sas({
+ stroke: "black",
+ "stroke-linecap": "round",
+ "stroke-dasharray": "5,10,5",
+ fill: "none"
+ }).move(w2*5/9,h2*7/9),
+ text = Lx.text(w2*1/6,h2*2/7,'😋').scale(3);
+
+ Lx.animate.motionPath(text, "M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z",{
+ dur: 2
+ });
+ Lx.append(text, path).render();
+ })();
-
- // document.body.appendChild(L.downloadAnchor());
+ })();
};
\ No newline at end of file
diff --git a/source/demo/circles/index.js b/source/demo/circles/index.js
index ea92e51..e3fe9c0 100755
--- a/source/demo/circles/index.js
+++ b/source/demo/circles/index.js
@@ -72,7 +72,9 @@ window.onload = function () {
Leo.append(c1);
}
var now = +new Date,
+ // every second add one
ti = setInterval(addCircle, 1E3);
+ // after 100 seconds stop adding
setTimeout(function () {clearInterval(ti)}, 1E5);
Leo.render();
}
diff --git a/source/demo/conway.json b/source/demo/conway.json
new file mode 100755
index 0000000..e73e7ed
--- /dev/null
+++ b/source/demo/conway.json
@@ -0,0 +1,8 @@
+{
+ "EXE": [
+ "mkdir -p demo/conway/js demo/conway/css"
+ ],
+ "source/demo/conway/index.js": "demo/conway/js -vars=source/vars.json",
+ "source/demo/conway/index.less": "demo/conway/css -plugins=malta-less -vars=source/vars.json",
+ "source/demo/conway/index.html": "demo/conway -plugins=malta-browser-refresh -vars=source/vars.json"
+}
\ No newline at end of file
diff --git a/source/demo/map/index.html b/source/demo/conway/index.html
similarity index 100%
rename from source/demo/map/index.html
rename to source/demo/conway/index.html
diff --git a/source/demo/map/index.js b/source/demo/conway/index.js
similarity index 78%
rename from source/demo/map/index.js
rename to source/demo/conway/index.js
index 16a9a5c..a11564a 100755
--- a/source/demo/map/index.js
+++ b/source/demo/conway/index.js
@@ -26,42 +26,32 @@ window.onload = function () {
}
Cell.prototype.setState = function (s) {this.alive = s;};
- function Matrix (target,) {
+
+
+ function Matrix (target) {
var self = this;
- this.target = target;
+
this.data = Array.from({ length: gridNum}, (_, i) =>
- Array.from({ length: gridNum}, (_, j) => new Cell(i, j, Math.random() > 0.5))
+ Array.from({ length: gridNum}, (_, j) => {
+ var c = new Cell(i, j, Math.random() > 0.5)
+ c.tag.on('click', function(e) {
+ if (e.shiftKey) {
+ getNeighbours(self.data, c.x, c.y).forEach(n => n && n.setState(true));
+ } else {
+ c.setState(true);
+ }
+ });
+ c.tag.on('mouseover', function(e) {
+ if(e.metaKey) {
+ getNeighbours(self.data, c.x, c.y).forEach(n => n && n.setState(true));
+ }
+ })
+ return c
+ })
);
- this.data.forEach(row => row.forEach(cell => self.target.append(cell.tag)));
+ this.data.forEach(row => row.forEach(cell => target.append(cell.tag)));
}
-
- function getNeighbours(mat, r, c) {
- var els = border ? {
- rPlus: (r + 1 + gridNum) % gridNum,
- rMinus: (r - 1 + gridNum) % gridNum,
- cPlus: (c + 1 + gridNum) % gridNum,
- cMinus: (c - 1 + gridNum) % gridNum,
- } : {
- rPlus: r+1,
- rMinus: r-1,
- cPlus: c+1,
- cMinus: c-1,
- };
- return [
- mat?.[els.rMinus]?.[els.cMinus],
- mat?.[els.rMinus]?.[c],
- mat?.[els.rMinus]?.[els.cPlus],
- mat?.[r]?.[els.cMinus],
-
- // mat?.[r]?.[c],
-
- mat?.[r]?.[els.cPlus],
- mat?.[els.rPlus]?.[els.cMinus],
- mat?.[els.rPlus]?.[c],
- mat?.[els.rPlus]?.[els.cPlus],
- ]
- }
Matrix.prototype.getAliveNeighboursCount = function (r, c) {
var self = this,
neighbours = getNeighbours(this.data, r, c);
@@ -77,7 +67,6 @@ window.onload = function () {
(_, j) => {
var n = self.getAliveNeighboursCount(i, j),
newState = false; //default death
-
if (n === 2) {
newState = self.data[i][j].alive;
} else if (n === 3) {
@@ -101,18 +90,40 @@ window.onload = function () {
requestAnimationFrame(() => self.calculateNextState())
};
+ function getNeighbours(mat, r, c) {
+ var els = border ? {
+ rPlus: (r + 1 + gridNum) % gridNum,
+ rMinus: (r - 1 + gridNum) % gridNum,
+ cPlus: (c + 1 + gridNum) % gridNum,
+ cMinus: (c - 1 + gridNum) % gridNum,
+ } : {
+ rPlus: r+1,
+ rMinus: r-1,
+ cPlus: c+1,
+ cMinus: c-1,
+ };
+ return [
+ mat?.[els.rMinus]?.[els.cMinus],
+ mat?.[els.rMinus]?.[c],
+ mat?.[els.rMinus]?.[els.cPlus],
+ mat?.[r]?.[els.cMinus],
+
+ // mat?.[r]?.[c],
+
+ mat?.[r]?.[els.cPlus],
+ mat?.[els.rPlus]?.[els.cMinus],
+ mat?.[els.rPlus]?.[c],
+ mat?.[els.rPlus]?.[els.cPlus],
+ ]
+ }
+
- var m = new Matrix(L
- // , [
- // [1,1], [1,2], [1,3]
- // [2,2], [2,3]
- // ]
- );
+ var m = new Matrix(L);
m.calculateNextState();
L.render({target: document.getElementById('trg')});
- document.body.appendChild(L.downloadAnchor());
+ document.body.appendChild(L.svgDownloadAnchor());
};
\ No newline at end of file
diff --git a/source/demo/conway/index.less b/source/demo/conway/index.less
new file mode 100755
index 0000000..45829dc
--- /dev/null
+++ b/source/demo/conway/index.less
@@ -0,0 +1,6 @@
+body{
+ background-color: black;
+ svg{
+ outline:1px dashed white
+ }
+}
\ No newline at end of file
diff --git a/source/demo/cver.json b/source/demo/cver.json
deleted file mode 100755
index aab4ed4..0000000
--- a/source/demo/cver.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "EXE": [
- "mkdir -p demo/cver/js demo/cver/css"
- ],
- "source/demo/cver/index.js": "demo/cver/js -vars=source/vars.json",
- "source/demo/cver/index.less": "demo/cver/css -plugins=malta-less -vars=source/vars.json",
- "source/demo/cver/index.html": "demo/cver -plugins=malta-browser-refresh -vars=source/vars.json"
-}
\ No newline at end of file
diff --git a/source/demo/cver/index.html b/source/demo/cver/index.html
deleted file mode 100755
index 592cdd2..0000000
--- a/source/demo/cver/index.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
- $$../_commonHead.html$$
- $DEMO.CVER.TITLE$
-
-
-
- ...
-
-
-
-
-
\ No newline at end of file
diff --git a/source/demo/cver/index.js b/source/demo/cver/index.js
deleted file mode 100755
index 5577d6b..0000000
--- a/source/demo/cver/index.js
+++ /dev/null
@@ -1,73 +0,0 @@
-window.onload = function () {
- var target = document.getElementById('trg'),
- Leo = Leonardo(600, 250, { ns: '*', target: target }),
- main = Leo.group(),
- c = Leo.group(),
- v = Leo.group(),
- e = Leo.group(),
- r = Leo.group(),
- stroke = 10;
- c.append(Leo.polygon(0,50, 50,0, 150,0, 100,50, 150,100, 50,100).setAttributes({
- fill : 'green',
- "stroke-width" : stroke,
- stroke : 'black',
- 'stroke-linejoin': 'round'
- }));
- v.append(Leo.polygon(0,50, 50,0, 100,50, 125,25, 175,25, 75,125).setAttributes({
- fill : 'white',
- "stroke-width" : stroke,
- stroke : 'black',
- 'stroke-linejoin': 'round'
- }));
- e.append(Leo.polygon(0,100, -25,75, 75,-25, 125,25, 100,50, 125,75, 100,100).setAttributes({
- fill : 'white',
- "stroke-width" : stroke,
- stroke : 'black',
- 'stroke-linejoin': 'round'
- }));
- e.append(Leo.polyline(50,25, 75,25, 100,50).setAttributes({
- fill : 'transparent',
- "stroke-width" : stroke,
- stroke : 'black',
- 'stroke-linecap': 'round',
- 'stroke-linejoin': 'round'
- }));
- e.append(Leo.polyline(50,75, 75,75, 100,50).setAttributes({
- fill : 'transparent',
- "stroke-width" : stroke,
- stroke : 'black',
- 'stroke-linecap': 'round',
- 'stroke-linejoin': 'round'
- }));
- r.append(Leo.polygon(0,0, 100,0, 150,50, 125,75, 150,100, 100,100, 75,75, 50,100, 0,100, 25,75, 0,50, 25,25).setAttributes({
- fill : 'red',
- "stroke-width" : stroke,
- stroke : 'black',
- 'stroke-linejoin': 'round'
- }));
- main.append(
- c,
- v.move(100),
- e.move(250),
- r.move(350)
- ).setAttributes({
- filter: Leo.filter([
- {type:'feDropShadow',
- attrs:{
- dx:5,
- dy:5,
- stdDeviation:"2.5",
- "flood-color":"gray",
- "flood-opacity":"6.5"
- }
- },
- ])
- })
-
- Leo.append(main.move(40, 90));
- Leo.render();
- document.body.appendChild(Leo.downloadAnchor())
-
- var img = Leo.toImageTag();
- target.appendChild(img);
-}
diff --git a/source/demo/cver/index.less b/source/demo/cver/index.less
deleted file mode 100755
index eeed0b2..0000000
--- a/source/demo/cver/index.less
+++ /dev/null
@@ -1,9 +0,0 @@
-body{
- margin:0;
- padding:0;
- #trg{
- svg{
- border:1px solid white
- }
- }
-}
\ No newline at end of file
diff --git a/source/demo/extra.json b/source/demo/extra.json
new file mode 100755
index 0000000..f7f045a
--- /dev/null
+++ b/source/demo/extra.json
@@ -0,0 +1,8 @@
+{
+ "EXE": [
+ "mkdir -p demo/extra/js demo/extra/css"
+ ],
+ "source/demo/extra/index.js": "demo/extra/js -vars=source/vars.json",
+ "source/demo/extra/index.less": "demo/extra/css -plugins=malta-less -vars=source/vars.json",
+ "source/demo/extra/index.html": "demo/extra -plugins=malta-browser-refresh -vars=source/vars.json"
+}
\ No newline at end of file
diff --git a/source/demo/malta/index.html b/source/demo/extra/index.html
similarity index 81%
rename from source/demo/malta/index.html
rename to source/demo/extra/index.html
index 9a29967..3a4aaae 100755
--- a/source/demo/malta/index.html
+++ b/source/demo/extra/index.html
@@ -2,7 +2,7 @@
$$../_commonHead.html$$
- $DEMO.MALTA.TITLE$
+ $DEMO.EXTRA.TITLE$
diff --git a/source/demo/extra/index.js b/source/demo/extra/index.js
new file mode 100755
index 0000000..6ef814d
--- /dev/null
+++ b/source/demo/extra/index.js
@@ -0,0 +1,74 @@
+window.onload = function () {
+ var target = document.getElementById('trg'),
+ width = 800,
+ height = 800,
+ L = Leonardo(width, height, {target : target}),
+ g = L.group();
+
+
+
+
+
+ g.append(
+ L.textBox('Some text here', 500, 80, {
+ fill: 'red',
+ stroke:'white',
+ 'font-size': '2em',
+ 'font-family': 'verdana',
+ 'font-weight': 'bold'
+ }, {fill: 'green'}, 190),
+ L.textPath(
+ L.pathBuild
+ .M(10, 300)
+ .A(100, 100, 0,0,0, 200, 100),
+ 'T e x t P a t h - I s - T h e r e - F o r - Y o u'
+ ).sas({
+ fill:'yellow'
+ }),
+
+ L.path(L.arcSectionPath(400, 200, 0, 70, 0, 90), {
+ stroke:'green',
+ 'stroke-width': 5,
+ fill: 'white'
+ }),
+
+ L.path(L.arcSectionPath(400, 200, 30, 60, 30, 105), {
+ stroke:'red',
+ 'stroke-width': 5,
+ fill: 'gray'
+ }),
+
+ L.path(L.arcSectionPath(400, 200, 50,120, 95, 280), {
+ stroke:'blue',
+ 'stroke-width': 3,
+ fill: '#ff770055'
+ }),
+ L.path(L.arcSectionPath(400, 200, 0, 90, 160, 270), {
+ stroke:'red',
+ 'stroke-width': 1,
+ "stroke-linejoin": 'round',
+ fill: '#ffffff66'
+ }),
+ L.path(L.arcSectionPath(400, 200, 50, 80, 270, 320), {
+ stroke:'red',
+ 'stroke-width': 1,
+ "stroke-linejoin": 'round',
+ fill: '#ff000055'
+ }),
+ L.path(L.arcSectionPath(400, 200, 20, 50, 290, 340), {
+ stroke:'orange',
+ 'stroke-width': 1,
+ "stroke-linejoin": 'round',
+ fill: 'transparent'
+ }),
+ L.path(L.arcSectionPath(400, 600, 20, 50, 0, 320,0,1), {
+ stroke:'orange',
+ 'stroke-width': 1,
+ "stroke-linejoin": 'round',
+ fill: 'green'
+ })
+ );
+
+ L.append(g);
+ L.render();
+};
\ No newline at end of file
diff --git a/source/demo/lotkavolterra/index.less b/source/demo/extra/index.less
similarity index 100%
rename from source/demo/lotkavolterra/index.less
rename to source/demo/extra/index.less
diff --git a/source/demo/fg/index.js b/source/demo/fg/index.js
index 2d0d06a..82f162b 100755
--- a/source/demo/fg/index.js
+++ b/source/demo/fg/index.js
@@ -48,5 +48,5 @@ window.onload = function () {
Leo.render();
Leo.positionInspector();
- document.body.appendChild(Leo.downloadAnchor())
+ document.body.appendChild(Leo.svgDownloadAnchor())
}
diff --git a/source/demo/filters/index.js b/source/demo/filters/index.js
index 70231bb..17f742e 100755
--- a/source/demo/filters/index.js
+++ b/source/demo/filters/index.js
@@ -17,7 +17,7 @@ function getShapeWithText(type, text, shapeAttrs, textAttrs) {
g.append(shape, textt);
return g;
}
-function getShapeWithCenteredText(type, text, shapeAttrs, textAttrs) {
+function getShapeWithTextBox(type, text, shapeAttrs, textAttrs) {
shapeAttrs = shapeAttrs || {}
textAttrs = textAttrs || {}
var size = 300,
@@ -34,7 +34,7 @@ function getShapeWithCenteredText(type, text, shapeAttrs, textAttrs) {
return Leo.rect(size*0.1,size*0.1,size*0.8, size*0.8).setAttributes(shapeAttrs)
},
}[type](),
- ctext = Leo.centeredText(size, size, text, textAttrs);
+ ctext = Leo.textBox(text, size, size, textAttrs);
g.append(shape, ctext);
return g;
@@ -44,12 +44,21 @@ function getShapeWithCenteredText(type, text, shapeAttrs, textAttrs) {
window.onload = function () {
var target = document.getElementById('trg'),
Leo = Leonardo(900, 900, { ns: '*', target: target }),
- main = Leo.group();
+ main = Leo.group(),
+ grad1 = Leo.linearGradient([
+ {perc: "0", color: "rgb(67, 57, 31)"},
+ {perc: "50", color: "#f60"},
+ ],{
+ x1: '0%',
+ y1: '0%',
+ x2: '100%',
+ y2: '100%'
+ });
main.append(
getShapeWithText('circle', 'Hello', {fill: 'red'}).setAttributes({
- filter: Leo.filter([
+ filter: Leo.filter(
{type:'feDropShadow',
attrs:{
dx:5,
@@ -59,10 +68,10 @@ window.onload = function () {
"flood-opacity":"6.5"
}
},
- ])
+ )
}),
- getShapeWithCenteredText('rect', 'Hello', {fill: '#e5e5e5'}, {fill: 'blue', 'font-size': '38'}).setAttributes({
- filter: Leo.filter([
+ getShapeWithTextBox('rect', 'Hello', {fill: '#e5e5e5'}, {fill: 'blue', 'font-size': '38'}).setAttributes({
+ filter: Leo.filter(
{type:'feDropShadow',
attrs:{
dx:5,
@@ -72,16 +81,18 @@ window.onload = function () {
"flood-opacity":"6.5"
}
},
- ])
+ )
}).move(300, 0),
- getShapeWithText('circle', 'Hello', {fill: 'green'}).setAttributes({
- filter: Leo.filter([
+
+
+ getShapeWithText('circle', 'Hello', {fill: grad1}).setAttributes({
+ filter: Leo.filter(
{
type:'feTurbulence',
attrs:{
type:"turbulence",
- baseFrequency:"0.2",
- numOctaves:"20",
+ baseFrequency:".02",
+ numOctaves:"2",
result:"turbulence"
}
},
@@ -90,15 +101,23 @@ window.onload = function () {
attrs:{
in2:"turbulence",
in:"SourceGraphic",
- scale:"30",
+ scale:"20",
xChannelSelector:"R",
yChannelSelector:"G"
}
},
- ])
+
+ {
+ type:'feConvolveMatrix',
+ attrs:{
+ kernelMatrix:"0 1 0 1 0 1 0 -5 0"
+ }
+ },
+ )
}).move(600, 0),
- getShapeWithCenteredText('square', 'Hello world', {}, {fill: 'yellow', 'font-size': '28', 'font-family': 'verdana'}).setAttributes({
- filter: Leo.filter([
+
+ getShapeWithTextBox('square', 'Hello world', {}, {fill: 'yellow', 'font-size': '28', 'font-family': 'verdana'}).setAttributes({
+ filter: Leo.filter(
{
type:'feDropShadow',
attrs:{
@@ -109,13 +128,13 @@ window.onload = function () {
"flood-opacity":"6.5"
}
},
- ])
+ )
}).move(0, 300),
// based on https://codepen.io/olawanlejoel/pen/jOBBRjd
Leo.path('M18.258,3.266c-0.693,0.405-1.46,0.698-2.277,0.857c-0.653-0.686-1.586-1.115-2.618-1.115c-1.98,0-3.586,1.581-3.586,3.53c0,0.276,0.031,0.545,0.092,0.805C6.888,7.195,4.245,5.79,2.476,3.654C2.167,4.176,1.99,4.781,1.99,5.429c0,1.224,0.633,2.305,1.596,2.938C2.999,8.349,2.445,8.19,1.961,7.925C1.96,7.94,1.96,7.954,1.96,7.97c0,1.71,1.237,3.138,2.877,3.462c-0.301,0.08-0.617,0.123-0.945,0.123c-0.23,0-0.456-0.021-0.674-0.062c0.456,1.402,1.781,2.422,3.35,2.451c-1.228,0.947-2.773,1.512-4.454,1.512c-0.291,0-0.575-0.016-0.855-0.049c1.588,1,3.473,1.586,5.498,1.586c6.598,0,10.205-5.379,10.205-10.045c0-0.153-0.003-0.305-0.01-0.456c0.7-0.499,1.308-1.12,1.789-1.827c-0.644,0.28-1.334,0.469-2.06,0.555C17.422,4.782,17.99,4.091,18.258,3.266').setAttributes({
fill: '#4691f6',
- filter: Leo.filter([
+ filter: Leo.filter(
{
type:'feOffset',
attrs:{
@@ -164,13 +183,13 @@ window.onload = function () {
in2:'SourceGraphic'
}
},
- ])
+ )
}).scale(15,15).move(300, 300),
)
Leo.append(main);
Leo.render();
- document.body.appendChild(Leo.downloadAnchor())
+ document.body.appendChild(Leo.svgDownloadAnchor())
}
diff --git a/source/demo/g-hero.json b/source/demo/g-hero.json
deleted file mode 100755
index cd6e026..0000000
--- a/source/demo/g-hero.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "EXE": [
- "mkdir -p demo/g-hero/js demo/g-hero/css"
- ],
- "source/demo/g-hero/index.js": "demo/g-hero/js -vars=source/vars.json",
- "source/demo/g-hero/index.less": "demo/g-hero/css -plugins=malta-less -vars=source/vars.json",
- "source/demo/g-hero/index.html": "demo/g-hero -plugins=malta-browser-refresh -vars=source/vars.json"
-}
\ No newline at end of file
diff --git a/source/demo/g-hero/index.html b/source/demo/g-hero/index.html
deleted file mode 100755
index 3fe7ac2..0000000
--- a/source/demo/g-hero/index.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
- $$../_commonHead.html$$
- $DEMO.GHERO.TITLE$
-
-
-
- ...
-
-
-
-
-
\ No newline at end of file
diff --git a/source/demo/g-hero/index.js b/source/demo/g-hero/index.js
deleted file mode 100755
index 6c53bed..0000000
--- a/source/demo/g-hero/index.js
+++ /dev/null
@@ -1,121 +0,0 @@
-window.onload = function () {
-
- var target = document.getElementById('trg'),
- ratio = 3,
- size = 1000,
- width = size,
- height = size / ratio,
- center = {
- x : width / 2,
- y : height / 2
- },
- L = Leonardo(width, height, {id : 'hero', target}),
- title = L.title('hero'),
- container = L.group(),
- w = L.getScaler(width),
- h = L.getScaler(height),
- s = L.getScaler(Math.min(width, height)),
- bgcolor = 'rgba(200, 200, 200, 1)'
- base = L.rect(0, 0, width, height).setAttributes({
- fill : bgcolor
- }),
- stroke = h(17),
-
- textStyle={
- "stroke-width" : stroke,
- "stroke" : 'black',
- // "font-size": h(80),
- // "stroke-opacity" : h(0.1),
- "stroke-linejoin" : "round",
- // "font-family": 'impact',
- // "stroke-width" : stroke,
- fill : 'transparent'
- },
- boldLine = {
- // "stroke-width" : stroke,
-
- "stroke" : 'black',
- // "font-size": h(80),
- // "stroke-opacity" : h(1),
-
- "stroke-linejoin" : "round",
- // "stroke-linejoin" : "arcs",
- // "font-family": 'impact',
- fill : 'transparent'
- },
- arrowStyle = {
- "stroke" : 'blue',
- "stroke-width" : stroke,
- "stroke-opacity" : 1,
- "stroke-linejoin" : "round",
- },
-
-
- G = L.path(L.pathBuild
- .M(s(25), s(70))
- .a(s(15), s(15), 0, 0, 0, s(30), 0)
- .l(s(0), s(-30))
- .a(s(15), s(15), 0, 0, 0, s(-30), 0)
- .a(s(15), s(15), 0, 0, 0, s(30), 0)
- ).setAttributes(textStyle).move(s(-5), 0),
-
- H = L.path(L.pathBuild
- .M(s(120), s(20)-stroke/2)
- .l(0, s(80))
- .m(0, s(-10))
- .a(s(10), s(10), 0,0,1, s(20), s(0))
- .l(s(0), s(14))
- // .Z()
- ).setAttributes(textStyle),
-
- E = L.path(L.pathBuild
- .M(s(165), s(60))
- .l(s(20), 0)
- .a(s(14), s(14), 0,1,0, s(-0), s(15))
- ).setAttributes(textStyle),
-
- R = L.path(L.pathBuild
- .M(s(210), s(50))
- .l(s(0), s(40))
- .m(s(0), s(-10))
- .a(s(20), s(20), 0,0,1, s(20), s(-20))
- .l(s(10), 0)
-
- ).setAttributes(textStyle),
-
- O = L.path(L.pathBuild
- .M(s(255), s(70))
- .a(s(15), s(15), 0,0,1, s(30), s(0))
- .a(s(15), s(15), 0,0,1, s(-30), s(0))
-
-
- ).setAttributes(textStyle),
-
- HERO = L.text(w(40), h(80), 'HERO').setAttributes({
- "text-align" : 'right',
- ...textStyle
- }),
- GIZMO = L.group(),
- arrPos = { x: w(30), y: h(20)},
- r = h(60),
-
- arrow = L.polyline(
- arrPos.x, arrPos.y,
- arrPos.x, arrPos.y + r,
- arrPos.x + w(5), arrPos.y + r - h(10),
- arrPos.x - w(5), arrPos.y + r - h(10),
- arrPos.x, arrPos.y + r,
- ).setAttributes(arrowStyle).move(s(-5), 0);
- GIZMO.append(arrow);
-
-
- container.setAttributes({viewBox : "0 0 " + size + " " + size});
-
- container.append(base, G, H, E, R, O, GIZMO);
-
- L.append(title, container);
-
- L.render();
- document.body.appendChild(L.downloadAnchor('download as svg'))
-
-};
\ No newline at end of file
diff --git a/source/demo/g-hero/index.less b/source/demo/g-hero/index.less
deleted file mode 100755
index eeed0b2..0000000
--- a/source/demo/g-hero/index.less
+++ /dev/null
@@ -1,9 +0,0 @@
-body{
- margin:0;
- padding:0;
- #trg{
- svg{
- border:1px solid white
- }
- }
-}
\ No newline at end of file
diff --git a/source/demo/g-hero2.json b/source/demo/g-hero2.json
deleted file mode 100755
index 2e3e451..0000000
--- a/source/demo/g-hero2.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "EXE": [
- "mkdir -p demo/g-hero2/js demo/g-hero2/css"
- ],
- "source/demo/g-hero2/index.js": "demo/g-hero2/js -vars=source/vars.json",
- "source/demo/g-hero2/index.less": "demo/g-hero2/css -plugins=malta-less -vars=source/vars.json",
- "source/demo/g-hero2/index.html": "demo/g-hero2 -plugins=malta-browser-refresh -vars=source/vars.json"
-}
\ No newline at end of file
diff --git a/source/demo/g-hero2/index.html b/source/demo/g-hero2/index.html
deleted file mode 100755
index 3fe7ac2..0000000
--- a/source/demo/g-hero2/index.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
- $$../_commonHead.html$$
- $DEMO.GHERO.TITLE$
-
-
-
- ...
-
-
-
-
-
\ No newline at end of file
diff --git a/source/demo/g-hero2/index.js b/source/demo/g-hero2/index.js
deleted file mode 100755
index d0bb0e5..0000000
--- a/source/demo/g-hero2/index.js
+++ /dev/null
@@ -1,54 +0,0 @@
-window.onload = function () {
-
- var target = document.getElementById('trg'),
- ratio = 3,
- size = 900,
- width = size,
- height = size / ratio,
- center = {
- x : width / 2,
- y : height / 2
- },
- L = Leonardo(width, height, {id : 'hero', target}),
- title = L.title('hero'),
- container = L.group(),
- w = L.getScaler(width),
- h = L.getScaler(height),
-
- bgcolor = 'rgba(200, 200, 200, 1)'
- base = L.rect(0, 0, width, height).setAttributes({
- fill : bgcolor,
- }),
- G = L.text(w(12), h(58), 'g↓').setAttributes({
- "font-size": h(50),
- "font-family": 'times',
- }),
- HERO = L.text(w(32), h(80), 'HERO').setAttributes({}),
- GIZMO = L.group(),
-
- stroke = 10,
- r = h(30),
- color2 = 'blue',
- TRI = L.polyline(w(30), h(95), w(35), h(80), w(25), h(80)).setAttributes({fill : color2})
-
- justLine = {
- // "stroke-width" : h(8),
- "stroke" : 'black',
- "font-size": h(80),
- "stroke-opacity" : h(0.1),
-
- "stroke-linejoin" : "round",
- "font-family": 'impact',
- fill : 'black'
- };
-
- container.setAttributes({viewBox : "0 0 " + size + " " + size, ...justLine});
-
- container.append(base, G, HERO);
-
- L.append(title, container);
-
- L.render();
- document.body.appendChild(L.downloadAnchor('download as svg'))
-
-};
\ No newline at end of file
diff --git a/source/demo/g-hero2/index.less b/source/demo/g-hero2/index.less
deleted file mode 100755
index eeed0b2..0000000
--- a/source/demo/g-hero2/index.less
+++ /dev/null
@@ -1,9 +0,0 @@
-body{
- margin:0;
- padding:0;
- #trg{
- svg{
- border:1px solid white
- }
- }
-}
\ No newline at end of file
diff --git a/source/demo/gbelt/index.html b/source/demo/gbelt/index.html
index 7b59f78..f1c49e2 100755
--- a/source/demo/gbelt/index.html
+++ b/source/demo/gbelt/index.html
@@ -10,6 +10,9 @@
...
+
\ No newline at end of file
diff --git a/source/demo/gbelt/index.js b/source/demo/gbelt/index.js
index 7e3ea70..c6758e4 100755
--- a/source/demo/gbelt/index.js
+++ b/source/demo/gbelt/index.js
@@ -2,14 +2,94 @@ window.onload = function () {
var target = document.getElementById('trg'),
prop = 350/350,
// width = Math.min(987, window.innerWidth-50),
- width = window.innerWidth,
+ width = 1050,
height = parseInt(width / prop, 10),
Leo = Leonardo(width, height, { ns: '*', target: target }),
- main = Leo.group();
+ main = Leo.group(),
img = Leo.image(0,0,width, height, './gbelt.png').setAttributes({opacity: 0.4}),
- main.append(img);
+ attrs = {
+ "stroke-width" : 5,
+ "stroke" : 'red',
+ "stroke-opacity" : 1,
+ "fill-opacity" : 1,
+ "stroke-linejoin" : "round",
+ fill : 'none'
+ },
+ tbox = Leo.textBox('Leonardo centered', 250, 30, {
+ "font-size" : 22,
+ "fill" : '#aa0000',
+ "font-family" : 'Verdana, sans-serif',
+ "stroke" : '#000000',
+ "text-anchor" : 'middle'
+ },{fill: '#fede76'});
+ main.append(img, tbox);
+
Leo.append(main);
+ var p1 = Leo.bezierThroughPoints([
+ [138, 735],
+ [124, 818],
+ [121, 903],
+ [126, 941],
+ [132, 961],
+ [308, 1001],
+ [328, 988],
+ [323, 957],
+ [319, 869],
+ [331, 792],
+ [334, 769],
+ [317, 769],
+ [315, 790],
+ [308, 819],
+ [304, 875],
+ [305, 959],
+ ]).setAttributes(attrs),
+ p2 = Leo.bezierThroughPoints([
+ [202, 734],
+ [190, 812],
+ [188, 905],
+ [193, 941],
+ ]).setAttributes({
+ ...attrs,
+ "stroke-dasharray" : "20,10",
+ stroke : 'blue'
+ }),
+ p3 = Leo.bezierThroughPoints([
+ [605, 284],
+ [545, 492],
+ [526, 620],
+ [549, 821],
+ [661, 802],
+ [748, 576],
+ [766, 310],
+ [714, 128],
+ [556, 68],
+ [426, 256]
+ ]).setAttributes({
+ ...attrs,
+ "stroke-dasharray" : "10,10",
+ stroke : 'green'
+ }),
+ s1 = Leo.bezierThroughPoints([
+ [219, 423],
+ [189, 527],
+ [177, 633],
+ [243, 649],
+ [309, 659],
+ [323, 540],
+ [348, 433],
+ [283, 421]
+ ]).setAttributes({
+ ...attrs,
+ fill : 'orange',
+ }),
+ p4 = Leo.bezierThroughPoints([
+ [347, 1019],
+ [98, 982],
+ [107, 718],
+ [365, 756]
+ ]).setAttributes(attrs);
+ Leo.append(p1, p2, p3, s1, p4);
Leo.render();
- Leo.positionInspector('[{r%x}, {r%y}],');
-}
+ Leo.positionInspector({tpl: '[{x}, {y}],'});
+};
diff --git a/source/demo/god/index.js b/source/demo/god/index.js
index baaeb3f..d0e537e 100755
--- a/source/demo/god/index.js
+++ b/source/demo/god/index.js
@@ -282,8 +282,8 @@ window.onload = function () {
Leo.render();
- Leo.positionInspector('[{r%x}, {r%y}],');
- document.body.appendChild(Leo.downloadAnchor());
+ Leo.positionInspector({tpl: '[{r%x}, {r%y}],'});
+ document.body.appendChild(Leo.svgDownloadAnchor());
}
render();
window.addEventListener('resize', render);
diff --git a/source/demo/gradients/index.html b/source/demo/gradients/index.html
index 7ad1f1f..ce51c69 100755
--- a/source/demo/gradients/index.html
+++ b/source/demo/gradients/index.html
@@ -8,6 +8,7 @@
...
+ ...
diff --git a/source/demo/gradients/index.js b/source/demo/gradients/index.js
index d2359e3..57360d0 100755
--- a/source/demo/gradients/index.js
+++ b/source/demo/gradients/index.js
@@ -1,46 +1,56 @@
window.onload = function () {
- var target = document.getElementById('trg'),
+ var target1 = document.getElementById('trg'),
+ target2 = document.getElementById('trg2'),
+
// REF
devSize = 2**10,
width = devSize,
height = devSize,
zoom = 1,
- L1 = Leonardo(width * zoom, height * zoom, {id : 'hero1', target}),
- container = L1.group(),
+ L1 = Leonardo(width * zoom, height * zoom, {id : 'hero1', target: target1}),
+ L2 = Leonardo(width * zoom, height * zoom, {id : 'hero2', target: target2}),
+ container1 = L1.group(),
+ container2 = L2.group(),
-
- // w = function (i) {return width * i/1E3 * zoom;},
- // h = function (i) {return height * i/1E3 * zoom;},
w = L1.getScaler(width, 1e3, zoom),
h = L1.getScaler(height, 1e3, zoom),
grad1 = L1.linearGradient([
- {perc: "0", color: "#f00"},
- {perc: "10", color: "#f60"},
- {perc: "20", color: "#fa0"},
- {perc: "30", color: "#ff0"},
- {perc: "40", color: "#5f8"},
- {perc: "50", color: "#3a3"},
- {perc: "60", color: "#58f"},
- {perc: "70", color: "#15f"},
- {perc: "80", color: "#13a"},
- {perc: "90", color: "#73a"},
- {perc: "100", color: "#f43"},
- ],'0%', '0%', '100%','100%'),
+ "#f00", "#f60", "#fa0",
+ "#ff0", "#5f8", "#3a3",
+ "#58f", "#15f", "#13a",
+ "#73a", "#f43",
+ ], {
+ x1: '0%',
+ y1: '0%',
+ x2: '100%',
+ y2: '100%'
+ }),
+ grad2 = L1.radialGradient([
+ "#f00", "#f60", "#fa0",
+ "#ff0", "#5f8", "#3a3",
+ "#58f", "#15f", "#13a",
+ "#73a", "#f43",
+ ], {
+ r: '60%',
+ spreadMethod: 'reflect',
+ }),
bg1 = L1.rect(0,0,w(1000),h(1000)).setAttributes({
- fill:grad1,
- // rx: h(140),
- // ry: h(140)
+ fill:grad1
+ }),
+ bg2 = L1.rect(0,0,w(1000),h(1000)).setAttributes({
+ fill:grad2
});
-
- container.setAttributes({
+ container1.setAttributes({
viewBox : "0 0 " + width + " " + height
}).append(bg1);
-
- // container.append(image);
-
- L1.append(container);
-
+ L1.append(container1);
L1.render();
+
+ container2.setAttributes({
+ viewBox : "0 0 " + width + " " + height
+ }).append(bg2);
+ L2.append(container2);
+ L2.render();
};
\ No newline at end of file
diff --git a/source/demo/hero.json b/source/demo/hero.json
deleted file mode 100755
index 6d8081a..0000000
--- a/source/demo/hero.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "EXE": [
- "mkdir -p demo/hero/js demo/hero/css"
- ],
- "source/demo/hero/index.js": "demo/hero/js -vars=source/vars.json",
- "source/demo/hero/index.less": "demo/hero/css -plugins=malta-less -vars=source/vars.json",
- "source/demo/hero/index.html": "demo/hero -plugins=malta-browser-refresh -vars=source/vars.json"
-}
\ No newline at end of file
diff --git a/source/demo/hero/index.html b/source/demo/hero/index.html
deleted file mode 100755
index 47a924d..0000000
--- a/source/demo/hero/index.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
- $$../_commonHead.html$$
- $DEMO.HERO.TITLE$
-
-
-
- ...
- ...
-
-
-
-
\ No newline at end of file
diff --git a/source/demo/hero/index.js b/source/demo/hero/index.js
deleted file mode 100755
index b53af1d..0000000
--- a/source/demo/hero/index.js
+++ /dev/null
@@ -1,259 +0,0 @@
-window.onload = function () {
-
- var target = document.getElementById('trg'),
- size = 1400,
- width = size/2,
- height = size,
- center = {
- x : width / 2,
- y : height / 2
- },
- L = Leonardo(width, height, {id : 'hero'}),
- title = L.title('hero'),
- container = L.group(),
- // w = function (i) {return i * width/800;},
- // h = function (i) {return i * height/1600;},
- w = L.getScaler(width, 800),
- h = L.getScaler(height, 1600),
-
- vest = L.path(L.pathBuild
- .M(w(300), h(605))
- .L(w(185), h(75))
- .L(w(35), h(125))
- .L(w(210), h(780))
- .L(w(220), h(1000))
- .L(w(70), h(1480))
- .L(w(235), h(1500))
- .L(w(355), h(1010))
-
- .L(w(445), h(1010))
- .L(w(565), h(1500))
- .L(w(730), h(1480))
- .L(w(580), h(1000))
- .L(w(590), h(780))
- .L(w(765), h(125))
- .L(w(615), h(75))
- .L(w(500), h(605))
- .Z()
- ),
- head = L.path(L.pathBuild
- .M(w(360), h(630))
- .L(w(270), h(530))
- .L(w(320), h(340))
- .L(w(480), h(340))
- .L(w(530), h(530))
- .L(w(440), h(630))
- .Z()
- ),
- nose = L.path(L.pathBuild
- .M(w(380), h(525))
- .L(w(385), h(540))
- .L(w(415), h(540))
- .L(w(420), h(525))
- ),
- hair = L.path(L.pathBuild
- .M(w(295), h(440))
- .L(w(270), h(260))
- .L(w(310), h(300))
- .L(w(305), h(325)) //
-
- .L(w(345), h(190))
- .L(w(400), h(305)) //
- .L(w(385), h(275))
-
- .L(w(450), h(180))
- .L(w(438), h(305))//
- .L(w(440), h(290))
-
- .L(w(480), h(220))
- .L(w(490), h(300))
- .L(w(480), h(315))//
- .L(w(530), h(250))
- .L(w(505), h(440))
- .L(w(480), h(340))
-
- .L(w(470), h(390))
- .L(w(440), h(350))
- .L(w(450), h(380)) //ciuff
- .L(w(360), h(345))
- .L(w(370), h(335))
- .L(w(330), h(370))
-
- .L(w(320), h(340))
- .Z()
- ),
- strap = L.path(L.pathBuild
- .M(w(210), h(900))
- .S(w(400), h(925) , w(590), h(900))
- .L(w(585), h(970))
- .S(w(400), h(995), w(215), h(970))
- .Z()
- ),
- eyeStrap = L.path(L.pathBuild
- .M(w(290), h(450))
- .S(w(400), h(480) , w(510), h(450))
- .L(w(518), h(480))
- .S(w(400), h(555), w(282), h(480))
- .Z()
- ),
- H = L.path(L.pathBuild
- .M(w(295), h(680))
- .L(w(305), h(880))
- .L(w(355), h(890))
- .L(w(355), h(850))
- .L(w(445), h(850))
- .L(w(445), h(890))
- .L(w(495), h(880))
- .L(w(505), h(680))
- .L(w(445), h(670))
- .L(w(445), h(810))
- .L(w(355), h(810))
- .L(w(355), h(670))
- .Z()
- ),
-
- rightEye = L.text(0,0,','),
- leftEye = L.text(0,0,','),
- pulpilLeft = L.group(),
- pulpilRight,
- smile = L.text(0,0,')'),
-
- leftGlove = L.path(
- L.pathBuild
- .M(0, 0)
- .L(w(-22), h(-30))
- .L(w(-22), h(-55))
- .L(w(28), h(-110))
- .L(w(63), h(-105))
- .L(w(78), h(-80))
- .L(w(80), h(-100))
- .L(w(100), h(-95))
- .L(w(105), h(-65))
- .L(w(85), h(-28))
- .Z()
- ), rightGlove,
- leftFoot = L.path(L.pathBuild
- .M(0,0)
- .L(w(-10), h(40))
- .L(w(0), h(70))
- .L(w(45), h(110))
- .L(w(70), h(115))
- .L(w(90), h(105))
- .L(w(105), h(65))
- .L(w(100), h(12))
- .Z()
- ),rightFoot,
-
- justLine = {
- "stroke-width" : h(8),
- "stroke" : 'black',
- "stroke-opacity" : 1,
- "fill-opacity" : 1,
- "stroke-linejoin" : "round",
- fill : 'none'
- };
-
- (function () {
- var p1 = L.circle(0,0,w(15)),
- p2 = L.circle(0,0,w(3)),
- coverUp = L.line(w(-20), h(5),w(20),h(18)),
- coverDown = L.line(w(-20),h(-20),w(20),h(-10));
- p1.setAttributes({
- "stroke-width" : h(4),
- "stroke" : 'black',
- fill:'DodgerBlue'
- });
- p2.setAttributes({fill:'black'});
-
- coverUp.setAttributes({
- "stroke-width" : h(9),
- "stroke" : 'black'
- });
- coverDown.setAttributes({
- "stroke-width" : h(9),
- "stroke" : 'black'
- });
-
- pulpilLeft.append(p1, p2, coverDown, coverUp);
-
- pulpilRight = pulpilLeft.clone().mirrorV();
- pulpilLeft.move(w(355),h(490));
- pulpilRight.move(w(445),h(490));
- })();
-
- container.setAttributes({viewBox : "0 0 " + size + " " + size});
-
- leftEye.setAttributes({
- 'font-size' : h(160),
- 'font-family' : 'Verdana',
- color:'black'
- }).rotate(85, w(350), h(460)).move(w(350), h(460));
-
- rightEye.setAttributes({
- 'font-size' : h(160),
- 'font-family' : 'Verdana',
- color:'black'
- }).mirrorH().rotate(95, w(450), h(460)).move(w(450), h(460));
-
- smile.setAttributes({
- 'font-size' : h(100),
- color:'black'
- // }).rotate(90, 0, 0).move(w(10), h(10));
- }).move(w(373), h(540)).rotate(90, w(373), h(540));
-
- vest.setAttributes(justLine);
- vest.setAttributes({fill : 'red'});
-
- nose.setAttributes(justLine);
- head.setAttributes(justLine);
- head.setAttributes({fill : 'pink'});
-
- hair.setAttributes(justLine);
- hair.setAttributes({fill:'yellow'});
-
- strap.setAttributes(justLine);
- strap.setAttributes({fill : 'chocolate'});
-
- eyeStrap.setAttributes(justLine);
- eyeStrap.setAttributes({fill :"black"});
-
- rightEye.setAttributes({'fill' : 'white'});
- leftEye.setAttributes({'fill' : 'white'});
-
- H.setAttributes(justLine);
- H.setAttributes({fill:'white'});
-
- leftGlove.setAttributes(justLine);
- leftFoot.setAttributes(justLine);
-
- leftGlove.setAttributes({fill:'#444'});
- leftFoot.setAttributes({fill:'#444'});
-
- rightGlove = leftGlove.clone().mirrorV().move(w(740), h(115));
- leftGlove.move(w(60), h(115));
-
- rightFoot = leftFoot.clone().mirrorV().move(w(705), h(1483));
- leftFoot.move(w(95), h(1483));
-
- container.append(
- vest, head, hair, strap, eyeStrap,
- leftEye, rightEye,
- smile, leftGlove, rightGlove,
- leftFoot, rightFoot,
- H, nose
- ,pulpilLeft,pulpilRight
- );
-
- L.append(title, container);
-
- L.render({target: target, cb : function () {
- var p = document.getElementById('point'),
- svg = this.tag;
- svg.style.width = width + 'px';
- svg.style.height = height + 'px';
- svg.addEventListener('mousemove', function (e) {
- p.innerHTML = '[' + e.clientX + ', ' + e.clientY + '] {' + (e.clientX/width).toFixed(3) + ', ' + (e.clientY/height).toFixed(3) + '}';
- },false);
- }});
-
-};
\ No newline at end of file
diff --git a/source/demo/hero/index.less b/source/demo/hero/index.less
deleted file mode 100755
index 28df107..0000000
--- a/source/demo/hero/index.less
+++ /dev/null
@@ -1,10 +0,0 @@
-body {
- background-color: white;
- margin : 0px;
- padding : 0px;
- font-family: verdana, sans;
- svg {
- outline: 1px solid black;
- }
-
-}
\ No newline at end of file
diff --git a/source/demo/index.html b/source/demo/index.html
index b94c09c..9129bcb 100755
--- a/source/demo/index.html
+++ b/source/demo/index.html
@@ -22,38 +22,35 @@
Leonardo demos
Follows a small list of samples I played with while developing Leonardo
diff --git a/source/demo/jshero/index.html b/source/demo/jshero/index.html
deleted file mode 100755
index 4f8692e..0000000
--- a/source/demo/jshero/index.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
- $$../_commonHead.html$$
- $DEMO.JSHERO.TITLE$
-
-
-
- ...
-
-
-
-
\ No newline at end of file
diff --git a/source/demo/jshero/index.js b/source/demo/jshero/index.js
deleted file mode 100755
index e371918..0000000
--- a/source/demo/jshero/index.js
+++ /dev/null
@@ -1,120 +0,0 @@
-window.onload = function () {
- var target = document.getElementById('trg'),
- // REF
- devSize = 512,
- width = devSize,
- height = devSize,
- zoom = 1,
- L = Leonardo(width * zoom, height * zoom, {id : 'hero', target}),
- title = L.title('jshero'),
- container = L.group(),
- logo = L.group(),
- // w = function (i) {return devSize * i/1E3 * zoom;},
- // h = function (i) {return devSize * i/1E3 * zoom;},
- w = L.getScaler(devSize, 1e3, zoom),
- h = L.getScaler(devSize, 1e3, zoom),
-
- fillStyle = {
- "stroke-width": h(80),
- "stroke": '#dd0000',
- "stroke-opacity": 1,
- "fill-opacity": 1,
- "stroke-linejoin": "round",
- fill: '#efda4f'
- },
-
- brdStyle = {
- // "stroke-width": h(20),
- // "stroke": 'black',
- "stroke-opacity": 1,
- "stroke-linejoin": "miter",
- fill: 'none'
- },
-
- bg = L.rect(0,0,w(1000),h(1000)).setAttributes({
- fill: L.radialGradient([
- { perc: 0, color: '#0055aa' },
-
- { perc: 50, color: '#0088ff' },
-
- { perc: 100, color: '#0055aa' },
- ]),
- rx: h(140),
- ry: h(140)
- }),
-
- brdFill = L.path(L.pathBuild
- .M(w(200), h(230))
-
- .L(w(800), h(230))
-
- .L(w(910), h(400))
-
- .L(w(500), h(850))
-
- .L(w(90), h(400))
- .Z()
- ).setAttributes(fillStyle),
-
- brdIn = L.path(L.pathBuild
- .M(w(177), h(190))
- .L(w(823), h(190))
- .L(w(960), h(405))
- .L(w(500), h(910))
- .L(w(40), h(405))
- .Z()
- ).setAttributes(brdStyle),
-
- brdOut = L.path(L.pathBuild
- .M(w(222), h(269))
- .L(w(778), h(269))
- .L(w(860), h(396))
- .L(w(500), h(792))
- .L(w(140), h(396))
- .Z()
- ).setAttributes(brdStyle),
-
- family = "Verdana", //Arial
-
- J = L.text(w(290), h(580), "J").setAttributes({
- 'font-size' : h(400),
- 'font-family' : family,
- "stroke-width": h(50),
- "stroke": '#dd0000',
- color:'black'
- }),
- S = L.text(w(490), h(580), "S").setAttributes({
- 'font-size' : h(400),
- 'font-family' : family,
- "stroke-width": h(50),
- "stroke": '#dd0000',
- color:'black'
- }),
- J2 = J.clone().move(w(10), h(10)).setAttributes({
- 'opacity' : 0.4
- }),
- S2 = S.clone().move(w(10), h(10)).setAttributes({
- 'opacity' : 0.4
- });
-
- container.setAttributes({
- viewBox : "0 0 " + width + " " + height
- }).append(bg);
-
- logo.append(title, brdFill, brdIn, brdOut, J, J2, S, S2)
- .move(0, -20);
-
- container.append(logo);
- L.append(
- // title,
- // bg,
- container.scale(0.8).move(w(35), h(165)).rotate(-8),
- // brdIn,
- // brdOut,
- // J, J2,
- // S, S2
- );
-
- L.render();
- document.body.appendChild(L.downloadAnchor());
-};
\ No newline at end of file
diff --git a/source/demo/jshero/index.less b/source/demo/jshero/index.less
deleted file mode 100755
index fb431a6..0000000
--- a/source/demo/jshero/index.less
+++ /dev/null
@@ -1,11 +0,0 @@
-body {
- background-color: #5585aa;
- margin : 0 auto;
- text-align:center;
- margin-top: 100px;
- font-family: verdana, sans;
- svg {
- outline: 1px solid black;
- }
-
-}
\ No newline at end of file
diff --git a/source/demo/kicker/index.js b/source/demo/kicker/index.js
index 4628d9f..bbc2222 100755
--- a/source/demo/kicker/index.js
+++ b/source/demo/kicker/index.js
@@ -79,7 +79,7 @@ window.onload = function () {
fsize = 200,
image = L.image(0, 0, width, height, 'http://localhost:3001/kicker/css/field.jpg'),
- person = L.centeredText(pwidth, pheight, '', {
+ person = L.textBox('', pwidth, pheight, {
// fill: 'blue',
"stroke-width" : 10,
stroke : 'black',
@@ -93,7 +93,7 @@ window.onload = function () {
defenseUp = L.group().append(
round,
defenseLineExt,
- defenseLineInt
+ defenseLineInt,
).setAttributes({
fill: bgcolor
}),
diff --git a/source/demo/krepo/index.js b/source/demo/krepo/index.js
index 393d0ad..a7b9f69 100755
--- a/source/demo/krepo/index.js
+++ b/source/demo/krepo/index.js
@@ -205,7 +205,7 @@ window.onload = function () {
Leo.render();
- Leo.positionInspector('[{r%x}, {r%y}],');
+ Leo.positionInspector({tpl: '[{r%x}, {r%y}],'});
}
render();
window.addEventListener('resize', render);
diff --git a/source/demo/logos.json b/source/demo/logos.json
new file mode 100755
index 0000000..bc74924
--- /dev/null
+++ b/source/demo/logos.json
@@ -0,0 +1,8 @@
+{
+ "EXE": [
+ "mkdir -p demo/logos/js demo/logos/css"
+ ],
+ "source/demo/logos/index.js": "demo/logos/js -vars=source/vars.json",
+ "source/demo/logos/index.less": "demo/logos/css -plugins=malta-less -vars=source/vars.json",
+ "source/demo/logos/index.html": "demo/logos -plugins=malta-browser-refresh -vars=source/vars.json"
+}
\ No newline at end of file
diff --git a/source/demo/logos/index.html b/source/demo/logos/index.html
new file mode 100644
index 0000000..fe57f4b
--- /dev/null
+++ b/source/demo/logos/index.html
@@ -0,0 +1,15 @@
+
+
+
+ $$../_commonHead.html$$
+ $DEMO.MALTA.LOGOS$
+
+
+
+ b
+ c
+ d
+ d
+
+
+
\ No newline at end of file
diff --git a/source/demo/logos/index.js b/source/demo/logos/index.js
new file mode 100644
index 0000000..e500d6f
--- /dev/null
+++ b/source/demo/logos/index.js
@@ -0,0 +1,411 @@
+window.onload = function () {
+
+ (function() {
+ var target = document.getElementById('trg1'),
+
+ width = 225,
+ height = 80,
+ bricks = [],
+
+ L = Leonardo(width, height, {ns : '*', target : target}),
+ bricksGroup = L.group(),
+ malta = L.path(
+ L.pathBuild.m(60,35)
+ .q(-60,-2, -50, 10)
+ .l(95,30)
+ .q(0,2, 5, 2)
+ .q(5,2, 5, -2)
+ .l(100,-10)
+ .q(5, 0, 5, -20)
+ .q(0, -12, -60, -10)
+ ).setAttributes({
+ fill : '#777',
+ "stroke-width" : 2.5,
+ stroke : 'black'
+ }),
+ brick = L.rect(0, 0, 100, 30).setAttributes({
+ "stroke-width" : 2.5,
+ "stroke-linejoin" : 'round',
+ "stroke" : 'black',
+ fill : 'brown'
+ });
+
+ bricks.push(brick.clone().move(55,0))
+ bricks.push(brick.clone().move(0,40))
+ bricks.push(brick.clone().move(110,40))
+
+ bricksGroup.append(bricks).move(5, 5);
+
+ L.append(malta, bricksGroup);
+
+ L.render();
+
+ target.appendChild(L.svgDownloadAnchor({name: 'malta'}))
+ })();
+
+
+ (function(){
+ var target = document.getElementById('trg2'),
+ Leo = Leonardo(600, 250, { ns: '*', target: target }),
+ main = Leo.group(),
+ c = Leo.group(),
+ v = Leo.group(),
+ e = Leo.group(),
+ r = Leo.group(),
+ stroke = 10;
+ c.append(Leo.polygon(0,50, 50,0, 150,0, 100,50, 150,100, 50,100).setAttributes({
+ fill : 'green',
+ "stroke-width" : stroke,
+ stroke : 'black',
+ 'stroke-linejoin': 'round'
+ }));
+ v.append(Leo.polygon(0,50, 50,0, 100,50, 125,25, 175,25, 75,125).setAttributes({
+ fill : 'white',
+ "stroke-width" : stroke,
+ stroke : 'black',
+ 'stroke-linejoin': 'round'
+ }));
+ e.append(Leo.polygon(0,100, -25,75, 75,-25, 125,25, 100,50, 125,75, 100,100).setAttributes({
+ fill : 'white',
+ "stroke-width" : stroke,
+ stroke : 'black',
+ 'stroke-linejoin': 'round'
+ }));
+ e.append(Leo.polyline(50,25, 75,25, 100,50).setAttributes({
+ fill : 'transparent',
+ "stroke-width" : stroke,
+ stroke : 'black',
+ 'stroke-linecap': 'round',
+ 'stroke-linejoin': 'round'
+ }));
+ e.append(Leo.polyline(50,75, 75,75, 100,50).setAttributes({
+ fill : 'transparent',
+ "stroke-width" : stroke,
+ stroke : 'black',
+ 'stroke-linecap': 'round',
+ 'stroke-linejoin': 'round'
+ }));
+ r.append(Leo.polygon(0,0, 100,0, 150,50, 125,75, 150,100, 100,100, 75,75, 50,100, 0,100, 25,75, 0,50, 25,25).setAttributes({
+ fill : 'red',
+ "stroke-width" : stroke,
+ stroke : 'black',
+ 'stroke-linejoin': 'round'
+ }));
+ main.append(
+ c,
+ v.move(100),
+ e.move(250),
+ r.move(350)
+ ).setAttributes({
+ filter: Leo.filter(
+ {type:'feDropShadow',
+ attrs:{
+ dx:5,
+ dy:5,
+ stdDeviation:"2.5",
+ "flood-color":"gray",
+ "flood-opacity":"6.5"
+ }
+ },
+ )
+ })
+
+ Leo.append(main.move(40, 90));
+ Leo.render();
+ target.appendChild(Leo.svgDownloadAnchor({name: 'cver'}));
+
+ // var img = Leo.toImageTag();
+ // target.appendChild(img);
+ })();
+
+ (function(){
+ var target = document.getElementById('trg3'),
+ // REF
+ devSize = 512,
+ width = devSize,
+ height = devSize,
+ zoom = 1,
+ L = Leonardo(width * zoom, height * zoom, {id : 'hero', target}),
+ title = L.title('jshero'),
+ container = L.group(),
+ logo = L.group(),
+ // w = function (i) {return devSize * i/1E3 * zoom;},
+ // h = function (i) {return devSize * i/1E3 * zoom;},
+ w = L.getScaler(devSize, 1e3, zoom),
+ h = L.getScaler(devSize, 1e3, zoom),
+
+ fillStyle = {
+ "stroke-width": h(80),
+ "stroke": '#dd0000',
+ "stroke-opacity": 1,
+ "fill-opacity": 1,
+ "stroke-linejoin": "round",
+ fill: '#efda4f'
+ },
+
+ brdStyle = {
+ // "stroke-width": h(20),
+ // "stroke": 'black',
+ "stroke-opacity": 1,
+ "stroke-linejoin": "miter",
+ fill: 'none'
+ },
+
+ bg = L.rect(0,0,w(1000),h(1000)).setAttributes({
+ fill: L.radialGradient([
+ { perc: 0, color: '#0055aa' },
+
+ { perc: 50, color: '#0088ff' },
+
+ { perc: 100, color: '#0055aa' },
+ ]),
+ rx: h(140),
+ ry: h(140)
+ }),
+
+ brdFill = L.path(L.pathBuild
+ .M(w(200), h(230))
+
+ .L(w(800), h(230))
+
+ .L(w(910), h(500))
+
+ .L(w(500), h(850))
+
+ .L(w(90), h(400))
+ .Z()
+ ).setAttributes(fillStyle),
+
+ brdIn = L.path(L.pathBuild
+ .M(w(177), h(190))
+ .L(w(823), h(190))
+ .L(w(960), h(405))
+ .L(w(500), h(910))
+ .L(w(40), h(405))
+ .Z()
+ ).setAttributes(brdStyle),
+
+ brdOut = L.path(L.pathBuild
+ .M(w(222), h(269))
+ .L(w(778), h(269))
+ .L(w(860), h(396))
+ .L(w(500), h(792))
+ .L(w(140), h(396))
+ .Z()
+ ).setAttributes(brdStyle),
+
+ family = "Verdana", //Arial
+
+ J = L.text(w(290), h(580), "J").setAttributes({
+ 'font-size' : h(400),
+ 'font-family' : family,
+ "stroke-width": h(50),
+ "stroke": '#dd0000',
+ color:'black'
+ }),
+ S = L.text(w(490), h(580), "S").setAttributes({
+ 'font-size' : h(400),
+ 'font-family' : family,
+ "stroke-width": h(50),
+ "stroke": '#dd0000',
+ color:'black'
+ }),
+ J2 = J.clone().move(w(10), h(10)).setAttributes({
+ 'opacity' : 0.4
+ }),
+ S2 = S.clone().move(w(10), h(10)).setAttributes({
+ 'opacity' : 0.4
+ });
+
+ container.setAttributes({
+ viewBox : "0 0 " + width + " " + height
+ }).append(bg);
+
+ logo.append(title, brdFill, brdIn, brdOut, J, J2, S, S2)
+ .move(0, -20);
+
+ container.append(logo);
+ L.append(
+ // title,
+ // bg,
+ container.scale(0.8).move(w(35), h(165)).rotate(-8),
+ // brdIn,
+ // brdOut,
+ // J, J2,
+ // S, S2
+ );
+
+ L.render();
+ target.appendChild(L.svgDownloadAnchor({name: 'jsHero'}));
+ })();
+
+
+ (function () {
+ var target = document.getElementById('trg4'),
+ width = 500,
+ height = 500,
+ min = width > height ? height : width,
+ wperc = width / 100,
+ hperc = height / 100,
+ mperc = min / 100,
+
+ w = function (n) { return n * wperc; },
+ h = function (n) { return n * hperc; },
+ m = function (n) { return n * mperc; },
+
+ L = Leonardo(width, height, { ns: '*', target: target }),
+ attrs = {
+ cloud: { fill: '#3C3C3B' },
+ thunder: {
+ fill: '#eeee00',
+ stroke: '#ff660077',
+ 'stroke-width': 15
+ },
+ },
+
+ elements = {
+ cloud: [
+ L.circle(w(20), h(50), m(15)),
+ L.circle(w(80), h(50), m(15)),
+ L.circle(w(58), h(33), m(22)),
+ L.circle(w(30), h(33), m(10)),
+ L.rect(w(20), h(35), w(60), h(30)),
+ ],
+ thunder: [
+ L.polygon(
+ w(50), h(0),
+ w(43), h(47),
+ w(67), h(38),
+
+ w(50), h(100),
+ w(57), h(53),
+ w(33), h(62)
+ ),
+ ]
+ },
+ cloud = L.group()
+ .append(elements.cloud)
+ .setAttributes(attrs.cloud),
+ thunder = L.group()
+ .append(elements.thunder)
+ .setAttributes(attrs.thunder)
+ .scale(1, 0.5)
+ .move(0, 200);
+ thunder.append(L.animate.attr({
+ attributeName: 'stroke',
+ values: '#ff660077;#ffaa00aa;#ff660077',
+ dur: '0.3s',
+ repeatCount: 'indefinite'
+ }))
+ thunder.append(L.animate.attr({
+ attributeName: 'fill',
+ values: '#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#eeee00;#fff',
+ dur: '5s',
+ repeatCount: 'indefinite'
+ }))
+
+ L.append(cloud, thunder);
+ L.render();
+
+ target.appendChild(
+ L.pngDownloadAnchor({txt: 'download as png', name: 'synchazard'})
+ );
+ // target.appendChild(L.svgDownloadAnchor({name: 'synchazard'}));
+ })();
+
+
+ (function () {
+ var target = document.getElementById('trg5'),
+ width = 500,
+ height = 100,
+ min = width > height ? height : width,
+ hperc = height / 100,
+ mperc = min / 100,
+
+ L = Leonardo(width, height, { ns: '*', target: target }),
+ w = L.getScaler(width, 1e3),
+ h = L.getScaler(height, 1e3),
+
+
+
+ blackBox = L.rect(0,0,w(700),h(1000)).setAttributes({
+ rx: h(140),
+ ry: h(140),
+ fill: '#222222'
+ }),
+ orangeBox = L.rect(w(600),0,w(400),h(1000)).setAttributes({
+ rx: h(140),
+ ry: h(140),
+ fill: '#048001'
+ }),
+
+ common = {
+ 'font-family': 'verdana',
+ 'font-size': '4rem',
+ 'font-weight': 'bold',
+ }
+ elements = {
+ good: L.text(w(50),75,'dooG').setAttributes({
+ ...common,
+ fill:'#ffffff',
+ 'letter-spacing': 21,
+ filter: L.filter(
+ {type:'feDropShadow',
+ attrs:{
+ dx:0,
+ dy:0,
+ stdDeviation:"5",
+ "flood-color":"#048001",
+ "flood-opacity":"6.5",
+ }
+ },
+ )
+ }),
+ boy: L.text(w(650),75,'yoB').setAttributes({
+ ...common,
+ 'letter-spacing': 10,
+ fill:'#000000',
+ filter: L.filter(
+ {type:'feDropShadow',
+ attrs:{
+ dx:0,
+ dy:0,
+ stdDeviation:"10",
+ "flood-color":"white",
+ "flood-opacity":"6.5",
+ }
+ },
+ )
+ }),
+
+ },
+ g = L.group(
+ blackBox,
+ orangeBox,
+ elements.good, elements.boy
+ )
+ .scale(0.9).sas({
+ filter: L.filter(
+ {type:'feDropShadow',
+ attrs:{
+ dx:5,
+ dy:5,
+ stdDeviation:"1",
+ "flood-color":"#444444",
+ "flood-opacity":"6.5",
+ }
+ },
+ )
+ });
+
+
+
+
+ L.append(g).render();
+
+ target.appendChild(
+ L.pngDownloadAnchor({txt: 'download as png', name: 'dooGyoB'})
+ );
+ // target.appendChild(L.svgDownloadAnchor({name: 'synchazard'}));
+ })();
+};
\ No newline at end of file
diff --git a/source/demo/logos/index.less b/source/demo/logos/index.less
new file mode 100644
index 0000000..5d6d9c4
--- /dev/null
+++ b/source/demo/logos/index.less
@@ -0,0 +1,17 @@
+body{
+ display:flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ div {
+ display: flex;
+ flex:1;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ flex-basis: 50%;
+ }
+ // svg{
+ // border:1px solid black
+ // }
+ background-color: #000;
+}
\ No newline at end of file
diff --git a/source/demo/lotkavolterra.json b/source/demo/lotkavolterra.json
deleted file mode 100755
index 1ebedd2..0000000
--- a/source/demo/lotkavolterra.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "EXE": [
- "mkdir -p demo/lotkavolterra/js demo/lotkavolterra/css"
- ],
- "source/demo/lotkavolterra/index.js": "demo/lotkavolterra/js -vars=source/vars.json",
- "source/demo/lotkavolterra/index.less": "demo/lotkavolterra/css -plugins=malta-less -vars=source/vars.json",
- "source/demo/lotkavolterra/index.html": "demo/lotkavolterra -plugins=malta-browser-refresh -vars=source/vars.json"
-}
\ No newline at end of file
diff --git a/source/demo/lotkavolterra/index.html b/source/demo/lotkavolterra/index.html
deleted file mode 100755
index 12e6a1e..0000000
--- a/source/demo/lotkavolterra/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
- $$../_commonHead.html$$
- $DEMO.LOTKAVOLTERRA.TITLE$
-
-
-
- ...
-
-
-
\ No newline at end of file
diff --git a/source/demo/lotkavolterra/index.js b/source/demo/lotkavolterra/index.js
deleted file mode 100755
index 04db992..0000000
--- a/source/demo/lotkavolterra/index.js
+++ /dev/null
@@ -1,60 +0,0 @@
-window.onload = function () {
- /**
- * x prey
- * y predator
- *
- * ∂x
- * ---- = 𝛂x - βxy
- * ∂t
- *
- * ∂y
- * ---- = 𝛅xy - 𝛾y
- * ∂t
- *
- * [𝛂, β, 𝛅, 𝛾] in ]0,1]
- *
- * all roam around randomly,
- *
- * if 2 x meet they reproduce if rand > 𝛂
- *
- * if x meet y then y eats x
- *
- * if 2 y meet they
- * reproduce if rand > 𝛾
- * kill one if rand < 𝛾
- */
-
- var target = document.getElementById('trg'),
- width = 225,
- height = 80,
- bricks = [],
- L = Leonardo(width, height, {ns : '*', target : target}),
- bricksGroup = L.group(),
- malta = L.path(
- L.pathBuild.m(60,35)
- .q(-60,-2, -50, 10)
- .l(95, 30)
- .q(0,2, 5, 2)
- .q(5,2, 5, -2)
- .l(100,-10)
- .q(5, 0, 5, -20)
- .q(0, -12, -60, -10)
- ).setAttributes({
- fill : '#777',
- "stroke-width" : 2.5,
- stroke : 'black'
- }),
- brick = L.rect(0, 0, 100, 30).setAttributes({
- "stroke-width" : 2.5,
- "stroke-linejoin" : 'round',
- "stroke" : 'black',
- fill : 'brown'
- });
-
- bricks.push(brick.clone().move(55,5))
- bricks.push(brick.clone().move(5,40))
- bricks.push(brick.clone().move(110,40))
- bricksGroup.append(bricks).move(5, 5);
- L.append(malta, bricksGroup);
- L.render();
-};
\ No newline at end of file
diff --git a/source/demo/malta.json b/source/demo/malta.json
deleted file mode 100755
index 969a8f6..0000000
--- a/source/demo/malta.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "EXE": [
- "mkdir -p demo/malta/js demo/malta/css"
- ],
- "source/demo/malta/index.js": "demo/malta/js -vars=source/vars.json",
- "source/demo/malta/index.less": "demo/malta/css -plugins=malta-less -vars=source/vars.json",
- "source/demo/malta/index.html": "demo/malta -plugins=malta-browser-refresh -vars=source/vars.json"
-}
\ No newline at end of file
diff --git a/source/demo/malta/index.js b/source/demo/malta/index.js
deleted file mode 100755
index 950e8c1..0000000
--- a/source/demo/malta/index.js
+++ /dev/null
@@ -1,41 +0,0 @@
-window.onload = function () {
-
- var target = document.getElementById('trg'),
-
- width = 225,
- height = 80,
- bricks = [],
-
- L = Leonardo(width, height, {ns : '*', target : target}),
- bricksGroup = L.group(),
- malta = L.path(
- L.pathBuild.m(60,35)
- .q(-60,-2, -50, 10)
- .l(95,30)
- .q(0,2, 5, 2)
- .q(5,2, 5, -2)
- .l(100,-10)
- .q(5, 0, 5, -20)
- .q(0, -12, -60, -10)
- ).setAttributes({
- fill : '#777',
- "stroke-width" : 2.5,
- stroke : 'black'
- }),
- brick = L.rect(0, 0, 100, 30).setAttributes({
- "stroke-width" : 2.5,
- "stroke-linejoin" : 'round',
- "stroke" : 'black',
- fill : 'brown'
- });
-
- bricks.push(brick.clone().move(55,0))
- bricks.push(brick.clone().move(0,40))
- bricks.push(brick.clone().move(110,40))
-
- bricksGroup.append(bricks).move(5, 5);
-
- L.append(malta, bricksGroup);
-
- L.render();
-};
\ No newline at end of file
diff --git a/source/demo/malta/index.less b/source/demo/malta/index.less
deleted file mode 100755
index abef36a..0000000
--- a/source/demo/malta/index.less
+++ /dev/null
@@ -1,6 +0,0 @@
-body{
- background-color: green;
- svg{
- border:1px solid black
- }
-}
\ No newline at end of file
diff --git a/source/demo/map.json b/source/demo/map.json
deleted file mode 100755
index dffd978..0000000
--- a/source/demo/map.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "EXE": [
- "mkdir -p demo/map/js demo/map/css"
- ],
- "source/demo/map/index.js": "demo/map/js -vars=source/vars.json",
- "source/demo/map/index.less": "demo/map/css -plugins=malta-less -vars=source/vars.json",
- "source/demo/map/index.html": "demo/map -plugins=malta-browser-refresh -vars=source/vars.json"
-}
\ No newline at end of file
diff --git a/source/demo/map/index.less b/source/demo/map/index.less
deleted file mode 100755
index 3e1eff0..0000000
--- a/source/demo/map/index.less
+++ /dev/null
@@ -1,6 +0,0 @@
-body{
- background-color: green;
- svg{
- outline:1px solid white
- }
-}
\ No newline at end of file
diff --git a/source/demo/media/qr.png b/source/demo/media/qr.png
new file mode 100644
index 0000000..0947841
Binary files /dev/null and b/source/demo/media/qr.png differ
diff --git a/source/demo/minefield/index.html b/source/demo/minefield/index.html
index 055d365..18fbde6 100755
--- a/source/demo/minefield/index.html
+++ b/source/demo/minefield/index.html
@@ -14,7 +14,7 @@
svg text {user-select: none}
#root{
width:100vw;
- height:100vh;
+ height:90vh;
display:flex;
justify-content: center;
align-items: center;
@@ -22,6 +22,51 @@
+
+
+
+ -
+
+ +
+
+
+