vega-wordcloud
Advanced tools
| export { default } from '../../rollup.config.mjs'; |
+110
-169
@@ -5,3 +5,3 @@ (function (global, factory) { | ||
| (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.vega = global.vega || {}, global.vega.transforms = {}), global.vega, global.vega, global.vega, global.vega, global.vega)); | ||
| }(this, (function (exports, vegaCanvas, vegaDataflow, vegaUtil, vegaScale, vegaStatistics) { 'use strict'; | ||
| })(this, (function (exports, vegaCanvas, vegaDataflow, vegaUtil, vegaScale, vegaStatistics) { 'use strict'; | ||
@@ -36,2 +36,3 @@ /* | ||
| */ | ||
| // Word cloud layout by Jason Davies, https://www.jasondavies.com/wordcloud/ | ||
@@ -41,44 +42,42 @@ // Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf | ||
| var cloudRadians = Math.PI / 180, | ||
| cw = 1 << 11 >> 5, | ||
| ch = 1 << 11; | ||
| cw = 1 << 11 >> 5, | ||
| ch = 1 << 11; | ||
| function cloud () { | ||
| var size = [256, 256], | ||
| text, | ||
| font, | ||
| fontSize, | ||
| fontStyle, | ||
| fontWeight, | ||
| rotate, | ||
| padding, | ||
| spiral = archimedeanSpiral, | ||
| words = [], | ||
| random = Math.random, | ||
| cloud = {}; | ||
| text, | ||
| font, | ||
| fontSize, | ||
| fontStyle, | ||
| fontWeight, | ||
| rotate, | ||
| padding, | ||
| spiral = archimedeanSpiral, | ||
| words = [], | ||
| random = Math.random, | ||
| cloud = {}; | ||
| cloud.layout = function () { | ||
| var contextAndRatio = getContext(vegaCanvas.canvas()), | ||
| board = zeroArray((size[0] >> 5) * size[1]), | ||
| bounds = null, | ||
| n = words.length, | ||
| i = -1, | ||
| tags = [], | ||
| data = words.map(d => ({ | ||
| text: text(d), | ||
| font: font(d), | ||
| style: fontStyle(d), | ||
| weight: fontWeight(d), | ||
| rotate: rotate(d), | ||
| size: ~~(fontSize(d) + 1e-14), | ||
| padding: padding(d), | ||
| xoff: 0, | ||
| yoff: 0, | ||
| x1: 0, | ||
| y1: 0, | ||
| x0: 0, | ||
| y0: 0, | ||
| hasText: false, | ||
| sprite: null, | ||
| datum: d | ||
| })).sort((a, b) => b.size - a.size); | ||
| board = zeroArray((size[0] >> 5) * size[1]), | ||
| bounds = null, | ||
| n = words.length, | ||
| i = -1, | ||
| tags = [], | ||
| data = words.map(d => ({ | ||
| text: text(d), | ||
| font: font(d), | ||
| style: fontStyle(d), | ||
| weight: fontWeight(d), | ||
| rotate: rotate(d), | ||
| size: ~~(fontSize(d) + 1e-14), | ||
| padding: padding(d), | ||
| xoff: 0, | ||
| yoff: 0, | ||
| x1: 0, | ||
| y1: 0, | ||
| x0: 0, | ||
| y0: 0, | ||
| hasText: false, | ||
| sprite: null, | ||
| datum: d | ||
| })).sort((a, b) => b.size - a.size); | ||
| while (++i < n) { | ||
@@ -89,3 +88,2 @@ var d = data[i]; | ||
| cloudSprite(contextAndRatio, d, data, i); | ||
| if (d.hasText && place(board, d, bounds)) { | ||
@@ -99,4 +97,4 @@ tags.push(d); | ||
| y: d.y + d.y1 | ||
| }]; // Temporary hack | ||
| }]; | ||
| // Temporary hack | ||
| d.x -= size[0] >> 1; | ||
@@ -106,6 +104,4 @@ d.y -= size[1] >> 1; | ||
| } | ||
| return tags; | ||
| }; | ||
| function getContext(canvas) { | ||
@@ -124,14 +120,12 @@ canvas.width = canvas.height = 1; | ||
| } | ||
| function place(board, tag, bounds) { | ||
| var startX = tag.x, | ||
| startY = tag.y, | ||
| maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]), | ||
| s = spiral(size), | ||
| dt = random() < .5 ? 1 : -1, | ||
| t = -dt, | ||
| dxdy, | ||
| dx, | ||
| dy; | ||
| startY = tag.y, | ||
| maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]), | ||
| s = spiral(size), | ||
| dt = random() < .5 ? 1 : -1, | ||
| t = -dt, | ||
| dxdy, | ||
| dx, | ||
| dy; | ||
| while (dxdy = s(t += dt)) { | ||
@@ -143,26 +137,22 @@ dx = ~~dxdy[0]; | ||
| tag.y = startY + dy; | ||
| if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 || tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue; // TODO only check for collisions within current bounds. | ||
| if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 || tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue; | ||
| // TODO only check for collisions within current bounds. | ||
| if (!bounds || !cloudCollide(tag, board, size[0])) { | ||
| if (!bounds || collideRects(tag, bounds)) { | ||
| var sprite = tag.sprite, | ||
| w = tag.width >> 5, | ||
| sw = size[0] >> 5, | ||
| lx = tag.x - (w << 4), | ||
| sx = lx & 0x7f, | ||
| msx = 32 - sx, | ||
| h = tag.y1 - tag.y0, | ||
| x = (tag.y + tag.y0) * sw + (lx >> 5), | ||
| last; | ||
| w = tag.width >> 5, | ||
| sw = size[0] >> 5, | ||
| lx = tag.x - (w << 4), | ||
| sx = lx & 0x7f, | ||
| msx = 32 - sx, | ||
| h = tag.y1 - tag.y0, | ||
| x = (tag.y + tag.y0) * sw + (lx >> 5), | ||
| last; | ||
| for (var j = 0; j < h; j++) { | ||
| last = 0; | ||
| for (var i = 0; i <= w; i++) { | ||
| board[x + i] |= last << msx | (i < w ? (last = sprite[j * w + i]) >>> sx : 0); | ||
| } | ||
| x += sw; | ||
| } | ||
| tag.sprite = null; | ||
@@ -173,6 +163,4 @@ return true; | ||
| } | ||
| return false; | ||
| } | ||
| cloud.words = function (_) { | ||
@@ -186,3 +174,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.size = function (_) { | ||
@@ -196,3 +183,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.font = function (_) { | ||
@@ -206,3 +192,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.fontStyle = function (_) { | ||
@@ -216,3 +201,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.fontWeight = function (_) { | ||
@@ -226,3 +210,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.rotate = function (_) { | ||
@@ -236,3 +219,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.text = function (_) { | ||
@@ -246,3 +228,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.spiral = function (_) { | ||
@@ -256,3 +237,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.fontSize = function (_) { | ||
@@ -266,3 +246,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.padding = function (_) { | ||
@@ -276,3 +255,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.random = function (_) { | ||
@@ -286,23 +264,22 @@ if (arguments.length) { | ||
| }; | ||
| return cloud; | ||
| } | ||
| return cloud; | ||
| } // Fetches a monochrome sprite bitmap for the specified text. | ||
| // Fetches a monochrome sprite bitmap for the specified text. | ||
| // Load in batches for speed. | ||
| function cloudSprite(contextAndRatio, d, data, di) { | ||
| if (d.sprite) return; | ||
| var c = contextAndRatio.context, | ||
| ratio = contextAndRatio.ratio; | ||
| ratio = contextAndRatio.ratio; | ||
| c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio); | ||
| var x = 0, | ||
| y = 0, | ||
| maxh = 0, | ||
| n = data.length, | ||
| w, | ||
| w32, | ||
| h, | ||
| i, | ||
| j; | ||
| y = 0, | ||
| maxh = 0, | ||
| n = data.length, | ||
| w, | ||
| w32, | ||
| h, | ||
| i, | ||
| j; | ||
| --di; | ||
| while (++di < n) { | ||
@@ -314,10 +291,9 @@ d = data[di]; | ||
| h = d.size << 1; | ||
| if (d.rotate) { | ||
| var sr = Math.sin(d.rotate * cloudRadians), | ||
| cr = Math.cos(d.rotate * cloudRadians), | ||
| wcr = w * cr, | ||
| wsr = w * sr, | ||
| hcr = h * cr, | ||
| hsr = h * sr; | ||
| cr = Math.cos(d.rotate * cloudRadians), | ||
| wcr = w * cr, | ||
| wsr = w * sr, | ||
| hcr = h * cr, | ||
| hsr = h * sr; | ||
| w = Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f >> 5 << 5; | ||
@@ -328,5 +304,3 @@ h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr)); | ||
| } | ||
| if (h > maxh) maxh = h; | ||
| if (x + w >= cw << 5) { | ||
@@ -337,3 +311,2 @@ x = 0; | ||
| } | ||
| if (y + h >= ch) break; | ||
@@ -343,3 +316,2 @@ c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio); | ||
| c.fillText(d.text, 0, 0); | ||
| if (d.padding) { | ||
@@ -349,3 +321,2 @@ c.lineWidth = 2 * d.padding; | ||
| } | ||
| c.restore(); | ||
@@ -363,6 +334,4 @@ d.width = w; | ||
| } | ||
| var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data, | ||
| sprite = []; | ||
| sprite = []; | ||
| while (--di >= 0) { | ||
@@ -373,6 +342,5 @@ d = data[di]; | ||
| w32 = w >> 5; | ||
| h = d.y1 - d.y0; // Zero the buffer | ||
| h = d.y1 - d.y0; | ||
| // Zero the buffer | ||
| for (i = 0; i < h * w32; i++) sprite[i] = 0; | ||
| x = d.xoff; | ||
@@ -382,12 +350,10 @@ if (x == null) return; | ||
| var seen = 0, | ||
| seenRow = -1; | ||
| seenRow = -1; | ||
| for (j = 0; j < h; j++) { | ||
| for (i = 0; i < w; i++) { | ||
| var k = w32 * j + (i >> 5), | ||
| m = pixels[(y + j) * (cw << 5) + (x + i) << 2] ? 1 << 31 - i % 32 : 0; | ||
| m = pixels[(y + j) * (cw << 5) + (x + i) << 2] ? 1 << 31 - i % 32 : 0; | ||
| sprite[k] |= m; | ||
| seen |= m; | ||
| } | ||
| if (seen) seenRow = j;else { | ||
@@ -400,36 +366,30 @@ d.y0++; | ||
| } | ||
| d.y1 = d.y0 + seenRow; | ||
| d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32); | ||
| } | ||
| } // Use mask-based collision detection. | ||
| } | ||
| // Use mask-based collision detection. | ||
| function cloudCollide(tag, board, sw) { | ||
| sw >>= 5; | ||
| var sprite = tag.sprite, | ||
| w = tag.width >> 5, | ||
| lx = tag.x - (w << 4), | ||
| sx = lx & 0x7f, | ||
| msx = 32 - sx, | ||
| h = tag.y1 - tag.y0, | ||
| x = (tag.y + tag.y0) * sw + (lx >> 5), | ||
| last; | ||
| w = tag.width >> 5, | ||
| lx = tag.x - (w << 4), | ||
| sx = lx & 0x7f, | ||
| msx = 32 - sx, | ||
| h = tag.y1 - tag.y0, | ||
| x = (tag.y + tag.y0) * sw + (lx >> 5), | ||
| last; | ||
| for (var j = 0; j < h; j++) { | ||
| last = 0; | ||
| for (var i = 0; i <= w; i++) { | ||
| if ((last << msx | (i < w ? (last = sprite[j * w + i]) >>> sx : 0)) & board[x + i]) return true; | ||
| } | ||
| x += sw; | ||
| } | ||
| return false; | ||
| } | ||
| function cloudBounds(bounds, d) { | ||
| var b0 = bounds[0], | ||
| b1 = bounds[1]; | ||
| b1 = bounds[1]; | ||
| if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0; | ||
@@ -440,7 +400,5 @@ if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0; | ||
| } | ||
| function collideRects(a, b) { | ||
| return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y; | ||
| } | ||
| function archimedeanSpiral(size) { | ||
@@ -452,11 +410,10 @@ var e = size[0] / size[1]; | ||
| } | ||
| function rectangularSpiral(size) { | ||
| var dy = 4, | ||
| dx = dy * size[0] / size[1], | ||
| x = 0, | ||
| y = 0; | ||
| dx = dy * size[0] / size[1], | ||
| x = 0, | ||
| y = 0; | ||
| return function (t) { | ||
| var sign = t < 0 ? -1 : 1; // See triangular numbers: T_n = n * (n + 1) / 2. | ||
| var sign = t < 0 ? -1 : 1; | ||
| // See triangular numbers: T_n = n * (n + 1) / 2. | ||
| switch (Math.sqrt(1 + 4 * sign * t) - sign & 3) { | ||
@@ -466,11 +423,8 @@ case 0: | ||
| break; | ||
| case 1: | ||
| y += dy; | ||
| break; | ||
| case 2: | ||
| x -= dx; | ||
| break; | ||
| default: | ||
@@ -480,17 +434,13 @@ y -= dy; | ||
| } | ||
| return [x, y]; | ||
| }; | ||
| } // TODO reuse arrays? | ||
| } | ||
| // TODO reuse arrays? | ||
| function zeroArray(n) { | ||
| var a = [], | ||
| i = -1; | ||
| i = -1; | ||
| while (++i < n) a[i] = 0; | ||
| return a; | ||
| } | ||
| function functor(d) { | ||
@@ -501,3 +451,2 @@ return typeof d === 'function' ? d : function () { | ||
| } | ||
| var spirals = { | ||
@@ -577,3 +526,2 @@ archimedean: archimedeanSpiral, | ||
| } | ||
| function modp(param) { | ||
@@ -583,20 +531,17 @@ const p = _[param]; | ||
| } | ||
| const mod = _.modified(); | ||
| if (!(mod || pulse.changed(pulse.ADD_REM) || Params.some(modp))) return; | ||
| const data = pulse.materialize(pulse.SOURCE).source, | ||
| layout = this.value, | ||
| as = _.as || Output; | ||
| layout = this.value, | ||
| as = _.as || Output; | ||
| let fontSize = _.fontSize || 14, | ||
| range; | ||
| vegaUtil.isFunction(fontSize) ? range = _.fontSizeRange : fontSize = vegaUtil.constant(fontSize); // create font size scaling function as needed | ||
| range; | ||
| vegaUtil.isFunction(fontSize) ? range = _.fontSizeRange : fontSize = vegaUtil.constant(fontSize); | ||
| // create font size scaling function as needed | ||
| if (range) { | ||
| const fsize = fontSize, | ||
| sizeScale = vegaScale.scale('sqrt')().domain(vegaUtil.extent(data, fsize)).range(range); | ||
| sizeScale = vegaScale.scale('sqrt')().domain(vegaUtil.extent(data, fsize)).range(range); | ||
| fontSize = x => sizeScale(fsize(x)); | ||
| } | ||
| data.forEach(t => { | ||
@@ -606,10 +551,10 @@ t[as[0]] = NaN; | ||
| t[as[3]] = 0; | ||
| }); // configure layout | ||
| }); | ||
| // configure layout | ||
| const words = layout.words(data).text(_.text).size(_.size || [500, 500]).padding(_.padding || 1).spiral(_.spiral || 'archimedean').rotate(_.rotate || 0).font(_.font || 'sans-serif').fontStyle(_.fontStyle || 'normal').fontWeight(_.fontWeight || 'normal').fontSize(fontSize).random(vegaStatistics.random).layout(); | ||
| const size = layout.size(), | ||
| dx = size[0] >> 1, | ||
| dy = size[1] >> 1, | ||
| n = words.length; | ||
| dx = size[0] >> 1, | ||
| dy = size[1] >> 1, | ||
| n = words.length; | ||
| for (let i = 0, w, t; i < n; ++i) { | ||
@@ -626,6 +571,4 @@ w = words[i]; | ||
| } | ||
| return pulse.reflow(mod).modifies(as); | ||
| } | ||
| }); | ||
@@ -635,4 +578,2 @@ | ||
| Object.defineProperty(exports, '__esModule', { value: true }); | ||
| }))); | ||
| })); |
@@ -1,2 +0,2 @@ | ||
| this.vega=this.vega||{},this.vega.transforms=function(t,e,n,r,a,i){"use strict";var o=Math.PI/180,f=2048;function s(){var t,n,r,a,i,o,s,d=[256,256],g=h,m=[],p=Math.random,v={};function z(t,e,n){for(var r,a,i,o,f,s=e.x,u=e.y,l=Math.sqrt(d[0]*d[0]+d[1]*d[1]),h=g(d),x=p()<.5?1:-1,c=-x;(r=h(c+=x))&&(a=~~r[0],i=~~r[1],!(Math.min(Math.abs(a),Math.abs(i))>=l));)if(e.x=s+a,e.y=u+i,!(e.x+e.x0<0||e.y+e.y0<0||e.x+e.x1>d[0]||e.y+e.y1>d[1]||n&&y(e,t,d[0])||n&&(f=n,!((o=e).x+o.x1>f[0].x&&o.x+o.x0<f[1].x&&o.y+o.y1>f[0].y&&o.y+o.y0<f[1].y)))){for(var m,v=e.sprite,z=e.width>>5,M=d[0]>>5,b=e.x-(z<<4),S=127&b,w=32-S,T=e.y1-e.y0,W=(e.y+e.y0)*M+(b>>5),k=0;k<T;k++){m=0;for(var D=0;D<=z;D++)t[W+D]|=m<<w|(D<z?(m=v[k*z+D])>>>S:0);W+=M}return e.sprite=null,!0}return!1}return v.layout=function(){for(var y=function(t){t.width=t.height=1;var e=Math.sqrt(t.getContext("2d").getImageData(0,0,1,1).data.length>>2);t.width=2048/e,t.height=f/e;var n=t.getContext("2d");return n.fillStyle=n.strokeStyle="red",n.textAlign="center",{context:n,ratio:e}}(e.canvas()),h=function(t){var e=[],n=-1;for(;++n<t;)e[n]=0;return e}((d[0]>>5)*d[1]),x=null,c=m.length,g=-1,v=[],M=m.map(e=>({text:t(e),font:n(e),style:a(e),weight:i(e),rotate:o(e),size:~~(r(e)+1e-14),padding:s(e),xoff:0,yoff:0,x1:0,y1:0,x0:0,y0:0,hasText:!1,sprite:null,datum:e})).sort((t,e)=>e.size-t.size);++g<c;){var b=M[g];b.x=d[0]*(p()+.5)>>1,b.y=d[1]*(p()+.5)>>1,u(y,b,M,g),b.hasText&&z(h,b,x)&&(v.push(b),x?l(x,b):x=[{x:b.x+b.x0,y:b.y+b.y0},{x:b.x+b.x1,y:b.y+b.y1}],b.x-=d[0]>>1,b.y-=d[1]>>1)}return v},v.words=function(t){return arguments.length?(m=t,v):m},v.size=function(t){return arguments.length?(d=[+t[0],+t[1]],v):d},v.font=function(t){return arguments.length?(n=x(t),v):n},v.fontStyle=function(t){return arguments.length?(a=x(t),v):a},v.fontWeight=function(t){return arguments.length?(i=x(t),v):i},v.rotate=function(t){return arguments.length?(o=x(t),v):o},v.text=function(e){return arguments.length?(t=x(e),v):t},v.spiral=function(t){return arguments.length?(g=c[t]||t,v):g},v.fontSize=function(t){return arguments.length?(r=x(t),v):r},v.padding=function(t){return arguments.length?(s=x(t),v):s},v.random=function(t){return arguments.length?(p=t,v):p},v}function u(t,e,n,r){if(!e.sprite){var a=t.context,i=t.ratio;a.clearRect(0,0,2048/i,f/i);var s,u,y,l,h,x=0,c=0,d=0,g=n.length;for(--r;++r<g;){if(e=n[r],a.save(),a.font=e.style+" "+e.weight+" "+~~((e.size+1)/i)+"px "+e.font,s=a.measureText(e.text+"m").width*i,y=e.size<<1,e.rotate){var m=Math.sin(e.rotate*o),p=Math.cos(e.rotate*o),v=s*p,z=s*m,M=y*p,b=y*m;s=Math.max(Math.abs(v+b),Math.abs(v-b))+31>>5<<5,y=~~Math.max(Math.abs(z+M),Math.abs(z-M))}else s=s+31>>5<<5;if(y>d&&(d=y),x+s>=2048&&(x=0,c+=d,d=0),c+y>=f)break;a.translate((x+(s>>1))/i,(c+(y>>1))/i),e.rotate&&a.rotate(e.rotate*o),a.fillText(e.text,0,0),e.padding&&(a.lineWidth=2*e.padding,a.strokeText(e.text,0,0)),a.restore(),e.width=s,e.height=y,e.xoff=x,e.yoff=c,e.x1=s>>1,e.y1=y>>1,e.x0=-e.x1,e.y0=-e.y1,e.hasText=!0,x+=s}for(var S=a.getImageData(0,0,2048/i,f/i).data,w=[];--r>=0;)if((e=n[r]).hasText){for(u=(s=e.width)>>5,y=e.y1-e.y0,l=0;l<y*u;l++)w[l]=0;if(null==(x=e.xoff))return;c=e.yoff;var T=0,W=-1;for(h=0;h<y;h++){for(l=0;l<s;l++){var k=u*h+(l>>5),D=S[2048*(c+h)+(x+l)<<2]?1<<31-l%32:0;w[k]|=D,T|=D}T?W=h:(e.y0++,y--,h--,c++)}e.y1=e.y0+W,e.sprite=w.slice(0,(e.y1-e.y0)*u)}}}function y(t,e,n){n>>=5;for(var r,a=t.sprite,i=t.width>>5,o=t.x-(i<<4),f=127&o,s=32-f,u=t.y1-t.y0,y=(t.y+t.y0)*n+(o>>5),l=0;l<u;l++){r=0;for(var h=0;h<=i;h++)if((r<<s|(h<i?(r=a[l*i+h])>>>f:0))&e[y+h])return!0;y+=n}return!1}function l(t,e){var n=t[0],r=t[1];e.x+e.x0<n.x&&(n.x=e.x+e.x0),e.y+e.y0<n.y&&(n.y=e.y+e.y0),e.x+e.x1>r.x&&(r.x=e.x+e.x1),e.y+e.y1>r.y&&(r.y=e.y+e.y1)}function h(t){var e=t[0]/t[1];return function(t){return[e*(t*=.1)*Math.cos(t),t*Math.sin(t)]}}function x(t){return"function"==typeof t?t:function(){return t}}var c={archimedean:h,rectangular:function(t){var e=4*t[0]/t[1],n=0,r=0;return function(t){var a=t<0?-1:1;switch(Math.sqrt(1+4*a*t)-a&3){case 0:n+=e;break;case 1:r+=4;break;case 2:n-=e;break;default:r-=4}return[n,r]}}};const d=["x","y","font","fontSize","fontStyle","fontWeight","angle"],g=["text","font","rotate","fontSize","fontStyle","fontWeight"];function m(t){n.Transform.call(this,s(),t)}return m.Definition={type:"Wordcloud",metadata:{modifies:!0},params:[{name:"size",type:"number",array:!0,length:2},{name:"font",type:"string",expr:!0,default:"sans-serif"},{name:"fontStyle",type:"string",expr:!0,default:"normal"},{name:"fontWeight",type:"string",expr:!0,default:"normal"},{name:"fontSize",type:"number",expr:!0,default:14},{name:"fontSizeRange",type:"number",array:"nullable",default:[10,50]},{name:"rotate",type:"number",expr:!0,default:0},{name:"text",type:"field"},{name:"spiral",type:"string",values:["archimedean","rectangular"]},{name:"padding",type:"number",expr:!0},{name:"as",type:"string",array:!0,length:7,default:d}]},r.inherits(m,n.Transform,{transform(t,e){!t.size||t.size[0]&&t.size[1]||r.error("Wordcloud size dimensions must be non-zero.");const n=t.modified();if(!(n||e.changed(e.ADD_REM)||g.some((function(n){const a=t[n];return r.isFunction(a)&&e.modified(a.fields)}))))return;const o=e.materialize(e.SOURCE).source,f=this.value,s=t.as||d;let u,y=t.fontSize||14;if(r.isFunction(y)?u=t.fontSizeRange:y=r.constant(y),u){const t=y,e=a.scale("sqrt")().domain(r.extent(o,t)).range(u);y=n=>e(t(n))}o.forEach(t=>{t[s[0]]=NaN,t[s[1]]=NaN,t[s[3]]=0});const l=f.words(o).text(t.text).size(t.size||[500,500]).padding(t.padding||1).spiral(t.spiral||"archimedean").rotate(t.rotate||0).font(t.font||"sans-serif").fontStyle(t.fontStyle||"normal").fontWeight(t.fontWeight||"normal").fontSize(y).random(i.random).layout(),h=f.size(),x=h[0]>>1,c=h[1]>>1,m=l.length;for(let t,e,n=0;n<m;++n)t=l[n],e=t.datum,e[s[0]]=t.x+x,e[s[1]]=t.y+c,e[s[2]]=t.font,e[s[3]]=t.size,e[s[4]]=t.style,e[s[5]]=t.weight,e[s[6]]=t.rotate;return e.reflow(n).modifies(s)}}),t.wordcloud=m,t}({},vega,vega,vega,vega,vega); | ||
| !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("vega-canvas"),require("vega-dataflow"),require("vega-util"),require("vega-scale"),require("vega-statistics")):"function"==typeof define&&define.amd?define(["exports","vega-canvas","vega-dataflow","vega-util","vega-scale","vega-statistics"],e):e(((t="undefined"!=typeof globalThis?globalThis:t||self).vega=t.vega||{},t.vega.transforms={}),t.vega,t.vega,t.vega,t.vega,t.vega)}(this,(function(t,e,n,a,r,i){"use strict";var o=Math.PI/180,f=64,s=2048;function u(){var t,n,a,r,i,o,u,c=[256,256],m=d,p=[],v=Math.random,z={};function b(t,e,n){for(var a,r,i,o,f,s=e.x,u=e.y,l=Math.sqrt(c[0]*c[0]+c[1]*c[1]),x=m(c),d=v()<.5?1:-1,g=-d;(a=x(g+=d))&&(r=~~a[0],i=~~a[1],!(Math.min(Math.abs(r),Math.abs(i))>=l));)if(e.x=s+r,e.y=u+i,!(e.x+e.x0<0||e.y+e.y0<0||e.x+e.x1>c[0]||e.y+e.y1>c[1]||n&&y(e,t,c[0])||n&&(f=n,!((o=e).x+o.x1>f[0].x&&o.x+o.x0<f[1].x&&o.y+o.y1>f[0].y&&o.y+o.y0<f[1].y)))){for(var h,p=e.sprite,z=e.width>>5,b=c[0]>>5,M=e.x-(z<<4),w=127&M,S=32-w,T=e.y1-e.y0,q=(e.y+e.y0)*b+(M>>5),W=0;W<T;W++){h=0;for(var k=0;k<=z;k++)t[q+k]|=h<<S|(k<z?(h=p[W*z+k])>>>w:0);q+=b}return e.sprite=null,!0}return!1}return z.layout=function(){for(var y=function(t){t.width=t.height=1;var e=Math.sqrt(t.getContext("2d").getImageData(0,0,1,1).data.length>>2);t.width=(f<<5)/e,t.height=s/e;var n=t.getContext("2d");return n.fillStyle=n.strokeStyle="red",n.textAlign="center",{context:n,ratio:e}}(e.canvas()),d=function(t){var e=[],n=-1;for(;++n<t;)e[n]=0;return e}((c[0]>>5)*c[1]),g=null,h=p.length,m=-1,z=[],M=p.map((e=>({text:t(e),font:n(e),style:r(e),weight:i(e),rotate:o(e),size:~~(a(e)+1e-14),padding:u(e),xoff:0,yoff:0,x1:0,y1:0,x0:0,y0:0,hasText:!1,sprite:null,datum:e}))).sort(((t,e)=>e.size-t.size));++m<h;){var w=M[m];w.x=c[0]*(v()+.5)>>1,w.y=c[1]*(v()+.5)>>1,l(y,w,M,m),w.hasText&&b(d,w,g)&&(z.push(w),g?x(g,w):g=[{x:w.x+w.x0,y:w.y+w.y0},{x:w.x+w.x1,y:w.y+w.y1}],w.x-=c[0]>>1,w.y-=c[1]>>1)}return z},z.words=function(t){return arguments.length?(p=t,z):p},z.size=function(t){return arguments.length?(c=[+t[0],+t[1]],z):c},z.font=function(t){return arguments.length?(n=g(t),z):n},z.fontStyle=function(t){return arguments.length?(r=g(t),z):r},z.fontWeight=function(t){return arguments.length?(i=g(t),z):i},z.rotate=function(t){return arguments.length?(o=g(t),z):o},z.text=function(e){return arguments.length?(t=g(e),z):t},z.spiral=function(t){return arguments.length?(m=h[t]||t,z):m},z.fontSize=function(t){return arguments.length?(a=g(t),z):a},z.padding=function(t){return arguments.length?(u=g(t),z):u},z.random=function(t){return arguments.length?(v=t,z):v},z}function l(t,e,n,a){if(!e.sprite){var r=t.context,i=t.ratio;r.clearRect(0,0,(f<<5)/i,s/i);var u,l,y,x,d,g=0,h=0,c=0,m=n.length;for(--a;++a<m;){if(e=n[a],r.save(),r.font=e.style+" "+e.weight+" "+~~((e.size+1)/i)+"px "+e.font,u=r.measureText(e.text+"m").width*i,y=e.size<<1,e.rotate){var p=Math.sin(e.rotate*o),v=Math.cos(e.rotate*o),z=u*v,b=u*p,M=y*v,w=y*p;u=Math.max(Math.abs(z+w),Math.abs(z-w))+31>>5<<5,y=~~Math.max(Math.abs(b+M),Math.abs(b-M))}else u=u+31>>5<<5;if(y>c&&(c=y),g+u>=f<<5&&(g=0,h+=c,c=0),h+y>=s)break;r.translate((g+(u>>1))/i,(h+(y>>1))/i),e.rotate&&r.rotate(e.rotate*o),r.fillText(e.text,0,0),e.padding&&(r.lineWidth=2*e.padding,r.strokeText(e.text,0,0)),r.restore(),e.width=u,e.height=y,e.xoff=g,e.yoff=h,e.x1=u>>1,e.y1=y>>1,e.x0=-e.x1,e.y0=-e.y1,e.hasText=!0,g+=u}for(var S=r.getImageData(0,0,(f<<5)/i,s/i).data,T=[];--a>=0;)if((e=n[a]).hasText){for(l=(u=e.width)>>5,y=e.y1-e.y0,x=0;x<y*l;x++)T[x]=0;if(null==(g=e.xoff))return;h=e.yoff;var q=0,W=-1;for(d=0;d<y;d++){for(x=0;x<u;x++){var k=l*d+(x>>5),D=S[(h+d)*(f<<5)+(g+x)<<2]?1<<31-x%32:0;T[k]|=D,q|=D}q?W=d:(e.y0++,y--,d--,h++)}e.y1=e.y0+W,e.sprite=T.slice(0,(e.y1-e.y0)*l)}}}function y(t,e,n){n>>=5;for(var a,r=t.sprite,i=t.width>>5,o=t.x-(i<<4),f=127&o,s=32-f,u=t.y1-t.y0,l=(t.y+t.y0)*n+(o>>5),y=0;y<u;y++){a=0;for(var x=0;x<=i;x++)if((a<<s|(x<i?(a=r[y*i+x])>>>f:0))&e[l+x])return!0;l+=n}return!1}function x(t,e){var n=t[0],a=t[1];e.x+e.x0<n.x&&(n.x=e.x+e.x0),e.y+e.y0<n.y&&(n.y=e.y+e.y0),e.x+e.x1>a.x&&(a.x=e.x+e.x1),e.y+e.y1>a.y&&(a.y=e.y+e.y1)}function d(t){var e=t[0]/t[1];return function(t){return[e*(t*=.1)*Math.cos(t),t*Math.sin(t)]}}function g(t){return"function"==typeof t?t:function(){return t}}var h={archimedean:d,rectangular:function(t){var e=4*t[0]/t[1],n=0,a=0;return function(t){var r=t<0?-1:1;switch(Math.sqrt(1+4*r*t)-r&3){case 0:n+=e;break;case 1:a+=4;break;case 2:n-=e;break;default:a-=4}return[n,a]}}};const c=["x","y","font","fontSize","fontStyle","fontWeight","angle"],m=["text","font","rotate","fontSize","fontStyle","fontWeight"];function p(t){n.Transform.call(this,u(),t)}p.Definition={type:"Wordcloud",metadata:{modifies:!0},params:[{name:"size",type:"number",array:!0,length:2},{name:"font",type:"string",expr:!0,default:"sans-serif"},{name:"fontStyle",type:"string",expr:!0,default:"normal"},{name:"fontWeight",type:"string",expr:!0,default:"normal"},{name:"fontSize",type:"number",expr:!0,default:14},{name:"fontSizeRange",type:"number",array:"nullable",default:[10,50]},{name:"rotate",type:"number",expr:!0,default:0},{name:"text",type:"field"},{name:"spiral",type:"string",values:["archimedean","rectangular"]},{name:"padding",type:"number",expr:!0},{name:"as",type:"string",array:!0,length:7,default:c}]},a.inherits(p,n.Transform,{transform(t,e){!t.size||t.size[0]&&t.size[1]||a.error("Wordcloud size dimensions must be non-zero.");const n=t.modified();if(!(n||e.changed(e.ADD_REM)||m.some((function(n){const r=t[n];return a.isFunction(r)&&e.modified(r.fields)}))))return;const o=e.materialize(e.SOURCE).source,f=this.value,s=t.as||c;let u,l=t.fontSize||14;if(a.isFunction(l)?u=t.fontSizeRange:l=a.constant(l),u){const t=l,e=r.scale("sqrt")().domain(a.extent(o,t)).range(u);l=n=>e(t(n))}o.forEach((t=>{t[s[0]]=NaN,t[s[1]]=NaN,t[s[3]]=0}));const y=f.words(o).text(t.text).size(t.size||[500,500]).padding(t.padding||1).spiral(t.spiral||"archimedean").rotate(t.rotate||0).font(t.font||"sans-serif").fontStyle(t.fontStyle||"normal").fontWeight(t.fontWeight||"normal").fontSize(l).random(i.random).layout(),x=f.size(),d=x[0]>>1,g=x[1]>>1,h=y.length;for(let t,e,n=0;n<h;++n)t=y[n],e=t.datum,e[s[0]]=t.x+d,e[s[1]]=t.y+g,e[s[2]]=t.font,e[s[3]]=t.size,e[s[4]]=t.style,e[s[5]]=t.weight,e[s[6]]=t.rotate;return e.reflow(n).modifies(s)}}),t.wordcloud=p})); | ||
| //# sourceMappingURL=vega-wordcloud.min.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"vega-wordcloud.min.js","sources":["../src/CloudLayout.js","../src/Wordcloud.js"],"sourcesContent":["import {canvas} from 'vega-canvas';\n\n/*\nCopyright (c) 2013, Jason Davies.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n * The name Jason Davies may not be used to endorse or promote products\n derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL JASON DAVIES BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\nOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\nADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n// Word cloud layout by Jason Davies, https://www.jasondavies.com/wordcloud/\n// Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf\n\nvar cloudRadians = Math.PI / 180,\n cw = 1 << 11 >> 5,\n ch = 1 << 11;\n\nexport default function() {\n var size = [256, 256],\n text,\n font,\n fontSize,\n fontStyle,\n fontWeight,\n rotate,\n padding,\n spiral = archimedeanSpiral,\n words = [],\n random = Math.random,\n cloud = {};\n\n cloud.layout = function() {\n var contextAndRatio = getContext(canvas()),\n board = zeroArray((size[0] >> 5) * size[1]),\n bounds = null,\n n = words.length,\n i = -1,\n tags = [],\n data = words.map(d => ({\n text: text(d),\n font: font(d),\n style: fontStyle(d),\n weight: fontWeight(d),\n rotate: rotate(d),\n size: ~~(fontSize(d) + 1e-14),\n padding: padding(d),\n xoff: 0,\n yoff: 0,\n x1: 0,\n y1: 0,\n x0: 0,\n y0: 0,\n hasText: false,\n sprite: null,\n datum: d\n })).sort((a, b) => b.size - a.size);\n\n while (++i < n) {\n var d = data[i];\n d.x = (size[0] * (random() + .5)) >> 1;\n d.y = (size[1] * (random() + .5)) >> 1;\n cloudSprite(contextAndRatio, d, data, i);\n if (d.hasText && place(board, d, bounds)) {\n tags.push(d);\n if (bounds) cloudBounds(bounds, d);\n else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}];\n // Temporary hack\n d.x -= size[0] >> 1;\n d.y -= size[1] >> 1;\n }\n }\n\n return tags;\n };\n\n function getContext(canvas) {\n canvas.width = canvas.height = 1;\n var ratio = Math.sqrt(canvas.getContext('2d').getImageData(0, 0, 1, 1).data.length >> 2);\n canvas.width = (cw << 5) / ratio;\n canvas.height = ch / ratio;\n\n var context = canvas.getContext('2d');\n context.fillStyle = context.strokeStyle = 'red';\n context.textAlign = 'center';\n\n return {context: context, ratio: ratio};\n }\n\n function place(board, tag, bounds) {\n var startX = tag.x,\n startY = tag.y,\n maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]),\n s = spiral(size),\n dt = random() < .5 ? 1 : -1,\n t = -dt,\n dxdy,\n dx,\n dy;\n\n while (dxdy = s(t += dt)) {\n dx = ~~dxdy[0];\n dy = ~~dxdy[1];\n\n if (Math.min(Math.abs(dx), Math.abs(dy)) >= maxDelta) break;\n\n tag.x = startX + dx;\n tag.y = startY + dy;\n\n if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 ||\n tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue;\n // TODO only check for collisions within current bounds.\n if (!bounds || !cloudCollide(tag, board, size[0])) {\n if (!bounds || collideRects(tag, bounds)) {\n var sprite = tag.sprite,\n w = tag.width >> 5,\n sw = size[0] >> 5,\n lx = tag.x - (w << 4),\n sx = lx & 0x7f,\n msx = 32 - sx,\n h = tag.y1 - tag.y0,\n x = (tag.y + tag.y0) * sw + (lx >> 5),\n last;\n for (var j = 0; j < h; j++) {\n last = 0;\n for (var i = 0; i <= w; i++) {\n board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0);\n }\n x += sw;\n }\n tag.sprite = null;\n return true;\n }\n }\n }\n return false;\n }\n\n cloud.words = function(_) {\n if (arguments.length) {\n words = _;\n return cloud;\n } else {\n return words;\n }\n };\n\n cloud.size = function(_) {\n if (arguments.length) {\n size = [+_[0], +_[1]];\n return cloud;\n } else {\n return size;\n }\n };\n\n cloud.font = function(_) {\n if (arguments.length) {\n font = functor(_);\n return cloud;\n } else {\n return font;\n }\n };\n\n cloud.fontStyle = function(_) {\n if (arguments.length) {\n fontStyle = functor(_);\n return cloud;\n } else {\n return fontStyle;\n }\n };\n\n cloud.fontWeight = function(_) {\n if (arguments.length) {\n fontWeight = functor(_);\n return cloud;\n } else {\n return fontWeight;\n }\n };\n\n cloud.rotate = function(_) {\n if (arguments.length) {\n rotate = functor(_);\n return cloud;\n } else {\n return rotate;\n }\n };\n\n cloud.text = function(_) {\n if (arguments.length) {\n text = functor(_);\n return cloud;\n } else {\n return text;\n }\n };\n\n cloud.spiral = function(_) {\n if (arguments.length) {\n spiral = spirals[_] || _;\n return cloud;\n } else {\n return spiral;\n }\n };\n\n cloud.fontSize = function(_) {\n if (arguments.length) {\n fontSize = functor(_);\n return cloud;\n } else {\n return fontSize;\n }\n };\n\n cloud.padding = function(_) {\n if (arguments.length) {\n padding = functor(_);\n return cloud;\n } else {\n return padding;\n }\n };\n\n cloud.random = function(_) {\n if (arguments.length) {\n random = _;\n return cloud;\n } else {\n return random;\n }\n };\n\n return cloud;\n}\n\n// Fetches a monochrome sprite bitmap for the specified text.\n// Load in batches for speed.\nfunction cloudSprite(contextAndRatio, d, data, di) {\n if (d.sprite) return;\n var c = contextAndRatio.context,\n ratio = contextAndRatio.ratio;\n\n c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio);\n var x = 0,\n y = 0,\n maxh = 0,\n n = data.length,\n w, w32, h, i, j;\n --di;\n while (++di < n) {\n d = data[di];\n c.save();\n c.font = d.style + ' ' + d.weight + ' ' + ~~((d.size + 1) / ratio) + 'px ' + d.font;\n w = c.measureText(d.text + 'm').width * ratio;\n h = d.size << 1;\n if (d.rotate) {\n var sr = Math.sin(d.rotate * cloudRadians),\n cr = Math.cos(d.rotate * cloudRadians),\n wcr = w * cr,\n wsr = w * sr,\n hcr = h * cr,\n hsr = h * sr;\n w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5;\n h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr));\n } else {\n w = (w + 0x1f) >> 5 << 5;\n }\n if (h > maxh) maxh = h;\n if (x + w >= (cw << 5)) {\n x = 0;\n y += maxh;\n maxh = 0;\n }\n if (y + h >= ch) break;\n c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio);\n if (d.rotate) c.rotate(d.rotate * cloudRadians);\n c.fillText(d.text, 0, 0);\n if (d.padding) {\n c.lineWidth = 2 * d.padding;\n c.strokeText(d.text, 0, 0);\n }\n c.restore();\n d.width = w;\n d.height = h;\n d.xoff = x;\n d.yoff = y;\n d.x1 = w >> 1;\n d.y1 = h >> 1;\n d.x0 = -d.x1;\n d.y0 = -d.y1;\n d.hasText = true;\n x += w;\n }\n var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data,\n sprite = [];\n while (--di >= 0) {\n d = data[di];\n if (!d.hasText) continue;\n w = d.width;\n w32 = w >> 5;\n h = d.y1 - d.y0;\n // Zero the buffer\n for (i = 0; i < h * w32; i++) sprite[i] = 0;\n x = d.xoff;\n if (x == null) return;\n y = d.yoff;\n var seen = 0,\n seenRow = -1;\n for (j = 0; j < h; j++) {\n for (i = 0; i < w; i++) {\n var k = w32 * j + (i >> 5),\n m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0;\n sprite[k] |= m;\n seen |= m;\n }\n if (seen) seenRow = j;\n else {\n d.y0++;\n h--;\n j--;\n y++;\n }\n }\n d.y1 = d.y0 + seenRow;\n d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32);\n }\n}\n\n// Use mask-based collision detection.\nfunction cloudCollide(tag, board, sw) {\n sw >>= 5;\n var sprite = tag.sprite,\n w = tag.width >> 5,\n lx = tag.x - (w << 4),\n sx = lx & 0x7f,\n msx = 32 - sx,\n h = tag.y1 - tag.y0,\n x = (tag.y + tag.y0) * sw + (lx >> 5),\n last;\n for (var j = 0; j < h; j++) {\n last = 0;\n for (var i = 0; i <= w; i++) {\n if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0))\n & board[x + i]) return true;\n }\n x += sw;\n }\n return false;\n}\n\nfunction cloudBounds(bounds, d) {\n var b0 = bounds[0],\n b1 = bounds[1];\n if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0;\n if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0;\n if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1;\n if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1;\n}\n\nfunction collideRects(a, b) {\n return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y;\n}\n\nfunction archimedeanSpiral(size) {\n var e = size[0] / size[1];\n return function(t) {\n return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)];\n };\n}\n\nfunction rectangularSpiral(size) {\n var dy = 4,\n dx = dy * size[0] / size[1],\n x = 0,\n y = 0;\n return function(t) {\n var sign = t < 0 ? -1 : 1;\n // See triangular numbers: T_n = n * (n + 1) / 2.\n switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) {\n case 0: x += dx; break;\n case 1: y += dy; break;\n case 2: x -= dx; break;\n default: y -= dy; break;\n }\n return [x, y];\n };\n}\n\n// TODO reuse arrays?\nfunction zeroArray(n) {\n var a = [],\n i = -1;\n while (++i < n) a[i] = 0;\n return a;\n}\n\nfunction functor(d) {\n return typeof d === 'function' ? d : function() { return d; };\n}\n\nvar spirals = {\n archimedean: archimedeanSpiral,\n rectangular: rectangularSpiral\n};\n","import cloud from './CloudLayout';\nimport {Transform} from 'vega-dataflow';\nimport {constant, error, extent, inherits, isFunction} from 'vega-util';\nimport {scale} from 'vega-scale';\nimport {random} from 'vega-statistics';\n\nconst Output = ['x', 'y', 'font', 'fontSize', 'fontStyle', 'fontWeight', 'angle'];\n\nconst Params = ['text', 'font', 'rotate', 'fontSize', 'fontStyle', 'fontWeight'];\n\nexport default function Wordcloud(params) {\n Transform.call(this, cloud(), params);\n}\n\nWordcloud.Definition = {\n 'type': 'Wordcloud',\n 'metadata': {'modifies': true},\n 'params': [\n { 'name': 'size', 'type': 'number', 'array': true, 'length': 2 },\n { 'name': 'font', 'type': 'string', 'expr': true, 'default': 'sans-serif' },\n { 'name': 'fontStyle', 'type': 'string', 'expr': true, 'default': 'normal' },\n { 'name': 'fontWeight', 'type': 'string', 'expr': true, 'default': 'normal' },\n { 'name': 'fontSize', 'type': 'number', 'expr': true, 'default': 14 },\n { 'name': 'fontSizeRange', 'type': 'number', 'array': 'nullable', 'default': [10, 50] },\n { 'name': 'rotate', 'type': 'number', 'expr': true, 'default': 0 },\n { 'name': 'text', 'type': 'field' },\n { 'name': 'spiral', 'type': 'string', 'values': ['archimedean', 'rectangular'] },\n { 'name': 'padding', 'type': 'number', 'expr': true },\n { 'name': 'as', 'type': 'string', 'array': true, 'length': 7, 'default': Output }\n ]\n};\n\ninherits(Wordcloud, Transform, {\n transform(_, pulse) {\n if (_.size && !(_.size[0] && _.size[1])) {\n error('Wordcloud size dimensions must be non-zero.');\n }\n\n function modp(param) {\n const p = _[param];\n return isFunction(p) && pulse.modified(p.fields);\n }\n\n const mod = _.modified();\n if (!(mod || pulse.changed(pulse.ADD_REM) || Params.some(modp))) return;\n\n const data = pulse.materialize(pulse.SOURCE).source,\n layout = this.value,\n as = _.as || Output;\n\n let fontSize = _.fontSize || 14,\n range;\n\n isFunction(fontSize)\n ? (range = _.fontSizeRange)\n : (fontSize = constant(fontSize));\n\n // create font size scaling function as needed\n if (range) {\n const fsize = fontSize,\n sizeScale = scale('sqrt')()\n .domain(extent(data, fsize))\n .range(range);\n fontSize = x => sizeScale(fsize(x));\n }\n\n data.forEach(t => {\n t[as[0]] = NaN;\n t[as[1]] = NaN;\n t[as[3]] = 0;\n });\n\n // configure layout\n const words = layout\n .words(data)\n .text(_.text)\n .size(_.size || [500, 500])\n .padding(_.padding || 1)\n .spiral(_.spiral || 'archimedean')\n .rotate(_.rotate || 0)\n .font(_.font || 'sans-serif')\n .fontStyle(_.fontStyle || 'normal')\n .fontWeight(_.fontWeight || 'normal')\n .fontSize(fontSize)\n .random(random)\n .layout();\n\n const size = layout.size(),\n dx = size[0] >> 1,\n dy = size[1] >> 1,\n n = words.length;\n\n for (let i = 0, w, t; i<n; ++i) {\n w = words[i];\n t = w.datum;\n t[as[0]] = w.x + dx;\n t[as[1]] = w.y + dy;\n t[as[2]] = w.font;\n t[as[3]] = w.size;\n t[as[4]] = w.style;\n t[as[5]] = w.weight;\n t[as[6]] = w.rotate;\n }\n\n return pulse.reflow(mod).modifies(as);\n }\n});\n"],"names":["cloudRadians","Math","PI","ch","text","font","fontSize","fontStyle","fontWeight","rotate","padding","size","spiral","archimedeanSpiral","words","random","cloud","place","board","tag","bounds","dxdy","dx","dy","a","b","startX","x","startY","y","maxDelta","sqrt","s","dt","t","min","abs","x0","y0","x1","y1","cloudCollide","last","sprite","w","width","sw","lx","sx","msx","h","j","i","layout","contextAndRatio","canvas","height","ratio","getContext","getImageData","data","length","context","fillStyle","strokeStyle","textAlign","n","zeroArray","tags","map","d","style","weight","xoff","yoff","hasText","datum","sort","cloudSprite","push","cloudBounds","_","arguments","functor","spirals","di","c","clearRect","w32","maxh","save","measureText","sr","sin","cr","cos","wcr","wsr","hcr","hsr","max","cw","translate","fillText","lineWidth","strokeText","restore","pixels","seen","seenRow","k","m","slice","b0","b1","e","archimedean","rectangular","sign","Output","Params","Wordcloud","params","Transform","call","this","Definition","transform","pulse","error","mod","modified","changed","ADD_REM","some","param","p","isFunction","fields","materialize","SOURCE","source","value","as","range","fontSizeRange","constant","fsize","sizeScale","scale","domain","extent","forEach","NaN","reflow","modifies"],"mappings":"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"} | ||
| {"version":3,"file":"vega-wordcloud.min.js","sources":["../src/CloudLayout.js","../src/Wordcloud.js"],"sourcesContent":["import {canvas} from 'vega-canvas';\n\n/*\nCopyright (c) 2013, Jason Davies.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n * The name Jason Davies may not be used to endorse or promote products\n derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL JASON DAVIES BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\nPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\nOR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\nADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n// Word cloud layout by Jason Davies, https://www.jasondavies.com/wordcloud/\n// Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf\n\nvar cloudRadians = Math.PI / 180,\n cw = 1 << 11 >> 5,\n ch = 1 << 11;\n\nexport default function() {\n var size = [256, 256],\n text,\n font,\n fontSize,\n fontStyle,\n fontWeight,\n rotate,\n padding,\n spiral = archimedeanSpiral,\n words = [],\n random = Math.random,\n cloud = {};\n\n cloud.layout = function() {\n var contextAndRatio = getContext(canvas()),\n board = zeroArray((size[0] >> 5) * size[1]),\n bounds = null,\n n = words.length,\n i = -1,\n tags = [],\n data = words.map(d => ({\n text: text(d),\n font: font(d),\n style: fontStyle(d),\n weight: fontWeight(d),\n rotate: rotate(d),\n size: ~~(fontSize(d) + 1e-14),\n padding: padding(d),\n xoff: 0,\n yoff: 0,\n x1: 0,\n y1: 0,\n x0: 0,\n y0: 0,\n hasText: false,\n sprite: null,\n datum: d\n })).sort((a, b) => b.size - a.size);\n\n while (++i < n) {\n var d = data[i];\n d.x = (size[0] * (random() + .5)) >> 1;\n d.y = (size[1] * (random() + .5)) >> 1;\n cloudSprite(contextAndRatio, d, data, i);\n if (d.hasText && place(board, d, bounds)) {\n tags.push(d);\n if (bounds) cloudBounds(bounds, d);\n else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}];\n // Temporary hack\n d.x -= size[0] >> 1;\n d.y -= size[1] >> 1;\n }\n }\n\n return tags;\n };\n\n function getContext(canvas) {\n canvas.width = canvas.height = 1;\n var ratio = Math.sqrt(canvas.getContext('2d').getImageData(0, 0, 1, 1).data.length >> 2);\n canvas.width = (cw << 5) / ratio;\n canvas.height = ch / ratio;\n\n var context = canvas.getContext('2d');\n context.fillStyle = context.strokeStyle = 'red';\n context.textAlign = 'center';\n\n return {context: context, ratio: ratio};\n }\n\n function place(board, tag, bounds) {\n var startX = tag.x,\n startY = tag.y,\n maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]),\n s = spiral(size),\n dt = random() < .5 ? 1 : -1,\n t = -dt,\n dxdy,\n dx,\n dy;\n\n while (dxdy = s(t += dt)) {\n dx = ~~dxdy[0];\n dy = ~~dxdy[1];\n\n if (Math.min(Math.abs(dx), Math.abs(dy)) >= maxDelta) break;\n\n tag.x = startX + dx;\n tag.y = startY + dy;\n\n if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 ||\n tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue;\n // TODO only check for collisions within current bounds.\n if (!bounds || !cloudCollide(tag, board, size[0])) {\n if (!bounds || collideRects(tag, bounds)) {\n var sprite = tag.sprite,\n w = tag.width >> 5,\n sw = size[0] >> 5,\n lx = tag.x - (w << 4),\n sx = lx & 0x7f,\n msx = 32 - sx,\n h = tag.y1 - tag.y0,\n x = (tag.y + tag.y0) * sw + (lx >> 5),\n last;\n for (var j = 0; j < h; j++) {\n last = 0;\n for (var i = 0; i <= w; i++) {\n board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0);\n }\n x += sw;\n }\n tag.sprite = null;\n return true;\n }\n }\n }\n return false;\n }\n\n cloud.words = function(_) {\n if (arguments.length) {\n words = _;\n return cloud;\n } else {\n return words;\n }\n };\n\n cloud.size = function(_) {\n if (arguments.length) {\n size = [+_[0], +_[1]];\n return cloud;\n } else {\n return size;\n }\n };\n\n cloud.font = function(_) {\n if (arguments.length) {\n font = functor(_);\n return cloud;\n } else {\n return font;\n }\n };\n\n cloud.fontStyle = function(_) {\n if (arguments.length) {\n fontStyle = functor(_);\n return cloud;\n } else {\n return fontStyle;\n }\n };\n\n cloud.fontWeight = function(_) {\n if (arguments.length) {\n fontWeight = functor(_);\n return cloud;\n } else {\n return fontWeight;\n }\n };\n\n cloud.rotate = function(_) {\n if (arguments.length) {\n rotate = functor(_);\n return cloud;\n } else {\n return rotate;\n }\n };\n\n cloud.text = function(_) {\n if (arguments.length) {\n text = functor(_);\n return cloud;\n } else {\n return text;\n }\n };\n\n cloud.spiral = function(_) {\n if (arguments.length) {\n spiral = spirals[_] || _;\n return cloud;\n } else {\n return spiral;\n }\n };\n\n cloud.fontSize = function(_) {\n if (arguments.length) {\n fontSize = functor(_);\n return cloud;\n } else {\n return fontSize;\n }\n };\n\n cloud.padding = function(_) {\n if (arguments.length) {\n padding = functor(_);\n return cloud;\n } else {\n return padding;\n }\n };\n\n cloud.random = function(_) {\n if (arguments.length) {\n random = _;\n return cloud;\n } else {\n return random;\n }\n };\n\n return cloud;\n}\n\n// Fetches a monochrome sprite bitmap for the specified text.\n// Load in batches for speed.\nfunction cloudSprite(contextAndRatio, d, data, di) {\n if (d.sprite) return;\n var c = contextAndRatio.context,\n ratio = contextAndRatio.ratio;\n\n c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio);\n var x = 0,\n y = 0,\n maxh = 0,\n n = data.length,\n w, w32, h, i, j;\n --di;\n while (++di < n) {\n d = data[di];\n c.save();\n c.font = d.style + ' ' + d.weight + ' ' + ~~((d.size + 1) / ratio) + 'px ' + d.font;\n w = c.measureText(d.text + 'm').width * ratio;\n h = d.size << 1;\n if (d.rotate) {\n var sr = Math.sin(d.rotate * cloudRadians),\n cr = Math.cos(d.rotate * cloudRadians),\n wcr = w * cr,\n wsr = w * sr,\n hcr = h * cr,\n hsr = h * sr;\n w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5;\n h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr));\n } else {\n w = (w + 0x1f) >> 5 << 5;\n }\n if (h > maxh) maxh = h;\n if (x + w >= (cw << 5)) {\n x = 0;\n y += maxh;\n maxh = 0;\n }\n if (y + h >= ch) break;\n c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio);\n if (d.rotate) c.rotate(d.rotate * cloudRadians);\n c.fillText(d.text, 0, 0);\n if (d.padding) {\n c.lineWidth = 2 * d.padding;\n c.strokeText(d.text, 0, 0);\n }\n c.restore();\n d.width = w;\n d.height = h;\n d.xoff = x;\n d.yoff = y;\n d.x1 = w >> 1;\n d.y1 = h >> 1;\n d.x0 = -d.x1;\n d.y0 = -d.y1;\n d.hasText = true;\n x += w;\n }\n var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data,\n sprite = [];\n while (--di >= 0) {\n d = data[di];\n if (!d.hasText) continue;\n w = d.width;\n w32 = w >> 5;\n h = d.y1 - d.y0;\n // Zero the buffer\n for (i = 0; i < h * w32; i++) sprite[i] = 0;\n x = d.xoff;\n if (x == null) return;\n y = d.yoff;\n var seen = 0,\n seenRow = -1;\n for (j = 0; j < h; j++) {\n for (i = 0; i < w; i++) {\n var k = w32 * j + (i >> 5),\n m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0;\n sprite[k] |= m;\n seen |= m;\n }\n if (seen) seenRow = j;\n else {\n d.y0++;\n h--;\n j--;\n y++;\n }\n }\n d.y1 = d.y0 + seenRow;\n d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32);\n }\n}\n\n// Use mask-based collision detection.\nfunction cloudCollide(tag, board, sw) {\n sw >>= 5;\n var sprite = tag.sprite,\n w = tag.width >> 5,\n lx = tag.x - (w << 4),\n sx = lx & 0x7f,\n msx = 32 - sx,\n h = tag.y1 - tag.y0,\n x = (tag.y + tag.y0) * sw + (lx >> 5),\n last;\n for (var j = 0; j < h; j++) {\n last = 0;\n for (var i = 0; i <= w; i++) {\n if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0))\n & board[x + i]) return true;\n }\n x += sw;\n }\n return false;\n}\n\nfunction cloudBounds(bounds, d) {\n var b0 = bounds[0],\n b1 = bounds[1];\n if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0;\n if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0;\n if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1;\n if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1;\n}\n\nfunction collideRects(a, b) {\n return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y;\n}\n\nfunction archimedeanSpiral(size) {\n var e = size[0] / size[1];\n return function(t) {\n return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)];\n };\n}\n\nfunction rectangularSpiral(size) {\n var dy = 4,\n dx = dy * size[0] / size[1],\n x = 0,\n y = 0;\n return function(t) {\n var sign = t < 0 ? -1 : 1;\n // See triangular numbers: T_n = n * (n + 1) / 2.\n switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) {\n case 0: x += dx; break;\n case 1: y += dy; break;\n case 2: x -= dx; break;\n default: y -= dy; break;\n }\n return [x, y];\n };\n}\n\n// TODO reuse arrays?\nfunction zeroArray(n) {\n var a = [],\n i = -1;\n while (++i < n) a[i] = 0;\n return a;\n}\n\nfunction functor(d) {\n return typeof d === 'function' ? d : function() { return d; };\n}\n\nvar spirals = {\n archimedean: archimedeanSpiral,\n rectangular: rectangularSpiral\n};\n","import cloud from './CloudLayout';\nimport {Transform} from 'vega-dataflow';\nimport {constant, error, extent, inherits, isFunction} from 'vega-util';\nimport {scale} from 'vega-scale';\nimport {random} from 'vega-statistics';\n\nconst Output = ['x', 'y', 'font', 'fontSize', 'fontStyle', 'fontWeight', 'angle'];\n\nconst Params = ['text', 'font', 'rotate', 'fontSize', 'fontStyle', 'fontWeight'];\n\nexport default function Wordcloud(params) {\n Transform.call(this, cloud(), params);\n}\n\nWordcloud.Definition = {\n 'type': 'Wordcloud',\n 'metadata': {'modifies': true},\n 'params': [\n { 'name': 'size', 'type': 'number', 'array': true, 'length': 2 },\n { 'name': 'font', 'type': 'string', 'expr': true, 'default': 'sans-serif' },\n { 'name': 'fontStyle', 'type': 'string', 'expr': true, 'default': 'normal' },\n { 'name': 'fontWeight', 'type': 'string', 'expr': true, 'default': 'normal' },\n { 'name': 'fontSize', 'type': 'number', 'expr': true, 'default': 14 },\n { 'name': 'fontSizeRange', 'type': 'number', 'array': 'nullable', 'default': [10, 50] },\n { 'name': 'rotate', 'type': 'number', 'expr': true, 'default': 0 },\n { 'name': 'text', 'type': 'field' },\n { 'name': 'spiral', 'type': 'string', 'values': ['archimedean', 'rectangular'] },\n { 'name': 'padding', 'type': 'number', 'expr': true },\n { 'name': 'as', 'type': 'string', 'array': true, 'length': 7, 'default': Output }\n ]\n};\n\ninherits(Wordcloud, Transform, {\n transform(_, pulse) {\n if (_.size && !(_.size[0] && _.size[1])) {\n error('Wordcloud size dimensions must be non-zero.');\n }\n\n function modp(param) {\n const p = _[param];\n return isFunction(p) && pulse.modified(p.fields);\n }\n\n const mod = _.modified();\n if (!(mod || pulse.changed(pulse.ADD_REM) || Params.some(modp))) return;\n\n const data = pulse.materialize(pulse.SOURCE).source,\n layout = this.value,\n as = _.as || Output;\n\n let fontSize = _.fontSize || 14,\n range;\n\n isFunction(fontSize)\n ? (range = _.fontSizeRange)\n : (fontSize = constant(fontSize));\n\n // create font size scaling function as needed\n if (range) {\n const fsize = fontSize,\n sizeScale = scale('sqrt')()\n .domain(extent(data, fsize))\n .range(range);\n fontSize = x => sizeScale(fsize(x));\n }\n\n data.forEach(t => {\n t[as[0]] = NaN;\n t[as[1]] = NaN;\n t[as[3]] = 0;\n });\n\n // configure layout\n const words = layout\n .words(data)\n .text(_.text)\n .size(_.size || [500, 500])\n .padding(_.padding || 1)\n .spiral(_.spiral || 'archimedean')\n .rotate(_.rotate || 0)\n .font(_.font || 'sans-serif')\n .fontStyle(_.fontStyle || 'normal')\n .fontWeight(_.fontWeight || 'normal')\n .fontSize(fontSize)\n .random(random)\n .layout();\n\n const size = layout.size(),\n dx = size[0] >> 1,\n dy = size[1] >> 1,\n n = words.length;\n\n for (let i = 0, w, t; i<n; ++i) {\n w = words[i];\n t = w.datum;\n t[as[0]] = w.x + dx;\n t[as[1]] = w.y + dy;\n t[as[2]] = w.font;\n t[as[3]] = w.size;\n t[as[4]] = w.style;\n t[as[5]] = w.weight;\n t[as[6]] = w.rotate;\n }\n\n return pulse.reflow(mod).modifies(as);\n }\n});\n"],"names":["cloudRadians","Math","PI","cw","ch","cloud","text","font","fontSize","fontStyle","fontWeight","rotate","padding","size","spiral","archimedeanSpiral","words","random","place","board","tag","bounds","dxdy","dx","dy","a","b","startX","x","startY","y","maxDelta","sqrt","s","dt","t","min","abs","x0","y0","x1","y1","cloudCollide","last","sprite","w","width","sw","lx","sx","msx","h","j","i","layout","contextAndRatio","canvas","height","ratio","getContext","getImageData","data","length","context","fillStyle","strokeStyle","textAlign","n","zeroArray","tags","map","d","style","weight","xoff","yoff","hasText","datum","sort","cloudSprite","push","cloudBounds","_","arguments","functor","spirals","di","c","clearRect","w32","maxh","save","measureText","sr","sin","cr","cos","wcr","wsr","hcr","hsr","max","translate","fillText","lineWidth","strokeText","restore","pixels","seen","seenRow","k","m","slice","b0","b1","e","archimedean","rectangular","sign","Output","Params","Wordcloud","params","Transform","call","this","Definition","type","metadata","modifies","name","array","expr","default","values","inherits","transform","pulse","error","mod","modified","changed","ADD_REM","some","param","p","isFunction","fields","materialize","SOURCE","source","value","as","range","fontSizeRange","constant","fsize","sizeScale","scale","domain","extent","forEach","NaN","reflow"],"mappings":"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"} |
+108
-165
@@ -35,2 +35,3 @@ import { canvas } from 'vega-canvas'; | ||
| */ | ||
| // Word cloud layout by Jason Davies, https://www.jasondavies.com/wordcloud/ | ||
@@ -40,44 +41,42 @@ // Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf | ||
| var cloudRadians = Math.PI / 180, | ||
| cw = 1 << 11 >> 5, | ||
| ch = 1 << 11; | ||
| cw = 1 << 11 >> 5, | ||
| ch = 1 << 11; | ||
| function cloud () { | ||
| var size = [256, 256], | ||
| text, | ||
| font, | ||
| fontSize, | ||
| fontStyle, | ||
| fontWeight, | ||
| rotate, | ||
| padding, | ||
| spiral = archimedeanSpiral, | ||
| words = [], | ||
| random = Math.random, | ||
| cloud = {}; | ||
| text, | ||
| font, | ||
| fontSize, | ||
| fontStyle, | ||
| fontWeight, | ||
| rotate, | ||
| padding, | ||
| spiral = archimedeanSpiral, | ||
| words = [], | ||
| random = Math.random, | ||
| cloud = {}; | ||
| cloud.layout = function () { | ||
| var contextAndRatio = getContext(canvas()), | ||
| board = zeroArray((size[0] >> 5) * size[1]), | ||
| bounds = null, | ||
| n = words.length, | ||
| i = -1, | ||
| tags = [], | ||
| data = words.map(d => ({ | ||
| text: text(d), | ||
| font: font(d), | ||
| style: fontStyle(d), | ||
| weight: fontWeight(d), | ||
| rotate: rotate(d), | ||
| size: ~~(fontSize(d) + 1e-14), | ||
| padding: padding(d), | ||
| xoff: 0, | ||
| yoff: 0, | ||
| x1: 0, | ||
| y1: 0, | ||
| x0: 0, | ||
| y0: 0, | ||
| hasText: false, | ||
| sprite: null, | ||
| datum: d | ||
| })).sort((a, b) => b.size - a.size); | ||
| board = zeroArray((size[0] >> 5) * size[1]), | ||
| bounds = null, | ||
| n = words.length, | ||
| i = -1, | ||
| tags = [], | ||
| data = words.map(d => ({ | ||
| text: text(d), | ||
| font: font(d), | ||
| style: fontStyle(d), | ||
| weight: fontWeight(d), | ||
| rotate: rotate(d), | ||
| size: ~~(fontSize(d) + 1e-14), | ||
| padding: padding(d), | ||
| xoff: 0, | ||
| yoff: 0, | ||
| x1: 0, | ||
| y1: 0, | ||
| x0: 0, | ||
| y0: 0, | ||
| hasText: false, | ||
| sprite: null, | ||
| datum: d | ||
| })).sort((a, b) => b.size - a.size); | ||
| while (++i < n) { | ||
@@ -88,3 +87,2 @@ var d = data[i]; | ||
| cloudSprite(contextAndRatio, d, data, i); | ||
| if (d.hasText && place(board, d, bounds)) { | ||
@@ -98,4 +96,4 @@ tags.push(d); | ||
| y: d.y + d.y1 | ||
| }]; // Temporary hack | ||
| }]; | ||
| // Temporary hack | ||
| d.x -= size[0] >> 1; | ||
@@ -105,6 +103,4 @@ d.y -= size[1] >> 1; | ||
| } | ||
| return tags; | ||
| }; | ||
| function getContext(canvas) { | ||
@@ -123,14 +119,12 @@ canvas.width = canvas.height = 1; | ||
| } | ||
| function place(board, tag, bounds) { | ||
| var startX = tag.x, | ||
| startY = tag.y, | ||
| maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]), | ||
| s = spiral(size), | ||
| dt = random() < .5 ? 1 : -1, | ||
| t = -dt, | ||
| dxdy, | ||
| dx, | ||
| dy; | ||
| startY = tag.y, | ||
| maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]), | ||
| s = spiral(size), | ||
| dt = random() < .5 ? 1 : -1, | ||
| t = -dt, | ||
| dxdy, | ||
| dx, | ||
| dy; | ||
| while (dxdy = s(t += dt)) { | ||
@@ -142,26 +136,22 @@ dx = ~~dxdy[0]; | ||
| tag.y = startY + dy; | ||
| if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 || tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue; // TODO only check for collisions within current bounds. | ||
| if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 || tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue; | ||
| // TODO only check for collisions within current bounds. | ||
| if (!bounds || !cloudCollide(tag, board, size[0])) { | ||
| if (!bounds || collideRects(tag, bounds)) { | ||
| var sprite = tag.sprite, | ||
| w = tag.width >> 5, | ||
| sw = size[0] >> 5, | ||
| lx = tag.x - (w << 4), | ||
| sx = lx & 0x7f, | ||
| msx = 32 - sx, | ||
| h = tag.y1 - tag.y0, | ||
| x = (tag.y + tag.y0) * sw + (lx >> 5), | ||
| last; | ||
| w = tag.width >> 5, | ||
| sw = size[0] >> 5, | ||
| lx = tag.x - (w << 4), | ||
| sx = lx & 0x7f, | ||
| msx = 32 - sx, | ||
| h = tag.y1 - tag.y0, | ||
| x = (tag.y + tag.y0) * sw + (lx >> 5), | ||
| last; | ||
| for (var j = 0; j < h; j++) { | ||
| last = 0; | ||
| for (var i = 0; i <= w; i++) { | ||
| board[x + i] |= last << msx | (i < w ? (last = sprite[j * w + i]) >>> sx : 0); | ||
| } | ||
| x += sw; | ||
| } | ||
| tag.sprite = null; | ||
@@ -172,6 +162,4 @@ return true; | ||
| } | ||
| return false; | ||
| } | ||
| cloud.words = function (_) { | ||
@@ -185,3 +173,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.size = function (_) { | ||
@@ -195,3 +182,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.font = function (_) { | ||
@@ -205,3 +191,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.fontStyle = function (_) { | ||
@@ -215,3 +200,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.fontWeight = function (_) { | ||
@@ -225,3 +209,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.rotate = function (_) { | ||
@@ -235,3 +218,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.text = function (_) { | ||
@@ -245,3 +227,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.spiral = function (_) { | ||
@@ -255,3 +236,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.fontSize = function (_) { | ||
@@ -265,3 +245,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.padding = function (_) { | ||
@@ -275,3 +254,2 @@ if (arguments.length) { | ||
| }; | ||
| cloud.random = function (_) { | ||
@@ -285,23 +263,22 @@ if (arguments.length) { | ||
| }; | ||
| return cloud; | ||
| } | ||
| return cloud; | ||
| } // Fetches a monochrome sprite bitmap for the specified text. | ||
| // Fetches a monochrome sprite bitmap for the specified text. | ||
| // Load in batches for speed. | ||
| function cloudSprite(contextAndRatio, d, data, di) { | ||
| if (d.sprite) return; | ||
| var c = contextAndRatio.context, | ||
| ratio = contextAndRatio.ratio; | ||
| ratio = contextAndRatio.ratio; | ||
| c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio); | ||
| var x = 0, | ||
| y = 0, | ||
| maxh = 0, | ||
| n = data.length, | ||
| w, | ||
| w32, | ||
| h, | ||
| i, | ||
| j; | ||
| y = 0, | ||
| maxh = 0, | ||
| n = data.length, | ||
| w, | ||
| w32, | ||
| h, | ||
| i, | ||
| j; | ||
| --di; | ||
| while (++di < n) { | ||
@@ -313,10 +290,9 @@ d = data[di]; | ||
| h = d.size << 1; | ||
| if (d.rotate) { | ||
| var sr = Math.sin(d.rotate * cloudRadians), | ||
| cr = Math.cos(d.rotate * cloudRadians), | ||
| wcr = w * cr, | ||
| wsr = w * sr, | ||
| hcr = h * cr, | ||
| hsr = h * sr; | ||
| cr = Math.cos(d.rotate * cloudRadians), | ||
| wcr = w * cr, | ||
| wsr = w * sr, | ||
| hcr = h * cr, | ||
| hsr = h * sr; | ||
| w = Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f >> 5 << 5; | ||
@@ -327,5 +303,3 @@ h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr)); | ||
| } | ||
| if (h > maxh) maxh = h; | ||
| if (x + w >= cw << 5) { | ||
@@ -336,3 +310,2 @@ x = 0; | ||
| } | ||
| if (y + h >= ch) break; | ||
@@ -342,3 +315,2 @@ c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio); | ||
| c.fillText(d.text, 0, 0); | ||
| if (d.padding) { | ||
@@ -348,3 +320,2 @@ c.lineWidth = 2 * d.padding; | ||
| } | ||
| c.restore(); | ||
@@ -362,6 +333,4 @@ d.width = w; | ||
| } | ||
| var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data, | ||
| sprite = []; | ||
| sprite = []; | ||
| while (--di >= 0) { | ||
@@ -372,6 +341,5 @@ d = data[di]; | ||
| w32 = w >> 5; | ||
| h = d.y1 - d.y0; // Zero the buffer | ||
| h = d.y1 - d.y0; | ||
| // Zero the buffer | ||
| for (i = 0; i < h * w32; i++) sprite[i] = 0; | ||
| x = d.xoff; | ||
@@ -381,12 +349,10 @@ if (x == null) return; | ||
| var seen = 0, | ||
| seenRow = -1; | ||
| seenRow = -1; | ||
| for (j = 0; j < h; j++) { | ||
| for (i = 0; i < w; i++) { | ||
| var k = w32 * j + (i >> 5), | ||
| m = pixels[(y + j) * (cw << 5) + (x + i) << 2] ? 1 << 31 - i % 32 : 0; | ||
| m = pixels[(y + j) * (cw << 5) + (x + i) << 2] ? 1 << 31 - i % 32 : 0; | ||
| sprite[k] |= m; | ||
| seen |= m; | ||
| } | ||
| if (seen) seenRow = j;else { | ||
@@ -399,36 +365,30 @@ d.y0++; | ||
| } | ||
| d.y1 = d.y0 + seenRow; | ||
| d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32); | ||
| } | ||
| } // Use mask-based collision detection. | ||
| } | ||
| // Use mask-based collision detection. | ||
| function cloudCollide(tag, board, sw) { | ||
| sw >>= 5; | ||
| var sprite = tag.sprite, | ||
| w = tag.width >> 5, | ||
| lx = tag.x - (w << 4), | ||
| sx = lx & 0x7f, | ||
| msx = 32 - sx, | ||
| h = tag.y1 - tag.y0, | ||
| x = (tag.y + tag.y0) * sw + (lx >> 5), | ||
| last; | ||
| w = tag.width >> 5, | ||
| lx = tag.x - (w << 4), | ||
| sx = lx & 0x7f, | ||
| msx = 32 - sx, | ||
| h = tag.y1 - tag.y0, | ||
| x = (tag.y + tag.y0) * sw + (lx >> 5), | ||
| last; | ||
| for (var j = 0; j < h; j++) { | ||
| last = 0; | ||
| for (var i = 0; i <= w; i++) { | ||
| if ((last << msx | (i < w ? (last = sprite[j * w + i]) >>> sx : 0)) & board[x + i]) return true; | ||
| } | ||
| x += sw; | ||
| } | ||
| return false; | ||
| } | ||
| function cloudBounds(bounds, d) { | ||
| var b0 = bounds[0], | ||
| b1 = bounds[1]; | ||
| b1 = bounds[1]; | ||
| if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0; | ||
@@ -439,7 +399,5 @@ if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0; | ||
| } | ||
| function collideRects(a, b) { | ||
| return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y; | ||
| } | ||
| function archimedeanSpiral(size) { | ||
@@ -451,11 +409,10 @@ var e = size[0] / size[1]; | ||
| } | ||
| function rectangularSpiral(size) { | ||
| var dy = 4, | ||
| dx = dy * size[0] / size[1], | ||
| x = 0, | ||
| y = 0; | ||
| dx = dy * size[0] / size[1], | ||
| x = 0, | ||
| y = 0; | ||
| return function (t) { | ||
| var sign = t < 0 ? -1 : 1; // See triangular numbers: T_n = n * (n + 1) / 2. | ||
| var sign = t < 0 ? -1 : 1; | ||
| // See triangular numbers: T_n = n * (n + 1) / 2. | ||
| switch (Math.sqrt(1 + 4 * sign * t) - sign & 3) { | ||
@@ -465,11 +422,8 @@ case 0: | ||
| break; | ||
| case 1: | ||
| y += dy; | ||
| break; | ||
| case 2: | ||
| x -= dx; | ||
| break; | ||
| default: | ||
@@ -479,17 +433,13 @@ y -= dy; | ||
| } | ||
| return [x, y]; | ||
| }; | ||
| } // TODO reuse arrays? | ||
| } | ||
| // TODO reuse arrays? | ||
| function zeroArray(n) { | ||
| var a = [], | ||
| i = -1; | ||
| i = -1; | ||
| while (++i < n) a[i] = 0; | ||
| return a; | ||
| } | ||
| function functor(d) { | ||
@@ -500,3 +450,2 @@ return typeof d === 'function' ? d : function () { | ||
| } | ||
| var spirals = { | ||
@@ -576,3 +525,2 @@ archimedean: archimedeanSpiral, | ||
| } | ||
| function modp(param) { | ||
@@ -582,20 +530,17 @@ const p = _[param]; | ||
| } | ||
| const mod = _.modified(); | ||
| if (!(mod || pulse.changed(pulse.ADD_REM) || Params.some(modp))) return; | ||
| const data = pulse.materialize(pulse.SOURCE).source, | ||
| layout = this.value, | ||
| as = _.as || Output; | ||
| layout = this.value, | ||
| as = _.as || Output; | ||
| let fontSize = _.fontSize || 14, | ||
| range; | ||
| isFunction(fontSize) ? range = _.fontSizeRange : fontSize = constant(fontSize); // create font size scaling function as needed | ||
| range; | ||
| isFunction(fontSize) ? range = _.fontSizeRange : fontSize = constant(fontSize); | ||
| // create font size scaling function as needed | ||
| if (range) { | ||
| const fsize = fontSize, | ||
| sizeScale = scale('sqrt')().domain(extent(data, fsize)).range(range); | ||
| sizeScale = scale('sqrt')().domain(extent(data, fsize)).range(range); | ||
| fontSize = x => sizeScale(fsize(x)); | ||
| } | ||
| data.forEach(t => { | ||
@@ -605,10 +550,10 @@ t[as[0]] = NaN; | ||
| t[as[3]] = 0; | ||
| }); // configure layout | ||
| }); | ||
| // configure layout | ||
| const words = layout.words(data).text(_.text).size(_.size || [500, 500]).padding(_.padding || 1).spiral(_.spiral || 'archimedean').rotate(_.rotate || 0).font(_.font || 'sans-serif').fontStyle(_.fontStyle || 'normal').fontWeight(_.fontWeight || 'normal').fontSize(fontSize).random(random).layout(); | ||
| const size = layout.size(), | ||
| dx = size[0] >> 1, | ||
| dy = size[1] >> 1, | ||
| n = words.length; | ||
| dx = size[0] >> 1, | ||
| dy = size[1] >> 1, | ||
| n = words.length; | ||
| for (let i = 0, w, t; i < n; ++i) { | ||
@@ -625,8 +570,6 @@ w = words[i]; | ||
| } | ||
| return pulse.reflow(mod).modifies(as); | ||
| } | ||
| }); | ||
| export { Wordcloud as wordcloud }; |
+1
-1
@@ -1,2 +0,2 @@ | ||
| Copyright (c) 2015-2018, University of Washington Interactive Data Lab | ||
| Copyright (c) 2015-2023, University of Washington Interactive Data Lab | ||
| All rights reserved. | ||
@@ -3,0 +3,0 @@ |
+8
-8
| { | ||
| "name": "vega-wordcloud", | ||
| "version": "4.1.3", | ||
| "version": "4.1.4", | ||
| "description": "Wordcloud layout transform for Vega dataflows.", | ||
@@ -18,3 +18,3 @@ "keywords": [ | ||
| "prebuild": "rimraf build", | ||
| "build": "rollup -c --config-transform", | ||
| "build": "rollup -c rollup.config.mjs --config-transform", | ||
| "pretest": "yarn build --config-test", | ||
@@ -25,7 +25,7 @@ "test": "tape 'test/**/*-test.js'", | ||
| "dependencies": { | ||
| "vega-canvas": "^1.2.5", | ||
| "vega-dataflow": "^5.7.3", | ||
| "vega-scale": "^7.1.1", | ||
| "vega-statistics": "^1.7.9", | ||
| "vega-util": "^1.15.2" | ||
| "vega-canvas": "^1.2.7", | ||
| "vega-dataflow": "^5.7.5", | ||
| "vega-scale": "^7.3.0", | ||
| "vega-statistics": "^1.8.1", | ||
| "vega-util": "^1.17.1" | ||
| }, | ||
@@ -35,3 +35,3 @@ "devDependencies": { | ||
| }, | ||
| "gitHead": "4affcbedb9d14815dbb6d3b250ed231b54fc95c0" | ||
| "gitHead": "fb1092f6b931d450f9c210b67ae4752bd3dd461b" | ||
| } |
| export { default } from '../../rollup.config'; |
79299
1.37%1554
1.17%Updated
Updated
Updated
Updated
Updated