{"version":3,"sources":["portfolio.js"],"names":["data","graph","getLabelAttribute","node","getNodeLabel","label","getNodeYear","n","substr","match","getDisplayAttr","attr","replace","jsonLdToGraph","nodes","links","nodeId","nodeAttr","Array","isArray","key","i","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","createBreadcrumbLayer","newPath","slice","push","nextSrcIds","_iteratorNormalCompletion2","_didIteratorError2","_iteratorError2","_step2","_iterator2","newNextIds","_iteratorNormalCompletion3","_didIteratorError3","_iteratorError3","_step3","_iterator3","nextIds","concat","nodePositions","currentNodePositionRadius","nodeIdx","type","types","document","showMoreTypeLinksEl","getElementById","moreTypeLinksEl","typeCounts","map","sort","first","second","_loop","typeCountIdx","typeName","typeLinkEl","createElement","typeLinkAEl","typeLinkCountEl","add","title","addEventListener","centerByType","typeNodeEls","getElementsByClassName","_iteratorNormalCompletion7","_didIteratorError7","_iteratorError7","_step7","_iterator7","_iteratorNormalCompletion8","_didIteratorError8","_iteratorError8","_step8","_iterator8","classList","remove","append","typeLinksEl","appendChild","body","e","preventDefault","stopPropagation","removeEventListener","hideMoreTypeLinks","nodeEls","svg","createLinkMap","simulation","d3","forceLink","d","strength","force","forceManyBody","container","selectAll","enter","l","linkLine","linkText","innerHTML","baseClasses","slashpos","lastIndexOf","typeNodeEl","getViewbox","split","parseFloat","positionNodesInCenter","idxs","setViewboxForceCenter","_typeof","positionNodesInCircle","forceCx","forceCy","each","nIdx","alpha","viewBox","max","height","zoom","forceSimulation","forceCollide","cos","stepSize","restart","updateHistory","idx","indexOf","deselectNode","history","pushState","join","nodeDetailEl","transition","ease","easeLinear","relNode","el","titleEl","selectNode","typeEl","listEl","nodeEl","videoType","nodeDatum","startsWith","relDown","currentCrumbs","relUp","linkEls","q","getElementsByTagName","setAttribute","attrEl","a","relsEl","fnodeIdx","linkedIdxs","classed","posSrc","posTrg","ddEl","rel","splice","scrollToY","lastChild","nodeDetailScalerEl","getZoomValues","drag","width","window","innerWidth","clientX","nodeDetails","breadcrumbsEl","_loop2","crumbNodeId","crumbEl","nodeYear","crumbWrapEl","pageTitles","_iteratorNormalCompletion4","_didIteratorError4","_iteratorError4","_step4","_iterator4","titleAttr","replaceState","selectedNodeTransition","skipNodeAttributes","setDetails","hasChildNodes","poster","valueHtml","b","createRelationshipEl","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","midX","angle","leftX","isCircle","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 }\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"]}