About

The parkrun p-index is an unofficial statistic that measures the number of different parkrun events a person has completed a specific number of times. To achieve a p-index of 10, you must have completed at least 10 different parkrun events 10 times each. This script calculates the p-index for a parkrunner and displays it on their results page.

Version 1.1.20 Updated

Screenshot

parkrun p-index display Screenshot

Install

Recommended: userscript. Bookmarklet works where a userscript manager isn’t available.

Userscript (recommended)

Install parkrun p-index display

First time? Userscript basics and installation steps

What is a userscript?

A userscript is a small piece of JavaScript that runs in your browser and enhances specific websites. These scripts work with parkrun event pages, parkrunner profile pages, and results pages, and can be used with any userscript manager including Userscripts, Tampermonkey, Violentmonkey, or any compatible browser extension.

Installation steps

  1. Install a userscript manager for your browser:
  2. Click the Install button above for this script.
  3. Click “Install” when prompted by your userscript manager.

Bookmarklet

A bookmarklet is a bookmark whose URL is JavaScript. Use it on browsers that support bookmarks but not userscript managers.

Drag this link to your bookmarks bar:

parkrun p-index display bookmarklet

Mobile bookmarklet setup and full code

Mobile bookmarklet

On mobile browsers that let you edit bookmark URLs:

  1. Copy the JavaScript code below to your clipboard.
  2. Create a new bookmark for any page.
  3. Edit the bookmark and replace its URL with the code you copied.
  4. Navigate to the relevant parkrun page.
  5. Select the bookmark to run the script.
