PageSourceSearch

https://yururi-hakone.com/wpcms/wp-content/themes/yururi_hakone/js/kute-svg.js

js yururi-hakone.com collected 2026-10-04 13:28:35 UTC 18,373 bytes, 416 lines download raw bytes

1/* KUTE.js - The Light Tweening Engine
2 * package - SVG Plugin
3 * desc - draw SVG strokes, morph SVG and SVG transforms
4 * by dnp_theme
5 * Licensed under MIT-License
6 */
7
8(function (root,factory) {
9  if (typeof define === 'function' && define.amd) {
10    define(['./kute.js'], factory);
11  } else if(typeof module == 'object' && typeof require == 'function') {
12    module.exports = factory(require('./kute.js'));
13  } else if ( typeof root.KUTE !== 'undefined' ) {
14    factory(root.KUTE);
15  } else {
16    throw new Error("SVG Plugin require KUTE.js.");
17  }
18}(this, function(KUTE) {
19  'use strict';
20
21  var g = typeof global !== 'undefined' ? global : window, K = KUTE, // connect plugin to KUTE object and global
22    DOM = K.dom, parseProperty = K.parseProperty, prepareStart = K.prepareStart, getCurrentStyle = K.getCurrentStyle,
23    trueColor = K.truC, trueDimension = K.truD, crossCheck = K.crossCheck,
24    number = g.Interpolate.number, unit = g.Interpolate.unit, color = g.Interpolate.color, // interpolate functions
25    defaultOptions = K.defaultOptions, // default tween options since 1.6.1
26
27    // browser detection
28    isIE = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) !== null ? parseFloat( RegExp.$1 ) : false;
29
30  if (isIE&&isIE<9) {return;} // return if SVG API is not supported
31
32  // here we go with the plugin
33  var pathReg = /(m[^(h|v|l)]*|[vhl][^(v|h|l|z)]*)/gmi, ns = 'http://www.w3.org/2000/svg',
34    // function(array1, array2, length, progress) for SVG morph
35    coords = g.Interpolate.coords = function(a,b,l,v) {
36      var points = [];
37      for(var i=0;i<l;i++) { // for each point
38        points[i] = [];
39        for(var j=0;j<2;j++) { // each point coordinate
40          points[i].push( ((a[i][j]+(b[i][j]-a[i][j])*v) * 1000 >> 0)/1000 );
41        }
42      }
43      return points;
44    };
45
46
47  // SVG MORPH
48  var getSegments = function(s,e,r){ // getSegments returns an array of points based on a sample size morphPrecision
49      var s1 = [], e1 = [], le1 = s.getTotalLength(), le2 = e.getTotalLength(), ml = Math.max(le1,le2),
50        d = r, ar = ml / r, j = 0, sl = ar*r; // sl = sample length
51
52      while ( (j += r) < sl ) { // populate the points arrays based on morphPrecision as sample size
53        s1.push( [s.getPointAtLength(j).x, s.getPointAtLength(j).y]);
54        e1.push( [e.getPointAtLength(j).x, e.getPointAtLength(j).y]);
55      }
56      return [s1,e1];
57    },
58    getClosestPoint = function(p,t,s){ // utility for polygon paths, returns a close point from the original path (length,pointAtLength,smallest); // intervalLength
59      var x, y, a = [], l = s.length, dx, nx, pr;
60      for (var i=0; i<l; i++){
61        x = Math.abs(s[i][0] - t.x);
62        y = Math.abs(s[i][1] - t.y);
63        a.push( Math.sqrt( x * x + y * y ) );
64      }
65      dx = a.indexOf(Math.min.apply(null,a));
66      pr = !!s[dx-1] ? dx-1 : l-1;
67      nx = !!s[dx+1] ? dx+1 : 0;
68      return Math.abs(s[pr][0] - t.x) < p && Math.abs(s[pr][1] - t.y) < p ? s[pr]
69      : Math.abs(s[nx][0] - t.x) < p && Math.abs(s[nx][1] - t.y) < p ? s[nx]
70      : Math.abs(s[dx][0] - t.x) < p && Math.abs(s[dx][1] - t.y) < p ? s[dx]
71      : [t.x,t.y];
72    },
73    pathToAbsolute = function(p) { // simple utility for polygons | this is still BETA / a work in progress
74      var np = p.match(pathReg), wp = [], l = np.length, s, c, r, x = 0, y = 0;
75      for (var i = 0; i<l; i++){
76        np[i] = np[i]; c = np[i][0]; r = new RegExp(c+'[^\\d|\\-]*','i');
77        np[i] = np[i].replace(/(^|[^,])\s*-/g, '$1,-').replace(/(\s+\,|\s|\,)/g,',').replace(r,'').split(',');
78        np[i][0] = parseFloat(np[i][0]);
79        np[i][1] = parseFloat(np[i][1]);
80        if (i === 0) { x+=np[i][0]; y +=np[i][1]; }
81        else {
82          x = np[i-1][0];
83          y = np[i-1][1];
84          if (/l/i.test(c)) {
85            np[i][0] = c === 'l' ? np[i][0] + x : np[i][0];
86            np[i][1] = c === 'l' ? np[i][1] + y : np[i][1];
87          } else if (/h/i.test(c)) {
88            np[i][0] = c === 'h' ? np[i][0] + x : np[i][0];
89            np[i][1] = y;
90          } else if (/v/i.test(c)) {
91            np[i][0] = x;
92            np[i][1] = c === 'v' ? np[i][0] + y : np[i][0];
93          }
94        }
95      }
96      return np;
97    },
98    getOnePath = function(p){ return p.split(/z/i).shift() + 'z'; }, // we only tween first path only
99    createPath = function (p){ // create a <path> when glyph
100      var createdPath = document.createElementNS(ns,'path'), d = typeof p === 'object' ? p.getAttribute('d') : p;
101      createdPath.setAttribute('d',d); return createdPath;
102    },
103    forcePath = function(p){ // forcePath for glyph elements
104      if (p.tagName === 'glyph') { // perhaps we can also change other SVG tags in the future
105        var c = createPath(p); p.parentNode.appendChild(c); return c;
106      }
107      return p;
108    },
109    clone = function(a) {
110      var copy;
111      if (a instanceof Array) {
112        copy = [];
113        for (var i = 0, len = a.length; i < len; i++) {
114          copy[i] = clone(a[i]);
115        }
116        return copy;
117      }
118      return a;
119    },
120    getPath = function(e){ // get path d attribute or create a path from string value
121      var p = {}, el = typeof e === 'object' ? e : /^\.|^\#/.test(e) ? document.querySelector(e) : null;
122      if ( el && /path|glyph/.test(el.tagName) ) {
123        p.e = forcePath(el);
124        p.o = el.getAttribute('d');
125
126      } else if (!el && /[a-z][^a-z]*/ig.test(e)) { // maybe it's a string path already
127        p.e = createPath(e.trim());
128        p.o = e;
129      }
130      return p;
131    },
132    computePathCross = function(s,e){ // pathCross
133      var s1, e1, pointsArray, largerPathLength, smallerPath, largerPath, simulatedSmallerPath, nsm = [], sml, cl = [], len, tl, cs,
134        index = this.options.morphIndex;
135
136      if (!this._isPolygon) {
137        s = createPath(s); e = createPath(e);
138        pointsArray = getSegments(s,e,this.options.morphPrecision);
139        s1 = pointsArray[0]; e1 = pointsArray[1]; largerPathLength = e1.length;
140      } else {
141        s = pathToAbsolute(s); e = pathToAbsolute(e);
142
143        if ( s.length !== e.length ){
144          largerPathLength = Math.max(s.length,e.length);
145          if ( largerPathLength === e.length) { smallerPath = s; largerPath = e; } else { smallerPath = e; largerPath = s; }
146          sml = smallerPath.length;
147
148          simulatedSmallerPath = createPath('M'+smallerPath.join('L')+'z'); len = simulatedSmallerPath.getTotalLength() / largerPathLength;
149          for (var i=0; i<largerPathLength; i++){
150            tl = simulatedSmallerPath.getPointAtLength(len*i);
151            cs = getClosestPoint(len,tl,smallerPath);
152            nsm.push( [ cs[0], cs[1] ] );
153          }
154
155          if (largerPathLength === e.length) { e1 = largerPath; s1 = nsm; } else { s1 = largerPath; e1 = nsm; }
156        } else {
157          s1 = s; e1 = e;
158        }
159      }
160
161      // reverse arrays
162      if (this.options.reverseFirstPath) { s1.reverse(); }
163      if (this.options.reverseSecondPath) { e1.reverse(); }
164
165      // shift second array to for smallest tween distance
166      if (index) {
167        var e11 = e1.splice(index,largerPathLength-index);
168        e1 = e11.concat(e1);
169      }
170
171      s = e = null;
172      return [s1,e1]
173    };
174
175  // set default morphPrecision since 1.6.1
176  defaultOptions.morphPrecision = 15;
177
178  // process path object and also register the render function
179  parseProperty.path = function(o,v) {
180    if (!('path' in DOM)) {
181      DOM.path = function(l,p,a,b,v){
182        l.setAttribute("d", v === 1 ? b.o : 'M' + coords( a['d'],b['d'],b['d'].length,v ) + 'Z' );
183      }
184    }
185    return getPath(v);
186  };
187
188  prepareStart.path = function(p){
189    return this.element.getAttribute('d');
190  };
191
192  crossCheck.path = function() { // unlike other cases, the crossCheck apply to both to() and fromTo() methods
193    var p1 = getOnePath(this.valuesStart.path.o), p2 = getOnePath(this.valuesEnd.path.o), paths;
194
195    // path tween options
196    this.options.morphPrecision = this.options && 'morphPrecision' in this.options ? parseInt(this.options.morphPrecision) : defaultOptions.morphPrecision;
197    this._isPolygon = !/[CSQTA]/i.test(p1) && !/[CSQTA]/i.test(p2); // check if both shapes are polygons
198
199    // begin processing paths
200    paths = computePathCross.apply(this,[p1,p2]);
201
202    this.valuesStart.path.d = paths[0];
203    this.valuesEnd.path.d = paths[1];
204  };
205
206
207  // SVG DRAW
208  var percent = function(v,l){ return parseFloat(v) / 100 * l; },
209    // SVG DRAW UTILITITES
210    // http://stackoverflow.com/a/30376660
211    getRectLength = function(el){ // returns the length of a Rect
212      var w = el.getAttribute('width');
213      var h = el.getAttribute('height');
214      return (w*2)+(h*2);
215    },
216    getPolyLength = function(el){ // getPolygonLength / getPolylineLength - return the length of the Polygon / Polyline
217      var points = el.getAttribute('points').split(' '), len = 0;
218      if (points.length > 1) {
219        var coord = function (p) {
220          var c = p.split(',');
221          if (c.length != 2) { return; } // return undefined
222          if (isNaN(c[0]) || isNaN(c[1])) { return; }
223          return [parseFloat(c[0]), parseFloat(c[1])];
224        };
225
226        var dist = function (c1, c2) {
227          if (c1 != undefined && c2 != undefined) {
228            return Math.sqrt(Math.pow((c2[0]-c1[0]), 2) + Math.pow((c2[1]-c1[1]), 2));
229          }
230          return 0;
231        };
232
233        if (points.length > 2) {
234          for (var i=0; i<points.length-1; i++) {
235            len += dist(coord(points[i]), coord(points[i+1]));
236          }
237        }
238        len += dist(coord(points[0]), coord(points[points.length-1]));
239      }
240      return len;
241    },
242    getLineLength = function(el){ // return the length of the line
243      var x1 = el.getAttribute('x1');
244      var x2 = el.getAttribute('x2');
245      var y1 = el.getAttribute('y1');
246      var y2 = el.getAttribute('y2');
247      return Math.sqrt(Math.pow((x2-x1), 2)+Math.pow((y2-y1),2));
248    },
249    getCircleLength = function(el){ // return the length of the circle
250      var r = el.getAttribute('r');
251      return 2 * Math.PI * r;
252    },
253    getEllipseLength = function(el) { // returns the length of an ellipse
254      var rx = el.getAttribute('rx'), ry = el.getAttribute('ry'),
255          len = 2*rx, wid = 2*ry;
256      return ((Math.sqrt(.5 * ((len * len) + (wid * wid)))) * (Math.PI * 2)) / 2;
257    },
258    getTotalLength = function(el){ // returns the result of any of the below functions
259      if (/rect/.test(el.tagName)) {
260        return getRectLength(el);
261      } else if (/circle/.test(el.tagName)) {
262        return getCircleLength(el);
263      } else if (/ellipse/.test(el.tagName)) {
264        return getEllipseLength(el);
265      } else if (/polygon|polyline/.test(el.tagName)) {
266        return getPolyLength(el);
267      } else if (/line/.test(el.tagName)) {
268        return getLineLength(el);
269      }
270    },
271    getDraw = function(e,v){
272      var l = /path|glyph/.test(e.tagName) ? e.getTotalLength() : getTotalLength(e), start, end, d, o;
273      if ( v instanceof Object ) {
274        return v;
275      } else if (typeof v === 'string') {
276        v = v.split(/\,|\s/);
277        start = /%/.test(v[0]) ? percent(v[0].trim(),l) : parseFloat(v[0]);
278        end = /%/.test(v[1]) ? percent(v[1].trim(),l) : parseFloat(v[1]);
279      } else if (typeof v === 'undefined') {
280        o = parseFloat(getCurrentStyle(e,'stroke-dashoffset'));
281        d = getCurrentStyle(e,'stroke-dasharray').split(/\,/);
282
283        start = 0-o;
284        end = parseFloat(d[0]) + start || l;
285      }
286      return { s: start, e: end, l: l }
287    };
288
289  parseProperty.draw = function(a,o){ // register the draw property
290    if (!('draw' in DOM)) {
291      DOM.draw = function(l,p,a,b,v){
292        var pathLength = (a.l*100>>0)/100, start = (number(a.s,b.s,v)*100>>0)/100, end = (number(a.e,b.e,v)*100>>0)/100,
293        offset = 0 - start, dashOne = end+offset;
294        l.style.strokeDashoffset = offset +'px';
295        l.style.strokeDasharray = (((dashOne <1 ? 0 : dashOne)*100>>0)/100) + 'px, ' + pathLength + 'px';
296      }
297    }
298    return getDraw(this.element,o);
299  }
300
301  prepareStart.draw = function(){
302    return getDraw(this.element);
303  }
304
305
306  // SVG Transform
307  var parseStringOrigin = function(origin,box){
308      return /[a-zA-Z]/.test(origin) && !/px/.test(origin) ? origin.replace(/top|left/,0).replace(/right|bottom/,100).replace(/center|middle/,50)
309                                     : /%/.test(origin) ? (box.x + parseFloat(origin) * box.width / 100) : parseFloat(origin);
310    },
311    parseTransformString = function (a){ // helper function that turns transform value from string to object
312      var d = a && /\)/.test(a) ? a.substring(0, a.length-1).split(/\)\s|\)/) : 'none', c = {};
313
314      if (d instanceof Array) {
315        for (var j=0, jl = d.length; j<jl; j++){
316          var p = d[j].trim().split('('); c[p[0]] = p[1];
317        }
318      }
319      return c;
320    },
321    parseTransformObject = function(v){
322      var svgTransformObject = {}, bb = this.element.getBBox(),
323        cx = bb.x + bb.width/2, cy = bb.y + bb.height/2, // by default the transformOrigin is "50% 50%" of the shape box
324        origin = this.options.transformOrigin, translation;
325
326      origin = !!origin ? (origin instanceof Array ? origin : origin.split(/\s/)) : [cx,cy];
327
328      origin[0] = typeof origin[0] === 'number' ? origin[0] : parseStringOrigin(origin[0],bb);
329      origin[1] = typeof origin[1] === 'number' ? origin[1] : parseStringOrigin(origin[1],bb);
330
331      svgTransformObject.origin = origin;
332
333      for ( var i in v ) { // populate the valuesStart and / or valuesEnd
334        if (i === 'rotate'){
335          svgTransformObject[i] = typeof v[i] === 'number' ? v[i] : v[i] instanceof Array ? v[i][0] : v[i].split(/\s/)[0]*1;
336        } else if (i === 'translate'){
337          translation = v[i] instanceof Array ? v[i] : /\,|\s/.test(v[i]) ? v[i].split(',') : [v[i],0];
338          svgTransformObject[i] = [translation[0]*1||0, translation[1]*1||0];
339        } else if (/skew/.test(i)) {
340          svgTransformObject[i] = v[i]*1||0;
341        } else if (i === 'scale'){
342          svgTransformObject[i] = parseFloat(v[i])||1;
343        }
344      }
345
346      return svgTransformObject;
347    };
348
349  parseProperty.svgTransform = function(p,v){
350    // register the render function
351    if (!('svgTransform' in DOM)) {
352      DOM.svgTransform = function(l,p,a,b,v){
353        var x = 0, y = 0, tmp, deg = Math.PI/180,
354          scale = 'scale' in b ? number(a.scale,b.scale,v) : 1,
355          rotate = 'rotate' in b ? number(a.rotate,b.rotate,v) : 0,
356          sin = Math.sin(rotate*deg), cos = Math.cos(rotate*deg),
357          skewX = 'skewX' in b ? number(a.skewX,b.skewX,v) : 0,
358          skewY = 'skewY' in b ? number(a.skewY,b.skewY,v) : 0,
359          complex = rotate||skewX||skewY||scale!==1 || 0;
360
361        // start normalizing the translation, we start from last to first (from last chained translation)
362        // the normalized translation will handle the transformOrigin tween option and makes sure to have a consistent transformation
363        x -= complex ? b.origin[0] : 0; y -= complex ? b.origin[1] : 0; // we start with removing transformOrigin from translation
364        x *= scale; y *= scale; // we now apply the scale
365        y += skewY ? x*Math.tan(skewY*deg) : 0; x += skewX ? y*Math.tan(skewX*deg) : 0; // now we apply skews
366        tmp = cos*x - sin*y; // apply rotation as well
367        y = rotate ? sin*x + cos*y : y; x = rotate ? tmp : x;
368        x += 'translate' in b ? number(a.translate[0],b.translate[0],v) : 0; // now we apply the actual translation
369        y += 'translate' in b ? number(a.translate[1],b.translate[1],v) : 0;
370        x += complex ? b.origin[0] : 0; y += complex ? b.origin[1] : 0; // normalizing ends with the addition of the transformOrigin to the translation
371
372        // finally we apply the transform attribute value
373        l.setAttribute('transform', ( x||y ? ('translate(' + (x*1000>>0)/1000 + ( y ? (',' + ((y*1000>>0)/1000)) : '') + ')') : '' )
374                                    +( rotate ? 'rotate(' + (rotate*1000>>0)/1000 + ')' : '' )
375                                    +( skewX ? 'skewX(' + (skewX*1000>>0)/1000 + ')' : '' )
376                                    +( skewY ? 'skewY(' + (skewY*1000>>0)/1000 + ')' : '' )
377                                    +( scale !== 1 ? 'scale(' + (scale*1000>>0)/1000 +')' : '' ) );
378      }
379    }
380
381    // now prepare transform
382    return parseTransformObject.call(this,v);
383  }
384
385  // returns an obect with current transform attribute value
386  prepareStart.svgTransform = function(p,t) {
387    var transformObject = {}, currentTransform = parseTransformString(this.element.getAttribute('transform'));
388    for (var i in t) { transformObject[i] = i in currentTransform ? currentTransform[i] : (i==='scale'?1:0); } // find a value in current attribute value or add a default value
389    return transformObject;
390  }
391
392  crossCheck.svgTransform = function() { // helper function that helps preserve current transform properties into the objects
393    if (!this.options.rpr) return;
393 // fix since 1.6.1 for fromTo() method
394    var valuesStart = this.valuesStart.svgTransform, valuesEnd = this.valuesEnd.svgTransform,
395      currentTransform = parseTransformObject.call(this, parseTransformString(this.element.getAttribute('transform')) );
396
397    for ( var i in currentTransform ) { valuesStart[i] = currentTransform[i]; } // populate the valuesStart first
398
399    // now try to determine the REAL translation
400    var parentSVG = this.element.ownerSVGElement,
401      newTransform = parentSVG.createSVGTransformFromMatrix(
402        parentSVG.createSVGMatrix()
403        .translate(-valuesStart.origin[0],-valuesStart.origin[1]) // - origin
404        .translate('translate' in valuesStart ? valuesStart.translate[0] : 0,'translate' in valuesStart ? valuesStart.translate[1] : 0) // the current translate
405        .rotate(valuesStart.rotate||0).skewX(valuesStart.skewX||0).skewY(valuesStart.skewY||0).scale(valuesStart.scale||1)// the other functions
406        .translate(+valuesStart.origin[0],+valuesStart.origin[1]) // + origin
407      );
408
409    valuesStart.translate = [newTransform.matrix.e,newTransform.matrix.f]; // finally the translate we're looking for
410
411    // copy existing and unused properties to the valuesEnd
412    for ( var i in valuesStart) { if ( !(i in valuesEnd)) { valuesEnd[i] = valuesStart[i]; } }
413  }
414
415  return this;
416}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.