In this example, we created a dynamic graphic that represents the results of an election. By changing the input data, the graphical representation of the election results is automatically updated. We also utilized interactive components to control the display of the election results.
To do this, we determine if the user has adjusted the election data inputs and when the data changes, we retrieve the updated information and render it on the graphic. We also ensure that the data is validated and clamped within acceptable ranges before updating the graphic elements.
letdrag=false;constrealSize=200;functiononPointerDown(e){drag=true;area.setPointerCapture(e.pointerId);}/* Define the IParty interface with optional properties for button, progress, and label elements */interfaceIParty{color:string;letter:string;button?:Button;progress?:Label;label?:Label;}// Initialize an array of parties with specific colors and lettersconstparties:IParty[]=[{color:'#9e0142',letter:'A'},{color:'#d53e4f',letter:'B'},{color:'#f46d43',letter:'C'},{color:'#fdae61',letter:'D'},{color:'#fee08b',letter:'E'},{color:'#e6f598',letter:'F'},{color:'#abdda4',letter:'G'},{color:'#66c2a5',letter:'H'},{color:'#3288bd',letter:'I'},{color:'#5e4fa2',letter:'J'},];// Define a constant for the margin between elementsconstMARGIN=5;// Variable to keep track of initialization stateletinitialized=false;// Function to initialize party elementsfunctioninitialize(){// Return if already initializedif(initialized)return;// Set initialized to trueinitialized=true;/* Loop through each party and create button, progress, and label elements */for(leti=0;i<parties.length;i++){constparty=parties[i];// Clone button template and set propertiesconstbutton=cloneElement(partyTemplate,{left:MARGIN,text:party.letter});button.style.backgroundColor=party.color;party.button=button;// Clone progress template and set propertiesconstprogress=cloneElement(progressTemplate);progress.width=0;progress.style.backgroundColor=party.color;party.progress=progress;// Clone label templateconstlabel=cloneElement(labelTemplate);party.label=label;}}// Function to handle the simulation onClick eventsimulate.onClick=()=>{// Initialize party elements if not already initializedinitialize();// Variables to store total value and individual party valuesletsum=0;constvalues:Record<string,number>={};// Generate random values for each party and calculate total sumfor(constpartyofparties){constvalue=Math.random()*100;sum+=value;values[party.letter]=value;}// Find the maximum value among the partiesconstmax=Math.max(...Object.values(values));// Sort parties based on their values in descending orderconstsorted=_.orderBy(parties,party=>values[party.letter],'desc');// Variable to track the top position for each party elementlettop=MARGIN;// Loop through each sorted party and update their elementsfor(constpartyofsorted){constvalue=values[party.letter];constprogress=value/max;constpercent=100*value/sum;// Update button positionparty.button.top=top;// Update progress bar position and widthparty.progress.top=top+progressTemplate.top-partyTemplate.top;party.progress.left=MARGIN+progressTemplate.left-partyTemplate.left;party.progress.width=progress*progressTemplate.width;// Update label position and textparty.label.top=top+labelTemplate.top-partyTemplate.top;party.label.left=MARGIN+labelTemplate.left-partyTemplate.left;party.label.text=`${percent.toFixed(1)} %`;// Increment top position for the next party elementtop+=party.button.height+MARGIN;}}// Initial ReadfunctionreadData(){updatePosition('x',vtxPosition.value.x);updatePosition('y',vtxPosition.value.y);}readData();