{"version":3,"sources":["portfolio.js"],"names":["data","graph","getLabelAttribute","node","getNodeLabel","label","getNodeYear","n","substr","match","getDisplayAttr","attr","replace","jsonLdToGraph","nodeId","nodes","links","i","nodeAttr","Array","isArray","key","currentId","name","Object","keys","length","source","target","nodeMap","linkMap","breadcrumbs","weights","requestPromise","fetch","then","r","json","rankingPromise","dx","dy","dxAbs","Math","abs","values","dyAbs","pow","_iteratorNormalCompletion","_didIteratorError","_iteratorError","undefined","_step","_iterator","Symbol","iterator","next","done","link","value","id","err","return","Promise","hasOwnProperty","startGraph","nodeSize","selectedNodeSize","firstNodeId","getSizeForNode","min","createBreadcrumbs","srcId","crumbs","newNextIds","_iteratorNormalCompletion3","_didIteratorError3","_iteratorError3","_step3","_iterator3","nextIds","newPath","slice","push","nextSrcIds","_iteratorNormalCompletion2","_didIteratorError2","_iteratorError2","_step2","_iterator2","concat","nodePositions","nodeIdx","currentNodePositionRadius","type","types","document","showMoreTypeLinksEl","getElementById","moreTypeLinksEl","typeCounts","map","sort","first","second","typeCountIdx","typeName","typeLinkEl","createElement","typeLinkAEl","typeLinkCountEl","add","title","addEventListener","centerByType","typeNodeEls","getElementsByClassName","_iteratorNormalCompletion7","_didIteratorError7","_iteratorError7","_step7","_iterator7","createBreadcrumbLayer","_iteratorNormalCompletion8","_didIteratorError8","_iteratorError8","_step8","_iterator8","classList","remove","append","typeLinksEl","appendChild","_loop","body","e","preventDefault","stopPropagation","removeEventListener","hideMoreTypeLinks","getViewbox","svg","split","parseFloat","positionNodesInCenter","idxs","setViewboxForceCenter","_typeof","positionNodesInCircle","forceCx","forceCy","each","d","nIdx","nodeEls","simulation","alpha","relNode","el","titleEl","innerHTML","idx","indexOf","selectNode","typeEl","scrollToY","nodeDetailEl","lastChild","relUp","restart","nodeDetailScalerEl","getZoomValues","drag","viewBox","width","window","innerWidth","clientX","max","nodeDetails","breadcrumbsEl","_iteratorNormalCompletion4","_didIteratorError4","_iteratorError4","_step4","_iterator4","crumbNodeId","crumbEl","nodeYear","updateHistory","crumbWrapEl","pageTitles","_loop2","nodeDatum","titleAttr","deselectNode","history","pushState","replaceState","selectedNodeTransition","skipNodeAttributes","relDown","listEl","setDetails","videoType","hasChildNodes","poster","valueHtml","attrEl","a","b","ddEl","rel","relsEl","createRelationshipEl","createLinkMap","d3","forceLink","strength","force","forceManyBody","container","selectAll","enter","l","linkLine","linkText","slashpos","baseClasses","lastIndexOf","typeNodeEl","height","zoom","forceSimulation","forceCollide","cos","stepSize","join","transition","ease","easeLinear","currentCrumbs","nodeEl","startsWith","linkEls","q","getElementsByTagName","setAttribute","fnodeIdx","linkedIdxs","classed","posSrc","posTrg","splice","event","firstNode","find","closeDetails","transform","baseVal","_iteratorNormalCompletion5","_didIteratorError5","_iteratorError5","_step5","_iterator5","zoomContainer","SVGTransform","SVG_TRANSFORM_TRANSLATE","matrix","f","SVG_TRANSFORM_SCALE","scale","k","fx","fy","graphInitialised","vy","vx","x","y","inCircle","random","filter","call","self","tspan","alphaTarget","titleTexts","textLength1","textLength2","textLength","titleText","on","state","hoverLinkEls","scaleExtent","c","text","nodePath","select","this","startX","splitPosChar","_iteratorNormalCompletion6","_didIteratorError6","_iteratorError6","_step6","_iterator6","char","mid","tmid","splitPos","text1","trim","splitText","getComputedTextLength","forEach","rightX","sourceX","targetX","leftX","isCircle","midX","angle","atan2","srcSize","tgtSize","sin","text2","targetY","sourceY","nodeTitle","deg","atan","PI","isNaN","distance","location","pathname","t","search","startNodeId","initPlaceholder","removeChild","setTimeout","reqAnimFrame","mozRequestAnimationFrame","callback","speed","easing","finishFunction","scrollTargetY","time","scrollY","easingEquations","easeOutSine","pos","tick","p","scrollTo"],"mappings":"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","file":"portfolio.min.js","sourcesContent":["var data;\n\nfunction getLabelAttribute(node) {\n if(typeof node['https://schema.org/name'] !== \"undefined\"){\n return 'https://schema.org/name';\n }\n switch (node['@type']) {\n case \"https://schema.org/WebSite\":\n if(typeof node['https://schema.org/url'] !== \"undefined\") {return 'https://schema.org/url';}\n break;\n case \"https://schema.org/ImageObject\":\n if(typeof node['https://schema.org/caption'] !== \"undefined\") {return 'https://schema.org/caption';}\n if(typeof node['https://schema.org/contentUrl'] !== \"undefined\") {return 'https://schema.org/contentUrl';}\n break;\n case \"https://schema.org/PostalAddress\":\n if(typeof node['https://schema.org/addressLocality'] !== \"undefined\") {return 'https://schema.org/addressLocality';}\n break;\n case \"https://schema.org/OrganizationRole\":\n if (typeof node['https://schema.org/roleName'] !== \"undefined\") {\n return 'https://schema.org/roleName';\n }\n break;\n }\n return '@id';\n}\nfunction getNodeLabel(node){\n let labelAttr = getLabelAttribute(node);\n let label = node[labelAttr];\n if(typeof label == \"undefined\") label = node[\"@id\"];\n if(typeof label == \"undefined\") label = \"\";\n return label;\n}\nfunction getNodeYear(n){\n if(typeof n['https://schema.org/dateCreated'] !== 'undefined') {\n return n['https://schema.org/dateCreated'].substr(0,4);\n }\n if(typeof n['https://schema.org/datePublished'] !== 'undefined') {\n return n['https://schema.org/datePublished'].substr(0,4);\n }\n if(typeof n['https://schema.org/startDate'] !== 'undefined') {\n // console.log(n['https://schema.org/startDate']);\n return n['https://schema.org/startDate'].substr(0,4);\n }\n if(typeof n['https://schema.org/endDate'] !== 'undefined') {\n return n['https://schema.org/endDate'].substr(0,4);\n }\n if(typeof n['https://schema.org/foundingDate'] !== 'undefined') {\n return n['https://schema.org/foundingDate'].substr(0,4);\n }\n if(typeof n['https://schema.org/temporalCoverage'] !== 'undefined') {\n if(n['https://schema.org/temporalCoverage'].match(/\\d{4}-\\d{4}/)) {\n return n['https://schema.org/temporalCoverage'].substr(5,4);\n }\n }\n return null;\n}\nfunction getDisplayAttr(attr) {\n return attr.replace(/.*[#|\\/]/, \"\");\n}\n/**\nTransform a flattened jsonld into a d3 compatible graph\n@param Object data flattened jsonld data\n@return Object graph has keys \"nodes\" and \"links\"\n*/\nfunction jsonLdToGraph(data){\n let nodes = {};\n let links = [];\n\n // collect all nodes\n for(let nodeId in data){\n // data[nodeId][\"@type\"][0] = data[nodeId][\"@type\"][0];\n nodes[data[nodeId][\"@id\"]] = data[nodeId];\n }\n\n // collect all links (separate loop as we need to check nodes)\n for(let nodeId in data) {\n let node = data[nodeId];\n let currentId = node[\"@id\"];\n for(let key in node){\n let nodeAttr = Array.isArray(node[key]) ? node[key] : [node[key]];\n // // relations should always be lists (eases assumptions)\n // if(typeof node[key] !== \"Array\" && typeof node[key]['id'] !== \"undefined\") {\n // node[key] = [node[key]];\n // }\n // every attribute is an Array after flatten(), loop them\n for(let i in nodeAttr) {\n if(key !== \"@id\" && typeof nodeAttr[i] === \"string\" && nodes[nodeAttr[i]]) {\n links[links.length] = {\n \"source\": currentId,\n \"target\": nodeAttr[i],\n \"name\": key\n };\n }\n else if(typeof nodeAttr[i][\"@id\"] !== \"undefined\") {\n // if there is just one item, flatten/expand has turned urls in objects with just an id\n // reverse this, as we don't want these separate for this project\n if (Object.keys(nodeAttr[i]).length == 1 && typeof nodes[nodeAttr[i][\"@id\"]] === \"undefined\") {\n // skip\n // nodeAttr = nodeAttr[i][\"id\"];\n } else {\n links[links.length] = {\n \"source\": currentId,\n \"target\": nodeAttr[i][\"@id\"],\n \"name\": key\n };\n }\n }\n }\n }\n }\n return {\n \"nodes\": Object.values(nodes),\n \"links\": links\n };\n}\n\nvar graph;\n// map nodes to their ID\nvar nodeMap = {};\nvar linkMap = {};\nvar breadcrumbs = {};\nvar weights = {};\n\n// load the flattened jsonld file\nconst requestPromise = fetch('/assets/js/rubenvandeven.jsonld').then(r => r.json());\nconst rankingPromise = fetch('/assets/js/ranking.json').then(r => r.json());\n\nPromise.all([requestPromise, rankingPromise])\n .then(values => {\n if(values[0].hasOwnProperty('@graph')) {\n data = values[0];\n weights = values[1];\n } else {\n data = values[1];\n weights = values[0];\n }\n graph = jsonLdToGraph(data['@graph']);\n // create a map of nodes by id.\n for(let i in graph.nodes) {\n nodeMap[graph.nodes[i]['@id']] = graph.nodes[i];\n }\n startGraph(graph);\n });\n\nfunction inCircle(dx, dy, r) {\n // fastest check if in circle: https://stackoverflow.com/a/7227057\n let dxAbs = Math.abs(dx);\n let dyAbs = Math.abs(dy);\n\n if(dxAbs > r || dyAbs > r) {\n return false;\n } else if(dxAbs + dyAbs <= r){\n return true;\n } else if( Math.pow(dx,2) + Math.pow(dy, 2) <= Math.pow(r,2)){\n return true;\n } else {\n return false;\n }\n}\n\nfunction createLinkMap(graph) {\n let linkMap = {};\n for(let link of graph['links']){\n if(typeof linkMap[link['source']] == 'undefined') {\n linkMap[link['source']] = [];\n }\n linkMap[link['source']][linkMap[link['source']].length] = {'id': link['target'], 'name': link['name']};\n\n\n if(typeof linkMap[link['target']] == 'undefined') {\n linkMap[link['target']] = [];\n }\n\n linkMap[link['target']][linkMap[link['target']].length] = {'id': link['source'], 'name': link['name']};\n }\n return linkMap;\n}\n\n\n // config\nvar nodeSize = 40;\nvar selectedNodeSize = 140;\nvar firstNodeId = \"https://rubenvandeven.com/\";\n\nfunction getSizeForNode(node) {\n if(node.hasOwnProperty('https://schema.org/thumbnailUrl'))\n return nodeSize;\n if(weights[node['@id']])\n return nodeSize * weights[node['@id']];\n if(node['@id'] == firstNodeId)\n return nodeSize*1.2;\n // everynode has at least one link. these should equal 1\n return nodeSize * (.7 + Math.min(20, linkMap[node['@id']].length) / 40)\n return nodeSize;\n}\n\n// TODO: make sure, 'shortest' path is favoured.\nfunction createBreadcrumbs(linkMap, srcId) {\n let crumbs = {};\n\n let createBreadcrumbLayer = function(srcId) {\n let path = crumbs[srcId];\n let newPath = path.slice();\n newPath.push(srcId);\n\n let nextSrcIds = [];\n for (let link of linkMap[srcId]) {\n if(typeof crumbs[link['id']] !== 'undefined') continue;\n crumbs[link['id']] = newPath;\n nextSrcIds.push(link['id']);\n }\n\n return nextSrcIds;\n }\n crumbs[srcId] = [];\n let nextIds = [srcId];\n while(nextIds.length > 0) {\n let newNextIds = [];\n for (let nextId of nextIds) {\n let r = createBreadcrumbLayer(nextId);\n newNextIds = newNextIds.concat(r);\n }\n nextIds = newNextIds;\n }\n return crumbs;\n}\n\nvar nodePositions = {};\nfunction startGraph(graph){\n\n\n// set some vars\nvar currentNodeIdx = 0;\nvar currentNodePositionRadius = 0;\nvar types = {};\n\nlinkMap = createLinkMap(graph);\nbreadcrumbs = createBreadcrumbs(linkMap, firstNodeId);\n\nfor (let nodeIdx in graph['nodes']) {\n let type = graph['nodes'][nodeIdx][\"@type\"];\n if(typeof types[type] == 'undefined') {\n types[type] = [];\n }\n types[type].push(nodeIdx);\n}\nvar graphControlsEl = document.getElementById('graphControls');\nvar typeLinksEl = document.getElementById('typeLinks');\nvar showMoreTypeLinksEl = document.getElementById('showMoreTypeLinks');\nvar moreTypeLinksEl = document.getElementById('moreTypeLinks');\nvar relLinksEl = document.getElementById('relLinks');\n\n// sort types by count:\nvar typeCounts = Object.keys(types).map(function(key) {\n return [key, types[key].length];\n});\ntypeCounts.sort(function(first, second) {\n return second[1] - first[1];\n});\n\n// make controls\nlet i = 0;\nfor (let typeCountIdx in typeCounts) {\n let typeName = typeCounts[typeCountIdx][0];\n let typeLinkEl = document.createElement(\"li\");\n let typeLinkAEl = document.createElement(\"a\");\n let typeLinkCountEl = document.createElement(\"span\");\n typeLinkCountEl.innerHTML = typeCounts[typeCountIdx][1];\n typeLinkCountEl.classList.add('typeCount');\n typeLinkAEl.innerHTML = getDisplayAttr(typeName);\n typeLinkAEl.title = typeName;\n typeLinkAEl.addEventListener('click', function(){\n centerByType(typeName);\n // positionNodesInCenter(types[typeName]);\n });\n typeLinkAEl.addEventListener('mouseover', function() {\n let typeNodeEls = document.getElementsByClassName(typeName);\n for(let typeNodeEl of typeNodeEls) {\n typeNodeEl.classList.add('typeHighlight');\n }\n });\n typeLinkAEl.addEventListener('mouseout', function() {\n let typeNodeEls = document.getElementsByClassName(typeName);\n for(let typeNodeEl of typeNodeEls) {\n typeNodeEl.classList.remove('typeHighlight');\n }\n });\n typeLinkEl.append(typeLinkAEl);\n typeLinkEl.append(typeLinkCountEl);\n (i < 5 ? typeLinksEl: moreTypeLinksEl).appendChild(typeLinkEl);\n i++;\n // typeLinksEl.appendChild(typeLinkEl);\n}\n\nshowMoreTypeLinksEl.addEventListener('click', function () {\n document.body.classList.add('showMoreLinks');\n var hideMoreTypeLinks = function(e) {\n e.preventDefault();\n e.stopPropagation();\n document.body.removeEventListener('mouseup', hideMoreTypeLinks, true);\n document.body.classList.remove('showMoreLinks');\n }\n document.body.addEventListener('mouseup', hideMoreTypeLinks, true);\n}, false)\n\n\n// make svg\nvar svg = d3.select(\"svg\"),\n width = +svg.attr(\"width\"),\n height = +svg.attr(\"height\");\nvar container = svg.append(\"g\")\n .attr(\"id\", \"container\")\n ;\n\nvar simulation = d3.forceSimulation()\n .force(\"link\", d3.forceLink().id(function(d) { return d[\"@id\"]; }).strength(.005))\n .force(\"charge\", d3.forceManyBody()) // doesn't seem necessary?\n .force(\"collision\", d3.forceCollide(function(d){\n return getSizeForNode(d) * 1.1; // avoid overlapping nodes\n }))\n // .force(\"center\", d3.forceCenter(width / 2, height / 2)) // position around center\n\n // .force(\"x\", d3.forceX())\n // .force(\"y\", d3.forceY())\n // .force(\"y\", d3.forceY())\n ;\n\n\nvar link = container.append(\"g\")\n .attr(\"class\", \"links\")\n .selectAll(\".relationship\")\n .data(graph['links'])\n .enter().append(\"g\")\n .attr(\"class\", function(l){return \"relationship \"+l.name;})\n ;\nvar linkLine = link\n // .append(\"line\");\n .append(\"line\").attr(\"marker-end\", \"url(#arrowHead)\")\n ;\nvar linkText = link\n .append(\"text\")\n .text(function(l){\n // l == Object { source: \"https://rubenvandeven.com/#codesandmodes\", target: \"_:b34\", name: \"https://schema.org/location\" }\n return getDisplayAttr(l.name);\n })\n ;\n\n var node = container.append(\"g\")\n .attr(\"class\", \"nodes\")\n .selectAll(\".node\")\n .data(graph.nodes)\n .enter().append(\"g\")\n .attr(\"class\", function(d) {\n let baseClasses = 'node ' + d['@type'];\n if(d['@type']) {\n let slashpos = d['@type'].lastIndexOf('/');\n if(slashpos > -1) {\n baseClasses += ' ' + d['@type'].substr(slashpos + 1);\n }\n }\n return baseClasses;\n })\n ;\nvar getViewbox = function() {\n return svg.attr(\"viewBox\").split(\" \").map(parseFloat);\n}\nvar positionNodesInCenter = function(idxs) {\n setViewboxForceCenter(); // sets forceCx & forceCy\n if(typeof idxs == \"object\" && idxs !== null && idxs.length == 1) {\n idxs = idxs[0];\n }\n\n nodePositions = {}; // reset\n if(idxs === null) {\n return;\n }\n else if(typeof idxs == \"object\") {\n // array or object -> each\n // calculate grid:\n // let itemsX = 4;\n // let itemsY = Math.ceil(idxs.length/itemsX);\n // console.log(itemsX,itemsY);\n // let rowDiffX = viewBox[3] * (1/(itemsX+1));\n // let rowDiffY = viewBox[2] * (1/(itemsY+1));\n // console.log(rowDiffX, rowDiffY);\n // for (var i = 0; i < idxs.length; i++) {\n // nodePositions[idxs[i]] = [\n // cx - itemsX/2*rowDiffX + rowDiffX * ((i % itemsX)),\n // cy - itemsY/2*rowDiffY + rowDiffY * (Math.floor(i / itemsX))\n // ];\n // }\n positionNodesInCircle(idxs);\n // console.log(nodePositions);\n }\n else{\n nodePositions[idxs] = [\n forceCx,\n forceCy\n ];\n // console.log(\"singleNode\", idxs, nodePositions);\n }\n\n node.each(function(d,nIdx,nodeEls){\n if(typeof nodePositions[nIdx] != 'undefined') {\n nodeEls[nIdx].classList.add('centeredNode');\n nodeEls[nIdx].classList.add('visibleNode');\n } else {\n nodeEls[nIdx].classList.remove('centeredNode');\n nodeEls[nIdx].classList.remove('visibleNode');\n }\n });\n\n // restart animation (they call that 'alpha' in d3 force)\n simulation.alpha(1);\n simulation.restart();\n}\nvar positionNodesInCircle = function(idxs, r) {\n let viewBox = getViewbox();\n let zoom = getZoomValues();\n setViewboxForceCenter(); // sets forceCx & forceCy\n if(typeof r == 'undefined') {\n if(idxs.length == 1) {\n r = viewBox[2] / 6;\n } else {\n r = viewBox[2] / (4 + Math.max(0, 2.5 - idxs.length));\n }\n }\n currentNodePositionRadius = r;\n let forceCx = viewBox[0] + viewBox[2]/2 - zoom['dx'];\n let forceCy = viewBox[1] + viewBox[3]/2 - zoom['dy'];\n\n let stepSize = 2*Math.PI / idxs.length;\n\n for (var i = 0; i < idxs.length; i++) {\n nodePositions[idxs[i]] = [\n forceCx + Math.sin(stepSize * i) * r,\n forceCy + Math.cos(stepSize * i) * r\n ];\n }\n\n // restart animation (they call that 'alpha' in d3 force)\n simulation.alpha(1);\n simulation.restart();\n}\nvar centerByType = function(types, updateHistory) {\n if(typeof updateHistory == 'undefined') {\n updateHistory = true;\n }\n if(!Array.isArray(types)) {\n types = [types];\n }\n let idxs = [];\n for(let idx in graph.nodes) {\n if(types.indexOf(graph.nodes[idx]['@type']) > -1) {\n idxs[idxs.length] = idx;\n }\n }\n deselectNode();\n if(updateHistory) {\n // TODO: working\n // console.log(types[0], getDisplayAttr(types[0]),types.map(getDisplayAttr));\n history.pushState({types: types}, \"\", \"/@type/\"+(types.map(getDisplayAttr).join(\"+\")));\n } else {\n history.replaceState({types: types}, \"\", \"/@type/\"+(types.map(getDisplayAttr).join(\"+\")));\n }\n positionNodesInCenter(idxs.length ? idxs : null);\n}\n\nvar selectedNodeTransition = d3.transition()\n .duration(750)\n .ease(d3.easeLinear);\n\nvar nodeDetailEl = document.getElementById(\"nodeDetails\");\n\nvar createRelationshipEl = function(relNode, i) {\n let el = document.createElement(\"dd\");\n el.classList.add('relLink');\n let titleEl = document.createElement('a');\n titleEl.innerHTML = getNodeLabel(relNode)\n let year = getNodeYear(relNode);\n if(year !== null) {\n titleEl.innerHTML += `${getNodeYear(relNode)}`;\n }\n titleEl.classList.add('nodeTitle');\n titleEl.classList.add('nodeTitleNr'+i);\n titleEl.addEventListener('click',function(e){\n let idx = graph.nodes.indexOf(relNode);\n selectNode(idx);\n });\n let typeEl = document.createElement('a');\n typeEl.classList.add('nodeType');\n typeEl.innerHTML = getDisplayAttr(relNode['@type']);\n typeEl.title = relNode['@type'];\n typeEl.addEventListener('click',function(e){\n centerByType(relNode['@type']);\n });\n el.appendChild(titleEl);\n el.appendChild(typeEl);\n return el;\n}\n\nvar setDetails = function(nodeDatum, nodeIdx) {\n document.body.classList.add(\"detailsOpen\");\n scrollToY(0, 4000);\n while (nodeDetailEl.hasChildNodes()) {\n nodeDetailEl.removeChild(nodeDetailEl.lastChild);\n }\n\n // TODO: replace relUp & relDown with linkMap\n let relUp = [];\n let relDown = [];\n let pageTitles = [];\n let nodeDetailScalerEl = document.createElement('div');\n // nodeDetailScalerEl.innerHTML = `
`;\n nodeDetailScalerEl.id = 'nodeDetailsScaler';\n nodeDetailScalerEl.addEventListener('mousedown', function(e){\n // console.log('go');\n let drag = function(e) {\n // 5px for padding\n nodeDetailEl.style.width = (window.innerWidth - e.clientX + 5) +'px';\n }\n document.body.addEventListener('mousemove', drag);\n document.body.addEventListener('mouseup', function(){\n document.body.removeEventListener('mousemove', drag);\n });\n });\n nodeDetails.appendChild(nodeDetailScalerEl);\n\n let breadcrumbsEl = document.createElement('ul');\n breadcrumbsEl.classList.add('breadcrumbs');\n for(let crumbNodeId of breadcrumbs[nodeDatum['@id']]) {\n let crumbWrapEl = document.createElement('li');\n let crumbEl = document.createElement('span');\n crumbEl.classList.add('crumb');\n crumbEl.addEventListener('click', function(e){\n let idx = graph.nodes.indexOf(nodeMap[crumbNodeId]);\n selectNode(idx);\n });\n crumbEl.innerHTML = `${getNodeLabel(nodeMap[crumbNodeId])}`;\n let nodeYear = getNodeYear(nodeMap[crumbNodeId]);\n if(nodeYear !== null) {\n crumbEl.innerHTML += `${nodeYear}`;\n }\n crumbWrapEl.appendChild(crumbEl);\n breadcrumbsEl.appendChild(crumbWrapEl);\n pageTitles.push(getNodeLabel(nodeMap[crumbNodeId]));\n }\n nodeDetailEl.appendChild(breadcrumbsEl);\n pageTitles.push(getNodeLabel(nodeDatum));\n\n let titleAttr = getLabelAttribute(nodeDatum);\n let titleEl = document.createElement('h2');\n titleEl.innerHTML = getNodeLabel(nodeDatum);\n\n let typeEl = document.createElement('span');\n typeEl.classList.add('nodeType')\n typeEl.innerHTML = getDisplayAttr(nodeDatum['@type']);\n typeEl.title = nodeDatum['@type']\n typeEl.addEventListener('click',function(e){\n centerByType(nodeDatum['@type']);\n });\n titleEl.appendChild(typeEl);\n nodeDetailEl.appendChild(titleEl);\n\n let listEl = document.createElement(\"dl\");\n // listEl.innerHTML += `
type
${nodeDatum['@type']}
`;\n\n let skipNodeAttributes = [\n '@id','x','y','index','@type','vy','vx','fx','fy','leftX','rightX'\n ];\n if(titleAttr !== 'https://schema.org/contentUrl') {\n skipNodeAttributes[skipNodeAttributes.length] = titleAttr;\n }\n for (let attr in nodeDatum) {\n if(skipNodeAttributes.indexOf(attr) != -1) {\n continue;\n }\n\n // approach all as array\n let nodeAttr = Array.isArray(nodeDatum[attr]) ? nodeDatum[attr] : [nodeDatum[attr]];\n for (let i in nodeAttr) {\n // check if relationship:\n if(typeof nodeAttr[i] === \"string\" && nodeMap[nodeAttr[i]]) {\n continue;\n } else if(typeof nodeAttr[i]['@id'] !== 'undefined') {\n continue;\n }\n if(attr == 'https://schema.org/url' || attr == 'http://www.w3.org/2000/01/rdf-schema#seeAlso') {\n listEl.innerHTML += `
${getDisplayAttr(attr)}
${nodeAttr[i]}
`;\n } else if(attr == 'https://schema.org/embedUrl') {\n listEl.innerHTML += `
${getDisplayAttr(attr)}
${nodeAttr[i]}
`;\n listEl.innerHTML += `
`;\n } else if(attr == 'https://schema.org/contentUrl') {\n listEl.innerHTML += `
${getDisplayAttr(attr)}
${nodeAttr[i]}
`;\n if(nodeDatum['@type'] == 'https://schema.org/VideoObject') {\n let videoType = nodeAttr['https://schema.org/encodingFormat'] ? `type='${nodeAttr['https://schema.org/encodingFormat']}'`: \"\";\n let poster = nodeAttr['https://schema.org/thumbnailUrl'] ? `poster='${nodeAttr['https://schema.org/thumbnailUrl']}'`: \"\";\n listEl.innerHTML += `
`;\n } else{\n listEl.innerHTML += `
`;\n }\n } else {\n let valueHtml = nodeAttr[i].replace(/\\n/g,\"
\");\n listEl.innerHTML += `
${getDisplayAttr(attr)}
${valueHtml}
`;\n }\n }\n }\n nodeDetailEl.appendChild(listEl);\n\n // let relTitleEl = document.createElement(\"h4\");\n // relTitleEl.classList.add('linkTitle');\n // relTitleEl.innerHTML = \"links\";\n // nodeDetailEl.appendChild(relTitleEl);\n\n let relsEl = document.createElement(\"dl\");\n // collect relationships\n for (var i = 0; i < graph.links.length; i++) {\n let link = graph.links[i];\n if(link['source']['@id'] == nodeDatum['@id']) {\n if(typeof relDown[link['name']] == \"undefined\") {\n relDown[link['name']] = [];\n }\n relDown[link['name']][relDown[link['name']].length] = link['target'];\n }\n if(link['target']['@id'] == nodeDatum['@id']) {\n if(typeof relUp[link['name']] == \"undefined\") {\n relUp[link['name']] = [];\n }\n relUp[link['name']][relUp[link['name']].length] = link['source'];\n }\n }\n\n // relationships / links incomming
\n for(let attr in relDown) {\n let attrEl = document.createElement(\"dt\");\n attrEl.innerHTML = getDisplayAttr(attr);\n relsEl.appendChild(attrEl);\n\n // highest pagerank first:\n relDown[attr].sort((a,b) => weights[b['@id']] - weights[a['@id']]);\n\n for(let i in relDown[attr]) {\n let rel = relDown[attr][i];\n relsEl.appendChild(createRelationshipEl(rel));\n if(typeof rel['https://schema.org/contentUrl'] != 'undefined') {\n let ddEl = document.createElement('dd')\n ddEl.classList.add('dd-contentobject');\n if(rel['@type'] == 'https://schema.org/VideoObject') {\n let videoType = rel['https://schema.org/encodingFormat'] ? `type='${rel['https://schema.org/encodingFormat']}'`: \"\";\n let poster = rel['https://schema.org/thumbnailUrl'] ? `poster='${rel['https://schema.org/thumbnailUrl']}'`: \"\";\n ddEl.innerHTML += ``;\n } else{\n ddEl.innerHTML = ``\n }\n relsEl.appendChild(ddEl);\n }\n }\n }\n\n // relationships / links outgoing
\n for(let attr in relUp) {\n let attrEl = document.createElement(\"dt\");\n attrEl.innerHTML = getDisplayAttr(attr);\n relsEl.appendChild(attrEl);\n\n // highest pagerank first:\n relUp[attr].sort((a,b) => weights[b['@id']] - weights[a['@id']]);\n\n for(let i in relUp[attr]) {\n let rel = relUp[attr][i];\n relsEl.appendChild(createRelationshipEl(rel, i));\n if(typeof rel['https://schema.org/contentUrl'] != 'undefined') {\n let ddEl = document.createElement('dd')\n ddEl.classList.add('dd-contentobject');\n ddEl.innerHTML = ``\n relsEl.appendChild(ddEl);\n }\n }\n }\n\n nodeDetailEl.appendChild(relsEl);\n\n node.each(function(d,nIdx,nodeEls){\n if(nIdx == nodeIdx) {\n nodeEls[nIdx].classList.add('selectedNode');\n } else {\n nodeEls[nIdx].classList.remove('selectedNode');\n }\n });\n\n // TODO: update history & title\n document.title = pageTitles.join(\" :: \");\n};\nvar closeDetails = function() {\n document.body.classList.remove(\"detailsOpen\");\n scrollToY(0, 4000); // for mobile\n}\n\n/**\n * Select a node, and center it + show details\n * @param int idx The index of the node in the graph.nodes array\n * @param Element|null nodeEl Optional, provide node element, so loop doesn't have to be used to change the Element\n * @return void\n */\nvar selectNode = function(idx, updateHistory){\n if(typeof updateHistory == 'undefined') {\n updateHistory = true;\n }\n\n let nodeEl = null;\n let nodeDatum = null;\n\n node.each(function(d,nIdx,nodeEls){\n if(nIdx == idx) {\n nodeEl = nodeEls[idx];\n nodeDatum = d;\n }\n });\n if(!nodeEl) {\n return;\n }\n\n\n if(true) { // always set history state, but replace instead of update on 'updatehistory'\n let id = null;\n if(nodeDatum['@id'].startsWith(/*location.origin*/'https://rubenvandeven.com/')){\n id = nodeDatum['@id'].substr(26);\n } else {\n id = '?id=' + nodeDatum['@id'];\n }\n\n if(updateHistory) {\n history.pushState({node: idx}, getNodeLabel(nodeDatum), \"/\"+id);\n } else {\n history.replaceState({node: idx}, getNodeLabel(nodeDatum), \"/\"+id);\n }\n }\n\n // set global var\n positionNodesInCenter(idx);\n\n let currentCrumbs = breadcrumbs[nodeDatum['@id']].slice();\n currentCrumbs[currentCrumbs.length] = nodeDatum['@id'];\n\n // set active links.\n let linkedIdxs = [];\n link.each(function(d,idx,linkEls,q){\n // set nodes 'visible'/highlighted when linked to active node\n if(d.source == nodeDatum || d.target == nodeDatum) {\n linkEls[idx].classList.add('activeLink','visibleLink');\n linkEls[idx].getElementsByTagName(\"line\")[0].setAttribute(\"marker-end\", \"url(#arrowHeadSelected)\");\n node.filter(function(a, fnodeIdx){\n let r = a['@id'] == d.source['@id'] || a['@id'] == d.target['@id']; //connected node: true/false\n if(r && linkedIdxs.indexOf(fnodeIdx) === -1){\n linkedIdxs[linkedIdxs.length] = fnodeIdx;\n }\n return r;\n }).classed('visibleNode', true);\n } else {\n linkEls[idx].classList.remove('activeLink');\n linkEls[idx].getElementsByTagName(\"line\")[0].setAttribute(\"marker-end\", \"url(#arrowHead)\");\n }\n // check if link is part of breadcrumb trail\n let posSrc = currentCrumbs.indexOf(d.source['@id']);\n let posTrg = currentCrumbs.indexOf(d.target['@id']);\n if(posSrc > -1 && posTrg > -1 && Math.abs(posSrc - posTrg) == 1) {\n linkEls[idx].classList.add('breadcrumbLink');\n linkEls[idx].getElementsByTagName(\"line\")[0].setAttribute(\"marker-end\", \"url(#arrowHeadCrumbTrail)\");\n } else {\n linkEls[idx].classList.remove('breadcrumbLink');\n }\n });\n\n let i = linkedIdxs.indexOf(idx);\n\n if(i !== -1) {\n linkedIdxs.splice(i, 1);\n }\n\n positionNodesInCircle(linkedIdxs);\n\n setDetails(nodeDatum ,idx);\n}\nvar deselectNode = function() {\n positionNodesInCenter(null);\n link.each(function(d,idx,linkEls,q){\n linkEls[idx].classList.remove('activeLink');\n linkEls[idx].classList.remove('breadcrumbLink');\n linkEls[idx].getElementsByTagName(\"line\")[0].setAttribute(\"marker-end\", \"url(#arrowHead)\")\n });\n closeDetails();\n}\n\n\nwindow.addEventListener('popstate', function(event) {\n if(event.state.hasOwnProperty('node')) {\n selectNode(event.state['node'], false);\n }\n else {\n // if not sure what to do, fall back to first node (also used to return to opening page)\n let firstNode = graph['nodes'].find(n => n['@id'] === firstNodeId);\n selectNode(graph['nodes'].indexOf(firstNode), false);\n }\n});\n\nvar forceCx, forceCy;\nvar setViewboxForceCenter = function() {\n let viewBox = getViewbox();\n let zoom = getZoomValues();\n forceCx = viewBox[0] + viewBox[2]/2 - zoom['dx'];\n forceCy = viewBox[1] + viewBox[3]/2 - zoom['dy'];\n}\n\nvar getZoomValues = function(){\n let zoomContainer = document.getElementById(\"container\");\n let dx = 0, dy = 0, scale = 1;\n if(zoomContainer.transform.baseVal.length > 0) {\n for(let transform of zoomContainer.transform.baseVal) {\n if(transform.type == SVGTransform.SVG_TRANSFORM_TRANSLATE) {\n dx += transform.matrix.e;\n dy += transform.matrix.f;\n }\n else if (transform.type == SVGTransform.SVG_TRANSFORM_SCALE) {\n scale *= transform.matrix.a; // assume simple scale\n }\n }\n }\n\n return {'dx': dx, 'dy': dy, 'scale': scale};\n}\n\nsetViewboxForceCenter(); // sets forceCx & forceCy\n\nvar graphInitialised = false;\nsimulation.force('centerActive', function force(alpha) {\n // let currentNode = node.selectAll('.detail');\n // console.log(currentNode);\n // console.log(forceCx, forceCy);\n node.each(function(d, idx, nodes){\n let n = d;\n let k = alpha * 0.1;\n n.fx = null;\n n.fy = null;\n if(typeof nodePositions[idx] != 'undefined') {\n if(graphInitialised == false) {\n n.x = nodePositions[idx][0];\n n.y = nodePositions[idx][1];\n n.vx = 0;\n n.vy = 0;\n } else {\n n.vx -= (n.x - nodePositions[idx][0]) * k * 5;\n n.vy -= (n.y - nodePositions[idx][1]) * k * 5;\n }\n } else {\n // if it's not positioned, move it out of the circle\n if(currentNodePositionRadius < 1) {\n return;\n }\n\n let dx = n.x - forceCx;\n let dy = n.y - forceCy;\n if(!inCircle(dx, dy, currentNodePositionRadius)) {\n return;\n }\n\n if(graphInitialised == false) {\n // on init, fixate items outside of circle\n n.fx = n.x + dx * (2+Math.random());\n n.fy = n.y + dy * (2+Math.random());\n } else {\n // if initialised, gradually move them outwards\n n.vx += dx * k*4;\n n.vy += dy * k*4;\n }\n }\n });\n});\n\n//path to curve the tile\nvar nodePath = node.append(\"path\")\n .attr(\"id\", function(d,idx){return \"nodePath\"+idx;})\n .attr(\"d\", function(d){\n var r = getSizeForNode(d) * 0.9;\n var startX = getSizeForNode(d);\n // M cx cy\n // m -r, 0\n // a r,r 0 1,0 (r * 2),0\n // a r,r 0 1,0 -(r * 2),0\n // return 'M' + nodeSize/2 + ' ' + nodeSize/2 + ' ' +\n return 'M' + 0 + ' ' + 0 + ' ' +\n 'm -' + r + ', 0'+' ' +\n 'a ' + r +','+r+' 0 1,0 '+ (r*2) +',0 '+\n 'a ' + r +','+r+' 0 1,0 -'+ (r*2) +',0'\n ;\n // return 'm' + startX + ',' + nodeSize + ' ' +\n // 'a' + r + ',' + r + ' 0 0 0 ' + (2*r) + ',0';\n })\n ;\n\nnode.call(d3.drag()\n .on(\"start\", dragstarted)\n .on(\"drag\", dragged)\n .on(\"end\", dragended))\n .on(\"click\", function(d, idx, nodes){\n let node = nodes[idx];\n selectNode(idx, node, d);\n })\n .on('mouseover', function(n, nIdx){\n link.each(function(l,idx,linkEls,q){\n // set nodes 'visible'/highlighted when linked to active node\n if(l.source == n || l.target == n) {\n linkEls[idx].classList.add('hoverLink');\n }\n });\n })\n .on('mouseout', function(){\n let hoverLinkEls = document.getElementsByClassName('hoverLink');\n while(hoverLinkEls.length > 0){\n hoverLinkEls[0].classList.remove('hoverLink');\n }\n });\n\n// svg.call(d3.drag()\n// .on(\"start\", function(d){\n// if(d3.event.sourceEvent.type == 'touchstart' && d3.event.sourceEvent.touches.length > 1) {\n// } else {\n// d3.event.sourceEvent.stopPropagation();\n// svg.node().classList.add(\"dragging\");\n// }\n// })\n// .on(\"drag\", function(){\n// moveViewboxPx(d3.event.dx, d3.event.dy);\n// })\n// .on(\"end\", function(){\n// svg.node().classList.remove(\"dragging\");\n// }));\nsvg.call(d3.zoom()\n .scaleExtent([0.3,3])\n .on(\"start\", function(){\n svg.node().classList.add(\"dragging\");\n })\n .on(\"end\", function(){\n svg.node().classList.remove(\"dragging\");\n })\n .on(\"zoom\", function(a,b,c){\n container.attr(\"transform\", d3.event.transform);\n })\n);\n\n// svg.call(d3.zoom.transform, d3.zoomIdentity);\n\nnode.append('circle')\n .attr(\"r\", (d) => getSizeForNode(d))\n .attr(\"class\", \"nodeBg\")\n ;\nnode.append('circle')\n .attr(\"r\", (d) => getSizeForNode(d) * 1.08) // nodeSize + margin\n .attr(\"class\", \"highlightCircle\")\n ;\n\nnode.append('text')\n .attr(\"class\", \"nodeType\")\n .text(function(n){\n return n['@type'];\n })\n\nnode.append('text')\n .attr(\"class\", \"nodeYear\")\n .attr(\"y\", \"22\")\n .text(function(n){\n return getNodeYear(n);\n })\n ;\nlet splitText = function(text){\n let characters = [\" \",\"-\",\"\\u00AD\"];\n let charSplitPos = {};\n let mid = Math.floor(text.length / 2);\n let splitPos = false;\n let splitPosChar = false;\n // split sentences\n for(let char of characters) {\n if(text.indexOf(char) < 0) {\n continue;\n }\n let tmid = text.substr(0,mid).lastIndexOf(char);\n if(tmid === -1) {\n tmid = text.indexOf(char);\n }\n tmid += 1; // we want to cut _after_ the character\n // console.log(\"Char\", char, tmid);\n if(splitPos === false || Math.abs(tmid-mid) < Math.abs(splitPos - mid)){\n // console.log(\"least!\");\n splitPos = tmid;\n splitPosChar = char;\n }\n }\n // console.log(\"pos\",splitPos)\n\n\n if(splitPos === false) {\n return false;\n }\n\n let text1 = text.substr(0, splitPos).trim();\n let text2 = text.substr(splitPos).trim();\n\n if(splitPosChar == \"\\u00AD\") {\n text1 += \"-\";\n }\n\n // find most equal split\n return [text1, text2];\n}\nlet nodeTitle = node.append('text')\n .attr(\"class\", \"nodeTitle\")\n .attr(\"y\", \"5\")\n ;\nnodeTitle\n // .append(\"textPath\")\n // .attr( \"xlink:href\",function(d, idx){return '#nodePath'+idx;})\n // .text(getNodeLabel)\n .each(function(node, nodes){\n let textLength;\n let self = d3.select(this);\n let titleText = getNodeLabel(node);\n let titleTexts = false;\n if(titleText.length > 20) {\n titleTexts = splitText(titleText);\n }\n if(titleTexts !== false) {\n let tspan1 = self.append(\"tspan\")\n .text(titleTexts[0])\n .attr(\"y\", \"-10\")\n .attr(\"x\", \"0\")\n ;\n let tspan = self.append(\"tspan\")\n .text(titleTexts[1])\n .attr(\"y\", \"10\")\n .attr(\"x\", \"0\")\n ;\n let textLength1 = tspan.node().getComputedTextLength();\n let textLength2 = tspan.node().getComputedTextLength();\n textLength = Math.max(textLength1, textLength2);\n } else {\n self.text(titleText);\n textLength = self.node().getComputedTextLength();\n }\n\n // scale according to text length:\n if(textLength > getSizeForNode(node) * 2) {\n self.attr('transform', `scale(${(getSizeForNode(node) * 2) / textLength / 1.05})`);\n }\n })\n ;\n\nnode.each(function(d) {\n if(!d['https://schema.org/thumbnailUrl']) {\n return;\n }\n d3.select(this).append('svg:image')\n .attr(\"xlink:href\", d['https://schema.org/thumbnailUrl'])\n .attr(\"width\", (d) => getSizeForNode(d)*2)\n .attr(\"height\", (d) => getSizeForNode(d)* 2)\n .attr(\"transform\",(d) => \"translate(-\"+getSizeForNode(d)+\" -\"+getSizeForNode(d)+\")\")\n .attr(\"clip-path\",\"url(#clipNodeImage)\")\n .attr(\"preserveAspectRatio\",\"xMidYMid slice\")\n ;\n });\n\nsimulation\n .nodes(graph.nodes)\n .on(\"tick\", ticked);\n\nsimulation.force(\"link\")\n .links(graph.links)\n .distance(function(l){\n switch (l.name) {\n // case 'publishedAt':\n // return 200;\n // case 'image':\n // return 200;\n default:\n return 300;\n }\n }) // distance between the nodes / link length\n // .charge(-100)\n;\n\n// run on each draw\nfunction ticked() {\n graph.nodes.forEach(function (d, idx) {\n d.leftX = d.rightX = d.x;\n\n // fix first node on center\n // if(idx === 0) {\n // d.fx = width/2;\n // d.fy = height/2;\n // return;\n // }\n });\n\n linkLine.each(function (d) {\n var sourceX, targetX, midX, dx, dy, angle;\n\n // This mess makes the arrows exactly perfect.\n // thanks to http://bl.ocks.org/curran/9b73eb564c1c8a3d8f3ab207de364bf4\n if( d.source.rightX < d.target.leftX ){\n sourceX = d.source.rightX;\n targetX = d.target.leftX;\n } else if( d.target.rightX < d.source.leftX ){\n targetX = d.target.rightX;\n sourceX = d.source.leftX;\n } else if (d.target.isCircle) {\n targetX = sourceX = d.target.x;\n } else if (d.source.isCircle) {\n targetX = sourceX = d.source.x;\n } else {\n midX = (d.source.x + d.target.x) / 2;\n if(midX > d.target.rightX){\n midX = d.target.rightX;\n } else if(midX > d.source.rightX){\n midX = d.source.rightX;\n } else if(midX < d.target.leftX){\n midX = d.target.leftX;\n } else if(midX < d.source.leftX){\n midX = d.source.leftX;\n }\n targetX = sourceX = midX;\n }\n\n dx = targetX - sourceX;\n dy = d.target.y - d.source.y;\n angle = Math.atan2(dx, dy);\n\n /* DISABLED\n srcSize = (typeof nodePositions[d.source.index] != 'undefined') ? selectedNodeSize : nodeSize;\n tgtSize = (typeof nodePositions[d.target.index] != 'undefined') ? selectedNodeSize : nodeSize;\n */\n let srcSize = getSizeForNode(d.source)+3.2;\n let tgtSize = getSizeForNode(d.target)+3.2;\n\n // Compute the line endpoint such that the arrow\n // is touching the edge of the node rectangle perfectly.\n d.sourceX = sourceX + Math.sin(angle) * srcSize;\n d.targetX = targetX - Math.sin(angle) * tgtSize;\n d.sourceY = d.source.y + Math.cos(angle) * srcSize;\n d.targetY = d.target.y - Math.cos(angle) * tgtSize;\n })\n .attr(\"x1\", function(d) { return d.sourceX; })\n .attr(\"y1\", function(d) { return d.sourceY; })\n .attr(\"x2\", function(d) { return d.targetX; })\n .attr(\"y2\", function(d) { return d.targetY; });\n linkText.attr(\"transform\", function(d){\n let dx = (d.target.x - d.source.x) /2;\n let dy = (d.target.y - d.source.y) /2;\n let x = d.source.x + dx;\n let y = d.source.y + dy;\n let deg = Math.atan(dy / dx) * 180 / Math.PI;\n // if dx/dy == 0/0 -> deg == NaN\n if(isNaN(deg)) {\n return \"\";\n }\n return \"translate(\"+x+\" \"+y+\") rotate(\"+deg+\") translate(0, -10)\";\n });\n\n node.attr(\"transform\", function(d) { return \"translate(\" + d.x + \",\" + d.y + \")\"; });\n}\n\nfunction dragstarted(d,idx,nodes) {\n if (!d3.event.active) simulation.alphaTarget(0.3).restart();\n let nodeEl = nodes[idx];\n d.fx = d.x;\n d.fy = d.y;\n // nodeEl.style.fill = '#00f';\n nodeEl.classList.add('drag');\n}\n\n// use to validate drag\n// function validate(x, a, b) {\n// if (x =< a) return a;\n// return b;\n// }\n\nfunction dragged(d, idx) {\n d.fx = d3.event.x;\n d.fy = d3.event.y;\n}\n\nfunction dragended(d, idx, nodes) {\n if (!d3.event.active) simulation.alphaTarget(0);\n let nodeEl = nodes[idx];\n d.fx = null;\n d.fy = null;\n nodeEl.classList.remove('drag');\n}\n\nfunction moveViewboxPx(dx, dy){\n let viewBox = svg.attr(\"viewBox\").split(\" \").map(parseFloat);\n viewBox[0] -= dx * 1;\n viewBox[1] -= dy * 1;\n svg.attr(\"viewBox\", viewBox.join(\" \"));\n}\n\n// start by selecting the first node :-)\n// selectNode(currentNodeIdx+1);\n// positionNodesInCenter(currentNodeIdx);\n\nif(location.pathname.startsWith('/@type/')) {\n for(let t in types) {\n if(getDisplayAttr(t) == location.pathname.substr(7)) {\n centerByType(t, false);\n }\n }\n} else{\n let startNodeId = location.search.startsWith(\"?id=\") ? location.search.substr(4) : 'https://rubenvandeven.com'+location.pathname;\n let firstNode = graph['nodes'].find(n => n['@id'] === startNodeId);\n selectNode(graph['nodes'].indexOf(firstNode), false);\n}\n\n\n\n// closeDetails(); // hide details at first\n// positionNodesInCenter(currentNodeIdx+1);\n\n// setTimeout(function(){\n // document.body.classList.add('graphInitialised');\n// }, 10);\n\nlet initPlaceholder = document.getElementById('initPlaceholder');\nsvg.node().removeChild(initPlaceholder);\nsetTimeout(function(){\n graphInitialised = true;\n document.body.classList.add('graphInitialised');\n }, 500);\n}\n\n\n// Detect request animation frame\nvar reqAnimFrame = window.requestAnimationFrame ||\n window.webkitRequestAnimationFrame ||\n window.mozRequestAnimationFrame ||\n window.msRequestAnimationFrame ||\n window.oRequestAnimationFrame ||\n // IE Fallback, you can even fallback to onscroll\n function(callback){ window.setTimeout(callback, 1000/60) };\n// all credits go to https://stackoverflow.com/a/26798337\nfunction scrollToY(scrollTargetY, speed, easing, finishFunction) {\n // scrollTargetY: the target scrollY property of the window\n // speed: time in pixels per second\n // easing: easing equation to use\n\n var scrollY = window.scrollY,\n scrollTargetY = scrollTargetY || 0,\n speed = speed || 2000,\n easing = easing || 'easeOutSine',\n currentTime = 0,\n finishFunction = finishFunction || false;\n\n // min time .1, max time .8 seconds\n let time = Math.max(.1, Math.min(Math.abs(scrollY - scrollTargetY) / speed, .8));\n\n // easing equations from https://github.com/danro/easing-js/blob/master/easing.js\n let PI_D2 = Math.PI / 2,\n easingEquations = {\n easeOutSine: function (pos) {\n return Math.sin(pos * (Math.PI / 2));\n },\n easeInOutSine: function (pos) {\n return (-0.5 * (Math.cos(Math.PI * pos) - 1));\n },\n easeInOutQuint: function (pos) {\n if ((pos /= 0.5) < 1) {\n return 0.5 * Math.pow(pos, 5);\n }\n return 0.5 * (Math.pow((pos - 2), 5) + 2);\n }\n };\n\n // add animation loop\n function tick() {\n currentTime += 1 / 60;\n\n var p = currentTime / time;\n var t = easingEquations[easing](p);\n\n if (p < 1) {\n reqAnimFrame(tick);\n\n window.scrollTo(0, scrollY + ((scrollTargetY - scrollY) * t));\n } else {\n window.scrollTo(0, scrollTargetY);\n if(finishFunction) {\n finishFunction();\n }\n }\n }\n\n // call it once to get started\n tick();\n}\n"]}