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 @@ -![alt text](https://raw.githubusercontent.com/fedeghe/leonardo/master/media/god.svg "... do not dare scum human!") -leonardo javascript svg library v. 1.0.43 +![alt text](https://raw.githubusercontent.com/fedeghe/leonardo/master/source/media/god.svg "... do not dare scum human!") +leonardo javascript svg library v. 1.1.0 -[![Coverage Status](https://coveralls.io/repos/github/fedeghe/leonardo/badge.svg?branch=master)](https://coveralls.io/github/fedeghe/leonardo?branch=master) +[![codecov](https://codecov.io/gh/fedeghe/leonardo/graph/badge.svg?token=OGmjNS9psx)](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 : -![alt text](https://raw.githubusercontent.com/fedeghe/leonardo/master/media/god.jpg "... do not dare scum human!") +![alt text](https://raw.githubusercontent.com/fedeghe/leonardo/master/source/media/god.jpg "... do not dare scum human!") we can start a simple file: ```js @@ -455,11 +574,136 @@ window.onload = function () { ``` to get -![out bro](https://raw.githubusercontent.com/fedeghe/leonardo/master/media/readme1.png "") +![out bro](https://raw.githubusercontent.com/fedeghe/leonardo/master/source/media/readme1.png "") + +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]+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 = "//\n" + cnt + "\n"; + } + 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 @@ + +
+ + - + + + + +
+ \ No newline at end of file diff --git a/source/demo/minefield/index.js b/source/demo/minefield/index.js index 535d348..6fb7548 100755 --- a/source/demo/minefield/index.js +++ b/source/demo/minefield/index.js @@ -203,7 +203,8 @@ window.onload = function () { } while (n--) return out; } - function start(){ + function start(c){ + if(c) levelCut =c startTime = false; outG.clear(); // prerandomize bombs @@ -213,7 +214,7 @@ window.onload = function () { Array.from({length: nr*nc}, (_, i) => i < nrBombs), 3 ); - console.log({nrBombs, tls}); + for (var i = 0, j; i < nr; i++) { tiles[i] = []; for (j = 0; j < nc; j++) { @@ -233,6 +234,7 @@ window.onload = function () { if(e.key === 'n') start() }); + window.start = start; L.append(base, outG); L.render(); diff --git a/source/demo/minefield/index.less b/source/demo/minefield/index.less index 4471c27..77f76dc 100755 --- a/source/demo/minefield/index.less +++ b/source/demo/minefield/index.less @@ -4,7 +4,7 @@ body{ margin:0; padding: 0; font-family: verdana; - background-color: blue; + background-color: rgb(4, 4, 29); svg{ outline:1px solid white; text { @@ -14,6 +14,17 @@ body{ .root{ // background-color: red; } + .cen{ + display:flex; + align-content: center; + justify-content: center; + min-width:400px; + color:white; + } + .level { + width:100px; + margin-left: 20px; + } .panel{ display:flex; justify-content: space-between; diff --git a/source/demo/minefield2.json b/source/demo/minefield2.json deleted file mode 100755 index da9c0ad..0000000 --- a/source/demo/minefield2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "EXE": [ - "mkdir -p demo/minefield2/js demo/minefield2/css" - ], - "source/demo/minefield2/index.js": "demo/minefield2/js -vars=source/vars.json -options=placeholderMode:'func'", - "source/demo/minefield2/index.less": "demo/minefield2/css -plugins=malta-less -vars=source/vars.json", - "source/demo/minefield2/index.html": "demo/minefield2 -plugins=malta-browser-refresh -vars=source/vars.json" -} \ No newline at end of file diff --git a/source/demo/minefield2/Board.js b/source/demo/minefield2/Board.js deleted file mode 100644 index 5ce798f..0000000 --- a/source/demo/minefield2/Board.js +++ /dev/null @@ -1,8 +0,0 @@ -function Board(p, cnf){ - var self = this; - this.game = p.game; - -} -Board.prototype.render = function(){ - -} \ No newline at end of file diff --git a/source/demo/minefield2/Game.js b/source/demo/minefield2/Game.js deleted file mode 100644 index 637dd83..0000000 --- a/source/demo/minefield2/Game.js +++ /dev/null @@ -1,80 +0,0 @@ -var levels = { - 'easy': { prop: 0.5, mines: 0.15 }, - 'medium': { prop: 0.7, mines: 0.18 }, - 'hard':{ prop: 0.85, mines: 0.22 }, - 'impossible': { prop: 1, mines: 0.25 } -} -function Game(p){ - var perc = 80, - prop = perc/100; - this.level = Storage.get(); - this.labels = { - mine: '💣', - flag: '🚩', - expl: '💥', - settings: '⚙', - }; - - this.levelData = levels[this.level]; - - this.viewport = { - width: window.innerWidth * this.levelData.prop, - height: window.innerHeight * this.levelData.prop - }; - - this.rows = 200; - this.cols = 100; - this.tileSize = 20; - - - this.width = this.viewport.width; - this.height = this.viewport.height; - this.midWidth = this.width/2; - this.midHeight = this.height/2; - this.startTime = null; - this.playing = false; - - this.cells = this.rows * this.cols; - - this.started = false; - this.rootSvg = Leonardo( - this.viewport.width, - this.viewport.height, - { - ns : '*', - target: p.target - } - ); - this.mines = Math.floor(this.cells * this.levelData.mines); - this.startTime = null; - this.init(); - -} -Game.prototype.init = function() { - - this.Panel = new Panel({ - game: this - }); - this.Starter = new Starter({ - game: this - }); - -}; -Game.prototype.start = function() { - var self = this; - if(this.playing) return; - this.playing = true; - this.startTime = +new Date; - setInterval(function () { - var now = + new Date, - elapsed = now - self.startTime; - // debugger; - self.Panel.updateTime( - (elapsed/1000).toFixed(2) - ); - }, 10) -}; -Game.prototype.render = function() { - - this.rootSvg.render(); -}; \ No newline at end of file diff --git a/source/demo/minefield2/Panel.js b/source/demo/minefield2/Panel.js deleted file mode 100644 index 932f8a6..0000000 --- a/source/demo/minefield2/Panel.js +++ /dev/null @@ -1,59 +0,0 @@ -function Panel(p){ - this.game = p.game; - - var l = this.game.rootSvg, - self = this, - g = this.game; - // this.render(); - this.leo = l; - this.bomb = l.text('1%', 20, '100').setAttributes({ - 'text-anchor': 'start', - 'font-weight': 'bold', - }); - this.time = l.text('10%', 20, '0s').setAttributes({ - 'text-anchor': 'start', - 'font-style': 'italic', - }); - this.start = l.text('50%', 20, 'start').setAttributes({ - 'text-anchor': 'middle', - cursor: 'pointer', - }); - this.setting = l.text('99%', 20, '⚙').setAttributes({ - 'text-anchor': 'end', - cursor: 'pointer' - }); - this.line = l.line(0,25, this.game.width, 25).setAttributes({ - 'stroke': 'gray', - 'stroke-width': 0.5, - }); - - this.start.on('click', function () { - console.log('click') - self.startGame(); - // console.log(self.time) - }) - this.setting.on('click', function (){ - if(!g.playing)g.Starter.show(); - }) - this.render(); - -} -Panel.prototype.startGame = function(){ - this.game.start(); -} -Panel.prototype.updateTime = function(t){ - console.log(this.time) - this.time.tag.innerHTML = t+'s' -}; -Panel.prototype.render = function(){ - var self = this; - // console.log(this.game.Starter) - this.leo.append([ - this.bomb, - this.start, - this.time, - this.setting, - this.line, - // this.game.Starter.tag - ]) -}; \ No newline at end of file diff --git a/source/demo/minefield2/Starter.js b/source/demo/minefield2/Starter.js deleted file mode 100644 index bee8d84..0000000 --- a/source/demo/minefield2/Starter.js +++ /dev/null @@ -1,46 +0,0 @@ -function Starter(p) { - var self = this, - game = p.game, - leo = game.rootSvg, - l = game.rootSvg; - // Storage.set('hard'); -console.log(Storage.get()) - this.leo = l; - - this.width = 300; - this.height = 200; - this.game = game; - this.starter = leo.group() - .setAttributes({visibility: 'hidden'}) - .move( - game.midWidth - this.width/2, - 10 - ); - this.cnt = leo.rect( - 0, 0, - this.width, this.height - ).setAttributes({ - stroke: 'black', - fill: '#eee', - 'opacity' :'0.9', - }); - this.close = leo.text(5,5,'x').setAttributes({ - 'text-anchor': 'end', - stroke:'green', - cursor: 'pointer' - }); - this.starter.append([this.cnt, this.close]) - this.close.on('click', function (){ - self.hide() - }); - this.render(); -} -Starter.prototype.render = function () { - this.leo.append(this.starter) -}; -Starter.prototype.show = function () { - this.starter.setAttributes({visibility:'visible'}); -}; -Starter.prototype.hide = function () { - this.starter.setAttributes({visibility:'hidden'}); -}; diff --git a/source/demo/minefield2/Storage.js b/source/demo/minefield2/Storage.js deleted file mode 100644 index 28f612c..0000000 --- a/source/demo/minefield2/Storage.js +++ /dev/null @@ -1,11 +0,0 @@ -var Storage = (function () { - var defaultLevel = 'easy' - return { - get:function (){ - return localStorage.getItem('mfLevel') || defaultLevel - }, - set:function (level){ - localStorage.setItem('mfLevel', level); - }, - } -})(); \ No newline at end of file diff --git a/source/demo/minefield2/Tile.js b/source/demo/minefield2/Tile.js deleted file mode 100644 index 3275fb4..0000000 --- a/source/demo/minefield2/Tile.js +++ /dev/null @@ -1,2 +0,0 @@ -function Tile(){} -Tile.prototype.init = function(){}; \ No newline at end of file diff --git a/source/demo/minefield2/dom.js b/source/demo/minefield2/dom.js deleted file mode 100644 index d02d3b1..0000000 --- a/source/demo/minefield2/dom.js +++ /dev/null @@ -1,17 +0,0 @@ -var dom = { - create : function(tag, attrs, children){ - var t = document.createElement(tag); - if (attrs) { - for(a in attrs) { - t.setAttribute(a, attrs[a]) - } - } - if (children) { - if (Array.isArray(children)) - children.forEach(child => t.appendChild(child)) - else - t.appendChild(children) - } - return t; - }, -} \ No newline at end of file diff --git a/source/demo/minefield2/index.html b/source/demo/minefield2/index.html deleted file mode 100755 index 265ca86..0000000 --- a/source/demo/minefield2/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - $$../_commonHead.html$$ - $DEMO.MINEFIELD2.TITLE$ - - - - -
- - \ No newline at end of file diff --git a/source/demo/minefield2/index.js b/source/demo/minefield2/index.js deleted file mode 100755 index d9101d9..0000000 --- a/source/demo/minefield2/index.js +++ /dev/null @@ -1,14 +0,0 @@ -window.onload = function () { - maltaF('./dom.js') - maltaF('./Storage.js') - maltaF('./Game.js') - maltaF('./Panel.js') - maltaF('./Starter.js') - maltaF('./Board.js') - maltaF('./Tile.js') - var target = document.getElementById('root'), - game = new Game({ - target, tileSize - }); - game.render(); -}; \ No newline at end of file diff --git a/source/demo/minefield2/index.less b/source/demo/minefield2/index.less deleted file mode 100755 index dacda4e..0000000 --- a/source/demo/minefield2/index.less +++ /dev/null @@ -1,8 +0,0 @@ -@panelHeight: 80px; - -body{ - margin:0; - padding: 0; - font-family: verdana; - -} \ No newline at end of file diff --git a/source/demo/monalisa/index.js b/source/demo/monalisa/index.js index 5f3f3bd..5c374c9 100755 --- a/source/demo/monalisa/index.js +++ b/source/demo/monalisa/index.js @@ -337,7 +337,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/mondaine/index.js b/source/demo/mondaine/index.js index d653503..7708a5c 100755 --- a/source/demo/mondaine/index.js +++ b/source/demo/mondaine/index.js @@ -55,7 +55,7 @@ cx + width * 0.028, cy + height * 0.09 ).setAttributes({ id: 'hours' }), text = L.text(cx * 0.78, cy * 0.7, "MONDAINE"), - textSM = L.textPath("smade", + textSM = L.textPath( L.pathBuild .M(cx * 0.925, size * 0.89 * 0.995) .Q(cx, size * 0.89, cx * 1.075, size * 0.89 * 0.995), @@ -149,10 +149,9 @@ }]; var yyy = daydate.reduce(function (acc, o, i) { if (!o.condition) return acc; - var g = L.group(), tx = o.getText(), - textDate = L.centeredText(o.size[0] * 2, o.size[1] * 1.2, tx), + textDate = L.textBox(tx, o.size[0], o.size[1]).move(0, o.size[1]*0.1), rectDate = L.rect(0, 0, o.size[0], o.size[1]) .setAttributes({ fill: L.radialGradient([ // linear @@ -266,7 +265,6 @@ withDay.checked = !!day; withDate.checked = !!date; - console.log('rendered'); } }); } diff --git a/source/demo/mondaine/index2.js b/source/demo/mondaine/index2.js index 164e722..6fa432f 100755 --- a/source/demo/mondaine/index2.js +++ b/source/demo/mondaine/index2.js @@ -67,7 +67,7 @@ cx + width * 0.028, cy + height * 0.09 ).setAttributes({ id: 'hours' }), text = L.text(cx * 0.78, cy * 0.7, "MONDAINE"), - textSM = L.textPath("smade", + textSM = L.textPath( L.pathBuild .M(cx * 0.925, size * 0.89 * 0.995) .Q(cx, size * 0.89, cx * 1.075, size * 0.89 * 0.995), @@ -164,7 +164,7 @@ var g = L.group(), tx = o.getText(), - textDate = L.centeredText(o.size[0]*2, o.size[1]*1.2, tx), + textDate = L.textBox(tx, o.size[0]*2, o.size[1]*1.2), rectDate = L.rect(0,0, o.size[0], o.size[1]) .setAttributes({ fill: L.radialGradient([ // linear diff --git a/source/demo/playground/index.js b/source/demo/playground/index.js index 295c9cb..d722d76 100755 --- a/source/demo/playground/index.js +++ b/source/demo/playground/index.js @@ -60,11 +60,14 @@ window.onload = function () { console.log(e.target); console.log(e); }); - var Arc = L.arcCentered(100, 100, 50, 0, 270).setAttributes({fill:'#ddd', stroke: 'red'}); + var Arc = L.path( + L.arcSectionPath(100, 100, 0, 50, 0, 270), + {fill:'#ddd', stroke: 'red'} + ); tria.rotate(20, 300, 50).move(10, 100); - var centeredText = L.centeredText(502, 100, 'hello', {fill:'#ddd', stroke: 'red' }); + var centeredText = L.textBox('hello', 502, 100, {fill:'#ddd', stroke: 'red' }); setInterval(function (){ var now = new Date(), sec = now.getSeconds(), diff --git a/source/demo/polarwatch/index.html b/source/demo/polarwatch/index.html index 47479fd..b44a50b 100755 --- a/source/demo/polarwatch/index.html +++ b/source/demo/polarwatch/index.html @@ -7,11 +7,14 @@ - dark - light - rainbow - rel -
...
+
+ + dark + light + rainbow + rel +
+
...
diff --git a/source/demo/polarwatch/index.js b/source/demo/polarwatch/index.js index c59fe87..2278ca1 100755 --- a/source/demo/polarwatch/index.js +++ b/source/demo/polarwatch/index.js @@ -41,6 +41,7 @@ window.onload = function () { function createTimingSlice(index, center, r, col, timing) { var now = new Date, i = timing.fun(now), + circle = Leo.slice(center.x, center.y, r, 0, 0).setAttributes({ fill: col }), grp = Leo.group(), innerC = Leo.circle(center.x, center.y, r - 2*step).setAttributes({ fill: color('bg') }); @@ -64,10 +65,11 @@ window.onload = function () { }, timing.timestep); return grp; } - setInterval(function () { - console.clear(); - console.log(new Date) - }, 1000) + + // setInterval(function () { + // console.clear(); + // console.log(new Date) + // }, 1000) container.append(cir0); container.append(circles); diff --git a/source/demo/polarwatch/index.less b/source/demo/polarwatch/index.less index cf6d971..0f02296 100755 --- a/source/demo/polarwatch/index.less +++ b/source/demo/polarwatch/index.less @@ -3,12 +3,17 @@ body { padding:0px; background-color: white; font-family:verdana; + display:flex; + align-items: center; + flex-direction: column; + justify-content: center; + height:100vh; svg { font-family: HelveticaNeueW01-55Roma,Arial,sans-serif; } #trg { margin:0 auto; - margin-top:10%; + margin-top:2rem; } a { display:inline-block; @@ -19,7 +24,7 @@ body { padding:10px; margin:10px; line-height:28px; - font-size:25px; + font-size:24px; text-decoration: none; &:hover{ color:red; diff --git a/source/demo/range.html b/source/demo/range.html new file mode 100755 index 0000000..c080f04 --- /dev/null +++ b/source/demo/range.html @@ -0,0 +1,132 @@ + + + + + + + range + + + + + + +
+
+ +
+ +
+ + + + + + \ No newline at end of file diff --git a/source/demo/require.json b/source/demo/require.json index a9db6eb..d874b8b 100755 --- a/source/demo/require.json +++ b/source/demo/require.json @@ -7,35 +7,27 @@ ], "source/demo/*.html": "demo -plugins=malta-browser-refresh...malta-dev-srv[folder:\"demo\",port:8787] -vars=source/vars.json", "source/demo/mondaine.json": true, - "source/demo/hero.json": true, - "source/demo/malta.json": true, "source/demo/understand.json": true, "source/demo/playground.json": true, - "source/demo/synchazard.json": true, "source/demo/vrr.json": true, "source/demo/polarwatch.json": true, "source/demo/circles.json": true, - "source/demo/cver.json": true, - "source/demo/map.json": true, + "source/demo/conway.json": true, "source/demo/kicker.json": true, "source/demo/animate.json": true, - "source/demo/jshero.json": true, "source/demo/gradients.json": true, - "source/demo/53hotseconds.json": true, "source/demo/53hotseconds2.json": true, "source/demo/53hotseconds3.json": true, "source/demo/filters.json": true, - "source/demo/g-hero.json": true, - "source/demo/g-hero2.json": true, "source/demo/fg.json": true, "source/demo/god.json": true, "source/demo/monalisa.json": true, "source/demo/vitruvian.json": true, "source/demo/uoullet.json": true, "source/demo/minefield.json": true, - "source/demo/minefield2.json": true, - "source/demo/lotkavolterra.json": true, + "source/demo/extra.json": true, "source/demo/gbelt.json": true, "source/demo/krepo.json": true, + "source/demo/logos.json": true, "source/demo/svg/*.svg": "source/demo/png -plugins=malta-svg2png" } \ No newline at end of file diff --git a/source/demo/synchazard.json b/source/demo/synchazard.json deleted file mode 100755 index d843d89..0000000 --- a/source/demo/synchazard.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "EXE": [ - "mkdir -p demo/synchazard/js demo/synchazard/css" - ], - "source/demo/synchazard/index.js": "demo/synchazard/js -vars=source/vars.json", - "source/demo/synchazard/index.html": "demo/synchazard -plugins=malta-browser-refresh -vars=source/vars.json" -} \ No newline at end of file diff --git a/source/demo/synchazard/index.html b/source/demo/synchazard/index.html deleted file mode 100755 index 8014af3..0000000 --- a/source/demo/synchazard/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - $$../_commonHead.html$$ - $DEMO.SYNCHAZARD.TITLE$ - - - - -
...
-
-
...
-
-
...
- - - - \ No newline at end of file diff --git a/source/demo/synchazard/index.js b/source/demo/synchazard/index.js deleted file mode 100755 index 627b052..0000000 --- a/source/demo/synchazard/index.js +++ /dev/null @@ -1,227 +0,0 @@ -window.onload = function () { - var target1 = document.getElementById('trg1'), - target2 = document.getElementById('trg2'), - target3 = document.getElementById('trg3'); - - (function () { - var width = 500, - height = 500, - min = width > height ? height : width, - L = Leonardo(width, height, { ns: '*', target: target1 }), - w = L.getScaler(width), - h = L.getScaler(height), - m = L.getScaler(min), - 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(60), h(15), - w(53), h(15), - w(42), h(52), - w(67), h(38), - w(53), h(85), - w(60), h(85), - w(50), h(100), - w(40), h(85), - w(47), h(85), - w(58), h(48), - w(33), h(62), - w(47), h(15), - w(40), h(15), - ), - ] - }, - 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: '#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#aa55ff;#000', - dur: '5s', - repeatCount: 'indefinite' - })) - - L.append(cloud, thunder); - L.render(); - })(); - - (function () { - var 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: target2 }), - attrs = { - cloud: { fill: '#3C3C3B' }, - thunder: { - fill: '#eeee00', - stroke: '#ff660077', - 'stroke-width': 15 - }, - contour: { - stroke: '#359', - fill: 'transparent', - 'stroke-width': 35 - } - }, - - 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(60), h(15), - w(53), h(15), - w(42), h(52), - w(67), h(38), - w(53), h(85), - w(60), h(85), - w(50), h(100), - w(40), h(85), - w(47), h(85), - w(58), h(48), - w(33), h(62), - w(47), h(15), - w(40), h(15), - ), - ] - }, - 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), - contour = L.circle(w(50), h(50), m(45)).setAttributes(attrs.contour), - logo = L.group(); - - thunder.append(L.animate.attr({ - attributeName: 'stroke', - values: '#ff6600;#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' - })); - - logo.append(cloud, thunder).scale(0.8, 0.8).move(50,50); - L.append(contour,logo); - L.render(); - })(); - - (function () { - var 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: target3 }), - 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(); - document.body.appendChild(L.downloadAnchor()); - })(); - - // document.body.appendChild(L.downloadAnchor()); -}; \ No newline at end of file diff --git a/source/demo/understand/index.html b/source/demo/understand/index.html index 6c3da78..2cde9fb 100755 --- a/source/demo/understand/index.html +++ b/source/demo/understand/index.html @@ -9,7 +9,7 @@
...
- speed: + speed:
add random noise:
diff --git a/source/demo/understand/index.js b/source/demo/understand/index.js index bb33b9f..1146b76 100755 --- a/source/demo/understand/index.js +++ b/source/demo/understand/index.js @@ -3,7 +3,10 @@ window.onload = function () { var target = document.getElementById('trg'), speedTuner = document.getElementById('speed'), rndTuner = document.getElementById('rnd'), - speed = 0.5, + speed = 1, + minSpeed = 0.1, + maxSpeed = 10, + speedStep = 0.01, rnd = false, width = 500, height = 500, hm = 20, @@ -60,15 +63,19 @@ window.onload = function () { [cg2, cg3, cg4, cg5, cg6, cg7, cg8, cg9].forEach(function (el, i) { var versus = i % 2 ? -1 : 1; L.animate.cartesian(el, function (x, t) { - return w20 * (rnd ? Math.random() : 1) * Math.sin(t * speed * versus); + return w20 * (rnd ? 1+Math.random()/10 : 1) * Math.sin(t * speed * versus); },function (y, t) { - return -w20 + w20 * (rnd ? Math.random() : 1) * Math.cos(t * speed); //here versus is not influent since cos is simmetric + return -w20 + w20 * (rnd ? 1+Math.random()/10 : 1) * Math.cos(t * speed); //here versus is not influent since cos is simmetric }); }); L.render({target: target}); speedTuner.value = speed; + speedTuner.min = minSpeed; + speedTuner.max = maxSpeed; + speedTuner.step = speedStep; + speedTuner.addEventListener('change', function() { speed = parseFloat(this.value, 10); }); @@ -76,5 +83,5 @@ window.onload = function () { rnd = !!this.checked; }); - document.body.appendChild(L.downloadAnchor()); + document.body.appendChild(L.svgDownloadAnchor()); }; \ No newline at end of file diff --git a/source/demo/uoullet.json b/source/demo/uoullet.json index d6be6df..5ec2eba 100755 --- a/source/demo/uoullet.json +++ b/source/demo/uoullet.json @@ -1,9 +1,15 @@ { "EXE": [ "mkdir -p demo/uoullet/js demo/uoullet/css", - "cp source/media/uoullet.jpg demo/uoullet/uoullet.jpg" + "cp source/media/uoullet.png demo/uoullet/uoullet.png", + "cp source/media/front.png demo/uoullet/front.png", + "cp source/media/frontSmall.png demo/uoullet/frontSmall.png", + "cp source/media/base.jpg demo/uoullet/base.jpg", + "cp source/media/uoullet.svg demo/uoullet/uoullet.svg", + "cp source/media/uoulletSph.svg demo/uoullet/uoulletSph.svg" ], "source/demo/uoullet/index.js": "demo/uoullet/js -vars=source/vars.json", "source/demo/uoullet/index.less": "demo/uoullet/css -plugins=malta-less -vars=source/vars.json", - "source/demo/uoullet/index.html": "demo/uoullet -plugins=malta-browser-refresh -vars=source/vars.json" + "source/demo/uoullet/index.html": "demo/uoullet -plugins=malta-browser-refresh -vars=source/vars.json", + "source/demo/uoullet/*.svg": "demo/uoullet -plugins=malta-browser-refresh -vars=source/vars.json" } \ No newline at end of file diff --git a/source/demo/uoullet/index.html b/source/demo/uoullet/index.html index 3b8c493..0ef1dbb 100755 --- a/source/demo/uoullet/index.html +++ b/source/demo/uoullet/index.html @@ -6,7 +6,7 @@ $DEMO.UOULLET.TITLE$