react-wordcloud
Version:
Simple React + D3 wordcloud component with powerful features.
3 lines (2 loc) • 9.5 kB
JavaScript
import t from"lodash.debounce";import e,{useRef as n,useState as o,useEffect as r}from"react";import{select as i,event as a}from"d3-selection";import s from"resize-observer-polyfill";import"d3-transition";import{range as l,min as c,max as f,descending as u}from"d3-array";import h from"d3-cloud";import d from"lodash.clonedeep";import m from"seedrandom";import y from"tippy.js";import{dispatch as p}from"d3-dispatch";import{scaleOrdinal as x,scaleLinear as g,scaleSqrt as b,scaleLog as v}from"d3-scale";import{schemeCategory10 as w}from"d3-scale-chromatic";const M=Math.PI/180;function z(t){return t.text}function k(){return"serif"}function W(){return"normal"}function S(t){return Math.sqrt(t.value)}function T(){return 30*(~~(6*Math.random())-3)}function O(){return 1}function $(t,e,n,o){if(e.sprite)return;const r=t.context,i=t.ratio;r.clearRect(0,0,2048/i,2048/i);let a=0,s=0,l=0,c=n.length;for(--o;++o<c;){e=n[o],r.save(),r.font=e.style+" "+e.weight+" "+~~((e.size+1)/i)+"px "+e.font;var f=r.measureText(e.text+"m").width*i,u=e.size<<1;if(e.rotate){const t=Math.sin(e.rotate*M),n=Math.cos(e.rotate*M),o=f*n,r=f*t,i=u*n,a=u*t;f=Math.max(Math.abs(o+a),Math.abs(o-a))+31>>5<<5,u=~~Math.max(Math.abs(r+i),Math.abs(r-i))}else f=f+31>>5<<5;if(u>l&&(l=u),a+f>=2048&&(a=0,s+=l,l=0),s+u>=2048)break;r.translate((a+(f>>1))/i,(s+(u>>1))/i),e.rotate&&r.rotate(e.rotate*M),r.fillText(e.text,0,0),e.padding&&(r.lineWidth=2*e.padding,r.strokeText(e.text,0,0)),r.restore(),e.width=f,e.height=u,e.xoff=a,e.yoff=s,e.x1=f>>1,e.y1=u>>1,e.x0=-e.x1,e.y0=-e.y1,e.hasText=!0,a+=f}const h=r.getImageData(0,0,2048/i,2048/i).data,d=[];for(;--o>=0;){if(!(e=n[o]).hasText)continue;for(var m=(f=e.width)>>5,y=(u=e.y1-e.y0,0);y<u*m;y++)d[y]=0;if(a=e.xoff,null==a)return;s=e.yoff;let t=0,r=-1;for(let n=0;n<u;n++){for(y=0;y<f;y++){const e=h[2048*(s+n)+(a+y)<<2]?1<<31-y%32:0;d[m*n+(y>>5)]|=e,t|=e}t?r=n:(e.y0++,u--,n--,s++)}e.y1=e.y0+r,e.sprite=d.slice(0,(e.y1-e.y0)*m)}}function A(t,e,n){let o,r=t.sprite,i=t.width>>5,a=t.x-(i<<4),s=127&a,l=32-s,c=t.y1-t.y0,f=(t.y+t.y0)*(n>>=5)+(a>>5);for(let t=0;t<c;t++){o=0;for(let n=0;n<=i;n++)if((o<<l|(n<i?(o=r[t*i+n])>>>s:0))&e[f+n])return!0;f+=n}return!1}function j(t,e){const n=t[0],o=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>o.x&&(o.x=e.x+e.x1),e.y+e.y1>o.y&&(o.y=e.y+e.y1)}function I(t){const e=t[0]/t[1];return function(t){return[e*(t*=.1)*Math.cos(t),t*Math.sin(t)]}}function q(){return document.createElement("canvas")}function E(t){return"function"==typeof t?t:function(){return t}}var C={archimedean:I,rectangular:function(t){let e=4*t[0]/t[1],n=0,o=0;return function(t){const r=t<0?-1:1;switch(Math.sqrt(1+4*r*t)-r&3){case 0:n+=e;break;case 1:o+=4;break;case 2:n-=e;break;default:o-=4}return[n,o]}}};function D(t,e){return t[Math.floor(e()*t.length)]}function F(t){return t.size+"px"}function L(t){return t.text}function N(t){return`translate(${t.x}, ${t.y})`+("number"==typeof t.rotate?`rotate(${t.rotate})`:"")}function P({callbacks:t,maxWords:e,options:n,selection:o,size:r,words:i}){const{deterministic:s,enableOptimizations:l,fontFamily:x,fontStyle:w,fontSizes:M,fontWeight:P,padding:R,randomSeed:U,rotations:H,rotationAngles:B,spiral:G,scale:J}=n,K=i.concat().sort((t,e)=>u(t.value,e.value)).slice(0,e),Q=m(s?U||"deterministic":null);let V;V=l?function(){let t=[256,256],e=z,n=k,o=S,r=W,i=W,a=T,s=O,l=I,c=[],f=Infinity,u=p("word","end"),h=Math.random,d={},m=q,y=!1;function x(e,n,o){let r,i,a,s=n.x,c=n.y,f=Math.sqrt(t[0]*t[0]+t[1]*t[1]),u=l(t),d=h()<.5?1:-1,m=-d;for(;(r=u(m+=d))&&(i=~~r[0],a=~~r[1],!(Math.min(Math.abs(i),Math.abs(a))>=f));)if(n.x=s+i,n.y=c+a,!(n.x+n.x0<0||n.y+n.y0<0||n.x+n.x1>t[0]||n.y+n.y1>t[1]||o&&A(n,e,t[0])||o&&!((k=n).x+k.x1>(W=o)[0].x&&k.x+k.x0<W[1].x&&k.y+k.y1>W[0].y&&k.y+k.y0<W[1].y))){var y,p=n.sprite,x=n.width>>5,g=t[0]>>5,b=n.x-(x<<4),v=127&b,w=32-v,M=n.y1-n.y0,z=(n.y+n.y0)*g+(b>>5);for(let t=0;t<M;t++){y=0;for(let n=0;n<=x;n++)e[z+n]|=y<<w|(n<x?(y=p[t*x+n])>>>v:0);z+=g}return delete n.sprite,!0}var k,W;return!1}return d.canvas=function(t){return arguments.length?(m=E(t),d):m},d.start=function(){let l=function(t){t.width=t.height=1;const e=Math.sqrt(t.getContext("2d").getImageData(0,0,1,1).data.length>>2);t.width=2048/e,t.height=2048/e;const n=t.getContext("2d");return n.fillStyle=n.strokeStyle="red",n.textAlign="center",{context:n,ratio:e}}(m()),f=new Uint32Array((t[0]>>5)*t[1]),p=null,g=[],b=c.map(function(t,l){return t.text=e.call(this,t,l),t.font=n.call(this,t,l),t.style=r.call(this,t,l),t.weight=i.call(this,t,l),t.rotate=a.call(this,t,l),t.size=~~o.call(this,t,l),t.padding=s.call(this,t,l),t}).sort(function(t,e){return e.size-t.size});return setTimeout(()=>function e(n){const o=50*n,r=Math.min(50*(n+1),c.length);!function(e,n){for(let o=e;o<n;o+=1){const e=b[o];e.x=t[0]*(h()+.5)>>1,e.y=t[1]*(h()+.5)>>1,$(l,e,b,o),e.hasText&&x(f,e,p)&&(g.push(e),u.call("word",d,e),p?j(p,e):p=[{x:e.x+e.x0,y:e.y+e.y0},{x:e.x+e.x1,y:e.y+e.y1}],e.x-=t[0]>>1,e.y-=t[1]>>1)}}(o,r),y||(r<c.length?setTimeout(()=>e(n+1),0):(d.stop(),u.call("end",d,g,p)))}(0),0),d},d.revive=()=>(y=!1,d),d.stop=function(){return y=!0,d},d.timeInterval=function(t){return arguments.length?(f=null==t?Infinity:t,d):f},d.words=function(t){return arguments.length?(c=t,d):c},d.size=function(e){return arguments.length?(t=[+e[0],+e[1]],d):t},d.font=function(t){return arguments.length?(n=E(t),d):n},d.fontStyle=function(t){return arguments.length?(r=E(t),d):r},d.fontWeight=function(t){return arguments.length?(i=E(t),d):i},d.rotate=function(t){return arguments.length?(a=E(t),d):a},d.text=function(t){return arguments.length?(e=E(t),d):e},d.spiral=function(t){return arguments.length?(l=C[t]||t,d):l},d.fontSize=function(t){return arguments.length?(o=E(t),d):o},d.padding=function(t){return arguments.length?(s=E(t),d):s},d.random=function(t){return arguments.length?(h=t,d):h},d.on=function(){const t=u.on.apply(u,arguments);return t===u?d:t},d}():h(),V.size(r).padding(R).words(d(K)).rotate(()=>void 0===H?30*(~~(6*Q())-3):function(t,e,n){if(t<1)return 0;let o=[];if(1===t)o=[e[0]];else{o=[...e];const n=(e[1]-e[0])/(t-1);let r=e[0]+n;for(;r<e[1];)o.push(r),r+=n}return D(o,n)}(H,B,Q)).spiral(G).random(Q).text(L).font(x).fontStyle(w).fontWeight(P),function e(r,i=1){l&&V.revive(),V.fontSize(t=>function(t,e,n){const o=c(t,t=>Number(t.value)),r=f(t,t=>Number(t.value));let i;switch(n){case"log":i=v;break;case"sqrt":i=b;break;case"linear":default:i=g}return i().domain([o,r]).range(e)}(K,r,J)(t.value)).on("end",s=>{if(K.length!==s.length&&i<=10){10===i&&console.warn(`Unable to layout ${K.length-s.length} word(s) after ${i} attempts. Consider: (1) Increasing the container/component size. (2) Lowering the max font size. (3) Limiting the rotation angles.`);const t=Math.max(.95*r[0],1);e([t,Math.max(.95*r[1],t)],i+1)}else!function({callbacks:t,options:e,random:n,selection:o,words:r}){const{getWordColor:i,getWordTooltip:s,onWordClick:l,onWordMouseOver:c,onWordMouseOut:f}=t,{colors:u,enableTooltip:h,fontStyle:d,fontWeight:m,textAttributes:p,tooltipOptions:x}=e,{fontFamily:g,transitionDuration:b}=e;function v(t){return i?i(t):D(u,n)}let w;o.selectAll("text").data(r).join(t=>{let e=t.append("text").on("click",t=>{l&&l(t,a)}).on("mouseover",t=>{h&&(w=y(a.target,{animation:"scale",arrow:!0,content:()=>s(t),...x})),c&&c(t,a)}).on("mouseout",t=>{w&&w.destroy(),f&&f(t,a)}).attr("cursor",l?"pointer":"default").attr("fill",v).attr("font-family",g).attr("font-style",d).attr("font-weight",m).attr("text-anchor","middle").attr("transform","translate(0, 0) rotate(0)");"object"==typeof p&&Object.keys(p).forEach(t=>{e=e.attr(t,p[t])}),e=e.call(t=>t.transition().duration(b).attr("font-size",F).attr("transform",N).text(L))},t=>{t.transition().duration(b).attr("fill",v).attr("font-family",g).attr("font-size",F).attr("transform",N).text(L)},t=>{t.transition().duration(b).attr("fill-opacity",0).remove()})}({callbacks:t,options:n,random:Q,selection:o,words:s})}).start()}(M)}const R={getWordTooltip:({text:t,value:e})=>`${t} (${e})`},U={colors:l(20).map(t=>t.toString()).map(x(w)),deterministic:!1,enableOptimizations:!1,enableTooltip:!0,fontFamily:"times new roman",fontSizes:[4,32],fontStyle:"normal",fontWeight:"normal",padding:1,rotationAngles:[-90,90],scale:"sqrt",spiral:"rectangular",tooltipOptions:{},transitionDuration:600};function H({callbacks:a,maxWords:l=100,minSize:c,options:f,size:u,words:h,...d}){const m={...R,...a},y={...U,...f},[p,x,g]=function(t,e,a){const l=n(),[c,f]=o(e),[u,h]=o(null);return r(()=>{const n=l.current;let o=i(n).append("svg").style("display","block");"object"==typeof a&&Object.keys(a).forEach(t=>{o=o.attr(t,a[t])});const r=o.append("g");function c(t,e){o.attr("height",e).attr("width",t),r.attr("transform",`translate(${t/2}, ${e/2})`),f([t,e])}h(r);let u=0,d=0;void 0===e?(u=n.parentElement.offsetWidth,d=n.parentElement.offsetHeight):[u,d]=e,u=Math.max(u,t[0]),d=Math.max(d,t[1]),c(u,d);const m=new s(t=>{if(t&&0!==t.length&&void 0===e){const{width:e,height:n}=t[0].contentRect;c(e,n)}});return m.observe(n),()=>{m.unobserve(n),i(n).selectAll("*").remove()}},[e,t,a]),[l,u,c]}(c,u,f.svgAttributes),b=n(t(P,100));return r(()=>{x&&b.current({callbacks:m,maxWords:l,options:y,selection:x,size:g,words:h})},[l,m,y,x,g,h]),e.createElement("div",Object.assign({ref:p,style:{height:"100%",width:"100%"}},d))}H.defaultProps={callbacks:R,maxWords:100,minSize:[300,300],options:U};export default H;export{R as defaultCallbacks,U as defaultOptions};
//# sourceMappingURL=index.modern.js.map