Attribution is provided for groups of files that share a common prefix. Each group can have one or more authors. Each file has one source. This information is displayed when an entity is selected.tags/v0.1.0
| @@ -68,7 +68,7 @@ body.toggle-entity-name .entity-name { | |||
| #main-area { | |||
| display: flex; | |||
| min-width: 100vw; | |||
| height: 100%; | |||
| height: 90vh; | |||
| flex-direction: row; | |||
| } | |||
| @@ -80,11 +80,14 @@ body.toggle-entity-name .entity-name { | |||
| flex-direction: column; | |||
| background: #444; | |||
| overflow-y: scroll; | |||
| height: 100%; | |||
| scrollbar-color: #e1e1e1 #888; | |||
| scrollbar-width: thin; | |||
| } | |||
| #options-attribution { | |||
| display: none; | |||
| } | |||
| #options::-webkit-scrollbar { | |||
| width: 3px; | |||
| height: 2px; | |||
| @@ -352,4 +355,4 @@ body.toggle-bottom-name .bottom-name { | |||
| a { | |||
| color: #999; | |||
| } | |||
| } | |||
| @@ -15,6 +15,7 @@ | |||
| <script src="presets/vehicles.js"></script> | |||
| <script src="presets/cities.js"></script> | |||
| <script src="presets/scenes.js"></script> | |||
| <script src="media/attribution.js"></script> | |||
| <script src="macrovision.js"></script> | |||
| <meta name="theme-color" content="#000000" /> | |||
| <meta name="description" content="How big are they anyway?" /> | |||
| @@ -120,6 +121,19 @@ | |||
| <div class="options-header">View options</div> | |||
| <span id="options-view"> | |||
| </span> | |||
| <div class="options-header">Attribution</div> | |||
| <span id="options-attribution"> | |||
| <div class="options-label"> | |||
| Authors | |||
| </div> | |||
| <span id="options-attribution-authors"> | |||
| </span> | |||
| <div class="options-label"> | |||
| Source | |||
| </div> | |||
| <span id="options-attribution-source"> | |||
| </span> | |||
| </span> | |||
| </div> | |||
| <div id="world"> | |||
| <div id="entities"> | |||
| @@ -345,6 +345,9 @@ function deselect() { | |||
| if (selected) { | |||
| selected.classList.remove("selected"); | |||
| } | |||
| clearAttribution(); | |||
| selected = null; | |||
| clearViewList(); | |||
| clearEntityOptions(); | |||
| @@ -357,6 +360,8 @@ function select(target) { | |||
| selectedEntity = entities[target.dataset.key]; | |||
| selected.classList.add("selected"); | |||
| displayAttribution(selectedEntity.views[selectedEntity.view].image.source); | |||
| configViewList(selectedEntity, selectedEntity.view); | |||
| configEntityOptions(selectedEntity, selectedEntity.view); | |||
| @@ -672,6 +677,47 @@ function removeAllEntities() { | |||
| }); | |||
| } | |||
| function clearAttribution() { | |||
| document.querySelector("#options-attribution").style.display = "none"; | |||
| } | |||
| function displayAttribution(file) { | |||
| document.querySelector("#options-attribution").style.display = "inline"; | |||
| const authors = authorsOfFull(file); | |||
| const source = sourceOf(file); | |||
| const authorHolder = document.querySelector("#options-attribution-authors"); | |||
| const sourceHolder = document.querySelector("#options-attribution-source"); | |||
| if (authors === []) { | |||
| authorHolder.innerText = "Unknown"; | |||
| } else if (authors === undefined) { | |||
| authorHolder.innerText = "Not yet entered"; | |||
| } else { | |||
| authorHolder.innerHTML = ""; | |||
| const list = document.createElement("ul"); | |||
| authorHolder.appendChild(list); | |||
| authors.forEach(author => { | |||
| const authorEntry = document.createElement("li"); | |||
| const link = document.createElement("a"); | |||
| link.href = author.url; | |||
| link.innerText = author.name; | |||
| authorEntry.appendChild(link); | |||
| list.appendChild(authorEntry); | |||
| }); | |||
| } | |||
| if (source === null) { | |||
| sourceHolder.innerText = "No Link" | |||
| } else if (source === undefined) { | |||
| sourceHolder.innerText = "Not yet entered"; | |||
| } else { | |||
| sourceHolder.innerText = source; | |||
| } | |||
| } | |||
| function removeEntity(element) { | |||
| if (selected == element) { | |||
| deselect(); | |||
| @@ -701,6 +747,8 @@ function displayEntity(entity, view, x, y) { | |||
| const image = entity.views[view].image; | |||
| img.src = image.source; | |||
| displayAttribution(image.source); | |||
| if (image.bottom !== undefined) { | |||
| img.style.setProperty("--offset", ((-1 + image.bottom) * 100) + "%") | |||
| } else { | |||
| @@ -855,6 +903,8 @@ document.addEventListener("DOMContentLoaded", () => { | |||
| const image = entities[selected.dataset.key].views[e.target.value].image; | |||
| selected.querySelector(".entity-image").src = image.source; | |||
| displayAttribution(image.source); | |||
| if (image.bottom !== undefined) { | |||
| selected.querySelector(".entity-image").style.setProperty("--offset", ((-1 + image.bottom) * 100) + "%") | |||
| } else { | |||
| @@ -0,0 +1,77 @@ | |||
| const attributionData = { | |||
| sources: [ | |||
| { | |||
| prefix: "./media/buildings/", | |||
| files: [ | |||
| { name: "house.svg", source: null }, | |||
| { name: "mailbox.svg", source: null }, | |||
| { name: "mobile-home.svg", source: null }, | |||
| ], | |||
| authors: [ | |||
| "chemicalcrux" | |||
| ] | |||
| }, | |||
| { | |||
| prefix: "./media/buildings/skyscrapers/", | |||
| files: [ | |||
| { name: "wide.svg", source: null }, | |||
| { name: "medium.svg", source: null }, | |||
| { name: "slender.svg", source: null }, | |||
| { name: "narrow.svg", source: null }, | |||
| ], | |||
| authors: [ | |||
| "chemicalcrux" | |||
| ] | |||
| } | |||
| ], | |||
| authors: { | |||
| "chemicalcrux": { | |||
| name: "chemicalcrux", | |||
| url: "https://www.furaffinity.net/user/chemicalcrux" | |||
| } | |||
| } | |||
| } | |||
| const attribution = {}; | |||
| function prepareAttribution() { | |||
| attribution["files"] = {}; | |||
| attributionData.sources.forEach(citation => { | |||
| citation.files.forEach(file => { | |||
| attribution.files[citation.prefix + file.name] = { | |||
| authors: citation.authors, | |||
| source: file.source | |||
| } | |||
| }) | |||
| }); | |||
| } | |||
| function authorsOf(file) { | |||
| if (attribution.files[file]) | |||
| return attribution.files[file].authors; | |||
| else | |||
| return undefined; | |||
| } | |||
| function authorsOfFull(file) { | |||
| if (attribution.files[file]) { | |||
| const result = []; | |||
| attribution.files[file].authors.forEach(author => { | |||
| result.push(attributionData.authors[author]); | |||
| }); | |||
| return result; | |||
| } | |||
| else | |||
| return undefined; | |||
| } | |||
| function sourceOf(file) { | |||
| if (attribution.files[file]) | |||
| return attribution.files[file].source; | |||
| else | |||
| return undefined; | |||
| } | |||
| prepareAttribution(); | |||