UNPKG

bubble-balls

Version:

This is d3 wrapper which makes the process of creating draggable and divided into groups amazing bubble charts much easier. You can use relative units to scale the bubbles to fit the screen width. Want to rescale the bubbles to fit the container? No probl

1 lines 17.3 kB
!function(t,i){"object"==typeof exports&&"object"==typeof module?module.exports=i(require("d3-scale"),require("d3-selection"),require("d3-array"),require("d3-drag"),require("d3-force")):"function"==typeof define&&define.amd?define(["d3-scale","d3-selection","d3-array","d3-drag","d3-force"],i):"object"==typeof exports?exports.Balls=i(require("d3-scale"),require("d3-selection"),require("d3-array"),require("d3-drag"),require("d3-force")):t.Balls=i(t["d3-scale"],t["d3-selection"],t["d3-array"],t["d3-drag"],t["d3-force"])}(self,((t,i,e,s,n)=>(()=>{"use strict";var a={44:(t,i,e)=>{e.d(i,{Z:()=>o});var s=e(81),n=e.n(s),a=e(645),r=e.n(a)()(n());r.push([t.id,".balls{position:relative;user-select:none;max-width:100%;overflow:hidden}.balls-unit-example{position:absolute;visibility:hidden}.balls svg{position:absolute;top:0}.ball{cursor:grab}.ball:active{cursor:grabbing}.ball-html{pointer-events:none}.ball-title{display:flex;align-items:center;justify-content:center;text-align:center;line-height:100%;height:100%;width:100%}",""]);const o=r},645:t=>{t.exports=function(t){var i=[];return i.toString=function(){return this.map((function(i){var e="",s=void 0!==i[5];return i[4]&&(e+="@supports (".concat(i[4],") {")),i[2]&&(e+="@media ".concat(i[2]," {")),s&&(e+="@layer".concat(i[5].length>0?" ".concat(i[5]):""," {")),e+=t(i),s&&(e+="}"),i[2]&&(e+="}"),i[4]&&(e+="}"),e})).join("")},i.i=function(t,e,s,n,a){"string"==typeof t&&(t=[[null,t,void 0]]);var r={};if(s)for(var o=0;o<this.length;o++){var l=this[o][0];null!=l&&(r[l]=!0)}for(var h=0;h<t.length;h++){var d=[].concat(t[h]);s&&r[d[0]]||(void 0!==a&&(void 0===d[5]||(d[1]="@layer".concat(d[5].length>0?" ".concat(d[5]):""," {").concat(d[1],"}")),d[5]=a),e&&(d[2]?(d[1]="@media ".concat(d[2]," {").concat(d[1],"}"),d[2]=e):d[2]=e),n&&(d[4]?(d[1]="@supports (".concat(d[4],") {").concat(d[1],"}"),d[4]=n):d[4]="".concat(n)),i.push(d))}},i}},81:t=>{t.exports=function(t){return t[1]}},379:t=>{var i=[];function e(t){for(var e=-1,s=0;s<i.length;s++)if(i[s].identifier===t){e=s;break}return e}function s(t,s){for(var a={},r=[],o=0;o<t.length;o++){var l=t[o],h=s.base?l[0]+s.base:l[0],d=a[h]||0,u="".concat(h," ").concat(d);a[h]=d+1;var m=e(u),c={css:l[1],media:l[2],sourceMap:l[3],supports:l[4],layer:l[5]};if(-1!==m)i[m].references++,i[m].updater(c);else{var p=n(c,s);s.byIndex=o,i.splice(o,0,{identifier:u,updater:p,references:1})}r.push(u)}return r}function n(t,i){var e=i.domAPI(i);return e.update(t),function(i){if(i){if(i.css===t.css&&i.media===t.media&&i.sourceMap===t.sourceMap&&i.supports===t.supports&&i.layer===t.layer)return;e.update(t=i)}else e.remove()}}t.exports=function(t,n){var a=s(t=t||[],n=n||{});return function(t){t=t||[];for(var r=0;r<a.length;r++){var o=e(a[r]);i[o].references--}for(var l=s(t,n),h=0;h<a.length;h++){var d=e(a[h]);0===i[d].references&&(i[d].updater(),i.splice(d,1))}a=l}}},569:t=>{var i={};t.exports=function(t,e){var s=function(t){if(void 0===i[t]){var e=document.querySelector(t);if(window.HTMLIFrameElement&&e instanceof window.HTMLIFrameElement)try{e=e.contentDocument.head}catch(t){e=null}i[t]=e}return i[t]}(t);if(!s)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");s.appendChild(e)}},216:t=>{t.exports=function(t){var i=document.createElement("style");return t.setAttributes(i,t.attributes),t.insert(i,t.options),i}},565:(t,i,e)=>{t.exports=function(t){var i=e.nc;i&&t.setAttribute("nonce",i)}},795:t=>{t.exports=function(t){var i=t.insertStyleElement(t);return{update:function(e){!function(t,i,e){var s="";e.supports&&(s+="@supports (".concat(e.supports,") {")),e.media&&(s+="@media ".concat(e.media," {"));var n=void 0!==e.layer;n&&(s+="@layer".concat(e.layer.length>0?" ".concat(e.layer):""," {")),s+=e.css,n&&(s+="}"),e.media&&(s+="}"),e.supports&&(s+="}");var a=e.sourceMap;a&&"undefined"!=typeof btoa&&(s+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),i.styleTagTransform(s,t,i.options)}(i,t,e)},remove:function(){!function(t){if(null===t.parentNode)return!1;t.parentNode.removeChild(t)}(i)}}}},589:t=>{t.exports=function(t,i){if(i.styleSheet)i.styleSheet.cssText=t;else{for(;i.firstChild;)i.removeChild(i.firstChild);i.appendChild(document.createTextNode(t))}}},448:t=>{t.exports=e},982:t=>{t.exports=s},187:t=>{t.exports=n},629:i=>{i.exports=t},512:t=>{t.exports=i}},r={};function o(t){var i=r[t];if(void 0!==i)return i.exports;var e=r[t]={id:t,exports:{}};return a[t](e,e.exports,o),e.exports}o.n=t=>{var i=t&&t.__esModule?()=>t.default:()=>t;return o.d(i,{a:i}),i},o.d=(t,i)=>{for(var e in i)o.o(i,e)&&!o.o(t,e)&&Object.defineProperty(t,e,{enumerable:!0,get:i[e]})},o.o=(t,i)=>Object.prototype.hasOwnProperty.call(t,i),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.nc=void 0;var l={};return(()=>{o.r(l),o.d(l,{default:()=>D});var t=o(629),i=o(512),e=o(448),s=o(982),n=o(187),a=o(379),r=o.n(a),h=o(795),d=o.n(h),u=o(569),m=o.n(u),c=o(565),p=o.n(c),f=o(216),g=o.n(f),y=o(589),v=o.n(y),b=o(44),x={};x.styleTagTransform=v(),x.setAttributes=p(),x.insert=m().bind(null,"head"),x.domAPI=d(),x.insertStyleElement=g(),r()(b.Z,x),b.Z&&b.Z.locals&&b.Z.locals;let S=1;const D=class{constructor(t,i,e){this.container="string"==typeof t?document.querySelector(t):t,this.options=e,this.appIndex=S,S++,this.data=i,this.formattedData=null,this.measurementUnit={name:this.options?.measurementUnit?.name||"px",initialRadiusData:{desktop:[],mobile:[]}},this.randomizeData=this.options?.randomizeData||!1,this.debounceDelay=this.options?.debounceDelay||100,this.scaleRadius=null,this.simulation=null,this.balls=null,this.svg=null,this.elements=null,this.title=null,this.htmlContainer=null,this.titlePropertyName=this.options?.titlePropertyName||"title",this.breakpoint=this.options?.breakpoint||667,this.defs=null,this.imgPropertyName=this.options?.imgPropertyName||"img",this.draggable=!1!==this.options?.draggable,this.groupsStyles=this.options?.groupsStyles||null,this.defaultStyles={color:void 0===this.options?.defaultStyles?.color?"#000000":e?.defaultStyles?.color,background:void 0===this.options?.defaultStyles?.background?"#FFFFFF":e?.defaultStyles?.background,borderColor:void 0===this.options?.defaultStyles?.borderColor?"#000000":e?.defaultStyles?.borderColor,borderWidth:void 0===this.options?.defaultStyles?.borderWidth?2:e?.defaultStyles?.borderWidth},this.dynamicFontSize={init:this.options?.dynamicFontSize?.init||!0,min:this.options?.dynamicFontSize?.min||"px"===this.measurementUnit.name?10:1},this.groupParam={name:this.options?.groupParam?.name||null,list:[]},this.radiusParam={name:this.options?.radiusParam?.name||null,min:this.options?.radiusParam?.min||"px"===this.measurementUnit.name?40:4,max:this.options?.radiusParam?.max||"px"===this.measurementUnit.name?100:7,extent:null},this.forces={y:this.options?.forces?.y||.05,x:this.options?.forces?.x||.05,collisionMultiplier:this.options?.forces?.collisionMultiplier||1.3,charge:this.options?.forces?.charge||200},this.dimensions={width:null,height:null,containerArea:null,ballsArea:null,relocationStepX:null,initialBallsArea:null,optimizeRelativeScaleDown:!1,padding:this.options?.dimensions?.padding||"px"===this.measurementUnit.name?10:1,defaultRadius:this.options?.dimensions?.defaultRadius||"px"===this.measurementUnit.name?60:6,cols:this.options?.dimensions?.cols||1,xCenter:this.options?.dimensions?.xCenter||[],yCenter:this.options?.dimensions?.yCenter||[]},this.on={mouseover:this.options?.on?.mouseover||null,mouseout:this.options?.on?.mouseout||null,afterInit:this.options?.on?.afterInit?.bind(this)||null},this.currentDevice=this.detectDevice(),this.start()}detectDevice=()=>window.innerWidth<this.breakpoint?"mobile":"desktop";debounce=(t,i,e)=>{let s=!1;return function(){s||(s=!0,setTimeout((()=>{t.apply(e),s=!1}),i))}};getOneUnit=()=>this.container.querySelector(".balls-unit-example").offsetWidth;calcDimensions=()=>{const t=this.container.getBoundingClientRect();this.dimensions.width=t.width,this.dimensions.height=t.height,this.dimensions.containerArea=Math.round(t.width*t.height),this.dimensions.relocationStepX=t.width/this.dimensions.cols};calcDimensionsY=()=>{this.dimensions.rows=Math.round(this.dimensions.amoutOfGroups/this.dimensions.cols),this.dimensions.relocationStepY=this.dimensions.height/this.dimensions.rows};scaleUpOnResize=(t,i)=>{t&&this.dimensions.ballsArea<this.dimensions.containerArea&&this.dimensions.initialBallsArea>this.dimensions.ballsArea&&(i.forEach((t=>t.radius+=.05*t.radius)),this.optimizeSize(i))};recalculateRadius=(t,i,e)=>{t.radius=i*e};optimizeStatic=(t,i)=>{this.dimensions.ballsArea>this.dimensions.containerArea?(t.forEach((t=>{t.radius-=.05*t.radius})),this.optimizeSize(t)):this.dimensions.initialBallsArea?this.scaleUpOnResize(i,t):this.dimensions.initialBallsArea=this.dimensions.ballsArea};onDeviceChange=(t,i,e)=>{0===this.measurementUnit.initialRadiusData[e].length&&t.forEach((t=>this.measurementUnit.initialRadiusData[e].push((t.radius/10).toFixed(1)))),this.measurementUnit.optimizedRadiusData=[...this.measurementUnit.initialRadiusData[e]],t.forEach(((t,e)=>{t.radius=this.measurementUnit.optimizedRadiusData[e]*i}))};optimizeRelative=(t,i)=>{this.dimensions.ballsArea>this.dimensions.containerArea?(this.optimizeRelativeScaleDown=!0,t.forEach(((t,i)=>{t.radius-=.05*t.radius,this.measurementUnit.optimizedRadiusData[i]=(t.radius/10).toFixed(1)})),this.optimizeSize(t)):this.optimizeRelativeScaleDown?this.optimizeRelativeScaleDown=!1:t.forEach(((t,e)=>{this.recalculateRadius(t,this.measurementUnit.optimizedRadiusData[e],i)}))};optimizeSize=t=>{let i=null,e=!1;if("px"!==this.measurementUnit.name){i=this.getOneUnit();const s=this.detectDevice();this.currentDevice!==s&&(this.currentDevice=s,this.onDeviceChange(t,i,s),e=!0)}this.dimensions.ballsArea=Math.round(t.reduce(((t,i)=>t+3.14*i.radius**2*(2*this.forces.collisionMultiplier)),0));const s=this.dimensions.lastWidth<this.dimensions.width;this.dimensions.lastWidth=this.dimensions.width,"px"===this.measurementUnit.name?this.optimizeStatic(t,s):!1===e&&this.optimizeRelative(t,i)};getAmountOfGroups=t=>{const i=t.map((t=>t.group)),e=new Set(i);this.dimensions.amoutOfGroups=e.size};shuffleData=t=>{const i=[...t];let e,s=i.length;for(;0!==s;)e=Math.floor(Math.random()*s),s--,[i[s],i[e]]=[i[e],i[s]];return i};getFormattedData=(i,s)=>{let n=null;"px"!==this.measurementUnit.name&&(n=this.getOneUnit()),this.options?.radiusParam?.name&&(this.radiusParam.extent=(0,e.extent)(i,(t=>t[this.options?.radiusParam?.name])),this.scaleRadius="px"!==this.measurementUnit.name?(0,t.scaleLinear)().domain(this.radiusParam.extent).range([this.radiusParam.min*n,this.radiusParam.max*n]):(0,t.scaleLinear)().domain(this.radiusParam.extent).range([this.radiusParam.min,this.radiusParam.max])),this.formattedData=(this.randomizeData?this.shuffleData(i):i).map((t=>{if(t.radius||(this.radiusParam.name?t.radius=this.scaleRadius(t[this.radiusParam.name]):t.radius=this.dimensions.defaultRadius),"px"!==this.measurementUnit.name&&(this.radiusParam.name?this.measurementUnit.initialRadiusData[s].push((t.radius/10).toFixed(1)):(this.measurementUnit.initialRadiusData[s].push(t.radius),t.radius*=n)),!t.group)if(this.groupParam.name){const i=this.groupParam.list.find((i=>i.name===t[this.groupParam.name]));if(i)t.group=i.index;else{const i={name:t[this.groupParam.name],index:this.groupParam.list.length+1};t.group=i.index,this.groupParam.list.push(i)}}else t.group=1;if(this.groupsStyles){const i=this.groupsStyles.find((i=>i.groupName===t[this.groupParam.name]))||this.groupsStyles[t.group-1];t.background=i?.background,t.color=i?.color,t.borderWidth=i?.borderWidth,t.borderColor=i?.borderColor}return t})),this.measurementUnit.optimizedRadiusData=[...this.measurementUnit.initialRadiusData[s]]};prepareData=()=>{const t=this.detectDevice();this.getFormattedData(this.data,t),this.getAmountOfGroups(this.formattedData),this.calcDimensionsY(),this.setPositionXY(),this.optimizeSize(this.formattedData)};getPositionX=()=>{this.dimensions.xCenter=[];let t=0,i=1;do{i>this.dimensions.cols&&(i=1),i<=this.dimensions.cols&&(1===this.dimensions.cols?this.dimensions.xCenter.push(this.dimensions.relocationStepX/2):this.dimensions.xCenter.push(this.dimensions.relocationStepX*i*.75)),i++,t++}while(t<this.dimensions.amoutOfGroups)};getPositionY=()=>{this.dimensions.yCenter=[];let t=0,i=1,e=1;do{i>this.dimensions.cols&&(i=1,e++),e<=this.dimensions.rows&&(1===this.dimensions.rows?this.dimensions.yCenter.push(this.dimensions.relocationStepY/2):this.dimensions.yCenter.push(this.dimensions.relocationStepY*e)),i++,t++}while(t<this.dimensions.amoutOfGroups)};tickBalls=()=>{const t="px"===this.measurementUnit.name?this.dimensions.padding:this.dimensions.padding*this.getOneUnit();this.balls.attr("r",(t=>t.radius)).attr("cx",(i=>{const e=i.radius+t;return i.x+e>this.dimensions.width?(i.x=this.dimensions.width-e,i.x):i.x<e?(i.x=0+e,i.x):i.x})).attr("cy",(i=>{const e=i.radius+t;return i.y+e>this.dimensions.height?(i.y=this.dimensions.height-e,i.y):i.y<e?(i.y=0+e,i.y):i.y})),this.images.attr("height",(t=>2*t.radius)).attr("width",(t=>2*t.radius)),this.htmlContainer.attr("x",(t=>t.x)).attr("y",(t=>t.y)),this.title.style("font-size",(t=>{const i=t[this.titlePropertyName];if(t[this.titlePropertyName]&&this.dynamicFontSize.init)return this.setDynamicFontSize(i,t.radius,this.dynamicFontSize.min)}))};setDynamicFontSize=(t,i,e)=>{const s=t.length;let n=i/4;if(s>n){n*=8/s;const t=this.measurementUnit.name?Math.round(n)/10:Math.round(n);return(t<e?e:t)+this.measurementUnit.name}};setSimulation=()=>{this.simulation=(0,n.forceSimulation)(this.formattedData).force("charge",(0,n.forceManyBody)().strength(this.forces.charge)).force("x",(0,n.forceX)().x((t=>this.dimensions.xCenter[t.group-1])).strength(this.forces.x)).force("y",(0,n.forceY)().y((t=>this.dimensions.yCenter[t.group-1])).strength(this.forces.y)).force("collision",(0,n.forceCollide)().radius((t=>t.radius*this.forces.collisionMultiplier))).on("tick",this.tickBalls)};setPositionXY=()=>{this.getPositionX(),this.getPositionY()};mouseover=t=>{this.on.mouseover.call((0,i.select)(t))};mouseout=t=>{this.on.mouseout.call((0,i.select)(t))};dragStart=(t,e)=>{const s=(0,i.select)(`ball-container-${this.appIndex}-${e.id}`).classed("dragging",!0);this.simulation.alphaTarget(.03).restart(),t.on("drag",((t,i)=>{s.raise().attr("cx",i.x=t.x).attr("cy",i.y=t.y)})).on("end",(()=>{s.classed("dragging",!1),this.simulation.alphaTarget(.03)}))};initBalls=()=>{this.setSimulation(),this.svg=(0,i.select)(this.container).append("svg").attr("height",this.dimensions.height).attr("width",this.dimensions.width),this.elements=this.svg.selectAll(".ball").data(this.formattedData).enter().append("g").attr("class",(t=>`ball-container-${this.appIndex}-${t.id}`)),this.draggable&&this.elements.call((0,s.drag)().on("start",this.dragStart,!0)),this.balls=this.elements.append("circle").classed("ball",!0).attr("r",(t=>t.radius)).attr("stroke",(t=>t.borderColor||this.defaultStyles.borderColor)).attr("stroke-width",(t=>t.borderWidth||this.defaultStyles.borderWidth)).attr("fill",(t=>t[this.imgPropertyName]?`url(#img-${this.appIndex}-${t.id})`:t.background||this.defaultStyles.background)).on("mouseover",(t=>{this.on.mouseover&&this.mouseover(t.target)})).on("mouseout",(t=>{this.on.mouseout&&this.mouseout(t.target)})),this.htmlContainer=this.elements.append("foreignObject").classed("ball-html",!0).attr("width",(t=>1.6*t.radius)).attr("overflow","visible").attr("height",(t=>2*t.radius)).attr("transform",(t=>`translate(-${.8*t.radius}, -${t.radius})`)),this.title=this.htmlContainer.append("xhtml:div").classed("ball-title",!0).html((t=>t[this.titlePropertyName])).style("color",(t=>t.color||this.defaultStyles.color)).style("font-size",(t=>{const i=t[this.titlePropertyName];if(t[this.titlePropertyName]&&this.dynamicFontSize.init)return this.setDynamicFontSize(i,t.radius,this.dynamicFontSize.min)})),this.defs=this.svg.append("defs"),this.patterns=this.defs.selectAll("pattern").data(this.formattedData.filter((t=>t[this.imgPropertyName]))).enter().append("pattern").attr("id",(t=>`img-${this.appIndex}-${t.id}`)).attr("width",1).attr("height",1).attr("patternUnits","objectBoundingBox").attr("preserveAspectRatio","xMidYMid slice"),this.images=this.patterns.append("image").attr("height",(t=>2*t.radius)).attr("width",(t=>2*t.radius)).style("transition","height 0.3s, width 0.3s").style("clip-path","circle(50%)").attr("preserveAspectRatio","xMidYMid slice").attr("xlink:href",(t=>{if(t[this.imgPropertyName])return t[this.imgPropertyName]}))};resizeBalls=()=>{this.calcDimensions(),this.setPositionXY(),this.optimizeSize(this.formattedData),this.svg.attr("height",this.dimensions.height),this.svg.attr("width",this.dimensions.width),this.simulation.restart(),this.setSimulation()};beforeInit=()=>{this.calcDimensions(),this.prepareData(this.data)};init=()=>{this.initBalls()};afterInit=()=>{window.addEventListener("resize",this.debounce(this.resizeBalls,this.debounceDelay)),this.on.afterInit&&this.on.afterInit()};start=()=>{this.beforeInit(),this.init(),this.afterInit()}}})(),l})()));