Compare commits

...

12 Commits

4 changed files with 128 additions and 49 deletions

View File

@@ -57,7 +57,8 @@
.translationText, .romanizationText { .translationText, .romanizationText {
visibility: hidden; visibility: hidden;
font-family: "Noto Sans"; font-family: "Noto Sans";
font-size:1.2em; /* font-size:1.2em; */
font-size: max(0.8vmax, 16px);
} }
.romanizationText { .romanizationText {
@@ -67,13 +68,11 @@
.languageText { .languageText {
pointer-events: none; pointer-events: none;
font-weight: bold; font-weight: bold;
font-size: 1em; /* font-size: 1em;*/
font-size: max(0.7vmax, 14px);
font-family: sans-serif; font-family: sans-serif;
visibility: hidden; visibility: hidden;
} }
.language:hover ~ .languageText {
visibility: visible;
}
.district { .district {
stroke: white; stroke: white;
@@ -113,10 +112,26 @@
transition: fill-opacity 0.3s; transition: fill-opacity 0.3s;
} }
section#textStuff {
min-width: 30em;
flex: 0 1 0;
}
section#textStuff ul {
font-size: 1.2em;
line-height: 1.5rem;
max-width: 35em;
}
section#textStuff li {
margin: 1em 0;
}
/* Position map load spinner in the middle of the SVG */ /* Position map load spinner in the middle of the SVG */
#svgContainer { #svgContainer {
position: relative; position: relative;
display: inline-block; display: inline-block;
flex-shrink: 1;
flex-grow: 1; flex-grow: 1;
max-width: 100%; max-width: 100%;
} }
@@ -178,7 +193,7 @@
#fetchingText { #fetchingText {
visibility: hidden; visibility: hidden;
} }
@media only screen and (max-width: 768px) { @media only screen and (max-width: 1366px) {
main { main {
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
@@ -186,15 +201,23 @@
.district { .district {
stroke-width: 0.1; stroke-width: 0.1;
} }
/* .translationText, .romanizationText {
font-size: 1em;
}
.languageText {
font-size: 0.8em;
} */
}
/* @media only screen and (max-width: 768px) {
.translationText, .romanizationText { .translationText, .romanizationText {
font-size: 0.7em; font-size: 0.8em;
} }
.languageText { .languageText {
font-size: 0.6em; font-size: 0.6em;
} }
} */
}
</style> </style>
</head> </head>
<body> <body>
@@ -211,6 +234,14 @@
<noscript> <noscript>
<h2>This website requires javascript to work.</h2> <h2>This website requires javascript to work.</h2>
</noscript> </noscript>
<ul>
<li>Enter text in English. Translations are displayed on the map, along with romanizations (translation converted to Latin script).</li>
<li>Hover over a language region (denoted by color) to see the language spoken in the region. Language boundaries were drawn using census data; they may be inaccurate.</li>
<li>Translations are retrieved from Google Translate - they may be innacurate.</li>
<li>Romanizations are made with the <kbd>ai4bharat-transliteration</kbd> AI model, developed by <a href="https://ai4bharat.iitm.ac.in/">Ai4Bharat</a>.</li>
</ul>
</section> </section>
<section id="svgContainer"> <section id="svgContainer">
@@ -220,6 +251,7 @@
<script type="text/javascript" src="index.js"></script> <script type="text/javascript" src="index.js"></script>
<script type="text/javascript" src="updateTranslations.js"></script> <script type="text/javascript" src="updateTranslations.js"></script>
<script type="text/javascript" src="svgHoverListener.js"></script>
</body> </body>

115
index.js
View File

@@ -1,28 +1,28 @@
const defaultColor = "#555555" const defaultColor = "#555555"
const languages = { const languages = {
tamil: {name: "Tamil", color: "#75d795", code: "ta", districts: []}, tamil: {name: "Tamil", color: "#75d795", code: "ta", text_align: "start", districts: []},
malayalam: {name: "Malayalam", color: "#ff7c7c", code: "ml", districts: []}, malayalam: {name: "Malayalam", color: "#ff7c7c", code: "ml", text_align: "end", districts: []},
kannada: {name: "Kannada", color: "#ffe77c", code: "kn", districts: []}, kannada: {name: "Kannada", color: "#ffe77c", code: "kn", text_align: "middle", districts: []},
telugu: {name: "Telugu", color: "#7c9dff", code: "te", districts: []}, telugu: {name: "Telugu", color: "#7c9dff", code: "te", text_align: "middle", districts: []},
marathi: {name: "Marathi", color: "#e0ff7c", code: "mr", districts: []}, marathi: {name: "Marathi", color: "#e0ff7c", code: "mr", text_align: "middle", districts: []},
konkani: {name: "Konkani", color: "#9b7cff", code: "gom", districts: []}, konkani: {name: "Konkani", color: "#9b7cff", code: "gom", text_align: "end", districts: []},
hindi: {name: "Hindi", color: "#d17cff", code: "hi", districts: []}, hindi: {name: "Hindi", color: "#d17cff", code: "hi", text_align: "middle", districts: []},
gujarati: {name: "Gujarati", color: "#7cffee", code: "gu", districts: []}, gujarati: {name: "Gujarati", color: "#7cffee", code: "gu", text_align: "middle", districts: []},
oriya: {name: "Oriya", color: "#9bcc9f", code: "or", districts: []}, oriya: {name: "Oriya", color: "#9bcc9f", code: "or", text_align: "middle", districts: []},
bengali: {name: "Bengali", color: "#bf9a77", code: "bn", districts: []}, bengali: {name: "Bengali", color: "#bf9a77", code: "bn", text_align: "middle", districts: []},
punjabi: {name: "Punjabi", color: "#e84a35", code: "pa", districts: []}, punjabi: {name: "Punjabi", color: "#e84a35", code: "pa", text_align: "middle", districts: []},
mizo: {name: "Mizo", color: "#a6a4de", code: "lus", districts: []}, mizo: {name: "Mizo", color: "#a6a4de", code: "lus", text_align: "middle", districts: []},
assamese: {name: "Assamese", color: "#c9535b", code: "as", districts: []}, assamese: {name: "Assamese", color: "#c9535b", code: "as", text_align: "middle", districts: []},
bhojpuri: {name: "Bhojpuri", color: "#b3b876", code: "bho", districts: []}, bhojpuri: {name: "Bhojpuri", color: "#b3b876", code: "bho", text_align: "end", districts: []},
manipuri: {name: "Manipuri", color: "#c9afad", code: "mni-Mtei", districts: []}, manipuri: {name: "Manipuri", color: "#c9afad", code: "mni-Mtei", text_align: "middle", districts: []},
dogri: {name: "Dogri", color: "#9595e6", code: "doi", districts: []}, dogri: {name: "Dogri", color: "#9595e6", code: "doi", text_align: "middle", districts: []},
nepali: {name: "Nepali", color: "#71998e", code: "ne", districts: []}, nepali: {name: "Nepali", color: "#71998e", code: "ne", text_align: "middle", districts: []},
urdu: {name: "Urdu", color: "#3fa179", code: "ur", districts: []}, urdu: {name: "Urdu", color: "#3fa179", code: "ur", text_align: "middle", districts: []},
tulu: {name: "Tulu", color: "#dedc52", code: "tcy", districts: []}, tulu: {name: "Tulu", color: "#dedc52", code: "tcy", text_align: "end", districts: []},
maithali: {name: "Maithali", color: "#4472a6", code: "mai", districts: []}, maithali: {name: "Maithali", color: "#4472a6", code: "mai", text_align: "middle", districts: []},
sindhi: {name: "Sindhi", color: "#e89931", code: "sd", districts: []}, sindhi: {name: "Sindhi", color: "#e89931", code: "sd", text_align: "middle", districts: []},
awadhi: {name: "Awadhi", color: "#847fb5", code: "awa", districts: []}, awadhi: {name: "Awadhi", color: "#847fb5", code: "awa", text_align: "middle", districts: []},
}; };
// Credit: https://www.artcraftblend.com/blogs/colors/shades-of-pastel // Credit: https://www.artcraftblend.com/blogs/colors/shades-of-pastel
@@ -213,9 +213,14 @@ function stateOrDistrictOrLanguage(d) {
// const mapWidth = document.getElementById("indiaMap").getAttribute("width") // const mapWidth = document.getElementById("indiaMap").getAttribute("width")
// const mapHeight = document.getElementById("indiaMap").getAttribute("height") // const mapHeight = document.getElementById("indiaMap").getAttribute("height")
const mapWidth = /*window.innerWidth - */document.querySelector("#svgContainer").offsetWidth * 0.85; let mapWidth = /*window.innerWidth - */document.querySelector("#svgContainer").offsetWidth * 0.85;
// const mapHeight = document.querySelector("#svgContainer").offsetHeight; // const mapHeight = document.querySelector("#svgContainer").offsetHeight;
const mapHeight = (window.innerHeight - document.querySelector("#svgContainer").getBoundingClientRect().top); let mapHeight = (window.innerHeight - document.querySelector("#svgContainer").getBoundingClientRect().top);
if (window.innerWidth <= 768) {
mapWidth *= 1.5;
mapHeight *= 1.5;
}
const svg = d3.select("#svgContainer") const svg = d3.select("#svgContainer")
.append('svg') .append('svg')
@@ -252,6 +257,11 @@ function drawMap(world) {
states.append("path") states.append("path")
.attr("d", path) .attr("d", path)
.attr("class", d => stateOrDistrictOrLanguage(d)) .attr("class", d => stateOrDistrictOrLanguage(d))
.attr("id", function(d) {
if (stateOrDistrictOrLanguage(d) === "language") {
return languages[d.properties.lang_name.toLowerCase()].code + "langMap";
}
})
.attr("fill", function(d) { .attr("fill", function(d) {
if (stateOrDistrictOrLanguage(d) === "language") { if (stateOrDistrictOrLanguage(d) === "language") {
return languages[d.properties.lang_name.toLowerCase()].color; return languages[d.properties.lang_name.toLowerCase()].color;
@@ -272,7 +282,8 @@ function drawMap(world) {
.append("title") // Tooltip .append("title") // Tooltip
.text(d => d.properties.district); .text(d => d.properties.district);
states.append("text") const textItems = svg.selectAll("g.textItem").data(world.features).enter().append("g");
textItems.append("text")
.attr("x", function(d) { .attr("x", function(d) {
if (stateOrDistrictOrLanguage(d) == "language") { if (stateOrDistrictOrLanguage(d) == "language") {
rtv = projection(d3.geoCentroid(d))[0]; rtv = projection(d3.geoCentroid(d))[0];
@@ -280,7 +291,10 @@ function drawMap(world) {
rtv -= 20; rtv -= 20;
} }
if (d.properties.lang_name == "Tamil") { if (d.properties.lang_name == "Tamil") {
rtv += 20; rtv -= 10;
}
if (d.properties.lang_name == "Kannada" && window.innerWidth <= 768) {
rtv += 15;
} }
if (d.properties.lang_name == "Maithali") { if (d.properties.lang_name == "Maithali") {
rtv += 10; rtv += 10;
@@ -298,10 +312,15 @@ function drawMap(world) {
if (stateOrDistrictOrLanguage(d) == "language") { if (stateOrDistrictOrLanguage(d) == "language") {
rtv = projection(d3.geoCentroid(d))[1] rtv = projection(d3.geoCentroid(d))[1]
if (d.properties.lang_name == "Kannada") { if (d.properties.lang_name == "Kannada") {
rtv += 15; if (window.innerWidth > 768) {
rtv += 10;
}
} }
if (d.properties.lang_name == "Tamil") { if (d.properties.lang_name == "Tamil") {
rtv -= 20; rtv -= 10;
}
if (d.properties.lang_name == "Malayalam") {
rtv += 10;
} }
if (d.properties.lang_name == "Gujarati") { if (d.properties.lang_name == "Gujarati") {
rtv -= 10; rtv -= 10;
@@ -315,12 +334,13 @@ function drawMap(world) {
if (d.properties.lang_name == "Bengali") { if (d.properties.lang_name == "Bengali") {
rtv += 25; rtv += 25;
} }
if (d.properties.lang_name == "Hindi") {
rtv += 5 * parseFloat(getComputedStyle(document.documentElement).fontSize); // 5rem
}
return rtv return rtv
} }
}) })
.attr("text-anchor", "middle")
.attr("fill", "black")
.attr("class", "translationText") .attr("class", "translationText")
.attr("id", function(d) { .attr("id", function(d) {
if (stateOrDistrictOrLanguage(d) == "language") { if (stateOrDistrictOrLanguage(d) == "language") {
@@ -335,18 +355,18 @@ function drawMap(world) {
} else { } else {
d3.select(this).remove() // Only add this attribute if the element is a language d3.select(this).remove() // Only add this attribute if the element is a language
} }
}); })
.attr("text-anchor", d => typeof d.properties.lang_name != "undefined" && languages[d.properties.lang_name.toLowerCase()].text_align)
.attr("fill", "black")
// Romanization // Romanization
states.append("text") textItems.append("text")
.attr("x", d => stateOrDistrictOrLanguage(d) == "language" ? .attr("x", d => stateOrDistrictOrLanguage(d) == "language" ?
document.getElementById(d.properties.lang_code + "Text").getAttribute("x") : document.getElementById(d.properties.lang_code + "Text").getAttribute("x") :
projection(d3.geoCentroid(d))[0]) projection(d3.geoCentroid(d))[0])
.attr("y", d => stateOrDistrictOrLanguage(d) == "language" ? .attr("y", d => stateOrDistrictOrLanguage(d) == "language" ?
parseFloat(document.getElementById(d.properties.lang_code + "Text").getAttribute("y")) + parseFloat(getComputedStyle(document.getElementsByClassName('translationText')[0]).getPropertyValue('font-size')) : parseFloat(document.getElementById(d.properties.lang_code + "Text").getAttribute("y")) + parseFloat(getComputedStyle(document.getElementsByClassName('translationText')[0]).getPropertyValue('font-size')) :
projection(d3.geoCentroid(d))[1]) projection(d3.geoCentroid(d))[1])
.attr("text-anchor", "middle")
.attr("fill", "black")
.attr("class", "romanizationText") .attr("class", "romanizationText")
.attr("id", function(d) { .attr("id", function(d) {
if (stateOrDistrictOrLanguage(d) == "language") { if (stateOrDistrictOrLanguage(d) == "language") {
@@ -359,18 +379,18 @@ function drawMap(world) {
if (!stateOrDistrictOrLanguage(d) == "language") { if (!stateOrDistrictOrLanguage(d) == "language") {
d3.select(this).remove() // Only add this attribute if the element is a language d3.select(this).remove() // Only add this attribute if the element is a language
} }
}); })
.attr("text-anchor", d => typeof d.properties.lang_name != "undefined" && languages[d.properties.lang_name.toLowerCase()].text_align)
.attr("fill", "black")
// Language // Language
states.append("text") textItems.append("text")
.attr("x", d => stateOrDistrictOrLanguage(d) == "language" ? .attr("x", d => stateOrDistrictOrLanguage(d) == "language" ?
document.getElementById(d.properties.lang_code + "Text").getAttribute("x") : document.getElementById(d.properties.lang_code + "Text").getAttribute("x") :
projection(d3.geoCentroid(d))[0]) projection(d3.geoCentroid(d))[0])
.attr("y", d => stateOrDistrictOrLanguage(d) == "language" ? .attr("y", d => stateOrDistrictOrLanguage(d) == "language" ?
parseFloat(document.getElementById(d.properties.lang_code + "Text").getAttribute("y")) - parseFloat(getComputedStyle(document.getElementsByClassName('translationText')[0]).getPropertyValue('font-size')) : parseFloat(document.getElementById(d.properties.lang_code + "Text").getAttribute("y")) - parseFloat(getComputedStyle(document.getElementsByClassName('translationText')[0]).getPropertyValue('font-size')) :
projection(d3.geoCentroid(d))[1]) projection(d3.geoCentroid(d))[1])
.attr("text-anchor", "middle")
.attr("fill", "black")
.attr("class", "languageText") .attr("class", "languageText")
.attr("id", function(d) { .attr("id", function(d) {
if (stateOrDistrictOrLanguage(d) == "language") { if (stateOrDistrictOrLanguage(d) == "language") {
@@ -391,11 +411,30 @@ function drawMap(world) {
d3.select(this).remove() // Only add this attribute if the element is a language d3.select(this).remove() // Only add this attribute if the element is a language
} }
}) })
.attr("text-anchor", d => typeof d.properties.lang_name != "undefined" && languages[d.properties.lang_name.toLowerCase()].text_align)
.attr("fill", "black")
let allLangs = [] let allLangs = []
const coordinates = [77.69916967457782,23.389970772934166]; const coordinates = [77.69916967457782,23.389970772934166];
const [xCoord, yCoord] = projection(coordinates); const [xCoord, yCoord] = projection(coordinates);
// Add a listener to toggle the language display when a language is hovered on the map
document.querySelectorAll(".language").
forEach(function(element) {
element.addEventListener("mouseover", toggleLanguageDisplay);
element.addEventListener("mouseout", toggleLanguageDisplay);
});
// Remove all 'g' elements that have no children (they don't have a language, translation, or romanization). This must mean they accidentally got created when I created the 'textItems' variable
document.querySelectorAll("g").
forEach(function(element) {
if (element.childElementCount == 0) {
element.remove()
}
});
// svg.append("text") // svg.append("text")
// .attr("x", xCoord) // .attr("x", xCoord)
// .attr("y", yCoord) // .attr("y", yCoord)

8
svgHoverListener.js Normal file
View File

@@ -0,0 +1,8 @@
function toggleLanguageDisplay(event) {
if (event.type == "mouseover") {
document.getElementById(this.id.replace(/langMap$/, '') + "Language").style.visibility = "visible";
}
if (event.type == "mouseout") {
document.getElementById(this.id.replace(/langMap$/, '') + "Language").style.visibility = "hidden";
}
}

Binary file not shown.