<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="favicon.png">
<title></title>
<meta name="description" content="" />
<style>
th {
padding: 0 0.25rem;
background: #EEF;
}
td {
padding: 0 0.25rem;
border: 1px solid black;
}
tr:nth-child(2n) {
background: #EEE;
}
form {
margin-bottom: 1.5rem;
}
</style>
</head>
<body>
<div id="container">
<form action="create" method="post">
<div>
Shapefile:
{% for i in shapefiles %}
<div>
<input type="radio" name="shapefile" value="{{i}}" /> {{i}}
</div>
{% endfor %}
</div>
<div>
CSV(s):
{% for i in csvs %}
<div>
<input type="checkbox" name="csv" value="{{i}}" /> {{i}}
</div>
{% endfor %}
</div>
<button type="submit">Submit</button>
</form>
</div>
<script>
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="favicon.png">
<title></title>
<meta name="description" content="" />
<style>
th {
padding: 0 0.25rem;
background: #EEF;
}
td {
padding: 0 0.25rem;
border: 1px solid black;
}
tr:nth-child(2n) {
background: #EEE;
}
form {
margin-bottom: 1.5rem;
}
</style>
</head>
<body>
<div id="container">
<form action="createsvg" method="post">
<input type="text" name="shapefile" value="{{shapefile}}" />
<input type="text" name="csvnames" value="{{csvnames}}" />
<div>
Regions: <input style="width: 40rem;" type="text" oninput="chgRegions(this.value)" value="" name="regions" />
</div>
<div>
ID Column: <input type="text" value="postal" name="idColumn" onchange="chgIdCol()" />
Projection: <input type="text" value="epsg:3857" name="projection" />
</div>
<!--<div>
Other shapefile Columns: <input type="text" value="postal" name="idColumn" onchange="chgIdCol()" />
</div>-->
<div id="colors">
Num Colors: <input type="number" min="1" value="5" name="ncolors" oninput="updateColors()" />
<input type="color" value="#0000FF" name="color1" />
<input type="color" value="#8888FF" name="color2" />
<input type="color" value="#AAAAAA" name="color3" />
<input type="color" value="#FF8888" name="color4" />
<input type="color" value="#FF0000" name="color5" />
</div>
<div id="formulas">
<br />
<hr />
Formula: <textarea cols="40" id="fillFormula" name="fillFormula">EV</textarea>
<br />
<hr />
</div>
<div>
File Name: <input type="text" value="" name="name" />
</div>
<button type="submit">Submit</button>
</form>
<button onclick="showOutput()">Show Output</button><button onclick="hideOutput()">Hide Output</button>
<div id="shapefile">
<button onclick="selectBox('all');">Select All</button><button onclick="selectBox('none');">Unselect All</button>
<table>
<thead>
{% for row in head %}
<tr><th>Use?</th>{% for i in row %}<th>{{i}}</th>{% endfor %}</tr>
{% endfor %}
</thead>
<tbody>
{% for row in body %}
<tr id="row-{{loop.index}}"><td><input type="checkbox" onchange="selectBox({{loop.index}},this.checked);" /></td>{% for i in row %}<td>{{i}}</td>{% endfor %}</tr>
{% endfor %}
</tbody>
</table>
</div>
{% for i in csvs %}
<div id="csv{{i}}" style="display: none;">
<table>
<thead>
{% for row in csvs[i].head %}
<tr>{% for ii in row %}<th>{{ii}}</th>{% endfor %}</tr>
{% endfor %}
</thead>
<tbody>
{% for row in csvs[i].body %}
<tr id="csv{{i}}-row-{{loop.index}}">{% for ii in row %}<td>{{ii}}</td>{% endfor %}</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
<div id="output" style="display: none;">
<table>
<thead>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<script>
var rows = document.querySelectorAll('#shapefile tbody tr');
var regions = [];
var regionIdx = 5;
chgIdCol();
function selectBox(id,checked){
if (id == "all"){
regions = [];
rows.forEach((el) => {
el.querySelector('td input').checked = true;
var name = el.querySelectorAll('td')[regionIdx].textContent.trim();
regions.push(name);
})
document.querySelector('[name=regions]').value = regions.join(", ");
return;
}
else if (id == "none"){
rows.forEach((el) => {
el.querySelector('td input').checked = false;
})
regions = [];
document.querySelector('[name=regions]').value = "";
return;
}
var el = document.getElementById('row-'+id);
var name = el.querySelectorAll('td')[regionIdx].textContent.trim();
if (checked){
regions.push(name);
}
else {
for (var i=0;i<regions.length;i++){
if (regions[i] == name){
regions.splice(i,1);
break;
}
}
}
document.querySelector('[name=regions]').value = regions.join(", ");
}
function chgIdCol() {
var val = document.querySelector('[name=idColumn]').value;
var heads = document.querySelectorAll('th');
var idx = 0;
var newIdx = -1;
heads.forEach((el) => {
if (el.textContent.trim() == val){
newIdx = idx;
}
idx++;
})
if (newIdx > 0){
regionIdx = newIdx;
}
else {
return;
}
regions = [];
rows.forEach((el) => {
var name = el.querySelectorAll('td')[regionIdx].textContent.trim();
if (el.querySelector('td input').checked){
regions.push(name);
}
})
document.querySelector('[name=regions]').value = regions.join(", ");
}
function chgRegions(str){
var regionsSplit = str.split(",");
regions = [];
for (var i=0;i<regionsSplit.length;i++){
regions.push(regionsSplit[i].trim())
}
console.log(regions);
rows.forEach((el) => {
var name = el.querySelectorAll('td')[regionIdx].textContent.trim();
if (inArray(name,regions)){
el.querySelector('td input').checked = true;
}
else {
el.querySelector('td input').checked = false;
}
})
}
function inArray(x,arr){
for (var i=0;i<arr.length;i++){
if (x == arr[i]){return true;}
}
return false;
}
var allData = {};
allData['shapefile']={"head":[],"body":[]};
{% for row in head %}
{% for i in row %}
allData['shapefile']["head"].push("{{i}}");
{% endfor %}
{% endfor %}
{% for row in body %}
allData['shapefile']["body"].push([]);
{% for i in row %}
allData['shapefile']["body"][allData['shapefile']["body"].length-1].push("{{i}}");
{% endfor %}
{% endfor %}
{% for ii in csvs %}
allData["csv{{ii}}"]={};
{% for row in csvs[ii].head %}
allData["csv{{ii}}"]["head"]=[];
{% for i in row %}
allData["csv{{ii}}"]["head"].push("{{i}}");
{% endfor %}
{% endfor %}
{% for row in csvs[ii].body %}
allData["csv{{ii}}"]["{{row[0]}}"]=[];
{% for i in row %}
allData["csv{{ii}}"]["{{row[0]}}"].push("{{i}}");
{% endfor %}
{% endfor %}
{% endfor %}
function showOutput(){
var thead = document.getElementById('output').querySelector('thead');
var tbody = document.getElementById('output').querySelector('tbody');
thead.innerHTML = "";
tbody.innerHTML = "";
var head = ["id"];
var tr = document.createElement('tr');
for (var ii=0;ii<allData["csv0"]["head"].length;ii++){
head.push(allData["csv0"]["head"][ii]);
var td = document.createElement('td');
td.textContent = allData["csv0"]["head"][ii];
tr.appendChild(td);
}
thead.appendChild(tr);
var rows = [];
for (var i=0;i<allData['shapefile']['body'].length;i++){
var row = [];
var id = allData['shapefile']['body'][i][regionIdx-1];
row.push(id);
if (id && allData["csv0"][id]){
var tr = document.createElement('tr');
for (var ii=0;ii<allData["csv0"][id].length;ii++){
var td = document.createElement('td');
td.textContent = allData["csv0"][id][ii];
row.push(allData["csv0"][id][ii]);
tr.appendChild(td);
}
tbody.appendChild(tr);
}
rows.push(row);
}
console.log(head);
console.log(rows);
document.getElementById('output').style.display = "block";
document.getElementById('shapefile').style.display = "none";
}
function hideOutput() {
document.getElementById('shapefile').style.display = "block";
document.getElementById('output').style.display = "none";
}
function updateColors() {
var ncolors = parseInt(document.querySelector('input[name=ncolors]').value);
var els = document.querySelectorAll('#colors input[type=color]');
if (els.length < ncolors){
var div = document.getElementById('colors');
for (var i=els.length;i<ncolors;i++){
var input = document.createElement('input');
input.setAttribute('type','color');
input.setAttribute('value','#FFFFFF');
input.setAttribute('name','color'+(i+1));
div.appendChild(input);
}
}
for (var i=0;i<els.length;i++){
if (i >= ncolors){
els[i].style.display = "none";
}
else {
els[i].style.display = "inline";
}
}
document.querySelector('input[name=ncolors]').value = ncolors;
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="favicon.png">
<title></title>
<meta name="description" content="" />
<style>
#container {
position: relative;
--gs: 1;
}
#container > svg {
position: absolute;
left: 16px;
top: 100px;
}
#vbTop {
display: inline-block;
position: absolute;
left: 16px;
height: 16px;
width: calc(743.52px);
background: blue;
}
#vbLeft {
display: inline-block;
position: absolute;
top: 100px;
width: 16px;
height: 600px;
background: blue;
}
#vbBottom {
display: inline-block;
position: absolute;
left: 16px;
height: 16px;
width: calc(743.52px);
background: blue;
}
#vbRight {
display: inline-block;
position: absolute;
top: 100px;
width: 16px;
height: 600px;
background: blue;
}
</style>
</head>
<body>
<div style="border: 1px solid red; background: #FEE;">
This page is an example of what you might create. Visit the /create url (<a href="./addfiles">this link might work</a>) to create a different map.
</div>
<div id="container">
<div id="menu">
Left: <input style="width: 5rem;" type="text" id="left" value="0" />
Right: <input style="width: 5rem;" type="text" id="right" value="123.92" />
Top: <input style="width: 5rem;" type="text" id="top" value="0" />
Bottom: <input style="width: 5rem;" type="text" id="bottom" value="100" />
<button onclick="updateVB()">Update</button>
<div>
<button onclick="copySVG()">Copy SVG</button>
<button onclick="downloadSVG()">Download SVG</button>
<!--Label Size: <input type="range" oninput="svg.style.setProperty('--fs',0.5*Math.pow(10,(this.value-10)/10)+'rem');" id="labelSize" min="0" max="20" value="10">
<button onclick="toggleMoveLabel()">Move Label(s)</button>-->
Region Size: <input type="range" oninput="setRegionSize(Math.pow(10,(this.value-50)/50));" id="regionSize" min="0" max="100" value="50">
Stroke Width: <input type="range" oninput="svg.style.setProperty('--sw',3*Math.pow(10,(this.value-10)/10));" id="strokeWidth" min="0" max="20" value="10">
</div>
<div>
<button onclick="duplicateRegion()">Duplicate</button>
<button onclick="deleteRegion()">Delete</button>
<!--Hover Box:
Key Box:
Table Box:-->
<button onclick="clearSelection()">Unselect Region</button>
</div>
</div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox='0 0 123.92 100' style="--fs:0.5rem; --sw: 3;" width='743.52px' height='600px'>
<style>
.interior {
stroke-width: calc(var(--sw) / var(--gs));
}
.selected path {
stroke-dasharray: 2 1 1 1;
}
.outline {
stroke-width: calc(1.5 * var(--sw) / var(--gs));
stroke: black;
fill: none;
}
text {
fill: white;
stroke: none;
font-size: calc(var(--fs) / var(--gs));
pointer-events: none;
cursor: pointer;
}
</style>
<clipPath id="clip-MN">
<path d="M 93.8 59.83 93.49 59.92 93.5 60.87 93.47 60.87 93.18 61.05 92.93 61.21 92.76 61.52 93.01 61.83 92.92 62.25 92.92 62.69 92.88 63.05 93.22 63.37 93.36 63.38 93.74 63.62 93.87 63.73 93.95 63.9 94.24 64.18 94.64 64.42 94.68 64.55 94.68 64.94 94.71 65.12 93.18 65.09 91.48 65.1 89.9 65.12 88.63 65.12 88.65 63.61 88.51 62.04 88.3 61.91 88.19 61.65 88.25 61.43 88.51 61.24 88.53 61.0 88.53 60.69 88.46 60.44 88.36 60.16 88.3 59.82 88.29 59.43 88.25 59.34 88.2 58.84 88.2 58.61 88.18 58.4 88.12 58.05 87.98 57.69 87.84 57.38 87.82 57.06 87.81 56.71 87.85 56.49 87.85 56.29 87.75 56.03 87.73 55.86 90.14 55.86 90.14 55.17 90.53 55.17 90.74 56.14 91.1 56.44 91.91 56.55 93.1 56.83 94.23 57.37 95.17 57.14 96.6 57.6 95.42 58.17 94.59 58.86 93.8 59.58 93.8 59.83" />
</clipPath>
<clipPath id="clip-MT">
<path d="M 65.83 55.86 69.31 55.86 72.79 55.85 76.26 55.85 79.74 55.85 79.76 59.04 79.82 61.1 79.76 62.62 77.82 62.6 75.72 62.61 73.91 62.59 71.62 62.6 71.63 63.44 71.61 63.5 71.48 63.41 71.37 63.18 71.24 63.13 71.08 63.46 70.81 63.51 70.15 63.41 70.12 63.57 69.74 63.51 69.53 63.73 69.32 63.31 69.18 63.07 68.94 63.03 68.87 62.91 68.79 62.48 68.59 62.28 68.46 61.75 68.32 61.52 68.17 61.48 68.06 61.71 67.83 61.91 67.62 61.75 67.61 61.32 67.74 61.21 67.64 60.78 67.76 60.34 67.88 59.96 67.53 59.95 67.23 59.7 66.91 59.17 66.72 58.91 66.45 58.75 66.23 58.47 66.23 58.16 65.93 57.7 65.83 55.86" />
</clipPath>
<clipPath id="clip-ND">
<path d="M 87.73 55.86 87.75 56.03 87.85 56.29 87.85 56.49 87.81 56.71 87.82 57.06 87.84 57.38 87.98 57.69 88.12 58.05 88.18 58.4 88.2 58.61 88.2 58.84 88.25 59.34 88.29 59.43 88.3 59.82 88.36 60.16 88.46 60.44 88.53 60.69 88.53 61.0 86.32 61.09 84.43 61.08 82.04 61.09 79.82 61.1 79.76 59.04 79.74 55.85 83.77 55.85 87.73 55.86" />
</clipPath>
<clipPath id="clip-HI">
<path d="M 19.43 98.84 19.46 98.5 19.27 98.05 19.32 97.91 19.53 97.71 19.45 97.47 19.51 97.35 19.6 97.37 20.05 97.58 20.25 97.69 20.44 97.86 20.74 98.29 20.71 98.36 20.26 98.62 19.88 98.81 19.71 99.02 19.43 98.84" />
<path d="M 19.36 96.73 19.26 96.88 18.87 96.97 18.67 96.71 18.54 96.61 18.53 96.53 18.64 96.42 19.05 96.54 19.36 96.73" />
<path d="M 16.88 96.05 16.73 95.77 16.68 95.72 17.0 95.54 17.09 95.62 17.43 96.04 17.37 96.11 17.28 96.09 16.88 96.05" />
<path d="M 14.93 95.11 14.99 95.02 15.17 94.89 15.44 94.92 15.46 95.21 15.32 95.34 14.93 95.11" />
<path d="M 18.47 96.22 18.43 96.35 17.81 96.32 17.9 96.17 18.47 96.22" />
</clipPath>
<clipPath id="clip-ID">
<path d="M 65.83 55.86 65.93 57.7 66.23 58.16 66.23 58.47 66.45 58.75 66.72 58.91 66.91 59.17 67.23 59.7 67.53 59.95 67.88 59.96 67.76 60.34 67.64 60.78 67.74 61.21 67.61 61.32 67.62 61.75 67.83 61.91 68.06 61.71 68.17 61.48 68.32 61.52 68.46 61.75 68.59 62.28 68.79 62.48 68.87 62.91 68.94 63.03 69.18 63.07 69.32 63.31 69.53 63.73 69.74 63.51 70.12 63.57 70.15 63.41 70.81 63.51 71.08 63.46 71.24 63.13 71.37 63.18 71.48 63.41 71.61 63.5 71.65 63.52 71.65 67.5 68.18 67.51 64.69 67.5 64.71 64.65 64.81 64.19 64.72 63.98 64.5 63.87 64.5 63.61 64.67 63.23 64.92 62.91 65.08 62.38 65.24 61.95 65.36 61.74 65.29 61.48 65.1 61.35 64.82 61.03 64.83 60.73 64.73 60.47 64.69 58.09 64.69 55.86 65.83 55.86" />
</clipPath>
<clipPath id="clip-WA">
<path d="M 64.69 55.86 64.69 58.09 64.73 60.47 64.83 60.73 64.82 61.03 62.42 61.04 62.01 61.21 61.71 61.14 61.48 61.28 61.05 61.46 60.53 61.44 60.26 61.57 60.02 61.63 59.83 61.54 59.42 61.47 59.16 61.53 58.71 61.7 58.42 61.71 58.15 61.64 58.06 61.41 58.03 61.13 57.82 60.81 57.48 60.71 57.2 60.56 56.84 60.55 56.58 60.55 56.49 59.57 56.12 58.1 55.78 57.29 55.92 56.95 57.61 57.54 58.23 59.17 58.51 58.72 58.33 57.3 57.93 55.86 61.23 55.86 64.69 55.86" />
</clipPath>
<clipPath id="clip-AZ">
<path d="M 73.98 75.04 73.98 83.01 71.68 83.02 69.02 82.05 67.27 81.38 67.38 81.11 67.53 81.12 67.66 80.84 67.45 80.65 67.41 80.44 67.35 80.2 67.58 79.88 67.67 79.24 68.02 78.95 67.8 78.68 67.65 78.41 67.56 78.16 67.49 77.97 67.47 77.85 67.54 77.57 67.48 77.29 67.46 77.01 67.46 76.7 67.36 76.5 67.43 76.33 67.68 76.33 67.9 76.43 68.06 76.49 68.14 76.27 68.19 76.22 68.18 75.05 70.06 75.03 72.29 75.03 73.98 75.04" />
</clipPath>
<clipPath id="clip-CA">
<path d="M 67.47 77.85 67.49 77.97 67.56 78.16 67.65 78.41 67.8 78.68 68.02 78.95 67.67 79.24 67.58 79.88 67.35 80.2 67.41 80.44 67.45 80.65 67.66 80.84 67.53 81.12 67.38 81.11 65.9 81.26 64.58 81.37 64.38 80.66 63.63 79.86 63.08 79.7 62.96 79.29 62.3 79.22 61.89 78.84 60.81 78.7 60.51 78.48 60.37 77.7 59.24 76.26 58.27 74.24 58.31 73.9 57.8 73.41 56.9 72.16 56.74 70.94 56.12 70.11 56.37 68.83 56.33 67.5 61.24 67.51 61.24 72.1 63.43 74.1 65.52 76.03 67.47 77.85" />
</clipPath>
<clipPath id="clip-CO">
<path d="M 82.12 70.58 82.13 72.9 82.13 75.06 81.01 75.05 79.62 75.05 77.64 75.05 75.8 75.04 73.98 75.04 73.97 69.05 75.14 69.05 76.3 69.05 78.63 69.05 79.8 69.05 82.12 69.05 82.12 70.53 82.12 70.58" />
</clipPath>
<clipPath id="clip-NV">
<path d="M 64.69 67.5 68.18 67.51 68.18 75.05 68.19 76.22 68.14 76.27 68.06 76.49 67.9 76.43 67.68 76.33 67.43 76.33 67.36 76.5 67.46 76.7 67.46 77.01 67.48 77.29 67.54 77.57 67.47 77.85 65.52 76.03 63.43 74.1 61.24 72.1 61.24 67.51 64.69 67.5" />
</clipPath>
<clipPath id="clip-NM">
<path d="M 73.98 83.01 73.98 75.04 75.8 75.04 77.64 75.05 79.62 75.05 81.01 75.05 81.01 75.77 81.01 79.5 81.01 82.11 79.93 82.11 77.84 82.11 76.79 82.11 76.8 82.22 76.93 82.44 74.92 82.44 74.91 83.01 73.98 83.01" />
</clipPath>
<clipPath id="clip-OR">
<path d="M 64.82 61.03 65.1 61.35 65.29 61.48 65.36 61.74 65.24 61.95 65.08 62.38 64.92 62.91 64.67 63.23 64.5 63.61 64.5 63.87 64.72 63.98 64.81 64.19 64.71 64.65 64.69 67.5 61.24 67.51 56.33 67.5 55.96 66.29 56.42 64.79 56.7 61.82 56.58 60.55 56.84 60.55 57.2 60.56 57.48 60.71 57.82 60.81 58.03 61.13 58.06 61.41 58.15 61.64 58.42 61.71 58.71 61.7 59.16 61.53 59.42 61.47 59.83 61.54 60.02 61.63 60.26 61.57 60.53 61.44 61.05 61.46 61.48 61.28 61.71 61.14 62.01 61.21 62.42 61.04 64.82 61.03" />
</clipPath>
<clipPath id="clip-UT">
<path d="M 68.18 67.51 71.65 67.5 71.64 69.01 73.97 69.05 73.98 75.04 72.29 75.03 70.06 75.03 68.18 75.05 68.18 67.51" />
</clipPath>
<clipPath id="clip-WY">
<path d="M 71.61 63.5 71.63 63.44 71.62 62.6 73.91 62.59 75.72 62.61 77.82 62.6 79.76 62.62 79.79 65.92 79.8 69.05 78.63 69.05 76.3 69.05 75.14 69.05 73.97 69.05 71.64 69.01 71.65 67.5 71.65 63.52 71.61 63.5" />
</clipPath>
<clipPath id="clip-AR">
<path d="M 96.53 76.46 96.52 76.58 96.4 76.78 96.2 76.92 96.15 77.16 95.97 77.34 95.98 77.76 95.85 77.89 95.83 78.0 95.62 78.11 95.61 78.31 95.46 78.69 95.32 78.77 95.12 78.96 95.0 79.25 94.74 79.74 94.71 80.07 94.85 80.44 94.79 80.71 93.81 80.67 92.54 80.71 91.41 80.71 91.48 79.92 91.21 79.92 90.99 79.93 90.93 79.84 90.96 78.61 90.98 77.23 90.75 75.71 92.17 75.73 93.45 75.74 94.68 75.74 96.01 75.83 96.1 76.0 95.97 76.16 95.84 76.32 95.77 76.46 96.53 76.46" />
</clipPath>
<clipPath id="clip-IA">
<path d="M 88.63 65.12 89.9 65.12 91.48 65.1 93.18 65.09 94.71 65.12 94.73 65.21 94.88 65.46 94.77 65.58 94.78 65.92 94.82 66.06 94.9 66.31 95.28 66.46 95.39 66.71 95.46 66.83 95.6 66.91 95.65 67.08 95.84 67.2 95.96 67.34 95.89 67.76 95.68 68.11 95.6 68.22 95.33 68.31 94.94 68.39 94.83 68.66 94.98 68.78 95.03 69.01 94.87 69.28 94.8 69.51 94.5 69.74 94.47 70.02 94.31 69.89 94.09 69.65 92.82 69.68 91.48 69.69 90.44 69.69 89.39 69.69 89.32 69.41 89.35 69.14 89.33 68.87 89.21 68.43 89.13 68.24 89.04 68.19 89.04 67.83 88.96 67.57 88.75 67.28 88.75 67.15 88.68 66.89 88.63 66.73 88.63 66.59 88.44 66.41 88.53 66.15 88.6 65.9 88.62 65.72 88.47 65.51 88.48 65.12 88.63 65.12" />
</clipPath>
<clipPath id="clip-KS">
<path d="M 82.13 75.06 82.13 72.9 82.12 70.58 84.15 70.58 85.67 70.58 88.34 70.58 89.95 70.58 90.22 70.78 90.37 70.78 90.41 71.0 90.24 71.28 90.33 71.42 90.47 71.74 90.78 71.88 90.77 73.48 90.76 75.04 89.74 75.05 87.65 75.05 85.55 75.05 84.39 75.05 83.22 75.05 82.13 75.06" />
</clipPath>
<clipPath id="clip-MO">
<path d="M 96.53 76.46 95.77 76.46 95.84 76.32 95.97 76.16 96.1 76.0 96.01 75.83 94.68 75.74 93.45 75.74 92.17 75.73 90.75 75.71 90.77 75.04 90.76 75.04 90.77 73.48 90.78 71.88 90.47 71.74 90.33 71.42 90.24 71.28 90.41 71.0 90.37 70.78 90.22 70.78 89.95 70.58 89.79 70.26 89.61 70.06 89.42 69.82 89.39 69.69 90.44 69.69 91.48 69.69 92.82 69.68 94.09 69.65 94.31 69.89 94.47 70.02 94.37 70.4 94.48 70.85 94.67 71.17 94.89 71.42 95.16 71.62 95.27 71.69 95.36 71.98 95.38 72.23 95.52 72.29 95.73 72.2 95.96 72.44 95.89 72.71 95.78 72.93 95.71 73.19 95.87 73.41 96.1 73.62 96.23 73.62 96.54 73.95 96.66 73.99 96.74 74.35 96.7 74.57 96.85 74.93 96.98 74.89 97.18 75.11 97.15 75.26 97.17 75.49 96.98 75.61 96.72 75.76 96.69 75.9 96.62 76.11 96.53 76.46" />
</clipPath>
<clipPath id="clip-NE">
<path d="M 82.12 70.58 82.12 70.53 82.12 69.05 79.8 69.05 79.79 65.92 82.06 65.92 83.81 65.92 86.14 65.92 86.44 66.12 86.87 66.25 86.97 66.18 87.24 66.18 87.66 66.17 87.96 66.37 88.28 66.5 88.33 66.63 88.43 66.71 88.63 66.73 88.68 66.89 88.75 67.15 88.75 67.28 88.96 67.57 89.04 67.83 89.04 68.19 89.13 68.24 89.21 68.43 89.33 68.87 89.35 69.14 89.32 69.41 89.39 69.69 89.42 69.82 89.61 70.06 89.79 70.26 89.95 70.58 88.34 70.58 85.67 70.58 84.15 70.58 82.12 70.58" />
</clipPath>
<clipPath id="clip-OK">
<path d="M 81.01 75.05 82.13 75.06 83.22 75.05 84.39 75.05 85.55 75.05 87.65 75.05 89.74 75.05 90.76 75.04 90.77 75.04 90.75 75.71 90.98 77.23 90.96 78.61 90.93 79.84 90.43 79.57 90.1 79.42 89.83 79.51 89.43 79.5 89.18 79.5 88.98 79.62 88.79 79.67 88.62 79.61 88.23 79.68 88.05 79.45 87.87 79.65 87.56 79.56 87.23 79.34 86.88 79.48 86.73 79.14 86.19 79.18 85.84 79.1 85.45 79.0 85.28 78.71 84.97 78.8 84.78 78.69 84.5 78.54 84.5 77.18 84.5 75.77 83.34 75.77 82.18 75.77 81.01 75.77 81.01 75.05" />
</clipPath>
<clipPath id="clip-SD">
<path d="M 88.53 61.0 88.51 61.24 88.25 61.43 88.19 61.65 88.3 61.91 88.51 62.04 88.65 63.61 88.63 65.12 88.48 65.12 88.47 65.51 88.62 65.72 88.6 65.9 88.53 66.15 88.44 66.41 88.63 66.59 88.63 66.73 88.43 66.71 88.33 66.63 88.28 66.5 87.96 66.37 87.66 66.17 87.24 66.18 86.97 66.18 86.87 66.25 86.44 66.12 86.14 65.92 83.81 65.92 82.06 65.92 79.79 65.92 79.76 62.62 79.82 61.1 82.04 61.09 84.43 61.08 86.32 61.09 88.53 61.0" />
</clipPath>
<clipPath id="clip-LA">
<path d="M 91.41 80.71 92.54 80.71 93.81 80.67 94.79 80.71 94.88 80.79 94.77 80.99 94.94 81.28 94.89 81.45 95.04 81.69 94.88 81.83 94.83 82.09 94.6 82.3 94.5 82.59 94.39 82.92 94.25 83.07 94.3 83.41 95.32 83.45 96.42 83.45 96.39 83.68 96.31 83.9 96.38 84.07 96.54 84.23 96.58 84.45 96.6 84.58 96.61 84.61 96.82 84.96 96.8 85.51 97.05 85.77 96.83 85.95 96.39 85.75 95.96 86.0 95.11 85.96 94.25 85.26 93.23 85.42 92.38 85.11 91.66 85.21 91.58 85.06 91.7 84.86 91.87 84.69 91.87 84.42 91.79 84.33 91.89 84.01 91.97 83.86 92.08 83.36 91.98 83.18 91.84 82.87 91.74 82.55 91.68 82.34 91.49 82.19 91.41 80.71" />
</clipPath>
<clipPath id="clip-TX">
<path d="M 76.93 82.44 76.8 82.22 76.79 82.11 77.84 82.11 79.93 82.11 81.01 82.11 81.01 79.5 81.01 75.77 82.18 75.77 83.34 75.77 84.5 75.77 84.5 77.18 84.5 78.54 84.78 78.69 84.97 78.8 85.28 78.71 85.45 79.0 85.84 79.1 86.19 79.18 86.73 79.14 86.88 79.48 87.23 79.34 87.56 79.56 87.87 79.65 88.05 79.45 88.23 79.68 88.62 79.61 88.79 79.67 88.98 79.62 89.18 79.5 89.43 79.5 89.83 79.51 90.1 79.42 90.43 79.57 90.93 79.84 90.99 79.93 91.21 79.92 91.48 79.92 91.41 80.71 91.49 82.19 91.68 82.34 91.74 82.55 91.84 82.87 91.98 83.18 92.08 83.36 91.97 83.86 91.89 84.01 91.79 84.33 91.87 84.42 91.87 84.69 91.7 84.86 91.58 85.06 91.66 85.21 90.68 85.52 89.62 86.51 88.47 87.08 87.83 87.71 87.56 88.3 87.55 89.2 87.61 89.82 87.83 90.26 87.38 90.3 86.55 90.02 85.64 89.61 85.32 89.0 85.06 88.09 84.38 87.34 83.97 86.56 83.39 85.65 82.57 85.12 81.62 85.14 80.89 86.2 79.92 85.8 79.32 85.4 79.03 84.66 78.64 83.95 77.95 83.36 77.36 82.93 76.93 82.44" />
</clipPath>
<clipPath id="clip-CT">
<path d="M 115.34 67.41 116.23 67.44 117.31 67.48 117.32 68.33 117.25 68.56 116.74 68.64 116.06 68.71 115.16 69.13 115.16 69.12 115.15 69.08 115.11 68.89 115.36 68.74 115.27 68.61 115.34 67.41" />
</clipPath>
<clipPath id="clip-MA">
<path d="M 117.31 67.48 116.23 67.44 115.34 67.41 115.59 66.33 116.55 66.35 117.95 66.37 118.07 66.21 118.32 66.11 118.46 66.14 118.45 66.97 118.83 67.8 119.31 67.84 119.19 67.27 119.54 67.62 119.45 68.07 118.66 68.32 118.1 68.29 118.07 68.05 117.89 67.87 117.8 67.46 117.31 67.48" />
</clipPath>
<clipPath id="clip-NH">
<path d="M 118.46 66.14 118.32 66.11 118.07 66.21 117.95 66.37 116.55 66.35 116.45 66.19 116.55 65.98 116.57 65.57 116.61 65.47 116.65 65.09 116.78 64.77 116.87 64.63 117.01 64.24 117.04 63.98 117.08 63.82 117.3 63.75 117.56 63.56 117.61 63.35 117.52 63.12 117.66 62.67 117.77 62.27 118.14 62.18 118.31 65.18 118.26 65.33 118.48 65.57 118.53 65.79 118.66 65.78 118.46 66.14" />
</clipPath>
<clipPath id="clip-RI">
<path d="M 117.25 68.56 117.32 68.33 117.31 67.48 117.8 67.46 117.89 67.87 118.07 68.05 118.1 68.29 117.25 68.56" />
</clipPath>
<clipPath id="clip-VT">
<path d="M 116.55 66.35 115.59 66.33 115.64 65.01 115.47 65.0 115.45 64.94 115.52 64.71 115.42 64.29 115.53 63.95 115.47 63.7 115.44 63.22 115.49 63.01 115.51 62.67 117.66 62.67 117.52 63.12 117.61 63.35 117.56 63.56 117.3 63.75 117.08 63.82 117.04 63.98 117.01 64.24 116.87 64.63 116.78 64.77 116.65 65.09 116.61 65.47 116.57 65.57 116.55 65.98 116.45 66.19 116.55 66.35" />
</clipPath>
<clipPath id="clip-AL">
<path d="M 98.27 77.92 99.73 77.92 101.23 77.94 101.53 79.69 101.8 81.07 101.97 81.5 102.07 81.75 101.88 81.99 101.82 82.43 101.88 82.69 101.85 82.93 101.82 83.15 101.89 83.32 101.95 83.48 99.58 83.49 98.91 83.57 98.89 83.67 99.16 84.0 99.1 84.27 99.01 84.45 97.98 84.3 97.94 82.23 98.15 80.02 98.35 78.2 98.27 77.92" />
</clipPath>
<clipPath id="clip-FL">
<path d="M 99.01 84.45 99.1 84.27 99.16 84.0 98.89 83.67 98.91 83.57 99.58 83.49 101.95 83.48 102.13 83.85 103.3 83.91 105.18 84.11 105.27 84.35 105.42 84.23 105.42 83.76 105.56 83.71 105.79 83.81 106.04 83.84 106.24 84.77 106.63 85.92 107.15 86.86 107.16 87.43 107.71 88.95 107.67 89.83 107.62 90.33 107.33 91.12 106.98 91.28 106.41 91.12 106.22 90.56 105.78 90.26 105.17 89.15 104.63 88.15 104.45 87.63 104.69 86.76 104.36 86.03 103.46 84.91 103.0 84.7 101.83 85.31 101.62 85.24 101.06 84.62 100.33 84.28 99.01 84.45" />
</clipPath>
<clipPath id="clip-GA">
<path d="M 101.95 83.48 101.89 83.32 101.82 83.15 101.85 82.93 101.88 82.69 101.82 82.43 101.88 81.99 102.07 81.75 101.97 81.5 101.8 81.07 101.53 79.69 101.23 77.94 102.12 77.95 102.75 77.94 104.19 77.95 104.07 78.07 103.88 78.34 104.19 78.57 104.4 78.66 104.61 79.1 104.75 79.35 105.16 79.68 105.24 79.86 105.51 80.09 105.65 80.42 106.02 80.7 106.1 81.01 106.17 81.17 106.13 81.27 106.35 81.42 106.46 81.68 106.46 81.94 106.57 81.99 106.77 82.06 106.22 82.87 106.04 83.84 105.79 83.81 105.56 83.71 105.42 83.76 105.42 84.23 105.27 84.35 105.18 84.11 103.3 83.91 102.13 83.85 101.95 83.48" />
</clipPath>
<clipPath id="clip-MS">
<path d="M 94.79 80.71 94.85 80.44 94.71 80.07 94.74 79.74 95.0 79.25 95.12 78.96 95.32 78.77 95.46 78.69 95.61 78.31 95.62 78.11 95.83 78.0 95.85 77.89 96.99 77.89 98.27 77.92 98.35 78.2 98.15 80.02 97.94 82.23 97.98 84.3 97.09 84.4 96.61 84.61 96.6 84.58 96.58 84.45 96.54 84.23 96.38 84.07 96.31 83.9 96.39 83.68 96.42 83.45 95.32 83.45 94.3 83.41 94.25 83.07 94.39 82.92 94.5 82.59 94.6 82.3 94.83 82.09 94.88 81.83 95.04 81.69 94.89 81.45 94.94 81.28 94.77 80.99 94.88 80.79 94.79 80.71" />
</clipPath>
<clipPath id="clip-SC">
<path d="M 106.77 82.06 106.57 81.99 106.46 81.94 106.46 81.68 106.35 81.42 106.13 81.27 106.17 81.17 106.1 81.01 106.02 80.7 105.65 80.42 105.51 80.09 105.24 79.86 105.16 79.68 104.75 79.35 104.61 79.1 104.4 78.66 104.19 78.57 103.88 78.34 104.07 78.07 104.19 77.95 104.31 77.91 104.94 77.66 106.01 77.68 106.56 77.74 106.56 77.87 106.68 77.77 106.86 78.01 106.86 78.18 108.15 78.19 109.45 79.53 108.87 80.04 108.7 80.51 107.42 81.41 106.77 82.06" />
</clipPath>
<clipPath id="clip-IL">
<path d="M 94.47 70.02 94.5 69.74 94.8 69.51 94.87 69.28 95.03 69.01 94.98 68.78 94.83 68.66 94.94 68.39 95.33 68.31 95.6 68.22 95.68 68.11 95.89 67.76 95.96 67.34 95.84 67.2 95.65 67.08 95.6 66.91 95.46 66.83 95.39 66.71 96.58 66.71 97.79 66.71 98.69 66.72 98.7 67.13 99.02 67.95 99.02 67.96 99.02 69.74 99.01 71.5 98.88 71.92 98.98 72.03 99.04 72.29 99.03 72.49 98.93 72.58 98.85 72.82 98.61 73.15 98.44 73.55 98.41 73.84 98.41 73.95 98.28 74.16 98.38 74.3 98.18 74.4 97.91 74.53 97.96 74.85 97.81 74.97 97.53 74.83 97.22 74.75 97.14 74.89 97.18 75.11 96.98 74.89 96.85 74.93 96.7 74.57 96.74 74.35 96.66 73.99 96.54 73.95 96.23 73.62 96.1 73.62 95.87 73.41 95.71 73.19 95.78 72.93 95.89 72.71 95.96 72.44 95.73 72.2 95.52 72.29 95.38 72.23 95.36 71.98 95.27 71.69 95.16 71.62 94.89 71.42 94.67 71.17 94.48 70.85 94.37 70.4 94.47 70.02" />
</clipPath>
<clipPath id="clip-IN">
<path d="M 98.41 73.84 98.44 73.55 98.61 73.15 98.85 72.82 98.93 72.58 99.03 72.49 99.04 72.29 98.98 72.03 98.88 71.92 99.01 71.5 99.02 69.74 99.02 67.96 99.12 68.06 99.52 68.05 99.83 67.88 101.08 67.89 102.18 67.88 102.18 68.0 102.18 69.4 102.17 70.89 102.16 71.93 102.09 72.0 102.19 72.31 102.14 72.42 101.94 72.42 101.76 72.55 101.49 72.5 101.46 72.78 101.3 72.89 101.14 73.15 100.98 73.19 100.72 73.64 100.49 73.51 100.41 73.33 100.21 73.62 100.08 73.79 99.83 73.61 99.56 73.75 99.48 73.9 99.12 73.67 98.87 73.83 98.57 73.72 98.56 73.88 98.41 73.84" />
</clipPath>
<clipPath id="clip-KY">
<path d="M 96.72 75.76 96.98 75.61 97.17 75.49 97.15 75.26 97.18 75.11 97.14 74.89 97.22 74.75 97.53 74.83 97.81 74.97 97.96 74.85 97.91 74.53 98.18 74.4 98.38 74.3 98.28 74.16 98.41 73.95 98.41 73.84 98.56 73.88 98.57 73.72 98.87 73.83 99.12 73.67 99.48 73.9 99.56 73.75 99.83 73.61 100.08 73.79 100.21 73.62 100.41 73.33 100.49 73.51 100.72 73.64 100.98 73.19 101.14 73.15 101.3 72.89 101.46 72.78 101.49 72.5 101.76 72.55 101.94 72.42 102.14 72.42 102.19 72.31 102.09 72.0 102.16 71.93 102.56 71.97 102.76 72.11 103.07 72.45 103.32 72.55 103.5 72.67 103.78 72.63 103.98 72.72 104.23 72.64 104.45 72.61 104.54 72.82 104.76 72.96 104.78 73.1 104.77 73.41 104.91 73.64 104.96 73.86 105.13 74.06 105.25 74.23 105.48 74.26 105.36 74.37 105.01 74.7 104.65 74.87 104.62 74.99 104.5 75.14 104.2 75.3 104.18 75.31 104.17 75.33 104.07 75.45 103.9 75.52 103.83 75.54 103.5 75.63 102.71 75.67 101.69 75.61 101.35 75.63 100.68 75.59 100.0 75.58 99.38 75.57 98.65 75.61 98.61 75.54 98.38 75.55 98.38 75.77 96.72 75.76" />
</clipPath>
<clipPath id="clip-NC">
<path d="M 104.19 77.95 102.75 77.94 102.77 77.64 103.02 77.55 103.1 77.4 103.26 77.22 103.5 77.18 103.77 77.12 104.04 77.0 104.15 76.87 104.37 76.75 104.37 76.65 104.66 76.46 104.76 76.58 105.19 76.31 105.39 76.34 105.56 76.1 105.8 76.03 105.79 75.83 105.82 75.65 105.36 75.67 105.82 75.65 107.78 75.71 110.1 75.72 111.33 75.7 112.43 75.7 112.58 75.7 112.74 77.14 112.0 78.19 110.8 78.61 110.04 79.44 109.45 79.53 108.15 78.19 106.86 78.18 106.86 78.01 106.68 77.77 106.56 77.87 106.56 77.74 106.01 77.68 104.94 77.66 104.31 77.91 104.19 77.95" />
</clipPath>
<clipPath id="clip-OH">
<path d="M 102.16 71.93 102.17 70.89 102.18 69.4 102.18 68.0 102.78 67.99 103.3 67.99 103.74 67.98 104.46 68.3 105.04 68.38 105.88 68.17 106.57 67.74 107.17 67.53 107.17 69.6 107.01 69.68 107.06 69.88 107.0 70.23 106.88 70.62 106.77 70.95 106.75 71.11 106.43 71.45 106.3 71.52 106.14 71.57 106.0 71.53 105.74 71.79 105.69 72.06 105.66 72.21 105.56 72.27 105.54 72.1 105.38 72.06 105.22 72.39 105.2 72.72 105.05 72.92 104.76 72.96 104.54 72.82 104.45 72.61 104.23 72.64 103.98 72.72 103.78 72.63 103.5 72.67 103.32 72.55 103.07 72.45 102.76 72.11 102.56 71.97 102.16 71.93" />
</clipPath>
<clipPath id="clip-TN">
<path d="M 95.85 77.89 95.98 77.76 95.97 77.34 96.15 77.16 96.2 76.92 96.4 76.78 96.52 76.58 96.53 76.46 96.62 76.11 96.69 75.9 96.72 75.76 98.38 75.77 98.38 75.55 98.61 75.54 98.65 75.61 99.38 75.57 100.0 75.58 100.68 75.59 101.35 75.63 101.69 75.61 102.71 75.67 103.5 75.63 103.83 75.54 103.9 75.52 103.83 75.54 103.5 75.63 105.23 75.67 105.36 75.67 105.82 75.65 105.79 75.83 105.8 76.03 105.56 76.1 105.39 76.34 105.19 76.31 104.76 76.58 104.66 76.46 104.37 76.65 104.37 76.75 104.15 76.87 104.04 77.0 103.77 77.12 103.5 77.18 103.26 77.22 103.1 77.4 103.02 77.55 102.77 77.64 102.75 77.94 102.12 77.95 101.23 77.94 99.73 77.92 98.27 77.92 96.99 77.89 95.85 77.89" />
</clipPath>
<clipPath id="clip-VA">
<path d="M 103.9 75.52 104.07 75.45 104.17 75.33 104.18 75.31 104.2 75.3 104.5 75.14 104.62 74.99 104.65 74.87 105.01 74.7 105.36 74.37 105.48 74.26 105.53 74.51 105.63 74.61 105.66 74.64 105.84 74.76 106.1 74.63 106.2 74.58 106.34 74.69 106.71 74.58 106.78 74.56 106.79 74.48 106.8 74.43 106.93 74.48 107.07 74.38 107.08 74.38 107.24 74.4 107.43 74.29 107.44 74.21 107.45 74.15 107.43 73.98 107.59 73.72 107.81 73.53 107.87 73.31 107.98 73.16 108.07 73.05 108.18 72.73 108.34 72.84 108.51 72.95 108.68 72.89 108.73 72.75 108.85 72.57 108.93 72.44 108.98 72.36 109.06 72.42 109.23 72.23 109.37 72.11 109.46 72.03 109.5 71.99 109.61 71.88 109.68 71.57 109.7 71.48 110.24 71.85 110.29 71.89 110.42 71.61 110.45 71.62 110.59 71.66 110.75 71.77 110.68 71.9 110.66 71.93 110.91 72.02 111.12 72.19 111.22 72.32 111.21 72.41 111.19 72.53 111.15 72.56 111.0 72.67 110.86 73.0 111.02 73.08 111.21 73.01 111.26 73.18 111.27 73.22 112.08 73.7 112.13 75.09 112.46 75.19 112.58 75.7 112.43 75.7 111.33 75.7 110.1 75.72 107.78 75.71 105.82 75.65 105.36 75.67 105.23 75.67 103.5 75.63 103.83 75.54 103.9 75.52" />
<path d="M 113.15 73.55 112.5 74.73 112.39 74.67 112.75 73.67 112.88 73.58 113.15 73.55" />
</clipPath>
<clipPath id="clip-WI">
<path d="M 94.71 65.12 94.68 64.94 94.68 64.55 94.64 64.42 94.24 64.18 93.95 63.9 93.87 63.73 93.74 63.62 93.36 63.38 93.22 63.37 92.88 63.05 92.92 62.69 92.92 62.25 93.01 61.83 92.76 61.52 92.93 61.21 93.18 61.05 93.47 60.87 93.5 60.87 93.49 59.92 93.8 59.83 94.96 59.47 95.67 60.05 95.68 60.06 95.75 60.02 95.75 60.03 95.93 60.08 96.03 60.39 97.04 60.69 97.72 60.99 98.04 60.99 98.27 61.01 98.33 61.29 98.61 61.39 98.71 61.63 98.64 61.76 98.59 62.03 98.85 62.05 98.76 62.31 98.91 62.51 98.92 62.5 98.94 62.52 98.93 62.53 98.48 63.12 98.64 63.32 99.49 62.26 99.67 62.25 99.06 63.52 98.8 64.65 98.58 65.55 98.72 66.33 98.69 66.72 97.79 66.71 96.58 66.71 95.39 66.71 95.28 66.46 94.9 66.31 94.82 66.06 94.78 65.92 94.77 65.58 94.88 65.46 94.73 65.21 94.71 65.12" />
</clipPath>
<clipPath id="clip-WV">
<path d="M 105.48 74.26 105.25 74.23 105.13 74.06 104.96 73.86 104.91 73.64 104.77 73.41 104.78 73.1 104.76 72.96 105.05 72.92 105.2 72.72 105.22 72.39 105.38 72.06 105.54 72.1 105.56 72.27 105.66 72.21 105.69 72.06 105.74 71.79 106.0 71.53 106.14 71.57 106.3 71.52 106.43 71.45 106.75 71.11 106.77 70.95 106.88 70.62 107.0 70.23 107.06 69.88 107.01 69.68 107.17 69.6 107.17 71.01 108.38 71.01 108.37 71.77 108.55 71.64 108.75 71.46 108.98 71.4 109.13 71.25 109.48 71.31 109.6 71.19 109.83 71.08 110.19 71.2 110.33 71.42 110.42 71.61 110.29 71.89 110.24 71.85 109.7 71.48 109.68 71.57 109.61 71.88 109.5 71.99 109.46 72.03 109.37 72.11 109.23 72.23 109.06 72.42 108.98 72.36 108.93 72.44 108.85 72.57 108.73 72.75 108.68 72.89 108.51 72.95 108.34 72.84 108.18 72.73 108.07 73.05 107.98 73.16 107.87 73.31 107.81 73.53 107.59 73.72 107.43 73.98 107.45 74.15 107.44 74.21 107.43 74.29 107.24 74.4 107.08 74.38 107.07 74.38 106.93 74.48 106.8 74.43 106.79 74.48 106.78 74.56 106.71 74.58 106.34 74.69 106.2 74.58 106.1 74.63 105.84 74.76 105.66 74.64 105.63 74.61 105.53 74.51 105.48 74.26" />
</clipPath>
<clipPath id="clip-DE">
<path d="M 113.53 72.91 112.76 72.91 112.67 71.0 112.76 70.88 112.87 70.81 113.12 70.89 112.94 71.05 112.98 71.34 113.22 72.15 113.51 72.42 113.53 72.91" />
</clipPath>
<clipPath id="clip-DC">
<path d="M 111.21 72.41 111.22 72.32 111.12 72.19 111.22 72.12 111.37 72.27 111.21 72.41" />
</clipPath>
<clipPath id="clip-MD">
<path d="M 113.15 73.55 112.88 73.58 112.75 73.67 112.16 73.11 112.02 71.87 111.79 72.51 112.04 73.45 111.27 73.22 111.26 73.18 111.21 73.01 111.02 73.08 110.86 73.0 111.0 72.67 111.15 72.56 111.19 72.53 111.21 72.41 111.37 72.27 111.22 72.12 111.12 72.19 110.91 72.02 110.66 71.93 110.68 71.9 110.75 71.77 110.59 71.66 110.45 71.62 110.42 71.61 110.33 71.42 110.19 71.2 109.83 71.08 109.6 71.19 109.48 71.31 109.13 71.25 108.98 71.4 108.75 71.46 108.55 71.64 108.37 71.77 108.38 71.01 109.46 71.01 109.83 71.01 110.65 71.0 111.65 71.01 112.67 71.0 112.76 72.91 113.53 72.91 113.52 72.98 113.15 73.55" />
</clipPath>
<clipPath id="clip-NJ">
<path d="M 112.98 71.34 112.94 71.05 113.12 70.89 113.36 70.75 113.44 70.66 113.72 70.46 113.87 70.29 113.5 69.9 113.48 69.74 113.35 69.69 113.36 69.44 113.49 69.25 113.43 69.05 113.62 68.92 113.82 68.57 113.96 68.5 114.85 69.11 114.81 69.44 114.45 69.86 114.8 69.93 114.55 71.02 113.7 72.18 113.61 71.8 113.36 71.72 112.98 71.34" />
</clipPath>
<clipPath id="clip-NY">
<path d="M 115.34 67.41 115.27 68.61 115.36 68.74 115.11 68.89 115.15 69.08 115.16 69.12 115.09 69.16 116.8 68.87 117.14 69.16 115.51 69.62 114.77 69.63 114.81 69.44 114.85 69.11 113.96 68.5 113.78 68.39 113.58 68.29 113.5 68.06 113.53 67.89 113.39 67.75 113.14 67.5 111.56 67.5 109.87 67.5 108.05 67.5 108.05 67.07 109.05 66.13 109.03 65.98 108.93 65.5 109.48 65.32 110.39 65.37 111.34 65.51 112.22 64.98 112.15 64.35 112.03 64.12 113.22 62.99 113.74 62.69 115.51 62.67 115.49 63.01 115.44 63.22 115.47 63.7 115.53 63.95 115.42 64.29 115.52 64.71 115.45 64.94 115.47 65.0 115.64 65.01 115.59 66.33 115.34 67.41" />
</clipPath>
<clipPath id="clip-PA">
<path d="M 107.17 69.6 107.17 67.53 108.05 67.08 108.05 67.07 108.05 67.5 109.87 67.5 111.56 67.5 113.14 67.5 113.39 67.75 113.53 67.89 113.5 68.06 113.58 68.29 113.78 68.39 113.96 68.5 113.82 68.57 113.62 68.92 113.43 69.05 113.49 69.25 113.36 69.44 113.35 69.69 113.48 69.74 113.5 69.9 113.87 70.29 113.72 70.46 113.44 70.66 113.36 70.75 113.12 70.89 112.87 70.81 112.76 70.88 112.67 71.0 111.65 71.01 110.65 71.0 109.83 71.01 109.46 71.01 108.38 71.01 107.17 71.01 107.17 69.6" />
</clipPath>
<clipPath id="clip-ME">
<path d="M 118.66 65.78 118.53 65.79 118.48 65.57 118.26 65.33 118.31 65.18 118.14 62.18 118.64 61.93 119.05 61.17 119.41 59.86 120.29 58.57 120.68 59.02 121.46 58.73 121.98 59.22 121.98 61.52 122.74 62.46 122.94 63.0 121.7 63.79 120.5 64.35 119.27 64.83 118.66 65.78" />
</clipPath>
<clipPath id="clip-MI">
<path d="M 104.95 65.95 104.4 66.82 104.14 67.37 103.74 67.98 103.3 67.99 102.78 67.99 102.18 68.0 102.18 67.88 101.08 67.89 99.83 67.88 100.07 67.66 100.54 66.9 100.57 65.86 100.19 64.87 100.24 64.18 100.55 63.38 100.84 62.83 101.3 62.44 101.41 62.99 101.62 62.18 101.87 62.01 102.04 61.38 103.03 61.71 103.89 62.36 103.98 63.1 103.87 63.85 103.24 64.5 103.29 64.9 103.53 64.91 104.25 64.2 104.68 64.37 104.89 65.3 104.95 65.95" />
<path d="M 102.49 60.12 102.41 60.29 102.73 60.34 103.31 61.01 102.28 61.16 102.24 61.15 101.33 60.98 100.42 61.31 99.63 61.46 98.94 62.52 98.92 62.5 98.91 62.51 98.76 62.31 98.85 62.05 98.59 62.03 98.64 61.76 98.71 61.63 98.61 61.39 98.33 61.29 98.27 61.01 98.04 60.99 97.72 60.99 97.04 60.69 96.03 60.39 95.93 60.08 95.75 60.03 95.75 60.02 95.68 60.06 95.67 60.05 95.68 60.06 96.57 59.62 97.51 59.07 98.53 58.5 98.16 59.41 98.82 59.62 99.64 60.27 100.67 59.89 101.82 59.74 102.06 60.22 102.41 60.29 102.49 60.12" />
</clipPath>
<clipPath id="clip-AK">
<path d="M 36.82 6.73 36.81 18.21 36.81 32.93 37.95 33.0 39.08 33.65 39.9 34.66 40.93 36.16 42.06 34.89 43.23 34.14 43.85 35.33 44.63 36.26 45.7 37.26 46.42 38.84 47.61 41.29 49.59 42.62 49.62 43.92 48.98 44.9 48.34 44.13 47.31 43.48 46.98 41.67 45.48 39.95 44.86 37.9 43.74 37.76 41.89 37.7 40.53 37.06 38.12 34.72 37.01 34.28 34.97 33.45 33.36 33.65 31.07 32.58 29.69 31.56 28.4 32.07 28.64 33.7 28.0 33.85 26.65 34.33 25.63 35.11 24.34 35.59 24.17 34.24 24.69 31.94 25.93 31.21 25.61 30.6 24.13 31.94 23.33 33.51 21.66 35.15 22.51 36.25 21.41 37.85 20.16 38.77 18.99 39.43 18.71 40.38 16.89 41.47 16.52 42.46 15.16 43.34 14.36 43.18 13.28 43.75 12.09 44.45 11.13 45.12 9.13 45.7 8.95 45.36 10.22 44.42 11.36 43.79 12.6 42.66 14.04 42.43 14.62 41.57 16.23 40.3 16.49 39.87 17.35 39.11 17.55 37.45 18.14 36.13 16.8 36.81 16.42 36.42 15.79 37.23 15.03 36.1 14.72 36.9 14.29 35.78 13.12 36.68 12.41 36.68 12.31 35.34 12.52 34.5 11.77 33.67 10.26 34.12 9.27 33.03 8.48 32.46 8.47 31.11 7.58 30.08 8.03 28.66 8.98 27.26 9.39 25.95 10.33 25.77 11.13 26.18 12.07 24.93 12.91 25.15 13.8 24.34 13.58 23.13 12.93 22.65 13.79 21.6 13.08 21.63 11.84 22.22 11.49 22.82 10.57 22.22 8.93 22.53 7.22 21.88 6.73 20.77 5.26 19.15 6.9 17.96 9.49 16.54 10.45 16.54 10.29 17.99 12.75 17.88 11.8 16.08 10.37 14.95 9.54 13.44 8.43 12.12 6.83 11.13 7.48 9.46 9.54 9.35 11.01 7.86 11.29 6.24 12.48 4.61 13.61 4.22 15.82 2.66 16.89 2.89 18.68 0.98 20.44 1.74 21.28 3.35 21.8 2.66 23.76 2.88 23.69 3.69 25.47 4.28 26.66 3.93 29.11 5.02 31.35 5.35 32.24 5.79 33.79 5.24 35.56 6.26 36.82 6.73" />
<path d="M 22.58 38.24 23.35 38.39 23.84 39.06 22.84 40.09 21.67 40.9 21.08 40.35 20.9 39.34 21.95 38.57 22.58 38.24" />
<path d="M 1.05 24.3 1.77 24.8 2.49 24.53 3.43 25.22 4.59 25.56 4.49 25.84 3.61 26.39 2.73 25.83 2.28 25.36 1.26 25.51 0.98 25.28 1.05 24.3" />
<path d="M 7.17 32.75 8.1 32.96 8.21 33.86 7.49 34.22 6.73 33.79 6.02 33.15 7.17 32.75" />
</clipPath>
<g id="region-MN" clip-path="url(#clip-MN)" stroke='#000000' fill='#8888ff' transform-origin='91.14 60.37' >
<path id="MN-0" d="M 93.8 59.83 93.49 59.92 93.5 60.87 93.47 60.87 93.18 61.05 92.93 61.21 92.76 61.52 93.01 61.83 92.92 62.25 92.92 62.69 92.88 63.05 93.22 63.37 93.36 63.38 93.74 63.62 93.87 63.73 93.95 63.9 94.24 64.18 94.64 64.42 94.68 64.55 94.68 64.94 94.71 65.12 93.18 65.09 91.48 65.1 89.9 65.12 88.63 65.12 88.65 63.61 88.51 62.04 88.3 61.91 88.19 61.65 88.25 61.43 88.51 61.24 88.53 61.0 88.53 60.69 88.46 60.44 88.36 60.16 88.3 59.82 88.29 59.43 88.25 59.34 88.2 58.84 88.2 58.61 88.18 58.4 88.12 58.05 87.98 57.69 87.84 57.38 87.82 57.06 87.81 56.71 87.85 56.49 87.85 56.29 87.75 56.03 87.73 55.86 90.14 55.86 90.14 55.17 90.53 55.17 90.74 56.14 91.1 56.44 91.91 56.55 93.1 56.83 94.23 57.37 95.17 57.14 96.6 57.6 95.42 58.17 94.59 58.86 93.8 59.58 93.8 59.83" class="interior" />
</g>
<g id="region-MT" clip-path="url(#clip-MT)" stroke='#000000' fill='#aaaaaa' transform-origin='73.26 59.19' >
<path id="MT-0" d="M 65.83 55.86 69.31 55.86 72.79 55.85 76.26 55.85 79.74 55.85 79.76 59.04 79.82 61.1 79.76 62.62 77.82 62.6 75.72 62.61 73.91 62.59 71.62 62.6 71.63 63.44 71.61 63.5 71.48 63.41 71.37 63.18 71.24 63.13 71.08 63.46 70.81 63.51 70.15 63.41 70.12 63.57 69.74 63.51 69.53 63.73 69.32 63.31 69.18 63.07 68.94 63.03 68.87 62.91 68.79 62.48 68.59 62.28 68.46 61.75 68.32 61.52 68.17 61.48 68.06 61.71 67.83 61.91 67.62 61.75 67.61 61.32 67.74 61.21 67.64 60.78 67.76 60.34 67.88 59.96 67.53 59.95 67.23 59.7 66.91 59.17 66.72 58.91 66.45 58.75 66.23 58.47 66.23 58.16 65.93 57.7 65.83 55.86" class="interior" />
</g>
<g id="region-ND" clip-path="url(#clip-ND)" stroke='#000000' fill='#aaaaaa' transform-origin='83.94 58.51' >
<path id="ND-0" d="M 87.73 55.86 87.75 56.03 87.85 56.29 87.85 56.49 87.81 56.71 87.82 57.06 87.84 57.38 87.98 57.69 88.12 58.05 88.18 58.4 88.2 58.61 88.2 58.84 88.25 59.34 88.29 59.43 88.3 59.82 88.36 60.16 88.46 60.44 88.53 60.69 88.53 61.0 86.32 61.09 84.43 61.08 82.04 61.09 79.82 61.1 79.76 59.04 79.74 55.85 83.77 55.85 87.73 55.86" class="interior" />
</g>
<g id="region-HI" clip-path="url(#clip-HI)" stroke='#000000' fill='#aaaaaa' transform-origin='19.91 98.18' >
<path id="HI-0" d="M 19.43 98.84 19.46 98.5 19.27 98.05 19.32 97.91 19.53 97.71 19.45 97.47 19.51 97.35 19.6 97.37 20.05 97.58 20.25 97.69 20.44 97.86 20.74 98.29 20.71 98.36 20.26 98.62 19.88 98.81 19.71 99.02 19.43 98.84" class="interior" />
<path id="HI-1" d="M 19.36 96.73 19.26 96.88 18.87 96.97 18.67 96.71 18.54 96.61 18.53 96.53 18.64 96.42 19.05 96.54 19.36 96.73" class="interior" />
<path id="HI-2" d="M 16.88 96.05 16.73 95.77 16.68 95.72 17.0 95.54 17.09 95.62 17.43 96.04 17.37 96.11 17.28 96.09 16.88 96.05" class="interior" />
<path id="HI-3" d="M 14.93 95.11 14.99 95.02 15.17 94.89 15.44 94.92 15.46 95.21 15.32 95.34 14.93 95.11" class="interior" />
<path id="HI-4" d="M 18.47 96.22 18.43 96.35 17.81 96.32 17.9 96.17 18.47 96.22" class="interior" />
</g>
<g id="region-ID" clip-path="url(#clip-ID)" stroke='#000000' fill='#aaaaaa' transform-origin='67.43 63.55' >
<path id="ID-0" d="M 65.83 55.86 65.93 57.7 66.23 58.16 66.23 58.47 66.45 58.75 66.72 58.91 66.91 59.17 67.23 59.7 67.53 59.95 67.88 59.96 67.76 60.34 67.64 60.78 67.74 61.21 67.61 61.32 67.62 61.75 67.83 61.91 68.06 61.71 68.17 61.48 68.32 61.52 68.46 61.75 68.59 62.28 68.79 62.48 68.87 62.91 68.94 63.03 69.18 63.07 69.32 63.31 69.53 63.73 69.74 63.51 70.12 63.57 70.15 63.41 70.81 63.51 71.08 63.46 71.24 63.13 71.37 63.18 71.48 63.41 71.61 63.5 71.65 63.52 71.65 67.5 68.18 67.51 64.69 67.5 64.71 64.65 64.81 64.19 64.72 63.98 64.5 63.87 64.5 63.61 64.67 63.23 64.92 62.91 65.08 62.38 65.24 61.95 65.36 61.74 65.29 61.48 65.1 61.35 64.82 61.03 64.83 60.73 64.73 60.47 64.69 58.09 64.69 55.86 65.83 55.86" class="interior" />
</g>
<g id="region-WA" clip-path="url(#clip-WA)" stroke='#000000' fill='#0000ff' transform-origin='60.78 58.65' >
<path id="WA-0" d="M 64.69 55.86 64.69 58.09 64.73 60.47 64.83 60.73 64.82 61.03 62.42 61.04 62.01 61.21 61.71 61.14 61.48 61.28 61.05 61.46 60.53 61.44 60.26 61.57 60.02 61.63 59.83 61.54 59.42 61.47 59.16 61.53 58.71 61.7 58.42 61.71 58.15 61.64 58.06 61.41 58.03 61.13 57.82 60.81 57.48 60.71 57.2 60.56 56.84 60.55 56.58 60.55 56.49 59.57 56.12 58.1 55.78 57.29 55.92 56.95 57.61 57.54 58.23 59.17 58.51 58.72 58.33 57.3 57.93 55.86 61.23 55.86 64.69 55.86" class="interior" />
</g>
<g id="region-AZ" clip-path="url(#clip-AZ)" stroke='#000000' fill='#0000ff' transform-origin='70.94 78.86' >
<path id="AZ-0" d="M 73.98 75.04 73.98 83.01 71.68 83.02 69.02 82.05 67.27 81.38 67.38 81.11 67.53 81.12 67.66 80.84 67.45 80.65 67.41 80.44 67.35 80.2 67.58 79.88 67.67 79.24 68.02 78.95 67.8 78.68 67.65 78.41 67.56 78.16 67.49 77.97 67.47 77.85 67.54 77.57 67.48 77.29 67.46 77.01 67.46 76.7 67.36 76.5 67.43 76.33 67.68 76.33 67.9 76.43 68.06 76.49 68.14 76.27 68.19 76.22 68.18 75.05 70.06 75.03 72.29 75.03 73.98 75.04" class="interior" />
</g>
<g id="region-CA" clip-path="url(#clip-CA)" stroke='#000000' fill='#0000ff' transform-origin='61.57 74.48' >
<path id="CA-0" d="M 67.47 77.85 67.49 77.97 67.56 78.16 67.65 78.41 67.8 78.68 68.02 78.95 67.67 79.24 67.58 79.88 67.35 80.2 67.41 80.44 67.45 80.65 67.66 80.84 67.53 81.12 67.38 81.11 65.9 81.26 64.58 81.37 64.38 80.66 63.63 79.86 63.08 79.7 62.96 79.29 62.3 79.22 61.89 78.84 60.81 78.7 60.51 78.48 60.37 77.7 59.24 76.26 58.27 74.24 58.31 73.9 57.8 73.41 56.9 72.16 56.74 70.94 56.12 70.11 56.37 68.83 56.33 67.5 61.24 67.51 61.24 72.1 63.43 74.1 65.52 76.03 67.47 77.85" class="interior" />
</g>
<g id="region-CO" clip-path="url(#clip-CO)" stroke='#000000' fill='#8888ff' transform-origin='78.05 72.05' >
<path id="CO-0" d="M 82.12 70.58 82.13 72.9 82.13 75.06 81.01 75.05 79.62 75.05 77.64 75.05 75.8 75.04 73.98 75.04 73.97 69.05 75.14 69.05 76.3 69.05 78.63 69.05 79.8 69.05 82.12 69.05 82.12 70.53 82.12 70.58" class="interior" />
</g>
<g id="region-NV" clip-path="url(#clip-NV)" stroke='#000000' fill='#8888ff' transform-origin='65.12 71.48' >
<path id="NV-0" d="M 64.69 67.5 68.18 67.51 68.18 75.05 68.19 76.22 68.14 76.27 68.06 76.49 67.9 76.43 67.68 76.33 67.43 76.33 67.36 76.5 67.46 76.7 67.46 77.01 67.48 77.29 67.54 77.57 67.47 77.85 65.52 76.03 63.43 74.1 61.24 72.1 61.24 67.51 64.69 67.5" class="interior" />
</g>
<g id="region-NM" clip-path="url(#clip-NM)" stroke='#000000' fill='#aaaaaa' transform-origin='77.43 78.69' >
<path id="NM-0" d="M 73.98 83.01 73.98 75.04 75.8 75.04 77.64 75.05 79.62 75.05 81.01 75.05 81.01 75.77 81.01 79.5 81.01 82.11 79.93 82.11 77.84 82.11 76.79 82.11 76.8 82.22 76.93 82.44 74.92 82.44 74.91 83.01 73.98 83.01" class="interior" />
</g>
<g id="region-OR" clip-path="url(#clip-OR)" stroke='#000000' fill='#8888ff' transform-origin='60.61 64.35' >
<path id="OR-0" d="M 64.82 61.03 65.1 61.35 65.29 61.48 65.36 61.74 65.24 61.95 65.08 62.38 64.92 62.91 64.67 63.23 64.5 63.61 64.5 63.87 64.72 63.98 64.81 64.19 64.71 64.65 64.69 67.5 61.24 67.51 56.33 67.5 55.96 66.29 56.42 64.79 56.7 61.82 56.58 60.55 56.84 60.55 57.2 60.56 57.48 60.71 57.82 60.81 58.03 61.13 58.06 61.41 58.15 61.64 58.42 61.71 58.71 61.7 59.16 61.53 59.42 61.47 59.83 61.54 60.02 61.63 60.26 61.57 60.53 61.44 61.05 61.46 61.48 61.28 61.71 61.14 62.01 61.21 62.42 61.04 64.82 61.03" class="interior" />
</g>
<g id="region-UT" clip-path="url(#clip-UT)" stroke='#000000' fill='#8888ff' transform-origin='70.92 71.54' >
<path id="UT-0" d="M 68.18 67.51 71.65 67.5 71.64 69.01 73.97 69.05 73.98 75.04 72.29 75.03 70.06 75.03 68.18 75.05 68.18 67.51" class="interior" />
</g>
<g id="region-WY" clip-path="url(#clip-WY)" stroke='#000000' fill='#aaaaaa' transform-origin='75.71 65.83' >
<path id="WY-0" d="M 71.61 63.5 71.63 63.44 71.62 62.6 73.91 62.59 75.72 62.61 77.82 62.6 79.76 62.62 79.79 65.92 79.8 69.05 78.63 69.05 76.3 69.05 75.14 69.05 73.97 69.05 71.64 69.01 71.65 67.5 71.65 63.52 71.61 63.5" class="interior" />
</g>
<g id="region-AR" clip-path="url(#clip-AR)" stroke='#000000' fill='#8888ff' transform-origin='93.3 78.01' >
<path id="AR-0" d="M 96.53 76.46 96.52 76.58 96.4 76.78 96.2 76.92 96.15 77.16 95.97 77.34 95.98 77.76 95.85 77.89 95.83 78.0 95.62 78.11 95.61 78.31 95.46 78.69 95.32 78.77 95.12 78.96 95.0 79.25 94.74 79.74 94.71 80.07 94.85 80.44 94.79 80.71 93.81 80.67 92.54 80.71 91.41 80.71 91.48 79.92 91.21 79.92 90.99 79.93 90.93 79.84 90.96 78.61 90.98 77.23 90.75 75.71 92.17 75.73 93.45 75.74 94.68 75.74 96.01 75.83 96.1 76.0 95.97 76.16 95.84 76.32 95.77 76.46 96.53 76.46" class="interior" />
</g>
<g id="region-IA" clip-path="url(#clip-IA)" stroke='#000000' fill='#8888ff' transform-origin='92.06 67.34' >
<path id="IA-0" d="M 88.63 65.12 89.9 65.12 91.48 65.1 93.18 65.09 94.71 65.12 94.73 65.21 94.88 65.46 94.77 65.58 94.78 65.92 94.82 66.06 94.9 66.31 95.28 66.46 95.39 66.71 95.46 66.83 95.6 66.91 95.65 67.08 95.84 67.2 95.96 67.34 95.89 67.76 95.68 68.11 95.6 68.22 95.33 68.31 94.94 68.39 94.83 68.66 94.98 68.78 95.03 69.01 94.87 69.28 94.8 69.51 94.5 69.74 94.47 70.02 94.31 69.89 94.09 69.65 92.82 69.68 91.48 69.69 90.44 69.69 89.39 69.69 89.32 69.41 89.35 69.14 89.33 68.87 89.21 68.43 89.13 68.24 89.04 68.19 89.04 67.83 88.96 67.57 88.75 67.28 88.75 67.15 88.68 66.89 88.63 66.73 88.63 66.59 88.44 66.41 88.53 66.15 88.6 65.9 88.62 65.72 88.47 65.51 88.48 65.12 88.63 65.12" class="interior" />
</g>
<g id="region-KS" clip-path="url(#clip-KS)" stroke='#000000' fill='#8888ff' transform-origin='86.39 72.84' >
<path id="KS-0" d="M 82.13 75.06 82.13 72.9 82.12 70.58 84.15 70.58 85.67 70.58 88.34 70.58 89.95 70.58 90.22 70.78 90.37 70.78 90.41 71.0 90.24 71.28 90.33 71.42 90.47 71.74 90.78 71.88 90.77 73.48 90.76 75.04 89.74 75.05 87.65 75.05 85.55 75.05 84.39 75.05 83.22 75.05 82.13 75.06" class="interior" />
</g>
<g id="region-MO" clip-path="url(#clip-MO)" stroke='#000000' fill='#8888ff' transform-origin='93.24 72.97' >
<path id="MO-0" d="M 96.53 76.46 95.77 76.46 95.84 76.32 95.97 76.16 96.1 76.0 96.01 75.83 94.68 75.74 93.45 75.74 92.17 75.73 90.75 75.71 90.77 75.04 90.76 75.04 90.77 73.48 90.78 71.88 90.47 71.74 90.33 71.42 90.24 71.28 90.41 71.0 90.37 70.78 90.22 70.78 89.95 70.58 89.79 70.26 89.61 70.06 89.42 69.82 89.39 69.69 90.44 69.69 91.48 69.69 92.82 69.68 94.09 69.65 94.31 69.89 94.47 70.02 94.37 70.4 94.48 70.85 94.67 71.17 94.89 71.42 95.16 71.62 95.27 71.69 95.36 71.98 95.38 72.23 95.52 72.29 95.73 72.2 95.96 72.44 95.89 72.71 95.78 72.93 95.71 73.19 95.87 73.41 96.1 73.62 96.23 73.62 96.54 73.95 96.66 73.99 96.74 74.35 96.7 74.57 96.85 74.93 96.98 74.89 97.18 75.11 97.15 75.26 97.17 75.49 96.98 75.61 96.72 75.76 96.69 75.9 96.62 76.11 96.53 76.46" class="interior" />
</g>
<g id="region-NE" clip-path="url(#clip-NE)" stroke='#000000' fill='#aaaaaa' transform-origin='84.71 68.22' >
<path id="NE-0" d="M 82.12 70.58 82.12 70.53 82.12 69.05 79.8 69.05 79.79 65.92 82.06 65.92 83.81 65.92 86.14 65.92 86.44 66.12 86.87 66.25 86.97 66.18 87.24 66.18 87.66 66.17 87.96 66.37 88.28 66.5 88.33 66.63 88.43 66.71 88.63 66.73 88.68 66.89 88.75 67.15 88.75 67.28 88.96 67.57 89.04 67.83 89.04 68.19 89.13 68.24 89.21 68.43 89.33 68.87 89.35 69.14 89.32 69.41 89.39 69.69 89.42 69.82 89.61 70.06 89.79 70.26 89.95 70.58 88.34 70.58 85.67 70.58 84.15 70.58 82.12 70.58" class="interior" />
</g>
<g id="region-OK" clip-path="url(#clip-OK)" stroke='#000000' fill='#8888ff' transform-origin='87.4 77.07' >
<path id="OK-0" d="M 81.01 75.05 82.13 75.06 83.22 75.05 84.39 75.05 85.55 75.05 87.65 75.05 89.74 75.05 90.76 75.04 90.77 75.04 90.75 75.71 90.98 77.23 90.96 78.61 90.93 79.84 90.43 79.57 90.1 79.42 89.83 79.51 89.43 79.5 89.18 79.5 88.98 79.62 88.79 79.67 88.62 79.61 88.23 79.68 88.05 79.45 87.87 79.65 87.56 79.56 87.23 79.34 86.88 79.48 86.73 79.14 86.19 79.18 85.84 79.1 85.45 79.0 85.28 78.71 84.97 78.8 84.78 78.69 84.5 78.54 84.5 77.18 84.5 75.77 83.34 75.77 82.18 75.77 81.01 75.77 81.01 75.05" class="interior" />
</g>
<g id="region-SD" clip-path="url(#clip-SD)" stroke='#000000' fill='#aaaaaa' transform-origin='84.24 63.56' >
<path id="SD-0" d="M 88.53 61.0 88.51 61.24 88.25 61.43 88.19 61.65 88.3 61.91 88.51 62.04 88.65 63.61 88.63 65.12 88.48 65.12 88.47 65.51 88.62 65.72 88.6 65.9 88.53 66.15 88.44 66.41 88.63 66.59 88.63 66.73 88.43 66.71 88.33 66.63 88.28 66.5 87.96 66.37 87.66 66.17 87.24 66.18 86.97 66.18 86.87 66.25 86.44 66.12 86.14 65.92 83.81 65.92 82.06 65.92 79.79 65.92 79.76 62.62 79.82 61.1 82.04 61.09 84.43 61.08 86.32 61.09 88.53 61.0" class="interior" />
</g>
<g id="region-LA" clip-path="url(#clip-LA)" stroke='#000000' fill='#8888ff' transform-origin='93.85 83.38' >
<path id="LA-0" d="M 91.41 80.71 92.54 80.71 93.81 80.67 94.79 80.71 94.88 80.79 94.77 80.99 94.94 81.28 94.89 81.45 95.04 81.69 94.88 81.83 94.83 82.09 94.6 82.3 94.5 82.59 94.39 82.92 94.25 83.07 94.3 83.41 95.32 83.45 96.42 83.45 96.39 83.68 96.31 83.9 96.38 84.07 96.54 84.23 96.58 84.45 96.6 84.58 96.61 84.61 96.82 84.96 96.8 85.51 97.05 85.77 96.83 85.95 96.39 85.75 95.96 86.0 95.11 85.96 94.25 85.26 93.23 85.42 92.38 85.11 91.66 85.21 91.58 85.06 91.7 84.86 91.87 84.69 91.87 84.42 91.79 84.33 91.89 84.01 91.97 83.86 92.08 83.36 91.98 83.18 91.84 82.87 91.74 82.55 91.68 82.34 91.49 82.19 91.41 80.71" class="interior" />
</g>
<g id="region-TX" clip-path="url(#clip-TX)" stroke='#000000' fill='#0000ff' transform-origin='85.27 82.75' >
<path id="TX-0" d="M 76.93 82.44 76.8 82.22 76.79 82.11 77.84 82.11 79.93 82.11 81.01 82.11 81.01 79.5 81.01 75.77 82.18 75.77 83.34 75.77 84.5 75.77 84.5 77.18 84.5 78.54 84.78 78.69 84.97 78.8 85.28 78.71 85.45 79.0 85.84 79.1 86.19 79.18 86.73 79.14 86.88 79.48 87.23 79.34 87.56 79.56 87.87 79.65 88.05 79.45 88.23 79.68 88.62 79.61 88.79 79.67 88.98 79.62 89.18 79.5 89.43 79.5 89.83 79.51 90.1 79.42 90.43 79.57 90.93 79.84 90.99 79.93 91.21 79.92 91.48 79.92 91.41 80.71 91.49 82.19 91.68 82.34 91.74 82.55 91.84 82.87 91.98 83.18 92.08 83.36 91.97 83.86 91.89 84.01 91.79 84.33 91.87 84.42 91.87 84.69 91.7 84.86 91.58 85.06 91.66 85.21 90.68 85.52 89.62 86.51 88.47 87.08 87.83 87.71 87.56 88.3 87.55 89.2 87.61 89.82 87.83 90.26 87.38 90.3 86.55 90.02 85.64 89.61 85.32 89.0 85.06 88.09 84.38 87.34 83.97 86.56 83.39 85.65 82.57 85.12 81.62 85.14 80.89 86.2 79.92 85.8 79.32 85.4 79.03 84.66 78.64 83.95 77.95 83.36 77.36 82.93 76.93 82.44" class="interior" />
</g>
<g id="region-CT" clip-path="url(#clip-CT)" stroke='#000000' fill='#8888ff' transform-origin='116.22 68.11' >
<path id="CT-0" d="M 115.34 67.41 116.23 67.44 117.31 67.48 117.32 68.33 117.25 68.56 116.74 68.64 116.06 68.71 115.16 69.13 115.16 69.12 115.15 69.08 115.11 68.89 115.36 68.74 115.27 68.61 115.34 67.41" class="interior" />
</g>
<g id="region-MA" clip-path="url(#clip-MA)" stroke='#000000' fill='#0000ff' transform-origin='117.38 67.12' >
<path id="MA-0" d="M 117.31 67.48 116.23 67.44 115.34 67.41 115.59 66.33 116.55 66.35 117.95 66.37 118.07 66.21 118.32 66.11 118.46 66.14 118.45 66.97 118.83 67.8 119.31 67.84 119.19 67.27 119.54 67.62 119.45 68.07 118.66 68.32 118.1 68.29 118.07 68.05 117.89 67.87 117.8 67.46 117.31 67.48" class="interior" />
</g>
<g id="region-NH" clip-path="url(#clip-NH)" stroke='#000000' fill='#aaaaaa' transform-origin='117.59 64.8' >
<path id="NH-0" d="M 118.46 66.14 118.32 66.11 118.07 66.21 117.95 66.37 116.55 66.35 116.45 66.19 116.55 65.98 116.57 65.57 116.61 65.47 116.65 65.09 116.78 64.77 116.87 64.63 117.01 64.24 117.04 63.98 117.08 63.82 117.3 63.75 117.56 63.56 117.61 63.35 117.52 63.12 117.66 62.67 117.77 62.27 118.14 62.18 118.31 65.18 118.26 65.33 118.48 65.57 118.53 65.79 118.66 65.78 118.46 66.14" class="interior" />
</g>
<g id="region-RI" clip-path="url(#clip-RI)" stroke='#000000' fill='#aaaaaa' transform-origin='117.63 68.0' >
<path id="RI-0" d="M 117.25 68.56 117.32 68.33 117.31 67.48 117.8 67.46 117.89 67.87 118.07 68.05 118.1 68.29 117.25 68.56" class="interior" />
</g>
<g id="region-VT" clip-path="url(#clip-VT)" stroke='#000000' fill='#aaaaaa' transform-origin='116.31 64.18' >
<path id="VT-0" d="M 116.55 66.35 115.59 66.33 115.64 65.01 115.47 65.0 115.45 64.94 115.52 64.71 115.42 64.29 115.53 63.95 115.47 63.7 115.44 63.22 115.49 63.01 115.51 62.67 117.66 62.67 117.52 63.12 117.61 63.35 117.56 63.56 117.3 63.75 117.08 63.82 117.04 63.98 117.01 64.24 116.87 64.63 116.78 64.77 116.65 65.09 116.61 65.47 116.57 65.57 116.55 65.98 116.45 66.19 116.55 66.35" class="interior" />
</g>
<g id="region-AL" clip-path="url(#clip-AL)" stroke='#000000' fill='#8888ff' transform-origin='99.83 81.01' >
<path id="AL-0" d="M 98.27 77.92 99.73 77.92 101.23 77.94 101.53 79.69 101.8 81.07 101.97 81.5 102.07 81.75 101.88 81.99 101.82 82.43 101.88 82.69 101.85 82.93 101.82 83.15 101.89 83.32 101.95 83.48 99.58 83.49 98.91 83.57 98.89 83.67 99.16 84.0 99.1 84.27 99.01 84.45 97.98 84.3 97.94 82.23 98.15 80.02 98.35 78.2 98.27 77.92" class="interior" />
</g>
<g id="region-FL" clip-path="url(#clip-FL)" stroke='#000000' fill='#0000ff' transform-origin='104.84 86.62' >
<path id="FL-0" d="M 99.01 84.45 99.1 84.27 99.16 84.0 98.89 83.67 98.91 83.57 99.58 83.49 101.95 83.48 102.13 83.85 103.3 83.91 105.18 84.11 105.27 84.35 105.42 84.23 105.42 83.76 105.56 83.71 105.79 83.81 106.04 83.84 106.24 84.77 106.63 85.92 107.15 86.86 107.16 87.43 107.71 88.95 107.67 89.83 107.62 90.33 107.33 91.12 106.98 91.28 106.41 91.12 106.22 90.56 105.78 90.26 105.17 89.15 104.63 88.15 104.45 87.63 104.69 86.76 104.36 86.03 103.46 84.91 103.0 84.7 101.83 85.31 101.62 85.24 101.06 84.62 100.33 84.28 99.01 84.45" class="interior" />
</g>
<g id="region-GA" clip-path="url(#clip-GA)" stroke='#000000' fill='#0000ff' transform-origin='103.75 81.18' >
<path id="GA-0" d="M 101.95 83.48 101.89 83.32 101.82 83.15 101.85 82.93 101.88 82.69 101.82 82.43 101.88 81.99 102.07 81.75 101.97 81.5 101.8 81.07 101.53 79.69 101.23 77.94 102.12 77.95 102.75 77.94 104.19 77.95 104.07 78.07 103.88 78.34 104.19 78.57 104.4 78.66 104.61 79.1 104.75 79.35 105.16 79.68 105.24 79.86 105.51 80.09 105.65 80.42 106.02 80.7 106.1 81.01 106.17 81.17 106.13 81.27 106.35 81.42 106.46 81.68 106.46 81.94 106.57 81.99 106.77 82.06 106.22 82.87 106.04 83.84 105.79 83.81 105.56 83.71 105.42 83.76 105.42 84.23 105.27 84.35 105.18 84.11 103.3 83.91 102.13 83.85 101.95 83.48" class="interior" />
</g>
<g id="region-MS" clip-path="url(#clip-MS)" stroke='#000000' fill='#aaaaaa' transform-origin='96.53 81.01' >
<path id="MS-0" d="M 94.79 80.71 94.85 80.44 94.71 80.07 94.74 79.74 95.0 79.25 95.12 78.96 95.32 78.77 95.46 78.69 95.61 78.31 95.62 78.11 95.83 78.0 95.85 77.89 96.99 77.89 98.27 77.92 98.35 78.2 98.15 80.02 97.94 82.23 97.98 84.3 97.09 84.4 96.61 84.61 96.6 84.58 96.58 84.45 96.54 84.23 96.38 84.07 96.31 83.9 96.39 83.68 96.42 83.45 95.32 83.45 94.3 83.41 94.25 83.07 94.39 82.92 94.5 82.59 94.6 82.3 94.83 82.09 94.88 81.83 95.04 81.69 94.89 81.45 94.94 81.28 94.77 80.99 94.88 80.79 94.79 80.71" class="interior" />
</g>
<g id="region-SC" clip-path="url(#clip-SC)" stroke='#000000' fill='#8888ff' transform-origin='106.74 79.46' >
<path id="SC-0" d="M 106.77 82.06 106.57 81.99 106.46 81.94 106.46 81.68 106.35 81.42 106.13 81.27 106.17 81.17 106.1 81.01 106.02 80.7 105.65 80.42 105.51 80.09 105.24 79.86 105.16 79.68 104.75 79.35 104.61 79.1 104.4 78.66 104.19 78.57 103.88 78.34 104.07 78.07 104.19 77.95 104.31 77.91 104.94 77.66 106.01 77.68 106.56 77.74 106.56 77.87 106.68 77.77 106.86 78.01 106.86 78.18 108.15 78.19 109.45 79.53 108.87 80.04 108.7 80.51 107.42 81.41 106.77 82.06" class="interior" />
</g>
<g id="region-IL" clip-path="url(#clip-IL)" stroke='#000000' fill='#0000ff' transform-origin='97.06 70.43' >
<path id="IL-0" d="M 94.47 70.02 94.5 69.74 94.8 69.51 94.87 69.28 95.03 69.01 94.98 68.78 94.83 68.66 94.94 68.39 95.33 68.31 95.6 68.22 95.68 68.11 95.89 67.76 95.96 67.34 95.84 67.2 95.65 67.08 95.6 66.91 95.46 66.83 95.39 66.71 96.58 66.71 97.79 66.71 98.69 66.72 98.7 67.13 99.02 67.95 99.02 67.96 99.02 69.74 99.01 71.5 98.88 71.92 98.98 72.03 99.04 72.29 99.03 72.49 98.93 72.58 98.85 72.82 98.61 73.15 98.44 73.55 98.41 73.84 98.41 73.95 98.28 74.16 98.38 74.3 98.18 74.4 97.91 74.53 97.96 74.85 97.81 74.97 97.53 74.83 97.22 74.75 97.14 74.89 97.18 75.11 96.98 74.89 96.85 74.93 96.7 74.57 96.74 74.35 96.66 73.99 96.54 73.95 96.23 73.62 96.1 73.62 95.87 73.41 95.71 73.19 95.78 72.93 95.89 72.71 95.96 72.44 95.73 72.2 95.52 72.29 95.38 72.23 95.36 71.98 95.27 71.69 95.16 71.62 94.89 71.42 94.67 71.17 94.48 70.85 94.37 70.4 94.47 70.02" class="interior" />
</g>
<g id="region-IN" clip-path="url(#clip-IN)" stroke='#000000' fill='#0000ff' transform-origin='100.47 70.7' >
<path id="IN-0" d="M 98.41 73.84 98.44 73.55 98.61 73.15 98.85 72.82 98.93 72.58 99.03 72.49 99.04 72.29 98.98 72.03 98.88 71.92 99.01 71.5 99.02 69.74 99.02 67.96 99.12 68.06 99.52 68.05 99.83 67.88 101.08 67.89 102.18 67.88 102.18 68.0 102.18 69.4 102.17 70.89 102.16 71.93 102.09 72.0 102.19 72.31 102.14 72.42 101.94 72.42 101.76 72.55 101.49 72.5 101.46 72.78 101.3 72.89 101.14 73.15 100.98 73.19 100.72 73.64 100.49 73.51 100.41 73.33 100.21 73.62 100.08 73.79 99.83 73.61 99.56 73.75 99.48 73.9 99.12 73.67 98.87 73.83 98.57 73.72 98.56 73.88 98.41 73.84" class="interior" />
</g>
<g id="region-KY" clip-path="url(#clip-KY)" stroke='#000000' fill='#8888ff' transform-origin='101.64 74.28' >
<path id="KY-0" d="M 96.72 75.76 96.98 75.61 97.17 75.49 97.15 75.26 97.18 75.11 97.14 74.89 97.22 74.75 97.53 74.83 97.81 74.97 97.96 74.85 97.91 74.53 98.18 74.4 98.38 74.3 98.28 74.16 98.41 73.95 98.41 73.84 98.56 73.88 98.57 73.72 98.87 73.83 99.12 73.67 99.48 73.9 99.56 73.75 99.83 73.61 100.08 73.79 100.21 73.62 100.41 73.33 100.49 73.51 100.72 73.64 100.98 73.19 101.14 73.15 101.3 72.89 101.46 72.78 101.49 72.5 101.76 72.55 101.94 72.42 102.14 72.42 102.19 72.31 102.09 72.0 102.16 71.93 102.56 71.97 102.76 72.11 103.07 72.45 103.32 72.55 103.5 72.67 103.78 72.63 103.98 72.72 104.23 72.64 104.45 72.61 104.54 72.82 104.76 72.96 104.78 73.1 104.77 73.41 104.91 73.64 104.96 73.86 105.13 74.06 105.25 74.23 105.48 74.26 105.36 74.37 105.01 74.7 104.65 74.87 104.62 74.99 104.5 75.14 104.2 75.3 104.18 75.31 104.17 75.33 104.07 75.45 103.9 75.52 103.83 75.54 103.5 75.63 102.71 75.67 101.69 75.61 101.35 75.63 100.68 75.59 100.0 75.58 99.38 75.57 98.65 75.61 98.61 75.54 98.38 75.55 98.38 75.77 96.72 75.76" class="interior" />
</g>
<g id="region-NC" clip-path="url(#clip-NC)" stroke='#000000' fill='#0000ff' transform-origin='108.64 77.15' >
<path id="NC-0" d="M 104.19 77.95 102.75 77.94 102.77 77.64 103.02 77.55 103.1 77.4 103.26 77.22 103.5 77.18 103.77 77.12 104.04 77.0 104.15 76.87 104.37 76.75 104.37 76.65 104.66 76.46 104.76 76.58 105.19 76.31 105.39 76.34 105.56 76.1 105.8 76.03 105.79 75.83 105.82 75.65 105.36 75.67 105.82 75.65 107.78 75.71 110.1 75.72 111.33 75.7 112.43 75.7 112.58 75.7 112.74 77.14 112.0 78.19 110.8 78.61 110.04 79.44 109.45 79.53 108.15 78.19 106.86 78.18 106.86 78.01 106.68 77.77 106.56 77.87 106.56 77.74 106.01 77.68 104.94 77.66 104.31 77.91 104.19 77.95" class="interior" />
</g>
<g id="region-OH" clip-path="url(#clip-OH)" stroke='#000000' fill='#0000ff' transform-origin='104.53 70.14' >
<path id="OH-0" d="M 102.16 71.93 102.17 70.89 102.18 69.4 102.18 68.0 102.78 67.99 103.3 67.99 103.74 67.98 104.46 68.3 105.04 68.38 105.88 68.17 106.57 67.74 107.17 67.53 107.17 69.6 107.01 69.68 107.06 69.88 107.0 70.23 106.88 70.62 106.77 70.95 106.75 71.11 106.43 71.45 106.3 71.52 106.14 71.57 106.0 71.53 105.74 71.79 105.69 72.06 105.66 72.21 105.56 72.27 105.54 72.1 105.38 72.06 105.22 72.39 105.2 72.72 105.05 72.92 104.76 72.96 104.54 72.82 104.45 72.61 104.23 72.64 103.98 72.72 103.78 72.63 103.5 72.67 103.32 72.55 103.07 72.45 102.76 72.11 102.56 71.97 102.16 71.93" class="interior" />
</g>
<g id="region-TN" clip-path="url(#clip-TN)" stroke='#000000' fill='#0000ff' transform-origin='100.42 76.72' >
<path id="TN-0" d="M 95.85 77.89 95.98 77.76 95.97 77.34 96.15 77.16 96.2 76.92 96.4 76.78 96.52 76.58 96.53 76.46 96.62 76.11 96.69 75.9 96.72 75.76 98.38 75.77 98.38 75.55 98.61 75.54 98.65 75.61 99.38 75.57 100.0 75.58 100.68 75.59 101.35 75.63 101.69 75.61 102.71 75.67 103.5 75.63 103.83 75.54 103.9 75.52 103.83 75.54 103.5 75.63 105.23 75.67 105.36 75.67 105.82 75.65 105.79 75.83 105.8 76.03 105.56 76.1 105.39 76.34 105.19 76.31 104.76 76.58 104.66 76.46 104.37 76.65 104.37 76.75 104.15 76.87 104.04 77.0 103.77 77.12 103.5 77.18 103.26 77.22 103.1 77.4 103.02 77.55 102.77 77.64 102.75 77.94 102.12 77.95 101.23 77.94 99.73 77.92 98.27 77.92 96.99 77.89 95.85 77.89" class="interior" />
</g>
<g id="region-VA" clip-path="url(#clip-VA)" stroke='#000000' fill='#0000ff' transform-origin='109.11 74.29' >
<path id="VA-0" d="M 103.9 75.52 104.07 75.45 104.17 75.33 104.18 75.31 104.2 75.3 104.5 75.14 104.62 74.99 104.65 74.87 105.01 74.7 105.36 74.37 105.48 74.26 105.53 74.51 105.63 74.61 105.66 74.64 105.84 74.76 106.1 74.63 106.2 74.58 106.34 74.69 106.71 74.58 106.78 74.56 106.79 74.48 106.8 74.43 106.93 74.48 107.07 74.38 107.08 74.38 107.24 74.4 107.43 74.29 107.44 74.21 107.45 74.15 107.43 73.98 107.59 73.72 107.81 73.53 107.87 73.31 107.98 73.16 108.07 73.05 108.18 72.73 108.34 72.84 108.51 72.95 108.68 72.89 108.73 72.75 108.85 72.57 108.93 72.44 108.98 72.36 109.06 72.42 109.23 72.23 109.37 72.11 109.46 72.03 109.5 71.99 109.61 71.88 109.68 71.57 109.7 71.48 110.24 71.85 110.29 71.89 110.42 71.61 110.45 71.62 110.59 71.66 110.75 71.77 110.68 71.9 110.66 71.93 110.91 72.02 111.12 72.19 111.22 72.32 111.21 72.41 111.19 72.53 111.15 72.56 111.0 72.67 110.86 73.0 111.02 73.08 111.21 73.01 111.26 73.18 111.27 73.22 112.08 73.7 112.13 75.09 112.46 75.19 112.58 75.7 112.43 75.7 111.33 75.7 110.1 75.72 107.78 75.71 105.82 75.65 105.36 75.67 105.23 75.67 103.5 75.63 103.83 75.54 103.9 75.52" class="interior" />
<path id="VA-1" d="M 113.15 73.55 112.5 74.73 112.39 74.67 112.75 73.67 112.88 73.58 113.15 73.55" class="interior" />
</g>
<g id="region-WI" clip-path="url(#clip-WI)" stroke='#000000' fill='#8888ff' transform-origin='96.13 63.2' >
<path id="WI-0" d="M 94.71 65.12 94.68 64.94 94.68 64.55 94.64 64.42 94.24 64.18 93.95 63.9 93.87 63.73 93.74 63.62 93.36 63.38 93.22 63.37 92.88 63.05 92.92 62.69 92.92 62.25 93.01 61.83 92.76 61.52 92.93 61.21 93.18 61.05 93.47 60.87 93.5 60.87 93.49 59.92 93.8 59.83 94.96 59.47 95.67 60.05 95.68 60.06 95.75 60.02 95.75 60.03 95.93 60.08 96.03 60.39 97.04 60.69 97.72 60.99 98.04 60.99 98.27 61.01 98.33 61.29 98.61 61.39 98.71 61.63 98.64 61.76 98.59 62.03 98.85 62.05 98.76 62.31 98.91 62.51 98.92 62.5 98.94 62.52 98.93 62.53 98.48 63.12 98.64 63.32 99.49 62.26 99.67 62.25 99.06 63.52 98.8 64.65 98.58 65.55 98.72 66.33 98.69 66.72 97.79 66.71 96.58 66.71 95.39 66.71 95.28 66.46 94.9 66.31 94.82 66.06 94.78 65.92 94.77 65.58 94.88 65.46 94.73 65.21 94.71 65.12" class="interior" />
</g>
<g id="region-WV" clip-path="url(#clip-WV)" stroke='#000000' fill='#aaaaaa' transform-origin='107.07 72.61' >
<path id="WV-0" d="M 105.48 74.26 105.25 74.23 105.13 74.06 104.96 73.86 104.91 73.64 104.77 73.41 104.78 73.1 104.76 72.96 105.05 72.92 105.2 72.72 105.22 72.39 105.38 72.06 105.54 72.1 105.56 72.27 105.66 72.21 105.69 72.06 105.74 71.79 106.0 71.53 106.14 71.57 106.3 71.52 106.43 71.45 106.75 71.11 106.77 70.95 106.88 70.62 107.0 70.23 107.06 69.88 107.01 69.68 107.17 69.6 107.17 71.01 108.38 71.01 108.37 71.77 108.55 71.64 108.75 71.46 108.98 71.4 109.13 71.25 109.48 71.31 109.6 71.19 109.83 71.08 110.19 71.2 110.33 71.42 110.42 71.61 110.29 71.89 110.24 71.85 109.7 71.48 109.68 71.57 109.61 71.88 109.5 71.99 109.46 72.03 109.37 72.11 109.23 72.23 109.06 72.42 108.98 72.36 108.93 72.44 108.85 72.57 108.73 72.75 108.68 72.89 108.51 72.95 108.34 72.84 108.18 72.73 108.07 73.05 107.98 73.16 107.87 73.31 107.81 73.53 107.59 73.72 107.43 73.98 107.45 74.15 107.44 74.21 107.43 74.29 107.24 74.4 107.08 74.38 107.07 74.38 106.93 74.48 106.8 74.43 106.79 74.48 106.78 74.56 106.71 74.58 106.34 74.69 106.2 74.58 106.1 74.63 105.84 74.76 105.66 74.64 105.63 74.61 105.53 74.51 105.48 74.26" class="interior" />
</g>
<g id="region-DE" clip-path="url(#clip-DE)" stroke='#000000' fill='#aaaaaa' transform-origin='113.01 72.1' >
<path id="DE-0" d="M 113.53 72.91 112.76 72.91 112.67 71.0 112.76 70.88 112.87 70.81 113.12 70.89 112.94 71.05 112.98 71.34 113.22 72.15 113.51 72.42 113.53 72.91" class="interior" />
</g>
<g id="region-DC" clip-path="url(#clip-DC)" stroke='#000000' fill='#aaaaaa' transform-origin='111.24 72.25' >
<path id="DC-0" d="M 111.21 72.41 111.22 72.32 111.12 72.19 111.22 72.12 111.37 72.27 111.21 72.41" class="interior" />
</g>
<g id="region-MD" clip-path="url(#clip-MD)" stroke='#000000' fill='#8888ff' transform-origin='111.53 72.03' >
<path id="MD-0" d="M 113.15 73.55 112.88 73.58 112.75 73.67 112.16 73.11 112.02 71.87 111.79 72.51 112.04 73.45 111.27 73.22 111.26 73.18 111.21 73.01 111.02 73.08 110.86 73.0 111.0 72.67 111.15 72.56 111.19 72.53 111.21 72.41 111.37 72.27 111.22 72.12 111.12 72.19 110.91 72.02 110.66 71.93 110.68 71.9 110.75 71.77 110.59 71.66 110.45 71.62 110.42 71.61 110.33 71.42 110.19 71.2 109.83 71.08 109.6 71.19 109.48 71.31 109.13 71.25 108.98 71.4 108.75 71.46 108.55 71.64 108.37 71.77 108.38 71.01 109.46 71.01 109.83 71.01 110.65 71.0 111.65 71.01 112.67 71.0 112.76 72.91 113.53 72.91 113.52 72.98 113.15 73.55" class="interior" />
</g>
<g id="region-NJ" clip-path="url(#clip-NJ)" stroke='#000000' fill='#0000ff' transform-origin='113.97 70.26' >
<path id="NJ-0" d="M 112.98 71.34 112.94 71.05 113.12 70.89 113.36 70.75 113.44 70.66 113.72 70.46 113.87 70.29 113.5 69.9 113.48 69.74 113.35 69.69 113.36 69.44 113.49 69.25 113.43 69.05 113.62 68.92 113.82 68.57 113.96 68.5 114.85 69.11 114.81 69.44 114.45 69.86 114.8 69.93 114.55 71.02 113.7 72.18 113.61 71.8 113.36 71.72 112.98 71.34" class="interior" />
</g>
<g id="region-NY" clip-path="url(#clip-NY)" stroke='#000000' fill='#0000ff' transform-origin='113.01 66.0' >
<path id="NY-0" d="M 115.34 67.41 115.27 68.61 115.36 68.74 115.11 68.89 115.15 69.08 115.16 69.12 115.09 69.16 116.8 68.87 117.14 69.16 115.51 69.62 114.77 69.63 114.81 69.44 114.85 69.11 113.96 68.5 113.78 68.39 113.58 68.29 113.5 68.06 113.53 67.89 113.39 67.75 113.14 67.5 111.56 67.5 109.87 67.5 108.05 67.5 108.05 67.07 109.05 66.13 109.03 65.98 108.93 65.5 109.48 65.32 110.39 65.37 111.34 65.51 112.22 64.98 112.15 64.35 112.03 64.12 113.22 62.99 113.74 62.69 115.51 62.67 115.49 63.01 115.44 63.22 115.47 63.7 115.53 63.95 115.42 64.29 115.52 64.71 115.45 64.94 115.47 65.0 115.64 65.01 115.59 66.33 115.34 67.41" class="interior" />
</g>
<g id="region-PA" clip-path="url(#clip-PA)" stroke='#000000' fill='#0000ff' transform-origin='110.32 69.23' >
<path id="PA-0" d="M 107.17 69.6 107.17 67.53 108.05 67.08 108.05 67.07 108.05 67.5 109.87 67.5 111.56 67.5 113.14 67.5 113.39 67.75 113.53 67.89 113.5 68.06 113.58 68.29 113.78 68.39 113.96 68.5 113.82 68.57 113.62 68.92 113.43 69.05 113.49 69.25 113.36 69.44 113.35 69.69 113.48 69.74 113.5 69.9 113.87 70.29 113.72 70.46 113.44 70.66 113.36 70.75 113.12 70.89 112.87 70.81 112.76 70.88 112.67 71.0 111.65 71.01 110.65 71.0 109.83 71.01 109.46 71.01 108.38 71.01 107.17 71.01 107.17 69.6" class="interior" />
</g>
<g id="region-ME" clip-path="url(#clip-ME)" stroke='#000000' fill='#aaaaaa' transform-origin='120.32 62.09' >
<path id="ME-0" d="M 118.66 65.78 118.53 65.79 118.48 65.57 118.26 65.33 118.31 65.18 118.14 62.18 118.64 61.93 119.05 61.17 119.41 59.86 120.29 58.57 120.68 59.02 121.46 58.73 121.98 59.22 121.98 61.52 122.74 62.46 122.94 63.0 121.7 63.79 120.5 64.35 119.27 64.83 118.66 65.78" class="interior" />
</g>
<g id="region-MI" clip-path="url(#clip-MI)" stroke='#000000' fill='#0000ff' transform-origin='102.41 65.11' >
<path id="MI-0" d="M 104.95 65.95 104.4 66.82 104.14 67.37 103.74 67.98 103.3 67.99 102.78 67.99 102.18 68.0 102.18 67.88 101.08 67.89 99.83 67.88 100.07 67.66 100.54 66.9 100.57 65.86 100.19 64.87 100.24 64.18 100.55 63.38 100.84 62.83 101.3 62.44 101.41 62.99 101.62 62.18 101.87 62.01 102.04 61.38 103.03 61.71 103.89 62.36 103.98 63.1 103.87 63.85 103.24 64.5 103.29 64.9 103.53 64.91 104.25 64.2 104.68 64.37 104.89 65.3 104.95 65.95" class="interior" />
<path id="MI-1" d="M 102.49 60.12 102.41 60.29 102.73 60.34 103.31 61.01 102.28 61.16 102.24 61.15 101.33 60.98 100.42 61.31 99.63 61.46 98.94 62.52 98.92 62.5 98.91 62.51 98.76 62.31 98.85 62.05 98.59 62.03 98.64 61.76 98.71 61.63 98.61 61.39 98.33 61.29 98.27 61.01 98.04 60.99 97.72 60.99 97.04 60.69 96.03 60.39 95.93 60.08 95.75 60.03 95.75 60.02 95.68 60.06 95.67 60.05 95.68 60.06 96.57 59.62 97.51 59.07 98.53 58.5 98.16 59.41 98.82 59.62 99.64 60.27 100.67 59.89 101.82 59.74 102.06 60.22 102.41 60.29 102.49 60.12" class="interior" />
</g>
<g id="region-AK" clip-path="url(#clip-AK)" stroke='#000000' fill='#aaaaaa' transform-origin='23.08 20.58' >
<path id="AK-0" d="M 36.82 6.73 36.81 18.21 36.81 32.93 37.95 33.0 39.08 33.65 39.9 34.66 40.93 36.16 42.06 34.89 43.23 34.14 43.85 35.33 44.63 36.26 45.7 37.26 46.42 38.84 47.61 41.29 49.59 42.62 49.62 43.92 48.98 44.9 48.34 44.13 47.31 43.48 46.98 41.67 45.48 39.95 44.86 37.9 43.74 37.76 41.89 37.7 40.53 37.06 38.12 34.72 37.01 34.28 34.97 33.45 33.36 33.65 31.07 32.58 29.69 31.56 28.4 32.07 28.64 33.7 28.0 33.85 26.65 34.33 25.63 35.11 24.34 35.59 24.17 34.24 24.69 31.94 25.93 31.21 25.61 30.6 24.13 31.94 23.33 33.51 21.66 35.15 22.51 36.25 21.41 37.85 20.16 38.77 18.99 39.43 18.71 40.38 16.89 41.47 16.52 42.46 15.16 43.34 14.36 43.18 13.28 43.75 12.09 44.45 11.13 45.12 9.13 45.7 8.95 45.36 10.22 44.42 11.36 43.79 12.6 42.66 14.04 42.43 14.62 41.57 16.23 40.3 16.49 39.87 17.35 39.11 17.55 37.45 18.14 36.13 16.8 36.81 16.42 36.42 15.79 37.23 15.03 36.1 14.72 36.9 14.29 35.78 13.12 36.68 12.41 36.68 12.31 35.34 12.52 34.5 11.77 33.67 10.26 34.12 9.27 33.03 8.48 32.46 8.47 31.11 7.58 30.08 8.03 28.66 8.98 27.26 9.39 25.95 10.33 25.77 11.13 26.18 12.07 24.93 12.91 25.15 13.8 24.34 13.58 23.13 12.93 22.65 13.79 21.6 13.08 21.63 11.84 22.22 11.49 22.82 10.57 22.22 8.93 22.53 7.22 21.88 6.73 20.77 5.26 19.15 6.9 17.96 9.49 16.54 10.45 16.54 10.29 17.99 12.75 17.88 11.8 16.08 10.37 14.95 9.54 13.44 8.43 12.12 6.83 11.13 7.48 9.46 9.54 9.35 11.01 7.86 11.29 6.24 12.48 4.61 13.61 4.22 15.82 2.66 16.89 2.89 18.68 0.98 20.44 1.74 21.28 3.35 21.8 2.66 23.76 2.88 23.69 3.69 25.47 4.28 26.66 3.93 29.11 5.02 31.35 5.35 32.24 5.79 33.79 5.24 35.56 6.26 36.82 6.73" class="interior" />
<path id="AK-1" d="M 22.58 38.24 23.35 38.39 23.84 39.06 22.84 40.09 21.67 40.9 21.08 40.35 20.9 39.34 21.95 38.57 22.58 38.24" class="interior" />
<path id="AK-2" d="M 1.05 24.3 1.77 24.8 2.49 24.53 3.43 25.22 4.59 25.56 4.49 25.84 3.61 26.39 2.73 25.83 2.28 25.36 1.26 25.51 0.98 25.28 1.05 24.3" class="interior" />
<path id="AK-3" d="M 7.17 32.75 8.1 32.96 8.21 33.86 7.49 34.22 6.73 33.79 6.02 33.15 7.17 32.75" class="interior" />
</g>
<foreignObject x="0" y="50" width="30" height="50">
</foreignObject>
<script>
var sortedList = [];
sortedList.push("CA");
sortedList.push("TX");
sortedList.push("FL");
sortedList.push("NY");
sortedList.push("IL");
sortedList.push("PA");
sortedList.push("OH");
sortedList.push("GA");
sortedList.push("NC");
sortedList.push("MI");
sortedList.push("NJ");
sortedList.push("VA");
sortedList.push("WA");
sortedList.push("AZ");
sortedList.push("MA");
sortedList.push("IN");
sortedList.push("TN");
sortedList.push("MN");
sortedList.push("CO");
sortedList.push("MO");
sortedList.push("WI");
sortedList.push("MD");
sortedList.push("AL");
sortedList.push("SC");
sortedList.push("OR");
sortedList.push("LA");
sortedList.push("KY");
sortedList.push("OK");
sortedList.push("CT");
sortedList.push("NV");
sortedList.push("UT");
sortedList.push("AR");
sortedList.push("IA");
sortedList.push("KS");
sortedList.push("MS");
sortedList.push("NM");
sortedList.push("NE");
sortedList.push("MT");
sortedList.push("HI");
sortedList.push("ID");
sortedList.push("NH");
sortedList.push("RI");
sortedList.push("WV");
sortedList.push("ME");
sortedList.push("ND");
sortedList.push("WY");
sortedList.push("SD");
sortedList.push("VT");
sortedList.push("DE");
sortedList.push("DC");
sortedList.push("AK");
</script>
<script href="script.js"></script>
</svg>
<div id="vbLeft" style="left: 0px;"></div>
<div id="vbRight" style="left: 759.52px;"></div>
<div id="vbTop" style="top: 84px;"></div>
<div id="vbBottom" style="top: 700px;"></div>
</div>
<script>
var activeRegion = false;
var activeScale = 50;
var labelAdj = 1;
var transformObject = {};
var moveLabel = false;
var svg = document.querySelector('svg');
var allGroups = svg.querySelectorAll('g:Not(#outline)');
allGroups.forEach((el) => {
el.addEventListener('click',regionClick);
});
document.getElementById('vbBottom').addEventListener('pointerdown',vbDown);
document.getElementById('vbRight').addEventListener('pointerdown',vbDown);
document.getElementById('vbTop').addEventListener('pointerdown',vbDown);
document.getElementById('vbLeft').addEventListener('pointerdown',vbDown);
var bcr = svg.getBoundingClientRect();
var initialEquivalent = [0,0];
var initialVB = [0,0];
var width = 123.92;
var height = 100;
var vbLTRB = [0,0,width,100];
function clearSelection(){
activeRegion = false;
allGroups.forEach((el) => {
el.classList.remove('selected');
el.removeEventListener('pointerdown',regionDown);
});
}
function regionClick(evt){
var id = evt.currentTarget.id;
if (id == activeRegion){
//activeRegion = false;
}
else {
activeRegion = id;
}
allGroups.forEach((el) => {
el.classList.remove('selected');
el.removeEventListener('pointerdown',regionDown);
});
if (activeRegion){
var el = svg.querySelector("#"+activeRegion);
el.classList.add('selected');
el.addEventListener('pointerdown',regionDown);
var oldT = el.getAttribute('transform');
activeScale = 50;
if (oldT){
var idx = oldT.indexOf('scale(');
if (idx >= 0){
var tstring = oldT.substring(idx+6).split(")")[0].trim();
var rawScale = parseFloat(tstring);
activeScale = Math.round(Math.log10(rawScale)*50+50);
}
}
document.getElementById('regionSize').value = activeScale;
var c = el.getAttribute('fill');
if (c.length == 4){
c = c.substring(0,2)+c.at(1)+c.at(2)+c.at(2)+c.at(3)+c.at(3);
}
document.getElementById('fillColor').value = c;
var c = el.getAttribute('stroke');
if (c.length == 4){
c = c.substring(0,2)+c.at(1)+c.at(2)+c.at(2)+c.at(3)+c.at(3);
}
document.getElementById('strokeColor').value = c;
}
}
function regionDown(evt){
var el = evt.currentTarget;
var id = el.id;
if (moveLabel && id && id.substring(0,7) == "region-"){return;}
else if (id != activeRegion && !moveLabel){return;}
el.addEventListener('pointerup',regionUp);
el.addEventListener('pointermove',regionMove);
console.log(evt.clientX,evt.clientY, id);
bcr = svg.getBoundingClientRect();
initialEquivalent[0] = (evt.clientX-bcr.left)*width/bcr.width;
initialEquivalent[1] = (evt.clientY-bcr.top)*height/bcr.height;
if (!id || id == ''){
transformObject[id]={t:[0,0],s:1};
labelAdj = Math.pow(10,(activeScale-50)/50);
}
else if (!transformObject[id]){
transformObject[id]={t:[0,0],s:Math.pow(10,(activeScale-50)/50)};
}
var offset = el.getAttribute('transform');
if (offset){
console.log(offset);
var idx = offset.indexOf('translate(');
if (idx >= 0){
var tstring = offset.substring(idx+10).split(")")[0].trim();
var x = parseFloat(tstring.split(" ")[0]);
var y = parseFloat(tstring.split(" ")[1]);
transformObject[id].t=[x,y];
if (!id || id == ''){
initialEquivalent[0] -= x*labelAdj;
initialEquivalent[1] -= y*labelAdj;
}
else {
initialEquivalent[0] -= x;
initialEquivalent[1] -= y;
}
}
}
}
function regionMove(evt){
var el = evt.currentTarget;
var id = el.id;
var eq = [(evt.clientX-bcr.left)*width/bcr.width, (evt.clientY-bcr.top)*height/bcr.height];
var offset = [eq[0]-initialEquivalent[0], eq[1]-initialEquivalent[1]];
transformObject[id].t=offset;
var t = "translate("+offset[0]+" "+offset[1]+")";
if (!id || id == ''){
offset[0] /= labelAdj;
offset[1] /= labelAdj;
el.setAttribute('transform',"translate("+offset[0]+" "+offset[1]+")");
}
else {
el.setAttribute('transform',t+" scale("+transformObject[id].s+")");
}
}
function regionUp(evt){
var el = evt.currentTarget;
el.removeEventListener('pointerup',regionUp);
el.removeEventListener('pointermove',regionMove);
var id = el.id;
var eq = [(evt.clientX-bcr.left)*width/bcr.width, (evt.clientY-bcr.top)*height/bcr.height];
var offset = [eq[0]-initialEquivalent[0], eq[1]-initialEquivalent[1]];
transformObject[id].t=offset;
var t = "translate("+offset[0]+" "+offset[1]+")";
if (!id || id == ''){
offset[0] /= labelAdj;
offset[1] /= labelAdj;
el.setAttribute('transform',"translate("+offset[0]+" "+offset[1]+")");
}
else {
el.setAttribute('transform',t+" scale("+transformObject[id].s+")");
}
}
function updateVB() {
var l = parseFloat(document.getElementById('left').value);
var r = parseFloat(document.getElementById('right').value);
var t = parseFloat(document.getElementById('top').value);
var b = parseFloat(document.getElementById('bottom').value);
vbLTRB = [l,t,r,b];
width = r - l;
height = b - t;
svg.setAttribute('viewBox',l + " " + t + " " + width + " " + height);
svg.setAttribute('width',600*width/height+"px");
var vbb = document.getElementById('vbBottom')
vbb.style.top = (100*6+100)+"px";
vbb.style.width = width/height*600+"px";
var vbr = document.getElementById('vbRight')
vbr.style.left = (600*width/height+16)+"px";
var vbr = document.getElementById('vbLeft')
vbr.style.left = (0)+"px";
var vbt = document.getElementById('vbTop')
vbt.style.width = width/height*600+"px";
vbt.style.top = 84+"px";
}
function vbDown(evt){
var el = evt.currentTarget;
var id = el.id;
el.addEventListener('pointerup',vbUp);
el.addEventListener('pointercancel',vbUp);
el.addEventListener('pointerout',vbUp);
el.addEventListener('pointermove',vbMove);
console.log(evt.clientX,evt.clientY);
bcr = svg.getBoundingClientRect();
if (id == "vbBottom"){
initialVB[0] = (evt.clientY-bcr.top);
initialVB[1] = parseFloat(document.getElementById('vbBottom').style.top);
}
else if (id == "vbRight") {
initialVB[0] = (evt.clientX-bcr.left);
initialVB[1] = parseFloat(document.getElementById('vbRight').style.left);
}
else if (id == "vbTop") {
initialVB[0] = (evt.clientY-bcr.top);
initialVB[1] = parseFloat(document.getElementById('vbTop').style.top);
}
else if (id == "vbLeft") {
initialVB[0] = (evt.clientX-bcr.left);
initialVB[1] = parseFloat(document.getElementById('vbLeft').style.left);
}
}
function vbMove(evt){
var el = evt.currentTarget;
var id = el.id;
var eq = [(evt.clientX-bcr.left), (evt.clientY-bcr.top)];
var offset;
if (id == "vbBottom"){
offset = eq[1]-initialVB[0];
document.getElementById('vbBottom').style.top = (initialVB[1]+offset)+"px";
}
else if (id == "vbRight"){
offset = eq[0]-initialVB[0];
document.getElementById('vbRight').style.left = (initialVB[1]+offset)+"px";
}
else if (id == "vbTop"){
offset = eq[1]-initialVB[0];
document.getElementById('vbTop').style.top = (initialVB[1]+offset)+"px";
}
else if (id == "vbLeft"){
offset = eq[0]-initialVB[0];
document.getElementById('vbLeft').style.left = (initialVB[1]+offset)+"px";
}
}
function vbUp(evt){
var el = evt.currentTarget;
el.removeEventListener('pointerup',vbUp);
el.removeEventListener('pointercancel',vbUp);
el.removeEventListener('pointerout',vbUp);
el.removeEventListener('pointermove',vbMove);
var id = el.id;
var eq = [(evt.clientX-bcr.left), (evt.clientY-bcr.top)];
var offset;
if (id == "vbBottom"){
offset = eq[1]-initialVB[0];
document.getElementById('vbBottom').style.top = (initialVB[1]+offset)+"px";
document.getElementById('bottom').value = parseFloat(document.getElementById('bottom').value)+offset*height/bcr.height;
}
else if (id == "vbRight"){
offset = eq[0]-initialVB[0];
document.getElementById('vbRight').style.left = (initialVB[1]+offset)+"px";
document.getElementById('right').value = parseFloat(document.getElementById('right').value)+offset*width/bcr.width;
}
else if (id == "vbTop"){
offset = eq[1]-initialVB[0];
document.getElementById('vbTop').style.top = (initialVB[1]+offset)+"px";
document.getElementById('top').value = parseFloat(document.getElementById('top').value)+offset*height/bcr.height;
}
else if (id == "vbLeft"){
offset = eq[0]-initialVB[0];
document.getElementById('vbLeft').style.left = (initialVB[1]+offset)+"px";
document.getElementById('left').value = parseFloat(document.getElementById('left').value)+offset*width/bcr.width;
}
}
function copySVG(){
var str = svg.outerHTML;
navigator.clipboard.writeText(str);
}
function downloadSVG() {
var svgString = svg.outerHTML;
var encodedSVG = svgString.replace(/"/g, '\'')
.replace(/%/g, '%25')
.replace(/#/g, '%23')
.replace(/</g, '%3C')
.replace(/>/g, '%3E')
.replace(/\s+/g,' ');
var url = 'data:image/svg+xml,'+encodedSVG;
var a = document.createElement('a');
a.setAttribute('href',url);
a.setAttribute('download','image.svg');
a.click();
}
function toggleMoveLabel(){
if (moveLabel){
moveLabel = false;
}
else {
moveLabel = true;
}
var els = svg.querySelectorAll('text');
els.forEach((el) => {
if (moveLabel){
el.style.pointerEvents = "all";
el.addEventListener('pointerdown',regionDown);
}
else {
el.style.pointerEvents = "none";
el.removeEventListener('pointerdown',regionDown);
}
})
}
function setRegionSize(sz){
if (!activeRegion){return;}
activeScale = Math.round(Math.log10(sz)*50+50);
var el = document.getElementById(activeRegion);
if (!transformObject[activeRegion]){
transformObject[activeRegion]={t:[0,0],s:sz};
}
transformObject[activeRegion].s = sz;
el.setAttribute('transform','translate('+transformObject[activeRegion].t[0]+" "+transformObject[activeRegion].t[1]+') scale('+sz+')');
el.style.setProperty('--gs',sz);
}
function duplicateRegion(){
if (!activeRegion){return;}
var el = document.getElementById(activeRegion);
clone = el.cloneNode(true);
clone.id = activeRegion+"-1";
clone.addEventListener('click',regionClick);
svg.appendChild(clone);
allGroups = svg.querySelectorAll('g:Not(#outline)');
}
function deleteRegion(){
if (!activeRegion){return;}
var el = document.getElementById(activeRegion);
el.parentElement.removeChild(el);
}
function chgFill(color){
if (!activeRegion){return;}
var el = document.getElementById(activeRegion);
el.setAttribute('fill',color);
}
function chgStroke(color){
if (!activeRegion){return;}
var el = document.getElementById(activeRegion);
el.setAttribute('stroke',color);
}
</script>
</body>
</html>
import math
import random
import csv
from os import walk
from pyproj import Transformer
from pyproj.crs import CRS
from shapely.geometry import Polygon, Point, MultiPolygon
from shapely.ops import unary_union
import fiona
from flask import Flask, render_template, request, send_from_directory, redirect
app = Flask(__name__)
#choose one of the filenames below or add your own
#U.S. states
filename = "ne_110m_admin_1_states_provinces_lakes"
#PUMAs in South Carolina
#filename = "cb_2018_45_puma10_500k"
#Countries of the World
#filename = "ne_110m_admin_0_countries_lakes"
def readcsv(filename):
obj = {}
obj["head"] = []
obj["body"] = []
with open(filename, newline='') as csvfile:
reader = csv.reader(csvfile, delimiter=',', quotechar='"')
idx = 0
for row in reader:
if idx == 0:
obj["head"].append(row)
else:
obj["body"].append(row)
idx += 1
return obj
def sortSecond(a):
return a[1]
def loadFileProperties(filename):
cFile = filename+"/"+filename+".shp"
regionPolygons = fiona.open(cFile)
table = {"head":[[]],"body":[]}
allProps = {}
for region in regionPolygons:
regionProps = region['properties']
for i in regionProps:
try:
prop = allProps[i]
except:
allProps[i] = len(table["head"][0])
table["head"][0].append(i)
prop = allProps[i]
row = []
for i in range(0,len(table["head"][0])):
row.append("")
for i in regionProps:
prop = allProps[i]
row[prop] = regionProps[i]
table["body"].append(row)
return table
def getfiles():
shapefiles = []
csvs = []
for (dirpath, dirnames, filenames) in walk("."):
#print(dirpath)
if len(dirpath) > 2:
for i in range(0,len(filenames)):
split = filenames[i].split(".")
if len(split) > 1 and split[1] == "shp":
shapefiles.append(split[0])
break
else:
for i in range(0,len(filenames)):
split = filenames[i].split(".")
if len(split) > 1 and split[1] == "csv":
csvs.append(split[0])
return [shapefiles,csvs]
@app.route('/addfiles', methods = ['GET'])
def addfiles():
allfiles = getfiles()
shapefiles = allfiles[0]
csvs = allfiles[1]
return render_template('addfiles.html',shapefiles=shapefiles,csvs=csvs)
@app.route('/create', methods = ['POST'])
def create():
if request.method == 'POST':
shapefile = request.form.get('shapefile')
csvsRaw = request.form.getlist('csv')
print(shapefile)
print(csvsRaw)
table = loadFileProperties(shapefile)
csvs = {}
for i in range(0,len(csvsRaw)):
csvs[i]=readcsv(csvsRaw[i]+".csv")
return render_template('create.html',head=table["head"],body=table["body"],csvs=csvs,shapefile=shapefile,csvnames=", ".join(csvsRaw))
@app.route('/createsvg', methods = ['POST'])
def createsvg():
if request.method == 'POST':
shapefile = request.form.get('shapefile')
csvsRaw = request.form.get('csvnames').split(",")
print(shapefile)
print(csvsRaw)
table = loadFileProperties(shapefile)
csvs = {}
csvdata = {}
for i in range(0,len(csvsRaw)):
csvs[i]=readcsv(csvsRaw[i].strip()+".csv")
header=csvs[i]["head"][0]
for ii in range(0,len(csvs[i]["body"])):
try:
x = csvdata[csvs[i]["body"][ii][0]]
except:
csvdata[csvs[i]["body"][ii][0]] = {}
for iii in range(1,min(len(header),len(csvs[i]["body"][ii]))):
csvdata[csvs[i]["body"][ii][0]][header[iii]]=csvs[i]["body"][ii][iii]
projection = request.form.get('projection')
idStr = request.form.get('idColumn')
colors = request.form.get('ncolors')
colorList = []
for i in range(1,int(colors)+1):
colorList.append(request.form.get('color'+str(i)))
formula = request.form.get('fillFormula').strip()
outname = "unnamed-region"
regionsPost = request.form.get('regions').split(",")
regions = []
sortedVals = []
for i in range(0,len(regionsPost)):
if len(regionsPost[i].strip()) > 0:
regions.append(regionsPost[i].strip().upper())
try:
sortedVals.append([regionsPost[i].strip().upper(),int(csvdata[regionsPost[i].strip().upper()][formula])])
except:
pass
sortedVals.sort(key=sortSecond,reverse=True)
for i in range(0,len(sortedVals)):
csvdata[sortedVals[i][0]]['rank']=i
idx = math.trunc(i*int(colors)/len(sortedVals))
csvdata[sortedVals[i][0]]['fillColor']=colorList[idx]
cFile = shapefile+"/"+shapefile+".shp"
regionPolygons = fiona.open(cFile)
print(regionPolygons.crs)
regionData = {"regions":{},"width":100,"viewBox":"0 0 100 100"}
cidx = 0
#transformer = Transformer.from_crs("epsg:4326", "epsg:5070")
transformer = Transformer.from_crs(regionPolygons.crs["init"], projection)#Web Mercator
bounds = [-1000,-1000,-1000,-1000]#left,right,bottom,top
scale = 1
width = 100
outline = []
for region in regionPolygons:
geoType = region['geometry']['type']
regionID = region['properties'][idStr].strip().upper()
if regionID not in regions and len(regions) > 0:
continue
paths = []
if geoType == 'Polygon':
coords = region['geometry']['coordinates'][0]
path = []
for ii in range(0,len(coords)):
out = transformer.transform(coords[ii][1],coords[ii][0])
out = [out[0],-1*out[1]]
path.append(out)
if coords[ii][1] > 75 or coords[ii][1] < -75 or coords[ii][0] > 180 or coords[ii][0] < -180:
continue
if bounds[0]==-1000 or out[0]<bounds[0]:
bounds[0] = out[0]
if bounds[1]==-1000 or out[0]>bounds[1]:
bounds[1] = out[0]
if bounds[2]==-1000 or out[1]<bounds[2]:
bounds[2] = out[1]
if bounds[3]==-1000 or out[1]>bounds[3]:
bounds[3] = out[1]
poly = Polygon(coords)
ppoly = Polygon(path)
outline.append(ppoly)
paths.append([path,0,ppoly.centroid])
elif geoType == 'MultiPolygon':
allPolys = []
for i in range(0,len(region['geometry']['coordinates'])):
coords = region['geometry']['coordinates'][i][0]
path = []
for ii in range(0,len(coords)):
out = transformer.transform(coords[ii][1],coords[ii][0])
out = [out[0],-1*out[1]]
path.append(out)
if coords[ii][1] > 75 or coords[ii][1] < -75 or coords[ii][0] > 180 or coords[ii][0] < -180:
continue
if bounds[0]==-1000 or out[0]<bounds[0]:
bounds[0] = out[0]
if bounds[1]==-1000 or out[0]>bounds[1]:
bounds[1] = out[0]
if bounds[2]==-1000 or out[1]<bounds[2]:
bounds[2] = out[1]
if bounds[3]==-1000 or out[1]>bounds[3]:
bounds[3] = out[1]
poly = Polygon(coords)
allPolys.append(poly)
ppoly = Polygon(path)
outline.append(ppoly)
paths.append([path,poly.area,ppoly.centroid])
poly = MultiPolygon(allPolys)
else:
print(geoType)
paths.sort(key=sortSecond,reverse=True)
try:
regionName = region['properties'][nameStr]
except:
regionName = ""
try:
color = str(csvdata[regionID]['fillColor'])
except:
color = "rgb(255,255,255)"
color2 = "#000000"
regionData["regions"][regionID]={"name":regionName,"id":regionID,"centroid":paths[0][2].coords[0],"paths":paths,"fillColor":color,"strokeColor":color2}
#regionData["regions"][regionID]["label"] = region['properties'][idStr]
scale = 100/(bounds[3]-bounds[2])
bounds[0] -= 1/scale
bounds[1] += 1/scale
bounds[2] -= 1/scale
bounds[3] += 1/scale
scale = 100/(bounds[3]-bounds[2])
width = round((bounds[1]-bounds[0])*scale,2)
regionData["width"]=width
regionData["viewBox"]="0 0 "+str(width)+" 100"
outlinePolys = unary_union(outline)
regionData["outline"]= []
outlineList = []
try:
ll = len(outlinePolys.geoms)
outlineList = outlinePolys.geoms
except:
outlineList = [outlinePolys]
for poly in outlineList:
coords = poly.exterior.coords
path = "M"
lastCoord = [-10,-10]
firstCoord = [-10,-10]
for ii in range(0,len(coords)):
x = round((coords[ii][0]-bounds[0])*scale,2)
y = round((coords[ii][1]-bounds[2])*scale,2)
if ii == 0:
firstCoord = [x,y]
if lastCoord[1]==y and lastCoord[0]==x:
continue
lastCoord = [x,y]
path += " "+str(x)+" "+str(y)
if lastCoord[0] != firstCoord[0] or lastCoord[1] != firstCoord[1]:
path += " "+str(firstCoord[0])+" "+str(firstCoord[1])
regionData["outline"].append(path)
for r in regionData["regions"]:
pathsRaw = regionData["regions"][r]["paths"]
regionData["regions"][r]["paths"] = []
centroidX = round((regionData["regions"][r]["centroid"][0]-bounds[0])*scale,2)
centroidY = round((regionData["regions"][r]["centroid"][1]-bounds[2])*scale,2)
regionData["regions"][r]["centroid"] = [centroidX,centroidY]
for i in range(0,len(pathsRaw)):
path = "M"
lastCoord = [-10,-10]
firstCoord = [-10,-10]
for ii in range(0,len(pathsRaw[i][0])):
x = round((pathsRaw[i][0][ii][0]-bounds[0])*scale,2)
y = round((pathsRaw[i][0][ii][1]-bounds[2])*scale,2)
if ii == 0:
firstCoord = [x,y]
if lastCoord[1]==y and lastCoord[0]==x:
continue
lastCoord = [x,y]
path += " "+str(x)+" "+str(y)
if lastCoord[0] != firstCoord[0] or lastCoord[1] != firstCoord[1]:
path += " "+str(firstCoord[0])+" "+str(firstCoord[1])
regionData["regions"][r]["paths"].append({"id":r+"-"+str(i),"d":path})
#print(regionData)
if 2 == 2:
regionData["outline"]=False
output = render_template("template.html",regions=regionData["regions"],outline=regionData["outline"],viewBox=regionData["viewBox"],width=regionData["width"],sortedVals=sortedVals)
with open("svgs/"+outname+".html", "w") as fh:
fh.write(output)
return redirect("svgs/"+outname+".html", code=302)
@app.route('/svgs/<path:path>')
def send_svg(path):
return send_from_directory('svgs',path)
@app.route('/', methods = ['GET', 'POST'])
def index():
return send_from_directory('.',"index.html")
app.run(host='0.0.0.0', port=81)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="favicon.png">
<title></title>
<meta name="description" content="" />
<style>
#container {
position: relative;
--gs: 1;
}
#container > svg {
position: absolute;
left: 16px;
top: 100px;
}
#vbTop {
display: inline-block;
position: absolute;
left: 16px;
height: 16px;
width: calc({{width * 6}}px);
background: blue;
}
#vbLeft {
display: inline-block;
position: absolute;
top: 100px;
width: 16px;
height: 600px;
background: blue;
}
#vbBottom {
display: inline-block;
position: absolute;
left: 16px;
height: 16px;
width: calc({{width * 6}}px);
background: blue;
}
#vbRight {
display: inline-block;
position: absolute;
top: 100px;
width: 16px;
height: 600px;
background: blue;
}
</style>
</head>
<body>
<div id="container">
<div id="menu">
Left: <input style="width: 5rem;" type="text" id="left" value="0" />
Right: <input style="width: 5rem;" type="text" id="right" value="{{width}}" />
Top: <input style="width: 5rem;" type="text" id="top" value="0" />
Bottom: <input style="width: 5rem;" type="text" id="bottom" value="100" />
<button onclick="updateVB()">Update</button>
<div>
<button onclick="copySVG()">Copy SVG</button>
<button onclick="downloadSVG()">Download SVG</button>
<!--Label Size: <input type="range" oninput="svg.style.setProperty('--fs',0.5*Math.pow(10,(this.value-10)/10)+'rem');" id="labelSize" min="0" max="20" value="10">
<button onclick="toggleMoveLabel()">Move Label(s)</button>-->
Region Size: <input type="range" oninput="setRegionSize(Math.pow(10,(this.value-50)/50));" id="regionSize" min="0" max="100" value="50">
Stroke Width: <input type="range" oninput="svg.style.setProperty('--sw',3*Math.pow(10,(this.value-10)/10));" id="strokeWidth" min="0" max="20" value="10">
</div>
<div>
<button onclick="duplicateRegion()">Duplicate</button>
<button onclick="deleteRegion()">Delete</button>
<!--Hover Box:
Key Box:
Table Box:-->
<button onclick="clearSelection()">Unselect Region</button>
</div>
</div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox='{{viewBox}}' style="--fs:0.5rem; --sw: 3;" width='{{width * 6}}px' height='600px'>
<style>
.interior {
stroke-width: calc(var(--sw) / var(--gs));
}
.selected path {
stroke-dasharray: 2 1 1 1;
}
.outline {
stroke-width: calc(1.5 * var(--sw) / var(--gs));
stroke: black;
fill: none;
}
text {
fill: white;
stroke: none;
font-size: calc(var(--fs) / var(--gs));
pointer-events: none;
cursor: pointer;
}
</style>
{% for region in regions %}
<clipPath id="clip-{{region}}">
{% for path in regions[region]["paths"] %}
<path d="{{path.d}}" />
{% endfor %}
</clipPath>
{% endfor %}
{% for region in regions %}
<g id="region-{{region}}" clip-path="url(#clip-{{region}})" stroke='{{regions[region]["strokeColor"]}}' fill='{{regions[region]["fillColor"]}}' transform-origin='{% if regions[region]["centroid"] %}{{regions[region]["centroid"][0] }} {{regions[region]["centroid"][1] }}{% else %}center{% endif %}' {% for d in regions[region].data %}{{d}}="{{regions[region].data[d]}}" {% endfor %}>
{% for path in regions[region]["paths"] %}
<path id="{{path.id}}" d="{{path.d}}" class="interior" />
{% endfor %}
{% if regions[region]["centroid"] and regions[region]["label"] %}
<text dominant-baseline="middle" text-anchor="middle" x='{{regions[region]["centroid"][0] }}' y='{{regions[region]["centroid"][1] }}'>
{{ regions[region]["label"] }}
</text>
{% endif %}
</g>
{% endfor %}
{% if outline %}
<g id="outline" fill='none'>
{% for path in outline %}
<path d="{{path}}" class="outline" />
{% endfor %}
</g>
{% endif %}
<foreignObject x="0" y="50" width="30" height="50">
</foreignObject>
<script>
var sortedList = [];
{% for i in sortedVals %}
sortedList.push("{{i[0]}}");{% endfor %}
</script>
<script href="script.js"></script>
</svg>
<div id="vbLeft" style="left: 0px;"></div>
<div id="vbRight" style="left: {{width * 6 + 16}}px;"></div>
<div id="vbTop" style="top: 84px;"></div>
<div id="vbBottom" style="top: 700px;"></div>
</div>
<script>
var activeRegion = false;
var activeScale = 50;
var labelAdj = 1;
var transformObject = {};
var moveLabel = false;
var svg = document.querySelector('svg');
var allGroups = svg.querySelectorAll('g:Not(#outline)');
allGroups.forEach((el) => {
el.addEventListener('click',regionClick);
});
document.getElementById('vbBottom').addEventListener('pointerdown',vbDown);
document.getElementById('vbRight').addEventListener('pointerdown',vbDown);
document.getElementById('vbTop').addEventListener('pointerdown',vbDown);
document.getElementById('vbLeft').addEventListener('pointerdown',vbDown);
var bcr = svg.getBoundingClientRect();
var initialEquivalent = [0,0];
var initialVB = [0,0];
var width = {{width}};
var height = 100;
var vbLTRB = [0,0,width,100];
function clearSelection(){
activeRegion = false;
allGroups.forEach((el) => {
el.classList.remove('selected');
el.removeEventListener('pointerdown',regionDown);
});
}
function regionClick(evt){
var id = evt.currentTarget.id;
if (id == activeRegion){
//activeRegion = false;
}
else {
activeRegion = id;
}
allGroups.forEach((el) => {
el.classList.remove('selected');
el.removeEventListener('pointerdown',regionDown);
});
if (activeRegion){
var el = svg.querySelector("#"+activeRegion);
el.classList.add('selected');
el.addEventListener('pointerdown',regionDown);
var oldT = el.getAttribute('transform');
activeScale = 50;
if (oldT){
var idx = oldT.indexOf('scale(');
if (idx >= 0){
var tstring = oldT.substring(idx+6).split(")")[0].trim();
var rawScale = parseFloat(tstring);
activeScale = Math.round(Math.log10(rawScale)*50+50);
}
}
document.getElementById('regionSize').value = activeScale;
var c = el.getAttribute('fill');
if (c.length == 4){
c = c.substring(0,2)+c.at(1)+c.at(2)+c.at(2)+c.at(3)+c.at(3);
}
document.getElementById('fillColor').value = c;
var c = el.getAttribute('stroke');
if (c.length == 4){
c = c.substring(0,2)+c.at(1)+c.at(2)+c.at(2)+c.at(3)+c.at(3);
}
document.getElementById('strokeColor').value = c;
}
}
function regionDown(evt){
var el = evt.currentTarget;
var id = el.id;
if (moveLabel && id && id.substring(0,7) == "region-"){return;}
else if (id != activeRegion && !moveLabel){return;}
el.addEventListener('pointerup',regionUp);
el.addEventListener('pointermove',regionMove);
console.log(evt.clientX,evt.clientY, id);
bcr = svg.getBoundingClientRect();
initialEquivalent[0] = (evt.clientX-bcr.left)*width/bcr.width;
initialEquivalent[1] = (evt.clientY-bcr.top)*height/bcr.height;
if (!id || id == ''){
transformObject[id]={t:[0,0],s:1};
labelAdj = Math.pow(10,(activeScale-50)/50);
}
else if (!transformObject[id]){
transformObject[id]={t:[0,0],s:Math.pow(10,(activeScale-50)/50)};
}
var offset = el.getAttribute('transform');
if (offset){
console.log(offset);
var idx = offset.indexOf('translate(');
if (idx >= 0){
var tstring = offset.substring(idx+10).split(")")[0].trim();
var x = parseFloat(tstring.split(" ")[0]);
var y = parseFloat(tstring.split(" ")[1]);
transformObject[id].t=[x,y];
if (!id || id == ''){
initialEquivalent[0] -= x*labelAdj;
initialEquivalent[1] -= y*labelAdj;
}
else {
initialEquivalent[0] -= x;
initialEquivalent[1] -= y;
}
}
}
}
function regionMove(evt){
var el = evt.currentTarget;
var id = el.id;
var eq = [(evt.clientX-bcr.left)*width/bcr.width, (evt.clientY-bcr.top)*height/bcr.height];
var offset = [eq[0]-initialEquivalent[0], eq[1]-initialEquivalent[1]];
transformObject[id].t=offset;
var t = "translate("+offset[0]+" "+offset[1]+")";
if (!id || id == ''){
offset[0] /= labelAdj;
offset[1] /= labelAdj;
el.setAttribute('transform',"translate("+offset[0]+" "+offset[1]+")");
}
else {
el.setAttribute('transform',t+" scale("+transformObject[id].s+")");
}
}
function regionUp(evt){
var el = evt.currentTarget;
el.removeEventListener('pointerup',regionUp);
el.removeEventListener('pointermove',regionMove);
var id = el.id;
var eq = [(evt.clientX-bcr.left)*width/bcr.width, (evt.clientY-bcr.top)*height/bcr.height];
var offset = [eq[0]-initialEquivalent[0], eq[1]-initialEquivalent[1]];
transformObject[id].t=offset;
var t = "translate("+offset[0]+" "+offset[1]+")";
if (!id || id == ''){
offset[0] /= labelAdj;
offset[1] /= labelAdj;
el.setAttribute('transform',"translate("+offset[0]+" "+offset[1]+")");
}
else {
el.setAttribute('transform',t+" scale("+transformObject[id].s+")");
}
}
function updateVB() {
var l = parseFloat(document.getElementById('left').value);
var r = parseFloat(document.getElementById('right').value);
var t = parseFloat(document.getElementById('top').value);
var b = parseFloat(document.getElementById('bottom').value);
vbLTRB = [l,t,r,b];
width = r - l;
height = b - t;
svg.setAttribute('viewBox',l + " " + t + " " + width + " " + height);
svg.setAttribute('width',600*width/height+"px");
var vbb = document.getElementById('vbBottom')
vbb.style.top = (100*6+100)+"px";
vbb.style.width = width/height*600+"px";
var vbr = document.getElementById('vbRight')
vbr.style.left = (600*width/height+16)+"px";
var vbr = document.getElementById('vbLeft')
vbr.style.left = (0)+"px";
var vbt = document.getElementById('vbTop')
vbt.style.width = width/height*600+"px";
vbt.style.top = 84+"px";
}
function vbDown(evt){
var el = evt.currentTarget;
var id = el.id;
el.addEventListener('pointerup',vbUp);
el.addEventListener('pointercancel',vbUp);
el.addEventListener('pointerout',vbUp);
el.addEventListener('pointermove',vbMove);
console.log(evt.clientX,evt.clientY);
bcr = svg.getBoundingClientRect();
if (id == "vbBottom"){
initialVB[0] = (evt.clientY-bcr.top);
initialVB[1] = parseFloat(document.getElementById('vbBottom').style.top);
}
else if (id == "vbRight") {
initialVB[0] = (evt.clientX-bcr.left);
initialVB[1] = parseFloat(document.getElementById('vbRight').style.left);
}
else if (id == "vbTop") {
initialVB[0] = (evt.clientY-bcr.top);
initialVB[1] = parseFloat(document.getElementById('vbTop').style.top);
}
else if (id == "vbLeft") {
initialVB[0] = (evt.clientX-bcr.left);
initialVB[1] = parseFloat(document.getElementById('vbLeft').style.left);
}
}
function vbMove(evt){
var el = evt.currentTarget;
var id = el.id;
var eq = [(evt.clientX-bcr.left), (evt.clientY-bcr.top)];
var offset;
if (id == "vbBottom"){
offset = eq[1]-initialVB[0];
document.getElementById('vbBottom').style.top = (initialVB[1]+offset)+"px";
}
else if (id == "vbRight"){
offset = eq[0]-initialVB[0];
document.getElementById('vbRight').style.left = (initialVB[1]+offset)+"px";
}
else if (id == "vbTop"){
offset = eq[1]-initialVB[0];
document.getElementById('vbTop').style.top = (initialVB[1]+offset)+"px";
}
else if (id == "vbLeft"){
offset = eq[0]-initialVB[0];
document.getElementById('vbLeft').style.left = (initialVB[1]+offset)+"px";
}
}
function vbUp(evt){
var el = evt.currentTarget;
el.removeEventListener('pointerup',vbUp);
el.removeEventListener('pointercancel',vbUp);
el.removeEventListener('pointerout',vbUp);
el.removeEventListener('pointermove',vbMove);
var id = el.id;
var eq = [(evt.clientX-bcr.left), (evt.clientY-bcr.top)];
var offset;
if (id == "vbBottom"){
offset = eq[1]-initialVB[0];
document.getElementById('vbBottom').style.top = (initialVB[1]+offset)+"px";
document.getElementById('bottom').value = parseFloat(document.getElementById('bottom').value)+offset*height/bcr.height;
}
else if (id == "vbRight"){
offset = eq[0]-initialVB[0];
document.getElementById('vbRight').style.left = (initialVB[1]+offset)+"px";
document.getElementById('right').value = parseFloat(document.getElementById('right').value)+offset*width/bcr.width;
}
else if (id == "vbTop"){
offset = eq[1]-initialVB[0];
document.getElementById('vbTop').style.top = (initialVB[1]+offset)+"px";
document.getElementById('top').value = parseFloat(document.getElementById('top').value)+offset*height/bcr.height;
}
else if (id == "vbLeft"){
offset = eq[0]-initialVB[0];
document.getElementById('vbLeft').style.left = (initialVB[1]+offset)+"px";
document.getElementById('left').value = parseFloat(document.getElementById('left').value)+offset*width/bcr.width;
}
}
function copySVG(){
var str = svg.outerHTML;
navigator.clipboard.writeText(str);
}
function downloadSVG() {
var svgString = svg.outerHTML;
var encodedSVG = svgString.replace(/"/g, '\'')
.replace(/%/g, '%25')
.replace(/#/g, '%23')
.replace(/</g, '%3C')
.replace(/>/g, '%3E')
.replace(/\s+/g,' ');
var url = 'data:image/svg+xml,'+encodedSVG;
var a = document.createElement('a');
a.setAttribute('href',url);
a.setAttribute('download','image.svg');
a.click();
}
function toggleMoveLabel(){
if (moveLabel){
moveLabel = false;
}
else {
moveLabel = true;
}
var els = svg.querySelectorAll('text');
els.forEach((el) => {
if (moveLabel){
el.style.pointerEvents = "all";
el.addEventListener('pointerdown',regionDown);
}
else {
el.style.pointerEvents = "none";
el.removeEventListener('pointerdown',regionDown);
}
})
}
function setRegionSize(sz){
if (!activeRegion){return;}
activeScale = Math.round(Math.log10(sz)*50+50);
var el = document.getElementById(activeRegion);
if (!transformObject[activeRegion]){
transformObject[activeRegion]={t:[0,0],s:sz};
}
transformObject[activeRegion].s = sz;
el.setAttribute('transform','translate('+transformObject[activeRegion].t[0]+" "+transformObject[activeRegion].t[1]+') scale('+sz+')');
el.style.setProperty('--gs',sz);
}
function duplicateRegion(){
if (!activeRegion){return;}
var el = document.getElementById(activeRegion);
clone = el.cloneNode(true);
clone.id = activeRegion+"-1";
clone.addEventListener('click',regionClick);
svg.appendChild(clone);
allGroups = svg.querySelectorAll('g:Not(#outline)');
}
function deleteRegion(){
if (!activeRegion){return;}
var el = document.getElementById(activeRegion);
el.parentElement.removeChild(el);
}
function chgFill(color){
if (!activeRegion){return;}
var el = document.getElementById(activeRegion);
el.setAttribute('fill',color);
}
function chgStroke(color){
if (!activeRegion){return;}
var el = document.getElementById(activeRegion);
el.setAttribute('stroke',color);
}
</script>
</body>
</html>
State | EV | |||||
AK | 3 | |||||
AL | 9 | |||||
AR | 6 | |||||
AZ | 11 | |||||
CA | 54 | |||||
CO | 10 | |||||
CT | 7 | |||||
DC | 3 | |||||
DE | 3 | |||||
FL | 30 | |||||
GA | 16 | |||||
HI | 4 | |||||
IA | 6 | |||||
ID | 4 | |||||
IL | 19 | |||||
IN | 11 | |||||
KS | 6 | |||||
KY | 8 | |||||
LA | 8 | |||||
MA | 11 | |||||
MD | 10 | |||||
ME | 4 | |||||
MI | 15 | |||||
MN | 10 | |||||
MO | 10 | |||||
MS | 6 | |||||
MT | 4 | |||||
NC | 16 | |||||
ND | 3 | |||||
NE | 5 | |||||
NH | 4 | |||||
NJ | 14 | |||||
NM | 5 | |||||
NV | 6 | |||||
NY | 28 | |||||
OH | 17 | |||||
OK | 7 | |||||
OR | 8 | |||||
PA | 19 | |||||
RI | 4 | |||||
SC | 9 | |||||
SD | 3 | |||||
TN | 11 | |||||
TX | 40 | |||||
UT | 6 | |||||
VA | 13 | |||||
VT | 3 | |||||
WA | 12 | |||||
WI | 10 | |||||
WV | 4 | |||||
WY | 3 |
This repl creates SVG element with Python from a provided shapefile and csv file. You can shapefiles and csvs to create the map of your choosing, but you may need to make lots of changes to get the data to work together for now.
The Python packages should install themselves if using Replit, but you will need to make sure everything gets installed if using another method.
Use fiona version 1.8.20 (not 1.8.21 or later) for replit (and maybe elsewhere if you get errors). python3 -m poetry add fiona==1.8.20
To view this on TripleLog, click here.
Modify the addfiles, template.html and/or create.html files in the templates directory.
Three shapefiles are provided, but you can download more from Natural Earth, the U.S. Census, or wherever else. Other formats like geoJSON also will easily work. If the shapefiles are very complex, then you may wish to simplify the curves. If the geoType is not a polygon or multipolygon you will need to figure out what to do.
The geo data is read and a viewBox and scaled version of the desired regions are created and fed into a template.
A Flask server is started to allow for a simple UI (at the /create url by default) to dictate details of the map which gets posted to the server where the SVG is generated.
The Python server will create an HTML file that includes lots of JavaScript functions to edit the map. You can read/edit this JS in the script tag at the bottom of the template.html file. You might wish to create a separate JS file.