javascript:(()=>{var n=Object.getOwnPropertyNames,e=(e,t)=>function(){try{return t||(0,e[n(e)[0]])((t={exports:{}}).exports,t),t.exports}catch(e){throw t=0,e}},u=e({"lib/p-index-core.js"(e,t){function p(e){e=e.reduce((e,{eventName:t,date:n,eventNumber:i})=>(e[t]||(e[t]=[]),e[t].push({date:n,eventNumber:i}),e),{});return Object.entries(e).sort((e,t)=>t[1].length-e[1].length)}function m(e){return e.filter(([,e],t)=>e.length>t).length}function x(e){let i=new Map;return e.forEach((e,t)=>{var n=i.get(e.eventName)||{count:0,lastVisitIndex:-1};i.set(e.eventName,{count:n.count+1,lastVisitIndex:t})}),Array.from(i.entries()).map(([e,t])=>({eventName:e,count:t.count,lastVisitIndex:t.lastVisitIndex}))}function h(e,n){var t=e.map(e=>({eventName:e.eventName,count:e.count,lastVisitIndex:"number"==typeof e.lastVisitIndex?e.lastVisitIndex:Number.NEGATIVE_INFINITY,score:Math.min(e.count,n)})).sort((e,t)=>t.score!==e.score?t.score-e.score:t.count!==e.count?t.count-e.count:t.lastVisitIndex!==e.lastVisitIndex?t.lastVisitIndex-e.lastVisitIndex:e.eventName.localeCompare(t.eventName)).slice(0,n);let i=[],a=0;var o=new Set(e.map(e=>e.eventName)),s=(t.filter(e=>e.count<n).sort((e,t)=>e.lastVisitIndex!==t.lastVisitIndex?e.lastVisitIndex-t.lastVisitIndex:e.eventName.localeCompare(t.eventName)).forEach(e=>{var t=Math.max(0,n-e.count);i.push({eventName:e.eventName,additionalFinishes:t,isNewEvent:!1}),a+=t}),Math.max(0,n-t.length));let r=1;for(let e=0;e<s;e++){for(;o.has("New event "+r);)r++;var l="New event "+r;o.add(l),i.push({eventName:l,additionalFinishes:n,isNewEvent:!0}),a+=n,r++}return{targetPIndex:n,totalAdditionalFinishes:a,actions:i}}function v(e,t){let n=new Map(e.map(e=>[e.eventName,{count:e.count,lastVisitIndex:"number"==typeof e.lastVisitIndex?e.lastVisitIndex:Number.NEGATIVE_INFINITY}]));e=e.reduce((e,t)=>"number"==typeof t.lastVisitIndex?Math.max(e,t.lastVisitIndex):e,Number.NEGATIVE_INFINITY)+1;let i=Number.isFinite(e)?e:0;return t.forEach(e=>{var t=n.get(e.eventName)||{count:0,lastVisitIndex:Number.NEGATIVE_INFINITY};n.set(e.eventName,{count:t.count+e.additionalFinishes,lastVisitIndex:i+e.additionalFinishes-1}),i+=e.additionalFinishes}),Array.from(n.entries()).map(([e,t])=>({eventName:e,count:t.count,lastVisitIndex:t.lastVisitIndex}))}t.exports={applyPlanToEventCounts:v,buildDifficultyMetrics:function(e,t){var n;return 0===e.length?{latestGap:0,longestGap:0,startLevel:0,endLevel:0,nextTarget:1,nextPlan:{targetPIndex:1,totalAdditionalFinishes:1,actions:[{eventName:"New event 1",additionalFinishes:1,isNewEvent:!0}]},lookaheadTarget:2,lookaheadPlan:{targetPIndex:2,totalAdditionalFinishes:3,actions:[{eventName:"New event 2",additionalFinishes:2,isNewEvent:!0},{eventName:"New event 3",additionalFinishes:1,isNewEvent:!0}]}}:(n=e.filter(e=>e.isJump),e=e[e.length-1],n=n.reduce((e,t)=>!e||t.finishesSincePreviousIncrease>e.finishesSincePreviousIncrease?t:e,null),{latestGap:e.finishesSincePreviousIncrease,longestGap:n?n.finishesSincePreviousIncrease:0,startLevel:n?n.previousPIndex:0,endLevel:n?n.pIndex:0,nextTarget:t+1,nextPlan:e.nextPlan,lookaheadTarget:t+2,lookaheadPlan:e.lookaheadPlan})},buildEventStats:x,calculateMinimumFinishesPlan:h,calculatePIndex:m,calculatePIndexProgression:function(t){var n=[];let i=0,a=0;for(let e=0;e<t.length;e++){var o=t.slice(0,e+1),s=x(o),o=m(p(o)),r=h(s,o+1),s=h(v(s,r.actions),o+2),l=t[e],d=e+1,u=o>i,c=d-a;n.push({finishes:d,date:l.date,eventName:l.eventName,eventNumber:l.eventNumber,pIndex:o,previousPIndex:i,isJump:u,finishesSincePreviousIncrease:c,nextPlan:r,lookaheadPlan:s}),u&&(a=d,i=o)}return n},groupFinishesByEvent:p,parseDateDdMmYyyy:function(e){var[e,t,n]=e.split("/").map(e=>parseInt(e,10));return new Date(n,t-1,e)}}}});e({"src/p-index.user.js"(e,a){{let{calculatePIndex:e,groupFinishesByEvent:t,parseDateDdMmYyyy:o}=u();function s(){return window.innerWidth<768?{isMobile:!0,spacing:{small:"10px"},container:{padding:"10px",marginTop:"10px",width:"100%",maxWidth:"800px",aspectRatio:"auto"},typography:{pIndex:"1.2em",listItem:"0.9em"},listItem:{marginBottom:"5px",textAlign:"left"},button:{padding:"6px 12px",fontSize:"0.9em",marginTop:"10px"}}:{isMobile:!1,spacing:{small:"20px"},container:{padding:"20px",marginTop:"20px",width:"auto",maxWidth:"none",aspectRatio:"1"},typography:{pIndex:"1.5em",listItem:"1em"},listItem:{marginBottom:"8px",textAlign:"center"},button:{padding:"8px 15px",fontSize:"1em",marginTop:"15px"}}}if(void 0!==a&&a.exports&&"undefined"!=typeof globalThis&&globalThis.process&&globalThis.process.versions&&globalThis.process.versions.node)a.exports={buildContributingEvents:d,extractFinishTimeline:n,findResultsTable:i};else{var r,a=i();if(a){a=n(a),a=t(a),r=e(a),a=d(a,r);{let i=s(),e=document.querySelector("h2");if(e){let t=document.createElement("div");t.style.fontSize=i.typography.pIndex,t.style.fontWeight="bold",t.style.marginTop=i.container.marginTop,t.style.backgroundColor="#2b223d",t.style.color="#ffa300",t.style.padding=i.container.padding,t.style.borderRadius="5px",t.style.display="flex",t.style.flexDirection="column",t.style.alignItems="center",t.style.justifyContent="center",t.style.width=i.container.width,t.style.maxWidth=i.container.maxWidth,t.style.marginLeft="auto",t.style.marginRight="auto",t.style.aspectRatio=i.container.aspectRatio,t.setAttribute("id","p-index-display");var l=document.createElement("div");l.textContent="p-index: "+r,t.appendChild(l);let n=document.createElement("ul");n.style.listStyleType="none",n.style.padding="0",n.style.marginTop=i.spacing.small,n.style.width="100%",a.forEach(e=>{var t=document.createElement("li");t.textContent=e,t.style.fontWeight="normal",t.style.fontSize=i.typography.listItem,t.style.marginBottom=i.listItem.marginBottom,t.style.textAlign=i.listItem.textAlign,t.style.wordBreak="break-word",n.appendChild(t)}),t.appendChild(n),(e=>{let t=s(),n=document.createElement("div"),a=(n.style.marginTop=t.button.marginTop,n.id="p-index-download-btn-container",document.createElement("button"));a.textContent="💾 Save as Image",a.style.padding=t.button.padding,a.style.backgroundColor="#ffa300",a.style.color="#2b223d",a.style.border="none",a.style.borderRadius="4px",a.style.cursor="pointer",a.style.fontWeight="bold",a.style.fontSize=t.button.fontSize,a.addEventListener("mouseover",function(){this.style.backgroundColor="#e59200"}),a.addEventListener("mouseout",function(){this.style.backgroundColor="#ffa300"}),a.addEventListener("click",function(){a.style.display="none",html2canvas(e,{backgroundColor:"#2b223d",scale:2,logging:!1,allowTaint:!0,useCORS:!0}).then(e=>{a.style.display="block";var t=document.createElement("a"),n=(new Date).toISOString().split("T")[0],i=window.location.pathname.split("/")[2]||"parkrunner";t.download=`p-index-${i}-${n}.png`,t.href=e.toDataURL("image/png"),t.click()})}),n.appendChild(a),e.appendChild(n)})(t),e.parentNode.insertBefore(t,e.nextSibling),i.isMobile||setTimeout(()=>{var e=t.getBoundingClientRect(),e=Math.max(e.width,e.height);t.style.width=e+"px",t.style.height=e+"px"},0)}}}else console.error("Results table not found")}function n(e){let i=[];return e.querySelectorAll("tbody > tr").forEach(e=>{var t=e.querySelector("td:nth-child(1)").textContent.trim(),n=e.querySelector("td:nth-child(2)").textContent.trim(),e=e.querySelector("td:nth-child(3)").textContent.trim();i.push({eventName:t,date:n,eventNumber:e})}),i.sort((e,t)=>o(e.date)-o(t.date))}function i(){var e=document.querySelectorAll("#results");return e[e.length-1]}function d(e,a){return e.slice(0,a).map(([e,t])=>{var n=t[0],i=t[a-1];return{eventName:e,eventCount:t.length,firstDate:n.date,firstEventNumber:n.eventNumber,pIndexDate:i.date,pIndexEventNumber:i.eventNumber,pIndexDateForSorting:o(i.date)}}).sort((e,t)=>e.pIndexDateForSorting-t.pIndexDateForSorting).map(e=>e.eventName+" ("+e.eventCount+"): "+e.firstDate+" (#"+e.firstEventNumber+") - "+e.pIndexDate+" (#"+e.pIndexEventNumber+")")}}}})()})();

Support

Issues and support on GitHub